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);