Browse Source

Add user entropy

taddr
Aditya Kulkarni 5 years ago
parent
commit
0ad84fd146
  1. 30
      cli/src/main.rs
  2. 27
      lib/Cargo.toml
  3. 46
      lib/src/paper.rs

30
cli/src/main.rs

@ -32,10 +32,14 @@ fn main() {
.long("output")
.index(1)
.help("Name of output file."))
.arg(Arg::with_name("entropy")
.short("e")
.long("entropy")
.help("Provide additional entropy to the random number generator. Any random string, containing 32-64 characters"))
.arg(Arg::with_name("z_addresses")
.short("z")
.long("z_addresses")
.help("Number of Z addresses (sapling) to generate")
.long("zaddrs")
.help("Number of Z addresses (Sapling) to generate")
.takes_value(true)
.default_value("1")
.validator(|i:String| match i.parse::<i32>() {
@ -48,6 +52,23 @@ fn main() {
let nohd: bool = matches.is_present("nohd");
// Get user entropy.
let mut entropy: Vec<u8> = Vec::new();
// If the user hasn't specified any, read from the stdin
if matches.value_of("entropy").is_none() {
// Read from stdin
println!("Provide additional entropy for generating random numbers. Type in a string of random characters, press [ENTER] when done");
let mut buffer = String::new();
let stdin = io::stdin();
stdin.lock().read_line(&mut buffer).unwrap();
entropy.extend_from_slice(buffer.as_bytes());
} else {
// Use provided entropy.
entropy.extend(matches.value_of("entropy").unwrap().as_bytes());
}
// Get the filename and output format
let filename = matches.value_of("output");
let format = matches.value_of("format").unwrap();
@ -57,11 +78,12 @@ fn main() {
return;
}
let num_addresses = matches.value_of("z_addresses").unwrap().parse::<u32>().unwrap();
// Number of z addresses to generate
let num_addresses = matches.value_of("z_addresses").unwrap().parse::<u32>().unwrap();
print!("Generating {} Sapling addresses.........", num_addresses);
io::stdout().flush().ok();
let addresses = generate_wallet(testnet, nohd, num_addresses);
let addresses = generate_wallet(testnet, nohd, num_addresses, &entropy);
println!("[OK]");
// If the default format is present, write to the console if the filename is absent

27
lib/Cargo.toml

@ -5,19 +5,20 @@ authors = ["ZecWallet"]
edition = "2018"
[dependencies]
bech32 = "0.6"
bellman = { git = "https://github.com/zcash/librustzcash" }
ff = { git = "https://github.com/zcash/librustzcash" }
hex = "0.3"
pairing = { git = "https://github.com/zcash/librustzcash" }
protobuf = "2"
rand = "0.5"
rusqlite = { version = "0.15", features = ["bundled"], optional = true }
sapling-crypto = { git = "https://github.com/zcash/librustzcash" }
time = { version = "0.1", optional = true }
zcash_primitives = { git = "https://github.com/zcash/librustzcash" }
zcash_proofs = { git = "https://github.com/zcash/librustzcash" }
zip32 = { git = "https://github.com/zcash/librustzcash" }
hex = "0.3"
bech32 = "0.6"
bellman = { git = "https://github.com/zcash/librustzcash", rev="3b6f5e3d5ede6469f6ae85357f0b03d4c1b45cfe" }
ff = { git = "https://github.com/zcash/librustzcash", rev="3b6f5e3d5ede6469f6ae85357f0b03d4c1b45cfe" }
pairing = { git = "https://github.com/zcash/librustzcash", rev="3b6f5e3d5ede6469f6ae85357f0b03d4c1b45cfe" }
sapling-crypto = { git = "https://github.com/zcash/librustzcash", rev="3b6f5e3d5ede6469f6ae85357f0b03d4c1b45cfe" }
zcash_primitives = { git = "https://github.com/zcash/librustzcash", rev="3b6f5e3d5ede6469f6ae85357f0b03d4c1b45cfe" }
zcash_proofs = { git = "https://github.com/zcash/librustzcash", rev="3b6f5e3d5ede6469f6ae85357f0b03d4c1b45cfe" }
zip32 = { git = "https://github.com/zcash/librustzcash", rev="3b6f5e3d5ede6469f6ae85357f0b03d4c1b45cfe" }
json = "0.11.14"
qrcode = { version = "0.8", default-features = false }
printpdf = "0.2.8"
printpdf = "0.2.8"
blake2-rfc = { git = "https://github.com/gtank/blake2-rfc", rev="7a5b5fc99ae483a0043db7547fb79a6fa44b88a9" }

46
lib/src/paper.rs

@ -1,25 +1,41 @@
use zip32::{ChildIndex, ExtendedSpendingKey};
use bech32::{Bech32, u5, ToBase32};
use rand::{Rng, ChaChaRng, FromEntropy};
use rand::{Rng, ChaChaRng, FromEntropy, SeedableRng};
use json::{array, object};
use blake2_rfc::blake2b::Blake2b;
/**
* Generate a series of `count` addresses and private keys.
*/
pub fn generate_wallet(testnet: bool, nohd: bool, count: u32) -> String {
pub fn generate_wallet(testnet: bool, nohd: bool, count: u32, user_entropy: &[u8]) -> String {
// Get 32 bytes of system entropy
let mut system_entropy:[u8; 32] = [0; 32];
{
let mut system_rng = ChaChaRng::from_entropy();
system_rng.fill(&mut system_entropy);
}
// Add in user entropy to the system entropy, and produce a 32 byte hash...
let mut state = Blake2b::new(32);
state.update(&system_entropy);
state.update(&user_entropy);
let mut final_entropy: [u8; 32] = [0; 32];
final_entropy.clone_from_slice(&state.finalize().as_bytes()[0..32]);
// ...which will we use to seed the RNG
let mut rng = ChaChaRng::from_seed(final_entropy);
if !nohd {
// Allow HD addresses, so use only 1 seed
let mut rng = ChaChaRng::from_entropy();
let mut seed:[u8; 32] = [0; 32];
// Allow HD addresses, so use only 1 seed
let mut seed: [u8; 32] = [0; 32];
rng.fill(&mut seed);
return gen_addresses_with_seed_as_json(testnet, count, |i| (seed.to_vec(), i));
} else {
// Not using HD addresses, so derive a new seed every time
return gen_addresses_with_seed_as_json(testnet, count, |_| {
let mut rng = ChaChaRng::from_entropy();
// Not using HD addresses, so derive a new seed every time
return gen_addresses_with_seed_as_json(testnet, count, |_| {
let mut seed:[u8; 32] = [0; 32];
rng.fill(&mut seed);
@ -39,8 +55,8 @@ pub fn generate_wallet(testnet: bool, nohd: bool, count: u32) -> String {
*
* It is useful if we want to reuse (or not) the seed across multiple wallets.
*/
fn gen_addresses_with_seed_as_json<F>(testnet: bool, count: u32, get_seed: F) -> String
where F: Fn(u32) -> (Vec<u8>, u32)
fn gen_addresses_with_seed_as_json<F>(testnet: bool, count: u32, mut get_seed: F) -> String
where F: FnMut(u32) -> (Vec<u8>, u32)
{
let mut ans = array![];
@ -113,7 +129,7 @@ mod tests {
use std::collections::HashSet;
// Testnet wallet
let w = generate_wallet(true, false, 1);
let w = generate_wallet(true, false, 1, &[]);
let j = json::parse(&w).unwrap();
assert_eq!(j.len(), 1);
assert!(j[0]["address"].as_str().unwrap().starts_with("ztestsapling"));
@ -122,7 +138,7 @@ mod tests {
// Mainnet wallet
let w = generate_wallet(false, false, 1);
let w = generate_wallet(false, false, 1, &[]);
let j = json::parse(&w).unwrap();
assert_eq!(j.len(), 1);
assert!(j[0]["address"].as_str().unwrap().starts_with("zs"));
@ -130,7 +146,7 @@ mod tests {
assert_eq!(j[0]["seed"]["path"].as_str().unwrap(), "m/32'/133'/0'");
// Check if all the addresses are the same
let w = generate_wallet(true, false, 3);
let w = generate_wallet(true, false, 3, &[]);
let j = json::parse(&w).unwrap();
assert_eq!(j.len(), 3);
@ -161,7 +177,7 @@ mod tests {
use std::collections::HashSet;
// Check if all the addresses use a different seed
let w = generate_wallet(true, true, 3);
let w = generate_wallet(true, true, 3, &[]);
let j = json::parse(&w).unwrap();
assert_eq!(j.len(), 3);

Loading…
Cancel
Save