keyfork-mnemonic-util: deprecate seed() in favor of generate_seed()

This commit is contained in:
Ryan Heywood 2024-02-18 18:01:18 -05:00
parent 9cb953414f
commit 883e0cdf65
Signed by: ryan
GPG Key ID: 8E401478A3FBEF72
3 changed files with 35 additions and 11 deletions

View File

@ -57,7 +57,7 @@ pub async fn start_and_run_server_on(
let service = ServiceBuilder::new() let service = ServiceBuilder::new()
.layer(middleware::BincodeLayer::new()) .layer(middleware::BincodeLayer::new())
// TODO: passphrase support and/or store passphrase with mnemonic // TODO: passphrase support and/or store passphrase with mnemonic
.service(Keyforkd::new(mnemonic.seed(None)?)); .service(Keyforkd::new(mnemonic.generate_seed(None)));
let mut server = match UnixServer::bind(socket_path) { let mut server = match UnixServer::bind(socket_path) {
Ok(s) => s, Ok(s) => s,

View File

@ -209,7 +209,7 @@ impl DerivationRequest {
/// # } /// # }
pub fn derive_with_mnemonic(&self, mnemonic: &Mnemonic) -> Result<DerivationResponse> { pub fn derive_with_mnemonic(&self, mnemonic: &Mnemonic) -> Result<DerivationResponse> {
// TODO: passphrase support and/or store passphrase within mnemonic // TODO: passphrase support and/or store passphrase within mnemonic
self.derive_with_master_seed(&mnemonic.seed(None)?) self.derive_with_master_seed(&mnemonic.generate_seed(None))
} }
/// Derive an [`ExtendedPrivateKey`] using the given seed. /// Derive an [`ExtendedPrivateKey`] using the given seed.

View File

@ -1,6 +1,11 @@
//! Zero-dependency Mnemonic encoding and decoding. //! Zero-dependency Mnemonic encoding and decoding.
use std::{error::Error, fmt::Display, str::FromStr, sync::Arc}; use std::{
error::Error,
fmt::Display,
str::FromStr,
sync::{Arc, OnceLock},
};
use hmac::Hmac; use hmac::Hmac;
use pbkdf2::pbkdf2; use pbkdf2::pbkdf2;
@ -96,6 +101,14 @@ pub struct Mnemonic {
wordlist: Arc<Wordlist>, wordlist: Arc<Wordlist>,
} }
impl PartialEq for Mnemonic {
fn eq(&self, other: &Self) -> bool {
self.entropy.eq(&other.entropy)
}
}
impl Eq for Mnemonic {}
impl Display for Mnemonic { impl Display for Mnemonic {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let bit_count = self.entropy.len() * 8; let bit_count = self.entropy.len() * 8;
@ -316,23 +329,34 @@ impl Mnemonic {
/// Create a BIP-0032 seed from the provided data and an optional passphrase. /// Create a BIP-0032 seed from the provided data and an optional passphrase.
/// ///
/// # Errors /// # Errors
/// The method may return an error if the pbkdf2 function returns an invalid length, but this /// The method should not return an error.
/// case should not be reached. #[deprecated = "Use generate_seed() instead"]
pub fn seed<'a>( pub fn seed<'a>(
&self, &self,
passphrase: impl Into<Option<&'a str>>, passphrase: impl Into<Option<&'a str>>,
) -> Result<Vec<u8>, MnemonicGenerationError> { ) -> Result<Vec<u8>, MnemonicGenerationError> {
Ok(self.generate_seed(passphrase))
}
/// Create a BIP-0032 seed from the provided data and an optional passphrase.
///
/// # Panics
/// The function may panic if the HmacSha512 function returns an error. The only error the
/// HmacSha512 function should return is an invalid length, which should not be possible.
///
pub fn generate_seed<'a>(&self, passphrase: impl Into<Option<&'a str>>) -> Vec<u8> {
let passphrase = passphrase.into(); let passphrase = passphrase.into();
let mut seed = [0u8; 64]; let mut seed = [0u8; 64];
let mnemonic = self.to_string(); let mnemonic = self.to_string();
let salt = ["mnemonic", passphrase.unwrap_or("")].join(""); let salt = ["mnemonic", passphrase.unwrap_or("")].join("");
pbkdf2::<Hmac<Sha512>>(mnemonic.as_bytes(), salt.as_bytes(), 2048, &mut seed) pbkdf2::<Hmac<Sha512>>(mnemonic.as_bytes(), salt.as_bytes(), 2048, &mut seed)
.map_err(|_| MnemonicGenerationError::InvalidPbkdf2Length)?; .expect("HmacSha512 InvalidLength should be infallible");
Ok(seed.to_vec()) seed.to_vec()
} }
/// Encode the mnemonic into a list of wordlist indexes. /// Encode the mnemonic into a list of integers 11 bits in length, matching the length of a
/// BIP-0039 wordlist.
pub fn words(self) -> (Vec<usize>, Arc<Wordlist>) { pub fn words(self) -> (Vec<usize>, Arc<Wordlist>) {
let bit_count = self.entropy.len() * 8; let bit_count = self.entropy.len() * 8;
let mut bits = vec![false; bit_count + bit_count / 32]; let mut bits = vec![false; bit_count + bit_count / 32];
@ -416,13 +440,13 @@ mod tests {
let my_mnemonic = super::Mnemonic::from_entropy(&entropy[..256 / 8], wordlist).unwrap(); let my_mnemonic = super::Mnemonic::from_entropy(&entropy[..256 / 8], wordlist).unwrap();
let their_mnemonic = bip39::Mnemonic::from_entropy(&entropy[..256 / 8]).unwrap(); let their_mnemonic = bip39::Mnemonic::from_entropy(&entropy[..256 / 8]).unwrap();
assert_eq!(my_mnemonic.to_string(), their_mnemonic.to_string()); assert_eq!(my_mnemonic.to_string(), their_mnemonic.to_string());
assert_eq!(my_mnemonic.seed(None).unwrap(), their_mnemonic.to_seed("")); assert_eq!(my_mnemonic.generate_seed(None), their_mnemonic.to_seed(""));
assert_eq!( assert_eq!(
my_mnemonic.seed("testing").unwrap(), my_mnemonic.generate_seed("testing"),
their_mnemonic.to_seed("testing") their_mnemonic.to_seed("testing")
); );
assert_ne!( assert_ne!(
my_mnemonic.seed("test1").unwrap(), my_mnemonic.generate_seed("test1"),
their_mnemonic.to_seed("test2") their_mnemonic.to_seed("test2")
); );
} }