diff --git a/noir/noir-repo/acvm-repo/acvm_js/src/execute.rs b/noir/noir-repo/acvm-repo/acvm_js/src/execute.rs index 338511874c94..fd9f7d93444d 100644 --- a/noir/noir-repo/acvm-repo/acvm_js/src/execute.rs +++ b/noir/noir-repo/acvm-repo/acvm_js/src/execute.rs @@ -19,20 +19,6 @@ use crate::{ JsExecutionError, JsSolvedAndReturnWitness, JsWitnessMap, JsWitnessStack, }; -#[wasm_bindgen] -pub struct WasmBlackBoxFunctionSolver(Bn254BlackBoxSolver); - -impl WasmBlackBoxFunctionSolver { - async fn initialize() -> WasmBlackBoxFunctionSolver { - WasmBlackBoxFunctionSolver(Bn254BlackBoxSolver::initialize().await) - } -} - -#[wasm_bindgen(js_name = "createBlackBoxSolver")] -pub async fn create_black_box_solver() -> WasmBlackBoxFunctionSolver { - WasmBlackBoxFunctionSolver::initialize().await -} - /// Executes an ACIR circuit to generate the solved witness from the initial witness. /// /// @param {Uint8Array} circuit - A serialized representation of an ACIR circuit @@ -47,15 +33,9 @@ pub async fn execute_circuit( ) -> Result { console_error_panic_hook::set_once(); - let solver = WasmBlackBoxFunctionSolver::initialize().await; - - let mut witness_stack = execute_program_with_native_type_return( - &solver, - program, - initial_witness, - &foreign_call_handler, - ) - .await?; + let mut witness_stack = + execute_program_with_native_type_return(program, initial_witness, &foreign_call_handler) + .await?; let witness_map = witness_stack.pop().expect("Should have at least one witness on the stack").witness; Ok(witness_map.into()) @@ -64,14 +44,12 @@ pub async fn execute_circuit( /// Executes an ACIR circuit to generate the solved witness from the initial witness. /// This method also extracts the public return values from the solved witness into its own return witness. /// -/// @param {&WasmBlackBoxFunctionSolver} solver - A black box solver. /// @param {Uint8Array} circuit - A serialized representation of an ACIR circuit /// @param {WitnessMap} initial_witness - The initial witness map defining all of the inputs to `circuit`.. /// @param {ForeignCallHandler} foreign_call_handler - A callback to process any foreign calls from the circuit. /// @returns {SolvedAndReturnWitness} The solved witness calculated by executing the circuit on the provided inputs, as well as the return witness indices as specified by the circuit. #[wasm_bindgen(js_name = executeCircuitWithReturnWitness, skip_jsdoc)] pub async fn execute_circuit_with_return_witness( - solver: &WasmBlackBoxFunctionSolver, program: Vec, initial_witness: JsWitnessMap, foreign_call_handler: ForeignCallHandler, @@ -82,7 +60,6 @@ pub async fn execute_circuit_with_return_witness( .map_err(|_| JsExecutionError::new("Failed to deserialize circuit. This is likely due to differing serialization formats between ACVM_JS and your compiler".to_string(), None, None))?; let mut witness_stack = execute_program_with_native_program_and_return( - solver, &program, initial_witness, &foreign_call_handler, @@ -101,32 +78,10 @@ pub async fn execute_circuit_with_return_witness( /// Executes an ACIR circuit to generate the solved witness from the initial witness. /// -/// @param {&WasmBlackBoxFunctionSolver} solver - A black box solver. -/// @param {Uint8Array} circuit - A serialized representation of an ACIR circuit -/// @param {WitnessMap} initial_witness - The initial witness map defining all of the inputs to `circuit`.. -/// @param {ForeignCallHandler} foreign_call_handler - A callback to process any foreign calls from the circuit. -/// @returns {WitnessMap} The solved witness calculated by executing the circuit on the provided inputs. -#[wasm_bindgen(js_name = executeCircuitWithBlackBoxSolver, skip_jsdoc)] -pub async fn execute_circuit_with_black_box_solver( - solver: &WasmBlackBoxFunctionSolver, - program: Vec, - initial_witness: JsWitnessMap, - foreign_call_handler: ForeignCallHandler, -) -> Result { - console_error_panic_hook::set_once(); - - let mut witness_stack = execute_program_with_native_type_return( - solver, - program, - initial_witness, - &foreign_call_handler, - ) - .await?; - let witness_map = - witness_stack.pop().expect("Should have at least one witness on the stack").witness; - Ok(witness_map.into()) -} - +/// @param {Uint8Array} program - A serialized representation of an ACIR program +/// @param {WitnessMap} initial_witness - The initial witness map defining all of the inputs to `program`. +/// @param {ForeignCallHandler} foreign_call_handler - A callback to process any foreign calls from the program. +/// @returns {WitnessStack} The solved witness calculated by executing the program on the provided inputs. #[wasm_bindgen(js_name = executeProgram, skip_jsdoc)] pub async fn execute_program( program: Vec, @@ -135,32 +90,14 @@ pub async fn execute_program( ) -> Result { console_error_panic_hook::set_once(); - let solver = WasmBlackBoxFunctionSolver::initialize().await; - - execute_program_with_black_box_solver(&solver, program, initial_witness, &foreign_call_handler) - .await -} - -#[wasm_bindgen(js_name = executeProgramWithBlackBoxSolver, skip_jsdoc)] -pub async fn execute_program_with_black_box_solver( - solver: &WasmBlackBoxFunctionSolver, - program: Vec, - initial_witness: JsWitnessMap, - foreign_call_executor: &ForeignCallHandler, -) -> Result { - let witness_stack = execute_program_with_native_type_return( - solver, - program, - initial_witness, - foreign_call_executor, - ) - .await?; + let witness_stack = + execute_program_with_native_type_return(program, initial_witness, &foreign_call_handler) + .await?; Ok(witness_stack.into()) } async fn execute_program_with_native_type_return( - solver: &WasmBlackBoxFunctionSolver, program: Vec, initial_witness: JsWitnessMap, foreign_call_executor: &ForeignCallHandler, @@ -171,25 +108,20 @@ async fn execute_program_with_native_type_return( None, None))?; - execute_program_with_native_program_and_return( - solver, - &program, - initial_witness, - foreign_call_executor, - ) - .await + execute_program_with_native_program_and_return(&program, initial_witness, foreign_call_executor) + .await } async fn execute_program_with_native_program_and_return( - solver: &WasmBlackBoxFunctionSolver, program: &Program, initial_witness: JsWitnessMap, foreign_call_executor: &ForeignCallHandler, ) -> Result { + let solver = Bn254BlackBoxSolver::initialize().await; let executor = ProgramExecutor::new( &program.functions, &program.unconstrained_functions, - &solver.0, + &solver, foreign_call_executor, ); let witness_stack = executor.execute(initial_witness.into()).await?; diff --git a/noir/noir-repo/acvm-repo/acvm_js/src/lib.rs b/noir/noir-repo/acvm-repo/acvm_js/src/lib.rs index 3b8210f48753..fdb8d5ffe08d 100644 --- a/noir/noir-repo/acvm-repo/acvm_js/src/lib.rs +++ b/noir/noir-repo/acvm-repo/acvm_js/src/lib.rs @@ -23,10 +23,7 @@ pub use build_info::build_info; pub use compression::{ compress_witness, compress_witness_stack, decompress_witness, decompress_witness_stack, }; -pub use execute::{ - create_black_box_solver, execute_circuit, execute_circuit_with_black_box_solver, - execute_circuit_with_return_witness, execute_program, execute_program_with_black_box_solver, -}; +pub use execute::{execute_circuit, execute_circuit_with_return_witness, execute_program}; pub use js_execution_error::JsExecutionError; pub use js_witness_map::JsSolvedAndReturnWitness; pub use js_witness_map::JsWitnessMap; diff --git a/noir/noir-repo/acvm-repo/acvm_js/test/browser/execute_circuit.test.ts b/noir/noir-repo/acvm-repo/acvm_js/test/browser/execute_circuit.test.ts index 625cc91cfe92..d6dc4f122a65 100644 --- a/noir/noir-repo/acvm-repo/acvm_js/test/browser/execute_circuit.test.ts +++ b/noir/noir-repo/acvm-repo/acvm_js/test/browser/execute_circuit.test.ts @@ -1,9 +1,6 @@ import { expect } from '@esm-bundle/chai'; import initACVM, { - createBlackBoxSolver, executeCircuit, - executeCircuitWithBlackBoxSolver, - WasmBlackBoxFunctionSolver, WitnessMap, initLogLevel, ForeignCallHandler, @@ -123,22 +120,3 @@ it('successfully executes a MemoryOp opcode', async () => { expect(solvedWitness).to.be.deep.eq(expectedWitnessMap); }); -it('successfully executes two circuits with same backend', async function () { - // chose pedersen op here because it is the one with slow initialization - // that led to the decision to pull backend initialization into a separate - // function/wasmbind - const solver: WasmBlackBoxFunctionSolver = await createBlackBoxSolver(); - - const { bytecode, initialWitnessMap, expectedWitnessMap } = await import('../shared/pedersen'); - - const solvedWitness0: WitnessMap = await executeCircuitWithBlackBoxSolver(solver, bytecode, initialWitnessMap, () => { - throw Error('unexpected oracle'); - }); - - expect(solvedWitness0).to.be.deep.eq(expectedWitnessMap); - - const solvedWitness1: WitnessMap = await executeCircuitWithBlackBoxSolver(solver, bytecode, initialWitnessMap, () => { - throw Error('unexpected oracle'); - }); - expect(solvedWitness1).to.be.deep.eq(expectedWitnessMap); -}); diff --git a/noir/noir-repo/acvm-repo/acvm_js/test/node/execute_circuit.test.ts b/noir/noir-repo/acvm-repo/acvm_js/test/node/execute_circuit.test.ts index 3f9bde2898e4..1e3517e8814d 100644 --- a/noir/noir-repo/acvm-repo/acvm_js/test/node/execute_circuit.test.ts +++ b/noir/noir-repo/acvm-repo/acvm_js/test/node/execute_circuit.test.ts @@ -1,9 +1,6 @@ import { expect } from 'chai'; import { - createBlackBoxSolver, executeCircuit, - executeCircuitWithBlackBoxSolver, - WasmBlackBoxFunctionSolver, WitnessMap, ForeignCallHandler, executeProgram, @@ -120,40 +117,18 @@ it('successfully executes a MemoryOp opcode', async () => { expect(solvedWitness).to.be.deep.eq(expectedWitnessMap); }); -it('successfully executes two circuits with same backend', async function () { - this.timeout(10000); - - // chose pedersen op here because it is the one with slow initialization - // that led to the decision to pull backend initialization into a separate - // function/wasmbind - const solver: WasmBlackBoxFunctionSolver = await createBlackBoxSolver(); - - const { bytecode, initialWitnessMap, expectedWitnessMap } = await import('../shared/pedersen'); - - const solvedWitness0 = await executeCircuitWithBlackBoxSolver(solver, bytecode, initialWitnessMap, () => { - throw Error('unexpected oracle'); - }); - - const solvedWitness1 = await executeCircuitWithBlackBoxSolver(solver, bytecode, initialWitnessMap, () => { - throw Error('unexpected oracle'); - }); - - expect(solvedWitness0).to.be.deep.eq(expectedWitnessMap); - expect(solvedWitness1).to.be.deep.eq(expectedWitnessMap); -}); - -it('successfully executes 500 circuits with same backend', async function () { +it('successfully executes 500 pedersen circuits', async function () { this.timeout(100000); - // chose pedersen op here because it is the one with slow initialization - // that led to the decision to pull backend initialization into a separate - // function/wasmbind - const solver: WasmBlackBoxFunctionSolver = await createBlackBoxSolver(); + // Pedersen opcodes used to have a large upfront cost due to generator calculation + // so we'd need to pass around the blackbox solver in JS to avoid redoing this work. + // + // This test now shows that we don't need to do this anymore without a performance regression. const { bytecode, initialWitnessMap, expectedWitnessMap } = await import('../shared/pedersen'); for (let i = 0; i < 500; i++) { - const solvedWitness = await executeCircuitWithBlackBoxSolver(solver, bytecode, initialWitnessMap, () => { + const solvedWitness = await executeCircuit(bytecode, initialWitnessMap, () => { throw Error('unexpected oracle'); }); diff --git a/noir/noir-repo/tooling/noir_js/src/witness_generation.ts b/noir/noir-repo/tooling/noir_js/src/witness_generation.ts index 7d018c81d53a..c84cb2e83b32 100644 --- a/noir/noir-repo/tooling/noir_js/src/witness_generation.ts +++ b/noir/noir-repo/tooling/noir_js/src/witness_generation.ts @@ -1,25 +1,8 @@ import { abiDecodeError, abiEncode, InputMap } from '@noir-lang/noirc_abi'; import { base64Decode } from './base64_decode.js'; -import { - WitnessStack, - ForeignCallHandler, - ForeignCallInput, - createBlackBoxSolver, - WasmBlackBoxFunctionSolver, - executeProgramWithBlackBoxSolver, - ExecutionError, -} from '@noir-lang/acvm_js'; +import { WitnessStack, ForeignCallHandler, ForeignCallInput, ExecutionError, executeProgram } from '@noir-lang/acvm_js'; import { Abi, CompiledCircuit } from '@noir-lang/types'; -let solver: Promise; - -const getSolver = (): Promise => { - if (!solver) { - solver = createBlackBoxSolver(); - } - return solver; -}; - const defaultForeignCallHandler: ForeignCallHandler = async (name: string, args: ForeignCallInput[]) => { if (name == 'print') { // By default we do not print anything for `print` foreign calls due to a need for formatting, @@ -70,12 +53,7 @@ export async function generateWitness( // Execute the circuit to generate the rest of the witnesses and serialize // them into a Uint8Array. try { - const solvedWitness = await executeProgramWithBlackBoxSolver( - await getSolver(), - base64Decode(compiledProgram.bytecode), - witnessMap, - foreignCallHandler, - ); + const solvedWitness = await executeProgram(base64Decode(compiledProgram.bytecode), witnessMap, foreignCallHandler); return solvedWitness; } catch (err) { // Typescript types catched errors as unknown or any, so we need to narrow its type to check if it has raw assertion payload. diff --git a/yarn-project/simulator/src/acvm/acvm.ts b/yarn-project/simulator/src/acvm/acvm.ts index 9f9edb98bd78..72f559da7436 100644 --- a/yarn-project/simulator/src/acvm/acvm.ts +++ b/yarn-project/simulator/src/acvm/acvm.ts @@ -6,7 +6,6 @@ import { type ExecutionError, type ForeignCallInput, type ForeignCallOutput, - type WasmBlackBoxFunctionSolver, executeCircuitWithReturnWitness, } from '@noir-lang/acvm_js'; @@ -85,7 +84,6 @@ export function resolveOpcodeLocations( * The function call that executes an ACIR. */ export async function acvm( - solver: WasmBlackBoxFunctionSolver, acir: Buffer, initialWitness: ACVMWitness, callback: ACIRCallback, @@ -93,7 +91,6 @@ export async function acvm( const logger = createDebugLogger('aztec:simulator:acvm'); const solvedAndReturnWitness = await executeCircuitWithReturnWitness( - solver, acir, initialWitness, async (name: string, args: ForeignCallInput[]) => { diff --git a/yarn-project/simulator/src/client/private_execution.ts b/yarn-project/simulator/src/client/private_execution.ts index 4b27d4c8cdf7..b4d2f6ceca45 100644 --- a/yarn-project/simulator/src/client/private_execution.ts +++ b/yarn-project/simulator/src/client/private_execution.ts @@ -8,7 +8,6 @@ import { Oracle, acvm, extractCallStack } from '../acvm/index.js'; import { ExecutionError } from '../common/errors.js'; import { type ClientExecutionContext } from './client_execution_context.js'; import { type ExecutionResult } from './execution_result.js'; -import { AcirSimulator } from './simulator.js'; /** * Execute a private function and return the execution result. @@ -24,19 +23,17 @@ export async function executePrivateFunction( const acir = artifact.bytecode; const initialWitness = context.getInitialWitness(artifact); const acvmCallback = new Oracle(context); - const acirExecutionResult = await acvm(await AcirSimulator.getSolver(), acir, initialWitness, acvmCallback).catch( - (err: Error) => { - throw new ExecutionError( - err.message, - { - contractAddress, - functionSelector, - }, - extractCallStack(err, artifact.debug), - { cause: err }, - ); - }, - ); + const acirExecutionResult = await acvm(acir, initialWitness, acvmCallback).catch((err: Error) => { + throw new ExecutionError( + err.message, + { + contractAddress, + functionSelector, + }, + extractCallStack(err, artifact.debug), + { cause: err }, + ); + }); const partialWitness = acirExecutionResult.partialWitness; const returnWitness = witnessMapToFields(acirExecutionResult.returnWitness); const publicInputs = PrivateCircuitPublicInputs.fromFields(returnWitness); diff --git a/yarn-project/simulator/src/client/simulator.ts b/yarn-project/simulator/src/client/simulator.ts index 44ce65225afc..756720bc8aa8 100644 --- a/yarn-project/simulator/src/client/simulator.ts +++ b/yarn-project/simulator/src/client/simulator.ts @@ -11,8 +11,6 @@ import { AztecAddress } from '@aztec/foundation/aztec-address'; import { Fr } from '@aztec/foundation/fields'; import { type DebugLogger, createDebugLogger } from '@aztec/foundation/log'; -import { type WasmBlackBoxFunctionSolver, createBlackBoxSolver } from '@noir-lang/acvm_js'; - import { createSimulationError } from '../common/errors.js'; import { PackedValuesCache } from '../common/packed_values_cache.js'; import { ClientExecutionContext } from './client_execution_context.js'; @@ -27,33 +25,12 @@ import { ViewDataOracle } from './view_data_oracle.js'; * The ACIR simulator. */ export class AcirSimulator { - private static solver: Promise; // ACVM's backend private log: DebugLogger; constructor(private db: DBOracle, private node: AztecNode) { this.log = createDebugLogger('aztec:simulator'); } - /** - * Gets or initializes the ACVM WasmBlackBoxFunctionSolver. - * - * @remarks - * - * Occurs only once across all instances of AcirSimulator. - * Speeds up execution by only performing setup tasks (like pedersen - * generator initialization) one time. - * TODO(https://github.com/AztecProtocol/aztec-packages/issues/1627): - * determine whether this requires a lock - * - * @returns ACVM WasmBlackBoxFunctionSolver - */ - public static getSolver(): Promise { - if (!this.solver) { - this.solver = createBlackBoxSolver(); - } - return this.solver; - } - /** * Runs a private function. * @param request - The transaction request. diff --git a/yarn-project/simulator/src/client/unconstrained_execution.ts b/yarn-project/simulator/src/client/unconstrained_execution.ts index 39f130c63c17..1a7b957f7998 100644 --- a/yarn-project/simulator/src/client/unconstrained_execution.ts +++ b/yarn-project/simulator/src/client/unconstrained_execution.ts @@ -11,7 +11,6 @@ import { createDebugLogger } from '@aztec/foundation/log'; import { witnessMapToFields } from '../acvm/deserialize.js'; import { Oracle, acvm, extractCallStack, toACVMWitness } from '../acvm/index.js'; import { ExecutionError } from '../common/errors.js'; -import { AcirSimulator } from './simulator.js'; import { type ViewDataOracle } from './view_data_oracle.js'; // docs:start:execute_unconstrained_function @@ -30,12 +29,7 @@ export async function executeUnconstrainedFunction( const acir = artifact.bytecode; const initialWitness = toACVMWitness(0, args); - const acirExecutionResult = await acvm( - await AcirSimulator.getSolver(), - acir, - initialWitness, - new Oracle(oracle), - ).catch((err: Error) => { + const acirExecutionResult = await acvm(acir, initialWitness, new Oracle(oracle)).catch((err: Error) => { throw new ExecutionError( err.message, { diff --git a/yarn-project/simulator/src/public/executor.ts b/yarn-project/simulator/src/public/executor.ts index 20c5d2ca970d..01dfb09ee64a 100644 --- a/yarn-project/simulator/src/public/executor.ts +++ b/yarn-project/simulator/src/public/executor.ts @@ -21,7 +21,6 @@ import { AvmMachineState } from '../avm/avm_machine_state.js'; import { AvmSimulator } from '../avm/avm_simulator.js'; import { HostStorage } from '../avm/journal/host_storage.js'; import { AvmPersistableStateManager } from '../avm/journal/index.js'; -import { AcirSimulator } from '../client/simulator.js'; import { ExecutionError, createSimulationError } from '../common/errors.js'; import { SideEffectCounter } from '../common/index.js'; import { PackedValuesCache } from '../common/packed_values_cache.js'; @@ -140,7 +139,7 @@ async function executePublicFunctionAcvm( const { partialWitness, returnWitnessMap, reverted, revertReason } = await (async () => { try { - const result = await acvm(await AcirSimulator.getSolver(), acir, initialWitness, acvmCallback); + const result = await acvm(acir, initialWitness, acvmCallback); return { partialWitness: result.partialWitness, returnWitnessMap: result.returnWitness, diff --git a/yarn-project/simulator/src/simulator/acvm_wasm.ts b/yarn-project/simulator/src/simulator/acvm_wasm.ts index d78838427785..102da71a40aa 100644 --- a/yarn-project/simulator/src/simulator/acvm_wasm.ts +++ b/yarn-project/simulator/src/simulator/acvm_wasm.ts @@ -1,24 +1,11 @@ import { foreignCallHandler } from '@aztec/noir-protocol-circuits-types'; import { type NoirCompiledCircuit } from '@aztec/types/noir'; -import { - type WasmBlackBoxFunctionSolver, - createBlackBoxSolver, - executeCircuitWithBlackBoxSolver, -} from '@noir-lang/acvm_js'; +import { executeCircuit } from '@noir-lang/acvm_js'; import { type WitnessMap } from '@noir-lang/types'; import { type SimulationProvider } from './simulation_provider.js'; -let solver: Promise; - -const getSolver = (): Promise => { - if (!solver) { - solver = createBlackBoxSolver(); - } - return solver; -}; - export class WASMSimulator implements SimulationProvider { async simulateCircuit(input: WitnessMap, compiledCircuit: NoirCompiledCircuit): Promise { // Execute the circuit on those initial witness values @@ -27,8 +14,7 @@ export class WASMSimulator implements SimulationProvider { const decodedBytecode = Buffer.from(compiledCircuit.bytecode, 'base64'); // // Execute the circuit - const _witnessMap = await executeCircuitWithBlackBoxSolver( - await getSolver(), + const _witnessMap = await executeCircuit( decodedBytecode, input, foreignCallHandler, // handle calls to debug_log diff --git a/yarn-project/yarn.lock b/yarn-project/yarn.lock index d9a4bcdd5296..2befd0ec51af 100644 --- a/yarn-project/yarn.lock +++ b/yarn-project/yarn.lock @@ -2884,12 +2884,12 @@ __metadata: "@noir-lang/noir_js@file:../noir/packages/noir_js::locator=%40aztec%2Faztec3-packages%40workspace%3A.": version: 0.30.0 - resolution: "@noir-lang/noir_js@file:../noir/packages/noir_js#../noir/packages/noir_js::hash=ae4724&locator=%40aztec%2Faztec3-packages%40workspace%3A." + resolution: "@noir-lang/noir_js@file:../noir/packages/noir_js#../noir/packages/noir_js::hash=50aa1b&locator=%40aztec%2Faztec3-packages%40workspace%3A." dependencies: "@noir-lang/acvm_js": 0.46.0 "@noir-lang/noirc_abi": 0.30.0 "@noir-lang/types": 0.30.0 - checksum: 5bb35e8085b52d6be22e5ec4c3f7aac71bafc519a69a6ef157fc166d8b7729f25850ab2838ef92b5b5955e8f74a9782a69669515f8ac85983df76157ca99da2e + checksum: fc5f0f3d0aeb38275053ba98306866b9c532989b8e2abc751d9b5113b9c6914f159c186bfcee6173a89511385baeb952c88e55b8bfa9f9b8979643e927db25f6 languageName: node linkType: hard