Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 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
1 change: 0 additions & 1 deletion noir-projects/aztec-nr/address-note/src/address_note.nr
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,6 @@ impl NoteInterface<ADDRESS_NOTE_LEN, ADDRESS_NOTE_BYTES_LEN> for AddressNote {
context.encrypt_and_emit_note(
(*context).this_address(),
slot,
Self::get_note_type_id(),
ovpk_m,
ivpk_m,
self,
Expand Down
29 changes: 12 additions & 17 deletions noir-projects/aztec-nr/aztec/src/context/private_context.nr
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use crate::encrypted_logs::{payload::compute_encrypted_note_log};

use crate::{
context::{inputs::PrivateContextInputs, packed_returns::PackedReturns},
messaging::process_l1_to_l2_message,
Expand Down Expand Up @@ -272,7 +274,10 @@ 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 @@ -317,7 +322,7 @@ impl PrivateContext {
) where [Field; N]: LensForEncryptedLog<N, M> {
let ovsk_app = self.request_ovsk_app(ovpk_m.hash());

// We are currently just encrypting it EXACTLY the same way as if it was a note.
// We are currently just encrypting it unconstrained, but otherwise the same way as if it was a note.
let counter = self.next_counter();
let encrypted_log: [u8; M] = compute_encrypted_log(
contract_address,
Expand All @@ -339,7 +344,6 @@ impl PrivateContext {
&mut self,
contract_address: AztecAddress,
storage_slot: Field,
note_type_id: Field,
ovpk_m: GrumpkinPoint,
ivpk_m: GrumpkinPoint,
note: Note
Expand All @@ -352,23 +356,11 @@ impl PrivateContext {
assert(
note_exists_index != MAX_NEW_NOTE_HASHES_PER_CALL, "Can only emit a note log for an existing note."
);
let preimage = note.serialize_content();

let counter = self.next_counter();

let ovsk_app = self.request_ovsk_app(ovpk_m.hash());

// TODO(#1139 | #6408): perform encryption in the circuit
let encrypted_log: [u8; M] = compute_encrypted_log(
contract_address,
storage_slot,
note_type_id,
ovsk_app,
ovpk_m,
ivpk_m,
preimage
);
emit_encrypted_note_log(note_hash_counter, encrypted_log, counter);

// Current unoptimized size of the encrypted log
// incoming_tag (32 bytes)
// outgoing_tag (32 bytes)
Expand All @@ -378,8 +370,11 @@ impl PrivateContext {
// outgoing_body (176 bytes)
// incoming_body_fixed (64 bytes)
// incoming_body_variable (N * 32 bytes + 16 bytes padding)
let encrypted_log: [u8; M] = compute_encrypted_note_log(contract_address, storage_slot, ovsk_app, ovpk_m, ivpk_m, note);
emit_encrypted_note_log(note_hash_counter, encrypted_log, counter);

// len of processed log (4 bytes)
let len = 32 + 32 + 64 + 48 + 48 + 176 + 64 + (preimage.len() as Field * 32) + 16 + 4;
let len = encrypted_log.len() as Field + 4;

let log_hash = sha256_to_field(encrypted_log);
let side_effect = NoteLogHash { value: log_hash, counter, length: len, note_hash_counter };
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
@@ -1,3 +1,4 @@
mod header;
mod incoming_body;
mod outgoing_body;
mod payload;
1 change: 0 additions & 1 deletion noir-projects/aztec-nr/aztec/src/encrypted_logs/header.nr
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ impl EncryptedLogHeader {
EncryptedLogHeader { address }
}

// @todo Issue(#5901) Figure out if we return the bytes or fields for the log
fn compute_ciphertext(self, secret: GrumpkinPrivateKey, point: GrumpkinPoint) -> [u8; 48] {
let full_key = point_to_symmetric_key(secret, point);
let mut sym_key = [0; 16];
Expand Down
100 changes: 100 additions & 0 deletions noir-projects/aztec-nr/aztec/src/encrypted_logs/payload.nr
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
use dep::protocol_types::{
address::AztecAddress, grumpkin_private_key::GrumpkinPrivateKey, grumpkin_point::GrumpkinPoint,
constants::{GENERATOR_INDEX__IVSK_M, GENERATOR_INDEX__OVSK_M}, hash::poseidon2_hash
};

use dep::std::{embedded_curve_ops::{embedded_curve_add, EmbeddedCurvePoint}, field::bytes32_to_field};

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

use crate::note::note_interface::NoteInterface;

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

pub fn compute_encrypted_note_log<Note, N, NB, M>(
contract_address: AztecAddress,
storage_slot: Field,
ovsk_app: Field,
ovpk: GrumpkinPoint,
ivpk: GrumpkinPoint,
note: Note
) -> [u8; M] where Note: NoteInterface<N, NB> {
// @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 This value needs to be populated!
let recipient = AztecAddress::from_field(0);

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_note(note, storage_slot).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; M] = [0; M];
// @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 = M - 400;
assert_eq(size, incoming_body_ciphertext.len(), "ciphertext length mismatch");
for i in 0..size {
encrypted_bytes[400 + i] = incoming_body_ciphertext[i];
}

encrypted_bytes
}

fn fr_to_private_key(r: Field) -> GrumpkinPrivateKey {
let r_bytes = r.to_be_bytes(32);

let mut high_bytes = [0; 32];
let mut low_bytes = [0; 32];

for i in 0..16 {
high_bytes[16 + i] = r_bytes[i];
low_bytes[16 + i] = r_bytes[i + 16];
}

let low = bytes32_to_field(low_bytes);
let high = bytes32_to_field(high_bytes);

GrumpkinPrivateKey::new(high, low)
}

fn compute_ivpk_app(ivpk: GrumpkinPoint, contract_address: AztecAddress) -> GrumpkinPoint {
// It is useless to compute this, it brings no value to derive fully.
ivpk

/*
// @todo Just setting infinite to false, but it should be checked.
// for example user could define ivpk = infinity using the registry
assert((ivpk.x != 0) & (ivpk.y != 0), "ivpk is infinite");

let i = fr_to_private_key(poseidon2_hash([contract_address.to_field(), ivpk.x, ivpk.y, GENERATOR_INDEX__IVSK_M]));
let I = i.derive_public_key();

let embed_I = EmbeddedCurvePoint { x: I.x, y: I.y, is_infinite: false };
let embed_ivpk = EmbeddedCurvePoint { x: ivpk.x, y: ivpk.y, is_infinite: false };

let embed_result = embedded_curve_add(embed_I, embed_ivpk);

GrumpkinPoint::new(embed_result.x, embed_result.y)*/
}
1 change: 0 additions & 1 deletion noir-projects/aztec-nr/value-note/src/value_note.nr
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,6 @@ impl NoteInterface<VALUE_NOTE_LEN, VALUE_NOTE_BYTES_LEN> for ValueNote {
context.encrypt_and_emit_note(
(*context).this_address(),
slot,
Self::get_note_type_id(),
ovpk_m,
ivpk_m,
self,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ impl NoteInterface<SUBSCRIPTION_NOTE_LEN, SUBSCRIPTION_NOTE_BYTES_LEN> for Subsc
context.encrypt_and_emit_note(
(*context).this_address(),
slot,
Self::get_note_type_id(),
ovpk_m,
ivpk_m,
self,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,6 @@ impl NoteInterface<CARD_NOTE_LEN, CARD_NOTE_BYTES_LEN> for CardNote {
context.encrypt_and_emit_note(
(*context).this_address(),
slot,
Self::get_note_type_id(),
ovpk_m,
ivpk_m,
self,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,6 @@ impl NoteInterface<ECDSA_PUBLIC_KEY_NOTE_LEN, ECDSA_PUBLIC_KEY_NOTE_BYTES_LEN> f
context.encrypt_and_emit_note(
(*context).this_address(),
slot,
Self::get_note_type_id(),
ovpk_m,
ivpk_m,
self,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,6 @@ contract PendingNoteHashes {
context.encrypt_and_emit_note(
context.this_address(),
note.get_header().storage_slot,
ValueNote::get_note_type_id(),
outgoing_viewer_ovpk_m,
owner_ivpk_m,
note
Expand Down Expand Up @@ -372,7 +371,6 @@ contract PendingNoteHashes {
context.encrypt_and_emit_note(
context.this_address(),
existing_note_header.storage_slot,
ValueNote::get_note_type_id(),
outgoing_viewer_ovpk_m,
owner_ivpk_m,
bad_note
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ impl NoteInterface<PUBLIC_KEY_NOTE_LEN, PUBLIC_KEY_NOTE_BYTES_LEN> for PublicKey
context.encrypt_and_emit_note(
(*context).this_address(),
slot,
Self::get_note_type_id(),
ovpk_m,
ivpk_m,
self,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,6 @@ impl NoteInterface<TOKEN_NOTE_LEN, TOKEN_NOTE_BYTES_LEN> for TokenNote {
context.encrypt_and_emit_note(
(*context).this_address(),
slot,
Self::get_note_type_id(),
ovpk_m,
ivpk_m,
self,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,6 @@ impl NoteInterface<TOKEN_NOTE_LEN, TOKEN_NOTE_BYTES_LEN> for TokenNote {
context.encrypt_and_emit_note(
(*context).this_address(),
slot,
Self::get_note_type_id(),
ovpk_m,
ivpk_m,
self,
Expand Down
4 changes: 4 additions & 0 deletions yarn-project/circuits.js/src/keys/derivation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,15 @@ export function computeAppSecretKey(skM: GrumpkinPrivateKey, app: AztecAddress,
}

export function computeIvpkApp(ivpk: PublicKey, address: AztecAddress) {
return ivpk;
// Computing the siloed key is actually useless because we can derive the master key from it

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Can we link issue here?

const I = Fq.fromBuffer(poseidon2Hash([address.toField(), ivpk.x, ivpk.y, GeneratorIndex.IVSK_M]).toBuffer());
return curve.add(curve.mul(Grumpkin.generator, I), ivpk);
}

export function computeIvskApp(ivsk: GrumpkinPrivateKey, address: AztecAddress) {
return ivsk;
// Computing the siloed key is actually useless because we can derive the master key from it

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Can we link issue here?

const ivpk = curve.mul(Grumpkin.generator, ivsk);
// Here we are intentionally converting Fr (output of poseidon) to Fq. This is fine even though a distribution of
// P = s * G will not be uniform because 2 * (q - r) / q is small.
Expand Down
5 changes: 4 additions & 1 deletion yarn-project/end-to-end/src/e2e_block_building.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,10 @@ describe('e2e_block_building', () => {

const ownerAddress = owner.getCompleteAddress().address;
const outgoingViewer = ownerAddress;
const methods = times(TX_COUNT, i => deployer.deploy(ownerAddress, outgoingViewer, i));
// Need to have value > 0, so adding + 1
// We need to do so, because noir currently will fail if the multiscalarmul is in an `if`
// that we DO NOT enter. This should be fixed by https://github.com/noir-lang/noir/issues/5045.
const methods = times(TX_COUNT, i => deployer.deploy(ownerAddress, outgoingViewer, i + 1));
for (let i = 0; i < TX_COUNT; i++) {
await methods[i].create({
contractAddressSalt: new Fr(BigInt(i + 1)),
Expand Down
3 changes: 3 additions & 0 deletions yarn-project/simulator/src/client/client_execution_context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -383,6 +383,9 @@ export class ClientExecutionContext extends ViewDataOracle {

const ephSk = GrumpkinScalar.random();

// @todo This should be populated properly.
// Note that this encryption function SHOULD not be used, but is currently used
// as oracle for encrypted event logs.
const recipient = AztecAddress.random();

return taggedNote.encrypt(ephSk, recipient, ivpkM, ovKeys);
Expand Down