1mod 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
36const PBKDF2_ROUNDS: u32 = 2048;
38const INDEX_BIT_SIZE: u32 = 11;
40
41#[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
54pub struct StandardMnemonic {}
56
57impl StandardMnemonic {
58 pub fn secure() -> MnemonicSize {
60 StandardMnemonic::size24()
61 }
62 pub fn simple() -> MnemonicSize {
64 StandardMnemonic::size15()
65 }
66
67 pub fn size12() -> MnemonicSize {
69 MnemonicSize::from_length(12).unwrap()
70 }
71 pub fn size15() -> MnemonicSize {
73 MnemonicSize::from_length(15).unwrap()
74 }
75 pub fn size18() -> MnemonicSize {
77 MnemonicSize::from_length(18).unwrap()
78 }
79 pub fn size21() -> MnemonicSize {
81 MnemonicSize::from_length(21).unwrap()
82 }
83 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 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 pub fn new(lang: Language, size: MnemonicSize) -> Result<Mnemonic, Error> {
189 Mnemonic::from_entropy(lang, size.entropy()?.as_slice())
190 }
191
192 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 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 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 &self.sentence().as_str().as_bytes(),
244 passphrase.as_bytes(),
246 PBKDF2_ROUNDS,
248 &mut result,
250 );
251
252 result
253 }
254
255 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
282pub 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
295fn 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
327fn 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 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]; 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}