use crate::error::ErrorKind;
use failure::Error;
use std::fmt;
const ENTROPY_OFFSET: usize = 8;
#[derive(Debug, Copy, Clone)]
pub enum KeyPhraseType {
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 KeyPhraseType {
pub fn for_word_count(size: usize) -> Result<KeyPhraseType, Error> {
let keyphrase_type: KeyPhraseType = match size {
12 => KeyPhraseType::Words12,
15 => KeyPhraseType::Words15,
18 => KeyPhraseType::Words18,
21 => KeyPhraseType::Words21,
24 => KeyPhraseType::Words24,
_ => return Err(ErrorKind::InvalidWordLength(size).into()),
};
Ok(keyphrase_type)
}
pub fn for_key_size(size: usize) -> Result<KeyPhraseType, Error> {
let keyphrase_type: KeyPhraseType = match size {
128 => KeyPhraseType::Words12,
160 => KeyPhraseType::Words15,
192 => KeyPhraseType::Words18,
224 => KeyPhraseType::Words21,
256 => KeyPhraseType::Words24,
_ => return Err(ErrorKind::InvalidKeysize(size).into()),
};
Ok(keyphrase_type)
}
pub fn for_phrase(phrase: &str) -> Result<KeyPhraseType, Error> {
let word_count: usize = 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 KeyPhraseType {
fn default() -> KeyPhraseType {
KeyPhraseType::Words12
}
}
impl fmt::Display for KeyPhraseType {
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!(KeyPhraseType::Words12.word_count(), 12);
assert_eq!(KeyPhraseType::Words15.word_count(), 15);
assert_eq!(KeyPhraseType::Words18.word_count(), 18);
assert_eq!(KeyPhraseType::Words21.word_count(), 21);
assert_eq!(KeyPhraseType::Words24.word_count(), 24);
}
#[test]
fn entropy_bits() {
assert_eq!(KeyPhraseType::Words12.entropy_bits(), 128);
assert_eq!(KeyPhraseType::Words15.entropy_bits(), 160);
assert_eq!(KeyPhraseType::Words18.entropy_bits(), 192);
assert_eq!(KeyPhraseType::Words21.entropy_bits(), 224);
assert_eq!(KeyPhraseType::Words24.entropy_bits(), 256);
}
#[test]
fn checksum_bits() {
assert_eq!(KeyPhraseType::Words12.checksum_bits(), 4);
assert_eq!(KeyPhraseType::Words15.checksum_bits(), 5);
assert_eq!(KeyPhraseType::Words18.checksum_bits(), 6);
assert_eq!(KeyPhraseType::Words21.checksum_bits(), 7);
assert_eq!(KeyPhraseType::Words24.checksum_bits(), 8);
}
}