Skip to content

Commit c822608

Browse files
committed
rename entropy choices, check checksum while re-creating mnemoning from string
1 parent fc69b39 commit c822608

File tree

4 files changed

+46
-33
lines changed

4 files changed

+46
-33
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "bitcoin-wallet"
3-
version = "1.0.1"
3+
version = "1.1.0"
44
authors = ["Tamas Blummer <tamas.blummer@gmail.com>"]
55
license = "Apache-2.0"
66
homepage = "https://github.com/rust-bitcoin/rust-wallet/"

src/account.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,8 @@ use crate::mnemonic::Mnemonic;
5353
/// chose your security level
5454
#[derive(Copy, Clone)]
5555
pub enum MasterKeyEntropy {
56-
Low = 16,
57-
Recommended = 32,
56+
Sufficient = 16,
57+
Double = 32,
5858
Paranoid = 64,
5959
}
6060

@@ -918,7 +918,7 @@ mod test {
918918
#[test]
919919
fn test_pkh() {
920920
let mut master =
921-
MasterAccount::new(MasterKeyEntropy::Low, Network::Bitcoin, PASSPHRASE).unwrap();
921+
MasterAccount::new(MasterKeyEntropy::Sufficient, Network::Bitcoin, PASSPHRASE).unwrap();
922922
let mut unlocker = Unlocker::new_for_master(&master, PASSPHRASE).unwrap();
923923
let account = Account::new(&mut unlocker, AccountAddressType::P2PKH, 0, 0, 10).unwrap();
924924
master.add_account(account);
@@ -987,7 +987,7 @@ mod test {
987987
#[test]
988988
fn test_wpkh() {
989989
let mut master =
990-
MasterAccount::new(MasterKeyEntropy::Low, Network::Bitcoin, PASSPHRASE).unwrap();
990+
MasterAccount::new(MasterKeyEntropy::Sufficient, Network::Bitcoin, PASSPHRASE).unwrap();
991991
let mut unlocker = Unlocker::new_for_master(&master, PASSPHRASE).unwrap();
992992
let account = Account::new(&mut unlocker, AccountAddressType::P2WPKH, 0, 0, 10).unwrap();
993993
master.add_account(account);
@@ -1057,7 +1057,7 @@ mod test {
10571057
#[test]
10581058
fn test_shwpkh() {
10591059
let mut master =
1060-
MasterAccount::new(MasterKeyEntropy::Low, Network::Bitcoin, PASSPHRASE).unwrap();
1060+
MasterAccount::new(MasterKeyEntropy::Sufficient, Network::Bitcoin, PASSPHRASE).unwrap();
10611061
let mut unlocker = Unlocker::new_for_master(&master, PASSPHRASE).unwrap();
10621062
let account = Account::new(&mut unlocker, AccountAddressType::P2SHWPKH, 0, 0, 10).unwrap();
10631063
master.add_account(account);
@@ -1128,7 +1128,7 @@ mod test {
11281128
#[test]
11291129
fn test_wsh() {
11301130
let mut master =
1131-
MasterAccount::new(MasterKeyEntropy::Low, Network::Bitcoin, PASSPHRASE).unwrap();
1131+
MasterAccount::new(MasterKeyEntropy::Sufficient, Network::Bitcoin, PASSPHRASE).unwrap();
11321132
let mut unlocker = Unlocker::new_for_master(&master, PASSPHRASE).unwrap();
11331133
let account =
11341134
Account::new(&mut unlocker, AccountAddressType::P2WSH(4711), 0, 0, 0).unwrap();
@@ -1213,7 +1213,7 @@ mod test {
12131213
#[test]
12141214
fn test_wsh_csv() {
12151215
let mut master =
1216-
MasterAccount::new(MasterKeyEntropy::Low, Network::Bitcoin, PASSPHRASE).unwrap();
1216+
MasterAccount::new(MasterKeyEntropy::Sufficient, Network::Bitcoin, PASSPHRASE).unwrap();
12171217
let mut unlocker = Unlocker::new_for_master(&master, PASSPHRASE).unwrap();
12181218
let account =
12191219
Account::new(&mut unlocker, AccountAddressType::P2WSH(4711), 0, 0, 0).unwrap();

src/mnemonic.rs

Lines changed: 37 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
//!
1919
//! TREZOR compatible mnemonic in english
2020
//!
21+
use bitcoin::util::bip158::{BitStreamReader, BitStreamWriter};
2122
use account::Seed;
2223
use crypto::{
2324
digest::Digest,
@@ -26,6 +27,7 @@ use crypto::{
2627
sha2::{Sha256, Sha512},
2728
};
2829
use error::Error;
30+
use std::io::Cursor;
2931

3032
#[derive(Clone, Eq, PartialEq, Debug)]
3133
pub 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(),

src/sss.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -692,7 +692,7 @@ mod test {
692692
#[test]
693693
pub fn reconstruct() {
694694
let master =
695-
MasterAccount::new(MasterKeyEntropy::Low, Network::Bitcoin, PASSPHRASE).unwrap();
695+
MasterAccount::new(MasterKeyEntropy::Sufficient, Network::Bitcoin, PASSPHRASE).unwrap();
696696
let seed = master.seed(Network::Bitcoin, PASSPHRASE).unwrap();
697697
let shares = ShamirSecretSharing::generate(1, &[(3, 5)], &seed, None, 1).unwrap();
698698
let reconstructed_seed = ShamirSecretSharing::combine(&shares[..3], None).unwrap();

0 commit comments

Comments
 (0)