keyfork-mnemonic-util: deprecate from{_raw,}_bytes

This commit is contained in:
Ryan Heywood 2024-02-18 18:14:50 -05:00
parent 31e51f65a5
commit d481c7e164
Signed by: ryan
GPG Key ID: 8E401478A3FBEF72
6 changed files with 68 additions and 38 deletions

View File

@ -75,10 +75,10 @@ pub fn remote_decrypt(w: &mut impl Write) -> Result<(), Box<dyn std::error::Erro
iter += 1; iter += 1;
let nonce = Aes256Gcm::generate_nonce(&mut OsRng); let nonce = Aes256Gcm::generate_nonce(&mut OsRng);
let nonce_mnemonic = let nonce_mnemonic =
unsafe { Mnemonic::from_raw_entropy(nonce.as_slice(), Default::default()) }; unsafe { Mnemonic::from_raw_bytes(nonce.as_slice(), Default::default()) };
let our_key = EphemeralSecret::random(); let our_key = EphemeralSecret::random();
let key_mnemonic = let key_mnemonic =
Mnemonic::from_entropy(PublicKey::from(&our_key).as_bytes(), Default::default())?; Mnemonic::from_bytes(PublicKey::from(&our_key).as_bytes(), Default::default())?;
#[cfg(feature = "qrcode")] #[cfg(feature = "qrcode")]
{ {

View File

@ -515,7 +515,7 @@ pub fn decrypt(
let our_key = EphemeralSecret::random(); let our_key = EphemeralSecret::random();
let our_pubkey_mnemonic = let our_pubkey_mnemonic =
Mnemonic::from_entropy(PublicKey::from(&our_key).as_bytes(), Default::default())?; Mnemonic::from_bytes(PublicKey::from(&our_key).as_bytes(), Default::default())?;
let shared_secret = our_key.diffie_hellman(&PublicKey::from(pubkey)).to_bytes(); let shared_secret = our_key.diffie_hellman(&PublicKey::from(pubkey)).to_bytes();
@ -560,7 +560,7 @@ pub fn decrypt(
} }
// safety: size of out_bytes is constant and always % 4 == 0 // safety: size of out_bytes is constant and always % 4 == 0
let payload_mnemonic = unsafe { Mnemonic::from_raw_entropy(&out_bytes, Default::default()) }; let payload_mnemonic = unsafe { Mnemonic::from_raw_bytes(&out_bytes, Default::default()) };
#[cfg(feature = "qrcode")] #[cfg(feature = "qrcode")]
{ {

View File

@ -109,7 +109,7 @@ impl MnemonicSeedSource {
MnemonicSeedSource::Tarot => todo!(), MnemonicSeedSource::Tarot => todo!(),
MnemonicSeedSource::Dice => todo!(), MnemonicSeedSource::Dice => todo!(),
}; };
let mnemonic = keyfork_mnemonic_util::Mnemonic::from_entropy(&seed, Default::default())?; let mnemonic = keyfork_mnemonic_util::Mnemonic::from_bytes(&seed, Default::default())?;
Ok(mnemonic.to_string()) Ok(mnemonic.to_string())
} }
} }

View File

@ -90,7 +90,7 @@ pub struct Recover {
impl Recover { impl Recover {
pub fn handle(&self, _k: &Keyfork) -> Result<()> { pub fn handle(&self, _k: &Keyfork) -> Result<()> {
let seed = self.command.handle()?; let seed = self.command.handle()?;
let mnemonic = Mnemonic::from_entropy(&seed, Default::default())?; let mnemonic = Mnemonic::from_bytes(&seed, Default::default())?;
tokio::runtime::Builder::new_multi_thread() tokio::runtime::Builder::new_multi_thread()
.enable_all() .enable_all()
.build() .build()

View File

@ -8,7 +8,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
input.read_line(&mut line)?; input.read_line(&mut line)?;
let decoded = smex::decode(line.trim())?; let decoded = smex::decode(line.trim())?;
let mnemonic = unsafe { Mnemonic::from_raw_entropy(&decoded, Default::default()) }; let mnemonic = unsafe { Mnemonic::from_raw_bytes(&decoded, Default::default()) };
println!("{mnemonic}"); println!("{mnemonic}");

View File

@ -109,14 +109,14 @@ impl Wordlist {
/// A BIP-0039 mnemonic with reference to a [`Wordlist`]. /// A BIP-0039 mnemonic with reference to a [`Wordlist`].
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Mnemonic { pub struct Mnemonic {
entropy: Vec<u8>, data: Vec<u8>,
// words: Vec<usize>, // words: Vec<usize>,
wordlist: Arc<Wordlist>, wordlist: Arc<Wordlist>,
} }
impl PartialEq for Mnemonic { impl PartialEq for Mnemonic {
fn eq(&self, other: &Self) -> bool { fn eq(&self, other: &Self) -> bool {
self.entropy.eq(&other.entropy) self.data.eq(&other.data)
} }
} }
@ -124,18 +124,18 @@ 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.data.len() * 8;
let mut bits = vec![false; bit_count + bit_count / 32]; let mut bits = vec![false; bit_count + bit_count / 32];
for byte_index in 0..bit_count / 8 { for byte_index in 0..bit_count / 8 {
for bit_index in 0..8 { for bit_index in 0..8 {
bits[byte_index * 8 + bit_index] = bits[byte_index * 8 + bit_index] =
(self.entropy[byte_index] & (1 << (7 - bit_index))) > 0; (self.data[byte_index] & (1 << (7 - bit_index))) > 0;
} }
} }
let mut hasher = Sha256::new(); let mut hasher = Sha256::new();
hasher.update(&self.entropy); hasher.update(&self.data);
let hash = hasher.finalize().to_vec(); let hash = hasher.finalize().to_vec();
for check_bit in 0..bit_count / 32 { for check_bit in 0..bit_count / 32 {
bits[bit_count + check_bit] = (hash[check_bit / 8] & (1 << (7 - (check_bit % 8)))) > 0; bits[bit_count + check_bit] = (hash[check_bit / 8] & (1 << (7 - (check_bit % 8)))) > 0;
@ -223,7 +223,7 @@ impl FromStr for Mnemonic {
bits.truncate(bits.len() * 32 / 33); bits.truncate(bits.len() * 32 / 33);
// bits.truncate(bits.len() - bits.len() % 32); // bits.truncate(bits.len() - bits.len() % 32);
let entropy: Vec<u8> = bits let data: Vec<u8> = bits
.chunks_exact(8) .chunks_exact(8)
.map(|chunk| { .map(|chunk| {
let mut num = 0u8; let mut num = 0u8;
@ -235,7 +235,7 @@ impl FromStr for Mnemonic {
.collect(); .collect();
let mut hasher = Sha256::new(); let mut hasher = Sha256::new();
hasher.update(&entropy); hasher.update(&data);
let hash = hasher.finalize().to_vec(); let hash = hasher.finalize().to_vec();
for (i, bit) in checksum_bits.iter().enumerate() { for (i, bit) in checksum_bits.iter().enumerate() {
@ -245,7 +245,7 @@ impl FromStr for Mnemonic {
} }
Ok(Mnemonic { Ok(Mnemonic {
entropy, data,
// words: usize_words, // words: usize_words,
wordlist, wordlist,
}) })
@ -253,18 +253,19 @@ impl FromStr for Mnemonic {
} }
impl Mnemonic { impl Mnemonic {
/// Generate a [`Mnemonic`] from the provided entropy and [`Wordlist`]. /// Generate a [`Mnemonic`] from the provided data and [`Wordlist`]. The data is expected to be
/// of 128, 192, or 256 bits, as per BIP-0039.
/// ///
/// # Errors /// # Errors
/// An error may be returned if the entropy is not within the acceptable lengths. /// An error may be returned if the data is not within the expected lengths.
/// ///
/// # Examples /// # Examples
/// ```rust /// ```rust
/// use keyfork_mnemonic_util::Mnemonic; /// use keyfork_mnemonic_util::Mnemonic;
/// let data = b"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"; /// let data = b"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
/// let mnemonic = Mnemonic::from_entropy(data.as_slice(), Default::default()).unwrap(); /// let mnemonic = Mnemonic::from_bytes(data.as_slice(), Default::default()).unwrap();
/// ``` /// ```
pub fn from_entropy( pub fn from_bytes(
bytes: &[u8], bytes: &[u8],
wordlist: Arc<Wordlist>, wordlist: Arc<Wordlist>,
) -> Result<Mnemonic, MnemonicGenerationError> { ) -> Result<Mnemonic, MnemonicGenerationError> {
@ -278,11 +279,24 @@ impl Mnemonic {
return Err(MnemonicGenerationError::InvalidByteLength(bit_count)); return Err(MnemonicGenerationError::InvalidByteLength(bit_count));
} }
Ok(unsafe { Self::from_raw_entropy(bytes, wordlist) }) Ok(unsafe { Self::from_raw_bytes(bytes, wordlist) })
} }
/// Create a Mnemonic using an arbitrary length of given entropy. The length does not need to /// Generate a [`Mnemonic`] from the provided data and [`Wordlist`]. The data is expected to be
/// conform to BIP-0039 standards. /// of 128, 192, or 256 bits, as per BIP-0039.
///
/// # Errors
/// An error may be returned if the data is not within the expected lengths.
#[deprecated = "use Mnemonic::from_bytes"]
pub fn from_entropy(
bytes: &[u8],
wordlist: Arc<Wordlist>,
) -> Result<Mnemonic, MnemonicGenerationError> {
Mnemonic::from_bytes(bytes, wordlist)
}
/// Create a Mnemonic using an arbitrary length of given data. The length does not need to
/// conform to BIP-0039 standards, but should be a multiple of 32 bits or 4 bytes.
/// ///
/// # Safety /// # Safety
/// ///
@ -294,7 +308,7 @@ impl Mnemonic {
/// ```rust /// ```rust
/// use keyfork_mnemonic_util::Mnemonic; /// use keyfork_mnemonic_util::Mnemonic;
/// let data = b"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"; /// let data = b"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
/// let mnemonic = unsafe { Mnemonic::from_raw_entropy(data.as_slice(), Default::default()) }; /// let mnemonic = unsafe { Mnemonic::from_raw_bytes(data.as_slice(), Default::default()) };
/// let mnemonic_text = mnemonic.to_string(); /// let mnemonic_text = mnemonic.to_string();
/// ``` /// ```
/// ///
@ -306,37 +320,53 @@ impl Mnemonic {
/// ///
/// // NOTE: Data is of invalid length, 31 /// // NOTE: Data is of invalid length, 31
/// let data = b"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"; /// let data = b"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
/// let mnemonic = unsafe { Mnemonic::from_raw_entropy(data.as_slice(), Default::default()) }; /// let mnemonic = unsafe { Mnemonic::from_raw_bytes(data.as_slice(), Default::default()) };
/// let mnemonic_text = mnemonic.to_string(); /// let mnemonic_text = mnemonic.to_string();
/// // NOTE: panic happens here /// // NOTE: panic happens here
/// let new_mnemonic = Mnemonic::from_str(&mnemonic_text).unwrap(); /// let new_mnemonic = Mnemonic::from_str(&mnemonic_text).unwrap();
/// ``` /// ```
pub unsafe fn from_raw_bytes(bytes: &[u8], wordlist: Arc<Wordlist>) -> Mnemonic {
Mnemonic {
data: bytes.to_vec(),
wordlist,
}
}
/// Create a Mnemonic using an arbitrary length of given data. The length does not need to
/// conform to BIP-0039 standards, but should be a multiple of 32 bits or 4 bytes.
///
/// # Safety
///
/// This function can potentially produce mnemonics that are not BIP-0039 compliant or can't
/// properly be encoded as a mnemonic. It is assumed the caller asserts the byte count is `% 4
/// == 0`. If the assumption is incorrect, code may panic.
#[deprecated = "use Mnemonic::from_raw_bytes"]
pub unsafe fn from_raw_entropy(bytes: &[u8], wordlist: Arc<Wordlist>) -> Mnemonic{ pub unsafe fn from_raw_entropy(bytes: &[u8], wordlist: Arc<Wordlist>) -> Mnemonic{
Mnemonic { Mnemonic {
entropy: bytes.to_vec(), data: bytes.to_vec(),
wordlist, wordlist,
} }
} }
/// A view to internal representation of the decoded data. /// A view to internal representation of the decoded data.
pub fn as_bytes(&self) -> &[u8] { pub fn as_bytes(&self) -> &[u8] {
&self.entropy &self.data
} }
/// A clone of the internal representation of the decoded data. /// A clone of the internal representation of the decoded data.
pub fn to_bytes(&self) -> Vec<u8> { pub fn to_bytes(&self) -> Vec<u8> {
self.entropy.to_vec() self.data.to_vec()
} }
/// Conver the Mnemonic into the internal representation of the decoded data. /// Conver the Mnemonic into the internal representation of the decoded data.
pub fn into_bytes(self) -> Vec<u8> { pub fn into_bytes(self) -> Vec<u8> {
self.entropy self.data
} }
/// Clone the existing data. /// Clone the existing data.
#[deprecated = "Use as_bytes(), to_bytes(), or into_bytes() instead"] #[deprecated = "Use as_bytes(), to_bytes(), or into_bytes() instead"]
pub fn entropy(&self) -> Vec<u8> { pub fn entropy(&self) -> Vec<u8> {
self.entropy.clone() self.data.clone()
} }
/// 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.
@ -371,18 +401,18 @@ impl Mnemonic {
/// Encode the mnemonic into a list of integers 11 bits in length, matching the length of a /// Encode the mnemonic into a list of integers 11 bits in length, matching the length of a
/// BIP-0039 wordlist. /// 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.data.len() * 8;
let mut bits = vec![false; bit_count + bit_count / 32]; let mut bits = vec![false; bit_count + bit_count / 32];
for byte_index in 0..bit_count / 8 { for byte_index in 0..bit_count / 8 {
for bit_index in 0..8 { for bit_index in 0..8 {
bits[byte_index * 8 + bit_index] = bits[byte_index * 8 + bit_index] =
(self.entropy[byte_index] & (1 << (7 - bit_index))) > 0; (self.data[byte_index] & (1 << (7 - bit_index))) > 0;
} }
} }
let mut hasher = Sha256::new(); let mut hasher = Sha256::new();
hasher.update(&self.entropy); hasher.update(&self.data);
let hash = hasher.finalize().to_vec(); let hash = hasher.finalize().to_vec();
for check_bit in 0..bit_count / 32 { for check_bit in 0..bit_count / 32 {
bits[bit_count + check_bit] = (hash[check_bit / 8] & (1 << (7 - (check_bit % 8)))) > 0; bits[bit_count + check_bit] = (hash[check_bit / 8] & (1 << (7 - (check_bit % 8)))) > 0;
@ -421,7 +451,7 @@ mod tests {
let entropy = &mut [0u8; 256 / 8]; let entropy = &mut [0u8; 256 / 8];
random_handle.read_exact(&mut entropy[..]).unwrap(); random_handle.read_exact(&mut entropy[..]).unwrap();
let wordlist = Wordlist::default().arc(); let wordlist = Wordlist::default().arc();
let mnemonic = super::Mnemonic::from_entropy(&entropy[..256 / 8], wordlist).unwrap(); let mnemonic = super::Mnemonic::from_bytes(&entropy[..256 / 8], wordlist).unwrap();
let new_entropy = mnemonic.as_bytes(); let new_entropy = mnemonic.as_bytes();
assert_eq!(new_entropy, entropy); assert_eq!(new_entropy, entropy);
} }
@ -438,7 +468,7 @@ mod tests {
}; };
let hex = hex::decode(hex_.as_str().unwrap()).unwrap(); let hex = hex::decode(hex_.as_str().unwrap()).unwrap();
let mnemonic = Mnemonic::from_entropy(&hex, wordlist.clone()).unwrap(); let mnemonic = Mnemonic::from_bytes(&hex, wordlist.clone()).unwrap();
assert_eq!(mnemonic.to_string(), seed.as_str().unwrap()); assert_eq!(mnemonic.to_string(), seed.as_str().unwrap());
} }
@ -450,7 +480,7 @@ mod tests {
let entropy = &mut [0u8; 256 / 8]; let entropy = &mut [0u8; 256 / 8];
random_handle.read_exact(&mut entropy[..]).unwrap(); random_handle.read_exact(&mut entropy[..]).unwrap();
let wordlist = Wordlist::default().arc(); let wordlist = Wordlist::default().arc();
let my_mnemonic = super::Mnemonic::from_entropy(&entropy[..256 / 8], wordlist).unwrap(); let my_mnemonic = super::Mnemonic::from_bytes(&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.generate_seed(None), their_mnemonic.to_seed("")); assert_eq!(my_mnemonic.generate_seed(None), their_mnemonic.to_seed(""));
@ -475,7 +505,7 @@ mod tests {
for _ in 0..tests { for _ in 0..tests {
random.read_exact(&mut entropy[..]).unwrap(); random.read_exact(&mut entropy[..]).unwrap();
let mnemonic = Mnemonic::from_entropy(&entropy[..256 / 8], wordlist.clone()).unwrap(); let mnemonic = Mnemonic::from_bytes(&entropy[..256 / 8], wordlist.clone()).unwrap();
let (words, _) = mnemonic.words(); let (words, _) = mnemonic.words();
hs.clear(); hs.clear();
hs.extend(words); hs.extend(words);
@ -507,7 +537,7 @@ mod tests {
let wordlist = Wordlist::default().arc(); let wordlist = Wordlist::default().arc();
let mut random = std::fs::File::open("/dev/urandom").unwrap(); let mut random = std::fs::File::open("/dev/urandom").unwrap();
random.read_exact(&mut entropy[..]).unwrap(); random.read_exact(&mut entropy[..]).unwrap();
let mnemonic = unsafe { Mnemonic::from_raw_entropy(&entropy[..], wordlist.clone()) }; let mnemonic = unsafe { Mnemonic::from_raw_bytes(&entropy[..], wordlist.clone()) };
let (words, _) = mnemonic.words(); let (words, _) = mnemonic.words();
assert!(words.len() == 96); assert!(words.len() == 96);
} }