From 3ebc46185c03e80d698ad03c5cede065df686ee1 Mon Sep 17 00:00:00 2001 From: Aditya Kulkarni Date: Sat, 19 Oct 2019 16:23:32 -0700 Subject: [PATCH] Add bug detection --- lib/src/commands.rs | 65 ++++++++++++++++++++++++++++--------- lib/src/lightwallet.rs | 2 +- lib/src/lightwallet/bugs.rs | 40 +++++++++++++++++++++++ 3 files changed, 91 insertions(+), 16 deletions(-) create mode 100644 lib/src/lightwallet/bugs.rs diff --git a/lib/src/commands.rs b/lib/src/commands.rs index 7f4b2de..7c57b7c 100644 --- a/lib/src/commands.rs +++ b/lib/src/commands.rs @@ -444,6 +444,40 @@ impl Command for NotesCommand { } } +struct FixBip39BugCommand {} +impl Command for FixBip39BugCommand { + fn help(&self) -> String { + let mut h = vec![]; + h.push("Detect if the wallet has the Bip39 derivation bug, and fix it automatically"); + h.push("Usage:"); + h.push("fixbip39bug"); + h.push(""); + + h.join("\n") + } + + fn short_help(&self) -> String { + "Detect if the wallet has the Bip39 derivation bug, and fix it automatically".to_string() + } + + fn exec(&self, _args: &[&str], lightclient: &LightClient) -> String { + use crate::lightwallet::bugs::BugBip39Derivation; + + let r = if BugBip39Derivation::has_bug(&lightclient.wallet.read().unwrap()) { + object!{ + "has_bug" => true, + "fixed" => false, + } + } else { + object!{ + "has_bug" => false, + "fixed" => false, + } + }; + + r.pretty(2) + } +} struct QuitCommand {} impl Command for QuitCommand { @@ -469,21 +503,22 @@ impl Command for QuitCommand { pub fn get_commands() -> Box>> { let mut map: HashMap> = HashMap::new(); - map.insert("sync".to_string(), Box::new(SyncCommand{})); - map.insert("rescan".to_string(), Box::new(RescanCommand{})); - map.insert("help".to_string(), Box::new(HelpCommand{})); - map.insert("balance".to_string(), Box::new(BalanceCommand{})); - map.insert("addresses".to_string(), Box::new(AddressCommand{})); - map.insert("height".to_string(), Box::new(HeightCommand{})); - map.insert("export".to_string(), Box::new(ExportCommand{})); - map.insert("info".to_string(), Box::new(InfoCommand{})); - map.insert("send".to_string(), Box::new(SendCommand{})); - map.insert("save".to_string(), Box::new(SaveCommand{})); - map.insert("quit".to_string(), Box::new(QuitCommand{})); - map.insert("list".to_string(), Box::new(TransactionsCommand{})); - map.insert("notes".to_string(), Box::new(NotesCommand{})); - map.insert("new".to_string(), Box::new(NewAddressCommand{})); - map.insert("seed".to_string(), Box::new(SeedCommand{})); + map.insert("sync".to_string(), Box::new(SyncCommand{})); + map.insert("rescan".to_string(), Box::new(RescanCommand{})); + map.insert("help".to_string(), Box::new(HelpCommand{})); + map.insert("balance".to_string(), Box::new(BalanceCommand{})); + map.insert("addresses".to_string(), Box::new(AddressCommand{})); + map.insert("height".to_string(), Box::new(HeightCommand{})); + map.insert("export".to_string(), Box::new(ExportCommand{})); + map.insert("info".to_string(), Box::new(InfoCommand{})); + map.insert("send".to_string(), Box::new(SendCommand{})); + map.insert("save".to_string(), Box::new(SaveCommand{})); + map.insert("quit".to_string(), Box::new(QuitCommand{})); + map.insert("list".to_string(), Box::new(TransactionsCommand{})); + map.insert("notes".to_string(), Box::new(NotesCommand{})); + map.insert("new".to_string(), Box::new(NewAddressCommand{})); + map.insert("seed".to_string(), Box::new(SeedCommand{})); + map.insert("fixbip39bug".to_string(), Box::new(FixBip39BugCommand{})); Box::new(map) } diff --git a/lib/src/lightwallet.rs b/lib/src/lightwallet.rs index 5d76af7..e29a12e 100644 --- a/lib/src/lightwallet.rs +++ b/lib/src/lightwallet.rs @@ -47,6 +47,7 @@ mod extended_key; mod utils; mod address; mod prover; +pub mod bugs; use data::{BlockData, WalletTx, Utxo, SaplingNoteData, SpendableNote, OutgoingTxMetadata}; use extended_key::{KeyIndex, ExtendedPrivKey}; @@ -626,7 +627,6 @@ impl LightWallet { format!("fvk mismatch at {}. {:?} vs {:?}", pos, extfvk, self.extfvks.read().unwrap()[pos]))); } - // Don't add it to self yet, we'll do that at the end when everything is verified extsks.push(extsk); } diff --git a/lib/src/lightwallet/bugs.rs b/lib/src/lightwallet/bugs.rs new file mode 100644 index 0000000..52dc82f --- /dev/null +++ b/lib/src/lightwallet/bugs.rs @@ -0,0 +1,40 @@ +use super::LightWallet; + +use bip39::{Mnemonic, Language}; + +pub struct BugBip39Derivation {} + +impl BugBip39Derivation { + + pub fn has_bug(wallet: &LightWallet) -> bool { + if wallet.zaddress.read().unwrap().len() <= 1 { + return false; + } + + // The seed bytes is the raw entropy. To pass it to HD wallet generation, + // we need to get the 64 byte bip39 entropy + let bip39_seed = bip39::Seed::new(&Mnemonic::from_entropy(&wallet.seed, Language::English).unwrap(), ""); + + // Check z addresses + for pos in 0..wallet.zaddress.read().unwrap().len() { + let (_, _, address) = + LightWallet::get_zaddr_from_bip39seed(&wallet.config, &bip39_seed.as_bytes(), pos as u32); + + if address != wallet.zaddress.read().unwrap()[pos] { + return true; + } + } + + // Check t addresses + for pos in 0..wallet.taddresses.read().unwrap().len() { + let sk = LightWallet::get_taddr_from_bip39seed(&wallet.config, &bip39_seed.as_bytes(), pos as u32); + let address = wallet.address_from_sk(&sk); + + if address != wallet.taddresses.read().unwrap()[pos] { + return true; + } + } + + false + } +} \ No newline at end of file