BIP39 + extra word
This commit is contained in:
parent
3205a4fe59
commit
6bbe39c236
115
src/key.rs
115
src/key.rs
|
@ -1,115 +0,0 @@
|
|||
//! DEAD CODE - Candidate for deletion
|
||||
//!
|
||||
|
||||
use bech32::{ToBase32, Variant};
|
||||
use bip39::{Language, Mnemonic, Seed};
|
||||
use rand::rngs::OsRng;
|
||||
use rand::RngCore;
|
||||
use zcash_client_backend::address::RecipientAddress;
|
||||
use zcash_client_backend::encoding::{
|
||||
decode_extended_full_viewing_key, decode_extended_spending_key,
|
||||
encode_extended_full_viewing_key, encode_extended_spending_key, encode_payment_address,
|
||||
};
|
||||
use zcash_params::coin::{get_coin_chain, CoinChain, CoinType};
|
||||
use zcash_primitives::consensus::Parameters;
|
||||
use zcash_primitives::zip32::{ChildIndex, ExtendedFullViewingKey, ExtendedSpendingKey};
|
||||
|
||||
pub struct KeyHelpers {
|
||||
coin_type: CoinType,
|
||||
}
|
||||
|
||||
impl KeyHelpers {
|
||||
pub fn new(coin_type: CoinType) -> Self {
|
||||
KeyHelpers { coin_type }
|
||||
}
|
||||
|
||||
fn chain(&self) -> &dyn CoinChain {
|
||||
get_coin_chain(self.coin_type)
|
||||
}
|
||||
|
||||
pub fn decode_key(
|
||||
&self,
|
||||
key: &str,
|
||||
index: u32,
|
||||
) -> anyhow::Result<(Option<String>, Option<String>, String, String)> {
|
||||
let network = self.chain().network();
|
||||
let res = if let Ok(mnemonic) = Mnemonic::from_phrase(key, Language::English) {
|
||||
let (sk, ivk, pa) = self.derive_secret_key(&mnemonic, index)?;
|
||||
Ok((Some(key.to_string()), Some(sk), ivk, pa))
|
||||
} else if let Ok(sk) =
|
||||
decode_extended_spending_key(network.hrp_sapling_extended_spending_key(), key)
|
||||
{
|
||||
let (ivk, pa) = self.derive_viewing_key(&sk)?;
|
||||
Ok((None, Some(key.to_string()), ivk, pa))
|
||||
} else if let Ok(fvk) =
|
||||
decode_extended_full_viewing_key(network.hrp_sapling_extended_full_viewing_key(), key)
|
||||
{
|
||||
let pa = self.derive_address(&fvk)?;
|
||||
Ok((None, None, key.to_string(), pa))
|
||||
} else {
|
||||
Err(anyhow::anyhow!("Not a valid key"))
|
||||
};
|
||||
res
|
||||
}
|
||||
|
||||
pub fn is_valid_key(&self, key: &str) -> i8 {
|
||||
let network = self.chain().network();
|
||||
if Mnemonic::from_phrase(key, Language::English).is_ok() {
|
||||
return 0;
|
||||
}
|
||||
if decode_extended_spending_key(network.hrp_sapling_extended_spending_key(), key).is_ok()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
if decode_extended_full_viewing_key(network.hrp_sapling_extended_full_viewing_key(), key).is_ok()
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
-1
|
||||
}
|
||||
|
||||
pub fn derive_secret_key(
|
||||
&self,
|
||||
mnemonic: &Mnemonic,
|
||||
index: u32,
|
||||
) -> anyhow::Result<(String, String, String)> {
|
||||
let network = self.chain().network();
|
||||
let seed = Seed::new(mnemonic, "");
|
||||
let master = ExtendedSpendingKey::master(seed.as_bytes());
|
||||
let path = [
|
||||
ChildIndex::Hardened(32),
|
||||
ChildIndex::Hardened(network.coin_type()),
|
||||
ChildIndex::Hardened(index),
|
||||
];
|
||||
let extsk = ExtendedSpendingKey::from_path(&master, &path);
|
||||
let sk = encode_extended_spending_key(network.hrp_sapling_extended_spending_key(), &extsk);
|
||||
|
||||
let (fvk, pa) = self.derive_viewing_key(&extsk)?;
|
||||
Ok((sk, fvk, pa))
|
||||
}
|
||||
|
||||
pub fn derive_viewing_key(
|
||||
&self,
|
||||
extsk: &ExtendedSpendingKey,
|
||||
) -> anyhow::Result<(String, String)> {
|
||||
let network = self.chain().network();
|
||||
let fvk = ExtendedFullViewingKey::from(extsk);
|
||||
let pa = self.derive_address(&fvk)?;
|
||||
let fvk =
|
||||
encode_extended_full_viewing_key(network.hrp_sapling_extended_full_viewing_key(), &fvk);
|
||||
Ok((fvk, pa))
|
||||
}
|
||||
|
||||
pub fn derive_address(&self, fvk: &ExtendedFullViewingKey) -> anyhow::Result<String> {
|
||||
let network = self.chain().network();
|
||||
let (_, payment_address) = fvk.default_address();
|
||||
let address =
|
||||
encode_payment_address(network.hrp_sapling_payment_address(), &payment_address);
|
||||
Ok(address)
|
||||
}
|
||||
|
||||
pub fn valid_address(&self, address: &str) -> bool {
|
||||
let recipient = RecipientAddress::decode(self.chain().network(), address);
|
||||
recipient.is_some()
|
||||
}
|
||||
}
|
27
src/key2.rs
27
src/key2.rs
|
@ -10,6 +10,20 @@ use zcash_client_backend::keys::UnifiedFullViewingKey;
|
|||
use zcash_primitives::consensus::{Network, Parameters};
|
||||
use zcash_primitives::zip32::{ChildIndex, ExtendedFullViewingKey, ExtendedSpendingKey};
|
||||
|
||||
pub fn split_key(key: &str) -> (String, String) {
|
||||
let words: Vec<_> = key.split_whitespace().collect();
|
||||
let len = words.len();
|
||||
let (phrase, password) = if len % 3 == 1 {
|
||||
// extra word
|
||||
let phrase = words[0..len - 1].join(" ");
|
||||
let password = words[len - 1].to_string();
|
||||
(phrase, password)
|
||||
} else {
|
||||
(key.to_string(), String::new())
|
||||
};
|
||||
(phrase, password)
|
||||
}
|
||||
|
||||
pub fn decode_key(
|
||||
coin: u8,
|
||||
key: &str,
|
||||
|
@ -23,8 +37,9 @@ pub fn decode_key(
|
|||
)> {
|
||||
let c = CoinConfig::get(coin);
|
||||
let network = c.chain.network();
|
||||
let res = if let Ok(mnemonic) = Mnemonic::from_phrase(key, Language::English) {
|
||||
let (sk, ivk, pa) = derive_secret_key(network, &mnemonic, index)?;
|
||||
let (phrase, password) = split_key(key);
|
||||
let res = if let Ok(mnemonic) = Mnemonic::from_phrase(&phrase, Language::English) {
|
||||
let (sk, ivk, pa) = derive_secret_key(network, &mnemonic, &password, index)?;
|
||||
Ok((Some(key.to_string()), Some(sk), ivk, pa, None))
|
||||
} else if let Ok(sk) =
|
||||
decode_extended_spending_key(network.hrp_sapling_extended_spending_key(), key)
|
||||
|
@ -59,7 +74,8 @@ pub fn decode_key(
|
|||
pub fn is_valid_key(coin: u8, key: &str) -> i8 {
|
||||
let c = CoinConfig::get(coin);
|
||||
let network = c.chain.network();
|
||||
if Mnemonic::from_phrase(key, Language::English).is_ok() {
|
||||
let (phrase, _password) = split_key(key);
|
||||
if Mnemonic::from_phrase(&phrase, Language::English).is_ok() {
|
||||
return 0;
|
||||
}
|
||||
if decode_extended_spending_key(network.hrp_sapling_extended_spending_key(), key).is_ok() {
|
||||
|
@ -80,15 +96,16 @@ pub fn is_valid_key(coin: u8, key: &str) -> i8 {
|
|||
pub fn decode_address(coin: u8, address: &str) -> Option<RecipientAddress> {
|
||||
let c = CoinConfig::get(coin);
|
||||
let network = c.chain.network();
|
||||
zcash_client_backend::address::RecipientAddress::decode(network, address)
|
||||
RecipientAddress::decode(network, address)
|
||||
}
|
||||
|
||||
fn derive_secret_key(
|
||||
network: &Network,
|
||||
mnemonic: &Mnemonic,
|
||||
password: &str,
|
||||
index: u32,
|
||||
) -> anyhow::Result<(String, String, String)> {
|
||||
let seed = Seed::new(mnemonic, "");
|
||||
let seed = Seed::new(mnemonic, password);
|
||||
let master = ExtendedSpendingKey::master(seed.as_bytes());
|
||||
let path = [
|
||||
ChildIndex::Hardened(32),
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
use crate::key2::split_key;
|
||||
use bip39::{Language, Mnemonic, Seed};
|
||||
use orchard::keys::{FullViewingKey, Scope, SpendingKey};
|
||||
use orchard::Address;
|
||||
|
@ -16,8 +17,9 @@ impl OrchardKeyBytes {
|
|||
}
|
||||
|
||||
pub fn derive_orchard_keys(coin_type: u32, seed: &str, account_index: u32) -> OrchardKeyBytes {
|
||||
let mnemonic = Mnemonic::from_phrase(seed, Language::English).unwrap();
|
||||
let seed = Seed::new(&mnemonic, "");
|
||||
let (phrase, password) = split_key(seed);
|
||||
let mnemonic = Mnemonic::from_phrase(&phrase, Language::English).unwrap();
|
||||
let seed = Seed::new(&mnemonic, &password);
|
||||
let sk = SpendingKey::from_zip32_seed(seed.as_bytes(), coin_type, account_index).unwrap();
|
||||
let fvk = FullViewingKey::from(&sk);
|
||||
OrchardKeyBytes {
|
||||
|
|
|
@ -3,6 +3,7 @@ use crate::api::recipient::RecipientMemo;
|
|||
use crate::chain::{get_checkpoint_height, EXPIRY_HEIGHT_OFFSET};
|
||||
use crate::coinconfig::CoinConfig;
|
||||
use crate::db::AccountData;
|
||||
use crate::key2::split_key;
|
||||
use crate::note_selection::{SecretKeys, Source, UTXO};
|
||||
use crate::unified::orchard_as_unified;
|
||||
use crate::{
|
||||
|
@ -214,8 +215,9 @@ pub fn derive_tkeys(
|
|||
phrase: &str,
|
||||
path: &str,
|
||||
) -> anyhow::Result<(String, String)> {
|
||||
let mnemonic = Mnemonic::from_phrase(phrase, Language::English)?;
|
||||
let seed = Seed::new(&mnemonic, "");
|
||||
let (phrase, password) = split_key(phrase);
|
||||
let mnemonic = Mnemonic::from_phrase(&phrase, Language::English)?;
|
||||
let seed = Seed::new(&mnemonic, &password);
|
||||
let ext = ExtendedPrivKey::derive(seed.as_bytes(), path)
|
||||
.map_err(|_| anyhow!("Invalid derivation path"))?;
|
||||
let secret_key = SecretKey::from_slice(&ext.secret())?;
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
use crate::key2::split_key;
|
||||
use anyhow::anyhow;
|
||||
use base58check::ToBase58Check;
|
||||
use bip39::{Language, Mnemonic, Seed};
|
||||
|
@ -28,8 +29,9 @@ pub fn derive_zip32(
|
|||
external: u32,
|
||||
address_index: Option<u32>,
|
||||
) -> anyhow::Result<KeyPack> {
|
||||
let mnemonic = Mnemonic::from_phrase(phrase, Language::English)?;
|
||||
let seed = Seed::new(&mnemonic, "");
|
||||
let (phrase, password) = split_key(phrase);
|
||||
let mnemonic = Mnemonic::from_phrase(&phrase, Language::English)?;
|
||||
let seed = Seed::new(&mnemonic, &password);
|
||||
let master = ExtendedSpendingKey::master(seed.as_bytes());
|
||||
let mut z_path = vec![
|
||||
ChildIndex::Hardened(32),
|
||||
|
|
Loading…
Reference in New Issue