bip39/mnemonic_type.rs
1use error::ErrorKind;
2use failure::Error;
3use std::fmt;
4
5const ENTROPY_OFFSET: usize = 8;
6
7/// Determines the number of words that will be present in a [`Mnemonic`][Mnemonic] phrase
8///
9/// Also directly affects the amount of entropy that will be used to create a [`Mnemonic`][Mnemonic],
10/// and therefore the cryptographic strength of the HD wallet keys/addresses that can be derived from
11/// it using the [`Seed`][Seed].
12///
13/// For example, a 12 word mnemonic phrase is essentially a friendly representation of a 128-bit key,
14/// while a 24 word mnemonic phrase is essentially a 256-bit key.
15///
16/// If you know you want a specific phrase length, you can use the enum variant directly, for example
17/// `MnemonicType::Words12`.
18///
19/// You can also get a `MnemonicType` that corresponds to one of the standard BIP39 key sizes by
20/// passing arbitrary `usize` values:
21///
22/// ```
23/// use bip39::{MnemonicType};
24///
25/// let mnemonic_type = MnemonicType::for_key_size(128).unwrap();
26/// ```
27///
28/// [MnemonicType]: ../mnemonic_type/struct.MnemonicType.html
29/// [Mnemonic]: ../mnemonic/struct.Mnemonic.html
30/// [Seed]: ../seed/struct.Seed.html
31///
32#[derive(Debug, Copy, Clone, Serialize, Deserialize, Eq, PartialEq)]
33pub enum MnemonicType {
34 // ... = (entropy_bits << ...) | checksum_bits
35 Words12 = (128 << ENTROPY_OFFSET) | 4,
36 Words15 = (160 << ENTROPY_OFFSET) | 5,
37 Words18 = (192 << ENTROPY_OFFSET) | 6,
38 Words21 = (224 << ENTROPY_OFFSET) | 7,
39 Words24 = (256 << ENTROPY_OFFSET) | 8,
40}
41
42impl MnemonicType {
43 /// Get a `MnemonicType` for a mnemonic phrase with a specific number of words
44 ///
45 /// Specifying a word count not provided for by the BIP39 standard will return an `Error`
46 /// of kind `ErrorKind::InvalidWordLength`.
47 ///
48 /// # Example
49 /// ```
50 /// use bip39::{MnemonicType};
51 ///
52 /// let mnemonic_type = MnemonicType::for_word_count(12).unwrap();
53 /// ```
54 pub fn for_word_count(size: usize) -> Result<MnemonicType, Error> {
55 let mnemonic_type = match size {
56 12 => MnemonicType::Words12,
57 15 => MnemonicType::Words15,
58 18 => MnemonicType::Words18,
59 21 => MnemonicType::Words21,
60 24 => MnemonicType::Words24,
61 _ => Err(ErrorKind::InvalidWordLength(size))?
62 };
63
64 Ok(mnemonic_type)
65 }
66
67 /// Get a `MnemonicType` for a mnemonic phrase representing the given key size as bits
68 ///
69 /// Specifying a key size not provided for by the BIP39 standard will return an `Error`
70 /// of kind `ErrorKind::InvalidKeysize`.
71 ///
72 /// # Example
73 /// ```
74 /// use bip39::{MnemonicType};
75 ///
76 /// let mnemonic_type = MnemonicType::for_key_size(128).unwrap();
77 /// ```
78 pub fn for_key_size(size: usize) -> Result<MnemonicType, Error> {
79 let mnemonic_type = match size {
80 128 => MnemonicType::Words12,
81 160 => MnemonicType::Words15,
82 192 => MnemonicType::Words18,
83 224 => MnemonicType::Words21,
84 256 => MnemonicType::Words24,
85 _ => Err(ErrorKind::InvalidKeysize(size))?
86 };
87
88 Ok(mnemonic_type)
89 }
90
91 /// Get a `MnemonicType` for an existing mnemonic phrase
92 ///
93 /// This can be used when you need information about a mnemonic phrase based on the number of
94 /// words, for example you can get the entropy value using [`MnemonicType::entropy_bits`][MnemonicType::entropy_bits()].
95 ///
96 /// Specifying a phrase that does not match one of the standard BIP39 phrase lengths will return
97 /// an `Error` of kind `ErrorKind::InvalidWordLength`. The phrase will not be validated in any
98 /// other way.
99 ///
100 /// # Example
101 /// ```
102 /// use bip39::{MnemonicType};
103 ///
104 /// let test_mnemonic = "park remain person kitchen mule spell knee armed position rail grid ankle";
105 ///
106 /// let mnemonic_type = MnemonicType::for_phrase(test_mnemonic).unwrap();
107 ///
108 /// let entropy_bits = mnemonic_type.entropy_bits();
109 /// ```
110 ///
111 /// [MnemonicType::entropy_bits()]: ./enum.MnemonicType.html#method.entropy_bits
112 pub fn for_phrase(phrase: &str) -> Result<MnemonicType, Error> {
113 let word_count = phrase.split(" ").count();
114
115 Self::for_word_count(word_count)
116 }
117
118 /// Return the number of entropy+checksum bits
119 ///
120 ///
121 /// # Example
122 /// ```
123 /// use bip39::{MnemonicType};
124 ///
125 /// let test_mnemonic = "park remain person kitchen mule spell knee armed position rail grid ankle";
126 ///
127 /// let mnemonic_type = MnemonicType::for_phrase(test_mnemonic).unwrap();
128 ///
129 /// let total_bits = mnemonic_type.total_bits();
130 /// ```
131 pub fn total_bits(&self) -> usize {
132 self.entropy_bits() + self.checksum_bits() as usize
133 }
134
135 /// Return the number of entropy bits
136 ///
137 ///
138 /// # Example
139 /// ```
140 /// use bip39::{MnemonicType};
141 ///
142 /// let test_mnemonic = "park remain person kitchen mule spell knee armed position rail grid ankle";
143 ///
144 /// let mnemonic_type = MnemonicType::for_phrase(test_mnemonic).unwrap();
145 ///
146 /// let entropy_bits = mnemonic_type.entropy_bits();
147 /// ```
148 pub fn entropy_bits(&self) -> usize {
149 (*self as usize) >> ENTROPY_OFFSET
150 }
151
152 /// Return the number of checksum bits
153 ///
154 ///
155 /// # Example
156 /// ```
157 /// use bip39::{MnemonicType};
158 ///
159 /// let test_mnemonic = "park remain person kitchen mule spell knee armed position rail grid ankle";
160 ///
161 /// let mnemonic_type = MnemonicType::for_phrase(test_mnemonic).unwrap();
162 ///
163 /// let checksum_bits = mnemonic_type.checksum_bits();
164 /// ```
165 pub fn checksum_bits(&self) -> u8 {
166 (*self as usize) as u8
167 }
168
169 /// Return the number of words
170 ///
171 ///
172 /// # Example
173 /// ```
174 /// use bip39::{MnemonicType};
175 ///
176 /// let mnemonic_type = MnemonicType::Words12;
177 ///
178 /// let word_count = mnemonic_type.word_count();
179 /// ```
180 pub fn word_count(&self) -> usize {
181 self.total_bits() / 11
182 }
183}
184
185impl Default for MnemonicType {
186 fn default() -> MnemonicType {
187 MnemonicType::Words12
188 }
189}
190
191impl fmt::Display for MnemonicType {
192 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
193 write!(f, "{} words ({}bits)", self.word_count(), self.entropy_bits())
194 }
195}
196
197#[cfg(test)]
198mod test {
199 use super::*;
200
201 #[test]
202 fn word_count() {
203 assert_eq!(MnemonicType::Words12.word_count(), 12);
204 assert_eq!(MnemonicType::Words15.word_count(), 15);
205 assert_eq!(MnemonicType::Words18.word_count(), 18);
206 assert_eq!(MnemonicType::Words21.word_count(), 21);
207 assert_eq!(MnemonicType::Words24.word_count(), 24);
208 }
209
210 #[test]
211 fn entropy_bits() {
212 assert_eq!(MnemonicType::Words12.entropy_bits(), 128);
213 assert_eq!(MnemonicType::Words15.entropy_bits(), 160);
214 assert_eq!(MnemonicType::Words18.entropy_bits(), 192);
215 assert_eq!(MnemonicType::Words21.entropy_bits(), 224);
216 assert_eq!(MnemonicType::Words24.entropy_bits(), 256);
217 }
218
219 #[test]
220 fn checksum_bits() {
221 assert_eq!(MnemonicType::Words12.checksum_bits(), 4);
222 assert_eq!(MnemonicType::Words15.checksum_bits(), 5);
223 assert_eq!(MnemonicType::Words18.checksum_bits(), 6);
224 assert_eq!(MnemonicType::Words21.checksum_bits(), 7);
225 assert_eq!(MnemonicType::Words24.checksum_bits(), 8);
226 }
227}