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::consensus::{Network, Parameters};
|
||||||
use zcash_primitives::zip32::{ChildIndex, ExtendedFullViewingKey, ExtendedSpendingKey};
|
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(
|
pub fn decode_key(
|
||||||
coin: u8,
|
coin: u8,
|
||||||
key: &str,
|
key: &str,
|
||||||
|
@ -23,8 +37,9 @@ pub fn decode_key(
|
||||||
)> {
|
)> {
|
||||||
let c = CoinConfig::get(coin);
|
let c = CoinConfig::get(coin);
|
||||||
let network = c.chain.network();
|
let network = c.chain.network();
|
||||||
let res = if let Ok(mnemonic) = Mnemonic::from_phrase(key, Language::English) {
|
let (phrase, password) = split_key(key);
|
||||||
let (sk, ivk, pa) = derive_secret_key(network, &mnemonic, index)?;
|
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))
|
Ok((Some(key.to_string()), Some(sk), ivk, pa, None))
|
||||||
} else if let Ok(sk) =
|
} else if let Ok(sk) =
|
||||||
decode_extended_spending_key(network.hrp_sapling_extended_spending_key(), key)
|
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 {
|
pub fn is_valid_key(coin: u8, key: &str) -> i8 {
|
||||||
let c = CoinConfig::get(coin);
|
let c = CoinConfig::get(coin);
|
||||||
let network = c.chain.network();
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
if decode_extended_spending_key(network.hrp_sapling_extended_spending_key(), key).is_ok() {
|
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> {
|
pub fn decode_address(coin: u8, address: &str) -> Option<RecipientAddress> {
|
||||||
let c = CoinConfig::get(coin);
|
let c = CoinConfig::get(coin);
|
||||||
let network = c.chain.network();
|
let network = c.chain.network();
|
||||||
zcash_client_backend::address::RecipientAddress::decode(network, address)
|
RecipientAddress::decode(network, address)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn derive_secret_key(
|
fn derive_secret_key(
|
||||||
network: &Network,
|
network: &Network,
|
||||||
mnemonic: &Mnemonic,
|
mnemonic: &Mnemonic,
|
||||||
|
password: &str,
|
||||||
index: u32,
|
index: u32,
|
||||||
) -> anyhow::Result<(String, String, String)> {
|
) -> anyhow::Result<(String, String, String)> {
|
||||||
let seed = Seed::new(mnemonic, "");
|
let seed = Seed::new(mnemonic, password);
|
||||||
let master = ExtendedSpendingKey::master(seed.as_bytes());
|
let master = ExtendedSpendingKey::master(seed.as_bytes());
|
||||||
let path = [
|
let path = [
|
||||||
ChildIndex::Hardened(32),
|
ChildIndex::Hardened(32),
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
use crate::key2::split_key;
|
||||||
use bip39::{Language, Mnemonic, Seed};
|
use bip39::{Language, Mnemonic, Seed};
|
||||||
use orchard::keys::{FullViewingKey, Scope, SpendingKey};
|
use orchard::keys::{FullViewingKey, Scope, SpendingKey};
|
||||||
use orchard::Address;
|
use orchard::Address;
|
||||||
|
@ -16,8 +17,9 @@ impl OrchardKeyBytes {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn derive_orchard_keys(coin_type: u32, seed: &str, account_index: u32) -> 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 (phrase, password) = split_key(seed);
|
||||||
let seed = Seed::new(&mnemonic, "");
|
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 sk = SpendingKey::from_zip32_seed(seed.as_bytes(), coin_type, account_index).unwrap();
|
||||||
let fvk = FullViewingKey::from(&sk);
|
let fvk = FullViewingKey::from(&sk);
|
||||||
OrchardKeyBytes {
|
OrchardKeyBytes {
|
||||||
|
|
|
@ -3,6 +3,7 @@ use crate::api::recipient::RecipientMemo;
|
||||||
use crate::chain::{get_checkpoint_height, EXPIRY_HEIGHT_OFFSET};
|
use crate::chain::{get_checkpoint_height, EXPIRY_HEIGHT_OFFSET};
|
||||||
use crate::coinconfig::CoinConfig;
|
use crate::coinconfig::CoinConfig;
|
||||||
use crate::db::AccountData;
|
use crate::db::AccountData;
|
||||||
|
use crate::key2::split_key;
|
||||||
use crate::note_selection::{SecretKeys, Source, UTXO};
|
use crate::note_selection::{SecretKeys, Source, UTXO};
|
||||||
use crate::unified::orchard_as_unified;
|
use crate::unified::orchard_as_unified;
|
||||||
use crate::{
|
use crate::{
|
||||||
|
@ -214,8 +215,9 @@ pub fn derive_tkeys(
|
||||||
phrase: &str,
|
phrase: &str,
|
||||||
path: &str,
|
path: &str,
|
||||||
) -> anyhow::Result<(String, String)> {
|
) -> anyhow::Result<(String, String)> {
|
||||||
let mnemonic = Mnemonic::from_phrase(phrase, Language::English)?;
|
let (phrase, password) = split_key(phrase);
|
||||||
let seed = Seed::new(&mnemonic, "");
|
let mnemonic = Mnemonic::from_phrase(&phrase, Language::English)?;
|
||||||
|
let seed = Seed::new(&mnemonic, &password);
|
||||||
let ext = ExtendedPrivKey::derive(seed.as_bytes(), path)
|
let ext = ExtendedPrivKey::derive(seed.as_bytes(), path)
|
||||||
.map_err(|_| anyhow!("Invalid derivation path"))?;
|
.map_err(|_| anyhow!("Invalid derivation path"))?;
|
||||||
let secret_key = SecretKey::from_slice(&ext.secret())?;
|
let secret_key = SecretKey::from_slice(&ext.secret())?;
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
use crate::key2::split_key;
|
||||||
use anyhow::anyhow;
|
use anyhow::anyhow;
|
||||||
use base58check::ToBase58Check;
|
use base58check::ToBase58Check;
|
||||||
use bip39::{Language, Mnemonic, Seed};
|
use bip39::{Language, Mnemonic, Seed};
|
||||||
|
@ -28,8 +29,9 @@ pub fn derive_zip32(
|
||||||
external: u32,
|
external: u32,
|
||||||
address_index: Option<u32>,
|
address_index: Option<u32>,
|
||||||
) -> anyhow::Result<KeyPack> {
|
) -> anyhow::Result<KeyPack> {
|
||||||
let mnemonic = Mnemonic::from_phrase(phrase, Language::English)?;
|
let (phrase, password) = split_key(phrase);
|
||||||
let seed = Seed::new(&mnemonic, "");
|
let mnemonic = Mnemonic::from_phrase(&phrase, Language::English)?;
|
||||||
|
let seed = Seed::new(&mnemonic, &password);
|
||||||
let master = ExtendedSpendingKey::master(seed.as_bytes());
|
let master = ExtendedSpendingKey::master(seed.as_bytes());
|
||||||
let mut z_path = vec![
|
let mut z_path = vec![
|
||||||
ChildIndex::Hardened(32),
|
ChildIndex::Hardened(32),
|
||||||
|
|
Loading…
Reference in New Issue