Avoid some unnecessary allocations

This commit is contained in:
Steven Roose 2020-09-22 12:35:52 +02:00
parent bc452184dc
commit cb9d5f91d8
No known key found for this signature in database
GPG Key ID: 2F2A88D7F8D68E87
1 changed files with 26 additions and 21 deletions

View File

@ -122,9 +122,10 @@ impl Mnemonic {
if (entropy.len() * 8) < 128 || (entropy.len() * 8) > 256 { if (entropy.len() * 8) < 128 || (entropy.len() * 8) > 256 {
return Err(Error::BadEntropyBitCount(entropy.len() * 8)); return Err(Error::BadEntropyBitCount(entropy.len() * 8));
} }
const MAX_ENTROPY_LEN: usize = 32;
let check = sha256::Hash::hash(&entropy); let check = sha256::Hash::hash(&entropy);
let mut bits = vec![false; entropy.len() * 8 + entropy.len() / 4]; let mut bits = [false; MAX_ENTROPY_LEN * 8 + MAX_ENTROPY_LEN / 4];
for i in 0..entropy.len() { for i in 0..entropy.len() {
for j in 0..8 { for j in 0..8 {
bits[i * 8 + j] = (entropy[i] & (1 << (7 - j))) > 0; bits[i * 8 + j] = (entropy[i] & (1 << (7 - j))) > 0;
@ -133,19 +134,20 @@ impl Mnemonic {
for i in 0..entropy.len() / 4 { for i in 0..entropy.len() / 4 {
bits[8 * entropy.len() + i] = (check[i / 8] & (1 << (7 - (i % 8)))) > 0; bits[8 * entropy.len() + i] = (check[i / 8] & (1 << (7 - (i % 8)))) > 0;
} }
let mlen = entropy.len() * 3 / 4;
let mut words = Vec::new(); let mut words: [&'static str; MAX_NB_WORDS] = Default::default();
for i in 0..mlen { let nb_words = entropy.len() * 3 / 4;
for i in 0..nb_words {
let mut idx = 0; let mut idx = 0;
for j in 0..11 { for j in 0..11 {
if bits[i * 11 + j] { if bits[i * 11 + j] {
idx += 1 << (10 - j); idx += 1 << (10 - j);
} }
} }
words.push(language.word_list()[idx]); words[i] = language.word_list()[idx];
} }
Ok(Mnemonic(words.join(" "))) Ok(Mnemonic(words[0..nb_words].join(" ")))
} }
/// Create a new English [Mnemonic] from the given entropy. /// Create a new English [Mnemonic] from the given entropy.
@ -164,8 +166,8 @@ impl Mnemonic {
let entropy_bytes = (word_count / 3) * 4; let entropy_bytes = (word_count / 3) * 4;
let mut rng = rand::thread_rng(); let mut rng = rand::thread_rng();
let mut entropy = vec![0u8; entropy_bytes]; let mut entropy = [0u8; (MAX_NB_WORDS / 3) * 4];
rand::RngCore::fill_bytes(&mut rng, &mut entropy); rand::RngCore::fill_bytes(&mut rng, &mut entropy[0..entropy_bytes]);
Mnemonic::from_entropy_in(language, &entropy) Mnemonic::from_entropy_in(language, &entropy)
} }
@ -178,13 +180,14 @@ impl Mnemonic {
/// Static method to validate a mnemonic in a given language. /// Static method to validate a mnemonic in a given language.
pub fn validate_in(language: Language, s: &str) -> Result<(), Error> { pub fn validate_in(language: Language, s: &str) -> Result<(), Error> {
let words: Vec<&str> = s.split_whitespace().collect(); let nb_words = s.split_whitespace().count();
if words.len() < 6 || words.len() % 6 != 0 || words.len() > MAX_NB_WORDS { if nb_words < 6 || nb_words % 6 != 0 || nb_words > MAX_NB_WORDS {
return Err(Error::BadWordCount(words.len())); return Err(Error::BadWordCount(nb_words));
} }
let mut bits = vec![false; words.len() * 11]; // We only use `nb_words * 11` elements in this array.
for (i, word) in words.iter().enumerate() { let mut bits = [false; MAX_NB_WORDS * 11];
for (i, word) in s.split_whitespace().enumerate() {
if let Some(idx) = language.find_word(word) { if let Some(idx) = language.find_word(word) {
for j in 0..11 { for j in 0..11 {
bits[i * 11 + j] = idx >> (10 - j) & 1 == 1; bits[i * 11 + j] = idx >> (10 - j) & 1 == 1;
@ -195,17 +198,19 @@ impl Mnemonic {
} }
// Verify the checksum. // Verify the checksum.
let mut entropy = vec![0u8; bits.len() / 33 * 4]; // We only use `nb_words / 3 * 4` elements in this array.
for i in 0..entropy.len() { let mut entropy = [0u8; MAX_NB_WORDS / 3 * 4];
let nb_bytes_entropy = nb_words / 3 * 4;
for i in 0..nb_bytes_entropy {
for j in 0..8 { for j in 0..8 {
if bits[i * 8 + j] { if bits[i * 8 + j] {
entropy[i] += 1 << (7 - j); entropy[i] += 1 << (7 - j);
} }
} }
} }
let check = sha256::Hash::hash(&entropy); let check = sha256::Hash::hash(&entropy[0..nb_bytes_entropy]);
for i in 0..entropy.len() / 4 { for i in 0..nb_bytes_entropy / 4 {
if bits[8 * entropy.len() + i] != ((check[i / 8] & (1 << (7 - (i % 8)))) > 0) { if bits[8 * nb_bytes_entropy + i] != ((check[i / 8] & (1 << (7 - (i % 8)))) > 0) {
return Err(Error::InvalidChecksum); return Err(Error::InvalidChecksum);
} }
} }
@ -319,8 +324,8 @@ impl Mnemonic {
let mut offset = 0; let mut offset = 0;
let mut remainder = 0; let mut remainder = 0;
let words: Vec<&str> = self.as_str().split_whitespace().collect(); let nb_words = self.as_str().split_whitespace().count();
for word in &words { for word in self.as_str().split_whitespace() {
let idx = language.find_word(word).unwrap(); let idx = language.find_word(word).unwrap();
remainder |= ((idx as u32) << (32 - 11)) >> offset; remainder |= ((idx as u32) << (32 - 11)) >> offset;
@ -338,7 +343,7 @@ impl Mnemonic {
} }
// Truncate to get rid of the byte containing the checksum // Truncate to get rid of the byte containing the checksum
let entropy_bytes = (words.len() / 3) * 4; let entropy_bytes = (nb_words / 3) * 4;
entropy.truncate(entropy_bytes); entropy.truncate(entropy_bytes);
entropy entropy
} }