diff --git a/yarn-project/simulator/src/acvm/oracle/oracle.ts b/yarn-project/simulator/src/acvm/oracle/oracle.ts index ac88228ef08d..9b91327c5f9b 100644 --- a/yarn-project/simulator/src/acvm/oracle/oracle.ts +++ b/yarn-project/simulator/src/acvm/oracle/oracle.ts @@ -4,6 +4,7 @@ import { EventSelector, FunctionSelector } from '@aztec/foundation/abi'; import { AztecAddress } from '@aztec/foundation/aztec-address'; import { Fr, Point } from '@aztec/foundation/fields'; import { createDebugLogger } from '@aztec/foundation/log'; +import { to2Fields } from '@aztec/foundation/serialize'; import { type ACVMField } from '../acvm_types.js'; import { frToBoolean, frToNumber, fromACVMField } from '../deserialize.js'; @@ -378,4 +379,22 @@ export class Oracle { ); return toAcvmEnqueuePublicFunctionResult(enqueuedRequest); } + + encrypt([symmetricKey]: ACVMField[], [initializationVector]: ACVMField[], plaintext: ACVMField[]): ACVMField[] { + // Symmetric key and initialization vector (IV) are 16 bytes and we store them as big endian in Fr + const processedSK = fromACVMField(symmetricKey).toBuffer().subarray(0, 16); + const processedIV = fromACVMField(initializationVector).toBuffer().subarray(0, 16); + // TODO(benesjan): we could save some info here by not including the 2 empty bits at the end of each serialized + // field --> this could be valuable as the ciphertext will go on-chain + const processedPlaintext = Buffer.concat(plaintext.map(fromACVMField).map(f => f.toBuffer())); + const ciphertext = this.typedOracle.encrypt(processedSK, processedIV, processedPlaintext); + // Chunk the ciphertext buffer to 32 bytes and on each chunk call to2Fields function + const ciphertextFields: Fr[] = []; + for (let i = 0; i < ciphertext.length; i += Fr.SIZE_IN_BYTES) { + const chunk = ciphertext.subarray(i, i + Fr.SIZE_IN_BYTES); + ciphertextFields.push(...to2Fields(chunk)); + } + + return ciphertextFields.map(toACVMField); + } } diff --git a/yarn-project/simulator/src/acvm/oracle/typed_oracle.ts b/yarn-project/simulator/src/acvm/oracle/typed_oracle.ts index 70f57233af17..3a0ebe415e30 100644 --- a/yarn-project/simulator/src/acvm/oracle/typed_oracle.ts +++ b/yarn-project/simulator/src/acvm/oracle/typed_oracle.ts @@ -233,4 +233,8 @@ export abstract class TypedOracle { ): Promise { throw new OracleMethodNotAvailableError('enqueuePublicFunctionCall'); } + + encrypt(_symmetricKey: Buffer, _initializationVector: Buffer, _plaintext: Buffer): Buffer { + throw new OracleMethodNotAvailableError('encrypt'); + } } diff --git a/yarn-project/simulator/src/client/client_execution_context.ts b/yarn-project/simulator/src/client/client_execution_context.ts index 0ec755281ccb..618cca083ce6 100644 --- a/yarn-project/simulator/src/client/client_execution_context.ts +++ b/yarn-project/simulator/src/client/client_execution_context.ts @@ -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'; @@ -522,4 +522,9 @@ export class ClientExecutionContext extends ViewDataOracle { } return values; } + + public override encrypt(symmetricKey: Buffer, initializationVector: Buffer, plaintext: Buffer): Buffer { + const aes128 = new Aes128(); + return aes128.encryptBufferCBC(plaintext, initializationVector, symmetricKey); + } }