diff --git a/zcash_client_backend/src/decrypt.rs b/zcash_client_backend/src/decrypt.rs index 8cfb6092f..27075c69e 100644 --- a/zcash_client_backend/src/decrypt.rs +++ b/zcash_client_backend/src/decrypt.rs @@ -96,7 +96,7 @@ pub fn decrypt_transaction( index, note, account, - memo, + memo: MemoBytes::from_bytes(&memo).expect("correct length"), transfer_type, }) }) diff --git a/zcash_client_backend/src/scanning.rs b/zcash_client_backend/src/scanning.rs index c773100cc..5e644f081 100644 --- a/zcash_client_backend/src/scanning.rs +++ b/zcash_client_backend/src/scanning.rs @@ -739,7 +739,7 @@ mod tests { let encryptor = sapling_note_encryption( Some(dfvk.fvk().ovk), note.clone(), - MemoBytes::empty(), + *MemoBytes::empty().as_array(), &mut rng, ); let cmu = note.cmu().to_bytes().to_vec(); diff --git a/zcash_client_sqlite/src/testing.rs b/zcash_client_sqlite/src/testing.rs index ab2d5eacd..86c8b997b 100644 --- a/zcash_client_sqlite/src/testing.rs +++ b/zcash_client_sqlite/src/testing.rs @@ -779,7 +779,7 @@ pub(crate) fn fake_compact_block( let encryptor = sapling_note_encryption( Some(dfvk.fvk().ovk), note.clone(), - MemoBytes::empty(), + *MemoBytes::empty().as_array(), &mut rng, ); let cmu = note.cmu().to_bytes().to_vec(); @@ -886,7 +886,7 @@ pub(crate) fn fake_compact_block_spending( let encryptor = sapling_note_encryption( Some(dfvk.fvk().ovk), note.clone(), - MemoBytes::empty(), + *MemoBytes::empty().as_array(), &mut rng, ); let cmu = note.cmu().to_bytes().to_vec(); @@ -912,7 +912,7 @@ pub(crate) fn fake_compact_block_spending( let encryptor = sapling_note_encryption( Some(dfvk.fvk().ovk), note.clone(), - MemoBytes::empty(), + *MemoBytes::empty().as_array(), &mut rng, ); let cmu = note.cmu().to_bytes().to_vec(); diff --git a/zcash_client_sqlite/src/wallet/sapling.rs b/zcash_client_sqlite/src/wallet/sapling.rs index db537f2b8..93b890721 100644 --- a/zcash_client_sqlite/src/wallet/sapling.rs +++ b/zcash_client_sqlite/src/wallet/sapling.rs @@ -1040,7 +1040,13 @@ pub(crate) mod tests { ); if result.is_some() { - return Ok(result); + return Ok(result.map(|(note, addr, memo)| { + ( + note, + addr, + MemoBytes::from_bytes(&memo).expect("correct length"), + ) + })); } } diff --git a/zcash_primitives/CHANGELOG.md b/zcash_primitives/CHANGELOG.md index a5d4c14de..e9842d675 100644 --- a/zcash_primitives/CHANGELOG.md +++ b/zcash_primitives/CHANGELOG.md @@ -112,6 +112,8 @@ and this library adheres to Rust's notion of - `builder::SaplingBuilder::new` now takes a `Zip212Enforcement` argument instead of a `P: consensus::Parameters` argument and a target height. - `builder::SaplingBuilder::add_spend` now takes `extsk` by reference. + - `builder::SaplingBuilder::add_output` now takes an `Option<[u8; 512]>` memo + instead of a `MemoBytes`. - `builder::SaplingBuilder::build` no longer takes a prover, proving context, progress notifier, or target height. Instead, it has `SpendProver, OutputProver` generic parameters and returns `(UnauthorizedBundle, SaplingMetadata)`. The @@ -137,6 +139,13 @@ and this library adheres to Rust's notion of - `try_sapling_compact_note_decryption` - `try_sapling_output_recovery_with_ock` - `try_sapling_output_recovery` + - `SaplingDomain::Memo` now has type `[u8; 512]` instead of `MemoBytes`. + - `sapling_note_encryption` now takes `memo` as a `[u8; 512]` instead of + `MemoBytes`. + - The following methods now return `[u8; 512]` instead of `MemoBytes`: + - `try_sapling_note_decryption` + - `try_sapling_output_recovery_with_ock` + - `try_sapling_output_recovery` - `util::generate_random_rseed` now takes a `Zip212Enforcement` argument instead of a `P: consensus::Parameters` argument and a height. - `zcash_primitives::transaction`: diff --git a/zcash_primitives/benches/note_decryption.rs b/zcash_primitives/benches/note_decryption.rs index 87bac4539..72696665d 100644 --- a/zcash_primitives/benches/note_decryption.rs +++ b/zcash_primitives/benches/note_decryption.rs @@ -6,7 +6,6 @@ use rand_core::OsRng; use zcash_note_encryption::batch; use zcash_primitives::{ consensus::{sapling_zip212_enforcement, NetworkUpgrade::Canopy, Parameters, TEST_NETWORK}, - memo::MemoBytes, sapling::{ builder::SaplingBuilder, note_encryption::{ @@ -38,13 +37,7 @@ fn bench_note_decryption(c: &mut Criterion) { let mut builder = SaplingBuilder::new(zip212_enforcement); builder - .add_output( - &mut rng, - None, - pa, - NoteValue::from_raw(100), - MemoBytes::empty(), - ) + .add_output(&mut rng, None, pa, NoteValue::from_raw(100), None) .unwrap(); let (bundle, _) = builder .build::(&mut rng) diff --git a/zcash_primitives/src/sapling/builder.rs b/zcash_primitives/src/sapling/builder.rs index 2d255c60a..c21c20e34 100644 --- a/zcash_primitives/src/sapling/builder.rs +++ b/zcash_primitives/src/sapling/builder.rs @@ -9,7 +9,6 @@ use rand_core::CryptoRng; use crate::{ keys::OutgoingViewingKey, - memo::MemoBytes, sapling::{ self, bundle::{ @@ -165,7 +164,7 @@ struct SaplingOutputInfo { /// `None` represents the `ovk = ⊥` case. ovk: Option, note: Note, - memo: MemoBytes, + memo: Option<[u8; 512]>, rcv: ValueCommitTrapdoor, } @@ -188,7 +187,7 @@ impl SaplingOutputInfo { None, dummy_to, NoteValue::from_raw(0), - MemoBytes::empty(), + None, zip212_enforcement, ) } @@ -198,7 +197,7 @@ impl SaplingOutputInfo { ovk: Option, to: PaymentAddress, value: NoteValue, - memo: MemoBytes, + memo: Option<[u8; 512]>, zip212_enforcement: Zip212Enforcement, ) -> Self { let rseed = generate_random_rseed_internal(zip212_enforcement, rng); @@ -217,7 +216,16 @@ impl SaplingOutputInfo { self, rng: &mut R, ) -> OutputDescription { - let encryptor = sapling_note_encryption::(self.ovk, self.note.clone(), self.memo, rng); + let encryptor = sapling_note_encryption::( + self.ovk, + self.note.clone(), + self.memo.unwrap_or_else(|| { + let mut memo = [0; 512]; + memo[0] = 0xf6; + memo + }), + rng, + ); // Construct the value commitment. let cv = ValueCommitment::derive(self.note.value(), self.rcv.clone()); @@ -396,7 +404,7 @@ impl SaplingBuilder { ovk: Option, to: PaymentAddress, value: NoteValue, - memo: MemoBytes, + memo: Option<[u8; 512]>, ) -> Result<(), Error> { let output = SaplingOutputInfo::new_internal( &mut rng, diff --git a/zcash_primitives/src/sapling/note_encryption.rs b/zcash_primitives/src/sapling/note_encryption.rs index 72790875b..7f757e0fe 100644 --- a/zcash_primitives/src/sapling/note_encryption.rs +++ b/zcash_primitives/src/sapling/note_encryption.rs @@ -15,17 +15,14 @@ use zcash_note_encryption::{ ENC_CIPHERTEXT_SIZE, NOTE_PLAINTEXT_SIZE, OUT_PLAINTEXT_SIZE, }; -use crate::{ - memo::MemoBytes, - sapling::{ - bundle::{GrothProofBytes, OutputDescription}, - keys::{ - DiversifiedTransmissionKey, EphemeralPublicKey, EphemeralSecretKey, OutgoingViewingKey, - SharedSecret, - }, - value::{NoteValue, ValueCommitment}, - Diversifier, Note, PaymentAddress, Rseed, +use crate::sapling::{ + bundle::{GrothProofBytes, OutputDescription}, + keys::{ + DiversifiedTransmissionKey, EphemeralPublicKey, EphemeralSecretKey, OutgoingViewingKey, + SharedSecret, }, + value::{NoteValue, ValueCommitment}, + Diversifier, Note, PaymentAddress, Rseed, }; use super::note::ExtractedNoteCommitment; @@ -145,7 +142,7 @@ impl Domain for SaplingDomain { type ValueCommitment = ValueCommitment; type ExtractedCommitment = ExtractedNoteCommitment; type ExtractedCommitmentBytes = [u8; 32]; - type Memo = MemoBytes; + type Memo = [u8; 512]; fn derive_esk(note: &Self::Note) -> Option { note.derive_esk() @@ -209,7 +206,7 @@ impl Domain for SaplingDomain { } } - input[COMPACT_NOTE_SIZE..NOTE_PLAINTEXT_SIZE].copy_from_slice(&memo.as_array()[..]); + input[COMPACT_NOTE_SIZE..NOTE_PLAINTEXT_SIZE].copy_from_slice(&memo[..]); NotePlaintextBytes(input) } @@ -286,7 +283,9 @@ impl Domain for SaplingDomain { } fn extract_memo(&self, plaintext: &NotePlaintextBytes) -> Self::Memo { - MemoBytes::from_bytes(&plaintext.0[COMPACT_NOTE_SIZE..NOTE_PLAINTEXT_SIZE]).unwrap() + plaintext.0[COMPACT_NOTE_SIZE..NOTE_PLAINTEXT_SIZE] + .try_into() + .expect("correct length") } } @@ -361,7 +360,6 @@ impl ShieldedOutput for CompactOutputDescripti /// use zcash_primitives::{ /// keys::{OutgoingViewingKey, prf_expand}, /// consensus::{TEST_NETWORK, NetworkUpgrade, Parameters}, -/// memo::MemoBytes, /// sapling::{ /// note_encryption::{sapling_note_encryption, Zip212Enforcement}, /// util::generate_random_rseed, @@ -388,14 +386,14 @@ impl ShieldedOutput for CompactOutputDescripti /// let note = to.create_note(value, rseed); /// let cmu = note.cmu(); /// -/// let mut enc = sapling_note_encryption(ovk, note, MemoBytes::empty(), &mut rng); +/// let mut enc = sapling_note_encryption(ovk, note, [0x37; 512], &mut rng); /// let encCiphertext = enc.encrypt_note_plaintext(); /// let outCiphertext = enc.encrypt_outgoing_plaintext(&cv, &cmu, &mut rng); /// ``` pub fn sapling_note_encryption( ovk: Option, note: Note, - memo: MemoBytes, + memo: [u8; 512], rng: &mut R, ) -> NoteEncryption { let esk = note.generate_or_derive_esk_internal(rng); @@ -416,7 +414,7 @@ pub fn try_sapling_note_decryption Option<(Note, PaymentAddress, MemoBytes)> { +) -> Option<(Note, PaymentAddress, [u8; 512])> { let domain = SaplingDomain::new(zip212_enforcement); try_note_decryption(&domain, ivk, output) } @@ -444,7 +442,7 @@ pub fn try_sapling_output_recovery_with_ock( ock: &OutgoingCipherKey, output: &OutputDescription, zip212_enforcement: Zip212Enforcement, -) -> Option<(Note, PaymentAddress, MemoBytes)> { +) -> Option<(Note, PaymentAddress, [u8; 512])> { let domain = SaplingDomain::new(zip212_enforcement); try_output_recovery_with_ock(&domain, ock, output, output.out_ciphertext()) } @@ -461,7 +459,7 @@ pub fn try_sapling_output_recovery( ovk: &OutgoingViewingKey, output: &OutputDescription, zip212_enforcement: Zip212Enforcement, -) -> Option<(Note, PaymentAddress, MemoBytes)> { +) -> Option<(Note, PaymentAddress, [u8; 512])> { let domain = SaplingDomain::new(zip212_enforcement); try_output_recovery_with_ovk(&domain, ovk, output, output.cv(), output.out_ciphertext()) } @@ -492,7 +490,6 @@ mod tests { use crate::{ keys::OutgoingViewingKey, - memo::MemoBytes, sapling::{ bundle::{GrothProofBytes, OutputDescription}, keys::{DiversifiedTransmissionKey, EphemeralSecretKey}, @@ -561,7 +558,7 @@ mod tests { let cmu = note.cmu(); let ovk = OutgoingViewingKey([0; 32]); - let ne = sapling_note_encryption(Some(ovk), note, MemoBytes::empty(), &mut rng); + let ne = sapling_note_encryption(Some(ovk), note, [0x37; 512], &mut rng); let epk = ne.epk(); let ock = prf_ock(&ovk, &cv, &cmu.to_bytes(), &epk.to_bytes()); @@ -1415,7 +1412,7 @@ mod tests { Some((decrypted_note, decrypted_to, decrypted_memo)) => { assert_eq!(decrypted_note, note); assert_eq!(decrypted_to, to); - assert_eq!(&decrypted_memo.as_array()[..], &tv.memo[..]); + assert_eq!(&decrypted_memo[..], &tv.memo[..]); } None => panic!("Note decryption failed"), } @@ -1436,7 +1433,7 @@ mod tests { Some((decrypted_note, decrypted_to, decrypted_memo)) => { assert_eq!(decrypted_note, note); assert_eq!(decrypted_to, to); - assert_eq!(&decrypted_memo.as_array()[..], &tv.memo[..]); + assert_eq!(&decrypted_memo[..], &tv.memo[..]); } None => panic!("Output recovery failed"), } @@ -1449,7 +1446,7 @@ mod tests { [Some(((decrypted_note, decrypted_to, decrypted_memo), i))] => { assert_eq!(decrypted_note, ¬e); assert_eq!(decrypted_to, &to); - assert_eq!(&decrypted_memo.as_array()[..], &tv.memo[..]); + assert_eq!(&decrypted_memo[..], &tv.memo[..]); assert_eq!(*i, 0); } _ => panic!("Note decryption failed"), @@ -1475,12 +1472,7 @@ mod tests { // Test encryption // - let ne = NoteEncryption::::new_with_esk( - esk, - Some(ovk), - note, - MemoBytes::from_bytes(&tv.memo).unwrap(), - ); + let ne = NoteEncryption::::new_with_esk(esk, Some(ovk), note, tv.memo); assert_eq!(ne.encrypt_note_plaintext().as_ref(), &tv.c_enc[..]); assert_eq!( diff --git a/zcash_primitives/src/transaction/builder.rs b/zcash_primitives/src/transaction/builder.rs index 9bf60b65f..135ee4aca 100644 --- a/zcash_primitives/src/transaction/builder.rs +++ b/zcash_primitives/src/transaction/builder.rs @@ -356,7 +356,7 @@ impl<'a, P: consensus::Parameters, R: RngCore + CryptoRng> Builder<'a, P, R> { ovk, to, sapling::value::NoteValue::from_raw(value.into()), - memo, + Some(*memo.as_array()), ) }