From b537f0f7124938bc2f4867894dd616789fae1600 Mon Sep 17 00:00:00 2001 From: therealyingtong Date: Thu, 30 Jul 2020 13:13:59 +0800 Subject: [PATCH] Pass height to methods which encrypt or decrypt Sapling outputs --- zcash_client_backend/src/decrypt.rs | 42 +++++++++++------- zcash_client_backend/src/welding_rig.rs | 47 +++++++++++++++++---- zcash_client_sqlite/src/scan.rs | 4 +- zcash_primitives/src/consensus.rs | 14 +++--- zcash_primitives/src/note_encryption.rs | 23 +++++++--- zcash_primitives/src/transaction/builder.rs | 17 +++++++- 6 files changed, 106 insertions(+), 41 deletions(-) diff --git a/zcash_client_backend/src/decrypt.rs b/zcash_client_backend/src/decrypt.rs index df44a2c67..ef6b94a2b 100644 --- a/zcash_client_backend/src/decrypt.rs +++ b/zcash_client_backend/src/decrypt.rs @@ -1,5 +1,6 @@ use pairing::bls12_381::Bls12; use zcash_primitives::{ + consensus, note_encryption::{try_sapling_note_decryption, try_sapling_output_recovery, Memo}, primitives::{Note, PaymentAddress}, transaction::Transaction, @@ -30,7 +31,8 @@ pub struct DecryptedOutput { /// Scans a [`Transaction`] for any information that can be decrypted by the set of /// [`ExtendedFullViewingKey`]s. -pub fn decrypt_transaction( +pub fn decrypt_transaction( + parameters: &P, tx: &Transaction, extfvks: &[ExtendedFullViewingKey], ) -> Vec { @@ -49,21 +51,29 @@ pub fn decrypt_transaction( }; for (account, (ivk, ovk)) in vks.iter().enumerate() { - let ((note, to, memo), outgoing) = - match try_sapling_note_decryption(ivk, &epk, &output.cmu, &output.enc_ciphertext) { - Some(ret) => (ret, false), - None => match try_sapling_output_recovery( - ovk, - &output.cv, - &output.cmu, - &epk, - &output.enc_ciphertext, - &output.out_ciphertext, - ) { - Some(ret) => (ret, true), - None => continue, - }, - }; + let ((note, to, memo), outgoing) = match try_sapling_note_decryption( + parameters, + tx.expiry_height, + ivk, + &epk, + &output.cmu, + &output.enc_ciphertext, + ) { + Some(ret) => (ret, false), + None => match try_sapling_output_recovery( + parameters, + tx.expiry_height, + ovk, + &output.cv, + &output.cmu, + &epk, + &output.enc_ciphertext, + &output.out_ciphertext, + ) { + Some(ret) => (ret, true), + None => continue, + }, + }; decrypted.push(DecryptedOutput { index, note, diff --git a/zcash_client_backend/src/welding_rig.rs b/zcash_client_backend/src/welding_rig.rs index 4099e7676..e830a9169 100644 --- a/zcash_client_backend/src/welding_rig.rs +++ b/zcash_client_backend/src/welding_rig.rs @@ -4,6 +4,7 @@ use ff::PrimeField; use std::collections::HashSet; use subtle::{ConditionallySelectable, ConstantTimeEq, CtOption}; use zcash_primitives::{ + consensus, jubjub::fs::Fs, merkle_tree::{CommitmentTree, IncrementalWitness}, note_encryption::try_sapling_compact_note_decryption, @@ -22,7 +23,9 @@ use crate::wallet::{WalletShieldedOutput, WalletShieldedSpend, WalletTx}; /// /// The given [`CommitmentTree`] and existing [`IncrementalWitness`]es are incremented /// with this output's commitment. -fn scan_output( +fn scan_output( + parameters: &P, + height: u32, (index, output): (usize, CompactOutput), ivks: &[Fs], spent_from_accounts: &HashSet, @@ -49,10 +52,11 @@ fn scan_output( tree.append(node).unwrap(); for (account, ivk) in ivks.iter().enumerate() { - let (note, to) = match try_sapling_compact_note_decryption(ivk, &epk, &cmu, &ct) { - Some(ret) => ret, - None => continue, - }; + let (note, to) = + match try_sapling_compact_note_decryption(parameters, height, ivk, &epk, &cmu, &ct) { + Some(ret) => ret, + None => continue, + }; // A note is marked as "change" if the account that received it // also spent notes in the same transaction. This will catch, @@ -83,7 +87,8 @@ fn scan_output( /// /// The given [`CommitmentTree`] and existing [`IncrementalWitness`]es are /// incremented appropriately. -pub fn scan_block( +pub fn scan_block( + parameters: &P, block: CompactBlock, extfvks: &[ExtendedFullViewingKey], nullifiers: &[(&[u8], usize)], @@ -151,6 +156,8 @@ pub fn scan_block( .collect(); if let Some(output) = scan_output( + parameters, + block.height as u32, to_scan, &ivks, &spent_from_accounts, @@ -187,6 +194,7 @@ mod tests { use pairing::bls12_381::{Bls12, Fr}; use rand_core::{OsRng, RngCore}; use zcash_primitives::{ + consensus, jubjub::{fs::Fs, FixedGenerators, JubjubParams, ToUniform}, merkle_tree::CommitmentTree, note_encryption::{Memo, SaplingNoteEncryption}, @@ -318,7 +326,14 @@ mod tests { assert_eq!(cb.vtx.len(), 2); let mut tree = CommitmentTree::new(); - let txs = scan_block(cb, &[extfvk], &[], &mut tree, &mut []); + let txs = scan_block( + &consensus::MainNetwork, + cb, + &[extfvk], + &[], + &mut tree, + &mut [], + ); assert_eq!(txs.len(), 1); let tx = &txs[0]; @@ -350,7 +365,14 @@ mod tests { assert_eq!(cb.vtx.len(), 3); let mut tree = CommitmentTree::new(); - let txs = scan_block(cb, &[extfvk], &[], &mut tree, &mut []); + let txs = scan_block( + &consensus::MainNetwork, + cb, + &[extfvk], + &[], + &mut tree, + &mut [], + ); assert_eq!(txs.len(), 1); let tx = &txs[0]; @@ -378,7 +400,14 @@ mod tests { assert_eq!(cb.vtx.len(), 2); let mut tree = CommitmentTree::new(); - let txs = scan_block(cb, &[], &[(&nf, account)], &mut tree, &mut []); + let txs = scan_block( + &consensus::MainNetwork, + cb, + &[], + &[(&nf, account)], + &mut tree, + &mut [], + ); assert_eq!(txs.len(), 1); let tx = &txs[0]; diff --git a/zcash_client_sqlite/src/scan.rs b/zcash_client_sqlite/src/scan.rs index 8dae82bb5..233e29750 100644 --- a/zcash_client_sqlite/src/scan.rs +++ b/zcash_client_sqlite/src/scan.rs @@ -9,6 +9,7 @@ use zcash_client_backend::{ proto::compact_formats::CompactBlock, welding_rig::scan_block, }; use zcash_primitives::{ + consensus, merkle_tree::{CommitmentTree, IncrementalWitness}, sapling::Node, transaction::Transaction, @@ -188,6 +189,7 @@ pub fn scan_cached_blocks, Q: AsRef>( let nf_refs: Vec<_> = nullifiers.iter().map(|(nf, acc)| (&nf[..], *acc)).collect(); let mut witness_refs: Vec<_> = witnesses.iter_mut().map(|w| &mut w.witness).collect(); scan_block( + &consensus::MainNetwork, block, &extfvks[..], &nf_refs, @@ -372,7 +374,7 @@ pub fn decrypt_and_store_transaction>( .collect::, _>, _>>()?? .ok_or(Error(ErrorKind::IncorrectHRPExtFVK))?; - let outputs = decrypt_transaction(tx, &extfvks); + let outputs = decrypt_transaction(&consensus::MainNetwork, tx, &extfvks); if outputs.is_empty() { // Nothing to see here diff --git a/zcash_primitives/src/consensus.rs b/zcash_primitives/src/consensus.rs index f0ea1003c..c2d42b756 100644 --- a/zcash_primitives/src/consensus.rs +++ b/zcash_primitives/src/consensus.rs @@ -5,10 +5,10 @@ use std::fmt; /// Zcash consensus parameters. pub trait Parameters { - fn activation_height(nu: NetworkUpgrade) -> Option; + fn activation_height(&self, nu: NetworkUpgrade) -> Option; - fn is_nu_active(nu: NetworkUpgrade, height: u32) -> bool { - match Self::activation_height(nu) { + fn is_nu_active(&self, nu: NetworkUpgrade, height: u32) -> bool { + match self.activation_height(nu) { Some(h) if h <= height => true, _ => false, } @@ -20,7 +20,7 @@ pub trait Parameters { pub struct MainNetwork; impl Parameters for MainNetwork { - fn activation_height(nu: NetworkUpgrade) -> Option { + fn activation_height(&self, nu: NetworkUpgrade) -> Option { match nu { NetworkUpgrade::Overwinter => Some(347_500), NetworkUpgrade::Sapling => Some(419_200), @@ -36,7 +36,7 @@ impl Parameters for MainNetwork { pub struct TestNetwork; impl Parameters for TestNetwork { - fn activation_height(nu: NetworkUpgrade) -> Option { + fn activation_height(&self, nu: NetworkUpgrade) -> Option { match nu { NetworkUpgrade::Overwinter => Some(207_500), NetworkUpgrade::Sapling => Some(280_000), @@ -174,9 +174,9 @@ impl BranchId { /// the given height. /// /// This is the branch ID that should be used when creating transactions. - pub fn for_height(height: u32) -> Self { + pub fn for_height(parameters: C, height: u32) -> Self { for nu in UPGRADES_IN_ORDER.iter().rev() { - if C::is_nu_active(*nu, height) { + if parameters.is_nu_active(*nu, height) { return nu.branch_id(); } } diff --git a/zcash_primitives/src/note_encryption.rs b/zcash_primitives/src/note_encryption.rs index c05a5c887..4238dc74a 100644 --- a/zcash_primitives/src/note_encryption.rs +++ b/zcash_primitives/src/note_encryption.rs @@ -1,6 +1,8 @@ //! Implementation of in-band secret distribution for Zcash transactions. use crate::{ + consensus, + consensus::NetworkUpgrade, jubjub::{ edwards, fs::{Fs, FsRepr}, @@ -335,7 +337,9 @@ impl SaplingNoteEncryption { } } -fn parse_note_plaintext_without_memo( +fn parse_note_plaintext_without_memo( + parameters: &P, + height: u32, ivk: &Fs, cmu: &Fr, plaintext: &[u8], @@ -380,7 +384,9 @@ fn parse_note_plaintext_without_memo( /// `PaymentAddress` to which the note was sent. /// /// Implements section 4.17.2 of the Zcash Protocol Specification. -pub fn try_sapling_note_decryption( +pub fn try_sapling_note_decryption( + parameters: &P, + height: u32, ivk: &Fs, epk: &edwards::Point, cmu: &Fr, @@ -405,7 +411,7 @@ pub fn try_sapling_note_decryption( NOTE_PLAINTEXT_SIZE ); - let (note, to) = parse_note_plaintext_without_memo(ivk, cmu, &plaintext)?; + let (note, to) = parse_note_plaintext_without_memo(parameters, height, ivk, cmu, &plaintext)?; let mut memo = [0u8; 512]; memo.copy_from_slice(&plaintext[COMPACT_NOTE_SIZE..NOTE_PLAINTEXT_SIZE]); @@ -422,7 +428,9 @@ pub fn try_sapling_note_decryption( /// Implements the procedure specified in [`ZIP 307`]. /// /// [`ZIP 307`]: https://github.com/zcash/zips/pull/226 -pub fn try_sapling_compact_note_decryption( +pub fn try_sapling_compact_note_decryption( + parameters: &P, + height: u32, ivk: &Fs, epk: &edwards::Point, cmu: &Fr, @@ -438,7 +446,7 @@ pub fn try_sapling_compact_note_decryption( plaintext.copy_from_slice(&enc_ciphertext); ChaCha20Ietf::xor(key.as_bytes(), &[0u8; 12], 1, &mut plaintext); - parse_note_plaintext_without_memo(ivk, cmu, &plaintext) + parse_note_plaintext_without_memo(parameters, height, ivk, cmu, &plaintext) } /// Recovery of the full note plaintext by the sender. @@ -448,7 +456,9 @@ pub fn try_sapling_compact_note_decryption( /// `PaymentAddress` to which the note was sent. /// /// Implements section 4.17.3 of the Zcash Protocol Specification. -pub fn try_sapling_output_recovery( +pub fn try_sapling_output_recovery( + parameters: &P, + height: u32, ovk: &OutgoingViewingKey, cv: &edwards::Point, cmu: &Fr, @@ -717,6 +727,7 @@ mod tests { } fn random_enc_ciphertext_with( + height: u32, ivk: Fs, mut rng: &mut R, ) -> ( diff --git a/zcash_primitives/src/transaction/builder.rs b/zcash_primitives/src/transaction/builder.rs index d554e27a6..3cc0cb941 100644 --- a/zcash_primitives/src/transaction/builder.rs +++ b/zcash_primitives/src/transaction/builder.rs @@ -13,6 +13,7 @@ use std::fmt; use crate::{ consensus, + consensus::NetworkUpgrade, keys::OutgoingViewingKey, legacy::TransparentAddress, merkle_tree::MerklePath, @@ -86,7 +87,9 @@ pub struct SaplingOutput { } impl SaplingOutput { - pub fn new( + pub fn new( + parameters: P, + height: u32, rng: &mut R, ovk: OutgoingViewingKey, to: PaymentAddress, @@ -304,6 +307,7 @@ impl TransactionMetadata { /// Generates a [`Transaction`] from its inputs and outputs. pub struct Builder { rng: R, + height: u32, mtx: TransactionData, fee: Amount, anchor: Option, @@ -344,6 +348,7 @@ impl Builder { Builder { rng, + height, mtx, fee: DEFAULT_FEE, anchor: None, @@ -399,7 +404,15 @@ impl Builder { value: Amount, memo: Option, ) -> Result<(), Error> { - let output = SaplingOutput::new(&mut self.rng, ovk, to, value, memo)?; + let output = SaplingOutput::new( + consensus::MainNetwork, + self.height, + &mut self.rng, + ovk, + to, + value, + memo, + )?; self.mtx.value_balance -= value;