emerald_vault/
mnemonic.rs

1/*
2Copyright 2019 ETCDEV GmbH
3Copyright 2020 EmeraldPay, Inc
4
5Licensed under the Apache License, Version 2.0 (the "License");
6you may not use this file except in compliance with the License.
7You may obtain a copy of the License at
8
9    http://www.apache.org/licenses/LICENSE-2.0
10
11Unless required by applicable law or agreed to in writing, software
12distributed under the License is distributed on an "AS IS" BASIS,
13WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14See the License for the specific language governing permissions and
15limitations under the License.
16*/
17//! # Module to work with mnemonic codes
18//!
19//! Refer `BIP39` for detailed specification on mnemonic codes
20//! [BIP39](https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki)
21
22mod error;
23mod language;
24
25pub use self::{
26    error::Error,
27    language::{Language, BIP39_ENGLISH_WORDLIST},
28};
29use hmac::Hmac;
30use num::{bigint::BigUint, FromPrimitive, ToPrimitive};
31use pbkdf2::pbkdf2;
32use rand::{distributions::Standard, rngs::OsRng, Rng};
33use sha2::{Digest, Sha512};
34use std::ops::{BitAnd, Shr};
35
36/// Count of iterations for `pbkdf2`
37const PBKDF2_ROUNDS: u32 = 2048;
38/// word index size in bits
39const INDEX_BIT_SIZE: u32 = 11;
40
41/// Mnemonic phrase
42#[derive(Debug, Clone)]
43pub struct Mnemonic {
44    language: Language,
45    words: Vec<String>,
46}
47
48#[derive(Debug, Clone, PartialEq, Copy)]
49pub struct MnemonicSize {
50    bits_length: usize,
51    checksum_length: usize,
52}
53
54/// Standard Mnemonics
55pub struct StandardMnemonic {}
56
57impl StandardMnemonic {
58    /// Most secure mnemonic (24 words currently)
59    pub fn secure() -> MnemonicSize {
60        StandardMnemonic::size24()
61    }
62    /// Simple mnemonic suitable for a single address generation (15 words)
63    pub fn simple() -> MnemonicSize {
64        StandardMnemonic::size15()
65    }
66
67    /// 12 words mnemonic
68    pub fn size12() -> MnemonicSize {
69        MnemonicSize::from_length(12).unwrap()
70    }
71    /// 15 words mnemonic
72    pub fn size15() -> MnemonicSize {
73        MnemonicSize::from_length(15).unwrap()
74    }
75    /// 18 words mnemonic
76    pub fn size18() -> MnemonicSize {
77        MnemonicSize::from_length(18).unwrap()
78    }
79    /// 21 words mnemonic
80    pub fn size21() -> MnemonicSize {
81        MnemonicSize::from_length(21).unwrap()
82    }
83    /// 24 words mnemonic
84    pub fn size24() -> MnemonicSize {
85        MnemonicSize::from_length(24).unwrap()
86    }
87}
88
89impl MnemonicSize {
90    pub fn standard() -> [MnemonicSize; 5] {
91        [
92            MnemonicSize::from_length(12).unwrap(),
93            MnemonicSize::from_length(15).unwrap(),
94            MnemonicSize::from_length(18).unwrap(),
95            MnemonicSize::from_length(21).unwrap(),
96            MnemonicSize::from_length(24).unwrap(),
97        ]
98    }
99
100    pub fn from_length(words: usize) -> Result<MnemonicSize, Error> {
101        match words {
102            12 => Ok(MnemonicSize {
103                bits_length: 128,
104                checksum_length: 4,
105            }),
106            15 => Ok(MnemonicSize {
107                bits_length: 160,
108                checksum_length: 5,
109            }),
110            18 => Ok(MnemonicSize {
111                bits_length: 192,
112                checksum_length: 6,
113            }),
114            21 => Ok(MnemonicSize {
115                bits_length: 224,
116                checksum_length: 7,
117            }),
118            24 => Ok(MnemonicSize {
119                bits_length: 256,
120                checksum_length: 8,
121            }),
122            _ => Err(Error::MnemonicError(format!(
123                "Invalid mnemonic size: {}",
124                words
125            ))),
126        }
127    }
128
129    pub fn from_entropy(entropy: &[u8]) -> Result<MnemonicSize, Error> {
130        let all = MnemonicSize::standard();
131        let entropy_len = entropy.len();
132        let found = all.iter().find(|x| x.entropy_bytes_length() == entropy_len);
133        match found {
134            Some(&m) => Ok(m),
135            None => Err(Error::MnemonicError(format!(
136                "Invalid entropy size: {}",
137                entropy_len
138            ))),
139        }
140    }
141
142    pub fn words_count(&self) -> usize {
143        (self.bits_length + self.checksum_length) / 11
144    }
145
146    pub fn entropy_bytes_length(&self) -> usize {
147        self.bits_length / 8
148    }
149
150    pub fn full_bytes_length(&self) -> usize {
151        let mut rem = 8 - (self.bits_length + self.checksum_length) % 8;
152        if rem == 8 {
153            rem = 0
154        }
155        (self.bits_length + self.checksum_length + rem) / 8
156    }
157
158    /// Generate a random entropy within current mnemonic size
159    pub fn entropy(&self) -> Result<Vec<u8>, Error> {
160        gen_entropy(self.entropy_bytes_length())
161    }
162
163    pub fn checksum_bits(&self, full: u8) -> u8 {
164        if self.checksum_length == 8 {
165            full
166        } else {
167            let mut mask: u8 = 0;
168            for _i in 0..self.checksum_length {
169                mask |= 1;
170                mask = mask << 1;
171            }
172            mask = mask << (8 - self.checksum_length - 1) as u8;
173            let bits = full & mask;
174            bits >> (8 - self.checksum_length) as u8
175        }
176    }
177}
178
179impl Default for Mnemonic {
180    fn default() -> Self {
181        Mnemonic::new(Language::English, StandardMnemonic::secure()).unwrap()
182    }
183}
184
185impl Mnemonic {
186    // Create new mnemonic phrase for selected lanaguage with provided size
187    //
188    pub fn new(lang: Language, size: MnemonicSize) -> Result<Mnemonic, Error> {
189        Mnemonic::from_entropy(lang, size.entropy()?.as_slice())
190    }
191
192    /// Create new mnemonic phrase for selected language with provided entropy
193    ///
194    /// # Arguments:
195    ///
196    /// * lang - language for words selection
197    ///
198    pub fn from_entropy(lang: Language, entropy: &[u8]) -> Result<Mnemonic, Error> {
199        let size = MnemonicSize::from_entropy(entropy)?;
200        let mut ent = entropy.to_owned();
201        let checksum = checksum(&ent, size);
202        ent = with_checksum(&ent, checksum, size);
203
204        let indexes = get_indexes(&ent, size)?;
205        let mut w = Vec::new();
206        for i in &indexes {
207            w.push(BIP39_ENGLISH_WORDLIST[*i].clone());
208        }
209
210        Ok(Mnemonic {
211            language: lang,
212            words: w,
213        })
214    }
215
216    /// Convert mnemonic to single string
217    pub fn sentence(&self) -> String {
218        let mut s = String::new();
219        for (i, w) in self.words.iter().enumerate() {
220            s.push_str(w);
221            if i != self.words.len() - 1 {
222                s.push_str(" ");
223            }
224        }
225        s
226    }
227
228    /// Get seed from mnemonic sentence
229    ///
230    /// # Arguments:
231    ///
232    /// * password - password for seed generation
233    ///
234    pub fn seed(&self, password: Option<String>) -> Vec<u8> {
235        let passphrase = match password {
236            Some(p) => "mnemonic".to_string() + p.as_str(),
237            None => "mnemonic".to_string(),
238        };
239
240        let mut result = vec![0u8; 64];
241        pbkdf2::<Hmac<Sha512>>(
242            // password
243            &self.sentence().as_str().as_bytes(),
244            // salt
245            passphrase.as_bytes(),
246            // size
247            PBKDF2_ROUNDS,
248            // result
249            &mut result,
250        );
251
252        result
253    }
254
255    /// Convert a string into `Mnemonic`.
256    ///
257    /// # Arguments
258    ///
259    /// * `lang` - A mnemonic language
260    /// * `src` - A mnemonic sentence with `MNEMONIC_SIZE` length
261    ///
262    pub fn try_from(lang: Language, src: &str) -> Result<Self, Error> {
263        let w: Vec<String> = src
264            .to_string()
265            .split_whitespace()
266            .map(|w| w.to_string())
267            .collect();
268
269        match w.len() {
270            0 => Err(Error::MnemonicError("empty initial sentence".to_string())),
271            l => {
272                MnemonicSize::from_length(l)?;
273                Ok(Mnemonic {
274                    language: lang,
275                    words: w,
276                })
277            }
278        }
279    }
280}
281
282/// Generate entropy
283
284/// # Arguments:
285///
286/// * `byte_length` - size of entropy in bytes
287///
288pub fn gen_entropy(byte_length: usize) -> Result<Vec<u8>, Error> {
289    let mut rng = OsRng::default();
290    let bytes = rng.sample_iter(&Standard).take(byte_length).collect();
291
292    Ok(bytes)
293}
294
295/// Calculate checksum for mnemonic
296fn checksum(data: &[u8], size: MnemonicSize) -> u8 {
297    let mut hash = sha2::Sha256::new();
298    hash.update(data);
299    let val = hash.finalize()[0];
300    size.checksum_bits(val)
301}
302
303fn with_checksum(entropy: &[u8], checksum: u8, size: MnemonicSize) -> Vec<u8> {
304    let mut copy = Vec::from(entropy);
305    if size.checksum_length == 8 {
306        copy.push(checksum);
307        copy
308    } else {
309        let empty_bits = (8 - size.checksum_length) as u8;
310        let checksum_corrected = checksum << empty_bits;
311        copy.push(checksum_corrected);
312
313        let full_size = size.full_bytes_length();
314        let mut data = BigUint::from_bytes_be(copy.as_slice());
315        data = data.clone().shr(empty_bits as usize);
316        let result = data.to_bytes_be().to_vec();
317        if result.len() < full_size {
318            let mut with_zeroes: Vec<u8> = vec![0; full_size - result.len()];
319            with_zeroes.extend_from_slice(result.as_slice());
320            with_zeroes
321        } else {
322            result
323        }
324    }
325}
326
327/// Get indexes from entropy
328///
329/// # Arguments:
330///
331/// * `entropy` - slice with entropy
332///
333fn get_indexes(entropy: &[u8], size: MnemonicSize) -> Result<Vec<usize>, Error> {
334    if entropy.len() != size.full_bytes_length() {
335        return Err(Error::MnemonicError(format!(
336            "invalid entropy length (required: {}, received: {})",
337            size.full_bytes_length(),
338            entropy.len()
339        )));
340    }
341
342    let data = BigUint::from_bytes_be(entropy);
343    // 11 bit for each word
344    let base_mask = BigUint::from_u16(0b11111111111).expect("expect initialize word index");
345    let mut out: Vec<usize> = Vec::with_capacity(size.words_count());
346    for i in 0..size.words_count() {
347        let pos = (size.words_count() - 1 - i) * (INDEX_BIT_SIZE as usize);
348        match data.clone().shr(pos).bitand(&base_mask.clone()).to_usize() {
349            Some(v) => out.push(v),
350            None => {
351                return Err(Error::MnemonicError(
352                    "can't extract words indexes".to_string(),
353                ))
354            }
355        }
356    }
357
358    Ok(out)
359}
360
361#[cfg(test)]
362mod tests {
363    use super::*;
364    use hex::FromHex;
365
366    #[test]
367    fn keeps_zeroes_with_checksum() {
368        let zeroes = vec![0; 2]; //0x0000
369        let act = with_checksum(zeroes.as_slice(), 15, StandardMnemonic::size12());
370        assert_eq!(hex::encode(act), "000000000000000000000000000000000f");
371
372        let zeroes =
373            Vec::from_hex("00000000000000000000000000000000000000000000000000000000000000")
374                .unwrap();
375        let act = with_checksum(zeroes.as_slice(), 15, StandardMnemonic::size24());
376        assert_eq!(
377            hex::encode(act),
378            "000000000000000000000000000000000000000000000000000000000000000f"
379        );
380
381        let zeroes = Vec::from_hex("000100").unwrap();
382        let act = with_checksum(zeroes.as_slice(), 15, StandardMnemonic::size12());
383        assert_eq!(hex::encode(act), "000000000000000000000000000000100f");
384
385        let zeroes = Vec::from_hex("000000000000000000000000000000000000000000000000").unwrap();
386        let act = with_checksum(zeroes.as_slice(), 0b100111, StandardMnemonic::size18());
387        assert_eq!(
388            hex::encode(act),
389            "00000000000000000000000000000000000000000000000027"
390        );
391    }
392
393    #[test]
394    fn should_extract_length() {
395        assert_eq!(
396            MnemonicSize::from_length(12).unwrap(),
397            StandardMnemonic::size12()
398        );
399        assert_eq!(
400            MnemonicSize::from_length(15).unwrap(),
401            StandardMnemonic::size15()
402        );
403        assert_eq!(
404            MnemonicSize::from_length(18).unwrap(),
405            StandardMnemonic::size18()
406        );
407        assert_eq!(
408            MnemonicSize::from_length(21).unwrap(),
409            StandardMnemonic::size21()
410        );
411        assert_eq!(
412            MnemonicSize::from_length(24).unwrap(),
413            StandardMnemonic::size24()
414        );
415    }
416
417    #[test]
418    fn should_fail_on_invalid_length() {
419        assert!(MnemonicSize::from_length(0).is_err());
420        assert!(MnemonicSize::from_length(1).is_err());
421        assert!(MnemonicSize::from_length(11).is_err());
422        assert!(MnemonicSize::from_length(32).is_err());
423    }
424
425    #[test]
426    fn should_calc_entropy_length() {
427        assert_eq!(StandardMnemonic::size12().entropy_bytes_length(), 16);
428        assert_eq!(StandardMnemonic::size15().entropy_bytes_length(), 20);
429        assert_eq!(StandardMnemonic::size18().entropy_bytes_length(), 24);
430        assert_eq!(StandardMnemonic::size21().entropy_bytes_length(), 28);
431        assert_eq!(StandardMnemonic::size24().entropy_bytes_length(), 32);
432    }
433
434    #[test]
435    fn should_calc_full_length() {
436        assert_eq!(StandardMnemonic::size12().full_bytes_length(), 17);
437        assert_eq!(StandardMnemonic::size15().full_bytes_length(), 21);
438        assert_eq!(StandardMnemonic::size18().full_bytes_length(), 25);
439        assert_eq!(StandardMnemonic::size21().full_bytes_length(), 29);
440        assert_eq!(StandardMnemonic::size24().full_bytes_length(), 33);
441    }
442
443    #[test]
444    fn generates_correct_entropy_length() {
445        assert_eq!(StandardMnemonic::size12().entropy().unwrap().len(), 16);
446        assert_eq!(StandardMnemonic::size15().entropy().unwrap().len(), 20);
447        assert_eq!(StandardMnemonic::size18().entropy().unwrap().len(), 24);
448        assert_eq!(StandardMnemonic::size21().entropy().unwrap().len(), 28);
449        assert_eq!(StandardMnemonic::size24().entropy().unwrap().len(), 32);
450    }
451
452    #[test]
453    fn generates_correct_mnemonic_length() {
454        assert_eq!(
455            Mnemonic::new(Language::English, StandardMnemonic::size12())
456                .unwrap()
457                .words
458                .len(),
459            12
460        );
461        assert_eq!(
462            Mnemonic::new(Language::English, StandardMnemonic::size15())
463                .unwrap()
464                .words
465                .len(),
466            15
467        );
468        assert_eq!(
469            Mnemonic::new(Language::English, StandardMnemonic::size18())
470                .unwrap()
471                .words
472                .len(),
473            18
474        );
475        assert_eq!(
476            Mnemonic::new(Language::English, StandardMnemonic::size21())
477                .unwrap()
478                .words
479                .len(),
480            21
481        );
482        assert_eq!(
483            Mnemonic::new(Language::English, StandardMnemonic::size24())
484                .unwrap()
485                .words
486                .len(),
487            24
488        );
489    }
490
491    #[test]
492    fn should_generate_entropy() {
493        let mut ent = gen_entropy(32);
494        assert!(ent.is_ok());
495        assert_eq!(ent.unwrap().len(), 32);
496
497        ent = gen_entropy(2);
498        assert!(ent.is_ok());
499        assert_eq!(ent.unwrap().len(), 2);
500    }
501
502    #[test]
503    fn should_generate_indexes_12words() {
504        let mut ent = gen_entropy(16).unwrap();
505        ent = with_checksum(ent.as_slice(), 1, StandardMnemonic::size12());
506        let res = get_indexes(&ent, StandardMnemonic::size12());
507        assert!(res.is_ok());
508
509        let mut indexes = res.unwrap();
510        assert_eq!(indexes.len(), 12);
511
512        indexes = indexes.into_iter().filter(|v| *v > 2048).collect();
513        assert_eq!(indexes.len(), 0);
514    }
515
516    #[test]
517    fn should_generate_indexes_15words() {
518        let mut ent = gen_entropy(20).unwrap();
519        ent = with_checksum(ent.as_slice(), 1, StandardMnemonic::size15());
520        let res = get_indexes(&ent, StandardMnemonic::size15());
521        assert!(res.is_ok());
522
523        let mut indexes = res.unwrap();
524        assert_eq!(indexes.len(), 15);
525
526        indexes = indexes.into_iter().filter(|v| *v > 2048).collect();
527        assert_eq!(indexes.len(), 0);
528    }
529
530    #[test]
531    fn should_generate_indexes_18words() {
532        let mut ent = gen_entropy(24).unwrap();
533        ent = with_checksum(ent.as_slice(), 1, StandardMnemonic::size18());
534        let res = get_indexes(&ent, StandardMnemonic::size18());
535        assert!(res.is_ok());
536
537        let mut indexes = res.unwrap();
538        assert_eq!(indexes.len(), 18);
539
540        indexes = indexes.into_iter().filter(|v| *v > 2048).collect();
541        assert_eq!(indexes.len(), 0);
542    }
543
544    #[test]
545    fn should_generate_indexes_21words() {
546        let mut ent = gen_entropy(28).unwrap();
547        ent = with_checksum(ent.as_slice(), 1, StandardMnemonic::size21());
548        let res = get_indexes(&ent, StandardMnemonic::size21());
549        assert!(res.is_ok());
550
551        let mut indexes = res.unwrap();
552        assert_eq!(indexes.len(), 21);
553
554        indexes = indexes.into_iter().filter(|v| *v > 2048).collect();
555        assert_eq!(indexes.len(), 0);
556    }
557
558    #[test]
559    fn should_generate_indexes_24words() {
560        let mut ent = gen_entropy(32).unwrap();
561        ent = with_checksum(ent.as_slice(), 1, StandardMnemonic::size24());
562        let res = get_indexes(&ent, StandardMnemonic::size24());
563        assert!(res.is_ok());
564
565        let mut indexes = res.unwrap();
566        assert_eq!(indexes.len(), 24);
567
568        indexes = indexes.into_iter().filter(|v| *v > 2048).collect();
569        assert_eq!(indexes.len(), 0);
570    }
571
572    #[test]
573    fn should_fail_generate_indexes() {
574        let res = get_indexes(&vec![0u8, 1u8], StandardMnemonic::size24());
575        assert!(res.is_err())
576    }
577
578    #[test]
579    fn get_index_24() {
580        let mut entropy =
581            Vec::from_hex("0000000000000000000000000000000000000000000000000000000000000000")
582                .unwrap();
583        entropy.push(0b01100110);
584        let res = get_indexes(entropy.as_slice(), StandardMnemonic::size24()).unwrap();
585        let exp: Vec<usize> = vec![
586            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 102,
587        ];
588        assert_eq!(res, exp);
589
590        let mut entropy =
591            Vec::from_hex("7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f")
592                .unwrap();
593        entropy.push(0b00010111);
594        let res = get_indexes(entropy.as_slice(), StandardMnemonic::size24()).unwrap();
595        let exp: Vec<usize> = vec![
596            1019, 2015, 1790, 2039, 1983, 1533, 2031, 1919, 1019, 2015, 1790, 2039, 1983, 1533,
597            2031, 1919, 1019, 2015, 1790, 2039, 1983, 1533, 2031, 1815,
598        ];
599
600        assert_eq!(res, exp);
601    }
602
603    #[test]
604    fn get_index_18() {
605        let entropy = Vec::from_hex("ffffffffffffffffffffffffffffffffffffffffffffffffd1").unwrap();
606        let res = get_indexes(entropy.as_slice(), StandardMnemonic::size18()).unwrap();
607        let exp: Vec<usize> = vec![
608            2047, 2047, 2047, 2047, 2047, 2047, 2047, 2047, 2047, 2047, 2047, 2047, 2047, 2047,
609            2047, 2047, 2047, 2001,
610        ];
611
612        assert_eq!(res, exp);
613    }
614
615    #[test]
616    fn should_convert_to_seed() {
617        let entropy = StandardMnemonic::size24().entropy().unwrap();
618        let mnemonic = Mnemonic::from_entropy(Language::English, &entropy).unwrap();
619
620        let seed = mnemonic.seed(Some("12345".to_string()));
621        assert_eq!(seed.len(), 64);
622    }
623
624    #[test]
625    fn should_convert_to_sentence() {
626        let entropy = StandardMnemonic::size24().entropy().unwrap();
627        let mnemonic = Mnemonic::from_entropy(Language::English, &entropy).unwrap();
628        let s: Vec<String> = mnemonic
629            .sentence()
630            .split_whitespace()
631            .map(|w| w.to_string())
632            .collect();
633
634        assert_eq!(s, mnemonic.words)
635    }
636
637    #[test]
638    fn should_generate_english_mnemonic() {
639        let entropy = vec![0u8; 32];
640        let res = Mnemonic::from_entropy(Language::English, &entropy);
641        assert!(res.is_ok());
642
643        let mnemonic = res.unwrap();
644        assert_eq!(
645            mnemonic.sentence(),
646            "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon \
647             abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon \
648             abandon abandon abandon art"
649        );
650
651        let entropy = mnemonic.seed(Some("TREZOR".to_string()));
652        assert_eq!(
653            entropy,
654            Vec::from_hex(
655                "bda85446c68413707090a52022edd26a\
656                 1c9462295029f2e60cd7c4f2bbd309717\
657                 0af7a4d73245cafa9c3cca8d561a7c3de6\
658                 f5d4a10be8ed2a5e608d68f92fcc8"
659            )
660            .unwrap()
661        );
662    }
663
664    #[test]
665    fn should_create_from_sentence_12() {
666        let s = "ozone drill grab fiber curtain grace pudding thank cruise elder eight picnic";
667        let mnemonic = Mnemonic::try_from(Language::English, s).unwrap();
668        let w: Vec<String> = s
669            .to_string()
670            .split_whitespace()
671            .map(|w| w.to_string())
672            .collect();
673
674        assert_eq!(w, mnemonic.words);
675        assert_eq!(
676            mnemonic.seed(Some("TREZOR".to_string())),
677            Vec::from_hex(
678                "274ddc525802f7c828d8ef7ddbcdc530\
679                 4e87ac3535913611fbbfa986d0c9e547\
680                 6c91689f9c8a54fd55bd38606aa6a859\
681                 5ad213d4c9c9f9aca3fb217069a41028"
682            )
683            .unwrap()
684        );
685    }
686
687    #[test]
688    fn should_be_compatible_with_bip39js() {
689        let s = "abandon abandon abandon abandon abandon abandon abandon abandon abandon \
690                 abandon abandon about";
691        let mnemonic = Mnemonic::try_from(Language::English, s).unwrap();
692
693        assert_eq!(
694            mnemonic.seed(Some("TREZOR".to_string())),
695            Vec::from_hex(
696                "c55257c360c07c72029aebc1b53c05ed03\
697                 62ada38ead3e3e9efa3708e53495531f0\
698                 9a6987599d18264c1e1c92f2cf141630c7a3c4ab7c81b2f001698e7463b04"
699            )
700            .unwrap()
701        );
702    }
703
704    #[test]
705    fn should_be_compatible_with_bip39js_emptypass() {
706        let s = "abandon abandon abandon abandon abandon abandon abandon abandon abandon \
707                 abandon abandon about";
708        let mnemonic = Mnemonic::try_from(Language::English, s).unwrap();
709
710        assert_eq!(
711            mnemonic.seed(None),
712            Vec::from_hex(
713                "5eb00bbddcf069084889a8ab9155568165f5c4\
714                 53ccb85e70811aaed6f6da5fc19a5ac40b3\
715                 89cd370d086206dec8aa6c43daea6690f20ad3d8d48b2d2ce9e38e4"
716            )
717            .unwrap()
718        );
719    }
720
721    #[test]
722    fn should_create_from_sentence_24() {
723        let s = "beyond stage sleep clip because twist token leaf atom beauty genius food \
724                 business side grid unable middle armed observe pair crouch tonight away coconut";
725        let mnemonic = Mnemonic::try_from(Language::English, s).unwrap();
726        let w: Vec<String> = s
727            .to_string()
728            .split_whitespace()
729            .map(|w| w.to_string())
730            .collect();
731
732        assert_eq!(w, mnemonic.words);
733        assert_eq!(
734            mnemonic.seed(Some("TREZOR".to_string())),
735            Vec::from_hex(
736                "b15509eaa2d09d3efd3e006ef42151b3\
737                 0367dc6e3aa5e44caba3fe4d3e352e65\
738                 101fbdb86a96776b91946ff06f8eac59\
739                 4dc6ee1d3e82a42dfe1b40fef6bcc3fd"
740            )
741            .unwrap()
742        );
743    }
744
745    #[test]
746    fn should_create_from_sentence_15() {
747        let s = "hover involve coyote admit barrel lawsuit near genuine divide ghost music episode dish churn castle";
748        let mnemonic = Mnemonic::try_from(Language::English, s).unwrap();
749        let w: Vec<String> = s
750            .to_string()
751            .split_whitespace()
752            .map(|w| w.to_string())
753            .collect();
754
755        assert_eq!(mnemonic.words, w);
756        assert_eq!(mnemonic.seed(None), Vec::from_hex(
757            "455f5de41e8ec000a32c26c3f411903020269f70fef532aed49f9a1f9cf1a300752f476bd88764449e9b5728b5a67020b5536b60947bf1123a4a6e100845afc6"
758        ).unwrap());
759        assert_eq!(mnemonic.seed(Some("test".to_string())), Vec::from_hex(
760            "a49a8045f542196e4d0c8af8bd9e80853bb4582db8df4d57fda69d5301fc2b65d984b4c8fa6d374e1507b4c30972d7950c5390e239f27961f79396974e600eef"
761        ).unwrap());
762    }
763
764    #[test]
765    fn should_create_from_entropy_15() {
766        let entropy = Vec::from_hex("ffffffffffffffffffffffffffffffffffffffffffffffff").unwrap();
767        let mnemonic = Mnemonic::from_entropy(Language::English, entropy.as_slice()).unwrap();
768        let words: Vec<String> =
769            "zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo when"
770                .split_whitespace()
771                .map(|w| w.to_string())
772                .collect();
773
774        assert_eq!(mnemonic.words, words);
775        assert_eq!(hex::encode(mnemonic.seed(None)),
776                   "d2911131a6dda23ac4441d1b66e2113ec6324354523acfa20899a2dcb3087849264e91f8ec5d75355f0f617be15369ffa13c3d18c8156b97cd2618ac693f759f"
777        );
778    }
779
780    #[test]
781    fn should_create_from_entropy_18() {
782        let entropy = vec![0; 24];
783        let mnemonic = Mnemonic::from_entropy(Language::English, entropy.as_slice()).unwrap();
784        let words: Vec<String> = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon agent"
785            .split_whitespace()
786            .map(|w| w.to_string())
787            .collect();
788
789        assert_eq!(mnemonic.words, words);
790        assert_eq!(hex::encode(mnemonic.seed(None)),
791                   "4975bb3d1faf5308c86a30893ee903a976296609db223fd717e227da5a813a34dc1428b71c84a787fc51f3b9f9dc28e9459f48c08bd9578e9d1b170f2d7ea506"
792        );
793
794        let entropy = Vec::from_hex("7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f").unwrap();
795        let mnemonic = Mnemonic::from_entropy(Language::English, entropy.as_slice()).unwrap();
796        let words: Vec<String> = "legal winner thank year wave sausage worth useful legal winner thank year wave sausage worth useful legal will"
797            .split_whitespace()
798            .map(|w| w.to_string())
799            .collect();
800
801        assert_eq!(mnemonic.words, words);
802        assert_eq!(hex::encode(mnemonic.seed(None)),
803                   "b059400ce0f55498a5527667e77048bb482ff6daa16c37b4b9e8af70c85b3f4df588004f19812a1a027c9a51e5e94259a560268e91cd10e206451a129826e740"
804        );
805
806        let entropy = Vec::from_hex("808080808080808080808080808080808080808080808080").unwrap();
807        let mnemonic = Mnemonic::from_entropy(Language::English, entropy.as_slice()).unwrap();
808        let words: Vec<String> = "letter advice cage absurd amount doctor acoustic avoid letter advice cage absurd amount doctor acoustic avoid letter always"
809            .split_whitespace()
810            .map(|w| w.to_string())
811            .collect();
812
813        assert_eq!(mnemonic.words, words);
814        assert_eq!(hex::encode(mnemonic.seed(None)),
815                   "04d5f77103510c41d610f7f5fb3f0badc77c377090815cee808ea5d2f264fdfabf7c7ded4be6d4c6d7cdb021ba4c777b0b7e57ca8aa6de15aeb9905dba674d66"
816        );
817
818        let entropy = Vec::from_hex("ffffffffffffffffffffffffffffffffffffffffffffffff").unwrap();
819        let mnemonic = Mnemonic::from_entropy(Language::English, entropy.as_slice()).unwrap();
820        let words: Vec<String> =
821            "zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo when"
822                .split_whitespace()
823                .map(|w| w.to_string())
824                .collect();
825
826        assert_eq!(mnemonic.words, words);
827        assert_eq!(hex::encode(mnemonic.seed(None)),
828                   "d2911131a6dda23ac4441d1b66e2113ec6324354523acfa20899a2dcb3087849264e91f8ec5d75355f0f617be15369ffa13c3d18c8156b97cd2618ac693f759f"
829        );
830    }
831
832    #[test]
833    fn should_create_from_entropy_24() {
834        let entropy =
835            Vec::from_hex("7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f")
836                .unwrap();
837        let mnemonic = Mnemonic::from_entropy(Language::English, entropy.as_slice()).unwrap();
838        let words: Vec<String> = "legal winner thank year wave sausage worth useful legal winner thank year wave sausage worth useful legal winner thank year wave sausage worth title"
839            .split_whitespace()
840            .map(|w| w.to_string())
841            .collect();
842
843        assert_eq!(mnemonic.words, words);
844        assert_eq!(hex::encode(mnemonic.seed(None)),
845                   "761914478ebf6fe16185749372e91549361af22b386de46322cf8b1ba7e92e80c4af05196f742be1e63aab603899842ddadf4e7248d8e43870a4b6ff9bf16324"
846        );
847    }
848
849    #[test]
850    fn should_fail_from_empty() {
851        let s = "";
852        let mnemonic = Mnemonic::try_from(Language::English, s);
853
854        assert!(mnemonic.is_err())
855    }
856
857    #[test]
858    fn should_fail_from_longer() {
859        let s = "test test test test test test test test test test test test test test test test \
860                 test test test test test test test test test test test test test";
861        let mnemonic = Mnemonic::try_from(Language::English, s);
862
863        assert!(mnemonic.is_err())
864    }
865
866    #[test]
867    fn should_fail_from_outrange() {
868        let s = "test test test test test test test test test test test test test test test test";
869        let mnemonic = Mnemonic::try_from(Language::English, s);
870
871        assert!(mnemonic.is_err())
872    }
873
874    #[test]
875    fn checksum_for_15() {
876        let value = Vec::from_hex("ffffffffffffffffffffffffffffffffffffffff").unwrap();
877        let act = checksum(value.as_slice(), StandardMnemonic::size15());
878        assert_eq!(act, 0b10011);
879    }
880
881    #[test]
882    fn checksum_for_18() {
883        let value = Vec::from_hex("000000000000000000000000000000000000000000000000").unwrap();
884        let act = checksum(value.as_slice(), StandardMnemonic::size18());
885        assert_eq!(act, 0b100111);
886
887        let value = Vec::from_hex("ffffffffffffffffffffffffffffffffffffffffffffffff").unwrap();
888        let act = checksum(value.as_slice(), StandardMnemonic::size18());
889        assert_eq!(act, 0b010001);
890
891        let value = Vec::from_hex("dd3e87806994a424a6161109bdbe195f585598e5f090b66a").unwrap();
892        let act = checksum(value.as_slice(), StandardMnemonic::size18());
893        assert_eq!(act, 0b001011);
894
895        let value = Vec::from_hex("f526453799d708306056bf170f640efd8cb9b8cc139df865").unwrap();
896        let act = checksum(value.as_slice(), StandardMnemonic::size18());
897        assert_eq!(act, 0b111011);
898    }
899
900    #[test]
901    fn checksum_for_21() {
902        let value =
903            Vec::from_hex("ffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap();
904        let act = checksum(value.as_slice(), StandardMnemonic::size21());
905        assert_eq!(act, 0b0011001);
906
907        let value =
908            Vec::from_hex("1205c0b2e048ceef790d0433a902a070d0744af9b5e88edf7923c561").unwrap();
909        let act = checksum(value.as_slice(), StandardMnemonic::size21());
910        assert_eq!(act, 0b0011011);
911
912        let value =
913            Vec::from_hex("b579f8e1dfc739a36a90a1f94cb33aef1bc28f43dc3533c829d5e935").unwrap();
914        let act = checksum(value.as_slice(), StandardMnemonic::size21());
915        assert_eq!(act, 0b0000000);
916
917        let value =
918            Vec::from_hex("b579f8e1dfc739a36a90a1f94cb33aef1bc28f43dc3533c829d5e95c").unwrap();
919        let act = checksum(value.as_slice(), StandardMnemonic::size21());
920        assert_eq!(act, 0b0000001);
921    }
922
923    #[test]
924    fn checksum_for_24() {
925        let value =
926            Vec::from_hex("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")
927                .unwrap();
928        let act = checksum(value.as_slice(), StandardMnemonic::size24());
929        assert_eq!(act, 0b10101111);
930
931        let value =
932            Vec::from_hex("e28a37058c7f5112ec9e16a3437cf363a2572d70b6ceb3b69654476253ed12fa")
933                .unwrap();
934        let act = checksum(value.as_slice(), StandardMnemonic::size24());
935        assert_eq!(act, 0b10111111);
936    }
937}