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: AES oracle #5996

Merged
merged 5 commits into from
Apr 24, 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
1 change: 1 addition & 0 deletions noir-projects/aztec-nr/aztec/src/oracle.nr
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

mod arguments;
mod call_private_function;
mod encryption;
mod get_contract_instance;
mod get_l1_to_l2_membership_witness;
mod get_nullifier_membership_witness;
Expand Down
7 changes: 7 additions & 0 deletions noir-projects/aztec-nr/aztec/src/oracle/encryption.nr
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@

#[oracle(aes128Encrypt)]
pub fn aes128_encrypt_oracle<N>(input: [u8; N], iv: [u8; 16], key: [u8; 16]) -> [u8; N] {}

unconstrained pub fn aes128_encrypt<N>(input: [u8; N], iv: [u8; 16], key: [u8; 16]) -> [u8; N] {
aes128_encrypt_oracle(input, iv, key)
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ contract Test {
note_getter_options::NoteStatus
},
deploy::deploy_contract as aztec_deploy_contract,
oracle::{get_public_key::get_public_key as get_public_key_oracle, unsafe_rand::unsafe_rand}
oracle::{encryption::aes128_encrypt, get_public_key::get_public_key as get_public_key_oracle, unsafe_rand::unsafe_rand}
};
use dep::token_portal_content_hash_lib::{get_mint_private_content_hash, get_mint_public_content_hash};
use dep::value_note::value_note::ValueNote;
Expand Down Expand Up @@ -309,6 +309,12 @@ contract Test {
assert(context.version() == version, "Invalid version");
}

#[aztec(private)]
fn encrypt(input: [u8; 64], iv: [u8; 16], key: [u8; 16]) {
let result = aes128_encrypt(input, iv, key);
context.emit_unencrypted_log(result);
}

#[aztec(public)]
fn assert_public_global_vars(
chain_id: Field,
Expand Down
41 changes: 41 additions & 0 deletions yarn-project/end-to-end/src/e2e_encryption.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { type Wallet } from '@aztec/aztec.js';
import { Aes128 } from '@aztec/circuits.js/barretenberg';
import { TestContract } from '@aztec/noir-contracts.js';

import { randomBytes } from 'crypto';

import { setup } from './fixtures/utils.js';

describe('e2e_encryption', () => {
const aes128 = new Aes128();

let wallet: Wallet;
let teardown: () => Promise<void>;

let contract: TestContract;

beforeAll(async () => {
({ teardown, wallet } = await setup());
contract = await TestContract.deploy(wallet).send().deployed();
}, 25_000);

afterAll(() => teardown());

it('encrypts', async () => {
const input = randomBytes(64);
const iv = randomBytes(16);
const key = randomBytes(16);

const expectedCiphertext = aes128.encryptBufferCBC(input, iv, key);

const logs = await contract.methods
.encrypt(Array.from(input), Array.from(iv), Array.from(key))
.send()
.getUnencryptedLogs();
// Each byte of encrypted data is in its own field and it's all serialized into a long buffer so we simply extract
// each 32nd byte from the buffer to get the encrypted data
const recoveredCiphertext = logs.logs[0].log.data.filter((_, i) => (i + 1) % 32 === 0);

expect(recoveredCiphertext).toEqual(expectedCiphertext);
});
});
13 changes: 13 additions & 0 deletions yarn-project/simulator/src/acvm/oracle/oracle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -378,4 +378,17 @@ export class Oracle {
);
return toAcvmEnqueuePublicFunctionResult(enqueuedRequest);
}

aes128Encrypt(input: ACVMField[], initializationVector: ACVMField[], key: ACVMField[]): ACVMField[] {
// Convert each field to a number and then to a buffer (1 byte is stored in 1 field)
const processedInput = Buffer.from(input.map(fromACVMField).map(f => f.toNumber()));
const processedIV = Buffer.from(initializationVector.map(fromACVMField).map(f => f.toNumber()));
const processedKey = Buffer.from(key.map(fromACVMField).map(f => f.toNumber()));

// Encrypt the input
const ciphertext = this.typedOracle.aes128Encrypt(processedInput, processedIV, processedKey);

// Convert each byte of ciphertext to a field and return it
return Array.from(ciphertext).map(byte => toACVMField(byte));
}
}
4 changes: 4 additions & 0 deletions yarn-project/simulator/src/acvm/oracle/typed_oracle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -233,4 +233,8 @@ export abstract class TypedOracle {
): Promise<PublicCallRequest> {
throw new OracleMethodNotAvailableError('enqueuePublicFunctionCall');
}

aes128Encrypt(_input: Buffer, _initializationVector: Buffer, _key: Buffer): Buffer {
throw new OracleMethodNotAvailableError('encrypt');
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import {
type SideEffect,
type TxContext,
} from '@aztec/circuits.js';
import { type Grumpkin } from '@aztec/circuits.js/barretenberg';
import { Aes128, type Grumpkin } from '@aztec/circuits.js/barretenberg';
import { computePublicDataTreeLeafSlot, computeUniqueNoteHash, siloNoteHash } from '@aztec/circuits.js/hash';
import { type FunctionAbi, type FunctionArtifact, countArgumentsSize } from '@aztec/foundation/abi';
import { type AztecAddress } from '@aztec/foundation/aztec-address';
Expand Down Expand Up @@ -522,4 +522,9 @@ export class ClientExecutionContext extends ViewDataOracle {
}
return values;
}

public override aes128Encrypt(input: Buffer, initializationVector: Buffer, key: Buffer): Buffer {
const aes128 = new Aes128();
return aes128.encryptBufferCBC(input, initializationVector, key);
}
}
Loading