keyfork-mnemonic-util: add MnemonicBase::from_nonstandard_bytes
This commit is contained in:
parent
5d2309e301
commit
6a265ad203
|
@ -249,7 +249,10 @@ pub trait Format {
|
|||
let our_key = EphemeralSecret::random();
|
||||
let our_pubkey_mnemonic = Mnemonic::from_bytes(PublicKey::from(&our_key).as_bytes())?;
|
||||
let shared_secret = our_key.diffie_hellman(&PublicKey::from(their_pubkey));
|
||||
assert!(shared_secret.was_contributory(), bug!("shared secret might be insecure"));
|
||||
assert!(
|
||||
shared_secret.was_contributory(),
|
||||
bug!("shared secret might be insecure")
|
||||
);
|
||||
let hkdf = Hkdf::<Sha256>::new(None, shared_secret.as_bytes());
|
||||
|
||||
let mut shared_key_data = [0u8; 256 / 8];
|
||||
|
@ -289,12 +292,15 @@ pub trait Format {
|
|||
|
||||
// encrypt data
|
||||
let encrypted_bytes = shared_key.encrypt(nonce, plaintext_bytes.as_slice())?;
|
||||
assert_eq!(
|
||||
encrypted_bytes.len(),
|
||||
ENCRYPTED_LENGTH as usize,
|
||||
bug!("encrypted bytes size != expected len"),
|
||||
);
|
||||
let mut mnemonic_bytes = [0u8; ENCRYPTED_LENGTH as usize];
|
||||
mnemonic_bytes.copy_from_slice(&encrypted_bytes);
|
||||
|
||||
assert_eq!(encrypted_bytes.len(), ENCRYPTED_LENGTH as usize);
|
||||
|
||||
// safety: size of out_bytes is constant and always % 4 == 0
|
||||
let payload_mnemonic = unsafe { Mnemonic::from_raw_bytes(&encrypted_bytes) };
|
||||
dbg!(payload_mnemonic.words().len());
|
||||
let payload_mnemonic = Mnemonic::from_nonstandard_bytes(mnemonic_bytes);
|
||||
|
||||
#[cfg(feature = "qrcode")]
|
||||
{
|
||||
|
@ -515,7 +521,10 @@ pub fn remote_decrypt(w: &mut impl Write) -> Result<(), Box<dyn std::error::Erro
|
|||
);
|
||||
|
||||
let shared_secret = our_key.diffie_hellman(&PublicKey::from(pubkey));
|
||||
assert!(shared_secret.was_contributory(), bug!("shared secret might be insecure"));
|
||||
assert!(
|
||||
shared_secret.was_contributory(),
|
||||
bug!("shared secret might be insecure")
|
||||
);
|
||||
let hkdf = Hkdf::<Sha256>::new(None, shared_secret.as_bytes());
|
||||
|
||||
let mut shared_key_data = [0u8; 256 / 8];
|
||||
|
|
|
@ -8,7 +8,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||
input.read_line(&mut line)?;
|
||||
let decoded = smex::decode(line.trim())?;
|
||||
|
||||
let mnemonic = unsafe { Mnemonic::from_raw_bytes(&decoded) };
|
||||
let mnemonic = Mnemonic::from_raw_bytes(&decoded) ;
|
||||
|
||||
println!("{mnemonic}");
|
||||
|
||||
|
|
|
@ -125,6 +125,13 @@ impl Wordlist for English {
|
|||
}
|
||||
}
|
||||
|
||||
struct AssertValidMnemonicSize<const N: usize>;
|
||||
|
||||
impl<const N: usize> AssertValidMnemonicSize<N> {
|
||||
const OK_CHUNKS: () = assert!(N % 4 == 0, "bytes must be a length divisible by 4");
|
||||
const OK_SIZE: () = assert!(N <= 1024, "bytes must be less-or-equal 1024");
|
||||
}
|
||||
|
||||
/// A BIP-0039 mnemonic with reference to a [`Wordlist`].
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct MnemonicBase<W: Wordlist> {
|
||||
|
@ -276,7 +283,36 @@ where
|
|||
return Err(MnemonicGenerationError::InvalidByteLength(bit_count));
|
||||
}
|
||||
|
||||
Ok(unsafe { Self::from_raw_bytes(bytes) })
|
||||
Ok( Self::from_raw_bytes(bytes) )
|
||||
}
|
||||
|
||||
/// Generate a [`Mnemonic`] from the provided data and [`Wordlist`]. The data may be of a size
|
||||
/// of a factor of 4, up to 1024 bytes.
|
||||
///
|
||||
/// ```rust
|
||||
/// use keyfork_mnemonic_util::Mnemonic;
|
||||
/// let data = b"hello world!";
|
||||
/// let mnemonic = Mnemonic::from_nonstandard_bytes(*data);
|
||||
/// ```
|
||||
///
|
||||
/// If an invalid size is requested, the code will fail to compile:
|
||||
///
|
||||
/// ```rust,compile_fail
|
||||
/// use keyfork_mnemonic_util::Mnemonic;
|
||||
/// let mnemonic = Mnemonic::from_nonstandard_bytes([0u8; 53]);
|
||||
/// ```
|
||||
///
|
||||
/// ```rust,compile_fail
|
||||
/// use keyfork_mnemonic_util::Mnemonic;
|
||||
/// let mnemonic = Mnemonic::from_nonstandard_bytes([0u8; 1024 + 4]);
|
||||
/// ```
|
||||
pub fn from_nonstandard_bytes<const N: usize>(bytes: [u8; N]) -> MnemonicBase<W> {
|
||||
#[allow(clippy::let_unit_value)]
|
||||
{
|
||||
let () = AssertValidMnemonicSize::<N>::OK_CHUNKS;
|
||||
let () = AssertValidMnemonicSize::<N>::OK_SIZE;
|
||||
}
|
||||
Self::from_raw_bytes(&bytes)
|
||||
}
|
||||
|
||||
/// Generate a [`Mnemonic`] from the provided data and [`Wordlist`]. The data is expected to be
|
||||
|
@ -292,11 +328,12 @@ where
|
|||
/// 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
|
||||
///
|
||||
/// # Panics
|
||||
/// 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.
|
||||
/// == 0`. If the assumption is incorrect, code may panic. The
|
||||
/// [`MnemonicBase::from_nonstandard_bytes`] function may be used to generate entropy if the
|
||||
/// length of the data is known at compile-time.
|
||||
///
|
||||
/// # Examples
|
||||
/// ```rust
|
||||
|
@ -315,11 +352,10 @@ where
|
|||
/// // NOTE: Data is of invalid length, 31
|
||||
/// let data = b"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
|
||||
/// let mnemonic = unsafe { Mnemonic::from_raw_bytes(data.as_slice()) };
|
||||
/// let mnemonic_text = mnemonic.to_string();
|
||||
/// // NOTE: panic happens here
|
||||
/// let new_mnemonic = Mnemonic::from_str(&mnemonic_text).unwrap();
|
||||
/// ```
|
||||
pub unsafe fn from_raw_bytes(bytes: &[u8]) -> MnemonicBase<W> {
|
||||
pub fn from_raw_bytes(bytes: &[u8]) -> MnemonicBase<W> {
|
||||
assert!(bytes.len() % 4 == 0);
|
||||
assert!(bytes.len() <= 1024);
|
||||
MnemonicBase {
|
||||
data: bytes.to_vec(),
|
||||
marker: PhantomData,
|
||||
|
@ -520,12 +556,30 @@ mod tests {
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn can_do_up_to_1024_bits() {
|
||||
let entropy = &mut [0u8; 128];
|
||||
fn can_do_up_to_8192_bits() {
|
||||
let mut entropy = [0u8; 1024];
|
||||
let mut random = std::fs::File::open("/dev/urandom").unwrap();
|
||||
random.read_exact(&mut entropy[..]).unwrap();
|
||||
let mnemonic = unsafe { Mnemonic::from_raw_bytes(&entropy[..]) };
|
||||
let mnemonic = Mnemonic::from_nonstandard_bytes(entropy);
|
||||
let words = mnemonic.words();
|
||||
assert!(words.len() == 96);
|
||||
assert_eq!(words.len(), 768);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn fails_over_8192_bits() {
|
||||
let entropy = &mut [0u8; 1024 + 4];
|
||||
let mut random = std::fs::File::open("/dev/urandom").unwrap();
|
||||
random.read_exact(&mut entropy[..]).unwrap();
|
||||
let _mnemonic = Mnemonic::from_raw_bytes(&entropy[..]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn fails_over_invalid_size() {
|
||||
let entropy = &mut [0u8; 255];
|
||||
let mut random = std::fs::File::open("/dev/urandom").unwrap();
|
||||
random.read_exact(&mut entropy[..]).unwrap();
|
||||
let _mnemonic = Mnemonic::from_raw_bytes(&entropy[..]);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue