base_d/wordlists/
mod.rs

1//! Built-in word lists for word-based encoding.
2//!
3//! Currently includes:
4//! - BIP-39 English (2048 words)
5//! - EFF Long (7776 words)
6//! - EFF Short 1 (1296 words)
7//! - EFF Short 2 (1296 words)
8//! - Diceware (7776 words)
9//! - PGP Even (256 words, 2-syllable)
10//! - PGP Odd (256 words, 3-syllable)
11
12use crate::core::word_dictionary::WordDictionary;
13
14/// The BIP-39 English word list (2048 words).
15/// Used for cryptocurrency seed phrases. Each word encodes 11 bits.
16pub const BIP39_ENGLISH: &str = include_str!("bip39-english.txt");
17
18/// The EFF Long word list (7776 words).
19/// Improved diceware list with longer, more memorable words.
20pub const EFF_LONG: &str = include_str!("eff-long.txt");
21
22/// The EFF Short word list #1 (1296 words).
23/// Shorter words, 4 dice rolls per word.
24pub const EFF_SHORT1: &str = include_str!("eff-short1.txt");
25
26/// The EFF Short word list #2 (1296 words).
27/// Longer memorable words, 4 dice rolls per word.
28pub const EFF_SHORT2: &str = include_str!("eff-short2.txt");
29
30/// The original Diceware word list (7776 words).
31/// Classic passphrase generation list by Arnold Reinhold.
32pub const DICEWARE: &str = include_str!("diceware.txt");
33
34/// PGP word list - even positions (256 words, 2-syllable).
35/// Used for fingerprint verification.
36pub const PGP_EVEN: &str = include_str!("pgp-even.txt");
37
38/// PGP word list - odd positions (256 words, 3-syllable).
39/// Used for fingerprint verification.
40pub const PGP_ODD: &str = include_str!("pgp-odd.txt");
41
42/// Creates a WordDictionary from the built-in BIP-39 English word list.
43///
44/// # Example
45///
46/// ```
47/// use base_d::wordlists::bip39_english;
48/// use base_d::word;
49///
50/// let dict = bip39_english();
51/// assert_eq!(dict.base(), 2048);
52///
53/// let encoded = word::encode(b"hello", &dict);
54/// let decoded = word::decode(&encoded, &dict).unwrap();
55/// assert_eq!(decoded, b"hello");
56/// ```
57pub fn bip39_english() -> WordDictionary {
58    WordDictionary::builder()
59        .words_from_str(BIP39_ENGLISH)
60        .delimiter(" ")
61        .case_sensitive(false)
62        .build()
63        .expect("BIP-39 English word list should be valid")
64}
65
66/// Creates a WordDictionary from the EFF Long word list (7776 words).
67pub fn eff_long() -> WordDictionary {
68    WordDictionary::builder()
69        .words_from_str(EFF_LONG)
70        .delimiter(" ")
71        .case_sensitive(false)
72        .build()
73        .expect("EFF Long word list should be valid")
74}
75
76/// Creates a WordDictionary from the EFF Short word list #1 (1296 words).
77pub fn eff_short1() -> WordDictionary {
78    WordDictionary::builder()
79        .words_from_str(EFF_SHORT1)
80        .delimiter(" ")
81        .case_sensitive(false)
82        .build()
83        .expect("EFF Short 1 word list should be valid")
84}
85
86/// Creates a WordDictionary from the EFF Short word list #2 (1296 words).
87pub fn eff_short2() -> WordDictionary {
88    WordDictionary::builder()
89        .words_from_str(EFF_SHORT2)
90        .delimiter(" ")
91        .case_sensitive(false)
92        .build()
93        .expect("EFF Short 2 word list should be valid")
94}
95
96/// Creates a WordDictionary from the Diceware word list (7776 words).
97pub fn diceware() -> WordDictionary {
98    WordDictionary::builder()
99        .words_from_str(DICEWARE)
100        .delimiter(" ")
101        .case_sensitive(false)
102        .build()
103        .expect("Diceware word list should be valid")
104}
105
106/// Creates a WordDictionary from the PGP even (2-syllable) word list (256 words).
107pub fn pgp_even() -> WordDictionary {
108    WordDictionary::builder()
109        .words_from_str(PGP_EVEN)
110        .delimiter("-")
111        .case_sensitive(false)
112        .build()
113        .expect("PGP Even word list should be valid")
114}
115
116/// Creates a WordDictionary from the PGP odd (3-syllable) word list (256 words).
117pub fn pgp_odd() -> WordDictionary {
118    WordDictionary::builder()
119        .words_from_str(PGP_ODD)
120        .delimiter("-")
121        .case_sensitive(false)
122        .build()
123        .expect("PGP Odd word list should be valid")
124}
125
126#[cfg(test)]
127mod tests {
128    use super::*;
129
130    #[test]
131    fn test_bip39_english_word_count() {
132        let dict = bip39_english();
133        assert_eq!(dict.base(), 2048);
134    }
135
136    #[test]
137    fn test_bip39_english_first_word() {
138        let dict = bip39_english();
139        assert_eq!(dict.encode_word(0), Some("abandon"));
140    }
141
142    #[test]
143    fn test_bip39_english_last_word() {
144        let dict = bip39_english();
145        assert_eq!(dict.encode_word(2047), Some("zoo"));
146    }
147
148    #[test]
149    fn test_bip39_english_roundtrip() {
150        use crate::encoders::algorithms::word;
151
152        let dict = bip39_english();
153        let data = b"The quick brown fox jumps over the lazy dog";
154        let encoded = word::encode(data, &dict);
155        let decoded = word::decode(&encoded, &dict).unwrap();
156        assert_eq!(decoded, data);
157    }
158
159    #[test]
160    fn test_bip39_english_case_insensitive() {
161        let dict = bip39_english();
162        assert_eq!(dict.decode_word("abandon"), Some(0));
163        assert_eq!(dict.decode_word("ABANDON"), Some(0));
164        assert_eq!(dict.decode_word("Abandon"), Some(0));
165    }
166}