From 58dd9e967feedede4debadf23ba87fc18e174440 Mon Sep 17 00:00:00 2001 From: Hansie Odendaal Date: Thu, 18 Jul 2024 10:09:28 +0200 Subject: [PATCH] wip --- .../comms/examples/ledger_demo/main.rs | 146 +++++++++++------- .../minotari_ledger_wallet/wallet/Cargo.toml | 1 + .../src/handlers/get_schnorr_signature.rs | 86 ++++++++++- .../src/handlers/get_script_signature.rs | 22 +-- 4 files changed, 188 insertions(+), 67 deletions(-) diff --git a/applications/minotari_ledger_wallet/comms/examples/ledger_demo/main.rs b/applications/minotari_ledger_wallet/comms/examples/ledger_demo/main.rs index daf5232d9e..0552e1d7d2 100644 --- a/applications/minotari_ledger_wallet/comms/examples/ledger_demo/main.rs +++ b/applications/minotari_ledger_wallet/comms/examples/ledger_demo/main.rs @@ -3,6 +3,7 @@ //! # Multi-party Ledger - command line example +use ledger_transport_hid::TransportNativeHID; // use tari_common_types::types::{PrivateKey, PublicKey}; // use tari_crypto::keys::{PublicKey as PK, SecretKey}; // use tari_utilities::hex::Hex; @@ -60,6 +61,56 @@ fn main() { // GetAppName println!("\ntest: GetAppName"); + if let Err(e) = test_get_app_name(&transport, &ledger) { + println!("\n Error: {}\n", e); + } + + // GetVersion + println!("\ntest: GetVersion"); + if let Err(e) = test_get_version(&transport, &ledger) { + println!("\n Error: {}\n", e); + } + + // GetPublicAlpha + println!("\ntest: GetPublicAlpha"); + if let Err(e) = test_public_alpha(&transport, &ledger) { + println!("\n Error: {}\n", e); + } + + // GetPublicKey + println!("\ntest: GetPublicKey"); + if let Err(e) = test_get_public_key(&transport, &ledger) { + println!("\n Error: {}\n", e); + } + + // GetScriptSignature + println!("\ntest: GetScriptSignature"); + if let Err(e) = test_get_script_signature(&transport, &ledger) { + println!("\n Error: {}\n", e); + } + + // GetViewKey + println!("\ntest: GetViewKey"); + if let Err(e) = test_get_view_key(&transport, &ledger) { + println!("\n Error: {}\n", e); + } + + // GetDHSharedSecret + println!("\ntest: GetDHSharedSecret"); + if let Err(e) = test_get_dh_shared_secret(&transport, &ledger) { + println!("\n Error: {}\n", e); + } + + // GetSchnorrSignature + println!("\ntest: GetSchnorrSignature"); + if let Err(e) = test_get_schnorr_signature(&transport, &ledger) { + println!("\n Error: {}\n", e); + } + + println!("\nTest completed successfully\n"); +} + +fn test_get_app_name(transport: &TransportNativeHID, ledger: &LedgerWallet) -> Result<(), String> { match ledger .build_command(Instruction::GetAppName, vec![0]) .execute_with_transport(&transport) @@ -68,19 +119,19 @@ fn main() { let name = match std::str::from_utf8(response.data()) { Ok(val) => val, Err(e) => { - println!("\nError: {}\n", e); - return; + return Err(format!("{}", e)) }, }; println!("app name: {}", name); + Ok(()) }, Err(e) => { - println!("\nError: {}\n", e); + Err(format!("{}", e)) }, } +} - // GetVersion - println!("\ntest: GetVersion"); +fn test_get_version(transport: &TransportNativeHID, ledger: &LedgerWallet) -> Result<(), String> { match ledger .build_command(Instruction::GetVersion, vec![0]) .execute_with_transport(&transport) @@ -89,42 +140,40 @@ fn main() { let name = match std::str::from_utf8(response.data()) { Ok(val) => val, Err(e) => { - println!("\nError: {}\n", e); - return; + return Err(format!("{}", e)) }, }; println!("version: {}", name); + Ok(()) }, Err(e) => { - println!("\nError: {}\n", e); + Err(format!("{}", e)) }, } +} - // GetPublicAlpha - println!("\ntest: GetPublicAlpha"); +fn test_public_alpha(transport: &TransportNativeHID, ledger: &LedgerWallet) -> Result<(), String> { match ledger .build_command(Instruction::GetPublicAlpha, vec![]) .execute_with_transport(&transport) { Ok(result) => { if result.data().len() < 33 { - println!("\nError: result less than 33\n"); - return; + return Err(format!("result less than 33, got {} ({:?})", result.data().len(), result)) } - let public_alpha = PublicKey::from_canonical_bytes(&result.data()[1..33]).unwrap(); println!("public_alpha: {}", public_alpha.to_hex()); + Ok(()) }, Err(e) => { - println!("\nError: {}\n", e); - return; + Err(format!("{}", e)) }, } +} - // GetPublicKey - println!("\ntest: GetPublicKey"); +fn test_get_public_key(transport: &TransportNativeHID, ledger: &LedgerWallet) -> Result<(), String> { let mut data = Vec::new(); - let index = OsRng.next_u64().to_le_bytes(); // OsRng.next_u64().to_le_bytes(); + let index = OsRng.next_u64().to_le_bytes(); data.extend_from_slice(&index); let branch_u8 = u64::from(TransactionKeyManagerBranch::CommitmentMask.as_byte()).to_le_bytes(); data.extend_from_slice(&branch_u8); @@ -135,21 +184,19 @@ fn main() { { Ok(result) => { if result.data().len() < 33 { - println!("\nError: result less than 33\n"); - return; + return Err(format!("result less than 33, got {} ({:?})", result.data().len(), result)) } - let public_key = PublicKey::from_canonical_bytes(&result.data()[1..33]).unwrap(); println!("public_key: {}", public_key.to_hex()); + Ok(()) }, Err(e) => { - println!("\nError: {}\n", e); - return; + Err(format!("{}", e)) }, } +} - // GetScriptSignature - println!("\ntest: GetScriptSignature"); +fn test_get_script_signature(transport: &TransportNativeHID, ledger: &LedgerWallet) -> Result<(), String> { let mut data = Vec::new(); let network = u64::from(Network::LocalNet.as_byte()).to_le_bytes(); data.extend_from_slice(&network); @@ -173,10 +220,8 @@ fn main() { { Ok(result) => { if result.data().len() < 161 { - println!("\nError: result less than 161\n"); - return; + return Err(format!("result less than 161, got {} ({:?})", result.data().len(), result)) } - let data = result.data(); let signature = ComAndPubSignature::new( Commitment::from_canonical_bytes(&data[1..33]).unwrap(), @@ -193,38 +238,36 @@ fn main() { signature.u_a().to_hex(), signature.u_y().to_hex() ); + Ok(()) }, Err(e) => { - println!("\nError: {}\n", e); - return; + Err(format!("{}", e)) }, } +} - // GetViewKey - println!("\ntest: GetViewKey"); +fn test_get_view_key(transport: &TransportNativeHID, ledger: &LedgerWallet) -> Result<(), String> { match ledger .build_command(Instruction::GetViewKey, vec![]) .execute_with_transport(&transport) { Ok(result) => { if result.data().len() < 33 { - println!("\nError: result less than 33\n"); - return; + return Err(format!("result less than 33, got {} ({:?})", result.data().len(), result)) } - let view_key = PrivateKey::from_canonical_bytes(&result.data()[1..33]).unwrap(); println!("view_key: {}", view_key.to_hex()); + Ok(()) }, Err(e) => { - println!("\nError: {}\n", e); - return; + Err(format!("{}", e)) }, } +} - // GetDHSharedSecret - println!("\ntest: GetDHSharedSecret"); +fn test_get_dh_shared_secret(transport: &TransportNativeHID, ledger: &LedgerWallet) -> Result<(), String> { let mut data = Vec::new(); - let index = OsRng.next_u64().to_le_bytes(); // OsRng.next_u64().to_le_bytes(); + let index = OsRng.next_u64().to_le_bytes(); data.extend_from_slice(&index); let branch_u8 = u64::from(TransactionKeyManagerBranch::SenderOffset.as_byte()).to_le_bytes(); data.extend_from_slice(&branch_u8); @@ -237,24 +280,22 @@ fn main() { { Ok(result) => { if result.data().len() < 33 { - println!("\nError: result less than 65\n"); - return; + return Err(format!("result less than 33, got {} ({:?})", result.data().len(), result)) } - let shared_secret = DiffieHellmanSharedSecret::::from_canonical_bytes(&result.data()[1..33]).unwrap(); println!("shared_secret: {}", shared_secret.as_bytes().to_vec().to_hex()); + Ok(()) }, Err(e) => { - println!("\nError: {}\n", e); - return; + Err(format!("{}", e)) }, } +} - // GetSchnorrSignature - println!("\ntest: GetSchnorrSignature"); +fn test_get_schnorr_signature(transport: &TransportNativeHID, ledger: &LedgerWallet) -> Result<(), String> { let mut data = Vec::new(); - let index = OsRng.next_u64().to_le_bytes(); // OsRng.next_u64().to_le_bytes(); + let index = OsRng.next_u64().to_le_bytes(); data.extend_from_slice(&index); let branch_u8 = u64::from(TransactionKeyManagerBranch::Nonce.as_byte()).to_le_bytes(); data.extend_from_slice(&branch_u8); @@ -269,8 +310,7 @@ fn main() { Ok(result) => { println!("signature data: {:?}", result.data()); if result.data().len() < 65 { - println!("\nError: result less than 65\n"); - return; + return Err(format!("result less than 65, got {} ({:?})", result.data().len(), result)) } let signature = CheckSigSchnorrSignature::new( @@ -282,14 +322,12 @@ fn main() { signature.get_signature().to_hex(), signature.get_public_nonce().to_hex() ); + Ok(()) }, Err(e) => { - println!("\nError: {}\n", e); - return; + Err(format!("{}", e)) }, } - - println!("\nTest completed successfully\n"); } fn get_random_nonce() -> PrivateKey { diff --git a/applications/minotari_ledger_wallet/wallet/Cargo.toml b/applications/minotari_ledger_wallet/wallet/Cargo.toml index 8e4d9a0e44..221222c116 100644 --- a/applications/minotari_ledger_wallet/wallet/Cargo.toml +++ b/applications/minotari_ledger_wallet/wallet/Cargo.toml @@ -16,6 +16,7 @@ digest = { version = "0.10", default-features = false } embedded-alloc = "0.5.0" include_gif = "1.0.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 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 index 8d4b908713..db0a672e9f 100644 --- a/applications/minotari_ledger_wallet/wallet/src/handlers/get_schnorr_signature.rs +++ b/applications/minotari_ledger_wallet/wallet/src/handlers/get_schnorr_signature.rs @@ -108,14 +108,92 @@ pub fn handler_get_schnorr_signature(comm: &mut Comm) -> Result<(), AppSW> { Ok(()) } +use ledger_device_sdk::random::Random; +use ledger_device_sdk::random::rand_bytes; +use ledger_device_sdk::random::LedgerRng; +use rand_core::CryptoRng; +use rand_core::{RngCore, Error, impls}; + fn get_random_nonce() -> Zeroizing { - use ledger_device_sdk::random::Random; - use ledger_device_sdk::random::rand_bytes; - let mut raw_bytes = [0u8; 64]; - rand_bytes(&mut raw_bytes); + SingleMessage::new(&format!("get_random_nonce")).show_and_wait(); + + let mut raw_bytes = [0u8; 64]; + LedgerRng.fill_bytes(&mut raw_bytes); SingleMessage::new(&format!("{}", raw_bytes.to_hex())).show_and_wait(); + let raw_bytes: [u8; 64] = core::array::from_fn(|_| u8::random()); SingleMessage::new(&format!("{}", raw_bytes.to_hex())).show_and_wait(); + + let v = LedgerRng.next_u64(); + SingleMessage::new(&format!("{}", v)).show_and_wait(); + + if let Some(val) = get_random_bytes::<8>() { + SingleMessage::new(&format!("{:?}", val)).show_and_wait(); + } + Zeroizing::new(RistrettoSecretKey::from_uniform_bytes(&raw_bytes).expect("will not fail")) } + +use core::ptr; + + +const IO_RNG_BASE: u32 = 0x40000000; // Hypothetical base address +const IO_RNG_STATUS_OFFSET: u32 = 0x000; +const IO_RNG_DATA_OFFSET: u32 = 0x004; + +fn read_random_byte() -> Option { + unsafe { + // Wait until the RNG has valid data + for _ in 0..1000 { // Timeout to avoid infinite loop + if ptr::read_volatile((IO_RNG_BASE + IO_RNG_STATUS_OFFSET) as *const u32) & 1 != 0 { + // Read the random byte + return Some(ptr::read_volatile((IO_RNG_BASE + IO_RNG_DATA_OFFSET) as *const u8)); + } + } + None // Return None if timeout is reached + } +} + +fn get_random_bytes() -> Option<[u8; N]> { + let mut array = [0u8; N]; + for i in 0..N { + match read_random_byte() { + Some(byte) => array[i] = byte, + None => return None, // Return None if reading a byte fails + } + } + Some(array) +} + + +// /// [`RngCore`] implementation via the [`rand_bytes`] syscall +// #[derive(Copy, Clone, Debug)] +// pub struct LedgerRng; +// +// /// Implement [`RngCore`] (for `rand_core@0.6.x`) using ledger syscalls +// /// +// /// For backwards compatibility with `rand_core@0.5.x` see [rand_compat](https://docs.rs/rand-compat/latest/rand_compat/) +// impl RngCore for LedgerRng { +// fn next_u32(&mut self) -> u32 { +// impls::next_u32_via_fill(self) +// } +// +// fn next_u64(&mut self) -> u64 { +// impls::next_u64_via_fill(self) +// } +// +// fn fill_bytes(&mut self, dest: &mut [u8]) { +// if let Err(e) = self.try_fill_bytes(dest) { +// panic!("Error: {}", e); +// } +// } +// +// fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { +// getrandom(dest)?; +// Ok(()) +// } +// } +// +// /// Mark LedgerRng as safe for cryptographic use +// impl CryptoRng for LedgerRng {} 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 dc35223d8a..7d053430f1 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 @@ -60,15 +60,19 @@ 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)?; - SingleMessage::new(&format!("r_a")).show_and_wait(); - SingleMessage::new(&format!("{}", r_a.reveal())).show_and_wait(); - let r_x = derive_from_bip32_key(account, u32::random().into(), KeyType::Nonce)?; - SingleMessage::new(&format!("r_x")).show_and_wait(); - SingleMessage::new(&format!("{}", r_x.reveal())).show_and_wait(); - let r_y = derive_from_bip32_key(account, u32::random().into(), KeyType::Nonce)?; - SingleMessage::new(&format!("r_y")).show_and_wait(); - SingleMessage::new(&format!("{}", r_y.reveal())).show_and_wait(); + let nonce_a = u32::random(); + let nonce_x = u32::random(); + let nonce_y = u32::random(); + SingleMessage::new(&format!("nonce_a: {}", nonce_a)).show_and_wait(); + SingleMessage::new(&format!("nonce_x: {}", nonce_x)).show_and_wait(); + SingleMessage::new(&format!("nonce_y: {}", nonce_y)).show_and_wait(); + if nonce_a == nonce_x || nonce_a == nonce_y || nonce_x == nonce_y { + SingleMessage::new("Nonces not unique!").show_and_wait(); + return Err(AppSW::ScriptSignatureFail); + } + let r_a = derive_from_bip32_key(account, nonce_a.into(), KeyType::Nonce)?; + let r_x = derive_from_bip32_key(account, nonce_x.into(), KeyType::Nonce)?; + let r_y = derive_from_bip32_key(account, nonce_y.into(), KeyType::Nonce)?; let factory = ExtendedPedersenCommitmentFactory::default();