Paper wallet for Hush, which you can use with no internet access while wearing a tinfoil hat inside of a Faraday cage. https://hush.is
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

134 lines
5.1 KiB

extern crate clap;
extern crate zecpaperlib;
mod version;
use clap::{Arg, App};
5 years ago
use zecpaperlib::paper::*;
use zecpaperlib::pdf;
use std::io;
use std::io::prelude::*;
fn main() {
let matches = App::new("zecpaperwaller")
.version(version::version())
.about("A command line Zcash Sapling paper wallet generator")
.arg(Arg::with_name("testnet")
.long("testnet")
5 years ago
.help("Generate Testnet addresses"))
.arg(Arg::with_name("format")
.short("f")
.long("format")
5 years ago
.help("What format to generate the output in")
.takes_value(true)
.value_name("FORMAT")
.possible_values(&["pdf", "json"])
5 years ago
.default_value("json"))
5 years ago
.arg(Arg::with_name("nohd")
.short("n")
.long("nohd")
.help("Don't reuse HD keys. Normally, zecpaperwallet will use the same HD key to derive multiple addresses. This flag will use a new seed for each address"))
.arg(Arg::with_name("output")
.short("o")
.long("output")
.index(1)
.help("Name of output file."))
5 years ago
.arg(Arg::with_name("entropy")
.short("e")
.long("entropy")
5 years ago
.takes_value(true)
5 years ago
.help("Provide additional entropy to the random number generator. Any random string, containing 32-64 characters"))
.arg(Arg::with_name("t_addresses")
.short("t")
.long("taddrs")
.help("Numbe rof T addresses to generate")
.takes_value(true)
.default_value("0")
.validator(|i:String| match i.parse::<i32>() {
Ok(_) => return Ok(()),
Err(_) => return Err(format!("Number of addresses '{}' is not a number", i))
}))
.arg(Arg::with_name("z_addresses")
.short("z")
5 years ago
.long("zaddrs")
.help("Number of Z addresses (Sapling) to generate")
.takes_value(true)
.default_value("1")
.validator(|i:String| match i.parse::<i32>() {
Ok(_) => return Ok(()),
Err(_) => return Err(format!("Number of addresses '{}' is not a number", i))
}))
.get_matches();
5 years ago
let testnet: bool = matches.is_present("testnet");
5 years ago
let nohd: bool = matches.is_present("nohd");
// Get the filename and output format
let filename = matches.value_of("output");
let format = matches.value_of("format").unwrap();
// Writing to PDF requires a filename
if format == "pdf" && filename.is_none() {
eprintln!("Need an output file name when writing to PDF");
return;
}
5 years ago
// 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();
// Writing to PDF requires a filename
if format == "pdf" && filename.is_none() {
eprintln!("Need an output file name when writing to PDF");
5 years ago
return;
}
// Number of t addresses to generate
let t_addresses = matches.value_of("t_addresses").unwrap().parse::<u32>().unwrap();
5 years ago
// Number of z addresses to generate
let z_addresses = matches.value_of("z_addresses").unwrap().parse::<u32>().unwrap();
print!("Generating {} Sapling addresses and {} Transparent addresses...", z_addresses, t_addresses);
io::stdout().flush().ok();
let addresses = generate_wallet(testnet, nohd, z_addresses, t_addresses, &entropy);
println!("[OK]");
// If the default format is present, write to the console if the filename is absent
if format == "json" {
if filename.is_none() {
println!("{}", addresses);
} else {
std::fs::write(filename.unwrap(), addresses).expect("Couldn't write to file!");
println!("Wrote {:?} as a plaintext file", filename);
}
} else if format == "pdf" {
// We already know the output file name was specified
print!("Writing {:?} as a PDF file...", filename.unwrap());
io::stdout().flush().ok();
5 years ago
match pdf::save_to_pdf(&addresses, filename.unwrap()) {
Ok(_) => { println!("[OK]");},
Err(e) => {
eprintln!("[ERROR]");
eprintln!("{}", e);
}
};
}
}