use rand::Rng;
use rand::distr::{Distribution, StandardUniform};
use bip39::{Mnemonic as Bip39Mnemonic, Language};
use finitelib::group::Group;
use crate::utils::*;
use crate::schema::Schema;
pub type Mnemonic = [String; 12];
pub struct Seed(Bip39Mnemonic);
impl Seed {
pub fn random<R: Rng>(rng: &mut R) -> Self {
rng.random()
}
pub fn from_value(value: &U256) -> Self {
let entropy: [u8; 16] = value.to_bytes()[..16].try_into().unwrap();
Self::from_entropy(&entropy)
}
pub fn from_mnemonic(mnemonic: &Mnemonic) -> Self {
let phrase = mnemonic.join(" ");
let bip93_mnemonic = Bip39Mnemonic::parse_normalized(&phrase).unwrap();
Self(bip93_mnemonic)
}
pub fn value(&self) -> U256 {
let entropy: [u8; 16] = self.0.to_entropy().try_into().unwrap();
u128::from_ne_bytes(entropy).into()
}
pub fn mnemonic(&self) -> Mnemonic {
self.0.words().take(12).map(|w| w.to_string())
.collect::<Vec<String>>().try_into().unwrap()
}
pub fn gen_keys(&self, schema: &Schema) -> impl Iterator<Item = U256> {
let curve = schema.curve();
let value = self.value();
let mut j = curve.generator.clone();
std::iter::from_fn(move || {
curve.mul_scalar_assign(&mut j, value.bit_iter());
let p = curve.convert_from(&j);
let key = &schema.point_to_number(&p) % &curve.base.order;
Some(key)
})
}
fn from_entropy(entropy: &[u8; 16]) -> Self {
let bip93_mnemonic = Bip39Mnemonic
::from_entropy_in(Language::English, entropy).unwrap();
Self(bip93_mnemonic)
}
}
impl Distribution<Seed> for StandardUniform {
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Seed {
let entropy: [u8; 16] = rng.random();
Seed::from_entropy(&entropy)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_seed() {
let schema = Schema::new();
let mut rng = rand::rng();
let seed: Seed = rng.random();
let mnemonic = seed.mnemonic();
let value = seed.value();
let seed_from_value = Seed::from_value(&value);
assert_eq!(seed_from_value.value(), value);
assert_eq!(seed_from_value.mnemonic(), mnemonic);
assert_eq!(seed_from_value.gen_keys(&schema).nth(3),
seed.gen_keys(&schema).nth(3));
let seed_from_mnemonic = Seed::from_mnemonic(&mnemonic);
assert_eq!(seed_from_mnemonic.value(), value);
assert_eq!(seed_from_mnemonic.mnemonic(), mnemonic);
assert_eq!(seed_from_mnemonic.gen_keys(&schema).nth(3),
seed.gen_keys(&schema).nth(3));
}
}