Derive Zip32 tool

This commit is contained in:
Hanh 2022-07-27 10:11:36 +08:00
parent 880fa1b4cb
commit 82a1872ccc
7 changed files with 140 additions and 2 deletions

View File

@ -121,3 +121,10 @@ char *get_tx_summary(char *tx);
char *get_best_server(char **servers, uint32_t count);
void import_from_zwl(uint8_t coin, char *name, char *data);
char *derive_zip32(uint8_t coin,
uint32_t id_account,
uint32_t account,
uint32_t external,
bool has_address,
uint32_t address);

View File

@ -3,6 +3,7 @@
use crate::coinconfig::CoinConfig;
use crate::key2::decode_key;
use crate::taddr::{derive_taddr, derive_tkeys};
use crate::{derive_zip32, KeyPack};
use anyhow::anyhow;
use bip39::{Language, Mnemonic};
use rand::rngs::OsRng;
@ -164,3 +165,17 @@ pub fn import_from_zwl(coin: u8, name: &str, data: &str) -> anyhow::Result<()> {
}
Ok(())
}
pub fn derive_keys(
coin: u8,
id_account: u32,
account: u32,
external: u32,
address: Option<u32>,
) -> anyhow::Result<KeyPack> {
let c = CoinConfig::get(coin);
let db = c.db()?;
let (seed, _) = db.get_seed(id_account)?;
let seed = seed.unwrap();
derive_zip32(c.chain.network(), &seed, account, external, address)
}

View File

@ -617,3 +617,21 @@ pub unsafe extern "C" fn import_from_zwl(coin: u8, name: *mut c_char, data: *mut
let res = crate::api::account::import_from_zwl(coin, &name, &data);
log_result(res)
}
#[no_mangle]
pub unsafe extern "C" fn derive_zip32(
coin: u8,
id_account: u32,
account: u32,
external: u32,
has_address: bool,
address: u32,
) -> *mut c_char {
let res = || {
let address = if has_address { Some(address) } else { None };
let kp = crate::api::account::derive_keys(coin, id_account, account, external, address)?;
let result = serde_json::to_string(&kp)?;
Ok(result)
};
to_c_str(log_string(res()))
}

View File

@ -38,6 +38,7 @@ mod scan;
mod taddr;
mod transaction;
mod ua;
mod zip32;
// mod wallet;
pub mod api;
@ -82,6 +83,7 @@ pub use crate::pay::{broadcast_tx, get_tx_summary, Tx, TxIn, TxOut};
pub use crate::print::*;
pub use crate::scan::{latest_height, sync_async};
pub use crate::ua::{get_sapling, get_ua};
pub use zip32::{derive_zip32, KeyPack};
// pub use crate::wallet::{decrypt_backup, encrypt_backup, RecipientMemo, Wallet, WalletBalance};
#[cfg(feature = "ledger_sapling")]

View File

@ -13,7 +13,9 @@ use std::sync::atomic::AtomicBool;
use thiserror::Error;
use warp_api_ffi::api::payment::{Recipient, RecipientMemo};
use warp_api_ffi::api::payment_uri::PaymentURI;
use warp_api_ffi::{get_best_server, AccountRec, CoinConfig, RaptorQDrops, Tx, TxRec};
use warp_api_ffi::{
derive_zip32, get_best_server, AccountRec, CoinConfig, KeyPack, RaptorQDrops, Tx, TxRec,
};
lazy_static! {
static ref SYNC_CANCELED: AtomicBool = AtomicBool::new(false);
@ -95,6 +97,7 @@ async fn main() -> anyhow::Result<()> {
parse_payment_uri,
split_data,
merge_data,
derive_keys,
],
)
.attach(AdHoc::config::<Config>())
@ -299,6 +302,18 @@ pub fn merge_data(data: String) -> Result<String, Error> {
Ok(result)
}
#[post("/zip32?<seed>&<account>&<external>&<address>")]
pub fn derive_keys(
seed: String,
account: u32,
external: u32,
address: Option<u32>,
) -> Result<Json<KeyPack>, Error> {
let active = CoinConfig::get_active();
let result = warp_api_ffi::api::account::derive_keys(active.coin, active.id, account, external, address)?;
Ok(Json(result))
}
#[derive(Deserialize)]
#[serde(crate = "rocket::serde")]
pub struct Config {

View File

@ -98,7 +98,10 @@ pub fn derive_taddr(network: &Network, key: &str) -> anyhow::Result<(String, Str
derive_from_secretkey(network, &secret_key)
}
fn derive_from_secretkey(network: &Network, sk: &SecretKey) -> anyhow::Result<(String, String)> {
pub fn derive_from_secretkey(
network: &Network,
sk: &SecretKey,
) -> anyhow::Result<(String, String)> {
let secp = Secp256k1::<All>::new();
let pub_key = PublicKey::from_secret_key(&secp, &sk);
let pub_key = pub_key.serialize();

78
src/zip32.rs Normal file
View File

@ -0,0 +1,78 @@
use anyhow::anyhow;
use base58check::ToBase58Check;
use bip39::{Language, Mnemonic, Seed};
use ripemd::{Digest, Ripemd160};
use secp256k1::{All, PublicKey, Secp256k1, SecretKey};
use serde::Serialize;
use sha2::Sha256;
use tiny_hderive::bip32::ExtendedPrivKey;
use zcash_client_backend::encoding::{
encode_extended_spending_key, encode_payment_address, encode_transparent_address,
};
use zcash_primitives::consensus::{Network, Parameters};
use zcash_primitives::legacy::TransparentAddress;
use zcash_primitives::zip32::{ChildIndex, ExtendedSpendingKey};
#[derive(Serialize)]
pub struct KeyPack {
pub t_addr: String,
pub t_key: String,
pub z_addr: String,
pub z_key: String,
}
pub fn derive_zip32(
network: &Network,
phrase: &str,
account_index: u32,
external: u32,
address_index: Option<u32>,
) -> anyhow::Result<KeyPack> {
let mnemonic = Mnemonic::from_phrase(phrase, Language::English)?;
let seed = Seed::new(&mnemonic, "");
let master = ExtendedSpendingKey::master(seed.as_bytes());
let mut z_path = vec![
ChildIndex::Hardened(32),
ChildIndex::Hardened(network.coin_type()),
ChildIndex::Hardened(account_index),
];
if let Some(address_index) = address_index {
z_path.push(ChildIndex::Hardened(address_index));
}
let extsk = ExtendedSpendingKey::from_path(&master, &z_path);
let z_key = encode_extended_spending_key(network.hrp_sapling_extended_spending_key(), &extsk);
let (_, pa) = extsk.default_address();
let z_addr = encode_payment_address(network.hrp_sapling_payment_address(), &pa);
let addr_index = address_index.unwrap_or(0);
let t_path = format!(
"m/44'/{}'/{}'/{}/{}",
network.coin_type(),
account_index,
external,
addr_index
);
let ext = ExtendedPrivKey::derive(seed.as_bytes(), &*t_path)
.map_err(|_| anyhow!("Invalid derivation path"))?;
let secret_key = SecretKey::from_slice(&ext.secret())?;
let secp = Secp256k1::<All>::new();
let pub_key = PublicKey::from_secret_key(&secp, &secret_key);
let pub_key = pub_key.serialize();
let pub_key = Ripemd160::digest(&Sha256::digest(&pub_key));
let t_addr = TransparentAddress::PublicKey(pub_key.into());
let t_addr = encode_transparent_address(
&network.b58_pubkey_address_prefix(),
&network.b58_script_address_prefix(),
&t_addr,
);
let mut sk = secret_key.serialize_secret().to_vec();
sk.push(0x01);
let t_key = sk.to_base58check(0x80);
Ok(KeyPack {
z_key,
z_addr,
t_key,
t_addr,
})
}