Skip to content

Commit

Permalink
feat: constrain encryption
Browse files Browse the repository at this point in the history
  • Loading branch information
LHerskind committed May 31, 2024
1 parent c12dc87 commit 0eb877a
Show file tree
Hide file tree
Showing 14 changed files with 113 additions and 23 deletions.
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
27 changes: 15 additions & 12 deletions noir-projects/aztec-nr/aztec/src/context/private_context.nr
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
// By updating the import here, you can "switch" between using an oracle for computing the encrypted
// logs, or constraining it in the circuit. The interfaces are the exact same, so just flip this.
// use crate::oracle::logs::compute_encrypted_log;
use crate::encrypted_logs::{payload::compute_encrypted_note_log};

use crate::{
context::{inputs::PrivateContextInputs, interface::ContextInterface, packed_returns::PackedReturns},
messaging::process_l1_to_l2_message,
Expand Down Expand Up @@ -274,7 +279,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 @@ -341,7 +349,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 @@ -354,21 +361,13 @@ 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
);
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);

// Current unoptimized size of the encrypted log
Expand All @@ -381,6 +380,10 @@ impl PrivateContext {
// incoming_body_fixed (64 bytes)
// incoming_body_variable (N * 32 bytes + 16 bytes padding)
// len of processed log (4 bytes)

// @todo The preimage size should be fetches somewhere else than this.
// preimage.len + 64 == NB.
let preimage = note.serialize_content();
let len = 32 + 32 + 64 + 48 + 48 + 176 + 64 + (preimage.len() as Field * 32) + 16 + 4;

let log_hash = sha256_to_field(encrypted_log);
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
96 changes: 96 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,96 @@
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 {
// @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
Original file line number Diff line number Diff line change
Expand Up @@ -383,6 +383,7 @@ export class ClientExecutionContext extends ViewDataOracle {

const ephSk = GrumpkinScalar.random();

// @todo Needs to be populated
const recipient = AztecAddress.random();

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

0 comments on commit 0eb877a

Please sign in to comment.