1818//!
1919//! TREZOR compatible mnemonic in english
2020//!
21+ use bitcoin:: util:: bip158:: { BitStreamReader , BitStreamWriter } ;
2122use account:: Seed ;
2223use crypto:: {
2324 digest:: Digest ,
@@ -26,6 +27,7 @@ use crypto::{
2627 sha2:: { Sha256 , Sha512 } ,
2728} ;
2829use error:: Error ;
30+ use std:: io:: Cursor ;
2931
3032#[ derive( Clone , Eq , PartialEq , Debug ) ]
3133pub struct Mnemonic ( Vec < & ' static str > ) ;
@@ -58,14 +60,23 @@ impl Mnemonic {
5860 "Mnemonic must have a word count divisible with 6" ,
5961 ) ) ;
6062 }
63+ let mut data = Vec :: new ( ) ;
64+ let mut writer = BitStreamWriter :: new ( & mut data) ;
6165 let mut mnemonic = Vec :: new ( ) ;
6266 for word in & words {
6367 if let Ok ( idx) = WORDS . binary_search ( word) {
6468 mnemonic. push ( WORDS [ idx] ) ;
69+ writer. write ( idx as u64 , 11 ) . unwrap ( ) ;
6570 } else {
6671 return Err ( Error :: Mnemonic ( "Mnemonic contains an unknown word" ) ) ;
6772 }
6873 }
74+ writer. flush ( ) . unwrap ( ) ;
75+ let ( payload, checksum) = data. split_at ( data. len ( ) - std:: cmp:: max ( 1 , data. len ( ) /32 ) ) ;
76+ if Self :: checksum ( payload) . as_slice ( ) != checksum {
77+ return Err ( Error :: Mnemonic ( "Checksum failed" ) ) ;
78+ }
79+
6980 Ok ( Mnemonic ( mnemonic) )
7081 }
7182
@@ -76,34 +87,34 @@ impl Mnemonic {
7687 "Data for mnemonic should have a length divisible by 4" ,
7788 ) ) ;
7889 }
79- let mut check = [ 0u8 ; 32 ] ;
80-
81- let mut sha2 = Sha256 :: new ( ) ;
82- sha2. input ( data) ;
83- sha2. result ( & mut check) ;
84-
85- let mut bits = vec ! [ false ; data. len( ) * 8 + data. len( ) / 4 ] ;
86- for i in 0 ..data. len ( ) {
87- for j in 0 ..8 {
88- bits[ i * 8 + j] = ( data[ i] & ( 1 << ( 7 - j) ) ) > 0 ;
89- }
90- }
91- for i in 0 ..data. len ( ) / 4 {
92- bits[ 8 * data. len ( ) + i] = ( check[ i / 8 ] & ( 1 << ( 7 - ( i % 8 ) ) ) ) > 0 ;
93- }
90+ let mut with_checksum = data. to_vec ( ) ;
91+ with_checksum. extend_from_slice ( Self :: checksum ( data) . as_slice ( ) ) ;
92+ let mut cursor = Cursor :: new ( & with_checksum) ;
93+ let mut reader = BitStreamReader :: new ( & mut cursor) ;
9494 let mlen = data. len ( ) * 3 / 4 ;
9595 let mut memo = Vec :: new ( ) ;
96- for i in 0 ..mlen {
97- let mut idx = 0 ;
98- for j in 0 ..11 {
99- if bits[ i * 11 + j] {
100- idx += 1 << ( 10 - j) ;
101- }
102- }
103- memo. push ( WORDS [ idx] ) ;
96+ for _ in 0 ..mlen {
97+ memo. push ( WORDS [ reader. read ( 11 ) . unwrap ( ) as usize ] ) ;
10498 }
10599 Ok ( Mnemonic ( memo) )
106100 }
101+
102+ fn checksum ( data : & [ u8 ] ) -> Vec < u8 > {
103+ let mut hash = [ 0u8 ; 32 ] ;
104+ let mut checksum = Vec :: new ( ) ;
105+ let mut writer = BitStreamWriter :: new ( & mut checksum) ;
106+
107+ let mut sha2 = Sha256 :: new ( ) ;
108+ sha2. input ( data) ;
109+ sha2. result ( & mut hash) ;
110+ let mut check_cursor = Cursor :: new ( & hash) ;
111+ let mut check_reader = BitStreamReader :: new ( & mut check_cursor) ;
112+ for _ in 0 ..data. len ( ) /4 {
113+ writer. write ( check_reader. read ( 1 ) . unwrap ( ) , 1 ) . unwrap ( ) ;
114+ }
115+ writer. flush ( ) . unwrap ( ) ;
116+ checksum
117+ }
107118}
108119
109120#[ cfg( test) ]
@@ -137,7 +148,9 @@ mod test {
137148 for t in 0 ..tests. len ( ) {
138149 let values = tests[ t] . as_array ( ) . unwrap ( ) ;
139150 let data = decode ( values[ 0 ] . as_str ( ) . unwrap ( ) ) . unwrap ( ) ;
140- let mnemonic = Mnemonic :: from_str ( values[ 1 ] . as_str ( ) . unwrap ( ) ) . unwrap ( ) ;
151+ let m = values[ 1 ] . as_str ( ) . unwrap ( ) ;
152+ println ! ( "{}" , m) ;
153+ let mnemonic = Mnemonic :: from_str ( m) . unwrap ( ) ;
141154 let seed = mnemonic. to_seed ( Some ( "TREZOR" ) ) ;
142155 assert_eq ! (
143156 mnemonic. to_string( ) ,
0 commit comments