diff --git a/Cargo.lock b/Cargo.lock index 74d6572b21be5b..32db743458d9a7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7010,9 +7010,12 @@ version = "2.2.0" dependencies = [ "bs58", "ed25519-dalek", + "ed25519-dalek-bip32", "rand 0.7.3", "serde_json", + "solana-derivation-path", "solana-pubkey", + "solana-seed-derivable", "solana-seed-phrase", "solana-signature", "solana-signer", @@ -8178,10 +8181,7 @@ checksum = "468aa43b7edb1f9b7b7b686d5c3aeb6630dc1708e86e31343499dd5c4d775183" name = "solana-seed-derivable" version = "2.2.0" dependencies = [ - "ed25519-dalek", - "ed25519-dalek-bip32", "solana-derivation-path", - "solana-keypair", ] [[package]] diff --git a/programs/sbf/Cargo.lock b/programs/sbf/Cargo.lock index 9637d41654dd78..d6f0641b191654 100644 --- a/programs/sbf/Cargo.lock +++ b/programs/sbf/Cargo.lock @@ -5544,8 +5544,11 @@ version = "2.2.0" dependencies = [ "bs58", "ed25519-dalek", + "ed25519-dalek-bip32", "rand 0.7.3", + "solana-derivation-path", "solana-pubkey", + "solana-seed-derivable", "solana-seed-phrase", "solana-signature", "solana-signer", @@ -6913,10 +6916,7 @@ checksum = "468aa43b7edb1f9b7b7b686d5c3aeb6630dc1708e86e31343499dd5c4d775183" name = "solana-seed-derivable" version = "2.2.0" dependencies = [ - "ed25519-dalek", - "ed25519-dalek-bip32", "solana-derivation-path", - "solana-keypair", ] [[package]] diff --git a/sdk/Cargo.toml b/sdk/Cargo.toml index 22ce22c441983e..762bc716ddaa2a 100644 --- a/sdk/Cargo.toml +++ b/sdk/Cargo.toml @@ -107,7 +107,7 @@ solana-frozen-abi-macro = { workspace = true, optional = true, features = [ ] } solana-inflation = { workspace = true, features = ["serde"] } solana-instruction = { workspace = true } -solana-keypair = { workspace = true, optional = true } +solana-keypair = { workspace = true, optional = true, features = ["seed-derivable"] } solana-native-token = { workspace = true } solana-packet = { workspace = true, features = ["bincode", "serde"] } solana-precompile-error = { workspace = true, optional = true } diff --git a/sdk/keypair/Cargo.toml b/sdk/keypair/Cargo.toml index 842fe0a5c47f48..dee76f0555a226 100644 --- a/sdk/keypair/Cargo.toml +++ b/sdk/keypair/Cargo.toml @@ -12,8 +12,11 @@ edition = { workspace = true } [dependencies] bs58 = { workspace = true, features = ["std"] } ed25519-dalek = { workspace = true } +ed25519-dalek-bip32 = { workspace = true, optional = true } rand0-7 = { workspace = true } +solana-derivation-path = { workspace = true, optional = true } solana-pubkey = { workspace = true } +solana-seed-derivable = { workspace = true, optional = true } solana-seed-phrase = { workspace = true } solana-signature = { workspace = true } solana-signer = { workspace = true } @@ -26,6 +29,9 @@ serde_json = { workspace = true } static_assertions = { workspace = true } tiny-bip39 = { workspace = true } +[features] +seed-derivable = ["dep:solana-derivation-path", "dep:solana-seed-derivable", "dep:ed25519-dalek-bip32"] + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] all-features = true diff --git a/sdk/keypair/src/lib.rs b/sdk/keypair/src/lib.rs index 36338af0a80bfa..08f9e2a5768bd2 100644 --- a/sdk/keypair/src/lib.rs +++ b/sdk/keypair/src/lib.rs @@ -16,6 +16,9 @@ use { }, }; +#[cfg(feature = "seed-derivable")] +pub mod seed_derivable; + /// A vanilla Ed25519 key pair #[cfg_attr(target_arch = "wasm32", wasm_bindgen)] #[derive(Debug)] diff --git a/sdk/keypair/src/seed_derivable.rs b/sdk/keypair/src/seed_derivable.rs new file mode 100644 index 00000000000000..4f530f41fc8acc --- /dev/null +++ b/sdk/keypair/src/seed_derivable.rs @@ -0,0 +1,53 @@ +//! Implementation of the SeedDerivable trait for Keypair + +use { + crate::{keypair_from_seed, keypair_from_seed_phrase_and_passphrase, Keypair}, + ed25519_dalek_bip32::Error as Bip32Error, + solana_derivation_path::DerivationPath, + solana_seed_derivable::SeedDerivable, + std::error, +}; + +impl SeedDerivable for Keypair { + fn from_seed(seed: &[u8]) -> Result> { + keypair_from_seed(seed) + } + + fn from_seed_and_derivation_path( + seed: &[u8], + derivation_path: Option, + ) -> Result> { + keypair_from_seed_and_derivation_path(seed, derivation_path) + } + + fn from_seed_phrase_and_passphrase( + seed_phrase: &str, + passphrase: &str, + ) -> Result> { + keypair_from_seed_phrase_and_passphrase(seed_phrase, passphrase) + } +} + +/// Generates a Keypair using Bip32 Hierarchical Derivation if derivation-path is provided; +/// otherwise generates the base Bip44 Solana keypair from the seed +pub fn keypair_from_seed_and_derivation_path( + seed: &[u8], + derivation_path: Option, +) -> Result> { + let derivation_path = derivation_path.unwrap_or_default(); + bip32_derived_keypair(seed, derivation_path).map_err(|err| err.to_string().into()) +} + +/// Generates a Keypair using Bip32 Hierarchical Derivation +fn bip32_derived_keypair( + seed: &[u8], + derivation_path: DerivationPath, +) -> Result { + let extended = ed25519_dalek_bip32::ExtendedSecretKey::from_seed(seed) + .and_then(|extended| extended.derive(&derivation_path))?; + let extended_public_key = extended.public_key(); + Ok(Keypair::from(ed25519_dalek::Keypair { + secret: extended.secret_key, + public: extended_public_key, + })) +} diff --git a/sdk/seed-derivable/Cargo.toml b/sdk/seed-derivable/Cargo.toml index 69e0eaa0e691c0..98acb4f9dd5184 100644 --- a/sdk/seed-derivable/Cargo.toml +++ b/sdk/seed-derivable/Cargo.toml @@ -10,10 +10,7 @@ license = { workspace = true } edition = { workspace = true } [dependencies] -ed25519-dalek = { workspace = true } -ed25519-dalek-bip32 = { workspace = true } solana-derivation-path = { workspace = true } -solana-keypair = { workspace = true } [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/sdk/seed-derivable/src/lib.rs b/sdk/seed-derivable/src/lib.rs index 99a39497d753a8..e9e34587ae7cc7 100644 --- a/sdk/seed-derivable/src/lib.rs +++ b/sdk/seed-derivable/src/lib.rs @@ -1,10 +1,5 @@ //! The interface by which keys are derived. -use { - ed25519_dalek_bip32::Error as Bip32Error, - solana_derivation_path::DerivationPath, - solana_keypair::{keypair_from_seed, keypair_from_seed_phrase_and_passphrase, Keypair}, - std::error, -}; +use {solana_derivation_path::DerivationPath, std::error}; /// The `SeedDerivable` trait defines the interface by which cryptographic keys/keypairs are /// derived from byte seeds, derivation paths, and passphrases. @@ -19,47 +14,3 @@ pub trait SeedDerivable: Sized { passphrase: &str, ) -> Result>; } - -impl SeedDerivable for Keypair { - fn from_seed(seed: &[u8]) -> Result> { - keypair_from_seed(seed) - } - - fn from_seed_and_derivation_path( - seed: &[u8], - derivation_path: Option, - ) -> Result> { - keypair_from_seed_and_derivation_path(seed, derivation_path) - } - - fn from_seed_phrase_and_passphrase( - seed_phrase: &str, - passphrase: &str, - ) -> Result> { - keypair_from_seed_phrase_and_passphrase(seed_phrase, passphrase) - } -} - -/// Generates a Keypair using Bip32 Hierarchical Derivation if derivation-path is provided; -/// otherwise generates the base Bip44 Solana keypair from the seed -pub fn keypair_from_seed_and_derivation_path( - seed: &[u8], - derivation_path: Option, -) -> Result> { - let derivation_path = derivation_path.unwrap_or_default(); - bip32_derived_keypair(seed, derivation_path).map_err(|err| err.to_string().into()) -} - -/// Generates a Keypair using Bip32 Hierarchical Derivation -fn bip32_derived_keypair( - seed: &[u8], - derivation_path: DerivationPath, -) -> Result { - let extended = ed25519_dalek_bip32::ExtendedSecretKey::from_seed(seed) - .and_then(|extended| extended.derive(&derivation_path))?; - let extended_public_key = extended.public_key(); - Ok(Keypair::from(ed25519_dalek::Keypair { - secret: extended.secret_key, - public: extended_public_key, - })) -} diff --git a/sdk/src/signer/keypair.rs b/sdk/src/signer/keypair.rs index c7e56aca47c4ee..3433931a7f95a7 100644 --- a/sdk/src/signer/keypair.rs +++ b/sdk/src/signer/keypair.rs @@ -1,7 +1,9 @@ #[deprecated(since = "2.2.0", note = "Use `solana-keypair` crate instead")] -pub use solana_keypair::*; -#[deprecated(since = "2.2.0", note = "Use `solana-seed-derivable` crate instead")] -pub use solana_seed_derivable::keypair_from_seed_and_derivation_path; +pub use solana_keypair::{ + keypair_from_seed, keypair_from_seed_phrase_and_passphrase, read_keypair, read_keypair_file, + seed_derivable::keypair_from_seed_and_derivation_path, write_keypair, write_keypair_file, + Keypair, +}; #[deprecated(since = "2.2.0", note = "Use `solana-seed-phrase` crate instead")] pub use solana_seed_phrase::generate_seed_from_seed_phrase_and_passphrase; #[deprecated(since = "2.2.0", note = "Use `solana-signer` crate instead")]