From 86a80d371c81c8efaef8f0ec169215f97783ffcd Mon Sep 17 00:00:00 2001 From: Hansie Odendaal Date: Mon, 15 Jul 2024 17:55:18 +0200 Subject: [PATCH] Add ledger methods Added ledger methods to support faucet spending. --- Cargo.lock | 166 ++++--- .../src/automation/commands.rs | 4 +- .../minotari_console_wallet/src/init/mod.rs | 10 +- .../minotari_ledger_wallet/comms/Cargo.toml | 11 +- .../comms/examples/ledger_demo/main.rs | 256 ++++++++++ .../comms/src/accessor_methods.rs | 445 ++++++++++++++++++ .../comms/src/ledger_wallet.rs | 93 +++- .../minotari_ledger_wallet/comms/src/lib.rs | 1 + .../minotari_ledger_wallet/wallet/Cargo.toml | 6 +- .../src/handlers/get_dh_shared_secret.rs | 6 +- .../wallet/src/handlers/get_public_key.rs | 6 +- .../src/handlers/get_public_spend_key.rs | 6 +- .../src/handlers/get_schnorr_signature.rs | 126 +++++ .../src/handlers/get_script_signature.rs | 22 +- .../wallet/src/handlers/get_view_key.rs | 6 +- .../minotari_ledger_wallet/wallet/src/main.rs | 58 ++- .../wallet/src/utils.rs | 16 + .../src/grpc/base_node_grpc_server.rs | 9 +- base_layer/common_types/src/key_manager.rs | 65 +++ base_layer/common_types/src/lib.rs | 1 + base_layer/common_types/src/wallet_types.rs | 6 +- base_layer/core/src/blocks/faucets/mod.rs | 2 +- .../core/src/transactions/coinbase_builder.rs | 13 +- .../src/transactions/key_manager/inner.rs | 432 ++++++++++------- .../src/transactions/key_manager/interface.rs | 57 +-- .../core/src/transactions/key_manager/mod.rs | 2 +- .../src/transactions/key_manager/wrapper.rs | 4 +- .../core/src/transactions/test_helpers.rs | 6 +- .../transaction_components/error.rs | 2 + .../transaction_components/wallet_output.rs | 2 +- .../wallet_output_builder.rs | 9 +- .../transaction_protocol/recipient.rs | 9 +- .../transaction_protocol/sender.rs | 4 +- .../transaction_protocol/single_receiver.rs | 4 +- .../transaction_initializer.rs | 3 +- .../core/src/validation/block_body/test.rs | 4 +- .../core/tests/helpers/block_builders.rs | 7 +- base_layer/core/tests/tests/mempool.rs | 12 +- .../core/tests/tests/node_comms_interface.rs | 2 +- .../src/key_manager_service/error.rs | 6 +- .../src/key_manager_service/service.rs | 12 +- .../recovery/standard_outputs_recoverer.rs | 3 +- .../src/output_manager_service/service.rs | 3 +- .../wallet/src/transaction_service/service.rs | 3 +- .../output_manager_service_tests/service.rs | 2 +- .../transaction_service_tests/storage.rs | 8 +- 46 files changed, 1498 insertions(+), 432 deletions(-) create mode 100644 applications/minotari_ledger_wallet/comms/examples/ledger_demo/main.rs create mode 100644 applications/minotari_ledger_wallet/comms/src/accessor_methods.rs create mode 100644 applications/minotari_ledger_wallet/wallet/src/handlers/get_schnorr_signature.rs create mode 100644 base_layer/common_types/src/key_manager.rs diff --git a/Cargo.lock b/Cargo.lock index e02a0966f2..11e2b7d526 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -62,7 +62,7 @@ dependencies = [ "getrandom", "once_cell", "version_check", - "zerocopy", + "zerocopy 0.7.32", ] [[package]] @@ -1250,7 +1250,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "740fe28e594155f10cfc383984cbefd529d7396050557148f79cb0f621204124" dependencies = [ "generic-array", - "rand_core", + "rand_core 0.6.4", "subtle", "zeroize", ] @@ -1262,7 +1262,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" dependencies = [ "generic-array", - "rand_core", + "rand_core 0.6.4", "typenum", ] @@ -1394,7 +1394,7 @@ dependencies = [ "digest 0.10.7", "fiat-crypto", "group", - "rand_core", + "rand_core 0.6.4", "rustc_version", "serde", "subtle", @@ -1805,7 +1805,7 @@ dependencies = [ "hkdf", "pem-rfc7468", "pkcs8", - "rand_core", + "rand_core 0.6.4", "sec1", "subtle", "zeroize", @@ -1939,7 +1939,7 @@ version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" dependencies = [ - "rand_core", + "rand_core 0.6.4", "subtle", ] @@ -1956,7 +1956,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "835c052cb0c08c1acf6ffd71c022172e18723949c8282f2b9f27efbc51e64534" dependencies = [ "byteorder", - "rand", + "rand 0.8.5", "rustc-hex", "static_assertions", ] @@ -2275,7 +2275,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" dependencies = [ "ff", - "rand_core", + "rand_core 0.6.4", "subtle", ] @@ -2965,7 +2965,7 @@ dependencies = [ "libtor-derive", "libtor-sys", "log", - "rand", + "rand 0.8.5", "sha1 0.6.0", ] @@ -3071,7 +3071,7 @@ dependencies = [ "log-mdc", "once_cell", "parking_lot 0.12.1", - "rand", + "rand 0.8.5", "serde", "serde-value", "serde_json", @@ -3165,7 +3165,7 @@ checksum = "58c38e2799fc0978b65dfff8023ec7843e2330bb462f19198840b34b6582397d" dependencies = [ "byteorder", "keccak", - "rand_core", + "rand_core 0.6.4", "zeroize", ] @@ -3232,7 +3232,7 @@ dependencies = [ "log", "prost", "prost-types", - "rand", + "rand 0.8.5", "rcgen", "subtle", "tari_common_types", @@ -3259,7 +3259,7 @@ dependencies = [ "json5", "log", "minotari_app_grpc", - "rand", + "rand 0.8.5", "serde", "tari_common", "tari_common_types", @@ -3283,7 +3283,7 @@ dependencies = [ "log4rs", "minotari_app_utilities", "openssl", - "rand", + "rand 0.8.5", "tari_chat_client", "tari_common", "tari_common_types", @@ -3317,7 +3317,7 @@ dependencies = [ "minotari_ledger_wallet_comms", "minotari_wallet", "qrcode", - "rand", + "rand 0.8.5", "regex", "reqwest", "rpassword", @@ -3360,9 +3360,14 @@ dependencies = [ "ledger-transport-hid", "num-derive", "num-traits", + "once_cell", + "rand 0.9.0-alpha.1", "serde", + "tari_common", "tari_common_types", "tari_crypto", + "tari_script", + "tari_utilities", "thiserror", ] @@ -3429,7 +3434,7 @@ dependencies = [ "native-tls", "num_cpus", "prost-types", - "rand", + "rand 0.8.5", "serde", "serde_json", "tari_common", @@ -3451,7 +3456,7 @@ dependencies = [ "cbindgen", "hex", "libc", - "rand", + "rand 0.8.5", "tari_common", "tari_common_types", "tari_comms", @@ -3541,7 +3546,7 @@ dependencies = [ "libsqlite3-sys", "log", "prost", - "rand", + "rand 0.8.5", "serde", "serde_json", "sha2 0.10.8", @@ -3587,7 +3592,7 @@ dependencies = [ "num-traits", "once_cell", "openssl", - "rand", + "rand 0.8.5", "serde_json", "tari_common", "tari_common_types", @@ -3838,7 +3843,7 @@ dependencies = [ "num-integer", "num-iter", "num-traits", - "rand", + "rand 0.8.5", "serde", "smallvec", "zeroize", @@ -4144,7 +4149,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7676374caaee8a325c9e7a2ae557f216c5563a171d6997b0ef8a65af35147700" dependencies = [ "base64ct", - "rand_core", + "rand_core 0.6.4", "subtle", ] @@ -4315,7 +4320,7 @@ dependencies = [ "num-traits", "p256", "p384", - "rand", + "rand 0.8.5", "ripemd", "rsa", "sha1 0.10.6", @@ -4365,7 +4370,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5d5285893bb5eb82e6aaf5d59ee909a06a16737a8970984dd7746ba9283498d6" dependencies = [ "phf_shared 0.10.0", - "rand", + "rand 0.8.5", ] [[package]] @@ -4375,7 +4380,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "48e4cc64c2ad9ebe670cb8fd69dd50ae301650392e81c05f9bfcb2d5bdbc24b0" dependencies = [ "phf_shared 0.11.2", - "rand", + "rand 0.8.5", ] [[package]] @@ -4760,7 +4765,7 @@ checksum = "588f6378e4dd99458b60ec275b4477add41ce4fa9f64dcba6f15adccb19b50d6" dependencies = [ "env_logger 0.8.4", "log", - "rand", + "rand 0.8.5", ] [[package]] @@ -4806,8 +4811,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", - "rand_chacha", - "rand_core", + "rand_chacha 0.3.1", + "rand_core 0.6.4", +] + +[[package]] +name = "rand" +version = "0.9.0-alpha.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d31e63ea85be51c423e52ba8f2e68a3efd53eed30203ee029dd09947333693e" +dependencies = [ + "rand_chacha 0.9.0-alpha.1", + "rand_core 0.9.0-alpha.1", + "zerocopy 0.8.0-alpha.6", ] [[package]] @@ -4817,7 +4833,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", - "rand_core", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_chacha" +version = "0.9.0-alpha.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78674ef918c19451dbd250f8201f8619b494f64c9aa6f3adb28fd8a0f1f6da46" +dependencies = [ + "ppv-lite86", + "rand_core 0.9.0-alpha.1", ] [[package]] @@ -4829,6 +4855,16 @@ dependencies = [ "getrandom", ] +[[package]] +name = "rand_core" +version = "0.9.0-alpha.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc89dffba8377c5ec847d12bb41492bda235dba31a25e8b695cd0fe6589eb8c9" +dependencies = [ + "getrandom", + "zerocopy 0.8.0-alpha.6", +] + [[package]] name = "randomx-rs" version = "1.3.0" @@ -5072,7 +5108,7 @@ dependencies = [ "num-traits", "pkcs1", "pkcs8", - "rand_core", + "rand_core 0.6.4", "signature", "spki", "subtle", @@ -5555,7 +5591,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e1788eed21689f9cf370582dfc467ef36ed9c707f073528ddafa8d83e3b8500" dependencies = [ "digest 0.10.7", - "rand_core", + "rand_core 0.6.4", ] [[package]] @@ -5628,7 +5664,7 @@ dependencies = [ "blake2", "chacha20poly1305", "curve25519-dalek", - "rand_core", + "rand_core 0.6.4", "rustc_version", "sha2 0.10.8", "subtle", @@ -5934,7 +5970,7 @@ dependencies = [ "itertools 0.12.1", "merlin", "once_cell", - "rand_core", + "rand_core 0.6.4", "serde", "sha3", "thiserror-no-std", @@ -5952,7 +5988,7 @@ dependencies = [ "lmdb-zero", "log", "minotari_app_utilities", - "rand", + "rand 0.8.5", "serde", "tari_common", "tari_common_sqlite", @@ -6022,7 +6058,7 @@ dependencies = [ "newtype-ops", "once_cell", "primitive-types", - "rand", + "rand 0.8.5", "serde", "strum", "strum_macros", @@ -6056,7 +6092,7 @@ dependencies = [ "once_cell", "pin-project 1.1.3", "prost", - "rand", + "rand 0.8.5", "serde", "serde_derive", "serde_json", @@ -6106,7 +6142,7 @@ dependencies = [ "petgraph 0.5.1", "pin-project 0.4.30", "prost", - "rand", + "rand 0.8.5", "serde", "tari_common", "tari_common_sqlite", @@ -6152,7 +6188,7 @@ dependencies = [ "num-derive", "num-traits", "prost", - "rand", + "rand 0.8.5", "serde", "serde_json", "tari_common", @@ -6209,7 +6245,7 @@ dependencies = [ "primitive-types", "prost", "quickcheck", - "rand", + "rand 0.8.5", "randomx-rs", "serde", "serde_json", @@ -6259,8 +6295,8 @@ dependencies = [ "log", "merlin", "once_cell", - "rand_chacha", - "rand_core", + "rand_chacha 0.3.1", + "rand_core 0.6.4", "serde", "sha3", "snafu", @@ -6309,7 +6345,7 @@ dependencies = [ "minotari_wallet", "minotari_wallet_ffi", "minotari_wallet_grpc_client", - "rand", + "rand 0.8.5", "reqwest", "serde_json", "tari_chat_client", @@ -6350,7 +6386,7 @@ dependencies = [ "futures 0.3.29", "js-sys", "log", - "rand", + "rand 0.8.5", "serde", "sha2 0.9.9", "strum", @@ -6375,7 +6411,7 @@ dependencies = [ "libtor", "log", "openssl", - "rand", + "rand 0.8.5", "tari_common", "tari_p2p", "tempfile", @@ -6407,7 +6443,7 @@ dependencies = [ "criterion 0.5.1", "digest 0.10.7", "log", - "rand", + "rand 0.8.5", "serde", "serde_json", "tari_common", @@ -6429,7 +6465,7 @@ dependencies = [ "log", "pgp", "prost", - "rand", + "rand 0.8.5", "reqwest", "rustls", "semver", @@ -6460,7 +6496,7 @@ dependencies = [ "borsh", "digest 0.10.7", "integer-encoding", - "rand", + "rand 0.8.5", "serde", "sha2 0.10.8", "sha3", @@ -6501,7 +6537,7 @@ dependencies = [ "bincode", "lmdb-zero", "log", - "rand", + "rand 0.8.5", "serde", "tari_utilities", "thiserror", @@ -6513,7 +6549,7 @@ version = "1.0.0-pre.16" dependencies = [ "futures 0.3.29", "futures-test", - "rand", + "rand 0.8.5", "tari_comms", "tari_shutdown", "tempfile", @@ -6992,7 +7028,7 @@ checksum = "8b83cd43a176c0c19d5db4401283e8f5c296b9c6c7fa29029de15cc445f26e12" dependencies = [ "hex", "hex-literal 0.3.4", - "rand", + "rand 0.8.5", "sha1 0.6.0", "thiserror", ] @@ -7009,7 +7045,7 @@ dependencies = [ "indexmap 1.9.3", "pin-project 1.1.3", "pin-project-lite", - "rand", + "rand 0.8.5", "slab", "tokio", "tokio-util 0.7.10", @@ -7101,7 +7137,7 @@ dependencies = [ "lazy_static", "log", "radix_trie", - "rand", + "rand 0.8.5", "ring 0.16.20", "rustls", "thiserror", @@ -7128,7 +7164,7 @@ dependencies = [ "ipnet", "lazy_static", "log", - "rand", + "rand 0.8.5", "ring 0.16.20", "rustls", "rustls-pemfile 0.3.0", @@ -7814,7 +7850,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fb66477291e7e8d2b0ff1bcb900bf29489a9692816d79874bea351e7a8b6de96" dependencies = [ "curve25519-dalek", - "rand_core", + "rand_core 0.6.4", "serde", "zeroize", ] @@ -7840,7 +7876,7 @@ dependencies = [ "nohash-hasher", "parking_lot 0.12.1", "pin-project 1.1.3", - "rand", + "rand 0.8.5", "static_assertions", ] @@ -7859,7 +7895,16 @@ version = "0.7.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be" dependencies = [ - "zerocopy-derive", + "zerocopy-derive 0.7.32", +] + +[[package]] +name = "zerocopy" +version = "0.8.0-alpha.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db678a6ee512bd06adf35c35be471cae2f9c82a5aed2b5d15e03628c98bddd57" +dependencies = [ + "zerocopy-derive 0.8.0-alpha.6", ] [[package]] @@ -7873,6 +7918,17 @@ dependencies = [ "syn 2.0.38", ] +[[package]] +name = "zerocopy-derive" +version = "0.8.0-alpha.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "201585ea96d37ee69f2ac769925ca57160cef31acb137c16f38b02b76f4c1e62" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.38", +] + [[package]] name = "zeroize" version = "1.6.0" diff --git a/applications/minotari_console_wallet/src/automation/commands.rs b/applications/minotari_console_wallet/src/automation/commands.rs index 83a6ceb329..b15ca1e63f 100644 --- a/applications/minotari_console_wallet/src/automation/commands.rs +++ b/applications/minotari_console_wallet/src/automation/commands.rs @@ -971,7 +971,7 @@ pub async fn command_runner( let mut script_signature = Signature::default(); match key_manager_service - .sign_with_nonce_and_message( + .sign_with_challenge_and_message( &party_info.wallet_spend_key_id, &party_info.script_nonce_key_id, &challenge, @@ -1007,7 +1007,7 @@ pub async fn command_runner( let mut metadata_signature = Signature::default(); match key_manager_service - .sign_with_nonce_and_message( + .sign_with_challenge_and_message( &party_info.sender_offset_key_id, &party_info.sender_offset_nonce_key_id, &challenge, diff --git a/applications/minotari_console_wallet/src/init/mod.rs b/applications/minotari_console_wallet/src/init/mod.rs index 09dcc86651..04ab9cd151 100644 --- a/applications/minotari_console_wallet/src/init/mod.rs +++ b/applications/minotari_console_wallet/src/init/mod.rs @@ -28,8 +28,7 @@ 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}; -#[cfg(feature = "ledger")] -use minotari_ledger_wallet_comms::ledger_wallet::LedgerCommands; +use minotari_ledger_wallet_comms::ledger_wallet::Command; #[cfg(feature = "ledger")] use minotari_ledger_wallet_comms::{ error::LedgerDeviceError, @@ -837,9 +836,7 @@ pub fn prompt_wallet_type( Ok(hid) => { println!("Device found."); let account = prompt_ledger_account(boot_mode).expect("An account value"); - let ledger = LedgerWallet::new(account, wallet_config.network, None, None); - match ledger - .build_command(Instruction::GetPublicAlpha, vec![]) + match Command::>::build_command(account, Instruction::GetPublicAlpha, vec![]) .execute_with_transport(&hid) { Ok(result) => { @@ -858,8 +855,7 @@ pub fn prompt_wallet_type( Err(e) => panic!("{}", e), }; - match ledger - .build_command(Instruction::GetViewKey, vec![]) + match Command::>::build_command(account, Instruction::GetViewKey, vec![]) .execute_with_transport(&hid) { Ok(result) => { diff --git a/applications/minotari_ledger_wallet/comms/Cargo.toml b/applications/minotari_ledger_wallet/comms/Cargo.toml index a22ea86e09..f2265103ae 100644 --- a/applications/minotari_ledger_wallet/comms/Cargo.toml +++ b/applications/minotari_ledger_wallet/comms/Cargo.toml @@ -7,10 +7,17 @@ edition = "2021" [dependencies] tari_crypto = { version = "0.20.2", default-features = false } -tari_common_types = { path = "../../../base_layer/common_types", version = "1.0.0-pre.16" } +tari_utilities = { version = "0.7" } +tari_common = { path = "../../../common" } +tari_common_types = { path = "../../../base_layer/common_types" } +tari_script = { path = "../../../infrastructure/tari_script" } + ledger-transport = { git = "https://github.com/Zondax/ledger-rs", rev = "20e2a20" } ledger-transport-hid = { git = "https://github.com/Zondax/ledger-rs", rev = "20e2a20" } num-derive = "0.4.2" num-traits = "0.2.15" serde = { version = "1.0.106", features = ["derive"] } -thiserror = "1.0.26" \ No newline at end of file +thiserror = "1.0.26" + +rand = "0.9.0-alpha.1" +once_cell = "1.19.0" diff --git a/applications/minotari_ledger_wallet/comms/examples/ledger_demo/main.rs b/applications/minotari_ledger_wallet/comms/examples/ledger_demo/main.rs new file mode 100644 index 0000000000..89d75c715b --- /dev/null +++ b/applications/minotari_ledger_wallet/comms/examples/ledger_demo/main.rs @@ -0,0 +1,256 @@ +// Copyright 2022 The Tari Project +// SPDX-License-Identifier: BSD-3-Clause + +//! # Multi-party Ledger - command line example + +use minotari_ledger_wallet_comms::{ + accessor_methods::{ + ledger_get_app_name, + ledger_get_dh_shared_secret, + ledger_get_public_alpha, + ledger_get_public_key, + ledger_get_raw_schnorr_signature, + ledger_get_script_offset, + ledger_get_script_schnorr_signature, + ledger_get_script_signature, + ledger_get_version, + ledger_get_view_key, + verify_ledger_application, + }, + ledger_wallet::get_transport, +}; +use rand::rngs::OsRng; +/// This example demonstrates how to use the Ledger Nano S/X for the Tari wallet. In order to run the example, you +/// need to have the `MinoTari Wallet` application installed on your Ledger device. For that, please follow the +/// instructions in the [README](../../wallet/README.md) file. +/// With this example, you can: +/// - Detect the hardware wallet +/// - Verify that the Ledger application is installed and the version is correct +/// - TBD +/// +/// ----------------------------------------------------------------------------------------------- +/// Example use: +/// `cargo run --release --example ledger_demo` +/// ----------------------------------------------------------------------------------------------- +use rand::RngCore; +use tari_common::configuration::Network; +use tari_common_types::{ + key_manager::TransactionKeyManagerBranch, + types::{Commitment, PrivateKey, PublicKey}, +}; +use tari_crypto::{ + keys::{PublicKey as PK, SecretKey}, + ristretto::RistrettoSecretKey, +}; +use tari_utilities::{hex::Hex, ByteArray}; + +#[allow(clippy::too_many_lines)] +fn main() { + println!(); + + // Repeated access to the transport is efficient + for _i in 0..10 { + let instant = std::time::Instant::now(); + match get_transport() { + Ok(_) => {}, + Err(e) => { + println!("\nError: {}\n", e); + return; + }, + }; + println!("Transport created in {:?}", instant.elapsed()); + } + + println!(); + + // Repeated ledger app verification is efficient + for _i in 0..10 { + let instant = std::time::Instant::now(); + match verify_ledger_application() { + Ok(_) => {}, + Err(e) => { + println!("\nError: {}\n", e); + return; + }, + } + println!("Application verified in {:?}", instant.elapsed()); + } + + println!(); + + // GetAppName + println!("\ntest: GetAppName"); + match ledger_get_app_name() { + Ok(name) => println!("app name: {}", name), + Err(e) => { + println!("\nError: {}\n", e); + return; + }, + } + + // GetVersion + println!("\ntest: GetVersion"); + match ledger_get_version() { + Ok(name) => println!("version: {}", name), + Err(e) => { + println!("\nError: {}\n", e); + return; + }, + } + + // GetPublicAlpha + println!("\ntest: GetPublicAlpha"); + let account = OsRng.next_u64(); + match ledger_get_public_alpha(account) { + Ok(public_alpha) => println!("public_alpha: {}", public_alpha.to_hex()), + Err(e) => { + println!("\nError: {}\n", e); + return; + }, + } + + // GetPublicKey + println!("\ntest: GetPublicKey"); + let index = OsRng.next_u64(); + let branch = TransactionKeyManagerBranch::RandomKey; + + match ledger_get_public_key(account, index, branch) { + Ok(public_key) => println!("public_key: {}", public_key.to_hex()), + Err(e) => { + println!("\nError: {}\n", e); + return; + }, + } + + // GetScriptSignature + println!("\ntest: GetScriptSignature"); + let network = Network::LocalNet; + let version = 0u8; + let branch_key = get_random_nonce(); + let value = PrivateKey::from(123456); + let spend_private_key = get_random_nonce(); + let commitment = Commitment::from_public_key(&PublicKey::from_secret_key(&get_random_nonce())); + let mut script_message = [0u8; 32]; + script_message.copy_from_slice(&get_random_nonce().to_vec()); + + match ledger_get_script_signature( + account, + network, + version, + &branch_key, + &value, + &spend_private_key, + &commitment, + script_message, + ) { + Ok(signature) => println!( + "script_sig: ({},{},{},{},{})", + signature.ephemeral_commitment().to_hex(), + signature.ephemeral_pubkey().to_hex(), + signature.u_x().to_hex(), + signature.u_a().to_hex(), + signature.u_y().to_hex() + ), + Err(e) => { + println!("\nError: {}\n", e); + return; + }, + } + + // GetScriptOffset + println!("\ntest: GetScriptOffset"); + let mut derived_key_commitments = Vec::new(); + let mut sender_offset_indexes = Vec::new(); + for _i in 0..5 { + derived_key_commitments.push(get_random_nonce()); + sender_offset_indexes.push(OsRng.next_u64()); + } + + match ledger_get_script_offset(account, &derived_key_commitments, &sender_offset_indexes) { + Ok(script_offset) => println!("script_offset: {}", script_offset.to_hex()), + Err(e) => { + println!("\nError: {}\n", e); + return; + }, + } + + // GetViewKey + println!("\ntest: GetViewKey"); + + match ledger_get_view_key(account) { + Ok(view_key) => println!("view_key: {}", view_key.to_hex()), + Err(e) => { + println!("\nError: {}\n", e); + return; + }, + } + + // GetDHSharedSecret + println!("\ntest: GetDHSharedSecret"); + let index = OsRng.next_u64(); + let branch = TransactionKeyManagerBranch::SenderOffsetLedger; + let public_key = PublicKey::from_secret_key(&get_random_nonce()); + + match ledger_get_dh_shared_secret(account, index, branch, &public_key) { + Ok(shared_secret) => println!("shared_secret: {}", shared_secret.as_bytes().to_vec().to_hex()), + Err(e) => { + println!("\nError: {}\n", e); + return; + }, + } + + // GetRawSchnorrSignature + println!("\ntest: GetRawSchnorrSignature"); + let private_key_index = OsRng.next_u64(); + let private_key_branch = TransactionKeyManagerBranch::Spend; + let nonce_index = OsRng.next_u64(); + let nonce_branch = TransactionKeyManagerBranch::RandomKey; + let mut challenge = [0u8; 64]; + OsRng.fill_bytes(&mut challenge); + + match ledger_get_raw_schnorr_signature( + account, + private_key_index, + private_key_branch, + nonce_index, + nonce_branch, + &challenge, + ) { + Ok(signature) => println!( + "signature: ({},{})", + signature.get_signature().to_hex(), + signature.get_public_nonce().to_hex() + ), + Err(e) => { + println!("\nError: {}\n", e); + return; + }, + } + + // GetScriptSchnorrSignature + println!("\ntest: GetScriptSchnorrSignature"); + let private_key_index = OsRng.next_u64(); + let private_key_branch = TransactionKeyManagerBranch::Spend; + let mut nonce = [0u8; 32]; + OsRng.fill_bytes(&mut nonce); + + match ledger_get_script_schnorr_signature(account, private_key_index, private_key_branch, &nonce) { + Ok(signature) => println!( + "signature: ({},{})", + signature.get_signature().to_hex(), + signature.get_public_nonce().to_hex() + ), + Err(e) => { + println!("\nError: {}\n", e); + return; + }, + } + + println!("\nTest completed successfully\n"); +} + +pub fn get_random_nonce() -> PrivateKey { + let mut raw_bytes = [0u8; 64]; + OsRng.fill_bytes(&mut raw_bytes); + RistrettoSecretKey::from_uniform_bytes(&raw_bytes).expect("will not fail") +} diff --git a/applications/minotari_ledger_wallet/comms/src/accessor_methods.rs b/applications/minotari_ledger_wallet/comms/src/accessor_methods.rs new file mode 100644 index 0000000000..ce7f1ecee5 --- /dev/null +++ b/applications/minotari_ledger_wallet/comms/src/accessor_methods.rs @@ -0,0 +1,445 @@ +// 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::sync::Mutex; + +use once_cell::sync::Lazy; +use rand::{rngs::OsRng, RngCore}; +use tari_common::configuration::Network; +use tari_common_types::{ + key_manager::TransactionKeyManagerBranch, + types::{ComAndPubSignature, Commitment, PrivateKey, PublicKey, Signature}, +}; +use tari_crypto::dhke::DiffieHellmanSharedSecret; +use tari_script::CheckSigSchnorrSignature; +use tari_utilities::ByteArray; + +use crate::{ + error::LedgerDeviceError, + ledger_wallet::{AppSW, Command, Instruction, EXPECTED_NAME, EXPECTED_VERSION}, +}; + +// hash_domain!(CheckSigHashDomain, "com.tari.script.check_sig", 1); +// type CheckSigSchnorrSignature = SchnorrSignature; + +/// Verify that the ledger application is working properly. +pub fn verify_ledger_application() -> Result<(), LedgerDeviceError> { + static VERIFIED: Lazy>>> = Lazy::new(|| Mutex::new(None)); + if let Ok(mut verified) = VERIFIED.try_lock() { + if verified.is_none() { + match verify() { + Ok(_) => *verified = Some(Ok(())), + Err(e) => return Err(e), + } + } + } + Ok(()) +} + +fn verify() -> Result<(), LedgerDeviceError> { + match ledger_get_app_name() { + Ok(app_name) => { + if app_name != EXPECTED_NAME { + return Err(LedgerDeviceError::Processing(format!( + "Ledger application is not the 'Minotari Wallet' application: expected '{}', running '{}'.", + EXPECTED_NAME, app_name + ))); + } + }, + Err(e) => { + return Err(LedgerDeviceError::Processing(format!( + "Ledger application is not the 'Minotari Wallet' application ({})", + e + ))) + }, + } + + match ledger_get_version() { + Ok(version) => { + if version != EXPECTED_VERSION { + return Err(LedgerDeviceError::Processing(format!( + "'Minotari Wallet' application version mismatch: expected '{}', running '{}'.", + EXPECTED_VERSION, version + ))); + } + }, + Err(e) => { + return Err(LedgerDeviceError::Processing(format!( + "'Minotari Wallet' application version mismatch ({})", + e + ))) + }, + } + + let account = OsRng.next_u64(); + let private_key_index = OsRng.next_u64(); + let private_key_branch = TransactionKeyManagerBranch::SenderOffsetLedger; + let mut nonce = [0u8; 32]; + OsRng.fill_bytes(&mut nonce); + match ledger_get_script_schnorr_signature(account, private_key_index, private_key_branch, &nonce) { + Ok(signature) => match ledger_get_public_key(account, private_key_index, private_key_branch) { + Ok(public_key) => { + if !signature.verify(&public_key, nonce) { + return Err(LedgerDeviceError::Processing( + "'Minotari Wallet' application could not create a valid signature".to_string(), + )); + } + }, + Err(e) => { + return Err(LedgerDeviceError::Processing(format!( + "'Minotari Wallet' application could not retrieve a public key ({:?})", + e + ))) + }, + }, + Err(e) => { + return Err(LedgerDeviceError::Processing(format!( + "'Minotari Wallet' application could not create a signature ({:?})", + e + ))) + }, + } + + Ok(()) +} + +/// Get the app name from the ledger device +pub fn ledger_get_app_name() -> Result { + verify_ledger_application()?; + + match Command::>::build_command(OsRng.next_u64(), Instruction::GetAppName, vec![0]).execute() { + Ok(response) => { + let name = match std::str::from_utf8(response.data()) { + Ok(val) => { + if val.is_empty() { + return Err(LedgerDeviceError::ApplicationNotStarted); + } + val + }, + Err(e) => return Err(LedgerDeviceError::Processing(format!("1 GetAppName: {}", e))), + }; + Ok(name.to_string()) + }, + Err(e) => Err(LedgerDeviceError::Processing(format!("2 GetAppName: {}", e))), + } +} + +/// Get the version from the ledger device +pub fn ledger_get_version() -> Result { + verify_ledger_application()?; + + match Command::>::build_command(OsRng.next_u64(), Instruction::GetVersion, vec![0]).execute() { + Ok(response) => { + let name = match std::str::from_utf8(response.data()) { + Ok(val) => { + if val.is_empty() { + return Err(LedgerDeviceError::ApplicationNotStarted); + } + val + }, + Err(e) => return Err(LedgerDeviceError::Processing(format!("1 GetVersion: {}", e))), + }; + Ok(name.to_string()) + }, + Err(e) => Err(LedgerDeviceError::Processing(format!("2 GetVersion: {}", e))), + } +} + +/// Get the public alpha key from the ledger device +pub fn ledger_get_public_alpha(account: u64) -> Result { + verify_ledger_application()?; + + match Command::>::build_command(account, Instruction::GetPublicAlpha, vec![]).execute() { + Ok(result) => { + if result.data().len() < 33 { + return Err(LedgerDeviceError::Processing(format!( + "GetPublicAlpha: expected 33 bytes, got {} ({:?})", + result.data().len(), + AppSW::from(result.retcode()) + ))); + } + let public_alpha = PublicKey::from_canonical_bytes(&result.data()[1..33])?; + Ok(public_alpha) + }, + Err(e) => Err(LedgerDeviceError::Processing(format!("GetPublicAlpha: {}", e))), + } +} + +/// Get a public key from the ledger device +pub fn ledger_get_public_key( + account: u64, + index: u64, + branch: TransactionKeyManagerBranch, +) -> Result { + verify_ledger_application()?; + + let mut data = Vec::new(); + data.extend_from_slice(&index.to_le_bytes()); + let branch_u64 = u64::from(branch.as_byte()).to_le_bytes(); + data.extend_from_slice(&branch_u64); + + match Command::>::build_command(account, Instruction::GetPublicKey, data).execute() { + Ok(result) => { + if result.data().len() < 33 { + return Err(LedgerDeviceError::Processing(format!( + "GetPublicAlpha: expected 33 bytes, got {} ({:?})", + result.data().len(), + AppSW::from(result.retcode()) + ))); + } + let public_key = PublicKey::from_canonical_bytes(&result.data()[1..33])?; + Ok(public_key) + }, + Err(e) => Err(LedgerDeviceError::Processing(format!("GetPublicKey: {}", e))), + } +} + +/// Get the script signature from the ledger device +pub fn ledger_get_script_signature( + account: u64, + network: Network, + version: u8, + branch_key: &PrivateKey, + value: &PrivateKey, + commitment_private_key: &PrivateKey, + commitment: &Commitment, + script_message: [u8; 32], +) -> Result { + verify_ledger_application()?; + + let mut data = Vec::new(); + let network = u64::from(network.as_byte()).to_le_bytes(); + data.extend_from_slice(&network); + let version = u64::from(version).to_le_bytes(); + data.extend_from_slice(&version); + let branch_key = branch_key.to_vec(); + data.extend_from_slice(&branch_key); + let value = value.to_vec(); + data.extend_from_slice(&value); + let commitment_private_key = commitment_private_key.to_vec(); + data.extend_from_slice(&commitment_private_key); + let commitment = commitment.to_vec(); + data.extend_from_slice(&commitment); + data.extend_from_slice(&script_message); + + match Command::>::build_command(account, Instruction::GetScriptSignature, data).execute() { + Ok(result) => { + if result.data().len() < 161 { + return Err(LedgerDeviceError::Processing(format!( + "GetScriptSignature: expected 161 bytes, got {} ({:?})", + result.data().len(), + AppSW::from(result.retcode()) + ))); + } + let data = result.data(); + let signature = ComAndPubSignature::new( + Commitment::from_canonical_bytes(&data[1..33])?, + PublicKey::from_canonical_bytes(&data[33..65])?, + PrivateKey::from_canonical_bytes(&data[65..97])?, + PrivateKey::from_canonical_bytes(&data[97..129])?, + PrivateKey::from_canonical_bytes(&data[129..161])?, + ); + Ok(signature) + }, + Err(e) => Err(LedgerDeviceError::Processing(format!("GetScriptSignature: {}", e))), + } +} + +/// Get the script offset from the ledger device +pub fn ledger_get_script_offset( + account: u64, + derived_key_commitments: &[PrivateKey], + sender_offset_indexes: &[u64], +) -> Result { + verify_ledger_application()?; + + 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 data: Vec> = vec![instructions.to_vec()]; + let total_script_private_key = PrivateKey::default(); + 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 in derived_key_commitments { + data.push(derived_key_commitment.to_vec()); + } + + let commands = Command::>::chunk_command(account, Instruction::GetScriptOffset, data); + + let mut result = None; + for command in commands { + match command.execute() { + Ok(r) => result = Some(r), + Err(e) => return Err(LedgerDeviceError::Processing(format!("GetScriptOffset: {}", e))), + } + } + + match result { + Some(result) => { + if result.data().len() < 33 { + return Err(LedgerDeviceError::Processing(format!( + "GetScriptOffset: expected 33 bytes, got {} ({:?})", + result.data().len(), + AppSW::from(result.retcode()) + ))); + } + let script_offset = PrivateKey::from_canonical_bytes(&result.data()[1..33])?; + Ok(script_offset) + }, + None => Err(LedgerDeviceError::Processing("GetScriptOffset: No result".to_string())), + } +} + +/// Get the view key from the ledger device +pub fn ledger_get_view_key(account: u64) -> Result { + verify_ledger_application()?; + + match Command::>::build_command(account, Instruction::GetViewKey, vec![]).execute() { + Ok(result) => { + if result.data().len() < 33 { + return Err(LedgerDeviceError::Processing(format!( + "GetViewKey: expected 33 bytes, got {} ({:?})", + result.data().len(), + AppSW::from(result.retcode()) + ))); + } + let view_key = PrivateKey::from_canonical_bytes(&result.data()[1..33])?; + Ok(view_key) + }, + Err(e) => Err(LedgerDeviceError::Processing(format!("GetViewKey: {}", e))), + } +} + +/// Get the Diffie-Hellman shared secret from the ledger device +pub fn ledger_get_dh_shared_secret( + account: u64, + index: u64, + branch: TransactionKeyManagerBranch, + public_key: &PublicKey, +) -> Result, LedgerDeviceError> { + verify_ledger_application()?; + + let mut data = Vec::new(); + data.extend_from_slice(&index.to_le_bytes()); + data.extend_from_slice(&u64::from(branch.as_byte()).to_le_bytes()); + data.extend_from_slice(&public_key.to_vec()); + + match Command::>::build_command(account, Instruction::GetDHSharedSecret, data).execute() { + Ok(result) => { + if result.data().len() < 33 { + return Err(LedgerDeviceError::Processing(format!( + "GetDHSharedSecret: expected 33 bytes, got {} ({:?})", + result.data().len(), + AppSW::from(result.retcode()) + ))); + } + let shared_secret = DiffieHellmanSharedSecret::::from_canonical_bytes(&result.data()[1..33])?; + Ok(shared_secret) + }, + Err(e) => Err(LedgerDeviceError::Processing(format!("GetDHSharedSecret: {}", e))), + } +} + +/// Get the raw schnorr signature from the ledger device +pub fn ledger_get_raw_schnorr_signature( + account: u64, + private_key_index: u64, + private_key_branch: TransactionKeyManagerBranch, + nonce_index: u64, + nonce_branch: TransactionKeyManagerBranch, + challenge: &[u8; 64], +) -> Result { + verify_ledger_application()?; + + let mut data = Vec::new(); + data.extend_from_slice(&private_key_index.to_le_bytes()); + data.extend_from_slice(&u64::from(private_key_branch.as_byte()).to_le_bytes()); + data.extend_from_slice(&nonce_index.to_le_bytes()); + data.extend_from_slice(&u64::from(nonce_branch.as_byte()).to_le_bytes()); + data.extend_from_slice(challenge); + + match Command::>::build_command(account, Instruction::GetRawSchnorrSignature, data).execute() { + Ok(result) => { + if result.data().len() < 65 { + return Err(LedgerDeviceError::Processing(format!( + "GetRawSchnorrSignature: expected 65 bytes, got {} ({:?})", + result.data().len(), + AppSW::from(result.retcode()) + ))); + } + + let signature = Signature::new( + PublicKey::from_canonical_bytes(&result.data()[1..33])?, + PrivateKey::from_canonical_bytes(&result.data()[33..65])?, + ); + Ok(signature) + }, + Err(e) => Err(LedgerDeviceError::Processing(format!("GetRawSchnorrSignature: {}", e))), + } +} + +/// Get the script schnorr signature from the ledger device +pub fn ledger_get_script_schnorr_signature( + account: u64, + private_key_index: u64, + private_key_branch: TransactionKeyManagerBranch, + nonce: &[u8], +) -> Result { + verify_ledger_application()?; + + let mut data = Vec::new(); + data.extend_from_slice(&private_key_index.to_le_bytes()); + data.extend_from_slice(&u64::from(private_key_branch.as_byte()).to_le_bytes()); + if nonce.len() != 32 { + return Err(LedgerDeviceError::Processing("Nonce must be 32 bytes".to_string())); + } + data.extend_from_slice(nonce); + + match Command::>::build_command(account, Instruction::GetScriptSchnorrSignature, data).execute() { + Ok(result) => { + if result.data().len() < 65 { + return Err(LedgerDeviceError::Processing(format!( + "GetScriptSchnorrSignature: expected 65 bytes, got {} ({:?})", + result.data().len(), + AppSW::from(result.retcode()) + ))); + } + + let signature = CheckSigSchnorrSignature::new( + PublicKey::from_canonical_bytes(&result.data()[1..33])?, + PrivateKey::from_canonical_bytes(&result.data()[33..65])?, + ); + Ok(signature) + }, + Err(e) => Err(LedgerDeviceError::Processing(format!( + "GetScriptSchnorrSignature: {}", + e + ))), + } +} diff --git a/applications/minotari_ledger_wallet/comms/src/ledger_wallet.rs b/applications/minotari_ledger_wallet/comms/src/ledger_wallet.rs index f85dfc4fb5..0e455c999c 100644 --- a/applications/minotari_ledger_wallet/comms/src/ledger_wallet.rs +++ b/applications/minotari_ledger_wallet/comms/src/ledger_wallet.rs @@ -26,7 +26,8 @@ use ledger_transport::{APDUAnswer, APDUCommand}; use ledger_transport_hid::{hidapi::HidApi, TransportNativeHID}; use num_derive::FromPrimitive; use num_traits::FromPrimitive; -use tari_common_types::wallet_types::LedgerWallet; +use once_cell::sync::Lazy; +use tari_utilities::ByteArray; use crate::error::LedgerDeviceError; @@ -39,12 +40,65 @@ pub enum Instruction { GetPublicKey = 0x04, GetScriptSignature = 0x05, GetScriptOffset = 0x06, - GetMetadataSignature = 0x07, - GetScriptSignatureFromChallenge = 0x08, - GetViewKey = 0x09, - GetDHSharedSecret = 0x10, + GetViewKey = 0x07, + GetDHSharedSecret = 0x08, + GetRawSchnorrSignature = 0x09, + GetScriptSchnorrSignature = 0x10, } +#[repr(u16)] +#[derive(FromPrimitive, Debug, Copy, Clone, PartialEq)] +pub enum AppSW { + Deny = 0xB001, + WrongP1P2 = 0xB002, + InsNotSupported = 0xB003, + ClaNotSupported = 0xB004, + ScriptSignatureFail = 0xB005, + MetadataSignatureFail = 0xB006, + RawSchnorrSignatureFail = 0xB007, + SchnorrSignatureFail = 0xB008, + ScriptOffsetNotUnique = 0xB009, + KeyDeriveFail = 0xB00A, + KeyDeriveFromCanonical = 0xB00B, + KeyDeriveFromUniform = 0xB00C, + VersionParsingFail = 0xB00D, + TooManyPayloads = 0xB00E, + RandomNonceFail = 0xB00F, + BadBranchKey = 0xB010, + WrongApduLength = 0x6e03, // See ledger-device-rust-sdk/ledger_device_sdk/src/io.rs:16 + UserCancelled = 0x6e04, // See ledger-device-rust-sdk/ledger_device_sdk/src/io.rs:16 +} + +impl From for AppSW { + fn from(value: u16) -> Self { + match value { + 0xB001 => AppSW::Deny, + 0xB002 => AppSW::WrongP1P2, + 0xB003 => AppSW::InsNotSupported, + 0xB004 => AppSW::ClaNotSupported, + 0xB005 => AppSW::ScriptSignatureFail, + 0xB006 => AppSW::MetadataSignatureFail, + 0xB007 => AppSW::RawSchnorrSignatureFail, + 0xB008 => AppSW::SchnorrSignatureFail, + 0xB009 => AppSW::ScriptOffsetNotUnique, + 0xB00A => AppSW::KeyDeriveFail, + 0xB00B => AppSW::KeyDeriveFromCanonical, + 0xB00C => AppSW::KeyDeriveFromUniform, + 0xB00D => AppSW::VersionParsingFail, + 0xB00E => AppSW::TooManyPayloads, + 0xB00F => AppSW::RandomNonceFail, + 0xB010 => AppSW::BadBranchKey, + 0x6e03 => AppSW::WrongApduLength, + 0x6e04 => AppSW::UserCancelled, + _ => AppSW::Deny, + } + } +} + +pub const EXPECTED_NAME: &str = "minotari_ledger_wallet"; +pub const EXPECTED_VERSION: &str = "1.0.0-pre.16"; +const WALLET_CLA: u8 = 0x80; + impl Instruction { pub fn as_byte(self) -> u8 { self as u8 @@ -56,8 +110,16 @@ impl Instruction { } 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())) + let hid = hidapi()?; + let transport = TransportNativeHID::new(hid).map_err(|e| LedgerDeviceError::NativeTransport(e.to_string()))?; + Ok(transport) +} + +fn hidapi() -> Result<&'static HidApi, LedgerDeviceError> { + static HIDAPI: Lazy> = + Lazy::new(|| HidApi::new().map_err(|e| format!("Unable to get HIDAPI: {}", e))); + + HIDAPI.as_ref().map_err(|e| LedgerDeviceError::HidApi(e.to_string())) } #[derive(Debug, Clone)] @@ -84,18 +146,9 @@ impl> Command { .exchange(&self.inner) .map_err(|e| LedgerDeviceError::NativeTransport(e.to_string())) } -} - -pub trait LedgerCommands { - fn build_command(&self, instruction: Instruction, data: Vec) -> Command>; - fn chunk_command(&self, instruction: Instruction, data: Vec>) -> Vec>>; -} - -const WALLET_CLA: u8 = 0x80; -impl LedgerCommands for LedgerWallet { - fn build_command(&self, instruction: Instruction, data: Vec) -> Command> { - let mut base_data = self.account_bytes(); + pub fn build_command(account: u64, instruction: Instruction, data: Vec) -> Command> { + let mut base_data = account.to_le_bytes().to_vec(); base_data.extend_from_slice(&data); Command::new(APDUCommand { @@ -107,7 +160,7 @@ impl LedgerCommands for LedgerWallet { }) } - fn chunk_command(&self, instruction: Instruction, data: Vec>) -> Vec>> { + pub fn chunk_command(account: u64, instruction: Instruction, data: Vec>) -> Vec>> { let num_chunks = data.len(); let mut more; let mut commands = vec![]; @@ -122,7 +175,7 @@ impl LedgerCommands for LedgerWallet { // 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(&account.to_le_bytes().to_vec()); } base_data.extend_from_slice(chunk); diff --git a/applications/minotari_ledger_wallet/comms/src/lib.rs b/applications/minotari_ledger_wallet/comms/src/lib.rs index a14b091c78..d9c242ccc9 100644 --- a/applications/minotari_ledger_wallet/comms/src/lib.rs +++ b/applications/minotari_ledger_wallet/comms/src/lib.rs @@ -20,5 +20,6 @@ // 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 accessor_methods; pub mod error; pub mod ledger_wallet; diff --git a/applications/minotari_ledger_wallet/wallet/Cargo.toml b/applications/minotari_ledger_wallet/wallet/Cargo.toml index 1c4839ab69..bccf45cfa4 100644 --- a/applications/minotari_ledger_wallet/wallet/Cargo.toml +++ b/applications/minotari_ledger_wallet/wallet/Cargo.toml @@ -15,7 +15,8 @@ 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" +ledger_device_sdk = "1.7" +rand_core = { version = "0.6", 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 @@ -32,7 +33,7 @@ lto = "fat" # same as `true` panic = "abort" [features] -default = ["pending_review_screen"] +default = [] pending_review_screen = [] [package.metadata.ledger] @@ -40,7 +41,6 @@ curve = ["ed25519"] flags = "0" path = ["44'/535348'"] name = "MinoTari Wallet" -api_level = "1" [package.metadata.ledger.nanos] icon = "key.gif" diff --git a/applications/minotari_ledger_wallet/wallet/src/handlers/get_dh_shared_secret.rs b/applications/minotari_ledger_wallet/wallet/src/handlers/get_dh_shared_secret.rs index 2abdea2e58..1518931d7e 100644 --- a/applications/minotari_ledger_wallet/wallet/src/handlers/get_dh_shared_secret.rs +++ b/applications/minotari_ledger_wallet/wallet/src/handlers/get_dh_shared_secret.rs @@ -3,7 +3,7 @@ use core::ops::Deref; -use ledger_device_sdk::io::Comm; +use ledger_device_sdk::{io::Comm, ui::gadgets::SingleMessage}; use tari_crypto::{ristretto::RistrettoPublicKey, tari_utilities::ByteArray}; use crate::{ @@ -15,6 +15,10 @@ use crate::{ pub fn handler_get_dh_shared_secret(comm: &mut Comm) -> Result<(), AppSW> { let data = comm.get_data().map_err(|_| AppSW::WrongApduLength)?; + if data.len() != 56 { + SingleMessage::new("Invalid data length").show_and_wait(); + return Err(AppSW::WrongApduLength); + } let mut account_bytes = [0u8; 8]; account_bytes.clone_from_slice(&data[0..8]); 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 2537538341..de470dfcdc 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,13 +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::SingleMessage}; use tari_crypto::{keys::PublicKey, ristretto::RistrettoPublicKey, tari_utilities::ByteArray}; 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)?; + if data.len() != 24 { + SingleMessage::new("Invalid data length").show_and_wait(); + return Err(AppSW::WrongApduLength); + } let mut account_bytes = [0u8; 8]; account_bytes.clone_from_slice(&data[0..8]); diff --git a/applications/minotari_ledger_wallet/wallet/src/handlers/get_public_spend_key.rs b/applications/minotari_ledger_wallet/wallet/src/handlers/get_public_spend_key.rs index f621e6dff2..19e36618a4 100644 --- a/applications/minotari_ledger_wallet/wallet/src/handlers/get_public_spend_key.rs +++ b/applications/minotari_ledger_wallet/wallet/src/handlers/get_public_spend_key.rs @@ -1,13 +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::SingleMessage}; use tari_crypto::{keys::PublicKey, ristretto::RistrettoPublicKey, tari_utilities::ByteArray}; use crate::{utils::derive_from_bip32_key, AppSW, KeyType, RESPONSE_VERSION, STATIC_SPEND_INDEX}; pub fn handler_get_public_spend_key(comm: &mut Comm) -> Result<(), AppSW> { let data = comm.get_data().map_err(|_| AppSW::WrongApduLength)?; + if data.len() != 8 { + SingleMessage::new("Invalid data length").show_and_wait(); + return Err(AppSW::WrongApduLength); + } let mut account_bytes = [0u8; 8]; account_bytes.clone_from_slice(&data[0..8]); diff --git a/applications/minotari_ledger_wallet/wallet/src/handlers/get_schnorr_signature.rs b/applications/minotari_ledger_wallet/wallet/src/handlers/get_schnorr_signature.rs new file mode 100644 index 0000000000..0ff27f7f76 --- /dev/null +++ b/applications/minotari_ledger_wallet/wallet/src/handlers/get_schnorr_signature.rs @@ -0,0 +1,126 @@ +// Copyright 2024 The Tari Project +// SPDX-License-Identifier: BSD-3-Clause + +use alloc::format; +use core::ops::Deref; + +use ledger_device_sdk::{io::Comm, ui::gadgets::SingleMessage}; +use tari_crypto::{ + hash_domain, + ristretto::{RistrettoPublicKey, RistrettoSchnorr, RistrettoSecretKey}, + signatures::SchnorrSignature, + tari_utilities::ByteArray, +}; + +use crate::{ + alloc::string::ToString, + utils::{derive_from_bip32_key, get_random_nonce}, + AppSW, + KeyType, + RESPONSE_VERSION, +}; + +hash_domain!(CheckSigHashDomain, "com.tari.script.check_sig", 1); + +/// The type used for `CheckSig`, `CheckMultiSig`, and related opcodes' signatures +pub type CheckSigSchnorrSignature = SchnorrSignature; + +pub fn handler_get_raw_schnorr_signature(comm: &mut Comm) -> Result<(), AppSW> { + let data = comm.get_data().map_err(|_| AppSW::WrongApduLength)?; + if data.len() != 104 { + SingleMessage::new("Invalid data length").show_and_wait(); + return 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 mut private_key_index_bytes = [0u8; 8]; + private_key_index_bytes.clone_from_slice(&data[8..16]); + let private_key_index = u64::from_le_bytes(private_key_index_bytes); + + let mut private_key_type_bytes = [0u8; 8]; + private_key_type_bytes.clone_from_slice(&data[16..24]); + let private_key_type = KeyType::from_branch_key(u64::from_le_bytes(private_key_type_bytes))?; + + let private_key = derive_from_bip32_key(account, private_key_index, private_key_type)?; + + let mut private_nonce_index_bytes = [0u8; 8]; + private_nonce_index_bytes.clone_from_slice(&data[24..32]); + let private_nonce_index = u64::from_le_bytes(private_nonce_index_bytes); + + let mut nonce_key_type_bytes = [0u8; 8]; + nonce_key_type_bytes.clone_from_slice(&data[32..40]); + let nonce_key_type = KeyType::from_branch_key(u64::from_le_bytes(nonce_key_type_bytes))?; + + let private_nonce = derive_from_bip32_key(account, private_nonce_index, nonce_key_type)?; + + let mut challenge_bytes = [0u8; 64]; + challenge_bytes.clone_from_slice(&data[40..104]); + + let signature = + match RistrettoSchnorr::sign_raw_uniform(&private_key, private_nonce.deref().clone(), &challenge_bytes) { + Ok(sig) => sig, + Err(e) => { + SingleMessage::new(&format!("Signing error: {:?}", e.to_string())).show_and_wait(); + return Err(AppSW::RawSchnorrSignatureFail); + }, + }; + + comm.append(&[RESPONSE_VERSION]); // version + comm.append(&signature.get_public_nonce().to_vec()); + comm.append(&signature.get_signature().to_vec()); + comm.reply_ok(); + + Ok(()) +} + +pub fn handler_get_script_schnorr_signature(comm: &mut Comm) -> Result<(), AppSW> { + let data = comm.get_data().map_err(|_| AppSW::WrongApduLength)?; + if data.len() != 56 { + SingleMessage::new("Invalid data length").show_and_wait(); + return 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 mut private_key_index_bytes = [0u8; 8]; + private_key_index_bytes.clone_from_slice(&data[8..16]); + let private_key_index = u64::from_le_bytes(private_key_index_bytes); + + let mut private_key_type_bytes = [0u8; 8]; + private_key_type_bytes.clone_from_slice(&data[16..24]); + let key_type = u64::from_le_bytes(private_key_type_bytes); + let private_key_type = KeyType::from_branch_key(key_type)?; + + let private_key = derive_from_bip32_key(account, private_key_index, private_key_type)?; + + let mut nonce_bytes = [0u8; 32]; + nonce_bytes.clone_from_slice(&data[24..56]); + + let random_nonce_a = get_random_nonce()?.deref().clone(); + let random_nonce_b = get_random_nonce()?.deref().clone(); + if random_nonce_a == random_nonce_b { + SingleMessage::new("Nonces not unique!").show_and_wait(); + return Err(AppSW::SchnorrSignatureFail); + } + let signature = + match CheckSigSchnorrSignature::sign_with_nonce_and_message(&private_key, random_nonce_a, &nonce_bytes) { + Ok(sig) => sig, + Err(e) => { + SingleMessage::new(&format!("Signing error:",)).show_and_wait(); + SingleMessage::new(&format!("{}", e.to_string())).show_and_wait(); + return Err(AppSW::SchnorrSignatureFail); + }, + }; + + comm.append(&[RESPONSE_VERSION]); // version + comm.append(&signature.get_public_nonce().to_vec()); + comm.append(&signature.get_signature().to_vec()); + 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 fc8d1f34fd..a243767a04 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 @@ -5,7 +5,7 @@ use alloc::format; use blake2::Blake2b; use digest::consts::U64; -use ledger_device_sdk::{io::Comm, random::Random, ui::gadgets::SingleMessage}; +use ledger_device_sdk::{io::Comm, ui::gadgets::SingleMessage}; use tari_crypto::{ commitment::HomomorphicCommitmentFactory, keys::PublicKey, @@ -22,7 +22,7 @@ use zeroize::Zeroizing; use crate::{ alloc::string::ToString, hashing::DomainSeparatedConsensusHasher, - utils::{alpha_hasher, derive_from_bip32_key, get_key_from_canonical_bytes}, + utils::{alpha_hasher, derive_from_bip32_key, get_key_from_canonical_bytes, get_random_nonce}, AppSW, KeyType, RESPONSE_VERSION, @@ -31,6 +31,10 @@ use crate::{ pub fn handler_get_script_signature(comm: &mut Comm) -> Result<(), AppSW> { let data = comm.get_data().map_err(|_| AppSW::WrongApduLength)?; + if data.len() != 184 { + SingleMessage::new("Invalid data length").show_and_wait(); + return Err(AppSW::WrongApduLength); + } let mut account_bytes = [0u8; 8]; account_bytes.clone_from_slice(&data[0..8]); @@ -52,7 +56,7 @@ pub fn handler_get_script_signature(comm: &mut Comm) -> Result<(), AppSW> { let value: Zeroizing = get_key_from_canonical_bytes::(&data[56..88])?.into(); - let spend_private_key: Zeroizing = + let commitment_private_key: Zeroizing = get_key_from_canonical_bytes::(&data[88..120])?.into(); let commitment: PedersenCommitment = get_key_from_canonical_bytes(&data[120..152])?; @@ -60,9 +64,13 @@ pub fn handler_get_script_signature(comm: &mut Comm) -> Result<(), AppSW> { let mut script_message = [0u8; 32]; script_message.clone_from_slice(&data[152..184]); - let r_a = derive_from_bip32_key(account, u32::random().into(), KeyType::Nonce)?; - let r_x = derive_from_bip32_key(account, u32::random().into(), KeyType::Nonce)?; - let r_y = derive_from_bip32_key(account, u32::random().into(), KeyType::Nonce)?; + let r_a = get_random_nonce()?; + let r_x = get_random_nonce()?; + let r_y = get_random_nonce()?; + if r_a == r_x || r_a == r_y || r_x == r_y { + SingleMessage::new("Nonces not unique!").show_and_wait(); + return Err(AppSW::ScriptSignatureFail); + } let factory = ExtendedPedersenCommitmentFactory::default(); @@ -81,7 +89,7 @@ pub fn handler_get_script_signature(comm: &mut Comm) -> Result<(), AppSW> { let script_signature = match RistrettoComAndPubSig::sign( &value, - &spend_private_key, + &commitment_private_key, &script_private_key, &r_a, &r_x, diff --git a/applications/minotari_ledger_wallet/wallet/src/handlers/get_view_key.rs b/applications/minotari_ledger_wallet/wallet/src/handlers/get_view_key.rs index 7fc11b9f27..e22397e3d3 100644 --- a/applications/minotari_ledger_wallet/wallet/src/handlers/get_view_key.rs +++ b/applications/minotari_ledger_wallet/wallet/src/handlers/get_view_key.rs @@ -1,13 +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::SingleMessage}; use tari_crypto::tari_utilities::ByteArray; use crate::{utils::derive_from_bip32_key, AppSW, KeyType, RESPONSE_VERSION, STATIC_VIEW_INDEX}; pub fn handler_get_view_key(comm: &mut Comm) -> Result<(), AppSW> { let data = comm.get_data().map_err(|_| AppSW::WrongApduLength)?; + if data.len() != 8 { + SingleMessage::new("Invalid data length").show_and_wait(); + return Err(AppSW::WrongApduLength); + } let mut account_bytes = [0u8; 8]; account_bytes.clone_from_slice(&data[0..8]); diff --git a/applications/minotari_ledger_wallet/wallet/src/main.rs b/applications/minotari_ledger_wallet/wallet/src/main.rs index 8974df03ca..039b8bd8c9 100644 --- a/applications/minotari_ledger_wallet/wallet/src/main.rs +++ b/applications/minotari_ledger_wallet/wallet/src/main.rs @@ -8,7 +8,7 @@ extern crate alloc; mod hashing; -mod utils; +pub mod utils; mod app_ui { pub mod menu; @@ -17,6 +17,7 @@ mod handlers { pub mod get_dh_shared_secret; pub mod get_public_key; pub mod get_public_spend_key; + pub mod get_schnorr_signature; pub mod get_script_offset; pub mod get_script_signature; pub mod get_version; @@ -31,6 +32,7 @@ use handlers::{ get_dh_shared_secret::handler_get_dh_shared_secret, get_public_key::handler_get_public_key, get_public_spend_key::handler_get_public_spend_key, + get_schnorr_signature::{handler_get_raw_schnorr_signature, handler_get_script_schnorr_signature}, get_script_offset::{handler_get_script_offset, ScriptOffsetCtx}, get_script_signature::handler_get_script_signature, get_version::handler_get_version, @@ -87,21 +89,24 @@ unsafe impl critical_section::Impl for MyCriticalSection { // Application status words. #[repr(u16)] pub enum AppSW { - Deny = 0x6985, - WrongP1P2 = 0x6A86, - InsNotSupported = 0x6D00, - ClaNotSupported = 0x6E00, - ScriptSignatureFail = 0xB001, - MetadataSignatureFail = 0xB002, - ScriptOffsetNotUnique = 0xB004, - BadBranchKey = 0xB005, - KeyDeriveFail = 0xB009, - KeyDeriveFromCanonical = 0xB010, - KeyDeriveFromUniform = 0xB011, - VersionParsingFail = 0xB00A, - TooManyPayloads = 0xB003, - WrongApduLength = StatusWords::BadLen as u16, - UserCancelled = StatusWords::UserCancelled as u16, + Deny = 0xB001, + WrongP1P2 = 0xB002, + InsNotSupported = 0xB003, + ClaNotSupported = 0xB004, + ScriptSignatureFail = 0xB005, + MetadataSignatureFail = 0xB006, + RawSchnorrSignatureFail = 0xB007, + SchnorrSignatureFail = 0xB008, + ScriptOffsetNotUnique = 0xB009, + KeyDeriveFail = 0xB00A, + KeyDeriveFromCanonical = 0xB00B, + KeyDeriveFromUniform = 0xB00C, + VersionParsingFail = 0xB00D, + TooManyPayloads = 0xB00E, + RandomNonceFail = 0xB00F, + BadBranchKey = 0xB010, + WrongApduLength = StatusWords::BadLen as u16, // See ledger-device-rust-sdk/ledger_device_sdk/src/io.rs:16 + UserCancelled = StatusWords::UserCancelled as u16, // See ledger-device-rust-sdk/ledger_device_sdk/src/io.rs:16 } impl From for Reply { @@ -118,9 +123,10 @@ pub enum Instruction { GetPublicSpendKey, GetScriptSignature, GetScriptOffset { chunk: u8, more: bool }, - GetScriptSignatureFromChallenge, GetViewKey, GetDHSharedSecret, + GetRawSchnorrSignature, + GetScriptSchnorrSignature, } const P2_MORE: u8 = 0x01; @@ -129,11 +135,13 @@ const STATIC_VIEW_INDEX: u64 = 57311; // No significance, just a random number b const MAX_PAYLOADS: u8 = 250; #[repr(u8)] +#[derive(Debug)] pub enum KeyType { Spend = 0x01, Nonce = 0x02, ViewKey = 0x03, OneSidedSenderOffset = 0x04, + Random = 0x06, } impl KeyType { @@ -144,9 +152,13 @@ impl KeyType { fn from_branch_key(n: u64) -> Result { // These numbers need to match the TransactionKeyManagerBranches in: // base_layer/core/src/transactions/key_manager/interface.rs + // See `pub enum TransactionKeyManagerBranch` in + // `tari_wallet/src/transaction_service/transaction_key_manager.rs` for the mapping of the branch key to + // the key type. match n { - 7 => Ok(Self::Spend), 6 => Ok(Self::OneSidedSenderOffset), + 7 => Ok(Self::Spend), + 8 => Ok(Self::Random), _ => Err(AppSW::BadBranchKey), } } @@ -177,9 +189,10 @@ impl TryFrom for Instruction { chunk: value.p1, more: value.p2 == P2_MORE, }), - (0x08, 0, 0) => Ok(Instruction::GetScriptSignatureFromChallenge), - (0x09, 0, 0) => Ok(Instruction::GetViewKey), - (0x10, 0, 0) => Ok(Instruction::GetDHSharedSecret), + (0x07, 0, 0) => Ok(Instruction::GetViewKey), + (0x08, 0, 0) => Ok(Instruction::GetDHSharedSecret), + (0x09, 0, 0) => Ok(Instruction::GetRawSchnorrSignature), + (0x10, 0, 0) => Ok(Instruction::GetScriptSchnorrSignature), (0x06, _, _) => Err(AppSW::WrongP1P2), (_, _, _) => Err(AppSW::InsNotSupported), } @@ -225,8 +238,9 @@ fn handle_apdu(comm: &mut Comm, ins: Instruction, offset_ctx: &mut ScriptOffsetC Instruction::GetPublicSpendKey => handler_get_public_spend_key(comm), Instruction::GetScriptSignature => handler_get_script_signature(comm), Instruction::GetScriptOffset { chunk, more } => handler_get_script_offset(comm, chunk, more, offset_ctx), - Instruction::GetScriptSignatureFromChallenge => handler_get_script_signature_from_challenge(comm), Instruction::GetViewKey => handler_get_view_key(comm), Instruction::GetDHSharedSecret => handler_get_dh_shared_secret(comm), + Instruction::GetRawSchnorrSignature => handler_get_raw_schnorr_signature(comm), + Instruction::GetScriptSchnorrSignature => handler_get_script_schnorr_signature(comm), } } diff --git a/applications/minotari_ledger_wallet/wallet/src/utils.rs b/applications/minotari_ledger_wallet/wallet/src/utils.rs index 9441768268..e5b5161801 100644 --- a/applications/minotari_ledger_wallet/wallet/src/utils.rs +++ b/applications/minotari_ledger_wallet/wallet/src/utils.rs @@ -9,8 +9,10 @@ use digest::{consts::U64, Digest}; use ledger_device_sdk::{ ecc::{bip32_derive, make_bip32_path, CurvesId, CxError}, io::SyscallError, + random::LedgerRng, ui::gadgets::SingleMessage, }; +use rand_core::RngCore; use tari_crypto::{ hashing::DomainSeparatedHasher, keys::SecretKey, @@ -158,6 +160,9 @@ fn get_raw_key_hash(path: &[u32]) -> Result, String> { let raw_key_64 = match bip32_derive(CurvesId::Ed25519, path, key_buffer.as_mut(), Some(&mut [])) { Ok(_) => { let binding = &key_buffer.as_ref()[..BIP32_KEY_LENGTH]; + if binding == &[0u8; BIP32_KEY_LENGTH] { + return Err(cx_error_to_string(CxError::InternalError)); + } 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); @@ -258,3 +263,14 @@ pub fn derive_from_bip32_key( }, } } + +pub fn get_random_nonce() -> Result, AppSW> { + let mut raw_bytes = [0u8; 64]; + LedgerRng.fill_bytes(&mut raw_bytes); + if raw_bytes == [0u8; 64] { + return Err(AppSW::RandomNonceFail); + } + Ok(Zeroizing::new( + RistrettoSecretKey::from_uniform_bytes(&raw_bytes).expect("will not fail"), + )) +} diff --git a/applications/minotari_node/src/grpc/base_node_grpc_server.rs b/applications/minotari_node/src/grpc/base_node_grpc_server.rs index 50872a8bb7..92bb6fa222 100644 --- a/applications/minotari_node/src/grpc/base_node_grpc_server.rs +++ b/applications/minotari_node/src/grpc/base_node_grpc_server.rs @@ -35,6 +35,7 @@ use minotari_app_grpc::{ }; use minotari_app_utilities::consts; use tari_common_types::{ + key_manager::TransactionKeyManagerBranch, tari_address::TariAddress, types::{Commitment, FixedHash, PublicKey, Signature}, }; @@ -54,13 +55,7 @@ use tari_core::{ proof_of_work::PowAlgorithm, transactions::{ generate_coinbase_with_wallet_output, - key_manager::{ - create_memory_db_key_manager, - TariKeyId, - TransactionKeyManagerBranch, - TransactionKeyManagerInterface, - TxoStage, - }, + key_manager::{create_memory_db_key_manager, TariKeyId, TransactionKeyManagerInterface, TxoStage}, transaction_components::{ encrypted_data::PaymentId, KernelBuilder, diff --git a/base_layer/common_types/src/key_manager.rs b/base_layer/common_types/src/key_manager.rs new file mode 100644 index 0000000000..7181366748 --- /dev/null +++ b/base_layer/common_types/src/key_manager.rs @@ -0,0 +1,65 @@ +use strum_macros::EnumIter; + +use crate::WALLET_COMMS_AND_SPEND_KEY_BRANCH; + +#[repr(u8)] +#[derive(Clone, Copy, EnumIter)] +// These byte reps must stay in sync with the ledger representations at: +// applications/minotari_ledger_wallet/wallet/src/main.rs +pub enum TransactionKeyManagerBranch { + DataEncryption = 0x00, + MetadataEphemeralNonce = 0x01, + CommitmentMask = 0x02, + Nonce = 0x03, + KernelNonce = 0x04, + SenderOffset = 0x05, + SenderOffsetLedger = 0x06, + Spend = 0x07, + RandomKey = 0x08, +} + +const DATA_ENCRYPTION: &str = "data encryption"; +const METADATA_EPHEMERAL_NONCE: &str = "metadata ephemeral nonce"; +const COMMITMENT_MASK: &str = "commitment mask"; +const NONCE: &str = "nonce"; +const KERNEL_NONCE: &str = "kernel nonce"; +const SENDER_OFFSET: &str = "sender offset"; +const SENDER_OFFSET_LEDGER: &str = "sender offset ledger"; +const RANDOM_KEY: &str = "random key"; + +impl TransactionKeyManagerBranch { + /// 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 { + TransactionKeyManagerBranch::DataEncryption => DATA_ENCRYPTION.to_string(), + TransactionKeyManagerBranch::MetadataEphemeralNonce => METADATA_EPHEMERAL_NONCE.to_string(), + TransactionKeyManagerBranch::CommitmentMask => COMMITMENT_MASK.to_string(), + TransactionKeyManagerBranch::Nonce => NONCE.to_string(), + TransactionKeyManagerBranch::KernelNonce => KERNEL_NONCE.to_string(), + TransactionKeyManagerBranch::SenderOffset => SENDER_OFFSET.to_string(), + TransactionKeyManagerBranch::SenderOffsetLedger => SENDER_OFFSET_LEDGER.to_string(), + TransactionKeyManagerBranch::RandomKey => RANDOM_KEY.to_string(), + TransactionKeyManagerBranch::Spend => WALLET_COMMS_AND_SPEND_KEY_BRANCH.to_string(), + } + } + + pub fn from_key(key: &str) -> Self { + match key { + DATA_ENCRYPTION => TransactionKeyManagerBranch::DataEncryption, + METADATA_EPHEMERAL_NONCE => TransactionKeyManagerBranch::MetadataEphemeralNonce, + COMMITMENT_MASK => TransactionKeyManagerBranch::CommitmentMask, + NONCE => TransactionKeyManagerBranch::Nonce, + KERNEL_NONCE => TransactionKeyManagerBranch::KernelNonce, + SENDER_OFFSET => TransactionKeyManagerBranch::SenderOffset, + SENDER_OFFSET_LEDGER => TransactionKeyManagerBranch::SenderOffsetLedger, + RANDOM_KEY => TransactionKeyManagerBranch::RandomKey, + WALLET_COMMS_AND_SPEND_KEY_BRANCH => TransactionKeyManagerBranch::Spend, + _ => TransactionKeyManagerBranch::Nonce, + } + } + + pub fn as_byte(self) -> u8 { + self as u8 + } +} diff --git a/base_layer/common_types/src/lib.rs b/base_layer/common_types/src/lib.rs index d77413e2af..018b2d902e 100644 --- a/base_layer/common_types/src/lib.rs +++ b/base_layer/common_types/src/lib.rs @@ -30,6 +30,7 @@ pub mod emoji; pub mod encryption; pub mod epoch; pub mod grpc_authentication; +pub mod key_manager; pub mod serializers; pub mod tari_address; pub mod transaction; diff --git a/base_layer/common_types/src/wallet_types.rs b/base_layer/common_types/src/wallet_types.rs index 8eac9c5a05..3da235a4e9 100644 --- a/base_layer/common_types/src/wallet_types.rs +++ b/base_layer/common_types/src/wallet_types.rs @@ -66,7 +66,7 @@ impl Display for ProvidedKeysWallet { #[derive(Debug, Clone, Serialize, Deserialize)] pub struct LedgerWallet { - account: u64, + pub account: u64, pub public_alpha: Option, pub network: Network, pub view_key: Option, @@ -89,8 +89,4 @@ impl LedgerWallet { view_key, } } - - pub fn account_bytes(&self) -> Vec { - self.account.to_le_bytes().to_vec() - } } diff --git a/base_layer/core/src/blocks/faucets/mod.rs b/base_layer/core/src/blocks/faucets/mod.rs index 103a56e52d..2ad43e2bee 100644 --- a/base_layer/core/src/blocks/faucets/mod.rs +++ b/base_layer/core/src/blocks/faucets/mod.rs @@ -26,6 +26,7 @@ mod test { use rand::rngs::OsRng; use tari_common_types::{ + key_manager::TransactionKeyManagerBranch, tari_address::TariAddress, types::{Commitment, PrivateKey, PublicKey, Signature}, }; @@ -40,7 +41,6 @@ mod test { key_manager::{ create_memory_db_key_manager, SecretTransactionKeyManagerInterface, - TransactionKeyManagerBranch, TransactionKeyManagerInterface, }, tari_amount::MicroMinotari, diff --git a/base_layer/core/src/transactions/coinbase_builder.rs b/base_layer/core/src/transactions/coinbase_builder.rs index d9ad3d5cbd..ab65d4f190 100644 --- a/base_layer/core/src/transactions/coinbase_builder.rs +++ b/base_layer/core/src/transactions/coinbase_builder.rs @@ -23,6 +23,7 @@ use log::*; use tari_common_types::{ + key_manager::TransactionKeyManagerBranch, tari_address::TariAddress, types::{Commitment, PrivateKey}, }; @@ -43,14 +44,7 @@ use crate::{ stealth_address_script_spending_key, }, transactions::{ - key_manager::{ - CoreKeyManagerError, - MemoryDbKeyManager, - TariKeyId, - TransactionKeyManagerBranch, - TransactionKeyManagerInterface, - TxoStage, - }, + key_manager::{CoreKeyManagerError, MemoryDbKeyManager, TariKeyId, TransactionKeyManagerInterface, TxoStage}, tari_amount::{uT, MicroMinotari}, transaction_components::{ encrypted_data::PaymentId, @@ -508,7 +502,7 @@ pub async fn generate_coinbase_with_wallet_output( #[cfg(test)] mod test { use tari_common::configuration::Network; - use tari_common_types::{tari_address::TariAddress, types::Commitment}; + use tari_common_types::{key_manager::TransactionKeyManagerBranch, tari_address::TariAddress, types::Commitment}; use crate::{ consensus::{emission::Emission, ConsensusManager, ConsensusManagerBuilder}, @@ -779,7 +773,6 @@ mod test { create_memory_db_key_manager, MemoryDbKeyManager, TariKeyId, - TransactionKeyManagerBranch, TransactionKeyManagerInterface, TxoStage, }, diff --git a/base_layer/core/src/transactions/key_manager/inner.rs b/base_layer/core/src/transactions/key_manager/inner.rs index d0a41d34ac..f77760be79 100644 --- a/base_layer/core/src/transactions/key_manager/inner.rs +++ b/base_layer/core/src/transactions/key_manager/inner.rs @@ -25,14 +25,18 @@ use blake2::Blake2b; use digest::consts::U64; use log::*; #[cfg(feature = "ledger")] -use minotari_ledger_wallet_comms::{ - error::LedgerDeviceError, - ledger_wallet::{get_transport, Instruction, LedgerCommands}, +use minotari_ledger_wallet_comms::accessor_methods::{ + ledger_get_dh_shared_secret, + ledger_get_public_key, + ledger_get_raw_schnorr_signature, + ledger_get_script_offset, + ledger_get_script_schnorr_signature, + ledger_get_script_signature, }; -use rand::rngs::OsRng; +use rand::{rngs::OsRng, RngCore}; use strum::IntoEnumIterator; +use tari_common_types::key_manager::TransactionKeyManagerBranch; #[cfg(feature = "ledger")] -use tari_common_types::wallet_types::LedgerWallet; use tari_common_types::{ types::{ComAndPubSignature, Commitment, PrivateKey, PublicKey, RangeProof, Signature}, wallet_types::WalletType, @@ -74,7 +78,7 @@ use crate::{ one_sided::diffie_hellman_stealth_domain_hasher, transactions::{ key_manager::{ - interface::{TransactionKeyManagerBranch, TransactionKeyManagerLabel, TxoStage}, + interface::{TransactionKeyManagerLabel, TxoStage}, TariKeyId, }, tari_amount::MicroMinotari, @@ -167,7 +171,10 @@ where TBackend: KeyManagerBackend + 'static let mut km = self .key_managers .get(branch) - .ok_or(KeyManagerServiceError::UnknownKeyBranch)? + .ok_or(KeyManagerServiceError::UnknownKeyBranch(format!( + "{}, {}", + branch, self.wallet_type + )))? .write() .await; self.db.increment_key_index(branch)?; @@ -182,18 +189,48 @@ where TBackend: KeyManagerBackend + 'static } pub async fn get_random_key(&self) -> Result, KeyManagerServiceError> { - let random_private_key = PrivateKey::random(&mut OsRng); - let key_id = self.import_key(random_private_key).await?; - let public_key = self.get_public_key_at_key_id(&key_id).await?; - Ok(KeyAndId { - key_id, - pub_key: public_key, - }) + match &self.wallet_type { + WalletType::Ledger(ledger) => { + #[cfg(not(feature = "ledger"))] + { + return Err(KeyManagerServiceError::LedgerError( + "Ledger is not supported".to_string(), + )); + } + #[cfg(feature = "ledger")] + { + let random_index = OsRng.next_u64(); + + let public_key = + ledger_get_public_key(ledger.account, random_index, TransactionKeyManagerBranch::RandomKey) + .map_err(|e| KeyManagerServiceError::LedgerError(e.to_string()))?; + Ok(KeyAndId { + key_id: KeyId::Managed { + branch: TransactionKeyManagerBranch::RandomKey.get_branch_key(), + index: random_index, + }, + pub_key: public_key, + }) + } + }, + _ => { + let random_private_key = PrivateKey::random(&mut OsRng); + let key_id = self.import_key(random_private_key).await?; + let public_key = self.get_public_key_at_key_id(&key_id).await?; + Ok(KeyAndId { + key_id, + pub_key: public_key, + }) + }, + } } pub async fn get_static_key(&self, branch: &str) -> Result { match self.key_managers.get(branch) { - None => Err(KeyManagerServiceError::UnknownKeyBranch), + None => Err(KeyManagerServiceError::UnknownKeyBranch(format!( + "{}, {}", + branch, self.wallet_type + ))), Some(_) => Ok(KeyId::Managed { branch: branch.to_string(), index: 0, @@ -201,6 +238,7 @@ where TBackend: KeyManagerBackend + 'static } } + #[allow(clippy::too_many_lines)] pub async fn get_public_key_at_key_id(&self, key_id: &TariKeyId) -> Result { match key_id { KeyId::Managed { branch, index } => { @@ -208,7 +246,9 @@ where TBackend: KeyManagerBackend + 'static // 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::SenderOffsetLedger.get_branch_key() { + if branch == &TransactionKeyManagerBranch::SenderOffsetLedger.get_branch_key() || + branch == &TransactionKeyManagerBranch::RandomKey.get_branch_key() + { #[cfg(not(feature = "ledger"))] { return Err(KeyManagerServiceError::LedgerError( @@ -218,25 +258,13 @@ where TBackend: KeyManagerBackend + 'static #[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 public_key = ledger_get_public_key( + ledger.account, + *index, + TransactionKeyManagerBranch::from_key(branch), + ) + .map_err(|e| KeyManagerServiceError::LedgerError(e.to_string()))?; + return Ok(public_key); } } @@ -247,12 +275,20 @@ where TBackend: KeyManagerBackend + 'static .ok_or(KeyManagerServiceError::LedgerViewKeyInaccessible)?; return Ok(PublicKey::from_secret_key(&view_key)); } + + return Err(KeyManagerServiceError::BranchNotSupported(format!( + "{}, {}", + branch, self.wallet_type + ))); } let km = self .key_managers .get(branch) - .ok_or(KeyManagerServiceError::UnknownKeyBranch)? + .ok_or(KeyManagerServiceError::UnknownKeyBranch(format!( + "{}, {}", + branch, self.wallet_type + )))? .read() .await; Ok(km.derive_public_key(*index)?.key) @@ -262,7 +298,10 @@ where TBackend: KeyManagerBackend + 'static let km = self .key_managers .get(branch) - .ok_or(KeyManagerServiceError::UnknownKeyBranch)? + .ok_or(KeyManagerServiceError::UnknownKeyBranch(format!( + "{}, {}", + branch, self.wallet_type + )))? .read() .await; let branch_key = km.get_private_key(*index)?; @@ -282,6 +321,7 @@ where TBackend: KeyManagerBackend + 'static } } + #[allow(clippy::too_many_lines)] pub(crate) async fn get_private_key(&self, key_id: &TariKeyId) -> Result { match key_id { KeyId::Managed { branch, index } => { @@ -320,7 +360,10 @@ where TBackend: KeyManagerBackend + 'static let km = self .key_managers .get(branch) - .ok_or(KeyManagerServiceError::UnknownKeyBranch)? + .ok_or(KeyManagerServiceError::UnknownKeyBranch(format!( + "{}, {}", + branch, self.wallet_type + )))? .read() .await; let key = km.get_private_key(*index)?; @@ -332,14 +375,20 @@ where TBackend: KeyManagerBackend + 'static let km = self .key_managers .get(&TransactionKeyManagerBranch::Spend.get_branch_key()) - .ok_or(KeyManagerServiceError::UnknownKeyBranch)? + .ok_or(KeyManagerServiceError::UnknownKeyBranch(format!( + "{}, {}", + branch, self.wallet_type + )))? .read() .await; let private_alpha = km.get_private_key(0)?; let km = self .key_managers .get(branch) - .ok_or(KeyManagerServiceError::UnknownKeyBranch)? + .ok_or(KeyManagerServiceError::UnknownKeyBranch(format!( + "{}, {}", + branch, self.wallet_type + )))? .read() .await; let branch_key = km.get_private_key(*index)?; @@ -360,7 +409,10 @@ where TBackend: KeyManagerBackend + 'static let km = self .key_managers .get(branch) - .ok_or(KeyManagerServiceError::UnknownKeyBranch)? + .ok_or(KeyManagerServiceError::UnknownKeyBranch(format!( + "{}, {}", + branch, self.wallet_type + )))? .read() .await; let branch_key = km.get_private_key(*index)?; @@ -481,7 +533,10 @@ where TBackend: KeyManagerBackend + 'static let km = self .key_managers .get(&branch) - .ok_or(KeyManagerServiceError::UnknownKeyBranch)? + .ok_or(KeyManagerServiceError::UnknownKeyBranch(format!( + "{}, {}", + branch, self.wallet_type + )))? .read() .await; let key = km.get_private_key(index)?; @@ -538,7 +593,10 @@ where TBackend: KeyManagerBackend + 'static let km = self .key_managers .get(branch) - .ok_or(KeyManagerServiceError::UnknownKeyBranch)? + .ok_or(KeyManagerServiceError::UnknownKeyBranch(format!( + "{}, {}", + branch, self.wallet_type + )))? .read() .await; @@ -569,7 +627,10 @@ where TBackend: KeyManagerBackend + 'static let km = self .key_managers .get(branch) - .ok_or(KeyManagerServiceError::UnknownKeyBranch)? + .ok_or(KeyManagerServiceError::UnknownKeyBranch(format!( + "{}, {}", + branch, self.wallet_type + )))? .read() .await; @@ -605,7 +666,10 @@ where TBackend: KeyManagerBackend + 'static let mut km = self .key_managers .get(branch) - .ok_or(KeyManagerServiceError::UnknownKeyBranch)? + .ok_or(KeyManagerServiceError::UnknownKeyBranch(format!( + "{}, {}", + branch, self.wallet_type + )))? .write() .await; let current_index = km.key_index(); @@ -660,9 +724,24 @@ where TBackend: KeyManagerBackend + 'static #[cfg(feature = "ledger")] { - return self.device_diffie_hellman(ledger, branch, index, public_key).await; + return ledger_get_dh_shared_secret( + ledger.account, + *index, + TransactionKeyManagerBranch::from_key(branch), + public_key, + ) + .map_err(TransactionError::LedgerDeviceError); } + } else { + return Err(TransactionError::from(KeyManagerServiceError::BranchNotSupported( + format!("{}, {}", branch, self.wallet_type), + ))); } + } else { + return Err(TransactionError::UnsupportedTariKeyId(format!( + "Expected 'KeyId::Managed', got {}", + secret_key_id + ))); } } @@ -687,12 +766,25 @@ where TBackend: KeyManagerBackend + 'static #[cfg(feature = "ledger")] { - return self - .device_diffie_hellman(ledger, branch, index, public_key) - .await - .map(diffie_hellman_stealth_domain_hasher); + return ledger_get_dh_shared_secret( + ledger.account, + *index, + TransactionKeyManagerBranch::from_key(branch), + public_key, + ) + .map_err(TransactionError::LedgerDeviceError) + .map(diffie_hellman_stealth_domain_hasher); } + } else { + return Err(TransactionError::from(KeyManagerServiceError::BranchNotSupported( + format!("{}, {}", branch, self.wallet_type), + ))); } + } else { + return Err(TransactionError::UnsupportedTariKeyId(format!( + "Expected 'KeyId::Managed', got {}", + secret_key_id + ))); } } @@ -701,36 +793,6 @@ where TBackend: KeyManagerBackend + 'static Ok(diffie_hellman_stealth_domain_hasher(dh)) } - #[allow(unused_variables)] // conditionally compiled paths - #[cfg(feature = "ledger")] - async fn device_diffie_hellman( - &self, - ledger: &LedgerWallet, - branch: &str, - index: &u64, - public_key: &PublicKey, - ) -> Result { - 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()); - data.extend_from_slice(public_key.as_bytes()); - let command = ledger.build_command(Instruction::GetDHSharedSecret, data); - - return 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 CommsDHKE::from_canonical_bytes(&result.data()[1..33]) - .map_err(|e| LedgerDeviceError::ByteArrayError(e.to_string()).into()); - }, - Err(e) => Err(KeyManagerServiceError::LedgerError(e.to_string()).into()), - }; - } - pub async fn import_add_offset_to_private_key( &self, secret_key_id: &TariKeyId, @@ -806,52 +868,28 @@ where TBackend: KeyManagerBackend + 'static let km = self .key_managers .get(branch) - .ok_or(KeyManagerServiceError::UnknownKeyBranch)? + .ok_or(KeyManagerServiceError::UnknownKeyBranch(format!( + "{}, {}", + branch, self.wallet_type + )))? .read() .await; let branch_key = km .get_private_key(*index) .map_err(|e| TransactionError::KeyManagerError(e.to_string()))?; - let mut data = u64::from(ledger.network.as_byte()).to_le_bytes().to_vec(); - data.extend_from_slice(&u64::from(txi_version.as_u8()).to_le_bytes()); - data.extend_from_slice(branch_key.as_bytes()); - data.extend_from_slice(value.as_bytes()); - data.extend_from_slice(commitment_private_key.as_bytes()); - data.extend_from_slice(commitment.as_bytes()); - data.extend_from_slice(script_message); - - let command = ledger.build_command(Instruction::GetScriptSignature, 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_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()); - 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!("GetScriptSignature: {}", e)).into()), - } + let signature = ledger_get_script_signature( + ledger.account, + ledger.network, + txi_version.as_u8(), + &branch_key, + value, + &commitment_private_key, + &commitment, + *script_message, + ) + .map_err(|e| TransactionError::InvalidSignatureError(e.to_string()))?; + Ok(signature) } }, (_, _) => { @@ -1008,7 +1046,10 @@ where TBackend: KeyManagerBackend + 'static let km = self .key_managers .get(branch) - .ok_or(KeyManagerServiceError::UnknownKeyBranch)? + .ok_or(KeyManagerServiceError::UnknownKeyBranch(format!( + "{}, {}", + branch, self.wallet_type + )))? .read() .await; let branch_key = km @@ -1048,62 +1089,16 @@ where TBackend: KeyManagerBackend + 'static label: _, index, } => { - sender_offset_indexes.push(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_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 data: Vec> = vec![instructions.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 in derived_key_commitments { - data.push(derived_key_commitment.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!("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()); - } - 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(), - ) + let script_offset = + ledger_get_script_offset(ledger.account, &derived_key_commitments, &sender_offset_indexes) + .map_err(|e| TransactionError::InvalidSignatureError(e.to_string()))?; + Ok(script_offset) } }, } @@ -1154,25 +1149,98 @@ where TBackend: KeyManagerBackend + 'static pub async fn sign_script_message( &self, private_key_id: &TariKeyId, - challenge: &[u8], + nonce: &[u8], ) -> Result { - let private_key = self.get_private_key(private_key_id).await?; - let signature = CheckSigSchnorrSignature::sign(&private_key, challenge, &mut OsRng)?; + match &self.wallet_type { + WalletType::Ledger(ledger) => { + #[cfg(not(feature = "ledger"))] + { + return Err(TransactionError::LedgerNotSupported); + } - Ok(signature) + #[cfg(feature = "ledger")] + { + match private_key_id { + KeyId::Managed { branch, index } => { + let signature = ledger_get_script_schnorr_signature( + ledger.account, + *index, + TransactionKeyManagerBranch::from_key(branch), + nonce, + )?; + Ok(signature) + }, + _ => Err(TransactionError::UnsupportedTariKeyId(format!( + "Expected 'KeyId::Managed', got {}", + private_key_id + ))), + } + } + }, + _ => { + let private_key = self.get_private_key(private_key_id).await?; + let signature = CheckSigSchnorrSignature::sign(&private_key, nonce, &mut OsRng)?; + + Ok(signature) + }, + } } - pub async fn sign_with_nonce_and_message( + pub async fn sign_with_challenge_and_message( &self, private_key_id: &TariKeyId, - nonce: &TariKeyId, + nonce_key_id: &TariKeyId, challenge: &[u8; 64], ) -> Result { - let private_key = self.get_private_key(private_key_id).await?; - let private_nonce = self.get_private_key(nonce).await?; - let signature = Signature::sign_raw_uniform(&private_key, private_nonce, challenge)?; + match &self.wallet_type { + WalletType::Ledger(ledger) => { + #[cfg(not(feature = "ledger"))] + { + return Err(TransactionError::LedgerNotSupported); + } - Ok(signature) + #[cfg(feature = "ledger")] + { + match private_key_id { + KeyId::Managed { + branch: private_key_branch, + index: private_key_index, + } => match nonce_key_id { + KeyId::Managed { + branch: nonce_branch, + index: nonce_index, + } => { + let signature = ledger_get_raw_schnorr_signature( + ledger.account, + *private_key_index, + TransactionKeyManagerBranch::from_key(private_key_branch), + *nonce_index, + TransactionKeyManagerBranch::from_key(nonce_branch), + challenge, + ) + .map_err(|e| KeyManagerServiceError::LedgerError(e.to_string()))?; + Ok(signature) + }, + _ => Err(TransactionError::UnsupportedTariKeyId(format!( + "Expected 'KeyId::Managed', got {}", + nonce_key_id + ))), + }, + _ => Err(TransactionError::UnsupportedTariKeyId(format!( + "Expected 'KeyId::Managed', got {}", + private_key_id + ))), + } + } + }, + _ => { + let private_key = self.get_private_key(private_key_id).await?; + let private_nonce = self.get_private_key(nonce_key_id).await?; + let signature = Signature::sign_raw_uniform(&private_key, private_nonce, challenge)?; + + Ok(signature) + }, + } } pub async fn get_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 6373fa4f95..d5d7e4edee 100644 --- a/base_layer/core/src/transactions/key_manager/interface.rs +++ b/base_layer/core/src/transactions/key_manager/interface.rs @@ -25,10 +25,7 @@ use std::str::FromStr; use blake2::Blake2b; use digest::consts::U64; use strum_macros::EnumIter; -use tari_common_types::{ - types::{ComAndPubSignature, Commitment, PrivateKey, PublicKey, RangeProof, Signature}, - WALLET_COMMS_AND_SPEND_KEY_BRANCH, -}; +use tari_common_types::types::{ComAndPubSignature, Commitment, PrivateKey, PublicKey, RangeProof, Signature}; use tari_comms::types::CommsDHKE; use tari_crypto::{hashing::DomainSeparatedHash, ristretto::RistrettoComSig}; use tari_key_manager::key_manager_service::{KeyAndId, KeyId, KeyManagerInterface, KeyManagerServiceError}; @@ -57,56 +54,6 @@ pub enum TxoStage { Output, } -#[repr(u8)] -#[derive(Clone, Copy, EnumIter)] -// These byte reps must stay in sync with the ledger representations at: -// applications/minotari_ledger_wallet/wallet/src/main.rs -pub enum TransactionKeyManagerBranch { - DataEncryption = 0x00, - MetadataEphemeralNonce = 0x01, - CommitmentMask = 0x02, - Nonce = 0x03, - KernelNonce = 0x04, - SenderOffset = 0x05, - SenderOffsetLedger = 0x06, - Spend = 0x07, -} - -impl TransactionKeyManagerBranch { - /// 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 { - TransactionKeyManagerBranch::DataEncryption => "data encryption".to_string(), - TransactionKeyManagerBranch::CommitmentMask => "commitment mask".to_string(), - TransactionKeyManagerBranch::Nonce => "nonce".to_string(), - TransactionKeyManagerBranch::MetadataEphemeralNonce => "metadata ephemeral nonce".to_string(), - TransactionKeyManagerBranch::KernelNonce => "kernel nonce".to_string(), - TransactionKeyManagerBranch::SenderOffset => "sender offset".to_string(), - TransactionKeyManagerBranch::SenderOffsetLedger => "sender offset ledger".to_string(), - TransactionKeyManagerBranch::Spend => WALLET_COMMS_AND_SPEND_KEY_BRANCH.to_string(), - } - } - - pub fn from_key(key: &str) -> Self { - match key { - "data encryption" => TransactionKeyManagerBranch::DataEncryption, - "commitment mask" => TransactionKeyManagerBranch::CommitmentMask, - "metadata ephemeral nonce" => TransactionKeyManagerBranch::MetadataEphemeralNonce, - "kernel nonce" => TransactionKeyManagerBranch::KernelNonce, - "sender offset" => TransactionKeyManagerBranch::SenderOffset, - "sender offset ledger" => TransactionKeyManagerBranch::SenderOffsetLedger, - "nonce" => TransactionKeyManagerBranch::Nonce, - WALLET_COMMS_AND_SPEND_KEY_BRANCH => TransactionKeyManagerBranch::Spend, - _ => TransactionKeyManagerBranch::Nonce, - } - } - - pub fn as_byte(self) -> u8 { - self as u8 - } -} - #[derive(Clone, Copy, EnumIter)] pub enum TransactionKeyManagerLabel { ScriptKey, @@ -279,7 +226,7 @@ pub trait TransactionKeyManagerInterface: KeyManagerInterface { challenge: &[u8], ) -> Result; - async fn sign_with_nonce_and_message( + async fn sign_with_challenge_and_message( &self, private_key_id: &TariKeyId, nonce: &TariKeyId, diff --git a/base_layer/core/src/transactions/key_manager/mod.rs b/base_layer/core/src/transactions/key_manager/mod.rs index b622a3715e..0563dc8bcd 100644 --- a/base_layer/core/src/transactions/key_manager/mod.rs +++ b/base_layer/core/src/transactions/key_manager/mod.rs @@ -27,7 +27,6 @@ mod interface; pub use interface::{ SecretTransactionKeyManagerInterface, TariKeyId, - TransactionKeyManagerBranch, TransactionKeyManagerInterface, TransactionKeyManagerLabel, TxoStage, @@ -48,3 +47,4 @@ pub use memory_db_key_manager::{ mod error; pub use error::CoreKeyManagerError; +pub use tari_common_types::key_manager::TransactionKeyManagerBranch; diff --git a/base_layer/core/src/transactions/key_manager/wrapper.rs b/base_layer/core/src/transactions/key_manager/wrapper.rs index 58415fdcea..eac880839c 100644 --- a/base_layer/core/src/transactions/key_manager/wrapper.rs +++ b/base_layer/core/src/transactions/key_manager/wrapper.rs @@ -473,7 +473,7 @@ where TBackend: KeyManagerBackend + 'static .await } - async fn sign_with_nonce_and_message( + async fn sign_with_challenge_and_message( &self, private_key_id: &TariKeyId, nonce: &TariKeyId, @@ -482,7 +482,7 @@ where TBackend: KeyManagerBackend + 'static self.transaction_key_manager_inner .read() .await - .sign_with_nonce_and_message(private_key_id, nonce, challenge) + .sign_with_challenge_and_message(private_key_id, nonce, challenge) .await } diff --git a/base_layer/core/src/transactions/test_helpers.rs b/base_layer/core/src/transactions/test_helpers.rs index d1f3d36f47..712ed541d1 100644 --- a/base_layer/core/src/transactions/test_helpers.rs +++ b/base_layer/core/src/transactions/test_helpers.rs @@ -25,7 +25,10 @@ use std::sync::Arc; use rand::rngs::OsRng; 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_common_types::{ + key_manager::TransactionKeyManagerBranch, + types::{Commitment, PrivateKey, PublicKey, Signature}, +}; use tari_crypto::keys::{PublicKey as PK, SecretKey}; use tari_key_manager::key_manager_service::{storage::sqlite_db::KeyManagerSqliteDatabase, KeyId, KeyManagerInterface}; use tari_script::{inputs, script, ExecutionStack, TariScript}; @@ -42,7 +45,6 @@ use crate::{ create_memory_db_key_manager, MemoryDbKeyManager, TariKeyId, - TransactionKeyManagerBranch, TransactionKeyManagerInterface, TransactionKeyManagerLabel, TransactionKeyManagerWrapper, diff --git a/base_layer/core/src/transactions/transaction_components/error.rs b/base_layer/core/src/transactions/transaction_components/error.rs index 28e0bcaed4..0a9e021315 100644 --- a/base_layer/core/src/transactions/transaction_components/error.rs +++ b/base_layer/core/src/transactions/transaction_components/error.rs @@ -84,6 +84,8 @@ pub enum TransactionError { ZeroWeight, #[error("Output with commitment {0} not found in transaction body")] OutputNotFound(String), + #[error("Unsupported TariKeyId: `{0}`")] + UnsupportedTariKeyId(String), } impl From for TransactionError { diff --git a/base_layer/core/src/transactions/transaction_components/wallet_output.rs b/base_layer/core/src/transactions/transaction_components/wallet_output.rs index ec1d50ca8e..aa626f02fb 100644 --- a/base_layer/core/src/transactions/transaction_components/wallet_output.rs +++ b/base_layer/core/src/transactions/transaction_components/wallet_output.rs @@ -276,7 +276,7 @@ impl WalletOutput { &message, ); let script_key_partial_script_signature = key_manager - .sign_with_nonce_and_message(&self.script_key_id, &ephemeral_public_key_self.key_id, &challenge) + .sign_with_challenge_and_message(&self.script_key_id, &ephemeral_public_key_self.key_id, &challenge) .await?; let script_signature = &commitment_partial_script_signature + &script_key_partial_script_signature; diff --git a/base_layer/core/src/transactions/transaction_components/wallet_output_builder.rs b/base_layer/core/src/transactions/transaction_components/wallet_output_builder.rs index 7280e139b3..075a3a2f19 100644 --- a/base_layer/core/src/transactions/transaction_components/wallet_output_builder.rs +++ b/base_layer/core/src/transactions/transaction_components/wallet_output_builder.rs @@ -21,13 +21,16 @@ // USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. use derivative::Derivative; -use tari_common_types::types::{ComAndPubSignature, PublicKey}; +use tari_common_types::{ + key_manager::TransactionKeyManagerBranch, + types::{ComAndPubSignature, PublicKey}, +}; use tari_script::{ExecutionStack, TariScript}; use crate::{ covenants::Covenant, transactions::{ - key_manager::{TariKeyId, TransactionKeyManagerBranch, TransactionKeyManagerInterface}, + key_manager::{TariKeyId, TransactionKeyManagerInterface}, tari_amount::MicroMinotari, transaction_components::{ encrypted_data::PaymentId, @@ -256,7 +259,7 @@ impl WalletOutputBuilder { &metadata_message, ); let sender_partial_metadata_signature_self = key_manager - .sign_with_nonce_and_message(sender_offset_key_id, &ephemeral_pubkey_self.key_id, &challenge) + .sign_with_challenge_and_message(sender_offset_key_id, &ephemeral_pubkey_self.key_id, &challenge) .await?; let metadata_signature = &receiver_partial_metadata_signature + &sender_partial_metadata_signature_self; diff --git a/base_layer/core/src/transactions/transaction_protocol/recipient.rs b/base_layer/core/src/transactions/transaction_protocol/recipient.rs index e516c3d031..54964e8e90 100644 --- a/base_layer/core/src/transactions/transaction_protocol/recipient.rs +++ b/base_layer/core/src/transactions/transaction_protocol/recipient.rs @@ -165,7 +165,7 @@ impl ReceiverTransactionProtocol { #[cfg(test)] mod test { - use tari_common_types::types::PublicKey; + use tari_common_types::{key_manager::TransactionKeyManagerBranch, types::PublicKey}; use tari_crypto::keys::PublicKey as PublicKeyTrait; use tari_key_manager::key_manager_service::{KeyId, KeyManagerInterface}; use tari_script::TariScript; @@ -175,12 +175,7 @@ mod test { test_helpers::create_consensus_constants, transactions::{ crypto_factories::CryptoFactories, - key_manager::{ - create_memory_db_key_manager, - TransactionKeyManagerBranch, - TransactionKeyManagerInterface, - TxoStage, - }, + key_manager::{create_memory_db_key_manager, TransactionKeyManagerInterface, TxoStage}, tari_amount::*, test_helpers::{TestParams, UtxoTestParams}, transaction_components::{ diff --git a/base_layer/core/src/transactions/transaction_protocol/sender.rs b/base_layer/core/src/transactions/transaction_protocol/sender.rs index af5a275ac8..5114ec6252 100644 --- a/base_layer/core/src/transactions/transaction_protocol/sender.rs +++ b/base_layer/core/src/transactions/transaction_protocol/sender.rs @@ -870,7 +870,7 @@ impl fmt::Display for SenderState { #[cfg(test)] mod test { - use tari_common_types::types::PrivateKey; + use tari_common_types::{key_manager::TransactionKeyManagerBranch, types::PrivateKey}; use tari_crypto::signatures::CommitmentAndPublicKeySignature; use tari_key_manager::key_manager_service::KeyManagerInterface; use tari_script::{inputs, script, ExecutionStack, TariScript}; @@ -882,7 +882,7 @@ mod test { test_helpers::{create_consensus_constants, create_consensus_rules}, transactions::{ crypto_factories::CryptoFactories, - key_manager::{create_memory_db_key_manager, TransactionKeyManagerBranch, TransactionKeyManagerInterface}, + key_manager::{create_memory_db_key_manager, TransactionKeyManagerInterface}, tari_amount::*, test_helpers::{create_test_input, create_wallet_output_with_data, TestParams}, transaction_components::{ diff --git a/base_layer/core/src/transactions/transaction_protocol/single_receiver.rs b/base_layer/core/src/transactions/transaction_protocol/single_receiver.rs index 883cff1f0d..2394a7df16 100644 --- a/base_layer/core/src/transactions/transaction_protocol/single_receiver.rs +++ b/base_layer/core/src/transactions/transaction_protocol/single_receiver.rs @@ -20,10 +20,12 @@ // 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 tari_common_types::key_manager::TransactionKeyManagerBranch; + use crate::{ consensus::ConsensusConstants, transactions::{ - key_manager::{TransactionKeyManagerBranch, TransactionKeyManagerInterface, TxoStage}, + key_manager::{TransactionKeyManagerInterface, TxoStage}, transaction_components::{TransactionKernel, WalletOutput}, transaction_protocol::{ recipient::RecipientSignedMessage, 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 85fdea1e0d..688f39767e 100644 --- a/base_layer/core/src/transactions/transaction_protocol/transaction_initializer.rs +++ b/base_layer/core/src/transactions/transaction_protocol/transaction_initializer.rs @@ -25,6 +25,7 @@ use std::fmt::{Debug, Error, Formatter}; use log::*; use serde::{Deserialize, Serialize}; use tari_common_types::{ + key_manager::TransactionKeyManagerBranch, transaction::TxId, types::{Commitment, PrivateKey, PublicKey, Signature}, }; @@ -37,7 +38,7 @@ use crate::{ covenants::Covenant, transactions::{ fee::Fee, - key_manager::{TariKeyId, TransactionKeyManagerBranch, TransactionKeyManagerInterface}, + key_manager::{TariKeyId, TransactionKeyManagerInterface}, tari_amount::*, transaction_components::{ encrypted_data::PaymentId, diff --git a/base_layer/core/src/validation/block_body/test.rs b/base_layer/core/src/validation/block_body/test.rs index 9e16a1b2b0..5dbff49555 100644 --- a/base_layer/core/src/validation/block_body/test.rs +++ b/base_layer/core/src/validation/block_body/test.rs @@ -22,7 +22,7 @@ use std::sync::Arc; use tari_common::configuration::Network; -use tari_common_types::tari_address::TariAddress; +use tari_common_types::{key_manager::TransactionKeyManagerBranch, tari_address::TariAddress}; use tari_key_manager::key_manager_service::KeyId; use tari_script::{push_pubkey_script, script}; use tari_test_utils::unpack_enum; @@ -37,7 +37,7 @@ use crate::{ test_helpers::{blockchain::TestBlockchain, BlockSpec}, transactions::{ aggregated_body::AggregateBody, - key_manager::{TariKeyId, TransactionKeyManagerBranch}, + key_manager::TariKeyId, tari_amount::{uT, T}, test_helpers::schema_to_transaction, transaction_components::{ diff --git a/base_layer/core/tests/helpers/block_builders.rs b/base_layer/core/tests/helpers/block_builders.rs index 1e133655db..36474d0f7c 100644 --- a/base_layer/core/tests/helpers/block_builders.rs +++ b/base_layer/core/tests/helpers/block_builders.rs @@ -22,7 +22,10 @@ use std::{convert::TryFrom, sync::Arc}; use rand::{rngs::OsRng, RngCore}; -use tari_common_types::types::{Commitment, FixedHash}; +use tari_common_types::{ + key_manager::TransactionKeyManagerBranch, + types::{Commitment, FixedHash}, +}; use tari_core::{ blocks::{Block, BlockHeader, BlockHeaderAccumulatedData, ChainBlock, ChainHeader, NewBlockTemplate}, chain_storage::{ @@ -35,7 +38,7 @@ use tari_core::{ consensus::{emission::Emission, ConsensusConstants, ConsensusManager}, proof_of_work::{sha3x_difficulty, AccumulatedDifficulty, AchievedTargetDifficulty, Difficulty}, transactions::{ - key_manager::{MemoryDbKeyManager, TransactionKeyManagerBranch, TransactionKeyManagerInterface, TxoStage}, + key_manager::{MemoryDbKeyManager, TransactionKeyManagerInterface, TxoStage}, tari_amount::MicroMinotari, test_helpers::{create_wallet_output_with_data, spend_utxos, TestParams, TransactionSchema}, transaction_components::{ diff --git a/base_layer/core/tests/tests/mempool.rs b/base_layer/core/tests/tests/mempool.rs index 083f3fec15..05773f7d8e 100644 --- a/base_layer/core/tests/tests/mempool.rs +++ b/base_layer/core/tests/tests/mempool.rs @@ -24,7 +24,10 @@ use std::{convert::TryFrom, ops::Deref, sync::Arc, time::Duration}; use randomx_rs::RandomXFlag; use tari_common::configuration::Network; -use tari_common_types::types::{Commitment, PrivateKey, PublicKey, Signature}; +use tari_common_types::{ + key_manager::TransactionKeyManagerBranch, + types::{Commitment, PrivateKey, PublicKey, Signature}, +}; use tari_comms_dht::domain_message::OutboundDomainMessage; use tari_core::{ base_node::state_machine_service::states::{ListeningInfo, StateInfo, StatusInfo}, @@ -35,12 +38,7 @@ use tari_core::{ proto, transactions::{ fee::Fee, - key_manager::{ - create_memory_db_key_manager, - TransactionKeyManagerBranch, - TransactionKeyManagerInterface, - TxoStage, - }, + key_manager::{create_memory_db_key_manager, TransactionKeyManagerInterface, TxoStage}, tari_amount::{uT, MicroMinotari, T}, test_helpers::{ create_wallet_output_with_data, diff --git a/base_layer/core/tests/tests/node_comms_interface.rs b/base_layer/core/tests/tests/node_comms_interface.rs index cd6c80d6a6..395b2c9541 100644 --- a/base_layer/core/tests/tests/node_comms_interface.rs +++ b/base_layer/core/tests/tests/node_comms_interface.rs @@ -23,6 +23,7 @@ use std::sync::{Arc, RwLock}; use tari_common::configuration::Network; +use tari_common_types::key_manager::TransactionKeyManagerBranch; use tari_comms::test_utils::mocks::create_connectivity_mock; use tari_core::{ base_node::comms_interface::{ @@ -44,7 +45,6 @@ use tari_core::{ key_manager::{ create_memory_db_key_manager, MemoryDbKeyManager, - TransactionKeyManagerBranch, TransactionKeyManagerInterface, TransactionKeyManagerLabel, }, 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 57cbd817a0..1b54466747 100644 --- a/base_layer/key_manager/src/key_manager_service/error.rs +++ b/base_layer/key_manager/src/key_manager_service/error.rs @@ -31,8 +31,10 @@ use crate::error::KeyManagerError as KMError; /// Error enum for the [KeyManagerService] #[derive(Debug, thiserror::Error)] pub enum KeyManagerServiceError { - #[error("Branch does not exist")] - UnknownKeyBranch, + #[error("Key manager branch not supported: `{0}`")] + BranchNotSupported(String), + #[error("Branch does not exist: `{0}`")] + UnknownKeyBranch(String), #[error("Key ID without an index, most likely `Imported`")] KyeIdWithoutIndex, #[error("Master seed does not match stored version")] 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 681edc5bb4..a18ca3ebe9 100644 --- a/base_layer/key_manager/src/key_manager_service/service.rs +++ b/base_layer/key_manager/src/key_manager_service/service.rs @@ -102,7 +102,7 @@ where let mut km = self .key_managers .get(branch) - .ok_or(KeyManagerServiceError::UnknownKeyBranch)? + .ok_or(KeyManagerServiceError::UnknownKeyBranch(branch.to_string()))? .lock() .await; self.db.increment_key_index(branch)?; @@ -130,7 +130,7 @@ where pub async fn get_static_key(&self, branch: &str) -> Result, KeyManagerServiceError> { match self.key_managers.get(branch) { - None => Err(KeyManagerServiceError::UnknownKeyBranch), + None => Err(KeyManagerServiceError::UnknownKeyBranch(branch.to_string())), Some(_) => Ok(KeyId::Managed { branch: branch.to_string(), index: 0, @@ -144,7 +144,7 @@ where let km = self .key_managers .get(branch) - .ok_or(KeyManagerServiceError::UnknownKeyBranch)? + .ok_or(KeyManagerServiceError::UnknownKeyBranch(branch.to_string()))? .lock() .await; Ok(km.derive_public_key(*index)?.key) @@ -153,7 +153,7 @@ where let km = self .key_managers .get(branch) - .ok_or(KeyManagerServiceError::UnknownKeyBranch)? + .ok_or(KeyManagerServiceError::UnknownKeyBranch(branch.to_string()))? .lock() .await; let branch_key = km.get_private_key(*index)?; @@ -182,7 +182,7 @@ where let km = self .key_managers .get(branch) - .ok_or(KeyManagerServiceError::UnknownKeyBranch)? + .ok_or(KeyManagerServiceError::UnknownKeyBranch(branch.to_string()))? .lock() .await; @@ -208,7 +208,7 @@ where let mut km = self .key_managers .get(branch) - .ok_or(KeyManagerServiceError::UnknownKeyBranch)? + .ok_or(KeyManagerServiceError::UnknownKeyBranch(branch.to_string()))? .lock() .await; let current_index = km.key_index(); 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 5134dd2287..ca79d70992 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 @@ -24,11 +24,12 @@ use std::time::Instant; use log::*; use tari_common_types::{ + key_manager::TransactionKeyManagerBranch, transaction::TxId, types::{FixedHash, PrivateKey}, }; use tari_core::transactions::{ - key_manager::{TariKeyId, TransactionKeyManagerBranch, TransactionKeyManagerInterface, TransactionKeyManagerLabel}, + key_manager::{TariKeyId, TransactionKeyManagerInterface, TransactionKeyManagerLabel}, tari_amount::MicroMinotari, transaction_components::{ encrypted_data::PaymentId, diff --git a/base_layer/wallet/src/output_manager_service/service.rs b/base_layer/wallet/src/output_manager_service/service.rs index b95f0fe44c..e81b4a8402 100644 --- a/base_layer/wallet/src/output_manager_service/service.rs +++ b/base_layer/wallet/src/output_manager_service/service.rs @@ -27,6 +27,7 @@ use futures::{pin_mut, StreamExt}; use log::*; use rand::{rngs::OsRng, RngCore}; use tari_common_types::{ + key_manager::TransactionKeyManagerBranch, tari_address::TariAddress, transaction::TxId, types::{BlockHash, Commitment, HashOutput, PrivateKey, PublicKey}, @@ -45,7 +46,7 @@ use tari_core::{ proto::base_node::FetchMatchingUtxos, transactions::{ fee::Fee, - key_manager::{TariKeyId, TransactionKeyManagerBranch, TransactionKeyManagerInterface}, + key_manager::{TariKeyId, TransactionKeyManagerInterface}, tari_amount::MicroMinotari, transaction_components::{ encrypted_data::PaymentId, diff --git a/base_layer/wallet/src/transaction_service/service.rs b/base_layer/wallet/src/transaction_service/service.rs index 7850127b2b..d5b55810bf 100644 --- a/base_layer/wallet/src/transaction_service/service.rs +++ b/base_layer/wallet/src/transaction_service/service.rs @@ -36,6 +36,7 @@ use sha2::Sha256; use tari_common::configuration::Network; use tari_common_types::{ burnt_proof::BurntProof, + key_manager::TransactionKeyManagerBranch, tari_address::{TariAddress, TariAddressFeatures}, transaction::{ImportStatus, TransactionDirection, TransactionStatus, TxId}, types::{CommitmentFactory, FixedHash, HashOutput, PrivateKey, PublicKey, Signature}, @@ -54,7 +55,7 @@ use tari_core::{ }, proto::{base_node as base_node_proto, base_node::FetchMatchingUtxos}, transactions::{ - key_manager::{TariKeyId, TransactionKeyManagerBranch, TransactionKeyManagerInterface}, + key_manager::{TariKeyId, TransactionKeyManagerInterface}, tari_amount::MicroMinotari, transaction_components::{ encrypted_data::PaymentId, 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 df7deae575..4ace381341 100644 --- a/base_layer/wallet/tests/output_manager_service_tests/service.rs +++ b/base_layer/wallet/tests/output_manager_service_tests/service.rs @@ -43,6 +43,7 @@ use minotari_wallet::{ }; use rand::{rngs::OsRng, RngCore}; use tari_common_types::{ + key_manager::TransactionKeyManagerBranch, transaction::TxId, types::{ComAndPubSignature, FixedHash, PublicKey}, }; @@ -62,7 +63,6 @@ use tari_core::{ key_manager::{ create_memory_db_key_manager, MemoryDbKeyManager, - TransactionKeyManagerBranch, TransactionKeyManagerInterface, TransactionKeyManagerLabel, }, diff --git a/base_layer/wallet/tests/transaction_service_tests/storage.rs b/base_layer/wallet/tests/transaction_service_tests/storage.rs index f991eb003e..596a897d35 100644 --- a/base_layer/wallet/tests/transaction_service_tests/storage.rs +++ b/base_layer/wallet/tests/transaction_service_tests/storage.rs @@ -42,6 +42,7 @@ use minotari_wallet::{ use rand::{rngs::OsRng, RngCore}; use tari_common::configuration::Network; use tari_common_types::{ + key_manager::TransactionKeyManagerBranch, tari_address::TariAddress, transaction::{TransactionDirection, TransactionStatus, TxId}, types::{FixedHash, PrivateKey, PublicKey, Signature}, @@ -49,12 +50,7 @@ use tari_common_types::{ use tari_core::{ covenants::Covenant, transactions::{ - key_manager::{ - create_memory_db_key_manager, - TransactionKeyManagerBranch, - TransactionKeyManagerInterface, - TransactionKeyManagerLabel, - }, + key_manager::{create_memory_db_key_manager, TransactionKeyManagerInterface, TransactionKeyManagerLabel}, tari_amount::{uT, MicroMinotari}, test_helpers::{create_wallet_output_with_data, TestParams}, transaction_components::{