wordlists 0.2.0

Take bits, give words.
Documentation
//! Wordlists is a set of functionality and abstractions for turning binary into lists of UTF-8
//! english (for now) words.
//!
//! This wordlists package has been implemented to fill a purpose for me; to generate a
//! printable list of words for building a hard-copy of some sort of binary data (certificates,
//! base64 encoded keys, etc). But because this functionality is fairly generic, I've pulled it
//! out into a separate package.
//!
//! Some wordlists have different licensing potentially. Take this in mind when enabling their
//! feature-flags as they may pull in other requirements. For me, I am not using this in any
//! public way, just as a personal project; but feel free to yell at me if I did something stupid.
//!

#![deny(missing_docs)]

use bitvec::prelude::*;
use thiserror::Error;

// General Library usage.
mod bits;

// High-level types of word-lists. These are always present types.
mod types;
pub use types::*;

// Implementations, which are exported from here if enabled.
mod gen;
use crate::bits::index_width;
pub use gen::*;

/// The set of possible error which this crate will emit. We should not be emitting
/// IO issues or generic panics as we should conform to the Result type structure.
#[derive(Error, Debug)]
pub enum WordlistError {
    /// Given an indexed wordlist, the index is out of bounds.
    #[error("Index `{0}` is out of bounds (`{1}`).")]
    IndexOutOfBounds(usize, usize), // (index given, size bound)

    /// If the indexed wordlist should have had a value but could not be unwrapped.
    /// This may happen if there was a problem pulling in the wordlist at compile-time.
    #[error("Wordlist is potentially incomplete as unable to index into it.")]
    WordlistIsIncomplete,

    /// The word given is invalid, and not part of the wordlist.
    #[error("The given word ('{0}') is not known to the given wordlist.")]
    InvalidWord(String),

    /// If the wordlist is not a safely index-able length (i.e. not of size 2^N).
    #[error("The wordlist has an invalid size ('{0}').")]
    InvalidWordlistSize(usize),
}

/// Simple Result type wrapper with the WordlistError as the error type.
pub type Result<T> = std::result::Result<T, WordlistError>;

/// A Vector of words is a vector of static string references into the backing wordlist.
pub type WordVec = std::vec::Vec<&'static str>;

/// A wordlist byte-converter is a utility that can convert bits/bytes into sets of words.
pub trait WordlistByteConverter {
    /// Convert a list of bits into a list of words.
    ///
    /// This can fail if the wordlist was loaded incorrectly at compile-time or if
    /// indexing fails for some unexpected reason.
    fn to_words(&self, bytes: &BitVec) -> Result<WordVec>;

    /// Convert a list of words into a list of bits.
    ///
    /// This can fail if the words in the list are not present in the wordlist; or there
    /// is some issue packing the indexes as binary for some unexpected reason.
    fn to_bytes(&self, words: &WordVec) -> Result<BitVec>;
}

/// A wordlist is pretty simply one or more lists of words. We can
pub trait Wordlist {
    /// The name of this Wordlist.
    fn name(&self) -> &String;

    /// The length of the wordlist. If this wordlist describes multiple lists,
    /// this will be one more than the highest acceptable index.
    fn size(&self) -> usize;

    /// Check whether the given word exists in this Wordlist.
    fn contains(&self, word: &str) -> bool;

    /// Get the number of bits required to index into this wordlist. This may fail if the length of
    /// the wordlist is not a valid one for indexing into.
    fn index_bit_width(&self) -> Result<usize> {
        index_width(self.size())
    }

    /// Confirm all words in the given list exist in this wordlist.
    fn validate_word_list(&self, possible_words: &Vec<String>) -> bool {
        possible_words.iter().all(|v| self.contains(v))
    }
}