Skip to content

Commit

Permalink
fix: cleanup of janky encryption apis (#9390)
Browse files Browse the repository at this point in the history
Following changes of #9272, we're now doing some cleanup of the
interfaces.

A big assumption we're making here is that the recipient will be the
same as the person we are encrypting to, but there have been no current
uses in the code where they are different, so I think it's okay to make
in the name of a cleaner, more streamlined API.
  • Loading branch information
sklppy88 authored Oct 27, 2024
1 parent 29b692f commit 9e3e536
Show file tree
Hide file tree
Showing 7 changed files with 90 additions and 59 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ where
contract_address,
ovsk_app,
ovpk,
ivpk,
recipient,
plaintext,
false,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,15 +36,8 @@ where
let plaintext = note.to_be_bytes(storage_slot);

// For note logs we always include public values prefix
let encrypted_log: [u8; 417 + N * 32] = compute_private_log_payload(
contract_address,
ovsk_app,
ovpk,
ivpk,
recipient,
plaintext,
true,
);
let encrypted_log: [u8; 417 + N * 32] =
compute_private_log_payload(contract_address, ovsk_app, ovpk, recipient, plaintext, true);
let log_hash = sha256_to_field(encrypted_log);

(note_hash_counter, encrypted_log, log_hash)
Expand Down
63 changes: 25 additions & 38 deletions noir-projects/aztec-nr/aztec/src/encrypted_logs/payload.nr
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,12 @@ use crate::{
keys::point_to_symmetric_key::point_to_symmetric_key, oracle::random::random,
utils::point::point_to_bytes,
};
use protocol_types::public_keys::AddressPoint;

fn compute_private_log_payload<let P: u32, let M: u32>(
contract_address: AztecAddress,
ovsk_app: Field,
ovpk: OvpkM,
ivpk: IvpkM,
recipient: AztecAddress,
plaintext: [u8; P],
include_public_values_prefix: bool,
Expand All @@ -30,17 +30,13 @@ fn compute_private_log_payload<let P: u32, let M: u32>(

let header = EncryptedLogHeader::new(contract_address);

let incoming_header_ciphertext: [u8; 48] = header.compute_ciphertext(eph_sk, recipient);
let incoming_header_ciphertext: [u8; 48] =
header.compute_ciphertext(eph_sk, recipient.to_address_point());
let outgoing_header_ciphertext: [u8; 48] = header.compute_ciphertext(eph_sk, ovpk);
let incoming_body_ciphertext =
compute_incoming_body_ciphertext(plaintext, eph_sk, IvpkM { inner: recipient.to_point() });
let outgoing_body_ciphertext: [u8; 144] = compute_outgoing_body_ciphertext(
recipient,
IvpkM { inner: recipient.to_point() },
fr_to_fq(ovsk_app),
eph_sk,
eph_pk,
);
compute_incoming_body_ciphertext(plaintext, eph_sk, recipient.to_address_point());
let outgoing_body_ciphertext: [u8; 144] =
compute_outgoing_body_ciphertext(recipient, fr_to_fq(ovsk_app), eph_sk, eph_pk);

// If we include the prefix for number of public values, we need to add 1 byte to the offset
let mut offset = if include_public_values_prefix { 1 } else { 0 };
Expand Down Expand Up @@ -113,9 +109,9 @@ fn generate_ephemeral_key_pair() -> (Scalar, Point) {
pub fn compute_incoming_body_ciphertext<let P: u32>(
plaintext: [u8; P],
eph_sk: Scalar,
ivpk: IvpkM,
address_point: AddressPoint,
) -> [u8] {
let full_key = point_to_symmetric_key(eph_sk, ivpk.to_point());
let full_key = point_to_symmetric_key(eph_sk, address_point.to_point());
let mut sym_key = [0; 16];
let mut iv = [0; 16];

Expand All @@ -130,7 +126,6 @@ pub fn compute_incoming_body_ciphertext<let P: u32>(
/// 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,
Expand All @@ -143,7 +138,7 @@ pub fn compute_outgoing_body_ciphertext(
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());
let serialized_recipient_ivpk = point_to_bytes(recipient.to_address_point().to_point());

for i in 0..32 {
buffer[i] = serialized_eph_sk_high[i];
Expand Down Expand Up @@ -182,6 +177,7 @@ mod test {
public_keys::{IvpkM, OvpkM},
scalar::Scalar,
};
use protocol_types::public_keys::AddressPoint;
use std::embedded_curve_ops::fixed_base_scalar_mul as derive_public_key;
use std::test::OracleMock;

Expand Down Expand Up @@ -228,13 +224,12 @@ mod test {
contract_address,
ovsk_app,
ovpk_m,
ivpk_m,
recipient,
plaintext,
false,
);

// The following value was generated by `tagged_log.test.ts`
// The following value was generated by `encrypted_log_payload.test.ts`
// --> Run the test with AZTEC_GENERATE_TEST_DATA=1 flag to update test data.
let encrypted_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,
Expand Down Expand Up @@ -271,7 +266,7 @@ mod test {
lo: 0x00000000000000000000000000000000649e7ca01d9de27b21624098b897babd,
hi: 0x0000000000000000000000000000000023b3127c127b1f29a7adff5cccf8fb06,
};
let ivpk = IvpkM {
let address_point = AddressPoint {
inner: Point {
x: 0x2688431c705a5ff3e6c6f2573c9e3ba1c1026d2251d0dbbf2d810aa53fd1d186,
y: 0x1e96887b117afca01c00468264f4f80b5bb16d94c1808a448595f115556e5c8e,
Expand All @@ -289,7 +284,7 @@ mod test {

// `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);
let ciphertext = compute_incoming_body_ciphertext(plaintext, eph_sk, address_point);

// 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.
Expand Down Expand Up @@ -319,39 +314,31 @@ mod test {
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,
let recipient = AztecAddress::from_field(
0x25afb798ea6d0b8c1618e50fdeafa463059415013d3b7c75d46abf5e242be70c,
);

// The following value was generated by `encrypted_log_outgoing_body.test.ts`
let ciphertext =
compute_outgoing_body_ciphertext(recipient, sender_ovsk_app, eph_sk, eph_pk);

// The following value was generated by `encrypted_log_payload.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,
211, 190, 124, 121, 79, 92, 238, 182, 194, 225, 34, 71, 67, 116, 27, 231, 68, 161, 147,
94, 53, 195, 83, 237, 172, 52, 173, 229, 26, 234, 107, 43, 82, 68, 16, 105, 37, 125,
117, 86, 133, 50, 21, 92, 74, 229, 105, 141, 83, 229, 255, 251, 21, 61, 234, 61, 168,
221, 106, 231, 8, 73, 208, 60, 251, 46, 251, 228, 148, 144, 187, 195, 38, 18, 223, 153,
8, 121, 178, 84, 237, 148, 254, 219, 59, 62,
];

assert_eq(outgoing_body_ciphertext_from_typescript, ciphertext);
Expand Down
2 changes: 0 additions & 2 deletions noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr
Original file line number Diff line number Diff line change
Expand Up @@ -396,7 +396,6 @@ comptime fn generate_multi_scalar_mul(
/// context.this_address(),
/// ovsk_app,
/// recipient_keys.ovpk_m,
/// recipient_keys.ivpk_m,
/// recipient,
/// self.log_plaintext
/// );
Expand Down Expand Up @@ -471,7 +470,6 @@ comptime fn generate_setup_payload(
context.this_address(),
ovsk_app,
recipient_keys.ovpk_m,
recipient_keys.ivpk_m,
recipient,
self.log_plaintext,
true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ use crate::{
// We do below because `use crate::point::Point;` does not work
use dep::std::embedded_curve_ops::EmbeddedCurvePoint as Point;

use crate::public_keys::AddressPoint;
use std::{
ec::{pow, sqrt},
embedded_curve_ops::{EmbeddedCurveScalar, fixed_base_scalar_mul as derive_public_key},
Expand Down Expand Up @@ -65,8 +66,12 @@ impl Deserialize<AZTEC_ADDRESS_LENGTH> for AztecAddress {
}
}

impl ToPoint for AztecAddress {
fn to_point(self) -> Point {
impl AztecAddress {
pub fn zero() -> Self {
Self { inner: 0 }
}

pub fn to_address_point(self) -> AddressPoint {
// We compute the address point by taking our address, setting it to x, and then solving for y in the
// equation which defines our bn curve:
// y^2 = x^3 - 17; x = address
Expand All @@ -83,13 +88,7 @@ impl ToPoint for AztecAddress {
y = (MAX_FIELD_VALUE + 1) - y;
}

Point { x: self.inner, y, is_infinite: false }
}
}

impl AztecAddress {
pub fn zero() -> Self {
Self { inner: 0 }
AddressPoint { inner: Point { x: self.inner, y, is_infinite: false } }
}

pub fn compute(public_keys: PublicKeys, partial_address: PartialAddress) -> AztecAddress {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,16 @@ impl Deserialize<PUBLIC_KEYS_LENGTH> for PublicKeys {
}
}

pub struct AddressPoint {
inner: Point,
}

impl ToPoint for AddressPoint {
fn to_point(self) -> Point {
self.inner
}
}

#[test]
unconstrained fn compute_public_keys_hash() {
let keys = PublicKeys {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,12 @@ import {
} from '@aztec/circuits.js';
import { randomBytes } from '@aztec/foundation/crypto';
import { Fr, GrumpkinScalar } from '@aztec/foundation/fields';
import { serializeToBuffer } from '@aztec/foundation/serialize';
import { updateInlineTestData } from '@aztec/foundation/testing';

import { EncryptedLogPayload } from './encrypted_log_payload.js';
import { encrypt } from './encryption_util.js';
import { derivePoseidonAESSecret } from './shared_secret_derivation.js';

// placeholder value until tagging is implemented
const PLACEHOLDER_TAG = new Fr(33);
Expand Down Expand Up @@ -59,6 +62,48 @@ describe('EncryptedLogPayload', () => {
});
});

it('outgoing ciphertest matches Noir', () => {
const ephSk = GrumpkinScalar.fromHighLow(
new Fr(0x000000000000000000000000000000000f096b423017226a18461115fa8d34bbn),
new Fr(0x00000000000000000000000000000000d0d302ee245dfaf2807e604eec4715fen),
);

const senderOvskApp = GrumpkinScalar.fromHighLow(
new Fr(0x00000000000000000000000000000000089c6887cb1446d86c64e81afc78048bn),
new Fr(0x0000000000000000000000000000000074d2e28c6bc5176ac02cf7c7d36a444en),
);

const ephPk = derivePublicKeyFromSecretKey(ephSk);

const recipient = AztecAddress.fromBigInt(0x25afb798ea6d0b8c1618e50fdeafa463059415013d3b7c75d46abf5e242be70cn);

const outgoingBodyPlaintext = serializeToBuffer(
ephSk.hi,
ephSk.lo,
recipient,
computePoint(recipient).toCompressedBuffer(),
);
const outgoingBodyCiphertext = encrypt(
outgoingBodyPlaintext,
senderOvskApp,
ephPk,
derivePoseidonAESSecret,
).toString('hex');

expect(outgoingBodyCiphertext).toMatchInlineSnapshot(
`"7fb6e34bc0c5362fa886e994fb2e560c4932ee321fae1bca6e4da1c5f47c11648f96e80e9cf82bb11052f467584a54c80f41bb0ea33c5b16681fd3be7c794f5ceeb6c2e1224743741be744a1935e35c353edac34ade51aea6b2b52441069257d75568532155c4ae5698d53e5fffb153dea3da8dd6ae70849d03cfb2efbe49490bbc32612df990879b254ed94fedb3b3e"`,
);

const byteArrayString = `[${outgoingBodyCiphertext.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/payload.nr',
'outgoing_body_ciphertext_from_typescript',
byteArrayString,
);
});

it('encrypted tagged log matches Noir', () => {
// All the values in this test were arbitrarily set and copied over to `payload.nr`
const contract = AztecAddress.fromString('0x10f48cd9eff7ae5b209c557c70de2e657ee79166868676b787e9417e19260e04');
Expand Down

0 comments on commit 9e3e536

Please sign in to comment.