@@ -67,6 +67,9 @@ const MIN_NB_WORDS: usize = 12;
6767/// The maximum number of words in a mnemonic.
6868const MAX_NB_WORDS : usize = 24 ;
6969
70+ /// The index used to indicate the mnemonic ended.
71+ const EOF : u16 = u16:: max_value ( ) ;
72+
7073/// A structured used in the [Error::AmbiguousLanguages] variant that iterates
7174/// over the possible languages.
7275#[ derive( Debug , Clone , PartialEq , Eq , Copy ) ]
@@ -149,7 +152,13 @@ impl error::Error for Error {}
149152///
150153/// Supported number of words are 12, 18 and 24.
151154#[ derive( Clone , Debug , Hash , PartialEq , Eq , PartialOrd , Ord ) ]
152- pub struct Mnemonic ( [ & ' static str ; MAX_NB_WORDS ] ) ;
155+ pub struct Mnemonic {
156+ /// The language the mnemonic.
157+ lang : Language ,
158+ /// The indiced of the words.
159+ /// Mnemonics with less than the max nb of words are terminated with EOF.
160+ words : [ u16 ; MAX_NB_WORDS ] ,
161+ }
153162
154163serde_string_impl ! ( Mnemonic , "a BIP-39 Mnemonic Code" ) ;
155164
@@ -194,7 +203,7 @@ impl Mnemonic {
194203 bits[ 8 * nb_bytes + i] = ( check[ i / 8 ] & ( 1 << ( 7 - ( i % 8 ) ) ) ) > 0 ;
195204 }
196205
197- let mut words: [ & ' static str ; MAX_NB_WORDS ] = Default :: default ( ) ;
206+ let mut words = [ EOF ; MAX_NB_WORDS ] ;
198207 let nb_words = nb_bytes * 3 / 4 ;
199208 for i in 0 ..nb_words {
200209 let mut idx = 0 ;
@@ -203,10 +212,13 @@ impl Mnemonic {
203212 idx += 1 << ( 10 - j) ;
204213 }
205214 }
206- words[ i] = language . word_list ( ) [ idx] ;
215+ words[ i] = idx;
207216 }
208217
209- Ok ( Mnemonic ( words) )
218+ Ok ( Mnemonic {
219+ lang : language,
220+ words : words,
221+ } )
210222 }
211223
212224 /// Create a new English [Mnemonic] from the given entropy.
@@ -282,9 +294,15 @@ impl Mnemonic {
282294 Mnemonic :: generate_in ( Language :: English , word_count)
283295 }
284296
297+ /// Get the language of the [Mnemonic].
298+ pub fn language ( & self ) -> Language {
299+ self . lang
300+ }
301+
285302 /// Get an iterator over the words.
286- pub fn word_iter ( & self ) -> impl Iterator < Item = & ' static str > + ' _ {
287- self . 0 . iter ( ) . take_while ( |w| !w. is_empty ( ) ) . map ( |w| * w)
303+ pub fn word_iter ( & self ) -> impl Iterator < Item = & ' static str > + Clone + ' _ {
304+ let list = self . lang . word_list ( ) ;
305+ self . words . iter ( ) . take_while ( |w| * * w != EOF ) . map ( move |w| list[ * w as usize ] )
288306 }
289307
290308 /// Determine the language of the mnemonic as a word iterator.
@@ -352,7 +370,7 @@ impl Mnemonic {
352370 /// word lists. In the extremely unlikely case that a word list can be
353371 /// interpreted in multiple languages, an [Error::AmbiguousLanguages] is
354372 /// returned, containing the possible languages.
355- fn language_of < S : AsRef < str > > ( mnemonic : S ) -> Result < Language , Error > {
373+ pub fn language_of < S : AsRef < str > > ( mnemonic : S ) -> Result < Language , Error > {
356374 Mnemonic :: language_of_iter ( mnemonic. as_ref ( ) . split_whitespace ( ) )
357375 }
358376
@@ -364,7 +382,7 @@ impl Mnemonic {
364382 }
365383
366384 // Here we will store the eventual words.
367- let mut words: [ & ' static str ; MAX_NB_WORDS ] = Default :: default ( ) ;
385+ let mut words = [ EOF ; MAX_NB_WORDS ] ;
368386
369387 // And here we keep track of the bits to calculate and validate the checksum.
370388 // We only use `nb_words * 11` elements in this array.
@@ -373,7 +391,7 @@ impl Mnemonic {
373391 for ( i, word) in s. split_whitespace ( ) . enumerate ( ) {
374392 let idx = language. find_word ( word) . ok_or ( Error :: UnknownWord ( i) ) ?;
375393
376- words[ i] = language . word_list ( ) [ idx] ;
394+ words[ i] = idx;
377395
378396 for j in 0 ..11 {
379397 bits[ i * 11 + j] = idx >> ( 10 - j) & 1 == 1 ;
@@ -398,7 +416,10 @@ impl Mnemonic {
398416 }
399417 }
400418
401- Ok ( Mnemonic ( words) )
419+ Ok ( Mnemonic {
420+ lang : language,
421+ words : words,
422+ } )
402423 }
403424
404425 /// Parse a mnemonic in normalized UTF8.
@@ -435,18 +456,17 @@ impl Mnemonic {
435456
436457 /// Get the number of words in the mnemonic.
437458 pub fn word_count ( & self ) -> usize {
438- self . 0 . iter ( ) . take_while ( |w| !w . is_empty ( ) ) . count ( )
459+ self . words . iter ( ) . take_while ( |w| * * w != EOF ) . count ( )
439460 }
440461
441462 /// Convert to seed bytes with a passphrase in normalized UTF8.
442463 pub fn to_seed_normalized ( & self , normalized_passphrase : & str ) -> [ u8 ; 64 ] {
443464 const PBKDF2_ROUNDS : usize = 2048 ;
444465 const PBKDF2_BYTES : usize = 64 ;
445466
446- let nb_words = self . word_count ( ) ;
447467 let mut seed = [ 0u8 ; PBKDF2_BYTES ] ;
448468 pbkdf2:: pbkdf2 (
449- & self . 0 [ 0 ..nb_words ] ,
469+ self . word_iter ( ) ,
450470 normalized_passphrase. as_bytes ( ) ,
451471 PBKDF2_ROUNDS ,
452472 & mut seed,
@@ -513,11 +533,7 @@ impl Mnemonic {
513533
514534impl fmt:: Display for Mnemonic {
515535 fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
516- for i in 0 ..self . 0 . len ( ) {
517- let word = & self . 0 [ i] ;
518- if word. is_empty ( ) {
519- break ;
520- }
536+ for ( i, word) in self . word_iter ( ) . enumerate ( ) {
521537 if i > 0 {
522538 f. write_str ( " " ) ?;
523539 }
0 commit comments