Derive Zip32 tool
This commit is contained in:
parent
880fa1b4cb
commit
82a1872ccc
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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()))
|
||||
}
|
||||
|
|
|
@ -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")]
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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,
|
||||
})
|
||||
}
|
Loading…
Reference in New Issue