From 65504d9ca784d9bc62ffbfae0dedad6945594edc Mon Sep 17 00:00:00 2001 From: therealyingtong Date: Thu, 30 Jul 2020 12:36:12 +0800 Subject: [PATCH] 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);