From 76d015ed119cd0ee0cf306690693efba75daa0b4 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Tue, 14 Jun 2022 02:27:55 +0000 Subject: [PATCH] zcash_client_backend: Fix `UnifiedFullViewingKey` Sapling item type Per ZIP 316, the Sapling FVK Encoding only includes `(ak, nk, ovk, dk)` which is a subset of the Sapling `ExtendedFullViewingKey`. We therefore need to use `DiversifiableFullViewingKey` inside `UnifiedFullViewingKey` in order to make it parseable from the UFVK string encoding. `zcash_client_sqlite::wallet::get_extended_full_viewing_keys` has been removed as a consequence of this change: we can no longer reconstruct the correct `ExtendedFullViewingKey` from the `UnifiedFullViewingKey`. --- zcash_client_backend/src/data_api/chain.rs | 5 +- zcash_client_backend/src/decrypt.rs | 6 +- zcash_client_backend/src/keys.rs | 31 ++++---- zcash_client_backend/src/welding_rig.rs | 21 ++++++ zcash_client_sqlite/CHANGELOG.md | 6 ++ zcash_client_sqlite/src/chain.rs | 58 +++++++-------- zcash_client_sqlite/src/lib.rs | 28 +++---- zcash_client_sqlite/src/wallet.rs | 29 ++------ zcash_client_sqlite/src/wallet/init.rs | 11 +-- zcash_client_sqlite/src/wallet/transact.rs | 87 ++++++++++------------ zcash_primitives/src/sapling/keys.rs | 7 ++ 11 files changed, 149 insertions(+), 140 deletions(-) diff --git a/zcash_client_backend/src/data_api/chain.rs b/zcash_client_backend/src/data_api/chain.rs index a8bade252..37faba2f5 100644 --- a/zcash_client_backend/src/data_api/chain.rs +++ b/zcash_client_backend/src/data_api/chain.rs @@ -84,7 +84,6 @@ use zcash_primitives::{ consensus::{self, BlockHeight, NetworkUpgrade}, merkle_tree::CommitmentTree, sapling::Nullifier, - zip32::{AccountId, ExtendedFullViewingKey}, }; use crate::{ @@ -214,7 +213,7 @@ where let ufvks = data.get_unified_full_viewing_keys()?; // TODO: Change `scan_block` to also scan Orchard. // https://github.com/zcash/librustzcash/issues/403 - let extfvks: Vec<(&AccountId, &ExtendedFullViewingKey)> = ufvks + let dfvks: Vec<_> = ufvks .iter() .map(|(account, ufvk)| (account, ufvk.sapling().expect("TODO Add Orchard support"))) .collect(); @@ -249,7 +248,7 @@ where scan_block( params, block, - &extfvks, + &dfvks, &nullifiers, &mut tree, &mut witness_refs[..], diff --git a/zcash_client_backend/src/decrypt.rs b/zcash_client_backend/src/decrypt.rs index f7400e3a1..b845d3dee 100644 --- a/zcash_client_backend/src/decrypt.rs +++ b/zcash_client_backend/src/decrypt.rs @@ -46,9 +46,9 @@ pub fn decrypt_transaction( if let Some(bundle) = tx.sapling_bundle() { for (account, ufvk) in ufvks.iter() { - let extfvk = ufvk.sapling().expect("TODO: Add Orchard support"); - let ivk = extfvk.fvk.vk.ivk(); - let ovk = extfvk.fvk.ovk; + let dfvk = ufvk.sapling().expect("TODO: Add Orchard support"); + let ivk = dfvk.fvk().vk.ivk(); + let ovk = dfvk.fvk().ovk; for (index, output) in bundle.shielded_outputs.iter().enumerate() { let ((note, to, memo), outgoing) = diff --git a/zcash_client_backend/src/keys.rs b/zcash_client_backend/src/keys.rs index 9b0b89889..5aac47b96 100644 --- a/zcash_client_backend/src/keys.rs +++ b/zcash_client_backend/src/keys.rs @@ -1,12 +1,12 @@ //! Helper functions for managing light client key material. use zcash_primitives::{ consensus, + sapling::keys as sapling_keys, zip32::{AccountId, DiversifierIndex}, }; use crate::address::UnifiedAddress; -#[cfg(feature = "transparent-inputs")] use std::convert::TryInto; #[cfg(feature = "transparent-inputs")] @@ -109,7 +109,7 @@ impl UnifiedSpendingKey { UnifiedFullViewingKey { #[cfg(feature = "transparent-inputs")] transparent: Some(self.transparent.to_account_pubkey()), - sapling: Some(sapling::ExtendedFullViewingKey::from(&self.sapling)), + sapling: Some(sapling::ExtendedFullViewingKey::from(&self.sapling).into()), } } @@ -138,9 +138,7 @@ impl UnifiedSpendingKey { pub struct UnifiedFullViewingKey { #[cfg(feature = "transparent-inputs")] transparent: Option, - // TODO: This type is invalid for a UFVK; create a `sapling::DiversifiableFullViewingKey` - // to replace it. - sapling: Option, + sapling: Option, } #[doc(hidden)] @@ -148,7 +146,7 @@ impl UnifiedFullViewingKey { /// Construct a new unified full viewing key, if the required components are present. pub fn new( #[cfg(feature = "transparent-inputs")] transparent: Option, - sapling: Option, + sapling: Option, ) -> Option { if sapling.is_none() { None @@ -185,7 +183,12 @@ impl UnifiedFullViewingKey { }; let sapling = if flag & 2 != 0 { - Some(sapling::ExtendedFullViewingKey::read(data).ok()?) + if data.len() != 128 { + return None; + } + Some(sapling_keys::DiversifiableFullViewingKey::from_bytes( + data.try_into().unwrap(), + )?) } else { None }; @@ -212,7 +215,7 @@ impl UnifiedFullViewingKey { }; if let Some(sapling) = self.sapling.as_ref() { - sapling.write(&mut ufvk).unwrap(); + ufvk.extend_from_slice(&sapling.to_bytes()); } format!("DONOTUSEUFVK{}", hex::encode(&ufvk)) @@ -225,9 +228,8 @@ impl UnifiedFullViewingKey { self.transparent.as_ref() } - /// Returns the Sapling extended full viewing key component of this - /// unified key. - pub fn sapling(&self) -> Option<&sapling::ExtendedFullViewingKey> { + /// Returns the Sapling diversifiable full viewing key component of this unified key. + pub fn sapling(&self) -> Option<&sapling_keys::DiversifiableFullViewingKey> { self.sapling.as_ref() } @@ -348,7 +350,7 @@ mod tests { let sapling = { let extsk = sapling::spending_key(&[0; 32], 0, account); - Some(ExtendedFullViewingKey::from(&extsk)) + Some(ExtendedFullViewingKey::from(&extsk).into()) }; #[cfg(feature = "transparent-inputs")] @@ -368,6 +370,9 @@ mod tests { decoded.transparent.map(|t| t.serialize()), ufvk.transparent.map(|t| t.serialize()), ); - assert_eq!(decoded.sapling, ufvk.sapling); + assert_eq!( + decoded.sapling.map(|s| s.to_bytes()), + ufvk.sapling.map(|s| s.to_bytes()), + ); } } diff --git a/zcash_client_backend/src/welding_rig.rs b/zcash_client_backend/src/welding_rig.rs index 662dea3a1..b1c9251b5 100644 --- a/zcash_client_backend/src/welding_rig.rs +++ b/zcash_client_backend/src/welding_rig.rs @@ -9,6 +9,7 @@ use zcash_primitives::{ consensus::{self, BlockHeight}, merkle_tree::{CommitmentTree, IncrementalWitness}, sapling::{ + keys::DiversifiableFullViewingKey, note_encryption::{try_sapling_compact_note_decryption, SaplingDomain}, Node, Note, Nullifier, PaymentAddress, SaplingIvk, }, @@ -127,6 +128,26 @@ pub trait ScanningKey { fn nf(&self, note: &Note, witness: &IncrementalWitness) -> Self::Nf; } +impl ScanningKey for DiversifiableFullViewingKey { + type Nf = Nullifier; + + fn try_decryption< + P: consensus::Parameters, + Output: ShieldedOutput, COMPACT_NOTE_SIZE>, + >( + &self, + params: &P, + height: BlockHeight, + output: &Output, + ) -> Option<(Note, PaymentAddress)> { + try_sapling_compact_note_decryption(params, height, &self.fvk().vk.ivk(), output) + } + + fn nf(&self, note: &Note, witness: &IncrementalWitness) -> Self::Nf { + note.nf(&self.fvk().vk, witness.position() as u64) + } +} + /// The [`ScanningKey`] implementation for [`ExtendedFullViewingKey`]s. /// Nullifiers may be derived when scanning with these keys. /// diff --git a/zcash_client_sqlite/CHANGELOG.md b/zcash_client_sqlite/CHANGELOG.md index 7f660a4e8..02168d2a7 100644 --- a/zcash_client_sqlite/CHANGELOG.md +++ b/zcash_client_sqlite/CHANGELOG.md @@ -49,6 +49,12 @@ and this library adheres to Rust's notion of constructed, rather than only in the case that a transaction has been decrypted after being retrieved from the network. +### Removed +- `zcash_client_sqlite::wallet`: + - `get_extended_full_viewing_keys` (use + `zcash_client_backend::data_api::WalletRead::get_unified_full_viewing_keys` + instead). + ### Deprecated - A number of public API methods that are used internally to support the `zcash_client_backend::data_api::{WalletRead, WalletWrite}` interfaces have diff --git a/zcash_client_sqlite/src/chain.rs b/zcash_client_sqlite/src/chain.rs index 66866f655..5902d9542 100644 --- a/zcash_client_sqlite/src/chain.rs +++ b/zcash_client_sqlite/src/chain.rs @@ -101,7 +101,7 @@ mod tests { init_wallet_db(&db_data).unwrap(); // Add an account to the wallet - let (extfvk, _taddr) = init_test_accounts_table(&db_data); + let (dfvk, _taddr) = init_test_accounts_table(&db_data); // Empty chain should be valid validate_chain( @@ -115,7 +115,7 @@ mod tests { let (cb, _) = fake_compact_block( sapling_activation_height(), BlockHash([0; 32]), - extfvk.clone(), + &dfvk, Amount::from_u64(5).unwrap(), ); insert_into_cache(&db_cache, &cb); @@ -144,7 +144,7 @@ mod tests { let (cb2, _) = fake_compact_block( sapling_activation_height() + 1, cb.hash(), - extfvk, + &dfvk, Amount::from_u64(7).unwrap(), ); insert_into_cache(&db_cache, &cb2); @@ -180,19 +180,19 @@ mod tests { init_wallet_db(&db_data).unwrap(); // Add an account to the wallet - let (extfvk, _taddr) = init_test_accounts_table(&db_data); + let (dfvk, _taddr) = init_test_accounts_table(&db_data); // Create some fake CompactBlocks let (cb, _) = fake_compact_block( sapling_activation_height(), BlockHash([0; 32]), - extfvk.clone(), + &dfvk, Amount::from_u64(5).unwrap(), ); let (cb2, _) = fake_compact_block( sapling_activation_height() + 1, cb.hash(), - extfvk.clone(), + &dfvk, Amount::from_u64(7).unwrap(), ); insert_into_cache(&db_cache, &cb); @@ -214,13 +214,13 @@ mod tests { let (cb3, _) = fake_compact_block( sapling_activation_height() + 2, BlockHash([1; 32]), - extfvk.clone(), + &dfvk, Amount::from_u64(8).unwrap(), ); let (cb4, _) = fake_compact_block( sapling_activation_height() + 3, cb3.hash(), - extfvk, + &dfvk, Amount::from_u64(3).unwrap(), ); insert_into_cache(&db_cache, &cb3); @@ -250,19 +250,19 @@ mod tests { init_wallet_db(&db_data).unwrap(); // Add an account to the wallet - let (extfvk, _taddr) = init_test_accounts_table(&db_data); + let (dfvk, _taddr) = init_test_accounts_table(&db_data); // Create some fake CompactBlocks let (cb, _) = fake_compact_block( sapling_activation_height(), BlockHash([0; 32]), - extfvk.clone(), + &dfvk, Amount::from_u64(5).unwrap(), ); let (cb2, _) = fake_compact_block( sapling_activation_height() + 1, cb.hash(), - extfvk.clone(), + &dfvk, Amount::from_u64(7).unwrap(), ); insert_into_cache(&db_cache, &cb); @@ -284,13 +284,13 @@ mod tests { let (cb3, _) = fake_compact_block( sapling_activation_height() + 2, cb2.hash(), - extfvk.clone(), + &dfvk, Amount::from_u64(8).unwrap(), ); let (cb4, _) = fake_compact_block( sapling_activation_height() + 3, BlockHash([1; 32]), - extfvk, + &dfvk, Amount::from_u64(3).unwrap(), ); insert_into_cache(&db_cache, &cb3); @@ -320,7 +320,7 @@ mod tests { init_wallet_db(&db_data).unwrap(); // Add an account to the wallet - let (extfvk, _taddr) = init_test_accounts_table(&db_data); + let (dfvk, _taddr) = init_test_accounts_table(&db_data); // Account balance should be zero assert_eq!( @@ -334,12 +334,12 @@ mod tests { let (cb, _) = fake_compact_block( sapling_activation_height(), BlockHash([0; 32]), - extfvk.clone(), + &dfvk, value, ); let (cb2, _) = - fake_compact_block(sapling_activation_height() + 1, cb.hash(), extfvk, value2); + fake_compact_block(sapling_activation_height() + 1, cb.hash(), &dfvk, value2); insert_into_cache(&db_cache, &cb); insert_into_cache(&db_cache, &cb2); @@ -389,14 +389,14 @@ mod tests { init_wallet_db(&db_data).unwrap(); // Add an account to the wallet - let (extfvk, _taddr) = init_test_accounts_table(&db_data); + let (dfvk, _taddr) = init_test_accounts_table(&db_data); // Create a block with height SAPLING_ACTIVATION_HEIGHT let value = Amount::from_u64(50000).unwrap(); let (cb1, _) = fake_compact_block( sapling_activation_height(), BlockHash([0; 32]), - extfvk.clone(), + &dfvk, value, ); insert_into_cache(&db_cache, &cb1); @@ -405,14 +405,10 @@ mod tests { assert_eq!(get_balance(&db_data, AccountId::from(0)).unwrap(), value); // We cannot scan a block of height SAPLING_ACTIVATION_HEIGHT + 2 next - let (cb2, _) = fake_compact_block( - sapling_activation_height() + 1, - cb1.hash(), - extfvk.clone(), - value, - ); + let (cb2, _) = + fake_compact_block(sapling_activation_height() + 1, cb1.hash(), &dfvk, value); let (cb3, _) = - fake_compact_block(sapling_activation_height() + 2, cb2.hash(), extfvk, value); + fake_compact_block(sapling_activation_height() + 2, cb2.hash(), &dfvk, value); insert_into_cache(&db_cache, &cb3); match scan_cached_blocks(&tests::network(), &db_cache, &mut db_write, None) { Err(SqliteClientError::BackendError(e)) => { @@ -448,7 +444,7 @@ mod tests { init_wallet_db(&db_data).unwrap(); // Add an account to the wallet - let (extfvk, _taddr) = init_test_accounts_table(&db_data); + let (dfvk, _taddr) = init_test_accounts_table(&db_data); // Account balance should be zero assert_eq!( @@ -461,7 +457,7 @@ mod tests { let (cb, _) = fake_compact_block( sapling_activation_height(), BlockHash([0; 32]), - extfvk.clone(), + &dfvk, value, ); insert_into_cache(&db_cache, &cb); @@ -476,7 +472,7 @@ mod tests { // Create a second fake CompactBlock sending more value to the address let value2 = Amount::from_u64(7).unwrap(); let (cb2, _) = - fake_compact_block(sapling_activation_height() + 1, cb.hash(), extfvk, value2); + fake_compact_block(sapling_activation_height() + 1, cb.hash(), &dfvk, value2); insert_into_cache(&db_cache, &cb2); // Scan the cache again @@ -500,7 +496,7 @@ mod tests { init_wallet_db(&db_data).unwrap(); // Add an account to the wallet - let (extfvk, _taddr) = init_test_accounts_table(&db_data); + let (dfvk, _taddr) = init_test_accounts_table(&db_data); // Account balance should be zero assert_eq!( @@ -513,7 +509,7 @@ mod tests { let (cb, nf) = fake_compact_block( sapling_activation_height(), BlockHash([0; 32]), - extfvk.clone(), + &dfvk, value, ); insert_into_cache(&db_cache, &cb); @@ -535,7 +531,7 @@ mod tests { sapling_activation_height() + 1, cb.hash(), (nf, value), - extfvk, + &dfvk, to2, value2, ), diff --git a/zcash_client_sqlite/src/lib.rs b/zcash_client_sqlite/src/lib.rs index 425757c54..742cfe220 100644 --- a/zcash_client_sqlite/src/lib.rs +++ b/zcash_client_sqlite/src/lib.rs @@ -745,8 +745,8 @@ mod tests { legacy::TransparentAddress, memo::MemoBytes, sapling::{ - note_encryption::sapling_note_encryption, util::generate_random_rseed, Note, Nullifier, - PaymentAddress, + keys::DiversifiableFullViewingKey, note_encryption::sapling_note_encryption, + util::generate_random_rseed, Note, Nullifier, PaymentAddress, }, transaction::components::Amount, zip32::ExtendedFullViewingKey, @@ -783,11 +783,11 @@ mod tests { #[cfg(test)] pub(crate) fn init_test_accounts_table( db_data: &WalletDb, - ) -> (ExtendedFullViewingKey, Option) { + ) -> (DiversifiableFullViewingKey, Option) { let seed = [0u8; 32]; let account = AccountId::from(0); let extsk = sapling::spending_key(&seed, network().coin_type(), account); - let extfvk = ExtendedFullViewingKey::from(&extsk); + let dfvk = DiversifiableFullViewingKey::from(ExtendedFullViewingKey::from(&extsk)); #[cfg(feature = "transparent-inputs")] let (tkey, taddr) = { @@ -804,13 +804,13 @@ mod tests { let ufvk = UnifiedFullViewingKey::new( #[cfg(feature = "transparent-inputs")] tkey, - Some(extfvk.clone()), + Some(dfvk.clone()), ) .unwrap(); init_accounts_table(db_data, &[ufvk]).unwrap(); - (extfvk, taddr) + (dfvk, taddr) } /// Create a fake CompactBlock at the given height, containing a single output paying @@ -818,10 +818,10 @@ mod tests { pub(crate) fn fake_compact_block( height: BlockHeight, prev_hash: BlockHash, - extfvk: ExtendedFullViewingKey, + dfvk: &DiversifiableFullViewingKey, value: Amount, ) -> (CompactBlock, Nullifier) { - let to = extfvk.default_address().1; + let to = dfvk.default_address().1; // Create a fake Note for the account let mut rng = OsRng; @@ -833,7 +833,7 @@ mod tests { rseed, }; let encryptor = sapling_note_encryption::<_, Network>( - Some(extfvk.fvk.ovk), + Some(dfvk.fvk().ovk), note.clone(), to, MemoBytes::empty(), @@ -859,7 +859,7 @@ mod tests { rng.fill_bytes(&mut cb.hash); cb.prevHash.extend_from_slice(&prev_hash.0); cb.vtx.push(ctx); - (cb, note.nf(&extfvk.fvk.vk, 0)) + (cb, note.nf(&dfvk.fvk().vk, 0)) } /// Create a fake CompactBlock at the given height, spending a single note from the @@ -868,7 +868,7 @@ mod tests { height: BlockHeight, prev_hash: BlockHash, (nf, in_value): (Nullifier, Amount), - extfvk: ExtendedFullViewingKey, + dfvk: &DiversifiableFullViewingKey, to: PaymentAddress, value: Amount, ) -> CompactBlock { @@ -893,7 +893,7 @@ mod tests { rseed, }; let encryptor = sapling_note_encryption::<_, Network>( - Some(extfvk.fvk.ovk), + Some(dfvk.fvk().ovk), note.clone(), to, MemoBytes::empty(), @@ -912,7 +912,7 @@ mod tests { // Create a fake Note for the change ctx.outputs.push({ - let change_addr = extfvk.default_address().1; + let change_addr = dfvk.default_address().1; let rseed = generate_random_rseed(&network(), height, &mut rng); let note = Note { g_d: change_addr.diversifier().g_d().unwrap(), @@ -921,7 +921,7 @@ mod tests { rseed, }; let encryptor = sapling_note_encryption::<_, Network>( - Some(extfvk.fvk.ovk), + Some(dfvk.fvk().ovk), note.clone(), change_addr, MemoBytes::empty(), diff --git a/zcash_client_sqlite/src/wallet.rs b/zcash_client_sqlite/src/wallet.rs index aa7f1b14b..974f883fb 100644 --- a/zcash_client_sqlite/src/wallet.rs +++ b/zcash_client_sqlite/src/wallet.rs @@ -17,7 +17,7 @@ use zcash_primitives::{ consensus::{self, BlockHeight, BranchId, NetworkUpgrade, Parameters}, memo::{Memo, MemoBytes}, merkle_tree::{CommitmentTree, IncrementalWitness}, - sapling::{Node, Note, Nullifier, PaymentAddress}, + sapling::{keys::DiversifiableFullViewingKey, Node, Note, Nullifier, PaymentAddress}, transaction::{components::Amount, Transaction, TxId}, zip32::{AccountId, ExtendedFullViewingKey}, }; @@ -172,28 +172,6 @@ pub fn get_address( }) } -/// Returns the [`ExtendedFullViewingKey`]s for the wallet. -/// -/// [`ExtendedFullViewingKey`]: zcash_primitives::zip32::ExtendedFullViewingKey -#[deprecated( - note = "This function will be removed in a future release. Use zcash_client_backend::data_api::WalletRead::get_unified_full_viewing_keys instead." -)] -pub fn get_extended_full_viewing_keys( - wdb: &WalletDb

, -) -> Result, SqliteClientError> { - get_unified_full_viewing_keys(wdb).map(|ufvks| { - ufvks - .into_iter() - .map(|(account, ufvk)| { - ( - account, - ufvk.sapling().cloned().expect("TODO: Add Orchard support"), - ) - }) - .collect() - }) -} - /// Returns the [`UnifiedFullViewingKey`]s for the wallet. pub(crate) fn get_unified_full_viewing_keys( wdb: &WalletDb

, @@ -248,7 +226,10 @@ pub fn is_valid_account_extfvk( .map_err(SqliteClientError::from) .and_then(|row| { if let Some(ufvk) = row { - ufvk.map(|ufvk| ufvk.sapling() == Some(extfvk)) + ufvk.map(|ufvk| { + ufvk.sapling().map(|dfvk| dfvk.to_bytes()) + == Some(DiversifiableFullViewingKey::from(extfvk.clone()).to_bytes()) + }) } else { Ok(false) } diff --git a/zcash_client_sqlite/src/wallet/init.rs b/zcash_client_sqlite/src/wallet/init.rs index d589f8ba0..ed405030f 100644 --- a/zcash_client_sqlite/src/wallet/init.rs +++ b/zcash_client_sqlite/src/wallet/init.rs @@ -179,8 +179,8 @@ pub fn init_wallet_db

(wdb: &WalletDb

) -> Result<(), rusqlite::Error> { /// let seed = [0u8; 32]; // insecure; replace with a strong random seed /// let account = AccountId::from(0); /// let extsk = sapling::spending_key(&seed, Network::TestNetwork.coin_type(), account); -/// let extfvk = ExtendedFullViewingKey::from(&extsk); -/// let ufvk = UnifiedFullViewingKey::new(None, Some(extfvk)).unwrap(); +/// let dfvk = ExtendedFullViewingKey::from(&extsk).into(); +/// let ufvk = UnifiedFullViewingKey::new(None, Some(dfvk)).unwrap(); /// init_accounts_table(&db_data, &[ufvk]).unwrap(); /// # } /// ``` @@ -293,6 +293,7 @@ mod tests { use zcash_primitives::{ block::BlockHash, consensus::{BlockHeight, Parameters}, + sapling::keys::DiversifiableFullViewingKey, zip32::ExtendedFullViewingKey, }; @@ -319,7 +320,7 @@ mod tests { // First call with data should initialise the accounts table let extsk = sapling::spending_key(&seed, network().coin_type(), account); - let extfvk = ExtendedFullViewingKey::from(&extsk); + let dfvk = DiversifiableFullViewingKey::from(ExtendedFullViewingKey::from(&extsk)); #[cfg(feature = "transparent-inputs")] let ufvk = UnifiedFullViewingKey::new( @@ -328,12 +329,12 @@ mod tests { .unwrap() .to_account_pubkey(), ), - Some(extfvk), + Some(dfvk), ) .unwrap(); #[cfg(not(feature = "transparent-inputs"))] - let ufvk = UnifiedFullViewingKey::new(Some(extfvk)).unwrap(); + let ufvk = UnifiedFullViewingKey::new(Some(dfvk), None).unwrap(); init_accounts_table(&db_data, &[ufvk.clone()]).unwrap(); diff --git a/zcash_client_sqlite/src/wallet/transact.rs b/zcash_client_sqlite/src/wallet/transact.rs index ef1aa6067..4bb345fa3 100644 --- a/zcash_client_sqlite/src/wallet/transact.rs +++ b/zcash_client_sqlite/src/wallet/transact.rs @@ -165,7 +165,10 @@ mod tests { block::BlockHash, consensus::{BlockHeight, BranchId, Parameters}, legacy::TransparentAddress, - sapling::{note_encryption::try_sapling_output_recovery, prover::TxProver}, + sapling::{ + keys::DiversifiableFullViewingKey, note_encryption::try_sapling_output_recovery, + prover::TxProver, + }, transaction::{components::Amount, Transaction}, zip32::{ExtendedFullViewingKey, ExtendedSpendingKey}, }; @@ -207,8 +210,8 @@ mod tests { // Add two accounts to the wallet let extsk0 = sapling::spending_key(&[0u8; 32], network().coin_type(), AccountId::from(0)); let extsk1 = sapling::spending_key(&[1u8; 32], network().coin_type(), AccountId::from(1)); - let extfvk0 = ExtendedFullViewingKey::from(&extsk0); - let extfvk1 = ExtendedFullViewingKey::from(&extsk1); + let dfvk0 = DiversifiableFullViewingKey::from(ExtendedFullViewingKey::from(&extsk0)); + let dfvk1 = DiversifiableFullViewingKey::from(ExtendedFullViewingKey::from(&extsk1)); #[cfg(feature = "transparent-inputs")] let ufvks = { @@ -219,14 +222,14 @@ mod tests { transparent::AccountPrivKey::from_seed(&network(), &[1u8; 32], AccountId::from(1)) .unwrap(); [ - UnifiedFullViewingKey::new(Some(tsk0.to_account_pubkey()), Some(extfvk0)).unwrap(), - UnifiedFullViewingKey::new(Some(tsk1.to_account_pubkey()), Some(extfvk1)).unwrap(), + UnifiedFullViewingKey::new(Some(tsk0.to_account_pubkey()), Some(dfvk0)).unwrap(), + UnifiedFullViewingKey::new(Some(tsk1.to_account_pubkey()), Some(dfvk1)).unwrap(), ] }; #[cfg(not(feature = "transparent-inputs"))] let ufvks = [ - UnifiedFullViewingKey::new(Some(extfvk0)).unwrap(), - UnifiedFullViewingKey::new(Some(extfvk1)).unwrap(), + UnifiedFullViewingKey::new(Some(dfvk0), None).unwrap(), + UnifiedFullViewingKey::new(Some(dfvk1), None).unwrap(), ]; init_accounts_table(&db_data, &ufvks).unwrap(); @@ -275,12 +278,12 @@ mod tests { // Add an account to the wallet let extsk = sapling::spending_key(&[0u8; 32], network().coin_type(), AccountId::from(0)); - let extfvk = ExtendedFullViewingKey::from(&extsk); + let dfvk = DiversifiableFullViewingKey::from(ExtendedFullViewingKey::from(&extsk)); #[cfg(feature = "transparent-inputs")] - let ufvk = UnifiedFullViewingKey::new(None, Some(extfvk)).unwrap(); + let ufvk = UnifiedFullViewingKey::new(None, Some(dfvk)).unwrap(); #[cfg(not(feature = "transparent-inputs"))] - let ufvk = UnifiedFullViewingKey::new(Some(extfvk)).unwrap(); + let ufvk = UnifiedFullViewingKey::new(Some(dfvk)).unwrap(); init_accounts_table(&db_data, &[ufvk]).unwrap(); let to = extsk.default_address().1.into(); @@ -319,11 +322,11 @@ mod tests { // Add an account to the wallet let extsk = sapling::spending_key(&[0u8; 32], network().coin_type(), AccountId::from(0)); - let extfvk = ExtendedFullViewingKey::from(&extsk); + let dfvk = DiversifiableFullViewingKey::from(ExtendedFullViewingKey::from(&extsk)); #[cfg(feature = "transparent-inputs")] - let ufvk = UnifiedFullViewingKey::new(None, Some(extfvk)).unwrap(); + let ufvk = UnifiedFullViewingKey::new(None, Some(dfvk)).unwrap(); #[cfg(not(feature = "transparent-inputs"))] - let ufvk = UnifiedFullViewingKey::new(Some(extfvk)).unwrap(); + let ufvk = UnifiedFullViewingKey::new(Some(dfvk)).unwrap(); init_accounts_table(&db_data, &[ufvk]).unwrap(); let to = extsk.default_address().1.into(); @@ -367,11 +370,11 @@ mod tests { // Add an account to the wallet let extsk = sapling::spending_key(&[0u8; 32], network().coin_type(), AccountId::from(0)); - let extfvk = ExtendedFullViewingKey::from(&extsk); + let dfvk = DiversifiableFullViewingKey::from(ExtendedFullViewingKey::from(&extsk)); #[cfg(feature = "transparent-inputs")] - let ufvk = UnifiedFullViewingKey::new(None, Some(extfvk.clone())).unwrap(); + let ufvk = UnifiedFullViewingKey::new(None, Some(dfvk.clone())).unwrap(); #[cfg(not(feature = "transparent-inputs"))] - let ufvk = UnifiedFullViewingKey::new(Some(extfvk.clone())).unwrap(); + let ufvk = UnifiedFullViewingKey::new(Some(dfvk.clone())).unwrap(); init_accounts_table(&db_data, &[ufvk]).unwrap(); // Add funds to the wallet in a single note @@ -379,7 +382,7 @@ mod tests { let (cb, _) = fake_compact_block( sapling_activation_height(), BlockHash([0; 32]), - extfvk.clone(), + &dfvk, value, ); insert_into_cache(&db_cache, &cb); @@ -398,12 +401,7 @@ mod tests { ); // Add more funds to the wallet in a second note - let (cb, _) = fake_compact_block( - sapling_activation_height() + 1, - cb.hash(), - extfvk.clone(), - value, - ); + let (cb, _) = fake_compact_block(sapling_activation_height() + 1, cb.hash(), &dfvk, value); insert_into_cache(&db_cache, &cb); scan_cached_blocks(&tests::network(), &db_cache, &mut db_write, None).unwrap(); @@ -446,12 +444,8 @@ mod tests { // Mine blocks SAPLING_ACTIVATION_HEIGHT + 2 to 9 until just before the second // note is verified for i in 2..10 { - let (cb, _) = fake_compact_block( - sapling_activation_height() + i, - cb.hash(), - extfvk.clone(), - value, - ); + let (cb, _) = + fake_compact_block(sapling_activation_height() + i, cb.hash(), &dfvk, value); insert_into_cache(&db_cache, &cb); } scan_cached_blocks(&tests::network(), &db_cache, &mut db_write, None).unwrap(); @@ -477,8 +471,7 @@ mod tests { } // Mine block 11 so that the second note becomes verified - let (cb, _) = - fake_compact_block(sapling_activation_height() + 10, cb.hash(), extfvk, value); + let (cb, _) = fake_compact_block(sapling_activation_height() + 10, cb.hash(), &dfvk, value); insert_into_cache(&db_cache, &cb); scan_cached_blocks(&tests::network(), &db_cache, &mut db_write, None).unwrap(); @@ -510,11 +503,11 @@ mod tests { // Add an account to the wallet let extsk = sapling::spending_key(&[0u8; 32], network().coin_type(), AccountId::from(0)); - let extfvk = ExtendedFullViewingKey::from(&extsk); + let dfvk = DiversifiableFullViewingKey::from(ExtendedFullViewingKey::from(&extsk)); #[cfg(feature = "transparent-inputs")] - let ufvk = UnifiedFullViewingKey::new(None, Some(extfvk.clone())).unwrap(); + let ufvk = UnifiedFullViewingKey::new(None, Some(dfvk.clone())).unwrap(); #[cfg(not(feature = "transparent-inputs"))] - let ufvk = UnifiedFullViewingKey::new(Some(extfvk.clone())).unwrap(); + let ufvk = UnifiedFullViewingKey::new(Some(dfvk.clone())).unwrap(); init_accounts_table(&db_data, &[ufvk]).unwrap(); // Add funds to the wallet in a single note @@ -522,7 +515,7 @@ mod tests { let (cb, _) = fake_compact_block( sapling_activation_height(), BlockHash([0; 32]), - extfvk, + &dfvk, value, ); insert_into_cache(&db_cache, &cb); @@ -573,7 +566,7 @@ mod tests { let (cb, _) = fake_compact_block( sapling_activation_height() + i, cb.hash(), - ExtendedFullViewingKey::from(&ExtendedSpendingKey::master(&[i as u8])), + &ExtendedFullViewingKey::from(&ExtendedSpendingKey::master(&[i as u8])).into(), value, ); insert_into_cache(&db_cache, &cb); @@ -604,7 +597,7 @@ mod tests { let (cb, _) = fake_compact_block( sapling_activation_height() + 22, cb.hash(), - ExtendedFullViewingKey::from(&ExtendedSpendingKey::master(&[22])), + &ExtendedFullViewingKey::from(&ExtendedSpendingKey::master(&[22])).into(), value, ); insert_into_cache(&db_cache, &cb); @@ -639,11 +632,11 @@ mod tests { // Add an account to the wallet let extsk = sapling::spending_key(&[0u8; 32], network.coin_type(), AccountId::from(0)); - let extfvk = ExtendedFullViewingKey::from(&extsk); + let dfvk = DiversifiableFullViewingKey::from(ExtendedFullViewingKey::from(&extsk)); #[cfg(feature = "transparent-inputs")] - let ufvk = UnifiedFullViewingKey::new(None, Some(extfvk.clone())).unwrap(); + let ufvk = UnifiedFullViewingKey::new(None, Some(dfvk.clone())).unwrap(); #[cfg(not(feature = "transparent-inputs"))] - let ufvk = UnifiedFullViewingKey::new(Some(extfvk.clone())).unwrap(); + let ufvk = UnifiedFullViewingKey::new(Some(dfvk.clone())).unwrap(); init_accounts_table(&db_data, &[ufvk]).unwrap(); // Add funds to the wallet in a single note @@ -651,7 +644,7 @@ mod tests { let (cb, _) = fake_compact_block( sapling_activation_height(), BlockHash([0; 32]), - extfvk.clone(), + &dfvk, value, ); insert_into_cache(&db_cache, &cb); @@ -708,7 +701,7 @@ mod tests { try_sapling_output_recovery( &network, sapling_activation_height(), - &extfvk.fvk.ovk, + &dfvk.fvk().ovk, output, ) }; @@ -725,7 +718,7 @@ mod tests { let (cb, _) = fake_compact_block( sapling_activation_height() + i, cb.hash(), - ExtendedFullViewingKey::from(&ExtendedSpendingKey::master(&[i as u8])), + &ExtendedFullViewingKey::from(&ExtendedSpendingKey::master(&[i as u8])).into(), value, ); insert_into_cache(&db_cache, &cb); @@ -749,11 +742,11 @@ mod tests { // Add an account to the wallet let extsk = sapling::spending_key(&[0u8; 32], network().coin_type(), AccountId::from(0)); - let extfvk = ExtendedFullViewingKey::from(&extsk); + let dfvk = DiversifiableFullViewingKey::from(ExtendedFullViewingKey::from(&extsk)); #[cfg(feature = "transparent-inputs")] - let ufvk = UnifiedFullViewingKey::new(None, Some(extfvk.clone())).unwrap(); + let ufvk = UnifiedFullViewingKey::new(None, Some(dfvk.clone())).unwrap(); #[cfg(not(feature = "transparent-inputs"))] - let ufvk = UnifiedFullViewingKey::new(Some(extfvk.clone())).unwrap(); + let ufvk = UnifiedFullViewingKey::new(Some(dfvk.clone())).unwrap(); init_accounts_table(&db_data, &[ufvk]).unwrap(); // Add funds to the wallet in a single note @@ -761,7 +754,7 @@ mod tests { let (cb, _) = fake_compact_block( sapling_activation_height(), BlockHash([0; 32]), - extfvk, + &dfvk, value, ); insert_into_cache(&db_cache, &cb); diff --git a/zcash_primitives/src/sapling/keys.rs b/zcash_primitives/src/sapling/keys.rs index 297ef2bad..822f3a438 100644 --- a/zcash_primitives/src/sapling/keys.rs +++ b/zcash_primitives/src/sapling/keys.rs @@ -276,6 +276,13 @@ impl DiversifiableFullViewingKey { zip32::sapling_find_address(&self.fvk, &self.dk, j) } + /// Returns the payment address corresponding to the smallest valid diversifier index, + /// along with that index. + // TODO: See if this is only used in tests. + pub fn default_address(&self) -> (zip32::DiversifierIndex, PaymentAddress) { + zip32::sapling_default_address(&self.fvk, &self.dk) + } + /// Attempts to decrypt the given address's diversifier with this full viewing key. /// /// This method extracts the diversifier from the given address and decrypts it as a