Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unify keys #1414

Merged
merged 28 commits into from
Oct 7, 2024
Merged
Show file tree
Hide file tree
Changes from 26 commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
a8c1344
unify transparent keys in wallet capability with LRZ
Oscar-Pepper Sep 20, 2024
bbcf074
replaced Capability with UnifiedKeyStore
Oscar-Pepper Sep 23, 2024
acbeb96
Merge branch 'move_crypto_provider_installer' into lrz_update
Oscar-Pepper Sep 25, 2024
c55b928
start implementing read and write and move old code to legacy
Oscar-Pepper Sep 26, 2024
35f011a
add legacy files
Oscar-Pepper Sep 26, 2024
38eeb17
Merge branch 'dev' into unify_keys
Oscar-Pepper Sep 26, 2024
ef6f007
Merge branch 'dev' into unify_keys
Oscar-Pepper Sep 27, 2024
07fb260
implemented read write for unified keystore
Oscar-Pepper Sep 27, 2024
36b0b95
ReadableWritable defaults
AloeareV Sep 27, 2024
681d40e
Merge pull request #21 from AloeareV/unify_keys
Oscar-Pepper Sep 27, 2024
388e458
Merge branch 'dev' into unify_keys
Oscar-Pepper Sep 30, 2024
a80dc4e
fix build errors in tests
Oscar-Pepper Sep 30, 2024
eec7ddb
fixed clippy warnings in production code
Oscar-Pepper Sep 30, 2024
565aa2c
add back testutils fns
Oscar-Pepper Oct 1, 2024
8f1909d
fix test build errors
Oscar-Pepper Oct 1, 2024
bf66942
implemented USK from legacy keys
Oscar-Pepper Oct 2, 2024
254355d
starting adding legacy new address fn
Oscar-Pepper Oct 3, 2024
69df7fc
Merge remote-tracking branch 'oscar/unify_keys' into unify_keys
Oscar-Pepper Oct 3, 2024
67db745
solved merge conflicts with dev
Oscar-Pepper Oct 3, 2024
b18253a
implement address generation for legacy keys for loading from pre-v29…
Oscar-Pepper Oct 3, 2024
4e8723f
apply clippy suggestions
Oscar-Pepper Oct 3, 2024
700928c
add legacy key logic to old wallet read
Oscar-Pepper Oct 3, 2024
f17c7b8
clean up and error handling
Oscar-Pepper Oct 3, 2024
b000ee6
solve merge conflicts with dev
Oscar-Pepper Oct 4, 2024
ab2d660
add back in write lock drop
Oscar-Pepper Oct 4, 2024
a7bf06b
Merge branch 'dev' into unify_keys
Oscar-Pepper Oct 4, 2024
eb7d2e6
requested changes: added consts for key types integers and cleaned up…
Oscar-Pepper Oct 7, 2024
173ea7f
solve merge conflicts with latest dev
Oscar-Pepper Oct 7, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 10 additions & 6 deletions libtonode-tests/tests/concrete.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ use zingolib::testutils::lightclient::from_inputs;
use zingolib::testutils::{build_fvk_client, increase_height_and_wait_for_client, scenarios};
use zingolib::utils::conversion::address_from_str;
use zingolib::wallet::data::summaries::TransactionSummaryInterface;
use zingolib::wallet::keys::unified::UnifiedKeyStore;
use zingolib::wallet::propose::ProposeSendError;
use zingolib::{check_client_balances, get_base_address_macro, get_otd, validate_otds};

Expand Down Expand Up @@ -69,15 +70,18 @@ fn check_view_capability_bounds(
sent_t_value: Option<u64>,
notes: &JsonValue,
) {
let UnifiedKeyStore::View(ufvk) = watch_wc.unified_key_store() else {
panic!("should be viewing key!")
};
//Orchard
if !fvks.contains(&ovk) {
Oscar-Pepper marked this conversation as resolved.
Show resolved Hide resolved
assert!(!watch_wc.orchard.can_view());
assert!(ufvk.orchard().is_none());
assert_eq!(balance.orchard_balance, None);
assert_eq!(balance.verified_orchard_balance, None);
assert_eq!(balance.unverified_orchard_balance, None);
assert_eq!(notes["unspent_orchard_notes"].members().count(), 0);
} else {
assert!(watch_wc.orchard.can_view());
assert!(ufvk.orchard().is_some());
assert_eq!(balance.orchard_balance, sent_o_value);
assert_eq!(balance.verified_orchard_balance, sent_o_value);
assert_eq!(balance.unverified_orchard_balance, Some(0));
Expand All @@ -87,24 +91,24 @@ fn check_view_capability_bounds(
}
//Sapling
if !fvks.contains(&svk) {
assert!(!watch_wc.sapling.can_view());
assert!(ufvk.sapling().is_none());
assert_eq!(balance.sapling_balance, None);
assert_eq!(balance.verified_sapling_balance, None);
assert_eq!(balance.unverified_sapling_balance, None);
assert_eq!(notes["unspent_sapling_notes"].members().count(), 0);
} else {
assert!(watch_wc.sapling.can_view());
assert!(ufvk.sapling().is_some());
assert_eq!(balance.sapling_balance, sent_s_value);
assert_eq!(balance.verified_sapling_balance, sent_s_value);
assert_eq!(balance.unverified_sapling_balance, Some(0));
assert_eq!(notes["unspent_sapling_notes"].members().count(), 1);
}
if !fvks.contains(&tvk) {
assert!(!watch_wc.transparent.can_view());
assert!(ufvk.transparent().is_none());
assert_eq!(balance.transparent_balance, None);
assert_eq!(notes["utxos"].members().count(), 0);
} else {
assert!(watch_wc.transparent.can_view());
assert!(ufvk.transparent().is_some());
assert_eq!(balance.transparent_balance, sent_t_value);
assert_eq!(notes["utxos"].members().count(), 1);
}
Expand Down
2 changes: 2 additions & 0 deletions zingolib/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ zcash_proofs = { workspace = true }
zip32.workspace = true

bip0039.workspace = true
bip32 = { version = "0.5", default-features = false, features = ["secp256k1-ffi"] }
zancas marked this conversation as resolved.
Show resolved Hide resolved
bs58 = { version = "0.5", features = ["check"] }

append-only-vec = { workspace = true }
base58 = { workspace = true }
Expand Down
14 changes: 8 additions & 6 deletions zingolib/src/blaze/trial_decryptions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,10 +89,12 @@ impl TrialDecryptions {
let mut workers = FuturesUnordered::new();
let mut cbs = vec![];

let sapling_ivk = sapling_crypto::zip32::DiversifiableFullViewingKey::try_from(&*wc)
.ok()
.map(|key| key.derive_ivk());
let orchard_ivk = orchard::keys::FullViewingKey::try_from(&*wc)
let sapling_ivk = sapling_crypto::zip32::DiversifiableFullViewingKey::try_from(
wc.unified_key_store(),
)
.ok()
.map(|key| key.derive_ivk());
let orchard_ivk = orchard::keys::FullViewingKey::try_from(wc.unified_key_store())
.ok()
.map(|key| key.derive_ivk());

Expand Down Expand Up @@ -315,7 +317,7 @@ impl TrialDecryptions {
let config = config.clone();

workers.push(tokio::spawn(async move {
let Ok(fvk) = D::wc_to_fvk(&wc) else {
let Ok(fvk) = D::unified_key_store_to_fvk(wc.unified_key_store()) else {
// skip any scanning if the wallet doesn't have viewing capability
return Ok::<_, String>(());
};
Expand Down Expand Up @@ -450,7 +452,7 @@ where
transaction_id,
Some(output_index),
position + i as u64,
&D::wc_to_fvk(wc).unwrap(),
&D::unified_key_store_to_fvk(wc.unified_key_store()).unwrap(),
)?;
}
nodes_retention.push((node, retention));
Expand Down
63 changes: 43 additions & 20 deletions zingolib/src/commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
//! upgrade-or-replace

use crate::data::proposal;
use crate::wallet::keys::unified::UnifiedKeyStore;
use crate::wallet::MemoDownloadOption;
use crate::{lightclient::LightClient, wallet};
use indoc::indoc;
Expand All @@ -13,7 +14,7 @@ use std::str::FromStr;
use tokio::runtime::Runtime;
use zcash_address::unified::{Container, Encoding, Ufvk};
use zcash_keys::address::Address;
use zcash_primitives::consensus::Parameters;
use zcash_keys::keys::UnifiedFullViewingKey;
use zcash_primitives::transaction::components::amount::NonNegativeAmount;
use zcash_primitives::transaction::fees::zip317::MINIMUM_FEE;

Expand Down Expand Up @@ -134,16 +135,36 @@ impl Command for WalletKindCommand {
fn exec(&self, _args: &[&str], lightclient: &LightClient) -> String {
RT.block_on(async move {
if lightclient.do_seed_phrase().await.is_ok() {
object! {"kind" => "Seeded"}.pretty(4)
} else {
let capability = lightclient.wallet.wallet_capability();
object! {
"kind" => "Loaded from key",
"transparent" => capability.transparent.kind_str(),
"sapling" => capability.sapling.kind_str(),
"orchard" => capability.orchard.kind_str(),
object! {"kind" => "Loaded from seed phrase",
AloeareV marked this conversation as resolved.
Show resolved Hide resolved
"transparent" => true,
"sapling" => true,
"orchard" => true,
}
.pretty(4)
} else {
match lightclient.wallet.wallet_capability().unified_key_store() {
UnifiedKeyStore::Spend(_) => object! {
"kind" => "Loaded from unified spending key",
"transparent" => true,
"sapling" => true,
"orchard" => true,
}
.pretty(4),
UnifiedKeyStore::View(ufvk) => object! {
"kind" => "Loaded from unified full viewing key",
"transparent" => ufvk.transparent().is_some(),
"sapling" => ufvk.sapling().is_some(),
"orchard" => ufvk.orchard().is_some(),
}
.pretty(4),
UnifiedKeyStore::Empty => object! {
"kind" => "No keys found",
"transparent" => false,
"sapling" => false,
"orchard" => false,
}
.pretty(4),
}
}
})
}
Expand Down Expand Up @@ -690,18 +711,20 @@ impl Command for ExportUfvkCommand {
}

fn exec(&self, _args: &[&str], lightclient: &LightClient) -> String {
let ufvk_res = lightclient.wallet.transaction_context.key.ufvk();
match ufvk_res {
Ok(ufvk) => {
use zcash_address::unified::Encoding as _;
object! {
"ufvk" => ufvk.encode(&lightclient.config().chain.network_type()),
"birthday" => RT.block_on(lightclient.wallet.get_birthday())
}
.pretty(2)
}
Err(e) => format!("Error: {e}"),
let ufvk: UnifiedFullViewingKey = match lightclient
.wallet
.wallet_capability()
.unified_key_store()
.try_into()
{
Ok(ufvk) => ufvk,
Err(e) => return e.to_string(),
};
object! {
"ufvk" => ufvk.encode(&lightclient.config().chain),
"birthday" => RT.block_on(lightclient.wallet.get_birthday())
}
.pretty(2)
}
}

Expand Down
2 changes: 1 addition & 1 deletion zingolib/src/lightclient.rs
Original file line number Diff line number Diff line change
Expand Up @@ -474,7 +474,7 @@ impl LightClient {
let new_address = self
.wallet
.wallet_capability()
.new_address(desired_receivers)?;
.new_address(desired_receivers, false)?;

// self.save_internal_rust().await?;

Expand Down
46 changes: 17 additions & 29 deletions zingolib/src/testutils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ use std::sync::atomic::AtomicBool;
use std::sync::Arc;
use std::time::Duration;
use tokio::task::JoinHandle;
use zcash_address::unified::{Fvk, Ufvk};
use zcash_address::unified::Fvk;

use crate::config::ZingoConfig;
use crate::lightclient::LightClient;
Expand All @@ -46,31 +46,27 @@ pub mod regtest;

/// TODO: Add Doc Comment Here!
pub fn build_fvks_from_wallet_capability(wallet_capability: &WalletCapability) -> [Fvk; 3] {
let o_fvk = Fvk::Orchard(
orchard::keys::FullViewingKey::try_from(wallet_capability)
.unwrap()
.to_bytes(),
);
let s_fvk = Fvk::Sapling(
zcash_client_backend::keys::sapling::DiversifiableFullViewingKey::try_from(
wallet_capability,
)
.unwrap()
.to_bytes(),
);
let mut t_fvk_bytes = [0u8; 65];
let t_ext_pk: crate::wallet::keys::extended_transparent::ExtendedPubKey =
(wallet_capability).try_into().unwrap();
t_fvk_bytes[0..32].copy_from_slice(&t_ext_pk.chain_code[..]);
t_fvk_bytes[32..65].copy_from_slice(&t_ext_pk.public_key.serialize()[..]);
let t_fvk = Fvk::P2pkh(t_fvk_bytes);
[o_fvk, s_fvk, t_fvk]
let orchard_vk: orchard::keys::FullViewingKey =
wallet_capability.unified_key_store().try_into().unwrap();
let sapling_vk: sapling_crypto::zip32::DiversifiableFullViewingKey =
wallet_capability.unified_key_store().try_into().unwrap();
let transparent_vk: zcash_primitives::legacy::keys::AccountPubKey =
wallet_capability.unified_key_store().try_into().unwrap();

let mut transparent_vk_bytes = [0u8; 65];
transparent_vk_bytes.copy_from_slice(&transparent_vk.serialize());

[
Fvk::Orchard(orchard_vk.to_bytes()),
Fvk::Sapling(sapling_vk.to_bytes()),
Fvk::P2pkh(transparent_vk_bytes),
]
}

/// TODO: Add Doc Comment Here!
pub async fn build_fvk_client(fvks: &[&Fvk], zingoconfig: &ZingoConfig) -> LightClient {
let ufvk = zcash_address::unified::Encoding::encode(
&<Ufvk as zcash_address::unified::Encoding>::try_from_items(
&<zcash_address::unified::Ufvk as zcash_address::unified::Encoding>::try_from_items(
fvks.iter().copied().cloned().collect(),
)
.unwrap(),
Expand All @@ -80,14 +76,6 @@ pub async fn build_fvk_client(fvks: &[&Fvk], zingoconfig: &ZingoConfig) -> Light
.await
.unwrap()
}

/// Converts a Lightclient with spending capability to a Lightclient with only viewing capability
pub async fn sk_client_to_fvk_client(client: &LightClient) -> LightClient {
let [o_fvk, s_fvk, t_fvk] =
build_fvks_from_wallet_capability(&client.wallet.wallet_capability().clone());
build_fvk_client(&[&o_fvk, &s_fvk, &t_fvk], client.config()).await
}

async fn get_synced_wallet_height(client: &LightClient) -> Result<u32, String> {
client.do_sync(true).await?;
Ok(client
Expand Down
23 changes: 15 additions & 8 deletions zingolib/src/wallet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
//! TODO: Add Mod Description Here

use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
use error::KeyError;
use getset::{Getters, MutGetters};
use zcash_keys::keys::UnifiedFullViewingKey;
#[cfg(feature = "sync")]
use zcash_primitives::consensus::BlockHeight;
use zcash_primitives::memo::Memo;
Expand All @@ -12,8 +14,6 @@ use log::{info, warn};
use rand::rngs::OsRng;
use rand::Rng;

use sapling_crypto::zip32::DiversifiableFullViewingKey;

#[cfg(feature = "sync")]
use zingo_sync::{
primitives::{NullifierMap, SyncState, WalletBlock},
Expand All @@ -35,7 +35,6 @@ use crate::config::ZingoConfig;
use zcash_client_backend::proto::service::TreeState;
use zcash_encoding::Optional;

use self::keys::unified::Fvk as _;
use self::keys::unified::WalletCapability;

use self::{
Expand Down Expand Up @@ -268,10 +267,18 @@ impl LightWallet {

///TODO: Make this work for orchard too
pub async fn decrypt_message(&self, enc: Vec<u8>) -> Result<Message, String> {
let sapling_ivk = DiversifiableFullViewingKey::try_from(&*self.wallet_capability())?
.derive_ivk::<keys::unified::External>();
let ufvk: UnifiedFullViewingKey =
match self.wallet_capability().unified_key_store().try_into() {
Ok(ufvk) => ufvk,
Err(e) => return Err(e.to_string()),
};
let sapling_ivk = if let Some(ivk) = ufvk.sapling() {
ivk.to_external_ivk().prepare()
} else {
return Err(KeyError::NoViewCapability.to_string());
};

if let Ok(msg) = Message::decrypt(&enc, &sapling_ivk.ivk) {
if let Ok(msg) = Message::decrypt(&enc, &sapling_ivk) {
// If decryption succeeded for this IVK, return the decrypted memo and the matched address
return Ok(msg);
}
Expand Down Expand Up @@ -367,13 +374,13 @@ impl LightWallet {
}
};

if let Err(e) = wc.new_address(wc.can_view()) {
if let Err(e) = wc.new_address(wc.can_view(), false) {
return Err(io::Error::new(
io::ErrorKind::InvalidData,
format!("could not create initial address: {e}"),
));
};
let transaction_metadata_set = if wc.can_spend_from_all_pools() {
let transaction_metadata_set = if wc.unified_key_store().is_spending_key() {
Arc::new(RwLock::new(TxMap::new_with_witness_trees(
wc.transparent_child_addresses().clone(),
)))
Expand Down
Loading
Loading