diff --git a/noir-projects/aztec-nr/aztec/src/encrypted_logs/encrypted_event_emission.nr b/noir-projects/aztec-nr/aztec/src/encrypted_logs/encrypted_event_emission.nr index 70953b5fe66..8c1293b590d 100644 --- a/noir-projects/aztec-nr/aztec/src/encrypted_logs/encrypted_event_emission.nr +++ b/noir-projects/aztec-nr/aztec/src/encrypted_logs/encrypted_event_emission.nr @@ -1,6 +1,6 @@ use crate::{ context::PrivateContext, event::event_interface::EventInterface, - encrypted_logs::payload::compute_encrypted_event_log, + encrypted_logs::payload::compute_encrypted_log, keys::{getters::get_public_keys, public_keys::{OvpkM, IvpkM}}, oracle::logs_traits::LensForEncryptedEvent, oracle::unsafe_rand::unsafe_rand }; @@ -35,15 +35,8 @@ fn compute( recipient: AztecAddress, event: Event ) -> ([u8; OB], Field) where Event: EventInterface, [u8; N * 32 + 64]: LensForEncryptedEvent { - let encrypted_log: [u8; OB] = compute_encrypted_event_log( - contract_address, - randomness, - ovsk_app, - ovpk, - ivpk, - recipient, - event - ); + let plaintext = event.private_to_be_bytes(randomness); + let encrypted_log: [u8; OB] = compute_encrypted_log(contract_address, ovsk_app, ovpk, ivpk, recipient, plaintext); let log_hash = sha256_to_field(encrypted_log); (encrypted_log, log_hash) } diff --git a/noir-projects/aztec-nr/aztec/src/encrypted_logs/encrypted_note_emission.nr b/noir-projects/aztec-nr/aztec/src/encrypted_logs/encrypted_note_emission.nr index ef119581594..c72c89ec958 100644 --- a/noir-projects/aztec-nr/aztec/src/encrypted_logs/encrypted_note_emission.nr +++ b/noir-projects/aztec-nr/aztec/src/encrypted_logs/encrypted_note_emission.nr @@ -1,7 +1,7 @@ use crate::{ context::PrivateContext, note::{note_emission::NoteEmission, note_interface::NoteInterface}, keys::{getters::{get_public_keys, get_ovsk_app}, public_keys::{OvpkM, IvpkM}}, - encrypted_logs::payload::compute_encrypted_note_log, oracle::logs_traits::LensForEncryptedLog + encrypted_logs::payload::compute_encrypted_log, oracle::logs_traits::LensForEncryptedLog }; use dep::protocol_types::{hash::sha256_to_field, address::AztecAddress, abis::note_hash::NoteHash}; @@ -23,15 +23,8 @@ fn compute_raw_note_log( let contract_address: AztecAddress = context.this_address(); - let encrypted_log: [u8; M] = compute_encrypted_note_log( - contract_address, - storage_slot, - ovsk_app, - ovpk, - ivpk, - recipient, - note - ); + let plaintext = note.to_be_bytes(storage_slot); + let encrypted_log: [u8; M] = compute_encrypted_log(contract_address, ovsk_app, ovpk, ivpk, recipient, plaintext); let log_hash = sha256_to_field(encrypted_log); (note_hash_counter, encrypted_log, log_hash) diff --git a/noir-projects/aztec-nr/aztec/src/encrypted_logs/incoming_body.nr b/noir-projects/aztec-nr/aztec/src/encrypted_logs/incoming_body.nr deleted file mode 100644 index 171ed82ebce..00000000000 --- a/noir-projects/aztec-nr/aztec/src/encrypted_logs/incoming_body.nr +++ /dev/null @@ -1,286 +0,0 @@ -use crate::note::note_interface::NoteInterface; -use crate::event::event_interface::EventInterface; -use dep::protocol_types::{scalar::Scalar}; - -use std::aes128::aes128_encrypt; -use crate::keys::{point_to_symmetric_key::point_to_symmetric_key, public_keys::IvpkM}; - -pub struct EncryptedLogIncomingBody { - plaintext: [u8; N * 32 + 64] -} - -impl EncryptedLogIncomingBody { - pub fn from_note(note: T, storage_slot: Field) -> Self where T: NoteInterface { - let mut plaintext = note.to_be_bytes(storage_slot); - EncryptedLogIncomingBody { plaintext } - } - - pub fn from_event(event: T, randomness: Field) -> Self where T: EventInterface { - let mut plaintext = event.private_to_be_bytes(randomness); - EncryptedLogIncomingBody { plaintext } - } - - pub fn compute_ciphertext(self, eph_sk: Scalar, ivpk: IvpkM) -> [u8] { - let full_key = point_to_symmetric_key(eph_sk, ivpk.to_point()); - let mut sym_key = [0; 16]; - let mut iv = [0; 16]; - - for i in 0..16 { - sym_key[i] = full_key[i]; - iv[i] = full_key[i + 16]; - } - aes128_encrypt(self.plaintext, iv, sym_key) - } -} - -mod test { - use dep::protocol_types::{ - address::AztecAddress, scalar::Scalar, point::Point, traits::Serialize, - abis::event_selector::EventSelector - }; - - use crate::{ - note::{note_header::NoteHeader, note_interface::{NoteInterface, NullifiableNote}}, - encrypted_logs::incoming_body::EncryptedLogIncomingBody, event::event_interface::EventInterface, - context::PrivateContext, keys::public_keys::IvpkM - }; - - struct AddressNote { - address: AztecAddress, - owner: AztecAddress, - randomness: Field, - header: NoteHeader, - } - - global ADDRESS_NOTE_LEN: u32 = 3; - - impl NullifiableNote for AddressNote { - fn compute_nullifier( - _self: Self, - _context: &mut PrivateContext, - _note_hash_for_nullify: Field - ) -> Field { - 1 - } - - unconstrained fn compute_nullifier_without_context(_self: Self) -> Field { - 1 - } - } - - struct AddressNoteHidingPoint { - inner: Point - } - - impl NoteInterface for AddressNote { - - fn get_note_type_id() -> Field { - 1 - } - - fn get_header(self) -> NoteHeader { - self.header - } - - fn set_header(&mut self, header: NoteHeader) { - self.header = header; - } - - fn serialize_content(self) -> [Field; ADDRESS_NOTE_LEN] { - [self.address.to_field(), self.owner.to_field(), self.randomness] - } - - fn deserialize_content(fields: [Field; ADDRESS_NOTE_LEN]) -> Self { - AddressNote { - address: AztecAddress::from_field(fields[0]), - owner: AztecAddress::from_field(fields[1]), - randomness: fields[2], - header: NoteHeader::empty() - } - } - - fn to_be_bytes(self, storage_slot: Field) -> [u8; ADDRESS_NOTE_LEN * 32 + 64] { - let serialized_note = self.serialize_content(); - - let mut buffer: [u8; ADDRESS_NOTE_LEN * 32 + 64] = [0; ADDRESS_NOTE_LEN * 32 + 64]; - - let storage_slot_bytes: [u8; 32] = storage_slot.to_be_bytes(); - let note_type_id_bytes: [u8; 32] = AddressNote::get_note_type_id().to_be_bytes(); - - for i in 0..32 { - buffer[i] = storage_slot_bytes[i]; - buffer[32 + i] = note_type_id_bytes[i]; - } - - for i in 0..serialized_note.len() { - let bytes: [u8; 32] = serialized_note[i].to_be_bytes(); - for j in 0..32 { - buffer[64 + i * 32 + j] = bytes[j]; - } - } - buffer - } - - fn compute_note_hash(_self: Self) -> Field { - crate::generators::Ga1.x - } - } - - impl AddressNote { - pub fn new(address: AztecAddress, owner: AztecAddress, randomness: Field) -> Self { - AddressNote { address, owner, randomness, header: NoteHeader::empty() } - } - } - - #[test] - unconstrained fn test_encrypted_note_log_incoming_body_matches_typescript() { - // All the values in this test were copied over from `encrypted_note_log_incoming_body.test.ts` - let note = AddressNote::new( - AztecAddress::from_field(0x1), - AztecAddress::from_field(0x2), - 3 - ); - - let storage_slot = 2; - - let eph_sk = Scalar { - lo: 0x00000000000000000000000000000000649e7ca01d9de27b21624098b897babd, - hi: 0x0000000000000000000000000000000023b3127c127b1f29a7adff5cccf8fb06 - }; - let ivpk = IvpkM { - inner: Point { - x: 0x2688431c705a5ff3e6c6f2573c9e3ba1c1026d2251d0dbbf2d810aa53fd1d186, - y: 0x1e96887b117afca01c00468264f4f80b5bb16d94c1808a448595f115556e5c8e, - is_infinite: false - } - }; - - // 1. `EncryptedLogIncomingBody::from_note` calls `note.to_be_bytes(storage_slot)` function which serializes - // the note to bytes - note that in the case of `AddressNote` the `to_be_bytes` function was automatically - // implemented by Aztec macros. - let body = EncryptedLogIncomingBody::from_note(note, storage_slot); - - // 2. `body.compute_ciphertext(...)` function then derives symmetric key from `eph_sk` and `ivpk` and encrypts - // the note plaintext using AES-128. - let ciphertext = body.compute_ciphertext(eph_sk, ivpk); - - // The following value was generated by `encrypted_note_log_incoming_body.test.ts`. - // --> Run the test with AZTEC_GENERATE_TEST_DATA=1 flag to update test data. - let note_body_ciphertext_from_typescript = [ - 226, 240, 253, 6, 28, 52, 19, 131, 33, 132, 178, 212, 245, 62, 14, 190, 147, 228, 160, 190, 146, 61, 95, 203, 124, 153, 68, 168, 17, 150, 92, 0, 99, 214, 85, 64, 191, 78, 157, 131, 149, 96, 236, 253, 96, 172, 157, 30, 27, 176, 228, 74, 242, 190, 138, 48, 33, 93, 46, 37, 223, 130, 25, 245, 188, 163, 159, 223, 187, 24, 139, 206, 131, 154, 159, 130, 37, 17, 158, 114, 242, 141, 124, 193, 232, 54, 146, 96, 145, 100, 125, 234, 57, 43, 95, 115, 183, 39, 121, 232, 134, 229, 148, 25, 46, 77, 87, 127, 95, 7, 77, 188, 37, 234, 245, 142, 232, 87, 252, 28, 67, 67, 90, 214, 254, 89, 47, 68, 66, 187, 227, 8, 59, 162, 25, 141, 97, 141, 217, 197, 115, 15, 212, 202, 157, 41, 150, 62, 219, 57, 224, 92, 185, 212, 142, 94, 146, 41, 178, 145, 68, 169, 23, 185, 206, 138, 70, 47, 176, 210, 165, 236, 23, 206, 229, 108 - ]; - - assert_eq(note_body_ciphertext_from_typescript.len(), ciphertext.len()); - - for i in 0..note_body_ciphertext_from_typescript.len() { - assert_eq(ciphertext[i], note_body_ciphertext_from_typescript[i]); - } - } - - struct TestEvent { - value0: Field, - value1: Field, - value2: Field, - } - - impl Serialize<3> for TestEvent { - fn serialize(self) -> [Field; 3] { - [self.value0, self.value1, self.value2] - } - } - - global TEST_EVENT_LEN: u32 = 3; - - impl EventInterface for TestEvent { - fn get_event_type_id() -> EventSelector { - comptime - { - EventSelector::from_signature("TestEvent(Field,Field,Field)") - } - } - - fn private_to_be_bytes(self, randomness: Field) -> [u8; TEST_EVENT_LEN * 32 + 64] { - let mut buffer: [u8; TEST_EVENT_LEN * 32 + 64] = [0; TEST_EVENT_LEN * 32 + 64]; - - let randomness_bytes: [u8; 32] = randomness.to_be_bytes(); - let event_type_id_bytes: [u8; 32] = TestEvent::get_event_type_id().to_field().to_be_bytes(); - - for i in 0..32 { - buffer[i] = randomness_bytes[i]; - buffer[32 + i] = event_type_id_bytes[i]; - } - - let serialized_event = self.serialize(); - - for i in 0..serialized_event.len() { - let bytes: [u8; 32] = serialized_event[i].to_be_bytes(); - for j in 0..32 { - buffer[64 + i * 32 + j] = bytes[j]; - } - } - - buffer - } - - fn to_be_bytes(self) -> [u8; TEST_EVENT_LEN * 32 + 32] { - let mut buffer: [u8; TEST_EVENT_LEN * 32 + 32] = [0; TEST_EVENT_LEN * 32 + 32]; - - let event_type_id_bytes: [u8; 32] = TestEvent::get_event_type_id().to_field().to_be_bytes(); - - for i in 0..32 { - buffer[i] = event_type_id_bytes[i]; - } - - let serialized_event = self.serialize(); - - for i in 0..serialized_event.len() { - let bytes: [u8; 32] = serialized_event[i].to_be_bytes(); - for j in 0..32 { - buffer[32 + i * 32 + j] = bytes[j]; - } - } - - buffer - } - - fn emit(self, _emit: fn[Env](Self) -> ()) { - _emit(self); - } - } - - #[test] - unconstrained fn test_encrypted_log_event_incoming_body() { - let test_event = TestEvent { value0: 1, value1: 2, value2: 3 }; - - let eph_sk = Scalar { - lo: 0x00000000000000000000000000000000649e7ca01d9de27b21624098b897babd, - hi: 0x0000000000000000000000000000000023b3127c127b1f29a7adff5cccf8fb06 - }; - - let ivpk = IvpkM { - inner: Point { - x: 0x2688431c705a5ff3e6c6f2573c9e3ba1c1026d2251d0dbbf2d810aa53fd1d186, - y: 0x1e96887b117afca01c00468264f4f80b5bb16d94c1808a448595f115556e5c8e, - is_infinite: false - } - }; - - let randomness = 2; - - let body = EncryptedLogIncomingBody::from_event(test_event, randomness); - - let ciphertext = body.compute_ciphertext(eph_sk, ivpk); - - // The following value was generated by `encrypted_event_log_incoming_body.test.ts` - // --> Run the test with AZTEC_GENERATE_TEST_DATA=1 flag to update test data. - let event_body_ciphertext_from_typescript = [ - 226, 240, 253, 6, 28, 52, 19, 131, 33, 132, 178, 212, 245, 62, 14, 190, 147, 228, 160, 190, 146, 61, 95, 203, 124, 153, 68, 168, 17, 150, 92, 0, 99, 214, 85, 64, 191, 78, 157, 131, 149, 96, 236, 253, 96, 172, 157, 30, 201, 247, 40, 80, 60, 188, 158, 251, 242, 103, 197, 79, 165, 195, 10, 160, 255, 35, 167, 152, 25, 233, 77, 145, 214, 243, 210, 119, 0, 20, 29, 95, 15, 63, 33, 190, 184, 67, 254, 96, 128, 243, 220, 228, 201, 130, 86, 163, 52, 127, 111, 10, 212, 7, 160, 16, 87, 13, 39, 11, 5, 1, 164, 65, 8, 56, 82, 245, 13, 68, 176, 90, 100, 69, 243, 78, 117, 188, 221, 34, 178, 31, 155, 89, 143, 176, 129, 118, 36, 236, 64, 179, 52, 239, 184, 51, 51, 199, 221, 49, 81, 197, 17, 199, 192, 99, 49, 168, 157, 164, 190, 33, 240, 182, 214, 173, 7, 156, 102, 95, 65, 217, 225, 123, 42, 21, 124, 144 - ]; - - assert_eq(event_body_ciphertext_from_typescript.len(), ciphertext.len()); - - for i in 0..event_body_ciphertext_from_typescript.len() { - assert_eq(ciphertext[i], event_body_ciphertext_from_typescript[i]); - } - } -} diff --git a/noir-projects/aztec-nr/aztec/src/encrypted_logs/mod.nr b/noir-projects/aztec-nr/aztec/src/encrypted_logs/mod.nr index dfc49fc0a86..3053e35728f 100644 --- a/noir-projects/aztec-nr/aztec/src/encrypted_logs/mod.nr +++ b/noir-projects/aztec-nr/aztec/src/encrypted_logs/mod.nr @@ -1,6 +1,4 @@ mod header; -mod incoming_body; -mod outgoing_body; mod payload; mod encrypted_note_emission; mod encrypted_event_emission; diff --git a/noir-projects/aztec-nr/aztec/src/encrypted_logs/outgoing_body.nr b/noir-projects/aztec-nr/aztec/src/encrypted_logs/outgoing_body.nr deleted file mode 100644 index 9b163ff3747..00000000000 --- a/noir-projects/aztec-nr/aztec/src/encrypted_logs/outgoing_body.nr +++ /dev/null @@ -1,100 +0,0 @@ -use dep::protocol_types::{ - address::AztecAddress, scalar::Scalar, point::Point, constants::GENERATOR_INDEX__SYMMETRIC_KEY, - hash::poseidon2_hash_with_separator -}; -use std::aes128::aes128_encrypt; - -use crate::{keys::public_keys::IvpkM, utils::point::point_to_bytes}; - -pub struct EncryptedLogOutgoingBody { - eph_sk: Scalar, - recipient: AztecAddress, - recipient_ivpk: IvpkM, -} - -impl EncryptedLogOutgoingBody { - pub fn new(eph_sk: Scalar, recipient: AztecAddress, recipient_ivpk: IvpkM) -> Self { - Self { eph_sk, recipient, recipient_ivpk } - } - - /// Encrypts ephemeral secret key and recipient's ivpk --> with this information the recipient of outgoing will - /// be able to derive the key with which the incoming log can be decrypted. - pub fn compute_ciphertext(self, ovsk_app: Scalar, eph_pk: Point) -> [u8; 144] { - // Again, we could compute `eph_pk` here, but we keep the interface more similar - // and also make it easier to optimise it later as we just pass it along - - let mut buffer = [0 as u8; 128]; - - let serialized_eph_sk_high: [u8; 32] = self.eph_sk.hi.to_be_bytes(); - let serialized_eph_sk_low: [u8; 32] = self.eph_sk.lo.to_be_bytes(); - - let address_bytes: [u8; 32] = self.recipient.to_field().to_be_bytes(); - let serialized_recipient_ivpk = point_to_bytes(self.recipient_ivpk.to_point()); - - for i in 0..32 { - buffer[i] = serialized_eph_sk_high[i]; - buffer[i + 32] = serialized_eph_sk_low[i]; - buffer[i + 64] = address_bytes[i]; - } - for i in 0..32 { - buffer[i + 96] = serialized_recipient_ivpk[i]; - } - - // We compute the symmetric key using poseidon. - let full_key: [u8; 32] = poseidon2_hash_with_separator( - [ovsk_app.hi, ovsk_app.lo, eph_pk.x, eph_pk.y], - GENERATOR_INDEX__SYMMETRIC_KEY as Field - ).to_be_bytes(); - - let mut sym_key = [0; 16]; - let mut iv = [0; 16]; - - for i in 0..16 { - sym_key[i] = full_key[i]; - iv[i] = full_key[i + 16]; - } - aes128_encrypt(buffer, iv, sym_key).as_array() - } -} - -mod test { - use crate::{encrypted_logs::outgoing_body::EncryptedLogOutgoingBody, keys::public_keys::IvpkM}; - use dep::protocol_types::{address::AztecAddress, scalar::Scalar}; - use std::embedded_curve_ops::fixed_base_scalar_mul as derive_public_key; - - #[test] - unconstrained fn test_encrypted_log_outgoing_body_matches_typescript() { - let eph_sk = Scalar { - lo: 0x00000000000000000000000000000000d0d302ee245dfaf2807e604eec4715fe, - hi: 0x000000000000000000000000000000000f096b423017226a18461115fa8d34bb - }; - let recipient_ivsk = Scalar { - lo: 0x000000000000000000000000000000004828f8f95676ebb481df163f87fd4022, - hi: 0x000000000000000000000000000000000f4d97c25d578f9348251a71ca17ae31 - }; - let sender_ovsk_app = Scalar { - lo: 0x0000000000000000000000000000000074d2e28c6bc5176ac02cf7c7d36a444e, - hi: 0x00000000000000000000000000000000089c6887cb1446d86c64e81afc78048b - }; - - let eph_pk = derive_public_key(eph_sk); - let recipient_ivpk = IvpkM { inner: derive_public_key(recipient_ivsk) }; - - let recipient = AztecAddress::from_field(0xdeadbeef); - - let body = EncryptedLogOutgoingBody::new(eph_sk, recipient, recipient_ivpk); - - let ciphertext = body.compute_ciphertext(sender_ovsk_app, eph_pk); - - // The following value was generated by `encrypted_log_outgoing_body.test.ts` - // --> Run the test with AZTEC_GENERATE_TEST_DATA=1 flag to update test data. - let outgoing_body_ciphertext_from_typescript = [ - 127, 182, 227, 75, 192, 197, 54, 47, 168, 134, 233, 148, 251, 46, 86, 12, 73, 50, 238, 50, 31, 174, 27, 202, 110, 77, 161, 197, 244, 124, 17, 100, 143, 150, 232, 14, 156, 248, 43, 177, 16, 82, 244, 103, 88, 74, 84, 200, 15, 65, 187, 14, 163, 60, 91, 22, 104, 31, 211, 190, 124, 121, 79, 92, 239, 65, 185, 106, 51, 178, 168, 137, 84, 43, 79, 158, 151, 152, 83, 42, 170, 13, 106, 209, 254, 74, 39, 145, 73, 215, 17, 234, 196, 89, 30, 58, 120, 127, 88, 69, 121, 61, 18, 206, 89, 118, 243, 238, 177, 71, 73, 47, 147, 4, 155, 25, 173, 248, 206, 52, 17, 180, 122, 186, 106, 191, 252, 102, 197, 91, 16, 39, 94, 91, 224, 30, 168, 177, 26, 144, 5, 124, 128, 6 - ]; - - for i in 0..outgoing_body_ciphertext_from_typescript.len() { - assert_eq(ciphertext[i], outgoing_body_ciphertext_from_typescript[i]); - } - assert_eq(outgoing_body_ciphertext_from_typescript.len(), ciphertext.len()); - } -} diff --git a/noir-projects/aztec-nr/aztec/src/encrypted_logs/payload.nr b/noir-projects/aztec-nr/aztec/src/encrypted_logs/payload.nr index 3446a668998..1ee263153e6 100644 --- a/noir-projects/aztec-nr/aztec/src/encrypted_logs/payload.nr +++ b/noir-projects/aztec-nr/aztec/src/encrypted_logs/payload.nr @@ -1,87 +1,34 @@ -use dep::protocol_types::{address::AztecAddress, scalar::Scalar, point::Point}; +use dep::protocol_types::{ + address::AztecAddress, scalar::Scalar, point::Point, constants::GENERATOR_INDEX__SYMMETRIC_KEY, + hash::poseidon2_hash_with_separator +}; use std::{ - embedded_curve_ops::fixed_base_scalar_mul as derive_public_key, + aes128::aes128_encrypt, embedded_curve_ops::fixed_base_scalar_mul as derive_public_key, hash::from_field_unsafe as fr_to_fq_unsafe, field::bn254::decompose }; use crate::{ - event::event_interface::EventInterface, oracle::unsafe_rand::unsafe_rand, - utils::point::point_to_bytes, note::note_interface::NoteInterface, - encrypted_logs::{ - header::EncryptedLogHeader, incoming_body::EncryptedLogIncomingBody, - outgoing_body::EncryptedLogOutgoingBody -}, - keys::public_keys::{OvpkM, IvpkM} + oracle::unsafe_rand::unsafe_rand, utils::point::point_to_bytes, + encrypted_logs::{header::EncryptedLogHeader}, + keys::{point_to_symmetric_key::point_to_symmetric_key, public_keys::{OvpkM, IvpkM}} }; -pub fn compute_encrypted_event_log( +pub fn compute_encrypted_log( contract_address: AztecAddress, - randomness: Field, ovsk_app: Field, ovpk: OvpkM, ivpk: IvpkM, recipient: AztecAddress, - event: Event -) -> [u8; OB] where Event: EventInterface { + plaintext: [u8; P] +) -> [u8; M] { let (eph_sk, eph_pk) = generate_ephemeral_key_pair(); let header = EncryptedLogHeader::new(contract_address); let incoming_header_ciphertext: [u8; 48] = header.compute_ciphertext(eph_sk, ivpk); let outgoing_header_ciphertext: [u8; 48] = header.compute_ciphertext(eph_sk, ovpk); - let incoming_body_ciphertext = EncryptedLogIncomingBody::from_event(event, randomness).compute_ciphertext(eph_sk, ivpk); - let outgoing_body_ciphertext: [u8; 144] = EncryptedLogOutgoingBody::new(eph_sk, recipient, ivpk).compute_ciphertext(fr_to_fq(ovsk_app), eph_pk); - - let mut encrypted_bytes: [u8; OB] = [0; OB]; - // @todo We ignore the tags for now - - let eph_pk_bytes = point_to_bytes(eph_pk); - for i in 0..32 { - encrypted_bytes[64 + i] = eph_pk_bytes[i]; - } - for i in 0..48 { - encrypted_bytes[96 + i] = incoming_header_ciphertext[i]; - encrypted_bytes[144 + i] = outgoing_header_ciphertext[i]; - } - for i in 0..144 { - encrypted_bytes[192 + i] = outgoing_body_ciphertext[i]; - } - // Then we fill in the rest as the incoming body ciphertext - let size = OB - 336; - assert_eq(size, incoming_body_ciphertext.len(), "ciphertext length mismatch"); - for i in 0..size { - encrypted_bytes[336 + i] = incoming_body_ciphertext[i]; - } - - // Current unoptimized size of the encrypted log - // incoming_tag (32 bytes) - // outgoing_tag (32 bytes) - // eph_pk (32 bytes) - // incoming_header (48 bytes) - // outgoing_header (48 bytes) - // outgoing_body (144 bytes) - // incoming_body_fixed (64 bytes) - // incoming_body_variable (N * 32 bytes + 16 bytes padding) - encrypted_bytes -} - -pub fn compute_encrypted_note_log( - contract_address: AztecAddress, - storage_slot: Field, - ovsk_app: Field, - ovpk: OvpkM, - ivpk: IvpkM, - recipient: AztecAddress, - note: Note -) -> [u8; M] where Note: NoteInterface { - let (eph_sk, eph_pk) = generate_ephemeral_key_pair(); - - let header = EncryptedLogHeader::new(contract_address); - - let incoming_header_ciphertext: [u8; 48] = header.compute_ciphertext(eph_sk, ivpk); - let outgoing_header_ciphertext: [u8; 48] = header.compute_ciphertext(eph_sk, ovpk); - let incoming_body_ciphertext = EncryptedLogIncomingBody::from_note(note, storage_slot).compute_ciphertext(eph_sk, ivpk); - let outgoing_body_ciphertext: [u8; 144] = EncryptedLogOutgoingBody::new(eph_sk, recipient, ivpk).compute_ciphertext(fr_to_fq(ovsk_app), eph_pk); + let incoming_body_ciphertext = compute_incoming_body_ciphertext(plaintext, eph_sk, ivpk); + let outgoing_body_ciphertext: [u8; 144] = compute_outgoing_body_ciphertext(recipient, ivpk, fr_to_fq(ovsk_app), eph_sk, eph_pk); let mut encrypted_bytes: [u8; M] = [0; M]; // @todo We ignore the tags for now @@ -112,7 +59,7 @@ pub fn compute_encrypted_note_log( // outgoing_header (48 bytes) // outgoing_body (144 bytes) // incoming_body_fixed (64 bytes) - // incoming_body_variable (N * 32 bytes + 16 bytes padding) + // incoming_body_variable (P + 16 bytes padding) encrypted_bytes } @@ -134,12 +81,70 @@ fn generate_ephemeral_key_pair() -> (Scalar, Point) { (eph_sk, eph_pk) } +pub fn compute_incoming_body_ciphertext(plaintext: [u8; P], eph_sk: Scalar, ivpk: IvpkM) -> [u8] { + let full_key = point_to_symmetric_key(eph_sk, ivpk.to_point()); + let mut sym_key = [0; 16]; + let mut iv = [0; 16]; + + for i in 0..16 { + sym_key[i] = full_key[i]; + iv[i] = full_key[i + 16]; + } + aes128_encrypt(plaintext, iv, sym_key) +} + +/// Encrypts ephemeral secret key and recipient's ivpk --> with this information the recipient of outgoing will +/// be able to derive the key with which the incoming log can be decrypted. +pub fn compute_outgoing_body_ciphertext( + recipient: AztecAddress, + recipient_ivpk: IvpkM, + ovsk_app: Scalar, + eph_sk: Scalar, + eph_pk: Point +) -> [u8; 144] { + // Again, we could compute `eph_pk` here, but we keep the interface more similar + // and also make it easier to optimise it later as we just pass it along + + let mut buffer = [0 as u8; 128]; + + let serialized_eph_sk_high: [u8; 32] = eph_sk.hi.to_be_bytes(); + let serialized_eph_sk_low: [u8; 32] = eph_sk.lo.to_be_bytes(); + + let address_bytes: [u8; 32] = recipient.to_field().to_be_bytes(); + let serialized_recipient_ivpk = point_to_bytes(recipient_ivpk.to_point()); + + for i in 0..32 { + buffer[i] = serialized_eph_sk_high[i]; + buffer[i + 32] = serialized_eph_sk_low[i]; + buffer[i + 64] = address_bytes[i]; + } + for i in 0..32 { + buffer[i + 96] = serialized_recipient_ivpk[i]; + } + + // We compute the symmetric key using poseidon. + let full_key: [u8; 32] = poseidon2_hash_with_separator( + [ovsk_app.hi, ovsk_app.lo, eph_pk.x, eph_pk.y], + GENERATOR_INDEX__SYMMETRIC_KEY as Field + ).to_be_bytes(); + + let mut sym_key = [0; 16]; + let mut iv = [0; 16]; + + for i in 0..16 { + sym_key[i] = full_key[i]; + iv[i] = full_key[i + 16]; + } + aes128_encrypt(buffer, iv, sym_key).as_array() +} + mod test { use crate::{ - encrypted_logs::payload::compute_encrypted_note_log, keys::public_keys::{OvpkM, IvpkM}, - test::mocks::mock_note::MockNoteBuilder + encrypted_logs::payload::{compute_encrypted_log, compute_incoming_body_ciphertext, compute_outgoing_body_ciphertext}, + keys::public_keys::{OvpkM, IvpkM}, test::mocks::mock_note::MockNoteBuilder }; - use dep::protocol_types::{address::AztecAddress, point::Point}; + use std::embedded_curve_ops::fixed_base_scalar_mul as derive_public_key; + use dep::protocol_types::{address::AztecAddress, point::Point, scalar::Scalar}; use std::test::OracleMock; #[test] @@ -165,21 +170,14 @@ mod test { let note_value = 0x301640ceea758391b2e161c92c0513f129020f4125256afdae2646ce31099f5c; let note = MockNoteBuilder::new(note_value).contract_address(contract_address).storage_slot(storage_slot).build(); + let plaintext = note.to_be_bytes(storage_slot); let eph_sk = 0x1358d15019d4639393d62b97e1588c095957ce74a1c32d6ec7d62fe6705d9538; let _ = OracleMock::mock("getRandomField").returns(eph_sk); let recipient = AztecAddress::from_field(0x10ee41ee4b62703b16f61e03cb0d88c4b306a9eb4a6ceeb2aff13428541689a2); - let log: [u8; 448] = compute_encrypted_note_log( - contract_address, - storage_slot, - ovsk_app, - ovpk_m, - ivpk_m, - recipient, - note - ); + let log: [u8; 448] = compute_encrypted_log(contract_address, ovsk_app, ovpk_m, ivpk_m, recipient, plaintext); // The following value was generated by `tagged_log.test.ts` // --> Run the test with AZTEC_GENERATE_TEST_DATA=1 flag to update test data. @@ -188,4 +186,73 @@ mod test { ]; assert_eq(encrypted_note_log_from_typescript, log); } + + #[test] + fn test_incoming_body_ciphertext_matches_typescript() { + // All the values in this test were copied over from `encrypted_note_log_incoming_body.test.ts` + let eph_sk = Scalar { + lo: 0x00000000000000000000000000000000649e7ca01d9de27b21624098b897babd, + hi: 0x0000000000000000000000000000000023b3127c127b1f29a7adff5cccf8fb06 + }; + let ivpk = IvpkM { + inner: Point { + x: 0x2688431c705a5ff3e6c6f2573c9e3ba1c1026d2251d0dbbf2d810aa53fd1d186, + y: 0x1e96887b117afca01c00468264f4f80b5bb16d94c1808a448595f115556e5c8e, + is_infinite: false + } + }; + let plaintext = [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3 + ]; + + // `compute_incoming_body_ciphertext(...)` function then derives symmetric key from `eph_sk` and `ivpk` and encrypts + // the note plaintext using AES-128. + let ciphertext = compute_incoming_body_ciphertext(plaintext, eph_sk, ivpk); + + // The following value was generated by `encrypted_note_log_incoming_body.test.ts`. + // --> Run the test with AZTEC_GENERATE_TEST_DATA=1 flag to update test data. + let note_body_ciphertext_from_typescript = [ + 226, 240, 253, 6, 28, 52, 19, 131, 33, 132, 178, 212, 245, 62, 14, 190, 147, 228, 160, 190, 146, 61, 95, 203, 124, 153, 68, 168, 17, 150, 92, 0, 99, 214, 85, 64, 191, 78, 157, 131, 149, 96, 236, 253, 96, 172, 157, 30, 27, 176, 228, 74, 242, 190, 138, 48, 33, 93, 46, 37, 223, 130, 25, 245, 188, 163, 159, 223, 187, 24, 139, 206, 131, 154, 159, 130, 37, 17, 158, 114, 242, 141, 124, 193, 232, 54, 146, 96, 145, 100, 125, 234, 57, 43, 95, 115, 183, 39, 121, 232, 134, 229, 148, 25, 46, 77, 87, 127, 95, 7, 77, 188, 37, 234, 245, 142, 232, 87, 252, 28, 67, 67, 90, 214, 254, 89, 47, 68, 66, 187, 227, 8, 59, 162, 25, 141, 97, 141, 217, 197, 115, 15, 212, 202, 157, 41, 150, 62, 219, 57, 224, 92, 185, 212, 142, 94, 146, 41, 178, 145, 68, 169, 23, 185, 206, 138, 70, 47, 176, 210, 165, 236, 23, 206, 229, 108 + ]; + + assert_eq(note_body_ciphertext_from_typescript.len(), ciphertext.len()); + + for i in 0..note_body_ciphertext_from_typescript.len() { + assert_eq(ciphertext[i], note_body_ciphertext_from_typescript[i]); + } + } + + #[test] + fn test_encrypted_log_outgoing_body_matches_typescript() { + let eph_sk = Scalar { + lo: 0x00000000000000000000000000000000d0d302ee245dfaf2807e604eec4715fe, + hi: 0x000000000000000000000000000000000f096b423017226a18461115fa8d34bb + }; + let recipient_ivsk = Scalar { + lo: 0x000000000000000000000000000000004828f8f95676ebb481df163f87fd4022, + hi: 0x000000000000000000000000000000000f4d97c25d578f9348251a71ca17ae31 + }; + let sender_ovsk_app = Scalar { + lo: 0x0000000000000000000000000000000074d2e28c6bc5176ac02cf7c7d36a444e, + hi: 0x00000000000000000000000000000000089c6887cb1446d86c64e81afc78048b + }; + + let eph_pk = derive_public_key(eph_sk); + let recipient_ivpk = IvpkM { inner: derive_public_key(recipient_ivsk) }; + + let recipient = AztecAddress::from_field(0xdeadbeef); + + let ciphertext = compute_outgoing_body_ciphertext(recipient, recipient_ivpk, sender_ovsk_app, eph_sk, eph_pk); + + // The following value was generated by `encrypted_log_outgoing_body.test.ts` + // --> Run the test with AZTEC_GENERATE_TEST_DATA=1 flag to update test data. + let outgoing_body_ciphertext_from_typescript = [ + 127, 182, 227, 75, 192, 197, 54, 47, 168, 134, 233, 148, 251, 46, 86, 12, 73, 50, 238, 50, 31, 174, 27, 202, 110, 77, 161, 197, 244, 124, 17, 100, 143, 150, 232, 14, 156, 248, 43, 177, 16, 82, 244, 103, 88, 74, 84, 200, 15, 65, 187, 14, 163, 60, 91, 22, 104, 31, 211, 190, 124, 121, 79, 92, 239, 65, 185, 106, 51, 178, 168, 137, 84, 43, 79, 158, 151, 152, 83, 42, 170, 13, 106, 209, 254, 74, 39, 145, 73, 215, 17, 234, 196, 89, 30, 58, 120, 127, 88, 69, 121, 61, 18, 206, 89, 118, 243, 238, 177, 71, 73, 47, 147, 4, 155, 25, 173, 248, 206, 52, 17, 180, 122, 186, 106, 191, 252, 102, 197, 91, 16, 39, 94, 91, 224, 30, 168, 177, 26, 144, 5, 124, 128, 6 + ]; + + for i in 0..outgoing_body_ciphertext_from_typescript.len() { + assert_eq(ciphertext[i], outgoing_body_ciphertext_from_typescript[i]); + } + assert_eq(outgoing_body_ciphertext_from_typescript.len(), ciphertext.len()); + } } diff --git a/noir-projects/noir-contracts/contracts/test_contract/src/main.nr b/noir-projects/noir-contracts/contracts/test_contract/src/main.nr index 0a2a879f457..5636fc84dec 100644 --- a/noir-projects/noir-contracts/contracts/test_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/test_contract/src/main.nr @@ -20,8 +20,7 @@ contract Test { }; use dep::aztec::encrypted_logs::header::EncryptedLogHeader; - use dep::aztec::encrypted_logs::incoming_body::EncryptedLogIncomingBody; - use dep::aztec::encrypted_logs::outgoing_body::EncryptedLogOutgoingBody; + use dep::aztec::encrypted_logs::payload::{compute_incoming_body_ciphertext, compute_outgoing_body_ciphertext}; use dep::aztec::note::constants::MAX_NOTES_PER_PAGE; use dep::aztec::keys::getters::get_public_keys; @@ -420,7 +419,8 @@ contract Test { value: Field ) -> [u8; 112] { let note = TestNote::new(value); - EncryptedLogIncomingBody::from_note(note, storage_slot).compute_ciphertext(secret, ivpk).as_array() + let plaintext = note.to_be_bytes(storage_slot); + compute_incoming_body_ciphertext(plaintext, secret, ivpk).as_array() } #[private] @@ -431,7 +431,7 @@ contract Test { ovsk_app: Scalar ) -> [u8; 144] { let eph_pk = derive_public_key(eph_sk); - EncryptedLogOutgoingBody::new(eph_sk, recipient, recipient_ivpk).compute_ciphertext(ovsk_app, eph_pk) + compute_outgoing_body_ciphertext(recipient, recipient_ivpk, ovsk_app, eph_sk, eph_pk) } #[public] diff --git a/noir-projects/noir-contracts/contracts/test_log_contract/src/main.nr b/noir-projects/noir-contracts/contracts/test_log_contract/src/main.nr index d3c6e29746d..0a6fc136b77 100644 --- a/noir-projects/noir-contracts/contracts/test_log_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/test_log_contract/src/main.nr @@ -7,7 +7,7 @@ contract TestLog { use dep::aztec::protocol_types::{scalar::Scalar, address::AztecAddress, traits::Serialize}; use dep::aztec::keys::public_keys::IvpkM; use dep::value_note::value_note::ValueNote; - use dep::aztec::encrypted_logs::incoming_body::EncryptedLogIncomingBody; + use dep::aztec::encrypted_logs::payload::compute_incoming_body_ciphertext; use dep::aztec::encrypted_logs::encrypted_event_emission::encode_and_encrypt_event_with_randomness; use dep::aztec::unencrypted_logs::unencrypted_event_emission::encode_event; use dep::aztec::macros::{storage::storage, events::event, functions::{private, public}}; @@ -44,10 +44,9 @@ contract TestLog { event_type_id: Field, preimage: [Field; 2] ) -> [u8; EXAMPLE_EVENT_0_CIPHERTEXT_BYTES_LEN] { - EncryptedLogIncomingBody::from_event( - ExampleEvent0 { value0: preimage[0], value1: preimage[1] }, - randomness - ).compute_ciphertext(secret, ivpk).as_array() + let event = ExampleEvent0 { value0: preimage[0], value1: preimage[1] }; + let plaintext = event.private_to_be_bytes(randomness); + compute_incoming_body_ciphertext(plaintext, secret, ivpk).as_array() } #[private] diff --git a/yarn-project/circuit-types/src/logs/l1_payload/encrypted_log_incoming_body/encrypted_event_log_incoming_body.test.ts b/yarn-project/circuit-types/src/logs/l1_payload/encrypted_log_incoming_body/encrypted_event_log_incoming_body.test.ts index fe3e6b752b0..ffac80e9f94 100644 --- a/yarn-project/circuit-types/src/logs/l1_payload/encrypted_log_incoming_body/encrypted_event_log_incoming_body.test.ts +++ b/yarn-project/circuit-types/src/logs/l1_payload/encrypted_log_incoming_body/encrypted_event_log_incoming_body.test.ts @@ -1,6 +1,5 @@ -import { Fr, FunctionSelector, GrumpkinScalar } from '@aztec/circuits.js'; +import { Fr, GrumpkinScalar } from '@aztec/circuits.js'; import { Grumpkin } from '@aztec/circuits.js/barretenberg'; -import { updateInlineTestData } from '@aztec/foundation/testing'; import { Event } from '../payload.js'; import { EncryptedEventLogIncomingBody } from './encrypted_event_log_incoming_body.js'; @@ -31,32 +30,4 @@ describe('encrypt log incoming body', () => { expect(recreated.toBuffer()).toEqual(body.toBuffer()); }); - - it('encrypt an event log incoming body, generate input for noir test', () => { - // The following 2 are arbitrary fixed values - fixed in order to test a match with Noir - const ephSecretKey = new GrumpkinScalar(0x23b3127c127b1f29a7adff5cccf8fb06649e7ca01d9de27b21624098b897babdn); - const viewingSecretKey = new GrumpkinScalar(0x1fdd0dd8c99b21af8e00d2d130bdc263b36dadcbea84ac5ec9293a0660deca01n); - - const viewingPubKey = grumpkin.mul(Grumpkin.generator, viewingSecretKey); - - const event = new Event([new Fr(1), new Fr(2), new Fr(3)]); - const eventTypeId = FunctionSelector.fromSignature('TestEvent(Field,Field,Field)').toField(); - const randomness = new Fr(2); - - const body = new EncryptedEventLogIncomingBody(randomness, eventTypeId, event); - - const encrypted = body.computeCiphertext(ephSecretKey, viewingPubKey); - - const byteArrayString = `[${encrypted - .toString('hex') - .match(/.{1,2}/g)! - .map(byte => parseInt(byte, 16))}]`; - - // Run with AZTEC_GENERATE_TEST_DATA=1 to update noir test data - updateInlineTestData( - 'noir-projects/aztec-nr/aztec/src/encrypted_logs/incoming_body.nr', - 'event_body_ciphertext_from_typescript', - byteArrayString, - ); - }); }); diff --git a/yarn-project/circuit-types/src/logs/l1_payload/encrypted_log_incoming_body/encrypted_note_log_incoming_body.test.ts b/yarn-project/circuit-types/src/logs/l1_payload/encrypted_log_incoming_body/encrypted_note_log_incoming_body.test.ts index 47a33fada1d..fa27ba06ca4 100644 --- a/yarn-project/circuit-types/src/logs/l1_payload/encrypted_log_incoming_body/encrypted_note_log_incoming_body.test.ts +++ b/yarn-project/circuit-types/src/logs/l1_payload/encrypted_log_incoming_body/encrypted_note_log_incoming_body.test.ts @@ -55,7 +55,7 @@ describe('encrypt log incoming body', () => { // Run with AZTEC_GENERATE_TEST_DATA=1 to update noir test data updateInlineTestData( - 'noir-projects/aztec-nr/aztec/src/encrypted_logs/incoming_body.nr', + 'noir-projects/aztec-nr/aztec/src/encrypted_logs/payload.nr', 'note_body_ciphertext_from_typescript', byteArrayString, ); diff --git a/yarn-project/circuit-types/src/logs/l1_payload/encrypted_log_outgoing_body.test.ts b/yarn-project/circuit-types/src/logs/l1_payload/encrypted_log_outgoing_body.test.ts index 35b89c559e0..ccda71df38d 100644 --- a/yarn-project/circuit-types/src/logs/l1_payload/encrypted_log_outgoing_body.test.ts +++ b/yarn-project/circuit-types/src/logs/l1_payload/encrypted_log_outgoing_body.test.ts @@ -55,7 +55,7 @@ describe('encrypt log outgoing body', () => { // Run with AZTEC_GENERATE_TEST_DATA=1 to update noir test data updateInlineTestData( - 'noir-projects/aztec-nr/aztec/src/encrypted_logs/outgoing_body.nr', + 'noir-projects/aztec-nr/aztec/src/encrypted_logs/payload.nr', 'outgoing_body_ciphertext_from_typescript', byteArrayString, );