From b537f0f7124938bc2f4867894dd616789fae1600 Mon Sep 17 00:00:00 2001 From: therealyingtong Date: Thu, 30 Jul 2020 13:13:59 +0800 Subject: [PATCH 01/31] 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; From 65504d9ca784d9bc62ffbfae0dedad6945594edc Mon Sep 17 00:00:00 2001 From: therealyingtong Date: Thu, 30 Jul 2020 12:36:12 +0800 Subject: [PATCH 02/31] Add enum Rseed to Note struct --- zcash_client_sqlite/src/scan.rs | 4 +- zcash_client_sqlite/src/transact.rs | 6 ++- zcash_primitives/src/note_encryption.rs | 60 ++++++++++++++------- zcash_primitives/src/primitives.rs | 31 ++++++++--- zcash_primitives/src/transaction/builder.rs | 28 ++++++---- zcash_proofs/src/sapling/prover.rs | 4 +- 6 files changed, 89 insertions(+), 44 deletions(-) diff --git a/zcash_client_sqlite/src/scan.rs b/zcash_client_sqlite/src/scan.rs index 233e29750..f4510c861 100644 --- a/zcash_client_sqlite/src/scan.rs +++ b/zcash_client_sqlite/src/scan.rs @@ -271,7 +271,7 @@ pub fn scan_cached_blocks, Q: AsRef>( .collect(); for output in tx.shielded_outputs { - let rcm = output.note.r.to_repr(); + let rcm = output.note.rcm().to_repr(); let nf = output.note.nf( &extfvks[output.account].fvk.vk, output.witness.position() as u64, @@ -459,7 +459,7 @@ pub fn decrypt_and_store_transaction>( ])?; } } else { - let rcm = output.note.r.to_repr(); + let rcm = output.note.rcm().to_repr(); // Try updating an existing received note. if stmt_update_received_note.execute(&[ diff --git a/zcash_client_sqlite/src/transact.rs b/zcash_client_sqlite/src/transact.rs index c7e9d285a..246877ae9 100644 --- a/zcash_client_sqlite/src/transact.rs +++ b/zcash_client_sqlite/src/transact.rs @@ -13,7 +13,7 @@ use zcash_primitives::{ keys::OutgoingViewingKey, merkle_tree::{IncrementalWitness, MerklePath}, note_encryption::Memo, - primitives::{Diversifier, Note}, + primitives::{Diversifier, Note, Rseed}, prover::TxProver, sapling::Node, transaction::{ @@ -249,7 +249,9 @@ pub fn create_to_address>( .vk .to_payment_address(diversifier, &JUBJUB) .unwrap(); - let note = from.create_note(note_value as u64, rcm, &JUBJUB).unwrap(); + let note = from + .create_note(note_value as u64, Rseed::BeforeZip212(rcm), &JUBJUB) + .unwrap(); let merkle_path = { let d: Vec<_> = row.get(3)?; diff --git a/zcash_primitives/src/note_encryption.rs b/zcash_primitives/src/note_encryption.rs index 4238dc74a..59623a9e4 100644 --- a/zcash_primitives/src/note_encryption.rs +++ b/zcash_primitives/src/note_encryption.rs @@ -8,7 +8,7 @@ use crate::{ fs::{Fs, FsRepr}, PrimeOrder, ToUniform, Unknown, }, - primitives::{Diversifier, Note, PaymentAddress}, + primitives::{Diversifier, Note, PaymentAddress, Rseed}, }; use blake2b_simd::{Hash as Blake2bHash, Params as Blake2bParams}; use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; @@ -233,12 +233,12 @@ fn prf_ock( /// let ovk = OutgoingViewingKey([0; 32]); /// /// let value = 1000; -/// let rcv = Fs::random(&mut rng); +/// let rcm = Fs::random(&mut rng); /// let cv = ValueCommitment:: { /// value, /// randomness: rcv.clone(), /// }; -/// let note = to.create_note(value, rcv, &JUBJUB).unwrap(); +/// let note = to.create_note(value, Rseed::BeforeZip212(rcm), &JUBJUB).unwrap(); /// let cmu = note.cm(&JUBJUB); /// /// let enc = SaplingNoteEncryption::new(ovk, note, to, Memo::default(), &mut rng); @@ -294,12 +294,22 @@ impl SaplingNoteEncryption { // Note plaintext encoding is defined in section 5.5 of the Zcash Protocol // Specification. let mut input = [0; NOTE_PLAINTEXT_SIZE]; - input[0] = 1; + input[0] = match self.note.rseed { + Rseed::BeforeZip212(_) => 1, + Rseed::AfterZip212(_) => 2, + }; input[1..12].copy_from_slice(&self.to.diversifier().0); (&mut input[12..20]) .write_u64::(self.note.value) .unwrap(); - input[20..COMPACT_NOTE_SIZE].copy_from_slice(self.note.r.to_repr().as_ref()); + match self.note.rseed { + Rseed::BeforeZip212(rcm) => { + input[20..COMPACT_NOTE_SIZE].copy_from_slice(rcm.to_repr().as_ref()); + } + Rseed::AfterZip212(rseed) => { + input[20..COMPACT_NOTE_SIZE].copy_from_slice(&rseed); + } + } input[COMPACT_NOTE_SIZE..NOTE_PLAINTEXT_SIZE].copy_from_slice(&self.memo.0); let mut output = [0u8; ENC_CIPHERTEXT_SIZE]; @@ -355,11 +365,15 @@ fn parse_note_plaintext_without_memo( let v = (&plaintext[12..20]).read_u64::().ok()?; - let rcm = Fs::from_repr(FsRepr( - plaintext[20..COMPACT_NOTE_SIZE] - .try_into() - .expect("slice is the correct length"), - ))?; + let mut r = [0u8; 32]; + r.copy_from_slice(&plaintext[20..COMPACT_NOTE_SIZE]); + + let rseed = if parameters.is_nu_active(NetworkUpgrade::Canopy, height) { + Rseed::AfterZip212(r) + } else { + let rcm = Fs::from_repr(FsRepr(r.try_into().expect("slice is the correct length")))?; + Rseed::BeforeZip212(rcm) + }; let diversifier = Diversifier(d); let pk_d = diversifier @@ -367,7 +381,7 @@ fn parse_note_plaintext_without_memo( .mul(ivk.to_repr(), &JUBJUB); let to = PaymentAddress::from_parts(diversifier, pk_d)?; - let note = to.create_note(v, rcm, &JUBJUB).unwrap(); + let note = to.create_note(v, rseed, &JUBJUB).unwrap(); if note.cm(&JUBJUB) != *cmu { // Published commitment doesn't match calculated commitment @@ -517,11 +531,15 @@ pub fn try_sapling_output_recovery( let v = (&plaintext[12..20]).read_u64::().ok()?; - let rcm = Fs::from_repr(FsRepr( - plaintext[20..COMPACT_NOTE_SIZE] - .try_into() - .expect("slice is the correct length"), - ))?; + let mut r = [0u8; 32]; + r.copy_from_slice(&plaintext[20..COMPACT_NOTE_SIZE]); + + let rseed = if parameters.is_nu_active(NetworkUpgrade::Canopy, height) { + Rseed::AfterZip212(r) + } else { + let rcm = Fs::from_repr(FsRepr(r.try_into().expect("slice is the correct length")))?; + Rseed::BeforeZip212(rcm) + }; let mut memo = [0u8; 512]; memo.copy_from_slice(&plaintext[COMPACT_NOTE_SIZE..NOTE_PLAINTEXT_SIZE]); @@ -537,7 +555,7 @@ pub fn try_sapling_output_recovery( } let to = PaymentAddress::from_parts(diversifier, pk_d)?; - let note = to.create_note(v, rcm, &JUBJUB).unwrap(); + let note = to.create_note(v, rseed, &JUBJUB).unwrap(); if note.cm(&JUBJUB) != *cmu { // Published commitment doesn't match calculated commitment @@ -555,7 +573,7 @@ mod tests { fs::{Fs, FsRepr}, PrimeOrder, Unknown, }, - primitives::{Diversifier, PaymentAddress, ValueCommitment}, + primitives::{Diversifier, PaymentAddress, Rseed, ValueCommitment}, }; use crypto_api_chachapoly::ChachaPolyIetf; use ff::{Field, PrimeField}; @@ -752,7 +770,7 @@ mod tests { let cv = value_commitment.cm(&JUBJUB).into(); let note = pa - .create_note(value, Fs::random(&mut rng), &JUBJUB) + .create_note(value, Rseed::BeforeZip212(Fs::random(&mut rng)), &JUBJUB) .unwrap(); let cmu = note.cm(&JUBJUB); @@ -1348,7 +1366,9 @@ mod tests { assert_eq!(ock.as_bytes(), tv.ock); let to = PaymentAddress::from_parts(Diversifier(tv.default_d), pk_d).unwrap(); - let note = to.create_note(tv.v, rcm, &JUBJUB).unwrap(); + let note = to + .create_note(tv.v, Rseed::BeforeZip212(rcm), &JUBJUB) + .unwrap(); assert_eq!(note.cm(&JUBJUB), cmu); // diff --git a/zcash_primitives/src/primitives.rs b/zcash_primitives/src/primitives.rs index cd06a60a9..fb7a4db5f 100644 --- a/zcash_primitives/src/primitives.rs +++ b/zcash_primitives/src/primitives.rs @@ -8,9 +8,11 @@ use crate::group_hash::group_hash; use crate::pedersen_hash::{pedersen_hash, Personalization}; -use byteorder::{LittleEndian, WriteBytesExt}; +use byteorder::{ByteOrder, LittleEndian, WriteBytesExt}; -use crate::jubjub::{edwards, FixedGenerators, JubjubEngine, JubjubParams, PrimeOrder}; +use crate::jubjub::{edwards, FixedGenerators, JubjubEngine, JubjubParams, PrimeOrder, ToUniform}; + +use crate::keys::prf_expand; use blake2s_simd::Params as Blake2sParams; @@ -207,18 +209,24 @@ impl PaymentAddress { pub fn create_note( &self, value: u64, - randomness: E::Fs, + randomness: Rseed, params: &E::Params, ) -> Option> { self.g_d(params).map(|g_d| Note { value, - r: randomness, + rseed: randomness, g_d, pk_d: self.pk_d.clone(), }) } } +#[derive(Clone, Debug)] +pub enum Rseed { + BeforeZip212(Fs), + AfterZip212([u8; 32]), +} + #[derive(Clone, Debug)] pub struct Note { /// The value of the note @@ -227,8 +235,8 @@ pub struct Note { pub g_d: edwards::Point, /// The public key of the address, g_d^ivk pub pk_d: edwards::Point, - /// The commitment randomness - pub r: E::Fs, + /// rseed + pub rseed: Rseed, } impl PartialEq for Note { @@ -236,7 +244,7 @@ impl PartialEq for Note { self.value == other.value && self.g_d == other.g_d && self.pk_d == other.pk_d - && self.r == other.r + && self.rcm() == other.rcm() } } @@ -280,7 +288,7 @@ impl Note { // Compute final commitment params .generator(FixedGenerators::NoteCommitmentRandomness) - .mul(self.r, params) + .mul(self.rcm(), params) .add(&hash_of_contents, params) } @@ -313,4 +321,11 @@ impl Note { // commitment to the x-coordinate is an injective encoding. self.cm_full_point(params).to_xy().0 } + + pub fn rcm(&self) -> E::Fs { + match self.rseed { + Rseed::BeforeZip212(rcm) => rcm, + Rseed::AfterZip212(rseed) => E::Fs::to_uniform(prf_expand(&rseed, &[0x04]).as_bytes()), + } + } } diff --git a/zcash_primitives/src/transaction/builder.rs b/zcash_primitives/src/transaction/builder.rs index 3cc0cb941..980aa8e34 100644 --- a/zcash_primitives/src/transaction/builder.rs +++ b/zcash_primitives/src/transaction/builder.rs @@ -3,7 +3,7 @@ use crate::zip32::ExtendedSpendingKey; use crate::{ jubjub::fs::Fs, - primitives::{Diversifier, Note, PaymentAddress}, + primitives::{Diversifier, Note, PaymentAddress, Rseed}, }; use ff::Field; use pairing::bls12_381::{Bls12, Fr}; @@ -110,7 +110,7 @@ impl SaplingOutput { g_d, pk_d: to.pk_d().clone(), value: value.into(), - r: rcm, + rseed: Rseed::BeforeZip212(rcm), }; Ok(SaplingOutput { @@ -139,7 +139,7 @@ impl SaplingOutput { ctx, encryptor.esk().clone(), self.to, - self.note.r, + self.note.rcm(), self.note.value, ); @@ -568,7 +568,7 @@ impl Builder { &mut ctx, proof_generation_key, spend.diversifier, - spend.note.r, + spend.note.rcm(), spend.alpha, spend.note.value, anchor, @@ -628,7 +628,7 @@ impl Builder { Note { g_d, pk_d, - r: Fs::random(&mut self.rng), + rseed: Rseed::BeforeZip212(Fs::random(&mut self.rng)), value: 0, }, ) @@ -637,8 +637,13 @@ impl Builder { let esk = generate_esk(&mut self.rng); let epk = dummy_note.g_d.mul(esk, &JUBJUB); - let (zkproof, cv) = - prover.output_proof(&mut ctx, esk, dummy_to, dummy_note.r, dummy_note.value); + let (zkproof, cv) = prover.output_proof( + &mut ctx, + esk, + dummy_to, + dummy_note.rcm(), + dummy_note.value, + ); let cmu = dummy_note.cm(&JUBJUB); @@ -717,6 +722,7 @@ mod tests { consensus, legacy::TransparentAddress, merkle_tree::{CommitmentTree, IncrementalWitness}, + primitives::Rseed, prover::mock::MockTxProver, sapling::Node, transaction::components::Amount, @@ -778,7 +784,7 @@ mod tests { let mut rng = OsRng; let note1 = to - .create_note(50000, Fs::random(&mut rng), &JUBJUB) + .create_note(50000, Rseed::BeforeZip212(Fs::random(&mut rng)), &JUBJUB) .unwrap(); let cm1 = Node::new(note1.cm(&JUBJUB).to_repr()); let mut tree = CommitmentTree::new(); @@ -877,7 +883,7 @@ mod tests { } let note1 = to - .create_note(59999, Fs::random(&mut rng), &JUBJUB) + .create_note(59999, Rseed::BeforeZip212(Fs::random(&mut rng)), &JUBJUB) .unwrap(); let cm1 = Node::new(note1.cm(&JUBJUB).to_repr()); let mut tree = CommitmentTree::new(); @@ -916,7 +922,9 @@ mod tests { ); } - let note2 = to.create_note(1, Fs::random(&mut rng), &JUBJUB).unwrap(); + let note2 = to + .create_note(1, Rseed::BeforeZip212(Fs::random(&mut rng)), &JUBJUB) + .unwrap(); let cm2 = Node::new(note2.cm(&JUBJUB).to_repr()); tree.append(cm2).unwrap(); witness1.append(cm2).unwrap(); diff --git a/zcash_proofs/src/sapling/prover.rs b/zcash_proofs/src/sapling/prover.rs index cc3898e06..6d578030f 100644 --- a/zcash_proofs/src/sapling/prover.rs +++ b/zcash_proofs/src/sapling/prover.rs @@ -8,7 +8,7 @@ use rand_core::OsRng; use std::ops::{AddAssign, Neg}; use zcash_primitives::{ jubjub::{edwards, fs::Fs, FixedGenerators, JubjubBls12, Unknown}, - primitives::{Diversifier, Note, PaymentAddress, ProofGenerationKey, ValueCommitment}, + primitives::{Diversifier, Note, PaymentAddress, ProofGenerationKey, Rseed, ValueCommitment}, }; use zcash_primitives::{ merkle_tree::MerklePath, @@ -102,7 +102,7 @@ impl SaplingProvingContext { .g_d::(params) .expect("was a valid diversifier before"), pk_d: payment_address.pk_d().clone(), - r: rcm, + rseed: Rseed::BeforeZip212(rcm), }; let nullifier = note.nf(&viewing_key, merkle_path.position, params); From eda00ec7ad6732fdab621dfce9c804c979872bc5 Mon Sep 17 00:00:00 2001 From: therealyingtong Date: Thu, 30 Jul 2020 22:34:29 +0800 Subject: [PATCH 03/31] Pass esk to SaplingNoteEncryption::new and add generate_or_derive_esk() --- zcash_primitives/src/note_encryption.rs | 17 +++-------------- zcash_primitives/src/primitives.rs | 18 +++++++++++++++++- zcash_primitives/src/transaction/builder.rs | 6 +++--- 3 files changed, 23 insertions(+), 18 deletions(-) diff --git a/zcash_primitives/src/note_encryption.rs b/zcash_primitives/src/note_encryption.rs index 59623a9e4..556e22e8b 100644 --- a/zcash_primitives/src/note_encryption.rs +++ b/zcash_primitives/src/note_encryption.rs @@ -6,7 +6,7 @@ use crate::{ jubjub::{ edwards, fs::{Fs, FsRepr}, - PrimeOrder, ToUniform, Unknown, + PrimeOrder, Unknown, }, primitives::{Diversifier, Note, PaymentAddress, Rseed}, }; @@ -15,7 +15,6 @@ use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; use crypto_api_chachapoly::{ChaCha20Ietf, ChachaPolyIetf}; use ff::PrimeField; use pairing::bls12_381::{Bls12, Fr}; -use rand_core::{CryptoRng, RngCore}; use std::convert::TryInto; use std::fmt; use std::str; @@ -135,15 +134,6 @@ impl str::FromStr for Memo { } } -pub fn generate_esk(rng: &mut R) -> Fs { - // create random 64 byte buffer - let mut buffer = [0u8; 64]; - rng.fill_bytes(&mut buffer); - - // reduce to uniform value - Fs::to_uniform(&buffer[..]) -} - /// Sapling key agreement for note encryption. /// /// Implements section 5.4.4.3 of the Zcash Protocol Specification. @@ -256,14 +246,13 @@ pub struct SaplingNoteEncryption { impl SaplingNoteEncryption { /// Creates a new encryption context for the given note. - pub fn new( + pub fn new( ovk: OutgoingViewingKey, note: Note, to: PaymentAddress, memo: Memo, - rng: &mut R, + esk: Fs, ) -> SaplingNoteEncryption { - let esk = generate_esk(rng); let epk = note.g_d.mul(esk, &JUBJUB); SaplingNoteEncryption { diff --git a/zcash_primitives/src/primitives.rs b/zcash_primitives/src/primitives.rs index fb7a4db5f..79d014649 100644 --- a/zcash_primitives/src/primitives.rs +++ b/zcash_primitives/src/primitives.rs @@ -8,7 +8,7 @@ use crate::group_hash::group_hash; use crate::pedersen_hash::{pedersen_hash, Personalization}; -use byteorder::{ByteOrder, LittleEndian, WriteBytesExt}; +use byteorder::{LittleEndian, WriteBytesExt}; use crate::jubjub::{edwards, FixedGenerators, JubjubEngine, JubjubParams, PrimeOrder, ToUniform}; @@ -16,6 +16,8 @@ use crate::keys::prf_expand; use blake2s_simd::Params as Blake2sParams; +use rand_core::{CryptoRng, RngCore}; + #[derive(Clone)] pub struct ValueCommitment { pub value: u64, @@ -328,4 +330,18 @@ impl Note { Rseed::AfterZip212(rseed) => E::Fs::to_uniform(prf_expand(&rseed, &[0x04]).as_bytes()), } } + + pub fn generate_or_derive_esk(&self, rng: &mut R) -> E::Fs { + match self.rseed { + Rseed::BeforeZip212(_) => { + // create random 64 byte buffer + let mut buffer = [0u8; 64]; + &rng.fill_bytes(&mut buffer); + + // reduce to uniform value + E::Fs::to_uniform(&buffer[..]) + } + Rseed::AfterZip212(rseed) => E::Fs::to_uniform(prf_expand(&rseed, &[0x05]).as_bytes()), + } + } } diff --git a/zcash_primitives/src/transaction/builder.rs b/zcash_primitives/src/transaction/builder.rs index 980aa8e34..36062f39d 100644 --- a/zcash_primitives/src/transaction/builder.rs +++ b/zcash_primitives/src/transaction/builder.rs @@ -17,7 +17,7 @@ use crate::{ keys::OutgoingViewingKey, legacy::TransparentAddress, merkle_tree::MerklePath, - note_encryption::{generate_esk, Memo, SaplingNoteEncryption}, + note_encryption::{Memo, SaplingNoteEncryption}, prover::TxProver, redjubjub::PrivateKey, sapling::{spend_sig, Node}, @@ -132,7 +132,7 @@ impl SaplingOutput { self.note.clone(), self.to.clone(), self.memo, - rng, + self.note.generate_or_derive_esk(rng), ); let (zkproof, cv) = prover.output_proof( @@ -634,7 +634,7 @@ impl Builder { ) }; - let esk = generate_esk(&mut self.rng); + let esk = dummy_note.generate_or_derive_esk(&mut self.rng); let epk = dummy_note.g_d.mul(esk, &JUBJUB); let (zkproof, cv) = prover.output_proof( From 6904c8f933fb74542ebef9b7c889a284c84d4aa4 Mon Sep 17 00:00:00 2001 From: therealyingtong Date: Thu, 30 Jul 2020 23:07:33 +0800 Subject: [PATCH 04/31] Implement plaintext_version_is_valid() --- zcash_primitives/src/consensus.rs | 4 +++ zcash_primitives/src/note_encryption.rs | 38 +++++++++++++++++---- zcash_primitives/src/transaction/builder.rs | 10 ++++-- 3 files changed, 44 insertions(+), 8 deletions(-) diff --git a/zcash_primitives/src/consensus.rs b/zcash_primitives/src/consensus.rs index c2d42b756..719231f02 100644 --- a/zcash_primitives/src/consensus.rs +++ b/zcash_primitives/src/consensus.rs @@ -13,6 +13,10 @@ pub trait Parameters { _ => false, } } + + fn zip_212_grace_period(&self) -> u32 { + 32256 + } } /// Marker struct for the production network. diff --git a/zcash_primitives/src/note_encryption.rs b/zcash_primitives/src/note_encryption.rs index 556e22e8b..b819acebc 100644 --- a/zcash_primitives/src/note_encryption.rs +++ b/zcash_primitives/src/note_encryption.rs @@ -344,9 +344,9 @@ fn parse_note_plaintext_without_memo( plaintext: &[u8], ) -> Option<(Note, PaymentAddress)> { // Check note plaintext version - match plaintext[0] { - 0x01 => (), - _ => return None, + match plaintext_version_is_valid(parameters, height, plaintext[0]) { + true => (), + false => return None, } let mut d = [0u8; 11]; @@ -380,6 +380,32 @@ fn parse_note_plaintext_without_memo( Some((note, to)) } +pub fn plaintext_version_is_valid( + parameters: &P, + height: u32, + leadbyte: u8, +) -> bool { + if parameters.is_nu_active(NetworkUpgrade::Canopy, height) { + let grace_period_end_height = parameters + .activation_height(NetworkUpgrade::Canopy) + .expect("Should have Canopy activation height") + + parameters.zip_212_grace_period(); + + if height < grace_period_end_height && leadbyte != 0x01 && leadbyte != 0x02 { + // non-{0x01,0x02} received after Canopy activation and before grace period has elapsed + false + } else if height >= grace_period_end_height && leadbyte != 0x02 { + // non-0x02 received past (Canopy activation height + grace period) + false + } else { + true + } + } else { + // return false if non-0x01 received when Canopy is not active + leadbyte == 0x01 + } +} + /// Trial decryption of the full note plaintext by the recipient. /// /// Attempts to decrypt and validate the given `enc_ciphertext` using the given `ivk`. @@ -510,9 +536,9 @@ pub fn try_sapling_output_recovery( ); // Check note plaintext version - match plaintext[0] { - 0x01 => (), - _ => return None, + match plaintext_version_is_valid(parameters, height, plaintext[0]) { + true => (), + false => return None, } let mut d = [0u8; 11]; diff --git a/zcash_primitives/src/transaction/builder.rs b/zcash_primitives/src/transaction/builder.rs index 36062f39d..81198c914 100644 --- a/zcash_primitives/src/transaction/builder.rs +++ b/zcash_primitives/src/transaction/builder.rs @@ -104,13 +104,19 @@ impl SaplingOutput { return Err(Error::InvalidAmount); } - let rcm = Fs::random(rng); + let rseed = if parameters.is_nu_active(NetworkUpgrade::Canopy, height) { + let mut buffer = [0u8; 32]; + &rng.fill_bytes(&mut buffer); + Rseed::AfterZip212(buffer) + } else { + Rseed::BeforeZip212(Fs::random(rng)) + }; let note = Note { g_d, pk_d: to.pk_d().clone(), value: value.into(), - rseed: Rseed::BeforeZip212(rcm), + rseed, }; Ok(SaplingOutput { From 895e251793542ab05dc1a8378227ac6624ae7cb4 Mon Sep 17 00:00:00 2001 From: therealyingtong Date: Fri, 31 Jul 2020 00:44:23 +0800 Subject: [PATCH 05/31] Fix tests --- zcash_client_backend/src/welding_rig.rs | 15 +- zcash_client_sqlite/src/lib.rs | 48 +- zcash_client_sqlite/src/transact.rs | 2 + zcash_primitives/src/consensus.rs | 37 +- zcash_primitives/src/note_encryption.rs | 922 ++++++++++++++------ zcash_primitives/src/transaction/builder.rs | 2 + zcash_proofs/src/circuit/sapling.rs | 16 +- 7 files changed, 724 insertions(+), 318 deletions(-) diff --git a/zcash_client_backend/src/welding_rig.rs b/zcash_client_backend/src/welding_rig.rs index e830a9169..e16634bd5 100644 --- a/zcash_client_backend/src/welding_rig.rs +++ b/zcash_client_backend/src/welding_rig.rs @@ -195,10 +195,11 @@ mod tests { use rand_core::{OsRng, RngCore}; use zcash_primitives::{ consensus, + consensus::{NetworkUpgrade, Parameters}, jubjub::{fs::Fs, FixedGenerators, JubjubParams, ToUniform}, merkle_tree::CommitmentTree, note_encryption::{Memo, SaplingNoteEncryption}, - primitives::Note, + primitives::{Note, Rseed}, transaction::components::Amount, zip32::{ExtendedFullViewingKey, ExtendedSpendingKey}, JUBJUB, @@ -257,18 +258,26 @@ mod tests { // Create a fake Note for the account let mut rng = OsRng; + let rseed = if consensus::MainNetwork.is_nu_active(NetworkUpgrade::Canopy, height as u32) { + let mut buffer = [0u8; 32]; + &rng.fill_bytes(&mut buffer); + Rseed::AfterZip212(buffer) + } else { + Rseed::BeforeZip212(Fs::random(&mut rng)) + }; let note = Note { g_d: to.diversifier().g_d::(&JUBJUB).unwrap(), pk_d: to.pk_d().clone(), value: value.into(), - r: Fs::random(&mut rng), + rseed, }; + let esk = note.generate_or_derive_esk(&mut rng); let encryptor = SaplingNoteEncryption::new( extfvk.fvk.ovk, note.clone(), to.clone(), Memo::default(), - &mut rng, + esk, ); let cmu = note.cm(&JUBJUB).to_repr().as_ref().to_owned(); let mut epk = vec![]; diff --git a/zcash_client_sqlite/src/lib.rs b/zcash_client_sqlite/src/lib.rs index e8f16de81..c0b4f7a8d 100644 --- a/zcash_client_sqlite/src/lib.rs +++ b/zcash_client_sqlite/src/lib.rs @@ -100,9 +100,11 @@ mod tests { }; use zcash_primitives::{ block::BlockHash, + consensus, + consensus::{NetworkUpgrade, Parameters}, jubjub::fs::Fs, note_encryption::{Memo, SaplingNoteEncryption}, - primitives::{Note, PaymentAddress}, + primitives::{Note, PaymentAddress, Rseed}, transaction::components::Amount, zip32::ExtendedFullViewingKey, JUBJUB, @@ -120,18 +122,26 @@ mod tests { // Create a fake Note for the account let mut rng = OsRng; + let rseed = if consensus::MainNetwork.is_nu_active(NetworkUpgrade::Canopy, height as u32) { + let mut buffer = [0u8; 32]; + &rng.fill_bytes(&mut buffer); + Rseed::AfterZip212(buffer) + } else { + Rseed::BeforeZip212(Fs::random(&mut rng)) + }; let note = Note { g_d: to.diversifier().g_d::(&JUBJUB).unwrap(), pk_d: to.pk_d().clone(), value: value.into(), - r: Fs::random(&mut rng), + rseed, }; + let esk = note.generate_or_derive_esk(&mut rng); let encryptor = SaplingNoteEncryption::new( extfvk.fvk.ovk, note.clone(), to.clone(), Memo::default(), - &mut rng, + esk, ); let cmu = note.cm(&JUBJUB).to_repr().as_ref().to_vec(); let mut epk = vec![]; @@ -168,6 +178,13 @@ mod tests { value: Amount, ) -> CompactBlock { let mut rng = OsRng; + let rseed = if consensus::MainNetwork.is_nu_active(NetworkUpgrade::Canopy, height as u32) { + let mut buffer = [0u8; 32]; + &rng.fill_bytes(&mut buffer); + Rseed::AfterZip212(buffer) + } else { + Rseed::BeforeZip212(Fs::random(&mut rng)) + }; // Create a fake CompactBlock containing the note let mut cspend = CompactSpend::new(); @@ -184,15 +201,11 @@ mod tests { g_d: to.diversifier().g_d::(&JUBJUB).unwrap(), pk_d: to.pk_d().clone(), value: value.into(), - r: Fs::random(&mut rng), + rseed, }; - let encryptor = SaplingNoteEncryption::new( - extfvk.fvk.ovk, - note.clone(), - to, - Memo::default(), - &mut rng, - ); + let esk = note.generate_or_derive_esk(&mut rng); + let encryptor = + SaplingNoteEncryption::new(extfvk.fvk.ovk, note.clone(), to, Memo::default(), esk); let cmu = note.cm(&JUBJUB).to_repr().as_ref().to_vec(); let mut epk = vec![]; encryptor.epk().write(&mut epk).unwrap(); @@ -208,18 +221,27 @@ mod tests { // Create a fake Note for the change ctx.outputs.push({ let change_addr = extfvk.default_address().unwrap().1; + let rseed = + if consensus::MainNetwork.is_nu_active(NetworkUpgrade::Canopy, height as u32) { + let mut buffer = [0u8; 32]; + &rng.fill_bytes(&mut buffer); + Rseed::AfterZip212(buffer) + } else { + Rseed::BeforeZip212(Fs::random(&mut rng)) + }; let note = Note { g_d: change_addr.diversifier().g_d::(&JUBJUB).unwrap(), pk_d: change_addr.pk_d().clone(), value: (in_value - value).into(), - r: Fs::random(&mut rng), + rseed, }; + let esk = note.generate_or_derive_esk(&mut rng); let encryptor = SaplingNoteEncryption::new( extfvk.fvk.ovk, note.clone(), change_addr, Memo::default(), - &mut rng, + esk, ); let cmu = note.cm(&JUBJUB).to_repr().as_ref().to_vec(); let mut epk = vec![]; diff --git a/zcash_client_sqlite/src/transact.rs b/zcash_client_sqlite/src/transact.rs index 246877ae9..8826e2449 100644 --- a/zcash_client_sqlite/src/transact.rs +++ b/zcash_client_sqlite/src/transact.rs @@ -816,6 +816,8 @@ mod tests { let output = &tx.shielded_outputs[output_index as usize]; try_sapling_output_recovery( + &consensus::MainNetwork, + SAPLING_ACTIVATION_HEIGHT as u32, &extfvk.fvk.ovk, &output.cv, &output.cmu, diff --git a/zcash_primitives/src/consensus.rs b/zcash_primitives/src/consensus.rs index 719231f02..45dcca16a 100644 --- a/zcash_primitives/src/consensus.rs +++ b/zcash_primitives/src/consensus.rs @@ -3,6 +3,12 @@ use std::convert::TryFrom; use std::fmt; +#[cfg(feature = "mainnet")] +pub const SAPLING_ACTIVATION_HEIGHT: u32 = 419_200; + +#[cfg(not(feature = "mainnet"))] +pub const SAPLING_ACTIVATION_HEIGHT: u32 = 280_000; + /// Zcash consensus parameters. pub trait Parameters { fn activation_height(&self, nu: NetworkUpgrade) -> Option; @@ -202,8 +208,8 @@ mod tests { let nu_a = UPGRADES_IN_ORDER[i - 1]; let nu_b = UPGRADES_IN_ORDER[i]; match ( - MainNetwork::activation_height(nu_a), - MainNetwork::activation_height(nu_b), + MainNetwork.activation_height(nu_a), + MainNetwork.activation_height(nu_b), ) { (Some(a), Some(b)) if a < b => (), (Some(_), None) => (), @@ -218,15 +224,9 @@ mod tests { #[test] fn nu_is_active() { - assert!(!MainNetwork::is_nu_active(NetworkUpgrade::Overwinter, 0)); - assert!(!MainNetwork::is_nu_active( - NetworkUpgrade::Overwinter, - 347_499 - )); - assert!(MainNetwork::is_nu_active( - NetworkUpgrade::Overwinter, - 347_500 - )); + assert!(!MainNetwork.is_nu_active(NetworkUpgrade::Overwinter, 0)); + assert!(!MainNetwork.is_nu_active(NetworkUpgrade::Overwinter, 347_499)); + assert!(MainNetwork.is_nu_active(NetworkUpgrade::Overwinter, 347_500)); } #[test] @@ -237,25 +237,28 @@ mod tests { #[test] fn branch_id_for_height() { - assert_eq!(BranchId::for_height::(0), BranchId::Sprout,); assert_eq!( - BranchId::for_height::(419_199), + BranchId::for_height::(MainNetwork, 0), + BranchId::Sprout, + ); + assert_eq!( + BranchId::for_height::(MainNetwork, 419_199), BranchId::Overwinter, ); assert_eq!( - BranchId::for_height::(419_200), + BranchId::for_height::(MainNetwork, 419_200), BranchId::Sapling, ); assert_eq!( - BranchId::for_height::(903_000), + BranchId::for_height::(MainNetwork, 903_000), BranchId::Heartwood, ); assert_eq!( - BranchId::for_height::(1_046_400), + BranchId::for_height::(MainNetwork, 1_046_400), BranchId::Canopy, ); assert_eq!( - BranchId::for_height::(5_000_000), + BranchId::for_height::(MainNetwork, 5_000_000), BranchId::Canopy, ); } diff --git a/zcash_primitives/src/note_encryption.rs b/zcash_primitives/src/note_encryption.rs index b819acebc..286ee2842 100644 --- a/zcash_primitives/src/note_encryption.rs +++ b/zcash_primitives/src/note_encryption.rs @@ -211,7 +211,7 @@ fn prf_ock( /// jubjub::fs::Fs, /// keys::OutgoingViewingKey, /// note_encryption::{Memo, SaplingNoteEncryption}, -/// primitives::{Diversifier, PaymentAddress, ValueCommitment}, +/// primitives::{Diversifier, PaymentAddress, Rseed, ValueCommitment}, /// JUBJUB, /// }; /// @@ -226,12 +226,13 @@ fn prf_ock( /// let rcm = Fs::random(&mut rng); /// let cv = ValueCommitment:: { /// value, -/// randomness: rcv.clone(), +/// randomness: rcm.clone(), /// }; /// let note = to.create_note(value, Rseed::BeforeZip212(rcm), &JUBJUB).unwrap(); /// let cmu = note.cm(&JUBJUB); /// -/// let enc = SaplingNoteEncryption::new(ovk, note, to, Memo::default(), &mut rng); +/// let esk = note.generate_or_derive_esk(&mut rng); +/// let enc = SaplingNoteEncryption::new(ovk, note, to, Memo::default(), esk); /// let encCiphertext = enc.encrypt_note_plaintext(); /// let outCiphertext = enc.encrypt_outgoing_plaintext(&cv.cm(&JUBJUB).into(), &cmu); /// ``` @@ -583,6 +584,8 @@ pub fn try_sapling_output_recovery( #[cfg(test)] mod tests { use crate::{ + consensus, + consensus::{NetworkUpgrade, Parameters, SAPLING_ACTIVATION_HEIGHT}, jubjub::{ edwards, fs::{Fs, FsRepr}, @@ -723,6 +726,7 @@ mod tests { } fn random_enc_ciphertext( + height: u32, mut rng: &mut R, ) -> ( OutgoingViewingKey, @@ -736,10 +740,20 @@ mod tests { let ivk = Fs::random(&mut rng); let (ovk, ivk, cv, cmu, epk, enc_ciphertext, out_ciphertext) = - random_enc_ciphertext_with(ivk, rng); + random_enc_ciphertext_with(height, ivk, rng); - assert!(try_sapling_note_decryption(&ivk, &epk, &cmu, &enc_ciphertext).is_some()); + assert!(try_sapling_note_decryption( + &consensus::MainNetwork, + height, + &ivk, + &epk, + &cmu, + &enc_ciphertext + ) + .is_some()); assert!(try_sapling_compact_note_decryption( + &consensus::MainNetwork, + height, &ivk, &epk, &cmu, @@ -747,6 +761,8 @@ mod tests { ) .is_some()); assert!(try_sapling_output_recovery( + &consensus::MainNetwork, + height, &ovk, &cv, &cmu, @@ -784,13 +800,20 @@ mod tests { }; let cv = value_commitment.cm(&JUBJUB).into(); - let note = pa - .create_note(value, Rseed::BeforeZip212(Fs::random(&mut rng)), &JUBJUB) - .unwrap(); + let rseed = if consensus::MainNetwork.is_nu_active(NetworkUpgrade::Canopy, height) { + let mut buffer = [0u8; 32]; + &rng.fill_bytes(&mut buffer); + Rseed::AfterZip212(buffer) + } else { + Rseed::BeforeZip212(Fs::random(rng)) + }; + + let note = pa.create_note(value, rseed, &JUBJUB).unwrap(); let cmu = note.cm(&JUBJUB); let ovk = OutgoingViewingKey([0; 32]); - let ne = SaplingNoteEncryption::new(ovk, note, pa, Memo([0; 512]), rng); + let esk = note.generate_or_derive_esk(&mut rng); + let ne = SaplingNoteEncryption::new(ovk, note, pa, Memo([0; 512]), esk); let epk = ne.epk(); let enc_ciphertext = ne.encrypt_note_plaintext(); let out_ciphertext = ne.encrypt_outgoing_plaintext(&cv, &cmu); @@ -895,432 +918,749 @@ mod tests { #[test] fn decryption_with_invalid_ivk() { let mut rng = OsRng; + let height_v1 = SAPLING_ACTIVATION_HEIGHT; + let height_v2 = consensus::MainNetwork + .activation_height(NetworkUpgrade::Canopy) + .unwrap(); + let height_array = [height_v1, height_v2]; - let (_, _, _, cmu, epk, enc_ciphertext, _) = random_enc_ciphertext(&mut rng); + for height_ref in height_array.iter() { + let height = *height_ref; + let (_, _, _, cmu, epk, enc_ciphertext, _) = random_enc_ciphertext(height, &mut rng); - assert_eq!( - try_sapling_note_decryption(&Fs::random(&mut rng), &epk, &cmu, &enc_ciphertext), - None - ); + assert_eq!( + try_sapling_note_decryption( + &consensus::MainNetwork, + height, + &Fs::random(&mut rng), + &epk, + &cmu, + &enc_ciphertext + ), + None + ); + } } #[test] fn decryption_with_invalid_epk() { let mut rng = OsRng; + let height_v1 = SAPLING_ACTIVATION_HEIGHT; + let height_v2 = consensus::MainNetwork + .activation_height(NetworkUpgrade::Canopy) + .unwrap(); + let height_array = [height_v1, height_v2]; - let (_, ivk, _, cmu, _, enc_ciphertext, _) = random_enc_ciphertext(&mut rng); + for height_ref in height_array.iter() { + let height = *height_ref; + let (_, ivk, _, cmu, _, enc_ciphertext, _) = random_enc_ciphertext(height, &mut rng); - assert_eq!( - try_sapling_note_decryption( - &ivk, - &edwards::Point::::rand(&mut rng, &JUBJUB).mul_by_cofactor(&JUBJUB), - &cmu, - &enc_ciphertext - ), - None - ); + assert_eq!( + try_sapling_note_decryption( + &consensus::MainNetwork, + height, + &ivk, + &edwards::Point::::rand(&mut rng, &JUBJUB).mul_by_cofactor(&JUBJUB), + &cmu, + &enc_ciphertext + ), + None + ); + } } #[test] fn decryption_with_invalid_cmu() { let mut rng = OsRng; + let height_v1 = SAPLING_ACTIVATION_HEIGHT; + let height_v2 = consensus::MainNetwork + .activation_height(NetworkUpgrade::Canopy) + .unwrap(); + let height_array = [height_v1, height_v2]; - let (_, ivk, _, _, epk, enc_ciphertext, _) = random_enc_ciphertext(&mut rng); + for height_ref in height_array.iter() { + let height = *height_ref; + let (_, ivk, _, _, epk, enc_ciphertext, _) = random_enc_ciphertext(height, &mut rng); - assert_eq!( - try_sapling_note_decryption(&ivk, &epk, &Fr::random(&mut rng), &enc_ciphertext), - None - ); + assert_eq!( + try_sapling_note_decryption( + &consensus::MainNetwork, + height, + &ivk, + &epk, + &Fr::random(&mut rng), + &enc_ciphertext + ), + None + ); + } } #[test] fn decryption_with_invalid_tag() { let mut rng = OsRng; + let height_v1 = SAPLING_ACTIVATION_HEIGHT; + let height_v2 = consensus::MainNetwork + .activation_height(NetworkUpgrade::Canopy) + .unwrap(); + let height_array = [height_v1, height_v2]; - let (_, ivk, _, cmu, epk, mut enc_ciphertext, _) = random_enc_ciphertext(&mut rng); + for height_ref in height_array.iter() { + let height = *height_ref; + let (_, ivk, _, cmu, epk, mut enc_ciphertext, _) = + random_enc_ciphertext(height, &mut rng); - enc_ciphertext[ENC_CIPHERTEXT_SIZE - 1] ^= 0xff; - assert_eq!( - try_sapling_note_decryption(&ivk, &epk, &cmu, &enc_ciphertext), - None - ); + enc_ciphertext[ENC_CIPHERTEXT_SIZE - 1] ^= 0xff; + assert_eq!( + try_sapling_note_decryption( + &consensus::MainNetwork, + height, + &ivk, + &epk, + &cmu, + &enc_ciphertext + ), + None + ); + } } #[test] fn decryption_with_invalid_version_byte() { let mut rng = OsRng; + let height_v1 = SAPLING_ACTIVATION_HEIGHT; + let height_v2 = consensus::MainNetwork + .activation_height(NetworkUpgrade::Canopy) + .unwrap(); + let height_array = [height_v1, height_v2]; + let leadbyte_array = [0x02, 0x03]; - let (ovk, ivk, cv, cmu, epk, mut enc_ciphertext, out_ciphertext) = - random_enc_ciphertext(&mut rng); + for (i, height_ref) in height_array.iter().enumerate() { + let height = *height_ref; + let (ovk, ivk, cv, cmu, epk, mut enc_ciphertext, out_ciphertext) = + random_enc_ciphertext(height, &mut rng); - reencrypt_enc_ciphertext( - &ovk, - &cv, - &cmu, - &epk, - &mut enc_ciphertext, - &out_ciphertext, - |pt| pt[0] = 0x02, - ); - assert_eq!( - try_sapling_note_decryption(&ivk, &epk, &cmu, &enc_ciphertext), - None - ); + reencrypt_enc_ciphertext( + &ovk, + &cv, + &cmu, + &epk, + &mut enc_ciphertext, + &out_ciphertext, + |pt| pt[0] = leadbyte_array[i], + ); + assert_eq!( + try_sapling_note_decryption( + &consensus::MainNetwork, + height, + &ivk, + &epk, + &cmu, + &enc_ciphertext + ), + None + ); + } } #[test] fn decryption_with_invalid_diversifier() { let mut rng = OsRng; + let height_v1 = SAPLING_ACTIVATION_HEIGHT; + let height_v2 = consensus::MainNetwork + .activation_height(NetworkUpgrade::Canopy) + .unwrap(); + let height_array = [height_v1, height_v2]; - let (ovk, ivk, cv, cmu, epk, mut enc_ciphertext, out_ciphertext) = - random_enc_ciphertext(&mut rng); + for height_ref in height_array.iter() { + let height = *height_ref; + let (ovk, ivk, cv, cmu, epk, mut enc_ciphertext, out_ciphertext) = + random_enc_ciphertext(height, &mut rng); - reencrypt_enc_ciphertext( - &ovk, - &cv, - &cmu, - &epk, - &mut enc_ciphertext, - &out_ciphertext, - |pt| pt[1..12].copy_from_slice(&find_invalid_diversifier().0), - ); - assert_eq!( - try_sapling_note_decryption(&ivk, &epk, &cmu, &enc_ciphertext), - None - ); + reencrypt_enc_ciphertext( + &ovk, + &cv, + &cmu, + &epk, + &mut enc_ciphertext, + &out_ciphertext, + |pt| pt[1..12].copy_from_slice(&find_invalid_diversifier().0), + ); + assert_eq!( + try_sapling_note_decryption( + &consensus::MainNetwork, + height, + &ivk, + &epk, + &cmu, + &enc_ciphertext + ), + None + ); + } } #[test] fn decryption_with_incorrect_diversifier() { let mut rng = OsRng; + let height_v1 = SAPLING_ACTIVATION_HEIGHT; + let height_v2 = consensus::MainNetwork + .activation_height(NetworkUpgrade::Canopy) + .unwrap(); + let height_array = [height_v1, height_v2]; - let (ovk, ivk, cv, cmu, epk, mut enc_ciphertext, out_ciphertext) = - random_enc_ciphertext(&mut rng); + for height_ref in height_array.iter() { + let height = *height_ref; + let (ovk, ivk, cv, cmu, epk, mut enc_ciphertext, out_ciphertext) = + random_enc_ciphertext(height, &mut rng); - reencrypt_enc_ciphertext( - &ovk, - &cv, - &cmu, - &epk, - &mut enc_ciphertext, - &out_ciphertext, - |pt| pt[1..12].copy_from_slice(&find_valid_diversifier().0), - ); - assert_eq!( - try_sapling_note_decryption(&ivk, &epk, &cmu, &enc_ciphertext), - None - ); + reencrypt_enc_ciphertext( + &ovk, + &cv, + &cmu, + &epk, + &mut enc_ciphertext, + &out_ciphertext, + |pt| pt[1..12].copy_from_slice(&find_valid_diversifier().0), + ); + assert_eq!( + try_sapling_note_decryption( + &consensus::MainNetwork, + height, + &ivk, + &epk, + &cmu, + &enc_ciphertext + ), + None + ); + } } #[test] fn compact_decryption_with_invalid_ivk() { let mut rng = OsRng; + let height_v1 = SAPLING_ACTIVATION_HEIGHT; + let height_v2 = consensus::MainNetwork + .activation_height(NetworkUpgrade::Canopy) + .unwrap(); + let height_array = [height_v1, height_v2]; - let (_, _, _, cmu, epk, enc_ciphertext, _) = random_enc_ciphertext(&mut rng); + for height_ref in height_array.iter() { + let height = *height_ref; + let (_, _, _, cmu, epk, enc_ciphertext, _) = random_enc_ciphertext(height, &mut rng); - assert_eq!( - try_sapling_compact_note_decryption( - &Fs::random(&mut rng), - &epk, - &cmu, - &enc_ciphertext[..COMPACT_NOTE_SIZE] - ), - None - ); + assert_eq!( + try_sapling_compact_note_decryption( + &consensus::MainNetwork, + height, + &Fs::random(&mut rng), + &epk, + &cmu, + &enc_ciphertext[..COMPACT_NOTE_SIZE] + ), + None + ); + } } #[test] fn compact_decryption_with_invalid_epk() { let mut rng = OsRng; + let height_v1 = SAPLING_ACTIVATION_HEIGHT; + let height_v2 = consensus::MainNetwork + .activation_height(NetworkUpgrade::Canopy) + .unwrap(); + let height_array = [height_v1, height_v2]; - let (_, ivk, _, cmu, _, enc_ciphertext, _) = random_enc_ciphertext(&mut rng); + for height_ref in height_array.iter() { + let height = *height_ref; + let (_, ivk, _, cmu, _, enc_ciphertext, _) = random_enc_ciphertext(height, &mut rng); - assert_eq!( - try_sapling_compact_note_decryption( - &ivk, - &edwards::Point::::rand(&mut rng, &JUBJUB).mul_by_cofactor(&JUBJUB), - &cmu, - &enc_ciphertext[..COMPACT_NOTE_SIZE] - ), - None - ); + assert_eq!( + try_sapling_compact_note_decryption( + &consensus::MainNetwork, + height, + &ivk, + &edwards::Point::::rand(&mut rng, &JUBJUB).mul_by_cofactor(&JUBJUB), + &cmu, + &enc_ciphertext[..COMPACT_NOTE_SIZE] + ), + None + ); + } } #[test] fn compact_decryption_with_invalid_cmu() { let mut rng = OsRng; + let height_v1 = SAPLING_ACTIVATION_HEIGHT; + let height_v2 = consensus::MainNetwork + .activation_height(NetworkUpgrade::Canopy) + .unwrap(); + let height_array = [height_v1, height_v2]; - let (_, ivk, _, _, epk, enc_ciphertext, _) = random_enc_ciphertext(&mut rng); + for height_ref in height_array.iter() { + let height = *height_ref; + let (_, ivk, _, _, epk, enc_ciphertext, _) = random_enc_ciphertext(height, &mut rng); - assert_eq!( - try_sapling_compact_note_decryption( - &ivk, - &epk, - &Fr::random(&mut rng), - &enc_ciphertext[..COMPACT_NOTE_SIZE] - ), - None - ); + assert_eq!( + try_sapling_compact_note_decryption( + &consensus::MainNetwork, + height, + &ivk, + &epk, + &Fr::random(&mut rng), + &enc_ciphertext[..COMPACT_NOTE_SIZE] + ), + None + ); + } } #[test] fn compact_decryption_with_invalid_version_byte() { let mut rng = OsRng; + let height_v1 = SAPLING_ACTIVATION_HEIGHT; + let height_v2 = consensus::MainNetwork + .activation_height(NetworkUpgrade::Canopy) + .unwrap(); + let height_array = [height_v1, height_v2]; + let leadbyte_array = [0x02, 0x03]; - let (ovk, ivk, cv, cmu, epk, mut enc_ciphertext, out_ciphertext) = - random_enc_ciphertext(&mut rng); + for (i, height_ref) in height_array.iter().enumerate() { + let height = *height_ref; + let (ovk, ivk, cv, cmu, epk, mut enc_ciphertext, out_ciphertext) = + random_enc_ciphertext(height, &mut rng); - reencrypt_enc_ciphertext( - &ovk, - &cv, - &cmu, - &epk, - &mut enc_ciphertext, - &out_ciphertext, - |pt| pt[0] = 0x02, - ); - assert_eq!( - try_sapling_compact_note_decryption( - &ivk, - &epk, + reencrypt_enc_ciphertext( + &ovk, + &cv, &cmu, - &enc_ciphertext[..COMPACT_NOTE_SIZE] - ), - None - ); + &epk, + &mut enc_ciphertext, + &out_ciphertext, + |pt| pt[0] = leadbyte_array[i], + ); + assert_eq!( + try_sapling_compact_note_decryption( + &consensus::MainNetwork, + height, + &ivk, + &epk, + &cmu, + &enc_ciphertext[..COMPACT_NOTE_SIZE] + ), + None + ); + } } #[test] fn compact_decryption_with_invalid_diversifier() { let mut rng = OsRng; + let height_v1 = SAPLING_ACTIVATION_HEIGHT; + let height_v2 = consensus::MainNetwork + .activation_height(NetworkUpgrade::Canopy) + .unwrap(); + let height_array = [height_v1, height_v2]; - let (ovk, ivk, cv, cmu, epk, mut enc_ciphertext, out_ciphertext) = - random_enc_ciphertext(&mut rng); + for height_ref in height_array.iter() { + let height = *height_ref; + let (ovk, ivk, cv, cmu, epk, mut enc_ciphertext, out_ciphertext) = + random_enc_ciphertext(height, &mut rng); - reencrypt_enc_ciphertext( - &ovk, - &cv, - &cmu, - &epk, - &mut enc_ciphertext, - &out_ciphertext, - |pt| pt[1..12].copy_from_slice(&find_invalid_diversifier().0), - ); - assert_eq!( - try_sapling_compact_note_decryption( - &ivk, - &epk, + reencrypt_enc_ciphertext( + &ovk, + &cv, &cmu, - &enc_ciphertext[..COMPACT_NOTE_SIZE] - ), - None - ); + &epk, + &mut enc_ciphertext, + &out_ciphertext, + |pt| pt[1..12].copy_from_slice(&find_invalid_diversifier().0), + ); + assert_eq!( + try_sapling_compact_note_decryption( + &consensus::MainNetwork, + height, + &ivk, + &epk, + &cmu, + &enc_ciphertext[..COMPACT_NOTE_SIZE] + ), + None + ); + } } #[test] fn compact_decryption_with_incorrect_diversifier() { let mut rng = OsRng; + let height_v1 = SAPLING_ACTIVATION_HEIGHT; + let height_v2 = consensus::MainNetwork + .activation_height(NetworkUpgrade::Canopy) + .unwrap(); + let height_array = [height_v1, height_v2]; - let (ovk, ivk, cv, cmu, epk, mut enc_ciphertext, out_ciphertext) = - random_enc_ciphertext(&mut rng); + for height_ref in height_array.iter() { + let height = *height_ref; + let (ovk, ivk, cv, cmu, epk, mut enc_ciphertext, out_ciphertext) = + random_enc_ciphertext(height, &mut rng); - reencrypt_enc_ciphertext( - &ovk, - &cv, - &cmu, - &epk, - &mut enc_ciphertext, - &out_ciphertext, - |pt| pt[1..12].copy_from_slice(&find_valid_diversifier().0), - ); - assert_eq!( - try_sapling_compact_note_decryption( - &ivk, - &epk, + reencrypt_enc_ciphertext( + &ovk, + &cv, &cmu, - &enc_ciphertext[..COMPACT_NOTE_SIZE] - ), - None - ); + &epk, + &mut enc_ciphertext, + &out_ciphertext, + |pt| pt[1..12].copy_from_slice(&find_valid_diversifier().0), + ); + assert_eq!( + try_sapling_compact_note_decryption( + &consensus::MainNetwork, + height, + &ivk, + &epk, + &cmu, + &enc_ciphertext[..COMPACT_NOTE_SIZE] + ), + None + ); + } } #[test] fn recovery_with_invalid_ovk() { let mut rng = OsRng; + let height_v1 = SAPLING_ACTIVATION_HEIGHT; + let height_v2 = consensus::MainNetwork + .activation_height(NetworkUpgrade::Canopy) + .unwrap(); + let height_array = [height_v1, height_v2]; - let (mut ovk, _, cv, cmu, epk, enc_ciphertext, out_ciphertext) = - random_enc_ciphertext(&mut rng); + for height_ref in height_array.iter() { + let height = *height_ref; + let (mut ovk, _, cv, cmu, epk, enc_ciphertext, out_ciphertext) = + random_enc_ciphertext(height, &mut rng); - ovk.0[0] ^= 0xff; - assert_eq!( - try_sapling_output_recovery(&ovk, &cv, &cmu, &epk, &enc_ciphertext, &out_ciphertext), - None - ); + ovk.0[0] ^= 0xff; + assert_eq!( + try_sapling_output_recovery( + &consensus::MainNetwork, + height, + &ovk, + &cv, + &cmu, + &epk, + &enc_ciphertext, + &out_ciphertext + ), + None + ); + } } #[test] fn recovery_with_invalid_cv() { let mut rng = OsRng; + let height_v1 = SAPLING_ACTIVATION_HEIGHT; + let height_v2 = consensus::MainNetwork + .activation_height(NetworkUpgrade::Canopy) + .unwrap(); + let height_array = [height_v1, height_v2]; - let (ovk, _, _, cmu, epk, enc_ciphertext, out_ciphertext) = random_enc_ciphertext(&mut rng); + for height_ref in height_array.iter() { + let height = *height_ref; + let (ovk, _, _, cmu, epk, enc_ciphertext, out_ciphertext) = + random_enc_ciphertext(height, &mut rng); - assert_eq!( - try_sapling_output_recovery( - &ovk, - &edwards::Point::::rand(&mut rng, &JUBJUB), - &cmu, - &epk, - &enc_ciphertext, - &out_ciphertext - ), - None - ); + assert_eq!( + try_sapling_output_recovery( + &consensus::MainNetwork, + height, + &ovk, + &edwards::Point::::rand(&mut rng, &JUBJUB), + &cmu, + &epk, + &enc_ciphertext, + &out_ciphertext + ), + None + ); + } } #[test] fn recovery_with_invalid_cmu() { let mut rng = OsRng; + let height_v1 = SAPLING_ACTIVATION_HEIGHT; + let height_v2 = consensus::MainNetwork + .activation_height(NetworkUpgrade::Canopy) + .unwrap(); + let height_array = [height_v1, height_v2]; - let (ovk, _, cv, _, epk, enc_ciphertext, out_ciphertext) = random_enc_ciphertext(&mut rng); + for height_ref in height_array.iter() { + let height = *height_ref; + let (ovk, _, cv, _, epk, enc_ciphertext, out_ciphertext) = + random_enc_ciphertext(height, &mut rng); - assert_eq!( - try_sapling_output_recovery( - &ovk, - &cv, - &Fr::random(&mut rng), - &epk, - &enc_ciphertext, - &out_ciphertext - ), - None - ); + assert_eq!( + try_sapling_output_recovery( + &consensus::MainNetwork, + height, + &ovk, + &cv, + &Fr::random(&mut rng), + &epk, + &enc_ciphertext, + &out_ciphertext + ), + None + ); + } } #[test] fn recovery_with_invalid_epk() { let mut rng = OsRng; + let height_v1 = SAPLING_ACTIVATION_HEIGHT; + let height_v2 = consensus::MainNetwork + .activation_height(NetworkUpgrade::Canopy) + .unwrap(); + let height_array = [height_v1, height_v2]; - let (ovk, _, cv, cmu, _, enc_ciphertext, out_ciphertext) = random_enc_ciphertext(&mut rng); + for height_ref in height_array.iter() { + let height = *height_ref; + let (ovk, _, cv, cmu, _, enc_ciphertext, out_ciphertext) = + random_enc_ciphertext(height, &mut rng); - assert_eq!( - try_sapling_output_recovery( - &ovk, - &cv, - &cmu, - &edwards::Point::::rand(&mut rng, &JUBJUB).mul_by_cofactor(&JUBJUB), - &enc_ciphertext, - &out_ciphertext - ), - None - ); + assert_eq!( + try_sapling_output_recovery( + &consensus::MainNetwork, + height, + &ovk, + &cv, + &cmu, + &edwards::Point::::rand(&mut rng, &JUBJUB).mul_by_cofactor(&JUBJUB), + &enc_ciphertext, + &out_ciphertext + ), + None + ); + } } #[test] fn recovery_with_invalid_enc_tag() { let mut rng = OsRng; + let height_v1 = SAPLING_ACTIVATION_HEIGHT; + let height_v2 = consensus::MainNetwork + .activation_height(NetworkUpgrade::Canopy) + .unwrap(); + let height_array = [height_v1, height_v2]; - let (ovk, _, cv, cmu, epk, mut enc_ciphertext, out_ciphertext) = - random_enc_ciphertext(&mut rng); + for height_ref in height_array.iter() { + let height = *height_ref; + let (ovk, _, cv, cmu, epk, mut enc_ciphertext, out_ciphertext) = + random_enc_ciphertext(height, &mut rng); - enc_ciphertext[ENC_CIPHERTEXT_SIZE - 1] ^= 0xff; - assert_eq!( - try_sapling_output_recovery(&ovk, &cv, &cmu, &epk, &enc_ciphertext, &out_ciphertext), - None - ); + enc_ciphertext[ENC_CIPHERTEXT_SIZE - 1] ^= 0xff; + assert_eq!( + try_sapling_output_recovery( + &consensus::MainNetwork, + height, + &ovk, + &cv, + &cmu, + &epk, + &enc_ciphertext, + &out_ciphertext + ), + None + ); + } } #[test] fn recovery_with_invalid_out_tag() { let mut rng = OsRng; + let height_v1 = SAPLING_ACTIVATION_HEIGHT; + let height_v2 = consensus::MainNetwork + .activation_height(NetworkUpgrade::Canopy) + .unwrap(); + let height_array = [height_v1, height_v2]; - let (ovk, _, cv, cmu, epk, enc_ciphertext, mut out_ciphertext) = - random_enc_ciphertext(&mut rng); + for height_ref in height_array.iter() { + let height = *height_ref; + let (ovk, _, cv, cmu, epk, enc_ciphertext, mut out_ciphertext) = + random_enc_ciphertext(height, &mut rng); - out_ciphertext[OUT_CIPHERTEXT_SIZE - 1] ^= 0xff; - assert_eq!( - try_sapling_output_recovery(&ovk, &cv, &cmu, &epk, &enc_ciphertext, &out_ciphertext), - None - ); + out_ciphertext[OUT_CIPHERTEXT_SIZE - 1] ^= 0xff; + assert_eq!( + try_sapling_output_recovery( + &consensus::MainNetwork, + height, + &ovk, + &cv, + &cmu, + &epk, + &enc_ciphertext, + &out_ciphertext + ), + None + ); + } } #[test] fn recovery_with_invalid_version_byte() { let mut rng = OsRng; + let height_v1 = SAPLING_ACTIVATION_HEIGHT; + let height_v2 = consensus::MainNetwork + .activation_height(NetworkUpgrade::Canopy) + .unwrap(); + let height_array = [height_v1, height_v2]; + let leadbyte_array = [0x02, 0x03]; - let (ovk, _, cv, cmu, epk, mut enc_ciphertext, out_ciphertext) = - random_enc_ciphertext(&mut rng); + for (i, height_ref) in height_array.iter().enumerate() { + let height = *height_ref; + let (ovk, _, cv, cmu, epk, mut enc_ciphertext, out_ciphertext) = + random_enc_ciphertext(height, &mut rng); - reencrypt_enc_ciphertext( - &ovk, - &cv, - &cmu, - &epk, - &mut enc_ciphertext, - &out_ciphertext, - |pt| pt[0] = 0x02, - ); - assert_eq!( - try_sapling_output_recovery(&ovk, &cv, &cmu, &epk, &enc_ciphertext, &out_ciphertext), - None - ); + reencrypt_enc_ciphertext( + &ovk, + &cv, + &cmu, + &epk, + &mut enc_ciphertext, + &out_ciphertext, + |pt| pt[0] = leadbyte_array[i], + ); + assert_eq!( + try_sapling_output_recovery( + &consensus::MainNetwork, + height, + &ovk, + &cv, + &cmu, + &epk, + &enc_ciphertext, + &out_ciphertext + ), + None + ); + } } #[test] fn recovery_with_invalid_diversifier() { let mut rng = OsRng; + let height_v1 = SAPLING_ACTIVATION_HEIGHT; + let height_v2 = consensus::MainNetwork + .activation_height(NetworkUpgrade::Canopy) + .unwrap(); + let height_array = [height_v1, height_v2]; - let (ovk, _, cv, cmu, epk, mut enc_ciphertext, out_ciphertext) = - random_enc_ciphertext(&mut rng); + for height_ref in height_array.iter() { + let height = *height_ref; + let (ovk, _, cv, cmu, epk, mut enc_ciphertext, out_ciphertext) = + random_enc_ciphertext(height, &mut rng); - reencrypt_enc_ciphertext( - &ovk, - &cv, - &cmu, - &epk, - &mut enc_ciphertext, - &out_ciphertext, - |pt| pt[1..12].copy_from_slice(&find_invalid_diversifier().0), - ); - assert_eq!( - try_sapling_output_recovery(&ovk, &cv, &cmu, &epk, &enc_ciphertext, &out_ciphertext), - None - ); + reencrypt_enc_ciphertext( + &ovk, + &cv, + &cmu, + &epk, + &mut enc_ciphertext, + &out_ciphertext, + |pt| pt[1..12].copy_from_slice(&find_invalid_diversifier().0), + ); + assert_eq!( + try_sapling_output_recovery( + &consensus::MainNetwork, + height, + &ovk, + &cv, + &cmu, + &epk, + &enc_ciphertext, + &out_ciphertext + ), + None + ); + } } #[test] fn recovery_with_incorrect_diversifier() { let mut rng = OsRng; + let height_v1 = SAPLING_ACTIVATION_HEIGHT; + let height_v2 = consensus::MainNetwork + .activation_height(NetworkUpgrade::Canopy) + .unwrap(); + let height_array = [height_v1, height_v2]; - let (ovk, _, cv, cmu, epk, mut enc_ciphertext, out_ciphertext) = - random_enc_ciphertext(&mut rng); + for height_ref in height_array.iter() { + let height = *height_ref; - reencrypt_enc_ciphertext( - &ovk, - &cv, - &cmu, - &epk, - &mut enc_ciphertext, - &out_ciphertext, - |pt| pt[1..12].copy_from_slice(&find_valid_diversifier().0), - ); - assert_eq!( - try_sapling_output_recovery(&ovk, &cv, &cmu, &epk, &enc_ciphertext, &out_ciphertext), - None - ); + let (ovk, _, cv, cmu, epk, mut enc_ciphertext, out_ciphertext) = + random_enc_ciphertext(height, &mut rng); + + reencrypt_enc_ciphertext( + &ovk, + &cv, + &cmu, + &epk, + &mut enc_ciphertext, + &out_ciphertext, + |pt| pt[1..12].copy_from_slice(&find_valid_diversifier().0), + ); + assert_eq!( + try_sapling_output_recovery( + &consensus::MainNetwork, + height, + &ovk, + &cv, + &cmu, + &epk, + &enc_ciphertext, + &out_ciphertext + ), + None + ); + } } #[test] fn recovery_with_invalid_pk_d() { let mut rng = OsRng; + let height_v1 = SAPLING_ACTIVATION_HEIGHT; + let height_v2 = consensus::MainNetwork + .activation_height(NetworkUpgrade::Canopy) + .unwrap(); + let height_array = [height_v1, height_v2]; - let ivk = Fs::zero(); - let (ovk, _, cv, cmu, epk, enc_ciphertext, out_ciphertext) = - random_enc_ciphertext_with(ivk, &mut rng); + for height_ref in height_array.iter() { + let height = *height_ref; + let ivk = Fs::zero(); + let (ovk, _, cv, cmu, epk, enc_ciphertext, out_ciphertext) = + random_enc_ciphertext_with(height, ivk, &mut rng); - assert_eq!( - try_sapling_output_recovery(&ovk, &cv, &cmu, &epk, &enc_ciphertext, &out_ciphertext), - None - ); + assert_eq!( + try_sapling_output_recovery( + &consensus::MainNetwork, + height, + &ovk, + &cv, + &cmu, + &epk, + &enc_ciphertext, + &out_ciphertext + ), + None + ); + } } #[test] @@ -1345,6 +1685,10 @@ mod tests { }; } + let height = consensus::MainNetwork + .activation_height(NetworkUpgrade::Sapling) + .expect("Should have Sapling activation height"); + for tv in test_vectors { // // Load the test vector components @@ -1391,7 +1735,14 @@ mod tests { // (Tested first because it only requires immutable references.) // - match try_sapling_note_decryption(&ivk, &epk, &cmu, &tv.c_enc) { + match try_sapling_note_decryption( + &consensus::MainNetwork, + height, + &ivk, + &epk, + &cmu, + &tv.c_enc, + ) { Some((decrypted_note, decrypted_to, decrypted_memo)) => { assert_eq!(decrypted_note, note); assert_eq!(decrypted_to, to); @@ -1401,6 +1752,8 @@ mod tests { } match try_sapling_compact_note_decryption( + &consensus::MainNetwork, + height, &ivk, &epk, &cmu, @@ -1413,7 +1766,16 @@ mod tests { None => panic!("Compact note decryption failed"), } - match try_sapling_output_recovery(&ovk, &cv, &cmu, &epk, &tv.c_enc, &tv.c_out) { + match try_sapling_output_recovery( + &consensus::MainNetwork, + height, + &ovk, + &cv, + &cmu, + &epk, + &tv.c_enc, + &tv.c_out, + ) { Some((decrypted_note, decrypted_to, decrypted_memo)) => { assert_eq!(decrypted_note, note); assert_eq!(decrypted_to, to); @@ -1426,7 +1788,9 @@ mod tests { // Test encryption // - let mut ne = SaplingNoteEncryption::new(ovk, note, to, Memo(tv.memo), &mut OsRng); + let _esk = note.generate_or_derive_esk(&mut OsRng); + + let mut ne = SaplingNoteEncryption::new(ovk, note, to, Memo(tv.memo), _esk); // Swap in the ephemeral keypair from the test vectors ne.esk = esk; ne.epk = epk; diff --git a/zcash_primitives/src/transaction/builder.rs b/zcash_primitives/src/transaction/builder.rs index 81198c914..dbcdea046 100644 --- a/zcash_primitives/src/transaction/builder.rs +++ b/zcash_primitives/src/transaction/builder.rs @@ -726,6 +726,7 @@ mod tests { use super::{Builder, Error}; use crate::{ consensus, + consensus::SAPLING_ACTIVATION_HEIGHT, legacy::TransparentAddress, merkle_tree::{CommitmentTree, IncrementalWitness}, primitives::Rseed, @@ -760,6 +761,7 @@ mod tests { // Create a builder with 0 fee, so we can construct t outputs let mut builder = builder::Builder { rng: OsRng, + height: SAPLING_ACTIVATION_HEIGHT, mtx: TransactionData::new(), fee: Amount::zero(), anchor: None, diff --git a/zcash_proofs/src/circuit/sapling.rs b/zcash_proofs/src/circuit/sapling.rs index 7aecb825c..c486a8e5f 100644 --- a/zcash_proofs/src/circuit/sapling.rs +++ b/zcash_proofs/src/circuit/sapling.rs @@ -544,7 +544,7 @@ fn test_input_circuit_with_bls12_381() { use zcash_primitives::{ jubjub::{edwards, fs, JubjubBls12}, pedersen_hash, - primitives::{Diversifier, Note, ProofGenerationKey}, + primitives::{Diversifier, Note, ProofGenerationKey, Rseed}, }; let params = &JubjubBls12::new(); @@ -598,7 +598,7 @@ fn test_input_circuit_with_bls12_381() { value: value_commitment.value, g_d: g_d.clone(), pk_d: payment_address.pk_d().clone(), - r: commitment_randomness.clone(), + rseed: Rseed::BeforeZip212(commitment_randomness.clone()), }; let mut position = 0u64; @@ -694,7 +694,7 @@ fn test_input_circuit_with_bls12_381_external_test_vectors() { use zcash_primitives::{ jubjub::{edwards, fs, JubjubBls12}, pedersen_hash, - primitives::{Diversifier, Note, ProofGenerationKey}, + primitives::{Diversifier, Note, ProofGenerationKey, Rseed}, }; let params = &JubjubBls12::new(); @@ -782,7 +782,7 @@ fn test_input_circuit_with_bls12_381_external_test_vectors() { value: value_commitment.value, g_d: g_d.clone(), pk_d: payment_address.pk_d().clone(), - r: commitment_randomness.clone(), + rseed: Rseed::BeforeZip212(commitment_randomness.clone()), }; let mut position = 0u64; @@ -877,7 +877,7 @@ fn test_output_circuit_with_bls12_381() { use rand_xorshift::XorShiftRng; use zcash_primitives::{ jubjub::{edwards, fs, JubjubBls12}, - primitives::{Diversifier, ProofGenerationKey}, + primitives::{Diversifier, ProofGenerationKey, Rseed}, }; let params = &JubjubBls12::new(); @@ -941,7 +941,11 @@ fn test_output_circuit_with_bls12_381() { ); let expected_cm = payment_address - .create_note(value_commitment.value, commitment_randomness, params) + .create_note( + value_commitment.value, + Rseed::BeforeZip212(commitment_randomness), + params, + ) .expect("should be valid") .cm(params); From b1ddd556af7e06fc0b0b5e844b0a8ed6ea884e41 Mon Sep 17 00:00:00 2001 From: therealyingtong Date: Fri, 31 Jul 2020 22:07:33 +0800 Subject: [PATCH 06/31] Check derived esk against claimed epk when decrypting note --- zcash_primitives/src/note_encryption.rs | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/zcash_primitives/src/note_encryption.rs b/zcash_primitives/src/note_encryption.rs index 286ee2842..a13e8ad8f 100644 --- a/zcash_primitives/src/note_encryption.rs +++ b/zcash_primitives/src/note_encryption.rs @@ -6,7 +6,7 @@ use crate::{ jubjub::{ edwards, fs::{Fs, FsRepr}, - PrimeOrder, Unknown, + PrimeOrder, ToUniform, Unknown, }, primitives::{Diversifier, Note, PaymentAddress, Rseed}, }; @@ -19,7 +19,10 @@ use std::convert::TryInto; use std::fmt; use std::str; -use crate::{keys::OutgoingViewingKey, JUBJUB}; +use crate::{ + keys::{prf_expand, OutgoingViewingKey}, + JUBJUB, +}; pub const KDF_SAPLING_PERSONALIZATION: &[u8; 16] = b"Zcash_SaplingKDF"; pub const PRF_OCK_PERSONALIZATION: &[u8; 16] = b"Zcash_Derive_ock"; @@ -209,7 +212,7 @@ fn prf_ock( /// use rand_core::OsRng; /// use zcash_primitives::{ /// jubjub::fs::Fs, -/// keys::OutgoingViewingKey, +/// keys::{OutgoingViewingKey, prf_expand}, /// note_encryption::{Memo, SaplingNoteEncryption}, /// primitives::{Diversifier, PaymentAddress, Rseed, ValueCommitment}, /// JUBJUB, @@ -443,6 +446,14 @@ pub fn try_sapling_note_decryption( let (note, to) = parse_note_plaintext_without_memo(parameters, height, ivk, cmu, &plaintext)?; + match note.rseed { + Rseed::AfterZip212(rseed) => { + let derived_esk = Fs::to_uniform(prf_expand(&rseed, &[0x05]).as_bytes()); + assert_eq!(note.g_d.mul(derived_esk, &JUBJUB), *epk); + } + _ => (), + } + let mut memo = [0u8; 512]; memo.copy_from_slice(&plaintext[COMPACT_NOTE_SIZE..NOTE_PLAINTEXT_SIZE]); From eba542c95feb990aa03543564dae15faf4050546 Mon Sep 17 00:00:00 2001 From: therealyingtong Date: Mon, 3 Aug 2020 13:39:36 +0800 Subject: [PATCH 07/31] Add activation heights as consts in consensus::Parameters --- zcash_primitives/src/consensus.rs | 28 ++- zcash_primitives/src/note_encryption.rs | 213 +++++++++----------- zcash_primitives/src/transaction/builder.rs | 8 +- 3 files changed, 120 insertions(+), 129 deletions(-) diff --git a/zcash_primitives/src/consensus.rs b/zcash_primitives/src/consensus.rs index 45dcca16a..891d50880 100644 --- a/zcash_primitives/src/consensus.rs +++ b/zcash_primitives/src/consensus.rs @@ -3,12 +3,6 @@ use std::convert::TryFrom; use std::fmt; -#[cfg(feature = "mainnet")] -pub const SAPLING_ACTIVATION_HEIGHT: u32 = 419_200; - -#[cfg(not(feature = "mainnet"))] -pub const SAPLING_ACTIVATION_HEIGHT: u32 = 280_000; - /// Zcash consensus parameters. pub trait Parameters { fn activation_height(&self, nu: NetworkUpgrade) -> Option; @@ -20,9 +14,11 @@ pub trait Parameters { } } - fn zip_212_grace_period(&self) -> u32 { - 32256 - } + const OVERWINTER_ACTIVATION_HEIGHT: u32; + const SAPLING_ACTIVATION_HEIGHT: u32; + const BLOSSOM_ACTIVATION_HEIGHT: u32; + const HEARTWOOD_ACTIVATION_HEIGHT: u32; + const CANOPY_ACTIVATION_HEIGHT: u32; } /// Marker struct for the production network. @@ -39,6 +35,12 @@ impl Parameters for MainNetwork { NetworkUpgrade::Canopy => Some(1_046_400), } } + + const OVERWINTER_ACTIVATION_HEIGHT: u32 = 347_500; + const SAPLING_ACTIVATION_HEIGHT: u32 = 419_200; + const BLOSSOM_ACTIVATION_HEIGHT: u32 = 653_600; + const HEARTWOOD_ACTIVATION_HEIGHT: u32 = 903_000; + const CANOPY_ACTIVATION_HEIGHT: u32 = 1_046_400; } /// Marker struct for the test network. @@ -55,6 +57,12 @@ impl Parameters for TestNetwork { NetworkUpgrade::Canopy => Some(1_028_500), } } + + const OVERWINTER_ACTIVATION_HEIGHT: u32 = 207_500; + const SAPLING_ACTIVATION_HEIGHT: u32 = 280_200; + const BLOSSOM_ACTIVATION_HEIGHT: u32 = 584_000; + const HEARTWOOD_ACTIVATION_HEIGHT: u32 = 903_800; + const CANOPY_ACTIVATION_HEIGHT: u32 = 1_028_500; } /// An event that occurs at a specified height on the Zcash chain, at which point the @@ -121,6 +129,8 @@ const UPGRADES_IN_ORDER: &[NetworkUpgrade] = &[ NetworkUpgrade::Canopy, ]; +pub const ZIP212_GRACE_PERIOD: u32 = 32256; + /// A globally-unique identifier for a set of consensus rules within the Zcash chain. /// /// Each branch ID in this enum corresponds to one of the epochs between a pair of Zcash diff --git a/zcash_primitives/src/note_encryption.rs b/zcash_primitives/src/note_encryption.rs index a13e8ad8f..d911225c6 100644 --- a/zcash_primitives/src/note_encryption.rs +++ b/zcash_primitives/src/note_encryption.rs @@ -2,7 +2,7 @@ use crate::{ consensus, - consensus::NetworkUpgrade, + consensus::{NetworkUpgrade, ZIP212_GRACE_PERIOD}, jubjub::{ edwards, fs::{Fs, FsRepr}, @@ -393,7 +393,7 @@ pub fn plaintext_version_is_valid( let grace_period_end_height = parameters .activation_height(NetworkUpgrade::Canopy) .expect("Should have Canopy activation height") - + parameters.zip_212_grace_period(); + + ZIP212_GRACE_PERIOD; if height < grace_period_end_height && leadbyte != 0x01 && leadbyte != 0x02 { // non-{0x01,0x02} received after Canopy activation and before grace period has elapsed @@ -596,7 +596,7 @@ pub fn try_sapling_output_recovery( mod tests { use crate::{ consensus, - consensus::{NetworkUpgrade, Parameters, SAPLING_ACTIVATION_HEIGHT}, + consensus::{NetworkUpgrade, Parameters, ZIP212_GRACE_PERIOD}, jubjub::{ edwards, fs::{Fs, FsRepr}, @@ -929,11 +929,10 @@ mod tests { #[test] fn decryption_with_invalid_ivk() { let mut rng = OsRng; - let height_v1 = SAPLING_ACTIVATION_HEIGHT; - let height_v2 = consensus::MainNetwork - .activation_height(NetworkUpgrade::Canopy) - .unwrap(); - let height_array = [height_v1, height_v2]; + let height_array = [ + consensus::MainNetwork::SAPLING_ACTIVATION_HEIGHT, + consensus::MainNetwork::CANOPY_ACTIVATION_HEIGHT, + ]; for height_ref in height_array.iter() { let height = *height_ref; @@ -956,11 +955,10 @@ mod tests { #[test] fn decryption_with_invalid_epk() { let mut rng = OsRng; - let height_v1 = SAPLING_ACTIVATION_HEIGHT; - let height_v2 = consensus::MainNetwork - .activation_height(NetworkUpgrade::Canopy) - .unwrap(); - let height_array = [height_v1, height_v2]; + let height_array = [ + consensus::MainNetwork::SAPLING_ACTIVATION_HEIGHT, + consensus::MainNetwork::CANOPY_ACTIVATION_HEIGHT, + ]; for height_ref in height_array.iter() { let height = *height_ref; @@ -983,11 +981,10 @@ mod tests { #[test] fn decryption_with_invalid_cmu() { let mut rng = OsRng; - let height_v1 = SAPLING_ACTIVATION_HEIGHT; - let height_v2 = consensus::MainNetwork - .activation_height(NetworkUpgrade::Canopy) - .unwrap(); - let height_array = [height_v1, height_v2]; + let height_array = [ + consensus::MainNetwork::SAPLING_ACTIVATION_HEIGHT, + consensus::MainNetwork::CANOPY_ACTIVATION_HEIGHT, + ]; for height_ref in height_array.iter() { let height = *height_ref; @@ -1010,11 +1007,10 @@ mod tests { #[test] fn decryption_with_invalid_tag() { let mut rng = OsRng; - let height_v1 = SAPLING_ACTIVATION_HEIGHT; - let height_v2 = consensus::MainNetwork - .activation_height(NetworkUpgrade::Canopy) - .unwrap(); - let height_array = [height_v1, height_v2]; + let height_array = [ + consensus::MainNetwork::SAPLING_ACTIVATION_HEIGHT, + consensus::MainNetwork::CANOPY_ACTIVATION_HEIGHT, + ]; for height_ref in height_array.iter() { let height = *height_ref; @@ -1039,11 +1035,10 @@ mod tests { #[test] fn decryption_with_invalid_version_byte() { let mut rng = OsRng; - let height_v1 = SAPLING_ACTIVATION_HEIGHT; - let height_v2 = consensus::MainNetwork - .activation_height(NetworkUpgrade::Canopy) - .unwrap(); - let height_array = [height_v1, height_v2]; + let height_array = [ + consensus::MainNetwork::SAPLING_ACTIVATION_HEIGHT, + consensus::MainNetwork::CANOPY_ACTIVATION_HEIGHT, + ]; let leadbyte_array = [0x02, 0x03]; for (i, height_ref) in height_array.iter().enumerate() { @@ -1077,11 +1072,10 @@ mod tests { #[test] fn decryption_with_invalid_diversifier() { let mut rng = OsRng; - let height_v1 = SAPLING_ACTIVATION_HEIGHT; - let height_v2 = consensus::MainNetwork - .activation_height(NetworkUpgrade::Canopy) - .unwrap(); - let height_array = [height_v1, height_v2]; + let height_array = [ + consensus::MainNetwork::SAPLING_ACTIVATION_HEIGHT, + consensus::MainNetwork::CANOPY_ACTIVATION_HEIGHT, + ]; for height_ref in height_array.iter() { let height = *height_ref; @@ -1114,11 +1108,10 @@ mod tests { #[test] fn decryption_with_incorrect_diversifier() { let mut rng = OsRng; - let height_v1 = SAPLING_ACTIVATION_HEIGHT; - let height_v2 = consensus::MainNetwork - .activation_height(NetworkUpgrade::Canopy) - .unwrap(); - let height_array = [height_v1, height_v2]; + let height_array = [ + consensus::MainNetwork::SAPLING_ACTIVATION_HEIGHT, + consensus::MainNetwork::CANOPY_ACTIVATION_HEIGHT, + ]; for height_ref in height_array.iter() { let height = *height_ref; @@ -1151,11 +1144,10 @@ mod tests { #[test] fn compact_decryption_with_invalid_ivk() { let mut rng = OsRng; - let height_v1 = SAPLING_ACTIVATION_HEIGHT; - let height_v2 = consensus::MainNetwork - .activation_height(NetworkUpgrade::Canopy) - .unwrap(); - let height_array = [height_v1, height_v2]; + let height_array = [ + consensus::MainNetwork::SAPLING_ACTIVATION_HEIGHT, + consensus::MainNetwork::CANOPY_ACTIVATION_HEIGHT, + ]; for height_ref in height_array.iter() { let height = *height_ref; @@ -1178,11 +1170,10 @@ mod tests { #[test] fn compact_decryption_with_invalid_epk() { let mut rng = OsRng; - let height_v1 = SAPLING_ACTIVATION_HEIGHT; - let height_v2 = consensus::MainNetwork - .activation_height(NetworkUpgrade::Canopy) - .unwrap(); - let height_array = [height_v1, height_v2]; + let height_array = [ + consensus::MainNetwork::SAPLING_ACTIVATION_HEIGHT, + consensus::MainNetwork::CANOPY_ACTIVATION_HEIGHT, + ]; for height_ref in height_array.iter() { let height = *height_ref; @@ -1205,11 +1196,10 @@ mod tests { #[test] fn compact_decryption_with_invalid_cmu() { let mut rng = OsRng; - let height_v1 = SAPLING_ACTIVATION_HEIGHT; - let height_v2 = consensus::MainNetwork - .activation_height(NetworkUpgrade::Canopy) - .unwrap(); - let height_array = [height_v1, height_v2]; + let height_array = [ + consensus::MainNetwork::SAPLING_ACTIVATION_HEIGHT, + consensus::MainNetwork::CANOPY_ACTIVATION_HEIGHT, + ]; for height_ref in height_array.iter() { let height = *height_ref; @@ -1232,11 +1222,10 @@ mod tests { #[test] fn compact_decryption_with_invalid_version_byte() { let mut rng = OsRng; - let height_v1 = SAPLING_ACTIVATION_HEIGHT; - let height_v2 = consensus::MainNetwork - .activation_height(NetworkUpgrade::Canopy) - .unwrap(); - let height_array = [height_v1, height_v2]; + let height_array = [ + consensus::MainNetwork::SAPLING_ACTIVATION_HEIGHT, + consensus::MainNetwork::CANOPY_ACTIVATION_HEIGHT, + ]; let leadbyte_array = [0x02, 0x03]; for (i, height_ref) in height_array.iter().enumerate() { @@ -1270,11 +1259,10 @@ mod tests { #[test] fn compact_decryption_with_invalid_diversifier() { let mut rng = OsRng; - let height_v1 = SAPLING_ACTIVATION_HEIGHT; - let height_v2 = consensus::MainNetwork - .activation_height(NetworkUpgrade::Canopy) - .unwrap(); - let height_array = [height_v1, height_v2]; + let height_array = [ + consensus::MainNetwork::SAPLING_ACTIVATION_HEIGHT, + consensus::MainNetwork::CANOPY_ACTIVATION_HEIGHT, + ]; for height_ref in height_array.iter() { let height = *height_ref; @@ -1307,11 +1295,10 @@ mod tests { #[test] fn compact_decryption_with_incorrect_diversifier() { let mut rng = OsRng; - let height_v1 = SAPLING_ACTIVATION_HEIGHT; - let height_v2 = consensus::MainNetwork - .activation_height(NetworkUpgrade::Canopy) - .unwrap(); - let height_array = [height_v1, height_v2]; + let height_array = [ + consensus::MainNetwork::SAPLING_ACTIVATION_HEIGHT, + consensus::MainNetwork::CANOPY_ACTIVATION_HEIGHT, + ]; for height_ref in height_array.iter() { let height = *height_ref; @@ -1344,11 +1331,10 @@ mod tests { #[test] fn recovery_with_invalid_ovk() { let mut rng = OsRng; - let height_v1 = SAPLING_ACTIVATION_HEIGHT; - let height_v2 = consensus::MainNetwork - .activation_height(NetworkUpgrade::Canopy) - .unwrap(); - let height_array = [height_v1, height_v2]; + let height_array = [ + consensus::MainNetwork::SAPLING_ACTIVATION_HEIGHT, + consensus::MainNetwork::CANOPY_ACTIVATION_HEIGHT, + ]; for height_ref in height_array.iter() { let height = *height_ref; @@ -1375,11 +1361,10 @@ mod tests { #[test] fn recovery_with_invalid_cv() { let mut rng = OsRng; - let height_v1 = SAPLING_ACTIVATION_HEIGHT; - let height_v2 = consensus::MainNetwork - .activation_height(NetworkUpgrade::Canopy) - .unwrap(); - let height_array = [height_v1, height_v2]; + let height_array = [ + consensus::MainNetwork::SAPLING_ACTIVATION_HEIGHT, + consensus::MainNetwork::CANOPY_ACTIVATION_HEIGHT, + ]; for height_ref in height_array.iter() { let height = *height_ref; @@ -1405,11 +1390,10 @@ mod tests { #[test] fn recovery_with_invalid_cmu() { let mut rng = OsRng; - let height_v1 = SAPLING_ACTIVATION_HEIGHT; - let height_v2 = consensus::MainNetwork - .activation_height(NetworkUpgrade::Canopy) - .unwrap(); - let height_array = [height_v1, height_v2]; + let height_array = [ + consensus::MainNetwork::SAPLING_ACTIVATION_HEIGHT, + consensus::MainNetwork::CANOPY_ACTIVATION_HEIGHT, + ]; for height_ref in height_array.iter() { let height = *height_ref; @@ -1435,11 +1419,10 @@ mod tests { #[test] fn recovery_with_invalid_epk() { let mut rng = OsRng; - let height_v1 = SAPLING_ACTIVATION_HEIGHT; - let height_v2 = consensus::MainNetwork - .activation_height(NetworkUpgrade::Canopy) - .unwrap(); - let height_array = [height_v1, height_v2]; + let height_array = [ + consensus::MainNetwork::SAPLING_ACTIVATION_HEIGHT, + consensus::MainNetwork::CANOPY_ACTIVATION_HEIGHT, + ]; for height_ref in height_array.iter() { let height = *height_ref; @@ -1465,11 +1448,10 @@ mod tests { #[test] fn recovery_with_invalid_enc_tag() { let mut rng = OsRng; - let height_v1 = SAPLING_ACTIVATION_HEIGHT; - let height_v2 = consensus::MainNetwork - .activation_height(NetworkUpgrade::Canopy) - .unwrap(); - let height_array = [height_v1, height_v2]; + let height_array = [ + consensus::MainNetwork::SAPLING_ACTIVATION_HEIGHT, + consensus::MainNetwork::CANOPY_ACTIVATION_HEIGHT, + ]; for height_ref in height_array.iter() { let height = *height_ref; @@ -1496,11 +1478,10 @@ mod tests { #[test] fn recovery_with_invalid_out_tag() { let mut rng = OsRng; - let height_v1 = SAPLING_ACTIVATION_HEIGHT; - let height_v2 = consensus::MainNetwork - .activation_height(NetworkUpgrade::Canopy) - .unwrap(); - let height_array = [height_v1, height_v2]; + let height_array = [ + consensus::MainNetwork::SAPLING_ACTIVATION_HEIGHT, + consensus::MainNetwork::CANOPY_ACTIVATION_HEIGHT, + ]; for height_ref in height_array.iter() { let height = *height_ref; @@ -1527,11 +1508,10 @@ mod tests { #[test] fn recovery_with_invalid_version_byte() { let mut rng = OsRng; - let height_v1 = SAPLING_ACTIVATION_HEIGHT; - let height_v2 = consensus::MainNetwork - .activation_height(NetworkUpgrade::Canopy) - .unwrap(); - let height_array = [height_v1, height_v2]; + let height_array = [ + consensus::MainNetwork::SAPLING_ACTIVATION_HEIGHT, + consensus::MainNetwork::CANOPY_ACTIVATION_HEIGHT, + ]; let leadbyte_array = [0x02, 0x03]; for (i, height_ref) in height_array.iter().enumerate() { @@ -1567,11 +1547,10 @@ mod tests { #[test] fn recovery_with_invalid_diversifier() { let mut rng = OsRng; - let height_v1 = SAPLING_ACTIVATION_HEIGHT; - let height_v2 = consensus::MainNetwork - .activation_height(NetworkUpgrade::Canopy) - .unwrap(); - let height_array = [height_v1, height_v2]; + let height_array = [ + consensus::MainNetwork::SAPLING_ACTIVATION_HEIGHT, + consensus::MainNetwork::CANOPY_ACTIVATION_HEIGHT, + ]; for height_ref in height_array.iter() { let height = *height_ref; @@ -1606,11 +1585,10 @@ mod tests { #[test] fn recovery_with_incorrect_diversifier() { let mut rng = OsRng; - let height_v1 = SAPLING_ACTIVATION_HEIGHT; - let height_v2 = consensus::MainNetwork - .activation_height(NetworkUpgrade::Canopy) - .unwrap(); - let height_array = [height_v1, height_v2]; + let height_array = [ + consensus::MainNetwork::SAPLING_ACTIVATION_HEIGHT, + consensus::MainNetwork::CANOPY_ACTIVATION_HEIGHT, + ]; for height_ref in height_array.iter() { let height = *height_ref; @@ -1646,11 +1624,10 @@ mod tests { #[test] fn recovery_with_invalid_pk_d() { let mut rng = OsRng; - let height_v1 = SAPLING_ACTIVATION_HEIGHT; - let height_v2 = consensus::MainNetwork - .activation_height(NetworkUpgrade::Canopy) - .unwrap(); - let height_array = [height_v1, height_v2]; + let height_array = [ + consensus::MainNetwork::SAPLING_ACTIVATION_HEIGHT, + consensus::MainNetwork::CANOPY_ACTIVATION_HEIGHT, + ]; for height_ref in height_array.iter() { let height = *height_ref; diff --git a/zcash_primitives/src/transaction/builder.rs b/zcash_primitives/src/transaction/builder.rs index dbcdea046..d4fb54e1f 100644 --- a/zcash_primitives/src/transaction/builder.rs +++ b/zcash_primitives/src/transaction/builder.rs @@ -726,7 +726,6 @@ mod tests { use super::{Builder, Error}; use crate::{ consensus, - consensus::SAPLING_ACTIVATION_HEIGHT, legacy::TransparentAddress, merkle_tree::{CommitmentTree, IncrementalWitness}, primitives::Rseed, @@ -753,15 +752,20 @@ mod tests { #[test] fn binding_sig_absent_if_no_shielded_spend_or_output() { + use crate::consensus::{NetworkUpgrade, Parameters}; use crate::transaction::{ builder::{self, TransparentInputs}, TransactionData, }; + let sapling_activation_height = consensus::MainNetwork + .activation_height(NetworkUpgrade::Sapling) + .unwrap(); + // Create a builder with 0 fee, so we can construct t outputs let mut builder = builder::Builder { rng: OsRng, - height: SAPLING_ACTIVATION_HEIGHT, + height: sapling_activation_height, mtx: TransactionData::new(), fee: Amount::zero(), anchor: None, From b34e8b903cdc48c56137acaab3823918f76ed29b Mon Sep 17 00:00:00 2001 From: therealyingtong Date: Mon, 3 Aug 2020 13:51:45 +0800 Subject: [PATCH 08/31] Add invalid version byte tests for ZIP212 --- zcash_primitives/src/note_encryption.rs | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/zcash_primitives/src/note_encryption.rs b/zcash_primitives/src/note_encryption.rs index d911225c6..cb7cd9044 100644 --- a/zcash_primitives/src/note_encryption.rs +++ b/zcash_primitives/src/note_encryption.rs @@ -1036,10 +1036,11 @@ mod tests { fn decryption_with_invalid_version_byte() { let mut rng = OsRng; let height_array = [ - consensus::MainNetwork::SAPLING_ACTIVATION_HEIGHT, + consensus::MainNetwork::CANOPY_ACTIVATION_HEIGHT - 1, consensus::MainNetwork::CANOPY_ACTIVATION_HEIGHT, + consensus::MainNetwork::CANOPY_ACTIVATION_HEIGHT + ZIP212_GRACE_PERIOD, ]; - let leadbyte_array = [0x02, 0x03]; + let leadbyte_array = [0x02, 0x03, 0x01]; for (i, height_ref) in height_array.iter().enumerate() { let height = *height_ref; @@ -1223,10 +1224,11 @@ mod tests { fn compact_decryption_with_invalid_version_byte() { let mut rng = OsRng; let height_array = [ - consensus::MainNetwork::SAPLING_ACTIVATION_HEIGHT, + consensus::MainNetwork::CANOPY_ACTIVATION_HEIGHT - 1, consensus::MainNetwork::CANOPY_ACTIVATION_HEIGHT, + consensus::MainNetwork::CANOPY_ACTIVATION_HEIGHT + ZIP212_GRACE_PERIOD, ]; - let leadbyte_array = [0x02, 0x03]; + let leadbyte_array = [0x02, 0x03, 0x01]; for (i, height_ref) in height_array.iter().enumerate() { let height = *height_ref; @@ -1509,10 +1511,11 @@ mod tests { fn recovery_with_invalid_version_byte() { let mut rng = OsRng; let height_array = [ - consensus::MainNetwork::SAPLING_ACTIVATION_HEIGHT, + consensus::MainNetwork::CANOPY_ACTIVATION_HEIGHT - 1, consensus::MainNetwork::CANOPY_ACTIVATION_HEIGHT, + consensus::MainNetwork::CANOPY_ACTIVATION_HEIGHT + ZIP212_GRACE_PERIOD, ]; - let leadbyte_array = [0x02, 0x03]; + let leadbyte_array = [0x02, 0x03, 0x01]; for (i, height_ref) in height_array.iter().enumerate() { let height = *height_ref; From 0a47a9dbea1e598a368cbd124f67fdce0f52b3ec Mon Sep 17 00:00:00 2001 From: therealyingtong Date: Tue, 4 Aug 2020 11:23:03 +0800 Subject: [PATCH 09/31] Pass rseed to Prover --- zcash_primitives/src/primitives.rs | 2 +- zcash_primitives/src/prover.rs | 8 ++++---- zcash_primitives/src/transaction/builder.rs | 2 +- zcash_proofs/src/prover.rs | 6 +++--- zcash_proofs/src/sapling/prover.rs | 6 +++--- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/zcash_primitives/src/primitives.rs b/zcash_primitives/src/primitives.rs index 79d014649..4f635a867 100644 --- a/zcash_primitives/src/primitives.rs +++ b/zcash_primitives/src/primitives.rs @@ -223,7 +223,7 @@ impl PaymentAddress { } } -#[derive(Clone, Debug)] +#[derive(Copy, Clone, Debug)] pub enum Rseed { BeforeZip212(Fs), AfterZip212([u8; 32]), diff --git a/zcash_primitives/src/prover.rs b/zcash_primitives/src/prover.rs index 932573d99..2c40f8d56 100644 --- a/zcash_primitives/src/prover.rs +++ b/zcash_primitives/src/prover.rs @@ -2,7 +2,7 @@ use crate::{ jubjub::{edwards, fs::Fs, Unknown}, - primitives::{Diversifier, PaymentAddress, ProofGenerationKey}, + primitives::{Diversifier, PaymentAddress, ProofGenerationKey, Rseed}, }; use pairing::bls12_381::{Bls12, Fr}; @@ -31,7 +31,7 @@ pub trait TxProver { ctx: &mut Self::SaplingProvingContext, proof_generation_key: ProofGenerationKey, diversifier: Diversifier, - rcm: Fs, + rseed: Rseed, ar: Fs, value: u64, anchor: Fr, @@ -78,7 +78,7 @@ pub(crate) mod mock { use crate::{ jubjub::{edwards, fs::Fs, FixedGenerators, Unknown}, - primitives::{Diversifier, PaymentAddress, ProofGenerationKey, ValueCommitment}, + primitives::{Diversifier, PaymentAddress, ProofGenerationKey, Rseed, ValueCommitment}, }; use crate::{ @@ -104,7 +104,7 @@ pub(crate) mod mock { _ctx: &mut Self::SaplingProvingContext, proof_generation_key: ProofGenerationKey, _diversifier: Diversifier, - _rcm: Fs, + _rcm: Rseed, ar: Fs, value: u64, _anchor: Fr, diff --git a/zcash_primitives/src/transaction/builder.rs b/zcash_primitives/src/transaction/builder.rs index d4fb54e1f..89bf44900 100644 --- a/zcash_primitives/src/transaction/builder.rs +++ b/zcash_primitives/src/transaction/builder.rs @@ -574,7 +574,7 @@ impl Builder { &mut ctx, proof_generation_key, spend.diversifier, - spend.note.rcm(), + spend.note.rseed, spend.alpha, spend.note.value, anchor, diff --git a/zcash_proofs/src/prover.rs b/zcash_proofs/src/prover.rs index d1c23aac7..9077410af 100644 --- a/zcash_proofs/src/prover.rs +++ b/zcash_proofs/src/prover.rs @@ -5,7 +5,7 @@ use pairing::bls12_381::{Bls12, Fr}; use std::path::Path; use zcash_primitives::{ jubjub::{edwards, fs::Fs, Unknown}, - primitives::{Diversifier, PaymentAddress, ProofGenerationKey}, + primitives::{Diversifier, PaymentAddress, ProofGenerationKey, Rseed}, }; use zcash_primitives::{ merkle_tree::MerklePath, @@ -109,7 +109,7 @@ impl TxProver for LocalTxProver { ctx: &mut Self::SaplingProvingContext, proof_generation_key: ProofGenerationKey, diversifier: Diversifier, - rcm: Fs, + rseed: Rseed, ar: Fs, value: u64, anchor: Fr, @@ -125,7 +125,7 @@ impl TxProver for LocalTxProver { let (proof, cv, rk) = ctx.spend_proof( proof_generation_key, diversifier, - rcm, + rseed, ar, value, anchor, diff --git a/zcash_proofs/src/sapling/prover.rs b/zcash_proofs/src/sapling/prover.rs index 6d578030f..7c55e6c87 100644 --- a/zcash_proofs/src/sapling/prover.rs +++ b/zcash_proofs/src/sapling/prover.rs @@ -43,7 +43,7 @@ impl SaplingProvingContext { &mut self, proof_generation_key: ProofGenerationKey, diversifier: Diversifier, - rcm: Fs, + rseed: Rseed, ar: Fs, value: u64, anchor: Fr, @@ -102,7 +102,7 @@ impl SaplingProvingContext { .g_d::(params) .expect("was a valid diversifier before"), pk_d: payment_address.pk_d().clone(), - rseed: Rseed::BeforeZip212(rcm), + rseed, }; let nullifier = note.nf(&viewing_key, merkle_path.position, params); @@ -113,7 +113,7 @@ impl SaplingProvingContext { value_commitment: Some(value_commitment.clone()), proof_generation_key: Some(proof_generation_key), payment_address: Some(payment_address), - commitment_randomness: Some(rcm), + commitment_randomness: Some(note.rcm()), ar: Some(ar), auth_path: merkle_path .auth_path From 74b2f0a79e71e223b9f3615a536b79d6d4d346f0 Mon Sep 17 00:00:00 2001 From: therealyingtong Date: Tue, 4 Aug 2020 18:27:41 +0800 Subject: [PATCH 10/31] Pass height to decrypt_transaction() --- zcash_client_backend/src/decrypt.rs | 5 +++-- zcash_client_sqlite/src/scan.rs | 11 ++++++++++- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/zcash_client_backend/src/decrypt.rs b/zcash_client_backend/src/decrypt.rs index ef6b94a2b..9079e9c9b 100644 --- a/zcash_client_backend/src/decrypt.rs +++ b/zcash_client_backend/src/decrypt.rs @@ -32,6 +32,7 @@ pub struct DecryptedOutput { /// Scans a [`Transaction`] for any information that can be decrypted by the set of /// [`ExtendedFullViewingKey`]s. pub fn decrypt_transaction( + height: u32, parameters: &P, tx: &Transaction, extfvks: &[ExtendedFullViewingKey], @@ -53,7 +54,7 @@ pub fn decrypt_transaction( for (account, (ivk, ovk)) in vks.iter().enumerate() { let ((note, to, memo), outgoing) = match try_sapling_note_decryption( parameters, - tx.expiry_height, + height, ivk, &epk, &output.cmu, @@ -62,7 +63,7 @@ pub fn decrypt_transaction( Some(ret) => (ret, false), None => match try_sapling_output_recovery( parameters, - tx.expiry_height, + height, ovk, &output.cv, &output.cmu, diff --git a/zcash_client_sqlite/src/scan.rs b/zcash_client_sqlite/src/scan.rs index f4510c861..d665e4b12 100644 --- a/zcash_client_sqlite/src/scan.rs +++ b/zcash_client_sqlite/src/scan.rs @@ -374,7 +374,16 @@ pub fn decrypt_and_store_transaction>( .collect::, _>, _>>()?? .ok_or(Error(ErrorKind::IncorrectHRPExtFVK))?; - let outputs = decrypt_transaction(&consensus::MainNetwork, tx, &extfvks); + // Height is block height for mined transactions, and the "mempool height" (chain height + 1) for mempool transactions. + let last_height = data.query_row("SELECT MAX(height) FROM blocks", NO_PARAMS, |row| { + row.get(0).or(Ok(SAPLING_ACTIVATION_HEIGHT - 1)) + })?; + let mut stmt_select_block = data.prepare("SELECT block FROM transactions WHERE txid = ?")?; + let height = stmt_select_block.query_row(&[tx.txid().0.to_vec()], |row| { + row.get(0).or(Ok(last_height + 1)) + })?; + + let outputs = decrypt_transaction(height as u32, &consensus::MainNetwork, tx, &extfvks); if outputs.is_empty() { // Nothing to see here From a25348dfbadb9b938768a85817e70b392e9ff641 Mon Sep 17 00:00:00 2001 From: therealyingtong Date: Wed, 5 Aug 2020 12:47:29 +0800 Subject: [PATCH 11/31] Revert passing Parameters to methods --- zcash_client_backend/src/decrypt.rs | 7 +- zcash_client_backend/src/lib.rs | 6 + zcash_client_backend/src/welding_rig.rs | 42 +-- zcash_client_sqlite/src/lib.rs | 28 +- zcash_client_sqlite/src/scan.rs | 8 +- zcash_client_sqlite/src/transact.rs | 9 +- zcash_primitives/src/consensus.rs | 49 ++-- zcash_primitives/src/lib.rs | 6 + zcash_primitives/src/note_encryption.rs | 267 +++++++------------- zcash_primitives/src/transaction/builder.rs | 34 +-- 10 files changed, 179 insertions(+), 277 deletions(-) diff --git a/zcash_client_backend/src/decrypt.rs b/zcash_client_backend/src/decrypt.rs index 9079e9c9b..1baabbf3d 100644 --- a/zcash_client_backend/src/decrypt.rs +++ b/zcash_client_backend/src/decrypt.rs @@ -33,7 +33,6 @@ pub struct DecryptedOutput { /// [`ExtendedFullViewingKey`]s. pub fn decrypt_transaction( height: u32, - parameters: &P, tx: &Transaction, extfvks: &[ExtendedFullViewingKey], ) -> Vec { @@ -52,8 +51,7 @@ pub fn decrypt_transaction( }; for (account, (ivk, ovk)) in vks.iter().enumerate() { - let ((note, to, memo), outgoing) = match try_sapling_note_decryption( - parameters, + let ((note, to, memo), outgoing) = match try_sapling_note_decryption::

( height, ivk, &epk, @@ -61,8 +59,7 @@ pub fn decrypt_transaction( &output.enc_ciphertext, ) { Some(ret) => (ret, false), - None => match try_sapling_output_recovery( - parameters, + None => match try_sapling_output_recovery::

( height, ovk, &output.cv, diff --git a/zcash_client_backend/src/lib.rs b/zcash_client_backend/src/lib.rs index e3852e6ac..a4e5fb422 100644 --- a/zcash_client_backend/src/lib.rs +++ b/zcash_client_backend/src/lib.rs @@ -15,3 +15,9 @@ pub mod wallet; pub mod welding_rig; pub use decrypt::{decrypt_transaction, DecryptedOutput}; + +#[cfg(feature = "mainnet")] +pub use zcash_primitives::consensus::MainNetwork as Network; + +#[cfg(not(feature = "mainnet"))] +pub use zcash_primitives::consensus::TestNetwork as Network; diff --git a/zcash_client_backend/src/welding_rig.rs b/zcash_client_backend/src/welding_rig.rs index e16634bd5..f51ef3eac 100644 --- a/zcash_client_backend/src/welding_rig.rs +++ b/zcash_client_backend/src/welding_rig.rs @@ -24,7 +24,6 @@ use crate::wallet::{WalletShieldedOutput, WalletShieldedSpend, WalletTx}; /// The given [`CommitmentTree`] and existing [`IncrementalWitness`]es are incremented /// with this output's commitment. fn scan_output( - parameters: &P, height: u32, (index, output): (usize, CompactOutput), ivks: &[Fs], @@ -53,7 +52,7 @@ fn scan_output( for (account, ivk) in ivks.iter().enumerate() { let (note, to) = - match try_sapling_compact_note_decryption(parameters, height, ivk, &epk, &cmu, &ct) { + match try_sapling_compact_note_decryption::

(height, ivk, &epk, &cmu, &ct) { Some(ret) => ret, None => continue, }; @@ -88,7 +87,6 @@ fn scan_output( /// The given [`CommitmentTree`] and existing [`IncrementalWitness`]es are /// incremented appropriately. pub fn scan_block( - parameters: &P, block: CompactBlock, extfvks: &[ExtendedFullViewingKey], nullifiers: &[(&[u8], usize)], @@ -155,8 +153,7 @@ pub fn scan_block( .map(|output| &mut output.witness) .collect(); - if let Some(output) = scan_output( - parameters, + if let Some(output) = scan_output::

( block.height as u32, to_scan, &ivks, @@ -194,7 +191,6 @@ mod tests { use pairing::bls12_381::{Bls12, Fr}; use rand_core::{OsRng, RngCore}; use zcash_primitives::{ - consensus, consensus::{NetworkUpgrade, Parameters}, jubjub::{fs::Fs, FixedGenerators, JubjubParams, ToUniform}, merkle_tree::CommitmentTree, @@ -206,7 +202,10 @@ mod tests { }; use super::scan_block; - use crate::proto::compact_formats::{CompactBlock, CompactOutput, CompactSpend, CompactTx}; + use crate::{ + proto::compact_formats::{CompactBlock, CompactOutput, CompactSpend, CompactTx}, + Network, + }; fn random_compact_tx(rng: &mut R) -> CompactTx { let fake_nf = { @@ -258,7 +257,7 @@ mod tests { // Create a fake Note for the account let mut rng = OsRng; - let rseed = if consensus::MainNetwork.is_nu_active(NetworkUpgrade::Canopy, height as u32) { + let rseed = if Network::is_nu_active(NetworkUpgrade::Canopy, height as u32) { let mut buffer = [0u8; 32]; &rng.fill_bytes(&mut buffer); Rseed::AfterZip212(buffer) @@ -335,14 +334,7 @@ mod tests { assert_eq!(cb.vtx.len(), 2); let mut tree = CommitmentTree::new(); - let txs = scan_block( - &consensus::MainNetwork, - cb, - &[extfvk], - &[], - &mut tree, - &mut [], - ); + let txs = scan_block::(cb, &[extfvk], &[], &mut tree, &mut []); assert_eq!(txs.len(), 1); let tx = &txs[0]; @@ -374,14 +366,7 @@ mod tests { assert_eq!(cb.vtx.len(), 3); let mut tree = CommitmentTree::new(); - let txs = scan_block( - &consensus::MainNetwork, - cb, - &[extfvk], - &[], - &mut tree, - &mut [], - ); + let txs = scan_block::(cb, &[extfvk], &[], &mut tree, &mut []); assert_eq!(txs.len(), 1); let tx = &txs[0]; @@ -409,14 +394,7 @@ mod tests { assert_eq!(cb.vtx.len(), 2); let mut tree = CommitmentTree::new(); - let txs = scan_block( - &consensus::MainNetwork, - cb, - &[], - &[(&nf, account)], - &mut tree, - &mut [], - ); + let txs = scan_block::(cb, &[], &[(&nf, account)], &mut tree, &mut []); assert_eq!(txs.len(), 1); let tx = &txs[0]; diff --git a/zcash_client_sqlite/src/lib.rs b/zcash_client_sqlite/src/lib.rs index c0b4f7a8d..df41cf4dd 100644 --- a/zcash_client_sqlite/src/lib.rs +++ b/zcash_client_sqlite/src/lib.rs @@ -33,12 +33,17 @@ use zcash_primitives::zip32::ExtendedFullViewingKey; use zcash_client_backend::constants::mainnet::{ HRP_SAPLING_EXTENDED_FULL_VIEWING_KEY, HRP_SAPLING_PAYMENT_ADDRESS, }; - #[cfg(not(feature = "mainnet"))] use zcash_client_backend::constants::testnet::{ HRP_SAPLING_EXTENDED_FULL_VIEWING_KEY, HRP_SAPLING_PAYMENT_ADDRESS, }; +#[cfg(feature = "mainnet")] +pub use zcash_primitives::consensus::MainNetwork as Network; + +#[cfg(not(feature = "mainnet"))] +pub use zcash_primitives::consensus::TestNetwork as Network; + pub mod address; pub mod chain; pub mod error; @@ -89,6 +94,7 @@ fn get_target_and_anchor_heights(data: &Connection) -> Result<(u32, u32), error: #[cfg(test)] mod tests { + use crate::Network; use ff::{Field, PrimeField}; use pairing::bls12_381::Bls12; use protobuf::Message; @@ -100,7 +106,6 @@ mod tests { }; use zcash_primitives::{ block::BlockHash, - consensus, consensus::{NetworkUpgrade, Parameters}, jubjub::fs::Fs, note_encryption::{Memo, SaplingNoteEncryption}, @@ -122,7 +127,7 @@ mod tests { // Create a fake Note for the account let mut rng = OsRng; - let rseed = if consensus::MainNetwork.is_nu_active(NetworkUpgrade::Canopy, height as u32) { + let rseed = if Network::is_nu_active(NetworkUpgrade::Canopy, height as u32) { let mut buffer = [0u8; 32]; &rng.fill_bytes(&mut buffer); Rseed::AfterZip212(buffer) @@ -178,7 +183,7 @@ mod tests { value: Amount, ) -> CompactBlock { let mut rng = OsRng; - let rseed = if consensus::MainNetwork.is_nu_active(NetworkUpgrade::Canopy, height as u32) { + let rseed = if Network::is_nu_active(NetworkUpgrade::Canopy, height as u32) { let mut buffer = [0u8; 32]; &rng.fill_bytes(&mut buffer); Rseed::AfterZip212(buffer) @@ -221,14 +226,13 @@ mod tests { // Create a fake Note for the change ctx.outputs.push({ let change_addr = extfvk.default_address().unwrap().1; - let rseed = - if consensus::MainNetwork.is_nu_active(NetworkUpgrade::Canopy, height as u32) { - let mut buffer = [0u8; 32]; - &rng.fill_bytes(&mut buffer); - Rseed::AfterZip212(buffer) - } else { - Rseed::BeforeZip212(Fs::random(&mut rng)) - }; + let rseed = if Network::is_nu_active(NetworkUpgrade::Canopy, height as u32) { + let mut buffer = [0u8; 32]; + &rng.fill_bytes(&mut buffer); + Rseed::AfterZip212(buffer) + } else { + Rseed::BeforeZip212(Fs::random(&mut rng)) + }; let note = Note { g_d: change_addr.diversifier().g_d::(&JUBJUB).unwrap(), pk_d: change_addr.pk_d().clone(), diff --git a/zcash_client_sqlite/src/scan.rs b/zcash_client_sqlite/src/scan.rs index d665e4b12..417d63bef 100644 --- a/zcash_client_sqlite/src/scan.rs +++ b/zcash_client_sqlite/src/scan.rs @@ -9,7 +9,6 @@ use zcash_client_backend::{ proto::compact_formats::CompactBlock, welding_rig::scan_block, }; use zcash_primitives::{ - consensus, merkle_tree::{CommitmentTree, IncrementalWitness}, sapling::Node, transaction::Transaction, @@ -19,7 +18,7 @@ use zcash_primitives::{ use crate::{ address::RecipientAddress, error::{Error, ErrorKind}, - HRP_SAPLING_EXTENDED_FULL_VIEWING_KEY, SAPLING_ACTIVATION_HEIGHT, + Network, HRP_SAPLING_EXTENDED_FULL_VIEWING_KEY, SAPLING_ACTIVATION_HEIGHT, }; struct CompactBlockRow { @@ -188,8 +187,7 @@ pub fn scan_cached_blocks, Q: AsRef>( let txs = { 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, + scan_block::( block, &extfvks[..], &nf_refs, @@ -383,7 +381,7 @@ pub fn decrypt_and_store_transaction>( row.get(0).or(Ok(last_height + 1)) })?; - let outputs = decrypt_transaction(height as u32, &consensus::MainNetwork, tx, &extfvks); + let outputs = decrypt_transaction::(height as u32, tx, &extfvks); if outputs.is_empty() { // Nothing to see here diff --git a/zcash_client_sqlite/src/transact.rs b/zcash_client_sqlite/src/transact.rs index 8826e2449..e8c6700cf 100644 --- a/zcash_client_sqlite/src/transact.rs +++ b/zcash_client_sqlite/src/transact.rs @@ -27,7 +27,7 @@ use zcash_primitives::{ use crate::{ address::RecipientAddress, error::{Error, ErrorKind}, - get_target_and_anchor_heights, HRP_SAPLING_EXTENDED_FULL_VIEWING_KEY, + get_target_and_anchor_heights, Network, HRP_SAPLING_EXTENDED_FULL_VIEWING_KEY, }; /// Describes a policy for which outgoing viewing key should be able to decrypt @@ -292,7 +292,7 @@ pub fn create_to_address>( } match to { RecipientAddress::Shielded(to) => { - builder.add_sapling_output(ovk, to.clone(), value, memo.clone()) + builder.add_sapling_output::(ovk, to.clone(), value, memo.clone()) } RecipientAddress::Transparent(to) => builder.add_transparent_output(&to, value), }?; @@ -393,7 +393,7 @@ mod tests { query::{get_balance, get_verified_balance}, scan::scan_cached_blocks, tests::{fake_compact_block, insert_into_cache}, - SAPLING_ACTIVATION_HEIGHT, + Network, SAPLING_ACTIVATION_HEIGHT, }; fn test_prover() -> impl TxProver { @@ -815,8 +815,7 @@ mod tests { .unwrap(); let output = &tx.shielded_outputs[output_index as usize]; - try_sapling_output_recovery( - &consensus::MainNetwork, + try_sapling_output_recovery::( SAPLING_ACTIVATION_HEIGHT as u32, &extfvk.fvk.ovk, &output.cv, diff --git a/zcash_primitives/src/consensus.rs b/zcash_primitives/src/consensus.rs index 891d50880..7020bae6e 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(&self, nu: NetworkUpgrade) -> Option; + fn activation_height(nu: NetworkUpgrade) -> Option; - fn is_nu_active(&self, nu: NetworkUpgrade, height: u32) -> bool { - match self.activation_height(nu) { + fn is_nu_active(nu: NetworkUpgrade, height: u32) -> bool { + match Self::activation_height(nu) { Some(h) if h <= height => true, _ => false, } @@ -26,7 +26,7 @@ pub trait Parameters { pub struct MainNetwork; impl Parameters for MainNetwork { - fn activation_height(&self, nu: NetworkUpgrade) -> Option { + fn activation_height(nu: NetworkUpgrade) -> Option { match nu { NetworkUpgrade::Overwinter => Some(347_500), NetworkUpgrade::Sapling => Some(419_200), @@ -48,7 +48,7 @@ impl Parameters for MainNetwork { pub struct TestNetwork; impl Parameters for TestNetwork { - fn activation_height(&self, nu: NetworkUpgrade) -> Option { + fn activation_height(nu: NetworkUpgrade) -> Option { match nu { NetworkUpgrade::Overwinter => Some(207_500), NetworkUpgrade::Sapling => Some(280_000), @@ -194,9 +194,9 @@ impl BranchId { /// the given height. /// /// This is the branch ID that should be used when creating transactions. - pub fn for_height(parameters: C, height: u32) -> Self { + pub fn for_height(height: u32) -> Self { for nu in UPGRADES_IN_ORDER.iter().rev() { - if parameters.is_nu_active(*nu, height) { + if C::is_nu_active(*nu, height) { return nu.branch_id(); } } @@ -208,18 +208,18 @@ impl BranchId { #[cfg(test)] mod tests { + use super::{BranchId, MainNetwork, NetworkUpgrade, UPGRADES_IN_ORDER}; + use crate::consensus::Parameters; use std::convert::TryFrom; - use super::{BranchId, MainNetwork, NetworkUpgrade, Parameters, UPGRADES_IN_ORDER}; - #[test] fn nu_ordering() { for i in 1..UPGRADES_IN_ORDER.len() { let nu_a = UPGRADES_IN_ORDER[i - 1]; let nu_b = UPGRADES_IN_ORDER[i]; match ( - MainNetwork.activation_height(nu_a), - MainNetwork.activation_height(nu_b), + MainNetwork::activation_height(nu_a), + MainNetwork::activation_height(nu_b), ) { (Some(a), Some(b)) if a < b => (), (Some(_), None) => (), @@ -234,9 +234,15 @@ mod tests { #[test] fn nu_is_active() { - assert!(!MainNetwork.is_nu_active(NetworkUpgrade::Overwinter, 0)); - assert!(!MainNetwork.is_nu_active(NetworkUpgrade::Overwinter, 347_499)); - assert!(MainNetwork.is_nu_active(NetworkUpgrade::Overwinter, 347_500)); + assert!(!MainNetwork::is_nu_active(NetworkUpgrade::Overwinter, 0)); + assert!(!MainNetwork::is_nu_active( + NetworkUpgrade::Overwinter, + 347_499 + )); + assert!(MainNetwork::is_nu_active( + NetworkUpgrade::Overwinter, + 347_500 + )); } #[test] @@ -247,28 +253,25 @@ mod tests { #[test] fn branch_id_for_height() { + assert_eq!(BranchId::for_height::(0), BranchId::Sprout,); assert_eq!( - BranchId::for_height::(MainNetwork, 0), - BranchId::Sprout, - ); - assert_eq!( - BranchId::for_height::(MainNetwork, 419_199), + BranchId::for_height::(419_199), BranchId::Overwinter, ); assert_eq!( - BranchId::for_height::(MainNetwork, 419_200), + BranchId::for_height::(419_200), BranchId::Sapling, ); assert_eq!( - BranchId::for_height::(MainNetwork, 903_000), + BranchId::for_height::(903_000), BranchId::Heartwood, ); assert_eq!( - BranchId::for_height::(MainNetwork, 1_046_400), + BranchId::for_height::(1_046_400), BranchId::Canopy, ); assert_eq!( - BranchId::for_height::(MainNetwork, 5_000_000), + BranchId::for_height::(5_000_000), BranchId::Canopy, ); } diff --git a/zcash_primitives/src/lib.rs b/zcash_primitives/src/lib.rs index 0050bbd95..2bbc801c2 100644 --- a/zcash_primitives/src/lib.rs +++ b/zcash_primitives/src/lib.rs @@ -35,3 +35,9 @@ use crate::jubjub::JubjubBls12; lazy_static! { pub static ref JUBJUB: JubjubBls12 = JubjubBls12::new(); } + +#[cfg(feature = "mainnet")] +use crate::consensus::MainNetwork as Network; + +#[cfg(not(feature = "mainnet"))] +use crate::consensus::TestNetwork as Network; diff --git a/zcash_primitives/src/note_encryption.rs b/zcash_primitives/src/note_encryption.rs index cb7cd9044..cc52356c6 100644 --- a/zcash_primitives/src/note_encryption.rs +++ b/zcash_primitives/src/note_encryption.rs @@ -341,14 +341,13 @@ impl SaplingNoteEncryption { } fn parse_note_plaintext_without_memo( - parameters: &P, height: u32, ivk: &Fs, cmu: &Fr, plaintext: &[u8], ) -> Option<(Note, PaymentAddress)> { // Check note plaintext version - match plaintext_version_is_valid(parameters, height, plaintext[0]) { + match plaintext_version_is_valid::

(height, plaintext[0]) { true => (), false => return None, } @@ -361,7 +360,7 @@ fn parse_note_plaintext_without_memo( let mut r = [0u8; 32]; r.copy_from_slice(&plaintext[20..COMPACT_NOTE_SIZE]); - let rseed = if parameters.is_nu_active(NetworkUpgrade::Canopy, height) { + let rseed = if P::is_nu_active(NetworkUpgrade::Canopy, height) { Rseed::AfterZip212(r) } else { let rcm = Fs::from_repr(FsRepr(r.try_into().expect("slice is the correct length")))?; @@ -384,14 +383,9 @@ fn parse_note_plaintext_without_memo( Some((note, to)) } -pub fn plaintext_version_is_valid( - parameters: &P, - height: u32, - leadbyte: u8, -) -> bool { - if parameters.is_nu_active(NetworkUpgrade::Canopy, height) { - let grace_period_end_height = parameters - .activation_height(NetworkUpgrade::Canopy) +pub fn plaintext_version_is_valid(height: u32, leadbyte: u8) -> bool { + if P::is_nu_active(NetworkUpgrade::Canopy, height) { + let grace_period_end_height = P::activation_height(NetworkUpgrade::Canopy) .expect("Should have Canopy activation height") + ZIP212_GRACE_PERIOD; @@ -418,7 +412,6 @@ pub fn plaintext_version_is_valid( /// /// Implements section 4.17.2 of the Zcash Protocol Specification. pub fn try_sapling_note_decryption( - parameters: &P, height: u32, ivk: &Fs, epk: &edwards::Point, @@ -444,7 +437,7 @@ pub fn try_sapling_note_decryption( NOTE_PLAINTEXT_SIZE ); - let (note, to) = parse_note_plaintext_without_memo(parameters, height, ivk, cmu, &plaintext)?; + let (note, to) = parse_note_plaintext_without_memo::

(height, ivk, cmu, &plaintext)?; match note.rseed { Rseed::AfterZip212(rseed) => { @@ -470,7 +463,6 @@ pub fn try_sapling_note_decryption( /// /// [`ZIP 307`]: https://github.com/zcash/zips/pull/226 pub fn try_sapling_compact_note_decryption( - parameters: &P, height: u32, ivk: &Fs, epk: &edwards::Point, @@ -487,7 +479,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(parameters, height, ivk, cmu, &plaintext) + parse_note_plaintext_without_memo::

(height, ivk, cmu, &plaintext) } /// Recovery of the full note plaintext by the sender. @@ -498,7 +490,6 @@ pub fn try_sapling_compact_note_decryption( /// /// Implements section 4.17.3 of the Zcash Protocol Specification. pub fn try_sapling_output_recovery( - parameters: &P, height: u32, ovk: &OutgoingViewingKey, cv: &edwards::Point, @@ -548,7 +539,7 @@ pub fn try_sapling_output_recovery( ); // Check note plaintext version - match plaintext_version_is_valid(parameters, height, plaintext[0]) { + match plaintext_version_is_valid::

(height, plaintext[0]) { true => (), false => return None, } @@ -561,7 +552,7 @@ pub fn try_sapling_output_recovery( let mut r = [0u8; 32]; r.copy_from_slice(&plaintext[20..COMPACT_NOTE_SIZE]); - let rseed = if parameters.is_nu_active(NetworkUpgrade::Canopy, height) { + let rseed = if P::is_nu_active(NetworkUpgrade::Canopy, height) { Rseed::AfterZip212(r) } else { let rcm = Fs::from_repr(FsRepr(r.try_into().expect("slice is the correct length")))?; @@ -595,7 +586,6 @@ pub fn try_sapling_output_recovery( #[cfg(test)] mod tests { use crate::{ - consensus, consensus::{NetworkUpgrade, Parameters, ZIP212_GRACE_PERIOD}, jubjub::{ edwards, @@ -603,6 +593,7 @@ mod tests { PrimeOrder, Unknown, }, primitives::{Diversifier, PaymentAddress, Rseed, ValueCommitment}, + Network, }; use crypto_api_chachapoly::ChachaPolyIetf; use ff::{Field, PrimeField}; @@ -753,17 +744,11 @@ mod tests { let (ovk, ivk, cv, cmu, epk, enc_ciphertext, out_ciphertext) = random_enc_ciphertext_with(height, ivk, rng); - assert!(try_sapling_note_decryption( - &consensus::MainNetwork, - height, - &ivk, - &epk, - &cmu, - &enc_ciphertext - ) - .is_some()); - assert!(try_sapling_compact_note_decryption( - &consensus::MainNetwork, + assert!( + try_sapling_note_decryption::(height, &ivk, &epk, &cmu, &enc_ciphertext) + .is_some() + ); + assert!(try_sapling_compact_note_decryption::( height, &ivk, &epk, @@ -771,8 +756,7 @@ mod tests { &enc_ciphertext[..COMPACT_NOTE_SIZE] ) .is_some()); - assert!(try_sapling_output_recovery( - &consensus::MainNetwork, + assert!(try_sapling_output_recovery::( height, &ovk, &cv, @@ -811,7 +795,7 @@ mod tests { }; let cv = value_commitment.cm(&JUBJUB).into(); - let rseed = if consensus::MainNetwork.is_nu_active(NetworkUpgrade::Canopy, height) { + let rseed = if Network::is_nu_active(NetworkUpgrade::Canopy, height) { let mut buffer = [0u8; 32]; &rng.fill_bytes(&mut buffer); Rseed::AfterZip212(buffer) @@ -930,8 +914,8 @@ mod tests { fn decryption_with_invalid_ivk() { let mut rng = OsRng; let height_array = [ - consensus::MainNetwork::SAPLING_ACTIVATION_HEIGHT, - consensus::MainNetwork::CANOPY_ACTIVATION_HEIGHT, + Network::SAPLING_ACTIVATION_HEIGHT, + Network::CANOPY_ACTIVATION_HEIGHT, ]; for height_ref in height_array.iter() { @@ -939,8 +923,7 @@ mod tests { let (_, _, _, cmu, epk, enc_ciphertext, _) = random_enc_ciphertext(height, &mut rng); assert_eq!( - try_sapling_note_decryption( - &consensus::MainNetwork, + try_sapling_note_decryption::( height, &Fs::random(&mut rng), &epk, @@ -956,8 +939,8 @@ mod tests { fn decryption_with_invalid_epk() { let mut rng = OsRng; let height_array = [ - consensus::MainNetwork::SAPLING_ACTIVATION_HEIGHT, - consensus::MainNetwork::CANOPY_ACTIVATION_HEIGHT, + Network::SAPLING_ACTIVATION_HEIGHT, + Network::CANOPY_ACTIVATION_HEIGHT, ]; for height_ref in height_array.iter() { @@ -965,8 +948,7 @@ mod tests { let (_, ivk, _, cmu, _, enc_ciphertext, _) = random_enc_ciphertext(height, &mut rng); assert_eq!( - try_sapling_note_decryption( - &consensus::MainNetwork, + try_sapling_note_decryption::( height, &ivk, &edwards::Point::::rand(&mut rng, &JUBJUB).mul_by_cofactor(&JUBJUB), @@ -982,8 +964,8 @@ mod tests { fn decryption_with_invalid_cmu() { let mut rng = OsRng; let height_array = [ - consensus::MainNetwork::SAPLING_ACTIVATION_HEIGHT, - consensus::MainNetwork::CANOPY_ACTIVATION_HEIGHT, + Network::SAPLING_ACTIVATION_HEIGHT, + Network::CANOPY_ACTIVATION_HEIGHT, ]; for height_ref in height_array.iter() { @@ -991,8 +973,7 @@ mod tests { let (_, ivk, _, _, epk, enc_ciphertext, _) = random_enc_ciphertext(height, &mut rng); assert_eq!( - try_sapling_note_decryption( - &consensus::MainNetwork, + try_sapling_note_decryption::( height, &ivk, &epk, @@ -1008,8 +989,8 @@ mod tests { fn decryption_with_invalid_tag() { let mut rng = OsRng; let height_array = [ - consensus::MainNetwork::SAPLING_ACTIVATION_HEIGHT, - consensus::MainNetwork::CANOPY_ACTIVATION_HEIGHT, + Network::SAPLING_ACTIVATION_HEIGHT, + Network::CANOPY_ACTIVATION_HEIGHT, ]; for height_ref in height_array.iter() { @@ -1019,14 +1000,7 @@ mod tests { enc_ciphertext[ENC_CIPHERTEXT_SIZE - 1] ^= 0xff; assert_eq!( - try_sapling_note_decryption( - &consensus::MainNetwork, - height, - &ivk, - &epk, - &cmu, - &enc_ciphertext - ), + try_sapling_note_decryption::(height, &ivk, &epk, &cmu, &enc_ciphertext), None ); } @@ -1036,9 +1010,9 @@ mod tests { fn decryption_with_invalid_version_byte() { let mut rng = OsRng; let height_array = [ - consensus::MainNetwork::CANOPY_ACTIVATION_HEIGHT - 1, - consensus::MainNetwork::CANOPY_ACTIVATION_HEIGHT, - consensus::MainNetwork::CANOPY_ACTIVATION_HEIGHT + ZIP212_GRACE_PERIOD, + Network::CANOPY_ACTIVATION_HEIGHT - 1, + Network::CANOPY_ACTIVATION_HEIGHT, + Network::CANOPY_ACTIVATION_HEIGHT + ZIP212_GRACE_PERIOD, ]; let leadbyte_array = [0x02, 0x03, 0x01]; @@ -1057,14 +1031,7 @@ mod tests { |pt| pt[0] = leadbyte_array[i], ); assert_eq!( - try_sapling_note_decryption( - &consensus::MainNetwork, - height, - &ivk, - &epk, - &cmu, - &enc_ciphertext - ), + try_sapling_note_decryption::(height, &ivk, &epk, &cmu, &enc_ciphertext), None ); } @@ -1074,8 +1041,8 @@ mod tests { fn decryption_with_invalid_diversifier() { let mut rng = OsRng; let height_array = [ - consensus::MainNetwork::SAPLING_ACTIVATION_HEIGHT, - consensus::MainNetwork::CANOPY_ACTIVATION_HEIGHT, + Network::SAPLING_ACTIVATION_HEIGHT, + Network::CANOPY_ACTIVATION_HEIGHT, ]; for height_ref in height_array.iter() { @@ -1093,14 +1060,7 @@ mod tests { |pt| pt[1..12].copy_from_slice(&find_invalid_diversifier().0), ); assert_eq!( - try_sapling_note_decryption( - &consensus::MainNetwork, - height, - &ivk, - &epk, - &cmu, - &enc_ciphertext - ), + try_sapling_note_decryption::(height, &ivk, &epk, &cmu, &enc_ciphertext), None ); } @@ -1110,8 +1070,8 @@ mod tests { fn decryption_with_incorrect_diversifier() { let mut rng = OsRng; let height_array = [ - consensus::MainNetwork::SAPLING_ACTIVATION_HEIGHT, - consensus::MainNetwork::CANOPY_ACTIVATION_HEIGHT, + Network::SAPLING_ACTIVATION_HEIGHT, + Network::CANOPY_ACTIVATION_HEIGHT, ]; for height_ref in height_array.iter() { @@ -1129,14 +1089,7 @@ mod tests { |pt| pt[1..12].copy_from_slice(&find_valid_diversifier().0), ); assert_eq!( - try_sapling_note_decryption( - &consensus::MainNetwork, - height, - &ivk, - &epk, - &cmu, - &enc_ciphertext - ), + try_sapling_note_decryption::(height, &ivk, &epk, &cmu, &enc_ciphertext), None ); } @@ -1146,8 +1099,8 @@ mod tests { fn compact_decryption_with_invalid_ivk() { let mut rng = OsRng; let height_array = [ - consensus::MainNetwork::SAPLING_ACTIVATION_HEIGHT, - consensus::MainNetwork::CANOPY_ACTIVATION_HEIGHT, + Network::SAPLING_ACTIVATION_HEIGHT, + Network::CANOPY_ACTIVATION_HEIGHT, ]; for height_ref in height_array.iter() { @@ -1155,8 +1108,7 @@ mod tests { let (_, _, _, cmu, epk, enc_ciphertext, _) = random_enc_ciphertext(height, &mut rng); assert_eq!( - try_sapling_compact_note_decryption( - &consensus::MainNetwork, + try_sapling_compact_note_decryption::( height, &Fs::random(&mut rng), &epk, @@ -1172,8 +1124,8 @@ mod tests { fn compact_decryption_with_invalid_epk() { let mut rng = OsRng; let height_array = [ - consensus::MainNetwork::SAPLING_ACTIVATION_HEIGHT, - consensus::MainNetwork::CANOPY_ACTIVATION_HEIGHT, + Network::SAPLING_ACTIVATION_HEIGHT, + Network::CANOPY_ACTIVATION_HEIGHT, ]; for height_ref in height_array.iter() { @@ -1181,8 +1133,7 @@ mod tests { let (_, ivk, _, cmu, _, enc_ciphertext, _) = random_enc_ciphertext(height, &mut rng); assert_eq!( - try_sapling_compact_note_decryption( - &consensus::MainNetwork, + try_sapling_compact_note_decryption::( height, &ivk, &edwards::Point::::rand(&mut rng, &JUBJUB).mul_by_cofactor(&JUBJUB), @@ -1198,8 +1149,8 @@ mod tests { fn compact_decryption_with_invalid_cmu() { let mut rng = OsRng; let height_array = [ - consensus::MainNetwork::SAPLING_ACTIVATION_HEIGHT, - consensus::MainNetwork::CANOPY_ACTIVATION_HEIGHT, + Network::SAPLING_ACTIVATION_HEIGHT, + Network::CANOPY_ACTIVATION_HEIGHT, ]; for height_ref in height_array.iter() { @@ -1207,8 +1158,7 @@ mod tests { let (_, ivk, _, _, epk, enc_ciphertext, _) = random_enc_ciphertext(height, &mut rng); assert_eq!( - try_sapling_compact_note_decryption( - &consensus::MainNetwork, + try_sapling_compact_note_decryption::( height, &ivk, &epk, @@ -1224,9 +1174,9 @@ mod tests { fn compact_decryption_with_invalid_version_byte() { let mut rng = OsRng; let height_array = [ - consensus::MainNetwork::CANOPY_ACTIVATION_HEIGHT - 1, - consensus::MainNetwork::CANOPY_ACTIVATION_HEIGHT, - consensus::MainNetwork::CANOPY_ACTIVATION_HEIGHT + ZIP212_GRACE_PERIOD, + Network::CANOPY_ACTIVATION_HEIGHT - 1, + Network::CANOPY_ACTIVATION_HEIGHT, + Network::CANOPY_ACTIVATION_HEIGHT + ZIP212_GRACE_PERIOD, ]; let leadbyte_array = [0x02, 0x03, 0x01]; @@ -1245,8 +1195,7 @@ mod tests { |pt| pt[0] = leadbyte_array[i], ); assert_eq!( - try_sapling_compact_note_decryption( - &consensus::MainNetwork, + try_sapling_compact_note_decryption::( height, &ivk, &epk, @@ -1262,8 +1211,8 @@ mod tests { fn compact_decryption_with_invalid_diversifier() { let mut rng = OsRng; let height_array = [ - consensus::MainNetwork::SAPLING_ACTIVATION_HEIGHT, - consensus::MainNetwork::CANOPY_ACTIVATION_HEIGHT, + Network::SAPLING_ACTIVATION_HEIGHT, + Network::CANOPY_ACTIVATION_HEIGHT, ]; for height_ref in height_array.iter() { @@ -1281,8 +1230,7 @@ mod tests { |pt| pt[1..12].copy_from_slice(&find_invalid_diversifier().0), ); assert_eq!( - try_sapling_compact_note_decryption( - &consensus::MainNetwork, + try_sapling_compact_note_decryption::( height, &ivk, &epk, @@ -1298,8 +1246,8 @@ mod tests { fn compact_decryption_with_incorrect_diversifier() { let mut rng = OsRng; let height_array = [ - consensus::MainNetwork::SAPLING_ACTIVATION_HEIGHT, - consensus::MainNetwork::CANOPY_ACTIVATION_HEIGHT, + Network::SAPLING_ACTIVATION_HEIGHT, + Network::CANOPY_ACTIVATION_HEIGHT, ]; for height_ref in height_array.iter() { @@ -1317,8 +1265,7 @@ mod tests { |pt| pt[1..12].copy_from_slice(&find_valid_diversifier().0), ); assert_eq!( - try_sapling_compact_note_decryption( - &consensus::MainNetwork, + try_sapling_compact_note_decryption::( height, &ivk, &epk, @@ -1334,8 +1281,8 @@ mod tests { fn recovery_with_invalid_ovk() { let mut rng = OsRng; let height_array = [ - consensus::MainNetwork::SAPLING_ACTIVATION_HEIGHT, - consensus::MainNetwork::CANOPY_ACTIVATION_HEIGHT, + Network::SAPLING_ACTIVATION_HEIGHT, + Network::CANOPY_ACTIVATION_HEIGHT, ]; for height_ref in height_array.iter() { @@ -1345,8 +1292,7 @@ mod tests { ovk.0[0] ^= 0xff; assert_eq!( - try_sapling_output_recovery( - &consensus::MainNetwork, + try_sapling_output_recovery::( height, &ovk, &cv, @@ -1364,8 +1310,8 @@ mod tests { fn recovery_with_invalid_cv() { let mut rng = OsRng; let height_array = [ - consensus::MainNetwork::SAPLING_ACTIVATION_HEIGHT, - consensus::MainNetwork::CANOPY_ACTIVATION_HEIGHT, + Network::SAPLING_ACTIVATION_HEIGHT, + Network::CANOPY_ACTIVATION_HEIGHT, ]; for height_ref in height_array.iter() { @@ -1374,8 +1320,7 @@ mod tests { random_enc_ciphertext(height, &mut rng); assert_eq!( - try_sapling_output_recovery( - &consensus::MainNetwork, + try_sapling_output_recovery::( height, &ovk, &edwards::Point::::rand(&mut rng, &JUBJUB), @@ -1393,8 +1338,8 @@ mod tests { fn recovery_with_invalid_cmu() { let mut rng = OsRng; let height_array = [ - consensus::MainNetwork::SAPLING_ACTIVATION_HEIGHT, - consensus::MainNetwork::CANOPY_ACTIVATION_HEIGHT, + Network::SAPLING_ACTIVATION_HEIGHT, + Network::CANOPY_ACTIVATION_HEIGHT, ]; for height_ref in height_array.iter() { @@ -1403,8 +1348,7 @@ mod tests { random_enc_ciphertext(height, &mut rng); assert_eq!( - try_sapling_output_recovery( - &consensus::MainNetwork, + try_sapling_output_recovery::( height, &ovk, &cv, @@ -1422,8 +1366,8 @@ mod tests { fn recovery_with_invalid_epk() { let mut rng = OsRng; let height_array = [ - consensus::MainNetwork::SAPLING_ACTIVATION_HEIGHT, - consensus::MainNetwork::CANOPY_ACTIVATION_HEIGHT, + Network::SAPLING_ACTIVATION_HEIGHT, + Network::CANOPY_ACTIVATION_HEIGHT, ]; for height_ref in height_array.iter() { @@ -1432,8 +1376,7 @@ mod tests { random_enc_ciphertext(height, &mut rng); assert_eq!( - try_sapling_output_recovery( - &consensus::MainNetwork, + try_sapling_output_recovery::( height, &ovk, &cv, @@ -1451,8 +1394,8 @@ mod tests { fn recovery_with_invalid_enc_tag() { let mut rng = OsRng; let height_array = [ - consensus::MainNetwork::SAPLING_ACTIVATION_HEIGHT, - consensus::MainNetwork::CANOPY_ACTIVATION_HEIGHT, + Network::SAPLING_ACTIVATION_HEIGHT, + Network::CANOPY_ACTIVATION_HEIGHT, ]; for height_ref in height_array.iter() { @@ -1462,8 +1405,7 @@ mod tests { enc_ciphertext[ENC_CIPHERTEXT_SIZE - 1] ^= 0xff; assert_eq!( - try_sapling_output_recovery( - &consensus::MainNetwork, + try_sapling_output_recovery::( height, &ovk, &cv, @@ -1481,8 +1423,8 @@ mod tests { fn recovery_with_invalid_out_tag() { let mut rng = OsRng; let height_array = [ - consensus::MainNetwork::SAPLING_ACTIVATION_HEIGHT, - consensus::MainNetwork::CANOPY_ACTIVATION_HEIGHT, + Network::SAPLING_ACTIVATION_HEIGHT, + Network::CANOPY_ACTIVATION_HEIGHT, ]; for height_ref in height_array.iter() { @@ -1492,8 +1434,7 @@ mod tests { out_ciphertext[OUT_CIPHERTEXT_SIZE - 1] ^= 0xff; assert_eq!( - try_sapling_output_recovery( - &consensus::MainNetwork, + try_sapling_output_recovery::( height, &ovk, &cv, @@ -1511,9 +1452,9 @@ mod tests { fn recovery_with_invalid_version_byte() { let mut rng = OsRng; let height_array = [ - consensus::MainNetwork::CANOPY_ACTIVATION_HEIGHT - 1, - consensus::MainNetwork::CANOPY_ACTIVATION_HEIGHT, - consensus::MainNetwork::CANOPY_ACTIVATION_HEIGHT + ZIP212_GRACE_PERIOD, + Network::CANOPY_ACTIVATION_HEIGHT - 1, + Network::CANOPY_ACTIVATION_HEIGHT, + Network::CANOPY_ACTIVATION_HEIGHT + ZIP212_GRACE_PERIOD, ]; let leadbyte_array = [0x02, 0x03, 0x01]; @@ -1532,8 +1473,7 @@ mod tests { |pt| pt[0] = leadbyte_array[i], ); assert_eq!( - try_sapling_output_recovery( - &consensus::MainNetwork, + try_sapling_output_recovery::( height, &ovk, &cv, @@ -1551,8 +1491,8 @@ mod tests { fn recovery_with_invalid_diversifier() { let mut rng = OsRng; let height_array = [ - consensus::MainNetwork::SAPLING_ACTIVATION_HEIGHT, - consensus::MainNetwork::CANOPY_ACTIVATION_HEIGHT, + Network::SAPLING_ACTIVATION_HEIGHT, + Network::CANOPY_ACTIVATION_HEIGHT, ]; for height_ref in height_array.iter() { @@ -1570,8 +1510,7 @@ mod tests { |pt| pt[1..12].copy_from_slice(&find_invalid_diversifier().0), ); assert_eq!( - try_sapling_output_recovery( - &consensus::MainNetwork, + try_sapling_output_recovery::( height, &ovk, &cv, @@ -1589,8 +1528,8 @@ mod tests { fn recovery_with_incorrect_diversifier() { let mut rng = OsRng; let height_array = [ - consensus::MainNetwork::SAPLING_ACTIVATION_HEIGHT, - consensus::MainNetwork::CANOPY_ACTIVATION_HEIGHT, + Network::SAPLING_ACTIVATION_HEIGHT, + Network::CANOPY_ACTIVATION_HEIGHT, ]; for height_ref in height_array.iter() { @@ -1609,8 +1548,7 @@ mod tests { |pt| pt[1..12].copy_from_slice(&find_valid_diversifier().0), ); assert_eq!( - try_sapling_output_recovery( - &consensus::MainNetwork, + try_sapling_output_recovery::( height, &ovk, &cv, @@ -1628,8 +1566,8 @@ mod tests { fn recovery_with_invalid_pk_d() { let mut rng = OsRng; let height_array = [ - consensus::MainNetwork::SAPLING_ACTIVATION_HEIGHT, - consensus::MainNetwork::CANOPY_ACTIVATION_HEIGHT, + Network::SAPLING_ACTIVATION_HEIGHT, + Network::CANOPY_ACTIVATION_HEIGHT, ]; for height_ref in height_array.iter() { @@ -1639,8 +1577,7 @@ mod tests { random_enc_ciphertext_with(height, ivk, &mut rng); assert_eq!( - try_sapling_output_recovery( - &consensus::MainNetwork, + try_sapling_output_recovery::( height, &ovk, &cv, @@ -1676,8 +1613,7 @@ mod tests { }; } - let height = consensus::MainNetwork - .activation_height(NetworkUpgrade::Sapling) + let height = Network::activation_height(NetworkUpgrade::Sapling) .expect("Should have Sapling activation height"); for tv in test_vectors { @@ -1726,14 +1662,7 @@ mod tests { // (Tested first because it only requires immutable references.) // - match try_sapling_note_decryption( - &consensus::MainNetwork, - height, - &ivk, - &epk, - &cmu, - &tv.c_enc, - ) { + match try_sapling_note_decryption::(height, &ivk, &epk, &cmu, &tv.c_enc) { Some((decrypted_note, decrypted_to, decrypted_memo)) => { assert_eq!(decrypted_note, note); assert_eq!(decrypted_to, to); @@ -1742,8 +1671,7 @@ mod tests { None => panic!("Note decryption failed"), } - match try_sapling_compact_note_decryption( - &consensus::MainNetwork, + match try_sapling_compact_note_decryption::( height, &ivk, &epk, @@ -1757,15 +1685,8 @@ mod tests { None => panic!("Compact note decryption failed"), } - match try_sapling_output_recovery( - &consensus::MainNetwork, - height, - &ovk, - &cv, - &cmu, - &epk, - &tv.c_enc, - &tv.c_out, + match try_sapling_output_recovery::( + height, &ovk, &cv, &cmu, &epk, &tv.c_enc, &tv.c_out, ) { Some((decrypted_note, decrypted_to, decrypted_memo)) => { assert_eq!(decrypted_note, note); diff --git a/zcash_primitives/src/transaction/builder.rs b/zcash_primitives/src/transaction/builder.rs index 89bf44900..68448f4f1 100644 --- a/zcash_primitives/src/transaction/builder.rs +++ b/zcash_primitives/src/transaction/builder.rs @@ -25,7 +25,7 @@ use crate::{ components::{amount::DEFAULT_FEE, Amount, OutputDescription, SpendDescription, TxOut}, signature_hash_data, Transaction, TransactionData, SIGHASH_ALL, }, - JUBJUB, + Network, JUBJUB, }; #[cfg(feature = "transparent-inputs")] @@ -88,7 +88,6 @@ pub struct SaplingOutput { impl SaplingOutput { pub fn new( - parameters: P, height: u32, rng: &mut R, ovk: OutgoingViewingKey, @@ -104,7 +103,7 @@ impl SaplingOutput { return Err(Error::InvalidAmount); } - let rseed = if parameters.is_nu_active(NetworkUpgrade::Canopy, height) { + let rseed = if P::is_nu_active(NetworkUpgrade::Canopy, height) { let mut buffer = [0u8; 32]; &rng.fill_bytes(&mut buffer); Rseed::AfterZip212(buffer) @@ -403,22 +402,14 @@ impl Builder { } /// Adds a Sapling address to send funds to. - pub fn add_sapling_output( + pub fn add_sapling_output( &mut self, ovk: OutgoingViewingKey, to: PaymentAddress, value: Amount, memo: Option, ) -> Result<(), Error> { - let output = SaplingOutput::new( - consensus::MainNetwork, - self.height, - &mut self.rng, - ovk, - to, - value, - memo, - )?; + let output = SaplingOutput::new::(self.height, &mut self.rng, ovk, to, value, memo)?; self.mtx.value_balance -= value; @@ -518,7 +509,7 @@ impl Builder { return Err(Error::NoChangeAddress); }; - self.add_sapling_output(change_address.0, change_address.1, change, None)?; + self.add_sapling_output::(change_address.0, change_address.1, change, None)?; } // @@ -733,7 +724,7 @@ mod tests { sapling::Node, transaction::components::Amount, zip32::{ExtendedFullViewingKey, ExtendedSpendingKey}, - JUBJUB, + Network, JUBJUB, }; #[test] @@ -745,7 +736,7 @@ mod tests { let mut builder = Builder::new(0); assert_eq!( - builder.add_sapling_output(ovk, to, Amount::from_i64(-1).unwrap(), None), + builder.add_sapling_output::(ovk, to, Amount::from_i64(-1).unwrap(), None), Err(Error::InvalidAmount) ); } @@ -758,9 +749,8 @@ mod tests { TransactionData, }; - let sapling_activation_height = consensus::MainNetwork - .activation_height(NetworkUpgrade::Sapling) - .unwrap(); + let sapling_activation_height = + Network::activation_height(NetworkUpgrade::Sapling).unwrap(); // Create a builder with 0 fee, so we can construct t outputs let mut builder = builder::Builder { @@ -865,7 +855,7 @@ mod tests { { let mut builder = Builder::new(0); builder - .add_sapling_output( + .add_sapling_output::( ovk.clone(), to.clone(), Amount::from_u64(50000).unwrap(), @@ -915,7 +905,7 @@ mod tests { ) .unwrap(); builder - .add_sapling_output( + .add_sapling_output::( ovk.clone(), to.clone(), Amount::from_u64(30000).unwrap(), @@ -961,7 +951,7 @@ mod tests { .add_sapling_spend(extsk, *to.diversifier(), note2, witness2.path().unwrap()) .unwrap(); builder - .add_sapling_output(ovk, to, Amount::from_u64(30000).unwrap(), None) + .add_sapling_output::(ovk, to, Amount::from_u64(30000).unwrap(), None) .unwrap(); builder .add_transparent_output( From d5f80618efa09d1399026078690c10f85a05730e Mon Sep 17 00:00:00 2001 From: therealyingtong Date: Wed, 5 Aug 2020 14:26:57 +0800 Subject: [PATCH 12/31] Switch plaintext version on height in commit_to_address() in zcash_client_sqlite --- zcash_client_sqlite/src/transact.rs | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/zcash_client_sqlite/src/transact.rs b/zcash_client_sqlite/src/transact.rs index e8c6700cf..0ad359701 100644 --- a/zcash_client_sqlite/src/transact.rs +++ b/zcash_client_sqlite/src/transact.rs @@ -9,6 +9,7 @@ use std::path::Path; use zcash_client_backend::encoding::encode_extended_full_viewing_key; use zcash_primitives::{ consensus, + consensus::Parameters, jubjub::fs::{Fs, FsRepr}, keys::OutgoingViewingKey, merkle_tree::{IncrementalWitness, MerklePath}, @@ -234,14 +235,20 @@ pub fn create_to_address>( let note_value: i64 = row.get(1)?; - let rcm = { - let d: Vec<_> = row.get(2)?; + let d: Vec<_> = row.get(2)?; + + let rseed = if height >= Network::CANOPY_ACTIVATION_HEIGHT { + let mut r = [0u8; 32]; + r.copy_from_slice(&d[..]); + Rseed::AfterZip212(r) + } else { let tmp = FsRepr( d[..] .try_into() .map_err(|_| Error(ErrorKind::InvalidNote))?, ); - Fs::from_repr(tmp).ok_or(Error(ErrorKind::InvalidNote))? + let r = Fs::from_repr(tmp).ok_or(Error(ErrorKind::InvalidNote))?; + Rseed::BeforeZip212(r) }; let from = extfvk @@ -249,9 +256,7 @@ pub fn create_to_address>( .vk .to_payment_address(diversifier, &JUBJUB) .unwrap(); - let note = from - .create_note(note_value as u64, Rseed::BeforeZip212(rcm), &JUBJUB) - .unwrap(); + let note = from.create_note(note_value as u64, rseed, &JUBJUB).unwrap(); let merkle_path = { let d: Vec<_> = row.get(3)?; From a3ae1b273d2480ebd1ce23b65704afcf29e4bef2 Mon Sep 17 00:00:00 2001 From: therealyingtong Date: Wed, 5 Aug 2020 14:27:36 +0800 Subject: [PATCH 13/31] Switch plaintext version on height for dummy outputs in Builder --- zcash_primitives/src/transaction/builder.rs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/zcash_primitives/src/transaction/builder.rs b/zcash_primitives/src/transaction/builder.rs index 68448f4f1..280880b3e 100644 --- a/zcash_primitives/src/transaction/builder.rs +++ b/zcash_primitives/src/transaction/builder.rs @@ -13,7 +13,7 @@ use std::fmt; use crate::{ consensus, - consensus::NetworkUpgrade, + consensus::{NetworkUpgrade, Parameters}, keys::OutgoingViewingKey, legacy::TransparentAddress, merkle_tree::MerklePath, @@ -620,12 +620,20 @@ impl Builder { } }; + let rseed = if self.height >= Network::CANOPY_ACTIVATION_HEIGHT { + let mut buffer = [0u8; 32]; + &mut self.rng.fill_bytes(&mut buffer); + Rseed::AfterZip212(buffer) + } else { + Rseed::BeforeZip212(Fs::random(&mut self.rng)) + }; + ( payment_address, Note { g_d, pk_d, - rseed: Rseed::BeforeZip212(Fs::random(&mut self.rng)), + rseed, value: 0, }, ) From 2ed9b6f881f71388127826b5b5ad44be17e937af Mon Sep 17 00:00:00 2001 From: therealyingtong Date: Wed, 5 Aug 2020 15:21:42 +0800 Subject: [PATCH 14/31] Refactor contextual random rseed generation into util method in zcash_primitives --- zcash_client_backend/src/welding_rig.rs | 17 ++++---- zcash_client_sqlite/src/lib.rs | 44 +++++++++------------ zcash_primitives/src/lib.rs | 2 +- zcash_primitives/src/note_encryption.rs | 9 +---- zcash_primitives/src/transaction/builder.rs | 9 +---- zcash_primitives/src/util.rs | 23 ++++++++++- 6 files changed, 54 insertions(+), 50 deletions(-) diff --git a/zcash_client_backend/src/welding_rig.rs b/zcash_client_backend/src/welding_rig.rs index f51ef3eac..e3b258f89 100644 --- a/zcash_client_backend/src/welding_rig.rs +++ b/zcash_client_backend/src/welding_rig.rs @@ -191,12 +191,13 @@ mod tests { use pairing::bls12_381::{Bls12, Fr}; use rand_core::{OsRng, RngCore}; use zcash_primitives::{ - consensus::{NetworkUpgrade, Parameters}, + consensus::NetworkUpgrade, jubjub::{fs::Fs, FixedGenerators, JubjubParams, ToUniform}, merkle_tree::CommitmentTree, note_encryption::{Memo, SaplingNoteEncryption}, - primitives::{Note, Rseed}, + primitives::Note, transaction::components::Amount, + util::generate_random_rseed, zip32::{ExtendedFullViewingKey, ExtendedSpendingKey}, JUBJUB, }; @@ -257,13 +258,11 @@ mod tests { // Create a fake Note for the account let mut rng = OsRng; - let rseed = if Network::is_nu_active(NetworkUpgrade::Canopy, height as u32) { - let mut buffer = [0u8; 32]; - &rng.fill_bytes(&mut buffer); - Rseed::AfterZip212(buffer) - } else { - Rseed::BeforeZip212(Fs::random(&mut rng)) - }; + let rseed = generate_random_rseed::( + NetworkUpgrade::Canopy, + height as u32, + &mut rng, + ); let note = Note { g_d: to.diversifier().g_d::(&JUBJUB).unwrap(), pk_d: to.pk_d().clone(), diff --git a/zcash_client_sqlite/src/lib.rs b/zcash_client_sqlite/src/lib.rs index df41cf4dd..533a25809 100644 --- a/zcash_client_sqlite/src/lib.rs +++ b/zcash_client_sqlite/src/lib.rs @@ -95,7 +95,7 @@ fn get_target_and_anchor_heights(data: &Connection) -> Result<(u32, u32), error: #[cfg(test)] mod tests { use crate::Network; - use ff::{Field, PrimeField}; + use ff::PrimeField; use pairing::bls12_381::Bls12; use protobuf::Message; use rand_core::{OsRng, RngCore}; @@ -106,11 +106,11 @@ mod tests { }; use zcash_primitives::{ block::BlockHash, - consensus::{NetworkUpgrade, Parameters}, - jubjub::fs::Fs, + consensus::NetworkUpgrade, note_encryption::{Memo, SaplingNoteEncryption}, - primitives::{Note, PaymentAddress, Rseed}, + primitives::{Note, PaymentAddress}, transaction::components::Amount, + util::generate_random_rseed, zip32::ExtendedFullViewingKey, JUBJUB, }; @@ -127,13 +127,11 @@ mod tests { // Create a fake Note for the account let mut rng = OsRng; - let rseed = if Network::is_nu_active(NetworkUpgrade::Canopy, height as u32) { - let mut buffer = [0u8; 32]; - &rng.fill_bytes(&mut buffer); - Rseed::AfterZip212(buffer) - } else { - Rseed::BeforeZip212(Fs::random(&mut rng)) - }; + let rseed = generate_random_rseed::( + NetworkUpgrade::Canopy, + height as u32, + &mut rng, + ); let note = Note { g_d: to.diversifier().g_d::(&JUBJUB).unwrap(), pk_d: to.pk_d().clone(), @@ -183,13 +181,11 @@ mod tests { value: Amount, ) -> CompactBlock { let mut rng = OsRng; - let rseed = if Network::is_nu_active(NetworkUpgrade::Canopy, height as u32) { - let mut buffer = [0u8; 32]; - &rng.fill_bytes(&mut buffer); - Rseed::AfterZip212(buffer) - } else { - Rseed::BeforeZip212(Fs::random(&mut rng)) - }; + let rseed = generate_random_rseed::( + NetworkUpgrade::Canopy, + height as u32, + &mut rng, + ); // Create a fake CompactBlock containing the note let mut cspend = CompactSpend::new(); @@ -226,13 +222,11 @@ mod tests { // Create a fake Note for the change ctx.outputs.push({ let change_addr = extfvk.default_address().unwrap().1; - let rseed = if Network::is_nu_active(NetworkUpgrade::Canopy, height as u32) { - let mut buffer = [0u8; 32]; - &rng.fill_bytes(&mut buffer); - Rseed::AfterZip212(buffer) - } else { - Rseed::BeforeZip212(Fs::random(&mut rng)) - }; + let rseed = generate_random_rseed::( + NetworkUpgrade::Canopy, + height as u32, + &mut rng, + ); let note = Note { g_d: change_addr.diversifier().g_d::(&JUBJUB).unwrap(), pk_d: change_addr.pk_d().clone(), diff --git a/zcash_primitives/src/lib.rs b/zcash_primitives/src/lib.rs index 2bbc801c2..2f23a6903 100644 --- a/zcash_primitives/src/lib.rs +++ b/zcash_primitives/src/lib.rs @@ -24,7 +24,7 @@ pub mod redjubjub; pub mod sapling; pub mod serialize; pub mod transaction; -mod util; +pub mod util; pub mod zip32; #[cfg(test)] diff --git a/zcash_primitives/src/note_encryption.rs b/zcash_primitives/src/note_encryption.rs index cc52356c6..6ac0a5022 100644 --- a/zcash_primitives/src/note_encryption.rs +++ b/zcash_primitives/src/note_encryption.rs @@ -593,6 +593,7 @@ mod tests { PrimeOrder, Unknown, }, primitives::{Diversifier, PaymentAddress, Rseed, ValueCommitment}, + util::generate_random_rseed, Network, }; use crypto_api_chachapoly::ChachaPolyIetf; @@ -795,13 +796,7 @@ mod tests { }; let cv = value_commitment.cm(&JUBJUB).into(); - let rseed = if Network::is_nu_active(NetworkUpgrade::Canopy, height) { - let mut buffer = [0u8; 32]; - &rng.fill_bytes(&mut buffer); - Rseed::AfterZip212(buffer) - } else { - Rseed::BeforeZip212(Fs::random(rng)) - }; + let rseed = generate_random_rseed::(NetworkUpgrade::Canopy, height, &mut rng); let note = pa.create_note(value, rseed, &JUBJUB).unwrap(); let cmu = note.cm(&JUBJUB); diff --git a/zcash_primitives/src/transaction/builder.rs b/zcash_primitives/src/transaction/builder.rs index 280880b3e..ba5a9e4d9 100644 --- a/zcash_primitives/src/transaction/builder.rs +++ b/zcash_primitives/src/transaction/builder.rs @@ -25,6 +25,7 @@ use crate::{ components::{amount::DEFAULT_FEE, Amount, OutputDescription, SpendDescription, TxOut}, signature_hash_data, Transaction, TransactionData, SIGHASH_ALL, }, + util::generate_random_rseed, Network, JUBJUB, }; @@ -103,13 +104,7 @@ impl SaplingOutput { return Err(Error::InvalidAmount); } - let rseed = if P::is_nu_active(NetworkUpgrade::Canopy, height) { - let mut buffer = [0u8; 32]; - &rng.fill_bytes(&mut buffer); - Rseed::AfterZip212(buffer) - } else { - Rseed::BeforeZip212(Fs::random(rng)) - }; + let rseed = generate_random_rseed::(NetworkUpgrade::Canopy, height, rng); let note = Note { g_d, diff --git a/zcash_primitives/src/util.rs b/zcash_primitives/src/util.rs index 1fdcde750..65d3418a4 100644 --- a/zcash_primitives/src/util.rs +++ b/zcash_primitives/src/util.rs @@ -1,6 +1,13 @@ use blake2b_simd::Params; -use crate::jubjub::{JubjubEngine, ToUniform}; +use crate::{ + consensus, + consensus::NetworkUpgrade, + jubjub::{fs::Fs, JubjubEngine, ToUniform}, + primitives::Rseed, +}; +use ff::Field; +use rand_core::{CryptoRng, RngCore}; pub fn hash_to_scalar(persona: &[u8], a: &[u8], b: &[u8]) -> E::Fs { let mut hasher = Params::new().hash_length(64).personal(persona).to_state(); @@ -9,3 +16,17 @@ pub fn hash_to_scalar(persona: &[u8], a: &[u8], b: &[u8]) -> E: let ret = hasher.finalize(); E::Fs::to_uniform(ret.as_ref()) } + +pub fn generate_random_rseed( + nu: NetworkUpgrade, + height: u32, + rng: &mut R, +) -> Rseed { + if P::is_nu_active(nu, height) { + let mut buffer = [0u8; 32]; + &rng.fill_bytes(&mut buffer); + Rseed::AfterZip212(buffer) + } else { + Rseed::BeforeZip212(Fs::random(rng)) + } +} From c8fcdeb50b3effe200d9b14f705fb5a35aac8abb Mon Sep 17 00:00:00 2001 From: therealyingtong Date: Wed, 5 Aug 2020 15:45:09 +0800 Subject: [PATCH 15/31] Minor changes in note_encryption.rs --- zcash_primitives/src/note_encryption.rs | 138 ++++++++++-------------- 1 file changed, 57 insertions(+), 81 deletions(-) diff --git a/zcash_primitives/src/note_encryption.rs b/zcash_primitives/src/note_encryption.rs index 6ac0a5022..1a88b367e 100644 --- a/zcash_primitives/src/note_encryption.rs +++ b/zcash_primitives/src/note_encryption.rs @@ -198,6 +198,7 @@ fn prf_ock( /// are consistent with each other. /// /// Implements section 4.17.1 of the Zcash Protocol Specification. +/// NB: the example code is only covering the pre-Canopy case. /// /// # Examples /// @@ -226,11 +227,12 @@ fn prf_ock( /// let ovk = OutgoingViewingKey([0; 32]); /// /// let value = 1000; -/// let rcm = Fs::random(&mut rng); +/// let rcv = Fs::random(&mut rng); /// let cv = ValueCommitment:: { /// value, -/// randomness: rcm.clone(), +/// randomness: rcv.clone(), /// }; +/// let rcm = Fs::random(&mut rng); /// let note = to.create_note(value, Rseed::BeforeZip212(rcm), &JUBJUB).unwrap(); /// let cmu = note.cm(&JUBJUB); /// @@ -347,9 +349,8 @@ fn parse_note_plaintext_without_memo( plaintext: &[u8], ) -> Option<(Note, PaymentAddress)> { // Check note plaintext version - match plaintext_version_is_valid::

(height, plaintext[0]) { - true => (), - false => return None, + if !plaintext_version_is_valid::

(height, plaintext[0]) { + return None; } let mut d = [0u8; 11]; @@ -539,9 +540,8 @@ pub fn try_sapling_output_recovery( ); // Check note plaintext version - match plaintext_version_is_valid::

(height, plaintext[0]) { - true => (), - false => return None, + if !plaintext_version_is_valid::

(height, plaintext[0]) { + return None; } let mut d = [0u8; 11]; @@ -908,13 +908,12 @@ mod tests { #[test] fn decryption_with_invalid_ivk() { let mut rng = OsRng; - let height_array = [ + let heights = [ Network::SAPLING_ACTIVATION_HEIGHT, Network::CANOPY_ACTIVATION_HEIGHT, ]; - for height_ref in height_array.iter() { - let height = *height_ref; + for &height in heights.iter() { let (_, _, _, cmu, epk, enc_ciphertext, _) = random_enc_ciphertext(height, &mut rng); assert_eq!( @@ -933,13 +932,12 @@ mod tests { #[test] fn decryption_with_invalid_epk() { let mut rng = OsRng; - let height_array = [ + let heights = [ Network::SAPLING_ACTIVATION_HEIGHT, Network::CANOPY_ACTIVATION_HEIGHT, ]; - for height_ref in height_array.iter() { - let height = *height_ref; + for &height in heights.iter() { let (_, ivk, _, cmu, _, enc_ciphertext, _) = random_enc_ciphertext(height, &mut rng); assert_eq!( @@ -958,13 +956,12 @@ mod tests { #[test] fn decryption_with_invalid_cmu() { let mut rng = OsRng; - let height_array = [ + let heights = [ Network::SAPLING_ACTIVATION_HEIGHT, Network::CANOPY_ACTIVATION_HEIGHT, ]; - for height_ref in height_array.iter() { - let height = *height_ref; + for &height in heights.iter() { let (_, ivk, _, _, epk, enc_ciphertext, _) = random_enc_ciphertext(height, &mut rng); assert_eq!( @@ -983,13 +980,12 @@ mod tests { #[test] fn decryption_with_invalid_tag() { let mut rng = OsRng; - let height_array = [ + let heights = [ Network::SAPLING_ACTIVATION_HEIGHT, Network::CANOPY_ACTIVATION_HEIGHT, ]; - for height_ref in height_array.iter() { - let height = *height_ref; + for &height in heights.iter() { let (_, ivk, _, cmu, epk, mut enc_ciphertext, _) = random_enc_ciphertext(height, &mut rng); @@ -1004,15 +1000,14 @@ mod tests { #[test] fn decryption_with_invalid_version_byte() { let mut rng = OsRng; - let height_array = [ + let heights = [ Network::CANOPY_ACTIVATION_HEIGHT - 1, Network::CANOPY_ACTIVATION_HEIGHT, Network::CANOPY_ACTIVATION_HEIGHT + ZIP212_GRACE_PERIOD, ]; let leadbyte_array = [0x02, 0x03, 0x01]; - for (i, height_ref) in height_array.iter().enumerate() { - let height = *height_ref; + for (i, &height) in heights.iter().enumerate() { let (ovk, ivk, cv, cmu, epk, mut enc_ciphertext, out_ciphertext) = random_enc_ciphertext(height, &mut rng); @@ -1035,13 +1030,12 @@ mod tests { #[test] fn decryption_with_invalid_diversifier() { let mut rng = OsRng; - let height_array = [ + let heights = [ Network::SAPLING_ACTIVATION_HEIGHT, Network::CANOPY_ACTIVATION_HEIGHT, ]; - for height_ref in height_array.iter() { - let height = *height_ref; + for &height in heights.iter() { let (ovk, ivk, cv, cmu, epk, mut enc_ciphertext, out_ciphertext) = random_enc_ciphertext(height, &mut rng); @@ -1064,13 +1058,12 @@ mod tests { #[test] fn decryption_with_incorrect_diversifier() { let mut rng = OsRng; - let height_array = [ + let heights = [ Network::SAPLING_ACTIVATION_HEIGHT, Network::CANOPY_ACTIVATION_HEIGHT, ]; - for height_ref in height_array.iter() { - let height = *height_ref; + for &height in heights.iter() { let (ovk, ivk, cv, cmu, epk, mut enc_ciphertext, out_ciphertext) = random_enc_ciphertext(height, &mut rng); @@ -1093,13 +1086,12 @@ mod tests { #[test] fn compact_decryption_with_invalid_ivk() { let mut rng = OsRng; - let height_array = [ + let heights = [ Network::SAPLING_ACTIVATION_HEIGHT, Network::CANOPY_ACTIVATION_HEIGHT, ]; - for height_ref in height_array.iter() { - let height = *height_ref; + for &height in heights.iter() { let (_, _, _, cmu, epk, enc_ciphertext, _) = random_enc_ciphertext(height, &mut rng); assert_eq!( @@ -1118,13 +1110,12 @@ mod tests { #[test] fn compact_decryption_with_invalid_epk() { let mut rng = OsRng; - let height_array = [ + let heights = [ Network::SAPLING_ACTIVATION_HEIGHT, Network::CANOPY_ACTIVATION_HEIGHT, ]; - for height_ref in height_array.iter() { - let height = *height_ref; + for &height in heights.iter() { let (_, ivk, _, cmu, _, enc_ciphertext, _) = random_enc_ciphertext(height, &mut rng); assert_eq!( @@ -1143,13 +1134,12 @@ mod tests { #[test] fn compact_decryption_with_invalid_cmu() { let mut rng = OsRng; - let height_array = [ + let heights = [ Network::SAPLING_ACTIVATION_HEIGHT, Network::CANOPY_ACTIVATION_HEIGHT, ]; - for height_ref in height_array.iter() { - let height = *height_ref; + for &height in heights.iter() { let (_, ivk, _, _, epk, enc_ciphertext, _) = random_enc_ciphertext(height, &mut rng); assert_eq!( @@ -1168,15 +1158,14 @@ mod tests { #[test] fn compact_decryption_with_invalid_version_byte() { let mut rng = OsRng; - let height_array = [ + let heights = [ Network::CANOPY_ACTIVATION_HEIGHT - 1, Network::CANOPY_ACTIVATION_HEIGHT, Network::CANOPY_ACTIVATION_HEIGHT + ZIP212_GRACE_PERIOD, ]; let leadbyte_array = [0x02, 0x03, 0x01]; - for (i, height_ref) in height_array.iter().enumerate() { - let height = *height_ref; + for (i, &height) in heights.iter().enumerate() { let (ovk, ivk, cv, cmu, epk, mut enc_ciphertext, out_ciphertext) = random_enc_ciphertext(height, &mut rng); @@ -1205,13 +1194,12 @@ mod tests { #[test] fn compact_decryption_with_invalid_diversifier() { let mut rng = OsRng; - let height_array = [ + let heights = [ Network::SAPLING_ACTIVATION_HEIGHT, Network::CANOPY_ACTIVATION_HEIGHT, ]; - for height_ref in height_array.iter() { - let height = *height_ref; + for &height in heights.iter() { let (ovk, ivk, cv, cmu, epk, mut enc_ciphertext, out_ciphertext) = random_enc_ciphertext(height, &mut rng); @@ -1240,13 +1228,12 @@ mod tests { #[test] fn compact_decryption_with_incorrect_diversifier() { let mut rng = OsRng; - let height_array = [ + let heights = [ Network::SAPLING_ACTIVATION_HEIGHT, Network::CANOPY_ACTIVATION_HEIGHT, ]; - for height_ref in height_array.iter() { - let height = *height_ref; + for &height in heights.iter() { let (ovk, ivk, cv, cmu, epk, mut enc_ciphertext, out_ciphertext) = random_enc_ciphertext(height, &mut rng); @@ -1275,13 +1262,12 @@ mod tests { #[test] fn recovery_with_invalid_ovk() { let mut rng = OsRng; - let height_array = [ + let heights = [ Network::SAPLING_ACTIVATION_HEIGHT, Network::CANOPY_ACTIVATION_HEIGHT, ]; - for height_ref in height_array.iter() { - let height = *height_ref; + for &height in heights.iter() { let (mut ovk, _, cv, cmu, epk, enc_ciphertext, out_ciphertext) = random_enc_ciphertext(height, &mut rng); @@ -1304,13 +1290,12 @@ mod tests { #[test] fn recovery_with_invalid_cv() { let mut rng = OsRng; - let height_array = [ + let heights = [ Network::SAPLING_ACTIVATION_HEIGHT, Network::CANOPY_ACTIVATION_HEIGHT, ]; - for height_ref in height_array.iter() { - let height = *height_ref; + for &height in heights.iter() { let (ovk, _, _, cmu, epk, enc_ciphertext, out_ciphertext) = random_enc_ciphertext(height, &mut rng); @@ -1332,14 +1317,13 @@ mod tests { #[test] fn recovery_with_invalid_cmu() { let mut rng = OsRng; - let height_array = [ + let heights = [ Network::SAPLING_ACTIVATION_HEIGHT, Network::CANOPY_ACTIVATION_HEIGHT, ]; - for height_ref in height_array.iter() { - let height = *height_ref; - let (ovk, _, cv, _, epk, enc_ciphertext, out_ciphertext) = + for &height in heights.iter() { + let (ovk, _, cv, _, epk, enc_ctext, out_ctext) = random_enc_ciphertext(height, &mut rng); assert_eq!( @@ -1349,8 +1333,8 @@ mod tests { &cv, &Fr::random(&mut rng), &epk, - &enc_ciphertext, - &out_ciphertext + &enc_ctext, + &out_ctext ), None ); @@ -1360,13 +1344,12 @@ mod tests { #[test] fn recovery_with_invalid_epk() { let mut rng = OsRng; - let height_array = [ + let heights = [ Network::SAPLING_ACTIVATION_HEIGHT, Network::CANOPY_ACTIVATION_HEIGHT, ]; - for height_ref in height_array.iter() { - let height = *height_ref; + for &height in heights.iter() { let (ovk, _, cv, cmu, _, enc_ciphertext, out_ciphertext) = random_enc_ciphertext(height, &mut rng); @@ -1388,13 +1371,12 @@ mod tests { #[test] fn recovery_with_invalid_enc_tag() { let mut rng = OsRng; - let height_array = [ + let heights = [ Network::SAPLING_ACTIVATION_HEIGHT, Network::CANOPY_ACTIVATION_HEIGHT, ]; - for height_ref in height_array.iter() { - let height = *height_ref; + for &height in heights.iter() { let (ovk, _, cv, cmu, epk, mut enc_ciphertext, out_ciphertext) = random_enc_ciphertext(height, &mut rng); @@ -1417,13 +1399,12 @@ mod tests { #[test] fn recovery_with_invalid_out_tag() { let mut rng = OsRng; - let height_array = [ + let heights = [ Network::SAPLING_ACTIVATION_HEIGHT, Network::CANOPY_ACTIVATION_HEIGHT, ]; - for height_ref in height_array.iter() { - let height = *height_ref; + for &height in heights.iter() { let (ovk, _, cv, cmu, epk, enc_ciphertext, mut out_ciphertext) = random_enc_ciphertext(height, &mut rng); @@ -1446,15 +1427,14 @@ mod tests { #[test] fn recovery_with_invalid_version_byte() { let mut rng = OsRng; - let height_array = [ + let heights = [ Network::CANOPY_ACTIVATION_HEIGHT - 1, Network::CANOPY_ACTIVATION_HEIGHT, Network::CANOPY_ACTIVATION_HEIGHT + ZIP212_GRACE_PERIOD, ]; let leadbyte_array = [0x02, 0x03, 0x01]; - for (i, height_ref) in height_array.iter().enumerate() { - let height = *height_ref; + for (i, &height) in heights.iter().enumerate() { let (ovk, _, cv, cmu, epk, mut enc_ciphertext, out_ciphertext) = random_enc_ciphertext(height, &mut rng); @@ -1485,13 +1465,12 @@ mod tests { #[test] fn recovery_with_invalid_diversifier() { let mut rng = OsRng; - let height_array = [ + let heights = [ Network::SAPLING_ACTIVATION_HEIGHT, Network::CANOPY_ACTIVATION_HEIGHT, ]; - for height_ref in height_array.iter() { - let height = *height_ref; + for &height in heights.iter() { let (ovk, _, cv, cmu, epk, mut enc_ciphertext, out_ciphertext) = random_enc_ciphertext(height, &mut rng); @@ -1522,14 +1501,12 @@ mod tests { #[test] fn recovery_with_incorrect_diversifier() { let mut rng = OsRng; - let height_array = [ + let heights = [ Network::SAPLING_ACTIVATION_HEIGHT, Network::CANOPY_ACTIVATION_HEIGHT, ]; - for height_ref in height_array.iter() { - let height = *height_ref; - + for &height in heights.iter() { let (ovk, _, cv, cmu, epk, mut enc_ciphertext, out_ciphertext) = random_enc_ciphertext(height, &mut rng); @@ -1560,13 +1537,12 @@ mod tests { #[test] fn recovery_with_invalid_pk_d() { let mut rng = OsRng; - let height_array = [ + let heights = [ Network::SAPLING_ACTIVATION_HEIGHT, Network::CANOPY_ACTIVATION_HEIGHT, ]; - for height_ref in height_array.iter() { - let height = *height_ref; + for &height in heights.iter() { let ivk = Fs::zero(); let (ovk, _, cv, cmu, epk, enc_ciphertext, out_ciphertext) = random_enc_ciphertext_with(height, ivk, &mut rng); From d6deaddc0a32e5c7dedf2832b8dca22bb0a922a5 Mon Sep 17 00:00:00 2001 From: therealyingtong Date: Wed, 5 Aug 2020 16:09:41 +0800 Subject: [PATCH 16/31] Only query last_height when needed in decrypt_and_store_transaction() --- zcash_client_sqlite/src/scan.rs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/zcash_client_sqlite/src/scan.rs b/zcash_client_sqlite/src/scan.rs index 417d63bef..d22a48662 100644 --- a/zcash_client_sqlite/src/scan.rs +++ b/zcash_client_sqlite/src/scan.rs @@ -373,12 +373,15 @@ pub fn decrypt_and_store_transaction>( .ok_or(Error(ErrorKind::IncorrectHRPExtFVK))?; // Height is block height for mined transactions, and the "mempool height" (chain height + 1) for mempool transactions. - let last_height = data.query_row("SELECT MAX(height) FROM blocks", NO_PARAMS, |row| { - row.get(0).or(Ok(SAPLING_ACTIVATION_HEIGHT - 1)) - })?; let mut stmt_select_block = data.prepare("SELECT block FROM transactions WHERE txid = ?")?; let height = stmt_select_block.query_row(&[tx.txid().0.to_vec()], |row| { - row.get(0).or(Ok(last_height + 1)) + row.get(0).or({ + let last_height = + data.query_row("SELECT MAX(height) FROM blocks", NO_PARAMS, |row| { + row.get(0).or(Ok(SAPLING_ACTIVATION_HEIGHT - 1)) + })?; + Ok(last_height + 1) + }) })?; let outputs = decrypt_transaction::(height as u32, tx, &extfvks); From 88072d64ecfb3250ce85511996e8d317349fa9af Mon Sep 17 00:00:00 2001 From: therealyingtong Date: Thu, 6 Aug 2020 11:35:05 +0800 Subject: [PATCH 17/31] Remove network cfg from zcash_client_backend and zcash_primitives --- zcash_client_backend/src/lib.rs | 6 - zcash_client_backend/src/welding_rig.rs | 15 +- zcash_primitives/src/lib.rs | 6 - zcash_primitives/src/note_encryption.rs | 198 ++++++++++++++---------- 4 files changed, 119 insertions(+), 106 deletions(-) diff --git a/zcash_client_backend/src/lib.rs b/zcash_client_backend/src/lib.rs index a4e5fb422..e3852e6ac 100644 --- a/zcash_client_backend/src/lib.rs +++ b/zcash_client_backend/src/lib.rs @@ -15,9 +15,3 @@ pub mod wallet; pub mod welding_rig; pub use decrypt::{decrypt_transaction, DecryptedOutput}; - -#[cfg(feature = "mainnet")] -pub use zcash_primitives::consensus::MainNetwork as Network; - -#[cfg(not(feature = "mainnet"))] -pub use zcash_primitives::consensus::TestNetwork as Network; diff --git a/zcash_client_backend/src/welding_rig.rs b/zcash_client_backend/src/welding_rig.rs index e3b258f89..c07001cdc 100644 --- a/zcash_client_backend/src/welding_rig.rs +++ b/zcash_client_backend/src/welding_rig.rs @@ -191,7 +191,7 @@ mod tests { use pairing::bls12_381::{Bls12, Fr}; use rand_core::{OsRng, RngCore}; use zcash_primitives::{ - consensus::NetworkUpgrade, + consensus::{NetworkUpgrade, TestNetwork}, jubjub::{fs::Fs, FixedGenerators, JubjubParams, ToUniform}, merkle_tree::CommitmentTree, note_encryption::{Memo, SaplingNoteEncryption}, @@ -203,10 +203,7 @@ mod tests { }; use super::scan_block; - use crate::{ - proto::compact_formats::{CompactBlock, CompactOutput, CompactSpend, CompactTx}, - Network, - }; + use crate::proto::compact_formats::{CompactBlock, CompactOutput, CompactSpend, CompactTx}; fn random_compact_tx(rng: &mut R) -> CompactTx { let fake_nf = { @@ -258,7 +255,7 @@ mod tests { // Create a fake Note for the account let mut rng = OsRng; - let rseed = generate_random_rseed::( + let rseed = generate_random_rseed::( NetworkUpgrade::Canopy, height as u32, &mut rng, @@ -333,7 +330,7 @@ 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::(cb, &[extfvk], &[], &mut tree, &mut []); assert_eq!(txs.len(), 1); let tx = &txs[0]; @@ -365,7 +362,7 @@ 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::(cb, &[extfvk], &[], &mut tree, &mut []); assert_eq!(txs.len(), 1); let tx = &txs[0]; @@ -393,7 +390,7 @@ 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::(cb, &[], &[(&nf, account)], &mut tree, &mut []); assert_eq!(txs.len(), 1); let tx = &txs[0]; diff --git a/zcash_primitives/src/lib.rs b/zcash_primitives/src/lib.rs index 2f23a6903..fefbad07e 100644 --- a/zcash_primitives/src/lib.rs +++ b/zcash_primitives/src/lib.rs @@ -35,9 +35,3 @@ use crate::jubjub::JubjubBls12; lazy_static! { pub static ref JUBJUB: JubjubBls12 = JubjubBls12::new(); } - -#[cfg(feature = "mainnet")] -use crate::consensus::MainNetwork as Network; - -#[cfg(not(feature = "mainnet"))] -use crate::consensus::TestNetwork as Network; diff --git a/zcash_primitives/src/note_encryption.rs b/zcash_primitives/src/note_encryption.rs index 1a88b367e..e85daaede 100644 --- a/zcash_primitives/src/note_encryption.rs +++ b/zcash_primitives/src/note_encryption.rs @@ -586,7 +586,7 @@ pub fn try_sapling_output_recovery( #[cfg(test)] mod tests { use crate::{ - consensus::{NetworkUpgrade, Parameters, ZIP212_GRACE_PERIOD}, + consensus::{NetworkUpgrade, Parameters, TestNetwork, ZIP212_GRACE_PERIOD}, jubjub::{ edwards, fs::{Fs, FsRepr}, @@ -594,7 +594,6 @@ mod tests { }, primitives::{Diversifier, PaymentAddress, Rseed, ValueCommitment}, util::generate_random_rseed, - Network, }; use crypto_api_chachapoly::ChachaPolyIetf; use ff::{Field, PrimeField}; @@ -745,11 +744,15 @@ mod tests { let (ovk, ivk, cv, cmu, epk, enc_ciphertext, out_ciphertext) = random_enc_ciphertext_with(height, ivk, rng); - assert!( - try_sapling_note_decryption::(height, &ivk, &epk, &cmu, &enc_ciphertext) - .is_some() - ); - assert!(try_sapling_compact_note_decryption::( + assert!(try_sapling_note_decryption::( + height, + &ivk, + &epk, + &cmu, + &enc_ciphertext + ) + .is_some()); + assert!(try_sapling_compact_note_decryption::( height, &ivk, &epk, @@ -757,7 +760,7 @@ mod tests { &enc_ciphertext[..COMPACT_NOTE_SIZE] ) .is_some()); - assert!(try_sapling_output_recovery::( + assert!(try_sapling_output_recovery::( height, &ovk, &cv, @@ -796,7 +799,8 @@ mod tests { }; let cv = value_commitment.cm(&JUBJUB).into(); - let rseed = generate_random_rseed::(NetworkUpgrade::Canopy, height, &mut rng); + let rseed = + generate_random_rseed::(NetworkUpgrade::Canopy, height, &mut rng); let note = pa.create_note(value, rseed, &JUBJUB).unwrap(); let cmu = note.cm(&JUBJUB); @@ -909,15 +913,15 @@ mod tests { fn decryption_with_invalid_ivk() { let mut rng = OsRng; let heights = [ - Network::SAPLING_ACTIVATION_HEIGHT, - Network::CANOPY_ACTIVATION_HEIGHT, + TestNetwork::SAPLING_ACTIVATION_HEIGHT, + TestNetwork::CANOPY_ACTIVATION_HEIGHT, ]; for &height in heights.iter() { let (_, _, _, cmu, epk, enc_ciphertext, _) = random_enc_ciphertext(height, &mut rng); assert_eq!( - try_sapling_note_decryption::( + try_sapling_note_decryption::( height, &Fs::random(&mut rng), &epk, @@ -933,15 +937,15 @@ mod tests { fn decryption_with_invalid_epk() { let mut rng = OsRng; let heights = [ - Network::SAPLING_ACTIVATION_HEIGHT, - Network::CANOPY_ACTIVATION_HEIGHT, + TestNetwork::SAPLING_ACTIVATION_HEIGHT, + TestNetwork::CANOPY_ACTIVATION_HEIGHT, ]; for &height in heights.iter() { let (_, ivk, _, cmu, _, enc_ciphertext, _) = random_enc_ciphertext(height, &mut rng); assert_eq!( - try_sapling_note_decryption::( + try_sapling_note_decryption::( height, &ivk, &edwards::Point::::rand(&mut rng, &JUBJUB).mul_by_cofactor(&JUBJUB), @@ -957,15 +961,15 @@ mod tests { fn decryption_with_invalid_cmu() { let mut rng = OsRng; let heights = [ - Network::SAPLING_ACTIVATION_HEIGHT, - Network::CANOPY_ACTIVATION_HEIGHT, + TestNetwork::SAPLING_ACTIVATION_HEIGHT, + TestNetwork::CANOPY_ACTIVATION_HEIGHT, ]; for &height in heights.iter() { let (_, ivk, _, _, epk, enc_ciphertext, _) = random_enc_ciphertext(height, &mut rng); assert_eq!( - try_sapling_note_decryption::( + try_sapling_note_decryption::( height, &ivk, &epk, @@ -981,8 +985,8 @@ mod tests { fn decryption_with_invalid_tag() { let mut rng = OsRng; let heights = [ - Network::SAPLING_ACTIVATION_HEIGHT, - Network::CANOPY_ACTIVATION_HEIGHT, + TestNetwork::SAPLING_ACTIVATION_HEIGHT, + TestNetwork::CANOPY_ACTIVATION_HEIGHT, ]; for &height in heights.iter() { @@ -991,7 +995,13 @@ mod tests { enc_ciphertext[ENC_CIPHERTEXT_SIZE - 1] ^= 0xff; assert_eq!( - try_sapling_note_decryption::(height, &ivk, &epk, &cmu, &enc_ciphertext), + try_sapling_note_decryption::( + height, + &ivk, + &epk, + &cmu, + &enc_ciphertext + ), None ); } @@ -1001,9 +1011,9 @@ mod tests { fn decryption_with_invalid_version_byte() { let mut rng = OsRng; let heights = [ - Network::CANOPY_ACTIVATION_HEIGHT - 1, - Network::CANOPY_ACTIVATION_HEIGHT, - Network::CANOPY_ACTIVATION_HEIGHT + ZIP212_GRACE_PERIOD, + TestNetwork::CANOPY_ACTIVATION_HEIGHT - 1, + TestNetwork::CANOPY_ACTIVATION_HEIGHT, + TestNetwork::CANOPY_ACTIVATION_HEIGHT + ZIP212_GRACE_PERIOD, ]; let leadbyte_array = [0x02, 0x03, 0x01]; @@ -1021,7 +1031,13 @@ mod tests { |pt| pt[0] = leadbyte_array[i], ); assert_eq!( - try_sapling_note_decryption::(height, &ivk, &epk, &cmu, &enc_ciphertext), + try_sapling_note_decryption::( + height, + &ivk, + &epk, + &cmu, + &enc_ciphertext + ), None ); } @@ -1031,8 +1047,8 @@ mod tests { fn decryption_with_invalid_diversifier() { let mut rng = OsRng; let heights = [ - Network::SAPLING_ACTIVATION_HEIGHT, - Network::CANOPY_ACTIVATION_HEIGHT, + TestNetwork::SAPLING_ACTIVATION_HEIGHT, + TestNetwork::CANOPY_ACTIVATION_HEIGHT, ]; for &height in heights.iter() { @@ -1049,7 +1065,13 @@ mod tests { |pt| pt[1..12].copy_from_slice(&find_invalid_diversifier().0), ); assert_eq!( - try_sapling_note_decryption::(height, &ivk, &epk, &cmu, &enc_ciphertext), + try_sapling_note_decryption::( + height, + &ivk, + &epk, + &cmu, + &enc_ciphertext + ), None ); } @@ -1059,8 +1081,8 @@ mod tests { fn decryption_with_incorrect_diversifier() { let mut rng = OsRng; let heights = [ - Network::SAPLING_ACTIVATION_HEIGHT, - Network::CANOPY_ACTIVATION_HEIGHT, + TestNetwork::SAPLING_ACTIVATION_HEIGHT, + TestNetwork::CANOPY_ACTIVATION_HEIGHT, ]; for &height in heights.iter() { @@ -1077,7 +1099,13 @@ mod tests { |pt| pt[1..12].copy_from_slice(&find_valid_diversifier().0), ); assert_eq!( - try_sapling_note_decryption::(height, &ivk, &epk, &cmu, &enc_ciphertext), + try_sapling_note_decryption::( + height, + &ivk, + &epk, + &cmu, + &enc_ciphertext + ), None ); } @@ -1087,15 +1115,15 @@ mod tests { fn compact_decryption_with_invalid_ivk() { let mut rng = OsRng; let heights = [ - Network::SAPLING_ACTIVATION_HEIGHT, - Network::CANOPY_ACTIVATION_HEIGHT, + TestNetwork::SAPLING_ACTIVATION_HEIGHT, + TestNetwork::CANOPY_ACTIVATION_HEIGHT, ]; for &height in heights.iter() { let (_, _, _, cmu, epk, enc_ciphertext, _) = random_enc_ciphertext(height, &mut rng); assert_eq!( - try_sapling_compact_note_decryption::( + try_sapling_compact_note_decryption::( height, &Fs::random(&mut rng), &epk, @@ -1111,15 +1139,15 @@ mod tests { fn compact_decryption_with_invalid_epk() { let mut rng = OsRng; let heights = [ - Network::SAPLING_ACTIVATION_HEIGHT, - Network::CANOPY_ACTIVATION_HEIGHT, + TestNetwork::SAPLING_ACTIVATION_HEIGHT, + TestNetwork::CANOPY_ACTIVATION_HEIGHT, ]; for &height in heights.iter() { let (_, ivk, _, cmu, _, enc_ciphertext, _) = random_enc_ciphertext(height, &mut rng); assert_eq!( - try_sapling_compact_note_decryption::( + try_sapling_compact_note_decryption::( height, &ivk, &edwards::Point::::rand(&mut rng, &JUBJUB).mul_by_cofactor(&JUBJUB), @@ -1135,15 +1163,15 @@ mod tests { fn compact_decryption_with_invalid_cmu() { let mut rng = OsRng; let heights = [ - Network::SAPLING_ACTIVATION_HEIGHT, - Network::CANOPY_ACTIVATION_HEIGHT, + TestNetwork::SAPLING_ACTIVATION_HEIGHT, + TestNetwork::CANOPY_ACTIVATION_HEIGHT, ]; for &height in heights.iter() { let (_, ivk, _, _, epk, enc_ciphertext, _) = random_enc_ciphertext(height, &mut rng); assert_eq!( - try_sapling_compact_note_decryption::( + try_sapling_compact_note_decryption::( height, &ivk, &epk, @@ -1159,9 +1187,9 @@ mod tests { fn compact_decryption_with_invalid_version_byte() { let mut rng = OsRng; let heights = [ - Network::CANOPY_ACTIVATION_HEIGHT - 1, - Network::CANOPY_ACTIVATION_HEIGHT, - Network::CANOPY_ACTIVATION_HEIGHT + ZIP212_GRACE_PERIOD, + TestNetwork::CANOPY_ACTIVATION_HEIGHT - 1, + TestNetwork::CANOPY_ACTIVATION_HEIGHT, + TestNetwork::CANOPY_ACTIVATION_HEIGHT + ZIP212_GRACE_PERIOD, ]; let leadbyte_array = [0x02, 0x03, 0x01]; @@ -1179,7 +1207,7 @@ mod tests { |pt| pt[0] = leadbyte_array[i], ); assert_eq!( - try_sapling_compact_note_decryption::( + try_sapling_compact_note_decryption::( height, &ivk, &epk, @@ -1195,8 +1223,8 @@ mod tests { fn compact_decryption_with_invalid_diversifier() { let mut rng = OsRng; let heights = [ - Network::SAPLING_ACTIVATION_HEIGHT, - Network::CANOPY_ACTIVATION_HEIGHT, + TestNetwork::SAPLING_ACTIVATION_HEIGHT, + TestNetwork::CANOPY_ACTIVATION_HEIGHT, ]; for &height in heights.iter() { @@ -1213,7 +1241,7 @@ mod tests { |pt| pt[1..12].copy_from_slice(&find_invalid_diversifier().0), ); assert_eq!( - try_sapling_compact_note_decryption::( + try_sapling_compact_note_decryption::( height, &ivk, &epk, @@ -1229,8 +1257,8 @@ mod tests { fn compact_decryption_with_incorrect_diversifier() { let mut rng = OsRng; let heights = [ - Network::SAPLING_ACTIVATION_HEIGHT, - Network::CANOPY_ACTIVATION_HEIGHT, + TestNetwork::SAPLING_ACTIVATION_HEIGHT, + TestNetwork::CANOPY_ACTIVATION_HEIGHT, ]; for &height in heights.iter() { @@ -1247,7 +1275,7 @@ mod tests { |pt| pt[1..12].copy_from_slice(&find_valid_diversifier().0), ); assert_eq!( - try_sapling_compact_note_decryption::( + try_sapling_compact_note_decryption::( height, &ivk, &epk, @@ -1263,8 +1291,8 @@ mod tests { fn recovery_with_invalid_ovk() { let mut rng = OsRng; let heights = [ - Network::SAPLING_ACTIVATION_HEIGHT, - Network::CANOPY_ACTIVATION_HEIGHT, + TestNetwork::SAPLING_ACTIVATION_HEIGHT, + TestNetwork::CANOPY_ACTIVATION_HEIGHT, ]; for &height in heights.iter() { @@ -1273,7 +1301,7 @@ mod tests { ovk.0[0] ^= 0xff; assert_eq!( - try_sapling_output_recovery::( + try_sapling_output_recovery::( height, &ovk, &cv, @@ -1291,8 +1319,8 @@ mod tests { fn recovery_with_invalid_cv() { let mut rng = OsRng; let heights = [ - Network::SAPLING_ACTIVATION_HEIGHT, - Network::CANOPY_ACTIVATION_HEIGHT, + TestNetwork::SAPLING_ACTIVATION_HEIGHT, + TestNetwork::CANOPY_ACTIVATION_HEIGHT, ]; for &height in heights.iter() { @@ -1300,7 +1328,7 @@ mod tests { random_enc_ciphertext(height, &mut rng); assert_eq!( - try_sapling_output_recovery::( + try_sapling_output_recovery::( height, &ovk, &edwards::Point::::rand(&mut rng, &JUBJUB), @@ -1318,8 +1346,8 @@ mod tests { fn recovery_with_invalid_cmu() { let mut rng = OsRng; let heights = [ - Network::SAPLING_ACTIVATION_HEIGHT, - Network::CANOPY_ACTIVATION_HEIGHT, + TestNetwork::SAPLING_ACTIVATION_HEIGHT, + TestNetwork::CANOPY_ACTIVATION_HEIGHT, ]; for &height in heights.iter() { @@ -1327,7 +1355,7 @@ mod tests { random_enc_ciphertext(height, &mut rng); assert_eq!( - try_sapling_output_recovery::( + try_sapling_output_recovery::( height, &ovk, &cv, @@ -1345,8 +1373,8 @@ mod tests { fn recovery_with_invalid_epk() { let mut rng = OsRng; let heights = [ - Network::SAPLING_ACTIVATION_HEIGHT, - Network::CANOPY_ACTIVATION_HEIGHT, + TestNetwork::SAPLING_ACTIVATION_HEIGHT, + TestNetwork::CANOPY_ACTIVATION_HEIGHT, ]; for &height in heights.iter() { @@ -1354,7 +1382,7 @@ mod tests { random_enc_ciphertext(height, &mut rng); assert_eq!( - try_sapling_output_recovery::( + try_sapling_output_recovery::( height, &ovk, &cv, @@ -1372,8 +1400,8 @@ mod tests { fn recovery_with_invalid_enc_tag() { let mut rng = OsRng; let heights = [ - Network::SAPLING_ACTIVATION_HEIGHT, - Network::CANOPY_ACTIVATION_HEIGHT, + TestNetwork::SAPLING_ACTIVATION_HEIGHT, + TestNetwork::CANOPY_ACTIVATION_HEIGHT, ]; for &height in heights.iter() { @@ -1382,7 +1410,7 @@ mod tests { enc_ciphertext[ENC_CIPHERTEXT_SIZE - 1] ^= 0xff; assert_eq!( - try_sapling_output_recovery::( + try_sapling_output_recovery::( height, &ovk, &cv, @@ -1400,8 +1428,8 @@ mod tests { fn recovery_with_invalid_out_tag() { let mut rng = OsRng; let heights = [ - Network::SAPLING_ACTIVATION_HEIGHT, - Network::CANOPY_ACTIVATION_HEIGHT, + TestNetwork::SAPLING_ACTIVATION_HEIGHT, + TestNetwork::CANOPY_ACTIVATION_HEIGHT, ]; for &height in heights.iter() { @@ -1410,7 +1438,7 @@ mod tests { out_ciphertext[OUT_CIPHERTEXT_SIZE - 1] ^= 0xff; assert_eq!( - try_sapling_output_recovery::( + try_sapling_output_recovery::( height, &ovk, &cv, @@ -1428,9 +1456,9 @@ mod tests { fn recovery_with_invalid_version_byte() { let mut rng = OsRng; let heights = [ - Network::CANOPY_ACTIVATION_HEIGHT - 1, - Network::CANOPY_ACTIVATION_HEIGHT, - Network::CANOPY_ACTIVATION_HEIGHT + ZIP212_GRACE_PERIOD, + TestNetwork::CANOPY_ACTIVATION_HEIGHT - 1, + TestNetwork::CANOPY_ACTIVATION_HEIGHT, + TestNetwork::CANOPY_ACTIVATION_HEIGHT + ZIP212_GRACE_PERIOD, ]; let leadbyte_array = [0x02, 0x03, 0x01]; @@ -1448,7 +1476,7 @@ mod tests { |pt| pt[0] = leadbyte_array[i], ); assert_eq!( - try_sapling_output_recovery::( + try_sapling_output_recovery::( height, &ovk, &cv, @@ -1466,8 +1494,8 @@ mod tests { fn recovery_with_invalid_diversifier() { let mut rng = OsRng; let heights = [ - Network::SAPLING_ACTIVATION_HEIGHT, - Network::CANOPY_ACTIVATION_HEIGHT, + TestNetwork::SAPLING_ACTIVATION_HEIGHT, + TestNetwork::CANOPY_ACTIVATION_HEIGHT, ]; for &height in heights.iter() { @@ -1484,7 +1512,7 @@ mod tests { |pt| pt[1..12].copy_from_slice(&find_invalid_diversifier().0), ); assert_eq!( - try_sapling_output_recovery::( + try_sapling_output_recovery::( height, &ovk, &cv, @@ -1502,8 +1530,8 @@ mod tests { fn recovery_with_incorrect_diversifier() { let mut rng = OsRng; let heights = [ - Network::SAPLING_ACTIVATION_HEIGHT, - Network::CANOPY_ACTIVATION_HEIGHT, + TestNetwork::SAPLING_ACTIVATION_HEIGHT, + TestNetwork::CANOPY_ACTIVATION_HEIGHT, ]; for &height in heights.iter() { @@ -1520,7 +1548,7 @@ mod tests { |pt| pt[1..12].copy_from_slice(&find_valid_diversifier().0), ); assert_eq!( - try_sapling_output_recovery::( + try_sapling_output_recovery::( height, &ovk, &cv, @@ -1538,8 +1566,8 @@ mod tests { fn recovery_with_invalid_pk_d() { let mut rng = OsRng; let heights = [ - Network::SAPLING_ACTIVATION_HEIGHT, - Network::CANOPY_ACTIVATION_HEIGHT, + TestNetwork::SAPLING_ACTIVATION_HEIGHT, + TestNetwork::CANOPY_ACTIVATION_HEIGHT, ]; for &height in heights.iter() { @@ -1548,7 +1576,7 @@ mod tests { random_enc_ciphertext_with(height, ivk, &mut rng); assert_eq!( - try_sapling_output_recovery::( + try_sapling_output_recovery::( height, &ovk, &cv, @@ -1584,7 +1612,7 @@ mod tests { }; } - let height = Network::activation_height(NetworkUpgrade::Sapling) + let height = TestNetwork::activation_height(NetworkUpgrade::Sapling) .expect("Should have Sapling activation height"); for tv in test_vectors { @@ -1633,7 +1661,7 @@ mod tests { // (Tested first because it only requires immutable references.) // - match try_sapling_note_decryption::(height, &ivk, &epk, &cmu, &tv.c_enc) { + match try_sapling_note_decryption::(height, &ivk, &epk, &cmu, &tv.c_enc) { Some((decrypted_note, decrypted_to, decrypted_memo)) => { assert_eq!(decrypted_note, note); assert_eq!(decrypted_to, to); @@ -1642,7 +1670,7 @@ mod tests { None => panic!("Note decryption failed"), } - match try_sapling_compact_note_decryption::( + match try_sapling_compact_note_decryption::( height, &ivk, &epk, @@ -1656,7 +1684,7 @@ mod tests { None => panic!("Compact note decryption failed"), } - match try_sapling_output_recovery::( + match try_sapling_output_recovery::( height, &ovk, &cv, &cmu, &epk, &tv.c_enc, &tv.c_out, ) { Some((decrypted_note, decrypted_to, decrypted_memo)) => { From 44f46e50ce05a5c9fcc78a4f2129fccad13f4247 Mon Sep 17 00:00:00 2001 From: therealyingtong Date: Thu, 6 Aug 2020 11:36:02 +0800 Subject: [PATCH 18/31] Add type parameter to Builder struct --- zcash_client_sqlite/src/transact.rs | 4 +- zcash_primitives/src/transaction/builder.rs | 81 +++++++++++++-------- 2 files changed, 52 insertions(+), 33 deletions(-) diff --git a/zcash_client_sqlite/src/transact.rs b/zcash_client_sqlite/src/transact.rs index 0ad359701..18a850073 100644 --- a/zcash_client_sqlite/src/transact.rs +++ b/zcash_client_sqlite/src/transact.rs @@ -286,7 +286,7 @@ pub fn create_to_address>( } // Create the transaction - let mut builder = Builder::new(height); + let mut builder = Builder::::new(height); for selected in notes { builder.add_sapling_spend( extsk.clone(), @@ -297,7 +297,7 @@ pub fn create_to_address>( } match to { RecipientAddress::Shielded(to) => { - builder.add_sapling_output::(ovk, to.clone(), value, memo.clone()) + builder.add_sapling_output(ovk, to.clone(), value, memo.clone()) } RecipientAddress::Transparent(to) => builder.add_transparent_output(&to, value), }?; diff --git a/zcash_primitives/src/transaction/builder.rs b/zcash_primitives/src/transaction/builder.rs index ba5a9e4d9..8497fea81 100644 --- a/zcash_primitives/src/transaction/builder.rs +++ b/zcash_primitives/src/transaction/builder.rs @@ -3,17 +3,18 @@ use crate::zip32::ExtendedSpendingKey; use crate::{ jubjub::fs::Fs, - primitives::{Diversifier, Note, PaymentAddress, Rseed}, + primitives::{Diversifier, Note, PaymentAddress}, }; use ff::Field; use pairing::bls12_381::{Bls12, Fr}; use rand::{rngs::OsRng, seq::SliceRandom, CryptoRng, RngCore}; use std::error; use std::fmt; +use std::marker::PhantomData; use crate::{ consensus, - consensus::{NetworkUpgrade, Parameters}, + consensus::{MainNetwork, NetworkUpgrade, TestNetwork}, keys::OutgoingViewingKey, legacy::TransparentAddress, merkle_tree::MerklePath, @@ -26,7 +27,7 @@ use crate::{ signature_hash_data, Transaction, TransactionData, SIGHASH_ALL, }, util::generate_random_rseed, - Network, JUBJUB, + JUBJUB, }; #[cfg(feature = "transparent-inputs")] @@ -305,7 +306,7 @@ impl TransactionMetadata { } /// Generates a [`Transaction`] from its inputs and outputs. -pub struct Builder { +pub struct Builder { rng: R, height: u32, mtx: TransactionData, @@ -315,9 +316,10 @@ pub struct Builder { outputs: Vec, transparent_inputs: TransparentInputs, change_address: Option<(OutgoingViewingKey, PaymentAddress)>, + phantom: PhantomData

, } -impl Builder { +impl Builder { /// Creates a new `Builder` targeted for inclusion in the block with the given height, /// using default values for general transaction fields and the default OS random. /// @@ -332,7 +334,22 @@ impl Builder { } } -impl Builder { +impl Builder { + /// Creates a new `Builder` targeted for inclusion in the block with the given height, + /// using default values for general transaction fields and the default OS random. + /// + /// # Default values + /// + /// The expiry height will be set to the given height plus the default transaction + /// expiry delta (20 blocks). + /// + /// The fee will be set to the default fee (0.0001 ZEC). + pub fn new(height: u32) -> Self { + Builder::new_with_rng(height, OsRng) + } +} + +impl Builder { /// Creates a new `Builder` targeted for inclusion in the block with the given height /// and randomness source, using default values for general transaction fields. /// @@ -342,7 +359,7 @@ impl Builder { /// expiry delta (20 blocks). /// /// The fee will be set to the default fee (0.0001 ZEC). - pub fn new_with_rng(height: u32, rng: R) -> Builder { + pub fn new_with_rng(height: u32, rng: R) -> Builder { let mut mtx = TransactionData::new(); mtx.expiry_height = height + DEFAULT_TX_EXPIRY_DELTA; @@ -356,6 +373,7 @@ impl Builder { outputs: vec![], transparent_inputs: TransparentInputs::default(), change_address: None, + phantom: PhantomData, } } @@ -397,7 +415,7 @@ impl Builder { } /// Adds a Sapling address to send funds to. - pub fn add_sapling_output( + pub fn add_sapling_output( &mut self, ovk: OutgoingViewingKey, to: PaymentAddress, @@ -504,7 +522,7 @@ impl Builder { return Err(Error::NoChangeAddress); }; - self.add_sapling_output::(change_address.0, change_address.1, change, None)?; + self.add_sapling_output(change_address.0, change_address.1, change, None)?; } // @@ -615,13 +633,11 @@ impl Builder { } }; - let rseed = if self.height >= Network::CANOPY_ACTIVATION_HEIGHT { - let mut buffer = [0u8; 32]; - &mut self.rng.fill_bytes(&mut buffer); - Rseed::AfterZip212(buffer) - } else { - Rseed::BeforeZip212(Fs::random(&mut self.rng)) - }; + let rseed = generate_random_rseed::( + NetworkUpgrade::Canopy, + self.height, + &mut self.rng, + ); ( payment_address, @@ -714,12 +730,14 @@ impl Builder { mod tests { use ff::{Field, PrimeField}; use rand_core::OsRng; + use std::marker::PhantomData; use crate::jubjub::fs::Fs; use super::{Builder, Error}; use crate::{ consensus, + consensus::TestNetwork, legacy::TransparentAddress, merkle_tree::{CommitmentTree, IncrementalWitness}, primitives::Rseed, @@ -727,7 +745,7 @@ mod tests { sapling::Node, transaction::components::Amount, zip32::{ExtendedFullViewingKey, ExtendedSpendingKey}, - Network, JUBJUB, + JUBJUB, }; #[test] @@ -737,9 +755,9 @@ mod tests { let ovk = extfvk.fvk.ovk; let to = extfvk.default_address().unwrap().1; - let mut builder = Builder::new(0); + let mut builder = Builder::::new(0); assert_eq!( - builder.add_sapling_output::(ovk, to, Amount::from_i64(-1).unwrap(), None), + builder.add_sapling_output(ovk, to, Amount::from_i64(-1).unwrap(), None), Err(Error::InvalidAmount) ); } @@ -753,10 +771,10 @@ mod tests { }; let sapling_activation_height = - Network::activation_height(NetworkUpgrade::Sapling).unwrap(); + TestNetwork::activation_height(NetworkUpgrade::Sapling).unwrap(); // Create a builder with 0 fee, so we can construct t outputs - let mut builder = builder::Builder { + let mut builder = builder::Builder:: { rng: OsRng, height: sapling_activation_height, mtx: TransactionData::new(), @@ -766,6 +784,7 @@ mod tests { outputs: vec![], transparent_inputs: TransparentInputs::default(), change_address: None, + phantom: PhantomData, }; // Create a tx with only t output. No binding_sig should be present @@ -796,7 +815,7 @@ mod tests { tree.append(cm1).unwrap(); let witness1 = IncrementalWitness::from_tree(&tree); - let mut builder = Builder::new(0); + let mut builder = Builder::::new(0); // Create a tx with a sapling spend. binding_sig should be present builder @@ -822,7 +841,7 @@ mod tests { #[test] fn fails_on_negative_transparent_output() { - let mut builder = Builder::new(0); + let mut builder = Builder::::new(0); assert_eq!( builder.add_transparent_output( &TransparentAddress::PublicKey([0; 20]), @@ -842,7 +861,7 @@ mod tests { // Fails with no inputs or outputs // 0.0001 t-ZEC fee { - let builder = Builder::new(0); + let builder = Builder::::new(0); assert_eq!( builder.build(consensus::BranchId::Sapling, &MockTxProver), Err(Error::ChangeIsNegative(Amount::from_i64(-10000).unwrap())) @@ -856,9 +875,9 @@ mod tests { // Fail if there is only a Sapling output // 0.0005 z-ZEC out, 0.0001 t-ZEC fee { - let mut builder = Builder::new(0); + let mut builder = Builder::::new(0); builder - .add_sapling_output::( + .add_sapling_output( ovk.clone(), to.clone(), Amount::from_u64(50000).unwrap(), @@ -874,7 +893,7 @@ mod tests { // Fail if there is only a transparent output // 0.0005 t-ZEC out, 0.0001 t-ZEC fee { - let mut builder = Builder::new(0); + let mut builder = Builder::::new(0); builder .add_transparent_output( &TransparentAddress::PublicKey([0; 20]), @@ -898,7 +917,7 @@ mod tests { // Fail if there is insufficient input // 0.0003 z-ZEC out, 0.0002 t-ZEC out, 0.0001 t-ZEC fee, 0.00059999 z-ZEC in { - let mut builder = Builder::new(0); + let mut builder = Builder::::new(0); builder .add_sapling_spend( extsk.clone(), @@ -908,7 +927,7 @@ mod tests { ) .unwrap(); builder - .add_sapling_output::( + .add_sapling_output( ovk.clone(), to.clone(), Amount::from_u64(30000).unwrap(), @@ -941,7 +960,7 @@ mod tests { // (Still fails because we are using a MockTxProver which doesn't correctly // compute bindingSig.) { - let mut builder = Builder::new(0); + let mut builder = Builder::::new(0); builder .add_sapling_spend( extsk.clone(), @@ -954,7 +973,7 @@ mod tests { .add_sapling_spend(extsk, *to.diversifier(), note2, witness2.path().unwrap()) .unwrap(); builder - .add_sapling_output::(ovk, to, Amount::from_u64(30000).unwrap(), None) + .add_sapling_output(ovk, to, Amount::from_u64(30000).unwrap(), None) .unwrap(); builder .add_transparent_output( From b05e257f79f878b0ea1dbd4c412c6d964f3d116a Mon Sep 17 00:00:00 2001 From: therealyingtong Date: Thu, 6 Aug 2020 12:00:49 +0800 Subject: [PATCH 19/31] Fix database queries in scan.rs and transact.rs --- zcash_client_sqlite/src/scan.rs | 24 +++++++++++++---------- zcash_client_sqlite/src/transact.rs | 30 +++++++++++++++-------------- 2 files changed, 30 insertions(+), 24 deletions(-) diff --git a/zcash_client_sqlite/src/scan.rs b/zcash_client_sqlite/src/scan.rs index d22a48662..a32df41e6 100644 --- a/zcash_client_sqlite/src/scan.rs +++ b/zcash_client_sqlite/src/scan.rs @@ -2,7 +2,7 @@ use ff::PrimeField; use protobuf::parse_from_bytes; -use rusqlite::{types::ToSql, Connection, NO_PARAMS}; +use rusqlite::{types::ToSql, Connection, OptionalExtension, NO_PARAMS}; use std::path::Path; use zcash_client_backend::{ decrypt_transaction, encoding::decode_extended_full_viewing_key, @@ -374,15 +374,19 @@ pub fn decrypt_and_store_transaction>( // Height is block height for mined transactions, and the "mempool height" (chain height + 1) for mempool transactions. let mut stmt_select_block = data.prepare("SELECT block FROM transactions WHERE txid = ?")?; - let height = stmt_select_block.query_row(&[tx.txid().0.to_vec()], |row| { - row.get(0).or({ - let last_height = - data.query_row("SELECT MAX(height) FROM blocks", NO_PARAMS, |row| { - row.get(0).or(Ok(SAPLING_ACTIVATION_HEIGHT - 1)) - })?; - Ok(last_height + 1) - }) - })?; + let height = match stmt_select_block + .query_row(&[tx.txid().0.to_vec()], |row| row.get(0)) + .optional()? + { + Some(height) => height, + None => data + .query_row("SELECT MAX(height) FROM blocks", NO_PARAMS, |row| { + row.get(0) + }) + .optional()? + .map(|last_height: u32| last_height + 1) + .unwrap_or(SAPLING_ACTIVATION_HEIGHT as u32), + }; let outputs = decrypt_transaction::(height as u32, tx, &extfvks); diff --git a/zcash_client_sqlite/src/transact.rs b/zcash_client_sqlite/src/transact.rs index 18a850073..9df019bab 100644 --- a/zcash_client_sqlite/src/transact.rs +++ b/zcash_client_sqlite/src/transact.rs @@ -9,7 +9,7 @@ use std::path::Path; use zcash_client_backend::encoding::encode_extended_full_viewing_key; use zcash_primitives::{ consensus, - consensus::Parameters, + consensus::{NetworkUpgrade, Parameters}, jubjub::fs::{Fs, FsRepr}, keys::OutgoingViewingKey, merkle_tree::{IncrementalWitness, MerklePath}, @@ -235,20 +235,22 @@ pub fn create_to_address>( let note_value: i64 = row.get(1)?; - let d: Vec<_> = row.get(2)?; + let rseed = { + let d: Vec<_> = row.get(2)?; - let rseed = if height >= Network::CANOPY_ACTIVATION_HEIGHT { - let mut r = [0u8; 32]; - r.copy_from_slice(&d[..]); - Rseed::AfterZip212(r) - } else { - let tmp = FsRepr( - d[..] - .try_into() - .map_err(|_| Error(ErrorKind::InvalidNote))?, - ); - let r = Fs::from_repr(tmp).ok_or(Error(ErrorKind::InvalidNote))?; - Rseed::BeforeZip212(r) + if Network::is_nu_active(NetworkUpgrade::Canopy, height) { + let mut r = [0u8; 32]; + r.copy_from_slice(&d[..]); + Rseed::AfterZip212(r) + } else { + let tmp = FsRepr( + d[..] + .try_into() + .map_err(|_| Error(ErrorKind::InvalidNote))?, + ); + let r = Fs::from_repr(tmp).ok_or(Error(ErrorKind::InvalidNote))?; + Rseed::BeforeZip212(r) + } }; let from = extfvk From 9970a8aefde5eecc3ea3d858cf909d82fecb65d8 Mon Sep 17 00:00:00 2001 From: therealyingtong Date: Thu, 6 Aug 2020 12:06:09 +0800 Subject: [PATCH 20/31] Hard-code NetworkUpgrade::Canopy in generate_random_rseed --- zcash_client_backend/src/welding_rig.rs | 8 ++------ zcash_client_sqlite/src/lib.rs | 19 +++---------------- zcash_primitives/src/note_encryption.rs | 3 +-- zcash_primitives/src/transaction/builder.rs | 10 +++------- zcash_primitives/src/util.rs | 3 +-- 5 files changed, 10 insertions(+), 33 deletions(-) diff --git a/zcash_client_backend/src/welding_rig.rs b/zcash_client_backend/src/welding_rig.rs index c07001cdc..fcb9c7a09 100644 --- a/zcash_client_backend/src/welding_rig.rs +++ b/zcash_client_backend/src/welding_rig.rs @@ -191,7 +191,7 @@ mod tests { use pairing::bls12_381::{Bls12, Fr}; use rand_core::{OsRng, RngCore}; use zcash_primitives::{ - consensus::{NetworkUpgrade, TestNetwork}, + consensus::{TestNetwork}, jubjub::{fs::Fs, FixedGenerators, JubjubParams, ToUniform}, merkle_tree::CommitmentTree, note_encryption::{Memo, SaplingNoteEncryption}, @@ -255,11 +255,7 @@ mod tests { // Create a fake Note for the account let mut rng = OsRng; - let rseed = generate_random_rseed::( - NetworkUpgrade::Canopy, - height as u32, - &mut rng, - ); + let rseed = generate_random_rseed::(height as u32, &mut rng); let note = Note { g_d: to.diversifier().g_d::(&JUBJUB).unwrap(), pk_d: to.pk_d().clone(), diff --git a/zcash_client_sqlite/src/lib.rs b/zcash_client_sqlite/src/lib.rs index 533a25809..655ae89e9 100644 --- a/zcash_client_sqlite/src/lib.rs +++ b/zcash_client_sqlite/src/lib.rs @@ -106,7 +106,6 @@ mod tests { }; use zcash_primitives::{ block::BlockHash, - consensus::NetworkUpgrade, note_encryption::{Memo, SaplingNoteEncryption}, primitives::{Note, PaymentAddress}, transaction::components::Amount, @@ -127,11 +126,7 @@ mod tests { // Create a fake Note for the account let mut rng = OsRng; - let rseed = generate_random_rseed::( - NetworkUpgrade::Canopy, - height as u32, - &mut rng, - ); + let rseed = generate_random_rseed::(height as u32, &mut rng); let note = Note { g_d: to.diversifier().g_d::(&JUBJUB).unwrap(), pk_d: to.pk_d().clone(), @@ -181,11 +176,7 @@ mod tests { value: Amount, ) -> CompactBlock { let mut rng = OsRng; - let rseed = generate_random_rseed::( - NetworkUpgrade::Canopy, - height as u32, - &mut rng, - ); + let rseed = generate_random_rseed::(height as u32, &mut rng); // Create a fake CompactBlock containing the note let mut cspend = CompactSpend::new(); @@ -222,11 +213,7 @@ mod tests { // Create a fake Note for the change ctx.outputs.push({ let change_addr = extfvk.default_address().unwrap().1; - let rseed = generate_random_rseed::( - NetworkUpgrade::Canopy, - height as u32, - &mut rng, - ); + let rseed = generate_random_rseed::(height as u32, &mut rng); let note = Note { g_d: change_addr.diversifier().g_d::(&JUBJUB).unwrap(), pk_d: change_addr.pk_d().clone(), diff --git a/zcash_primitives/src/note_encryption.rs b/zcash_primitives/src/note_encryption.rs index e85daaede..5d91321ad 100644 --- a/zcash_primitives/src/note_encryption.rs +++ b/zcash_primitives/src/note_encryption.rs @@ -799,8 +799,7 @@ mod tests { }; let cv = value_commitment.cm(&JUBJUB).into(); - let rseed = - generate_random_rseed::(NetworkUpgrade::Canopy, height, &mut rng); + let rseed = generate_random_rseed::(height, &mut rng); let note = pa.create_note(value, rseed, &JUBJUB).unwrap(); let cmu = note.cm(&JUBJUB); diff --git a/zcash_primitives/src/transaction/builder.rs b/zcash_primitives/src/transaction/builder.rs index 8497fea81..9ace40656 100644 --- a/zcash_primitives/src/transaction/builder.rs +++ b/zcash_primitives/src/transaction/builder.rs @@ -14,7 +14,7 @@ use std::marker::PhantomData; use crate::{ consensus, - consensus::{MainNetwork, NetworkUpgrade, TestNetwork}, + consensus::{MainNetwork, TestNetwork}, keys::OutgoingViewingKey, legacy::TransparentAddress, merkle_tree::MerklePath, @@ -105,7 +105,7 @@ impl SaplingOutput { return Err(Error::InvalidAmount); } - let rseed = generate_random_rseed::(NetworkUpgrade::Canopy, height, rng); + let rseed = generate_random_rseed::(height, rng); let note = Note { g_d, @@ -633,11 +633,7 @@ impl Builder { } }; - let rseed = generate_random_rseed::( - NetworkUpgrade::Canopy, - self.height, - &mut self.rng, - ); + let rseed = generate_random_rseed::(self.height, &mut self.rng); ( payment_address, diff --git a/zcash_primitives/src/util.rs b/zcash_primitives/src/util.rs index 65d3418a4..4edfbc759 100644 --- a/zcash_primitives/src/util.rs +++ b/zcash_primitives/src/util.rs @@ -18,11 +18,10 @@ pub fn hash_to_scalar(persona: &[u8], a: &[u8], b: &[u8]) -> E: } pub fn generate_random_rseed( - nu: NetworkUpgrade, height: u32, rng: &mut R, ) -> Rseed { - if P::is_nu_active(nu, height) { + if P::is_nu_active(NetworkUpgrade::Canopy, height) { let mut buffer = [0u8; 32]; &rng.fill_bytes(&mut buffer); Rseed::AfterZip212(buffer) From 4f22077cf6adf8df42ec9e78fbb6f1335c7cc3af Mon Sep 17 00:00:00 2001 From: therealyingtong Date: Thu, 6 Aug 2020 12:30:48 +0800 Subject: [PATCH 21/31] Remove const activation heights from consensus.rs --- zcash_client_backend/src/welding_rig.rs | 2 +- zcash_primitives/src/consensus.rs | 22 +---- zcash_primitives/src/note_encryption.rs | 107 +++++++++++++----------- 3 files changed, 60 insertions(+), 71 deletions(-) diff --git a/zcash_client_backend/src/welding_rig.rs b/zcash_client_backend/src/welding_rig.rs index fcb9c7a09..b37ee13f0 100644 --- a/zcash_client_backend/src/welding_rig.rs +++ b/zcash_client_backend/src/welding_rig.rs @@ -191,7 +191,7 @@ mod tests { use pairing::bls12_381::{Bls12, Fr}; use rand_core::{OsRng, RngCore}; use zcash_primitives::{ - consensus::{TestNetwork}, + consensus::TestNetwork, jubjub::{fs::Fs, FixedGenerators, JubjubParams, ToUniform}, merkle_tree::CommitmentTree, note_encryption::{Memo, SaplingNoteEncryption}, diff --git a/zcash_primitives/src/consensus.rs b/zcash_primitives/src/consensus.rs index 7020bae6e..4cc67f49b 100644 --- a/zcash_primitives/src/consensus.rs +++ b/zcash_primitives/src/consensus.rs @@ -13,12 +13,6 @@ pub trait Parameters { _ => false, } } - - const OVERWINTER_ACTIVATION_HEIGHT: u32; - const SAPLING_ACTIVATION_HEIGHT: u32; - const BLOSSOM_ACTIVATION_HEIGHT: u32; - const HEARTWOOD_ACTIVATION_HEIGHT: u32; - const CANOPY_ACTIVATION_HEIGHT: u32; } /// Marker struct for the production network. @@ -35,12 +29,6 @@ impl Parameters for MainNetwork { NetworkUpgrade::Canopy => Some(1_046_400), } } - - const OVERWINTER_ACTIVATION_HEIGHT: u32 = 347_500; - const SAPLING_ACTIVATION_HEIGHT: u32 = 419_200; - const BLOSSOM_ACTIVATION_HEIGHT: u32 = 653_600; - const HEARTWOOD_ACTIVATION_HEIGHT: u32 = 903_000; - const CANOPY_ACTIVATION_HEIGHT: u32 = 1_046_400; } /// Marker struct for the test network. @@ -57,12 +45,6 @@ impl Parameters for TestNetwork { NetworkUpgrade::Canopy => Some(1_028_500), } } - - const OVERWINTER_ACTIVATION_HEIGHT: u32 = 207_500; - const SAPLING_ACTIVATION_HEIGHT: u32 = 280_200; - const BLOSSOM_ACTIVATION_HEIGHT: u32 = 584_000; - const HEARTWOOD_ACTIVATION_HEIGHT: u32 = 903_800; - const CANOPY_ACTIVATION_HEIGHT: u32 = 1_028_500; } /// An event that occurs at a specified height on the Zcash chain, at which point the @@ -208,10 +190,10 @@ impl BranchId { #[cfg(test)] mod tests { - use super::{BranchId, MainNetwork, NetworkUpgrade, UPGRADES_IN_ORDER}; - use crate::consensus::Parameters; use std::convert::TryFrom; + use super::{BranchId, MainNetwork, NetworkUpgrade, Parameters, UPGRADES_IN_ORDER}; + #[test] fn nu_ordering() { for i in 1..UPGRADES_IN_ORDER.len() { diff --git a/zcash_primitives/src/note_encryption.rs b/zcash_primitives/src/note_encryption.rs index 5d91321ad..7a94fc66a 100644 --- a/zcash_primitives/src/note_encryption.rs +++ b/zcash_primitives/src/note_encryption.rs @@ -586,7 +586,11 @@ pub fn try_sapling_output_recovery( #[cfg(test)] mod tests { use crate::{ - consensus::{NetworkUpgrade, Parameters, TestNetwork, ZIP212_GRACE_PERIOD}, + consensus::{ + NetworkUpgrade, + NetworkUpgrade::{Canopy, Sapling}, + Parameters, TestNetwork, ZIP212_GRACE_PERIOD, + }, jubjub::{ edwards, fs::{Fs, FsRepr}, @@ -912,8 +916,8 @@ mod tests { fn decryption_with_invalid_ivk() { let mut rng = OsRng; let heights = [ - TestNetwork::SAPLING_ACTIVATION_HEIGHT, - TestNetwork::CANOPY_ACTIVATION_HEIGHT, + TestNetwork::activation_height(Sapling).unwrap(), + TestNetwork::activation_height(Canopy).unwrap(), ]; for &height in heights.iter() { @@ -936,8 +940,8 @@ mod tests { fn decryption_with_invalid_epk() { let mut rng = OsRng; let heights = [ - TestNetwork::SAPLING_ACTIVATION_HEIGHT, - TestNetwork::CANOPY_ACTIVATION_HEIGHT, + TestNetwork::activation_height(Sapling).unwrap(), + TestNetwork::activation_height(Canopy).unwrap(), ]; for &height in heights.iter() { @@ -960,8 +964,8 @@ mod tests { fn decryption_with_invalid_cmu() { let mut rng = OsRng; let heights = [ - TestNetwork::SAPLING_ACTIVATION_HEIGHT, - TestNetwork::CANOPY_ACTIVATION_HEIGHT, + TestNetwork::activation_height(Sapling).unwrap(), + TestNetwork::activation_height(Canopy).unwrap(), ]; for &height in heights.iter() { @@ -984,8 +988,8 @@ mod tests { fn decryption_with_invalid_tag() { let mut rng = OsRng; let heights = [ - TestNetwork::SAPLING_ACTIVATION_HEIGHT, - TestNetwork::CANOPY_ACTIVATION_HEIGHT, + TestNetwork::activation_height(Sapling).unwrap(), + TestNetwork::activation_height(Canopy).unwrap(), ]; for &height in heights.iter() { @@ -1009,10 +1013,11 @@ mod tests { #[test] fn decryption_with_invalid_version_byte() { let mut rng = OsRng; + let canopy_activation_height = TestNetwork::activation_height(Canopy).unwrap(); let heights = [ - TestNetwork::CANOPY_ACTIVATION_HEIGHT - 1, - TestNetwork::CANOPY_ACTIVATION_HEIGHT, - TestNetwork::CANOPY_ACTIVATION_HEIGHT + ZIP212_GRACE_PERIOD, + canopy_activation_height - 1, + canopy_activation_height, + canopy_activation_height + ZIP212_GRACE_PERIOD, ]; let leadbyte_array = [0x02, 0x03, 0x01]; @@ -1046,8 +1051,8 @@ mod tests { fn decryption_with_invalid_diversifier() { let mut rng = OsRng; let heights = [ - TestNetwork::SAPLING_ACTIVATION_HEIGHT, - TestNetwork::CANOPY_ACTIVATION_HEIGHT, + TestNetwork::activation_height(Sapling).unwrap(), + TestNetwork::activation_height(Canopy).unwrap(), ]; for &height in heights.iter() { @@ -1080,8 +1085,8 @@ mod tests { fn decryption_with_incorrect_diversifier() { let mut rng = OsRng; let heights = [ - TestNetwork::SAPLING_ACTIVATION_HEIGHT, - TestNetwork::CANOPY_ACTIVATION_HEIGHT, + TestNetwork::activation_height(Sapling).unwrap(), + TestNetwork::activation_height(Canopy).unwrap(), ]; for &height in heights.iter() { @@ -1114,8 +1119,8 @@ mod tests { fn compact_decryption_with_invalid_ivk() { let mut rng = OsRng; let heights = [ - TestNetwork::SAPLING_ACTIVATION_HEIGHT, - TestNetwork::CANOPY_ACTIVATION_HEIGHT, + TestNetwork::activation_height(Sapling).unwrap(), + TestNetwork::activation_height(Canopy).unwrap(), ]; for &height in heights.iter() { @@ -1138,8 +1143,8 @@ mod tests { fn compact_decryption_with_invalid_epk() { let mut rng = OsRng; let heights = [ - TestNetwork::SAPLING_ACTIVATION_HEIGHT, - TestNetwork::CANOPY_ACTIVATION_HEIGHT, + TestNetwork::activation_height(Sapling).unwrap(), + TestNetwork::activation_height(Canopy).unwrap(), ]; for &height in heights.iter() { @@ -1162,8 +1167,8 @@ mod tests { fn compact_decryption_with_invalid_cmu() { let mut rng = OsRng; let heights = [ - TestNetwork::SAPLING_ACTIVATION_HEIGHT, - TestNetwork::CANOPY_ACTIVATION_HEIGHT, + TestNetwork::activation_height(Sapling).unwrap(), + TestNetwork::activation_height(Canopy).unwrap(), ]; for &height in heights.iter() { @@ -1185,10 +1190,11 @@ mod tests { #[test] fn compact_decryption_with_invalid_version_byte() { let mut rng = OsRng; + let canopy_activation_height = TestNetwork::activation_height(Canopy).unwrap(); let heights = [ - TestNetwork::CANOPY_ACTIVATION_HEIGHT - 1, - TestNetwork::CANOPY_ACTIVATION_HEIGHT, - TestNetwork::CANOPY_ACTIVATION_HEIGHT + ZIP212_GRACE_PERIOD, + canopy_activation_height - 1, + canopy_activation_height, + canopy_activation_height + ZIP212_GRACE_PERIOD, ]; let leadbyte_array = [0x02, 0x03, 0x01]; @@ -1222,8 +1228,8 @@ mod tests { fn compact_decryption_with_invalid_diversifier() { let mut rng = OsRng; let heights = [ - TestNetwork::SAPLING_ACTIVATION_HEIGHT, - TestNetwork::CANOPY_ACTIVATION_HEIGHT, + TestNetwork::activation_height(Sapling).unwrap(), + TestNetwork::activation_height(Canopy).unwrap(), ]; for &height in heights.iter() { @@ -1256,8 +1262,8 @@ mod tests { fn compact_decryption_with_incorrect_diversifier() { let mut rng = OsRng; let heights = [ - TestNetwork::SAPLING_ACTIVATION_HEIGHT, - TestNetwork::CANOPY_ACTIVATION_HEIGHT, + TestNetwork::activation_height(Sapling).unwrap(), + TestNetwork::activation_height(Canopy).unwrap(), ]; for &height in heights.iter() { @@ -1290,8 +1296,8 @@ mod tests { fn recovery_with_invalid_ovk() { let mut rng = OsRng; let heights = [ - TestNetwork::SAPLING_ACTIVATION_HEIGHT, - TestNetwork::CANOPY_ACTIVATION_HEIGHT, + TestNetwork::activation_height(Sapling).unwrap(), + TestNetwork::activation_height(Canopy).unwrap(), ]; for &height in heights.iter() { @@ -1318,8 +1324,8 @@ mod tests { fn recovery_with_invalid_cv() { let mut rng = OsRng; let heights = [ - TestNetwork::SAPLING_ACTIVATION_HEIGHT, - TestNetwork::CANOPY_ACTIVATION_HEIGHT, + TestNetwork::activation_height(Sapling).unwrap(), + TestNetwork::activation_height(Canopy).unwrap(), ]; for &height in heights.iter() { @@ -1345,8 +1351,8 @@ mod tests { fn recovery_with_invalid_cmu() { let mut rng = OsRng; let heights = [ - TestNetwork::SAPLING_ACTIVATION_HEIGHT, - TestNetwork::CANOPY_ACTIVATION_HEIGHT, + TestNetwork::activation_height(Sapling).unwrap(), + TestNetwork::activation_height(Canopy).unwrap(), ]; for &height in heights.iter() { @@ -1372,8 +1378,8 @@ mod tests { fn recovery_with_invalid_epk() { let mut rng = OsRng; let heights = [ - TestNetwork::SAPLING_ACTIVATION_HEIGHT, - TestNetwork::CANOPY_ACTIVATION_HEIGHT, + TestNetwork::activation_height(Sapling).unwrap(), + TestNetwork::activation_height(Canopy).unwrap(), ]; for &height in heights.iter() { @@ -1399,8 +1405,8 @@ mod tests { fn recovery_with_invalid_enc_tag() { let mut rng = OsRng; let heights = [ - TestNetwork::SAPLING_ACTIVATION_HEIGHT, - TestNetwork::CANOPY_ACTIVATION_HEIGHT, + TestNetwork::activation_height(Sapling).unwrap(), + TestNetwork::activation_height(Canopy).unwrap(), ]; for &height in heights.iter() { @@ -1427,8 +1433,8 @@ mod tests { fn recovery_with_invalid_out_tag() { let mut rng = OsRng; let heights = [ - TestNetwork::SAPLING_ACTIVATION_HEIGHT, - TestNetwork::CANOPY_ACTIVATION_HEIGHT, + TestNetwork::activation_height(Sapling).unwrap(), + TestNetwork::activation_height(Canopy).unwrap(), ]; for &height in heights.iter() { @@ -1454,10 +1460,11 @@ mod tests { #[test] fn recovery_with_invalid_version_byte() { let mut rng = OsRng; + let canopy_activation_height = TestNetwork::activation_height(Canopy).unwrap(); let heights = [ - TestNetwork::CANOPY_ACTIVATION_HEIGHT - 1, - TestNetwork::CANOPY_ACTIVATION_HEIGHT, - TestNetwork::CANOPY_ACTIVATION_HEIGHT + ZIP212_GRACE_PERIOD, + canopy_activation_height - 1, + canopy_activation_height, + canopy_activation_height + ZIP212_GRACE_PERIOD, ]; let leadbyte_array = [0x02, 0x03, 0x01]; @@ -1493,8 +1500,8 @@ mod tests { fn recovery_with_invalid_diversifier() { let mut rng = OsRng; let heights = [ - TestNetwork::SAPLING_ACTIVATION_HEIGHT, - TestNetwork::CANOPY_ACTIVATION_HEIGHT, + TestNetwork::activation_height(Sapling).unwrap(), + TestNetwork::activation_height(Canopy).unwrap(), ]; for &height in heights.iter() { @@ -1529,8 +1536,8 @@ mod tests { fn recovery_with_incorrect_diversifier() { let mut rng = OsRng; let heights = [ - TestNetwork::SAPLING_ACTIVATION_HEIGHT, - TestNetwork::CANOPY_ACTIVATION_HEIGHT, + TestNetwork::activation_height(Sapling).unwrap(), + TestNetwork::activation_height(Canopy).unwrap(), ]; for &height in heights.iter() { @@ -1565,8 +1572,8 @@ mod tests { fn recovery_with_invalid_pk_d() { let mut rng = OsRng; let heights = [ - TestNetwork::SAPLING_ACTIVATION_HEIGHT, - TestNetwork::CANOPY_ACTIVATION_HEIGHT, + TestNetwork::activation_height(Sapling).unwrap(), + TestNetwork::activation_height(Canopy).unwrap(), ]; for &height in heights.iter() { From c3d89644e2ba8445be66f57bfb62c11151f4ad95 Mon Sep 17 00:00:00 2001 From: therealyingtong Date: Thu, 6 Aug 2020 12:47:35 +0800 Subject: [PATCH 22/31] Revert SaplingNoteEncryption::new() API to take rng instead of esk --- zcash_client_backend/src/welding_rig.rs | 3 +-- zcash_client_sqlite/src/lib.rs | 16 +++++++++------- zcash_primitives/src/note_encryption.rs | 16 +++++++--------- zcash_primitives/src/transaction/builder.rs | 2 +- 4 files changed, 18 insertions(+), 19 deletions(-) diff --git a/zcash_client_backend/src/welding_rig.rs b/zcash_client_backend/src/welding_rig.rs index b37ee13f0..fd7503153 100644 --- a/zcash_client_backend/src/welding_rig.rs +++ b/zcash_client_backend/src/welding_rig.rs @@ -262,13 +262,12 @@ mod tests { value: value.into(), rseed, }; - let esk = note.generate_or_derive_esk(&mut rng); let encryptor = SaplingNoteEncryption::new( extfvk.fvk.ovk, note.clone(), to.clone(), Memo::default(), - esk, + &mut rng, ); let cmu = note.cm(&JUBJUB).to_repr().as_ref().to_owned(); let mut epk = vec![]; diff --git a/zcash_client_sqlite/src/lib.rs b/zcash_client_sqlite/src/lib.rs index 655ae89e9..4eb6dcf49 100644 --- a/zcash_client_sqlite/src/lib.rs +++ b/zcash_client_sqlite/src/lib.rs @@ -133,13 +133,12 @@ mod tests { value: value.into(), rseed, }; - let esk = note.generate_or_derive_esk(&mut rng); let encryptor = SaplingNoteEncryption::new( extfvk.fvk.ovk, note.clone(), to.clone(), Memo::default(), - esk, + &mut rng, ); let cmu = note.cm(&JUBJUB).to_repr().as_ref().to_vec(); let mut epk = vec![]; @@ -195,9 +194,13 @@ mod tests { value: value.into(), rseed, }; - let esk = note.generate_or_derive_esk(&mut rng); - let encryptor = - SaplingNoteEncryption::new(extfvk.fvk.ovk, note.clone(), to, Memo::default(), esk); + let encryptor = SaplingNoteEncryption::new( + extfvk.fvk.ovk, + note.clone(), + to, + Memo::default(), + &mut rng, + ); let cmu = note.cm(&JUBJUB).to_repr().as_ref().to_vec(); let mut epk = vec![]; encryptor.epk().write(&mut epk).unwrap(); @@ -220,13 +223,12 @@ mod tests { value: (in_value - value).into(), rseed, }; - let esk = note.generate_or_derive_esk(&mut rng); let encryptor = SaplingNoteEncryption::new( extfvk.fvk.ovk, note.clone(), change_addr, Memo::default(), - esk, + &mut rng, ); let cmu = note.cm(&JUBJUB).to_repr().as_ref().to_vec(); let mut epk = vec![]; diff --git a/zcash_primitives/src/note_encryption.rs b/zcash_primitives/src/note_encryption.rs index 7a94fc66a..ee0f99666 100644 --- a/zcash_primitives/src/note_encryption.rs +++ b/zcash_primitives/src/note_encryption.rs @@ -15,6 +15,7 @@ use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; use crypto_api_chachapoly::{ChaCha20Ietf, ChachaPolyIetf}; use ff::PrimeField; use pairing::bls12_381::{Bls12, Fr}; +use rand_core::{CryptoRng, RngCore}; use std::convert::TryInto; use std::fmt; use std::str; @@ -236,8 +237,7 @@ fn prf_ock( /// let note = to.create_note(value, Rseed::BeforeZip212(rcm), &JUBJUB).unwrap(); /// let cmu = note.cm(&JUBJUB); /// -/// let esk = note.generate_or_derive_esk(&mut rng); -/// let enc = SaplingNoteEncryption::new(ovk, note, to, Memo::default(), esk); +/// let enc = SaplingNoteEncryption::new(ovk, note, to, Memo::default(), &mut rng); /// let encCiphertext = enc.encrypt_note_plaintext(); /// let outCiphertext = enc.encrypt_outgoing_plaintext(&cv.cm(&JUBJUB).into(), &cmu); /// ``` @@ -252,13 +252,14 @@ pub struct SaplingNoteEncryption { impl SaplingNoteEncryption { /// Creates a new encryption context for the given note. - pub fn new( + pub fn new( ovk: OutgoingViewingKey, note: Note, to: PaymentAddress, memo: Memo, - esk: Fs, + rng: &mut R, ) -> SaplingNoteEncryption { + let esk = note.generate_or_derive_esk(rng); let epk = note.g_d.mul(esk, &JUBJUB); SaplingNoteEncryption { @@ -809,8 +810,7 @@ mod tests { let cmu = note.cm(&JUBJUB); let ovk = OutgoingViewingKey([0; 32]); - let esk = note.generate_or_derive_esk(&mut rng); - let ne = SaplingNoteEncryption::new(ovk, note, pa, Memo([0; 512]), esk); + let ne = SaplingNoteEncryption::new(ovk, note, pa, Memo([0; 512]), &mut rng); let epk = ne.epk(); let enc_ciphertext = ne.encrypt_note_plaintext(); let out_ciphertext = ne.encrypt_outgoing_plaintext(&cv, &cmu); @@ -1705,9 +1705,7 @@ mod tests { // Test encryption // - let _esk = note.generate_or_derive_esk(&mut OsRng); - - let mut ne = SaplingNoteEncryption::new(ovk, note, to, Memo(tv.memo), _esk); + let mut ne = SaplingNoteEncryption::new(ovk, note, to, Memo(tv.memo), &mut OsRng); // Swap in the ephemeral keypair from the test vectors ne.esk = esk; ne.epk = epk; diff --git a/zcash_primitives/src/transaction/builder.rs b/zcash_primitives/src/transaction/builder.rs index 9ace40656..d17b194bd 100644 --- a/zcash_primitives/src/transaction/builder.rs +++ b/zcash_primitives/src/transaction/builder.rs @@ -133,7 +133,7 @@ impl SaplingOutput { self.note.clone(), self.to.clone(), self.memo, - self.note.generate_or_derive_esk(rng), + rng, ); let (zkproof, cv) = prover.output_proof( From 878646855c36cded6a32eb47bcb711ca000289fa Mon Sep 17 00:00:00 2001 From: therealyingtong Date: Thu, 6 Aug 2020 12:57:48 +0800 Subject: [PATCH 23/31] Switch on leadbyte instead of tx height when decrypting outputs --- zcash_primitives/src/note_encryption.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/zcash_primitives/src/note_encryption.rs b/zcash_primitives/src/note_encryption.rs index ee0f99666..6dcf25173 100644 --- a/zcash_primitives/src/note_encryption.rs +++ b/zcash_primitives/src/note_encryption.rs @@ -362,11 +362,11 @@ fn parse_note_plaintext_without_memo( let mut r = [0u8; 32]; r.copy_from_slice(&plaintext[20..COMPACT_NOTE_SIZE]); - let rseed = if P::is_nu_active(NetworkUpgrade::Canopy, height) { - Rseed::AfterZip212(r) - } else { + let rseed = if plaintext[0] == 0x01 { let rcm = Fs::from_repr(FsRepr(r.try_into().expect("slice is the correct length")))?; Rseed::BeforeZip212(rcm) + } else { + Rseed::AfterZip212(r) }; let diversifier = Diversifier(d); @@ -553,11 +553,11 @@ pub fn try_sapling_output_recovery( let mut r = [0u8; 32]; r.copy_from_slice(&plaintext[20..COMPACT_NOTE_SIZE]); - let rseed = if P::is_nu_active(NetworkUpgrade::Canopy, height) { - Rseed::AfterZip212(r) - } else { + let rseed = if plaintext[0] == 0x01 { let rcm = Fs::from_repr(FsRepr(r.try_into().expect("slice is the correct length")))?; Rseed::BeforeZip212(rcm) + } else { + Rseed::AfterZip212(r) }; let mut memo = [0u8; 512]; From 8968547981f823734c93537764d59c0732636b52 Mon Sep 17 00:00:00 2001 From: therealyingtong Date: Thu, 6 Aug 2020 13:13:49 +0800 Subject: [PATCH 24/31] Document pub enum Rseed with link to ZIP 212 --- zcash_primitives/src/primitives.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/zcash_primitives/src/primitives.rs b/zcash_primitives/src/primitives.rs index 4f635a867..1c81fc03b 100644 --- a/zcash_primitives/src/primitives.rs +++ b/zcash_primitives/src/primitives.rs @@ -223,6 +223,11 @@ impl PaymentAddress { } } +/// Enum for note randomness before and after [ZIP 212](https://zips.z.cash/zip-0212). +/// +/// Before ZIP 212, the note commitment trapdoor `rcm` must be a scalar value. +/// After ZIP 212, the note randomness `rseed` is a 32-byte sequence, used to derive +/// both the note commitment trapdoor `rcm` and the ephemeral private key `esk`. #[derive(Copy, Clone, Debug)] pub enum Rseed { BeforeZip212(Fs), From 40a908e0a8d3f5cda0768d99409807fdf8cd5863 Mon Sep 17 00:00:00 2001 From: ying tong Date: Thu, 6 Aug 2020 17:19:15 +0800 Subject: [PATCH 25/31] Refactor leadbyte_array in note_encryption tests Co-authored-by: str4d --- zcash_primitives/src/note_encryption.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/zcash_primitives/src/note_encryption.rs b/zcash_primitives/src/note_encryption.rs index 6dcf25173..eff786188 100644 --- a/zcash_primitives/src/note_encryption.rs +++ b/zcash_primitives/src/note_encryption.rs @@ -1019,9 +1019,9 @@ mod tests { canopy_activation_height, canopy_activation_height + ZIP212_GRACE_PERIOD, ]; - let leadbyte_array = [0x02, 0x03, 0x01]; + let leadbytes = [0x02, 0x03, 0x01]; - for (i, &height) in heights.iter().enumerate() { + for (_i, (&height, &leadbyte)) in heights.iter().zip(leadbytes.iter()).enumerate() { let (ovk, ivk, cv, cmu, epk, mut enc_ciphertext, out_ciphertext) = random_enc_ciphertext(height, &mut rng); @@ -1032,7 +1032,7 @@ mod tests { &epk, &mut enc_ciphertext, &out_ciphertext, - |pt| pt[0] = leadbyte_array[i], + |pt| pt[0] = leadbyte, ); assert_eq!( try_sapling_note_decryption::( @@ -1196,9 +1196,9 @@ mod tests { canopy_activation_height, canopy_activation_height + ZIP212_GRACE_PERIOD, ]; - let leadbyte_array = [0x02, 0x03, 0x01]; + let leadbytes = [0x02, 0x03, 0x01]; - for (i, &height) in heights.iter().enumerate() { + for (_i, (&height, &leadbyte)) in heights.iter().zip(leadbytes.iter()).enumerate() { let (ovk, ivk, cv, cmu, epk, mut enc_ciphertext, out_ciphertext) = random_enc_ciphertext(height, &mut rng); @@ -1209,7 +1209,7 @@ mod tests { &epk, &mut enc_ciphertext, &out_ciphertext, - |pt| pt[0] = leadbyte_array[i], + |pt| pt[0] = leadbyte, ); assert_eq!( try_sapling_compact_note_decryption::( @@ -1466,9 +1466,9 @@ mod tests { canopy_activation_height, canopy_activation_height + ZIP212_GRACE_PERIOD, ]; - let leadbyte_array = [0x02, 0x03, 0x01]; + let leadbytes = [0x02, 0x03, 0x01]; - for (i, &height) in heights.iter().enumerate() { + for (_i, (&height, &leadbyte)) in heights.iter().zip(leadbytes.iter()).enumerate() { let (ovk, _, cv, cmu, epk, mut enc_ciphertext, out_ciphertext) = random_enc_ciphertext(height, &mut rng); @@ -1479,7 +1479,7 @@ mod tests { &epk, &mut enc_ciphertext, &out_ciphertext, - |pt| pt[0] = leadbyte_array[i], + |pt| pt[0] = leadbyte, ); assert_eq!( try_sapling_output_recovery::( From 0f8f1b3f5d6c58c00dd28b96ef3e3be889a9675b Mon Sep 17 00:00:00 2001 From: ying tong Date: Thu, 6 Aug 2020 17:25:19 +0800 Subject: [PATCH 26/31] Fix parsing of rseed in parse_note_plaintext_without_memo() and try_sapling_output_recovery() Co-authored-by: str4d --- zcash_primitives/src/note_encryption.rs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/zcash_primitives/src/note_encryption.rs b/zcash_primitives/src/note_encryption.rs index eff786188..af48c38cb 100644 --- a/zcash_primitives/src/note_encryption.rs +++ b/zcash_primitives/src/note_encryption.rs @@ -359,11 +359,12 @@ fn parse_note_plaintext_without_memo( let v = (&plaintext[12..20]).read_u64::().ok()?; - let mut r = [0u8; 32]; - r.copy_from_slice(&plaintext[20..COMPACT_NOTE_SIZE]); + let r: [u8; 32] = plaintext[20..COMPACT_NOTE_SIZE] + .try_into() + .expect("slice is the correct length"); let rseed = if plaintext[0] == 0x01 { - let rcm = Fs::from_repr(FsRepr(r.try_into().expect("slice is the correct length")))?; + let rcm = Fs::from_repr(FsRepr(r))?; Rseed::BeforeZip212(rcm) } else { Rseed::AfterZip212(r) @@ -550,11 +551,12 @@ pub fn try_sapling_output_recovery( let v = (&plaintext[12..20]).read_u64::().ok()?; - let mut r = [0u8; 32]; - r.copy_from_slice(&plaintext[20..COMPACT_NOTE_SIZE]); + let r: [u8; 32] = plaintext[20..COMPACT_NOTE_SIZE] + .try_into() + .expect("slice is the correct length"); let rseed = if plaintext[0] == 0x01 { - let rcm = Fs::from_repr(FsRepr(r.try_into().expect("slice is the correct length")))?; + let rcm = Fs::from_repr(FsRepr(r))?; Rseed::BeforeZip212(rcm) } else { Rseed::AfterZip212(r) From 7cee29bbccabb5451595e97f701b6796acd75430 Mon Sep 17 00:00:00 2001 From: therealyingtong Date: Thu, 6 Aug 2020 17:33:33 +0800 Subject: [PATCH 27/31] Use type for Builder impl --- zcash_primitives/src/transaction/builder.rs | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/zcash_primitives/src/transaction/builder.rs b/zcash_primitives/src/transaction/builder.rs index d17b194bd..928744276 100644 --- a/zcash_primitives/src/transaction/builder.rs +++ b/zcash_primitives/src/transaction/builder.rs @@ -14,7 +14,6 @@ use std::marker::PhantomData; use crate::{ consensus, - consensus::{MainNetwork, TestNetwork}, keys::OutgoingViewingKey, legacy::TransparentAddress, merkle_tree::MerklePath, @@ -319,22 +318,7 @@ pub struct Builder { phantom: PhantomData

, } -impl Builder { - /// Creates a new `Builder` targeted for inclusion in the block with the given height, - /// using default values for general transaction fields and the default OS random. - /// - /// # Default values - /// - /// The expiry height will be set to the given height plus the default transaction - /// expiry delta (20 blocks). - /// - /// The fee will be set to the default fee (0.0001 ZEC). - pub fn new(height: u32) -> Self { - Builder::new_with_rng(height, OsRng) - } -} - -impl Builder { +impl Builder { /// Creates a new `Builder` targeted for inclusion in the block with the given height, /// using default values for general transaction fields and the default OS random. /// From 5480a376dfa823d3331d3964d36590afcb6e889e Mon Sep 17 00:00:00 2001 From: therealyingtong Date: Thu, 6 Aug 2020 18:07:15 +0800 Subject: [PATCH 28/31] Extract derive_esk() into separate function --- zcash_primitives/src/primitives.rs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/zcash_primitives/src/primitives.rs b/zcash_primitives/src/primitives.rs index 1c81fc03b..bb5b2e1c9 100644 --- a/zcash_primitives/src/primitives.rs +++ b/zcash_primitives/src/primitives.rs @@ -346,7 +346,17 @@ impl Note { // reduce to uniform value E::Fs::to_uniform(&buffer[..]) } - Rseed::AfterZip212(rseed) => E::Fs::to_uniform(prf_expand(&rseed, &[0x05]).as_bytes()), + Rseed::AfterZip212(_) => self.derive_esk().unwrap(), + } + } + + /// Returns the derived `esk` if this note was created after ZIP 212 activated. + pub fn derive_esk(&self) -> Option { + match self.rseed { + Rseed::BeforeZip212(_) => None, + Rseed::AfterZip212(rseed) => { + Some(E::Fs::to_uniform(prf_expand(&rseed, &[0x05]).as_bytes())) + } } } } From d54fd09c5f736ec0da168beed3bd6f5e54defceb Mon Sep 17 00:00:00 2001 From: therealyingtong Date: Thu, 6 Aug 2020 18:18:58 +0800 Subject: [PATCH 29/31] Add esk check in parse_note_plaintext_without_memo() and try_sapling_output_recovery() --- zcash_primitives/src/note_encryption.rs | 33 ++++++++++++++----------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/zcash_primitives/src/note_encryption.rs b/zcash_primitives/src/note_encryption.rs index af48c38cb..cf0b446e0 100644 --- a/zcash_primitives/src/note_encryption.rs +++ b/zcash_primitives/src/note_encryption.rs @@ -6,7 +6,7 @@ use crate::{ jubjub::{ edwards, fs::{Fs, FsRepr}, - PrimeOrder, ToUniform, Unknown, + PrimeOrder, Unknown, }, primitives::{Diversifier, Note, PaymentAddress, Rseed}, }; @@ -20,10 +20,7 @@ use std::convert::TryInto; use std::fmt; use std::str; -use crate::{ - keys::{prf_expand, OutgoingViewingKey}, - JUBJUB, -}; +use crate::{keys::OutgoingViewingKey, JUBJUB}; pub const KDF_SAPLING_PERSONALIZATION: &[u8; 16] = b"Zcash_SaplingKDF"; pub const PRF_OCK_PERSONALIZATION: &[u8; 16] = b"Zcash_Derive_ock"; @@ -346,6 +343,7 @@ impl SaplingNoteEncryption { fn parse_note_plaintext_without_memo( height: u32, ivk: &Fs, + epk: &edwards::Point, cmu: &Fr, plaintext: &[u8], ) -> Option<(Note, PaymentAddress)> { @@ -383,6 +381,13 @@ fn parse_note_plaintext_without_memo( return None; } + if let Rseed::AfterZip212(_) = note.rseed { + let derived_esk = note.derive_esk().unwrap(); + if note.g_d.mul(derived_esk, &JUBJUB) != *epk { + return None; + } + } + Some((note, to)) } @@ -440,15 +445,7 @@ pub fn try_sapling_note_decryption( NOTE_PLAINTEXT_SIZE ); - let (note, to) = parse_note_plaintext_without_memo::

(height, ivk, cmu, &plaintext)?; - - match note.rseed { - Rseed::AfterZip212(rseed) => { - let derived_esk = Fs::to_uniform(prf_expand(&rseed, &[0x05]).as_bytes()); - assert_eq!(note.g_d.mul(derived_esk, &JUBJUB), *epk); - } - _ => (), - } + let (note, to) = parse_note_plaintext_without_memo::

(height, ivk, epk, cmu, &plaintext)?; let mut memo = [0u8; 512]; memo.copy_from_slice(&plaintext[COMPACT_NOTE_SIZE..NOTE_PLAINTEXT_SIZE]); @@ -482,7 +479,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::

(height, ivk, cmu, &plaintext) + parse_note_plaintext_without_memo::

(height, ivk, epk, cmu, &plaintext) } /// Recovery of the full note plaintext by the sender. @@ -583,6 +580,12 @@ pub fn try_sapling_output_recovery( return None; } + if let Rseed::AfterZip212(_) = note.rseed { + if note.derive_esk().unwrap() != esk { + return None; + } + } + Some((note, to, Memo(memo))) } From 13f4d0844e30159f262eef66cb73744c94c421ec Mon Sep 17 00:00:00 2001 From: ying tong Date: Fri, 7 Aug 2020 00:12:07 +0800 Subject: [PATCH 30/31] Avoid using unwrap() when calling derive_esk() Co-authored-by: Daira Hopwood --- zcash_primitives/src/note_encryption.rs | 9 ++++----- zcash_primitives/src/primitives.rs | 6 +++--- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/zcash_primitives/src/note_encryption.rs b/zcash_primitives/src/note_encryption.rs index cf0b446e0..e6a64f061 100644 --- a/zcash_primitives/src/note_encryption.rs +++ b/zcash_primitives/src/note_encryption.rs @@ -381,8 +381,7 @@ fn parse_note_plaintext_without_memo( return None; } - if let Rseed::AfterZip212(_) = note.rseed { - let derived_esk = note.derive_esk().unwrap(); + if let Some(derived_esk) = note.derive_esk() { if note.g_d.mul(derived_esk, &JUBJUB) != *epk { return None; } @@ -461,7 +460,7 @@ pub fn try_sapling_note_decryption( /// /// Implements the procedure specified in [`ZIP 307`]. /// -/// [`ZIP 307`]: https://github.com/zcash/zips/pull/226 +/// [`ZIP 307`]: https://zips.z.cash/zip-0307 pub fn try_sapling_compact_note_decryption( height: u32, ivk: &Fs, @@ -580,8 +579,8 @@ pub fn try_sapling_output_recovery( return None; } - if let Rseed::AfterZip212(_) = note.rseed { - if note.derive_esk().unwrap() != esk { + if let Some(derived_esk) = note.derive_esk() { + if derived_esk != esk { return None; } } diff --git a/zcash_primitives/src/primitives.rs b/zcash_primitives/src/primitives.rs index bb5b2e1c9..e475bd7ce 100644 --- a/zcash_primitives/src/primitives.rs +++ b/zcash_primitives/src/primitives.rs @@ -337,8 +337,8 @@ impl Note { } pub fn generate_or_derive_esk(&self, rng: &mut R) -> E::Fs { - match self.rseed { - Rseed::BeforeZip212(_) => { + match self.derive_esk() { + None => { // create random 64 byte buffer let mut buffer = [0u8; 64]; &rng.fill_bytes(&mut buffer); @@ -346,7 +346,7 @@ impl Note { // reduce to uniform value E::Fs::to_uniform(&buffer[..]) } - Rseed::AfterZip212(_) => self.derive_esk().unwrap(), + Some(esk) => esk, } } From 72cc8fc9165ad5593982242c7667907db3f09d02 Mon Sep 17 00:00:00 2001 From: ying tong Date: Fri, 7 Aug 2020 08:46:15 +0800 Subject: [PATCH 31/31] Minor refactor of enumeration in tests in note_encryption.rs Co-authored-by: str4d --- zcash_primitives/src/note_encryption.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/zcash_primitives/src/note_encryption.rs b/zcash_primitives/src/note_encryption.rs index e6a64f061..bdd6ee119 100644 --- a/zcash_primitives/src/note_encryption.rs +++ b/zcash_primitives/src/note_encryption.rs @@ -1025,7 +1025,7 @@ mod tests { ]; let leadbytes = [0x02, 0x03, 0x01]; - for (_i, (&height, &leadbyte)) in heights.iter().zip(leadbytes.iter()).enumerate() { + for (&height, &leadbyte) in heights.iter().zip(leadbytes.iter()) { let (ovk, ivk, cv, cmu, epk, mut enc_ciphertext, out_ciphertext) = random_enc_ciphertext(height, &mut rng); @@ -1202,7 +1202,7 @@ mod tests { ]; let leadbytes = [0x02, 0x03, 0x01]; - for (_i, (&height, &leadbyte)) in heights.iter().zip(leadbytes.iter()).enumerate() { + for (&height, &leadbyte) in heights.iter().zip(leadbytes.iter()) { let (ovk, ivk, cv, cmu, epk, mut enc_ciphertext, out_ciphertext) = random_enc_ciphertext(height, &mut rng); @@ -1472,7 +1472,7 @@ mod tests { ]; let leadbytes = [0x02, 0x03, 0x01]; - for (_i, (&height, &leadbyte)) in heights.iter().zip(leadbytes.iter()).enumerate() { + for (&height, &leadbyte) in heights.iter().zip(leadbytes.iter()) { let (ovk, _, cv, cmu, epk, mut enc_ciphertext, out_ciphertext) = random_enc_ciphertext(height, &mut rng);