Skip to content

Commit

Permalink
feat: partial notes log encoding (#8538)
Browse files Browse the repository at this point in the history
  • Loading branch information
benesjan committed Sep 18, 2024
1 parent 6788165 commit 5f5ec20
Show file tree
Hide file tree
Showing 10 changed files with 267 additions and 94 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ fn compute_raw_note_log<Note, let N: u32, let NB: u32, let M: u32>(
ovsk_app: Field,
ovpk: OvpkM,
ivpk: IvpkM,
recipient: AztecAddress
recipient: AztecAddress,
num_public_values: u8 // Number of values to be appended to the log in public (used in partial note flow).
) -> (u32, [u8; M], Field) where Note: NoteInterface<N, NB>, [Field; N]: LensForEncryptedLog<N, M> {
let note_header = note.get_header();
let note_hash_counter = note_header.note_hash_counter;
Expand All @@ -30,7 +31,8 @@ fn compute_raw_note_log<Note, let N: u32, let NB: u32, let M: u32>(
ovpk,
ivpk,
recipient,
note
note,
num_public_values
);
let log_hash = sha256_to_field(encrypted_log);

Expand All @@ -42,10 +44,11 @@ unconstrained fn compute_raw_note_log_unconstrained<Note, let N: u32, let NB: u3
note: Note,
ovpk: OvpkM,
ivpk: IvpkM,
recipient: AztecAddress
recipient: AztecAddress,
num_public_values: u8 // Number of values to be appended to the log in public (used in partial note flow).
) -> (u32, [u8; M], Field) where Note: NoteInterface<N, NB>, [Field; N]: LensForEncryptedLog<N, M> {
let ovsk_app = get_ovsk_app(ovpk.hash());
compute_raw_note_log(context, note, ovsk_app, ovpk, ivpk, recipient)
compute_raw_note_log(context, note, ovsk_app, ovpk, ivpk, recipient, num_public_values)
}

pub fn encode_and_encrypt_note<Note, let N: u32, let NB: u32, let M: u32>(
Expand All @@ -58,7 +61,10 @@ pub fn encode_and_encrypt_note<Note, let N: u32, let NB: u32, let M: u32>(
let ivpk = get_current_public_keys(context, iv).ivpk_m;
let ovsk_app: Field = context.request_ovsk_app(ovpk.hash());

let (note_hash_counter, encrypted_log, log_hash) = compute_raw_note_log(*context, e.note, ovsk_app, ovpk, ivpk, iv);
// Number of public values is always 0 here because `encode_and_encrypt_note(...)` is only called
// in the non-partial note flow.
let num_public_values = 0;
let (note_hash_counter, encrypted_log, log_hash) = compute_raw_note_log(*context, e.note, ovsk_app, ovpk, ivpk, iv, num_public_values);
context.emit_raw_note_log(note_hash_counter, encrypted_log, log_hash);
}
}
Expand All @@ -74,10 +80,14 @@ pub fn encode_and_encrypt_note_unconstrained<Note, let N: u32, let NB: u32, let
let ovpk = get_current_public_keys(context, ov).ovpk_m;
let ivpk = get_current_public_keys(context, iv).ivpk_m;

// Number of public values is always 0 here because `encode_and_encrypt_note_unconstrained(...)` is only called
// in the non-partial note flow.
let num_public_values = 0;

// See the comment in `encode_and_encrypt_note_with_keys_unconstrained` for why having note hash counter
// and log hash unconstrained here is fine.
let (note_hash_counter, encrypted_log, log_hash) = unsafe {
compute_raw_note_log_unconstrained(*context, e.note, ovpk, ivpk, iv)
compute_raw_note_log_unconstrained(*context, e.note, ovpk, ivpk, iv, num_public_values)
};
context.emit_raw_note_log(note_hash_counter, encrypted_log, log_hash);
}
Expand All @@ -92,7 +102,11 @@ pub fn encode_and_encrypt_note_with_keys<Note, let N: u32, let NB: u32, let M: u
| e: NoteEmission<Note> | {
let ovsk_app: Field = context.request_ovsk_app(ovpk.hash());

let (note_hash_counter, encrypted_log, log_hash) = compute_raw_note_log(*context, e.note, ovsk_app, ovpk, ivpk, recipient);
// Number of public values is always 0 here because `encode_and_encrypt_note_unconstrained(...)` is only called
// in the non-partial note flow.
let num_public_values = 0;

let (note_hash_counter, encrypted_log, log_hash) = compute_raw_note_log(*context, e.note, ovsk_app, ovpk, ivpk, recipient, num_public_values);
context.emit_raw_note_log(note_hash_counter, encrypted_log, log_hash);
}
}
Expand All @@ -104,6 +118,10 @@ pub fn encode_and_encrypt_note_with_keys_unconstrained<Note, let N: u32, let NB:
recipient: AztecAddress
) -> fn[(&mut PrivateContext, OvpkM, IvpkM, AztecAddress)](NoteEmission<Note>) -> () where Note: NoteInterface<N, NB>, [Field; N]: LensForEncryptedLog<N, M> {
| e: NoteEmission<Note> | {
// Number of public values is always 0 here because `encode_and_encrypt_note_with_keys_unconstrained(...)` is only called
// in the non-partial note flow.
let num_public_values = 0;

// Having the log hash be unconstrained here is fine because the way this works is we send the log hash
// to the kernel, and it gets included as part of its public inputs. Then we send the tx to the sequencer,
// which includes the kernel proof and the log preimages. The sequencer computes the hashes of the logs
Expand All @@ -124,7 +142,7 @@ pub fn encode_and_encrypt_note_with_keys_unconstrained<Note, let N: u32, let NB:
// whatever), or cause for the log to not be deleted when it should have (which is also fine - it'll be a log
// for a note that doesn't exist).
let (note_hash_counter, encrypted_log, log_hash) = unsafe {
compute_raw_note_log_unconstrained(*context, e.note, ovpk, ivpk, recipient)
compute_raw_note_log_unconstrained(*context, e.note, ovpk, ivpk, recipient, num_public_values)
};
context.emit_raw_note_log(note_hash_counter, encrypted_log, log_hash);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,9 +92,6 @@ mod test {
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());
assert_eq(outgoing_body_ciphertext_from_typescript, ciphertext);
}
}
92 changes: 79 additions & 13 deletions noir-projects/aztec-nr/aztec/src/encrypted_logs/payload.nr
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,8 @@ pub fn compute_encrypted_note_log<Note, let N: u32, let NB: u32, let M: u32>(
ovpk: OvpkM,
ivpk: IvpkM,
recipient: AztecAddress,
note: Note
note: Note,
num_public_values: u8 // Number of values to be appended to the log in public (used in partial note flow).
) -> [u8; M] where Note: NoteInterface<N, NB> {
let (eph_sk, eph_pk) = generate_ephemeral_key_pair();

Expand All @@ -86,27 +87,29 @@ pub fn compute_encrypted_note_log<Note, let N: u32, let NB: u32, let M: u32>(
let mut encrypted_bytes: [u8; M] = [0; M];
// @todo We ignore the tags for now

encrypted_bytes[64] = num_public_values; // TODO(#8558): This can be just a single bit if we store info about partial fields in ABI
let eph_pk_bytes = point_to_bytes(eph_pk);
for i in 0..32 {
encrypted_bytes[64 + i] = eph_pk_bytes[i];
encrypted_bytes[65 + 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];
encrypted_bytes[97 + i] = incoming_header_ciphertext[i];
encrypted_bytes[145 + i] = outgoing_header_ciphertext[i];
}
for i in 0..144 {
encrypted_bytes[192 + i] = outgoing_body_ciphertext[i];
encrypted_bytes[193 + i] = outgoing_body_ciphertext[i];
}
// Then we fill in the rest as the incoming body ciphertext
let size = M - 336;
let size = M - 337;
assert_eq(size, incoming_body_ciphertext.len(), "ciphertext length mismatch");
for i in 0..size {
encrypted_bytes[336 + i] = incoming_body_ciphertext[i];
encrypted_bytes[337 + i] = incoming_body_ciphertext[i];
}

// Current unoptimized size of the encrypted log
// incoming_tag (32 bytes)
// outgoing_tag (32 bytes)
// num_public_values (1 byte)
// eph_pk (32 bytes)
// incoming_header (48 bytes)
// outgoing_header (48 bytes)
Expand Down Expand Up @@ -170,25 +173,88 @@ mod test {
let _ = OracleMock::mock("getRandomField").returns(eph_sk);

let recipient = AztecAddress::from_field(0x10ee41ee4b62703b16f61e03cb0d88c4b306a9eb4a6ceeb2aff13428541689a2);
let num_public_values: u8 = 0;

let log: [u8; 448] = compute_encrypted_note_log(
let log: [u8; 449] = compute_encrypted_note_log(
contract_address,
storage_slot,
ovsk_app,
ovpk_m,
ivpk_m,
recipient,
note
note,
num_public_values
);

// The following value was generated by `tagged_log.test.ts`
// --> Run the test with AZTEC_GENERATE_TEST_DATA=1 flag to update test data.
let encrypted_note_log_from_typescript = [
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, 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, 0, 0, 141, 70, 12, 14, 67, 77, 132, 110, 193, 234, 40, 110, 64, 144, 235, 86, 55, 111, 242, 123, 221, 193, 170, 202, 225, 216, 86, 84, 159, 112, 31, 167, 126, 79, 51, 186, 47, 71, 253, 172, 99, 112, 241, 59, 197, 241, 107, 186, 232, 87, 187, 230, 171, 62, 228, 234, 42, 51, 145, 146, 238, 242, 42, 71, 206, 13, 244, 66, 111, 195, 20, 203, 98, 148, 204, 242, 145, 183, 156, 29, 141, 54, 44, 220, 194, 35, 229, 16, 32, 204, 211, 49, 142, 112, 82, 202, 116, 241, 254, 146, 42, 217, 20, 189, 70, 228, 182, 171, 205, 104, 27, 99, 171, 28, 91, 244, 21, 30, 130, 240, 5, 72, 174, 124, 97, 197, 157, 248, 193, 23, 193, 76, 46, 141, 144, 70, 211, 45, 67, 167, 218, 129, 140, 104, 190, 41, 110, 249, 209, 68, 106, 135, 164, 80, 235, 63, 101, 80, 32, 13, 38, 99, 145, 91, 11, 173, 151, 231, 247, 65, 153, 117, 229, 167, 64, 239, 182, 126, 235, 83, 4, 169, 8, 8, 160, 4, 235, 252, 21, 96, 84, 161, 69, 145, 145, 215, 254, 161, 117, 246, 198, 65, 89, 179, 194, 90, 19, 121, 12, 202, 114, 80, 195, 14, 60, 128, 105, 142, 100, 86, 90, 108, 157, 219, 22, 172, 20, 121, 195, 25, 159, 236, 2, 70, 75, 42, 37, 34, 2, 17, 149, 20, 176, 32, 18, 204, 56, 117, 121, 34, 15, 3, 88, 123, 64, 68, 74, 233, 63, 59, 131, 222, 194, 192, 167, 110, 217, 10, 128, 73, 129, 172, 205, 103, 212, 60, 151, 141, 10, 151, 222, 151, 180, 43, 91, 148, 201, 110, 165, 10, 238, 32, 134, 235, 99, 216, 200, 182, 31, 22, 156, 18, 209, 222, 172, 239, 193, 212, 86, 99, 62, 70, 182, 45, 175, 241, 91, 202, 179, 225, 236, 95, 71, 66, 151, 225, 203, 53, 216, 85, 102, 130, 6, 8, 25, 180, 86, 58, 140, 198, 105, 102, 177, 42, 94, 115, 247, 145, 147, 24, 231, 39, 73, 27, 10, 219, 130, 115, 188, 74, 114, 5, 177, 199, 83, 183, 106, 87, 204, 238, 231, 72, 45, 240, 39, 174, 25, 98, 53, 187, 156, 159, 244, 38
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, 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, 0, 0, 0, 141, 70, 12, 14, 67, 77, 132, 110, 193, 234, 40, 110, 64, 144, 235, 86, 55, 111, 242, 123, 221, 193, 170, 202, 225, 216, 86, 84, 159, 112, 31, 167, 126, 79, 51, 186, 47, 71, 253, 172, 99, 112, 241, 59, 197, 241, 107, 186, 232, 87, 187, 230, 171, 62, 228, 234, 42, 51, 145, 146, 238, 242, 42, 71, 206, 13, 244, 66, 111, 195, 20, 203, 98, 148, 204, 242, 145, 183, 156, 29, 141, 54, 44, 220, 194, 35, 229, 16, 32, 204, 211, 49, 142, 112, 82, 202, 116, 241, 254, 146, 42, 217, 20, 189, 70, 228, 182, 171, 205, 104, 27, 99, 171, 28, 91, 244, 21, 30, 130, 240, 5, 72, 174, 124, 97, 197, 157, 248, 193, 23, 193, 76, 46, 141, 144, 70, 211, 45, 67, 167, 218, 129, 140, 104, 190, 41, 110, 249, 209, 68, 106, 135, 164, 80, 235, 63, 101, 80, 32, 13, 38, 99, 145, 91, 11, 173, 151, 231, 247, 65, 153, 117, 229, 167, 64, 239, 182, 126, 235, 83, 4, 169, 8, 8, 160, 4, 235, 252, 21, 96, 84, 161, 69, 145, 145, 215, 254, 161, 117, 246, 198, 65, 89, 179, 194, 90, 19, 121, 12, 202, 114, 80, 195, 14, 60, 128, 105, 142, 100, 86, 90, 108, 157, 219, 22, 172, 20, 121, 195, 25, 159, 236, 2, 70, 75, 42, 37, 34, 2, 17, 149, 20, 176, 32, 18, 204, 56, 117, 121, 34, 15, 3, 88, 123, 64, 68, 74, 233, 63, 59, 131, 222, 194, 192, 167, 110, 217, 10, 128, 73, 129, 172, 205, 103, 212, 60, 151, 141, 10, 151, 222, 151, 180, 43, 91, 148, 201, 110, 165, 10, 238, 32, 134, 235, 99, 216, 200, 182, 31, 22, 156, 18, 209, 222, 172, 239, 193, 212, 86, 99, 62, 70, 182, 45, 175, 241, 91, 202, 179, 225, 236, 95, 71, 66, 151, 225, 203, 53, 216, 85, 102, 130, 6, 8, 25, 180, 86, 58, 140, 198, 105, 102, 177, 42, 94, 115, 247, 145, 147, 24, 231, 39, 73, 27, 10, 219, 130, 115, 188, 74, 114, 5, 177, 199, 83, 183, 106, 87, 204, 238, 231, 72, 45, 240, 39, 174, 25, 98, 53, 187, 156, 159, 244, 38
];
for i in 0..encrypted_note_log_from_typescript.len() {
assert_eq(log[i], encrypted_note_log_from_typescript[i]);
assert_eq(encrypted_note_log_from_typescript, log);
}

#[test]
fn test_encrypted_note_log_of_finalized_partial_note_matches_typescript() {
// All the values in this test were copied over from `tagged_log.test.ts`
let contract_address = AztecAddress::from_field(0x10f48cd9eff7ae5b209c557c70de2e657ee79166868676b787e9417e19260e04);
let storage_slot = 0x0fe46be583b71f4ab5b70c2657ff1d05cccf1d292a9369628d1a194f944e6599;
let ovsk_app = 0x03a6513d6def49f41d20373d2cec894c23e7492794b08fc50c0e8a1bd2512612;
let ovpk_m = OvpkM {
inner: Point {
x: 0x1961448682803198631f299340e4206bb12809d4bebbf012b30f59af73ba1a15,
y: 0x133674060c3925142aceb4f1dcd9f9137d0217d37ff8729ee5ceaa6e2790353d,
is_infinite: false
}
};
let ivpk_m = IvpkM {
inner: Point {
x: 0x260cd3904f6df16e974c29944fdc839e40fb5cf293f03df2eb370851d3a527bc,
y: 0x0eef2964fe6640e84c82b5d2915892409b38e9e25d39f68dd79edb725c55387f,
is_infinite: false
}
};

let note_value = 0x301640ceea758391b2e161c92c0513f129020f4125256afdae2646ce31099f5c;
let note_public_value1 = 0x14172339287e8d281545c177313f02b6aa2fedfd628cfd8b7f11a136fd0d6557;
let note_public_value2 = 0x0834d81e3f73c7e2809b08ae38600ffc76a2554473eeab6de7bff4b33a84feac;
let note = MockNoteBuilder::new(note_value).contract_address(contract_address).storage_slot(storage_slot).build();

let eph_sk = 0x1358d15019d4639393d62b97e1588c095957ce74a1c32d6ec7d62fe6705d9538;
let _ = OracleMock::mock("getRandomField").returns(eph_sk);

let recipient = AztecAddress::from_field(0x10ee41ee4b62703b16f61e03cb0d88c4b306a9eb4a6ceeb2aff13428541689a2);
let num_public_values: u8 = 2;

// First we compute the encrypted log without the public values
let log_without_public_values: [u8; 449] = compute_encrypted_note_log(
contract_address,
storage_slot,
ovsk_app,
ovpk_m,
ivpk_m,
recipient,
note,
num_public_values
);

// Then we "append" the public values to the log by copying both the original log and the current log into a new byte array
let mut log: [u8; 513] = [0; 513];
for i in 0..449 {
log[i] = log_without_public_values[i];
}
let note_public_value1_bytes: [u8; 32] = note_public_value1.to_be_bytes();
let note_public_value2_bytes: [u8; 32] = note_public_value2.to_be_bytes();
for i in 0..32 {
log[449 + i] = note_public_value1_bytes[i];
log[481 + i] = note_public_value2_bytes[i];
}
assert_eq(encrypted_note_log_from_typescript.len(), log.len());

// The following value was generated by `tagged_log.test.ts`
// --> Run the test with AZTEC_GENERATE_TEST_DATA=1 flag to update test data.
let encrypted_note_log_of_finalized_partial_from_typescript = [
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, 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, 0, 0, 2, 141, 70, 12, 14, 67, 77, 132, 110, 193, 234, 40, 110, 64, 144, 235, 86, 55, 111, 242, 123, 221, 193, 170, 202, 225, 216, 86, 84, 159, 112, 31, 167, 126, 79, 51, 186, 47, 71, 253, 172, 99, 112, 241, 59, 197, 241, 107, 186, 232, 87, 187, 230, 171, 62, 228, 234, 42, 51, 145, 146, 238, 242, 42, 71, 206, 13, 244, 66, 111, 195, 20, 203, 98, 148, 204, 242, 145, 183, 156, 29, 141, 54, 44, 220, 194, 35, 229, 16, 32, 204, 211, 49, 142, 112, 82, 202, 116, 241, 254, 146, 42, 217, 20, 189, 70, 228, 182, 171, 205, 104, 27, 99, 171, 28, 91, 244, 21, 30, 130, 240, 5, 72, 174, 124, 97, 197, 157, 248, 193, 23, 193, 76, 46, 141, 144, 70, 211, 45, 67, 167, 218, 129, 140, 104, 190, 41, 110, 249, 209, 68, 106, 135, 164, 80, 235, 63, 101, 80, 32, 13, 38, 99, 145, 91, 11, 173, 151, 231, 247, 65, 153, 117, 229, 167, 64, 239, 182, 126, 235, 83, 4, 169, 8, 8, 160, 4, 235, 252, 21, 96, 84, 161, 69, 145, 145, 215, 254, 161, 117, 246, 198, 65, 89, 179, 194, 90, 19, 121, 12, 202, 114, 80, 195, 14, 60, 128, 105, 142, 100, 86, 90, 108, 157, 219, 22, 172, 20, 121, 195, 25, 159, 236, 2, 70, 75, 42, 37, 34, 2, 17, 149, 20, 176, 32, 18, 204, 56, 117, 121, 34, 15, 3, 88, 123, 64, 68, 74, 233, 63, 59, 131, 222, 194, 192, 167, 110, 217, 10, 128, 73, 129, 172, 205, 103, 212, 60, 151, 141, 10, 151, 222, 151, 180, 43, 91, 148, 201, 110, 165, 10, 238, 32, 134, 235, 99, 216, 200, 182, 31, 22, 156, 18, 209, 222, 172, 239, 193, 212, 86, 99, 62, 70, 182, 45, 175, 241, 91, 202, 179, 225, 236, 95, 71, 66, 151, 225, 203, 53, 216, 85, 102, 130, 6, 8, 25, 180, 86, 58, 140, 198, 105, 102, 177, 42, 94, 115, 247, 145, 147, 24, 231, 39, 73, 27, 10, 219, 130, 115, 188, 74, 114, 5, 177, 199, 83, 183, 106, 87, 204, 238, 231, 72, 45, 240, 39, 174, 25, 98, 53, 187, 156, 159, 244, 38, 20, 23, 35, 57, 40, 126, 141, 40, 21, 69, 193, 119, 49, 63, 2, 182, 170, 47, 237, 253, 98, 140, 253, 139, 127, 17, 161, 54, 253, 13, 101, 87, 8, 52, 216, 30, 63, 115, 199, 226, 128, 155, 8, 174, 56, 96, 15, 252, 118, 162, 85, 68, 115, 238, 171, 109, 231, 191, 244, 179, 58, 132, 254, 172
];
assert_eq(encrypted_note_log_of_finalized_partial_from_typescript, log);
}
}
Loading

0 comments on commit 5f5ec20

Please sign in to comment.