From 2f50d24b6532ce0264381c786953aab33563fb3f Mon Sep 17 00:00:00 2001 From: moana Date: Mon, 17 Jun 2024 13:15:22 +0200 Subject: [PATCH] core: Add recipient encryption to the `Note` --- core/src/lib.rs | 4 +- core/src/note.rs | 182 ++++++++++++++++++++++--------- core/src/recipient.rs | 220 -------------------------------------- core/src/transaction.rs | 8 +- core/tests/keys.rs | 6 +- core/tests/note_test.rs | 111 ++++++++++++++----- core/tests/transaction.rs | 25 ++--- 7 files changed, 236 insertions(+), 320 deletions(-) delete mode 100644 core/src/recipient.rs diff --git a/core/src/lib.rs b/core/src/lib.rs index 842b8d0..fe02181 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -15,7 +15,6 @@ mod encryption; mod error; mod keys; mod note; -mod recipient; #[cfg(feature = "alloc")] mod transaction; @@ -31,8 +30,7 @@ pub use keys::hash; pub use keys::public::PublicKey; pub use keys::secret::SecretKey; pub use keys::view::ViewKey; -pub use note::{Note, NoteType, ENCRYPTION_SIZE as NOTE_ENCRYPTION_SIZE}; -pub use recipient::RecipientParameters; +pub use note::{Note, NoteType, VALUE_ENC_SIZE as NOTE_VAL_ENC_SIZE}; #[cfg(feature = "alloc")] /// Transaction Skeleton used by the phoenix transaction model diff --git a/core/src/note.rs b/core/src/note.rs index f98dfeb..4ca3d56 100644 --- a/core/src/note.rs +++ b/core/src/note.rs @@ -7,8 +7,8 @@ use core::convert::{TryFrom, TryInto}; use crate::{ - transparent_value_commitment, value_commitment, Error, PublicKey, - SecretKey, StealthAddress, SyncAddress, ViewKey, + encryption::elgamal, transparent_value_commitment, value_commitment, Error, + PublicKey, SecretKey, StealthAddress, SyncAddress, ViewKey, }; use dusk_bls12_381::BlsScalar; use dusk_bytes::{DeserializableSlice, Error as BytesError, Serializable}; @@ -29,8 +29,8 @@ pub(crate) const TRANSPARENT_BLINDER: JubJubScalar = JubJubScalar::zero(); /// Size of the Phoenix notes plaintext: value (8 bytes) + blinder (32 bytes) pub(crate) const PLAINTEXT_SIZE: usize = 40; -/// Size of the Phoenix notes encryption -pub const ENCRYPTION_SIZE: usize = PLAINTEXT_SIZE + aes::ENCRYPTION_EXTRA_SIZE; +/// Size of the Phoenix notes value_enc +pub const VALUE_ENC_SIZE: usize = PLAINTEXT_SIZE + aes::ENCRYPTION_EXTRA_SIZE; /// The types of a Note #[derive(Debug, Clone, Copy, Eq, PartialEq)] @@ -79,7 +79,9 @@ pub struct Note { pub(crate) stealth_address: StealthAddress, pub(crate) sync_address: SyncAddress, pub(crate) pos: u64, - pub(crate) encryption: [u8; ENCRYPTION_SIZE], + pub(crate) value_enc: [u8; VALUE_ENC_SIZE], + // the elgamal encryption of the sender_pk encrypted using the output_npk + pub(crate) sender_enc: [(JubJubAffine, JubJubAffine); 2], } impl PartialEq for Note { @@ -97,7 +99,8 @@ impl Note { note_type: NoteType, pk: &PublicKey, value: u64, - blinding_factor: JubJubScalar, + value_blinder: JubJubScalar, + sender_blinder: [JubJubScalar; 2], ) -> Self { let r = JubJubScalar::random(&mut *rng); let stealth_address = pk.gen_stealth_address(&r); @@ -105,37 +108,54 @@ impl Note { let r_sync = JubJubScalar::random(&mut *rng); let sync_address = pk.gen_sync_address(&r_sync); - let value_commitment = value_commitment(value, blinding_factor); + let value_commitment = value_commitment(value, value_blinder); // Output notes have undefined position, equals to u64's MAX value let pos = u64::MAX; - let encryption = match note_type { + let value_enc = match note_type { NoteType::Transparent => { - let mut encryption = [0u8; ENCRYPTION_SIZE]; - encryption[..u64::SIZE].copy_from_slice(&value.to_bytes()); + let mut value_enc = [0u8; VALUE_ENC_SIZE]; + value_enc[..u64::SIZE].copy_from_slice(&value.to_bytes()); - encryption + value_enc } NoteType::Obfuscated => { let shared_secret = dhke(&r, pk.A()); - let blinding_factor = BlsScalar::from(blinding_factor); + let value_blinder = BlsScalar::from(value_blinder); let mut plaintext = value.to_bytes().to_vec(); - plaintext.append(&mut blinding_factor.to_bytes().to_vec()); + plaintext.append(&mut value_blinder.to_bytes().to_vec()); aes::encrypt(&shared_secret, &plaintext, rng) .expect("Encrypted correctly.") } }; + let sender_enc_A = elgamal::encrypt( + pk.A(), + stealth_address.note_pk.as_ref(), + &sender_blinder[0], + ); + + let sender_enc_B = elgamal::encrypt( + pk.B(), + stealth_address.note_pk.as_ref(), + &sender_blinder[1], + ); + let sender_enc_A: (JubJubAffine, JubJubAffine) = + (sender_enc_A.0.into(), sender_enc_A.1.into()); + let sender_enc_B: (JubJubAffine, JubJubAffine) = + (sender_enc_B.0.into(), sender_enc_B.1.into()); + Note { note_type, value_commitment, stealth_address, sync_address, pos, - encryption, + value_enc, + sender_enc: [sender_enc_A, sender_enc_B], } } @@ -148,8 +168,16 @@ impl Note { rng: &mut R, pk: &PublicKey, value: u64, + sender_blinder: [JubJubScalar; 2], ) -> Self { - Self::new(rng, NoteType::Transparent, pk, value, TRANSPARENT_BLINDER) + Self::new( + rng, + NoteType::Transparent, + pk, + value, + TRANSPARENT_BLINDER, + sender_blinder, + ) } /// Creates a new transparent note @@ -161,13 +189,14 @@ impl Note { stealth_address: StealthAddress, sync_address: SyncAddress, value: u64, + sender_enc: [(JubJubAffine, JubJubAffine); 2], ) -> Self { let value_commitment = transparent_value_commitment(value); let pos = u64::MAX; - let mut encryption = [0u8; ENCRYPTION_SIZE]; - encryption[..u64::SIZE].copy_from_slice(&value.to_bytes()); + let mut value_enc = [0u8; VALUE_ENC_SIZE]; + value_enc[..u64::SIZE].copy_from_slice(&value.to_bytes()); Note { note_type: NoteType::Transparent, @@ -175,23 +204,32 @@ impl Note { stealth_address, sync_address, pos, - encryption, + value_enc, + sender_enc, } } /// Creates a new obfuscated note /// /// The provided blinding factor will be used to calculate the value - /// commitment of the note. The tuple (value, blinding_factor), known by + /// commitment of the note. The tuple (value, value_blinder), known by /// the caller of this function, must be later used to prove the /// knowledge of the value commitment of this note. pub fn obfuscated( rng: &mut R, pk: &PublicKey, value: u64, - blinding_factor: JubJubScalar, + value_blinder: JubJubScalar, + sender_blinder: [JubJubScalar; 2], ) -> Self { - Self::new(rng, NoteType::Obfuscated, pk, value, blinding_factor) + Self::new( + rng, + NoteType::Obfuscated, + pk, + value, + value_blinder, + sender_blinder, + ) } /// Creates a new empty [`Note`] @@ -202,7 +240,8 @@ impl Note { stealth_address: StealthAddress::default(), sync_address: SyncAddress::default(), pos: 0, - encryption: [0; ENCRYPTION_SIZE], + value_enc: [0; VALUE_ENC_SIZE], + sender_enc: [(JubJubAffine::default(), JubJubAffine::default()); 2], } } @@ -214,21 +253,21 @@ impl Note { let shared_secret = dhke(vk.a(), R); let dec_plaintext: [u8; PLAINTEXT_SIZE] = - aes::decrypt(&shared_secret, &self.encryption)?; + aes::decrypt(&shared_secret, &self.value_enc)?; let value = u64::from_slice(&dec_plaintext[..u64::SIZE])?; // Converts the BLS Scalar into a JubJub Scalar. // If the `vk` is wrong it might fails since the resulting BLS Scalar // might not fit into a JubJub Scalar. - let blinding_factor = + let value_blinder = match JubJubScalar::from_slice(&dec_plaintext[u64::SIZE..])?.into() { Some(scalar) => scalar, None => return Err(BytesError::InvalidData), }; - Ok((value, blinding_factor)) + Ok((value, value_blinder)) } /// Create a unique nullifier for the note @@ -291,14 +330,14 @@ impl Note { self.pos = pos; } - /// Return the value commitment `H(value, blinding_factor)` + /// Return the value commitment `H(value, value_blinder)` pub const fn value_commitment(&self) -> &JubJubAffine { &self.value_commitment } /// Returns the cipher of the encrypted data - pub const fn encryption(&self) -> &[u8; ENCRYPTION_SIZE] { - &self.encryption + pub const fn value_enc(&self) -> &[u8; VALUE_ENC_SIZE] { + &self.value_enc } /// Attempt to decrypt the note value provided a [`ViewKey`]. Always @@ -308,7 +347,7 @@ impl Note { match (self.note_type, vk) { (NoteType::Transparent, _) => { let value = - u64::from_slice(&self.encryption[..u64::SIZE]).unwrap(); + u64::from_slice(&self.value_enc[..u64::SIZE]).unwrap(); Ok(value) } (NoteType::Obfuscated, Some(vk)) => self @@ -322,7 +361,7 @@ impl Note { /// Decrypt the blinding factor with the provided [`ViewKey`] /// /// If the decrypt fails, a random value is returned - pub fn blinding_factor( + pub fn value_blinder( &self, vk: Option<&ViewKey>, ) -> Result { @@ -330,17 +369,33 @@ impl Note { (NoteType::Transparent, _) => Ok(TRANSPARENT_BLINDER), (NoteType::Obfuscated, Some(vk)) => self .decrypt_data(vk) - .map(|(_, blinding_factor)| blinding_factor) + .map(|(_, value_blinder)| value_blinder) .map_err(|_| Error::InvalidEncryption), _ => Err(Error::MissingViewKey), } } } -// Serialize into 169 + ENCRYPTION_SIZE bytes, where 169 is the size of all the -// note elements without the encryption. ENCRYPTION_SIZE = PLAINTEXT_SIZE + +// Serialize into 169 + VALUE_ENC_SIZE bytes, where 169 is the size of all the +// note elements without the value_enc. VALUE_ENC_SIZE = PLAINTEXT_SIZE + // ENCRYPTION_EXTRA_SIZE -impl Serializable<{ 169 + ENCRYPTION_SIZE }> for Note { +// pub(crate) note_type: NoteType, +// pub(crate) value_commitment: JubJubAffine, +// pub(crate) stealth_address: StealthAddress, +// pub(crate) sync_address: SyncAddress, +// pub(crate) pos: u64, +// pub(crate) value_enc: [u8; VALUE_ENC_SIZE], +// // the elgamal encryption of the sender_pk encrypted using the output_npk +// pub(crate) sender_enc: [(JubJubAffine, JubJubAffine); 2], +const SIZE: usize = 1 + + JubJubAffine::SIZE + + StealthAddress::SIZE + + SyncAddress::SIZE + + u64::SIZE + + VALUE_ENC_SIZE + + 4 * JubJubAffine::SIZE; + +impl Serializable for Note { type Error = BytesError; /// Converts a Note into a byte representation @@ -349,31 +404,56 @@ impl Serializable<{ 169 + ENCRYPTION_SIZE }> for Note { buf[0] = self.note_type as u8; - buf[1..33].copy_from_slice(&self.value_commitment.to_bytes()); - buf[33..97].copy_from_slice(&self.stealth_address.to_bytes()); - buf[97..161].copy_from_slice(&self.sync_address.to_bytes()); - buf[161..169].copy_from_slice(&self.pos.to_le_bytes()); - buf[169..].copy_from_slice(&self.encryption); + let mut start = 1; + buf[start..start + JubJubAffine::SIZE] + .copy_from_slice(&self.value_commitment.to_bytes()); + start += JubJubAffine::SIZE; + buf[start..start + StealthAddress::SIZE] + .copy_from_slice(&self.stealth_address.to_bytes()); + start += StealthAddress::SIZE; + buf[start..start + SyncAddress::SIZE] + .copy_from_slice(&self.sync_address.to_bytes()); + start += SyncAddress::SIZE; + buf[start..start + u64::SIZE].copy_from_slice(&self.pos.to_le_bytes()); + start += u64::SIZE; + buf[start..start + VALUE_ENC_SIZE].copy_from_slice(&self.value_enc); + start += VALUE_ENC_SIZE; + buf[start..start + JubJubAffine::SIZE] + .copy_from_slice(&self.sender_enc[0].0.to_bytes()); + start += JubJubAffine::SIZE; + buf[start..start + JubJubAffine::SIZE] + .copy_from_slice(&self.sender_enc[0].1.to_bytes()); + start += JubJubAffine::SIZE; + buf[start..start + JubJubAffine::SIZE] + .copy_from_slice(&self.sender_enc[1].0.to_bytes()); + start += JubJubAffine::SIZE; + buf[start..start + JubJubAffine::SIZE] + .copy_from_slice(&self.sender_enc[1].1.to_bytes()); + buf } /// Attempts to convert a byte representation of a note into a `Note`, /// failing if the input is invalid fn from_bytes(bytes: &[u8; Self::SIZE]) -> Result { - let mut one_u64 = [0u8; 8]; - let note_type = bytes[0].try_into().map_err(|_| BytesError::InvalidData)?; - let value_commitment = JubJubAffine::from_slice(&bytes[1..33])?; - let stealth_address = StealthAddress::from_slice(&bytes[33..97])?; - let sync_address = SyncAddress::from_slice(&bytes[97..161])?; + let mut buf = &bytes[1..]; + let value_commitment = JubJubAffine::from_reader(&mut buf)?; + let stealth_address = StealthAddress::from_reader(&mut buf)?; + let sync_address = SyncAddress::from_reader(&mut buf)?; + let pos = u64::from_reader(&mut buf)?; + + let mut value_enc = [0u8; VALUE_ENC_SIZE]; + value_enc.copy_from_slice(&buf[..VALUE_ENC_SIZE]); - one_u64.copy_from_slice(&bytes[161..169]); - let pos = u64::from_le_bytes(one_u64); + buf = &buf[VALUE_ENC_SIZE..]; - let mut encryption = [0u8; ENCRYPTION_SIZE]; - encryption.copy_from_slice(&bytes[169..]); + let sender_enc_A_0 = JubJubAffine::from_reader(&mut buf)?; + let sender_enc_A_1 = JubJubAffine::from_reader(&mut buf)?; + let sender_enc_B_0 = JubJubAffine::from_reader(&mut buf)?; + let sender_enc_B_1 = JubJubAffine::from_reader(&mut buf)?; Ok(Note { note_type, @@ -381,7 +461,11 @@ impl Serializable<{ 169 + ENCRYPTION_SIZE }> for Note { stealth_address, sync_address, pos, - encryption, + value_enc, + sender_enc: [ + (sender_enc_A_0, sender_enc_A_1), + (sender_enc_B_0, sender_enc_B_1), + ], }) } } diff --git a/core/src/recipient.rs b/core/src/recipient.rs deleted file mode 100644 index e113154..0000000 --- a/core/src/recipient.rs +++ /dev/null @@ -1,220 +0,0 @@ -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this -// file, You can obtain one at http://mozilla.org/MPL/2.0/. -// -// Copyright (c) DUSK NETWORK. All rights reserved. - -#![allow(non_snake_case)] - -use dusk_bls12_381::BlsScalar; -use dusk_bytes::{DeserializableSlice, Serializable}; -use dusk_jubjub::{JubJubAffine, JubJubScalar}; -use ff::Field; -use jubjub_schnorr::{SecretKey as SchnorrSecretKey, Signature}; -use rand::{CryptoRng, RngCore}; - -#[cfg(feature = "rkyv-impl")] -use rkyv::{Archive, Deserialize, Serialize}; - -use crate::{encryption::elgamal, PublicKey, SecretKey, OUTPUT_NOTES}; - -/// Parameters needed to prove a recipient in-circuit -#[derive(Debug, Clone, Copy, PartialEq)] -#[cfg_attr( - feature = "rkyv-impl", - derive(Archive, Serialize, Deserialize), - archive_attr(derive(bytecheck::CheckBytes)) -)] -pub struct RecipientParameters { - /// Public key of the transaction sender - pub sender_pk: PublicKey, - /// Note public keys of each note recipient - pub output_npk: [JubJubAffine; OUTPUT_NOTES], - /// Signatures of 'payload_hash' verifiable using 'pk_A' and 'pk_B' - pub sig: [Signature; OUTPUT_NOTES], - /// Asymmetric encryption of 'pk_A' using both recipients 'npk' - pub enc_A: [(JubJubAffine, JubJubAffine); OUTPUT_NOTES], - /// Asymmetric encryption of 'pk_B' using both recipients 'npk' - pub enc_B: [(JubJubAffine, JubJubAffine); OUTPUT_NOTES], - /// Randomness needed to encrypt/decrypt 'pk_A' - pub r_A: [JubJubScalar; OUTPUT_NOTES], - /// Randomness needed to encrypt/decrypt 'pk_B' - pub r_B: [JubJubScalar; OUTPUT_NOTES], -} - -impl Default for RecipientParameters { - fn default() -> Self { - let sk = - SecretKey::new(JubJubScalar::default(), JubJubScalar::default()); - let sender_pk = PublicKey::from(&sk); - - Self { - sender_pk, - output_npk: [JubJubAffine::default(), JubJubAffine::default()], - sig: [Signature::default(), Signature::default()], - enc_A: [(JubJubAffine::default(), JubJubAffine::default()); - OUTPUT_NOTES], - enc_B: [(JubJubAffine::default(), JubJubAffine::default()); - OUTPUT_NOTES], - r_A: [JubJubScalar::default(); OUTPUT_NOTES], - r_B: [JubJubScalar::default(); OUTPUT_NOTES], - } - } -} - -const PARAMS_SIZE: usize = PublicKey::SIZE - + JubJubAffine::SIZE * OUTPUT_NOTES - + Signature::SIZE * OUTPUT_NOTES - + JubJubAffine::SIZE * 2 * OUTPUT_NOTES - + JubJubAffine::SIZE * 2 * OUTPUT_NOTES - + JubJubScalar::SIZE * OUTPUT_NOTES - + JubJubScalar::SIZE * OUTPUT_NOTES; - -impl Serializable for RecipientParameters { - type Error = dusk_bytes::Error; - - fn from_bytes(buf: &[u8; PARAMS_SIZE]) -> Result - where - Self: Sized, - { - let mut reader = &buf[..]; - - let sender_pk = PublicKey::from_reader(&mut reader)?; - - let output_npk_0 = JubJubAffine::from_reader(&mut reader)?; - let output_npk_1 = JubJubAffine::from_reader(&mut reader)?; - - let sig_0 = Signature::from_reader(&mut reader)?; - let sig_1 = Signature::from_reader(&mut reader)?; - - let enc_A_0_0 = JubJubAffine::from_reader(&mut reader)?; - let enc_A_1_0 = JubJubAffine::from_reader(&mut reader)?; - let enc_A_0_1 = JubJubAffine::from_reader(&mut reader)?; - let enc_A_1_1 = JubJubAffine::from_reader(&mut reader)?; - - let enc_B_0_0 = JubJubAffine::from_reader(&mut reader)?; - let enc_B_1_0 = JubJubAffine::from_reader(&mut reader)?; - let enc_B_0_1 = JubJubAffine::from_reader(&mut reader)?; - let enc_B_1_1 = JubJubAffine::from_reader(&mut reader)?; - - let r_A_0 = JubJubScalar::from_reader(&mut reader)?; - let r_A_1 = JubJubScalar::from_reader(&mut reader)?; - - let r_B_0 = JubJubScalar::from_reader(&mut reader)?; - let r_B_1 = JubJubScalar::from_reader(&mut reader)?; - - Ok(Self { - sender_pk, - output_npk: [output_npk_0, output_npk_1], - sig: [sig_0, sig_1], - enc_A: [(enc_A_0_0, enc_A_1_0), (enc_A_0_1, enc_A_1_1)], - enc_B: [(enc_B_0_0, enc_B_1_0), (enc_B_0_1, enc_B_1_1)], - r_A: [r_A_0, r_A_1], - r_B: [r_B_0, r_B_1], - }) - } - - fn to_bytes(&self) -> [u8; PARAMS_SIZE] { - let mut bytes = [0u8; PARAMS_SIZE]; - - bytes[0..64].copy_from_slice(&self.sender_pk.to_bytes()); - - bytes[64..96].copy_from_slice(&self.output_npk[0].to_bytes()); - bytes[96..128].copy_from_slice(&self.output_npk[1].to_bytes()); - - bytes[128..192].copy_from_slice(&self.sig[0].to_bytes()); - bytes[192..256].copy_from_slice(&self.sig[1].to_bytes()); - - bytes[256..288].copy_from_slice(&self.enc_A[0].0.to_bytes()); - bytes[288..320].copy_from_slice(&self.enc_A[0].1.to_bytes()); - bytes[320..352].copy_from_slice(&self.enc_A[1].0.to_bytes()); - bytes[352..384].copy_from_slice(&self.enc_A[1].1.to_bytes()); - - bytes[384..416].copy_from_slice(&self.enc_B[0].0.to_bytes()); - bytes[416..448].copy_from_slice(&self.enc_B[0].1.to_bytes()); - bytes[448..480].copy_from_slice(&self.enc_B[1].0.to_bytes()); - bytes[480..512].copy_from_slice(&self.enc_B[1].1.to_bytes()); - - bytes[512..544].copy_from_slice(&self.r_A[0].to_bytes()); - bytes[544..576].copy_from_slice(&self.r_A[1].to_bytes()); - - bytes[576..608].copy_from_slice(&self.r_B[0].to_bytes()); - bytes[608..640].copy_from_slice(&self.r_B[1].to_bytes()); - - bytes - } -} - -impl RecipientParameters { - /// Create the recipient parameter - pub fn new( - rng: &mut (impl RngCore + CryptoRng), - sender_sk: &SecretKey, - output_npk: [JubJubAffine; OUTPUT_NOTES], - payload_hash: BlsScalar, - ) -> Self { - // Encrypt the public key of the sender. We need to encrypt - // both 'A' and 'B', using both tx output note public keys. - let sender_pk = PublicKey::from(sender_sk); - - let r_A = [ - JubJubScalar::random(&mut *rng), - JubJubScalar::random(&mut *rng), - ]; - let r_B = [ - JubJubScalar::random(&mut *rng), - JubJubScalar::random(&mut *rng), - ]; - - let (A_enc_1_c1, A_enc_1_c2) = elgamal::encrypt( - &output_npk[0].into(), // note_pk_1.as_ref(), - sender_pk.A(), - &r_A[0], - ); - - let (B_enc_1_c1, B_enc_1_c2) = elgamal::encrypt( - &output_npk[0].into(), // note_pk_1.as_ref(), - sender_pk.B(), - &r_B[0], - ); - let (A_enc_2_c1, A_enc_2_c2) = elgamal::encrypt( - &output_npk[1].into(), // note_pk_2.as_ref(), - sender_pk.A(), - &r_A[1], - ); - - let (B_enc_2_c1, B_enc_2_c2) = elgamal::encrypt( - &output_npk[1].into(), // note_pk_2.as_ref(), - sender_pk.B(), - &r_B[1], - ); - - let enc_A = [ - (A_enc_1_c1.into(), A_enc_1_c2.into()), - (A_enc_2_c1.into(), A_enc_2_c2.into()), - ]; - let enc_B = [ - (B_enc_1_c1.into(), B_enc_1_c2.into()), - (B_enc_2_c1.into(), B_enc_2_c2.into()), - ]; - - // Sign the payload hash using both 'a' and 'b' - let schnorr_sk_a = SchnorrSecretKey::from(sender_sk.a()); - let sig_A = schnorr_sk_a.sign(rng, payload_hash); - - let schnorr_sk_b = SchnorrSecretKey::from(sender_sk.b()); - let sig_B = schnorr_sk_b.sign(rng, payload_hash); - - let sig = [sig_A, sig_B]; - - RecipientParameters { - sender_pk, - output_npk, - sig, - enc_A, - enc_B, - r_A, - r_B, - } - } -} diff --git a/core/src/transaction.rs b/core/src/transaction.rs index b4e99f6..d7a3e7a 100644 --- a/core/src/transaction.rs +++ b/core/src/transaction.rs @@ -16,7 +16,7 @@ use rkyv::{Archive, Deserialize, Serialize}; use dusk_bls12_381::BlsScalar; use dusk_bytes::{DeserializableSlice, Error as BytesError, Serializable}; -use crate::{Note, RecipientParameters, OUTPUT_NOTES}; +use crate::{Note, OUTPUT_NOTES}; /// A phoenix transaction, referred to as tx-skeleton in the specs. #[derive(Debug, Clone, PartialEq)] @@ -37,8 +37,6 @@ pub struct TxSkeleton { pub tx_max_fee: u64, /// A deposit is used to transferring funds to a contract pub deposit: u64, - /// Parameters needed to prove a recipient in-circuit - pub recipient_params: RecipientParameters, } impl TxSkeleton { @@ -58,7 +56,6 @@ impl TxSkeleton { bytes.extend(self.tx_max_fee.to_bytes()); bytes.extend(self.deposit.to_bytes()); - bytes.extend(self.recipient_params.to_bytes()); bytes } @@ -83,7 +80,6 @@ impl TxSkeleton { bytes.extend(self.tx_max_fee.to_bytes()); bytes.extend(self.deposit.to_bytes()); - bytes.extend(self.recipient_params.to_bytes()); bytes } @@ -108,7 +104,6 @@ impl TxSkeleton { let tx_max_fee = u64::from_reader(&mut buffer)?; let deposit = u64::from_reader(&mut buffer)?; - let recipient_params = RecipientParameters::from_reader(&mut buffer)?; Ok(Self { root, @@ -116,7 +111,6 @@ impl TxSkeleton { outputs, tx_max_fee, deposit, - recipient_params, }) } diff --git a/core/tests/keys.rs b/core/tests/keys.rs index 4b3415f..10f953e 100644 --- a/core/tests/keys.rs +++ b/core/tests/keys.rs @@ -66,7 +66,11 @@ fn keys_consistency() { let pk = PublicKey::from(&sk); let vk = ViewKey::from(&sk); - let note = Note::transparent(&mut rng, &pk, NOTE_VALUE); + let sender_blinder = [ + JubJubScalar::random(&mut rng), + JubJubScalar::random(&mut rng), + ]; + let note = Note::transparent(&mut rng, &pk, NOTE_VALUE, sender_blinder); assert!(vk.owns(¬e)); assert!(vk.owns_unchecked(¬e)); diff --git a/core/tests/note_test.rs b/core/tests/note_test.rs index 4d71917..e0f05e3 100644 --- a/core/tests/note_test.rs +++ b/core/tests/note_test.rs @@ -4,10 +4,11 @@ // // Copyright (c) DUSK NETWORK. All rights reserved. -use dusk_jubjub::JubJubScalar; +use dusk_jubjub::{JubJubAffine, JubJubScalar}; use ff::Field; use phoenix_core::{ - value_commitment, Error, Note, NoteType, PublicKey, SecretKey, ViewKey, + elgamal, value_commitment, Error, Note, NoteType, PublicKey, SecretKey, + ViewKey, }; use rand::rngs::StdRng; use rand::SeedableRng; @@ -20,7 +21,12 @@ fn transparent_note() -> Result<(), Error> { let pk = PublicKey::from(&sk); let value = 25; - let note = Note::transparent(&mut rng, &pk, value); + let sender_blinder = [ + JubJubScalar::random(&mut rng), + JubJubScalar::random(&mut rng), + ]; + + let note = Note::transparent(&mut rng, &pk, value, sender_blinder); assert_eq!(note.note_type(), NoteType::Transparent); assert_eq!(value, note.value(None)?); @@ -36,18 +42,43 @@ fn transparent_stealth_note() -> Result<(), Error> { let pk = PublicKey::from(&sk); let r = JubJubScalar::random(&mut rng); - let sa = pk.gen_stealth_address(&r); + let stealth = pk.gen_stealth_address(&r); let r = JubJubScalar::random(&mut rng); let sync_address = pk.gen_sync_address(&r); let value = 25; - let note = Note::transparent_stealth(sa, sync_address, value); + let sender_blinder = [ + JubJubScalar::random(&mut rng), + JubJubScalar::random(&mut rng), + ]; + let sender_enc_a = elgamal::encrypt( + pk.A(), + stealth.note_pk().as_ref(), + &sender_blinder[0], + ); + + let sender_enc_b = elgamal::encrypt( + pk.B(), + stealth.note_pk().as_ref(), + &sender_blinder[0], + ); + let sender_enc_a: (JubJubAffine, JubJubAffine) = + (sender_enc_a.0.into(), sender_enc_a.1.into()); + let sender_enc_b: (JubJubAffine, JubJubAffine) = + (sender_enc_b.0.into(), sender_enc_b.1.into()); + + let note = Note::transparent_stealth( + stealth, + sync_address, + value, + [sender_enc_a, sender_enc_b], + ); assert_eq!(note.note_type(), NoteType::Transparent); assert_eq!(value, note.value(None)?); - assert_eq!(sa, *note.stealth_address()); + assert_eq!(stealth, *note.stealth_address()); Ok(()) } @@ -61,8 +92,14 @@ fn obfuscated_note() -> Result<(), Error> { let vk = ViewKey::from(&sk); let value = 25; - let blinding_factor = JubJubScalar::random(&mut rng); - let note = Note::obfuscated(&mut rng, &pk, value, blinding_factor); + let value_blinder = JubJubScalar::random(&mut rng); + let sender_blinder = [ + JubJubScalar::random(&mut rng), + JubJubScalar::random(&mut rng), + ]; + + let note = + Note::obfuscated(&mut rng, &pk, value, value_blinder, sender_blinder); assert_eq!(note.note_type(), NoteType::Obfuscated); assert_eq!(value, note.value(Some(&vk))?); @@ -79,13 +116,23 @@ fn obfuscated_deterministic_note() -> Result<(), Error> { let vk = ViewKey::from(&sk); let value = 25; - let blinding_factor = JubJubScalar::random(&mut rng); - - let note = - Note::new(&mut rng, NoteType::Obfuscated, &pk, value, blinding_factor); + let value_blinder = JubJubScalar::random(&mut rng); + let sender_blinder = [ + JubJubScalar::random(&mut rng), + JubJubScalar::random(&mut rng), + ]; + + let note = Note::new( + &mut rng, + NoteType::Obfuscated, + &pk, + value, + value_blinder, + sender_blinder, + ); assert_eq!(value, note.value(Some(&vk))?); - assert_eq!(blinding_factor, note.blinding_factor(Some(&vk))?); + assert_eq!(value_blinder, note.value_blinder(Some(&vk))?); Ok(()) } @@ -98,19 +145,23 @@ fn value_commitment_transparent() { let vk = ViewKey::from(&sk); let pk = PublicKey::from(&sk); let value = 25; + let sender_blinder = [ + JubJubScalar::random(&mut rng), + JubJubScalar::random(&mut rng), + ]; - let note = Note::transparent(&mut rng, &pk, value); + let note = Note::transparent(&mut rng, &pk, value, sender_blinder); let value = note .value(Some(&vk)) .expect("The note should be owned by the provided vk"); - let blinding_factor = note - .blinding_factor(Some(&vk)) + let value_blinder = note + .value_blinder(Some(&vk)) .expect("The note should be owned by the provided vk"); let commitment = note.value_commitment(); - let commitment_p = value_commitment(value, blinding_factor); + let commitment_p = value_commitment(value, value_blinder); assert_eq!(commitment, &commitment_p.into()); } @@ -124,19 +175,25 @@ fn value_commitment_obfuscated() { let pk = PublicKey::from(&sk); let value = 25; - let blinding_factor = JubJubScalar::random(&mut rng); - let note = Note::obfuscated(&mut rng, &pk, value, blinding_factor); + let value_blinder = JubJubScalar::random(&mut rng); + let sender_blinder = [ + JubJubScalar::random(&mut rng), + JubJubScalar::random(&mut rng), + ]; + + let note = + Note::obfuscated(&mut rng, &pk, value, value_blinder, sender_blinder); let value = note .value(Some(&vk)) .expect("The note should be owned by the provided vk"); - let blinding_factor = note - .blinding_factor(Some(&vk)) + let value_blinder = note + .value_blinder(Some(&vk)) .expect("The note should be owned by the provided vk"); let commitment = note.value_commitment(); - let commitment_p = value_commitment(value, blinding_factor); + let commitment_p = value_commitment(value, value_blinder); assert_eq!(commitment, &commitment_p.into()); } @@ -156,8 +213,14 @@ fn note_keys_consistency() { assert_ne!(sk, wrong_sk); assert_ne!(vk, wrong_vk); - let blinding_factor = JubJubScalar::random(&mut rng); - let note = Note::obfuscated(&mut rng, &pk, value, blinding_factor); + let value_blinder = JubJubScalar::random(&mut rng); + let sender_blinder = [ + JubJubScalar::random(&mut rng), + JubJubScalar::random(&mut rng), + ]; + + let note = + Note::obfuscated(&mut rng, &pk, value, value_blinder, sender_blinder); assert!(!wrong_vk.owns(¬e)); assert!(vk.owns(¬e)); diff --git a/core/tests/transaction.rs b/core/tests/transaction.rs index 76e6f18..d341fbe 100644 --- a/core/tests/transaction.rs +++ b/core/tests/transaction.rs @@ -7,11 +7,9 @@ #![cfg(feature = "alloc")] use dusk_bls12_381::BlsScalar; -use dusk_jubjub::{JubJubScalar, GENERATOR}; +use dusk_jubjub::JubJubScalar; use ff::Field; -use phoenix_core::{ - Error, Note, PublicKey, RecipientParameters, SecretKey, TxSkeleton, -}; +use phoenix_core::{Error, Note, PublicKey, SecretKey, TxSkeleton}; use rand::rngs::OsRng; #[test] @@ -22,8 +20,13 @@ fn transaction_parse() -> Result<(), Error> { let pk = PublicKey::from(&sk); let value = 25; - let blinding_factor = JubJubScalar::random(&mut rng); - let note = Note::obfuscated(&mut rng, &pk, value, blinding_factor); + let value_blinder = JubJubScalar::random(&mut rng); + let sender_blinder = [ + JubJubScalar::random(&mut rng), + JubJubScalar::random(&mut rng), + ]; + let note = + Note::obfuscated(&mut rng, &pk, value, value_blinder, sender_blinder); let root = BlsScalar::from(123); let nullifiers = vec![BlsScalar::from(456), BlsScalar::from(789)]; @@ -31,22 +34,12 @@ fn transaction_parse() -> Result<(), Error> { let tx_max_fee = 0; let deposit = 0; - let output_npks = [ - (GENERATOR * JubJubScalar::random(&mut rng)).into(), - (GENERATOR * JubJubScalar::random(&mut rng)).into(), - ]; - let hash = BlsScalar::random(&mut rng); - - let recipient_params = - RecipientParameters::new(&mut rng, &sk, output_npks, hash); - let tx_skeleton = TxSkeleton { root, nullifiers, outputs, tx_max_fee, deposit, - recipient_params, }; let bytes_of_transaction = tx_skeleton.to_var_bytes(); assert_eq!(