diff --git a/circuits/src/sender_enc.rs b/circuits/src/sender_enc.rs index 2987752..25567ae 100644 --- a/circuits/src/sender_enc.rs +++ b/circuits/src/sender_enc.rs @@ -19,7 +19,7 @@ pub(crate) fn gadget( sender_pk: PublicKey, signatures: (SchnorrSignature, SchnorrSignature), output_npk: [JubJubAffine; OUTPUT_NOTES], - sender_blinder: [(JubJubScalar, JubJubScalar); OUTPUT_NOTES], + sender_blinder: [[JubJubScalar; 2]; OUTPUT_NOTES], // [enc_A, enc_B] for note 0 sender_enc_out0: [(JubJubAffine, JubJubAffine); 2], // [enc_A, enc_B] for note 1 @@ -55,11 +55,11 @@ pub(crate) fn gadget( let note_pk_0 = composer.append_public_point(output_npk[0]); let note_pk_1 = composer.append_public_point(output_npk[1]); - let blinder_A_0 = composer.append_witness(sender_blinder[0].0); - let blinder_B_0 = composer.append_witness(sender_blinder[0].1); + let blinder_A_0 = composer.append_witness(sender_blinder[0][0]); + let blinder_B_0 = composer.append_witness(sender_blinder[0][1]); - let blinder_A_1 = composer.append_witness(sender_blinder[1].0); - let blinder_B_1 = composer.append_witness(sender_blinder[1].1); + let blinder_A_1 = composer.append_witness(sender_blinder[1][0]); + let blinder_B_1 = composer.append_witness(sender_blinder[1][1]); // assert that the sender encryption of the first note is correct // appends the values of sender_enc_out0 as public input diff --git a/circuits/src/transaction.rs b/circuits/src/transaction.rs index 854ba75..8726c00 100644 --- a/circuits/src/transaction.rs +++ b/circuits/src/transaction.rs @@ -316,7 +316,7 @@ pub struct TxCircuit { max_fee: u64, sender_pk: PublicKey, signatures: (SchnorrSignature, SchnorrSignature), - sender_blinder: [(JubJubScalar, JubJubScalar); OUTPUT_NOTES], + sender_blinder: [[JubJubScalar; 2]; OUTPUT_NOTES], } impl Default for TxCircuit { @@ -367,7 +367,7 @@ impl Default for TxCircuit { let signatures = (SchnorrSignature::default(), SchnorrSignature::default()); let sender_blinder = - [(JubJubScalar::default(), JubJubScalar::default()); OUTPUT_NOTES]; + [[JubJubScalar::default(), JubJubScalar::default()]; OUTPUT_NOTES]; Self { tx_input_notes: tx_input_notes.try_into().unwrap(), @@ -394,7 +394,7 @@ impl TxCircuit { max_fee: u64, sender_pk: PublicKey, signatures: (SchnorrSignature, SchnorrSignature), - sender_blinder: [(JubJubScalar, JubJubScalar); OUTPUT_NOTES], + sender_blinder: [[JubJubScalar; 2]; OUTPUT_NOTES], ) -> Self { Self { tx_input_notes, diff --git a/circuits/tests/transaction.rs b/circuits/tests/transaction.rs index f86617b..c2a16a0 100644 --- a/circuits/tests/transaction.rs +++ b/circuits/tests/transaction.rs @@ -38,7 +38,7 @@ struct TestingParameters { sender_pk: PublicKey, output_npk: [JubJubAffine; OUTPUT_NOTES], signatures: (SchnorrSignature, SchnorrSignature), - sender_blinder: [(JubJubScalar, JubJubScalar); OUTPUT_NOTES], + sender_blinder: [[JubJubScalar; 2]; OUTPUT_NOTES], } lazy_static! { @@ -49,6 +49,8 @@ lazy_static! { let pp = PublicParameters::setup(1 << CAPACITY, &mut rng).unwrap(); let sender_sk = SecretKey::random(&mut rng); + let sender_pk = PublicKey::from(&sender_sk); + let receiver_pk = PublicKey::from(&SecretKey::random(&mut rng)); let mut tree = Tree::<(), HEIGHT>::new(); let payload_hash = BlsScalar::from(1234u64); @@ -67,8 +69,6 @@ lazy_static! { let deposit = 5; let max_fee = 5; - let sender_pk = PublicKey::from(&sender_sk); - let receiver_pk = PublicKey::from(&SecretKey::random(&mut rng)); // generate both ouput note public keys let receiver_npk = *receiver_pk.gen_stealth_address( @@ -88,14 +88,15 @@ lazy_static! { let schnorr_sk_b = SchnorrSecretKey::from(sender_sk.b()); let sig_b = schnorr_sk_b.sign(&mut rng, payload_hash); - let sender_blinder_0 = ( + // sender blinder for the output notes + let sender_blinder_0 = [ JubJubScalar::random(&mut rng), JubJubScalar::random(&mut rng), - ); - let sender_blinder_1 = ( + ]; + let sender_blinder_1 = [ JubJubScalar::random(&mut rng), JubJubScalar::random(&mut rng), - ); + ]; TestingParameters { pp, @@ -115,7 +116,7 @@ lazy_static! { fn create_and_insert_test_note( rng: &mut (impl RngCore + CryptoRng), tree: &mut Tree<(), HEIGHT>, - pk: &PublicKey, + sender_pk: &PublicKey, pos: u64, value: u64, ) -> Note { @@ -123,7 +124,10 @@ fn create_and_insert_test_note( JubJubScalar::random(&mut *rng), JubJubScalar::random(&mut *rng), ]; - let mut note = Note::transparent(rng, pk, value, sender_blinder); + + // create a note that belongs to the sender + let mut note = + Note::transparent(rng, sender_pk, sender_pk, value, sender_blinder); note.set_pos(pos); let item = Item { @@ -138,17 +142,17 @@ fn create_and_insert_test_note( fn create_test_tx_input_notes( rng: &mut (impl RngCore + CryptoRng), tree: &mut Tree<(), HEIGHT>, - sk: &SecretKey, + sender_sk: &SecretKey, payload_hash: BlsScalar, ) -> [TxInputNote; I] { - let pk = PublicKey::from(sk); + let sender_pk = PublicKey::from(sender_sk); let mut notes = Vec::new(); for i in 0..I { notes.push(create_and_insert_test_note( rng, tree, - &pk, + &sender_pk, i.try_into().unwrap(), 25, )); @@ -157,9 +161,14 @@ fn create_test_tx_input_notes( let mut input_notes = Vec::new(); for i in 0..I { let merkle_opening = tree.opening(*notes[i].pos()).expect("Tree read."); - let input_note = - TxInputNote::new(rng, ¬es[i], merkle_opening, &sk, payload_hash) - .expect("Note created properly."); + let input_note = TxInputNote::new( + rng, + ¬es[i], + merkle_opening, + sender_sk, + payload_hash, + ) + .expect("Note created properly."); input_notes.push(input_note); } @@ -171,17 +180,16 @@ fn create_tx_output_note( rng: &mut (impl RngCore + CryptoRng), value: u64, note_pk: JubJubAffine, - // (blinder_A, blinder_B) - sender_blinder: (JubJubScalar, JubJubScalar), + sender_blinder: [JubJubScalar; 2], ) -> TxOutputNote { let value_blinder = JubJubScalar::random(&mut *rng); let value_commitment = value_commitment(value, value_blinder); - let sender_blinder_a = sender_blinder.0; + let sender_blinder_a = sender_blinder[0]; let sender_enc_a = elgamal::encrypt(¬e_pk.into(), TP.sender_pk.A(), &sender_blinder_a); - let sender_blinder_b = sender_blinder.1; + let sender_blinder_b = sender_blinder[1]; let sender_enc_b = elgamal::encrypt(¬e_pk.into(), TP.sender_pk.B(), &sender_blinder_b); diff --git a/core/CHANGELOG.md b/core/CHANGELOG.md index 7b53b28..e15927f 100644 --- a/core/CHANGELOG.md +++ b/core/CHANGELOG.md @@ -9,6 +9,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added +- Add `encrypt_sender` function to encrypt the sender with the npk [#214] +- Add `decrypt_sender` method to the `Note` [#214] - Add `elgamal::encrypt` and `elgamal::decrypt` - Add `stealth_address` function directly to note [#208] - Add function `value_commitment` [#201] @@ -20,6 +22,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Rename `tx_max_fee` to `max_fee` [#214] - Add `sender_enc` field to the `Note` [#214] - Add `sender_blinder` parameter for `Note` contructors [#214] +- Add `sender_pk` parameter for `Note` contructors [#214] +- Add `sender_enc` parameter for `Note::transparent_stealth` [#214] - Rename `encryption_blinder` to `value_blinder` [#214] - Rename `NOTE_ENCRYPTION_SIZE` to `NOTE_VALUE_ENC_SIZE` [#214] - Move `OUTPUT_NOTES` to crate root diff --git a/core/src/encryption/elgamal.rs b/core/src/encryption/elgamal.rs index b9fcb08..3fd80cd 100644 --- a/core/src/encryption/elgamal.rs +++ b/core/src/encryption/elgamal.rs @@ -33,9 +33,11 @@ pub fn encrypt( /// Returns a JubJubExtended plaintext. pub fn decrypt( secret_key: &JubJubScalar, - ciphertext_1: &JubJubExtended, - ciphertext_2: &JubJubExtended, + ciphertext: &(JubJubExtended, JubJubExtended), ) -> JubJubExtended { + let ciphertext_1 = ciphertext.0; + let ciphertext_2 = ciphertext.1; + // return the plaintext ciphertext_2 - ciphertext_1 * secret_key } diff --git a/core/src/lib.rs b/core/src/lib.rs index bc0eb7b..c8b57e7 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -28,7 +28,9 @@ pub use keys::hash; pub use keys::public::PublicKey; pub use keys::secret::SecretKey; pub use keys::view::ViewKey; -pub use note::{Note, NoteType, VALUE_ENC_SIZE as NOTE_VAL_ENC_SIZE}; +pub use note::{ + encrypt_sender, Note, NoteType, VALUE_ENC_SIZE as NOTE_VAL_ENC_SIZE, +}; pub use stealth_address::StealthAddress; #[cfg(feature = "alloc")] diff --git a/core/src/note.rs b/core/src/note.rs index dabe6c0..9af02a4 100644 --- a/core/src/note.rs +++ b/core/src/note.rs @@ -6,20 +6,19 @@ use core::convert::{TryFrom, TryInto}; -use crate::{ - encryption::elgamal, transparent_value_commitment, value_commitment, Error, - PublicKey, SecretKey, StealthAddress, ViewKey, -}; use dusk_bls12_381::BlsScalar; use dusk_bytes::{DeserializableSlice, Error as BytesError, Serializable}; use dusk_jubjub::{dhke, JubJubAffine, JubJubScalar, GENERATOR_NUMS_EXTENDED}; - -use crate::aes; - use dusk_poseidon::{Domain, Hash}; use ff::Field; +use jubjub_schnorr::{PublicKey as NotePublicKey, SecretKey as NoteSecretKey}; use rand::{CryptoRng, RngCore}; +use crate::{ + aes, elgamal, transparent_value_commitment, value_commitment, Error, + PublicKey, SecretKey, StealthAddress, ViewKey, +}; + #[cfg(feature = "rkyv-impl")] use rkyv::{Archive, Deserialize, Serialize}; @@ -79,7 +78,6 @@ pub struct Note { pub(crate) stealth_address: StealthAddress, 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], } @@ -96,13 +94,14 @@ impl Note { pub fn new( rng: &mut R, note_type: NoteType, - pk: &PublicKey, + sender_pk: &PublicKey, + receiver_pk: &PublicKey, value: u64, value_blinder: JubJubScalar, sender_blinder: [JubJubScalar; 2], ) -> Self { let r = JubJubScalar::random(&mut *rng); - let stealth_address = pk.gen_stealth_address(&r); + let stealth_address = receiver_pk.gen_stealth_address(&r); let value_commitment = value_commitment(value, value_blinder); @@ -117,7 +116,7 @@ impl Note { value_enc } NoteType::Obfuscated => { - let shared_secret = dhke(&r, pk.A()); + let shared_secret = dhke(&r, receiver_pk.A()); let value_blinder = BlsScalar::from(value_blinder); let mut plaintext = value.to_bytes().to_vec(); @@ -128,29 +127,17 @@ impl Note { } }; - 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, pos, value_enc, - sender_enc: [sender_enc_A, sender_enc_B], + sender_enc: encrypt_sender( + stealth_address.note_pk(), + sender_pk, + &sender_blinder, + ), } } @@ -161,14 +148,16 @@ impl Note { /// notes, so this can be trivially treated as a constant. pub fn transparent( rng: &mut R, - pk: &PublicKey, + sender_pk: &PublicKey, + receiver_pk: &PublicKey, value: u64, sender_blinder: [JubJubScalar; 2], ) -> Self { Self::new( rng, NoteType::Transparent, - pk, + sender_pk, + receiver_pk, value, TRANSPARENT_BLINDER, sender_blinder, @@ -210,7 +199,8 @@ impl Note { /// knowledge of the value commitment of this note. pub fn obfuscated( rng: &mut R, - pk: &PublicKey, + sender_pk: &PublicKey, + receiver_pk: &PublicKey, value: u64, value_blinder: JubJubScalar, sender_blinder: [JubJubScalar; 2], @@ -218,7 +208,8 @@ impl Note { Self::new( rng, NoteType::Obfuscated, - pk, + sender_pk, + receiver_pk, value, value_blinder, sender_blinder, @@ -237,7 +228,7 @@ impl Note { } } - fn decrypt_data( + fn decrypt_value( &self, vk: &ViewKey, ) -> Result<(u64, JubJubScalar), BytesError> { @@ -327,6 +318,13 @@ impl Note { &self.value_enc } + /// Returns elgamal encryption of the sender's [`PublicKey`] encrypted using + /// the [`StealthAddress::note_pk`] so only the receiver of the [`Note`] + /// can decrypt. + pub const fn sender_enc(&self) -> &[(JubJubAffine, JubJubAffine); 2] { + &self.sender_enc + } + /// Attempt to decrypt the note value provided a [`ViewKey`]. Always /// succeeds for transparent notes, might fails or return random values for /// obfuscated notes if the provided view key is wrong. @@ -338,7 +336,7 @@ impl Note { Ok(value) } (NoteType::Obfuscated, Some(vk)) => self - .decrypt_data(vk) + .decrypt_value(vk) .map(|(value, _)| value) .map_err(|_| Error::InvalidEncryption), _ => Err(Error::MissingViewKey), @@ -355,12 +353,56 @@ impl Note { match (self.note_type, vk) { (NoteType::Transparent, _) => Ok(TRANSPARENT_BLINDER), (NoteType::Obfuscated, Some(vk)) => self - .decrypt_data(vk) + .decrypt_value(vk) .map(|(_, value_blinder)| value_blinder) .map_err(|_| Error::InvalidEncryption), _ => Err(Error::MissingViewKey), } } + + /// Decrypts the [`PublicKey`] of the sender of the [`Note`], using the + /// [`NoteSecretKey`] generated by the receiver's [`SecretKey`] and the + /// [`StealthAddress`] of the [`Note`]. + /// + /// Note: Decryption with an incorrect [`NoteSecretKey`] will still yield a + /// [`PublicKey`], but it will a random one that has nothing to do with the + /// sender's [`PublicKey`]. + pub fn decrypt_sender(&self, note_sk: &NoteSecretKey) -> PublicKey { + let sender_enc_A = self.sender_enc()[0]; + let sender_enc_B = self.sender_enc()[1]; + + let decrypt_A = elgamal::decrypt( + note_sk.as_ref(), + &(sender_enc_A.0.into(), sender_enc_A.1.into()), + ); + let decrypt_B = elgamal::decrypt( + note_sk.as_ref(), + &(sender_enc_B.0.into(), sender_enc_B.1.into()), + ); + + PublicKey::new(decrypt_A, decrypt_B) + } +} + +/// Encrypt the sender [`PublicKey`] in a way that only the receiver of the note +/// can decrypt. +pub fn encrypt_sender( + note_pk: &NotePublicKey, + sender_pk: &PublicKey, + blinder: &[JubJubScalar; 2], +) -> [(JubJubAffine, JubJubAffine); 2] { + let sender_enc_A = + elgamal::encrypt(note_pk.as_ref(), sender_pk.A(), &blinder[0]); + + let sender_enc_B = + elgamal::encrypt(note_pk.as_ref(), sender_pk.B(), &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()); + + [sender_enc_A, sender_enc_B] } const SIZE: usize = 1 diff --git a/core/tests/encryption.rs b/core/tests/encryption.rs index 52f22c4..e4b746b 100644 --- a/core/tests/encryption.rs +++ b/core/tests/encryption.rs @@ -44,10 +44,10 @@ fn test_elgamal_encrypt_and_decrypt() { let (c1, c2) = elgamal::encrypt(pk.A(), &message, &blinder); // Assert decryption - let dec_message = elgamal::decrypt(sk.a(), &c1, &c2); + let dec_message = elgamal::decrypt(sk.a(), &(c1, c2)); assert_eq!(message, dec_message); // Assert decryption using an incorrect key - let dec_message_wrong = elgamal::decrypt(sk.b(), &c1, &c2); + let dec_message_wrong = elgamal::decrypt(sk.b(), &(c1, c2)); assert_ne!(message, dec_message_wrong); } diff --git a/core/tests/keys.rs b/core/tests/keys.rs index 593906e..5226ddb 100644 --- a/core/tests/keys.rs +++ b/core/tests/keys.rs @@ -62,31 +62,38 @@ fn keys_consistency() { let r = JubJubScalar::random(&mut rng); - let sk = SecretKey::random(&mut rng); - let pk = PublicKey::from(&sk); - let vk = ViewKey::from(&sk); + let sender_pk = PublicKey::from(&SecretKey::random(&mut rng)); + let receiver_sk = SecretKey::random(&mut rng); + let receiver_pk = PublicKey::from(&receiver_sk); + let receiver_vk = ViewKey::from(&receiver_sk); let sender_blinder = [ JubJubScalar::random(&mut rng), JubJubScalar::random(&mut rng), ]; - let note = Note::transparent(&mut rng, &pk, NOTE_VALUE, sender_blinder); + let note = Note::transparent( + &mut rng, + &sender_pk, + &receiver_pk, + NOTE_VALUE, + sender_blinder, + ); - assert!(vk.owns(¬e)); - assert!(sk.owns(¬e)); + assert!(receiver_vk.owns(¬e)); + assert!(receiver_sk.owns(¬e)); let wrong_sk = SecretKey::random(&mut rng); let wrong_vk = ViewKey::from(&wrong_sk); - assert_ne!(sk, wrong_sk); - assert_ne!(vk, wrong_vk); + assert_ne!(receiver_sk, wrong_sk); + assert_ne!(receiver_vk, wrong_vk); assert!(!wrong_vk.owns(¬e)); assert!(!wrong_sk.owns(¬e)); - let sa = pk.gen_stealth_address(&r); + let sa = receiver_pk.gen_stealth_address(&r); - let note_sk = sk.gen_note_sk(&sa); + let note_sk = receiver_sk.gen_note_sk(&sa); let wrong_note_sk = wrong_sk.gen_note_sk(&sa); assert_eq!( diff --git a/core/tests/note_test.rs b/core/tests/note_test.rs index c32dd78..eaa64b9 100644 --- a/core/tests/note_test.rs +++ b/core/tests/note_test.rs @@ -4,21 +4,25 @@ // // Copyright (c) DUSK NETWORK. All rights reserved. -use dusk_jubjub::{JubJubAffine, JubJubScalar}; +use dusk_jubjub::JubJubScalar; use ff::Field; use phoenix_core::{ - elgamal, value_commitment, Error, Note, NoteType, PublicKey, SecretKey, - ViewKey, + encrypt_sender, value_commitment, Error, Note, NoteType, PublicKey, + SecretKey, ViewKey, }; use rand::rngs::StdRng; use rand::SeedableRng; +const TRANSPARENT_BLINDER: JubJubScalar = JubJubScalar::zero(); + #[test] fn transparent_note() -> Result<(), Error> { let mut rng = StdRng::seed_from_u64(0xc0b); - let sk = SecretKey::random(&mut rng); - let pk = PublicKey::from(&sk); + let sender_pk = PublicKey::from(&SecretKey::random(&mut rng)); + let receiver_sk = SecretKey::random(&mut rng); + let receiver_pk = PublicKey::from(&receiver_sk); + let value = 25; let sender_blinder = [ @@ -26,10 +30,24 @@ fn transparent_note() -> Result<(), Error> { JubJubScalar::random(&mut rng), ]; - let note = Note::transparent(&mut rng, &pk, value, sender_blinder); + let note = Note::transparent( + &mut rng, + &sender_pk, + &receiver_pk, + value, + sender_blinder, + ); assert_eq!(note.note_type(), NoteType::Transparent); + assert_eq!( + value_commitment(value, TRANSPARENT_BLINDER), + *note.value_commitment() + ); assert_eq!(value, note.value(None)?); + assert_eq!( + sender_pk, + note.decrypt_sender(&receiver_sk.gen_note_sk(note.stealth_address())) + ); Ok(()) } @@ -38,40 +56,37 @@ fn transparent_note() -> Result<(), Error> { fn transparent_stealth_note() -> Result<(), Error> { let mut rng = StdRng::seed_from_u64(0xc0b); - let sk = SecretKey::random(&mut rng); - let pk = PublicKey::from(&sk); + let sender_pk = PublicKey::from(&SecretKey::random(&mut rng)); + let receiver_sk = SecretKey::random(&mut rng); + let receiver_pk = PublicKey::from(&receiver_sk); let r = JubJubScalar::random(&mut rng); - let stealth = pk.gen_stealth_address(&r); + let stealth = receiver_pk.gen_stealth_address(&r); let value = 25; - 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 = encrypt_sender( + stealth.note_pk(), + &sender_pk, + &[ + JubJubScalar::random(&mut rng), + JubJubScalar::random(&mut rng), + ], ); - 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, value, [sender_enc_a, sender_enc_b]); + let note = Note::transparent_stealth(stealth, value, sender_enc); assert_eq!(note.note_type(), NoteType::Transparent); + assert_eq!( + value_commitment(value, TRANSPARENT_BLINDER), + *note.value_commitment() + ); assert_eq!(value, note.value(None)?); assert_eq!(stealth, *note.stealth_address()); + assert_eq!( + sender_pk, + note.decrypt_sender(&receiver_sk.gen_note_sk(note.stealth_address())) + ); Ok(()) } @@ -80,9 +95,11 @@ fn transparent_stealth_note() -> Result<(), Error> { fn obfuscated_note() -> Result<(), Error> { let mut rng = StdRng::seed_from_u64(0xc0b); - let sk = SecretKey::random(&mut rng); - let pk = PublicKey::from(&sk); - let vk = ViewKey::from(&sk); + let sender_pk = PublicKey::from(&SecretKey::random(&mut rng)); + let receiver_sk = SecretKey::random(&mut rng); + let receiver_pk = PublicKey::from(&receiver_sk); + let receiver_vk = ViewKey::from(&receiver_sk); + let value = 25; let value_blinder = JubJubScalar::random(&mut rng); @@ -91,11 +108,25 @@ fn obfuscated_note() -> Result<(), Error> { JubJubScalar::random(&mut rng), ]; - let note = - Note::obfuscated(&mut rng, &pk, value, value_blinder, sender_blinder); + let note = Note::obfuscated( + &mut rng, + &sender_pk, + &receiver_pk, + value, + value_blinder, + sender_blinder, + ); + assert_eq!( + value_commitment(value, value_blinder), + *note.value_commitment() + ); assert_eq!(note.note_type(), NoteType::Obfuscated); - assert_eq!(value, note.value(Some(&vk))?); + assert_eq!(value, note.value(Some(&receiver_vk))?); + assert_eq!( + sender_pk, + note.decrypt_sender(&receiver_sk.gen_note_sk(note.stealth_address())) + ); Ok(()) } @@ -104,9 +135,10 @@ fn obfuscated_note() -> Result<(), Error> { fn obfuscated_deterministic_note() -> Result<(), Error> { let mut rng = StdRng::seed_from_u64(0xc0b); - let sk = SecretKey::random(&mut rng); - let pk = PublicKey::from(&sk); - let vk = ViewKey::from(&sk); + let sender_pk = PublicKey::from(&SecretKey::random(&mut rng)); + let receiver_sk = SecretKey::random(&mut rng); + let receiver_pk = PublicKey::from(&receiver_sk); + let receiver_vk = ViewKey::from(&receiver_sk); let value = 25; let value_blinder = JubJubScalar::random(&mut rng); @@ -118,103 +150,23 @@ fn obfuscated_deterministic_note() -> Result<(), Error> { let note = Note::new( &mut rng, NoteType::Obfuscated, - &pk, + &sender_pk, + &receiver_pk, value, value_blinder, sender_blinder, ); - assert_eq!(value, note.value(Some(&vk))?); - assert_eq!(value_blinder, note.value_blinder(Some(&vk))?); + assert_eq!( + value_commitment(value, value_blinder), + *note.value_commitment() + ); + assert_eq!(value, note.value(Some(&receiver_vk))?); + assert_eq!(value_blinder, note.value_blinder(Some(&receiver_vk))?); + assert_eq!( + sender_pk, + note.decrypt_sender(&receiver_sk.gen_note_sk(note.stealth_address())) + ); Ok(()) } - -#[test] -fn value_commitment_transparent() { - let mut rng = StdRng::seed_from_u64(0xc0b); - - let sk = SecretKey::random(&mut rng); - 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, sender_blinder); - - let value = note - .value(Some(&vk)) - .expect("The note should be owned by the provided 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, value_blinder); - - assert_eq!(commitment, &commitment_p.into()); -} - -#[test] -fn value_commitment_obfuscated() { - let mut rng = StdRng::seed_from_u64(0xc0b); - - let sk = SecretKey::random(&mut rng); - let vk = ViewKey::from(&sk); - let pk = PublicKey::from(&sk); - let value = 25; - - 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 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, value_blinder); - - assert_eq!(commitment, &commitment_p.into()); -} - -#[test] -fn note_keys_consistency() { - let mut rng = StdRng::seed_from_u64(0xc0b); - - let sk = SecretKey::random(&mut rng); - let pk = PublicKey::from(&sk); - let vk = ViewKey::from(&sk); - let value = 25; - - let wrong_sk = SecretKey::random(&mut rng); - let wrong_vk = ViewKey::from(&wrong_sk); - - assert_ne!(sk, wrong_sk); - assert_ne!(vk, wrong_vk); - - 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 b86e676..f5351f8 100644 --- a/core/tests/transaction.rs +++ b/core/tests/transaction.rs @@ -16,8 +16,8 @@ use rand::rngs::OsRng; fn transaction_parse() -> Result<(), Error> { let mut rng = OsRng; - let sk = SecretKey::random(&mut rng); - let pk = PublicKey::from(&sk); + let sender_pk = PublicKey::from(&SecretKey::random(&mut rng)); + let receiver_pk = PublicKey::from(&SecretKey::random(&mut rng)); let value = 25; let value_blinder = JubJubScalar::random(&mut rng); @@ -25,8 +25,14 @@ fn transaction_parse() -> Result<(), Error> { JubJubScalar::random(&mut rng), JubJubScalar::random(&mut rng), ]; - let note = - Note::obfuscated(&mut rng, &pk, value, value_blinder, sender_blinder); + let note = Note::obfuscated( + &mut rng, + &sender_pk, + &receiver_pk, + value, + value_blinder, + sender_blinder, + ); let root = BlsScalar::from(123); let nullifiers = vec![BlsScalar::from(456), BlsScalar::from(789)];