Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add SecretManage::generate_ed25519_public_keys #1655

Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 40 additions & 34 deletions sdk/src/client/secret/ledger_nano.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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},
Expand Down Expand Up @@ -131,41 +134,44 @@ impl TryFrom<u8> 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<u32>,
options: impl Into<Option<GenerateAddressOptions>> + Send,
) -> Result<Vec<Ed25519Address>, 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<u32>,
_options: impl Into<Option<GenerateAddressOptions>> + Send,
) -> Result<Vec<ed25519::PublicKey>, 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(
Expand Down
16 changes: 5 additions & 11 deletions sdk/src/client/secret/mnemonic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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,
},
};

Expand All @@ -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<u32>,
options: impl Into<Option<GenerateAddressOptions>> + Send,
) -> Result<Vec<Ed25519Address>, Self::Error> {
) -> Result<Vec<ed25519::PublicKey>, Self::Error> {
let internal = options.into().map(|o| o.internal).unwrap_or_default();

Ok(address_indexes
Expand All @@ -59,13 +57,9 @@ impl SecretManage for MnemonicSecretManager {
let public_key = chain
.derive(&self.0.to_master_key::<ed25519::SecretKey>())
.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::<Result<_, _>>()?)
}
Expand Down
36 changes: 28 additions & 8 deletions sdk/src/client/secret/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -66,6 +70,15 @@ use crate::{
pub trait SecretManage: Send + Sync {
type Error: std::error::Error + Send + Sync;

/// Generates public keys.
Alex6323 marked this conversation as resolved.
Show resolved Hide resolved
async fn generate_ed25519_public_keys(
&self,
coin_type: u32,
account_index: u32,
address_indexes: Range<u32>,
options: impl Into<Option<GenerateAddressOptions>> + Send,
) -> Result<Vec<ed25519::PublicKey>, Self::Error>;

/// Generates addresses.
///
/// For `coin_type`, see also <https://github.com/satoshilabs/slips/blob/master/slip-0044.md>.
Expand All @@ -75,7 +88,14 @@ pub trait SecretManage: Send + Sync {
account_index: u32,
address_indexes: Range<u32>,
options: impl Into<Option<GenerateAddressOptions>> + Send,
) -> Result<Vec<Ed25519Address>, Self::Error>;
) -> Result<Vec<Ed25519Address>, 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,
Expand Down Expand Up @@ -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<u32>,
options: impl Into<Option<GenerateAddressOptions>> + Send,
) -> crate::client::Result<Vec<Ed25519Address>> {
) -> Result<Vec<ed25519::PublicKey>, 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),
Expand Down
15 changes: 4 additions & 11 deletions sdk/src/client/secret/private_key.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ use std::ops::Range;

use async_trait::async_trait;
use crypto::{
hashes::{blake2b::Blake2b256, Digest},
keys::bip44::Bip44,
signatures::{
ed25519,
Expand All @@ -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,
},
};

Expand All @@ -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<u32>,
_options: impl Into<Option<GenerateAddressOptions>> + Send,
) -> Result<Vec<Ed25519Address>, 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<Vec<ed25519::PublicKey>, Self::Error> {
crate::client::Result::Ok(vec![self.0.public_key()])
}

async fn generate_evm_addresses(
Expand Down
32 changes: 11 additions & 21 deletions sdk/src/client/stronghold/secret.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -36,22 +35,21 @@ use crate::{
stronghold::Error,
},
types::block::{
address::Ed25519Address, payload::signed_transaction::SignedTransactionPayload, signature::Ed25519Signature,
unlock::Unlocks,
payload::signed_transaction::SignedTransactionPayload, signature::Ed25519Signature, unlock::Unlocks,
},
};

#[async_trait]
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<u32>,
options: impl Into<Option<GenerateAddressOptions>> + Send,
) -> Result<Vec<Ed25519Address>, Self::Error> {
) -> Result<Vec<ed25519::PublicKey>, 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).
Expand All @@ -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 {
Expand Down Expand Up @@ -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(
Expand Down Expand Up @@ -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();

Expand Down
Loading