librustzcash/zcash_client_backend/examples/diversify-address.rs

85 lines
2.5 KiB
Rust

use std::convert::TryInto;
use gumdrop::Options;
use zcash_client_backend::encoding::{decode_extended_full_viewing_key, encode_payment_address};
use zcash_primitives::{
constants::{mainnet, testnet},
zip32::{DiversifierIndex, ExtendedFullViewingKey},
};
fn parse_viewing_key(s: &str) -> Result<(ExtendedFullViewingKey, bool), &'static str> {
decode_extended_full_viewing_key(mainnet::HRP_SAPLING_EXTENDED_FULL_VIEWING_KEY, s)
.ok()
.flatten()
.map(|vk| (vk, true))
.or_else(|| {
decode_extended_full_viewing_key(testnet::HRP_SAPLING_EXTENDED_FULL_VIEWING_KEY, s)
.ok()
.flatten()
.map(|vk| (vk, false))
})
.ok_or("Invalid Sapling viewing key")
}
fn parse_diversifier_index(s: &str) -> Result<DiversifierIndex, &'static str> {
let i: u128 = s.parse().map_err(|_| "Diversifier index is not a number")?;
if i >= (1 << 88) {
return Err("Diversifier index too large");
}
Ok(DiversifierIndex(i.to_le_bytes()[..11].try_into().unwrap()))
}
fn encode_diversifier_index(di: &DiversifierIndex) -> u128 {
let mut bytes = [0; 16];
bytes[..11].copy_from_slice(&di.0);
u128::from_le_bytes(bytes)
}
#[derive(Debug, Options)]
struct MyOptions {
#[options(help = "Print this help message and exit.")]
help: bool,
#[options(
free,
help = "The Sapling viewing key to generate diversified addresses from",
parse(try_from_str = "parse_viewing_key")
)]
viewing_key: Option<(ExtendedFullViewingKey, bool)>,
#[options(
free,
help = "The index of the diversified address to generate (default 0). Some indices don't have a corresponding address.",
parse(try_from_str = "parse_diversifier_index")
)]
diversifier_index: DiversifierIndex,
}
fn main() {
let opts = MyOptions::parse_args_default_or_exit();
let (extfvk, is_mainnet) = if let Some(res) = opts.viewing_key {
res
} else {
eprintln!("Missing Sapling viewing key");
return;
};
let (diversifier_index, address) = extfvk.find_address(opts.diversifier_index).unwrap();
println!(
"# Diversifier index: {}",
encode_diversifier_index(&diversifier_index)
);
println!(
"{}",
encode_payment_address(
if is_mainnet {
mainnet::HRP_SAPLING_PAYMENT_ADDRESS
} else {
testnet::HRP_SAPLING_PAYMENT_ADDRESS
},
&address
)
);
}