use std::fmt;
use failure::Error;
use crate::error::ErrorKind;
const ENTROPY_OFFSET: usize = 8;
#[derive(Debug, Copy, Clone)]
pub enum MnemonicType {
Words12 = (128 << ENTROPY_OFFSET) | 4,
Words15 = (160 << ENTROPY_OFFSET) | 5,
Words18 = (192 << ENTROPY_OFFSET) | 6,
Words21 = (224 << ENTROPY_OFFSET) | 7,
Words24 = (256 << ENTROPY_OFFSET) | 8,
}
impl MnemonicType {
pub fn for_word_count(size: usize) -> Result<MnemonicType, Error> {
let mnemonic_type = match size {
12 => MnemonicType::Words12,
15 => MnemonicType::Words15,
18 => MnemonicType::Words18,
21 => MnemonicType::Words21,
24 => MnemonicType::Words24,
_ => Err(ErrorKind::InvalidWordLength(size))?,
};
Ok(mnemonic_type)
}
pub fn for_key_size(size: usize) -> Result<MnemonicType, Error> {
let mnemonic_type = match size {
128 => MnemonicType::Words12,
160 => MnemonicType::Words15,
192 => MnemonicType::Words18,
224 => MnemonicType::Words21,
256 => MnemonicType::Words24,
_ => Err(ErrorKind::InvalidKeysize(size))?,
};
Ok(mnemonic_type)
}
pub fn for_phrase(phrase: &str) -> Result<MnemonicType, Error> {
let word_count = phrase.split(" ").count();
Self::for_word_count(word_count)
}
pub fn total_bits(&self) -> usize {
self.entropy_bits() + self.checksum_bits() as usize
}
pub fn entropy_bits(&self) -> usize {
(*self as usize) >> ENTROPY_OFFSET
}
pub fn checksum_bits(&self) -> u8 {
(*self as usize) as u8
}
pub fn word_count(&self) -> usize {
self.total_bits() / 11
}
}
impl Default for MnemonicType {
fn default() -> MnemonicType {
MnemonicType::Words12
}
}
impl fmt::Display for MnemonicType {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"{} words ({}bits)",
self.word_count(),
self.entropy_bits()
)
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn word_count() {
assert_eq!(MnemonicType::Words12.word_count(), 12);
assert_eq!(MnemonicType::Words15.word_count(), 15);
assert_eq!(MnemonicType::Words18.word_count(), 18);
assert_eq!(MnemonicType::Words21.word_count(), 21);
assert_eq!(MnemonicType::Words24.word_count(), 24);
}
#[test]
fn entropy_bits() {
assert_eq!(MnemonicType::Words12.entropy_bits(), 128);
assert_eq!(MnemonicType::Words15.entropy_bits(), 160);
assert_eq!(MnemonicType::Words18.entropy_bits(), 192);
assert_eq!(MnemonicType::Words21.entropy_bits(), 224);
assert_eq!(MnemonicType::Words24.entropy_bits(), 256);
}
#[test]
fn checksum_bits() {
assert_eq!(MnemonicType::Words12.checksum_bits(), 4);
assert_eq!(MnemonicType::Words15.checksum_bits(), 5);
assert_eq!(MnemonicType::Words18.checksum_bits(), 6);
assert_eq!(MnemonicType::Words21.checksum_bits(), 7);
assert_eq!(MnemonicType::Words24.checksum_bits(), 8);
}
}