diff --git a/docs/docs/migration_notes.md b/docs/docs/migration_notes.md index f71ec322758b..a73799aaf364 100644 --- a/docs/docs/migration_notes.md +++ b/docs/docs/migration_notes.md @@ -8,6 +8,10 @@ Aztec is in full-speed development. Literally every version breaks compatibility ## TBD +## [aztec.js] AztecNode.getPublicDataTreeWitness renamed as AztecNode.getPublicDataWitness + +This change was done to have consistent naming across codebase. + ## [aztec.js] Wallet interface and Authwit management The `Wallet` interface in `aztec.js` is undergoing transformations, trying to be friendlier to wallet builders and reducing the surface of its API. This means `Wallet` no longer extends `PXE`, and instead just implements a subset of the methods of the former. This is NOT going to be its final form, but paves the way towards better interfaces and starts to clarify what the responsibilities of the wallet are: diff --git a/noir-projects/aztec-nr/aztec/src/encrypted_logs/log_assembly_strategies/default_aes128/note/encryption.nr b/noir-projects/aztec-nr/aztec/src/encrypted_logs/log_assembly_strategies/default_aes128/note/encryption.nr index 22cd2f8c43d6..c22047499739 100644 --- a/noir-projects/aztec-nr/aztec/src/encrypted_logs/log_assembly_strategies/default_aes128/note/encryption.nr +++ b/noir-projects/aztec-nr/aztec/src/encrypted_logs/log_assembly_strategies/default_aes128/note/encryption.nr @@ -302,11 +302,11 @@ mod test { test::helpers::test_environment::TestEnvironment, }; use super::{decrypt_log, encrypt_log, PRIVATE_LOG_PLAINTEXT_SIZE_IN_FIELDS}; - use protocol_types::{address::AztecAddress, traits::{FromField, Serialize}}; + use protocol_types::{address::AztecAddress, traits::FromField}; use std::{embedded_curve_ops::EmbeddedCurveScalar, test::OracleMock}; #[test] - unconstrained fn test_encrypt_decrypt_log() { + unconstrained fn encrypt_decrypt_log() { let mut env = TestEnvironment::new(); // Advance 1 block so we can read historic state from private env.advance_block_by(1); @@ -344,7 +344,7 @@ mod test { EmbeddedCurveScalar::from_field(eph_sk), recipient, ); - let _ = OracleMock::mock("getSharedSecret").returns(shared_secret.serialize()); + let _ = OracleMock::mock("getSharedSecret").returns(shared_secret); // Decrypt the log let decrypted = decrypt_log(encrypted_log, recipient); diff --git a/noir-projects/aztec-nr/aztec/src/oracle/block_header.nr b/noir-projects/aztec-nr/aztec/src/oracle/block_header.nr index 270319405741..65a8e60a4300 100644 --- a/noir-projects/aztec-nr/aztec/src/oracle/block_header.nr +++ b/noir-projects/aztec-nr/aztec/src/oracle/block_header.nr @@ -1,20 +1,16 @@ -use dep::protocol_types::{ - block_header::BlockHeader, - constants::BLOCK_HEADER_LENGTH, - traits::{Deserialize, Hash}, +use protocol_types::{ + block_header::BlockHeader, merkle_tree::root::root_from_sibling_path, traits::Hash, }; -use dep::protocol_types::merkle_tree::root::root_from_sibling_path; use crate::{ context::PrivateContext, oracle::get_membership_witness::get_archive_membership_witness, }; #[oracle(getBlockHeader)] -unconstrained fn get_block_header_at_oracle(_block_number: u32) -> [Field; BLOCK_HEADER_LENGTH] {} +unconstrained fn get_block_header_at_oracle(_block_number: u32) -> BlockHeader {} unconstrained fn get_block_header_at_internal(block_number: u32) -> BlockHeader { - let header = get_block_header_at_oracle(block_number); - BlockHeader::deserialize(header) + get_block_header_at_oracle(block_number) } pub fn get_block_header_at(block_number: u32, context: PrivateContext) -> BlockHeader { diff --git a/noir-projects/aztec-nr/aztec/src/oracle/get_contract_instance.nr b/noir-projects/aztec-nr/aztec/src/oracle/get_contract_instance.nr index 70ce38c43595..543b5c955611 100644 --- a/noir-projects/aztec-nr/aztec/src/oracle/get_contract_instance.nr +++ b/noir-projects/aztec-nr/aztec/src/oracle/get_contract_instance.nr @@ -1,21 +1,14 @@ -use dep::protocol_types::{ - address::AztecAddress, - constants::CONTRACT_INSTANCE_LENGTH, - contract_class_id::ContractClassId, - contract_instance::ContractInstance, - traits::{Deserialize, FromField}, +use protocol_types::{ + address::AztecAddress, contract_class_id::ContractClassId, contract_instance::ContractInstance, + traits::FromField, }; // NOTE: this is for use in private only #[oracle(getContractInstance)] -unconstrained fn get_contract_instance_oracle( - _address: AztecAddress, -) -> [Field; CONTRACT_INSTANCE_LENGTH] {} +unconstrained fn get_contract_instance_oracle(_address: AztecAddress) -> ContractInstance {} // NOTE: this is for use in private only -unconstrained fn get_contract_instance_internal( - address: AztecAddress, -) -> [Field; CONTRACT_INSTANCE_LENGTH] { +unconstrained fn get_contract_instance_internal(address: AztecAddress) -> ContractInstance { get_contract_instance_oracle(address) } @@ -23,8 +16,7 @@ unconstrained fn get_contract_instance_internal( pub fn get_contract_instance(address: AztecAddress) -> ContractInstance { // Safety: The to_address function combines all values in the instance object to produce an address, // so by checking that we get the expected address we validate the entire struct. - let instance = - unsafe { ContractInstance::deserialize(get_contract_instance_internal(address)) }; + let instance = unsafe { get_contract_instance_internal(address) }; assert_eq(instance.to_address(), address); instance diff --git a/noir-projects/aztec-nr/aztec/src/oracle/get_l1_to_l2_membership_witness.nr b/noir-projects/aztec-nr/aztec/src/oracle/get_l1_to_l2_membership_witness.nr index d648f7f2b12e..f1e1c8cb6352 100644 --- a/noir-projects/aztec-nr/aztec/src/oracle/get_l1_to_l2_membership_witness.nr +++ b/noir-projects/aztec-nr/aztec/src/oracle/get_l1_to_l2_membership_witness.nr @@ -1,4 +1,3 @@ -use crate::utils::array; use dep::protocol_types::{address::AztecAddress, constants::L1_TO_L2_MSG_TREE_HEIGHT}; /// Returns the leaf index and sibling path of an entry in the L1 to L2 messaging tree, which can then be used to prove @@ -8,12 +7,7 @@ pub unconstrained fn get_l1_to_l2_membership_witness( message_hash: Field, secret: Field, ) -> (Field, [Field; L1_TO_L2_MSG_TREE_HEIGHT]) { - let returned_message = - get_l1_to_l2_membership_witness_oracle(contract_address, message_hash, secret); - let leaf_index = returned_message[0]; - let sibling_path = array::subarray(returned_message, 1); - - (leaf_index, sibling_path) + get_l1_to_l2_membership_witness_oracle(contract_address, message_hash, secret) } // Obtains membership witness (index and sibling path) for a message in the L1 to L2 message tree. @@ -22,4 +16,4 @@ unconstrained fn get_l1_to_l2_membership_witness_oracle( _contract_address: AztecAddress, _message_hash: Field, _secret: Field, -) -> [Field; L1_TO_L2_MSG_TREE_HEIGHT + 1] {} +) -> (Field, [Field; L1_TO_L2_MSG_TREE_HEIGHT]) {} diff --git a/noir-projects/aztec-nr/aztec/src/oracle/get_membership_witness.nr b/noir-projects/aztec-nr/aztec/src/oracle/get_membership_witness.nr index 7a6a28b385be..5588a8d31dae 100644 --- a/noir-projects/aztec-nr/aztec/src/oracle/get_membership_witness.nr +++ b/noir-projects/aztec-nr/aztec/src/oracle/get_membership_witness.nr @@ -1,5 +1,4 @@ -use crate::utils::array; -use dep::protocol_types::constants::{ARCHIVE_HEIGHT, NOTE_HASH_TREE_HEIGHT}; +use protocol_types::constants::{ARCHIVE_HEIGHT, NOTE_HASH_TREE_HEIGHT}; global NOTE_HASH_TREE_ID: Field = 1; global ARCHIVE_TREE_ID: Field = 4; @@ -17,20 +16,11 @@ pub struct MembershipWitness { } #[oracle(getMembershipWitness)] -unconstrained fn get_membership_witness_oracle( +unconstrained fn get_membership_witness( _block_number: u32, _tree_id: Field, _leaf_value: Field, -) -> [Field; M] {} - -pub unconstrained fn get_membership_witness( - block_number: u32, - tree_id: Field, - leaf_value: Field, -) -> MembershipWitness { - let fields: [Field; M] = get_membership_witness_oracle(block_number, tree_id, leaf_value); - MembershipWitness { index: fields[0], path: array::subarray(fields, 1) } -} +) -> MembershipWitness {} // Note: get_nullifier_membership_witness function is implemented in get_nullifier_membership_witness.nr diff --git a/noir-projects/aztec-nr/aztec/src/oracle/get_nullifier_membership_witness.nr b/noir-projects/aztec-nr/aztec/src/oracle/get_nullifier_membership_witness.nr index d41ac58cf148..668f51df5862 100644 --- a/noir-projects/aztec-nr/aztec/src/oracle/get_nullifier_membership_witness.nr +++ b/noir-projects/aztec-nr/aztec/src/oracle/get_nullifier_membership_witness.nr @@ -28,7 +28,7 @@ impl NullifierMembershipWitness { unconstrained fn get_low_nullifier_membership_witness_oracle( _block_number: u32, _nullifier: Field, -) -> [Field; NULLIFIER_MEMBERSHIP_WITNESS] {} +) -> NullifierMembershipWitness {} // Nullifier here refers to the nullifier we are looking to get non-inclusion proof for (by proving that a lower // nullifier's next_value is bigger than the nullifier) @@ -36,15 +36,14 @@ pub unconstrained fn get_low_nullifier_membership_witness( block_number: u32, nullifier: Field, ) -> NullifierMembershipWitness { - let fields = get_low_nullifier_membership_witness_oracle(block_number, nullifier); - NullifierMembershipWitness::deserialize(fields) + get_low_nullifier_membership_witness_oracle(block_number, nullifier) } #[oracle(getNullifierMembershipWitness)] unconstrained fn get_nullifier_membership_witness_oracle( _block_number: u32, _nullifier: Field, -) -> [Field; NULLIFIER_MEMBERSHIP_WITNESS] {} +) -> NullifierMembershipWitness {} // Nullifier here refers to the nullifier we are looking to get non-inclusion proof for (by proving that a lower // nullifier's next_value is bigger than the nullifier) @@ -52,6 +51,5 @@ pub unconstrained fn get_nullifier_membership_witness( block_number: u32, nullifier: Field, ) -> NullifierMembershipWitness { - let fields = get_nullifier_membership_witness_oracle(block_number, nullifier); - NullifierMembershipWitness::deserialize(fields) + get_nullifier_membership_witness_oracle(block_number, nullifier) } diff --git a/noir-projects/aztec-nr/aztec/src/oracle/get_public_data_witness.nr b/noir-projects/aztec-nr/aztec/src/oracle/get_public_data_witness.nr index 07879b4fd3e1..9954e4f570da 100644 --- a/noir-projects/aztec-nr/aztec/src/oracle/get_public_data_witness.nr +++ b/noir-projects/aztec-nr/aztec/src/oracle/get_public_data_witness.nr @@ -1,34 +1,20 @@ -use crate::utils::array; use dep::protocol_types::{constants::PUBLIC_DATA_TREE_HEIGHT, data::PublicDataTreeLeafPreimage}; -global LEAF_PREIMAGE_LENGTH: u32 = 4; -global PUBLIC_DATA_WITNESS: u32 = 45; - pub struct PublicDataWitness { pub index: Field, pub leaf_preimage: PublicDataTreeLeafPreimage, pub path: [Field; PUBLIC_DATA_TREE_HEIGHT], } -#[oracle(getPublicDataTreeWitness)] +#[oracle(getPublicDataWitness)] unconstrained fn get_public_data_witness_oracle( _block_number: u32, _public_data_tree_index: Field, -) -> [Field; PUBLIC_DATA_WITNESS] {} +) -> PublicDataWitness {} pub unconstrained fn get_public_data_witness( block_number: u32, public_data_tree_index: Field, ) -> PublicDataWitness { - let fields = get_public_data_witness_oracle(block_number, public_data_tree_index); - PublicDataWitness { - index: fields[0], - leaf_preimage: PublicDataTreeLeafPreimage { - slot: fields[1], - value: fields[2], - next_index: fields[3] as u32, - next_slot: fields[4], - }, - path: array::subarray(fields, 1 + LEAF_PREIMAGE_LENGTH), - } + get_public_data_witness_oracle(block_number, public_data_tree_index) } diff --git a/noir-projects/aztec-nr/aztec/src/oracle/key_validation_request.nr b/noir-projects/aztec-nr/aztec/src/oracle/key_validation_request.nr index a6754e5458aa..117c0c01b370 100644 --- a/noir-projects/aztec-nr/aztec/src/oracle/key_validation_request.nr +++ b/noir-projects/aztec-nr/aztec/src/oracle/key_validation_request.nr @@ -1,27 +1,14 @@ -use dep::protocol_types::{ - abis::validation_requests::{ - key_validation_request::KEY_VALIDATION_REQUEST_LENGTH, KeyValidationRequest, - }, - traits::Deserialize, -}; +use protocol_types::abis::validation_requests::KeyValidationRequest; #[oracle(getKeyValidationRequest)] unconstrained fn get_key_validation_request_oracle( _pk_m_hash: Field, _key_index: Field, -) -> [Field; KEY_VALIDATION_REQUEST_LENGTH] {} - -unconstrained fn get_key_validation_request_internal( - npk_m_hash: Field, - key_index: Field, -) -> KeyValidationRequest { - let result = get_key_validation_request_oracle(npk_m_hash, key_index); - KeyValidationRequest::deserialize(result) -} +) -> KeyValidationRequest {} pub unconstrained fn get_key_validation_request( pk_m_hash: Field, key_index: Field, ) -> KeyValidationRequest { - get_key_validation_request_internal(pk_m_hash, key_index) + get_key_validation_request_oracle(pk_m_hash, key_index) } diff --git a/noir-projects/aztec-nr/aztec/src/oracle/notes.nr b/noir-projects/aztec-nr/aztec/src/oracle/notes.nr index db2b8f6413cb..766ad74032da 100644 --- a/noir-projects/aztec-nr/aztec/src/oracle/notes.nr +++ b/noir-projects/aztec-nr/aztec/src/oracle/notes.nr @@ -54,7 +54,7 @@ unconstrained fn notify_created_note_oracle_wrapper( note_hash: Field, counter: u32, ) { - let _ = notify_created_note_oracle(storage_slot, note_type_id, packed_note, note_hash, counter); + notify_created_note_oracle(storage_slot, note_type_id, packed_note, note_hash, counter); } #[oracle(notifyCreatedNote)] @@ -64,29 +64,25 @@ unconstrained fn notify_created_note_oracle( _packed_note: [Field; N], _note_hash: Field, _counter: u32, -) -> Field {} +) {} unconstrained fn notify_nullified_note_oracle_wrapper( nullifier: Field, note_hash: Field, counter: u32, ) { - let _ = notify_nullified_note_oracle(nullifier, note_hash, counter); + notify_nullified_note_oracle(nullifier, note_hash, counter); } #[oracle(notifyNullifiedNote)] -unconstrained fn notify_nullified_note_oracle( - _nullifier: Field, - _note_hash: Field, - _counter: u32, -) -> Field {} +unconstrained fn notify_nullified_note_oracle(_nullifier: Field, _note_hash: Field, _counter: u32) {} unconstrained fn notify_created_nullifier_oracle_wrapper(nullifier: Field) { - let _ = notify_created_nullifier_oracle(nullifier); + notify_created_nullifier_oracle(nullifier); } #[oracle(notifyCreatedNullifier)] -unconstrained fn notify_created_nullifier_oracle(_nullifier: Field) -> Field {} +unconstrained fn notify_created_nullifier_oracle(_nullifier: Field) {} #[oracle(getNotes)] unconstrained fn get_notes_oracle( @@ -213,11 +209,11 @@ where /// current transaction is included in a block. While this might seem of little use at first, certain design patterns /// benefit from this abstraction (see e.g. `PrivateMutable`). pub unconstrained fn check_nullifier_exists(inner_nullifier: Field) -> bool { - check_nullifier_exists_oracle(inner_nullifier) == 1 + check_nullifier_exists_oracle(inner_nullifier) } #[oracle(checkNullifierExists)] -unconstrained fn check_nullifier_exists_oracle(_inner_nullifier: Field) -> Field {} +unconstrained fn check_nullifier_exists_oracle(_inner_nullifier: Field) -> bool {} /// Same as `get_indexed_tagging_secret_as_sender`, except it returns the derived tag, ready to be included in a log. pub unconstrained fn get_app_tag_as_sender(sender: AztecAddress, recipient: AztecAddress) -> Field { diff --git a/noir-projects/aztec-nr/aztec/src/oracle/shared_secret.nr b/noir-projects/aztec-nr/aztec/src/oracle/shared_secret.nr index 4462f4b04e2d..646ffe9e378e 100644 --- a/noir-projects/aztec-nr/aztec/src/oracle/shared_secret.nr +++ b/noir-projects/aztec-nr/aztec/src/oracle/shared_secret.nr @@ -1,15 +1,8 @@ -use dep::protocol_types::{ - address::aztec_address::AztecAddress, - point::{Point, POINT_LENGTH}, - traits::Deserialize, -}; +use protocol_types::{address::aztec_address::AztecAddress, point::Point}; // TODO(#12656): return an app-siloed secret + document this #[oracle(getSharedSecret)] -unconstrained fn get_shared_secret_oracle( - address: AztecAddress, - ephPk: Point, -) -> [Field; POINT_LENGTH] {} +unconstrained fn get_shared_secret_oracle(address: AztecAddress, ephPk: Point) -> Point {} /// Returns an app-siloed shared secret between `address` and someone who knows the secret key behind an /// ephemeral public key `ephPk`. The app-siloing means that contracts cannot retrieve secrets that belong to @@ -21,6 +14,5 @@ unconstrained fn get_shared_secret_oracle( /// where `ivsk + h` is the 'preaddress' i.e. the preimage of the address, also called the address secret. /// TODO(#12656): app-silo this secret pub unconstrained fn get_shared_secret(address: AztecAddress, ephPk: Point) -> Point { - let fields = get_shared_secret_oracle(address, ephPk); - Point::deserialize(fields) + get_shared_secret_oracle(address, ephPk) } diff --git a/noir-projects/aztec-nr/aztec/src/state_vars/private_mutable/test.nr b/noir-projects/aztec-nr/aztec/src/state_vars/private_mutable/test.nr index 0d7a7f8da2f9..09e54751cde4 100644 --- a/noir-projects/aztec-nr/aztec/src/state_vars/private_mutable/test.nr +++ b/noir-projects/aztec-nr/aztec/src/state_vars/private_mutable/test.nr @@ -19,8 +19,8 @@ unconstrained fn in_private( ) -> PrivateMutable { let state_var = PrivateMutable::new(&mut env.private(), storage_slot); - // This oracle is called for its side effects alone - it's always expected to return 0. - let _ = OracleMock::mock("notifyCreatedNote").returns(0); + // This oracle is called for its side effects alone - it does not return anything. + let _ = OracleMock::mock("notifyCreatedNote").returns(()); state_var } diff --git a/yarn-project/aztec-node/src/aztec-node/server.ts b/yarn-project/aztec-node/src/aztec-node/server.ts index 82463cb700b1..a79abb677d51 100644 --- a/yarn-project/aztec-node/src/aztec-node/server.ts +++ b/yarn-project/aztec-node/src/aztec-node/server.ts @@ -784,7 +784,7 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable { return new NullifierMembershipWitness(BigInt(index), preimageData as NullifierLeafPreimage, siblingPath); } - async getPublicDataTreeWitness(blockNumber: L2BlockNumber, leafSlot: Fr): Promise { + async getPublicDataWitness(blockNumber: L2BlockNumber, leafSlot: Fr): Promise { const committedDb = await this.#getWorldState(blockNumber); const lowLeafResult = await committedDb.getPreviousValueIndex(MerkleTreeId.PUBLIC_DATA_TREE, leafSlot.toBigInt()); if (!lowLeafResult) { diff --git a/yarn-project/noir-protocol-circuits-types/src/utils/client/foreign_call_handler.ts b/yarn-project/noir-protocol-circuits-types/src/utils/client/foreign_call_handler.ts index 22a1874029f3..d66f915cca88 100644 --- a/yarn-project/noir-protocol-circuits-types/src/utils/client/foreign_call_handler.ts +++ b/yarn-project/noir-protocol-circuits-types/src/utils/client/foreign_call_handler.ts @@ -4,10 +4,6 @@ import type { ForeignCallInput, ForeignCallOutput } from '@aztec/noir-acvm_js'; import { strict as assert } from 'assert'; -function fromACVMField(field: string): Fr { - return Fr.fromBuffer(Buffer.from(field.slice(2), 'hex')); -} - export function foreignCallHandler(name: string, args: ForeignCallInput[]): Promise { // ForeignCallInput is actually a string[], so the args are string[][]. const log = createLogger('noir-protocol-circuits:oracle'); @@ -15,8 +11,8 @@ export function foreignCallHandler(name: string, args: ForeignCallInput[]): Prom if (name === 'debugLog') { assert(args.length === 3, 'expected 3 arguments for debugLog: msg, fields_length, fields'); const [msgRaw, _ignoredFieldsSize, fields] = args; - const msg: string = msgRaw.map(acvmField => String.fromCharCode(fromACVMField(acvmField).toNumber())).join(''); - const fieldsFr: Fr[] = fields.map((field: string) => fromACVMField(field)); + const msg: string = msgRaw.map(acvmField => String.fromCharCode(Fr.fromString(acvmField).toNumber())).join(''); + const fieldsFr: Fr[] = fields.map((field: string) => Fr.fromString(field)); log.verbose('debug_log ' + applyStringFormatting(msg, fieldsFr)); } else if (name === 'noOp') { // Workaround for compiler issues where data is deleted because it's "unused" diff --git a/yarn-project/noir-protocol-circuits-types/src/utils/server/foreign_call_handler.ts b/yarn-project/noir-protocol-circuits-types/src/utils/server/foreign_call_handler.ts index a436fd0a31ba..eefd55037115 100644 --- a/yarn-project/noir-protocol-circuits-types/src/utils/server/foreign_call_handler.ts +++ b/yarn-project/noir-protocol-circuits-types/src/utils/server/foreign_call_handler.ts @@ -5,14 +5,6 @@ import type { ForeignCallInput, ForeignCallOutput } from '@aztec/noir-acvm_js'; import { strict as assert } from 'assert'; -function fromACVMField(field: string): Fr { - return Fr.fromBuffer(Buffer.from(field.slice(2), 'hex')); -} - -function toACVMField(field: Fr): string { - return `0x${field.toBuffer().toString('hex')}`; -} - export async function foreignCallHandler(name: string, args: ForeignCallInput[]): Promise { // ForeignCallInput is actually a string[], so the args are string[][]. const log = createLogger('noir-protocol-circuits:oracle'); @@ -20,25 +12,25 @@ export async function foreignCallHandler(name: string, args: ForeignCallInput[]) if (name === 'debugLog') { assert(args.length === 3, 'expected 3 arguments for debugLog: msg, fields_length, fields'); const [msgRaw, _ignoredFieldsSize, fields] = args; - const msg: string = msgRaw.map(acvmField => String.fromCharCode(fromACVMField(acvmField).toNumber())).join(''); - const fieldsFr: Fr[] = fields.map((field: string) => fromACVMField(field)); + const msg: string = msgRaw.map(acvmField => String.fromCharCode(Fr.fromString(acvmField).toNumber())).join(''); + const fieldsFr: Fr[] = fields.map((field: string) => Fr.fromString(field)); log.verbose('debug_log ' + applyStringFormatting(msg, fieldsFr)); } else if (name === 'evaluateBlobs') { // TODO(#10323): this was added to save simulation time (~1min in ACVM, ~3mins in wasm -> 500ms). // The use of bignum adds a lot of unconstrained code which overloads limits when simulating. // If/when simulation times of unconstrained are improved, remove this. // Create and evaulate our blobs: - const paddedBlobsAsFr: Fr[] = args[0].map((field: string) => fromACVMField(field)); - const kzgCommitments = args[1].map((field: string) => fromACVMField(field)); + const paddedBlobsAsFr: Fr[] = args[0].map((field: string) => Fr.fromString(field)); + const kzgCommitments = args[1].map((field: string) => Fr.fromString(field)); const spongeBlob = SpongeBlob.fromFields( args .slice(2) .flat() - .map((field: string) => fromACVMField(field)), + .map((field: string) => Fr.fromString(field)), ); const blobsAsFr = paddedBlobsAsFr.slice(0, spongeBlob.expectedFields); // NB: the above used to be: - // const blobsAsFr: Fr[] = args[0].map((field: string) => fromACVMField(field)).filter(field => !field.isZero()); + // const blobsAsFr: Fr[] = args[0].map((field: string) => Fr.fromString(field)).filter(field => !field.isZero()); // ...but we now have private logs which have a fixed number of fields and may have 0 values. // TODO(Miranda): trim 0 fields from private logs const blobs = await Blob.getBlobs(blobsAsFr); @@ -57,7 +49,7 @@ export async function foreignCallHandler(name: string, args: ForeignCallInput[]) ); } }); - return Promise.resolve([blobPublicInputs.toFields().map(toACVMField)]); + return Promise.resolve([blobPublicInputs.toFields().map(field => field.toString())]); } else if (name === 'noOp') { // Workaround for compiler issues where data is deleted because it's "unused" } else { diff --git a/yarn-project/pxe/src/private_kernel/private_kernel_oracle_impl.ts b/yarn-project/pxe/src/private_kernel/private_kernel_oracle_impl.ts index 3a0da8a20d66..f68faee33dc0 100644 --- a/yarn-project/pxe/src/private_kernel/private_kernel_oracle_impl.ts +++ b/yarn-project/pxe/src/private_kernel/private_kernel_oracle_impl.ts @@ -95,7 +95,7 @@ export class PrivateKernelOracleImpl implements PrivateKernelOracle { ProtocolContractAddress.ContractInstanceDeployer, sharedMutableHashSlot, ); - const updatedClassIdWitness = await this.node.getPublicDataTreeWitness(this.blockNumber, hashLeafSlot); + const updatedClassIdWitness = await this.node.getPublicDataWitness(this.blockNumber, hashLeafSlot); if (!updatedClassIdWitness) { throw new Error(`No public data tree witness found for ${hashLeafSlot}`); diff --git a/yarn-project/pxe/src/pxe_oracle_interface/pxe_oracle_interface.ts b/yarn-project/pxe/src/pxe_oracle_interface/pxe_oracle_interface.ts index 0c2950395ed7..1cff4c39112c 100644 --- a/yarn-project/pxe/src/pxe_oracle_interface/pxe_oracle_interface.ts +++ b/yarn-project/pxe/src/pxe_oracle_interface/pxe_oracle_interface.ts @@ -209,8 +209,8 @@ export class PXEOracleInterface implements ExecutionDataProvider { return await this.aztecNode.getBlock(blockNumber); } - public async getPublicDataTreeWitness(blockNumber: number, leafSlot: Fr): Promise { - return await this.aztecNode.getPublicDataTreeWitness(blockNumber, leafSlot); + public async getPublicDataWitness(blockNumber: number, leafSlot: Fr): Promise { + return await this.aztecNode.getPublicDataWitness(blockNumber, leafSlot); } public async getPublicStorageAt(blockNumber: number, contract: AztecAddress, slot: Fr): Promise { diff --git a/yarn-project/simulator/src/common/message_load_oracle_inputs.ts b/yarn-project/simulator/src/common/message_load_oracle_inputs.ts index 47b29ec4571e..e5f65d15cffb 100644 --- a/yarn-project/simulator/src/common/message_load_oracle_inputs.ts +++ b/yarn-project/simulator/src/common/message_load_oracle_inputs.ts @@ -12,4 +12,12 @@ export class MessageLoadOracleInputs { toFields(): Fr[] { return [new Fr(this.index), ...this.siblingPath.toFields()]; } + + /** + * Returns a representation of the public data witness as expected by intrinsic Noir deserialization. + */ + public toNoirRepresentation(): (string | string[])[] { + // TODO(#12874): remove the stupid as string conversion by modifying ForeignCallOutput type in acvm.js + return [new Fr(this.index).toString() as string, this.siblingPath.toFields().map(fr => fr.toString()) as string[]]; + } } diff --git a/yarn-project/simulator/src/private/acvm/acvm.ts b/yarn-project/simulator/src/private/acvm/acvm.ts index d85ff1fbf4b9..f06bb5e42cfc 100644 --- a/yarn-project/simulator/src/private/acvm/acvm.ts +++ b/yarn-project/simulator/src/private/acvm/acvm.ts @@ -15,18 +15,7 @@ import type { ORACLE_NAMES } from './oracle/index.js'; /** * The callback interface for the ACIR. */ -export type ACIRCallback = Record< - ORACLE_NAMES, - ( - ...args: ForeignCallInput[] - ) => - | void - | Promise - | ForeignCallOutput - | ForeignCallOutput[] - | Promise - | Promise ->; +export type ACIRCallback = Record Promise>; /** * The result of executing an ACIR. @@ -54,7 +43,7 @@ export async function acvm( const solvedAndReturnWitness = await executeCircuitWithReturnWitness( acir, initialWitness, - async (name: string, args: ForeignCallInput[]) => { + (name: string, args: ForeignCallInput[]) => { try { logger.debug(`Oracle callback ${name}`); const oracleFunction = callback[name as ORACLE_NAMES]; @@ -62,17 +51,7 @@ export async function acvm( throw new Error(`Oracle callback ${name} not found`); } - const result = await oracleFunction.call(callback, ...args); - - if (typeof result === 'undefined') { - return []; - } else if (result instanceof Array && !result.every(item => typeof item === 'string')) { - // We are dealing with a nested array which means that we do not need it wrap it in another array as to have - // the nested array structure it is already "wrapped". - return result; - } else { - return [result] as ForeignCallOutput[]; - } + return oracleFunction.call(callback, ...args); } catch (err) { let typedError: Error; if (err instanceof Error) { diff --git a/yarn-project/simulator/src/private/acvm/deserialize.ts b/yarn-project/simulator/src/private/acvm/deserialize.ts index fb970e304b9d..77423ca5d6ad 100644 --- a/yarn-project/simulator/src/private/acvm/deserialize.ts +++ b/yarn-project/simulator/src/private/acvm/deserialize.ts @@ -3,33 +3,6 @@ import { hexToBuffer } from '@aztec/foundation/string'; import type { ACVMField, ACVMWitness } from './acvm_types.js'; -/** - * Converts an ACVM field to a Fr. - * @param field - The ACVM field to convert. - * @returns The Fr. - */ -export function fromACVMField(field: ACVMField): Fr { - return Fr.fromBuffer(Buffer.from(field.slice(2), 'hex')); -} - -/** - * Converts a field to a number. - * @param fr - The field to convert. - * @returns The number. - * TODO(#4102): Nuke this once block number is big int. - */ -export function frToNumber(fr: Fr): number { - return Number(fr.value); -} - -/** - * Converts a field to a boolean. - * @param fr - The field to convert. - */ -export function frToBoolean(fr: Fr): boolean { - return fr.toBigInt() === BigInt(1); -} - /** * Converts a Noir BoundedVec of Fields into an Fr array. Note that BoundedVecs are structs, and therefore translated as * two separate ACVMField values (an array and a single field). @@ -39,7 +12,7 @@ export function frToBoolean(fr: Fr): boolean { * @returns An array with the same content as the Noir version. Elements past the length are discarded. */ export function fromBoundedVec(storage: ACVMField[], length: ACVMField): Fr[] { - return storage.slice(0, frToNumber(fromACVMField(length))).map(fromACVMField); + return storage.slice(0, Fr.fromString(length).toNumber()).map(Fr.fromString); } /** @@ -56,7 +29,7 @@ export function fromUintBoundedVec(storage: ACVMField[], length: ACVMField, uint throw new Error(`u${uintBitSize} is not a supported type in Noir`); } const uintByteSize = uintBitSize / 8; - const boundedStorage = storage.slice(0, frToNumber(fromACVMField(length))); + const boundedStorage = storage.slice(0, Fr.fromString(length).toNumber()); return Buffer.concat(boundedStorage.map(str => hexToBuffer(str).subarray(-uintByteSize))); } @@ -67,7 +40,7 @@ export function fromUintBoundedVec(storage: ACVMField[], length: ACVMField, uint */ export function witnessMapToFields(witness: ACVMWitness): Fr[] { const sortedKeys = [...witness.keys()].sort((a, b) => a - b); - return sortedKeys.map(key => witness.get(key)!).map(fromACVMField); + return sortedKeys.map(key => witness.get(key)!).map(Fr.fromString); } /** diff --git a/yarn-project/simulator/src/private/acvm/oracle/oracle.ts b/yarn-project/simulator/src/private/acvm/oracle/oracle.ts index ba1cdb767ea3..d791679c5ae0 100644 --- a/yarn-project/simulator/src/private/acvm/oracle/oracle.ts +++ b/yarn-project/simulator/src/private/acvm/oracle/oracle.ts @@ -5,14 +5,7 @@ import { ContractClassLog, LogWithTxData } from '@aztec/stdlib/logs'; import { MerkleTreeId } from '@aztec/stdlib/trees'; import type { ACVMField } from '../acvm_types.js'; -import { - frToBoolean, - frToNumber, - fromACVMField, - fromBoundedVec, - fromUintArray, - fromUintBoundedVec, -} from '../deserialize.js'; +import { fromBoundedVec, fromUintArray, fromUintBoundedVec } from '../deserialize.js'; import { bufferToBoundedVec, toACVMField, toACVMFieldSingleOrArray } from '../serialize.js'; import type { TypedOracle } from './typed_oracle.js'; @@ -22,46 +15,46 @@ import type { TypedOracle } from './typed_oracle.js'; export class Oracle { constructor(private typedOracle: TypedOracle) {} - getRandomField(): ACVMField { + getRandomField(): Promise { const val = this.typedOracle.getRandomField(); - return toACVMField(val); + return Promise.resolve([toACVMField(val)]); } // Since the argument is a slice, noir automatically adds a length field to oracle call. - async storeInExecutionCache(_length: ACVMField[], values: ACVMField[]): Promise { - const hash = await this.typedOracle.storeInExecutionCache(values.map(fromACVMField)); - return toACVMField(hash); + async storeInExecutionCache(_length: ACVMField[], values: ACVMField[]): Promise { + const hash = await this.typedOracle.storeInExecutionCache(values.map(Fr.fromString)); + return [toACVMField(hash)]; } - async loadFromExecutionCache([returnsHash]: ACVMField[]): Promise { - const values = await this.typedOracle.loadFromExecutionCache(fromACVMField(returnsHash)); - return values.map(toACVMField); + async loadFromExecutionCache([returnsHash]: ACVMField[]): Promise { + const values = await this.typedOracle.loadFromExecutionCache(Fr.fromString(returnsHash)); + return [values.map(toACVMField)]; } - async getBlockNumber(): Promise { - return toACVMField(await this.typedOracle.getBlockNumber()); + async getBlockNumber(): Promise { + return [toACVMField(await this.typedOracle.getBlockNumber())]; } - async getContractAddress(): Promise { - return toACVMField(await this.typedOracle.getContractAddress()); + async getContractAddress(): Promise { + return [toACVMField(await this.typedOracle.getContractAddress())]; } - async getVersion(): Promise { - return toACVMField(await this.typedOracle.getVersion()); + async getVersion(): Promise { + return [toACVMField(await this.typedOracle.getVersion())]; } - async getChainId(): Promise { - return toACVMField(await this.typedOracle.getChainId()); + async getChainId(): Promise { + return [toACVMField(await this.typedOracle.getChainId())]; } async getKeyValidationRequest([pkMHash]: ACVMField[]): Promise { - const { pkM, skApp } = await this.typedOracle.getKeyValidationRequest(fromACVMField(pkMHash)); + const keyValidationRequest = await this.typedOracle.getKeyValidationRequest(Fr.fromString(pkMHash)); - return [toACVMField(pkM.x), toACVMField(pkM.y), toACVMField(pkM.isInfinite), toACVMField(skApp)]; + return keyValidationRequest.toFields().map(toACVMField); } - async getContractInstance([address]: ACVMField[]) { - const instance = await this.typedOracle.getContractInstance(AztecAddress.fromField(fromACVMField(address))); + async getContractInstance([address]: ACVMField[]): Promise { + const instance = await this.typedOracle.getContractInstance(AztecAddress.fromField(Fr.fromString(address))); return [ instance.salt, @@ -76,10 +69,10 @@ export class Oracle { [blockNumber]: ACVMField[], [treeId]: ACVMField[], [leafValue]: ACVMField[], - ): Promise { - const parsedBlockNumber = frToNumber(fromACVMField(blockNumber)); - const parsedTreeId = frToNumber(fromACVMField(treeId)); - const parsedLeafValue = fromACVMField(leafValue); + ): Promise<(ACVMField | ACVMField[])[]> { + const parsedBlockNumber = Fr.fromString(blockNumber).toNumber(); + const parsedTreeId = Fr.fromString(treeId).toNumber(); + const parsedLeafValue = Fr.fromString(leafValue); const witness = await this.typedOracle.getMembershipWitness(parsedBlockNumber, parsedTreeId, parsedLeafValue); if (!witness) { @@ -87,29 +80,29 @@ export class Oracle { `Leaf ${leafValue} not found in the tree ${MerkleTreeId[parsedTreeId]} at block ${parsedBlockNumber}.`, ); } - return witness.map(toACVMField); + return [toACVMField(witness[0]), witness.slice(1).map(toACVMField)]; } async getNullifierMembershipWitness( [blockNumber]: ACVMField[], [nullifier]: ACVMField[], // nullifier, we try to find the witness for (to prove inclusion) - ): Promise { - const parsedBlockNumber = frToNumber(fromACVMField(blockNumber)); - const parsedNullifier = fromACVMField(nullifier); + ): Promise<(ACVMField | ACVMField[])[]> { + const parsedBlockNumber = Fr.fromString(blockNumber).toNumber(); + const parsedNullifier = Fr.fromString(nullifier); const witness = await this.typedOracle.getNullifierMembershipWitness(parsedBlockNumber, parsedNullifier); if (!witness) { throw new Error(`Nullifier witness not found for nullifier ${parsedNullifier} at block ${parsedBlockNumber}.`); } - return witness.toFields().map(toACVMField); + return witness.toNoirRepresentation(); } async getLowNullifierMembershipWitness( [blockNumber]: ACVMField[], [nullifier]: ACVMField[], // nullifier, we try to find the low nullifier witness for (to prove non-inclusion) - ): Promise { - const parsedBlockNumber = frToNumber(fromACVMField(blockNumber)); - const parsedNullifier = fromACVMField(nullifier); + ): Promise<(ACVMField | ACVMField[])[]> { + const parsedBlockNumber = Fr.fromString(blockNumber).toNumber(); + const parsedNullifier = Fr.fromString(nullifier); const witness = await this.typedOracle.getLowNullifierMembershipWitness(parsedBlockNumber, parsedNullifier); if (!witness) { @@ -117,22 +110,25 @@ export class Oracle { `Low nullifier witness not found for nullifier ${parsedNullifier} at block ${parsedBlockNumber}.`, ); } - return witness.toFields().map(toACVMField); + return witness.toNoirRepresentation(); } - async getPublicDataTreeWitness([blockNumber]: ACVMField[], [leafSlot]: ACVMField[]): Promise { - const parsedBlockNumber = frToNumber(fromACVMField(blockNumber)); - const parsedLeafSlot = fromACVMField(leafSlot); + async getPublicDataWitness( + [blockNumber]: ACVMField[], + [leafSlot]: ACVMField[], + ): Promise<(ACVMField | ACVMField[])[]> { + const parsedBlockNumber = Fr.fromString(blockNumber).toNumber(); + const parsedLeafSlot = Fr.fromString(leafSlot); - const witness = await this.typedOracle.getPublicDataTreeWitness(parsedBlockNumber, parsedLeafSlot); + const witness = await this.typedOracle.getPublicDataWitness(parsedBlockNumber, parsedLeafSlot); if (!witness) { throw new Error(`Public data witness not found for slot ${parsedLeafSlot} at block ${parsedBlockNumber}.`); } - return witness.toFields().map(toACVMField); + return witness.toNoirRepresentation(); } async getBlockHeader([blockNumber]: ACVMField[]): Promise { - const parsedBlockNumber = frToNumber(fromACVMField(blockNumber)); + const parsedBlockNumber = Fr.fromString(blockNumber).toNumber(); const header = await this.typedOracle.getBlockHeader(parsedBlockNumber); if (!header) { @@ -141,20 +137,20 @@ export class Oracle { return header.toFields().map(toACVMField); } - async getAuthWitness([messageHash]: ACVMField[]): Promise { - const messageHashField = fromACVMField(messageHash); + async getAuthWitness([messageHash]: ACVMField[]): Promise { + const messageHashField = Fr.fromString(messageHash); const witness = await this.typedOracle.getAuthWitness(messageHashField); if (!witness) { throw new Error(`Unknown auth witness for message hash ${messageHashField}`); } - return witness.map(toACVMField); + return [witness.map(toACVMField)]; } - async getPublicKeysAndPartialAddress([address]: ACVMField[]): Promise { - const parsedAddress = AztecAddress.fromField(fromACVMField(address)); + async getPublicKeysAndPartialAddress([address]: ACVMField[]): Promise { + const parsedAddress = AztecAddress.fromField(Fr.fromString(address)); const { publicKeys, partialAddress } = await this.typedOracle.getCompleteAddress(parsedAddress); - return [...publicKeys.toFields(), partialAddress].map(toACVMField); + return [[...publicKeys.toFields(), partialAddress].map(toACVMField)]; } async getNotes( @@ -173,14 +169,14 @@ export class Oracle { [offset]: ACVMField[], [status]: ACVMField[], [returnSize]: ACVMField[], - ): Promise { + ): Promise { const noteDatas = await this.typedOracle.getNotes( - fromACVMField(storageSlot), + Fr.fromString(storageSlot), +numSelects, selectByIndexes.map(s => +s), selectByOffsets.map(s => +s), selectByLengths.map(s => +s), - selectValues.map(fromACVMField), + selectValues.map(Fr.fromString), selectComparators.map(s => +s), sortByIndexes.map(s => +s), sortByOffsets.map(s => +s), @@ -216,7 +212,7 @@ export class Oracle { } const paddedZeros = Array(returnFieldSize - returnData.length).fill(toACVMField(0)); - return returnData.concat(paddedZeros); + return [returnData.concat(paddedZeros)]; } notifyCreatedNote( @@ -225,47 +221,47 @@ export class Oracle { note: ACVMField[], [noteHash]: ACVMField[], [counter]: ACVMField[], - ): ACVMField { + ): Promise { this.typedOracle.notifyCreatedNote( - fromACVMField(storageSlot), - NoteSelector.fromField(fromACVMField(noteTypeId)), - note.map(fromACVMField), - fromACVMField(noteHash), + Fr.fromString(storageSlot), + NoteSelector.fromField(Fr.fromString(noteTypeId)), + note.map(Fr.fromString), + Fr.fromString(noteHash), +counter, ); - return toACVMField(0); + return Promise.resolve([]); } async notifyNullifiedNote( [innerNullifier]: ACVMField[], [noteHash]: ACVMField[], [counter]: ACVMField[], - ): Promise { - await this.typedOracle.notifyNullifiedNote(fromACVMField(innerNullifier), fromACVMField(noteHash), +counter); - return toACVMField(0); + ): Promise { + await this.typedOracle.notifyNullifiedNote(Fr.fromString(innerNullifier), Fr.fromString(noteHash), +counter); + return []; } - async notifyCreatedNullifier([innerNullifier]: ACVMField[]): Promise { - await this.typedOracle.notifyCreatedNullifier(fromACVMField(innerNullifier)); - return toACVMField(0); + async notifyCreatedNullifier([innerNullifier]: ACVMField[]): Promise { + await this.typedOracle.notifyCreatedNullifier(Fr.fromString(innerNullifier)); + return []; } - async checkNullifierExists([innerNullifier]: ACVMField[]): Promise { - const exists = await this.typedOracle.checkNullifierExists(fromACVMField(innerNullifier)); - return toACVMField(exists); + async checkNullifierExists([innerNullifier]: ACVMField[]): Promise { + const exists = await this.typedOracle.checkNullifierExists(Fr.fromString(innerNullifier)); + return [toACVMField(exists)]; } async getL1ToL2MembershipWitness( [contractAddress]: ACVMField[], [messageHash]: ACVMField[], [secret]: ACVMField[], - ): Promise { + ): Promise<(ACVMField | ACVMField[])[]> { const message = await this.typedOracle.getL1ToL2MembershipWitness( AztecAddress.fromString(contractAddress), - fromACVMField(messageHash), - fromACVMField(secret), + Fr.fromString(messageHash), + Fr.fromString(secret), ); - return message.toFields().map(toACVMField); + return message.toNoirRepresentation(); } async storageRead( @@ -273,32 +269,38 @@ export class Oracle { [startStorageSlot]: ACVMField[], [blockNumber]: ACVMField[], [numberOfElements]: ACVMField[], - ): Promise { + ): Promise { const values = await this.typedOracle.storageRead( - new AztecAddress(fromACVMField(contractAddress)), - fromACVMField(startStorageSlot), + new AztecAddress(Fr.fromString(contractAddress)), + Fr.fromString(startStorageSlot), +blockNumber, +numberOfElements, ); - return values.map(toACVMField); + return [values.map(toACVMField)]; } async storageWrite([startStorageSlot]: ACVMField[], values: ACVMField[]): Promise { - const newValues = await this.typedOracle.storageWrite(fromACVMField(startStorageSlot), values.map(fromACVMField)); + const newValues = await this.typedOracle.storageWrite(Fr.fromString(startStorageSlot), values.map(Fr.fromString)); return newValues.map(toACVMField); } - notifyCreatedContractClassLog([contractAddress]: ACVMField[], message: ACVMField[], [counter]: ACVMField[]): void { - const logPayload = message.map(fromACVMField); - const log = new ContractClassLog(new AztecAddress(fromACVMField(contractAddress)), logPayload); + notifyCreatedContractClassLog( + [contractAddress]: ACVMField[], + message: ACVMField[], + [counter]: ACVMField[], + ): Promise { + const logPayload = message.map(Fr.fromString); + const log = new ContractClassLog(new AztecAddress(Fr.fromString(contractAddress)), logPayload); this.typedOracle.notifyCreatedContractClassLog(log, +counter); + return Promise.resolve([]); } - debugLog(message: ACVMField[], _ignoredFieldsSize: ACVMField[], fields: ACVMField[]): void { - const messageStr = message.map(acvmField => String.fromCharCode(fromACVMField(acvmField).toNumber())).join(''); - const fieldsFr = fields.map(fromACVMField); + debugLog(message: ACVMField[], _ignoredFieldsSize: ACVMField[], fields: ACVMField[]): Promise { + const messageStr = message.map(acvmField => String.fromCharCode(Fr.fromString(acvmField).toNumber())).join(''); + const fieldsFr = fields.map(Fr.fromString); this.typedOracle.debugLog(messageStr, fieldsFr); + return Promise.resolve([]); } async callPrivateFunction( @@ -307,15 +309,15 @@ export class Oracle { [argsHash]: ACVMField[], [sideEffectCounter]: ACVMField[], [isStaticCall]: ACVMField[], - ): Promise { + ): Promise { const { endSideEffectCounter, returnsHash } = await this.typedOracle.callPrivateFunction( - AztecAddress.fromField(fromACVMField(contractAddress)), - FunctionSelector.fromField(fromACVMField(functionSelector)), - fromACVMField(argsHash), - frToNumber(fromACVMField(sideEffectCounter)), - frToBoolean(fromACVMField(isStaticCall)), + AztecAddress.fromField(Fr.fromString(contractAddress)), + FunctionSelector.fromField(Fr.fromString(functionSelector)), + Fr.fromString(argsHash), + Fr.fromString(sideEffectCounter).toNumber(), + Fr.fromString(isStaticCall).toBool(), ); - return [endSideEffectCounter, returnsHash].map(toACVMField); + return [[endSideEffectCounter, returnsHash].map(toACVMField)]; } async enqueuePublicFunctionCall( @@ -324,15 +326,15 @@ export class Oracle { [argsHash]: ACVMField[], [sideEffectCounter]: ACVMField[], [isStaticCall]: ACVMField[], - ): Promise { + ): Promise { const newArgsHash = await this.typedOracle.enqueuePublicFunctionCall( AztecAddress.fromString(contractAddress), - FunctionSelector.fromField(fromACVMField(functionSelector)), - fromACVMField(argsHash), - frToNumber(fromACVMField(sideEffectCounter)), - frToBoolean(fromACVMField(isStaticCall)), + FunctionSelector.fromField(Fr.fromString(functionSelector)), + Fr.fromString(argsHash), + Fr.fromString(sideEffectCounter).toNumber(), + Fr.fromString(isStaticCall).toBool(), ); - return toACVMField(newArgsHash); + return [toACVMField(newArgsHash)]; } async setPublicTeardownFunctionCall( @@ -341,38 +343,41 @@ export class Oracle { [argsHash]: ACVMField[], [sideEffectCounter]: ACVMField[], [isStaticCall]: ACVMField[], - ): Promise { + ): Promise { const newArgsHash = await this.typedOracle.setPublicTeardownFunctionCall( AztecAddress.fromString(contractAddress), - FunctionSelector.fromField(fromACVMField(functionSelector)), - fromACVMField(argsHash), - frToNumber(fromACVMField(sideEffectCounter)), - frToBoolean(fromACVMField(isStaticCall)), + FunctionSelector.fromField(Fr.fromString(functionSelector)), + Fr.fromString(argsHash), + Fr.fromString(sideEffectCounter).toNumber(), + Fr.fromString(isStaticCall).toBool(), ); - return toACVMField(newArgsHash); + return [toACVMField(newArgsHash)]; } - notifySetMinRevertibleSideEffectCounter([minRevertibleSideEffectCounter]: ACVMField[]) { - this.typedOracle.notifySetMinRevertibleSideEffectCounter(frToNumber(fromACVMField(minRevertibleSideEffectCounter))); + notifySetMinRevertibleSideEffectCounter([minRevertibleSideEffectCounter]: ACVMField[]): Promise { + this.typedOracle.notifySetMinRevertibleSideEffectCounter(Fr.fromString(minRevertibleSideEffectCounter).toNumber()); + return Promise.resolve([]); } - async getIndexedTaggingSecretAsSender([sender]: ACVMField[], [recipient]: ACVMField[]): Promise { + async getIndexedTaggingSecretAsSender([sender]: ACVMField[], [recipient]: ACVMField[]): Promise { const taggingSecret = await this.typedOracle.getIndexedTaggingSecretAsSender( AztecAddress.fromString(sender), AztecAddress.fromString(recipient), ); - return taggingSecret.toFields().map(toACVMField); + return [taggingSecret.toFields().map(toACVMField)]; } - async incrementAppTaggingSecretIndexAsSender([sender]: ACVMField[], [recipient]: ACVMField[]) { + async incrementAppTaggingSecretIndexAsSender([sender]: ACVMField[], [recipient]: ACVMField[]): Promise { await this.typedOracle.incrementAppTaggingSecretIndexAsSender( AztecAddress.fromString(sender), AztecAddress.fromString(recipient), ); + return []; } - async syncNotes() { + async syncNotes(): Promise { await this.typedOracle.syncNotes(); + return []; } async deliverNote( @@ -385,26 +390,26 @@ export class Oracle { [nullifier]: ACVMField[], [txHash]: ACVMField[], [recipient]: ACVMField[], - ): Promise { + ): Promise { // TODO(#10728): try-catch this block and return false if we get an exception so that the contract can decide what // to do if a note fails delivery (e.g. not increment the tagging index, or add it to some pending work list). // Delivery might fail due to temporary issues, such as poor node connectivity. await this.typedOracle.deliverNote( AztecAddress.fromString(contractAddress), - fromACVMField(storageSlot), - fromACVMField(nonce), + Fr.fromString(storageSlot), + Fr.fromString(nonce), fromBoundedVec(content, contentLength), - fromACVMField(noteHash), - fromACVMField(nullifier), - fromACVMField(txHash), + Fr.fromString(noteHash), + Fr.fromString(nullifier), + Fr.fromString(txHash), AztecAddress.fromString(recipient), ); - return toACVMField(true); + return [toACVMField(true)]; } async getLogByTag([tag]: ACVMField[]): Promise<(ACVMField | ACVMField[])[]> { - const log = await this.typedOracle.getLogByTag(fromACVMField(tag)); + const log = await this.typedOracle.getLogByTag(Fr.fromString(tag)); if (log == null) { return [toACVMField(0), ...LogWithTxData.noirSerializationOfEmpty().map(toACVMFieldSingleOrArray)]; @@ -413,12 +418,13 @@ export class Oracle { } } - async storeCapsule([contractAddress]: ACVMField[], [slot]: ACVMField[], capsule: ACVMField[]) { + async storeCapsule([contractAddress]: ACVMField[], [slot]: ACVMField[], capsule: ACVMField[]): Promise { await this.typedOracle.storeCapsule( - AztecAddress.fromField(fromACVMField(contractAddress)), - fromACVMField(slot), - capsule.map(fromACVMField), + AztecAddress.fromField(Fr.fromString(contractAddress)), + Fr.fromString(slot), + capsule.map(Fr.fromString), ); + return []; } async loadCapsule( @@ -427,23 +433,24 @@ export class Oracle { [tSize]: ACVMField[], ): Promise<(ACVMField | ACVMField[])[]> { const values = await this.typedOracle.loadCapsule( - AztecAddress.fromField(fromACVMField(contractAddress)), - fromACVMField(slot), + AztecAddress.fromField(Fr.fromString(contractAddress)), + Fr.fromString(slot), ); // We are going to return a Noir Option struct to represent the possibility of null values. Options are a struct // with two fields: `some` (a boolean) and `value` (a field array in this case). if (values === null) { // No data was found so we set `some` to 0 and pad `value` with zeros get the correct return size. - return [toACVMField(0), Array(frToNumber(fromACVMField(tSize))).fill(toACVMField(0))]; + return [toACVMField(0), Array(Fr.fromString(tSize).toNumber()).fill(toACVMField(0))]; } else { // Data was found so we set `some` to 1 and return it along with `value`. return [toACVMField(1), values.map(toACVMField)]; } } - async deleteCapsule([contractAddress]: ACVMField[], [slot]: ACVMField[]) { - await this.typedOracle.deleteCapsule(AztecAddress.fromField(fromACVMField(contractAddress)), fromACVMField(slot)); + async deleteCapsule([contractAddress]: ACVMField[], [slot]: ACVMField[]): Promise { + await this.typedOracle.deleteCapsule(AztecAddress.fromField(Fr.fromString(contractAddress)), Fr.fromString(slot)); + return []; } async copyCapsule( @@ -451,13 +458,14 @@ export class Oracle { [srcSlot]: ACVMField[], [dstSlot]: ACVMField[], [numEntries]: ACVMField[], - ) { + ): Promise { await this.typedOracle.copyCapsule( - AztecAddress.fromField(fromACVMField(contractAddress)), - fromACVMField(srcSlot), - fromACVMField(dstSlot), - frToNumber(fromACVMField(numEntries)), + AztecAddress.fromField(Fr.fromString(contractAddress)), + Fr.fromString(srcSlot), + Fr.fromString(dstSlot), + Fr.fromString(numEntries).toNumber(), ); + return []; } async aes128Decrypt( @@ -481,8 +489,8 @@ export class Oracle { [ephPKField2]: ACVMField[], ): Promise { const secret = await this.typedOracle.getSharedSecret( - AztecAddress.fromField(fromACVMField(address)), - Point.fromFields([ephPKField0, ephPKField1, ephPKField2].map(fromACVMField)), + AztecAddress.fromField(Fr.fromString(address)), + Point.fromFields([ephPKField0, ephPKField1, ephPKField2].map(Fr.fromString)), ); return secret.toFields().map(toACVMField); } diff --git a/yarn-project/simulator/src/private/acvm/oracle/typed_oracle.ts b/yarn-project/simulator/src/private/acvm/oracle/typed_oracle.ts index a94d9af06970..4fd3c5580653 100644 --- a/yarn-project/simulator/src/private/acvm/oracle/typed_oracle.ts +++ b/yarn-project/simulator/src/private/acvm/oracle/typed_oracle.ts @@ -87,8 +87,8 @@ export abstract class TypedOracle { return Promise.reject(new OracleMethodNotAvailableError('getNullifierMembershipWitness')); } - getPublicDataTreeWitness(_blockNumber: number, _leafSlot: Fr): Promise { - return Promise.reject(new OracleMethodNotAvailableError('getPublicDataTreeWitness')); + getPublicDataWitness(_blockNumber: number, _leafSlot: Fr): Promise { + return Promise.reject(new OracleMethodNotAvailableError('getPublicDataWitness')); } getLowNullifierMembershipWitness( diff --git a/yarn-project/simulator/src/private/execution_data_provider.ts b/yarn-project/simulator/src/private/execution_data_provider.ts index 0b13338d40a1..21ba493c4b41 100644 --- a/yarn-project/simulator/src/private/execution_data_provider.ts +++ b/yarn-project/simulator/src/private/execution_data_provider.ts @@ -150,7 +150,7 @@ export interface ExecutionDataProvider extends CommitmentsDBInterface { * @param blockNumber - The block number at which to get the witness. * @param leafSlot - The slot of the public data in the public data tree. */ - getPublicDataTreeWitness(blockNumber: number, leafSlot: Fr): Promise; + getPublicDataWitness(blockNumber: number, leafSlot: Fr): Promise; /** * Gets the storage value at the given contract storage slot. diff --git a/yarn-project/simulator/src/private/private_execution.ts b/yarn-project/simulator/src/private/private_execution.ts index 006733051924..e15f2cf84803 100644 --- a/yarn-project/simulator/src/private/private_execution.ts +++ b/yarn-project/simulator/src/private/private_execution.ts @@ -13,7 +13,7 @@ import type { CircuitWitnessGenerationStats } from '@aztec/stdlib/stats'; import { PrivateCallExecutionResult } from '@aztec/stdlib/tx'; import { ExecutionError, resolveAssertionMessageFromError } from '../common/errors.js'; -import { fromACVMField, witnessMapToFields } from './acvm/deserialize.js'; +import { witnessMapToFields } from './acvm/deserialize.js'; import { type ACVMWitness, Oracle, extractCallStack } from './acvm/index.js'; import type { ExecutionDataProvider } from './execution_data_provider.js'; import type { PrivateExecutionOracle } from './private_execution_oracle.js'; @@ -113,7 +113,7 @@ export function extractPrivateCircuitPublicInputs( if (returnedField === undefined) { throw new Error(`Missing return value for index ${i}`); } - returnData.push(fromACVMField(returnedField)); + returnData.push(Fr.fromString(returnedField)); } return PrivateCircuitPublicInputs.fromFields(returnData); } diff --git a/yarn-project/simulator/src/private/unconstrained_execution_oracle.ts b/yarn-project/simulator/src/private/unconstrained_execution_oracle.ts index 2480da38825b..5a00e623b534 100644 --- a/yarn-project/simulator/src/private/unconstrained_execution_oracle.ts +++ b/yarn-project/simulator/src/private/unconstrained_execution_oracle.ts @@ -103,11 +103,11 @@ export class UnconstrainedExecutionOracle extends TypedOracle { * @param leafSlot - The slot of the public data tree to get the witness for. * @returns - The witness */ - public override async getPublicDataTreeWitness( + public override async getPublicDataWitness( blockNumber: number, leafSlot: Fr, ): Promise { - return await this.executionDataProvider.getPublicDataTreeWitness(blockNumber, leafSlot); + return await this.executionDataProvider.getPublicDataWitness(blockNumber, leafSlot); } /** diff --git a/yarn-project/stdlib/src/interfaces/aztec-node.test.ts b/yarn-project/stdlib/src/interfaces/aztec-node.test.ts index 7ff5871d7ec1..1add6f7cb609 100644 --- a/yarn-project/stdlib/src/interfaces/aztec-node.test.ts +++ b/yarn-project/stdlib/src/interfaces/aztec-node.test.ts @@ -152,8 +152,8 @@ describe('AztecNodeApiSchema', () => { expect(response).toBeInstanceOf(NullifierMembershipWitness); }); - it('getPublicDataTreeWitness', async () => { - const response = await context.client.getPublicDataTreeWitness(1, Fr.random()); + it('getPublicDataWitness', async () => { + const response = await context.client.getPublicDataWitness(1, Fr.random()); expect(response).toBeInstanceOf(PublicDataWitness); }); @@ -460,7 +460,7 @@ class MockAztecNode implements AztecNode { expect(nullifier).toBeInstanceOf(Fr); return Promise.resolve(NullifierMembershipWitness.random()); } - getPublicDataTreeWitness(blockNumber: number | 'latest', leafSlot: Fr): Promise { + getPublicDataWitness(blockNumber: number | 'latest', leafSlot: Fr): Promise { expect(leafSlot).toBeInstanceOf(Fr); return Promise.resolve(PublicDataWitness.random()); } diff --git a/yarn-project/stdlib/src/interfaces/aztec-node.ts b/yarn-project/stdlib/src/interfaces/aztec-node.ts index 913425c8c5c6..7b931fe7a1a5 100644 --- a/yarn-project/stdlib/src/interfaces/aztec-node.ts +++ b/yarn-project/stdlib/src/interfaces/aztec-node.ts @@ -219,7 +219,7 @@ export interface AztecNode * "in range" slot, means that the slot doesn't exist and the value is 0. If the low leaf preimage corresponds to the exact slot, the current value * is contained in the leaf preimage. */ - getPublicDataTreeWitness(blockNumber: L2BlockNumber, leafSlot: Fr): Promise; + getPublicDataWitness(blockNumber: L2BlockNumber, leafSlot: Fr): Promise; /** * Get a block specified by its number. @@ -500,10 +500,7 @@ export const AztecNodeApiSchema: ApiSchemaFor = { .args(L2BlockNumberSchema, schemas.Fr) .returns(NullifierMembershipWitness.schema.optional()), - getPublicDataTreeWitness: z - .function() - .args(L2BlockNumberSchema, schemas.Fr) - .returns(PublicDataWitness.schema.optional()), + getPublicDataWitness: z.function().args(L2BlockNumberSchema, schemas.Fr).returns(PublicDataWitness.schema.optional()), getBlock: z.function().args(z.number()).returns(L2Block.schema.optional()), diff --git a/yarn-project/stdlib/src/trees/nullifier_membership_witness.ts b/yarn-project/stdlib/src/trees/nullifier_membership_witness.ts index 128874a6690f..521f715b549e 100644 --- a/yarn-project/stdlib/src/trees/nullifier_membership_witness.ts +++ b/yarn-project/stdlib/src/trees/nullifier_membership_witness.ts @@ -56,4 +56,16 @@ export class NullifierMembershipWitness { public toFields(): Fr[] { return [new Fr(this.index), ...this.leafPreimage.toFields(), ...this.siblingPath.toFields()]; } + + /** + * Returns a representation of the nullifier membership witness as expected by intrinsic Noir deserialization. + */ + public toNoirRepresentation(): (string | string[])[] { + // TODO(#12874): remove the stupid as string conversion by modifying ForeignCallOutput type in acvm.js + return [ + new Fr(this.index).toString() as string, + ...(this.leafPreimage.toFields().map(fr => fr.toString()) as string[]), + this.siblingPath.toFields().map(fr => fr.toString()) as string[], + ]; + } } diff --git a/yarn-project/stdlib/src/trees/public_data_witness.ts b/yarn-project/stdlib/src/trees/public_data_witness.ts index 35c913eacfca..3ae48769057b 100644 --- a/yarn-project/stdlib/src/trees/public_data_witness.ts +++ b/yarn-project/stdlib/src/trees/public_data_witness.ts @@ -58,6 +58,21 @@ export class PublicDataWitness { ]; } + /** + * Returns a representation of the public data witness as expected by intrinsic Noir deserialization. + */ + public toNoirRepresentation(): (string | string[])[] { + // TODO(#12874): remove the stupid as string conversion by modifying ForeignCallOutput type in acvm.js + return [ + new Fr(this.index).toString() as string, + new Fr(this.leafPreimage.slot).toString() as string, + new Fr(this.leafPreimage.value).toString() as string, + new Fr(this.leafPreimage.nextSlot).toString() as string, + new Fr(this.leafPreimage.nextIndex).toString() as string, + this.siblingPath.toFields().map(fr => fr.toString()) as string[], + ]; + } + toBuffer(): Buffer { return serializeToBuffer([this.index, this.leafPreimage, this.siblingPath]); } diff --git a/yarn-project/txe/src/node/txe_node.ts b/yarn-project/txe/src/node/txe_node.ts index c44f0f48ca2a..8dcbcd4868a4 100644 --- a/yarn-project/txe/src/node/txe_node.ts +++ b/yarn-project/txe/src/node/txe_node.ts @@ -383,8 +383,8 @@ export class TXENode implements AztecNode { * "in range" slot, means that the slot doesn't exist and the value is 0. If the low leaf preimage corresponds to the exact slot, the current value * is contained in the leaf preimage. */ - getPublicDataTreeWitness(_blockNumber: L2BlockNumber, _leafSlot: Fr): Promise { - throw new Error('TXE Node method getPublicDataTreeWitness not implemented'); + getPublicDataWitness(_blockNumber: L2BlockNumber, _leafSlot: Fr): Promise { + throw new Error('TXE Node method getPublicDataWitness not implemented'); } /** diff --git a/yarn-project/txe/src/oracle/txe_oracle.ts b/yarn-project/txe/src/oracle/txe_oracle.ts index 26d7aadf3fcd..b569a0675119 100644 --- a/yarn-project/txe/src/oracle/txe_oracle.ts +++ b/yarn-project/txe/src/oracle/txe_oracle.ts @@ -468,7 +468,7 @@ export class TXE implements TypedOracle { return new NullifierMembershipWitness(BigInt(index), leafPreimage as NullifierLeafPreimage, siblingPath); } - async getPublicDataTreeWitness(blockNumber: number, leafSlot: Fr): Promise { + async getPublicDataWitness(blockNumber: number, leafSlot: Fr): Promise { const snap = this.nativeWorldStateService.getSnapshot(blockNumber); const lowLeafResult = await snap.getPreviousValueIndex(MerkleTreeId.PUBLIC_DATA_TREE, leafSlot.toBigInt()); diff --git a/yarn-project/txe/src/txe_service/txe_service.ts b/yarn-project/txe/src/txe_service/txe_service.ts index e14568425c29..69d6c539cd0e 100644 --- a/yarn-project/txe/src/txe_service/txe_service.ts +++ b/yarn-project/txe/src/txe_service/txe_service.ts @@ -263,15 +263,15 @@ export class TXEService { return toForeignCallResult([toArray(newValues)]); } - async getPublicDataTreeWitness(blockNumber: ForeignCallSingle, leafSlot: ForeignCallSingle) { + async getPublicDataWitness(blockNumber: ForeignCallSingle, leafSlot: ForeignCallSingle) { const parsedBlockNumber = fromSingle(blockNumber).toNumber(); const parsedLeafSlot = fromSingle(leafSlot); - const witness = await this.typedOracle.getPublicDataTreeWitness(parsedBlockNumber, parsedLeafSlot); + const witness = await this.typedOracle.getPublicDataWitness(parsedBlockNumber, parsedLeafSlot); if (!witness) { throw new Error(`Public data witness not found for slot ${parsedLeafSlot} at block ${parsedBlockNumber}.`); } - return toForeignCallResult([toArray(witness.toFields())]); + return toForeignCallResult(witness.toNoirRepresentation()); } async getNotes( @@ -349,7 +349,7 @@ export class TXEService { fromSingle(noteHash), fromSingle(counter).toNumber(), ); - return toForeignCallResult([toSingle(new Fr(0))]); + return toForeignCallResult([]); } async notifyNullifiedNote( @@ -362,12 +362,12 @@ export class TXEService { fromSingle(noteHash), fromSingle(counter).toNumber(), ); - return toForeignCallResult([toSingle(new Fr(0))]); + return toForeignCallResult([]); } async notifyCreatedNullifier(innerNullifier: ForeignCallSingle) { await this.typedOracle.notifyCreatedNullifier(fromSingle(innerNullifier)); - return toForeignCallResult([toSingle(new Fr(0))]); + return toForeignCallResult([]); } async checkNullifierExists(innerNullifier: ForeignCallSingle) { @@ -377,15 +377,15 @@ export class TXEService { async getContractInstance(address: ForeignCallSingle) { const instance = await this.typedOracle.getContractInstance(addressFromSingle(address)); - return toForeignCallResult([ - toArray([ + return toForeignCallResult( + [ instance.salt, instance.deployer.toField(), instance.currentContractClassId, instance.initializationHash, ...instance.publicKeys.toFields(), - ]), - ]); + ].map(toSingle), + ); } async getPublicKeysAndPartialAddress(address: ForeignCallSingle) { @@ -396,7 +396,7 @@ export class TXEService { async getKeyValidationRequest(pkMHash: ForeignCallSingle) { const keyValidationRequest = await this.typedOracle.getKeyValidationRequest(fromSingle(pkMHash)); - return toForeignCallResult([toArray(keyValidationRequest.toFields())]); + return toForeignCallResult(keyValidationRequest.toFields().map(toSingle)); } async callPrivateFunction( @@ -422,7 +422,7 @@ export class TXEService { if (!witness) { throw new Error(`Nullifier membership witness not found at block ${parsedBlockNumber}.`); } - return toForeignCallResult([toArray(witness.toFields())]); + return toForeignCallResult(witness.toNoirRepresentation()); } async getAuthWitness(messageHash: ForeignCallSingle) { @@ -485,7 +485,7 @@ export class TXEService { if (!header) { throw new Error(`Block header not found for block ${blockNumber}.`); } - return toForeignCallResult([toArray(header.toFields())]); + return toForeignCallResult(header.toFields().map(toSingle)); } async getMembershipWitness(blockNumber: ForeignCallSingle, treeId: ForeignCallSingle, leafValue: ForeignCallSingle) { @@ -498,7 +498,7 @@ export class TXEService { `Membership witness in tree ${MerkleTreeId[parsedTreeId]} not found for value ${parsedLeafValue} at block ${parsedBlockNumber}.`, ); } - return toForeignCallResult([toArray(witness)]); + return toForeignCallResult([toSingle(witness[0]), toArray(witness.slice(1))]); } async getLowNullifierMembershipWitness(blockNumber: ForeignCallSingle, nullifier: ForeignCallSingle) { @@ -508,7 +508,7 @@ export class TXEService { if (!witness) { throw new Error(`Low nullifier witness not found for nullifier ${nullifier} at block ${parsedBlockNumber}.`); } - return toForeignCallResult([toArray(witness.toFields())]); + return toForeignCallResult(witness.toNoirRepresentation()); } async getIndexedTaggingSecretAsSender(sender: ForeignCallSingle, recipient: ForeignCallSingle) { @@ -630,7 +630,7 @@ export class TXEService { AztecAddress.fromField(fromSingle(address)), Point.fromFields(fromArray(ephPk)), ); - return toForeignCallResult([toArray(secret.toFields())]); + return toForeignCallResult(secret.toFields().map(toSingle)); } // AVM opcodes