From 828d7bf034192dd0417884b7341c8f95ce2b79df Mon Sep 17 00:00:00 2001 From: Thibault Martinez Date: Mon, 20 Nov 2023 20:49:16 +0100 Subject: [PATCH 1/2] Add SecretManage::generate_ed25519_public_keys --- sdk/src/client/secret/ledger_nano.rs | 74 +++++++++++++++------------- sdk/src/client/secret/mnemonic.rs | 16 ++---- sdk/src/client/secret/mod.rs | 36 +++++++++++--- sdk/src/client/secret/private_key.rs | 15 ++---- sdk/src/client/stronghold/secret.rs | 32 +++++------- 5 files changed, 88 insertions(+), 85 deletions(-) diff --git a/sdk/src/client/secret/ledger_nano.rs b/sdk/src/client/secret/ledger_nano.rs index e627293adf..7c38f03597 100644 --- a/sdk/src/client/secret/ledger_nano.rs +++ b/sdk/src/client/secret/ledger_nano.rs @@ -10,7 +10,10 @@ use std::{collections::HashMap, ops::Range}; use async_trait::async_trait; use crypto::{ keys::{bip44::Bip44, slip10::Segment}, - signatures::secp256k1_ecdsa::{self, EvmAddress}, + signatures::{ + ed25519, + secp256k1_ecdsa::{self, EvmAddress}, + }, }; use iota_ledger_nano::{ api::errors::APIError, get_app_config, get_buffer_size, get_ledger, get_opened_app, LedgerBIP32Index, @@ -26,7 +29,7 @@ use crate::{ LedgerNanoStatus, PreparedTransactionData, }, types::block::{ - address::{AccountAddress, Address, AnchorAddress, Ed25519Address, NftAddress}, + address::{AccountAddress, Address, AnchorAddress, NftAddress}, output::Output, payload::signed_transaction::SignedTransactionPayload, signature::{Ed25519Signature, Signature}, @@ -131,41 +134,44 @@ impl TryFrom for LedgerDeviceType { impl SecretManage for LedgerSecretManager { type Error = crate::client::Error; - async fn generate_ed25519_addresses( + async fn generate_ed25519_public_keys( &self, // https://github.com/satoshilabs/slips/blob/master/slip-0044.md // current ledger app only supports IOTA_COIN_TYPE, SHIMMER_COIN_TYPE and TESTNET_COIN_TYPE - coin_type: u32, - account_index: u32, - address_indexes: Range, - options: impl Into> + Send, - ) -> Result, Self::Error> { - let options = options.into().unwrap_or_default(); - let bip32_account = account_index.harden().into(); - - let bip32 = LedgerBIP32Index { - bip32_index: address_indexes.start.harden().into(), - bip32_change: u32::from(options.internal).harden().into(), - }; - - // lock the mutex to prevent multiple simultaneous requests to a ledger - let lock = self.mutex.lock().await; - - // get ledger - let ledger = get_ledger(coin_type, bip32_account, self.is_simulator).map_err(Error::from)?; - if ledger.is_debug_app() { - ledger - .set_non_interactive_mode(self.non_interactive) - .map_err(Error::from)?; - } - - let addresses = ledger - .get_addresses(options.ledger_nano_prompt, bip32, address_indexes.len()) - .map_err(Error::from)?; - - drop(lock); - - Ok(addresses.into_iter().map(Ed25519Address::new).collect()) + _coin_type: u32, + _account_index: u32, + _address_indexes: Range, + _options: impl Into> + Send, + ) -> Result, Self::Error> { + // need an update on the ledger C lib + todo!(); + // + // let options = options.into().unwrap_or_default(); + // let bip32_account = account_index.harden().into(); + + // let bip32 = LedgerBIP32Index { + // bip32_index: address_indexes.start.harden().into(), + // bip32_change: u32::from(options.internal).harden().into(), + // }; + + // // lock the mutex to prevent multiple simultaneous requests to a ledger + // let lock = self.mutex.lock().await; + + // // get ledger + // let ledger = get_ledger(coin_type, bip32_account, self.is_simulator).map_err(Error::from)?; + // if ledger.is_debug_app() { + // ledger + // .set_non_interactive_mode(self.non_interactive) + // .map_err(Error::from)?; + // } + + // let addresses = ledger + // .get_addresses(options.ledger_nano_prompt, bip32, address_indexes.len()) + // .map_err(Error::from)?; + + // drop(lock); + + // Ok(addresses.into_iter().map(Ed25519Address::new).collect()) } async fn generate_evm_addresses( diff --git a/sdk/src/client/secret/mnemonic.rs b/sdk/src/client/secret/mnemonic.rs index d955309c1e..ee705d0c8e 100644 --- a/sdk/src/client/secret/mnemonic.rs +++ b/sdk/src/client/secret/mnemonic.rs @@ -7,7 +7,6 @@ use std::ops::Range; use async_trait::async_trait; use crypto::{ - hashes::{blake2b::Blake2b256, Digest}, keys::{bip39::Mnemonic, bip44::Bip44, slip10::Seed}, signatures::{ ed25519, @@ -20,8 +19,7 @@ use super::{GenerateAddressOptions, SecretManage}; use crate::{ client::{api::PreparedTransactionData, Client, Error}, types::block::{ - address::Ed25519Address, payload::signed_transaction::SignedTransactionPayload, signature::Ed25519Signature, - unlock::Unlocks, + payload::signed_transaction::SignedTransactionPayload, signature::Ed25519Signature, unlock::Unlocks, }, }; @@ -40,13 +38,13 @@ impl std::fmt::Debug for MnemonicSecretManager { impl SecretManage for MnemonicSecretManager { type Error = Error; - async fn generate_ed25519_addresses( + async fn generate_ed25519_public_keys( &self, coin_type: u32, account_index: u32, address_indexes: Range, options: impl Into> + Send, - ) -> Result, Self::Error> { + ) -> Result, Self::Error> { let internal = options.into().map(|o| o.internal).unwrap_or_default(); Ok(address_indexes @@ -59,13 +57,9 @@ impl SecretManage for MnemonicSecretManager { let public_key = chain .derive(&self.0.to_master_key::()) .secret_key() - .public_key() - .to_bytes(); - - // Hash the public key to get the address - let result = Blake2b256::digest(public_key).into(); + .public_key(); - crate::client::Result::Ok(Ed25519Address::new(result)) + crate::client::Result::Ok(public_key) }) .collect::>()?) } diff --git a/sdk/src/client/secret/mod.rs b/sdk/src/client/secret/mod.rs index 9c6af509c8..19fe7dc2c2 100644 --- a/sdk/src/client/secret/mod.rs +++ b/sdk/src/client/secret/mod.rs @@ -26,8 +26,12 @@ use std::{collections::HashMap, fmt::Debug, ops::Range, str::FromStr}; use async_trait::async_trait; use crypto::{ + hashes::{blake2b::Blake2b256, Digest}, keys::{bip39::Mnemonic, bip44::Bip44}, - signatures::secp256k1_ecdsa::{self, EvmAddress}, + signatures::{ + ed25519, + secp256k1_ecdsa::{self, EvmAddress}, + }, }; use serde::{de::DeserializeOwned, Deserialize, Serialize}; use zeroize::Zeroizing; @@ -66,6 +70,15 @@ use crate::{ pub trait SecretManage: Send + Sync { type Error: std::error::Error + Send + Sync; + /// Generates public keys. + async fn generate_ed25519_public_keys( + &self, + coin_type: u32, + account_index: u32, + address_indexes: Range, + options: impl Into> + Send, + ) -> Result, Self::Error>; + /// Generates addresses. /// /// For `coin_type`, see also . @@ -75,7 +88,14 @@ pub trait SecretManage: Send + Sync { account_index: u32, address_indexes: Range, options: impl Into> + Send, - ) -> Result, Self::Error>; + ) -> Result, Self::Error> { + Ok(self + .generate_ed25519_public_keys(coin_type, account_index, address_indexes, options) + .await? + .iter() + .map(|public_key| Ed25519Address::new(Blake2b256::digest(public_key.to_bytes()).into())) + .collect()) + } async fn generate_evm_addresses( &self, @@ -308,31 +328,31 @@ impl From<&SecretManager> for SecretManagerDto { impl SecretManage for SecretManager { type Error = Error; - async fn generate_ed25519_addresses( + async fn generate_ed25519_public_keys( &self, coin_type: u32, account_index: u32, address_indexes: Range, options: impl Into> + Send, - ) -> crate::client::Result> { + ) -> Result, Self::Error> { match self { #[cfg(feature = "stronghold")] Self::Stronghold(secret_manager) => Ok(secret_manager - .generate_ed25519_addresses(coin_type, account_index, address_indexes, options) + .generate_ed25519_public_keys(coin_type, account_index, address_indexes, options) .await?), #[cfg(feature = "ledger_nano")] Self::LedgerNano(secret_manager) => Ok(secret_manager - .generate_ed25519_addresses(coin_type, account_index, address_indexes, options) + .generate_ed25519_public_keys(coin_type, account_index, address_indexes, options) .await?), Self::Mnemonic(secret_manager) => { secret_manager - .generate_ed25519_addresses(coin_type, account_index, address_indexes, options) + .generate_ed25519_public_keys(coin_type, account_index, address_indexes, options) .await } #[cfg(feature = "private_key_secret_manager")] Self::PrivateKey(secret_manager) => { secret_manager - .generate_ed25519_addresses(coin_type, account_index, address_indexes, options) + .generate_ed25519_public_keys(coin_type, account_index, address_indexes, options) .await } Self::Placeholder => Err(Error::PlaceholderSecretManager), diff --git a/sdk/src/client/secret/private_key.rs b/sdk/src/client/secret/private_key.rs index f1b23862b6..0be00cd7a3 100644 --- a/sdk/src/client/secret/private_key.rs +++ b/sdk/src/client/secret/private_key.rs @@ -7,7 +7,6 @@ use std::ops::Range; use async_trait::async_trait; use crypto::{ - hashes::{blake2b::Blake2b256, Digest}, keys::bip44::Bip44, signatures::{ ed25519, @@ -20,8 +19,7 @@ use super::{GenerateAddressOptions, SecretManage}; use crate::{ client::{api::PreparedTransactionData, Error}, types::block::{ - address::Ed25519Address, payload::signed_transaction::SignedTransactionPayload, signature::Ed25519Signature, - unlock::Unlocks, + payload::signed_transaction::SignedTransactionPayload, signature::Ed25519Signature, unlock::Unlocks, }, }; @@ -38,19 +36,14 @@ impl std::fmt::Debug for PrivateKeySecretManager { impl SecretManage for PrivateKeySecretManager { type Error = Error; - async fn generate_ed25519_addresses( + async fn generate_ed25519_public_keys( &self, _coin_type: u32, _account_index: u32, _address_indexes: Range, _options: impl Into> + Send, - ) -> Result, Self::Error> { - let public_key = self.0.public_key().to_bytes(); - - // Hash the public key to get the address - let result = Blake2b256::digest(public_key).into(); - - crate::client::Result::Ok(vec![Ed25519Address::new(result)]) + ) -> Result, Self::Error> { + crate::client::Result::Ok(vec![self.0.public_key()]) } async fn generate_evm_addresses( diff --git a/sdk/src/client/stronghold/secret.rs b/sdk/src/client/stronghold/secret.rs index bdcc3e1dd3..cc0993a522 100644 --- a/sdk/src/client/stronghold/secret.rs +++ b/sdk/src/client/stronghold/secret.rs @@ -8,7 +8,6 @@ use std::ops::Range; use async_trait::async_trait; use crypto::{ - hashes::{blake2b::Blake2b256, Digest}, keys::{ bip39::{Mnemonic, MnemonicRef, Passphrase}, bip44::Bip44, @@ -36,8 +35,7 @@ use crate::{ stronghold::Error, }, types::block::{ - address::Ed25519Address, payload::signed_transaction::SignedTransactionPayload, signature::Ed25519Signature, - unlock::Unlocks, + payload::signed_transaction::SignedTransactionPayload, signature::Ed25519Signature, unlock::Unlocks, }, }; @@ -45,13 +43,13 @@ use crate::{ impl SecretManage for StrongholdAdapter { type Error = crate::client::Error; - async fn generate_ed25519_addresses( + async fn generate_ed25519_public_keys( &self, coin_type: u32, account_index: u32, address_indexes: Range, options: impl Into> + Send, - ) -> Result, Self::Error> { + ) -> Result, Self::Error> { // Prevent the method from being invoked when the key has been cleared from the memory. Do note that Stronghold // only asks for a key for reading / writing a snapshot, so without our cached key this method is invocable, but // it doesn't make sense when it comes to our user (signing transactions / generating addresses without a key). @@ -64,8 +62,8 @@ impl SecretManage for StrongholdAdapter { // Stronghold arguments. let seed_location = Slip10DeriveInput::Seed(Location::generic(SECRET_VAULT_PATH, SEED_RECORD_PATH)); - // Addresses to return. - let mut addresses = Vec::new(); + // Public keys to return. + let mut public_keys = Vec::new(); let internal = options.into().map(|o| o.internal).unwrap_or_default(); for address_index in address_indexes { @@ -104,17 +102,11 @@ impl SecretManage for StrongholdAdapter { .delete_secret(derive_location.record_path()) .map_err(Error::from)?; - // Hash the public key to get the address. - let hash = Blake2b256::digest(public_key); - - // Convert the hash into [Address]. - let address = Ed25519Address::new(hash.into()); - // Collect it. - addresses.push(address); + public_keys.push(public_key); } - Ok(addresses) + Ok(public_keys) } async fn generate_evm_addresses( @@ -589,12 +581,10 @@ mod tests { stronghold_adapter.clear_key().await; // Address generation returns an error when the key is cleared. - assert!( - stronghold_adapter - .generate_ed25519_addresses(IOTA_COIN_TYPE, 0, 0..1, None,) - .await - .is_err() - ); + assert!(stronghold_adapter + .generate_ed25519_addresses(IOTA_COIN_TYPE, 0, 0..1, None,) + .await + .is_err()); stronghold_adapter.set_password("drowssap".to_owned()).await.unwrap(); From 6f30d43c5858b9f80a0750c4e77deceae5f36f8d Mon Sep 17 00:00:00 2001 From: Thibault Martinez Date: Tue, 21 Nov 2023 09:36:52 +0100 Subject: [PATCH 2/2] Add doc --- sdk/src/client/secret/mod.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sdk/src/client/secret/mod.rs b/sdk/src/client/secret/mod.rs index 19fe7dc2c2..7293ccfd24 100644 --- a/sdk/src/client/secret/mod.rs +++ b/sdk/src/client/secret/mod.rs @@ -71,6 +71,8 @@ pub trait SecretManage: Send + Sync { type Error: std::error::Error + Send + Sync; /// Generates public keys. + /// + /// For `coin_type`, see also . async fn generate_ed25519_public_keys( &self, coin_type: u32,