Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: constrain event encryption and unify note and event emit api #7171

Merged
merged 2 commits into from
Jun 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions boxes/boxes/react/src/contracts/src/main.nr
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
contract BoxReact {
use dep::aztec::prelude::{AztecAddress, PrivateMutable, Map, NoteInterface, NoteHeader};
use dep::aztec::protocol_types::grumpkin_point::GrumpkinPoint;
use dep::aztec::encrypted_logs::encrypted_note_emission::encode_and_encrypt_with_keys;
use dep::aztec::encrypted_logs::encrypted_note_emission::encode_and_encrypt_note_with_keys;
use dep::value_note::value_note::{ValueNote, VALUE_NOTE_LEN};

#[aztec(storage)]
Expand All @@ -20,7 +20,7 @@ contract BoxReact {
) {
let numbers = storage.numbers;
let mut new_number = ValueNote::new(number, owner_npk_m_hash);
numbers.at(owner).initialize(&mut new_number).emit(encode_and_encrypt_with_keys(&mut context, owner_ovpk_m, owner_ivpk_m));
numbers.at(owner).initialize(&mut new_number).emit(encode_and_encrypt_note_with_keys(&mut context, owner_ovpk_m, owner_ivpk_m));
}

#[aztec(private)]
Expand All @@ -33,7 +33,7 @@ contract BoxReact {
) {
let numbers = storage.numbers;
let mut new_number = ValueNote::new(number, owner_npk_m_hash);
numbers.at(owner).replace(&mut new_number).emit(encode_and_encrypt_with_keys(&mut context, owner_ovpk_m, owner_ivpk_m));
numbers.at(owner).replace(&mut new_number).emit(encode_and_encrypt_note_with_keys(&mut context, owner_ovpk_m, owner_ivpk_m));
}

unconstrained fn getNumber(owner: AztecAddress) -> pub ValueNote {
Expand Down
6 changes: 3 additions & 3 deletions boxes/boxes/vanilla/src/contracts/src/main.nr
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
contract Vanilla {
use dep::aztec::prelude::{AztecAddress, PrivateMutable, Map, NoteInterface, NoteHeader};
use dep::aztec::protocol_types::grumpkin_point::GrumpkinPoint;
use dep::aztec::encrypted_logs::encrypted_note_emission::encode_and_encrypt_with_keys;
use dep::aztec::encrypted_logs::encrypted_note_emission::encode_and_encrypt_note_with_keys;
use dep::value_note::value_note::{ValueNote, VALUE_NOTE_LEN};

#[aztec(storage)]
Expand All @@ -20,7 +20,7 @@ contract Vanilla {
) {
let numbers = storage.numbers;
let mut new_number = ValueNote::new(number, owner_npk_m_hash);
numbers.at(owner).initialize(&mut new_number).emit(encode_and_encrypt_with_keys(&mut context, owner_ovpk_m, owner_ivpk_m));
numbers.at(owner).initialize(&mut new_number).emit(encode_and_encrypt_note_with_keys(&mut context, owner_ovpk_m, owner_ivpk_m));
}

#[aztec(private)]
Expand All @@ -33,7 +33,7 @@ contract Vanilla {
) {
let numbers = storage.numbers;
let mut new_number = ValueNote::new(number, owner_npk_m_hash);
numbers.at(owner).replace(&mut new_number).emit(encode_and_encrypt_with_keys(&mut context, owner_ovpk_m, owner_ivpk_m));
numbers.at(owner).replace(&mut new_number).emit(encode_and_encrypt_note_with_keys(&mut context, owner_ovpk_m, owner_ivpk_m));
}

unconstrained fn getNumber(owner: AztecAddress) -> pub ValueNote {
Expand Down
40 changes: 3 additions & 37 deletions noir-projects/aztec-nr/aztec/src/context/private_context.nr
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
use crate::encrypted_logs::{payload::compute_encrypted_note_log};

use crate::{
context::{inputs::PrivateContextInputs, packed_returns::PackedReturns},
messaging::process_l1_to_l2_message,
Expand All @@ -10,7 +8,7 @@ use crate::{
key_validation_request::get_key_validation_request, arguments, returns::pack_returns,
call_private_function::call_private_function_internal, header::get_header_at,
logs::{
emit_encrypted_note_log, emit_encrypted_event_log, compute_encrypted_event_log,
emit_encrypted_note_log, emit_encrypted_event_log,
emit_contract_class_unencrypted_log_private_internal, emit_unencrypted_log_private_internal
},
logs_traits::{LensForEncryptedLog, ToBytesForUnencryptedLog},
Expand Down Expand Up @@ -276,10 +274,7 @@ impl PrivateContext {
// --> might be a better approach to force devs to make a public function call that emits the log if needed then
// it would be less easy to accidentally leak information.
// If we decide to keep this function around would make sense to wait for traits and then merge it with emit_unencrypted_log.
pub fn emit_unencrypted_log<T, N, M>(
&mut self,
log: T
) where T: ToBytesForUnencryptedLog<N, M> {
pub fn emit_unencrypted_log<T, N, M>(&mut self, log: T) where T: ToBytesForUnencryptedLog<N, M> {
let event_selector = 5; // TODO: compute actual event selector.
let contract_address = self.this_address();
let counter = self.next_counter();
Expand Down Expand Up @@ -313,36 +308,7 @@ impl PrivateContext {

// NB: A randomness value of 0 signals that the kernels should not mask the contract address
// used in siloing later on e.g. 'handshaking' contract w/ known address.
pub fn encrypt_and_emit_event<N, M>(
&mut self,
randomness: Field, // Secret random value used later for masked_contract_address
event_type_id: Field,
ovpk_m: GrumpkinPoint,
ivpk_m: GrumpkinPoint,
preimage: [Field; N]
) where [Field; N]: LensForEncryptedLog<N, M> {
let ovsk_app = self.request_ovsk_app(ovpk_m.hash());
let contract_address = self.this_address();

// We are currently just encrypting it unconstrained, but otherwise the same way as if it was a note.
let encrypted_log: [u8; M] = compute_encrypted_event_log(
contract_address,
randomness,
event_type_id,
ovsk_app,
ovpk_m,
ivpk_m,
preimage
);

self.emit_raw_event_log_with_masked_address(randomness, encrypted_log);
}

pub fn emit_raw_event_log_with_masked_address<M>(
&mut self,
randomness: Field,
encrypted_log: [u8; M]
) {
pub fn emit_raw_event_log_with_masked_address<M>(&mut self, randomness: Field, encrypted_log: [u8; M]) {
let counter = self.next_counter();
let contract_address = self.this_address();
let len = encrypted_log.len() as Field + 4;
Expand Down
1 change: 1 addition & 0 deletions noir-projects/aztec-nr/aztec/src/encrypted_logs.nr
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ mod incoming_body;
mod outgoing_body;
mod payload;
mod encrypted_note_emission;
mod encrypted_event_emission;
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
use crate::{
context::PrivateContext, event::event_interface::EventInterface,
encrypted_logs::payload::compute_encrypted_event_log, oracle::logs_traits::LensForEncryptedEvent
};
use dep::protocol_types::{address::AztecAddress, grumpkin_point::GrumpkinPoint};

fn emit_with_keys<Event, NB, MB, OB>(
context: &mut PrivateContext,
randomness: Field,
event: Event,
ovpk: GrumpkinPoint,
ivpk: GrumpkinPoint
) where Event: EventInterface<NB, MB>, [u8; NB]: LensForEncryptedEvent<NB, OB> {
let contract_address: AztecAddress = context.this_address();
let ovsk_app: Field = context.request_ovsk_app(ovpk.hash());

let encrypted_log: [u8; OB] = compute_encrypted_event_log(contract_address, randomness, ovsk_app, ovpk, ivpk, event);

context.emit_raw_event_log_with_masked_address(randomness, encrypted_log);
}

pub fn encode_and_encrypt_event<Event, NB, MB, OB>(
context: &mut PrivateContext,
randomness: Field,
ov: AztecAddress,
iv: AztecAddress
) -> fn[(&mut PrivateContext, AztecAddress, AztecAddress, Field)](Event) -> () where Event: EventInterface<NB, MB>, [u8; NB]: LensForEncryptedEvent<NB, OB> {
| e: Event | {
let header = context.get_header();
let ovpk = header.get_ovpk_m(context, ov);
let ivpk = header.get_ivpk_m(context, iv);
emit_with_keys(context, randomness, e, ovpk, ivpk);
}
}

pub fn encode_and_encrypt_event_with_keys<Event, NB, MB, OB>(
context: &mut PrivateContext,
randomness: Field,
ovpk: GrumpkinPoint,
ivpk: GrumpkinPoint
) -> fn[(&mut PrivateContext, Field, GrumpkinPoint, GrumpkinPoint)](Event) -> () where Event: EventInterface<NB, MB>, [u8; NB]: LensForEncryptedEvent<NB, OB> {
| e: Event | {
emit_with_keys(context, randomness, e, ovpk, ivpk);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ fn emit_with_keys<Note, N, NB, M>(
context.emit_raw_note_log(note_hash_counter, encrypted_log);
}

pub fn encode_and_encrypt<Note, N, NB, M>(
pub fn encode_and_encrypt_note<Note, N, NB, M>(
context: &mut PrivateContext,
ov: AztecAddress,
iv: AztecAddress
Expand All @@ -46,7 +46,7 @@ pub fn encode_and_encrypt<Note, N, NB, M>(
}
}

pub fn encode_and_encrypt_with_keys<Note, N, NB, M>(
pub fn encode_and_encrypt_note_with_keys<Note, N, NB, M>(
context: &mut PrivateContext,
ovpk: GrumpkinPoint,
ivpk: GrumpkinPoint
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,10 @@ mod test {

buffer
}

fn emit<Env>(self, _emit: fn[Env](Self) -> ()) {
_emit(self);
}
}

#[test]
Expand Down
60 changes: 59 additions & 1 deletion noir-projects/aztec-nr/aztec/src/encrypted_logs/payload.nr
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,71 @@ use dep::std::{embedded_curve_ops::{embedded_curve_add, EmbeddedCurvePoint}, fie

use crate::oracle::unsafe_rand::unsafe_rand;

use crate::event::event_interface::EventInterface;
use crate::note::note_interface::NoteInterface;

use crate::encrypted_logs::{
header::EncryptedLogHeader, incoming_body::EncryptedLogIncomingBody,
outgoing_body::EncryptedLogOutgoingBody
};

pub fn compute_encrypted_event_log<Event, NB, MB, OB>(
contract_address: AztecAddress,
randomness: Field,
ovsk_app: Field,
ovpk: GrumpkinPoint,
ivpk: GrumpkinPoint,
event: Event
) -> [u8; OB] where Event: EventInterface<NB, MB> {
// @todo Need to draw randomness from the full domain of Fq not only Fr
let eph_sk: GrumpkinPrivateKey = fr_to_private_key(unsafe_rand());
let eph_pk = eph_sk.derive_public_key();

// TODO: (#7177) This value needs to be populated!
let recipient = AztecAddress::from_field(0);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have created #7177 such that we can deal with these. There are two of them here as it was never fully finished 👍

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good, I have added the issue nr to the code as well.


let ivpk_app = compute_ivpk_app(ivpk, contract_address);

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_app);
let outgoing_body_ciphertext: [u8; 176] = EncryptedLogOutgoingBody::new(eph_sk, recipient, ivpk_app).compute_ciphertext(fr_to_private_key(ovsk_app), eph_pk);

let mut encrypted_bytes: [u8; OB] = [0; OB];
// @todo We ignore the tags for now

let eph_pk_bytes = eph_pk.to_be_bytes();
for i in 0..64 {
encrypted_bytes[64 + i] = eph_pk_bytes[i];
}
for i in 0..48 {
encrypted_bytes[128 + i] = incoming_header_ciphertext[i];
encrypted_bytes[176 + i] = outgoing_Header_ciphertext[i];
}
for i in 0..176 {
encrypted_bytes[224 + i] = outgoing_body_ciphertext[i];
}
// Then we fill in the rest as the incoming body ciphertext
let size = OB - 400;
assert_eq(size, incoming_body_ciphertext.len(), "ciphertext length mismatch");
for i in 0..size {
encrypted_bytes[400 + i] = incoming_body_ciphertext[i];
}

// Current unoptimized size of the encrypted log
// incoming_tag (32 bytes)
// outgoing_tag (32 bytes)
// eph_pk (64 bytes)
// incoming_header (48 bytes)
// outgoing_header (48 bytes)
// outgoing_body (176 bytes)
// incoming_body_fixed (64 bytes)
// incoming_body_variable (N * 32 bytes + 16 bytes padding)
encrypted_bytes
}

pub fn compute_encrypted_note_log<Note, N, NB, M>(
contract_address: AztecAddress,
storage_slot: Field,
Expand All @@ -26,7 +84,7 @@ pub fn compute_encrypted_note_log<Note, N, NB, M>(
let eph_sk: GrumpkinPrivateKey = fr_to_private_key(unsafe_rand());
let eph_pk = eph_sk.derive_public_key();

// @todo This value needs to be populated!
// TODO: (#7177) This value needs to be populated!
let recipient = AztecAddress::from_field(0);

let ivpk_app = compute_ivpk_app(ivpk, contract_address);
Expand Down
1 change: 1 addition & 0 deletions noir-projects/aztec-nr/aztec/src/event/event_interface.nr
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ trait EventInterface<NB, MB> {
fn private_to_be_bytes(self, randomness: Field) -> [u8; NB];
fn to_be_bytes(self) -> [u8; MB];
fn get_event_type_id() -> EventSelector;
fn emit<Env>(self, _emit: fn[Env](Self) -> ());
}
25 changes: 24 additions & 1 deletion noir-projects/aztec-nr/aztec/src/oracle/logs_traits.nr
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ impl LensForEncryptedLog<3, 576> for [Field; 3] {
impl LensForEncryptedLog<4, 608> for [Field; 4] {
fn output_fields(self) -> [Field; 4] {[self[0]; 4]}
fn output_bytes(self) -> [u8; 608] {[self[0] as u8; 608]}

}
impl LensForEncryptedLog<5, 640> for [Field; 5] {
fn output_fields(self) -> [Field; 5] {[self[0]; 5]}
Expand All @@ -40,7 +39,31 @@ impl LensForEncryptedLog<5, 640> for [Field; 5] {
impl LensForEncryptedLog<6, 672> for [Field; 6] {
fn output_fields(self) -> [Field; 6] {[self[0]; 6]}
fn output_bytes(self) -> [u8; 672] {[self[0] as u8; 672]}
}

trait LensForEncryptedEvent<N, M> {
// N = event preimage input in bytes
// M = encryption output len in bytes (= 480 + M)
fn output(self: [u8; N]) -> [u8; M];
}

impl LensForEncryptedEvent<96, 512> for [u8; 96] {
fn output(self) -> [u8; 512] {[self[0] as u8; 512]}
}
impl LensForEncryptedEvent<128, 544> for [u8; 128] {
fn output(self) -> [u8; 544] {[self[0] as u8; 544]}
}
impl LensForEncryptedEvent<160, 576> for [u8; 160] {
fn output(self) -> [u8; 576] {[self[0] as u8; 576]}
}
impl LensForEncryptedEvent<192, 608> for [u8; 192] {
fn output(self) -> [u8; 608] {[self[0] as u8; 608]}
}
impl LensForEncryptedEvent<224, 640> for [u8; 224] {
fn output(self) -> [u8; 640] {[self[0] as u8; 640]}
}
impl LensForEncryptedEvent<256, 672> for [u8; 256] {
fn output(self) -> [u8; 672] {[self[0] as u8; 672]}
}

// This trait defines the length of the inputs in bytes to
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use dep::aztec::{
context::PrivateContext, protocol_types::{address::AztecAddress, grumpkin_point::GrumpkinPoint},
note::note_getter_options::NoteGetterOptions, state_vars::PrivateSet,
encrypted_logs::encrypted_note_emission::encode_and_encrypt
encrypted_logs::encrypted_note_emission::encode_and_encrypt_note
};
use dep::value_note::{filter::filter_notes_min_sum, value_note::ValueNote};

Expand Down Expand Up @@ -30,7 +30,7 @@ impl<Context> EasyPrivateUint<&mut PrivateContext> {

// Insert the new note to the owner's set of notes.
// docs:start:insert
self.set.insert(&mut addend_note).emit(encode_and_encrypt(self.context, outgoing_viewer, owner));
self.set.insert(&mut addend_note).emit(encode_and_encrypt_note(self.context, outgoing_viewer, owner));
// docs:end:insert
}

Expand Down Expand Up @@ -63,6 +63,6 @@ impl<Context> EasyPrivateUint<&mut PrivateContext> {
// Creates change note for the owner.
let result_value = minuend - subtrahend;
let mut result_note = ValueNote::new(result_value as Field, owner_npk_m_hash);
self.set.insert(&mut result_note).emit(encode_and_encrypt(self.context, outgoing_viewer, owner));
self.set.insert(&mut result_note).emit(encode_and_encrypt_note(self.context, outgoing_viewer, owner));
}
}
4 changes: 2 additions & 2 deletions noir-projects/aztec-nr/value-note/src/utils.nr
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use dep::aztec::prelude::{AztecAddress, PrivateContext, PrivateSet, NoteGetterOptions};
use dep::aztec::note::note_getter_options::SortOrder;
use dep::aztec::protocol_types::grumpkin_point::GrumpkinPoint;
use dep::aztec::encrypted_logs::encrypted_note_emission::encode_and_encrypt;
use dep::aztec::encrypted_logs::encrypted_note_emission::encode_and_encrypt_note;
use crate::{filter::filter_notes_min_sum, value_note::{ValueNote, VALUE_NOTE_LEN, VALUE_NOTE_BYTES_LEN}};

// Sort the note values (0th field) in descending order.
Expand All @@ -23,7 +23,7 @@ pub fn increment(

let mut note = ValueNote::new(amount, recipient_npk_m_hash);
// Insert the new note to the owner's set of notes and emit the log if value is non-zero.
balance.insert(&mut note).emit(encode_and_encrypt(balance.context, outgoing_viewer, recipient));
balance.insert(&mut note).emit(encode_and_encrypt_note(balance.context, outgoing_viewer, recipient));
}

// Find some of the `owner`'s notes whose values add up to the `amount`.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ contract AppSubscription {
AztecAddress, FunctionSelector, PrivateContext, NoteHeader, Map, PrivateMutable, PublicMutable,
SharedImmutable
},
encrypted_logs::encrypted_note_emission::encode_and_encrypt,
encrypted_logs::encrypted_note_emission::encode_and_encrypt_note,
protocol_types::{traits::is_empty, grumpkin_point::GrumpkinPoint}
},
authwit::{auth_witness::get_auth_witness, auth::assert_current_call_valid_authwit},
Expand Down Expand Up @@ -45,7 +45,7 @@ contract AppSubscription {

// We are emitting both the outgoing and the incoming logs to the subscriber here because passing a separate
// outgoing_viewer arg to entrypoint function is impractical and the outgoing are not so valuable here.
storage.subscriptions.at(user_address).replace(&mut note).emit(encode_and_encrypt(&mut context, user_address, user_address));
storage.subscriptions.at(user_address).replace(&mut note).emit(encode_and_encrypt_note(&mut context, user_address, user_address));

context.set_as_fee_payer();

Expand Down Expand Up @@ -116,7 +116,7 @@ contract AppSubscription {
let subscriber_npk_m_hash = header.get_npk_m_hash(&mut context, subscriber_address);

let mut subscription_note = SubscriptionNote::new(subscriber_npk_m_hash, expiry_block_number, tx_count);
storage.subscriptions.at(subscriber_address).initialize_or_replace(&mut subscription_note).emit(encode_and_encrypt(&mut context, context.msg_sender(), subscriber_address));
storage.subscriptions.at(subscriber_address).initialize_or_replace(&mut subscription_note).emit(encode_and_encrypt_note(&mut context, context.msg_sender(), subscriber_address));
}

unconstrained fn is_initialized(subscriber_address: AztecAddress) -> pub bool {
Expand Down
Loading
Loading