#[cfg(not(feature = "std"))]
use alloc::string::String;
use sha2::{Digest, Sha256};
use super::{BITS_PER_BYTE, BITS_PER_WORD, BitAccumulator, Count};
use crate::{
error::Error,
language::{AnyLanguage, Language},
};
pub fn encode_entropy<L: Language>(entropy: &[u8]) -> Result<String, Error> {
encode_entropy_with(AnyLanguage::of::<L>(), entropy)
}
pub fn encode_entropy_with(language: AnyLanguage, entropy: &[u8]) -> Result<String, Error> {
let count = Count::from_key_size(entropy.len() * BITS_PER_BYTE)?;
let checksum_byte = Sha256::digest(entropy)[0];
let checksum_bit_length = count.checksum_bit_length();
let mut phrase = {
let words = count.word_count();
let rough_phrase_cap = words * 8 + (words.saturating_sub(1));
String::with_capacity(rough_phrase_cap)
};
let mut accumulator = BitAccumulator::new();
let push_index = |idx: usize, phrase: &mut String| {
if !phrase.is_empty() {
phrase.push(' ');
}
phrase.push_str(language.word_of(idx));
};
for &b in entropy {
accumulator.push_bits(b as u64, BITS_PER_BYTE);
while accumulator.can_take(BITS_PER_WORD) {
let index = accumulator.take_bits(BITS_PER_WORD) as usize;
push_index(index, &mut phrase);
}
}
{
let checksum_bits = checksum_byte >> (BITS_PER_BYTE - checksum_bit_length);
accumulator.push_bits(checksum_bits as u64, checksum_bit_length);
while accumulator.can_take(BITS_PER_WORD) {
let index = accumulator.take_bits(BITS_PER_WORD) as usize;
push_index(index, &mut phrase);
}
}
debug_assert_eq!(
accumulator.bits(),
0,
"entropy + checksum bits not exhausted during encoding"
);
Ok(phrase)
}