From 89ab8eeab35dfeae36efbb1ae159c6600f40e059 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Bene=C5=A1?= Date: Thu, 9 May 2024 11:56:14 +0200 Subject: [PATCH 01/11] fix: `CombinedConstantData` not registered for serialization (#6292) Fixes: image I decided to not register `CombinedConstantData` directly on JsonRpc server and client since that would just make it all much less readable because CombinedConstantData is not a return value itself on any of AztecNode methods. And since I am a fan of nice readable encapsulated classes instead of the `Pick` type typescript freestyle I refactored ProcessOutput such that we can register that directly on the Json RPC server. --- .../src/aztec-node/http_rpc_server.ts | 10 +++- .../aztec-node/src/aztec-node/server.ts | 22 ++++---- .../src/aztec_node/rpc/aztec_node_client.ts | 13 ++++- .../src/interfaces/aztec-node.ts | 4 +- yarn-project/circuit-types/src/mocks.ts | 20 ++++---- yarn-project/circuit-types/src/tx/index.ts | 1 + .../src/tx/public_simulation_output.ts | 48 +++++++++++++++++ .../circuit-types/src/tx/simulated_tx.ts | 51 ++++--------------- 8 files changed, 102 insertions(+), 67 deletions(-) create mode 100644 yarn-project/circuit-types/src/tx/public_simulation_output.ts diff --git a/yarn-project/aztec-node/src/aztec-node/http_rpc_server.ts b/yarn-project/aztec-node/src/aztec-node/http_rpc_server.ts index 8270b171ffe..6234870fe42 100644 --- a/yarn-project/aztec-node/src/aztec-node/http_rpc_server.ts +++ b/yarn-project/aztec-node/src/aztec-node/http_rpc_server.ts @@ -6,6 +6,7 @@ import { LogId, NullifierMembershipWitness, PublicDataWitness, + PublicSimulationOutput, SiblingPath, Tx, TxEffect, @@ -41,7 +42,14 @@ export function createAztecNodeRpcServer(node: AztecNode) { PublicDataWitness, SiblingPath, }, - { Tx, TxReceipt, EncryptedL2BlockL2Logs, UnencryptedL2BlockL2Logs, NullifierMembershipWitness }, + { + PublicSimulationOutput, + Tx, + TxReceipt, + EncryptedL2BlockL2Logs, + UnencryptedL2BlockL2Logs, + NullifierMembershipWitness, + }, // disable methods not part of the AztecNode interface ['start', 'stop'], ); diff --git a/yarn-project/aztec-node/src/aztec-node/server.ts b/yarn-project/aztec-node/src/aztec-node/server.ts index 980c9cf6df0..54b15609cd4 100644 --- a/yarn-project/aztec-node/src/aztec-node/server.ts +++ b/yarn-project/aztec-node/src/aztec-node/server.ts @@ -13,10 +13,10 @@ import { LogType, MerkleTreeId, NullifierMembershipWitness, - type ProcessOutput, type ProverClient, type ProverConfig, PublicDataWitness, + PublicSimulationOutput, type SequencerConfig, type SiblingPath, type Tx, @@ -634,7 +634,7 @@ export class AztecNodeService implements AztecNode { * Simulates the public part of a transaction with the current state. * @param tx - The transaction to simulate. **/ - public async simulatePublicCalls(tx: Tx): Promise { + public async simulatePublicCalls(tx: Tx): Promise { this.log.info(`Simulating tx ${tx.getTxHash()}`); const blockNumber = (await this.blockSource.getBlockNumber()) + 1; @@ -674,15 +674,15 @@ export class AztecNodeService implements AztecNode { } this.log.debug(`Simulated tx ${tx.getTxHash()} succeeds`); const [processedTx] = processedTxs; - return { - constants: processedTx.data.constants, - encryptedLogs: processedTx.encryptedLogs, - unencryptedLogs: processedTx.unencryptedLogs, - end: processedTx.data.end, - revertReason: processedTx.revertReason, - publicReturnValues: returns[0], - gasUsed: processedTx.gasUsed, - }; + return new PublicSimulationOutput( + processedTx.encryptedLogs, + processedTx.unencryptedLogs, + processedTx.revertReason, + processedTx.data.constants, + processedTx.data.end, + returns[0], + processedTx.gasUsed, + ); } public async setConfig(config: Partial): Promise { diff --git a/yarn-project/circuit-types/src/aztec_node/rpc/aztec_node_client.ts b/yarn-project/circuit-types/src/aztec_node/rpc/aztec_node_client.ts index 79f9795f9f4..8591c53795f 100644 --- a/yarn-project/circuit-types/src/aztec_node/rpc/aztec_node_client.ts +++ b/yarn-project/circuit-types/src/aztec_node/rpc/aztec_node_client.ts @@ -9,8 +9,9 @@ import { type AztecNode } from '../../interfaces/aztec-node.js'; import { NullifierMembershipWitness } from '../../interfaces/nullifier_tree.js'; import { L2Block } from '../../l2_block.js'; import { EncryptedL2BlockL2Logs, ExtendedUnencryptedL2Log, LogId, UnencryptedL2BlockL2Logs } from '../../logs/index.js'; +import { PublicDataWitness } from '../../public_data_witness.js'; import { SiblingPath } from '../../sibling_path/index.js'; -import { Tx, TxHash, TxReceipt } from '../../tx/index.js'; +import { PublicSimulationOutput, Tx, TxHash, TxReceipt } from '../../tx/index.js'; import { TxEffect } from '../../tx_effect.js'; /** @@ -34,9 +35,17 @@ export function createAztecNodeClient(url: string, fetch = defaultFetch): AztecN TxEffect, LogId, TxHash, + PublicDataWitness, SiblingPath, }, - { Tx, TxReceipt, EncryptedL2BlockL2Logs, UnencryptedL2BlockL2Logs, NullifierMembershipWitness }, + { + PublicSimulationOutput, + Tx, + TxReceipt, + EncryptedL2BlockL2Logs, + UnencryptedL2BlockL2Logs, + NullifierMembershipWitness, + }, false, 'node', fetch, diff --git a/yarn-project/circuit-types/src/interfaces/aztec-node.ts b/yarn-project/circuit-types/src/interfaces/aztec-node.ts index d59543943e8..bf1df022131 100644 --- a/yarn-project/circuit-types/src/interfaces/aztec-node.ts +++ b/yarn-project/circuit-types/src/interfaces/aztec-node.ts @@ -22,7 +22,7 @@ import { import { type MerkleTreeId } from '../merkle_tree_id.js'; import { type PublicDataWitness } from '../public_data_witness.js'; import { type SiblingPath } from '../sibling_path/index.js'; -import { type ProcessOutput, type Tx, type TxHash, type TxReceipt } from '../tx/index.js'; +import { type PublicSimulationOutput, type Tx, type TxHash, type TxReceipt } from '../tx/index.js'; import { type TxEffect } from '../tx_effect.js'; import { type SequencerConfig } from './configs.js'; import { type L2BlockNumber } from './l2_block_number.js'; @@ -283,7 +283,7 @@ export interface AztecNode { * This currently just checks that the transaction execution succeeds. * @param tx - The transaction to simulate. **/ - simulatePublicCalls(tx: Tx): Promise; + simulatePublicCalls(tx: Tx): Promise; /** * Updates the configuration of this node. diff --git a/yarn-project/circuit-types/src/mocks.ts b/yarn-project/circuit-types/src/mocks.ts index 9cda922037c..ba36cd68556 100644 --- a/yarn-project/circuit-types/src/mocks.ts +++ b/yarn-project/circuit-types/src/mocks.ts @@ -27,7 +27,7 @@ import { type ContractInstanceWithAddress, SerializableContractInstance } from ' import { EncryptedL2Log } from './logs/encrypted_l2_log.js'; import { EncryptedFunctionL2Logs, EncryptedTxL2Logs, Note, UnencryptedTxL2Logs } from './logs/index.js'; import { ExtendedNote } from './notes/index.js'; -import { type ProcessOutput, type ProcessReturnValues, SimulatedTx, Tx, TxHash } from './tx/index.js'; +import { type ProcessReturnValues, PublicSimulationOutput, SimulatedTx, Tx, TxHash } from './tx/index.js'; /** * Testing utility to create empty logs composed from a single empty log. @@ -129,15 +129,15 @@ export const mockTxForRollup = (seed = 1, { hasLogs = false }: { hasLogs?: boole export const mockSimulatedTx = (seed = 1, hasLogs = true) => { const tx = mockTx(seed, { hasLogs }); const dec: ProcessReturnValues = [new Fr(1n), new Fr(2n), new Fr(3n), new Fr(4n)]; - const output: ProcessOutput = { - constants: makeCombinedConstantData(), - encryptedLogs: tx.encryptedLogs, - unencryptedLogs: tx.unencryptedLogs, - end: makeCombinedAccumulatedData(), - revertReason: undefined, - publicReturnValues: dec, - gasUsed: {}, - }; + const output = new PublicSimulationOutput( + tx.encryptedLogs, + tx.unencryptedLogs, + undefined, + makeCombinedConstantData(), + makeCombinedAccumulatedData(), + dec, + {}, + ); return new SimulatedTx(tx, dec, output); }; diff --git a/yarn-project/circuit-types/src/tx/index.ts b/yarn-project/circuit-types/src/tx/index.ts index e113a56430e..6d69130adaf 100644 --- a/yarn-project/circuit-types/src/tx/index.ts +++ b/yarn-project/circuit-types/src/tx/index.ts @@ -3,4 +3,5 @@ export * from './simulated_tx.js'; export * from './tx_hash.js'; export * from './tx_receipt.js'; export * from './processed_tx.js'; +export * from './public_simulation_output.js'; export * from './tx_validator.js'; diff --git a/yarn-project/circuit-types/src/tx/public_simulation_output.ts b/yarn-project/circuit-types/src/tx/public_simulation_output.ts new file mode 100644 index 00000000000..24443814680 --- /dev/null +++ b/yarn-project/circuit-types/src/tx/public_simulation_output.ts @@ -0,0 +1,48 @@ +import { CombinedAccumulatedData, CombinedConstantData, Fr, Gas } from '@aztec/circuits.js'; +import { mapValues } from '@aztec/foundation/collection'; + +import { EncryptedTxL2Logs, UnencryptedTxL2Logs } from '../logs/tx_l2_logs.js'; +import { type SimulationError } from '../simulation_error.js'; +import { type PublicKernelType } from './processed_tx.js'; + +/** Return values of simulating a circuit. */ +export type ProcessReturnValues = Fr[] | undefined; + +/** + * Outputs of processing the public component of a transaction. + */ +export class PublicSimulationOutput { + constructor( + public encryptedLogs: EncryptedTxL2Logs, + public unencryptedLogs: UnencryptedTxL2Logs, + public revertReason: SimulationError | undefined, + public constants: CombinedConstantData, + public end: CombinedAccumulatedData, + public publicReturnValues: ProcessReturnValues, + public gasUsed: Partial>, + ) {} + + toJSON() { + return { + encryptedLogs: this.encryptedLogs.toJSON(), + unencryptedLogs: this.unencryptedLogs.toJSON(), + revertReason: this.revertReason, + constants: this.constants.toBuffer().toString('hex'), + end: this.end.toBuffer().toString('hex'), + publicReturnValues: this.publicReturnValues?.map(fr => fr.toString()), + gasUsed: mapValues(this.gasUsed, gas => gas?.toJSON()), + }; + } + + static fromJSON(json: any): PublicSimulationOutput { + return new PublicSimulationOutput( + EncryptedTxL2Logs.fromJSON(json.encryptedLogs), + UnencryptedTxL2Logs.fromJSON(json.unencryptedLogs), + json.revertReason, + CombinedConstantData.fromBuffer(Buffer.from(json.constants, 'hex')), + CombinedAccumulatedData.fromBuffer(Buffer.from(json.end, 'hex')), + json.publicReturnValues?.map(Fr.fromString), + mapValues(json.gasUsed, gas => (gas ? Gas.fromJSON(gas) : undefined)), + ); + } +} diff --git a/yarn-project/circuit-types/src/tx/simulated_tx.ts b/yarn-project/circuit-types/src/tx/simulated_tx.ts index 61883a5d1f5..45387f1664a 100644 --- a/yarn-project/circuit-types/src/tx/simulated_tx.ts +++ b/yarn-project/circuit-types/src/tx/simulated_tx.ts @@ -1,44 +1,9 @@ -import { CombinedAccumulatedData, CombinedConstantData, Fr, Gas } from '@aztec/circuits.js'; -import { mapValues } from '@aztec/foundation/collection'; +import { Fr, Gas } from '@aztec/circuits.js'; -import { EncryptedTxL2Logs, UnencryptedTxL2Logs } from '../logs/index.js'; -import { type ProcessedTx, PublicKernelType } from './processed_tx.js'; +import { PublicKernelType } from './processed_tx.js'; +import { type ProcessReturnValues, PublicSimulationOutput } from './public_simulation_output.js'; import { Tx } from './tx.js'; -/** Return values of simulating a circuit. */ -export type ProcessReturnValues = Fr[] | undefined; - -/** - * Outputs of processing the public component of a transaction. - * REFACTOR: Rename. - */ -export type ProcessOutput = Pick & - Pick & { publicReturnValues: ProcessReturnValues }; - -function processOutputToJSON(output: ProcessOutput) { - return { - encryptedLogs: output.encryptedLogs.toJSON(), - unencryptedLogs: output.unencryptedLogs.toJSON(), - revertReason: output.revertReason, - constants: output.constants.toBuffer().toString('hex'), - end: output.end.toBuffer().toString('hex'), - publicReturnValues: output.publicReturnValues?.map(fr => fr.toString()), - gasUsed: mapValues(output.gasUsed, gas => gas?.toJSON()), - }; -} - -function processOutputFromJSON(json: any): ProcessOutput { - return { - encryptedLogs: EncryptedTxL2Logs.fromJSON(json.encryptedLogs), - unencryptedLogs: UnencryptedTxL2Logs.fromJSON(json.unencryptedLogs), - revertReason: json.revertReason, - constants: CombinedConstantData.fromBuffer(Buffer.from(json.constants, 'hex')), - end: CombinedAccumulatedData.fromBuffer(Buffer.from(json.end, 'hex')), - publicReturnValues: json.publicReturnValues?.map(Fr.fromString), - gasUsed: mapValues(json.gasUsed, gas => (gas ? Gas.fromJSON(gas) : undefined)), - }; -} - // REFACTOR: Review what we need to expose to the user when running a simulation. // Eg tx already has encrypted and unencrypted logs, but those cover only the ones // emitted during private. We need the ones from ProcessOutput to include the public @@ -46,7 +11,11 @@ function processOutputFromJSON(json: any): ProcessOutput { // the public side of things. This also points at this class needing to be split into // two: one with just private simulation, and one that also includes public simulation. export class SimulatedTx { - constructor(public tx: Tx, public privateReturnValues?: ProcessReturnValues, public publicOutput?: ProcessOutput) {} + constructor( + public tx: Tx, + public privateReturnValues?: ProcessReturnValues, + public publicOutput?: PublicSimulationOutput, + ) {} /** * Returns suggested total and teardown gas limits for the simulated tx. @@ -79,7 +48,7 @@ export class SimulatedTx { return { tx: this.tx.toJSON(), privateReturnValues: this.privateReturnValues?.map(fr => fr.toString()), - publicOutput: this.publicOutput && processOutputToJSON(this.publicOutput), + publicOutput: this.publicOutput && this.publicOutput.toJSON(), }; } @@ -90,7 +59,7 @@ export class SimulatedTx { */ public static fromJSON(obj: any) { const tx = Tx.fromJSON(obj.tx); - const publicOutput = obj.publicOutput ? processOutputFromJSON(obj.publicOutput) : undefined; + const publicOutput = obj.publicOutput ? PublicSimulationOutput.fromJSON(obj.publicOutput) : undefined; const privateReturnValues = obj.privateReturnValues?.map(Fr.fromString); return new SimulatedTx(tx, privateReturnValues, publicOutput); From eae5822cfcf47d03739e09911c183ba9f4ced18b Mon Sep 17 00:00:00 2001 From: PhilWindle <60546371+PhilWindle@users.noreply.github.com> Date: Thu, 9 May 2024 11:24:04 +0100 Subject: [PATCH 02/11] feat: Private Kernel Recursion (#6278) This PR introduces recursive verification to the private kernel circuits. Both app circuit and previous kernel circuit proofs are verified. This closes #5978 The changes can be largely categorised as: 1. PXE modifications to pass proofs and verification keys from the output of a proving process as inputs to the next simulation/proving process. 2. Serialisation of `PrivateCircuitPublicInputs` and `PrivateKernelCircuitPublicInputs` structs to fields. 3. Aggregation of proofs using Noir's `verify_proof` api. Additional task create [here](https://github.com/AztecProtocol/aztec-packages/issues/6285) to prevent the specification of `pub` on arguments to private functions. --- .../src/core/libraries/ConstantsGen.sol | 29 ++++ .../schnorr_account_contract/src/main.nr | 2 +- .../crates/private-kernel-init/src/main.nr | 3 +- .../crates/private-kernel-inner/src/main.nr | 3 +- .../kernel_circuit_public_inputs_composer.nr | 2 +- .../src/private_kernel_init.nr | 7 +- .../src/private_kernel_inner.nr | 18 +-- .../src/private_kernel_tail.nr | 19 ++- .../src/private_kernel_tail_to_public.nr | 5 +- .../private-kernel-tail-to-public/src/main.nr | 3 +- .../crates/private-kernel-tail/src/main.nr | 3 +- .../src/public_kernel_tail.nr | 1 - .../rollup-lib/src/base/base_rollup_inputs.nr | 2 +- .../crates/types/src/abis.nr | 1 + .../combined_accumulated_data.nr | 28 +++- .../private_accumulated_data.nr | 45 +++++- .../crates/types/src/abis/call_request.nr | 19 ++- .../crates/types/src/abis/caller_context.nr | 16 +- .../types/src/abis/combined_constant_data.nr | 17 +- .../kernel_circuit_public_inputs.nr | 3 - .../private_kernel_circuit_public_inputs.nr | 20 ++- ...te_kernel_circuit_public_inputs_builder.nr | 5 - .../public_kernel_circuit_public_inputs.nr | 2 - ...ic_kernel_circuit_public_inputs_builder.nr | 6 +- .../crates/types/src/abis/kernel_data.nr | 24 +-- .../abis/private_kernel/private_call_data.nr | 19 ++- .../types/src/abis/private_kernel_data.nr | 34 ++++ .../crates/types/src/abis/public_data_read.nr | 10 +- .../src/abis/public_data_update_request.nr | 10 +- .../crates/types/src/abis/read_request.nr | 13 +- .../rollup_validation_requests.nr | 8 +- .../validation_requests.nr | 36 ++++- .../crates/types/src/constants.nr | 14 ++ .../crates/types/src/hash.nr | 2 +- .../crates/types/src/tests/fixture_builder.nr | 44 ++--- .../src/tests/private_call_data_builder.nr | 8 +- .../brillig/brillig_gen/brillig_black_box.rs | 4 +- yarn-project/circuits.js/src/constants.gen.ts | 36 +++++ .../src/structs/kernel/private_call_data.ts | 13 +- .../src/structs/kernel/private_kernel_data.ts | 18 +-- .../src/structs/verification_key.ts | 8 + .../circuits.js/src/tests/factories.ts | 4 +- .../client_prover_integration.test.ts | 2 +- .../src/type_conversion.ts | 21 +-- .../bb_prover/bb_native_proof_creator.ts | 153 +++++++++++------- .../kernel_prover/interface/proof_creator.ts | 32 +++- .../src/kernel_prover/kernel_prover.test.ts | 19 ++- .../pxe/src/kernel_prover/kernel_prover.ts | 39 ++--- .../src/kernel_prover/proving_data_oracle.ts | 4 +- .../kernel_prover/test/test_circuit_prover.ts | 48 +++--- .../pxe/src/pxe_service/pxe_service.ts | 2 +- 51 files changed, 617 insertions(+), 267 deletions(-) create mode 100644 noir-projects/noir-protocol-circuits/crates/types/src/abis/private_kernel_data.nr diff --git a/l1-contracts/src/core/libraries/ConstantsGen.sol b/l1-contracts/src/core/libraries/ConstantsGen.sol index a026721c12f..ac060def61e 100644 --- a/l1-contracts/src/core/libraries/ConstantsGen.sol +++ b/l1-contracts/src/core/libraries/ConstantsGen.sol @@ -128,6 +128,7 @@ library Constants { uint256 internal constant NULLIFIER_LENGTH = 3; uint256 internal constant SCOPED_NULLIFIER_LENGTH = NULLIFIER_LENGTH + 1; uint256 internal constant SIDE_EFFECT_LENGTH = 2; + uint256 internal constant ROLLUP_VALIDATION_REQUESTS_LENGTH = MAX_BLOCK_NUMBER_LENGTH; uint256 internal constant STATE_REFERENCE_LENGTH = APPEND_ONLY_TREE_SNAPSHOT_LENGTH + PARTIAL_STATE_REFERENCE_LENGTH; uint256 internal constant TX_CONTEXT_LENGTH = 2 + GAS_SETTINGS_LENGTH; @@ -157,6 +158,34 @@ library Constants { + 1; uint256 internal constant PRIVATE_CALL_STACK_ITEM_LENGTH = AZTEC_ADDRESS_LENGTH + FUNCTION_DATA_LENGTH + PRIVATE_CIRCUIT_PUBLIC_INPUTS_LENGTH; + uint256 internal constant SCOPED_READ_REQUEST_LEN = READ_REQUEST_LENGTH + 1; + uint256 internal constant PUBLIC_DATA_READ_LENGTH = 2; + uint256 internal constant VALIDATION_REQUESTS_LENGTH = ROLLUP_VALIDATION_REQUESTS_LENGTH + + (SCOPED_READ_REQUEST_LEN * MAX_NOTE_HASH_READ_REQUESTS_PER_TX) + + (SCOPED_READ_REQUEST_LEN * MAX_NULLIFIER_READ_REQUESTS_PER_TX) + + (SCOPED_READ_REQUEST_LEN * MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_TX) + + (SCOPED_NULLIFIER_KEY_VALIDATION_REQUEST_LENGTH * MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX) + + (PUBLIC_DATA_READ_LENGTH * MAX_PUBLIC_DATA_READS_PER_TX); + uint256 internal constant PUBLIC_DATA_UPDATE_REQUEST_LENGTH = 2; + uint256 internal constant COMBINED_ACCUMULATED_DATA_LENGTH = MAX_NEW_NOTE_HASHES_PER_TX + + MAX_NEW_NULLIFIERS_PER_TX + MAX_NEW_L2_TO_L1_MSGS_PER_TX + 4 + + (MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX * PUBLIC_DATA_UPDATE_REQUEST_LENGTH) + GAS_LENGTH; + uint256 internal constant COMBINED_CONSTANT_DATA_LENGTH = + HEADER_LENGTH + TX_CONTEXT_LENGTH + GLOBAL_VARIABLES_LENGTH; + uint256 internal constant CALLER_CONTEXT_LENGTH = 2 * AZTEC_ADDRESS_LENGTH; + uint256 internal constant CALL_REQUEST_LENGTH = + 1 + AZTEC_ADDRESS_LENGTH + CALLER_CONTEXT_LENGTH + 2; + uint256 internal constant PRIVATE_ACCUMULATED_DATA_LENGTH = ( + SCOPED_NOTE_HASH_LENGTH * MAX_NEW_NOTE_HASHES_PER_TX + ) + (SCOPED_NULLIFIER_LENGTH * MAX_NEW_NULLIFIERS_PER_TX) + + (MAX_NEW_L2_TO_L1_MSGS_PER_TX * SCOPED_L2_TO_L1_MESSAGE_LENGTH) + + (SIDE_EFFECT_LENGTH * MAX_ENCRYPTED_LOGS_PER_TX) + + (SIDE_EFFECT_LENGTH * MAX_UNENCRYPTED_LOGS_PER_TX) + 2 + + (CALL_REQUEST_LENGTH * MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX) + + (CALL_REQUEST_LENGTH * MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX); + uint256 internal constant PRIVATE_KERNEL_CIRCUIT_PUBLIC_INPUTS_LENGTH = 1 + + VALIDATION_REQUESTS_LENGTH + PRIVATE_ACCUMULATED_DATA_LENGTH + COMBINED_CONSTANT_DATA_LENGTH + + CALL_REQUEST_LENGTH; uint256 internal constant ENQUEUE_PUBLIC_FUNCTION_CALL_RETURN_LENGTH = 2 + FUNCTION_DATA_LENGTH + CALL_CONTEXT_LENGTH; uint256 internal constant GET_NOTES_ORACLE_RETURN_LENGTH = 674; diff --git a/noir-projects/noir-contracts/contracts/schnorr_account_contract/src/main.nr b/noir-projects/noir-contracts/contracts/schnorr_account_contract/src/main.nr index 1ec2152e7c3..d42ee2119d6 100644 --- a/noir-projects/noir-contracts/contracts/schnorr_account_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/schnorr_account_contract/src/main.nr @@ -39,7 +39,7 @@ contract SchnorrAccount { // Note: If you globally change the entrypoint signature don't forget to update default_entrypoint.ts file #[aztec(private)] #[aztec(noinitcheck)] - fn entrypoint(app_payload: pub AppPayload, fee_payload: pub FeePayload) { + fn entrypoint(app_payload: AppPayload, fee_payload: FeePayload) { let actions = AccountActions::private( &mut context, storage.approved_actions.storage_slot, diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-init/src/main.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-init/src/main.nr index 635b9da54d9..76a82613767 100644 --- a/noir-projects/noir-protocol-circuits/crates/private-kernel-init/src/main.nr +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-init/src/main.nr @@ -1,6 +1,7 @@ use dep::private_kernel_lib::PrivateKernelInitCircuitPrivateInputs; use dep::types::PrivateKernelCircuitPublicInputs; -fn main(input: PrivateKernelInitCircuitPrivateInputs) -> pub PrivateKernelCircuitPublicInputs { +#[recursive] +fn main(input: PrivateKernelInitCircuitPrivateInputs) -> pub PrivateKernelCircuitPublicInputs { input.native_private_kernel_circuit_initial() } diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-inner/src/main.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-inner/src/main.nr index 861d229580c..686cce6b595 100644 --- a/noir-projects/noir-protocol-circuits/crates/private-kernel-inner/src/main.nr +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-inner/src/main.nr @@ -1,6 +1,7 @@ use dep::private_kernel_lib::PrivateKernelInnerCircuitPrivateInputs; use dep::types::PrivateKernelCircuitPublicInputs; -fn main(input: PrivateKernelInnerCircuitPrivateInputs) -> pub PrivateKernelCircuitPublicInputs { +#[recursive] +fn main(input: PrivateKernelInnerCircuitPrivateInputs) -> pub PrivateKernelCircuitPublicInputs { input.native_private_kernel_circuit_inner() } diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/kernel_circuit_public_inputs_composer.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/kernel_circuit_public_inputs_composer.nr index 5abc9c8f4f4..18115cc2ea6 100644 --- a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/kernel_circuit_public_inputs_composer.nr +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/kernel_circuit_public_inputs_composer.nr @@ -1,7 +1,7 @@ use dep::reset_kernel_lib::verify_squashed_transient_note_hashes_and_nullifiers; use dep::types::{ abis::{ - kernel_data::PrivateKernelData, + private_kernel_data::PrivateKernelData, kernel_circuit_public_inputs::{KernelCircuitPublicInputs, PrivateKernelCircuitPublicInputsBuilder, PublicKernelCircuitPublicInputs}, note_hash::ScopedNoteHash, nullifier::ScopedNullifier, side_effect::{SideEffect, Ordered}, gas::Gas }, diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_init.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_init.nr index 64a08cdc7b1..bb4a7db587c 100644 --- a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_init.nr +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_init.nr @@ -1,7 +1,7 @@ use crate::{common, private_kernel_circuit_public_inputs_composer::PrivateKernelCircuitPublicInputsComposer}; use dep::types::{ abis::{ - private_kernel::private_call_data::PrivateCallData, + private_kernel::private_call_data::{PrivateCallData, verify_private_call}, kernel_circuit_public_inputs::PrivateKernelCircuitPublicInputs }, constants::MAX_NEW_NOTE_HASHES_PER_CALL, mocked::verify_private_function_proof, @@ -68,14 +68,15 @@ impl PrivateKernelInitCircuitPrivateInputs { pub fn native_private_kernel_circuit_initial(self) -> PrivateKernelCircuitPublicInputs { let private_call_public_inputs = self.private_call.call_stack_item.public_inputs; + // verify/aggregate the private call proof + verify_private_call(self.private_call); + self.validate_inputs(); common::validate_private_call_data(self.private_call); self.validate_this_private_call_against_tx_request(); - assert(verify_private_function_proof(self.private_call.proof), "Invalid private function proof."); - PrivateKernelCircuitPublicInputsComposer::new_from_tx_request(self.tx_request, private_call_public_inputs).compose( private_call_public_inputs, self.hints.note_hash_nullifier_counters, diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_inner.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_inner.nr index 6a291bafbfa..61a06ea345b 100644 --- a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_inner.nr +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_inner.nr @@ -1,12 +1,12 @@ use crate::{common, private_kernel_circuit_public_inputs_composer::PrivateKernelCircuitPublicInputsComposer}; use dep::types::{ abis::{ - kernel_data::PrivateKernelData, private_kernel::private_call_data::PrivateCallData, + private_kernel_data::{PrivateKernelData, verify_previous_kernel_proof}, + private_kernel::private_call_data::{PrivateCallData, verify_private_call}, kernel_circuit_public_inputs::{PrivateKernelCircuitPublicInputs, PrivateKernelCircuitPublicInputsBuilder}, side_effect::SideEffect }, - constants::MAX_NEW_NOTE_HASHES_PER_CALL, mocked::verify_previous_kernel_state, - utils::arrays::array_length + constants::MAX_NEW_NOTE_HASHES_PER_CALL, utils::arrays::array_length }; struct PrivateKernelInnerHints { @@ -30,6 +30,12 @@ impl PrivateKernelInnerCircuitPrivateInputs { let private_call_public_inputs = self.private_call.call_stack_item.public_inputs; let previous_kernel_public_inputs = self.previous_kernel.public_inputs; + // verify/aggregate the private call proof + verify_private_call(self.private_call); + + // verify/aggregate the previous kernel + verify_previous_kernel_proof(self.previous_kernel); + common::validate_previous_kernel_values(previous_kernel_public_inputs.end); self.validate_inputs(); @@ -42,12 +48,6 @@ impl PrivateKernelInnerCircuitPrivateInputs { let call_request = private_call_stack[private_call_stack_size - 1]; common::validate_call_against_request(self.private_call, call_request); - let (is_previous_state_valid, _updated_aggregation_object) = verify_previous_kernel_state( - previous_kernel_public_inputs.aggregation_object, - self.private_call.proof - ); - assert(is_previous_state_valid); - PrivateKernelCircuitPublicInputsComposer::new_from_previous_kernel(self.previous_kernel.public_inputs).compose( private_call_public_inputs, self.hints.note_hash_nullifier_counters, diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_tail.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_tail.nr index 2471caad0be..51d6efd7a07 100644 --- a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_tail.nr +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_tail.nr @@ -1,14 +1,14 @@ use crate::kernel_circuit_public_inputs_composer::KernelCircuitPublicInputsComposer; use dep::reset_kernel_lib::{NoteHashReadRequestHints, NullifierReadRequestHints, PrivateValidationRequestProcessor}; use dep::types::{ - abis::{ - kernel_data::PrivateKernelData, kernel_circuit_public_inputs::KernelCircuitPublicInputs, - note_hash::ScopedNoteHash, nullifier::ScopedNullifier, side_effect::SideEffect -}, - constants::{ - MAX_NEW_NOTE_HASHES_PER_TX, MAX_NEW_NULLIFIERS_PER_TX, MAX_NOTE_HASH_READ_REQUESTS_PER_TX, - MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, MAX_ENCRYPTED_LOGS_PER_TX, MAX_UNENCRYPTED_LOGS_PER_TX -}, + abis::{ + private_kernel_data::{PrivateKernelData, verify_previous_kernel_proof}, kernel_circuit_public_inputs::KernelCircuitPublicInputs, + note_hash::ScopedNoteHash, nullifier::ScopedNullifier, side_effect::SideEffect + }, + constants::{ + MAX_NEW_NOTE_HASHES_PER_TX, MAX_NEW_NULLIFIERS_PER_TX, MAX_NOTE_HASH_READ_REQUESTS_PER_TX, + MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, MAX_ENCRYPTED_LOGS_PER_TX, MAX_UNENCRYPTED_LOGS_PER_TX + }, grumpkin_private_key::GrumpkinPrivateKey, utils::arrays::array_length }; @@ -47,6 +47,9 @@ impl PrivateKernelTailCircuitPrivateInputs { array_length(previous_public_inputs.end.public_call_stack), 0, "Public call stack must be empty when executing the tail circuit" ); + // verify/aggregate the previous kernel + verify_previous_kernel_proof(self.previous_kernel); + let note_hash_tree_root = previous_public_inputs.constants.historical_header.state.partial.note_hash_tree.root; let nullifier_tree_root = previous_public_inputs.constants.historical_header.state.partial.nullifier_tree.root; PrivateValidationRequestProcessor { diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_tail_to_public.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_tail_to_public.nr index a16c3ea41ba..7b7e17eba88 100644 --- a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_tail_to_public.nr +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_tail_to_public.nr @@ -2,7 +2,7 @@ use crate::kernel_circuit_public_inputs_composer::KernelCircuitPublicInputsCompo use dep::reset_kernel_lib::{NoteHashReadRequestHints, NullifierReadRequestHints, PrivateValidationRequestProcessor}; use dep::types::{ abis::{ - kernel_data::PrivateKernelData, kernel_circuit_public_inputs::PublicKernelCircuitPublicInputs, + private_kernel_data::{PrivateKernelData, verify_previous_kernel_proof}, kernel_circuit_public_inputs::PublicKernelCircuitPublicInputs, note_hash::ScopedNoteHash, nullifier::ScopedNullifier, side_effect::SideEffect }, constants::{ @@ -47,6 +47,9 @@ impl PrivateKernelTailToPublicCircuitPrivateInputs { array_length(previous_public_inputs.end.public_call_stack) != 0, "Public call stack must not be empty when exporting public kernel data from the tail circuit" ); + // verify/aggregate the previous kernel + verify_previous_kernel_proof(self.previous_kernel); + let note_hash_tree_root = previous_public_inputs.constants.historical_header.state.partial.note_hash_tree.root; let nullifier_tree_root = previous_public_inputs.constants.historical_header.state.partial.nullifier_tree.root; PrivateValidationRequestProcessor { diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-tail-to-public/src/main.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-tail-to-public/src/main.nr index 85050fa143b..fd35f8397f3 100644 --- a/noir-projects/noir-protocol-circuits/crates/private-kernel-tail-to-public/src/main.nr +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-tail-to-public/src/main.nr @@ -1,6 +1,7 @@ use dep::private_kernel_lib::PrivateKernelTailToPublicCircuitPrivateInputs; use dep::types::PublicKernelCircuitPublicInputs; -fn main(input: PrivateKernelTailToPublicCircuitPrivateInputs) -> pub PublicKernelCircuitPublicInputs { +#[recursive] +fn main(input: PrivateKernelTailToPublicCircuitPrivateInputs) -> pub PublicKernelCircuitPublicInputs { input.execute() } diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-tail/src/main.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-tail/src/main.nr index 681eaacb72d..41485a79a2b 100644 --- a/noir-projects/noir-protocol-circuits/crates/private-kernel-tail/src/main.nr +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-tail/src/main.nr @@ -1,6 +1,7 @@ use dep::private_kernel_lib::PrivateKernelTailCircuitPrivateInputs; use dep::types::KernelCircuitPublicInputs; -fn main(input: PrivateKernelTailCircuitPrivateInputs) -> pub KernelCircuitPublicInputs { +#[recursive] +fn main(input: PrivateKernelTailCircuitPrivateInputs) -> pub KernelCircuitPublicInputs { input.native_private_kernel_circuit_tail() } diff --git a/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/public_kernel_tail.nr b/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/public_kernel_tail.nr index f8bc620c100..e92e4c791a4 100644 --- a/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/public_kernel_tail.nr +++ b/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/public_kernel_tail.nr @@ -92,7 +92,6 @@ impl PublicKernelTailCircuitPrivateInputs { let end = self.propagate_accumulated_data(); KernelCircuitPublicInputs { - aggregation_object: previous_public_inputs.aggregation_object, rollup_validation_requests: previous_public_inputs.validation_requests.for_rollup, end, constants: previous_public_inputs.constants, diff --git a/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/base/base_rollup_inputs.nr b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/base/base_rollup_inputs.nr index 238cc1dbd13..704b1ac6e65 100644 --- a/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/base/base_rollup_inputs.nr +++ b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/base/base_rollup_inputs.nr @@ -247,7 +247,7 @@ impl BaseRollupInputs { // TODO(Kev): This aggregate_proof method is duplicated in a lot of places fn aggregate_proofs(self) -> AggregationObject { // TODO: for now we simply return the aggregation object from the first proof - self.kernel_data.public_inputs.aggregation_object + AggregationObject {} } } diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis.nr index 2c2a9325bcb..9b95b164f5a 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis.nr @@ -27,6 +27,7 @@ mod max_block_number; mod private_kernel; mod kernel_circuit_public_inputs; mod kernel_data; +mod private_kernel_data; mod call_request; mod private_call_stack_item; diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/combined_accumulated_data.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/combined_accumulated_data.nr index 1a49b8de968..21e62582622 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/combined_accumulated_data.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/combined_accumulated_data.nr @@ -7,9 +7,9 @@ use crate::{ }, constants::{ MAX_NEW_NOTE_HASHES_PER_TX, MAX_NEW_NULLIFIERS_PER_TX, MAX_NEW_L2_TO_L1_MSGS_PER_TX, - MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX + MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, COMBINED_ACCUMULATED_DATA_LENGTH }, - utils::arrays::array_merge, traits::Empty + utils::arrays::array_merge, traits::{Empty, Serialize} }; struct CombinedAccumulatedData { @@ -82,3 +82,27 @@ impl Empty for CombinedAccumulatedData { } } } + +impl Serialize for CombinedAccumulatedData { + fn serialize(self) -> [Field; COMBINED_ACCUMULATED_DATA_LENGTH] { + let mut fields: BoundedVec = BoundedVec::new(); + + fields.extend_from_array(self.new_note_hashes); + fields.extend_from_array(self.new_nullifiers); + fields.extend_from_array(self.new_l2_to_l1_msgs); + fields.push(self.encrypted_logs_hash); + fields.push(self.unencrypted_logs_hash); + fields.push(self.encrypted_log_preimages_length); + fields.push(self.unencrypted_log_preimages_length); + + for i in 0..MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX { + fields.extend_from_array(self.public_data_update_requests[i].serialize()); + } + + fields.extend_from_array(self.gas_used.serialize()); + + assert_eq(fields.len(), COMBINED_ACCUMULATED_DATA_LENGTH); + + fields.storage + } +} diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/private_accumulated_data.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/private_accumulated_data.nr index 12c19d640b1..502acaab910 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/private_accumulated_data.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/private_accumulated_data.nr @@ -3,12 +3,12 @@ use crate::{ call_request::CallRequest, gas::Gas, note_hash::ScopedNoteHash, nullifier::ScopedNullifier, side_effect::SideEffect }, - messaging::l2_to_l1_message::ScopedL2ToL1Message + traits::Serialize, messaging::l2_to_l1_message::ScopedL2ToL1Message }; use crate::constants::{ MAX_NEW_NOTE_HASHES_PER_TX, MAX_NEW_NULLIFIERS_PER_TX, MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX, MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX, MAX_NEW_L2_TO_L1_MSGS_PER_TX, MAX_ENCRYPTED_LOGS_PER_TX, - MAX_UNENCRYPTED_LOGS_PER_TX + MAX_UNENCRYPTED_LOGS_PER_TX, PRIVATE_ACCUMULATED_DATA_LENGTH }; struct PrivateAccumulatedData { @@ -27,3 +27,44 @@ struct PrivateAccumulatedData { private_call_stack: [CallRequest; MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX], public_call_stack: [CallRequest; MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX], } + +impl Serialize for PrivateAccumulatedData { + fn serialize(self) -> [Field; PRIVATE_ACCUMULATED_DATA_LENGTH] { + let mut fields: BoundedVec = BoundedVec::new(); + + for i in 0..MAX_NEW_NOTE_HASHES_PER_TX { + fields.extend_from_array(self.new_note_hashes[i].serialize()); + } + + for i in 0..MAX_NEW_NULLIFIERS_PER_TX { + fields.extend_from_array(self.new_nullifiers[i].serialize()); + } + + for i in 0..MAX_NEW_L2_TO_L1_MSGS_PER_TX { + fields.extend_from_array(self.new_l2_to_l1_msgs[i].serialize()); + } + + for i in 0..MAX_ENCRYPTED_LOGS_PER_TX { + fields.extend_from_array(self.encrypted_logs_hashes[i].serialize()); + } + + for i in 0..MAX_UNENCRYPTED_LOGS_PER_TX { + fields.extend_from_array(self.unencrypted_logs_hashes[i].serialize()); + } + + fields.push(self.encrypted_log_preimages_length); + fields.push(self.unencrypted_log_preimages_length); + + for i in 0..MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX { + fields.extend_from_array(self.private_call_stack[i].serialize()); + } + + for i in 0..MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX { + fields.extend_from_array(self.public_call_stack[i].serialize()); + } + + assert_eq(fields.len(), PRIVATE_ACCUMULATED_DATA_LENGTH); + + fields.storage + } +} diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/call_request.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/call_request.nr index 8eca6227d7c..140b1967ca7 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/call_request.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/call_request.nr @@ -1,7 +1,8 @@ use crate::address::AztecAddress; use dep::std::cmp::Eq; -use crate::traits::Empty; +use crate::traits::{Empty, Serialize}; use crate::abis::caller_context::CallerContext; +use crate::constants::CALL_REQUEST_LENGTH; struct CallRequest { hash: Field, @@ -38,3 +39,19 @@ impl CallRequest { self.hash == 0 } } + +impl Serialize for CallRequest { + fn serialize(self) -> [Field; CALL_REQUEST_LENGTH] { + let mut fields: BoundedVec = BoundedVec::new(); + + fields.push(self.hash); + fields.extend_from_array(self.caller_contract_address.serialize()); + fields.extend_from_array(self.caller_context.serialize()); + fields.push(self.start_side_effect_counter as Field); + fields.push(self.end_side_effect_counter as Field); + + assert_eq(fields.len(), CALL_REQUEST_LENGTH); + + fields.storage + } +} diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/caller_context.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/caller_context.nr index 829429e4e9e..70c929fc04a 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/caller_context.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/caller_context.nr @@ -1,6 +1,7 @@ use crate::address::AztecAddress; use dep::std::cmp::Eq; -use crate::traits::Empty; +use crate::traits::{Empty, Serialize}; +use crate::constants::CALLER_CONTEXT_LENGTH; struct CallerContext { msg_sender: AztecAddress, @@ -28,3 +29,16 @@ impl CallerContext { self.msg_sender.is_zero() & self.storage_contract_address.is_zero() } } + +impl Serialize for CallerContext { + fn serialize(self) -> [Field; CALLER_CONTEXT_LENGTH] { + let mut fields: BoundedVec = BoundedVec::new(); + + fields.extend_from_array(self.msg_sender.serialize()); + fields.extend_from_array(self.storage_contract_address.serialize()); + + assert_eq(fields.len(), CALLER_CONTEXT_LENGTH); + + fields.storage + } +} diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/combined_constant_data.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/combined_constant_data.nr index 0d823df58d2..2fcd910a23b 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/combined_constant_data.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/combined_constant_data.nr @@ -1,7 +1,8 @@ use crate::transaction::tx_context::TxContext; use crate::header::Header; -use crate::traits::Empty; +use crate::traits::{Empty, Serialize}; use crate::abis::global_variables::GlobalVariables; +use crate::constants::COMBINED_CONSTANT_DATA_LENGTH; struct CombinedConstantData { historical_header: Header, @@ -29,3 +30,17 @@ impl Empty for CombinedConstantData { } } } + +impl Serialize for CombinedConstantData { + fn serialize(self) -> [Field; COMBINED_CONSTANT_DATA_LENGTH] { + let mut fields: BoundedVec = BoundedVec::new(); + + fields.extend_from_array(self.historical_header.serialize()); + fields.extend_from_array(self.tx_context.serialize()); + fields.extend_from_array(self.global_variables.serialize()); + + assert_eq(fields.len(), COMBINED_CONSTANT_DATA_LENGTH); + + fields.storage + } +} diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/kernel_circuit_public_inputs.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/kernel_circuit_public_inputs.nr index 5584918af23..5256f275a3e 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/kernel_circuit_public_inputs.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/kernel_circuit_public_inputs.nr @@ -8,7 +8,6 @@ use crate::{ use crate::mocked::AggregationObject; struct KernelCircuitPublicInputs { - aggregation_object: AggregationObject, rollup_validation_requests: RollupValidationRequests, end: CombinedAccumulatedData, constants: CombinedConstantData, @@ -28,7 +27,6 @@ impl KernelCircuitPublicInputs { impl Empty for KernelCircuitPublicInputs { fn empty() -> Self { KernelCircuitPublicInputs { - aggregation_object: AggregationObject::empty(), rollup_validation_requests: RollupValidationRequests::empty(), end: CombinedAccumulatedData::empty(), constants: CombinedConstantData::empty(), @@ -56,7 +54,6 @@ mod tests { #[test] unconstrained fn non_empty_gas_and_fee() { let mut inputs = KernelCircuitPublicInputs { - aggregation_object: AggregationObject::empty(), rollup_validation_requests: RollupValidationRequests::empty(), end: CombinedAccumulatedData::empty(), constants: CombinedConstantData::empty(), diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/private_kernel_circuit_public_inputs.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/private_kernel_circuit_public_inputs.nr index 6715590d341..e7aee9e9d52 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/private_kernel_circuit_public_inputs.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/private_kernel_circuit_public_inputs.nr @@ -2,13 +2,29 @@ use crate::abis::{ accumulated_data::PrivateAccumulatedData, combined_constant_data::CombinedConstantData, validation_requests::ValidationRequests, call_request::CallRequest }; -use crate::mocked::AggregationObject; +use crate::constants::PRIVATE_KERNEL_CIRCUIT_PUBLIC_INPUTS_LENGTH; +use crate::traits::Serialize; struct PrivateKernelCircuitPublicInputs { - aggregation_object: AggregationObject, min_revertible_side_effect_counter: u32, validation_requests: ValidationRequests, end: PrivateAccumulatedData, constants: CombinedConstantData, public_teardown_call_request: CallRequest, } + +impl Serialize for PrivateKernelCircuitPublicInputs { + fn serialize(self) -> [Field; PRIVATE_KERNEL_CIRCUIT_PUBLIC_INPUTS_LENGTH] { + let mut fields: BoundedVec = BoundedVec::new(); + + fields.push(self.min_revertible_side_effect_counter as Field); + fields.extend_from_array(self.validation_requests.serialize()); + fields.extend_from_array(self.end.serialize()); + fields.extend_from_array(self.constants.serialize()); + fields.extend_from_array(self.public_teardown_call_request.serialize()); + + assert_eq(fields.len(), PRIVATE_KERNEL_CIRCUIT_PUBLIC_INPUTS_LENGTH); + + fields.storage + } +} diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/private_kernel_circuit_public_inputs_builder.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/private_kernel_circuit_public_inputs_builder.nr index a6424f53c89..aa137a82225 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/private_kernel_circuit_public_inputs_builder.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/private_kernel_circuit_public_inputs_builder.nr @@ -17,7 +17,6 @@ use crate::{ // .finish_tail: KernelCircuitPublicInputs (from KernelCircuitPublicInputsComposer) // .finish_to_public: PublicKernelCircuitPublicInputs (from KernelCircuitPublicInputsComposer) struct PrivateKernelCircuitPublicInputsBuilder { - aggregation_object: AggregationObject, min_revertible_side_effect_counter: u32, validation_requests: ValidationRequestsBuilder, end: PrivateAccumulatedDataBuilder, @@ -28,7 +27,6 @@ struct PrivateKernelCircuitPublicInputsBuilder { impl PrivateKernelCircuitPublicInputsBuilder { pub fn finish(self) -> PrivateKernelCircuitPublicInputs { PrivateKernelCircuitPublicInputs { - aggregation_object: self.aggregation_object, min_revertible_side_effect_counter: self.min_revertible_side_effect_counter, validation_requests: self.validation_requests.finish(), end: self.end.finish(), @@ -39,7 +37,6 @@ impl PrivateKernelCircuitPublicInputsBuilder { pub fn finish_tail(self, teardown_gas: Gas) -> KernelCircuitPublicInputs { KernelCircuitPublicInputs { - aggregation_object: self.aggregation_object, rollup_validation_requests: self.validation_requests.to_rollup(), end: self.end.to_combined(teardown_gas), constants: self.constants, @@ -56,7 +53,6 @@ impl PrivateKernelCircuitPublicInputsBuilder { let (end_non_revertible, end) = self.end.split_to_public(min_revertible_side_effect_counter, teardown_gas); PublicKernelCircuitPublicInputs { - aggregation_object: self.aggregation_object, validation_requests: self.validation_requests.finish(), end_non_revertible, end, @@ -70,7 +66,6 @@ impl PrivateKernelCircuitPublicInputsBuilder { impl Empty for PrivateKernelCircuitPublicInputsBuilder { fn empty() -> Self { PrivateKernelCircuitPublicInputsBuilder { - aggregation_object: AggregationObject::empty(), min_revertible_side_effect_counter: 0 as u32, validation_requests: ValidationRequestsBuilder::empty(), end: PrivateAccumulatedDataBuilder::empty(), diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/public_kernel_circuit_public_inputs.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/public_kernel_circuit_public_inputs.nr index 4687e3de77c..8e8e4d62045 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/public_kernel_circuit_public_inputs.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/public_kernel_circuit_public_inputs.nr @@ -2,10 +2,8 @@ use crate::abis::{ accumulated_data::PublicAccumulatedData, combined_constant_data::CombinedConstantData, validation_requests::{RollupValidationRequests, ValidationRequests}, call_request::CallRequest }; -use crate::mocked::AggregationObject; struct PublicKernelCircuitPublicInputs { - aggregation_object: AggregationObject, validation_requests: ValidationRequests, end_non_revertible: PublicAccumulatedData, end: PublicAccumulatedData, diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/public_kernel_circuit_public_inputs_builder.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/public_kernel_circuit_public_inputs_builder.nr index 824f595430e..41f92bd5f22 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/public_kernel_circuit_public_inputs_builder.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/public_kernel_circuit_public_inputs_builder.nr @@ -4,12 +4,10 @@ use crate::{ combined_constant_data::CombinedConstantData, kernel_circuit_public_inputs::{public_kernel_circuit_public_inputs::PublicKernelCircuitPublicInputs}, validation_requests::ValidationRequestsBuilder, call_request::CallRequest -}, - mocked::AggregationObject, traits::Empty +}, traits::Empty }; struct PublicKernelCircuitPublicInputsBuilder { - aggregation_object: AggregationObject, validation_requests: ValidationRequestsBuilder, end_non_revertible: PublicAccumulatedDataBuilder, end: PublicAccumulatedDataBuilder, @@ -21,7 +19,6 @@ struct PublicKernelCircuitPublicInputsBuilder { impl PublicKernelCircuitPublicInputsBuilder { pub fn finish(self) -> PublicKernelCircuitPublicInputs { PublicKernelCircuitPublicInputs { - aggregation_object: self.aggregation_object, // Note that we're including both the validation_requests AND the rollup_validation requests, because this // struct is used as an input for both the public kernel and base rollup circuits. In the near future the // base rollup will only receive rollup_validation_requests, and the public kernel only validation_requests. @@ -38,7 +35,6 @@ impl PublicKernelCircuitPublicInputsBuilder { impl Empty for PublicKernelCircuitPublicInputsBuilder { fn empty() -> Self { PublicKernelCircuitPublicInputsBuilder { - aggregation_object: AggregationObject::empty(), validation_requests: ValidationRequestsBuilder::empty(), end_non_revertible: PublicAccumulatedDataBuilder::empty(), end: PublicAccumulatedDataBuilder::empty(), diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_data.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_data.nr index f0dd35e98b1..6bdbbb4d4a5 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_data.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_data.nr @@ -1,28 +1,6 @@ use crate::mocked::{Proof, VerificationKey}; use crate::constants::VK_TREE_HEIGHT; -use crate::abis::kernel_circuit_public_inputs::{PrivateKernelCircuitPublicInputs, PublicKernelCircuitPublicInputs, KernelCircuitPublicInputs}; - -struct PrivateKernelData { - // TODO(David): Left a note asking if we need this due to it - // already being in the proof. - public_inputs: PrivateKernelCircuitPublicInputs, - - // TODO(David): Mentions the dichotomy between a proof created for the - // circuit, which is a sequence of field elements, versus a proof - // created for solidity/native verification which is a collection of bytes. - // Kev: I've been questioning if we _need_ the sequence of field elements. - // It makes verification cheaper, though I have not tested how much cheaper. - // Removing it would also reduce complexity on the Noir side, as we have - // special methods to convert "inner proofs" into sequence of field elements. - proof: Proof, - - vk: VerificationKey, - - // TODO(Mike): left a note saying : this index and path are meant to be those of a leaf within the tree of _kernel circuit_ vks; not the tree - // of functions within the contract tree. - vk_index: u32, - vk_path: [Field; VK_TREE_HEIGHT], -} +use crate::abis::kernel_circuit_public_inputs::{PublicKernelCircuitPublicInputs, KernelCircuitPublicInputs}; struct PublicKernelData { public_inputs: PublicKernelCircuitPublicInputs, diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/private_kernel/private_call_data.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/private_kernel/private_call_data.nr index 760189375dd..7bca0c1d616 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/private_kernel/private_call_data.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/private_kernel/private_call_data.nr @@ -1,7 +1,10 @@ -use crate::abis::{call_request::CallRequest, private_call_stack_item::PrivateCallStackItem}; use crate::address::{SaltedInitializationHash, PublicKeysHash, EthAddress}; use crate::contract_class_id::ContractClassId; -use crate::mocked::{Proof, VerificationKey}; +use crate::recursion::{verification_key::VerificationKey, proof::RecursiveProof}; +use crate::abis::{ + call_request::CallRequest, private_call_stack_item::PrivateCallStackItem, + private_circuit_public_inputs::PrivateCircuitPublicInputs +}; use crate::constants::{MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL, MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL, FUNCTION_TREE_HEIGHT}; use crate::merkle_tree::membership::MembershipWitness; @@ -11,7 +14,7 @@ struct PrivateCallData { private_call_stack: [CallRequest; MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL], public_call_stack: [CallRequest; MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL], - proof: Proof, + proof: RecursiveProof, vk: VerificationKey, salted_initialization_hash: SaltedInitializationHash, @@ -22,3 +25,13 @@ struct PrivateCallData { acir_hash: Field, } + +fn verify_private_call(call: PrivateCallData) { + let inputs = PrivateCircuitPublicInputs::serialize(call.call_stack_item.public_inputs); + dep::std::verify_proof( + call.vk.key.as_slice(), + call.proof.fields.as_slice(), + inputs.as_slice(), + call.vk.hash + ); +} diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/private_kernel_data.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/private_kernel_data.nr new file mode 100644 index 00000000000..9e9564ebf25 --- /dev/null +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/private_kernel_data.nr @@ -0,0 +1,34 @@ +use crate::recursion::{verification_key::VerificationKey, proof::NestedRecursiveProof}; +use crate::constants::VK_TREE_HEIGHT; +use crate::abis::kernel_circuit_public_inputs::PrivateKernelCircuitPublicInputs; + +struct PrivateKernelData { + // TODO(David): Left a note asking if we need this due to it + // already being in the proof. + public_inputs: PrivateKernelCircuitPublicInputs, + + // TODO(David): Mentions the dichotomy between a proof created for the + // circuit, which is a sequence of field elements, versus a proof + // created for solidity/native verification which is a collection of bytes. + // Kev: I've been questioning if we _need_ the sequence of field elements. + // It makes verification cheaper, though I have not tested how much cheaper. + // Removing it would also reduce complexity on the Noir side, as we have + // special methods to convert "inner proofs" into sequence of field elements. + proof: NestedRecursiveProof, + vk: VerificationKey, + + // TODO(Mike): left a note saying : this index and path are meant to be those of a leaf within the tree of _kernel circuit_ vks; not the tree + // of functions within the contract tree. + vk_index: u32, + vk_path: [Field; VK_TREE_HEIGHT], +} + +fn verify_previous_kernel_proof(previous_kernel: PrivateKernelData) { + let inputs = PrivateKernelCircuitPublicInputs::serialize(previous_kernel.public_inputs); + dep::std::verify_proof( + previous_kernel.vk.key.as_slice(), + previous_kernel.proof.fields.as_slice(), + inputs.as_slice(), + previous_kernel.vk.hash + ); +} diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/public_data_read.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/public_data_read.nr index f790fe142c8..a434580019b 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/public_data_read.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/public_data_read.nr @@ -1,6 +1,6 @@ -use crate::constants::GENERATOR_INDEX__PUBLIC_DATA_READ; +use crate::constants::{GENERATOR_INDEX__PUBLIC_DATA_READ, PUBLIC_DATA_READ_LENGTH}; use dep::std::cmp::Eq; -use crate::traits::{Empty, Hash}; +use crate::traits::{Empty, Hash, Serialize}; struct PublicDataRead { leaf_slot : Field, @@ -36,3 +36,9 @@ impl PublicDataRead { (self.leaf_slot == 0) & (self.value == 0) } } + +impl Serialize for PublicDataRead { + fn serialize(self) -> [Field; PUBLIC_DATA_READ_LENGTH] { + [self.leaf_slot, self.value] + } +} diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/public_data_update_request.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/public_data_update_request.nr index 8177f389f18..ab887214acf 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/public_data_update_request.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/public_data_update_request.nr @@ -1,6 +1,6 @@ -use crate::constants::GENERATOR_INDEX__PUBLIC_DATA_UPDATE_REQUEST; +use crate::constants::{PUBLIC_DATA_UPDATE_REQUEST_LENGTH, GENERATOR_INDEX__PUBLIC_DATA_UPDATE_REQUEST}; use dep::std::cmp::Eq; -use crate::traits::{Empty, Hash}; +use crate::traits::{Empty, Hash, Serialize}; struct PublicDataUpdateRequest { leaf_slot : Field, @@ -37,3 +37,9 @@ impl PublicDataUpdateRequest { (self.leaf_slot == 0) & (self.new_value == 0) } } + +impl Serialize for PublicDataUpdateRequest { + fn serialize(self) -> [Field; PUBLIC_DATA_UPDATE_REQUEST_LENGTH] { + [self.leaf_slot, self.new_value] + } +} diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/read_request.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/read_request.nr index 9cac3dc5c88..6d3663354b0 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/read_request.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/read_request.nr @@ -1,11 +1,10 @@ use crate::{ - traits::{Empty, Serialize, Deserialize}, address::AztecAddress, constants::READ_REQUEST_LENGTH, + traits::{Empty, Serialize, Deserialize}, address::AztecAddress, + constants::{READ_REQUEST_LENGTH, SCOPED_READ_REQUEST_LEN}, utils::{arrays::array_concat, reader::Reader} }; use dep::std::cmp::Eq; -global SCOPED_READ_REQUEST_SERIALIZED_LEN = READ_REQUEST_LENGTH + 1; - struct ReadRequest { value: Field, counter: u32, @@ -69,14 +68,14 @@ impl Empty for ScopedReadRequest { } } -impl Serialize for ScopedReadRequest { - fn serialize(self) -> [Field; SCOPED_READ_REQUEST_SERIALIZED_LEN] { +impl Serialize for ScopedReadRequest { + fn serialize(self) -> [Field; SCOPED_READ_REQUEST_LEN] { array_concat(self.read_request.serialize(), [self.contract_address.to_field()]) } } -impl Deserialize for ScopedReadRequest { - fn deserialize(values: [Field; SCOPED_READ_REQUEST_SERIALIZED_LEN]) -> Self { +impl Deserialize for ScopedReadRequest { + fn deserialize(values: [Field; SCOPED_READ_REQUEST_LEN]) -> Self { let mut reader = Reader::new(values); let res = Self { read_request: reader.read_struct(ReadRequest::deserialize), diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/validation_requests/rollup_validation_requests.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/validation_requests/rollup_validation_requests.nr index 258167f0bbc..1840668e1b3 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/validation_requests/rollup_validation_requests.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/validation_requests/rollup_validation_requests.nr @@ -1,4 +1,4 @@ -use crate::{abis::max_block_number::MaxBlockNumber, traits::Empty}; +use crate::{abis::max_block_number::MaxBlockNumber, traits::{Empty, Serialize}, constants::ROLLUP_VALIDATION_REQUESTS_LENGTH}; // These are validation requests that cannot be fulfilled in the current context (private or public), and must be // instead forwarded to the rollup for it to take care of them. @@ -14,3 +14,9 @@ impl Empty for RollupValidationRequests { } } +impl Serialize for RollupValidationRequests { + fn serialize(self) -> [Field; ROLLUP_VALIDATION_REQUESTS_LENGTH] { + MaxBlockNumber::serialize(self.max_block_number) + } +} + diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/validation_requests/validation_requests.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/validation_requests/validation_requests.nr index 850afddbade..8d56adb7ea6 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/validation_requests/validation_requests.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/validation_requests/validation_requests.nr @@ -8,8 +8,8 @@ use crate::{ constants::{ MAX_NOTE_HASH_READ_REQUESTS_PER_TX, MAX_NULLIFIER_READ_REQUESTS_PER_TX, MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_TX, MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, - MAX_PUBLIC_DATA_READS_PER_TX -} + MAX_PUBLIC_DATA_READS_PER_TX, VALIDATION_REQUESTS_LENGTH +}, traits::Serialize }; // TODO - Use specific structs for private and public: PrivateValidationRequests vs PublicValidationRequests @@ -21,3 +21,35 @@ struct ValidationRequests { nullifier_key_validation_requests: [ScopedNullifierKeyValidationRequest; MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX], public_data_reads: [PublicDataRead; MAX_PUBLIC_DATA_READS_PER_TX], } + +impl Serialize for ValidationRequests { + fn serialize(self) -> [Field; VALIDATION_REQUESTS_LENGTH] { + let mut fields: BoundedVec = BoundedVec::new(); + + fields.extend_from_array(self.for_rollup.serialize()); + + for i in 0..MAX_NOTE_HASH_READ_REQUESTS_PER_TX { + fields.extend_from_array(self.note_hash_read_requests[i].serialize()); + } + + for i in 0..MAX_NULLIFIER_READ_REQUESTS_PER_TX { + fields.extend_from_array(self.nullifier_read_requests[i].serialize()); + } + + for i in 0..MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_TX { + fields.extend_from_array(self.nullifier_non_existent_read_requests[i].serialize()); + } + + for i in 0..MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX { + fields.extend_from_array(self.nullifier_key_validation_requests[i].serialize()); + } + + for i in 0..MAX_PUBLIC_DATA_READS_PER_TX { + fields.extend_from_array(self.public_data_reads[i].serialize()); + } + + assert_eq(fields.len(), VALIDATION_REQUESTS_LENGTH); + + fields.storage + } +} \ No newline at end of file diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr b/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr index 5e1631cc24d..84f47f12d87 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr @@ -167,6 +167,7 @@ global SCOPED_NOTE_HASH_LENGTH = NOTE_HASH_LENGTH + 2; global NULLIFIER_LENGTH = 3; global SCOPED_NULLIFIER_LENGTH = NULLIFIER_LENGTH + 1; global SIDE_EFFECT_LENGTH = 2; +global ROLLUP_VALIDATION_REQUESTS_LENGTH = MAX_BLOCK_NUMBER_LENGTH; global STATE_REFERENCE_LENGTH: u64 = APPEND_ONLY_TREE_SNAPSHOT_LENGTH + PARTIAL_STATE_REFERENCE_LENGTH; global TX_CONTEXT_LENGTH: u64 = 2 + GAS_SETTINGS_LENGTH; global TX_REQUEST_LENGTH: u64 = 2 + TX_CONTEXT_LENGTH + FUNCTION_DATA_LENGTH; @@ -175,6 +176,19 @@ global PRIVATE_CIRCUIT_PUBLIC_INPUTS_LENGTH: u64 = CALL_CONTEXT_LENGTH + 3 + MAX global PUBLIC_CIRCUIT_PUBLIC_INPUTS_LENGTH: u64 = CALL_CONTEXT_LENGTH + 2 + (READ_REQUEST_LENGTH * MAX_NULLIFIER_READ_REQUESTS_PER_CALL) + (READ_REQUEST_LENGTH * MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_CALL) + (CONTRACT_STORAGE_UPDATE_REQUEST_LENGTH * MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_CALL) + (CONTRACT_STORAGE_READ_LENGTH * MAX_PUBLIC_DATA_READS_PER_CALL) + MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL + (NOTE_HASH_LENGTH * MAX_NEW_NOTE_HASHES_PER_CALL) + (NULLIFIER_LENGTH * MAX_NEW_NULLIFIERS_PER_CALL) + (L2_TO_L1_MESSAGE_LENGTH * MAX_NEW_L2_TO_L1_MSGS_PER_CALL) + 2 + (SIDE_EFFECT_LENGTH * MAX_UNENCRYPTED_LOGS_PER_CALL) + 1 + HEADER_LENGTH + GLOBAL_VARIABLES_LENGTH + AZTEC_ADDRESS_LENGTH + /* revert_code */ 1 + 2 * GAS_LENGTH + /* transaction_fee */ 1; global PRIVATE_CALL_STACK_ITEM_LENGTH: u64 = AZTEC_ADDRESS_LENGTH + FUNCTION_DATA_LENGTH + PRIVATE_CIRCUIT_PUBLIC_INPUTS_LENGTH; +global SCOPED_READ_REQUEST_LEN = READ_REQUEST_LENGTH + 1; +global PUBLIC_DATA_READ_LENGTH = 2; +global VALIDATION_REQUESTS_LENGTH = ROLLUP_VALIDATION_REQUESTS_LENGTH + (SCOPED_READ_REQUEST_LEN * MAX_NOTE_HASH_READ_REQUESTS_PER_TX) + (SCOPED_READ_REQUEST_LEN * MAX_NULLIFIER_READ_REQUESTS_PER_TX) + (SCOPED_READ_REQUEST_LEN * MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_TX) + (SCOPED_NULLIFIER_KEY_VALIDATION_REQUEST_LENGTH * MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX) + (PUBLIC_DATA_READ_LENGTH * MAX_PUBLIC_DATA_READS_PER_TX); + +global PUBLIC_DATA_UPDATE_REQUEST_LENGTH = 2; +global COMBINED_ACCUMULATED_DATA_LENGTH = MAX_NEW_NOTE_HASHES_PER_TX + MAX_NEW_NULLIFIERS_PER_TX + MAX_NEW_L2_TO_L1_MSGS_PER_TX + 4 + (MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX * PUBLIC_DATA_UPDATE_REQUEST_LENGTH) + GAS_LENGTH; +global COMBINED_CONSTANT_DATA_LENGTH = HEADER_LENGTH + TX_CONTEXT_LENGTH + GLOBAL_VARIABLES_LENGTH; + +global CALLER_CONTEXT_LENGTH = 2 * AZTEC_ADDRESS_LENGTH; +global CALL_REQUEST_LENGTH = 1 + AZTEC_ADDRESS_LENGTH + CALLER_CONTEXT_LENGTH + 2; +global PRIVATE_ACCUMULATED_DATA_LENGTH = (SCOPED_NOTE_HASH_LENGTH * MAX_NEW_NOTE_HASHES_PER_TX) + (SCOPED_NULLIFIER_LENGTH * MAX_NEW_NULLIFIERS_PER_TX) + (MAX_NEW_L2_TO_L1_MSGS_PER_TX * SCOPED_L2_TO_L1_MESSAGE_LENGTH) + (SIDE_EFFECT_LENGTH * MAX_ENCRYPTED_LOGS_PER_TX) + (SIDE_EFFECT_LENGTH * MAX_UNENCRYPTED_LOGS_PER_TX) + 2 + (CALL_REQUEST_LENGTH * MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX) + (CALL_REQUEST_LENGTH * MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX); +global PRIVATE_KERNEL_CIRCUIT_PUBLIC_INPUTS_LENGTH = 1 + VALIDATION_REQUESTS_LENGTH + PRIVATE_ACCUMULATED_DATA_LENGTH + COMBINED_CONSTANT_DATA_LENGTH + CALL_REQUEST_LENGTH; + global ENQUEUE_PUBLIC_FUNCTION_CALL_RETURN_LENGTH: u64 = 2 + FUNCTION_DATA_LENGTH + CALL_CONTEXT_LENGTH; global GET_NOTES_ORACLE_RETURN_LENGTH: u64 = 674; global NOTE_HASHES_NUM_BYTES_PER_BASE_ROLLUP: Field = 2048; diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/hash.nr b/noir-projects/noir-protocol-circuits/crates/types/src/hash.nr index efb7f6b38c3..b6efc83586f 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/hash.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/hash.nr @@ -1,5 +1,5 @@ use crate::address::{AztecAddress, EthAddress}; -use crate::mocked::VerificationKey; +use crate::recursion::verification_key::VerificationKey; use crate::abis::function_selector::FunctionSelector; use crate::abis::contract_class_function_leaf_preimage::ContractClassFunctionLeafPreimage; use crate::contract_class_id::ContractClassId; diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/tests/fixture_builder.nr b/noir-projects/noir-protocol-circuits/crates/types/src/tests/fixture_builder.nr index 077007c2b5a..b0f043c80ab 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/tests/fixture_builder.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/tests/fixture_builder.nr @@ -5,8 +5,9 @@ use crate::{ accumulated_data::{CombinedAccumulatedData, PrivateAccumulatedData, PrivateAccumulatedDataBuilder, PublicAccumulatedData}, global_variables::GlobalVariables, combined_constant_data::CombinedConstantData, kernel_circuit_public_inputs::{KernelCircuitPublicInputs, PrivateKernelCircuitPublicInputs, PublicKernelCircuitPublicInputs}, - kernel_data::{PrivateKernelData, PublicKernelData, KernelData}, max_block_number::MaxBlockNumber, - note_hash::{NoteHash, ScopedNoteHash}, nullifier::{Nullifier, ScopedNullifier}, + kernel_data::{PublicKernelData, KernelData}, max_block_number::MaxBlockNumber, + private_kernel_data::PrivateKernelData, note_hash::{NoteHash, ScopedNoteHash}, + nullifier::{Nullifier, ScopedNullifier}, nullifier_key_validation_request::ScopedNullifierKeyValidationRequest, public_data_read::PublicDataRead, public_data_update_request::PublicDataUpdateRequest, read_request::{ReadRequest, ScopedReadRequest}, side_effect::SideEffect, @@ -23,8 +24,8 @@ use crate::{ }, hash::silo_nullifier, header::Header, messaging::l2_to_l1_message::{L2ToL1Message, ScopedL2ToL1Message}, - mocked::{AggregationObject, Proof, VerificationKey}, partial_state_reference::PartialStateReference, - tests::fixtures, transaction::tx_context::TxContext, traits::Empty + partial_state_reference::PartialStateReference, tests::fixtures, transaction::tx_context::TxContext, + traits::Empty, recursion::{verification_key::VerificationKey, proof::NestedRecursiveProof} }; struct FixtureBuilder { @@ -62,7 +63,7 @@ struct FixtureBuilder { public_data_reads: BoundedVec, // Proof. - proof: Proof, + proof: NestedRecursiveProof, vk: VerificationKey, vk_index: u32, vk_path: [Field; VK_TREE_HEIGHT], @@ -103,8 +104,8 @@ impl FixtureBuilder { nullifier_non_existent_read_requests: BoundedVec::new(), nullifier_key_validation_requests: BoundedVec::new(), public_data_reads: BoundedVec::new(), - proof: Proof {}, - vk: VerificationKey {}, + proof: NestedRecursiveProof::empty(), + vk: VerificationKey::empty(), vk_index: 0, vk_path: [0; VK_TREE_HEIGHT], revert_code: 0, @@ -188,7 +189,6 @@ impl FixtureBuilder { let constants = self.to_constant_data(); PrivateKernelCircuitPublicInputs { - aggregation_object: AggregationObject {}, min_revertible_side_effect_counter: self.min_revertible_side_effect_counter, end, validation_requests, @@ -218,7 +218,6 @@ impl FixtureBuilder { let constants = self.to_constant_data(); PublicKernelCircuitPublicInputs { - aggregation_object: AggregationObject {}, end_non_revertible, end, validation_requests, @@ -230,7 +229,13 @@ impl FixtureBuilder { pub fn to_public_kernel_data(self, revertible: bool) -> PublicKernelData { let public_inputs = self.to_public_kernel_circuit_public_inputs(revertible); - PublicKernelData { public_inputs, proof: self.proof, vk: self.vk, vk_index: self.vk_index, vk_path: self.vk_path } + PublicKernelData { + public_inputs, + proof: crate::mocked::Proof::empty(), + vk: crate::mocked::VerificationKey::empty(), + vk_index: self.vk_index, + vk_path: self.vk_path + } } pub fn to_kernel_circuit_public_inputs(self) -> KernelCircuitPublicInputs { @@ -238,19 +243,18 @@ impl FixtureBuilder { let end = self.to_combined_accumulated_data(); let constants = self.to_constant_data(); - KernelCircuitPublicInputs { - aggregation_object: AggregationObject {}, - rollup_validation_requests, - end, - constants, - start_state: self.start_state, - revert_code: self.revert_code - } + KernelCircuitPublicInputs { rollup_validation_requests, end, constants, start_state: self.start_state, revert_code: self.revert_code } } pub fn to_kernel_data(self) -> KernelData { let public_inputs = self.to_kernel_circuit_public_inputs(); - KernelData { public_inputs, proof: self.proof, vk: self.vk, vk_index: self.vk_index, vk_path: self.vk_path } + KernelData { + public_inputs, + proof: crate::mocked::Proof::empty(), + vk: crate::mocked::VerificationKey::empty(), + vk_index: self.vk_index, + vk_path: self.vk_path + } } pub fn add_new_note_hash(&mut self, value: Field) { @@ -483,7 +487,7 @@ impl Empty for FixtureBuilder { nullifier_non_existent_read_requests: BoundedVec::new(), nullifier_key_validation_requests: BoundedVec::new(), public_data_reads: BoundedVec::new(), - proof: Proof::empty(), + proof: NestedRecursiveProof::empty(), vk: VerificationKey::empty(), vk_index: 0, vk_path: [0; VK_TREE_HEIGHT], diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/tests/private_call_data_builder.nr b/noir-projects/noir-protocol-circuits/crates/types/src/tests/private_call_data_builder.nr index a4c6a52930e..44d060051a9 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/tests/private_call_data_builder.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/tests/private_call_data_builder.nr @@ -7,7 +7,7 @@ use crate::{ }, merkle_tree::membership::MembershipWitness, address::{AztecAddress, EthAddress, SaltedInitializationHash, PublicKeysHash}, - mocked::{Proof, VerificationKey}, + recursion::{proof::RecursiveProof, verification_key::VerificationKey}, tests::{fixtures, private_circuit_public_inputs_builder::PrivateCircuitPublicInputsBuilder}, transaction::{tx_request::TxRequest, tx_context::TxContext} }; @@ -22,7 +22,7 @@ struct PrivateCallDataBuilder { // The rest of the values of PrivateCallData. private_call_stack: BoundedVec, public_call_stack: BoundedVec, - proof: Proof, + proof: RecursiveProof, vk: VerificationKey, salted_initialization_hash: SaltedInitializationHash, public_keys_hash: PublicKeysHash, @@ -48,8 +48,8 @@ impl PrivateCallDataBuilder { function_data, private_call_stack: BoundedVec::new(), public_call_stack: BoundedVec::new(), - proof: Proof {}, - vk: VerificationKey {}, + proof: RecursiveProof::empty(), + vk: VerificationKey::empty(), function_leaf_membership_witness: contract_function.membership_witness, salted_initialization_hash: contract_data.salted_initialization_hash, public_keys_hash: contract_data.public_keys_hash, diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_black_box.rs b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_black_box.rs index d982d864d06..d587abc9463 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_black_box.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_black_box.rs @@ -233,9 +233,7 @@ pub(crate) fn convert_black_box_call( BlackBoxFunc::RANGE => unreachable!( "ICE: `BlackBoxFunc::RANGE` calls should be transformed into a `Instruction::Cast`" ), - BlackBoxFunc::RecursiveAggregation => unimplemented!( - "ICE: `BlackBoxFunc::RecursiveAggregation` is not implemented by the Brillig VM" - ), + BlackBoxFunc::RecursiveAggregation => {} BlackBoxFunc::BigIntAdd => { if let ( [BrilligVariable::SingleAddr(lhs), BrilligVariable::SingleAddr(lhs_modulus), BrilligVariable::SingleAddr(rhs), BrilligVariable::SingleAddr(rhs_modulus)], diff --git a/yarn-project/circuits.js/src/constants.gen.ts b/yarn-project/circuits.js/src/constants.gen.ts index 8e143fd70ca..e15a83aa388 100644 --- a/yarn-project/circuits.js/src/constants.gen.ts +++ b/yarn-project/circuits.js/src/constants.gen.ts @@ -110,6 +110,7 @@ export const SCOPED_NOTE_HASH_LENGTH = NOTE_HASH_LENGTH + 2; export const NULLIFIER_LENGTH = 3; export const SCOPED_NULLIFIER_LENGTH = NULLIFIER_LENGTH + 1; export const SIDE_EFFECT_LENGTH = 2; +export const ROLLUP_VALIDATION_REQUESTS_LENGTH = MAX_BLOCK_NUMBER_LENGTH; export const STATE_REFERENCE_LENGTH = APPEND_ONLY_TREE_SNAPSHOT_LENGTH + PARTIAL_STATE_REFERENCE_LENGTH; export const TX_CONTEXT_LENGTH = 2 + GAS_SETTINGS_LENGTH; export const TX_REQUEST_LENGTH = 2 + TX_CONTEXT_LENGTH + FUNCTION_DATA_LENGTH; @@ -156,6 +157,41 @@ export const PUBLIC_CIRCUIT_PUBLIC_INPUTS_LENGTH = /* transaction_fee */ 1; export const PRIVATE_CALL_STACK_ITEM_LENGTH = AZTEC_ADDRESS_LENGTH + FUNCTION_DATA_LENGTH + PRIVATE_CIRCUIT_PUBLIC_INPUTS_LENGTH; +export const SCOPED_READ_REQUEST_LEN = READ_REQUEST_LENGTH + 1; +export const PUBLIC_DATA_READ_LENGTH = 2; +export const VALIDATION_REQUESTS_LENGTH = + ROLLUP_VALIDATION_REQUESTS_LENGTH + + SCOPED_READ_REQUEST_LEN * MAX_NOTE_HASH_READ_REQUESTS_PER_TX + + SCOPED_READ_REQUEST_LEN * MAX_NULLIFIER_READ_REQUESTS_PER_TX + + SCOPED_READ_REQUEST_LEN * MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_TX + + SCOPED_NULLIFIER_KEY_VALIDATION_REQUEST_LENGTH * MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX + + PUBLIC_DATA_READ_LENGTH * MAX_PUBLIC_DATA_READS_PER_TX; +export const PUBLIC_DATA_UPDATE_REQUEST_LENGTH = 2; +export const COMBINED_ACCUMULATED_DATA_LENGTH = + MAX_NEW_NOTE_HASHES_PER_TX + + MAX_NEW_NULLIFIERS_PER_TX + + MAX_NEW_L2_TO_L1_MSGS_PER_TX + + 4 + + MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX * PUBLIC_DATA_UPDATE_REQUEST_LENGTH + + GAS_LENGTH; +export const COMBINED_CONSTANT_DATA_LENGTH = HEADER_LENGTH + TX_CONTEXT_LENGTH + GLOBAL_VARIABLES_LENGTH; +export const CALLER_CONTEXT_LENGTH = 2 * AZTEC_ADDRESS_LENGTH; +export const CALL_REQUEST_LENGTH = 1 + AZTEC_ADDRESS_LENGTH + CALLER_CONTEXT_LENGTH + 2; +export const PRIVATE_ACCUMULATED_DATA_LENGTH = + SCOPED_NOTE_HASH_LENGTH * MAX_NEW_NOTE_HASHES_PER_TX + + SCOPED_NULLIFIER_LENGTH * MAX_NEW_NULLIFIERS_PER_TX + + MAX_NEW_L2_TO_L1_MSGS_PER_TX * SCOPED_L2_TO_L1_MESSAGE_LENGTH + + SIDE_EFFECT_LENGTH * MAX_ENCRYPTED_LOGS_PER_TX + + SIDE_EFFECT_LENGTH * MAX_UNENCRYPTED_LOGS_PER_TX + + 2 + + CALL_REQUEST_LENGTH * MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX + + CALL_REQUEST_LENGTH * MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX; +export const PRIVATE_KERNEL_CIRCUIT_PUBLIC_INPUTS_LENGTH = + 1 + + VALIDATION_REQUESTS_LENGTH + + PRIVATE_ACCUMULATED_DATA_LENGTH + + COMBINED_CONSTANT_DATA_LENGTH + + CALL_REQUEST_LENGTH; export const ENQUEUE_PUBLIC_FUNCTION_CALL_RETURN_LENGTH = 2 + FUNCTION_DATA_LENGTH + CALL_CONTEXT_LENGTH; export const GET_NOTES_ORACLE_RETURN_LENGTH = 674; export const NOTE_HASHES_NUM_BYTES_PER_BASE_ROLLUP = 2048; diff --git a/yarn-project/circuits.js/src/structs/kernel/private_call_data.ts b/yarn-project/circuits.js/src/structs/kernel/private_call_data.ts index 689f2d1d297..1b492da9c87 100644 --- a/yarn-project/circuits.js/src/structs/kernel/private_call_data.ts +++ b/yarn-project/circuits.js/src/structs/kernel/private_call_data.ts @@ -6,12 +6,13 @@ import { FUNCTION_TREE_HEIGHT, MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL, MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL, + RECURSIVE_PROOF_LENGTH, } from '../../constants.gen.js'; import { CallRequest } from '../call_request.js'; import { MembershipWitness } from '../membership_witness.js'; import { PrivateCallStackItem } from '../private_call_stack_item.js'; -import { Proof } from '../proof.js'; -import { VerificationKey } from '../verification_key.js'; +import { RecursiveProof } from '../recursive_proof.js'; +import { VerificationKeyAsFields } from '../verification_key.js'; /** * Private call data. @@ -33,11 +34,11 @@ export class PrivateCallData { /** * The proof of the execution of this private call. */ - public proof: Proof, + public proof: RecursiveProof, /** * The verification key for the function being invoked. */ - public vk: VerificationKey, + public vk: VerificationKeyAsFields, /** * Artifact hash of the contract class for this private call. */ @@ -108,8 +109,8 @@ export class PrivateCallData { reader.readObject(PrivateCallStackItem), reader.readArray(MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL, CallRequest), reader.readArray(MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL, CallRequest), - reader.readObject(Proof), - reader.readObject(VerificationKey), + RecursiveProof.fromBuffer(reader, RECURSIVE_PROOF_LENGTH), + reader.readObject(VerificationKeyAsFields), reader.readObject(Fr), reader.readObject(Fr), reader.readObject(Fr), diff --git a/yarn-project/circuits.js/src/structs/kernel/private_kernel_data.ts b/yarn-project/circuits.js/src/structs/kernel/private_kernel_data.ts index d7310402ee4..6293bfad56e 100644 --- a/yarn-project/circuits.js/src/structs/kernel/private_kernel_data.ts +++ b/yarn-project/circuits.js/src/structs/kernel/private_kernel_data.ts @@ -2,10 +2,10 @@ import { makeTuple } from '@aztec/foundation/array'; import { Fr } from '@aztec/foundation/fields'; import { BufferReader, type Tuple, serializeToBuffer } from '@aztec/foundation/serialize'; -import { VK_TREE_HEIGHT } from '../../constants.gen.js'; -import { Proof, makeEmptyProof } from '../proof.js'; +import { NESTED_RECURSIVE_PROOF_LENGTH, VK_TREE_HEIGHT } from '../../constants.gen.js'; +import { RecursiveProof, makeRecursiveProof } from '../recursive_proof.js'; import { type UInt32 } from '../shared.js'; -import { VerificationKey } from '../verification_key.js'; +import { VerificationKeyAsFields } from '../verification_key.js'; import { PrivateKernelCircuitPublicInputs } from './private_kernel_circuit_public_inputs.js'; /** @@ -20,11 +20,11 @@ export class PrivateKernelData { /** * Proof of the previous kernel. */ - public proof: Proof, + public proof: RecursiveProof, /** * Verification key of the previous kernel. */ - public vk: VerificationKey, + public vk: VerificationKeyAsFields, /** * Index of the previous kernel's vk in a tree of vks. */ @@ -47,8 +47,8 @@ export class PrivateKernelData { const reader = BufferReader.asReader(buffer); return new this( reader.readObject(PrivateKernelCircuitPublicInputs), - reader.readObject(Proof), - reader.readObject(VerificationKey), + RecursiveProof.fromBuffer(reader, NESTED_RECURSIVE_PROOF_LENGTH), + reader.readObject(VerificationKeyAsFields), reader.readNumber(), reader.readArray(VK_TREE_HEIGHT, Fr), ); @@ -57,8 +57,8 @@ export class PrivateKernelData { static empty(): PrivateKernelData { return new PrivateKernelData( PrivateKernelCircuitPublicInputs.empty(), - makeEmptyProof(), - VerificationKey.makeFake(), + makeRecursiveProof(NESTED_RECURSIVE_PROOF_LENGTH), + VerificationKeyAsFields.makeFake(), 0, makeTuple(VK_TREE_HEIGHT, Fr.zero), ); diff --git a/yarn-project/circuits.js/src/structs/verification_key.ts b/yarn-project/circuits.js/src/structs/verification_key.ts index b7f47e23162..e617e48f7a9 100644 --- a/yarn-project/circuits.js/src/structs/verification_key.ts +++ b/yarn-project/circuits.js/src/structs/verification_key.ts @@ -108,6 +108,14 @@ export class VerificationKeyAsFields { static makeFake(seed = 1): VerificationKeyAsFields { return new VerificationKeyAsFields(makeTuple(VERIFICATION_KEY_LENGTH_IN_FIELDS, Fr.random, seed), Fr.random()); } + + /** + * Builds an 'empty' verification key + * @returns An 'empty' verification key + */ + static makeEmpty(): VerificationKeyAsFields { + return new VerificationKeyAsFields(makeTuple(VERIFICATION_KEY_LENGTH_IN_FIELDS, Fr.zero), Fr.zero()); + } } export class VerificationKey { diff --git a/yarn-project/circuits.js/src/tests/factories.ts b/yarn-project/circuits.js/src/tests/factories.ts index 6dc5712a2fa..90208fa660a 100644 --- a/yarn-project/circuits.js/src/tests/factories.ts +++ b/yarn-project/circuits.js/src/tests/factories.ts @@ -729,8 +729,8 @@ export function makePrivateCallData(seed = 1): PrivateCallData { callStackItem: makePrivateCallStackItem(seed), privateCallStack: makeTuple(MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL, makeCallRequest, seed + 0x10), publicCallStack: makeTuple(MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL, makeCallRequest, seed + 0x20), - proof: new Proof(Buffer.alloc(16).fill(seed + 0x50)), - vk: makeVerificationKey(), + proof: makeRecursiveProof(RECURSIVE_PROOF_LENGTH, seed + 0x50), + vk: makeVerificationKeyAsFields(), contractClassArtifactHash: fr(seed + 0x70), contractClassPublicBytecodeCommitment: fr(seed + 0x71), publicKeysHash: fr(seed + 0x72), diff --git a/yarn-project/end-to-end/src/client_prover_integration/client_prover_integration.test.ts b/yarn-project/end-to-end/src/client_prover_integration/client_prover_integration.test.ts index ed244b2da64..2cda2f3aa0c 100644 --- a/yarn-project/end-to-end/src/client_prover_integration/client_prover_integration.test.ts +++ b/yarn-project/end-to-end/src/client_prover_integration/client_prover_integration.test.ts @@ -5,7 +5,7 @@ import { type BBNativeProofCreator } from '@aztec/pxe'; import { ClientProverTest } from './client_prover_test.js'; async function verifyProof(circuitType: ClientProtocolArtifact, tx: Tx, proofCreator: BBNativeProofCreator) { - await expect(proofCreator.verifyProof(circuitType, tx.proof)).resolves.not.toThrow(); + await expect(proofCreator.verifyProofForProtocolCircuit(circuitType, tx.proof)).resolves.not.toThrow(); } describe('client_prover_integration', () => { diff --git a/yarn-project/noir-protocol-circuits-types/src/type_conversion.ts b/yarn-project/noir-protocol-circuits-types/src/type_conversion.ts index ec844c1a3d6..659afa884a7 100644 --- a/yarn-project/noir-protocol-circuits-types/src/type_conversion.ts +++ b/yarn-project/noir-protocol-circuits-types/src/type_conversion.ts @@ -786,8 +786,8 @@ export function mapPrivateCallDataToNoir(privateCallData: PrivateCallData): Priv call_stack_item: mapPrivateCallStackItemToNoir(privateCallData.callStackItem), private_call_stack: mapTuple(privateCallData.privateCallStack, mapCallRequestToNoir), public_call_stack: mapTuple(privateCallData.publicCallStack, mapCallRequestToNoir), - proof: {}, - vk: {}, + proof: mapRecursiveProofToNoir(privateCallData.proof), + vk: mapVerificationKeyToNoir(privateCallData.vk), function_leaf_membership_witness: mapMembershipWitnessToNoir(privateCallData.functionLeafMembershipWitness), contract_class_artifact_hash: mapFieldToNoir(privateCallData.contractClassArtifactHash), contract_class_public_bytecode_commitment: mapFieldToNoir(privateCallData.contractClassPublicBytecodeCommitment), @@ -1235,7 +1235,6 @@ export function mapPublicKernelCircuitPublicInputsToNoir( inputs: PublicKernelCircuitPublicInputs, ): PublicKernelCircuitPublicInputsNoir { return { - aggregation_object: {}, constants: mapCombinedConstantDataToNoir(inputs.constants), validation_requests: mapValidationRequestsToNoir(inputs.validationRequests), end: mapPublicAccumulatedDataToNoir(inputs.end), @@ -1258,7 +1257,6 @@ export function mapKernelCircuitPublicInputsFromNoir(inputs: KernelCircuitPublic export function mapKernelCircuitPublicInputsToNoir(inputs: KernelCircuitPublicInputs): KernelCircuitPublicInputsNoir { return { - aggregation_object: {}, rollup_validation_requests: mapRollupValidationRequestsToNoir(inputs.rollupValidationRequests), constants: mapCombinedConstantDataToNoir(inputs.constants), end: mapCombinedAccumulatedDataToNoir(inputs.end), @@ -1316,7 +1314,6 @@ export function mapPrivateKernelCircuitPublicInputsToNoir( inputs: PrivateKernelCircuitPublicInputs, ): PrivateKernelCircuitPublicInputsNoir { return { - aggregation_object: {}, constants: mapCombinedConstantDataToNoir(inputs.constants), validation_requests: mapValidationRequestsToNoir(inputs.validationRequests), end: mapPrivateAccumulatedDataToNoir(inputs.end), @@ -1333,8 +1330,8 @@ export function mapPrivateKernelCircuitPublicInputsToNoir( export function mapPrivateKernelDataToNoir(privateKernelInnerData: PrivateKernelData): PrivateKernelDataNoir { return { public_inputs: mapPrivateKernelCircuitPublicInputsToNoir(privateKernelInnerData.publicInputs), - proof: {}, - vk: {}, + proof: mapRecursiveProofToNoir(privateKernelInnerData.proof), + vk: mapVerificationKeyToNoir(privateKernelInnerData.vk), vk_index: mapFieldToNoir(new Fr(privateKernelInnerData.vkIndex)), vk_path: mapTuple(privateKernelInnerData.vkPath, mapFieldToNoir), }; @@ -1733,17 +1730,11 @@ export function mapAppendOnlyTreeSnapshotToNoir(snapshot: AppendOnlyTreeSnapshot }; } -export function mapRootRollupRecursiveProofToNoir(proof: RecursiveProof) { - return { - fields: mapTuple(proof.proof, mapFieldToNoir), - }; -} - export function mapRootRollupParityInputToNoir( rootParityInput: RootParityInput, ): RootRollupParityInputNoir { return { - proof: mapRootRollupRecursiveProofToNoir(rootParityInput.proof), + proof: mapRecursiveProofToNoir(rootParityInput.proof), verification_key: mapVerificationKeyToNoir(rootParityInput.verificationKey), public_inputs: mapParityPublicInputsToNoir(rootParityInput.publicInputs), }; @@ -1771,7 +1762,7 @@ export function mapRootRollupInputsToNoir(rootRollupInputs: RootRollupInputs): R }; } -export function mapRecursiveProofToNoir(proof: RecursiveProof) { +export function mapRecursiveProofToNoir(proof: RecursiveProof) { return { fields: mapTuple(proof.proof, mapFieldToNoir), }; diff --git a/yarn-project/pxe/src/kernel_prover/bb_prover/bb_native_proof_creator.ts b/yarn-project/pxe/src/kernel_prover/bb_prover/bb_native_proof_creator.ts index 15eed0996a9..cfb7c5d8870 100644 --- a/yarn-project/pxe/src/kernel_prover/bb_prover/bb_native_proof_creator.ts +++ b/yarn-project/pxe/src/kernel_prover/bb_prover/bb_native_proof_creator.ts @@ -1,5 +1,6 @@ import { Fr, + NESTED_RECURSIVE_PROOF_LENGTH, type PrivateCircuitPublicInputs, type PrivateKernelCircuitPublicInputs, type PrivateKernelInitCircuitPrivateInputs, @@ -7,7 +8,10 @@ import { type PrivateKernelTailCircuitPrivateInputs, type PrivateKernelTailCircuitPublicInputs, Proof, + RECURSIVE_PROOF_LENGTH, + RecursiveProof, type VERIFICATION_KEY_LENGTH_IN_FIELDS, + VerificationKeyAsFields, } from '@aztec/circuits.js'; import { siloNoteHash } from '@aztec/circuits.js/hash'; import { randomBytes, sha256 } from '@aztec/foundation/crypto'; @@ -34,7 +38,7 @@ import { serializeWitness } from '@noir-lang/noirc_abi'; import * as proc from 'child_process'; import * as fs from 'fs/promises'; -import { type ProofCreator, type ProofOutput } from '../interface/proof_creator.js'; +import { type AppCircuitProofOutput, type KernelProofOutput, type ProofCreator } from '../interface/proof_creator.js'; /** * Temporary implementation of ProofCreator using the native bb binary. @@ -44,9 +48,9 @@ import { type ProofCreator, type ProofOutput } from '../interface/proof_creator. const VK_FILENAME = 'vk'; const VK_FIELDS_FILENAME = 'vk_fields.json'; const PROOF_FILENAME = 'proof'; -//const PROOF_FIELDS_FILENAME = 'proof_fields.json'; +const PROOF_FIELDS_FILENAME = 'proof_fields.json'; -//const AGGREGATION_OBJECT_SIZE = 16; +const AGGREGATION_OBJECT_SIZE = 16; const CIRCUIT_SIZE_INDEX = 3; const CIRCUIT_PUBLIC_INPUTS_INDEX = 4; const CIRCUIT_RECURSIVE_INDEX = 5; @@ -452,21 +456,21 @@ export class BBNativeProofCreator implements ProofCreator { public async createProofInit( inputs: PrivateKernelInitCircuitPrivateInputs, - ): Promise> { + ): Promise> { const witnessMap = convertPrivateKernelInitInputsToWitnessMap(inputs); return await this.createSafeProof(witnessMap, 'PrivateKernelInitArtifact'); } public async createProofInner( inputs: PrivateKernelInnerCircuitPrivateInputs, - ): Promise> { + ): Promise> { const witnessMap = convertPrivateKernelInnerInputsToWitnessMap(inputs); return await this.createSafeProof(witnessMap, 'PrivateKernelInnerArtifact'); } public async createProofTail( inputs: PrivateKernelTailCircuitPrivateInputs, - ): Promise> { + ): Promise> { if (!inputs.isForPublic()) { const witnessMap = convertPrivateKernelTailInputsToWitnessMap(inputs); return await this.createSafeProof(witnessMap, 'PrivateKernelTailArtifact'); @@ -475,14 +479,25 @@ export class BBNativeProofCreator implements ProofCreator { return await this.createSafeProof(witnessMap, 'PrivateKernelTailToPublicArtifact'); } - public async createAppCircuitProof(partialWitness: Map, bytecode: Buffer): Promise { + public async createAppCircuitProof( + partialWitness: Map, + bytecode: Buffer, + ): Promise { const directory = `${this.bbWorkingDirectory}/${randomBytes(8).toString('hex')}`; await fs.mkdir(directory, { recursive: true }); this.log.debug(`Created directory: ${directory}`); try { this.log.debug(`Proving app circuit`); - const proof = await this.createProof(directory, partialWitness, bytecode, 'App'); - return new Proof(proof); + const proofOutput = await this.createProof(directory, partialWitness, bytecode, 'App'); + if (proofOutput.proof.proof.length != RECURSIVE_PROOF_LENGTH) { + throw new Error(`Incorrect proof length`); + } + const proof = proofOutput.proof as RecursiveProof; + const output: AppCircuitProofOutput = { + proof, + verificationKey: proofOutput.verificationKey, + }; + return output; } finally { await fs.rm(directory, { recursive: true, force: true }); this.log.debug(`Deleted directory: ${directory}`); @@ -494,27 +509,16 @@ export class BBNativeProofCreator implements ProofCreator { * @param circuitType - The type of circuit whose proof is to be verified * @param proof - The proof to be verified */ - public async verifyProof(circuitType: ClientProtocolArtifact, proof: Proof) { - // Create random directory to be used for temp files - const bbWorkingDirectory = `${this.bbWorkingDirectory}/${randomBytes(8).toString('hex')}`; - await fs.mkdir(bbWorkingDirectory, { recursive: true }); - - const proofFileName = `${bbWorkingDirectory}/proof`; - const verificationKeyPath = `${bbWorkingDirectory}/vk`; + public async verifyProofForProtocolCircuit(circuitType: ClientProtocolArtifact, proof: Proof) { const verificationKey = await this.getVerificationKeyDataForCircuit(circuitType); this.log.debug(`Verifying with key: ${verificationKey.hash.toString()}`); - await fs.writeFile(proofFileName, proof.buffer); - await fs.writeFile(verificationKeyPath, verificationKey.keyAsBytes); - const logFunction = (message: string) => { this.log.debug(`${circuitType} BB out - ${message}`); }; - const result = await verifyProof(this.bbBinaryPath, proofFileName, verificationKeyPath!, logFunction); - - await fs.rm(bbWorkingDirectory, { recursive: true, force: true }); + const result = await this.verifyProofFromKey(verificationKey.keyAsBytes, proof, logFunction); if (result.status === BB_RESULT.FAILURE) { const errorMessage = `Failed to verify ${circuitType} proof!`; @@ -524,6 +528,28 @@ export class BBNativeProofCreator implements ProofCreator { this.log.info(`Successfully verified ${circuitType} proof in ${result.duration} ms`); } + private async verifyProofFromKey( + verificationKey: Buffer, + proof: Proof, + logFunction: (message: string) => void = () => {}, + ) { + // Create random directory to be used for temp files + const bbWorkingDirectory = `${this.bbWorkingDirectory}/${randomBytes(8).toString('hex')}`; + await fs.mkdir(bbWorkingDirectory, { recursive: true }); + + const proofFileName = `${bbWorkingDirectory}/proof`; + const verificationKeyPath = `${bbWorkingDirectory}/vk`; + + await fs.writeFile(proofFileName, proof.buffer); + await fs.writeFile(verificationKeyPath, verificationKey); + + try { + return await verifyProof(this.bbBinaryPath, proofFileName, verificationKeyPath!, logFunction); + } finally { + await fs.rm(bbWorkingDirectory, { recursive: true, force: true }); + } + } + /** * Returns the verification key data for a circuit, will generate and cache it if not cached internally * @param circuitType - The type of circuit for which the verification key is required @@ -588,10 +614,13 @@ export class BBNativeProofCreator implements ProofCreator { this.log.debug(`Updated verification key for circuit: ${circuitType}`); this.verificationKeys.set(circuitType, promise); } - await promise; + return await promise; } - private async createSafeProof(inputs: WitnessMap, circuitType: ClientProtocolArtifact): Promise> { + private async createSafeProof( + inputs: WitnessMap, + circuitType: ClientProtocolArtifact, + ): Promise> { const directory = `${this.bbWorkingDirectory}/${randomBytes(8).toString('hex')}`; await fs.mkdir(directory, { recursive: true }); this.log.debug(`Created directory: ${directory}`); @@ -607,7 +636,7 @@ export class BBNativeProofCreator implements ProofCreator { inputs: WitnessMap, circuitType: ClientProtocolArtifact, directory: string, - ): Promise> { + ): Promise> { this.log.debug(`Generating witness for ${circuitType}`); const compiledCircuit: NoirCompiledCircuit = ClientCircuitArtifacts[circuitType]; @@ -617,18 +646,23 @@ export class BBNativeProofCreator implements ProofCreator { const publicInputs = KernelArtifactMapping[circuitType].convertOutputs(outputWitness) as T; - const proofBuffer = await this.createProof( + const proofOutput = await this.createProof( directory, outputWitness, Buffer.from(compiledCircuit.bytecode, 'base64'), circuitType, ); + if (proofOutput.proof.proof.length != NESTED_RECURSIVE_PROOF_LENGTH) { + throw new Error(`Incorrect proof length`); + } + const nestedProof = proofOutput.proof as RecursiveProof; - const proofOutput: ProofOutput = { + const kernelOutput: KernelProofOutput = { publicInputs, - proof: new Proof(proofBuffer), + proof: nestedProof, + verificationKey: proofOutput.verificationKey, }; - return proofOutput; + return kernelOutput; } private async createProof( @@ -636,7 +670,10 @@ export class BBNativeProofCreator implements ProofCreator { partialWitness: WitnessMap, bytecode: Buffer, circuitType: ClientProtocolArtifact | 'App', - ) { + ): Promise<{ + proof: RecursiveProof | RecursiveProof; + verificationKey: VerificationKeyAsFields; + }> { const compressedBincodedWitness = serializeWitness(partialWitness); const inputsWitnessFile = `${directory}/witness.gz`; @@ -659,11 +696,15 @@ export class BBNativeProofCreator implements ProofCreator { throw new Error(provingResult.reason); } - if (circuitType !== 'App') { - await this.updateVerificationKeyAfterProof(directory, circuitType); + if (circuitType === 'App') { + const vkData = await this.convertVk(directory); + const proof = await this.readProofAsFields(directory, circuitType, vkData); + return { proof, verificationKey: new VerificationKeyAsFields(vkData.keyAsFields, vkData.hash) }; } - const proofFile = `${directory}/${PROOF_FILENAME}`; - return await fs.readFile(proofFile); + + const vkData = await this.updateVerificationKeyAfterProof(directory, circuitType); + const proof = await this.readProofAsFields(directory, circuitType, vkData); + return { proof, verificationKey: new VerificationKeyAsFields(vkData.keyAsFields, vkData.hash) }; } /** @@ -672,28 +713,24 @@ export class BBNativeProofCreator implements ProofCreator { * @param circuitType - The type of circuit proven * @returns The proof */ - // private async readProofAsFields( - // filePath: string, - // circuitType: ClientProtocolArtifact, - // ): Promise> { - // const [binaryProof, proofString] = await Promise.all([ - // fs.readFile(`${filePath}/${PROOF_FILENAME}`), - // fs.readFile(`${filePath}/${PROOF_FIELDS_FILENAME}`, { encoding: 'utf-8' }), - // ]); - // const json = JSON.parse(proofString); - // const fields = json.map(Fr.fromString); - // const vkData = await this.verificationKeys.get(circuitType); - // if (!vkData) { - // throw new Error(`Invalid verification key for ${circuitType}`); - // } - // const numPublicInputs = CIRCUITS_WITHOUT_AGGREGATION.has(circuitType) - // ? vkData.numPublicInputs - // : vkData.numPublicInputs - AGGREGATION_OBJECT_SIZE; - // const fieldsWithoutPublicInputs = fields.slice(numPublicInputs); - // logger.debug( - // `Circuit type: ${circuitType}, complete proof length: ${fields.length}, without public inputs: ${fieldsWithoutPublicInputs.length}, num public inputs: ${numPublicInputs}, circuit size: ${vkData.circuitSize}, is recursive: ${vkData.isRecursive}, raw length: ${binaryProof.length}`, - // ); - // const proof = new RecursiveProof(fieldsWithoutPublicInputs, new Proof(binaryProof)); - // return proof; - // } + private async readProofAsFields( + filePath: string, + circuitType: ClientProtocolArtifact | 'App', + vkData: VerificationKeyData, + ): Promise> { + const [binaryProof, proofString] = await Promise.all([ + fs.readFile(`${filePath}/${PROOF_FILENAME}`), + fs.readFile(`${filePath}/${PROOF_FIELDS_FILENAME}`, { encoding: 'utf-8' }), + ]); + const json = JSON.parse(proofString); + const fields = json.map(Fr.fromString); + const numPublicInputs = + circuitType === 'App' ? vkData.numPublicInputs : vkData.numPublicInputs - AGGREGATION_OBJECT_SIZE; + const fieldsWithoutPublicInputs = fields.slice(numPublicInputs); + this.log.debug( + `Circuit type: ${circuitType}, complete proof length: ${fields.length}, without public inputs: ${fieldsWithoutPublicInputs.length}, num public inputs: ${numPublicInputs}, circuit size: ${vkData.circuitSize}, is recursive: ${vkData.isRecursive}, raw length: ${binaryProof.length}`, + ); + const proof = new RecursiveProof(fieldsWithoutPublicInputs, new Proof(binaryProof)); + return proof; + } } diff --git a/yarn-project/pxe/src/kernel_prover/interface/proof_creator.ts b/yarn-project/pxe/src/kernel_prover/interface/proof_creator.ts index 5e085ae3b34..5b93d698058 100644 --- a/yarn-project/pxe/src/kernel_prover/interface/proof_creator.ts +++ b/yarn-project/pxe/src/kernel_prover/interface/proof_creator.ts @@ -1,11 +1,14 @@ import { + type NESTED_RECURSIVE_PROOF_LENGTH, type PrivateCircuitPublicInputs, type PrivateKernelCircuitPublicInputs, type PrivateKernelInitCircuitPrivateInputs, type PrivateKernelInnerCircuitPrivateInputs, type PrivateKernelTailCircuitPrivateInputs, type PrivateKernelTailCircuitPublicInputs, - type Proof, + type RECURSIVE_PROOF_LENGTH, + type RecursiveProof, + type VerificationKeyAsFields, } from '@aztec/circuits.js'; import { type Fr } from '@aztec/foundation/fields'; import { type ACVMField } from '@aztec/simulator'; @@ -14,7 +17,7 @@ import { type ACVMField } from '@aztec/simulator'; * Represents the output of the proof creation process for init and inner private kernel circuit. * Contains the public inputs required for the init and inner private kernel circuit and the generated proof. */ -export type ProofOutput = { +export type KernelProofOutput = { /** * The public inputs required for the proof generation process. */ @@ -22,7 +25,22 @@ export type ProofOutput = { /** * The zk-SNARK proof for the kernel execution. */ - proof: Proof; + proof: RecursiveProof; + + verificationKey: VerificationKeyAsFields; +}; + +/** + * Represents the output of the proof creation process for init and inner private kernel circuit. + * Contains the public inputs required for the init and inner private kernel circuit and the generated proof. + */ +export type AppCircuitProofOutput = { + /** + * The zk-SNARK proof for the kernel execution. + */ + proof: RecursiveProof; + + verificationKey: VerificationKeyAsFields; }; /** @@ -46,7 +64,7 @@ export interface ProofCreator { */ createProofInit( privateKernelInputsInit: PrivateKernelInitCircuitPrivateInputs, - ): Promise>; + ): Promise>; /** * Creates a proof output for a given previous kernel data and private call data for an inner iteration. @@ -56,7 +74,7 @@ export interface ProofCreator { */ createProofInner( privateKernelInputsInner: PrivateKernelInnerCircuitPrivateInputs, - ): Promise>; + ): Promise>; /** * Creates a proof output based on the last inner kernel iteration kernel data for the final ordering iteration. @@ -66,7 +84,7 @@ export interface ProofCreator { */ createProofTail( privateKernelInputsTail: PrivateKernelTailCircuitPrivateInputs, - ): Promise>; + ): Promise>; /** * Creates a proof for an app circuit. @@ -75,5 +93,5 @@ export interface ProofCreator { * @param bytecode - The circuit bytecode in gzipped bincode format * @returns A Promise resolving to a Proof object */ - createAppCircuitProof(partialWitness: Map, bytecode: Buffer): Promise; + createAppCircuitProof(partialWitness: Map, bytecode: Buffer): Promise; } diff --git a/yarn-project/pxe/src/kernel_prover/kernel_prover.test.ts b/yarn-project/pxe/src/kernel_prover/kernel_prover.test.ts index 58f29d4ceda..6a52d2c7a67 100644 --- a/yarn-project/pxe/src/kernel_prover/kernel_prover.test.ts +++ b/yarn-project/pxe/src/kernel_prover/kernel_prover.test.ts @@ -5,16 +5,19 @@ import { MAX_NEW_NOTE_HASHES_PER_CALL, MAX_NEW_NOTE_HASHES_PER_TX, MembershipWitness, + NESTED_RECURSIVE_PROOF_LENGTH, NoteHash, PrivateCallStackItem, PrivateCircuitPublicInputs, PrivateKernelCircuitPublicInputs, PrivateKernelTailCircuitPublicInputs, + RECURSIVE_PROOF_LENGTH, ScopedNoteHash, type TxRequest, VK_TREE_HEIGHT, VerificationKey, - makeEmptyProof, + VerificationKeyAsFields, + makeRecursiveProof, } from '@aztec/circuits.js'; import { makeTxRequest } from '@aztec/circuits.js/testing'; import { makeTuple } from '@aztec/foundation/array'; @@ -91,7 +94,8 @@ describe('Kernel Prover', () => { publicInputs.end.newNoteHashes = noteHashes; return { publicInputs, - proof: makeEmptyProof(), + proof: makeRecursiveProof(NESTED_RECURSIVE_PROOF_LENGTH), + verificationKey: VerificationKeyAsFields.makeEmpty(), }; }; @@ -105,7 +109,15 @@ describe('Kernel Prover', () => { return { publicInputs, - proof: makeEmptyProof(), + proof: makeRecursiveProof(NESTED_RECURSIVE_PROOF_LENGTH), + verificationKey: VerificationKeyAsFields.makeEmpty(), + }; + }; + + const createAppCircuitProofOutput = () => { + return { + proof: makeRecursiveProof(RECURSIVE_PROOF_LENGTH), + verificationKey: VerificationKeyAsFields.makeEmpty(), }; }; @@ -151,6 +163,7 @@ describe('Kernel Prover', () => { proofCreator.createProofInit.mockResolvedValue(createProofOutput([])); proofCreator.createProofInner.mockResolvedValue(createProofOutput([])); proofCreator.createProofTail.mockResolvedValue(createProofOutputFinal([])); + proofCreator.createAppCircuitProof.mockResolvedValue(createAppCircuitProofOutput()); prover = new KernelProver(oracle, proofCreator); }); diff --git a/yarn-project/pxe/src/kernel_prover/kernel_prover.ts b/yarn-project/pxe/src/kernel_prover/kernel_prover.ts index 73612e9e751..e0f2a0fad4a 100644 --- a/yarn-project/pxe/src/kernel_prover/kernel_prover.ts +++ b/yarn-project/pxe/src/kernel_prover/kernel_prover.ts @@ -3,6 +3,7 @@ import { Fr, MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL, MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL, + NESTED_RECURSIVE_PROOF_LENGTH, PrivateCallData, PrivateKernelCircuitPublicInputs, PrivateKernelData, @@ -10,11 +11,12 @@ import { PrivateKernelInnerCircuitPrivateInputs, PrivateKernelTailCircuitPrivateInputs, type PrivateKernelTailCircuitPublicInputs, - type Proof, + type RECURSIVE_PROOF_LENGTH, + type RecursiveProof, type TxRequest, VK_TREE_HEIGHT, - VerificationKey, - makeEmptyProof, + VerificationKeyAsFields, + makeRecursiveProof, } from '@aztec/circuits.js'; import { padArrayEnd } from '@aztec/foundation/collection'; import { createDebugLogger } from '@aztec/foundation/log'; @@ -22,7 +24,7 @@ import { assertLength } from '@aztec/foundation/serialize'; import { pushTestData } from '@aztec/foundation/testing'; import { type ExecutionResult, collectNoteHashLeafIndexMap, collectNullifiedNoteHashCounters } from '@aztec/simulator'; -import { type ProofCreator, type ProofOutput } from './interface/proof_creator.js'; +import { type KernelProofOutput, type ProofCreator } from './interface/proof_creator.js'; import { buildPrivateKernelInnerHints, buildPrivateKernelTailHints, @@ -54,14 +56,14 @@ export class KernelProver { async prove( txRequest: TxRequest, executionResult: ExecutionResult, - ): Promise> { + ): Promise> { const executionStack = [executionResult]; let firstIteration = true; - let previousVerificationKey = VerificationKey.makeFake(); - let output: ProofOutput = { + let output: KernelProofOutput = { publicInputs: PrivateKernelCircuitPublicInputs.empty(), - proof: makeEmptyProof(), + proof: makeRecursiveProof(NESTED_RECURSIVE_PROOF_LENGTH), + verificationKey: VerificationKeyAsFields.makeEmpty(), }; const noteHashLeafIndexMap = collectNoteHashLeafIndexMap(executionResult); @@ -76,7 +78,7 @@ export class KernelProver { ); const publicCallRequests = currentExecution.enqueuedPublicFunctionCalls.map(result => result.toCallRequest()); - const proof = await this.proofCreator.createAppCircuitProof( + const proofOutput = await this.proofCreator.createAppCircuitProof( currentExecution.partialWitness, currentExecution.acir, ); @@ -85,7 +87,8 @@ export class KernelProver { currentExecution, privateCallRequests, publicCallRequests, - proof, + proofOutput.proof, + proofOutput.verificationKey, ); const hints = buildPrivateKernelInnerHints( @@ -98,11 +101,11 @@ export class KernelProver { pushTestData('private-kernel-inputs-init', proofInput); output = await this.proofCreator.createProofInit(proofInput); } else { - const previousVkMembershipWitness = await this.oracle.getVkMembershipWitness(previousVerificationKey); + const previousVkMembershipWitness = await this.oracle.getVkMembershipWitness(output.verificationKey); const previousKernelData = new PrivateKernelData( output.publicInputs, output.proof, - previousVerificationKey, + output.verificationKey, Number(previousVkMembershipWitness.leafIndex), assertLength(previousVkMembershipWitness.siblingPath, VK_TREE_HEIGHT), ); @@ -111,14 +114,13 @@ export class KernelProver { output = await this.proofCreator.createProofInner(proofInput); } firstIteration = false; - previousVerificationKey = privateCallData.vk; } - const previousVkMembershipWitness = await this.oracle.getVkMembershipWitness(previousVerificationKey); + const previousVkMembershipWitness = await this.oracle.getVkMembershipWitness(output.verificationKey); const previousKernelData = new PrivateKernelData( output.publicInputs, output.proof, - previousVerificationKey, + output.verificationKey, Number(previousVkMembershipWitness.leafIndex), assertLength(previousVkMembershipWitness.siblingPath, VK_TREE_HEIGHT), ); @@ -138,10 +140,11 @@ export class KernelProver { } private async createPrivateCallData( - { callStackItem, vk }: ExecutionResult, + { callStackItem }: ExecutionResult, privateCallRequests: CallRequest[], publicCallRequests: CallRequest[], - proof: Proof, + proof: RecursiveProof, + vk: VerificationKeyAsFields, ) { const { contractAddress, functionData } = callStackItem; @@ -172,7 +175,7 @@ export class KernelProver { privateCallStack, publicCallStack, proof, - vk: VerificationKey.fromBuffer(vk), + vk, publicKeysHash, contractClassArtifactHash, contractClassPublicBytecodeCommitment, diff --git a/yarn-project/pxe/src/kernel_prover/proving_data_oracle.ts b/yarn-project/pxe/src/kernel_prover/proving_data_oracle.ts index ba408e4cf77..04af3cad3ed 100644 --- a/yarn-project/pxe/src/kernel_prover/proving_data_oracle.ts +++ b/yarn-project/pxe/src/kernel_prover/proving_data_oracle.ts @@ -8,7 +8,7 @@ import { type NOTE_HASH_TREE_HEIGHT, type Point, type VK_TREE_HEIGHT, - type VerificationKey, + type VerificationKeyAsFields, } from '@aztec/circuits.js'; import { type AztecAddress } from '@aztec/foundation/aztec-address'; @@ -50,7 +50,7 @@ export interface ProvingDataOracle { * @param vk - The VerificationKey for which the membership witness is needed. * @returns A Promise that resolves to the MembershipWitness instance. */ - getVkMembershipWitness(vk: VerificationKey): Promise>; + getVkMembershipWitness(vk: VerificationKeyAsFields): Promise>; /** * Get the note membership witness for a note in the note hash tree at the given leaf index. diff --git a/yarn-project/pxe/src/kernel_prover/test/test_circuit_prover.ts b/yarn-project/pxe/src/kernel_prover/test/test_circuit_prover.ts index 4880e937eeb..6b3a29e72b8 100644 --- a/yarn-project/pxe/src/kernel_prover/test/test_circuit_prover.ts +++ b/yarn-project/pxe/src/kernel_prover/test/test_circuit_prover.ts @@ -1,20 +1,22 @@ import { type CircuitSimulationStats } from '@aztec/circuit-types/stats'; import { + NESTED_RECURSIVE_PROOF_LENGTH, type PrivateCircuitPublicInputs, type PrivateKernelCircuitPublicInputs, type PrivateKernelInitCircuitPrivateInputs, type PrivateKernelInnerCircuitPrivateInputs, type PrivateKernelTailCircuitPrivateInputs, type PrivateKernelTailCircuitPublicInputs, - Proof, - makeEmptyProof, + RECURSIVE_PROOF_LENGTH, + VerificationKeyAsFields, + makeRecursiveProof, } from '@aztec/circuits.js'; import { siloNoteHash } from '@aztec/circuits.js/hash'; import { createDebugLogger } from '@aztec/foundation/log'; import { elapsed } from '@aztec/foundation/timer'; import { executeInit, executeInner, executeTail, executeTailForPublic } from '@aztec/noir-protocol-circuits-types'; -import { type ProofCreator, type ProofOutput } from '../interface/proof_creator.js'; +import { type AppCircuitProofOutput, type KernelProofOutput, type ProofCreator } from '../interface/proof_creator.js'; /** * Test Proof Creator executes circuit simulations and provides fake proofs. @@ -32,7 +34,7 @@ export class TestProofCreator implements ProofCreator { public async createProofInit( privateInputs: PrivateKernelInitCircuitPrivateInputs, - ): Promise> { + ): Promise> { const [duration, result] = await elapsed(() => executeInit(privateInputs)); this.log.debug(`Simulated private kernel init`, { eventName: 'circuit-simulation', @@ -41,17 +43,12 @@ export class TestProofCreator implements ProofCreator { inputSize: privateInputs.toBuffer().length, outputSize: result.toBuffer().length, } satisfies CircuitSimulationStats); - const proof = makeEmptyProof(); - - return { - publicInputs: result, - proof: proof, - }; + return this.makeEmptyKernelProofOutput(result); } public async createProofInner( privateInputs: PrivateKernelInnerCircuitPrivateInputs, - ): Promise> { + ): Promise> { const [duration, result] = await elapsed(() => executeInner(privateInputs)); this.log.debug(`Simulated private kernel inner`, { eventName: 'circuit-simulation', @@ -60,17 +57,12 @@ export class TestProofCreator implements ProofCreator { inputSize: privateInputs.toBuffer().length, outputSize: result.toBuffer().length, } satisfies CircuitSimulationStats); - const proof = makeEmptyProof(); - - return { - publicInputs: result, - proof: proof, - }; + return this.makeEmptyKernelProofOutput(result); } public async createProofTail( privateInputs: PrivateKernelTailCircuitPrivateInputs, - ): Promise> { + ): Promise> { const isForPublic = privateInputs.isForPublic(); const [duration, result] = await elapsed(() => isForPublic ? executeTailForPublic(privateInputs) : executeTail(privateInputs), @@ -82,15 +74,23 @@ export class TestProofCreator implements ProofCreator { inputSize: privateInputs.toBuffer().length, outputSize: result.toBuffer().length, } satisfies CircuitSimulationStats); - const proof = makeEmptyProof(); + return this.makeEmptyKernelProofOutput(result); + } - return { - publicInputs: result, - proof: proof, + createAppCircuitProof(_1: Map, _2: Buffer): Promise { + const appCircuitProofOutput: AppCircuitProofOutput = { + proof: makeRecursiveProof(RECURSIVE_PROOF_LENGTH), + verificationKey: VerificationKeyAsFields.makeEmpty(), }; + return Promise.resolve(appCircuitProofOutput); } - createAppCircuitProof(_1: Map, _2: Buffer): Promise { - return Promise.resolve(new Proof(Buffer.alloc(0))); + private makeEmptyKernelProofOutput(publicInputs: PublicInputsType) { + const kernelProofOutput: KernelProofOutput = { + publicInputs, + proof: makeRecursiveProof(NESTED_RECURSIVE_PROOF_LENGTH), + verificationKey: VerificationKeyAsFields.makeEmpty(), + }; + return kernelProofOutput; } } diff --git a/yarn-project/pxe/src/pxe_service/pxe_service.ts b/yarn-project/pxe/src/pxe_service/pxe_service.ts index 1f0e859fa8f..02ff03a95ee 100644 --- a/yarn-project/pxe/src/pxe_service/pxe_service.ts +++ b/yarn-project/pxe/src/pxe_service/pxe_service.ts @@ -678,7 +678,7 @@ export class PXEService implements PXE { const tx = new Tx( publicInputs, - proof, + proof.binaryProof, encryptedLogs, unencryptedLogs, enqueuedPublicFunctions, From 8079f601a23219ddd96f01064d0c31c6e8109471 Mon Sep 17 00:00:00 2001 From: Maxim Vezenov Date: Thu, 9 May 2024 12:12:33 +0100 Subject: [PATCH 03/11] chore(dsl): Update backend gateCount command to query a Program in a single request (#6228) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Resolves https://github.com/AztecProtocol/aztec-packages/issues/6168 This PR does a very minor update to simply now go through the entire list of functions contained inside of a Program and generate a basic circuit report for each functions. Currently `nargo info` now takes in a JSON report that it works with instead of an individual printed gate count. This PR also does some initial work on making a gate report that is ready for noir-lang/noir-gates-diff. This is yet to be updated but has most of the initial skeleton needed to get a gates report for an entire workspace. Also, once https://github.com/noir-lang/noir/pull/4975 is merged and synced into this repo we can remove the `bb info` command and rename `bb gates` -> `bb info` Nargo info still works as expected: Screenshot 2024-05-08 at 2 55 32 PM --------- Co-authored-by: Tom French --- barretenberg/cpp/src/barretenberg/bb/main.cpp | 38 ++++++++++++++---- .../dsl/acir_format/acir_format.hpp | 2 + .../dsl/acir_format/acir_format.test.cpp | 6 +++ .../acir_format/acir_to_constraint_buf.hpp | 1 + .../acir_format/bigint_constraint.test.cpp | 5 +++ .../dsl/acir_format/block_constraint.test.cpp | 1 + .../dsl/acir_format/ec_operations.test.cpp | 1 + .../dsl/acir_format/ecdsa_secp256k1.test.cpp | 3 ++ .../dsl/acir_format/ecdsa_secp256r1.test.cpp | 4 ++ .../acir_format/poseidon2_constraint.test.cpp | 1 + .../acir_format/recursion_constraint.test.cpp | 2 + .../acir_format/sha256_constraint.test.cpp | 1 + noir-projects/gates_report.sh | 39 +++++++++++++++++++ noir/noir-repo/Cargo.lock | 1 + .../tooling/backend_interface/Cargo.toml | 1 + .../backend_interface/src/cli/gates.rs | 32 ++++++++------- .../tooling/backend_interface/src/cli/mod.rs | 2 + .../backend_interface/src/proof_system.rs | 9 +++-- .../mock_backend/src/gates_cmd.rs | 4 +- .../tooling/nargo_cli/src/cli/info_cmd.rs | 18 +++++---- 20 files changed, 139 insertions(+), 32 deletions(-) create mode 100755 noir-projects/gates_report.sh diff --git a/barretenberg/cpp/src/barretenberg/bb/main.cpp b/barretenberg/cpp/src/barretenberg/bb/main.cpp index 9db639ea0a5..820cc522ad7 100644 --- a/barretenberg/cpp/src/barretenberg/bb/main.cpp +++ b/barretenberg/cpp/src/barretenberg/bb/main.cpp @@ -296,19 +296,43 @@ void prove(const std::string& bytecodePath, const std::string& witnessPath, cons * @brief Computes the number of Barretenberg specific gates needed to create a proof for the specific ACIR circuit * * Communication: - * - stdout: The number of gates is written to stdout + * - stdout: A JSON string of the number of ACIR opcodes and final backend circuit size * * @param bytecodePath Path to the file containing the serialized circuit */ void gateCount(const std::string& bytecodePath) { - auto constraint_system = get_constraint_system(bytecodePath); - acir_proofs::AcirComposer acir_composer(0, verbose); - acir_composer.create_circuit(constraint_system); - auto gate_count = acir_composer.get_total_circuit_size(); + // All circuit reports will be built into the string below + std::string functions_string = "{\"functions\": [\n "; + auto constraint_systems = get_constraint_systems(bytecodePath); + size_t i = 0; + for (auto constraint_system : constraint_systems) { + acir_proofs::AcirComposer acir_composer(0, verbose); + acir_composer.create_circuit(constraint_system); + auto circuit_size = acir_composer.get_total_circuit_size(); + + // Build individual circuit report + auto result_string = format("{\n \"acir_opcodes\": ", + constraint_system.num_acir_opcodes, + ",\n \"circuit_size\": ", + circuit_size, + "\n }"); + + // Attach a comma if we still circuit reports to generate + if (i != (constraint_systems.size() - 1)) { + result_string = format(result_string, ","); + } - writeUint64AsRawBytesToStdout(static_cast(gate_count)); - vinfo("gate count: ", gate_count); + functions_string = format(functions_string, result_string); + + i++; + } + functions_string = format(functions_string, "\n]}"); + + const char* jsonData = functions_string.c_str(); + size_t length = strlen(jsonData); + std::vector data(jsonData, jsonData + length); + writeRawBytesToStdout(data); } /** diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_format.hpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_format.hpp index 8b7823260d0..9add17a1451 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_format.hpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_format.hpp @@ -32,6 +32,8 @@ struct AcirFormat { // to be able to verify SNARKs on Ethereum. bool recursive; + uint32_t num_acir_opcodes; + std::vector public_inputs; std::vector logic_constraints; diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_format.test.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_format.test.cpp index 2d23b057c64..038db2a28f9 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_format.test.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_format.test.cpp @@ -32,6 +32,7 @@ TEST_F(AcirFormatTests, TestASingleConstraintNoPubInputs) AcirFormat constraint_system{ .varnum = 4, .recursive = false, + .num_acir_opcodes = 1, .public_inputs = {}, .logic_constraints = {}, .range_constraints = {}, @@ -149,6 +150,7 @@ TEST_F(AcirFormatTests, TestLogicGateFromNoirCircuit) AcirFormat constraint_system{ .varnum = 6, .recursive = false, + .num_acir_opcodes = 7, .public_inputs = { 1 }, .logic_constraints = { logic_constraint }, .range_constraints = { range_a, range_b }, @@ -218,6 +220,7 @@ TEST_F(AcirFormatTests, TestSchnorrVerifyPass) }; AcirFormat constraint_system{ .varnum = 81, .recursive = false, + .num_acir_opcodes = 75, .public_inputs = {}, .logic_constraints = {}, .range_constraints = range_constraints, @@ -314,6 +317,7 @@ TEST_F(AcirFormatTests, TestSchnorrVerifySmallRange) AcirFormat constraint_system{ .varnum = 81, .recursive = false, + .num_acir_opcodes = 75, .public_inputs = {}, .logic_constraints = {}, .range_constraints = range_constraints, @@ -429,6 +433,7 @@ TEST_F(AcirFormatTests, TestVarKeccak) AcirFormat constraint_system{ .varnum = 36, .recursive = false, + .num_acir_opcodes = 6, .public_inputs = {}, .logic_constraints = {}, .range_constraints = { range_a, range_b, range_c, range_d }, @@ -477,6 +482,7 @@ TEST_F(AcirFormatTests, TestKeccakPermutation) AcirFormat constraint_system{ .varnum = 51, .recursive = false, + .num_acir_opcodes = 1, .public_inputs = {}, .logic_constraints = {}, .range_constraints = {}, diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_to_constraint_buf.hpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_to_constraint_buf.hpp index 110087d40af..3e77b60d689 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_to_constraint_buf.hpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_to_constraint_buf.hpp @@ -477,6 +477,7 @@ AcirFormat circuit_serde_to_acir_format(Program::Circuit const& circuit) // `varnum` is the true number of variables, thus we add one to the index which starts at zero af.varnum = circuit.current_witness_index + 1; af.recursive = circuit.recursive; + af.num_acir_opcodes = static_cast(circuit.opcodes.size()); af.public_inputs = join({ map(circuit.public_parameters.value, [](auto e) { return e.value; }), map(circuit.return_values.value, [](auto e) { return e.value; }) }); std::map block_id_to_block_constraint; diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/bigint_constraint.test.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/bigint_constraint.test.cpp index 863737703ef..1cc86262bd1 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/bigint_constraint.test.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/bigint_constraint.test.cpp @@ -169,6 +169,7 @@ TEST_F(BigIntTests, TestBigIntConstraintMultiple) AcirFormat constraint_system{ .varnum = static_cast(witness.size() + 1), .recursive = false, + .num_acir_opcodes = 5, .public_inputs = {}, .logic_constraints = {}, .range_constraints = {}, @@ -238,6 +239,7 @@ TEST_F(BigIntTests, TestBigIntConstraintSimple) AcirFormat constraint_system{ .varnum = 5, .recursive = false, + .num_acir_opcodes = 3, .public_inputs = {}, .logic_constraints = {}, .range_constraints = {}, @@ -292,6 +294,7 @@ TEST_F(BigIntTests, TestBigIntConstraintReuse) AcirFormat constraint_system{ .varnum = static_cast(witness.size() + 1), .recursive = false, + .num_acir_opcodes = 5, .public_inputs = {}, .logic_constraints = {}, .range_constraints = {}, @@ -350,6 +353,7 @@ TEST_F(BigIntTests, TestBigIntConstraintReuse2) AcirFormat constraint_system{ .varnum = static_cast(witness.size() + 1), .recursive = false, + .num_acir_opcodes = 5, .public_inputs = {}, .logic_constraints = {}, .range_constraints = {}, @@ -429,6 +433,7 @@ TEST_F(BigIntTests, TestBigIntDIV) AcirFormat constraint_system{ .varnum = 5, .recursive = false, + .num_acir_opcodes = 4, .public_inputs = {}, .logic_constraints = {}, .range_constraints = {}, diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/block_constraint.test.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/block_constraint.test.cpp index 7cb3e5955bd..5d649d8feb3 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/block_constraint.test.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/block_constraint.test.cpp @@ -111,6 +111,7 @@ TEST_F(UltraPlonkRAM, TestBlockConstraint) AcirFormat constraint_system{ .varnum = static_cast(num_variables), .recursive = false, + .num_acir_opcodes = 7, .public_inputs = {}, .logic_constraints = {}, .range_constraints = {}, diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/ec_operations.test.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/ec_operations.test.cpp index fb676af0a8b..65be4aaae55 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/ec_operations.test.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/ec_operations.test.cpp @@ -51,6 +51,7 @@ TEST_F(EcOperations, TestECOperations) AcirFormat constraint_system{ .varnum = static_cast(num_variables + 1), .recursive = false, + .num_acir_opcodes = 1, .public_inputs = {}, .logic_constraints = {}, .range_constraints = {}, diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/ecdsa_secp256k1.test.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/ecdsa_secp256k1.test.cpp index 20dddfe4abe..61782002c85 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/ecdsa_secp256k1.test.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/ecdsa_secp256k1.test.cpp @@ -91,6 +91,7 @@ TEST_F(ECDSASecp256k1, TestECDSAConstraintSucceed) AcirFormat constraint_system{ .varnum = static_cast(num_variables), .recursive = false, + .num_acir_opcodes = 1, .public_inputs = {}, .logic_constraints = {}, .range_constraints = {}, @@ -141,6 +142,7 @@ TEST_F(ECDSASecp256k1, TestECDSACompilesForVerifier) AcirFormat constraint_system{ .varnum = static_cast(num_variables), .recursive = false, + .num_acir_opcodes = 1, .public_inputs = {}, .logic_constraints = {}, .range_constraints = {}, @@ -186,6 +188,7 @@ TEST_F(ECDSASecp256k1, TestECDSAConstraintFail) AcirFormat constraint_system{ .varnum = static_cast(num_variables), .recursive = false, + .num_acir_opcodes = 1, .public_inputs = {}, .logic_constraints = {}, .range_constraints = {}, diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/ecdsa_secp256r1.test.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/ecdsa_secp256r1.test.cpp index 6217149fdf0..de1d0931d8c 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/ecdsa_secp256r1.test.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/ecdsa_secp256r1.test.cpp @@ -125,6 +125,7 @@ TEST(ECDSASecp256r1, test_hardcoded) AcirFormat constraint_system{ .varnum = static_cast(num_variables), .recursive = false, + .num_acir_opcodes = 1, .public_inputs = {}, .logic_constraints = {}, .range_constraints = {}, @@ -177,6 +178,7 @@ TEST(ECDSASecp256r1, TestECDSAConstraintSucceed) AcirFormat constraint_system{ .varnum = static_cast(num_variables), .recursive = false, + .num_acir_opcodes = 1, .public_inputs = {}, .logic_constraints = {}, .range_constraints = {}, @@ -227,6 +229,7 @@ TEST(ECDSASecp256r1, TestECDSACompilesForVerifier) AcirFormat constraint_system{ .varnum = static_cast(num_variables), .recursive = false, + .num_acir_opcodes = 1, .public_inputs = {}, .logic_constraints = {}, .range_constraints = {}, @@ -272,6 +275,7 @@ TEST(ECDSASecp256r1, TestECDSAConstraintFail) AcirFormat constraint_system{ .varnum = static_cast(num_variables), .recursive = false, + .num_acir_opcodes = 1, .public_inputs = {}, .logic_constraints = {}, .range_constraints = {}, diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/poseidon2_constraint.test.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/poseidon2_constraint.test.cpp index d35a9d36974..4922c63cd69 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/poseidon2_constraint.test.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/poseidon2_constraint.test.cpp @@ -31,6 +31,7 @@ TEST_F(Poseidon2Tests, TestPoseidon2Permutation) AcirFormat constraint_system{ .varnum = 9, .recursive = false, + .num_acir_opcodes = 1, .public_inputs = {}, .logic_constraints = {}, .range_constraints = {}, diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/recursion_constraint.test.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/recursion_constraint.test.cpp index 0b12a411951..b837f94ba2a 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/recursion_constraint.test.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/recursion_constraint.test.cpp @@ -83,6 +83,7 @@ Builder create_inner_circuit() AcirFormat constraint_system{ .varnum = 6, .recursive = true, + .num_acir_opcodes = 7, .public_inputs = { 1, 2 }, .logic_constraints = { logic_constraint }, .range_constraints = { range_a, range_b }, @@ -241,6 +242,7 @@ Builder create_outer_circuit(std::vector& inner_circuits) AcirFormat constraint_system{ .varnum = static_cast(witness.size()), .recursive = false, + .num_acir_opcodes = static_cast(recursion_constraints.size()), .public_inputs = {}, .logic_constraints = {}, .range_constraints = {}, diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/sha256_constraint.test.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/sha256_constraint.test.cpp index 4b78a9550e7..5af032bedd1 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/sha256_constraint.test.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/sha256_constraint.test.cpp @@ -33,6 +33,7 @@ TEST_F(Sha256Tests, TestSha256Compression) AcirFormat constraint_system{ .varnum = 34, .recursive = false, + .num_acir_opcodes = 1, .public_inputs = {}, .logic_constraints = {}, .range_constraints = {}, diff --git a/noir-projects/gates_report.sh b/noir-projects/gates_report.sh new file mode 100755 index 00000000000..affbf07d1f4 --- /dev/null +++ b/noir-projects/gates_report.sh @@ -0,0 +1,39 @@ +#!/usr/bin/env bash +set -eu + +# TODO(https://github.com/noir-lang/noir/issues/4962): This script is still yet to be integrated with noir-lang/noir-gates-diff +# The script needs some slight updating as `nargo info` expects a complete JSON object, while this script expects a single object field +# representing a list of circuit reports for a program. +# The ACIR tests in barretenberg also expect every target bytecode to have the name `acir.gz` while this script expects the same name of the package +echo "Compile noir-protocol-circuits for gates report..." +cd noir-protocol-circuits +PROTOCOL_CIRCUITS_DIR=$PWD + +# Compile programs into artifacts that the backend expects +NARGO=${NARGO:-../../noir/noir-repo/target/release/nargo} +$NARGO compile --only-acir + +BB_BIN=${BB_BIN:-../../barretenberg/cpp/build/bin/bb} + +echo "{\"programs\": [" > gates_report.json + +# Bound for checking where to place last parentheses +NUM_ARTIFACTS=$(ls -1q "$PROTOCOL_CIRCUITS_DIR/target"/*.gz | wc -l) + +ITER="1" +for pathname in "$PROTOCOL_CIRCUITS_DIR/target"/*.gz; do + ARTIFACT_NAME=$(basename -s .gz "$pathname") + + echo "{\"package_name\": \"$ARTIFACT_NAME\"," >> gates_report.json + $BB_BIN gates -b "./target/$ARTIFACT_NAME.gz" >> gates_report.json + + if (($ITER == $NUM_ARTIFACTS)); then + echo "}" >> gates_report.json + else + echo "}, " >> gates_report.json + fi + + ITER=$(( $ITER + 1 )) +done + +echo "]}" >> gates_report.json \ No newline at end of file diff --git a/noir/noir-repo/Cargo.lock b/noir/noir-repo/Cargo.lock index a8c63c032aa..859579c077f 100644 --- a/noir/noir-repo/Cargo.lock +++ b/noir/noir-repo/Cargo.lock @@ -462,6 +462,7 @@ dependencies = [ "dirs", "flate2", "reqwest", + "serde", "serde_json", "tar", "tempfile", diff --git a/noir/noir-repo/tooling/backend_interface/Cargo.toml b/noir/noir-repo/tooling/backend_interface/Cargo.toml index f6b5d5d0132..b731c138c7d 100644 --- a/noir/noir-repo/tooling/backend_interface/Cargo.toml +++ b/noir/noir-repo/tooling/backend_interface/Cargo.toml @@ -13,6 +13,7 @@ license.workspace = true acvm.workspace = true dirs.workspace = true thiserror.workspace = true +serde.workspace = true serde_json.workspace = true bb_abstraction_leaks.workspace = true tracing.workspace = true diff --git a/noir/noir-repo/tooling/backend_interface/src/cli/gates.rs b/noir/noir-repo/tooling/backend_interface/src/cli/gates.rs index aca05f0232a..9e12596bfd7 100644 --- a/noir/noir-repo/tooling/backend_interface/src/cli/gates.rs +++ b/noir/noir-repo/tooling/backend_interface/src/cli/gates.rs @@ -1,3 +1,4 @@ +use serde::Deserialize; use std::path::{Path, PathBuf}; use crate::BackendError; @@ -12,8 +13,19 @@ pub(crate) struct GatesCommand { pub(crate) bytecode_path: PathBuf, } +#[derive(Deserialize)] +struct GatesResponse { + functions: Vec, +} + +#[derive(Deserialize)] +pub struct CircuitReport { + pub acir_opcodes: u32, + pub circuit_size: u32, +} + impl GatesCommand { - pub(crate) fn run(self, binary_path: &Path) -> Result { + pub(crate) fn run(self, binary_path: &Path) -> Result, BackendError> { let output = std::process::Command::new(binary_path) .arg("gates") .arg("-c") @@ -25,19 +37,11 @@ impl GatesCommand { if !output.status.success() { return Err(BackendError::CommandFailed(string_from_stderr(&output.stderr))); } - // Note: barretenberg includes the newline, so that subsequent prints to stdout - // are not on the same line as the gates output. - - const EXPECTED_BYTES: usize = 8; - let gates_bytes: [u8; EXPECTED_BYTES] = - output.stdout.as_slice().try_into().map_err(|_| { - BackendError::UnexpectedNumberOfBytes(EXPECTED_BYTES, output.stdout.clone()) - })?; - // Convert bytes to u64 in little-endian format - let value = u64::from_le_bytes(gates_bytes); + let gates_info: GatesResponse = + serde_json::from_slice(&output.stdout).expect("Backend should return valid json"); - Ok(value as u32) + Ok(gates_info.functions) } } @@ -58,7 +62,9 @@ fn gate_command() -> Result<(), BackendError> { let output = gate_command.run(backend.binary_path())?; // Mock backend always returns zero gates. - assert_eq!(output, 0); + assert_eq!(output.len(), 1); + assert_eq!(output[0].acir_opcodes, 123); + assert_eq!(output[0].circuit_size, 125); Ok(()) } diff --git a/noir/noir-repo/tooling/backend_interface/src/cli/mod.rs b/noir/noir-repo/tooling/backend_interface/src/cli/mod.rs index df43bd5cc2f..16a9517e129 100644 --- a/noir/noir-repo/tooling/backend_interface/src/cli/mod.rs +++ b/noir/noir-repo/tooling/backend_interface/src/cli/mod.rs @@ -18,6 +18,8 @@ pub(crate) use version::VersionCommand; pub(crate) use vk_as_fields::VkAsFieldsCommand; pub(crate) use write_vk::WriteVkCommand; +pub(crate) use gates::CircuitReport; + #[test] fn no_command_provided_works() -> Result<(), crate::BackendError> { // This is a simple test to check that the binaries work diff --git a/noir/noir-repo/tooling/backend_interface/src/proof_system.rs b/noir/noir-repo/tooling/backend_interface/src/proof_system.rs index 20a6dcf70f1..ffd46acef0e 100644 --- a/noir/noir-repo/tooling/backend_interface/src/proof_system.rs +++ b/noir/noir-repo/tooling/backend_interface/src/proof_system.rs @@ -11,13 +11,16 @@ use tempfile::tempdir; use tracing::warn; use crate::cli::{ - GatesCommand, ProofAsFieldsCommand, ProveCommand, VerifyCommand, VkAsFieldsCommand, - WriteVkCommand, + CircuitReport, GatesCommand, ProofAsFieldsCommand, ProveCommand, VerifyCommand, + VkAsFieldsCommand, WriteVkCommand, }; use crate::{Backend, BackendError}; impl Backend { - pub fn get_exact_circuit_size(&self, program: &Program) -> Result { + pub fn get_exact_circuit_sizes( + &self, + program: &Program, + ) -> Result, BackendError> { let binary_path = self.assert_binary_exists()?; self.assert_correct_version()?; diff --git a/noir/noir-repo/tooling/backend_interface/test-binaries/mock_backend/src/gates_cmd.rs b/noir/noir-repo/tooling/backend_interface/test-binaries/mock_backend/src/gates_cmd.rs index 3cc397d3292..0cebfbca42d 100644 --- a/noir/noir-repo/tooling/backend_interface/test-binaries/mock_backend/src/gates_cmd.rs +++ b/noir/noir-repo/tooling/backend_interface/test-binaries/mock_backend/src/gates_cmd.rs @@ -14,5 +14,7 @@ pub(crate) struct GatesCommand { pub(crate) fn run(args: GatesCommand) { assert!(args.bytecode_path.is_file(), "Could not find bytecode file at provided path"); - std::io::stdout().write_all(&0u64.to_le_bytes()).unwrap(); + let response: &str = r#"{ "functions": [{"acir_opcodes": 123, "circuit_size": 125 }] }"#; + + std::io::stdout().write_all(response.as_bytes()).unwrap(); } diff --git a/noir/noir-repo/tooling/nargo_cli/src/cli/info_cmd.rs b/noir/noir-repo/tooling/nargo_cli/src/cli/info_cmd.rs index 1ae2d5db104..f8f645d3c3a 100644 --- a/noir/noir-repo/tooling/nargo_cli/src/cli/info_cmd.rs +++ b/noir/noir-repo/tooling/nargo_cli/src/cli/info_cmd.rs @@ -1,6 +1,6 @@ use std::collections::HashMap; -use acvm::acir::circuit::{ExpressionWidth, Program}; +use acvm::acir::circuit::ExpressionWidth; use backend_interface::BackendError; use clap::Args; use iter_extended::vecmap; @@ -283,10 +283,15 @@ impl From for Vec { fn count_opcodes_and_gates_in_program( backend: &Backend, - compiled_program: ProgramArtifact, + mut compiled_program: ProgramArtifact, package: &Package, expression_width: ExpressionWidth, ) -> Result { + // Unconstrained functions do not matter to a backend circuit count so we clear them + // before sending a serialized program to the backend + compiled_program.bytecode.unconstrained_functions.clear(); + + let program_circuit_sizes = backend.get_exact_circuit_sizes(&compiled_program.bytecode)?; let functions = compiled_program .bytecode .functions @@ -295,12 +300,9 @@ fn count_opcodes_and_gates_in_program( .map(|(i, function)| -> Result<_, BackendError> { Ok(FunctionInfo { name: compiled_program.names[i].clone(), + // Required while mock backend doesn't return correct circuit size. acir_opcodes: function.opcodes.len(), - // Unconstrained functions do not matter to a backend circuit count so we pass nothing here - circuit_size: backend.get_exact_circuit_size(&Program { - functions: vec![function], - unconstrained_functions: Vec::new(), - })?, + circuit_size: program_circuit_sizes[i].circuit_size, }) }) .collect::>()?; @@ -321,7 +323,7 @@ fn count_opcodes_and_gates_in_contract( name: function.name, // TODO(https://github.com/noir-lang/noir/issues/4720) acir_opcodes: function.bytecode.functions[0].opcodes.len(), - circuit_size: backend.get_exact_circuit_size(&function.bytecode)?, + circuit_size: backend.get_exact_circuit_sizes(&function.bytecode)?[0].circuit_size, }) }) .collect::>()?; From 8e111f8bab5a0348fe8c7185f89e979541f91a67 Mon Sep 17 00:00:00 2001 From: Ilyas Ridhuan Date: Thu, 9 May 2024 12:16:05 +0100 Subject: [PATCH 04/11] feat: div opcode (#6053) Please read [contributing guidelines](CONTRIBUTING.md) and remove this line. --------- Co-authored-by: Jean M <132435771+jeanmon@users.noreply.github.com> --- barretenberg/cpp/pil/avm/avm_alu.pil | 123 +++++- barretenberg/cpp/pil/avm/avm_main.pil | 35 +- .../relations/generated/avm/avm_alu.hpp | 318 +++++++++++-- .../relations/generated/avm/avm_main.hpp | 28 +- .../relations/generated/avm/declare_views.hpp | 44 ++ .../generated/avm/lookup_div_u16_0.hpp | 166 +++++++ .../generated/avm/lookup_div_u16_1.hpp | 166 +++++++ .../generated/avm/lookup_div_u16_2.hpp | 166 +++++++ .../generated/avm/lookup_div_u16_3.hpp | 166 +++++++ .../generated/avm/lookup_div_u16_4.hpp | 166 +++++++ .../generated/avm/lookup_div_u16_5.hpp | 166 +++++++ .../generated/avm/lookup_div_u16_6.hpp | 166 +++++++ .../generated/avm/lookup_div_u16_7.hpp | 166 +++++++ .../vm/avm_trace/avm_alu_trace.cpp | 111 ++++- .../vm/avm_trace/avm_alu_trace.hpp | 16 + .../vm/avm_trace/avm_execution.cpp | 7 + .../barretenberg/vm/avm_trace/avm_trace.cpp | 120 ++++- .../barretenberg/vm/avm_trace/avm_trace.hpp | 3 + .../vm/generated/avm_circuit_builder.hpp | 116 ++++- .../barretenberg/vm/generated/avm_flavor.hpp | 417 +++++++++++++++++- .../barretenberg/vm/generated/avm_prover.cpp | 79 ++++ .../vm/generated/avm_verifier.cpp | 68 +++ .../vm/tests/avm_arithmetic.test.cpp | 90 +++- .../vm/tests/avm_bitwise.test.cpp | 158 +++---- .../vm/tests/avm_comparison.test.cpp | 11 - .../barretenberg/vm/tests/helpers.test.cpp | 12 + .../barretenberg/vm/tests/helpers.test.hpp | 4 + 27 files changed, 2897 insertions(+), 191 deletions(-) create mode 100644 barretenberg/cpp/src/barretenberg/relations/generated/avm/lookup_div_u16_0.hpp create mode 100644 barretenberg/cpp/src/barretenberg/relations/generated/avm/lookup_div_u16_1.hpp create mode 100644 barretenberg/cpp/src/barretenberg/relations/generated/avm/lookup_div_u16_2.hpp create mode 100644 barretenberg/cpp/src/barretenberg/relations/generated/avm/lookup_div_u16_3.hpp create mode 100644 barretenberg/cpp/src/barretenberg/relations/generated/avm/lookup_div_u16_4.hpp create mode 100644 barretenberg/cpp/src/barretenberg/relations/generated/avm/lookup_div_u16_5.hpp create mode 100644 barretenberg/cpp/src/barretenberg/relations/generated/avm/lookup_div_u16_6.hpp create mode 100644 barretenberg/cpp/src/barretenberg/relations/generated/avm/lookup_div_u16_7.hpp diff --git a/barretenberg/cpp/pil/avm/avm_alu.pil b/barretenberg/cpp/pil/avm/avm_alu.pil index 35771b3fb48..5d6db0544ba 100644 --- a/barretenberg/cpp/pil/avm/avm_alu.pil +++ b/barretenberg/cpp/pil/avm/avm_alu.pil @@ -64,7 +64,7 @@ namespace avm_alu(256); pol commit cf; // Compute predicate telling whether there is a row entry in the ALU table. - alu_sel = op_add + op_sub + op_mul + op_not + op_eq + op_cast + op_lt + op_lte + op_shr + op_shl; + alu_sel = op_add + op_sub + op_mul + op_not + op_eq + op_cast + op_lt + op_lte + op_shr + op_shl + op_div; cmp_sel = op_lt + op_lte; shift_sel = op_shl + op_shr; @@ -317,9 +317,9 @@ namespace avm_alu(256); // First condition is if borrow = 0, second condition is if borrow = 1 // This underflow check is done by the 128-bit check that is performed on each of these lo and hi limbs. #[SUB_LO_1] - (p_sub_a_lo - (53438638232309528389504892708671455232 - a_lo + p_a_borrow * 2 ** 128)) * (cmp_sel + op_cast) = 0; + (p_sub_a_lo - (53438638232309528389504892708671455232 - a_lo + p_a_borrow * 2 ** 128)) * (cmp_sel + op_cast + op_div_std) = 0; #[SUB_HI_1] - (p_sub_a_hi - (64323764613183177041862057485226039389 - a_hi - p_a_borrow)) * (cmp_sel + op_cast) = 0; + (p_sub_a_hi - (64323764613183177041862057485226039389 - a_hi - p_a_borrow)) * (cmp_sel + op_cast + op_div_std) = 0; pol commit p_sub_b_lo; pol commit p_sub_b_hi; @@ -438,13 +438,13 @@ namespace avm_alu(256); cmp_rng_ctr * ((1 - rng_chk_sel) * (1 - op_eq_diff_inv) + op_eq_diff_inv) - rng_chk_sel = 0; // We perform a range check if we have some range checks remaining or we are performing a comparison op - pol RNG_CHK_OP = rng_chk_sel + cmp_sel + op_cast + op_cast_prev + shift_lt_bit_len; + pol RNG_CHK_OP = rng_chk_sel + cmp_sel + op_cast + op_cast_prev + shift_lt_bit_len + op_div; pol commit rng_chk_lookup_selector; // TODO: Possible optimisation here if we swap the op_shl and op_shr with shift_lt_bit_len. // Shift_lt_bit_len is a more restrictive form therefore we can avoid performing redundant range checks when we know the result == 0. #[RNG_CHK_LOOKUP_SELECTOR] - rng_chk_lookup_selector' = cmp_sel' + rng_chk_sel' + op_add' + op_sub' + op_mul' + op_mul * u128_tag + op_cast' + op_cast_prev' + op_shl' + op_shr'; + rng_chk_lookup_selector' = cmp_sel' + rng_chk_sel' + op_add' + op_sub' + op_mul' + op_mul * u128_tag + op_cast' + op_cast_prev' + op_shl' + op_shr' + op_div'; // Perform 128-bit range check on lo part #[LOWER_CMP_RNG_CHK] @@ -622,3 +622,116 @@ namespace avm_alu(256); #[SHL_OUTPUT] op_shl * (ic - (b_lo * two_pow_s * shift_lt_bit_len)) = 0; + // ========= INTEGER DIVISION =============================== + // Operands: ia contains the dividend, ib contains the divisor, and ic contains the quotient (i.e. the result). + // All operands are restricted to be up to 128. + // The logic for integer division is to assert the correctness of this relationship: + // dividend - remainder = divisor * quotient ==> ia - remainder = ib * ic; where remainder < ib + // We do this using the following steps + // (1) The only non-trivial division is the situation where ia > ib && ib > 0 + // (a) if ia == ib => ic = 1 and remainder = 0 --> we can handle this as part of the standard division + // (b) if ia < ib => ic = 0 and remainder = ia --> isolating this case eliminates the risk of ia - remainder underflowing as remainder < ib < ia + // (c) if ib == 0 => error_tag = 1 --> Handled in main trace + // (2) Given ib and ic are restricted to U128, at most ib * ic will produce a 256-bit number. + // (3) We use the primality check from cmp to check that this product has not overflowed the field. + // The Primality check takes a field element as input and ouputs two 128-bit limbs. + // i.e. it checks that the field element, represented with two 128-bit limbs lies in [0, p). + // (a) Given x, PC(x) -> [x_lo, x_hi], where x_lo < 2**128 && x_hi < 2**128 && x == x_lo + x_hi * 2**128 + // (b) Additionally produces a witness that the x < (p - 1) + // p_sub_x_lo = p_lo - x_lo + borrow * 2**128 < 2**128 + // p_sub_x_hi = p_hi - x_hi - borrow < 2**128 + // (c) Range checks over 128-bits are applied to x_lo, x_hi, p_sub_x_lo, and p_sub_x_hi. + + // Range check the remainder < divisor. + pol commit remainder; + // The op_div boolean must be set based on which division case it is. + op_div = op_div_std + op_div_a_lt_b; + + // ======= Handling ia < ib ===== + // Boolean if ia < ib ==> ic = 0; + pol commit op_div_a_lt_b; + op_div_a_lt_b * (1 - op_div_a_lt_b) = 0; + // To show this, we constrain ib - ia - 1 to be within 128 bits. + // Since we need a range check we use the existing a_lo column that is range checked over 128 bits. + op_div_a_lt_b * (a_lo - (ib - ia - 1)) = 0; + op_div_a_lt_b * ic = 0; // ic = 0 + op_div_a_lt_b * (ia - remainder) = 0; // remainder = a, might not be needed. + + + // ====== Handling ia >= ib ===== + pol commit op_div_std; + op_div_std * (1 - op_div_std) = 0; + pol commit divisor_lo; // b + pol commit divisor_hi; + op_div_std * (ib - divisor_lo - 2**64 * divisor_hi) = 0; + pol commit quotient_lo; // c + pol commit quotient_hi; + op_div_std * (ic - quotient_lo - 2**64 * quotient_hi) = 0; + + // Multiplying the limbs gives us the following relations. + // (1) divisor_lo * quotient_lo --> Represents the bottom 128 bits of the result, i.e. values between [0, 2**128). + // (2) divisor_lo * quotient_hi + quotient_lo * divisor_hi --> Represents the middle 128 bits of the result, i.e. values between [2**64, 2**196) + // (3) divisor_hi * quotient_hi --> Represents the topmost 128 bits of the result, i.e. values between [2**128, 2**256). + + // We simplify (2) by further decomposing it into two limbs of 64 bits and adding the upper 64 bit to (3) + // divisor_lo * quotient_hi + quotient_lo * divisor_hi = partial_prod_lo + 2**64 * partial_prod_hi + // Need to range check that these are 64 bits + pol commit partial_prod_lo; + pol commit partial_prod_hi; + divisor_hi * quotient_lo + divisor_lo * quotient_hi = partial_prod_lo + 2**64 * partial_prod_hi; + + pol PRODUCT = divisor_lo * quotient_lo + 2**64 * partial_prod_lo + 2**128 * (partial_prod_hi + divisor_hi * quotient_hi); + + // a_lo and a_hi contains the hi and lo limbs of PRODUCT + // p_sub_a_lo and p_sub_a_hi contain the primality checks + #[ALU_PROD_DIV] + op_div_std * (PRODUCT - (a_lo + 2 ** 128 * a_hi)) = 0; + // Range checks already performed via a_lo and a_hi + // Primality checks already performed above via p_sub_a_lo and p_sub_a_hi + + // Range check remainder < ib and put the value in b_hi, it has to fit into a 128 bit range check + #[REMAINDER_RANGE_CHK] + op_div_std * (b_hi - (ib - remainder - 1)) = 0; + + // We need to perform 3 x 256-bit range checks: (a_lo, a_hi), (b_lo, b_hi), and (p_sub_a_lo, p_sub_a_hi) + // One range check happens in-line with the division + #[CMP_CTR_REL_3] + (cmp_rng_ctr' - 2) * op_div_std = 0; + + // If we have more range checks left we cannot do more divisions operations that might truncate the steps + rng_chk_sel * op_div_std = 0; + + // Check PRODUCT = ia - remainder + #[DIVISION_RELATION] + op_div_std * (PRODUCT - (ia - remainder)) = 0; + + // === DIVISION 64-BIT RANGE CHECKS + // 64-bit decompositions and implicit 64-bit range checks for each limb, + // TODO: We need extra slice registers because we are performing an additional 64-bit range check in the same row, look into re-using old columns or refactoring + // range checks to be more modular. + // boolean to account for the division-specific 64-bit range checks. + pol commit div_rng_chk_selector; + div_rng_chk_selector * (1 - div_rng_chk_selector) = 0; + // div_rng_chk_selector && div_rng_chk_selector' = 1 if op_div_std = 1 + div_rng_chk_selector * div_rng_chk_selector' = op_div_std; + + pol commit div_u16_r0; + pol commit div_u16_r1; + pol commit div_u16_r2; + pol commit div_u16_r3; + pol commit div_u16_r4; + pol commit div_u16_r5; + pol commit div_u16_r6; + pol commit div_u16_r7; + + divisor_lo = op_div_std * (div_u16_r0 + div_u16_r1 * 2**16 + div_u16_r2 * 2**32 + div_u16_r3 * 2**48); + divisor_hi = op_div_std * (div_u16_r4 + div_u16_r5 * 2**16 + div_u16_r6 * 2**32 + div_u16_r7 * 2**48); + quotient_lo = op_div_std * (div_u16_r0' + div_u16_r1' * 2**16 + div_u16_r2' * 2**32 + div_u16_r3' * 2**48); + quotient_hi = op_div_std * (div_u16_r4' + div_u16_r5' * 2**16 + div_u16_r6' * 2**32 + div_u16_r7' * 2**48); + + // We need an extra 128 bits to do 2 more 64-bit range checks. We use b_lo (128 bits) to store partial_prod_lo(64 bits) and partial_prod_hi(64 bits. + // Use a shift to access the slices (b_lo is moved into the alu slice registers on the next row anyways as part of the SHIFT_RELS_0 relations) + pol NEXT_SUM_64_LO = u8_r0' + u8_r1' * 2**8 + u16_r0' * 2**16 + u16_r1' * 2**32 + u16_r2' * 2**48; + pol NEXT_SUM_128_HI = u16_r3' + u16_r4' * 2**16 + u16_r5' * 2**32 + u16_r6' * 2**48; + partial_prod_lo = op_div_std * NEXT_SUM_64_LO; + partial_prod_hi = op_div_std * NEXT_SUM_128_HI; diff --git a/barretenberg/cpp/pil/avm/avm_main.pil b/barretenberg/cpp/pil/avm/avm_main.pil index 4306643acf3..8d9f3010ec4 100644 --- a/barretenberg/cpp/pil/avm/avm_main.pil +++ b/barretenberg/cpp/pil/avm/avm_main.pil @@ -197,15 +197,16 @@ namespace avm_main(256); #[SUBOP_FDIV] sel_op_fdiv * (1 - op_err) * (ic * ib - ia) = 0; - // When sel_op_fdiv == 1, we want ib == 0 <==> op_err == 1 + // When sel_op_fdiv == 1 or sel_op_div, we want ib == 0 <==> op_err == 1 // This can be achieved with the 2 following relations. // inv is an extra witness to show that we can invert ib, i.e., inv = ib^(-1) // If ib == 0, we have to set inv = 1 to satisfy the second relation, // because op_err == 1 from the first relation. + // TODO: Update the name of these relations once negative tests are updated #[SUBOP_FDIV_ZERO_ERR1] - sel_op_fdiv * (ib * inv - 1 + op_err) = 0; + (sel_op_fdiv + sel_op_div) * (ib * inv - 1 + op_err) = 0; #[SUBOP_FDIV_ZERO_ERR2] - sel_op_fdiv * op_err * (1 - inv) = 0; + (sel_op_fdiv + sel_op_div) * op_err * (1 - inv) = 0; // Enforcement that instruction tags are FF (tag constant 6). // TODO: These 2 conditions might be removed and enforced through @@ -222,7 +223,7 @@ namespace avm_main(256); // that exactly one sel_op_XXX must be true. // At this time, we have only division producing an error. #[SUBOP_ERROR_RELEVANT_OP] - op_err * (sel_op_fdiv - 1) = 0; + op_err * ((sel_op_fdiv + sel_op_div) - 1) = 0; // TODO: constraint that we stop execution at the first error (tag_err or op_err) // An error can only happen at the last sub-operation row. @@ -322,7 +323,7 @@ namespace avm_main(256); // Predicate to activate the copy of intermediate registers to ALU table. If tag_err == 1, // the operation is not copied to the ALU table. - alu_sel = ALU_ALL_SEL * (1 - tag_err); + alu_sel = ALU_ALL_SEL * (1 - tag_err) * (1 - op_err); // Dispatch the correct in_tag for alu ALU_R_TAG_SEL * (alu_in_tag - r_in_tag) = 0; @@ -472,3 +473,27 @@ namespace avm_main(256); #[LOOKUP_U16_14] avm_alu.rng_chk_lookup_selector {avm_alu.u16_r14 } in sel_rng_16 { clk }; + // ==== Additional row range checks for division + #[LOOKUP_DIV_U16_0] + avm_alu.div_rng_chk_selector {avm_alu.div_u16_r0} in sel_rng_16 { clk }; + + #[LOOKUP_DIV_U16_1] + avm_alu.div_rng_chk_selector {avm_alu.div_u16_r1 } in sel_rng_16 { clk }; + + #[LOOKUP_DIV_U16_2] + avm_alu.div_rng_chk_selector {avm_alu.div_u16_r2 } in sel_rng_16 { clk }; + + #[LOOKUP_DIV_U16_3] + avm_alu.div_rng_chk_selector {avm_alu.div_u16_r3 } in sel_rng_16 { clk }; + + #[LOOKUP_DIV_U16_4] + avm_alu.div_rng_chk_selector {avm_alu.div_u16_r4 } in sel_rng_16 { clk }; + + #[LOOKUP_DIV_U16_5] + avm_alu.div_rng_chk_selector {avm_alu.div_u16_r5 } in sel_rng_16 { clk }; + + #[LOOKUP_DIV_U16_6] + avm_alu.div_rng_chk_selector {avm_alu.div_u16_r6 } in sel_rng_16 { clk }; + + #[LOOKUP_DIV_U16_7] + avm_alu.div_rng_chk_selector {avm_alu.div_u16_r7 } in sel_rng_16 { clk }; diff --git a/barretenberg/cpp/src/barretenberg/relations/generated/avm/avm_alu.hpp b/barretenberg/cpp/src/barretenberg/relations/generated/avm/avm_alu.hpp index 95ced4b652b..2022d640185 100644 --- a/barretenberg/cpp/src/barretenberg/relations/generated/avm/avm_alu.hpp +++ b/barretenberg/cpp/src/barretenberg/relations/generated/avm/avm_alu.hpp @@ -23,6 +23,26 @@ template struct Avm_aluRow { FF avm_alu_cmp_rng_ctr_shift{}; FF avm_alu_cmp_sel{}; FF avm_alu_cmp_sel_shift{}; + FF avm_alu_div_rng_chk_selector{}; + FF avm_alu_div_rng_chk_selector_shift{}; + FF avm_alu_div_u16_r0{}; + FF avm_alu_div_u16_r0_shift{}; + FF avm_alu_div_u16_r1{}; + FF avm_alu_div_u16_r1_shift{}; + FF avm_alu_div_u16_r2{}; + FF avm_alu_div_u16_r2_shift{}; + FF avm_alu_div_u16_r3{}; + FF avm_alu_div_u16_r3_shift{}; + FF avm_alu_div_u16_r4{}; + FF avm_alu_div_u16_r4_shift{}; + FF avm_alu_div_u16_r5{}; + FF avm_alu_div_u16_r5_shift{}; + FF avm_alu_div_u16_r6{}; + FF avm_alu_div_u16_r6_shift{}; + FF avm_alu_div_u16_r7{}; + FF avm_alu_div_u16_r7_shift{}; + FF avm_alu_divisor_hi{}; + FF avm_alu_divisor_lo{}; FF avm_alu_ff_tag{}; FF avm_alu_ia{}; FF avm_alu_ib{}; @@ -34,6 +54,10 @@ template struct Avm_aluRow { FF avm_alu_op_cast_prev{}; FF avm_alu_op_cast_prev_shift{}; FF avm_alu_op_cast_shift{}; + FF avm_alu_op_div{}; + FF avm_alu_op_div_a_lt_b{}; + FF avm_alu_op_div_shift{}; + FF avm_alu_op_div_std{}; FF avm_alu_op_eq{}; FF avm_alu_op_eq_diff_inv{}; FF avm_alu_op_lt{}; @@ -57,6 +81,11 @@ template struct Avm_aluRow { FF avm_alu_p_sub_b_hi_shift{}; FF avm_alu_p_sub_b_lo{}; FF avm_alu_p_sub_b_lo_shift{}; + FF avm_alu_partial_prod_hi{}; + FF avm_alu_partial_prod_lo{}; + FF avm_alu_quotient_hi{}; + FF avm_alu_quotient_lo{}; + FF avm_alu_remainder{}; FF avm_alu_res_hi{}; FF avm_alu_res_lo{}; FF avm_alu_rng_chk_lookup_selector_shift{}; @@ -228,6 +257,18 @@ inline std::string get_relation_label_avm_alu(int index) case 64: return "SHL_OUTPUT"; + + case 74: + return "ALU_PROD_DIV"; + + case 75: + return "REMAINDER_RANGE_CHK"; + + case 76: + return "CMP_CTR_REL_3"; + + case 78: + return "DIVISION_RELATION"; } return std::to_string(index); } @@ -236,9 +277,10 @@ template class avm_aluImpl { public: using FF = FF_; - static constexpr std::array SUBRELATION_PARTIAL_LENGTHS{ - 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 5, 5, 5, 5, 6, 6, 8, 3, 4, 4, 5, 4, 4, 3, 4, 3, 3, 4, 3, 6, - 5, 3, 3, 3, 3, 4, 3, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 2, 5, 3, 3, 4, 4, 4, 4, 4, 3, 5, 5, 4, 5, 5, + static constexpr std::array SUBRELATION_PARTIAL_LENGTHS{ + 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 5, 5, 5, 5, 6, 6, 8, 3, 4, 4, 5, 4, 4, 3, 4, 3, + 3, 4, 3, 6, 5, 3, 3, 3, 3, 4, 3, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 2, 5, 3, 3, 4, 4, 4, 4, + 4, 3, 5, 5, 4, 5, 5, 2, 3, 3, 3, 3, 3, 4, 4, 3, 5, 3, 3, 3, 5, 3, 3, 4, 4, 4, 4, 4, 4, }; template @@ -252,13 +294,15 @@ template class avm_aluImpl { { Avm_DECLARE_VIEWS(0); - auto tmp = (avm_alu_alu_sel - - (((((((((avm_alu_op_add + avm_alu_op_sub) + avm_alu_op_mul) + avm_alu_op_not) + avm_alu_op_eq) + - avm_alu_op_cast) + - avm_alu_op_lt) + - avm_alu_op_lte) + - avm_alu_op_shr) + - avm_alu_op_shl)); + auto tmp = + (avm_alu_alu_sel - + ((((((((((avm_alu_op_add + avm_alu_op_sub) + avm_alu_op_mul) + avm_alu_op_not) + avm_alu_op_eq) + + avm_alu_op_cast) + + avm_alu_op_lt) + + avm_alu_op_lte) + + avm_alu_op_shr) + + avm_alu_op_shl) + + avm_alu_op_div)); tmp *= scaling_factor; std::get<0>(evals) += tmp; } @@ -575,7 +619,7 @@ template class avm_aluImpl { auto tmp = ((avm_alu_p_sub_a_lo - ((-avm_alu_a_lo + FF(uint256_t{ 4891460686036598784UL, 2896914383306846353UL, 0UL, 0UL })) + (avm_alu_p_a_borrow * FF(uint256_t{ 0UL, 0UL, 1UL, 0UL })))) * - (avm_alu_cmp_sel + avm_alu_op_cast)); + ((avm_alu_cmp_sel + avm_alu_op_cast) + avm_alu_op_div_std)); tmp *= scaling_factor; std::get<27>(evals) += tmp; } @@ -586,7 +630,7 @@ template class avm_aluImpl { auto tmp = ((avm_alu_p_sub_a_hi - ((-avm_alu_a_hi + FF(uint256_t{ 13281191951274694749UL, 3486998266802970665UL, 0UL, 0UL })) - avm_alu_p_a_borrow)) * - (avm_alu_cmp_sel + avm_alu_op_cast)); + ((avm_alu_cmp_sel + avm_alu_op_cast) + avm_alu_op_div_std)); tmp *= scaling_factor; std::get<28>(evals) += tmp; } @@ -694,14 +738,15 @@ template class avm_aluImpl { Avm_DECLARE_VIEWS(39); auto tmp = (avm_alu_rng_chk_lookup_selector_shift - - (((((((((avm_alu_cmp_sel_shift + avm_alu_rng_chk_sel_shift) + avm_alu_op_add_shift) + - avm_alu_op_sub_shift) + - avm_alu_op_mul_shift) + - (avm_alu_op_mul * avm_alu_u128_tag)) + - avm_alu_op_cast_shift) + - avm_alu_op_cast_prev_shift) + - avm_alu_op_shl_shift) + - avm_alu_op_shr_shift)); + ((((((((((avm_alu_cmp_sel_shift + avm_alu_rng_chk_sel_shift) + avm_alu_op_add_shift) + + avm_alu_op_sub_shift) + + avm_alu_op_mul_shift) + + (avm_alu_op_mul * avm_alu_u128_tag)) + + avm_alu_op_cast_shift) + + avm_alu_op_cast_prev_shift) + + avm_alu_op_shl_shift) + + avm_alu_op_shr_shift) + + avm_alu_op_div_shift)); tmp *= scaling_factor; std::get<39>(evals) += tmp; } @@ -709,16 +754,17 @@ template class avm_aluImpl { { Avm_DECLARE_VIEWS(40); - auto tmp = - (avm_alu_a_lo - (((((((((avm_alu_u8_r0 + (avm_alu_u8_r1 * FF(256))) + (avm_alu_u16_r0 * FF(65536))) + - (avm_alu_u16_r1 * FF(4294967296UL))) + - (avm_alu_u16_r2 * FF(281474976710656UL))) + - (avm_alu_u16_r3 * FF(uint256_t{ 0UL, 1UL, 0UL, 0UL }))) + - (avm_alu_u16_r4 * FF(uint256_t{ 0UL, 65536UL, 0UL, 0UL }))) + - (avm_alu_u16_r5 * FF(uint256_t{ 0UL, 4294967296UL, 0UL, 0UL }))) + - (avm_alu_u16_r6 * FF(uint256_t{ 0UL, 281474976710656UL, 0UL, 0UL }))) * - ((((avm_alu_rng_chk_sel + avm_alu_cmp_sel) + avm_alu_op_cast) + avm_alu_op_cast_prev) + - avm_alu_shift_lt_bit_len))); + auto tmp = (avm_alu_a_lo - + (((((((((avm_alu_u8_r0 + (avm_alu_u8_r1 * FF(256))) + (avm_alu_u16_r0 * FF(65536))) + + (avm_alu_u16_r1 * FF(4294967296UL))) + + (avm_alu_u16_r2 * FF(281474976710656UL))) + + (avm_alu_u16_r3 * FF(uint256_t{ 0UL, 1UL, 0UL, 0UL }))) + + (avm_alu_u16_r4 * FF(uint256_t{ 0UL, 65536UL, 0UL, 0UL }))) + + (avm_alu_u16_r5 * FF(uint256_t{ 0UL, 4294967296UL, 0UL, 0UL }))) + + (avm_alu_u16_r6 * FF(uint256_t{ 0UL, 281474976710656UL, 0UL, 0UL }))) * + (((((avm_alu_rng_chk_sel + avm_alu_cmp_sel) + avm_alu_op_cast) + avm_alu_op_cast_prev) + + avm_alu_shift_lt_bit_len) + + avm_alu_op_div))); tmp *= scaling_factor; std::get<40>(evals) += tmp; } @@ -733,8 +779,9 @@ template class avm_aluImpl { (avm_alu_u16_r12 * FF(uint256_t{ 0UL, 65536UL, 0UL, 0UL }))) + (avm_alu_u16_r13 * FF(uint256_t{ 0UL, 4294967296UL, 0UL, 0UL }))) + (avm_alu_u16_r14 * FF(uint256_t{ 0UL, 281474976710656UL, 0UL, 0UL }))) * - ((((avm_alu_rng_chk_sel + avm_alu_cmp_sel) + avm_alu_op_cast) + avm_alu_op_cast_prev) + - avm_alu_shift_lt_bit_len))); + (((((avm_alu_rng_chk_sel + avm_alu_cmp_sel) + avm_alu_op_cast) + avm_alu_op_cast_prev) + + avm_alu_shift_lt_bit_len) + + avm_alu_op_div))); tmp *= scaling_factor; std::get<41>(evals) += tmp; } @@ -958,6 +1005,213 @@ template class avm_aluImpl { tmp *= scaling_factor; std::get<64>(evals) += tmp; } + // Contribution 65 + { + Avm_DECLARE_VIEWS(65); + + auto tmp = (avm_alu_op_div - (avm_alu_op_div_std + avm_alu_op_div_a_lt_b)); + tmp *= scaling_factor; + std::get<65>(evals) += tmp; + } + // Contribution 66 + { + Avm_DECLARE_VIEWS(66); + + auto tmp = (avm_alu_op_div_a_lt_b * (-avm_alu_op_div_a_lt_b + FF(1))); + tmp *= scaling_factor; + std::get<66>(evals) += tmp; + } + // Contribution 67 + { + Avm_DECLARE_VIEWS(67); + + auto tmp = (avm_alu_op_div_a_lt_b * (avm_alu_a_lo - ((avm_alu_ib - avm_alu_ia) - FF(1)))); + tmp *= scaling_factor; + std::get<67>(evals) += tmp; + } + // Contribution 68 + { + Avm_DECLARE_VIEWS(68); + + auto tmp = (avm_alu_op_div_a_lt_b * avm_alu_ic); + tmp *= scaling_factor; + std::get<68>(evals) += tmp; + } + // Contribution 69 + { + Avm_DECLARE_VIEWS(69); + + auto tmp = (avm_alu_op_div_a_lt_b * (avm_alu_ia - avm_alu_remainder)); + tmp *= scaling_factor; + std::get<69>(evals) += tmp; + } + // Contribution 70 + { + Avm_DECLARE_VIEWS(70); + + auto tmp = (avm_alu_op_div_std * (-avm_alu_op_div_std + FF(1))); + tmp *= scaling_factor; + std::get<70>(evals) += tmp; + } + // Contribution 71 + { + Avm_DECLARE_VIEWS(71); + + auto tmp = (avm_alu_op_div_std * ((avm_alu_ib - avm_alu_divisor_lo) - + (avm_alu_divisor_hi * FF(uint256_t{ 0UL, 1UL, 0UL, 0UL })))); + tmp *= scaling_factor; + std::get<71>(evals) += tmp; + } + // Contribution 72 + { + Avm_DECLARE_VIEWS(72); + + auto tmp = (avm_alu_op_div_std * ((avm_alu_ic - avm_alu_quotient_lo) - + (avm_alu_quotient_hi * FF(uint256_t{ 0UL, 1UL, 0UL, 0UL })))); + tmp *= scaling_factor; + std::get<72>(evals) += tmp; + } + // Contribution 73 + { + Avm_DECLARE_VIEWS(73); + + auto tmp = (((avm_alu_divisor_hi * avm_alu_quotient_lo) + (avm_alu_divisor_lo * avm_alu_quotient_hi)) - + (avm_alu_partial_prod_lo + (avm_alu_partial_prod_hi * FF(uint256_t{ 0UL, 1UL, 0UL, 0UL })))); + tmp *= scaling_factor; + std::get<73>(evals) += tmp; + } + // Contribution 74 + { + Avm_DECLARE_VIEWS(74); + + auto tmp = (avm_alu_op_div_std * ((((avm_alu_divisor_lo * avm_alu_quotient_lo) + + (avm_alu_partial_prod_lo * FF(uint256_t{ 0UL, 1UL, 0UL, 0UL }))) + + ((avm_alu_partial_prod_hi + (avm_alu_divisor_hi * avm_alu_quotient_hi)) * + FF(uint256_t{ 0UL, 0UL, 1UL, 0UL }))) - + (avm_alu_a_lo + (avm_alu_a_hi * FF(uint256_t{ 0UL, 0UL, 1UL, 0UL }))))); + tmp *= scaling_factor; + std::get<74>(evals) += tmp; + } + // Contribution 75 + { + Avm_DECLARE_VIEWS(75); + + auto tmp = (avm_alu_op_div_std * (avm_alu_b_hi - ((avm_alu_ib - avm_alu_remainder) - FF(1)))); + tmp *= scaling_factor; + std::get<75>(evals) += tmp; + } + // Contribution 76 + { + Avm_DECLARE_VIEWS(76); + + auto tmp = ((avm_alu_cmp_rng_ctr_shift - FF(2)) * avm_alu_op_div_std); + tmp *= scaling_factor; + std::get<76>(evals) += tmp; + } + // Contribution 77 + { + Avm_DECLARE_VIEWS(77); + + auto tmp = (avm_alu_rng_chk_sel * avm_alu_op_div_std); + tmp *= scaling_factor; + std::get<77>(evals) += tmp; + } + // Contribution 78 + { + Avm_DECLARE_VIEWS(78); + + auto tmp = (avm_alu_op_div_std * ((((avm_alu_divisor_lo * avm_alu_quotient_lo) + + (avm_alu_partial_prod_lo * FF(uint256_t{ 0UL, 1UL, 0UL, 0UL }))) + + ((avm_alu_partial_prod_hi + (avm_alu_divisor_hi * avm_alu_quotient_hi)) * + FF(uint256_t{ 0UL, 0UL, 1UL, 0UL }))) - + (avm_alu_ia - avm_alu_remainder))); + tmp *= scaling_factor; + std::get<78>(evals) += tmp; + } + // Contribution 79 + { + Avm_DECLARE_VIEWS(79); + + auto tmp = (avm_alu_div_rng_chk_selector * (-avm_alu_div_rng_chk_selector + FF(1))); + tmp *= scaling_factor; + std::get<79>(evals) += tmp; + } + // Contribution 80 + { + Avm_DECLARE_VIEWS(80); + + auto tmp = ((avm_alu_div_rng_chk_selector * avm_alu_div_rng_chk_selector_shift) - avm_alu_op_div_std); + tmp *= scaling_factor; + std::get<80>(evals) += tmp; + } + // Contribution 81 + { + Avm_DECLARE_VIEWS(81); + + auto tmp = + (avm_alu_divisor_lo - (avm_alu_op_div_std * (((avm_alu_div_u16_r0 + (avm_alu_div_u16_r1 * FF(65536))) + + (avm_alu_div_u16_r2 * FF(4294967296UL))) + + (avm_alu_div_u16_r3 * FF(281474976710656UL))))); + tmp *= scaling_factor; + std::get<81>(evals) += tmp; + } + // Contribution 82 + { + Avm_DECLARE_VIEWS(82); + + auto tmp = + (avm_alu_divisor_hi - (avm_alu_op_div_std * (((avm_alu_div_u16_r4 + (avm_alu_div_u16_r5 * FF(65536))) + + (avm_alu_div_u16_r6 * FF(4294967296UL))) + + (avm_alu_div_u16_r7 * FF(281474976710656UL))))); + tmp *= scaling_factor; + std::get<82>(evals) += tmp; + } + // Contribution 83 + { + Avm_DECLARE_VIEWS(83); + + auto tmp = (avm_alu_quotient_lo - + (avm_alu_op_div_std * (((avm_alu_div_u16_r0_shift + (avm_alu_div_u16_r1_shift * FF(65536))) + + (avm_alu_div_u16_r2_shift * FF(4294967296UL))) + + (avm_alu_div_u16_r3_shift * FF(281474976710656UL))))); + tmp *= scaling_factor; + std::get<83>(evals) += tmp; + } + // Contribution 84 + { + Avm_DECLARE_VIEWS(84); + + auto tmp = (avm_alu_quotient_hi - + (avm_alu_op_div_std * (((avm_alu_div_u16_r4_shift + (avm_alu_div_u16_r5_shift * FF(65536))) + + (avm_alu_div_u16_r6_shift * FF(4294967296UL))) + + (avm_alu_div_u16_r7_shift * FF(281474976710656UL))))); + tmp *= scaling_factor; + std::get<84>(evals) += tmp; + } + // Contribution 85 + { + Avm_DECLARE_VIEWS(85); + + auto tmp = + (avm_alu_partial_prod_lo - + (avm_alu_op_div_std * + ((((avm_alu_u8_r0_shift + (avm_alu_u8_r1_shift * FF(256))) + (avm_alu_u16_r0_shift * FF(65536))) + + (avm_alu_u16_r1_shift * FF(4294967296UL))) + + (avm_alu_u16_r2_shift * FF(281474976710656UL))))); + tmp *= scaling_factor; + std::get<85>(evals) += tmp; + } + // Contribution 86 + { + Avm_DECLARE_VIEWS(86); + + auto tmp = (avm_alu_partial_prod_hi - + (avm_alu_op_div_std * (((avm_alu_u16_r3_shift + (avm_alu_u16_r4_shift * FF(65536))) + + (avm_alu_u16_r5_shift * FF(4294967296UL))) + + (avm_alu_u16_r6_shift * FF(281474976710656UL))))); + tmp *= scaling_factor; + std::get<86>(evals) += tmp; + } } }; diff --git a/barretenberg/cpp/src/barretenberg/relations/generated/avm/avm_main.hpp b/barretenberg/cpp/src/barretenberg/relations/generated/avm/avm_main.hpp index 681210ee41d..27319832d00 100644 --- a/barretenberg/cpp/src/barretenberg/relations/generated/avm/avm_main.hpp +++ b/barretenberg/cpp/src/barretenberg/relations/generated/avm/avm_main.hpp @@ -131,7 +131,7 @@ template class avm_mainImpl { static constexpr std::array SUBRELATION_PARTIAL_LENGTHS{ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 5, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 5, 3, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, + 3, 3, 5, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 5, 3, 4, 4, 3, 3, 3, 3, 3, 4, 3, 3, 3, 2, }; template @@ -451,7 +451,8 @@ template class avm_mainImpl { { Avm_DECLARE_VIEWS(38); - auto tmp = (avm_main_sel_op_fdiv * (((avm_main_ib * avm_main_inv) - FF(1)) + avm_main_op_err)); + auto tmp = ((avm_main_sel_op_fdiv + avm_main_sel_op_div) * + (((avm_main_ib * avm_main_inv) - FF(1)) + avm_main_op_err)); tmp *= scaling_factor; std::get<38>(evals) += tmp; } @@ -459,7 +460,7 @@ template class avm_mainImpl { { Avm_DECLARE_VIEWS(39); - auto tmp = ((avm_main_sel_op_fdiv * avm_main_op_err) * (-avm_main_inv + FF(1))); + auto tmp = (((avm_main_sel_op_fdiv + avm_main_sel_op_div) * avm_main_op_err) * (-avm_main_inv + FF(1))); tmp *= scaling_factor; std::get<39>(evals) += tmp; } @@ -483,7 +484,7 @@ template class avm_mainImpl { { Avm_DECLARE_VIEWS(42); - auto tmp = (avm_main_op_err * (avm_main_sel_op_fdiv - FF(1))); + auto tmp = (avm_main_op_err * ((avm_main_sel_op_fdiv + avm_main_sel_op_div) - FF(1))); tmp *= scaling_factor; std::get<42>(evals) += tmp; } @@ -676,15 +677,16 @@ template class avm_mainImpl { auto tmp = (avm_main_alu_sel - - (((((((((((avm_main_sel_op_add + avm_main_sel_op_sub) + avm_main_sel_op_mul) + avm_main_sel_op_div) + - avm_main_sel_op_not) + - avm_main_sel_op_eq) + - avm_main_sel_op_lt) + - avm_main_sel_op_lte) + - avm_main_sel_op_shr) + - avm_main_sel_op_shl) + - avm_main_sel_op_cast) * - (-avm_main_tag_err + FF(1)))); + ((((((((((((avm_main_sel_op_add + avm_main_sel_op_sub) + avm_main_sel_op_mul) + avm_main_sel_op_div) + + avm_main_sel_op_not) + + avm_main_sel_op_eq) + + avm_main_sel_op_lt) + + avm_main_sel_op_lte) + + avm_main_sel_op_shr) + + avm_main_sel_op_shl) + + avm_main_sel_op_cast) * + (-avm_main_tag_err + FF(1))) * + (-avm_main_op_err + FF(1)))); tmp *= scaling_factor; std::get<64>(evals) += tmp; } diff --git a/barretenberg/cpp/src/barretenberg/relations/generated/avm/declare_views.hpp b/barretenberg/cpp/src/barretenberg/relations/generated/avm/declare_views.hpp index 5225e83adfa..8b595c5ab27 100644 --- a/barretenberg/cpp/src/barretenberg/relations/generated/avm/declare_views.hpp +++ b/barretenberg/cpp/src/barretenberg/relations/generated/avm/declare_views.hpp @@ -14,6 +14,17 @@ [[maybe_unused]] auto avm_alu_clk = View(new_term.avm_alu_clk); \ [[maybe_unused]] auto avm_alu_cmp_rng_ctr = View(new_term.avm_alu_cmp_rng_ctr); \ [[maybe_unused]] auto avm_alu_cmp_sel = View(new_term.avm_alu_cmp_sel); \ + [[maybe_unused]] auto avm_alu_div_rng_chk_selector = View(new_term.avm_alu_div_rng_chk_selector); \ + [[maybe_unused]] auto avm_alu_div_u16_r0 = View(new_term.avm_alu_div_u16_r0); \ + [[maybe_unused]] auto avm_alu_div_u16_r1 = View(new_term.avm_alu_div_u16_r1); \ + [[maybe_unused]] auto avm_alu_div_u16_r2 = View(new_term.avm_alu_div_u16_r2); \ + [[maybe_unused]] auto avm_alu_div_u16_r3 = View(new_term.avm_alu_div_u16_r3); \ + [[maybe_unused]] auto avm_alu_div_u16_r4 = View(new_term.avm_alu_div_u16_r4); \ + [[maybe_unused]] auto avm_alu_div_u16_r5 = View(new_term.avm_alu_div_u16_r5); \ + [[maybe_unused]] auto avm_alu_div_u16_r6 = View(new_term.avm_alu_div_u16_r6); \ + [[maybe_unused]] auto avm_alu_div_u16_r7 = View(new_term.avm_alu_div_u16_r7); \ + [[maybe_unused]] auto avm_alu_divisor_hi = View(new_term.avm_alu_divisor_hi); \ + [[maybe_unused]] auto avm_alu_divisor_lo = View(new_term.avm_alu_divisor_lo); \ [[maybe_unused]] auto avm_alu_ff_tag = View(new_term.avm_alu_ff_tag); \ [[maybe_unused]] auto avm_alu_ia = View(new_term.avm_alu_ia); \ [[maybe_unused]] auto avm_alu_ib = View(new_term.avm_alu_ib); \ @@ -23,6 +34,8 @@ [[maybe_unused]] auto avm_alu_op_cast = View(new_term.avm_alu_op_cast); \ [[maybe_unused]] auto avm_alu_op_cast_prev = View(new_term.avm_alu_op_cast_prev); \ [[maybe_unused]] auto avm_alu_op_div = View(new_term.avm_alu_op_div); \ + [[maybe_unused]] auto avm_alu_op_div_a_lt_b = View(new_term.avm_alu_op_div_a_lt_b); \ + [[maybe_unused]] auto avm_alu_op_div_std = View(new_term.avm_alu_op_div_std); \ [[maybe_unused]] auto avm_alu_op_eq = View(new_term.avm_alu_op_eq); \ [[maybe_unused]] auto avm_alu_op_eq_diff_inv = View(new_term.avm_alu_op_eq_diff_inv); \ [[maybe_unused]] auto avm_alu_op_lt = View(new_term.avm_alu_op_lt); \ @@ -38,6 +51,11 @@ [[maybe_unused]] auto avm_alu_p_sub_a_lo = View(new_term.avm_alu_p_sub_a_lo); \ [[maybe_unused]] auto avm_alu_p_sub_b_hi = View(new_term.avm_alu_p_sub_b_hi); \ [[maybe_unused]] auto avm_alu_p_sub_b_lo = View(new_term.avm_alu_p_sub_b_lo); \ + [[maybe_unused]] auto avm_alu_partial_prod_hi = View(new_term.avm_alu_partial_prod_hi); \ + [[maybe_unused]] auto avm_alu_partial_prod_lo = View(new_term.avm_alu_partial_prod_lo); \ + [[maybe_unused]] auto avm_alu_quotient_hi = View(new_term.avm_alu_quotient_hi); \ + [[maybe_unused]] auto avm_alu_quotient_lo = View(new_term.avm_alu_quotient_lo); \ + [[maybe_unused]] auto avm_alu_remainder = View(new_term.avm_alu_remainder); \ [[maybe_unused]] auto avm_alu_res_hi = View(new_term.avm_alu_res_hi); \ [[maybe_unused]] auto avm_alu_res_lo = View(new_term.avm_alu_res_lo); \ [[maybe_unused]] auto avm_alu_rng_chk_lookup_selector = View(new_term.avm_alu_rng_chk_lookup_selector); \ @@ -215,6 +233,14 @@ [[maybe_unused]] auto lookup_u16_12 = View(new_term.lookup_u16_12); \ [[maybe_unused]] auto lookup_u16_13 = View(new_term.lookup_u16_13); \ [[maybe_unused]] auto lookup_u16_14 = View(new_term.lookup_u16_14); \ + [[maybe_unused]] auto lookup_div_u16_0 = View(new_term.lookup_div_u16_0); \ + [[maybe_unused]] auto lookup_div_u16_1 = View(new_term.lookup_div_u16_1); \ + [[maybe_unused]] auto lookup_div_u16_2 = View(new_term.lookup_div_u16_2); \ + [[maybe_unused]] auto lookup_div_u16_3 = View(new_term.lookup_div_u16_3); \ + [[maybe_unused]] auto lookup_div_u16_4 = View(new_term.lookup_div_u16_4); \ + [[maybe_unused]] auto lookup_div_u16_5 = View(new_term.lookup_div_u16_5); \ + [[maybe_unused]] auto lookup_div_u16_6 = View(new_term.lookup_div_u16_6); \ + [[maybe_unused]] auto lookup_div_u16_7 = View(new_term.lookup_div_u16_7); \ [[maybe_unused]] auto lookup_byte_lengths_counts = View(new_term.lookup_byte_lengths_counts); \ [[maybe_unused]] auto lookup_byte_operations_counts = View(new_term.lookup_byte_operations_counts); \ [[maybe_unused]] auto incl_main_tag_err_counts = View(new_term.incl_main_tag_err_counts); \ @@ -240,6 +266,14 @@ [[maybe_unused]] auto lookup_u16_12_counts = View(new_term.lookup_u16_12_counts); \ [[maybe_unused]] auto lookup_u16_13_counts = View(new_term.lookup_u16_13_counts); \ [[maybe_unused]] auto lookup_u16_14_counts = View(new_term.lookup_u16_14_counts); \ + [[maybe_unused]] auto lookup_div_u16_0_counts = View(new_term.lookup_div_u16_0_counts); \ + [[maybe_unused]] auto lookup_div_u16_1_counts = View(new_term.lookup_div_u16_1_counts); \ + [[maybe_unused]] auto lookup_div_u16_2_counts = View(new_term.lookup_div_u16_2_counts); \ + [[maybe_unused]] auto lookup_div_u16_3_counts = View(new_term.lookup_div_u16_3_counts); \ + [[maybe_unused]] auto lookup_div_u16_4_counts = View(new_term.lookup_div_u16_4_counts); \ + [[maybe_unused]] auto lookup_div_u16_5_counts = View(new_term.lookup_div_u16_5_counts); \ + [[maybe_unused]] auto lookup_div_u16_6_counts = View(new_term.lookup_div_u16_6_counts); \ + [[maybe_unused]] auto lookup_div_u16_7_counts = View(new_term.lookup_div_u16_7_counts); \ [[maybe_unused]] auto avm_alu_a_hi_shift = View(new_term.avm_alu_a_hi_shift); \ [[maybe_unused]] auto avm_alu_a_lo_shift = View(new_term.avm_alu_a_lo_shift); \ [[maybe_unused]] auto avm_alu_alu_sel_shift = View(new_term.avm_alu_alu_sel_shift); \ @@ -247,9 +281,19 @@ [[maybe_unused]] auto avm_alu_b_lo_shift = View(new_term.avm_alu_b_lo_shift); \ [[maybe_unused]] auto avm_alu_cmp_rng_ctr_shift = View(new_term.avm_alu_cmp_rng_ctr_shift); \ [[maybe_unused]] auto avm_alu_cmp_sel_shift = View(new_term.avm_alu_cmp_sel_shift); \ + [[maybe_unused]] auto avm_alu_div_rng_chk_selector_shift = View(new_term.avm_alu_div_rng_chk_selector_shift); \ + [[maybe_unused]] auto avm_alu_div_u16_r0_shift = View(new_term.avm_alu_div_u16_r0_shift); \ + [[maybe_unused]] auto avm_alu_div_u16_r1_shift = View(new_term.avm_alu_div_u16_r1_shift); \ + [[maybe_unused]] auto avm_alu_div_u16_r2_shift = View(new_term.avm_alu_div_u16_r2_shift); \ + [[maybe_unused]] auto avm_alu_div_u16_r3_shift = View(new_term.avm_alu_div_u16_r3_shift); \ + [[maybe_unused]] auto avm_alu_div_u16_r4_shift = View(new_term.avm_alu_div_u16_r4_shift); \ + [[maybe_unused]] auto avm_alu_div_u16_r5_shift = View(new_term.avm_alu_div_u16_r5_shift); \ + [[maybe_unused]] auto avm_alu_div_u16_r6_shift = View(new_term.avm_alu_div_u16_r6_shift); \ + [[maybe_unused]] auto avm_alu_div_u16_r7_shift = View(new_term.avm_alu_div_u16_r7_shift); \ [[maybe_unused]] auto avm_alu_op_add_shift = View(new_term.avm_alu_op_add_shift); \ [[maybe_unused]] auto avm_alu_op_cast_prev_shift = View(new_term.avm_alu_op_cast_prev_shift); \ [[maybe_unused]] auto avm_alu_op_cast_shift = View(new_term.avm_alu_op_cast_shift); \ + [[maybe_unused]] auto avm_alu_op_div_shift = View(new_term.avm_alu_op_div_shift); \ [[maybe_unused]] auto avm_alu_op_mul_shift = View(new_term.avm_alu_op_mul_shift); \ [[maybe_unused]] auto avm_alu_op_shl_shift = View(new_term.avm_alu_op_shl_shift); \ [[maybe_unused]] auto avm_alu_op_shr_shift = View(new_term.avm_alu_op_shr_shift); \ diff --git a/barretenberg/cpp/src/barretenberg/relations/generated/avm/lookup_div_u16_0.hpp b/barretenberg/cpp/src/barretenberg/relations/generated/avm/lookup_div_u16_0.hpp new file mode 100644 index 00000000000..67284e42972 --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/relations/generated/avm/lookup_div_u16_0.hpp @@ -0,0 +1,166 @@ + + +#pragma once + +#include "barretenberg/relations/generic_lookup/generic_lookup_relation.hpp" + +#include +#include + +namespace bb { + +/** + * @brief This class contains an example of how to set LookupSettings classes used by the + * GenericLookupRelationImpl class to specify a scaled lookup + * + * @details To create your own lookup: + * 1) Create a copy of this class and rename it + * 2) Update all the values with the ones needed for your lookup + * 3) Update "DECLARE_LOOKUP_IMPLEMENTATIONS_FOR_ALL_SETTINGS" and "DEFINE_LOOKUP_IMPLEMENTATIONS_FOR_ALL_SETTINGS" to + * include the new settings + * 4) Add the relation with the chosen settings to Relations in the flavor (for example,"` + * using Relations = std::tuple>;)` + * + */ +class lookup_div_u16_0_lookup_settings { + public: + /** + * @brief The number of read terms (how many lookups we perform) in each row + * + */ + static constexpr size_t READ_TERMS = 1; + /** + * @brief The number of write terms (how many additions to the lookup table we make) in each row + * + */ + static constexpr size_t WRITE_TERMS = 1; + + /** + * @brief The type of READ_TERM used for each read index (basic and scaled) + * + */ + static constexpr size_t READ_TERM_TYPES[READ_TERMS] = { 0 }; + + /** + * @brief They type of WRITE_TERM used for each write index + * + */ + static constexpr size_t WRITE_TERM_TYPES[WRITE_TERMS] = { 0 }; + + /** + * @brief How many values represent a single lookup object. This value is used by the automatic read term + * implementation in the relation in case the lookup is a basic or scaled tuple and in the write term if it's a + * basic tuple + * + */ + static constexpr size_t LOOKUP_TUPLE_SIZE = 1; + + /** + * @brief The polynomial degree of the relation telling us if the inverse polynomial value needs to be computed + * + */ + static constexpr size_t INVERSE_EXISTS_POLYNOMIAL_DEGREE = 4; + + /** + * @brief The degree of the read term if implemented arbitrarily. This value is not used by basic and scaled read + * terms, but will cause compilation error if not defined + * + */ + static constexpr size_t READ_TERM_DEGREE = 0; + + /** + * @brief The degree of the write term if implemented arbitrarily. This value is not used by the basic write + * term, but will cause compilation error if not defined + * + */ + + static constexpr size_t WRITE_TERM_DEGREE = 0; + + /** + * @brief If this method returns true on a row of values, then the inverse polynomial exists at this index. + * Otherwise the value needs to be set to zero. + * + * @details If this is true then the lookup takes place in this row + * + */ + + template static inline auto inverse_polynomial_is_computed_at_row(const AllEntities& in) + { + return (in.avm_alu_div_rng_chk_selector == 1 || in.avm_main_sel_rng_16 == 1); + } + + /** + * @brief Subprocedure for computing the value deciding if the inverse polynomial value needs to be checked in this + * row + * + * @tparam Accumulator Type specified by the lookup relation + * @tparam AllEntities Values/Univariates of all entities row + * @param in Value/Univariate of all entities at row/edge + * @return Accumulator + */ + + template + static inline auto compute_inverse_exists(const AllEntities& in) + { + using View = typename Accumulator::View; + const auto is_operation = View(in.avm_alu_div_rng_chk_selector); + const auto is_table_entry = View(in.avm_main_sel_rng_16); + return (is_operation + is_table_entry - is_operation * is_table_entry); + } + + /** + * @brief Get all the entities for the lookup when need to update them + * + * @details The generic structure of this tuple is described in ./generic_lookup_relation.hpp . The following is + description for the current case: + The entities are returned as a tuple of references in the following order (this is for ): + * - The entity/polynomial used to store the product of the inverse values + * - The entity/polynomial that specifies how many times the lookup table entry at this row has been looked up + * - READ_TERMS entities/polynomials that enable individual lookup operations + * - The entity/polynomial that enables adding an entry to the lookup table in this row + * - LOOKUP_TUPLE_SIZE entities/polynomials representing the basic tuple being looked up as the first read term + * - LOOKUP_TUPLE_SIZE entities/polynomials representing the previous accumulators in the second read term + (scaled tuple) + * - LOOKUP_TUPLE_SIZE entities/polynomials representing the shifts in the second read term (scaled tuple) + * - LOOKUP_TUPLE_SIZE entities/polynomials representing the current accumulators in the second read term + (scaled tuple) + * - LOOKUP_TUPLE_SIZE entities/polynomials representing basic tuples added to the table + * + * @return All the entities needed for the lookup + */ + + template static inline auto get_const_entities(const AllEntities& in) + { + + return std::forward_as_tuple(in.lookup_div_u16_0, + in.lookup_div_u16_0_counts, + in.avm_alu_div_rng_chk_selector, + in.avm_main_sel_rng_16, + in.avm_alu_div_u16_r0, + in.avm_main_clk); + } + + /** + * @brief Get all the entities for the lookup when we only need to read them + * @details Same as in get_const_entities, but nonconst + * + * @return All the entities needed for the lookup + */ + + template static inline auto get_nonconst_entities(AllEntities& in) + { + + return std::forward_as_tuple(in.lookup_div_u16_0, + in.lookup_div_u16_0_counts, + in.avm_alu_div_rng_chk_selector, + in.avm_main_sel_rng_16, + in.avm_alu_div_u16_r0, + in.avm_main_clk); + } +}; + +template using lookup_div_u16_0_relation = GenericLookupRelation; +template using lookup_div_u16_0 = GenericLookup; + +} // namespace bb diff --git a/barretenberg/cpp/src/barretenberg/relations/generated/avm/lookup_div_u16_1.hpp b/barretenberg/cpp/src/barretenberg/relations/generated/avm/lookup_div_u16_1.hpp new file mode 100644 index 00000000000..38c6fd614f8 --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/relations/generated/avm/lookup_div_u16_1.hpp @@ -0,0 +1,166 @@ + + +#pragma once + +#include "barretenberg/relations/generic_lookup/generic_lookup_relation.hpp" + +#include +#include + +namespace bb { + +/** + * @brief This class contains an example of how to set LookupSettings classes used by the + * GenericLookupRelationImpl class to specify a scaled lookup + * + * @details To create your own lookup: + * 1) Create a copy of this class and rename it + * 2) Update all the values with the ones needed for your lookup + * 3) Update "DECLARE_LOOKUP_IMPLEMENTATIONS_FOR_ALL_SETTINGS" and "DEFINE_LOOKUP_IMPLEMENTATIONS_FOR_ALL_SETTINGS" to + * include the new settings + * 4) Add the relation with the chosen settings to Relations in the flavor (for example,"` + * using Relations = std::tuple>;)` + * + */ +class lookup_div_u16_1_lookup_settings { + public: + /** + * @brief The number of read terms (how many lookups we perform) in each row + * + */ + static constexpr size_t READ_TERMS = 1; + /** + * @brief The number of write terms (how many additions to the lookup table we make) in each row + * + */ + static constexpr size_t WRITE_TERMS = 1; + + /** + * @brief The type of READ_TERM used for each read index (basic and scaled) + * + */ + static constexpr size_t READ_TERM_TYPES[READ_TERMS] = { 0 }; + + /** + * @brief They type of WRITE_TERM used for each write index + * + */ + static constexpr size_t WRITE_TERM_TYPES[WRITE_TERMS] = { 0 }; + + /** + * @brief How many values represent a single lookup object. This value is used by the automatic read term + * implementation in the relation in case the lookup is a basic or scaled tuple and in the write term if it's a + * basic tuple + * + */ + static constexpr size_t LOOKUP_TUPLE_SIZE = 1; + + /** + * @brief The polynomial degree of the relation telling us if the inverse polynomial value needs to be computed + * + */ + static constexpr size_t INVERSE_EXISTS_POLYNOMIAL_DEGREE = 4; + + /** + * @brief The degree of the read term if implemented arbitrarily. This value is not used by basic and scaled read + * terms, but will cause compilation error if not defined + * + */ + static constexpr size_t READ_TERM_DEGREE = 0; + + /** + * @brief The degree of the write term if implemented arbitrarily. This value is not used by the basic write + * term, but will cause compilation error if not defined + * + */ + + static constexpr size_t WRITE_TERM_DEGREE = 0; + + /** + * @brief If this method returns true on a row of values, then the inverse polynomial exists at this index. + * Otherwise the value needs to be set to zero. + * + * @details If this is true then the lookup takes place in this row + * + */ + + template static inline auto inverse_polynomial_is_computed_at_row(const AllEntities& in) + { + return (in.avm_alu_div_rng_chk_selector == 1 || in.avm_main_sel_rng_16 == 1); + } + + /** + * @brief Subprocedure for computing the value deciding if the inverse polynomial value needs to be checked in this + * row + * + * @tparam Accumulator Type specified by the lookup relation + * @tparam AllEntities Values/Univariates of all entities row + * @param in Value/Univariate of all entities at row/edge + * @return Accumulator + */ + + template + static inline auto compute_inverse_exists(const AllEntities& in) + { + using View = typename Accumulator::View; + const auto is_operation = View(in.avm_alu_div_rng_chk_selector); + const auto is_table_entry = View(in.avm_main_sel_rng_16); + return (is_operation + is_table_entry - is_operation * is_table_entry); + } + + /** + * @brief Get all the entities for the lookup when need to update them + * + * @details The generic structure of this tuple is described in ./generic_lookup_relation.hpp . The following is + description for the current case: + The entities are returned as a tuple of references in the following order (this is for ): + * - The entity/polynomial used to store the product of the inverse values + * - The entity/polynomial that specifies how many times the lookup table entry at this row has been looked up + * - READ_TERMS entities/polynomials that enable individual lookup operations + * - The entity/polynomial that enables adding an entry to the lookup table in this row + * - LOOKUP_TUPLE_SIZE entities/polynomials representing the basic tuple being looked up as the first read term + * - LOOKUP_TUPLE_SIZE entities/polynomials representing the previous accumulators in the second read term + (scaled tuple) + * - LOOKUP_TUPLE_SIZE entities/polynomials representing the shifts in the second read term (scaled tuple) + * - LOOKUP_TUPLE_SIZE entities/polynomials representing the current accumulators in the second read term + (scaled tuple) + * - LOOKUP_TUPLE_SIZE entities/polynomials representing basic tuples added to the table + * + * @return All the entities needed for the lookup + */ + + template static inline auto get_const_entities(const AllEntities& in) + { + + return std::forward_as_tuple(in.lookup_div_u16_1, + in.lookup_div_u16_1_counts, + in.avm_alu_div_rng_chk_selector, + in.avm_main_sel_rng_16, + in.avm_alu_div_u16_r1, + in.avm_main_clk); + } + + /** + * @brief Get all the entities for the lookup when we only need to read them + * @details Same as in get_const_entities, but nonconst + * + * @return All the entities needed for the lookup + */ + + template static inline auto get_nonconst_entities(AllEntities& in) + { + + return std::forward_as_tuple(in.lookup_div_u16_1, + in.lookup_div_u16_1_counts, + in.avm_alu_div_rng_chk_selector, + in.avm_main_sel_rng_16, + in.avm_alu_div_u16_r1, + in.avm_main_clk); + } +}; + +template using lookup_div_u16_1_relation = GenericLookupRelation; +template using lookup_div_u16_1 = GenericLookup; + +} // namespace bb diff --git a/barretenberg/cpp/src/barretenberg/relations/generated/avm/lookup_div_u16_2.hpp b/barretenberg/cpp/src/barretenberg/relations/generated/avm/lookup_div_u16_2.hpp new file mode 100644 index 00000000000..36c347a5ba9 --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/relations/generated/avm/lookup_div_u16_2.hpp @@ -0,0 +1,166 @@ + + +#pragma once + +#include "barretenberg/relations/generic_lookup/generic_lookup_relation.hpp" + +#include +#include + +namespace bb { + +/** + * @brief This class contains an example of how to set LookupSettings classes used by the + * GenericLookupRelationImpl class to specify a scaled lookup + * + * @details To create your own lookup: + * 1) Create a copy of this class and rename it + * 2) Update all the values with the ones needed for your lookup + * 3) Update "DECLARE_LOOKUP_IMPLEMENTATIONS_FOR_ALL_SETTINGS" and "DEFINE_LOOKUP_IMPLEMENTATIONS_FOR_ALL_SETTINGS" to + * include the new settings + * 4) Add the relation with the chosen settings to Relations in the flavor (for example,"` + * using Relations = std::tuple>;)` + * + */ +class lookup_div_u16_2_lookup_settings { + public: + /** + * @brief The number of read terms (how many lookups we perform) in each row + * + */ + static constexpr size_t READ_TERMS = 1; + /** + * @brief The number of write terms (how many additions to the lookup table we make) in each row + * + */ + static constexpr size_t WRITE_TERMS = 1; + + /** + * @brief The type of READ_TERM used for each read index (basic and scaled) + * + */ + static constexpr size_t READ_TERM_TYPES[READ_TERMS] = { 0 }; + + /** + * @brief They type of WRITE_TERM used for each write index + * + */ + static constexpr size_t WRITE_TERM_TYPES[WRITE_TERMS] = { 0 }; + + /** + * @brief How many values represent a single lookup object. This value is used by the automatic read term + * implementation in the relation in case the lookup is a basic or scaled tuple and in the write term if it's a + * basic tuple + * + */ + static constexpr size_t LOOKUP_TUPLE_SIZE = 1; + + /** + * @brief The polynomial degree of the relation telling us if the inverse polynomial value needs to be computed + * + */ + static constexpr size_t INVERSE_EXISTS_POLYNOMIAL_DEGREE = 4; + + /** + * @brief The degree of the read term if implemented arbitrarily. This value is not used by basic and scaled read + * terms, but will cause compilation error if not defined + * + */ + static constexpr size_t READ_TERM_DEGREE = 0; + + /** + * @brief The degree of the write term if implemented arbitrarily. This value is not used by the basic write + * term, but will cause compilation error if not defined + * + */ + + static constexpr size_t WRITE_TERM_DEGREE = 0; + + /** + * @brief If this method returns true on a row of values, then the inverse polynomial exists at this index. + * Otherwise the value needs to be set to zero. + * + * @details If this is true then the lookup takes place in this row + * + */ + + template static inline auto inverse_polynomial_is_computed_at_row(const AllEntities& in) + { + return (in.avm_alu_div_rng_chk_selector == 1 || in.avm_main_sel_rng_16 == 1); + } + + /** + * @brief Subprocedure for computing the value deciding if the inverse polynomial value needs to be checked in this + * row + * + * @tparam Accumulator Type specified by the lookup relation + * @tparam AllEntities Values/Univariates of all entities row + * @param in Value/Univariate of all entities at row/edge + * @return Accumulator + */ + + template + static inline auto compute_inverse_exists(const AllEntities& in) + { + using View = typename Accumulator::View; + const auto is_operation = View(in.avm_alu_div_rng_chk_selector); + const auto is_table_entry = View(in.avm_main_sel_rng_16); + return (is_operation + is_table_entry - is_operation * is_table_entry); + } + + /** + * @brief Get all the entities for the lookup when need to update them + * + * @details The generic structure of this tuple is described in ./generic_lookup_relation.hpp . The following is + description for the current case: + The entities are returned as a tuple of references in the following order (this is for ): + * - The entity/polynomial used to store the product of the inverse values + * - The entity/polynomial that specifies how many times the lookup table entry at this row has been looked up + * - READ_TERMS entities/polynomials that enable individual lookup operations + * - The entity/polynomial that enables adding an entry to the lookup table in this row + * - LOOKUP_TUPLE_SIZE entities/polynomials representing the basic tuple being looked up as the first read term + * - LOOKUP_TUPLE_SIZE entities/polynomials representing the previous accumulators in the second read term + (scaled tuple) + * - LOOKUP_TUPLE_SIZE entities/polynomials representing the shifts in the second read term (scaled tuple) + * - LOOKUP_TUPLE_SIZE entities/polynomials representing the current accumulators in the second read term + (scaled tuple) + * - LOOKUP_TUPLE_SIZE entities/polynomials representing basic tuples added to the table + * + * @return All the entities needed for the lookup + */ + + template static inline auto get_const_entities(const AllEntities& in) + { + + return std::forward_as_tuple(in.lookup_div_u16_2, + in.lookup_div_u16_2_counts, + in.avm_alu_div_rng_chk_selector, + in.avm_main_sel_rng_16, + in.avm_alu_div_u16_r2, + in.avm_main_clk); + } + + /** + * @brief Get all the entities for the lookup when we only need to read them + * @details Same as in get_const_entities, but nonconst + * + * @return All the entities needed for the lookup + */ + + template static inline auto get_nonconst_entities(AllEntities& in) + { + + return std::forward_as_tuple(in.lookup_div_u16_2, + in.lookup_div_u16_2_counts, + in.avm_alu_div_rng_chk_selector, + in.avm_main_sel_rng_16, + in.avm_alu_div_u16_r2, + in.avm_main_clk); + } +}; + +template using lookup_div_u16_2_relation = GenericLookupRelation; +template using lookup_div_u16_2 = GenericLookup; + +} // namespace bb diff --git a/barretenberg/cpp/src/barretenberg/relations/generated/avm/lookup_div_u16_3.hpp b/barretenberg/cpp/src/barretenberg/relations/generated/avm/lookup_div_u16_3.hpp new file mode 100644 index 00000000000..e167bae69bb --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/relations/generated/avm/lookup_div_u16_3.hpp @@ -0,0 +1,166 @@ + + +#pragma once + +#include "barretenberg/relations/generic_lookup/generic_lookup_relation.hpp" + +#include +#include + +namespace bb { + +/** + * @brief This class contains an example of how to set LookupSettings classes used by the + * GenericLookupRelationImpl class to specify a scaled lookup + * + * @details To create your own lookup: + * 1) Create a copy of this class and rename it + * 2) Update all the values with the ones needed for your lookup + * 3) Update "DECLARE_LOOKUP_IMPLEMENTATIONS_FOR_ALL_SETTINGS" and "DEFINE_LOOKUP_IMPLEMENTATIONS_FOR_ALL_SETTINGS" to + * include the new settings + * 4) Add the relation with the chosen settings to Relations in the flavor (for example,"` + * using Relations = std::tuple>;)` + * + */ +class lookup_div_u16_3_lookup_settings { + public: + /** + * @brief The number of read terms (how many lookups we perform) in each row + * + */ + static constexpr size_t READ_TERMS = 1; + /** + * @brief The number of write terms (how many additions to the lookup table we make) in each row + * + */ + static constexpr size_t WRITE_TERMS = 1; + + /** + * @brief The type of READ_TERM used for each read index (basic and scaled) + * + */ + static constexpr size_t READ_TERM_TYPES[READ_TERMS] = { 0 }; + + /** + * @brief They type of WRITE_TERM used for each write index + * + */ + static constexpr size_t WRITE_TERM_TYPES[WRITE_TERMS] = { 0 }; + + /** + * @brief How many values represent a single lookup object. This value is used by the automatic read term + * implementation in the relation in case the lookup is a basic or scaled tuple and in the write term if it's a + * basic tuple + * + */ + static constexpr size_t LOOKUP_TUPLE_SIZE = 1; + + /** + * @brief The polynomial degree of the relation telling us if the inverse polynomial value needs to be computed + * + */ + static constexpr size_t INVERSE_EXISTS_POLYNOMIAL_DEGREE = 4; + + /** + * @brief The degree of the read term if implemented arbitrarily. This value is not used by basic and scaled read + * terms, but will cause compilation error if not defined + * + */ + static constexpr size_t READ_TERM_DEGREE = 0; + + /** + * @brief The degree of the write term if implemented arbitrarily. This value is not used by the basic write + * term, but will cause compilation error if not defined + * + */ + + static constexpr size_t WRITE_TERM_DEGREE = 0; + + /** + * @brief If this method returns true on a row of values, then the inverse polynomial exists at this index. + * Otherwise the value needs to be set to zero. + * + * @details If this is true then the lookup takes place in this row + * + */ + + template static inline auto inverse_polynomial_is_computed_at_row(const AllEntities& in) + { + return (in.avm_alu_div_rng_chk_selector == 1 || in.avm_main_sel_rng_16 == 1); + } + + /** + * @brief Subprocedure for computing the value deciding if the inverse polynomial value needs to be checked in this + * row + * + * @tparam Accumulator Type specified by the lookup relation + * @tparam AllEntities Values/Univariates of all entities row + * @param in Value/Univariate of all entities at row/edge + * @return Accumulator + */ + + template + static inline auto compute_inverse_exists(const AllEntities& in) + { + using View = typename Accumulator::View; + const auto is_operation = View(in.avm_alu_div_rng_chk_selector); + const auto is_table_entry = View(in.avm_main_sel_rng_16); + return (is_operation + is_table_entry - is_operation * is_table_entry); + } + + /** + * @brief Get all the entities for the lookup when need to update them + * + * @details The generic structure of this tuple is described in ./generic_lookup_relation.hpp . The following is + description for the current case: + The entities are returned as a tuple of references in the following order (this is for ): + * - The entity/polynomial used to store the product of the inverse values + * - The entity/polynomial that specifies how many times the lookup table entry at this row has been looked up + * - READ_TERMS entities/polynomials that enable individual lookup operations + * - The entity/polynomial that enables adding an entry to the lookup table in this row + * - LOOKUP_TUPLE_SIZE entities/polynomials representing the basic tuple being looked up as the first read term + * - LOOKUP_TUPLE_SIZE entities/polynomials representing the previous accumulators in the second read term + (scaled tuple) + * - LOOKUP_TUPLE_SIZE entities/polynomials representing the shifts in the second read term (scaled tuple) + * - LOOKUP_TUPLE_SIZE entities/polynomials representing the current accumulators in the second read term + (scaled tuple) + * - LOOKUP_TUPLE_SIZE entities/polynomials representing basic tuples added to the table + * + * @return All the entities needed for the lookup + */ + + template static inline auto get_const_entities(const AllEntities& in) + { + + return std::forward_as_tuple(in.lookup_div_u16_3, + in.lookup_div_u16_3_counts, + in.avm_alu_div_rng_chk_selector, + in.avm_main_sel_rng_16, + in.avm_alu_div_u16_r3, + in.avm_main_clk); + } + + /** + * @brief Get all the entities for the lookup when we only need to read them + * @details Same as in get_const_entities, but nonconst + * + * @return All the entities needed for the lookup + */ + + template static inline auto get_nonconst_entities(AllEntities& in) + { + + return std::forward_as_tuple(in.lookup_div_u16_3, + in.lookup_div_u16_3_counts, + in.avm_alu_div_rng_chk_selector, + in.avm_main_sel_rng_16, + in.avm_alu_div_u16_r3, + in.avm_main_clk); + } +}; + +template using lookup_div_u16_3_relation = GenericLookupRelation; +template using lookup_div_u16_3 = GenericLookup; + +} // namespace bb diff --git a/barretenberg/cpp/src/barretenberg/relations/generated/avm/lookup_div_u16_4.hpp b/barretenberg/cpp/src/barretenberg/relations/generated/avm/lookup_div_u16_4.hpp new file mode 100644 index 00000000000..6248bc098d6 --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/relations/generated/avm/lookup_div_u16_4.hpp @@ -0,0 +1,166 @@ + + +#pragma once + +#include "barretenberg/relations/generic_lookup/generic_lookup_relation.hpp" + +#include +#include + +namespace bb { + +/** + * @brief This class contains an example of how to set LookupSettings classes used by the + * GenericLookupRelationImpl class to specify a scaled lookup + * + * @details To create your own lookup: + * 1) Create a copy of this class and rename it + * 2) Update all the values with the ones needed for your lookup + * 3) Update "DECLARE_LOOKUP_IMPLEMENTATIONS_FOR_ALL_SETTINGS" and "DEFINE_LOOKUP_IMPLEMENTATIONS_FOR_ALL_SETTINGS" to + * include the new settings + * 4) Add the relation with the chosen settings to Relations in the flavor (for example,"` + * using Relations = std::tuple>;)` + * + */ +class lookup_div_u16_4_lookup_settings { + public: + /** + * @brief The number of read terms (how many lookups we perform) in each row + * + */ + static constexpr size_t READ_TERMS = 1; + /** + * @brief The number of write terms (how many additions to the lookup table we make) in each row + * + */ + static constexpr size_t WRITE_TERMS = 1; + + /** + * @brief The type of READ_TERM used for each read index (basic and scaled) + * + */ + static constexpr size_t READ_TERM_TYPES[READ_TERMS] = { 0 }; + + /** + * @brief They type of WRITE_TERM used for each write index + * + */ + static constexpr size_t WRITE_TERM_TYPES[WRITE_TERMS] = { 0 }; + + /** + * @brief How many values represent a single lookup object. This value is used by the automatic read term + * implementation in the relation in case the lookup is a basic or scaled tuple and in the write term if it's a + * basic tuple + * + */ + static constexpr size_t LOOKUP_TUPLE_SIZE = 1; + + /** + * @brief The polynomial degree of the relation telling us if the inverse polynomial value needs to be computed + * + */ + static constexpr size_t INVERSE_EXISTS_POLYNOMIAL_DEGREE = 4; + + /** + * @brief The degree of the read term if implemented arbitrarily. This value is not used by basic and scaled read + * terms, but will cause compilation error if not defined + * + */ + static constexpr size_t READ_TERM_DEGREE = 0; + + /** + * @brief The degree of the write term if implemented arbitrarily. This value is not used by the basic write + * term, but will cause compilation error if not defined + * + */ + + static constexpr size_t WRITE_TERM_DEGREE = 0; + + /** + * @brief If this method returns true on a row of values, then the inverse polynomial exists at this index. + * Otherwise the value needs to be set to zero. + * + * @details If this is true then the lookup takes place in this row + * + */ + + template static inline auto inverse_polynomial_is_computed_at_row(const AllEntities& in) + { + return (in.avm_alu_div_rng_chk_selector == 1 || in.avm_main_sel_rng_16 == 1); + } + + /** + * @brief Subprocedure for computing the value deciding if the inverse polynomial value needs to be checked in this + * row + * + * @tparam Accumulator Type specified by the lookup relation + * @tparam AllEntities Values/Univariates of all entities row + * @param in Value/Univariate of all entities at row/edge + * @return Accumulator + */ + + template + static inline auto compute_inverse_exists(const AllEntities& in) + { + using View = typename Accumulator::View; + const auto is_operation = View(in.avm_alu_div_rng_chk_selector); + const auto is_table_entry = View(in.avm_main_sel_rng_16); + return (is_operation + is_table_entry - is_operation * is_table_entry); + } + + /** + * @brief Get all the entities for the lookup when need to update them + * + * @details The generic structure of this tuple is described in ./generic_lookup_relation.hpp . The following is + description for the current case: + The entities are returned as a tuple of references in the following order (this is for ): + * - The entity/polynomial used to store the product of the inverse values + * - The entity/polynomial that specifies how many times the lookup table entry at this row has been looked up + * - READ_TERMS entities/polynomials that enable individual lookup operations + * - The entity/polynomial that enables adding an entry to the lookup table in this row + * - LOOKUP_TUPLE_SIZE entities/polynomials representing the basic tuple being looked up as the first read term + * - LOOKUP_TUPLE_SIZE entities/polynomials representing the previous accumulators in the second read term + (scaled tuple) + * - LOOKUP_TUPLE_SIZE entities/polynomials representing the shifts in the second read term (scaled tuple) + * - LOOKUP_TUPLE_SIZE entities/polynomials representing the current accumulators in the second read term + (scaled tuple) + * - LOOKUP_TUPLE_SIZE entities/polynomials representing basic tuples added to the table + * + * @return All the entities needed for the lookup + */ + + template static inline auto get_const_entities(const AllEntities& in) + { + + return std::forward_as_tuple(in.lookup_div_u16_4, + in.lookup_div_u16_4_counts, + in.avm_alu_div_rng_chk_selector, + in.avm_main_sel_rng_16, + in.avm_alu_div_u16_r4, + in.avm_main_clk); + } + + /** + * @brief Get all the entities for the lookup when we only need to read them + * @details Same as in get_const_entities, but nonconst + * + * @return All the entities needed for the lookup + */ + + template static inline auto get_nonconst_entities(AllEntities& in) + { + + return std::forward_as_tuple(in.lookup_div_u16_4, + in.lookup_div_u16_4_counts, + in.avm_alu_div_rng_chk_selector, + in.avm_main_sel_rng_16, + in.avm_alu_div_u16_r4, + in.avm_main_clk); + } +}; + +template using lookup_div_u16_4_relation = GenericLookupRelation; +template using lookup_div_u16_4 = GenericLookup; + +} // namespace bb diff --git a/barretenberg/cpp/src/barretenberg/relations/generated/avm/lookup_div_u16_5.hpp b/barretenberg/cpp/src/barretenberg/relations/generated/avm/lookup_div_u16_5.hpp new file mode 100644 index 00000000000..052eafcaa3b --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/relations/generated/avm/lookup_div_u16_5.hpp @@ -0,0 +1,166 @@ + + +#pragma once + +#include "barretenberg/relations/generic_lookup/generic_lookup_relation.hpp" + +#include +#include + +namespace bb { + +/** + * @brief This class contains an example of how to set LookupSettings classes used by the + * GenericLookupRelationImpl class to specify a scaled lookup + * + * @details To create your own lookup: + * 1) Create a copy of this class and rename it + * 2) Update all the values with the ones needed for your lookup + * 3) Update "DECLARE_LOOKUP_IMPLEMENTATIONS_FOR_ALL_SETTINGS" and "DEFINE_LOOKUP_IMPLEMENTATIONS_FOR_ALL_SETTINGS" to + * include the new settings + * 4) Add the relation with the chosen settings to Relations in the flavor (for example,"` + * using Relations = std::tuple>;)` + * + */ +class lookup_div_u16_5_lookup_settings { + public: + /** + * @brief The number of read terms (how many lookups we perform) in each row + * + */ + static constexpr size_t READ_TERMS = 1; + /** + * @brief The number of write terms (how many additions to the lookup table we make) in each row + * + */ + static constexpr size_t WRITE_TERMS = 1; + + /** + * @brief The type of READ_TERM used for each read index (basic and scaled) + * + */ + static constexpr size_t READ_TERM_TYPES[READ_TERMS] = { 0 }; + + /** + * @brief They type of WRITE_TERM used for each write index + * + */ + static constexpr size_t WRITE_TERM_TYPES[WRITE_TERMS] = { 0 }; + + /** + * @brief How many values represent a single lookup object. This value is used by the automatic read term + * implementation in the relation in case the lookup is a basic or scaled tuple and in the write term if it's a + * basic tuple + * + */ + static constexpr size_t LOOKUP_TUPLE_SIZE = 1; + + /** + * @brief The polynomial degree of the relation telling us if the inverse polynomial value needs to be computed + * + */ + static constexpr size_t INVERSE_EXISTS_POLYNOMIAL_DEGREE = 4; + + /** + * @brief The degree of the read term if implemented arbitrarily. This value is not used by basic and scaled read + * terms, but will cause compilation error if not defined + * + */ + static constexpr size_t READ_TERM_DEGREE = 0; + + /** + * @brief The degree of the write term if implemented arbitrarily. This value is not used by the basic write + * term, but will cause compilation error if not defined + * + */ + + static constexpr size_t WRITE_TERM_DEGREE = 0; + + /** + * @brief If this method returns true on a row of values, then the inverse polynomial exists at this index. + * Otherwise the value needs to be set to zero. + * + * @details If this is true then the lookup takes place in this row + * + */ + + template static inline auto inverse_polynomial_is_computed_at_row(const AllEntities& in) + { + return (in.avm_alu_div_rng_chk_selector == 1 || in.avm_main_sel_rng_16 == 1); + } + + /** + * @brief Subprocedure for computing the value deciding if the inverse polynomial value needs to be checked in this + * row + * + * @tparam Accumulator Type specified by the lookup relation + * @tparam AllEntities Values/Univariates of all entities row + * @param in Value/Univariate of all entities at row/edge + * @return Accumulator + */ + + template + static inline auto compute_inverse_exists(const AllEntities& in) + { + using View = typename Accumulator::View; + const auto is_operation = View(in.avm_alu_div_rng_chk_selector); + const auto is_table_entry = View(in.avm_main_sel_rng_16); + return (is_operation + is_table_entry - is_operation * is_table_entry); + } + + /** + * @brief Get all the entities for the lookup when need to update them + * + * @details The generic structure of this tuple is described in ./generic_lookup_relation.hpp . The following is + description for the current case: + The entities are returned as a tuple of references in the following order (this is for ): + * - The entity/polynomial used to store the product of the inverse values + * - The entity/polynomial that specifies how many times the lookup table entry at this row has been looked up + * - READ_TERMS entities/polynomials that enable individual lookup operations + * - The entity/polynomial that enables adding an entry to the lookup table in this row + * - LOOKUP_TUPLE_SIZE entities/polynomials representing the basic tuple being looked up as the first read term + * - LOOKUP_TUPLE_SIZE entities/polynomials representing the previous accumulators in the second read term + (scaled tuple) + * - LOOKUP_TUPLE_SIZE entities/polynomials representing the shifts in the second read term (scaled tuple) + * - LOOKUP_TUPLE_SIZE entities/polynomials representing the current accumulators in the second read term + (scaled tuple) + * - LOOKUP_TUPLE_SIZE entities/polynomials representing basic tuples added to the table + * + * @return All the entities needed for the lookup + */ + + template static inline auto get_const_entities(const AllEntities& in) + { + + return std::forward_as_tuple(in.lookup_div_u16_5, + in.lookup_div_u16_5_counts, + in.avm_alu_div_rng_chk_selector, + in.avm_main_sel_rng_16, + in.avm_alu_div_u16_r5, + in.avm_main_clk); + } + + /** + * @brief Get all the entities for the lookup when we only need to read them + * @details Same as in get_const_entities, but nonconst + * + * @return All the entities needed for the lookup + */ + + template static inline auto get_nonconst_entities(AllEntities& in) + { + + return std::forward_as_tuple(in.lookup_div_u16_5, + in.lookup_div_u16_5_counts, + in.avm_alu_div_rng_chk_selector, + in.avm_main_sel_rng_16, + in.avm_alu_div_u16_r5, + in.avm_main_clk); + } +}; + +template using lookup_div_u16_5_relation = GenericLookupRelation; +template using lookup_div_u16_5 = GenericLookup; + +} // namespace bb diff --git a/barretenberg/cpp/src/barretenberg/relations/generated/avm/lookup_div_u16_6.hpp b/barretenberg/cpp/src/barretenberg/relations/generated/avm/lookup_div_u16_6.hpp new file mode 100644 index 00000000000..c52d71bdb99 --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/relations/generated/avm/lookup_div_u16_6.hpp @@ -0,0 +1,166 @@ + + +#pragma once + +#include "barretenberg/relations/generic_lookup/generic_lookup_relation.hpp" + +#include +#include + +namespace bb { + +/** + * @brief This class contains an example of how to set LookupSettings classes used by the + * GenericLookupRelationImpl class to specify a scaled lookup + * + * @details To create your own lookup: + * 1) Create a copy of this class and rename it + * 2) Update all the values with the ones needed for your lookup + * 3) Update "DECLARE_LOOKUP_IMPLEMENTATIONS_FOR_ALL_SETTINGS" and "DEFINE_LOOKUP_IMPLEMENTATIONS_FOR_ALL_SETTINGS" to + * include the new settings + * 4) Add the relation with the chosen settings to Relations in the flavor (for example,"` + * using Relations = std::tuple>;)` + * + */ +class lookup_div_u16_6_lookup_settings { + public: + /** + * @brief The number of read terms (how many lookups we perform) in each row + * + */ + static constexpr size_t READ_TERMS = 1; + /** + * @brief The number of write terms (how many additions to the lookup table we make) in each row + * + */ + static constexpr size_t WRITE_TERMS = 1; + + /** + * @brief The type of READ_TERM used for each read index (basic and scaled) + * + */ + static constexpr size_t READ_TERM_TYPES[READ_TERMS] = { 0 }; + + /** + * @brief They type of WRITE_TERM used for each write index + * + */ + static constexpr size_t WRITE_TERM_TYPES[WRITE_TERMS] = { 0 }; + + /** + * @brief How many values represent a single lookup object. This value is used by the automatic read term + * implementation in the relation in case the lookup is a basic or scaled tuple and in the write term if it's a + * basic tuple + * + */ + static constexpr size_t LOOKUP_TUPLE_SIZE = 1; + + /** + * @brief The polynomial degree of the relation telling us if the inverse polynomial value needs to be computed + * + */ + static constexpr size_t INVERSE_EXISTS_POLYNOMIAL_DEGREE = 4; + + /** + * @brief The degree of the read term if implemented arbitrarily. This value is not used by basic and scaled read + * terms, but will cause compilation error if not defined + * + */ + static constexpr size_t READ_TERM_DEGREE = 0; + + /** + * @brief The degree of the write term if implemented arbitrarily. This value is not used by the basic write + * term, but will cause compilation error if not defined + * + */ + + static constexpr size_t WRITE_TERM_DEGREE = 0; + + /** + * @brief If this method returns true on a row of values, then the inverse polynomial exists at this index. + * Otherwise the value needs to be set to zero. + * + * @details If this is true then the lookup takes place in this row + * + */ + + template static inline auto inverse_polynomial_is_computed_at_row(const AllEntities& in) + { + return (in.avm_alu_div_rng_chk_selector == 1 || in.avm_main_sel_rng_16 == 1); + } + + /** + * @brief Subprocedure for computing the value deciding if the inverse polynomial value needs to be checked in this + * row + * + * @tparam Accumulator Type specified by the lookup relation + * @tparam AllEntities Values/Univariates of all entities row + * @param in Value/Univariate of all entities at row/edge + * @return Accumulator + */ + + template + static inline auto compute_inverse_exists(const AllEntities& in) + { + using View = typename Accumulator::View; + const auto is_operation = View(in.avm_alu_div_rng_chk_selector); + const auto is_table_entry = View(in.avm_main_sel_rng_16); + return (is_operation + is_table_entry - is_operation * is_table_entry); + } + + /** + * @brief Get all the entities for the lookup when need to update them + * + * @details The generic structure of this tuple is described in ./generic_lookup_relation.hpp . The following is + description for the current case: + The entities are returned as a tuple of references in the following order (this is for ): + * - The entity/polynomial used to store the product of the inverse values + * - The entity/polynomial that specifies how many times the lookup table entry at this row has been looked up + * - READ_TERMS entities/polynomials that enable individual lookup operations + * - The entity/polynomial that enables adding an entry to the lookup table in this row + * - LOOKUP_TUPLE_SIZE entities/polynomials representing the basic tuple being looked up as the first read term + * - LOOKUP_TUPLE_SIZE entities/polynomials representing the previous accumulators in the second read term + (scaled tuple) + * - LOOKUP_TUPLE_SIZE entities/polynomials representing the shifts in the second read term (scaled tuple) + * - LOOKUP_TUPLE_SIZE entities/polynomials representing the current accumulators in the second read term + (scaled tuple) + * - LOOKUP_TUPLE_SIZE entities/polynomials representing basic tuples added to the table + * + * @return All the entities needed for the lookup + */ + + template static inline auto get_const_entities(const AllEntities& in) + { + + return std::forward_as_tuple(in.lookup_div_u16_6, + in.lookup_div_u16_6_counts, + in.avm_alu_div_rng_chk_selector, + in.avm_main_sel_rng_16, + in.avm_alu_div_u16_r6, + in.avm_main_clk); + } + + /** + * @brief Get all the entities for the lookup when we only need to read them + * @details Same as in get_const_entities, but nonconst + * + * @return All the entities needed for the lookup + */ + + template static inline auto get_nonconst_entities(AllEntities& in) + { + + return std::forward_as_tuple(in.lookup_div_u16_6, + in.lookup_div_u16_6_counts, + in.avm_alu_div_rng_chk_selector, + in.avm_main_sel_rng_16, + in.avm_alu_div_u16_r6, + in.avm_main_clk); + } +}; + +template using lookup_div_u16_6_relation = GenericLookupRelation; +template using lookup_div_u16_6 = GenericLookup; + +} // namespace bb diff --git a/barretenberg/cpp/src/barretenberg/relations/generated/avm/lookup_div_u16_7.hpp b/barretenberg/cpp/src/barretenberg/relations/generated/avm/lookup_div_u16_7.hpp new file mode 100644 index 00000000000..dde1e6f54b4 --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/relations/generated/avm/lookup_div_u16_7.hpp @@ -0,0 +1,166 @@ + + +#pragma once + +#include "barretenberg/relations/generic_lookup/generic_lookup_relation.hpp" + +#include +#include + +namespace bb { + +/** + * @brief This class contains an example of how to set LookupSettings classes used by the + * GenericLookupRelationImpl class to specify a scaled lookup + * + * @details To create your own lookup: + * 1) Create a copy of this class and rename it + * 2) Update all the values with the ones needed for your lookup + * 3) Update "DECLARE_LOOKUP_IMPLEMENTATIONS_FOR_ALL_SETTINGS" and "DEFINE_LOOKUP_IMPLEMENTATIONS_FOR_ALL_SETTINGS" to + * include the new settings + * 4) Add the relation with the chosen settings to Relations in the flavor (for example,"` + * using Relations = std::tuple>;)` + * + */ +class lookup_div_u16_7_lookup_settings { + public: + /** + * @brief The number of read terms (how many lookups we perform) in each row + * + */ + static constexpr size_t READ_TERMS = 1; + /** + * @brief The number of write terms (how many additions to the lookup table we make) in each row + * + */ + static constexpr size_t WRITE_TERMS = 1; + + /** + * @brief The type of READ_TERM used for each read index (basic and scaled) + * + */ + static constexpr size_t READ_TERM_TYPES[READ_TERMS] = { 0 }; + + /** + * @brief They type of WRITE_TERM used for each write index + * + */ + static constexpr size_t WRITE_TERM_TYPES[WRITE_TERMS] = { 0 }; + + /** + * @brief How many values represent a single lookup object. This value is used by the automatic read term + * implementation in the relation in case the lookup is a basic or scaled tuple and in the write term if it's a + * basic tuple + * + */ + static constexpr size_t LOOKUP_TUPLE_SIZE = 1; + + /** + * @brief The polynomial degree of the relation telling us if the inverse polynomial value needs to be computed + * + */ + static constexpr size_t INVERSE_EXISTS_POLYNOMIAL_DEGREE = 4; + + /** + * @brief The degree of the read term if implemented arbitrarily. This value is not used by basic and scaled read + * terms, but will cause compilation error if not defined + * + */ + static constexpr size_t READ_TERM_DEGREE = 0; + + /** + * @brief The degree of the write term if implemented arbitrarily. This value is not used by the basic write + * term, but will cause compilation error if not defined + * + */ + + static constexpr size_t WRITE_TERM_DEGREE = 0; + + /** + * @brief If this method returns true on a row of values, then the inverse polynomial exists at this index. + * Otherwise the value needs to be set to zero. + * + * @details If this is true then the lookup takes place in this row + * + */ + + template static inline auto inverse_polynomial_is_computed_at_row(const AllEntities& in) + { + return (in.avm_alu_div_rng_chk_selector == 1 || in.avm_main_sel_rng_16 == 1); + } + + /** + * @brief Subprocedure for computing the value deciding if the inverse polynomial value needs to be checked in this + * row + * + * @tparam Accumulator Type specified by the lookup relation + * @tparam AllEntities Values/Univariates of all entities row + * @param in Value/Univariate of all entities at row/edge + * @return Accumulator + */ + + template + static inline auto compute_inverse_exists(const AllEntities& in) + { + using View = typename Accumulator::View; + const auto is_operation = View(in.avm_alu_div_rng_chk_selector); + const auto is_table_entry = View(in.avm_main_sel_rng_16); + return (is_operation + is_table_entry - is_operation * is_table_entry); + } + + /** + * @brief Get all the entities for the lookup when need to update them + * + * @details The generic structure of this tuple is described in ./generic_lookup_relation.hpp . The following is + description for the current case: + The entities are returned as a tuple of references in the following order (this is for ): + * - The entity/polynomial used to store the product of the inverse values + * - The entity/polynomial that specifies how many times the lookup table entry at this row has been looked up + * - READ_TERMS entities/polynomials that enable individual lookup operations + * - The entity/polynomial that enables adding an entry to the lookup table in this row + * - LOOKUP_TUPLE_SIZE entities/polynomials representing the basic tuple being looked up as the first read term + * - LOOKUP_TUPLE_SIZE entities/polynomials representing the previous accumulators in the second read term + (scaled tuple) + * - LOOKUP_TUPLE_SIZE entities/polynomials representing the shifts in the second read term (scaled tuple) + * - LOOKUP_TUPLE_SIZE entities/polynomials representing the current accumulators in the second read term + (scaled tuple) + * - LOOKUP_TUPLE_SIZE entities/polynomials representing basic tuples added to the table + * + * @return All the entities needed for the lookup + */ + + template static inline auto get_const_entities(const AllEntities& in) + { + + return std::forward_as_tuple(in.lookup_div_u16_7, + in.lookup_div_u16_7_counts, + in.avm_alu_div_rng_chk_selector, + in.avm_main_sel_rng_16, + in.avm_alu_div_u16_r7, + in.avm_main_clk); + } + + /** + * @brief Get all the entities for the lookup when we only need to read them + * @details Same as in get_const_entities, but nonconst + * + * @return All the entities needed for the lookup + */ + + template static inline auto get_nonconst_entities(AllEntities& in) + { + + return std::forward_as_tuple(in.lookup_div_u16_7, + in.lookup_div_u16_7_counts, + in.avm_alu_div_rng_chk_selector, + in.avm_main_sel_rng_16, + in.avm_alu_div_u16_r7, + in.avm_main_clk); + } +}; + +template using lookup_div_u16_7_relation = GenericLookupRelation; +template using lookup_div_u16_7 = GenericLookup; + +} // namespace bb diff --git a/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_alu_trace.cpp b/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_alu_trace.cpp index 497d4143f44..9a055c79aba 100644 --- a/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_alu_trace.cpp +++ b/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_alu_trace.cpp @@ -1,4 +1,5 @@ #include "avm_alu_trace.hpp" +#include "barretenberg/numeric/uint256/uint256.hpp" namespace bb::avm_trace { @@ -50,7 +51,7 @@ bool AvmAluTraceBuilder::is_range_check_required() const bool AvmAluTraceBuilder::is_alu_row_enabled(AvmAluTraceBuilder::AluTraceEntry const& r) { return (r.alu_op_add || r.alu_op_sub || r.alu_op_mul || r.alu_op_eq || r.alu_op_not || r.alu_op_lt || - r.alu_op_lte || r.alu_op_shr || r.alu_op_shl || r.alu_op_cast); + r.alu_op_lte || r.alu_op_shr || r.alu_op_shl || r.alu_op_cast || r.alu_op_div); } /** @@ -468,11 +469,11 @@ std::tuple> AvmAluTraceBuilder::to_al } /** - * @brief This is a helper function that is used to generate the range check entries for the comparison operation - * (LT/LTE opcodes). This additionally increments the counts for the corresponding range lookups entries. + * @brief This is a helper function that is used to generate the range check entries for operations that require + * multi-row range checks This additionally increments the counts for the corresponding range lookups entries. * @param row The initial row where the comparison operation was performed * @param hi_lo_limbs The vector of 128-bit limbs hi and lo pairs of limbs that will be range checked. - * @return A vector of AluTraceEntry rows for the range checks for the comparison operation. + * @return A vector of AluTraceEntry rows for the range checks for the operation. */ std::vector AvmAluTraceBuilder::cmp_range_check_helper( AvmAluTraceBuilder::AluTraceEntry row, std::vector hi_lo_limbs) @@ -544,7 +545,7 @@ std::tuple gt_witness(uint256_t const& a, uint256_t // where q = 1 if a > b and q = 0 if a <= b std::tuple gt_or_lte_witness(uint256_t const& a, uint256_t const& b) { - uint256_t two_pow_128 = uint256_t(1) << uint256_t(128); + uint256_t two_pow_126 = uint256_t(1) << uint256_t(128); auto [a_lo, a_hi] = decompose(a, 128); auto [b_lo, b_hi] = decompose(b, 128); bool isGT = a > b; @@ -553,7 +554,7 @@ std::tuple gt_or_lte_witness(uint256_t const& a, uin } bool borrow = b_lo < a_lo; auto borrow_u256 = uint256_t(static_cast(borrow)); - uint256_t r_lo = b_lo - a_lo + borrow_u256 * two_pow_128; + uint256_t r_lo = b_lo - a_lo + borrow_u256 * two_pow_126; uint256_t r_hi = b_hi - a_hi - borrow_u256; return std::make_tuple(r_lo, r_hi, borrow); } @@ -963,4 +964,102 @@ FF AvmAluTraceBuilder::op_shl(FF const& a, FF const& b, AvmMemoryTag in_tag, uin }); return c; } +FF AvmAluTraceBuilder::op_div(FF const& a, FF const& b, AvmMemoryTag in_tag, uint32_t clk) +{ + uint256_t a_u256{ a }; + uint256_t b_u256{ b }; + uint256_t c_u256 = a_u256 / b_u256; + uint256_t rem_u256 = a_u256 % b_u256; + + // If dividing by zero, don't add any rows in the ALU, the error will be handled in the main trace + if (b_u256 == 0) { + return 0; + } + + if (a_u256 < b_u256) { + // If a < b, the result is trivially 0 + uint256_t rng_chk_lo = b_u256 - a_u256 - 1; + auto [u8_r0, u8_r1, u16_reg] = to_alu_slice_registers(rng_chk_lo); + alu_trace.push_back(AvmAluTraceBuilder::AluTraceEntry({ + .alu_clk = clk, + .alu_op_div = true, + .alu_u8_tag = in_tag == AvmMemoryTag::U8, + .alu_u16_tag = in_tag == AvmMemoryTag::U16, + .alu_u32_tag = in_tag == AvmMemoryTag::U32, + .alu_u64_tag = in_tag == AvmMemoryTag::U64, + .alu_u128_tag = in_tag == AvmMemoryTag::U128, + .alu_ia = a, + .alu_ib = b, + .alu_ic = 0, + .alu_u8_r0 = u8_r0, + .alu_u8_r1 = u8_r1, + .alu_u16_reg = u16_reg, + .hi_lo_limbs = { rng_chk_lo, 0, 0, 0, 0, 0 }, + .remainder = a, + + })); + return 0; + } + // Decompose a and primality check that b*c < p when a is a 256-bit integer + auto [a_lo, a_hi] = decompose(b_u256 * c_u256, 128); + auto [p_sub_a_lo, p_sub_a_hi, p_a_borrow] = gt_witness(FF::modulus, b_u256 * c_u256); + // Decompose the divisor + auto [divisor_lo, divisor_hi] = decompose(b_u256, 64); + // Decompose the quotient + auto [quotient_lo, quotient_hi] = decompose(c_u256, 64); + uint256_t partial_prod = divisor_lo * quotient_hi + divisor_hi * quotient_lo; + // Decompose the partial product + auto [partial_prod_lo, partial_prod_hi] = decompose(partial_prod, 64); + + FF b_hi = b_u256 - rem_u256 - 1; + + // 64 bit range checks for the divisor and quotient limbs + // Spread over two rows + std::array div_u64_rng_chk; + std::array div_u64_rng_chk_shifted; + for (size_t i = 0; i < 4; i++) { + div_u64_rng_chk.at(i) = uint16_t(divisor_lo >> (16 * i)); + div_u64_rng_chk.at(i + 4) = uint16_t(divisor_hi >> (16 * i)); + div_u64_range_chk_counters[i][uint16_t(divisor_lo >> (16 * i))]++; + div_u64_range_chk_counters[i + 4][uint16_t(divisor_hi >> (16 * i))]++; + + div_u64_rng_chk_shifted.at(i) = uint16_t(quotient_lo >> (16 * i)); + div_u64_rng_chk_shifted.at(i + 4) = uint16_t(quotient_hi >> (16 * i)); + div_u64_range_chk_counters[i][uint16_t(quotient_lo >> (16 * i))]++; + div_u64_range_chk_counters[i + 4][uint16_t(quotient_hi >> (16 * i))]++; + } + + // Each hi and lo limb is range checked over 128 bits + // Load the range check values into the ALU registers + auto hi_lo_limbs = std::vector{ a_lo, a_hi, partial_prod, b_hi, p_sub_a_lo, p_sub_a_hi }; + AvmAluTraceBuilder::AluTraceEntry row{ + .alu_clk = clk, + .alu_op_div = true, + .alu_u8_tag = in_tag == AvmMemoryTag::U8, + .alu_u16_tag = in_tag == AvmMemoryTag::U16, + .alu_u32_tag = in_tag == AvmMemoryTag::U32, + .alu_u64_tag = in_tag == AvmMemoryTag::U64, + .alu_u128_tag = in_tag == AvmMemoryTag::U128, + .alu_ia = a, + .alu_ib = b, + .alu_ic = FF{ c_u256 }, + .remainder = rem_u256, + .divisor_lo = divisor_lo, + .divisor_hi = divisor_hi, + .quotient_lo = quotient_lo, + .quotient_hi = quotient_hi, + .partial_prod_lo = partial_prod_lo, + .partial_prod_hi = partial_prod_hi, + .div_u64_range_chk_sel = true, + .div_u64_range_chk = div_u64_rng_chk, + + }; + // We perform the range checks here + std::vector rows = cmp_range_check_helper(row, hi_lo_limbs); + // Add the range checks for the quotient limbs in the row after the division operation + rows.at(1).div_u64_range_chk = div_u64_rng_chk_shifted; + rows.at(1).div_u64_range_chk_sel = true; + alu_trace.insert(alu_trace.end(), rows.begin(), rows.end()); + return c_u256; +} } // namespace bb::avm_trace diff --git a/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_alu_trace.hpp b/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_alu_trace.hpp index e01e8e53b4b..42d2a550fea 100644 --- a/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_alu_trace.hpp +++ b/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_alu_trace.hpp @@ -21,6 +21,7 @@ class AvmAluTraceBuilder { bool alu_op_cast_prev = false; bool alu_op_shr = false; bool alu_op_shl = false; + bool alu_op_div = false; bool alu_ff_tag = false; bool alu_u8_tag = false; @@ -55,11 +56,25 @@ class AvmAluTraceBuilder { uint8_t mem_tag_bits = 0; uint8_t mem_tag_sub_shift = 0; bool shift_lt_bit_len = true; + FF quot_div_rem_lo{}; + FF quot_div_rem_hi{}; + + // Div Operations + FF remainder{}; + FF divisor_lo{}; + FF divisor_hi{}; + FF quotient_lo{}; + FF quotient_hi{}; + FF partial_prod_lo{}; + FF partial_prod_hi{}; + bool div_u64_range_chk_sel = false; + std::array div_u64_range_chk{}; }; std::array, 2> u8_range_chk_counters; std::array, 2> u8_pow_2_counters; std::array, 15> u16_range_chk_counters; + std::array, 8> div_u64_range_chk_counters; AvmAluTraceBuilder(); void reset(); @@ -75,6 +90,7 @@ class AvmAluTraceBuilder { FF op_cast(FF const& a, AvmMemoryTag in_tag, uint32_t clk); FF op_shr(FF const& a, FF const& b, AvmMemoryTag in_tag, uint32_t clk); FF op_shl(FF const& a, FF const& b, AvmMemoryTag in_tag, uint32_t clk); + FF op_div(FF const& a, FF const& b, AvmMemoryTag in_tag, uint32_t clk); bool is_range_check_required() const; static bool is_alu_row_enabled(AvmAluTraceBuilder::AluTraceEntry const& r); diff --git a/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_execution.cpp b/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_execution.cpp index 7cf6154fac8..c472af776a3 100644 --- a/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_execution.cpp +++ b/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_execution.cpp @@ -110,6 +110,13 @@ std::vector Execution::gen_trace(std::vector const& instructio std::get(inst.operands.at(2)), std::get(inst.operands.at(3))); break; + case OpCode::DIV: + trace_builder.op_div(std::get(inst.operands.at(0)), + std::get(inst.operands.at(2)), + std::get(inst.operands.at(3)), + std::get(inst.operands.at(4)), + std::get(inst.operands.at(1))); + break; // Compute - Comparators case OpCode::EQ: trace_builder.op_eq(std::get(inst.operands.at(0)), diff --git a/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_trace.cpp b/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_trace.cpp index 39f54fe80b8..6ec6782aa6a 100644 --- a/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_trace.cpp +++ b/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_trace.cpp @@ -1118,6 +1118,84 @@ void AvmTraceBuilder::op_cast(uint8_t indirect, uint32_t a_offset, uint32_t dst_ .avm_main_w_in_tag = FF(static_cast(dst_tag)), }); } +/** + * @brief Integer division with direct or indirect memory access. + * + * @param indirect A byte encoding information about indirect/direct memory access. + * @param a_offset An index in memory pointing to the first operand of the division. + * @param b_offset An index in memory pointing to the second operand of the division. + * @param dst_offset An index in memory pointing to the output of the division. + * @param in_tag The instruction memory tag of the operands. + */ +void AvmTraceBuilder::op_div( + uint8_t indirect, uint32_t a_offset, uint32_t b_offset, uint32_t dst_offset, AvmMemoryTag in_tag) +{ + auto clk = static_cast(main_trace.size()); + + auto const res = resolve_ind_three(clk, indirect, a_offset, b_offset, dst_offset); + bool tag_match = res.tag_match; + + // Reading from memory and loading into ia resp. ib. + auto read_a = + mem_trace_builder.read_and_load_from_memory(clk, IntermRegister::IA, res.direct_a_offset, in_tag, in_tag); + auto read_b = + mem_trace_builder.read_and_load_from_memory(clk, IntermRegister::IB, res.direct_b_offset, in_tag, in_tag); + tag_match = read_a.tag_match && read_b.tag_match; + + // a / b = c + FF a = read_a.val; + FF b = read_b.val; + + // In case of a memory tag error, we do not perform the computation. + // Therefore, we do not create any entry in ALU table and store the value 0 as + // output (c) in memory. + FF c; + FF inv; + FF error; + + if (!b.is_zero()) { + // If b is not zero, we prove it is not by providing its inverse as well + inv = b.invert(); + c = tag_match ? alu_trace_builder.op_div(a, b, in_tag, clk) : FF(0); + error = 0; + } else { + inv = 1; + c = 0; + error = 1; + } + + // Write into memory value c from intermediate register ic. + mem_trace_builder.write_into_memory(clk, IntermRegister::IC, res.direct_c_offset, c, in_tag, in_tag); + + main_trace.push_back(Row{ + .avm_main_clk = clk, + .avm_main_alu_in_tag = FF(static_cast(in_tag)), + .avm_main_ia = a, + .avm_main_ib = b, + .avm_main_ic = c, + .avm_main_ind_a = res.indirect_flag_a ? FF(a_offset) : FF(0), + .avm_main_ind_b = res.indirect_flag_b ? FF(b_offset) : FF(0), + .avm_main_ind_c = res.indirect_flag_c ? FF(dst_offset) : FF(0), + .avm_main_ind_op_a = FF(static_cast(res.indirect_flag_a)), + .avm_main_ind_op_b = FF(static_cast(res.indirect_flag_b)), + .avm_main_ind_op_c = FF(static_cast(res.indirect_flag_c)), + .avm_main_internal_return_ptr = FF(internal_return_ptr), + .avm_main_inv = tag_match ? inv : FF(1), + .avm_main_mem_idx_a = FF(res.direct_a_offset), + .avm_main_mem_idx_b = FF(res.direct_b_offset), + .avm_main_mem_idx_c = FF(res.direct_c_offset), + .avm_main_mem_op_a = FF(1), + .avm_main_mem_op_b = FF(1), + .avm_main_mem_op_c = FF(1), + .avm_main_op_err = tag_match ? error : FF(1), + .avm_main_pc = FF(pc++), + .avm_main_r_in_tag = FF(static_cast(in_tag)), + .avm_main_rwc = FF(1), + .avm_main_sel_op_div = FF(1), + .avm_main_tag_err = FF(static_cast(!tag_match)), + .avm_main_w_in_tag = FF(static_cast(in_tag)), + }); +} /** * @brief CALLDATACOPY opcode with direct or indirect memory access, i.e., @@ -1657,6 +1735,7 @@ std::vector AvmTraceBuilder::finalize() dest.avm_alu_rng_chk_sel = FF(static_cast(src.rng_chk_sel)); dest.avm_alu_op_shr = FF(static_cast(src.alu_op_shr)); dest.avm_alu_op_shl = FF(static_cast(src.alu_op_shl)); + dest.avm_alu_op_div = FF(static_cast(src.alu_op_div)); dest.avm_alu_ff_tag = FF(static_cast(src.alu_ff_tag)); dest.avm_alu_u8_tag = FF(static_cast(src.alu_u8_tag)); @@ -1694,6 +1773,15 @@ std::vector AvmTraceBuilder::finalize() dest.avm_alu_u16_r13 = FF(src.alu_u16_reg.at(13)); dest.avm_alu_u16_r14 = FF(src.alu_u16_reg.at(14)); + dest.avm_alu_div_rng_chk_selector = FF(static_cast(src.div_u64_range_chk_sel)); + dest.avm_alu_div_u16_r0 = FF(src.div_u64_range_chk.at(0)); + dest.avm_alu_div_u16_r1 = FF(src.div_u64_range_chk.at(1)); + dest.avm_alu_div_u16_r2 = FF(src.div_u64_range_chk.at(2)); + dest.avm_alu_div_u16_r3 = FF(src.div_u64_range_chk.at(3)); + dest.avm_alu_div_u16_r4 = FF(src.div_u64_range_chk.at(4)); + dest.avm_alu_div_u16_r5 = FF(src.div_u64_range_chk.at(5)); + dest.avm_alu_div_u16_r6 = FF(src.div_u64_range_chk.at(6)); + dest.avm_alu_div_u16_r7 = FF(src.div_u64_range_chk.at(7)); dest.avm_alu_op_eq_diff_inv = FF(src.alu_op_eq_diff_inv); // Not all rows in ALU are enabled with a selector. For instance, @@ -1716,10 +1804,27 @@ std::vector AvmTraceBuilder::finalize() dest.avm_alu_p_a_borrow = FF(static_cast(src.p_a_borrow)); dest.avm_alu_p_b_borrow = FF(static_cast(src.p_b_borrow)); dest.avm_alu_borrow = FF(static_cast(src.borrow)); - dest.avm_alu_rng_chk_sel = FF(static_cast(src.rng_chk_sel)); dest.avm_alu_cmp_rng_ctr = FF(static_cast(src.cmp_rng_ctr)); dest.avm_alu_rng_chk_lookup_selector = FF(1); } + if (dest.avm_alu_op_div == FF(1)) { + dest.avm_alu_op_div_std = uint256_t(src.alu_ia) >= uint256_t(src.alu_ib); + dest.avm_alu_op_div_a_lt_b = uint256_t(src.alu_ia) < uint256_t(src.alu_ib); + dest.avm_alu_rng_chk_lookup_selector = FF(1); + dest.avm_alu_a_lo = FF(src.hi_lo_limbs.at(0)); + dest.avm_alu_a_hi = FF(src.hi_lo_limbs.at(1)); + dest.avm_alu_b_lo = FF(src.hi_lo_limbs.at(2)); + dest.avm_alu_b_hi = FF(src.hi_lo_limbs.at(3)); + dest.avm_alu_p_sub_a_lo = FF(src.hi_lo_limbs.at(4)); + dest.avm_alu_p_sub_a_hi = FF(src.hi_lo_limbs.at(5)); + dest.avm_alu_remainder = src.remainder; + dest.avm_alu_divisor_lo = src.divisor_lo; + dest.avm_alu_divisor_hi = src.divisor_hi; + dest.avm_alu_quotient_lo = src.quotient_lo; + dest.avm_alu_quotient_hi = src.quotient_hi; + dest.avm_alu_partial_prod_lo = src.partial_prod_lo; + dest.avm_alu_partial_prod_hi = src.partial_prod_hi; + } if (dest.avm_alu_op_add == FF(1) || dest.avm_alu_op_sub == FF(1) || dest.avm_alu_op_mul == FF(1)) { dest.avm_alu_rng_chk_lookup_selector = FF(1); @@ -1763,8 +1868,8 @@ std::vector AvmTraceBuilder::finalize() if ((r.avm_main_sel_op_add == FF(1) || r.avm_main_sel_op_sub == FF(1) || r.avm_main_sel_op_mul == FF(1) || r.avm_main_sel_op_eq == FF(1) || r.avm_main_sel_op_not == FF(1) || r.avm_main_sel_op_lt == FF(1) || r.avm_main_sel_op_lte == FF(1) || r.avm_main_sel_op_cast == FF(1) || r.avm_main_sel_op_shr == FF(1) || - r.avm_main_sel_op_shl == FF(1)) && - r.avm_main_tag_err == FF(0)) { + r.avm_main_sel_op_shl == FF(1) || r.avm_main_sel_op_div == FF(1)) && + r.avm_main_tag_err == FF(0) && r.avm_main_op_err == FF(0)) { r.avm_main_alu_sel = FF(1); } @@ -1800,6 +1905,15 @@ std::vector AvmTraceBuilder::finalize() r.lookup_mem_rng_chk_hi_counts = mem_rng_check_hi_counts[static_cast(i)]; r.lookup_mem_rng_chk_lo_counts = mem_rng_check_lo_counts[static_cast(i)]; + r.lookup_div_u16_0_counts = alu_trace_builder.div_u64_range_chk_counters[0][static_cast(i)]; + r.lookup_div_u16_1_counts = alu_trace_builder.div_u64_range_chk_counters[1][static_cast(i)]; + r.lookup_div_u16_2_counts = alu_trace_builder.div_u64_range_chk_counters[2][static_cast(i)]; + r.lookup_div_u16_3_counts = alu_trace_builder.div_u64_range_chk_counters[3][static_cast(i)]; + r.lookup_div_u16_4_counts = alu_trace_builder.div_u64_range_chk_counters[4][static_cast(i)]; + r.lookup_div_u16_5_counts = alu_trace_builder.div_u64_range_chk_counters[5][static_cast(i)]; + r.lookup_div_u16_6_counts = alu_trace_builder.div_u64_range_chk_counters[6][static_cast(i)]; + r.lookup_div_u16_7_counts = alu_trace_builder.div_u64_range_chk_counters[7][static_cast(i)]; + r.avm_main_clk = FF(static_cast(i)); r.avm_main_sel_rng_16 = FF(1); } diff --git a/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_trace.hpp b/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_trace.hpp index d6ba959df17..88b3ced5578 100644 --- a/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_trace.hpp +++ b/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_trace.hpp @@ -82,6 +82,9 @@ class AvmTraceBuilder { // store the result in address given by dst_offset. void op_cast(uint8_t indirect, uint32_t a_offset, uint32_t dst_offset, AvmMemoryTag dst_tag); + // Integer Division with direct or indirect memory access. + void op_div(uint8_t indirect, uint32_t a_offset, uint32_t b_offset, uint32_t dst_offset, AvmMemoryTag in_tag); + // Jump to a given program counter. void jump(uint32_t jmp_dest); diff --git a/barretenberg/cpp/src/barretenberg/vm/generated/avm_circuit_builder.hpp b/barretenberg/cpp/src/barretenberg/vm/generated/avm_circuit_builder.hpp index 8e46d8e00f4..f8b40095206 100644 --- a/barretenberg/cpp/src/barretenberg/vm/generated/avm_circuit_builder.hpp +++ b/barretenberg/cpp/src/barretenberg/vm/generated/avm_circuit_builder.hpp @@ -19,6 +19,14 @@ #include "barretenberg/relations/generated/avm/incl_mem_tag_err.hpp" #include "barretenberg/relations/generated/avm/lookup_byte_lengths.hpp" #include "barretenberg/relations/generated/avm/lookup_byte_operations.hpp" +#include "barretenberg/relations/generated/avm/lookup_div_u16_0.hpp" +#include "barretenberg/relations/generated/avm/lookup_div_u16_1.hpp" +#include "barretenberg/relations/generated/avm/lookup_div_u16_2.hpp" +#include "barretenberg/relations/generated/avm/lookup_div_u16_3.hpp" +#include "barretenberg/relations/generated/avm/lookup_div_u16_4.hpp" +#include "barretenberg/relations/generated/avm/lookup_div_u16_5.hpp" +#include "barretenberg/relations/generated/avm/lookup_div_u16_6.hpp" +#include "barretenberg/relations/generated/avm/lookup_div_u16_7.hpp" #include "barretenberg/relations/generated/avm/lookup_mem_rng_chk_hi.hpp" #include "barretenberg/relations/generated/avm/lookup_mem_rng_chk_lo.hpp" #include "barretenberg/relations/generated/avm/lookup_pow_2_0.hpp" @@ -67,6 +75,17 @@ template struct AvmFullRow { FF avm_alu_clk{}; FF avm_alu_cmp_rng_ctr{}; FF avm_alu_cmp_sel{}; + FF avm_alu_div_rng_chk_selector{}; + FF avm_alu_div_u16_r0{}; + FF avm_alu_div_u16_r1{}; + FF avm_alu_div_u16_r2{}; + FF avm_alu_div_u16_r3{}; + FF avm_alu_div_u16_r4{}; + FF avm_alu_div_u16_r5{}; + FF avm_alu_div_u16_r6{}; + FF avm_alu_div_u16_r7{}; + FF avm_alu_divisor_hi{}; + FF avm_alu_divisor_lo{}; FF avm_alu_ff_tag{}; FF avm_alu_ia{}; FF avm_alu_ib{}; @@ -76,6 +95,8 @@ template struct AvmFullRow { FF avm_alu_op_cast{}; FF avm_alu_op_cast_prev{}; FF avm_alu_op_div{}; + FF avm_alu_op_div_a_lt_b{}; + FF avm_alu_op_div_std{}; FF avm_alu_op_eq{}; FF avm_alu_op_eq_diff_inv{}; FF avm_alu_op_lt{}; @@ -91,6 +112,11 @@ template struct AvmFullRow { FF avm_alu_p_sub_a_lo{}; FF avm_alu_p_sub_b_hi{}; FF avm_alu_p_sub_b_lo{}; + FF avm_alu_partial_prod_hi{}; + FF avm_alu_partial_prod_lo{}; + FF avm_alu_quotient_hi{}; + FF avm_alu_quotient_lo{}; + FF avm_alu_remainder{}; FF avm_alu_res_hi{}; FF avm_alu_res_lo{}; FF avm_alu_rng_chk_lookup_selector{}; @@ -268,6 +294,14 @@ template struct AvmFullRow { FF lookup_u16_12{}; FF lookup_u16_13{}; FF lookup_u16_14{}; + FF lookup_div_u16_0{}; + FF lookup_div_u16_1{}; + FF lookup_div_u16_2{}; + FF lookup_div_u16_3{}; + FF lookup_div_u16_4{}; + FF lookup_div_u16_5{}; + FF lookup_div_u16_6{}; + FF lookup_div_u16_7{}; FF lookup_byte_lengths_counts{}; FF lookup_byte_operations_counts{}; FF incl_main_tag_err_counts{}; @@ -293,6 +327,14 @@ template struct AvmFullRow { FF lookup_u16_12_counts{}; FF lookup_u16_13_counts{}; FF lookup_u16_14_counts{}; + FF lookup_div_u16_0_counts{}; + FF lookup_div_u16_1_counts{}; + FF lookup_div_u16_2_counts{}; + FF lookup_div_u16_3_counts{}; + FF lookup_div_u16_4_counts{}; + FF lookup_div_u16_5_counts{}; + FF lookup_div_u16_6_counts{}; + FF lookup_div_u16_7_counts{}; FF avm_alu_a_hi_shift{}; FF avm_alu_a_lo_shift{}; FF avm_alu_alu_sel_shift{}; @@ -300,9 +342,19 @@ template struct AvmFullRow { FF avm_alu_b_lo_shift{}; FF avm_alu_cmp_rng_ctr_shift{}; FF avm_alu_cmp_sel_shift{}; + FF avm_alu_div_rng_chk_selector_shift{}; + FF avm_alu_div_u16_r0_shift{}; + FF avm_alu_div_u16_r1_shift{}; + FF avm_alu_div_u16_r2_shift{}; + FF avm_alu_div_u16_r3_shift{}; + FF avm_alu_div_u16_r4_shift{}; + FF avm_alu_div_u16_r5_shift{}; + FF avm_alu_div_u16_r6_shift{}; + FF avm_alu_div_u16_r7_shift{}; FF avm_alu_op_add_shift{}; FF avm_alu_op_cast_prev_shift{}; FF avm_alu_op_cast_shift{}; + FF avm_alu_op_div_shift{}; FF avm_alu_op_mul_shift{}; FF avm_alu_op_shl_shift{}; FF avm_alu_op_shr_shift{}; @@ -347,8 +399,8 @@ class AvmCircuitBuilder { using Polynomial = Flavor::Polynomial; using ProverPolynomials = Flavor::ProverPolynomials; - static constexpr size_t num_fixed_columns = 280; - static constexpr size_t num_polys = 238; + static constexpr size_t num_fixed_columns = 324; + static constexpr size_t num_polys = 272; std::vector rows; void set_trace(std::vector&& trace) { rows = std::move(trace); } @@ -376,6 +428,17 @@ class AvmCircuitBuilder { polys.avm_alu_clk[i] = rows[i].avm_alu_clk; polys.avm_alu_cmp_rng_ctr[i] = rows[i].avm_alu_cmp_rng_ctr; polys.avm_alu_cmp_sel[i] = rows[i].avm_alu_cmp_sel; + polys.avm_alu_div_rng_chk_selector[i] = rows[i].avm_alu_div_rng_chk_selector; + polys.avm_alu_div_u16_r0[i] = rows[i].avm_alu_div_u16_r0; + polys.avm_alu_div_u16_r1[i] = rows[i].avm_alu_div_u16_r1; + polys.avm_alu_div_u16_r2[i] = rows[i].avm_alu_div_u16_r2; + polys.avm_alu_div_u16_r3[i] = rows[i].avm_alu_div_u16_r3; + polys.avm_alu_div_u16_r4[i] = rows[i].avm_alu_div_u16_r4; + polys.avm_alu_div_u16_r5[i] = rows[i].avm_alu_div_u16_r5; + polys.avm_alu_div_u16_r6[i] = rows[i].avm_alu_div_u16_r6; + polys.avm_alu_div_u16_r7[i] = rows[i].avm_alu_div_u16_r7; + polys.avm_alu_divisor_hi[i] = rows[i].avm_alu_divisor_hi; + polys.avm_alu_divisor_lo[i] = rows[i].avm_alu_divisor_lo; polys.avm_alu_ff_tag[i] = rows[i].avm_alu_ff_tag; polys.avm_alu_ia[i] = rows[i].avm_alu_ia; polys.avm_alu_ib[i] = rows[i].avm_alu_ib; @@ -385,6 +448,8 @@ class AvmCircuitBuilder { polys.avm_alu_op_cast[i] = rows[i].avm_alu_op_cast; polys.avm_alu_op_cast_prev[i] = rows[i].avm_alu_op_cast_prev; polys.avm_alu_op_div[i] = rows[i].avm_alu_op_div; + polys.avm_alu_op_div_a_lt_b[i] = rows[i].avm_alu_op_div_a_lt_b; + polys.avm_alu_op_div_std[i] = rows[i].avm_alu_op_div_std; polys.avm_alu_op_eq[i] = rows[i].avm_alu_op_eq; polys.avm_alu_op_eq_diff_inv[i] = rows[i].avm_alu_op_eq_diff_inv; polys.avm_alu_op_lt[i] = rows[i].avm_alu_op_lt; @@ -400,6 +465,11 @@ class AvmCircuitBuilder { polys.avm_alu_p_sub_a_lo[i] = rows[i].avm_alu_p_sub_a_lo; polys.avm_alu_p_sub_b_hi[i] = rows[i].avm_alu_p_sub_b_hi; polys.avm_alu_p_sub_b_lo[i] = rows[i].avm_alu_p_sub_b_lo; + polys.avm_alu_partial_prod_hi[i] = rows[i].avm_alu_partial_prod_hi; + polys.avm_alu_partial_prod_lo[i] = rows[i].avm_alu_partial_prod_lo; + polys.avm_alu_quotient_hi[i] = rows[i].avm_alu_quotient_hi; + polys.avm_alu_quotient_lo[i] = rows[i].avm_alu_quotient_lo; + polys.avm_alu_remainder[i] = rows[i].avm_alu_remainder; polys.avm_alu_res_hi[i] = rows[i].avm_alu_res_hi; polys.avm_alu_res_lo[i] = rows[i].avm_alu_res_lo; polys.avm_alu_rng_chk_lookup_selector[i] = rows[i].avm_alu_rng_chk_lookup_selector; @@ -567,6 +637,14 @@ class AvmCircuitBuilder { polys.lookup_u16_12_counts[i] = rows[i].lookup_u16_12_counts; polys.lookup_u16_13_counts[i] = rows[i].lookup_u16_13_counts; polys.lookup_u16_14_counts[i] = rows[i].lookup_u16_14_counts; + polys.lookup_div_u16_0_counts[i] = rows[i].lookup_div_u16_0_counts; + polys.lookup_div_u16_1_counts[i] = rows[i].lookup_div_u16_1_counts; + polys.lookup_div_u16_2_counts[i] = rows[i].lookup_div_u16_2_counts; + polys.lookup_div_u16_3_counts[i] = rows[i].lookup_div_u16_3_counts; + polys.lookup_div_u16_4_counts[i] = rows[i].lookup_div_u16_4_counts; + polys.lookup_div_u16_5_counts[i] = rows[i].lookup_div_u16_5_counts; + polys.lookup_div_u16_6_counts[i] = rows[i].lookup_div_u16_6_counts; + polys.lookup_div_u16_7_counts[i] = rows[i].lookup_div_u16_7_counts; } polys.avm_alu_a_hi_shift = Polynomial(polys.avm_alu_a_hi.shifted()); @@ -576,9 +654,19 @@ class AvmCircuitBuilder { polys.avm_alu_b_lo_shift = Polynomial(polys.avm_alu_b_lo.shifted()); polys.avm_alu_cmp_rng_ctr_shift = Polynomial(polys.avm_alu_cmp_rng_ctr.shifted()); polys.avm_alu_cmp_sel_shift = Polynomial(polys.avm_alu_cmp_sel.shifted()); + polys.avm_alu_div_rng_chk_selector_shift = Polynomial(polys.avm_alu_div_rng_chk_selector.shifted()); + polys.avm_alu_div_u16_r0_shift = Polynomial(polys.avm_alu_div_u16_r0.shifted()); + polys.avm_alu_div_u16_r1_shift = Polynomial(polys.avm_alu_div_u16_r1.shifted()); + polys.avm_alu_div_u16_r2_shift = Polynomial(polys.avm_alu_div_u16_r2.shifted()); + polys.avm_alu_div_u16_r3_shift = Polynomial(polys.avm_alu_div_u16_r3.shifted()); + polys.avm_alu_div_u16_r4_shift = Polynomial(polys.avm_alu_div_u16_r4.shifted()); + polys.avm_alu_div_u16_r5_shift = Polynomial(polys.avm_alu_div_u16_r5.shifted()); + polys.avm_alu_div_u16_r6_shift = Polynomial(polys.avm_alu_div_u16_r6.shifted()); + polys.avm_alu_div_u16_r7_shift = Polynomial(polys.avm_alu_div_u16_r7.shifted()); polys.avm_alu_op_add_shift = Polynomial(polys.avm_alu_op_add.shifted()); polys.avm_alu_op_cast_prev_shift = Polynomial(polys.avm_alu_op_cast_prev.shifted()); polys.avm_alu_op_cast_shift = Polynomial(polys.avm_alu_op_cast.shifted()); + polys.avm_alu_op_div_shift = Polynomial(polys.avm_alu_op_div.shifted()); polys.avm_alu_op_mul_shift = Polynomial(polys.avm_alu_op_mul.shifted()); polys.avm_alu_op_shl_shift = Polynomial(polys.avm_alu_op_shl.shifted()); polys.avm_alu_op_shr_shift = Polynomial(polys.avm_alu_op_shr.shifted()); @@ -805,6 +893,30 @@ class AvmCircuitBuilder { if (!evaluate_logderivative.template operator()>("LOOKUP_U16_14")) { return false; } + if (!evaluate_logderivative.template operator()>("LOOKUP_DIV_U16_0")) { + return false; + } + if (!evaluate_logderivative.template operator()>("LOOKUP_DIV_U16_1")) { + return false; + } + if (!evaluate_logderivative.template operator()>("LOOKUP_DIV_U16_2")) { + return false; + } + if (!evaluate_logderivative.template operator()>("LOOKUP_DIV_U16_3")) { + return false; + } + if (!evaluate_logderivative.template operator()>("LOOKUP_DIV_U16_4")) { + return false; + } + if (!evaluate_logderivative.template operator()>("LOOKUP_DIV_U16_5")) { + return false; + } + if (!evaluate_logderivative.template operator()>("LOOKUP_DIV_U16_6")) { + return false; + } + if (!evaluate_logderivative.template operator()>("LOOKUP_DIV_U16_7")) { + return false; + } return true; } diff --git a/barretenberg/cpp/src/barretenberg/vm/generated/avm_flavor.hpp b/barretenberg/cpp/src/barretenberg/vm/generated/avm_flavor.hpp index 08c3cffd783..1921397837f 100644 --- a/barretenberg/cpp/src/barretenberg/vm/generated/avm_flavor.hpp +++ b/barretenberg/cpp/src/barretenberg/vm/generated/avm_flavor.hpp @@ -21,6 +21,14 @@ #include "barretenberg/relations/generated/avm/incl_mem_tag_err.hpp" #include "barretenberg/relations/generated/avm/lookup_byte_lengths.hpp" #include "barretenberg/relations/generated/avm/lookup_byte_operations.hpp" +#include "barretenberg/relations/generated/avm/lookup_div_u16_0.hpp" +#include "barretenberg/relations/generated/avm/lookup_div_u16_1.hpp" +#include "barretenberg/relations/generated/avm/lookup_div_u16_2.hpp" +#include "barretenberg/relations/generated/avm/lookup_div_u16_3.hpp" +#include "barretenberg/relations/generated/avm/lookup_div_u16_4.hpp" +#include "barretenberg/relations/generated/avm/lookup_div_u16_5.hpp" +#include "barretenberg/relations/generated/avm/lookup_div_u16_6.hpp" +#include "barretenberg/relations/generated/avm/lookup_div_u16_7.hpp" #include "barretenberg/relations/generated/avm/lookup_mem_rng_chk_hi.hpp" #include "barretenberg/relations/generated/avm/lookup_mem_rng_chk_lo.hpp" #include "barretenberg/relations/generated/avm/lookup_pow_2_0.hpp" @@ -73,11 +81,11 @@ class AvmFlavor { using RelationSeparator = FF; static constexpr size_t NUM_PRECOMPUTED_ENTITIES = 2; - static constexpr size_t NUM_WITNESS_ENTITIES = 236; + static constexpr size_t NUM_WITNESS_ENTITIES = 270; static constexpr size_t NUM_WIRES = NUM_WITNESS_ENTITIES + NUM_PRECOMPUTED_ENTITIES; // We have two copies of the witness entities, so we subtract the number of fixed ones (they have no shift), one for // the unshifted and one for the shifted - static constexpr size_t NUM_ALL_ENTITIES = 280; + static constexpr size_t NUM_ALL_ENTITIES = 324; using GrandProductRelations = std::tuple, perm_main_bin_relation, @@ -113,7 +121,15 @@ class AvmFlavor { lookup_u16_11_relation, lookup_u16_12_relation, lookup_u16_13_relation, - lookup_u16_14_relation>; + lookup_u16_14_relation, + lookup_div_u16_0_relation, + lookup_div_u16_1_relation, + lookup_div_u16_2_relation, + lookup_div_u16_3_relation, + lookup_div_u16_4_relation, + lookup_div_u16_5_relation, + lookup_div_u16_6_relation, + lookup_div_u16_7_relation>; using Relations = std::tuple, Avm_vm::avm_binary, @@ -153,7 +169,15 @@ class AvmFlavor { lookup_u16_11_relation, lookup_u16_12_relation, lookup_u16_13_relation, - lookup_u16_14_relation>; + lookup_u16_14_relation, + lookup_div_u16_0_relation, + lookup_div_u16_1_relation, + lookup_div_u16_2_relation, + lookup_div_u16_3_relation, + lookup_div_u16_4_relation, + lookup_div_u16_5_relation, + lookup_div_u16_6_relation, + lookup_div_u16_7_relation>; static constexpr size_t MAX_PARTIAL_RELATION_LENGTH = compute_max_partial_relation_length(); @@ -197,6 +221,17 @@ class AvmFlavor { avm_alu_clk, avm_alu_cmp_rng_ctr, avm_alu_cmp_sel, + avm_alu_div_rng_chk_selector, + avm_alu_div_u16_r0, + avm_alu_div_u16_r1, + avm_alu_div_u16_r2, + avm_alu_div_u16_r3, + avm_alu_div_u16_r4, + avm_alu_div_u16_r5, + avm_alu_div_u16_r6, + avm_alu_div_u16_r7, + avm_alu_divisor_hi, + avm_alu_divisor_lo, avm_alu_ff_tag, avm_alu_ia, avm_alu_ib, @@ -206,6 +241,8 @@ class AvmFlavor { avm_alu_op_cast, avm_alu_op_cast_prev, avm_alu_op_div, + avm_alu_op_div_a_lt_b, + avm_alu_op_div_std, avm_alu_op_eq, avm_alu_op_eq_diff_inv, avm_alu_op_lt, @@ -221,6 +258,11 @@ class AvmFlavor { avm_alu_p_sub_a_lo, avm_alu_p_sub_b_hi, avm_alu_p_sub_b_lo, + avm_alu_partial_prod_hi, + avm_alu_partial_prod_lo, + avm_alu_quotient_hi, + avm_alu_quotient_lo, + avm_alu_remainder, avm_alu_res_hi, avm_alu_res_lo, avm_alu_rng_chk_lookup_selector, @@ -398,6 +440,14 @@ class AvmFlavor { lookup_u16_12, lookup_u16_13, lookup_u16_14, + lookup_div_u16_0, + lookup_div_u16_1, + lookup_div_u16_2, + lookup_div_u16_3, + lookup_div_u16_4, + lookup_div_u16_5, + lookup_div_u16_6, + lookup_div_u16_7, lookup_byte_lengths_counts, lookup_byte_operations_counts, incl_main_tag_err_counts, @@ -422,7 +472,15 @@ class AvmFlavor { lookup_u16_11_counts, lookup_u16_12_counts, lookup_u16_13_counts, - lookup_u16_14_counts) + lookup_u16_14_counts, + lookup_div_u16_0_counts, + lookup_div_u16_1_counts, + lookup_div_u16_2_counts, + lookup_div_u16_3_counts, + lookup_div_u16_4_counts, + lookup_div_u16_5_counts, + lookup_div_u16_6_counts, + lookup_div_u16_7_counts) RefVector get_wires() { @@ -436,6 +494,17 @@ class AvmFlavor { avm_alu_clk, avm_alu_cmp_rng_ctr, avm_alu_cmp_sel, + avm_alu_div_rng_chk_selector, + avm_alu_div_u16_r0, + avm_alu_div_u16_r1, + avm_alu_div_u16_r2, + avm_alu_div_u16_r3, + avm_alu_div_u16_r4, + avm_alu_div_u16_r5, + avm_alu_div_u16_r6, + avm_alu_div_u16_r7, + avm_alu_divisor_hi, + avm_alu_divisor_lo, avm_alu_ff_tag, avm_alu_ia, avm_alu_ib, @@ -445,6 +514,8 @@ class AvmFlavor { avm_alu_op_cast, avm_alu_op_cast_prev, avm_alu_op_div, + avm_alu_op_div_a_lt_b, + avm_alu_op_div_std, avm_alu_op_eq, avm_alu_op_eq_diff_inv, avm_alu_op_lt, @@ -460,6 +531,11 @@ class AvmFlavor { avm_alu_p_sub_a_lo, avm_alu_p_sub_b_hi, avm_alu_p_sub_b_lo, + avm_alu_partial_prod_hi, + avm_alu_partial_prod_lo, + avm_alu_quotient_hi, + avm_alu_quotient_lo, + avm_alu_remainder, avm_alu_res_hi, avm_alu_res_lo, avm_alu_rng_chk_lookup_selector, @@ -637,6 +713,14 @@ class AvmFlavor { lookup_u16_12, lookup_u16_13, lookup_u16_14, + lookup_div_u16_0, + lookup_div_u16_1, + lookup_div_u16_2, + lookup_div_u16_3, + lookup_div_u16_4, + lookup_div_u16_5, + lookup_div_u16_6, + lookup_div_u16_7, lookup_byte_lengths_counts, lookup_byte_operations_counts, incl_main_tag_err_counts, @@ -661,7 +745,15 @@ class AvmFlavor { lookup_u16_11_counts, lookup_u16_12_counts, lookup_u16_13_counts, - lookup_u16_14_counts }; + lookup_u16_14_counts, + lookup_div_u16_0_counts, + lookup_div_u16_1_counts, + lookup_div_u16_2_counts, + lookup_div_u16_3_counts, + lookup_div_u16_4_counts, + lookup_div_u16_5_counts, + lookup_div_u16_6_counts, + lookup_div_u16_7_counts }; }; }; @@ -680,6 +772,17 @@ class AvmFlavor { avm_alu_clk, avm_alu_cmp_rng_ctr, avm_alu_cmp_sel, + avm_alu_div_rng_chk_selector, + avm_alu_div_u16_r0, + avm_alu_div_u16_r1, + avm_alu_div_u16_r2, + avm_alu_div_u16_r3, + avm_alu_div_u16_r4, + avm_alu_div_u16_r5, + avm_alu_div_u16_r6, + avm_alu_div_u16_r7, + avm_alu_divisor_hi, + avm_alu_divisor_lo, avm_alu_ff_tag, avm_alu_ia, avm_alu_ib, @@ -689,6 +792,8 @@ class AvmFlavor { avm_alu_op_cast, avm_alu_op_cast_prev, avm_alu_op_div, + avm_alu_op_div_a_lt_b, + avm_alu_op_div_std, avm_alu_op_eq, avm_alu_op_eq_diff_inv, avm_alu_op_lt, @@ -704,6 +809,11 @@ class AvmFlavor { avm_alu_p_sub_a_lo, avm_alu_p_sub_b_hi, avm_alu_p_sub_b_lo, + avm_alu_partial_prod_hi, + avm_alu_partial_prod_lo, + avm_alu_quotient_hi, + avm_alu_quotient_lo, + avm_alu_remainder, avm_alu_res_hi, avm_alu_res_lo, avm_alu_rng_chk_lookup_selector, @@ -881,6 +991,14 @@ class AvmFlavor { lookup_u16_12, lookup_u16_13, lookup_u16_14, + lookup_div_u16_0, + lookup_div_u16_1, + lookup_div_u16_2, + lookup_div_u16_3, + lookup_div_u16_4, + lookup_div_u16_5, + lookup_div_u16_6, + lookup_div_u16_7, lookup_byte_lengths_counts, lookup_byte_operations_counts, incl_main_tag_err_counts, @@ -906,6 +1024,14 @@ class AvmFlavor { lookup_u16_12_counts, lookup_u16_13_counts, lookup_u16_14_counts, + lookup_div_u16_0_counts, + lookup_div_u16_1_counts, + lookup_div_u16_2_counts, + lookup_div_u16_3_counts, + lookup_div_u16_4_counts, + lookup_div_u16_5_counts, + lookup_div_u16_6_counts, + lookup_div_u16_7_counts, avm_alu_a_hi_shift, avm_alu_a_lo_shift, avm_alu_alu_sel_shift, @@ -913,9 +1039,19 @@ class AvmFlavor { avm_alu_b_lo_shift, avm_alu_cmp_rng_ctr_shift, avm_alu_cmp_sel_shift, + avm_alu_div_rng_chk_selector_shift, + avm_alu_div_u16_r0_shift, + avm_alu_div_u16_r1_shift, + avm_alu_div_u16_r2_shift, + avm_alu_div_u16_r3_shift, + avm_alu_div_u16_r4_shift, + avm_alu_div_u16_r5_shift, + avm_alu_div_u16_r6_shift, + avm_alu_div_u16_r7_shift, avm_alu_op_add_shift, avm_alu_op_cast_prev_shift, avm_alu_op_cast_shift, + avm_alu_op_div_shift, avm_alu_op_mul_shift, avm_alu_op_shl_shift, avm_alu_op_shr_shift, @@ -963,6 +1099,17 @@ class AvmFlavor { avm_alu_clk, avm_alu_cmp_rng_ctr, avm_alu_cmp_sel, + avm_alu_div_rng_chk_selector, + avm_alu_div_u16_r0, + avm_alu_div_u16_r1, + avm_alu_div_u16_r2, + avm_alu_div_u16_r3, + avm_alu_div_u16_r4, + avm_alu_div_u16_r5, + avm_alu_div_u16_r6, + avm_alu_div_u16_r7, + avm_alu_divisor_hi, + avm_alu_divisor_lo, avm_alu_ff_tag, avm_alu_ia, avm_alu_ib, @@ -972,6 +1119,8 @@ class AvmFlavor { avm_alu_op_cast, avm_alu_op_cast_prev, avm_alu_op_div, + avm_alu_op_div_a_lt_b, + avm_alu_op_div_std, avm_alu_op_eq, avm_alu_op_eq_diff_inv, avm_alu_op_lt, @@ -987,6 +1136,11 @@ class AvmFlavor { avm_alu_p_sub_a_lo, avm_alu_p_sub_b_hi, avm_alu_p_sub_b_lo, + avm_alu_partial_prod_hi, + avm_alu_partial_prod_lo, + avm_alu_quotient_hi, + avm_alu_quotient_lo, + avm_alu_remainder, avm_alu_res_hi, avm_alu_res_lo, avm_alu_rng_chk_lookup_selector, @@ -1164,6 +1318,14 @@ class AvmFlavor { lookup_u16_12, lookup_u16_13, lookup_u16_14, + lookup_div_u16_0, + lookup_div_u16_1, + lookup_div_u16_2, + lookup_div_u16_3, + lookup_div_u16_4, + lookup_div_u16_5, + lookup_div_u16_6, + lookup_div_u16_7, lookup_byte_lengths_counts, lookup_byte_operations_counts, incl_main_tag_err_counts, @@ -1189,6 +1351,14 @@ class AvmFlavor { lookup_u16_12_counts, lookup_u16_13_counts, lookup_u16_14_counts, + lookup_div_u16_0_counts, + lookup_div_u16_1_counts, + lookup_div_u16_2_counts, + lookup_div_u16_3_counts, + lookup_div_u16_4_counts, + lookup_div_u16_5_counts, + lookup_div_u16_6_counts, + lookup_div_u16_7_counts, avm_alu_a_hi_shift, avm_alu_a_lo_shift, avm_alu_alu_sel_shift, @@ -1196,9 +1366,19 @@ class AvmFlavor { avm_alu_b_lo_shift, avm_alu_cmp_rng_ctr_shift, avm_alu_cmp_sel_shift, + avm_alu_div_rng_chk_selector_shift, + avm_alu_div_u16_r0_shift, + avm_alu_div_u16_r1_shift, + avm_alu_div_u16_r2_shift, + avm_alu_div_u16_r3_shift, + avm_alu_div_u16_r4_shift, + avm_alu_div_u16_r5_shift, + avm_alu_div_u16_r6_shift, + avm_alu_div_u16_r7_shift, avm_alu_op_add_shift, avm_alu_op_cast_prev_shift, avm_alu_op_cast_shift, + avm_alu_op_div_shift, avm_alu_op_mul_shift, avm_alu_op_shl_shift, avm_alu_op_shr_shift, @@ -1246,6 +1426,17 @@ class AvmFlavor { avm_alu_clk, avm_alu_cmp_rng_ctr, avm_alu_cmp_sel, + avm_alu_div_rng_chk_selector, + avm_alu_div_u16_r0, + avm_alu_div_u16_r1, + avm_alu_div_u16_r2, + avm_alu_div_u16_r3, + avm_alu_div_u16_r4, + avm_alu_div_u16_r5, + avm_alu_div_u16_r6, + avm_alu_div_u16_r7, + avm_alu_divisor_hi, + avm_alu_divisor_lo, avm_alu_ff_tag, avm_alu_ia, avm_alu_ib, @@ -1255,6 +1446,8 @@ class AvmFlavor { avm_alu_op_cast, avm_alu_op_cast_prev, avm_alu_op_div, + avm_alu_op_div_a_lt_b, + avm_alu_op_div_std, avm_alu_op_eq, avm_alu_op_eq_diff_inv, avm_alu_op_lt, @@ -1270,6 +1463,11 @@ class AvmFlavor { avm_alu_p_sub_a_lo, avm_alu_p_sub_b_hi, avm_alu_p_sub_b_lo, + avm_alu_partial_prod_hi, + avm_alu_partial_prod_lo, + avm_alu_quotient_hi, + avm_alu_quotient_lo, + avm_alu_remainder, avm_alu_res_hi, avm_alu_res_lo, avm_alu_rng_chk_lookup_selector, @@ -1447,6 +1645,14 @@ class AvmFlavor { lookup_u16_12, lookup_u16_13, lookup_u16_14, + lookup_div_u16_0, + lookup_div_u16_1, + lookup_div_u16_2, + lookup_div_u16_3, + lookup_div_u16_4, + lookup_div_u16_5, + lookup_div_u16_6, + lookup_div_u16_7, lookup_byte_lengths_counts, lookup_byte_operations_counts, incl_main_tag_err_counts, @@ -1471,7 +1677,15 @@ class AvmFlavor { lookup_u16_11_counts, lookup_u16_12_counts, lookup_u16_13_counts, - lookup_u16_14_counts }; + lookup_u16_14_counts, + lookup_div_u16_0_counts, + lookup_div_u16_1_counts, + lookup_div_u16_2_counts, + lookup_div_u16_3_counts, + lookup_div_u16_4_counts, + lookup_div_u16_5_counts, + lookup_div_u16_6_counts, + lookup_div_u16_7_counts }; }; RefVector get_to_be_shifted() { @@ -1482,9 +1696,19 @@ class AvmFlavor { avm_alu_b_lo, avm_alu_cmp_rng_ctr, avm_alu_cmp_sel, + avm_alu_div_rng_chk_selector, + avm_alu_div_u16_r0, + avm_alu_div_u16_r1, + avm_alu_div_u16_r2, + avm_alu_div_u16_r3, + avm_alu_div_u16_r4, + avm_alu_div_u16_r5, + avm_alu_div_u16_r6, + avm_alu_div_u16_r7, avm_alu_op_add, avm_alu_op_cast_prev, avm_alu_op_cast, + avm_alu_op_div, avm_alu_op_mul, avm_alu_op_shl, avm_alu_op_shr, @@ -1527,9 +1751,19 @@ class AvmFlavor { avm_alu_b_lo_shift, avm_alu_cmp_rng_ctr_shift, avm_alu_cmp_sel_shift, + avm_alu_div_rng_chk_selector_shift, + avm_alu_div_u16_r0_shift, + avm_alu_div_u16_r1_shift, + avm_alu_div_u16_r2_shift, + avm_alu_div_u16_r3_shift, + avm_alu_div_u16_r4_shift, + avm_alu_div_u16_r5_shift, + avm_alu_div_u16_r6_shift, + avm_alu_div_u16_r7_shift, avm_alu_op_add_shift, avm_alu_op_cast_prev_shift, avm_alu_op_cast_shift, + avm_alu_op_div_shift, avm_alu_op_mul_shift, avm_alu_op_shl_shift, avm_alu_op_shr_shift, @@ -1582,9 +1816,19 @@ class AvmFlavor { avm_alu_b_lo, avm_alu_cmp_rng_ctr, avm_alu_cmp_sel, + avm_alu_div_rng_chk_selector, + avm_alu_div_u16_r0, + avm_alu_div_u16_r1, + avm_alu_div_u16_r2, + avm_alu_div_u16_r3, + avm_alu_div_u16_r4, + avm_alu_div_u16_r5, + avm_alu_div_u16_r6, + avm_alu_div_u16_r7, avm_alu_op_add, avm_alu_op_cast_prev, avm_alu_op_cast, + avm_alu_op_div, avm_alu_op_mul, avm_alu_op_shl, avm_alu_op_shr, @@ -1693,6 +1937,22 @@ class AvmFlavor { prover_polynomials, relation_parameters, this->circuit_size); bb::compute_logderivative_inverse>( prover_polynomials, relation_parameters, this->circuit_size); + bb::compute_logderivative_inverse>( + prover_polynomials, relation_parameters, this->circuit_size); + bb::compute_logderivative_inverse>( + prover_polynomials, relation_parameters, this->circuit_size); + bb::compute_logderivative_inverse>( + prover_polynomials, relation_parameters, this->circuit_size); + bb::compute_logderivative_inverse>( + prover_polynomials, relation_parameters, this->circuit_size); + bb::compute_logderivative_inverse>( + prover_polynomials, relation_parameters, this->circuit_size); + bb::compute_logderivative_inverse>( + prover_polynomials, relation_parameters, this->circuit_size); + bb::compute_logderivative_inverse>( + prover_polynomials, relation_parameters, this->circuit_size); + bb::compute_logderivative_inverse>( + prover_polynomials, relation_parameters, this->circuit_size); } }; @@ -1765,13 +2025,6 @@ class AvmFlavor { * @details During folding and sumcheck, the prover evaluates the relations on these univariates. */ template using ProverUnivariates = AllEntities>; - /** - * @brief A container for univariates used during Protogalaxy folding and sumcheck with some of the computation - * optmistically ignored - * @details During folding and sumcheck, the prover evaluates the relations on these univariates. - */ - template - using OptimisedProverUnivariates = AllEntities>; /** * @brief A container for univariates produced during the hot loop in sumcheck. @@ -1804,6 +2057,17 @@ class AvmFlavor { Base::avm_alu_clk = "AVM_ALU_CLK"; Base::avm_alu_cmp_rng_ctr = "AVM_ALU_CMP_RNG_CTR"; Base::avm_alu_cmp_sel = "AVM_ALU_CMP_SEL"; + Base::avm_alu_div_rng_chk_selector = "AVM_ALU_DIV_RNG_CHK_SELECTOR"; + Base::avm_alu_div_u16_r0 = "AVM_ALU_DIV_U16_R0"; + Base::avm_alu_div_u16_r1 = "AVM_ALU_DIV_U16_R1"; + Base::avm_alu_div_u16_r2 = "AVM_ALU_DIV_U16_R2"; + Base::avm_alu_div_u16_r3 = "AVM_ALU_DIV_U16_R3"; + Base::avm_alu_div_u16_r4 = "AVM_ALU_DIV_U16_R4"; + Base::avm_alu_div_u16_r5 = "AVM_ALU_DIV_U16_R5"; + Base::avm_alu_div_u16_r6 = "AVM_ALU_DIV_U16_R6"; + Base::avm_alu_div_u16_r7 = "AVM_ALU_DIV_U16_R7"; + Base::avm_alu_divisor_hi = "AVM_ALU_DIVISOR_HI"; + Base::avm_alu_divisor_lo = "AVM_ALU_DIVISOR_LO"; Base::avm_alu_ff_tag = "AVM_ALU_FF_TAG"; Base::avm_alu_ia = "AVM_ALU_IA"; Base::avm_alu_ib = "AVM_ALU_IB"; @@ -1813,6 +2077,8 @@ class AvmFlavor { Base::avm_alu_op_cast = "AVM_ALU_OP_CAST"; Base::avm_alu_op_cast_prev = "AVM_ALU_OP_CAST_PREV"; Base::avm_alu_op_div = "AVM_ALU_OP_DIV"; + Base::avm_alu_op_div_a_lt_b = "AVM_ALU_OP_DIV_A_LT_B"; + Base::avm_alu_op_div_std = "AVM_ALU_OP_DIV_STD"; Base::avm_alu_op_eq = "AVM_ALU_OP_EQ"; Base::avm_alu_op_eq_diff_inv = "AVM_ALU_OP_EQ_DIFF_INV"; Base::avm_alu_op_lt = "AVM_ALU_OP_LT"; @@ -1828,6 +2094,11 @@ class AvmFlavor { Base::avm_alu_p_sub_a_lo = "AVM_ALU_P_SUB_A_LO"; Base::avm_alu_p_sub_b_hi = "AVM_ALU_P_SUB_B_HI"; Base::avm_alu_p_sub_b_lo = "AVM_ALU_P_SUB_B_LO"; + Base::avm_alu_partial_prod_hi = "AVM_ALU_PARTIAL_PROD_HI"; + Base::avm_alu_partial_prod_lo = "AVM_ALU_PARTIAL_PROD_LO"; + Base::avm_alu_quotient_hi = "AVM_ALU_QUOTIENT_HI"; + Base::avm_alu_quotient_lo = "AVM_ALU_QUOTIENT_LO"; + Base::avm_alu_remainder = "AVM_ALU_REMAINDER"; Base::avm_alu_res_hi = "AVM_ALU_RES_HI"; Base::avm_alu_res_lo = "AVM_ALU_RES_LO"; Base::avm_alu_rng_chk_lookup_selector = "AVM_ALU_RNG_CHK_LOOKUP_SELECTOR"; @@ -2005,6 +2276,14 @@ class AvmFlavor { Base::lookup_u16_12 = "LOOKUP_U16_12"; Base::lookup_u16_13 = "LOOKUP_U16_13"; Base::lookup_u16_14 = "LOOKUP_U16_14"; + Base::lookup_div_u16_0 = "LOOKUP_DIV_U16_0"; + Base::lookup_div_u16_1 = "LOOKUP_DIV_U16_1"; + Base::lookup_div_u16_2 = "LOOKUP_DIV_U16_2"; + Base::lookup_div_u16_3 = "LOOKUP_DIV_U16_3"; + Base::lookup_div_u16_4 = "LOOKUP_DIV_U16_4"; + Base::lookup_div_u16_5 = "LOOKUP_DIV_U16_5"; + Base::lookup_div_u16_6 = "LOOKUP_DIV_U16_6"; + Base::lookup_div_u16_7 = "LOOKUP_DIV_U16_7"; Base::lookup_byte_lengths_counts = "LOOKUP_BYTE_LENGTHS_COUNTS"; Base::lookup_byte_operations_counts = "LOOKUP_BYTE_OPERATIONS_COUNTS"; Base::incl_main_tag_err_counts = "INCL_MAIN_TAG_ERR_COUNTS"; @@ -2030,6 +2309,14 @@ class AvmFlavor { Base::lookup_u16_12_counts = "LOOKUP_U16_12_COUNTS"; Base::lookup_u16_13_counts = "LOOKUP_U16_13_COUNTS"; Base::lookup_u16_14_counts = "LOOKUP_U16_14_COUNTS"; + Base::lookup_div_u16_0_counts = "LOOKUP_DIV_U16_0_COUNTS"; + Base::lookup_div_u16_1_counts = "LOOKUP_DIV_U16_1_COUNTS"; + Base::lookup_div_u16_2_counts = "LOOKUP_DIV_U16_2_COUNTS"; + Base::lookup_div_u16_3_counts = "LOOKUP_DIV_U16_3_COUNTS"; + Base::lookup_div_u16_4_counts = "LOOKUP_DIV_U16_4_COUNTS"; + Base::lookup_div_u16_5_counts = "LOOKUP_DIV_U16_5_COUNTS"; + Base::lookup_div_u16_6_counts = "LOOKUP_DIV_U16_6_COUNTS"; + Base::lookup_div_u16_7_counts = "LOOKUP_DIV_U16_7_COUNTS"; }; }; @@ -2059,6 +2346,17 @@ class AvmFlavor { Commitment avm_alu_clk; Commitment avm_alu_cmp_rng_ctr; Commitment avm_alu_cmp_sel; + Commitment avm_alu_div_rng_chk_selector; + Commitment avm_alu_div_u16_r0; + Commitment avm_alu_div_u16_r1; + Commitment avm_alu_div_u16_r2; + Commitment avm_alu_div_u16_r3; + Commitment avm_alu_div_u16_r4; + Commitment avm_alu_div_u16_r5; + Commitment avm_alu_div_u16_r6; + Commitment avm_alu_div_u16_r7; + Commitment avm_alu_divisor_hi; + Commitment avm_alu_divisor_lo; Commitment avm_alu_ff_tag; Commitment avm_alu_ia; Commitment avm_alu_ib; @@ -2068,6 +2366,8 @@ class AvmFlavor { Commitment avm_alu_op_cast; Commitment avm_alu_op_cast_prev; Commitment avm_alu_op_div; + Commitment avm_alu_op_div_a_lt_b; + Commitment avm_alu_op_div_std; Commitment avm_alu_op_eq; Commitment avm_alu_op_eq_diff_inv; Commitment avm_alu_op_lt; @@ -2083,6 +2383,11 @@ class AvmFlavor { Commitment avm_alu_p_sub_a_lo; Commitment avm_alu_p_sub_b_hi; Commitment avm_alu_p_sub_b_lo; + Commitment avm_alu_partial_prod_hi; + Commitment avm_alu_partial_prod_lo; + Commitment avm_alu_quotient_hi; + Commitment avm_alu_quotient_lo; + Commitment avm_alu_remainder; Commitment avm_alu_res_hi; Commitment avm_alu_res_lo; Commitment avm_alu_rng_chk_lookup_selector; @@ -2260,6 +2565,14 @@ class AvmFlavor { Commitment lookup_u16_12; Commitment lookup_u16_13; Commitment lookup_u16_14; + Commitment lookup_div_u16_0; + Commitment lookup_div_u16_1; + Commitment lookup_div_u16_2; + Commitment lookup_div_u16_3; + Commitment lookup_div_u16_4; + Commitment lookup_div_u16_5; + Commitment lookup_div_u16_6; + Commitment lookup_div_u16_7; Commitment lookup_byte_lengths_counts; Commitment lookup_byte_operations_counts; Commitment incl_main_tag_err_counts; @@ -2285,6 +2598,14 @@ class AvmFlavor { Commitment lookup_u16_12_counts; Commitment lookup_u16_13_counts; Commitment lookup_u16_14_counts; + Commitment lookup_div_u16_0_counts; + Commitment lookup_div_u16_1_counts; + Commitment lookup_div_u16_2_counts; + Commitment lookup_div_u16_3_counts; + Commitment lookup_div_u16_4_counts; + Commitment lookup_div_u16_5_counts; + Commitment lookup_div_u16_6_counts; + Commitment lookup_div_u16_7_counts; std::vector> sumcheck_univariates; std::array sumcheck_evaluations; @@ -2314,6 +2635,17 @@ class AvmFlavor { avm_alu_clk = deserialize_from_buffer(Transcript::proof_data, num_frs_read); avm_alu_cmp_rng_ctr = deserialize_from_buffer(Transcript::proof_data, num_frs_read); avm_alu_cmp_sel = deserialize_from_buffer(Transcript::proof_data, num_frs_read); + avm_alu_div_rng_chk_selector = deserialize_from_buffer(Transcript::proof_data, num_frs_read); + avm_alu_div_u16_r0 = deserialize_from_buffer(Transcript::proof_data, num_frs_read); + avm_alu_div_u16_r1 = deserialize_from_buffer(Transcript::proof_data, num_frs_read); + avm_alu_div_u16_r2 = deserialize_from_buffer(Transcript::proof_data, num_frs_read); + avm_alu_div_u16_r3 = deserialize_from_buffer(Transcript::proof_data, num_frs_read); + avm_alu_div_u16_r4 = deserialize_from_buffer(Transcript::proof_data, num_frs_read); + avm_alu_div_u16_r5 = deserialize_from_buffer(Transcript::proof_data, num_frs_read); + avm_alu_div_u16_r6 = deserialize_from_buffer(Transcript::proof_data, num_frs_read); + avm_alu_div_u16_r7 = deserialize_from_buffer(Transcript::proof_data, num_frs_read); + avm_alu_divisor_hi = deserialize_from_buffer(Transcript::proof_data, num_frs_read); + avm_alu_divisor_lo = deserialize_from_buffer(Transcript::proof_data, num_frs_read); avm_alu_ff_tag = deserialize_from_buffer(Transcript::proof_data, num_frs_read); avm_alu_ia = deserialize_from_buffer(Transcript::proof_data, num_frs_read); avm_alu_ib = deserialize_from_buffer(Transcript::proof_data, num_frs_read); @@ -2323,6 +2655,8 @@ class AvmFlavor { avm_alu_op_cast = deserialize_from_buffer(Transcript::proof_data, num_frs_read); avm_alu_op_cast_prev = deserialize_from_buffer(Transcript::proof_data, num_frs_read); avm_alu_op_div = deserialize_from_buffer(Transcript::proof_data, num_frs_read); + avm_alu_op_div_a_lt_b = deserialize_from_buffer(Transcript::proof_data, num_frs_read); + avm_alu_op_div_std = deserialize_from_buffer(Transcript::proof_data, num_frs_read); avm_alu_op_eq = deserialize_from_buffer(Transcript::proof_data, num_frs_read); avm_alu_op_eq_diff_inv = deserialize_from_buffer(Transcript::proof_data, num_frs_read); avm_alu_op_lt = deserialize_from_buffer(Transcript::proof_data, num_frs_read); @@ -2338,6 +2672,11 @@ class AvmFlavor { avm_alu_p_sub_a_lo = deserialize_from_buffer(Transcript::proof_data, num_frs_read); avm_alu_p_sub_b_hi = deserialize_from_buffer(Transcript::proof_data, num_frs_read); avm_alu_p_sub_b_lo = deserialize_from_buffer(Transcript::proof_data, num_frs_read); + avm_alu_partial_prod_hi = deserialize_from_buffer(Transcript::proof_data, num_frs_read); + avm_alu_partial_prod_lo = deserialize_from_buffer(Transcript::proof_data, num_frs_read); + avm_alu_quotient_hi = deserialize_from_buffer(Transcript::proof_data, num_frs_read); + avm_alu_quotient_lo = deserialize_from_buffer(Transcript::proof_data, num_frs_read); + avm_alu_remainder = deserialize_from_buffer(Transcript::proof_data, num_frs_read); avm_alu_res_hi = deserialize_from_buffer(Transcript::proof_data, num_frs_read); avm_alu_res_lo = deserialize_from_buffer(Transcript::proof_data, num_frs_read); avm_alu_rng_chk_lookup_selector = deserialize_from_buffer(Transcript::proof_data, num_frs_read); @@ -2516,6 +2855,14 @@ class AvmFlavor { lookup_u16_12 = deserialize_from_buffer(Transcript::proof_data, num_frs_read); lookup_u16_13 = deserialize_from_buffer(Transcript::proof_data, num_frs_read); lookup_u16_14 = deserialize_from_buffer(Transcript::proof_data, num_frs_read); + lookup_div_u16_0 = deserialize_from_buffer(Transcript::proof_data, num_frs_read); + lookup_div_u16_1 = deserialize_from_buffer(Transcript::proof_data, num_frs_read); + lookup_div_u16_2 = deserialize_from_buffer(Transcript::proof_data, num_frs_read); + lookup_div_u16_3 = deserialize_from_buffer(Transcript::proof_data, num_frs_read); + lookup_div_u16_4 = deserialize_from_buffer(Transcript::proof_data, num_frs_read); + lookup_div_u16_5 = deserialize_from_buffer(Transcript::proof_data, num_frs_read); + lookup_div_u16_6 = deserialize_from_buffer(Transcript::proof_data, num_frs_read); + lookup_div_u16_7 = deserialize_from_buffer(Transcript::proof_data, num_frs_read); lookup_byte_lengths_counts = deserialize_from_buffer(Transcript::proof_data, num_frs_read); lookup_byte_operations_counts = deserialize_from_buffer(Transcript::proof_data, num_frs_read); incl_main_tag_err_counts = deserialize_from_buffer(Transcript::proof_data, num_frs_read); @@ -2541,6 +2888,14 @@ class AvmFlavor { lookup_u16_12_counts = deserialize_from_buffer(Transcript::proof_data, num_frs_read); lookup_u16_13_counts = deserialize_from_buffer(Transcript::proof_data, num_frs_read); lookup_u16_14_counts = deserialize_from_buffer(Transcript::proof_data, num_frs_read); + lookup_div_u16_0_counts = deserialize_from_buffer(Transcript::proof_data, num_frs_read); + lookup_div_u16_1_counts = deserialize_from_buffer(Transcript::proof_data, num_frs_read); + lookup_div_u16_2_counts = deserialize_from_buffer(Transcript::proof_data, num_frs_read); + lookup_div_u16_3_counts = deserialize_from_buffer(Transcript::proof_data, num_frs_read); + lookup_div_u16_4_counts = deserialize_from_buffer(Transcript::proof_data, num_frs_read); + lookup_div_u16_5_counts = deserialize_from_buffer(Transcript::proof_data, num_frs_read); + lookup_div_u16_6_counts = deserialize_from_buffer(Transcript::proof_data, num_frs_read); + lookup_div_u16_7_counts = deserialize_from_buffer(Transcript::proof_data, num_frs_read); for (size_t i = 0; i < log_n; ++i) { sumcheck_univariates.emplace_back( @@ -2574,6 +2929,17 @@ class AvmFlavor { serialize_to_buffer(avm_alu_clk, Transcript::proof_data); serialize_to_buffer(avm_alu_cmp_rng_ctr, Transcript::proof_data); serialize_to_buffer(avm_alu_cmp_sel, Transcript::proof_data); + serialize_to_buffer(avm_alu_div_rng_chk_selector, Transcript::proof_data); + serialize_to_buffer(avm_alu_div_u16_r0, Transcript::proof_data); + serialize_to_buffer(avm_alu_div_u16_r1, Transcript::proof_data); + serialize_to_buffer(avm_alu_div_u16_r2, Transcript::proof_data); + serialize_to_buffer(avm_alu_div_u16_r3, Transcript::proof_data); + serialize_to_buffer(avm_alu_div_u16_r4, Transcript::proof_data); + serialize_to_buffer(avm_alu_div_u16_r5, Transcript::proof_data); + serialize_to_buffer(avm_alu_div_u16_r6, Transcript::proof_data); + serialize_to_buffer(avm_alu_div_u16_r7, Transcript::proof_data); + serialize_to_buffer(avm_alu_divisor_hi, Transcript::proof_data); + serialize_to_buffer(avm_alu_divisor_lo, Transcript::proof_data); serialize_to_buffer(avm_alu_ff_tag, Transcript::proof_data); serialize_to_buffer(avm_alu_ia, Transcript::proof_data); serialize_to_buffer(avm_alu_ib, Transcript::proof_data); @@ -2583,6 +2949,8 @@ class AvmFlavor { serialize_to_buffer(avm_alu_op_cast, Transcript::proof_data); serialize_to_buffer(avm_alu_op_cast_prev, Transcript::proof_data); serialize_to_buffer(avm_alu_op_div, Transcript::proof_data); + serialize_to_buffer(avm_alu_op_div_a_lt_b, Transcript::proof_data); + serialize_to_buffer(avm_alu_op_div_std, Transcript::proof_data); serialize_to_buffer(avm_alu_op_eq, Transcript::proof_data); serialize_to_buffer(avm_alu_op_eq_diff_inv, Transcript::proof_data); serialize_to_buffer(avm_alu_op_lt, Transcript::proof_data); @@ -2598,6 +2966,11 @@ class AvmFlavor { serialize_to_buffer(avm_alu_p_sub_a_lo, Transcript::proof_data); serialize_to_buffer(avm_alu_p_sub_b_hi, Transcript::proof_data); serialize_to_buffer(avm_alu_p_sub_b_lo, Transcript::proof_data); + serialize_to_buffer(avm_alu_partial_prod_hi, Transcript::proof_data); + serialize_to_buffer(avm_alu_partial_prod_lo, Transcript::proof_data); + serialize_to_buffer(avm_alu_quotient_hi, Transcript::proof_data); + serialize_to_buffer(avm_alu_quotient_lo, Transcript::proof_data); + serialize_to_buffer(avm_alu_remainder, Transcript::proof_data); serialize_to_buffer(avm_alu_res_hi, Transcript::proof_data); serialize_to_buffer(avm_alu_res_lo, Transcript::proof_data); serialize_to_buffer(avm_alu_rng_chk_lookup_selector, Transcript::proof_data); @@ -2775,6 +3148,14 @@ class AvmFlavor { serialize_to_buffer(lookup_u16_12, Transcript::proof_data); serialize_to_buffer(lookup_u16_13, Transcript::proof_data); serialize_to_buffer(lookup_u16_14, Transcript::proof_data); + serialize_to_buffer(lookup_div_u16_0, Transcript::proof_data); + serialize_to_buffer(lookup_div_u16_1, Transcript::proof_data); + serialize_to_buffer(lookup_div_u16_2, Transcript::proof_data); + serialize_to_buffer(lookup_div_u16_3, Transcript::proof_data); + serialize_to_buffer(lookup_div_u16_4, Transcript::proof_data); + serialize_to_buffer(lookup_div_u16_5, Transcript::proof_data); + serialize_to_buffer(lookup_div_u16_6, Transcript::proof_data); + serialize_to_buffer(lookup_div_u16_7, Transcript::proof_data); serialize_to_buffer(lookup_byte_lengths_counts, Transcript::proof_data); serialize_to_buffer(lookup_byte_operations_counts, Transcript::proof_data); serialize_to_buffer(incl_main_tag_err_counts, Transcript::proof_data); @@ -2800,6 +3181,14 @@ class AvmFlavor { serialize_to_buffer(lookup_u16_12_counts, Transcript::proof_data); serialize_to_buffer(lookup_u16_13_counts, Transcript::proof_data); serialize_to_buffer(lookup_u16_14_counts, Transcript::proof_data); + serialize_to_buffer(lookup_div_u16_0_counts, Transcript::proof_data); + serialize_to_buffer(lookup_div_u16_1_counts, Transcript::proof_data); + serialize_to_buffer(lookup_div_u16_2_counts, Transcript::proof_data); + serialize_to_buffer(lookup_div_u16_3_counts, Transcript::proof_data); + serialize_to_buffer(lookup_div_u16_4_counts, Transcript::proof_data); + serialize_to_buffer(lookup_div_u16_5_counts, Transcript::proof_data); + serialize_to_buffer(lookup_div_u16_6_counts, Transcript::proof_data); + serialize_to_buffer(lookup_div_u16_7_counts, Transcript::proof_data); for (size_t i = 0; i < log_n; ++i) { serialize_to_buffer(sumcheck_univariates[i], Transcript::proof_data); diff --git a/barretenberg/cpp/src/barretenberg/vm/generated/avm_prover.cpp b/barretenberg/cpp/src/barretenberg/vm/generated/avm_prover.cpp index 064a1e7e3ac..feb378a1326 100644 --- a/barretenberg/cpp/src/barretenberg/vm/generated/avm_prover.cpp +++ b/barretenberg/cpp/src/barretenberg/vm/generated/avm_prover.cpp @@ -69,6 +69,17 @@ void AvmProver::execute_wire_commitments_round() witness_commitments.avm_alu_clk = commitment_key->commit(key->avm_alu_clk); witness_commitments.avm_alu_cmp_rng_ctr = commitment_key->commit(key->avm_alu_cmp_rng_ctr); witness_commitments.avm_alu_cmp_sel = commitment_key->commit(key->avm_alu_cmp_sel); + witness_commitments.avm_alu_div_rng_chk_selector = commitment_key->commit(key->avm_alu_div_rng_chk_selector); + witness_commitments.avm_alu_div_u16_r0 = commitment_key->commit(key->avm_alu_div_u16_r0); + witness_commitments.avm_alu_div_u16_r1 = commitment_key->commit(key->avm_alu_div_u16_r1); + witness_commitments.avm_alu_div_u16_r2 = commitment_key->commit(key->avm_alu_div_u16_r2); + witness_commitments.avm_alu_div_u16_r3 = commitment_key->commit(key->avm_alu_div_u16_r3); + witness_commitments.avm_alu_div_u16_r4 = commitment_key->commit(key->avm_alu_div_u16_r4); + witness_commitments.avm_alu_div_u16_r5 = commitment_key->commit(key->avm_alu_div_u16_r5); + witness_commitments.avm_alu_div_u16_r6 = commitment_key->commit(key->avm_alu_div_u16_r6); + witness_commitments.avm_alu_div_u16_r7 = commitment_key->commit(key->avm_alu_div_u16_r7); + witness_commitments.avm_alu_divisor_hi = commitment_key->commit(key->avm_alu_divisor_hi); + witness_commitments.avm_alu_divisor_lo = commitment_key->commit(key->avm_alu_divisor_lo); witness_commitments.avm_alu_ff_tag = commitment_key->commit(key->avm_alu_ff_tag); witness_commitments.avm_alu_ia = commitment_key->commit(key->avm_alu_ia); witness_commitments.avm_alu_ib = commitment_key->commit(key->avm_alu_ib); @@ -78,6 +89,8 @@ void AvmProver::execute_wire_commitments_round() witness_commitments.avm_alu_op_cast = commitment_key->commit(key->avm_alu_op_cast); witness_commitments.avm_alu_op_cast_prev = commitment_key->commit(key->avm_alu_op_cast_prev); witness_commitments.avm_alu_op_div = commitment_key->commit(key->avm_alu_op_div); + witness_commitments.avm_alu_op_div_a_lt_b = commitment_key->commit(key->avm_alu_op_div_a_lt_b); + witness_commitments.avm_alu_op_div_std = commitment_key->commit(key->avm_alu_op_div_std); witness_commitments.avm_alu_op_eq = commitment_key->commit(key->avm_alu_op_eq); witness_commitments.avm_alu_op_eq_diff_inv = commitment_key->commit(key->avm_alu_op_eq_diff_inv); witness_commitments.avm_alu_op_lt = commitment_key->commit(key->avm_alu_op_lt); @@ -93,6 +106,11 @@ void AvmProver::execute_wire_commitments_round() witness_commitments.avm_alu_p_sub_a_lo = commitment_key->commit(key->avm_alu_p_sub_a_lo); witness_commitments.avm_alu_p_sub_b_hi = commitment_key->commit(key->avm_alu_p_sub_b_hi); witness_commitments.avm_alu_p_sub_b_lo = commitment_key->commit(key->avm_alu_p_sub_b_lo); + witness_commitments.avm_alu_partial_prod_hi = commitment_key->commit(key->avm_alu_partial_prod_hi); + witness_commitments.avm_alu_partial_prod_lo = commitment_key->commit(key->avm_alu_partial_prod_lo); + witness_commitments.avm_alu_quotient_hi = commitment_key->commit(key->avm_alu_quotient_hi); + witness_commitments.avm_alu_quotient_lo = commitment_key->commit(key->avm_alu_quotient_lo); + witness_commitments.avm_alu_remainder = commitment_key->commit(key->avm_alu_remainder); witness_commitments.avm_alu_res_hi = commitment_key->commit(key->avm_alu_res_hi); witness_commitments.avm_alu_res_lo = commitment_key->commit(key->avm_alu_res_lo); witness_commitments.avm_alu_rng_chk_lookup_selector = commitment_key->commit(key->avm_alu_rng_chk_lookup_selector); @@ -261,6 +279,14 @@ void AvmProver::execute_wire_commitments_round() witness_commitments.lookup_u16_12_counts = commitment_key->commit(key->lookup_u16_12_counts); witness_commitments.lookup_u16_13_counts = commitment_key->commit(key->lookup_u16_13_counts); witness_commitments.lookup_u16_14_counts = commitment_key->commit(key->lookup_u16_14_counts); + witness_commitments.lookup_div_u16_0_counts = commitment_key->commit(key->lookup_div_u16_0_counts); + witness_commitments.lookup_div_u16_1_counts = commitment_key->commit(key->lookup_div_u16_1_counts); + witness_commitments.lookup_div_u16_2_counts = commitment_key->commit(key->lookup_div_u16_2_counts); + witness_commitments.lookup_div_u16_3_counts = commitment_key->commit(key->lookup_div_u16_3_counts); + witness_commitments.lookup_div_u16_4_counts = commitment_key->commit(key->lookup_div_u16_4_counts); + witness_commitments.lookup_div_u16_5_counts = commitment_key->commit(key->lookup_div_u16_5_counts); + witness_commitments.lookup_div_u16_6_counts = commitment_key->commit(key->lookup_div_u16_6_counts); + witness_commitments.lookup_div_u16_7_counts = commitment_key->commit(key->lookup_div_u16_7_counts); // Send all commitments to the verifier transcript->send_to_verifier(commitment_labels.avm_alu_a_hi, witness_commitments.avm_alu_a_hi); @@ -273,6 +299,18 @@ void AvmProver::execute_wire_commitments_round() transcript->send_to_verifier(commitment_labels.avm_alu_clk, witness_commitments.avm_alu_clk); transcript->send_to_verifier(commitment_labels.avm_alu_cmp_rng_ctr, witness_commitments.avm_alu_cmp_rng_ctr); transcript->send_to_verifier(commitment_labels.avm_alu_cmp_sel, witness_commitments.avm_alu_cmp_sel); + transcript->send_to_verifier(commitment_labels.avm_alu_div_rng_chk_selector, + witness_commitments.avm_alu_div_rng_chk_selector); + transcript->send_to_verifier(commitment_labels.avm_alu_div_u16_r0, witness_commitments.avm_alu_div_u16_r0); + transcript->send_to_verifier(commitment_labels.avm_alu_div_u16_r1, witness_commitments.avm_alu_div_u16_r1); + transcript->send_to_verifier(commitment_labels.avm_alu_div_u16_r2, witness_commitments.avm_alu_div_u16_r2); + transcript->send_to_verifier(commitment_labels.avm_alu_div_u16_r3, witness_commitments.avm_alu_div_u16_r3); + transcript->send_to_verifier(commitment_labels.avm_alu_div_u16_r4, witness_commitments.avm_alu_div_u16_r4); + transcript->send_to_verifier(commitment_labels.avm_alu_div_u16_r5, witness_commitments.avm_alu_div_u16_r5); + transcript->send_to_verifier(commitment_labels.avm_alu_div_u16_r6, witness_commitments.avm_alu_div_u16_r6); + transcript->send_to_verifier(commitment_labels.avm_alu_div_u16_r7, witness_commitments.avm_alu_div_u16_r7); + transcript->send_to_verifier(commitment_labels.avm_alu_divisor_hi, witness_commitments.avm_alu_divisor_hi); + transcript->send_to_verifier(commitment_labels.avm_alu_divisor_lo, witness_commitments.avm_alu_divisor_lo); transcript->send_to_verifier(commitment_labels.avm_alu_ff_tag, witness_commitments.avm_alu_ff_tag); transcript->send_to_verifier(commitment_labels.avm_alu_ia, witness_commitments.avm_alu_ia); transcript->send_to_verifier(commitment_labels.avm_alu_ib, witness_commitments.avm_alu_ib); @@ -282,6 +320,8 @@ void AvmProver::execute_wire_commitments_round() transcript->send_to_verifier(commitment_labels.avm_alu_op_cast, witness_commitments.avm_alu_op_cast); transcript->send_to_verifier(commitment_labels.avm_alu_op_cast_prev, witness_commitments.avm_alu_op_cast_prev); transcript->send_to_verifier(commitment_labels.avm_alu_op_div, witness_commitments.avm_alu_op_div); + transcript->send_to_verifier(commitment_labels.avm_alu_op_div_a_lt_b, witness_commitments.avm_alu_op_div_a_lt_b); + transcript->send_to_verifier(commitment_labels.avm_alu_op_div_std, witness_commitments.avm_alu_op_div_std); transcript->send_to_verifier(commitment_labels.avm_alu_op_eq, witness_commitments.avm_alu_op_eq); transcript->send_to_verifier(commitment_labels.avm_alu_op_eq_diff_inv, witness_commitments.avm_alu_op_eq_diff_inv); transcript->send_to_verifier(commitment_labels.avm_alu_op_lt, witness_commitments.avm_alu_op_lt); @@ -297,6 +337,13 @@ void AvmProver::execute_wire_commitments_round() transcript->send_to_verifier(commitment_labels.avm_alu_p_sub_a_lo, witness_commitments.avm_alu_p_sub_a_lo); transcript->send_to_verifier(commitment_labels.avm_alu_p_sub_b_hi, witness_commitments.avm_alu_p_sub_b_hi); transcript->send_to_verifier(commitment_labels.avm_alu_p_sub_b_lo, witness_commitments.avm_alu_p_sub_b_lo); + transcript->send_to_verifier(commitment_labels.avm_alu_partial_prod_hi, + witness_commitments.avm_alu_partial_prod_hi); + transcript->send_to_verifier(commitment_labels.avm_alu_partial_prod_lo, + witness_commitments.avm_alu_partial_prod_lo); + transcript->send_to_verifier(commitment_labels.avm_alu_quotient_hi, witness_commitments.avm_alu_quotient_hi); + transcript->send_to_verifier(commitment_labels.avm_alu_quotient_lo, witness_commitments.avm_alu_quotient_lo); + transcript->send_to_verifier(commitment_labels.avm_alu_remainder, witness_commitments.avm_alu_remainder); transcript->send_to_verifier(commitment_labels.avm_alu_res_hi, witness_commitments.avm_alu_res_hi); transcript->send_to_verifier(commitment_labels.avm_alu_res_lo, witness_commitments.avm_alu_res_lo); transcript->send_to_verifier(commitment_labels.avm_alu_rng_chk_lookup_selector, @@ -484,6 +531,22 @@ void AvmProver::execute_wire_commitments_round() transcript->send_to_verifier(commitment_labels.lookup_u16_12_counts, witness_commitments.lookup_u16_12_counts); transcript->send_to_verifier(commitment_labels.lookup_u16_13_counts, witness_commitments.lookup_u16_13_counts); transcript->send_to_verifier(commitment_labels.lookup_u16_14_counts, witness_commitments.lookup_u16_14_counts); + transcript->send_to_verifier(commitment_labels.lookup_div_u16_0_counts, + witness_commitments.lookup_div_u16_0_counts); + transcript->send_to_verifier(commitment_labels.lookup_div_u16_1_counts, + witness_commitments.lookup_div_u16_1_counts); + transcript->send_to_verifier(commitment_labels.lookup_div_u16_2_counts, + witness_commitments.lookup_div_u16_2_counts); + transcript->send_to_verifier(commitment_labels.lookup_div_u16_3_counts, + witness_commitments.lookup_div_u16_3_counts); + transcript->send_to_verifier(commitment_labels.lookup_div_u16_4_counts, + witness_commitments.lookup_div_u16_4_counts); + transcript->send_to_verifier(commitment_labels.lookup_div_u16_5_counts, + witness_commitments.lookup_div_u16_5_counts); + transcript->send_to_verifier(commitment_labels.lookup_div_u16_6_counts, + witness_commitments.lookup_div_u16_6_counts); + transcript->send_to_verifier(commitment_labels.lookup_div_u16_7_counts, + witness_commitments.lookup_div_u16_7_counts); } void AvmProver::execute_log_derivative_inverse_round() @@ -531,6 +594,14 @@ void AvmProver::execute_log_derivative_inverse_round() witness_commitments.lookup_u16_12 = commitment_key->commit(key->lookup_u16_12); witness_commitments.lookup_u16_13 = commitment_key->commit(key->lookup_u16_13); witness_commitments.lookup_u16_14 = commitment_key->commit(key->lookup_u16_14); + witness_commitments.lookup_div_u16_0 = commitment_key->commit(key->lookup_div_u16_0); + witness_commitments.lookup_div_u16_1 = commitment_key->commit(key->lookup_div_u16_1); + witness_commitments.lookup_div_u16_2 = commitment_key->commit(key->lookup_div_u16_2); + witness_commitments.lookup_div_u16_3 = commitment_key->commit(key->lookup_div_u16_3); + witness_commitments.lookup_div_u16_4 = commitment_key->commit(key->lookup_div_u16_4); + witness_commitments.lookup_div_u16_5 = commitment_key->commit(key->lookup_div_u16_5); + witness_commitments.lookup_div_u16_6 = commitment_key->commit(key->lookup_div_u16_6); + witness_commitments.lookup_div_u16_7 = commitment_key->commit(key->lookup_div_u16_7); // Send all commitments to the verifier transcript->send_to_verifier(commitment_labels.perm_main_alu, witness_commitments.perm_main_alu); @@ -568,6 +639,14 @@ void AvmProver::execute_log_derivative_inverse_round() transcript->send_to_verifier(commitment_labels.lookup_u16_12, witness_commitments.lookup_u16_12); transcript->send_to_verifier(commitment_labels.lookup_u16_13, witness_commitments.lookup_u16_13); transcript->send_to_verifier(commitment_labels.lookup_u16_14, witness_commitments.lookup_u16_14); + transcript->send_to_verifier(commitment_labels.lookup_div_u16_0, witness_commitments.lookup_div_u16_0); + transcript->send_to_verifier(commitment_labels.lookup_div_u16_1, witness_commitments.lookup_div_u16_1); + transcript->send_to_verifier(commitment_labels.lookup_div_u16_2, witness_commitments.lookup_div_u16_2); + transcript->send_to_verifier(commitment_labels.lookup_div_u16_3, witness_commitments.lookup_div_u16_3); + transcript->send_to_verifier(commitment_labels.lookup_div_u16_4, witness_commitments.lookup_div_u16_4); + transcript->send_to_verifier(commitment_labels.lookup_div_u16_5, witness_commitments.lookup_div_u16_5); + transcript->send_to_verifier(commitment_labels.lookup_div_u16_6, witness_commitments.lookup_div_u16_6); + transcript->send_to_verifier(commitment_labels.lookup_div_u16_7, witness_commitments.lookup_div_u16_7); } /** diff --git a/barretenberg/cpp/src/barretenberg/vm/generated/avm_verifier.cpp b/barretenberg/cpp/src/barretenberg/vm/generated/avm_verifier.cpp index 89f357cc400..ecce0af1b4d 100644 --- a/barretenberg/cpp/src/barretenberg/vm/generated/avm_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/vm/generated/avm_verifier.cpp @@ -64,6 +64,28 @@ bool AvmVerifier::verify_proof(const HonkProof& proof) transcript->template receive_from_prover(commitment_labels.avm_alu_cmp_rng_ctr); commitments.avm_alu_cmp_sel = transcript->template receive_from_prover(commitment_labels.avm_alu_cmp_sel); + commitments.avm_alu_div_rng_chk_selector = + transcript->template receive_from_prover(commitment_labels.avm_alu_div_rng_chk_selector); + commitments.avm_alu_div_u16_r0 = + transcript->template receive_from_prover(commitment_labels.avm_alu_div_u16_r0); + commitments.avm_alu_div_u16_r1 = + transcript->template receive_from_prover(commitment_labels.avm_alu_div_u16_r1); + commitments.avm_alu_div_u16_r2 = + transcript->template receive_from_prover(commitment_labels.avm_alu_div_u16_r2); + commitments.avm_alu_div_u16_r3 = + transcript->template receive_from_prover(commitment_labels.avm_alu_div_u16_r3); + commitments.avm_alu_div_u16_r4 = + transcript->template receive_from_prover(commitment_labels.avm_alu_div_u16_r4); + commitments.avm_alu_div_u16_r5 = + transcript->template receive_from_prover(commitment_labels.avm_alu_div_u16_r5); + commitments.avm_alu_div_u16_r6 = + transcript->template receive_from_prover(commitment_labels.avm_alu_div_u16_r6); + commitments.avm_alu_div_u16_r7 = + transcript->template receive_from_prover(commitment_labels.avm_alu_div_u16_r7); + commitments.avm_alu_divisor_hi = + transcript->template receive_from_prover(commitment_labels.avm_alu_divisor_hi); + commitments.avm_alu_divisor_lo = + transcript->template receive_from_prover(commitment_labels.avm_alu_divisor_lo); commitments.avm_alu_ff_tag = transcript->template receive_from_prover(commitment_labels.avm_alu_ff_tag); commitments.avm_alu_ia = transcript->template receive_from_prover(commitment_labels.avm_alu_ia); commitments.avm_alu_ib = transcript->template receive_from_prover(commitment_labels.avm_alu_ib); @@ -75,6 +97,10 @@ bool AvmVerifier::verify_proof(const HonkProof& proof) commitments.avm_alu_op_cast_prev = transcript->template receive_from_prover(commitment_labels.avm_alu_op_cast_prev); commitments.avm_alu_op_div = transcript->template receive_from_prover(commitment_labels.avm_alu_op_div); + commitments.avm_alu_op_div_a_lt_b = + transcript->template receive_from_prover(commitment_labels.avm_alu_op_div_a_lt_b); + commitments.avm_alu_op_div_std = + transcript->template receive_from_prover(commitment_labels.avm_alu_op_div_std); commitments.avm_alu_op_eq = transcript->template receive_from_prover(commitment_labels.avm_alu_op_eq); commitments.avm_alu_op_eq_diff_inv = transcript->template receive_from_prover(commitment_labels.avm_alu_op_eq_diff_inv); @@ -97,6 +123,16 @@ bool AvmVerifier::verify_proof(const HonkProof& proof) transcript->template receive_from_prover(commitment_labels.avm_alu_p_sub_b_hi); commitments.avm_alu_p_sub_b_lo = transcript->template receive_from_prover(commitment_labels.avm_alu_p_sub_b_lo); + commitments.avm_alu_partial_prod_hi = + transcript->template receive_from_prover(commitment_labels.avm_alu_partial_prod_hi); + commitments.avm_alu_partial_prod_lo = + transcript->template receive_from_prover(commitment_labels.avm_alu_partial_prod_lo); + commitments.avm_alu_quotient_hi = + transcript->template receive_from_prover(commitment_labels.avm_alu_quotient_hi); + commitments.avm_alu_quotient_lo = + transcript->template receive_from_prover(commitment_labels.avm_alu_quotient_lo); + commitments.avm_alu_remainder = + transcript->template receive_from_prover(commitment_labels.avm_alu_remainder); commitments.avm_alu_res_hi = transcript->template receive_from_prover(commitment_labels.avm_alu_res_hi); commitments.avm_alu_res_lo = transcript->template receive_from_prover(commitment_labels.avm_alu_res_lo); commitments.avm_alu_rng_chk_lookup_selector = @@ -389,6 +425,22 @@ bool AvmVerifier::verify_proof(const HonkProof& proof) transcript->template receive_from_prover(commitment_labels.lookup_u16_13_counts); commitments.lookup_u16_14_counts = transcript->template receive_from_prover(commitment_labels.lookup_u16_14_counts); + commitments.lookup_div_u16_0_counts = + transcript->template receive_from_prover(commitment_labels.lookup_div_u16_0_counts); + commitments.lookup_div_u16_1_counts = + transcript->template receive_from_prover(commitment_labels.lookup_div_u16_1_counts); + commitments.lookup_div_u16_2_counts = + transcript->template receive_from_prover(commitment_labels.lookup_div_u16_2_counts); + commitments.lookup_div_u16_3_counts = + transcript->template receive_from_prover(commitment_labels.lookup_div_u16_3_counts); + commitments.lookup_div_u16_4_counts = + transcript->template receive_from_prover(commitment_labels.lookup_div_u16_4_counts); + commitments.lookup_div_u16_5_counts = + transcript->template receive_from_prover(commitment_labels.lookup_div_u16_5_counts); + commitments.lookup_div_u16_6_counts = + transcript->template receive_from_prover(commitment_labels.lookup_div_u16_6_counts); + commitments.lookup_div_u16_7_counts = + transcript->template receive_from_prover(commitment_labels.lookup_div_u16_7_counts); auto [beta, gamm] = transcript->template get_challenges("beta", "gamma"); relation_parameters.beta = beta; @@ -444,6 +496,22 @@ bool AvmVerifier::verify_proof(const HonkProof& proof) commitments.lookup_u16_12 = transcript->template receive_from_prover(commitment_labels.lookup_u16_12); commitments.lookup_u16_13 = transcript->template receive_from_prover(commitment_labels.lookup_u16_13); commitments.lookup_u16_14 = transcript->template receive_from_prover(commitment_labels.lookup_u16_14); + commitments.lookup_div_u16_0 = + transcript->template receive_from_prover(commitment_labels.lookup_div_u16_0); + commitments.lookup_div_u16_1 = + transcript->template receive_from_prover(commitment_labels.lookup_div_u16_1); + commitments.lookup_div_u16_2 = + transcript->template receive_from_prover(commitment_labels.lookup_div_u16_2); + commitments.lookup_div_u16_3 = + transcript->template receive_from_prover(commitment_labels.lookup_div_u16_3); + commitments.lookup_div_u16_4 = + transcript->template receive_from_prover(commitment_labels.lookup_div_u16_4); + commitments.lookup_div_u16_5 = + transcript->template receive_from_prover(commitment_labels.lookup_div_u16_5); + commitments.lookup_div_u16_6 = + transcript->template receive_from_prover(commitment_labels.lookup_div_u16_6); + commitments.lookup_div_u16_7 = + transcript->template receive_from_prover(commitment_labels.lookup_div_u16_7); // Execute Sumcheck Verifier const size_t log_circuit_size = numeric::get_msb(circuit_size); diff --git a/barretenberg/cpp/src/barretenberg/vm/tests/avm_arithmetic.test.cpp b/barretenberg/cpp/src/barretenberg/vm/tests/avm_arithmetic.test.cpp index 30601dd613e..c0754b31d4c 100644 --- a/barretenberg/cpp/src/barretenberg/vm/tests/avm_arithmetic.test.cpp +++ b/barretenberg/cpp/src/barretenberg/vm/tests/avm_arithmetic.test.cpp @@ -1,6 +1,7 @@ #include "avm_common.test.hpp" #include "barretenberg/numeric/uint128/uint128.hpp" #include "barretenberg/vm/avm_trace/avm_common.hpp" +#include "barretenberg/vm/tests/helpers.test.hpp" #include namespace tests_avm { @@ -167,6 +168,35 @@ size_t common_validate_eq(std::vector const& trace, return static_cast(alu_row - trace.begin()); } +size_t common_validate_div(std::vector const& trace, + FF const& a, + FF const& b, + FF const& c, + FF const& addr_a, + FF const& addr_b, + FF const& addr_c, + avm_trace::AvmMemoryTag const tag) +{ + // Find the first row enabling the division selector + auto row = std::ranges::find_if(trace.begin(), trace.end(), [](Row r) { return r.avm_main_sel_op_div == FF(1); }); + + // Find the corresponding Alu trace row + auto clk = row->avm_main_clk; + auto alu_row = std::ranges::find_if(trace.begin(), trace.end(), [clk](Row r) { return r.avm_alu_clk == clk; }); + + // Check that both rows were found + EXPECT_TRUE(row != trace.end()); + EXPECT_TRUE(alu_row != trace.end()); + + common_validate_arithmetic_op(*row, *alu_row, a, b, c, addr_a, addr_b, addr_c, tag); + EXPECT_EQ(row->avm_main_w_in_tag, FF(static_cast(tag))); + + // Check that division selector is set. + EXPECT_EQ(alu_row->avm_alu_op_div, FF(1)); + + return static_cast(alu_row - trace.begin()); +} + // Generate a trace with an EQ opcode operation. std::vector gen_trace_eq(uint128_t const& a, uint128_t const& b, @@ -282,6 +312,7 @@ class AvmArithmeticTestsU16 : public AvmArithmeticTests {}; class AvmArithmeticTestsU32 : public AvmArithmeticTests {}; class AvmArithmeticTestsU64 : public AvmArithmeticTests {}; class AvmArithmeticTestsU128 : public AvmArithmeticTests {}; +class AvmArithmeticTestsDiv : public AvmArithmeticTests, public testing::WithParamInterface {}; class AvmArithmeticNegativeTestsFF : public AvmArithmeticTests {}; class AvmArithmeticNegativeTestsU8 : public AvmArithmeticTests {}; @@ -290,6 +321,18 @@ class AvmArithmeticNegativeTestsU32 : public AvmArithmeticTests {}; class AvmArithmeticNegativeTestsU64 : public AvmArithmeticTests {}; class AvmArithmeticNegativeTestsU128 : public AvmArithmeticTests {}; +std::vector uint_mem_tags{ + { AvmMemoryTag::U8, AvmMemoryTag::U16, AvmMemoryTag::U32, AvmMemoryTag::U64, AvmMemoryTag::U128 } +}; +std::vector> positive_op_div_test_values = { { + { FF(10), FF(5), FF(2) }, + { FF(5323), FF(5323), FF(1) }, + { FF(13793), FF(10590617LLU), FF(0) }, + { FF(0x7bff744e3cdf79LLU), FF(0x14ccccccccb6LLU), FF(1526) }, + { uint256_t::from_uint128((uint128_t{ 0x1006021301080000 } << 64) + uint128_t{ 0x000000000000001080876844827 }), + uint256_t::from_uint128(uint128_t{ 0xb900000000000001 }), + uint256_t::from_uint128(uint128_t{ 0x162c4ad3b97863a1 }) }, +} }; /****************************************************************************** * * POSITIVE TESTS @@ -334,7 +377,7 @@ TEST_F(AvmArithmeticTestsFF, addition) EXPECT_EQ(alu_row.avm_alu_cf, FF(0)); EXPECT_EQ(alu_row.avm_alu_u8_r0, FF(0)); - validate_trace(std::move(trace)); + validate_trace(std::move(trace), true); } // Test on basic subtraction over finite field type. @@ -549,6 +592,51 @@ TEST_F(AvmArithmeticTestsFF, nonEquality) validate_trace(std::move(trace)); } +TEST_P(AvmArithmeticTestsDiv, division) +{ + const auto [operands, mem_tag] = GetParam(); + const auto [a, b, output] = operands; + auto trace_builder = avm_trace::AvmTraceBuilder(); + trace_builder.op_set(0, uint128_t(a), 0, mem_tag); + trace_builder.op_set(0, uint128_t(b), 1, mem_tag); + trace_builder.op_div(0, 0, 1, 2, mem_tag); + trace_builder.return_op(0, 0, 0); + auto trace = trace_builder.finalize(); + + common_validate_div(trace, a, b, output, 0, 1, 2, mem_tag); + // auto alu_row = trace.at(alu_row_index); + + validate_trace(std::move(trace)); +} +INSTANTIATE_TEST_SUITE_P(AvmArithmeticTestsDiv, + AvmArithmeticTestsDiv, + testing::ValuesIn(gen_three_op_params(positive_op_div_test_values, uint_mem_tags))); + +// Test on division by zero over U128. +// We check that the operator error flag is raised. +TEST_F(AvmArithmeticTests, DivisionByZeroError) +{ + auto trace_builder = avm_trace::AvmTraceBuilder(); + trace_builder.op_set(0, 100, 0, AvmMemoryTag::U128); + trace_builder.op_set(0, 0, 1, AvmMemoryTag::U128); + trace_builder.op_div(0, 0, 1, 2, AvmMemoryTag::U128); + trace_builder.halt(); + auto trace = trace_builder.finalize(); + + // Find the first row enabling the div selector + auto row = std::ranges::find_if(trace.begin(), trace.end(), [](Row r) { return r.avm_main_sel_op_div == FF(1); }); + + // Check that the correct result is stored at the expected memory location. + EXPECT_TRUE(row != trace.end()); + EXPECT_EQ(row->avm_main_ic, FF(0)); + EXPECT_EQ(row->avm_main_mem_idx_c, FF(2)); + EXPECT_EQ(row->avm_main_mem_op_c, FF(1)); + EXPECT_EQ(row->avm_main_rwc, FF(1)); + EXPECT_EQ(row->avm_main_op_err, FF(1)); + + validate_trace(std::move(trace)); +} + /****************************************************************************** * Positive Tests - U8 ******************************************************************************/ diff --git a/barretenberg/cpp/src/barretenberg/vm/tests/avm_bitwise.test.cpp b/barretenberg/cpp/src/barretenberg/vm/tests/avm_bitwise.test.cpp index 256501f41ea..bbe1ef3e5b0 100644 --- a/barretenberg/cpp/src/barretenberg/vm/tests/avm_bitwise.test.cpp +++ b/barretenberg/cpp/src/barretenberg/vm/tests/avm_bitwise.test.cpp @@ -372,7 +372,6 @@ class AvmBitwiseTests : public ::testing::Test { * ******************************************************************************/ -using ThreeOpParamRow = std::tuple, AvmMemoryTag>; using TwoOpParamRow = std::tuple, AvmMemoryTag>; std::vector mem_tags{ { AvmMemoryTag::U8, AvmMemoryTag::U16, AvmMemoryTag::U32, AvmMemoryTag::U64, AvmMemoryTag::U128 } @@ -397,59 +396,51 @@ std::vector gen_two_op_params(std::vector> positive_op_and_test_values = { - { { 1, 1, 1 }, - { 5323, 321, 65 }, - { 13793, 10590617LLU, 4481 }, - { 0x7bff744e3cdf79LLU, 0x14ccccccccb6LLU, 0x14444c0ccc30LLU }, - { (uint128_t{ 0xb900000000000001 } << 64), - (uint128_t{ 0x1006021301080000 } << 64) + uint128_t{ 0x000000000000001080876844827 }, - (uint128_t{ 0x1000000000000000 } << 64) } } +std::vector positive_op_and_test_values = { + { { FF(1), FF(1), FF(1) }, + { FF(5323), FF(321), FF(65) }, + { FF(13793), FF(10590617LLU), FF(4481) }, + { FF(0x7bff744e3cdf79LLU), FF(0x14ccccccccb6LLU), FF(0x14444c0ccc30LLU) }, + { uint256_t::from_uint128(uint128_t{ 0xb900000000000001 } << 64), + uint256_t::from_uint128((uint128_t{ 0x1006021301080000 } << 64) + uint128_t{ 0x000000000000001080876844827 }), + uint256_t::from_uint128(uint128_t{ 0x1000000000000000 } << 64) } } }; -std::vector> positive_op_or_test_values = { - { { 1, 1, 1 }, - { 5323, 321, 0x15cb }, - { 13793, 10590617LLU, 0xa1bdf9 }, - { 0x7bff744e3cdf79LLU, 0x14ccccccccb6LLU, 0x7bfffccefcdfffLLU }, - { (uint128_t{ 0xb900000000000000 } << 64), - (uint128_t{ 0x1006021301080000 } << 64) + uint128_t{ 0x000000000000001080876844827 }, - (uint128_t{ 0xb906021301080000 } << 64) + uint128_t{ 0x0001080876844827 } } } +std::vector> positive_op_or_test_values = { + { { FF(1), FF(1), FF(1) }, + { FF(5323), FF(321), FF(0x15cb) }, + { FF(13793), FF(10590617LLU), FF(0xa1bdf9) }, + { FF(0x7bff744e3cdf79LLU), FF(0x14ccccccccb6LLU), FF(0x7bfffccefcdfffLLU) }, + { uint256_t::from_uint128(uint128_t{ 0xb900000000000000 } << 64), + uint256_t::from_uint128(uint128_t{ 0x1006021301080000 } << 64) + uint128_t{ 0x000000000000001080876844827 }, + uint256_t::from_uint128(uint128_t{ 0xb906021301080000 } << 64) + uint128_t{ 0x0001080876844827 } } } }; -std::vector> positive_op_xor_test_values = { - { { 1, 1, 0 }, - { 5323, 321, 0x158a }, - { 13793, 10590617LLU, 0xa1ac78 }, - { 0x7bff744e3cdf79LLU, 0x14ccccccccb6LLU, 0x7bebb882f013cf }, - { (uint128_t{ 0xb900000000000001 } << 64), - (uint128_t{ 0x1006021301080000 } << 64) + uint128_t{ 0x000000000000001080876844827 }, - (uint128_t{ 0xa906021301080001 } << 64) + uint128_t{ 0x0001080876844827 } } } +std::vector> positive_op_xor_test_values = { + { { FF(1), FF(1), FF(0) }, + { FF(5323), FF(321), FF(0x158a) }, + { FF(13793), FF(10590617LLU), FF(0xa1ac78) }, + { FF(0x7bff744e3cdf79LLU), FF(0x14ccccccccb6LLU), uint256_t::from_uint128(0x7bebb882f013cf) }, + { uint256_t::from_uint128(uint128_t{ 0xb900000000000001 } << 64), + uint256_t::from_uint128((uint128_t{ 0x1006021301080000 } << 64) + uint128_t{ 0x000000000000001080876844827 }), + uint256_t::from_uint128((uint128_t{ 0xa906021301080001 } << 64) + uint128_t{ 0x0001080876844827 }) } } }; -std::vector> positive_op_shr_test_values = { - { { 20, 3, 2 }, - { 5323, 255, 0 }, - { 36148, 13, 4 }, - { 0x7bff744e3cdf79LLU, 64, 0 }, - { (uint128_t{ 0x1006021301080000 } << 64) + uint128_t{ 0x000000000000001080876844827 }, 123, 2 } } +std::vector> positive_op_shr_test_values = { + { { FF(20), FF(3), FF(2) }, + { FF(5323), FF(255), FF(0) }, + { FF(36148), FF(13), FF(4) }, + { FF(0x7bff744e3cdf79LLU), FF(64), FF(0) }, + { uint256_t::from_uint128((uint128_t{ 0x1006021301080000 } << 64) + uint128_t{ 0x000000000000001080876844827 }), + FF(123), + FF(2) } } }; -std::vector> positive_op_shl_test_values = { - { { 20, 8, 0 }, - { 5323, 10, 11264 }, - { 13793, 255, 0 }, - { 239, 50, 269090077735387136 }, - { 9, 127, (uint128_t{ 0x4800000000000000LLU } << 68) } } +std::vector> positive_op_shl_test_values = { + { { FF(20), FF(8), FF(0) }, + { FF(5323), FF(10), FF(11264) }, + { FF(13793), FF(255), FF(0) }, + { FF(239), FF(50), uint256_t::from_uint128(269090077735387136) }, + { FF(9), FF(127), uint256_t::from_uint128(uint128_t{ 0x4800000000000000LLU } << 68) } } }; -std::vector gen_three_op_params(std::vector> operands, - std::vector mem_tags) -{ - std::vector params; - for (size_t i = 0; i < 5; i++) { - params.emplace_back(operands[i], mem_tags[i]); - } - return params; -} - class AvmBitwiseTestsNot : public AvmBitwiseTests, public testing::WithParamInterface {}; class AvmBitwiseTestsAnd : public AvmBitwiseTests, public testing::WithParamInterface {}; class AvmBitwiseTestsOr : public AvmBitwiseTests, public testing::WithParamInterface {}; @@ -490,16 +481,13 @@ TEST_P(AvmBitwiseTestsAnd, AllAndTest) { const auto [operands, mem_tag] = GetParam(); const auto [a, b, output] = operands; - trace_builder.op_set(0, a, 0, mem_tag); - trace_builder.op_set(0, b, 1, mem_tag); + trace_builder.op_set(0, uint128_t(a), 0, mem_tag); + trace_builder.op_set(0, uint128_t(b), 1, mem_tag); trace_builder.op_and(0, 0, 1, 2, mem_tag); trace_builder.return_op(0, 2, 1); auto trace = trace_builder.finalize(); - FF ff_a = FF(uint256_t::from_uint128(a)); - FF ff_b = FF(uint256_t::from_uint128(b)); - FF ff_output = FF(uint256_t::from_uint128(output)); - common_validate_bit_op(trace, 0, ff_a, ff_b, ff_output, FF(0), FF(1), FF(2), mem_tag); + common_validate_bit_op(trace, 0, a, b, output, FF(0), FF(1), FF(2), mem_tag); validate_trace(std::move(trace), true); } INSTANTIATE_TEST_SUITE_P(AvmBitwiseTests, @@ -510,17 +498,13 @@ TEST_P(AvmBitwiseTestsOr, AllOrTest) { const auto [operands, mem_tag] = GetParam(); const auto [a, b, output] = operands; - trace_builder.op_set(0, a, 0, mem_tag); - trace_builder.op_set(0, b, 1, mem_tag); + trace_builder.op_set(0, uint128_t(a), 0, mem_tag); + trace_builder.op_set(0, uint128_t(b), 1, mem_tag); trace_builder.op_or(0, 0, 1, 2, mem_tag); trace_builder.return_op(0, 2, 1); auto trace = trace_builder.finalize(); - FF ff_a = FF(uint256_t::from_uint128(a)); - FF ff_b = FF(uint256_t::from_uint128(b)); - FF ff_output = FF(uint256_t::from_uint128(output)); - - common_validate_bit_op(trace, 1, ff_a, ff_b, ff_output, FF(0), FF(1), FF(2), mem_tag); + common_validate_bit_op(trace, 1, a, b, output, FF(0), FF(1), FF(2), mem_tag); validate_trace(std::move(trace)); } INSTANTIATE_TEST_SUITE_P(AvmBitwiseTests, @@ -531,17 +515,13 @@ TEST_P(AvmBitwiseTestsXor, AllXorTest) { const auto [operands, mem_tag] = GetParam(); const auto [a, b, output] = operands; - trace_builder.op_set(0, a, 0, mem_tag); - trace_builder.op_set(0, b, 1, mem_tag); + trace_builder.op_set(0, uint128_t(a), 0, mem_tag); + trace_builder.op_set(0, uint128_t(b), 1, mem_tag); trace_builder.op_xor(0, 0, 1, 2, mem_tag); trace_builder.return_op(0, 2, 1); auto trace = trace_builder.finalize(); - FF ff_a = FF(uint256_t::from_uint128(a)); - FF ff_b = FF(uint256_t::from_uint128(b)); - FF ff_output = FF(uint256_t::from_uint128(output)); - - common_validate_bit_op(trace, 2, ff_a, ff_b, ff_output, FF(0), FF(1), FF(2), mem_tag); + common_validate_bit_op(trace, 2, a, b, output, FF(0), FF(1), FF(2), mem_tag); validate_trace(std::move(trace)); } @@ -553,20 +533,12 @@ TEST_P(AvmBitwiseTestsShr, AllShrTest) { const auto [operands, mem_tag] = GetParam(); const auto [a, b, output] = operands; - trace_builder.op_set(0, a, 0, mem_tag); - trace_builder.op_set(0, b, 1, mem_tag); + trace_builder.op_set(0, uint128_t(a), 0, mem_tag); + trace_builder.op_set(0, uint128_t(b), 1, mem_tag); trace_builder.op_shr(0, 0, 1, 2, mem_tag); trace_builder.return_op(0, 2, 1); auto trace = trace_builder.finalize(); - common_validate_shift_op(trace, - uint256_t::from_uint128(a), - uint256_t::from_uint128(b), - uint256_t::from_uint128(output), - FF(0), - FF(1), - FF(2), - mem_tag, - true); + common_validate_shift_op(trace, a, b, output, FF(0), FF(1), FF(2), mem_tag, true); validate_trace(std::move(trace)); } @@ -578,21 +550,13 @@ TEST_P(AvmBitwiseTestsShl, AllShlTest) { const auto [operands, mem_tag] = GetParam(); const auto [a, b, output] = operands; - trace_builder.op_set(0, a, 0, mem_tag); - trace_builder.op_set(0, b, 1, mem_tag); + trace_builder.op_set(0, uint128_t(a), 0, mem_tag); + trace_builder.op_set(0, uint128_t(b), 1, mem_tag); trace_builder.op_shl(0, 0, 1, 2, mem_tag); trace_builder.return_op(0, 2, 1); auto trace = trace_builder.finalize(); - common_validate_shift_op(trace, - uint256_t::from_uint128(a), - uint256_t::from_uint128(b), - uint256_t::from_uint128(output), - FF(0), - FF(1), - FF(2), - mem_tag, - false); + common_validate_shift_op(trace, a, b, output, FF(0), FF(1), FF(2), mem_tag, false); validate_trace(std::move(trace)); } @@ -660,9 +624,8 @@ TEST_P(AvmBitwiseNegativeTestsAnd, AllNegativeTests) trace_builder.op_and(0, 0, 1, 2, mem_tag); trace_builder.halt(); auto trace = trace_builder.finalize(); - FF ff_output = FF(uint256_t::from_uint128(output)); std::function&& select_row = [](Row r) { return r.avm_main_sel_op_and == FF(1); }; - trace = gen_mutated_trace_bit(trace, std::move(select_row), ff_output, failure_mode); + trace = gen_mutated_trace_bit(trace, std::move(select_row), output, failure_mode); EXPECT_THROW_WITH_MESSAGE(validate_trace_check_circuit(std::move(trace)), failure_string); } INSTANTIATE_TEST_SUITE_P(AvmBitwiseNegativeTests, @@ -681,9 +644,8 @@ TEST_P(AvmBitwiseNegativeTestsOr, AllNegativeTests) trace_builder.op_or(0, 0, 1, 2, mem_tag); trace_builder.halt(); auto trace = trace_builder.finalize(); - FF ff_output = FF(uint256_t::from_uint128(output)); std::function&& select_row = [](Row r) { return r.avm_main_sel_op_or == FF(1); }; - trace = gen_mutated_trace_bit(trace, std::move(select_row), ff_output, failure_mode); + trace = gen_mutated_trace_bit(trace, std::move(select_row), output, failure_mode); EXPECT_THROW_WITH_MESSAGE(validate_trace_check_circuit(std::move(trace)), failure_string); } INSTANTIATE_TEST_SUITE_P(AvmBitwiseNegativeTests, @@ -701,9 +663,8 @@ TEST_P(AvmBitwiseNegativeTestsXor, AllNegativeTests) trace_builder.op_xor(0, 0, 1, 2, mem_tag); trace_builder.halt(); auto trace = trace_builder.finalize(); - FF ff_output = FF(uint256_t::from_uint128(output)); std::function&& select_row = [](Row r) { return r.avm_main_sel_op_xor == FF(1); }; - trace = gen_mutated_trace_bit(trace, std::move(select_row), ff_output, failure_mode); + trace = gen_mutated_trace_bit(trace, std::move(select_row), output, failure_mode); EXPECT_THROW_WITH_MESSAGE(validate_trace_check_circuit(std::move(trace)), failure_string) } INSTANTIATE_TEST_SUITE_P(AvmBitwiseNegativeTests, @@ -723,8 +684,7 @@ TEST_P(AvmBitwiseNegativeTestsShr, AllNegativeTests) auto trace = trace_builder.finalize(); std::function&& select_row = [](Row r) { return r.avm_main_sel_op_shr == FF(1); }; - auto [mutated_trace, str] = gen_mutated_trace_shift( - std::move(trace), std::move(select_row), FF(uint256_t::from_uint128(output)), failure, true); + auto [mutated_trace, str] = gen_mutated_trace_shift(std::move(trace), std::move(select_row), output, failure, true); EXPECT_THROW_WITH_MESSAGE(validate_trace_check_circuit(std::move(mutated_trace)), str); } INSTANTIATE_TEST_SUITE_P(AvmBitwiseNegativeTests, @@ -744,8 +704,8 @@ TEST_P(AvmBitwiseNegativeTestsShl, AllNegativeTests) auto trace = trace_builder.finalize(); std::function&& select_row = [](Row r) { return r.avm_main_sel_op_shl == FF(1); }; - auto [mutated_trace, str] = gen_mutated_trace_shift( - std::move(trace), std::move(select_row), FF(uint256_t::from_uint128(output)), failure, false); + auto [mutated_trace, str] = + gen_mutated_trace_shift(std::move(trace), std::move(select_row), output, failure, false); EXPECT_THROW_WITH_MESSAGE(validate_trace_check_circuit(std::move(mutated_trace)), str); } INSTANTIATE_TEST_SUITE_P(AvmBitwiseNegativeTests, diff --git a/barretenberg/cpp/src/barretenberg/vm/tests/avm_comparison.test.cpp b/barretenberg/cpp/src/barretenberg/vm/tests/avm_comparison.test.cpp index 16ea72cbcaf..26eaf202fe7 100644 --- a/barretenberg/cpp/src/barretenberg/vm/tests/avm_comparison.test.cpp +++ b/barretenberg/cpp/src/barretenberg/vm/tests/avm_comparison.test.cpp @@ -57,8 +57,6 @@ void common_validate_cmp(Row const& row, EXPECT_EQ(alu_row.avm_alu_ic, c); } } // namespace -using ThreeOpParam = std::array; -using ThreeOpParamRow = std::tuple; std::vector positive_op_lt_test_values = { { { FF(1), FF(1), FF(0) }, { FF(5323), FF(321), FF(0) }, { FF(13793), FF(10590617LLU), FF(1) }, @@ -77,15 +75,6 @@ std::vector positive_op_lte_test_values = { FF(1) } } }; -std::vector gen_three_op_params(std::vector operands, - std::vector mem_tag_arr) -{ - std::vector params; - for (size_t i = 0; i < 5; i++) { - params.emplace_back(operands[i], mem_tag_arr[i]); - } - return params; -} std::vector mem_tag_arr{ { AvmMemoryTag::U8, AvmMemoryTag::U16, AvmMemoryTag::U32, AvmMemoryTag::U64, AvmMemoryTag::U128 } }; diff --git a/barretenberg/cpp/src/barretenberg/vm/tests/helpers.test.cpp b/barretenberg/cpp/src/barretenberg/vm/tests/helpers.test.cpp index 290b15585a0..b0dc065027d 100644 --- a/barretenberg/cpp/src/barretenberg/vm/tests/helpers.test.cpp +++ b/barretenberg/cpp/src/barretenberg/vm/tests/helpers.test.cpp @@ -1,7 +1,18 @@ +#include "barretenberg/vm/tests/helpers.test.hpp" #include "avm_common.test.hpp" #include "barretenberg/vm/generated/avm_flavor.hpp" namespace tests_avm { + +std::vector gen_three_op_params(std::vector operands, + std::vector mem_tags) +{ + std::vector params; + for (size_t i = 0; i < 5; i++) { + params.emplace_back(operands[i], mem_tags[i]); + } + return params; +} /** * @brief Helper routine checking the circuit constraints without proving * @@ -25,6 +36,7 @@ void validate_trace(std::vector&& trace, bool with_proof) EXPECT_TRUE(circuit_builder.check_circuit()); if (with_proof) { + info("With proof"); auto composer = AvmComposer(); auto prover = composer.create_prover(circuit_builder); auto proof = prover.construct_proof(); diff --git a/barretenberg/cpp/src/barretenberg/vm/tests/helpers.test.hpp b/barretenberg/cpp/src/barretenberg/vm/tests/helpers.test.hpp index fd1f862404d..5df14f93cd7 100644 --- a/barretenberg/cpp/src/barretenberg/vm/tests/helpers.test.hpp +++ b/barretenberg/cpp/src/barretenberg/vm/tests/helpers.test.hpp @@ -15,6 +15,8 @@ namespace tests_avm { using Flavor = bb::AvmFlavor; using FF = Flavor::FF; using Row = bb::AvmFullRow; +using ThreeOpParam = std::array; +using ThreeOpParamRow = std::tuple; // To toggle all relevant unit tests with proving, set the env variable "AVM_TESTS_ENABLE_PROVING". static const bool ENABLE_PROVING = std::getenv("AVM_TESTS_ENABLE_PROVING") != nullptr; @@ -30,5 +32,7 @@ void mutate_ic_in_trace(std::vector& trace, bool alu = false); void clear_range_check_counters(std::vector& trace, uint256_t previous_value); void update_slice_registers(Row& row, uint256_t a); +std::vector gen_three_op_params(std::vector> operands, + std::vector mem_tags); } // namespace tests_avm From cc59981a8f69375c4ca92999a12a955e0d385ada Mon Sep 17 00:00:00 2001 From: Facundo Date: Thu, 9 May 2024 13:05:23 +0100 Subject: [PATCH 05/11] fix(avm-simulator): always set revertReason when reverting (#6297) Part of the current setup seems to assume that a simulation reverts if and only if there's a revertReason. This is why some e2e tests were failing to see the revert (and throw an exception) when the revert message was empty. Example ```ts /** * Makes a processed tx out of source tx. * @param tx - Source tx. * @param kernelOutput - Output of the kernel circuit simulation for this tx. * @param proof - Proof of the kernel circuit for this tx. */ export function makeProcessedTx( tx: Tx, kernelOutput: KernelCircuitPublicInputs, proof: Proof, publicKernelRequests: PublicKernelRequest[], revertReason?: SimulationError, gasUsed: ProcessedTx['gasUsed'] = {}, ): ProcessedTx { return { hash: tx.getTxHash(), data: kernelOutput, proof, encryptedLogs: revertReason ? EncryptedTxL2Logs.empty() : tx.encryptedLogs, unencryptedLogs: revertReason ? UnencryptedTxL2Logs.empty() : tx.unencryptedLogs, isEmpty: false, revertReason, publicKernelRequests, gasUsed, }; } ``` cc @just-mitch because I see his name in some parts of the code. --- .../end-to-end/src/e2e_avm_simulator.test.ts | 7 +++--- .../simulator/src/avm/avm_machine_state.ts | 22 ++++++++++++------- .../simulator/src/avm/avm_simulator.test.ts | 2 +- .../src/public/abstract_phase_manager.ts | 10 ++++++++- yarn-project/simulator/src/public/executor.ts | 4 ---- 5 files changed, 28 insertions(+), 17 deletions(-) diff --git a/yarn-project/end-to-end/src/e2e_avm_simulator.test.ts b/yarn-project/end-to-end/src/e2e_avm_simulator.test.ts index 3acebe956a0..56cca9370f4 100644 --- a/yarn-project/end-to-end/src/e2e_avm_simulator.test.ts +++ b/yarn-project/end-to-end/src/e2e_avm_simulator.test.ts @@ -121,7 +121,7 @@ describe('e2e_avm_simulator', () => { }); }); - describe('ACVM interoperability', () => { + describe.skip('ACVM interoperability', () => { let avmContract: AvmAcvmInteropTestContract; beforeEach(async () => { @@ -136,7 +136,7 @@ describe('e2e_avm_simulator', () => { expect(await avmContract.methods.call_avm_from_acvm().simulate()).toEqual(123456n); }); - it.skip('Can call ACVM function from AVM', async () => { + it('Can call ACVM function from AVM', async () => { expect(await avmContract.methods.call_acvm_from_avm().simulate()).toEqual(123456n); }); @@ -146,7 +146,7 @@ describe('e2e_avm_simulator', () => { await avmContract.methods.assert_unsiloed_nullifier_acvm(nullifier).send().wait(); }); - it.skip('AVM nested call to ACVM sees settled nullifiers', async () => { + it('AVM nested call to ACVM sees settled nullifiers', async () => { const nullifier = new Fr(123456); await avmContract.methods.new_nullifier(nullifier).send().wait(); await avmContract.methods @@ -155,6 +155,7 @@ describe('e2e_avm_simulator', () => { .wait(); }); + // TODO: Enable (or delete) authwit tests once the AVM is fully functional. describe.skip('Authwit', () => { it('Works if authwit provided', async () => { const recipient = AztecAddress.random(); diff --git a/yarn-project/simulator/src/avm/avm_machine_state.ts b/yarn-project/simulator/src/avm/avm_machine_state.ts index ca4b5e72056..0af30ddefb3 100644 --- a/yarn-project/simulator/src/avm/avm_machine_state.ts +++ b/yarn-project/simulator/src/avm/avm_machine_state.ts @@ -136,14 +136,20 @@ export class AvmMachineState { throw new Error('Execution results are not ready! Execution is ongoing.'); } let revertReason = undefined; - if (this.reverted && this.output.length > 0) { - try { - // We remove the first element which is the 'error selector'. - const revertOutput = this.output.slice(1); - // Try to interpret the output as a text string. - revertReason = new Error('Assertion failed: ' + String.fromCharCode(...revertOutput.map(fr => fr.toNumber()))); - } catch (e) { - revertReason = new Error(''); + if (this.reverted) { + if (this.output.length === 0) { + revertReason = new Error('Assertion failed.'); + } else { + try { + // We remove the first element which is the 'error selector'. + const revertOutput = this.output.slice(1); + // Try to interpret the output as a text string. + revertReason = new Error( + 'Assertion failed: ' + String.fromCharCode(...revertOutput.map(fr => fr.toNumber())), + ); + } catch (e) { + revertReason = new Error('Assertion failed: '); + } } } return new AvmContractCallResults(this.reverted, this.output, revertReason); diff --git a/yarn-project/simulator/src/avm/avm_simulator.test.ts b/yarn-project/simulator/src/avm/avm_simulator.test.ts index 346e2861a8f..a18b4c05e43 100644 --- a/yarn-project/simulator/src/avm/avm_simulator.test.ts +++ b/yarn-project/simulator/src/avm/avm_simulator.test.ts @@ -115,7 +115,7 @@ describe('AVM simulator: transpiled Noir contracts', () => { const bytecode = getAvmTestContractBytecode('u128_from_integer_overflow'); const results = await new AvmSimulator(initContext()).executeBytecode(bytecode); expect(results.reverted).toBe(true); - expect(results.revertReason?.message).toEqual(undefined); + expect(results.revertReason?.message).toEqual('Assertion failed.'); // Note: compiler intrinsic messages (like below) are not known to the AVM //expect(results.revertReason?.message).toEqual("Assertion failed: call to assert_max_bit_size 'self.__assert_max_bit_size(bit_size)'"); }); diff --git a/yarn-project/simulator/src/public/abstract_phase_manager.ts b/yarn-project/simulator/src/public/abstract_phase_manager.ts index 06e89e93ef9..28d5b40ba9c 100644 --- a/yarn-project/simulator/src/public/abstract_phase_manager.ts +++ b/yarn-project/simulator/src/public/abstract_phase_manager.ts @@ -283,10 +283,18 @@ export abstract class AbstractPhaseManager { ) : current; + // Sanity check for a current upstream assumption. + // Consumers of the result seem to expect "reverted <=> revertReason !== undefined". + const functionSelector = result.execution.functionData.selector.toString(); + if (result.reverted && !result.revertReason) { + throw new Error( + `Simulation of ${result.execution.contractAddress.toString()}:${functionSelector} reverted with no reason.`, + ); + } + // Accumulate gas used in this execution gasUsed = gasUsed.add(Gas.from(result.startGasLeft).sub(Gas.from(result.endGasLeft))); - const functionSelector = result.execution.functionData.selector.toString(); if (result.reverted && !PhaseIsRevertible[this.phase]) { this.log.debug( `Simulation error on ${result.execution.contractAddress.toString()}:${functionSelector} with reason: ${ diff --git a/yarn-project/simulator/src/public/executor.ts b/yarn-project/simulator/src/public/executor.ts index 89951608404..2576bdd29da 100644 --- a/yarn-project/simulator/src/public/executor.ts +++ b/yarn-project/simulator/src/public/executor.ts @@ -168,10 +168,6 @@ async function executePublicFunctionAcvm( })(); if (reverted) { - if (!revertReason) { - throw new Error('Reverted but no revert reason'); - } - return { execution, returnValues: [], From f0a1c89a064c1e170db4751be46874f089dd1385 Mon Sep 17 00:00:00 2001 From: Tom French <15848336+TomAFrench@users.noreply.github.com> Date: Thu, 9 May 2024 14:29:45 +0100 Subject: [PATCH 06/11] chore: remove `bb info` command (#6276) This command is no longer used and so we can remove it. --- barretenberg/cpp/src/barretenberg/bb/main.cpp | 36 ------------------- 1 file changed, 36 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/bb/main.cpp b/barretenberg/cpp/src/barretenberg/bb/main.cpp index 820cc522ad7..674e4e67e92 100644 --- a/barretenberg/cpp/src/barretenberg/bb/main.cpp +++ b/barretenberg/cpp/src/barretenberg/bb/main.cpp @@ -508,37 +508,6 @@ void vk_as_fields(const std::string& vk_path, const std::string& output_path) } } -/** - * @brief Returns ACVM related backend information - * - * Communication: - * - stdout: The json string is written to stdout - * - Filesystem: The json string is written to the path specified - * - * @param output_path Path to write the information to - */ -void acvm_info(const std::string& output_path) -{ - - const char* jsonData = R"({ - "language": { - "name" : "PLONK-CSAT", - "width" : 4 - } - })"; - - size_t length = strlen(jsonData); - std::vector data(jsonData, jsonData + length); - - if (output_path == "-") { - writeRawBytesToStdout(data); - vinfo("info written to stdout"); - } else { - write_file(output_path, data); - vinfo("info written to: ", output_path); - } -} - /** * @brief Writes an avm proof and corresponding (incomplete) verification key to files. * @@ -797,11 +766,6 @@ int main(int argc, char* argv[]) writeStringToStdout(BB_VERSION); return 0; } - if (command == "info") { - std::string output_path = get_option(args, "-o", "info.json"); - acvm_info(output_path); - return 0; - } if (command == "prove_and_verify") { return proveAndVerify(bytecode_path, witness_path) ? 0 : 1; } From 95b499bead8b05afcb4cac8c7a12832ce7c7bfcd Mon Sep 17 00:00:00 2001 From: Tom French <15848336+TomAFrench@users.noreply.github.com> Date: Thu, 9 May 2024 14:32:01 +0100 Subject: [PATCH 07/11] chore: skip formatting informattable comments (#6288) I've flipped the config to just skip formatting any comments which would be lost if formatted (really not sure why that was turned on as the default behaviour). --- noir-projects/Earthfile | 5 ++- .../private-kernel-init-simulated/src/main.nr | 2 +- .../src/main.nr | 2 +- .../src/private_kernel_tail.nr | 36 ++++++++++--------- .../src/private_kernel_tail_to_public.nr | 5 +-- .../src/main.nr | 2 +- .../src/main.nr | 2 +- .../public-kernel-app-logic/src/main.nr | 2 +- .../public-kernel-setup-simulated/src/main.nr | 2 +- .../crates/public-kernel-setup/src/main.nr | 2 +- .../public-kernel-tail-simulated/src/main.nr | 2 +- .../crates/public-kernel-tail/src/main.nr | 2 +- .../src/main.nr | 2 +- .../base_or_merge_rollup_public_inputs.nr | 6 ++-- .../src/abis/constant_rollup_data.nr | 2 +- ...ic_kernel_circuit_public_inputs_builder.nr | 3 +- .../rollup_validation_requests.nr | 5 ++- .../validation_requests.nr | 5 +-- .../noir-repo/tooling/nargo_fmt/src/config.rs | 2 +- 19 files changed, 47 insertions(+), 42 deletions(-) diff --git a/noir-projects/Earthfile b/noir-projects/Earthfile index 907f009151d..108f36f3715 100644 --- a/noir-projects/Earthfile +++ b/noir-projects/Earthfile @@ -33,9 +33,8 @@ test: format: FROM +build - # TODO: https://github.com/noir-lang/noir/issues/4980 - # WORKDIR /usr/src/noir-projects/noir-protocol-circuits - # RUN nargo fmt --check + WORKDIR /usr/src/noir-projects/noir-protocol-circuits + RUN nargo fmt --check WORKDIR /usr/src/noir-projects/noir-contracts RUN nargo fmt --check diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-init-simulated/src/main.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-init-simulated/src/main.nr index 2d0470155e5..a59e08872e9 100644 --- a/noir-projects/noir-protocol-circuits/crates/private-kernel-init-simulated/src/main.nr +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-init-simulated/src/main.nr @@ -1,6 +1,6 @@ use dep::private_kernel_lib::PrivateKernelInitCircuitPrivateInputs; use dep::types::PrivateKernelCircuitPublicInputs; -unconstrained fn main(input: PrivateKernelInitCircuitPrivateInputs) -> pub PrivateKernelCircuitPublicInputs { +unconstrained fn main(input: PrivateKernelInitCircuitPrivateInputs) -> pub PrivateKernelCircuitPublicInputs { input.native_private_kernel_circuit_initial() } diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-inner-simulated/src/main.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-inner-simulated/src/main.nr index f3494a35038..0f58903b973 100644 --- a/noir-projects/noir-protocol-circuits/crates/private-kernel-inner-simulated/src/main.nr +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-inner-simulated/src/main.nr @@ -1,6 +1,6 @@ use dep::private_kernel_lib::PrivateKernelInnerCircuitPrivateInputs; use dep::types::PrivateKernelCircuitPublicInputs; -unconstrained fn main(input: PrivateKernelInnerCircuitPrivateInputs) -> pub PrivateKernelCircuitPublicInputs { +unconstrained fn main(input: PrivateKernelInnerCircuitPrivateInputs) -> pub PrivateKernelCircuitPublicInputs { input.native_private_kernel_circuit_inner() } diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_tail.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_tail.nr index 51d6efd7a07..598dfe018f7 100644 --- a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_tail.nr +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_tail.nr @@ -1,14 +1,15 @@ use crate::kernel_circuit_public_inputs_composer::KernelCircuitPublicInputsComposer; use dep::reset_kernel_lib::{NoteHashReadRequestHints, NullifierReadRequestHints, PrivateValidationRequestProcessor}; use dep::types::{ - abis::{ - private_kernel_data::{PrivateKernelData, verify_previous_kernel_proof}, kernel_circuit_public_inputs::KernelCircuitPublicInputs, - note_hash::ScopedNoteHash, nullifier::ScopedNullifier, side_effect::SideEffect - }, - constants::{ - MAX_NEW_NOTE_HASHES_PER_TX, MAX_NEW_NULLIFIERS_PER_TX, MAX_NOTE_HASH_READ_REQUESTS_PER_TX, - MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, MAX_ENCRYPTED_LOGS_PER_TX, MAX_UNENCRYPTED_LOGS_PER_TX - }, + abis::{ + private_kernel_data::{PrivateKernelData, verify_previous_kernel_proof}, + kernel_circuit_public_inputs::KernelCircuitPublicInputs, note_hash::ScopedNoteHash, + nullifier::ScopedNullifier, side_effect::SideEffect +}, + constants::{ + MAX_NEW_NOTE_HASHES_PER_TX, MAX_NEW_NULLIFIERS_PER_TX, MAX_NOTE_HASH_READ_REQUESTS_PER_TX, + MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, MAX_ENCRYPTED_LOGS_PER_TX, MAX_UNENCRYPTED_LOGS_PER_TX +}, grumpkin_private_key::GrumpkinPrivateKey, utils::arrays::array_length }; @@ -94,16 +95,19 @@ mod tests { use dep::types::constants::{ MAX_NOTE_HASH_READ_REQUESTS_PER_TX, MAX_NEW_NOTE_HASHES_PER_TX, MAX_NEW_NULLIFIERS_PER_TX, MAX_NULLIFIER_READ_REQUESTS_PER_TX, MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, - MAX_ENCRYPTED_LOGS_PER_TX, MAX_UNENCRYPTED_LOGS_PER_TX, - DA_BYTES_PER_FIELD, DA_GAS_PER_BYTE + MAX_ENCRYPTED_LOGS_PER_TX, MAX_UNENCRYPTED_LOGS_PER_TX, DA_BYTES_PER_FIELD, DA_GAS_PER_BYTE }; use dep::types::{ abis::{ kernel_circuit_public_inputs::KernelCircuitPublicInputs, max_block_number::MaxBlockNumber, - note_hash::{NoteHash, ScopedNoteHash}, nullifier::{Nullifier, ScopedNullifier}, side_effect::SideEffect, gas::Gas + note_hash::{NoteHash, ScopedNoteHash}, nullifier::{Nullifier, ScopedNullifier}, + side_effect::SideEffect, gas::Gas }, grumpkin_private_key::GrumpkinPrivateKey, - hash::{compute_note_hash_nonce, compute_unique_siloed_note_hash, sha256_to_field, silo_note_hash, silo_nullifier}, + hash::{ + compute_note_hash_nonce, compute_unique_siloed_note_hash, sha256_to_field, silo_note_hash, + silo_nullifier + }, tests::{fixture_builder::FixtureBuilder, sort::sort_get_sorted_hints}, utils::{arrays::{array_eq, array_length}}, traits::{Empty, is_empty, is_empty_array} }; @@ -135,10 +139,7 @@ mod tests { // A helper function that uses the first nullifer in the previous kernel to compute the unique siloed // note_hashes for the given note_hashes. - pub fn compute_output_note_hashes( - self, - note_hashes: [ScopedNoteHash; N] - ) -> [Field; N] { + pub fn compute_output_note_hashes(self, note_hashes: [ScopedNoteHash; N]) -> [Field; N] { let first_nullifier = self.previous_kernel.new_nullifiers.get_unchecked(0); let mut unique_siloed_note_hashes = [0; N]; for i in 0..N { @@ -308,6 +309,7 @@ mod tests { public_inputs.end.unencrypted_log_preimages_length, unencrypted_log_preimages_length + prev_unencrypted_log_preimages_length ); + // noir-fmt:ignore let hash_bytes: [u8; MAX_ENCRYPTED_LOGS_PER_TX * 32] = prev_encrypted_logs_hash .to_be_bytes(32) .append(&[0; MAX_ENCRYPTED_LOGS_PER_TX * 32 - 32]) @@ -315,6 +317,7 @@ mod tests { let expected_encrypted_logs_hash = sha256_to_field(hash_bytes); assert_eq(public_inputs.end.encrypted_logs_hash, expected_encrypted_logs_hash); + // noir-fmt:ignore let hash_bytes: [u8; MAX_UNENCRYPTED_LOGS_PER_TX * 32] = prev_unencrypted_logs_hash .to_be_bytes(32) .append(unencrypted_logs_hash.to_be_bytes(32)) @@ -584,7 +587,6 @@ mod tests { builder.previous_kernel.tx_context.gas_settings.teardown_gas_limits = Gas::new(300, 300); let public_inputs = builder.execute(); - let expected_gas_consumed = Gas::new(300, 300) // teardown gas + Gas::tx_overhead() // tx overhead + Gas::new(DA_GAS_PER_BYTE * DA_BYTES_PER_FIELD * 1, 0); // tx nullifier diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_tail_to_public.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_tail_to_public.nr index 7b7e17eba88..9dd2319a041 100644 --- a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_tail_to_public.nr +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_tail_to_public.nr @@ -2,8 +2,9 @@ use crate::kernel_circuit_public_inputs_composer::KernelCircuitPublicInputsCompo use dep::reset_kernel_lib::{NoteHashReadRequestHints, NullifierReadRequestHints, PrivateValidationRequestProcessor}; use dep::types::{ abis::{ - private_kernel_data::{PrivateKernelData, verify_previous_kernel_proof}, kernel_circuit_public_inputs::PublicKernelCircuitPublicInputs, - note_hash::ScopedNoteHash, nullifier::ScopedNullifier, side_effect::SideEffect + private_kernel_data::{PrivateKernelData, verify_previous_kernel_proof}, + kernel_circuit_public_inputs::PublicKernelCircuitPublicInputs, note_hash::ScopedNoteHash, + nullifier::ScopedNullifier, side_effect::SideEffect }, constants::{ MAX_NEW_NOTE_HASHES_PER_TX, MAX_NEW_NULLIFIERS_PER_TX, MAX_NOTE_HASH_READ_REQUESTS_PER_TX, diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-tail-to-public-simulated/src/main.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-tail-to-public-simulated/src/main.nr index 6c20fcfdeb0..3683ecbd8cc 100644 --- a/noir-projects/noir-protocol-circuits/crates/private-kernel-tail-to-public-simulated/src/main.nr +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-tail-to-public-simulated/src/main.nr @@ -1,6 +1,6 @@ use dep::private_kernel_lib::PrivateKernelTailToPublicCircuitPrivateInputs; use dep::types::PublicKernelCircuitPublicInputs; -unconstrained fn main(input: PrivateKernelTailToPublicCircuitPrivateInputs) -> pub PublicKernelCircuitPublicInputs { +unconstrained fn main(input: PrivateKernelTailToPublicCircuitPrivateInputs) -> pub PublicKernelCircuitPublicInputs { input.execute() } diff --git a/noir-projects/noir-protocol-circuits/crates/public-kernel-app-logic-simulated/src/main.nr b/noir-projects/noir-protocol-circuits/crates/public-kernel-app-logic-simulated/src/main.nr index eaf2169e3a1..8bcc9f1643f 100644 --- a/noir-projects/noir-protocol-circuits/crates/public-kernel-app-logic-simulated/src/main.nr +++ b/noir-projects/noir-protocol-circuits/crates/public-kernel-app-logic-simulated/src/main.nr @@ -1,6 +1,6 @@ use dep::public_kernel_lib::PublicKernelAppLogicCircuitPrivateInputs; use dep::types::PublicKernelCircuitPublicInputs; -unconstrained fn main(input: PublicKernelAppLogicCircuitPrivateInputs) -> pub PublicKernelCircuitPublicInputs { +unconstrained fn main(input: PublicKernelAppLogicCircuitPrivateInputs) -> pub PublicKernelCircuitPublicInputs { input.public_kernel_app_logic() } diff --git a/noir-projects/noir-protocol-circuits/crates/public-kernel-app-logic/src/main.nr b/noir-projects/noir-protocol-circuits/crates/public-kernel-app-logic/src/main.nr index fc4185f03b3..1126e42d576 100644 --- a/noir-projects/noir-protocol-circuits/crates/public-kernel-app-logic/src/main.nr +++ b/noir-projects/noir-protocol-circuits/crates/public-kernel-app-logic/src/main.nr @@ -1,6 +1,6 @@ use dep::public_kernel_lib::PublicKernelAppLogicCircuitPrivateInputs; use dep::types::PublicKernelCircuitPublicInputs; -fn main(input: PublicKernelAppLogicCircuitPrivateInputs) -> pub PublicKernelCircuitPublicInputs { +fn main(input: PublicKernelAppLogicCircuitPrivateInputs) -> pub PublicKernelCircuitPublicInputs { input.public_kernel_app_logic() } diff --git a/noir-projects/noir-protocol-circuits/crates/public-kernel-setup-simulated/src/main.nr b/noir-projects/noir-protocol-circuits/crates/public-kernel-setup-simulated/src/main.nr index 35f53631a04..be09565d0ac 100644 --- a/noir-projects/noir-protocol-circuits/crates/public-kernel-setup-simulated/src/main.nr +++ b/noir-projects/noir-protocol-circuits/crates/public-kernel-setup-simulated/src/main.nr @@ -1,6 +1,6 @@ use dep::public_kernel_lib::PublicKernelSetupCircuitPrivateInputs; use dep::types::PublicKernelCircuitPublicInputs; -unconstrained fn main(input: PublicKernelSetupCircuitPrivateInputs) -> pub PublicKernelCircuitPublicInputs { +unconstrained fn main(input: PublicKernelSetupCircuitPrivateInputs) -> pub PublicKernelCircuitPublicInputs { input.public_kernel_setup() } diff --git a/noir-projects/noir-protocol-circuits/crates/public-kernel-setup/src/main.nr b/noir-projects/noir-protocol-circuits/crates/public-kernel-setup/src/main.nr index da84636684b..f9b31176fa0 100644 --- a/noir-projects/noir-protocol-circuits/crates/public-kernel-setup/src/main.nr +++ b/noir-projects/noir-protocol-circuits/crates/public-kernel-setup/src/main.nr @@ -1,6 +1,6 @@ use dep::public_kernel_lib::PublicKernelSetupCircuitPrivateInputs; use dep::types::PublicKernelCircuitPublicInputs; -fn main(input: PublicKernelSetupCircuitPrivateInputs) -> pub PublicKernelCircuitPublicInputs { +fn main(input: PublicKernelSetupCircuitPrivateInputs) -> pub PublicKernelCircuitPublicInputs { input.public_kernel_setup() } diff --git a/noir-projects/noir-protocol-circuits/crates/public-kernel-tail-simulated/src/main.nr b/noir-projects/noir-protocol-circuits/crates/public-kernel-tail-simulated/src/main.nr index bd928276f4c..0a9f18ffd54 100644 --- a/noir-projects/noir-protocol-circuits/crates/public-kernel-tail-simulated/src/main.nr +++ b/noir-projects/noir-protocol-circuits/crates/public-kernel-tail-simulated/src/main.nr @@ -1,6 +1,6 @@ use dep::public_kernel_lib::PublicKernelTailCircuitPrivateInputs; use dep::types::KernelCircuitPublicInputs; -unconstrained fn main(input: PublicKernelTailCircuitPrivateInputs) -> pub KernelCircuitPublicInputs { +unconstrained fn main(input: PublicKernelTailCircuitPrivateInputs) -> pub KernelCircuitPublicInputs { input.public_kernel_tail() } diff --git a/noir-projects/noir-protocol-circuits/crates/public-kernel-tail/src/main.nr b/noir-projects/noir-protocol-circuits/crates/public-kernel-tail/src/main.nr index 8b6ba443c87..3227791a09a 100644 --- a/noir-projects/noir-protocol-circuits/crates/public-kernel-tail/src/main.nr +++ b/noir-projects/noir-protocol-circuits/crates/public-kernel-tail/src/main.nr @@ -1,6 +1,6 @@ use dep::public_kernel_lib::PublicKernelTailCircuitPrivateInputs; use dep::types::KernelCircuitPublicInputs; -fn main(input: PublicKernelTailCircuitPrivateInputs) -> pub KernelCircuitPublicInputs { +fn main(input: PublicKernelTailCircuitPrivateInputs) -> pub KernelCircuitPublicInputs { input.public_kernel_tail() } diff --git a/noir-projects/noir-protocol-circuits/crates/public-kernel-teardown-simulated/src/main.nr b/noir-projects/noir-protocol-circuits/crates/public-kernel-teardown-simulated/src/main.nr index 55e9d441348..78cb6040500 100644 --- a/noir-projects/noir-protocol-circuits/crates/public-kernel-teardown-simulated/src/main.nr +++ b/noir-projects/noir-protocol-circuits/crates/public-kernel-teardown-simulated/src/main.nr @@ -1,6 +1,6 @@ use dep::public_kernel_lib::PublicKernelTeardownCircuitPrivateInputs; use dep::types::PublicKernelCircuitPublicInputs; -unconstrained fn main(input: PublicKernelTeardownCircuitPrivateInputs) -> pub PublicKernelCircuitPublicInputs { +unconstrained fn main(input: PublicKernelTeardownCircuitPrivateInputs) -> pub PublicKernelCircuitPublicInputs { input.public_kernel_teardown() } diff --git a/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/abis/base_or_merge_rollup_public_inputs.nr b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/abis/base_or_merge_rollup_public_inputs.nr index 5e1b9b33dc6..90406f9e18e 100644 --- a/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/abis/base_or_merge_rollup_public_inputs.nr +++ b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/abis/base_or_merge_rollup_public_inputs.nr @@ -1,8 +1,6 @@ use dep::types::{ abis::append_only_tree_snapshot::AppendOnlyTreeSnapshot, - partial_state_reference::PartialStateReference, - mocked::AggregationObject, - traits::Empty + partial_state_reference::PartialStateReference, mocked::AggregationObject, traits::Empty }; use crate::abis::constant_rollup_data::ConstantRollupData; @@ -44,4 +42,4 @@ impl Empty for BaseOrMergeRollupPublicInputs { out_hash : 0, } } -} \ No newline at end of file +} diff --git a/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/abis/constant_rollup_data.nr b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/abis/constant_rollup_data.nr index b688397a7d9..824860f74b1 100644 --- a/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/abis/constant_rollup_data.nr +++ b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/abis/constant_rollup_data.nr @@ -40,4 +40,4 @@ impl Empty for ConstantRollupData { global_variables: GlobalVariables::empty(), } } -} \ No newline at end of file +} diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/public_kernel_circuit_public_inputs_builder.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/public_kernel_circuit_public_inputs_builder.nr index 41f92bd5f22..70169e44548 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/public_kernel_circuit_public_inputs_builder.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/public_kernel_circuit_public_inputs_builder.nr @@ -4,7 +4,8 @@ use crate::{ combined_constant_data::CombinedConstantData, kernel_circuit_public_inputs::{public_kernel_circuit_public_inputs::PublicKernelCircuitPublicInputs}, validation_requests::ValidationRequestsBuilder, call_request::CallRequest -}, traits::Empty +}, + traits::Empty }; struct PublicKernelCircuitPublicInputsBuilder { diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/validation_requests/rollup_validation_requests.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/validation_requests/rollup_validation_requests.nr index 1840668e1b3..d1761a1a859 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/validation_requests/rollup_validation_requests.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/validation_requests/rollup_validation_requests.nr @@ -1,4 +1,7 @@ -use crate::{abis::max_block_number::MaxBlockNumber, traits::{Empty, Serialize}, constants::ROLLUP_VALIDATION_REQUESTS_LENGTH}; +use crate::{ + abis::max_block_number::MaxBlockNumber, traits::{Empty, Serialize}, + constants::ROLLUP_VALIDATION_REQUESTS_LENGTH +}; // These are validation requests that cannot be fulfilled in the current context (private or public), and must be // instead forwarded to the rollup for it to take care of them. diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/validation_requests/validation_requests.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/validation_requests/validation_requests.nr index 8d56adb7ea6..d8e34e36311 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/validation_requests/validation_requests.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/validation_requests/validation_requests.nr @@ -9,7 +9,8 @@ use crate::{ MAX_NOTE_HASH_READ_REQUESTS_PER_TX, MAX_NULLIFIER_READ_REQUESTS_PER_TX, MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_TX, MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, MAX_PUBLIC_DATA_READS_PER_TX, VALIDATION_REQUESTS_LENGTH -}, traits::Serialize +}, + traits::Serialize }; // TODO - Use specific structs for private and public: PrivateValidationRequests vs PublicValidationRequests @@ -52,4 +53,4 @@ impl Serialize for ValidationRequests { fields.storage } -} \ No newline at end of file +} diff --git a/noir/noir-repo/tooling/nargo_fmt/src/config.rs b/noir/noir-repo/tooling/nargo_fmt/src/config.rs index 2bb5d97c0af..5e38dc7d8b0 100644 --- a/noir/noir-repo/tooling/nargo_fmt/src/config.rs +++ b/noir/noir-repo/tooling/nargo_fmt/src/config.rs @@ -45,7 +45,7 @@ config! { max_width: usize, 100, "Maximum width of each line"; tab_spaces: usize, 4, "Number of spaces per tab"; remove_nested_parens: bool, true, "Remove nested parens"; - error_on_lost_comment: bool, true, "Error if unable to get comments"; + error_on_lost_comment: bool, false, "Error if unable to get comments"; short_array_element_width_threshold: usize, 10, "Width threshold for an array element to be considered short"; array_width: usize, 100, "Maximum width of an array literal before falling back to vertical formatting"; fn_call_width: usize, 60, "Maximum width of the args of a function call before falling back to vertical formatting"; From ac27376b9a0cdf0624a02d36c64ec25886b44b4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Rodr=C3=ADguez?= Date: Thu, 9 May 2024 15:33:27 +0200 Subject: [PATCH 08/11] feat: move to_radix to a blackbox (#6294) This PR moves to_radix to a Brillig-specific blackbox. The AVM won't easily support field integer division, and the only usecase for field integer division in regular noir code is to radix / to bits. We extract to radix to a bb func so it can be directly integrated as a gadget in the avm. --- .../dsl/acir_format/serde/acir.hpp | 74 +++++++++++++++++-- .../noir-repo/acvm-repo/acir/codegen/acir.cpp | 56 +++++++++++++- .../acvm-repo/brillig/src/black_box.rs | 5 ++ .../acvm-repo/brillig_vm/src/black_box.rs | 21 ++++++ .../src/brillig/brillig_gen/brillig_block.rs | 38 +++++++--- .../brillig/brillig_ir/codegen_intrinsic.rs | 62 +++++++--------- .../src/brillig/brillig_ir/debug_show.rs | 9 +++ noir/noir-repo/noir_stdlib/src/field/bn254.nr | 57 ++++++++------ 8 files changed, 249 insertions(+), 73 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/serde/acir.hpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/serde/acir.hpp index 9fb0e2b3a35..683e4c62407 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/serde/acir.hpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/serde/acir.hpp @@ -686,7 +686,6 @@ struct BlackBoxOp { Program::HeapVector inputs; Program::HeapArray iv; Program::HeapArray key; - Program::MemoryAddress length; Program::HeapVector outputs; friend bool operator==(const AES128Encrypt&, const AES128Encrypt&); @@ -896,6 +895,16 @@ struct BlackBoxOp { static Sha256Compression bincodeDeserialize(std::vector); }; + struct ToRadix { + Program::MemoryAddress input; + uint32_t radix; + Program::HeapArray output; + + friend bool operator==(const ToRadix&, const ToRadix&); + std::vector bincodeSerialize() const; + static ToRadix bincodeDeserialize(std::vector); + }; + std::variant + Sha256Compression, + ToRadix> value; friend bool operator==(const BlackBoxOp&, const BlackBoxOp&); @@ -3939,9 +3949,6 @@ inline bool operator==(const BlackBoxOp::AES128Encrypt& lhs, const BlackBoxOp::A if (!(lhs.key == rhs.key)) { return false; } - if (!(lhs.length == rhs.length)) { - return false; - } if (!(lhs.outputs == rhs.outputs)) { return false; } @@ -5141,6 +5148,63 @@ Program::BlackBoxOp::Sha256Compression serde::Deserializable BlackBoxOp::ToRadix::bincodeSerialize() const +{ + auto serializer = serde::BincodeSerializer(); + serde::Serializable::serialize(*this, serializer); + return std::move(serializer).bytes(); +} + +inline BlackBoxOp::ToRadix BlackBoxOp::ToRadix::bincodeDeserialize(std::vector input) +{ + auto deserializer = serde::BincodeDeserializer(input); + auto value = serde::Deserializable::deserialize(deserializer); + if (deserializer.get_buffer_offset() < input.size()) { + throw_or_abort("Some input bytes were not read"); + } + return value; +} + +} // end of namespace Program + +template <> +template +void serde::Serializable::serialize(const Program::BlackBoxOp::ToRadix& obj, + Serializer& serializer) +{ + serde::Serializable::serialize(obj.input, serializer); + serde::Serializable::serialize(obj.radix, serializer); + serde::Serializable::serialize(obj.output, serializer); +} + +template <> +template +Program::BlackBoxOp::ToRadix serde::Deserializable::deserialize( + Deserializer& deserializer) +{ + Program::BlackBoxOp::ToRadix obj; + obj.input = serde::Deserializable::deserialize(deserializer); + obj.radix = serde::Deserializable::deserialize(deserializer); + obj.output = serde::Deserializable::deserialize(deserializer); + return obj; +} + +namespace Program { + inline bool operator==(const BlockId& lhs, const BlockId& rhs) { if (!(lhs.value == rhs.value)) { diff --git a/noir/noir-repo/acvm-repo/acir/codegen/acir.cpp b/noir/noir-repo/acvm-repo/acir/codegen/acir.cpp index 5afcd68e987..222a7da6399 100644 --- a/noir/noir-repo/acvm-repo/acir/codegen/acir.cpp +++ b/noir/noir-repo/acvm-repo/acir/codegen/acir.cpp @@ -870,7 +870,17 @@ namespace Program { static Sha256Compression bincodeDeserialize(std::vector); }; - std::variant value; + struct ToRadix { + Program::MemoryAddress input; + uint32_t radix; + Program::HeapArray output; + + friend bool operator==(const ToRadix&, const ToRadix&); + std::vector bincodeSerialize() const; + static ToRadix bincodeDeserialize(std::vector); + }; + + std::variant value; friend bool operator==(const BlackBoxOp&, const BlackBoxOp&); std::vector bincodeSerialize() const; @@ -4293,6 +4303,50 @@ Program::BlackBoxOp::Sha256Compression serde::Deserializable BlackBoxOp::ToRadix::bincodeSerialize() const { + auto serializer = serde::BincodeSerializer(); + serde::Serializable::serialize(*this, serializer); + return std::move(serializer).bytes(); + } + + inline BlackBoxOp::ToRadix BlackBoxOp::ToRadix::bincodeDeserialize(std::vector input) { + auto deserializer = serde::BincodeDeserializer(input); + auto value = serde::Deserializable::deserialize(deserializer); + if (deserializer.get_buffer_offset() < input.size()) { + throw serde::deserialization_error("Some input bytes were not read"); + } + return value; + } + +} // end of namespace Program + +template <> +template +void serde::Serializable::serialize(const Program::BlackBoxOp::ToRadix &obj, Serializer &serializer) { + serde::Serializable::serialize(obj.input, serializer); + serde::Serializable::serialize(obj.radix, serializer); + serde::Serializable::serialize(obj.output, serializer); +} + +template <> +template +Program::BlackBoxOp::ToRadix serde::Deserializable::deserialize(Deserializer &deserializer) { + Program::BlackBoxOp::ToRadix obj; + obj.input = serde::Deserializable::deserialize(deserializer); + obj.radix = serde::Deserializable::deserialize(deserializer); + obj.output = serde::Deserializable::deserialize(deserializer); + return obj; +} + namespace Program { inline bool operator==(const BlockId &lhs, const BlockId &rhs) { diff --git a/noir/noir-repo/acvm-repo/brillig/src/black_box.rs b/noir/noir-repo/acvm-repo/brillig/src/black_box.rs index 15abc19ed90..9a66b428dc3 100644 --- a/noir/noir-repo/acvm-repo/brillig/src/black_box.rs +++ b/noir/noir-repo/acvm-repo/brillig/src/black_box.rs @@ -126,4 +126,9 @@ pub enum BlackBoxOp { hash_values: HeapVector, output: HeapArray, }, + ToRadix { + input: MemoryAddress, + radix: u32, + output: HeapArray, + }, } diff --git a/noir/noir-repo/acvm-repo/brillig_vm/src/black_box.rs b/noir/noir-repo/acvm-repo/brillig_vm/src/black_box.rs index c999b5bf330..d6ecd25f454 100644 --- a/noir/noir-repo/acvm-repo/brillig_vm/src/black_box.rs +++ b/noir/noir-repo/acvm-repo/brillig_vm/src/black_box.rs @@ -5,6 +5,7 @@ use acvm_blackbox_solver::{ aes128_encrypt, blake2s, blake3, ecdsa_secp256k1_verify, ecdsa_secp256r1_verify, keccak256, keccakf1600, sha256, sha256compression, BlackBoxFunctionSolver, BlackBoxResolutionError, }; +use num_bigint::BigUint; use crate::memory::MemoryValue; use crate::Memory; @@ -295,6 +296,25 @@ pub(crate) fn evaluate_black_box( memory.write_slice(memory.read_ref(output.pointer), &state); Ok(()) } + BlackBoxOp::ToRadix { input, radix, output } => { + let input: FieldElement = + memory.read(*input).try_into().expect("ToRadix input not a field"); + + let mut input = BigUint::from_bytes_be(&input.to_be_bytes()); + let radix = BigUint::from(*radix); + + let mut limbs: Vec = Vec::with_capacity(output.size); + + for _ in 0..output.size { + let limb = &input % &radix; + limbs.push(FieldElement::from_be_bytes_reduce(&limb.to_bytes_be()).into()); + input /= &radix; + } + + memory.write_slice(memory.read_ref(output.pointer), &limbs); + + Ok(()) + } } } @@ -321,6 +341,7 @@ fn black_box_function_from_op(op: &BlackBoxOp) -> BlackBoxFunc { BlackBoxOp::BigIntToLeBytes { .. } => BlackBoxFunc::BigIntToLeBytes, BlackBoxOp::Poseidon2Permutation { .. } => BlackBoxFunc::Poseidon2Permutation, BlackBoxOp::Sha256Compression { .. } => BlackBoxFunc::Sha256Compression, + BlackBoxOp::ToRadix { .. } => unreachable!("ToRadix is not an ACIR BlackBoxFunc"), } } diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block.rs b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block.rs index f660c8e0b7a..6a4f9f5cc0e 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block.rs @@ -488,8 +488,22 @@ impl<'block> BrilligBlock<'block> { } Value::Intrinsic(Intrinsic::ToRadix(endianness)) => { let source = self.convert_ssa_single_addr_value(arguments[0], dfg); - let radix = self.convert_ssa_single_addr_value(arguments[1], dfg); - let limb_count = self.convert_ssa_single_addr_value(arguments[2], dfg); + + let radix: u32 = dfg + .get_numeric_constant(arguments[1]) + .expect("Radix should be known") + .try_to_u64() + .expect("Radix should fit in u64") + .try_into() + .expect("Radix should be u32"); + + let limb_count: usize = dfg + .get_numeric_constant(arguments[2]) + .expect("Limb count should be known") + .try_to_u64() + .expect("Limb count should fit in u64") + .try_into() + .expect("Limb count should fit in usize"); let results = dfg.instruction_results(instruction_id); @@ -511,7 +525,8 @@ impl<'block> BrilligBlock<'block> { .extract_vector(); // Update the user-facing slice length - self.brillig_context.cast_instruction(target_len, limb_count); + self.brillig_context + .usize_const_instruction(target_len.address, limb_count.into()); self.brillig_context.codegen_to_radix( source, @@ -524,7 +539,13 @@ impl<'block> BrilligBlock<'block> { } Value::Intrinsic(Intrinsic::ToBits(endianness)) => { let source = self.convert_ssa_single_addr_value(arguments[0], dfg); - let limb_count = self.convert_ssa_single_addr_value(arguments[1], dfg); + let limb_count: usize = dfg + .get_numeric_constant(arguments[1]) + .expect("Limb count should be known") + .try_to_u64() + .expect("Limb count should fit in u64") + .try_into() + .expect("Limb count should fit in usize"); let results = dfg.instruction_results(instruction_id); @@ -549,21 +570,18 @@ impl<'block> BrilligBlock<'block> { BrilligVariable::SingleAddr(..) => unreachable!("ICE: ToBits on non-array"), }; - let radix = self.brillig_context.make_constant_instruction(2_usize.into(), 32); - // Update the user-facing slice length - self.brillig_context.cast_instruction(target_len, limb_count); + self.brillig_context + .usize_const_instruction(target_len.address, limb_count.into()); self.brillig_context.codegen_to_radix( source, target_vector, - radix, + 2, limb_count, matches!(endianness, Endian::Big), 1, ); - - self.brillig_context.deallocate_single_addr(radix); } _ => { unreachable!("unsupported function call type {:?}", dfg[*func]) diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/codegen_intrinsic.rs b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/codegen_intrinsic.rs index ab756217bcd..58166554e1d 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/codegen_intrinsic.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/codegen_intrinsic.rs @@ -1,6 +1,7 @@ -use acvm::FieldElement; - -use crate::brillig::brillig_ir::BrilligBinaryOp; +use acvm::{ + acir::brillig::{BlackBoxOp, HeapArray}, + FieldElement, +}; use super::{ brillig_variable::{BrilligVector, SingleAddrVariable}, @@ -36,57 +37,46 @@ impl BrilligContext { &mut self, source_field: SingleAddrVariable, target_vector: BrilligVector, - radix: SingleAddrVariable, - limb_count: SingleAddrVariable, + radix: u32, + limb_count: usize, big_endian: bool, limb_bit_size: u32, ) { assert!(source_field.bit_size == FieldElement::max_num_bits()); - assert!(radix.bit_size == 32); - assert!(limb_count.bit_size == 32); - let radix_as_field = - SingleAddrVariable::new(self.allocate_register(), FieldElement::max_num_bits()); - self.cast_instruction(radix_as_field, radix); - self.cast_instruction(SingleAddrVariable::new_usize(target_vector.size), limb_count); + self.usize_const_instruction(target_vector.size, limb_count.into()); self.usize_const_instruction(target_vector.rc, 1_usize.into()); self.codegen_allocate_array(target_vector.pointer, target_vector.size); - let shifted_field = - SingleAddrVariable::new(self.allocate_register(), FieldElement::max_num_bits()); - self.mov_instruction(shifted_field.address, source_field.address); + self.black_box_op_instruction(BlackBoxOp::ToRadix { + input: source_field.address, + radix, + output: HeapArray { pointer: target_vector.pointer, size: limb_count }, + }); let limb_field = SingleAddrVariable::new(self.allocate_register(), FieldElement::max_num_bits()); let limb_casted = SingleAddrVariable::new(self.allocate_register(), limb_bit_size); - self.codegen_loop(target_vector.size, |ctx, iterator_register| { - // Compute the modulus - ctx.binary_instruction( - shifted_field, - radix_as_field, - limb_field, - BrilligBinaryOp::Modulo, - ); - // Cast it - ctx.cast_instruction(limb_casted, limb_field); - // Write it - ctx.codegen_array_set(target_vector.pointer, iterator_register, limb_casted.address); - // Integer div the field - ctx.binary_instruction( - shifted_field, - radix_as_field, - shifted_field, - BrilligBinaryOp::UnsignedDiv, - ); - }); + if limb_bit_size != FieldElement::max_num_bits() { + self.codegen_loop(target_vector.size, |ctx, iterator_register| { + // Read the limb + ctx.codegen_array_get(target_vector.pointer, iterator_register, limb_field.address); + // Cast it + ctx.cast_instruction(limb_casted, limb_field); + // Write it + ctx.codegen_array_set( + target_vector.pointer, + iterator_register, + limb_casted.address, + ); + }); + } // Deallocate our temporary registers - self.deallocate_single_addr(shifted_field); self.deallocate_single_addr(limb_field); self.deallocate_single_addr(limb_casted); - self.deallocate_single_addr(radix_as_field); if big_endian { self.codegen_reverse_vector_in_place(target_vector); diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/debug_show.rs b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/debug_show.rs index 667ccf6ddbe..f02f6059e7c 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/debug_show.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/debug_show.rs @@ -451,6 +451,15 @@ impl DebugShow { output ); } + BlackBoxOp::ToRadix { input, radix, output } => { + debug_println!( + self.enable_debug_trace, + " TO_RADIX {} {} -> {}", + input, + radix, + output + ); + } } } diff --git a/noir/noir-repo/noir_stdlib/src/field/bn254.nr b/noir/noir-repo/noir_stdlib/src/field/bn254.nr index d70310be391..2e82d9e7c23 100644 --- a/noir/noir-repo/noir_stdlib/src/field/bn254.nr +++ b/noir/noir-repo/noir_stdlib/src/field/bn254.nr @@ -25,7 +25,7 @@ unconstrained fn decompose_unsafe(x: Field) -> (Field, Field) { fn assert_gt_limbs(a: (Field, Field), b: (Field, Field)) { let (alo, ahi) = a; let (blo, bhi) = b; - let borrow = lte_unsafe(alo, blo, 16); + let borrow = lte_unsafe_16(alo, blo); let rlo = alo - blo - 1 + (borrow as Field) * TWO_POW_128; let rhi = ahi - bhi - (borrow as Field); @@ -51,9 +51,9 @@ pub fn decompose(x: Field) -> (Field, Field) { (xlo, xhi) } -unconstrained fn lt_unsafe(x: Field, y: Field, num_bytes: u32) -> bool { - let x_bytes = x.__to_le_radix(256, num_bytes); - let y_bytes = y.__to_le_radix(256, num_bytes); +fn lt_unsafe_internal(x: Field, y: Field, num_bytes: u32) -> bool { + let x_bytes = x.to_le_radix(256, num_bytes); + let y_bytes = y.to_le_radix(256, num_bytes); let mut x_is_lt = false; let mut done = false; for i in 0..num_bytes { @@ -70,8 +70,20 @@ unconstrained fn lt_unsafe(x: Field, y: Field, num_bytes: u32) -> bool { x_is_lt } -unconstrained fn lte_unsafe(x: Field, y: Field, num_bytes: u32) -> bool { - lt_unsafe(x, y, num_bytes) | (x == y) +fn lte_unsafe_internal(x: Field, y: Field, num_bytes: u32) -> bool { + if x == y { + true + } else { + lt_unsafe_internal(x, y, num_bytes) + } +} + +unconstrained fn lt_unsafe_32(x: Field, y: Field) -> bool { + lt_unsafe_internal(x, y, 32) +} + +unconstrained fn lte_unsafe_16(x: Field, y: Field) -> bool { + lte_unsafe_internal(x, y, 16) } pub fn assert_gt(a: Field, b: Field) { @@ -90,7 +102,7 @@ pub fn assert_lt(a: Field, b: Field) { pub fn gt(a: Field, b: Field) -> bool { if a == b { false - } else if lt_unsafe(a, b, 32) { + } else if lt_unsafe_32(a, b) { assert_gt(b, a); false } else { @@ -105,7 +117,10 @@ pub fn lt(a: Field, b: Field) -> bool { mod tests { // TODO: Allow imports from "super" - use crate::field::bn254::{decompose_unsafe, decompose, lt_unsafe, assert_gt, gt, lt, TWO_POW_128, lte_unsafe, PLO, PHI}; + use crate::field::bn254::{ + decompose_unsafe, decompose, lt_unsafe_internal, assert_gt, gt, lt, TWO_POW_128, + lte_unsafe_internal, PLO, PHI + }; #[test] fn check_decompose_unsafe() { @@ -123,23 +138,23 @@ mod tests { #[test] fn check_lt_unsafe() { - assert(lt_unsafe(0, 1, 16)); - assert(lt_unsafe(0, 0x100, 16)); - assert(lt_unsafe(0x100, TWO_POW_128 - 1, 16)); - assert(!lt_unsafe(0, TWO_POW_128, 16)); + assert(lt_unsafe_internal(0, 1, 16)); + assert(lt_unsafe_internal(0, 0x100, 16)); + assert(lt_unsafe_internal(0x100, TWO_POW_128 - 1, 16)); + assert(!lt_unsafe_internal(0, TWO_POW_128, 16)); } #[test] fn check_lte_unsafe() { - assert(lte_unsafe(0, 1, 16)); - assert(lte_unsafe(0, 0x100, 16)); - assert(lte_unsafe(0x100, TWO_POW_128 - 1, 16)); - assert(!lte_unsafe(0, TWO_POW_128, 16)); - - assert(lte_unsafe(0, 0, 16)); - assert(lte_unsafe(0x100, 0x100, 16)); - assert(lte_unsafe(TWO_POW_128 - 1, TWO_POW_128 - 1, 16)); - assert(lte_unsafe(TWO_POW_128, TWO_POW_128, 16)); + assert(lte_unsafe_internal(0, 1, 16)); + assert(lte_unsafe_internal(0, 0x100, 16)); + assert(lte_unsafe_internal(0x100, TWO_POW_128 - 1, 16)); + assert(!lte_unsafe_internal(0, TWO_POW_128, 16)); + + assert(lte_unsafe_internal(0, 0, 16)); + assert(lte_unsafe_internal(0x100, 0x100, 16)); + assert(lte_unsafe_internal(TWO_POW_128 - 1, TWO_POW_128 - 1, 16)); + assert(lte_unsafe_internal(TWO_POW_128, TWO_POW_128, 16)); } #[test] From 26525764396ccfb2176e47a1016d194244b374f9 Mon Sep 17 00:00:00 2001 From: ludamad Date: Thu, 9 May 2024 09:55:22 -0400 Subject: [PATCH 09/11] fix(ci): bench list (#6282) --- .github/workflows/ci.yml | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d696c0d41bf..7a6fcbe4485 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -37,11 +37,10 @@ jobs: runs-on: ${{ inputs.username || github.actor }}-x86 outputs: e2e_list: ${{ steps.e2e_list.outputs.list }} + bench_list: ${{ steps.bench_list.outputs.list }} steps: - - { - uses: actions/checkout@v4, - with: { ref: "${{ github.event.pull_request.head.sha }}" }, - } + - uses: actions/checkout@v4 + with: { ref: "${{ github.event.pull_request.head.sha }}" } - uses: ./.github/ci-setup-action with: dockerhub_password: "${{ secrets.DOCKERHUB_PASSWORD }}" From bd2ccf0bd58f66bed0846617ac2a737f4a619262 Mon Sep 17 00:00:00 2001 From: Facundo Date: Thu, 9 May 2024 15:11:40 +0100 Subject: [PATCH 10/11] fix(avm-context): enqueueing of public from private (#6299) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes ``` e2e_token_contract burn › private › burn less than balance Simulation error: Packed values for hash 0x237f08330472d6db6fdd49901b949f2d7fbdbdc3062ef5339753f8c6bd784d15 not found in cache ``` Also fix calculation of unencrypted log length since after fixing the packing I was getting "No unencrypted logs are allowed for static calls". --- .../aztec-nr/aztec/src/context/interface.nr | 69 +++++++++++++++---- .../contracts/avm_test_contract/src/main.nr | 6 ++ .../end-to-end/src/e2e_avm_simulator.test.ts | 6 ++ .../simulator/src/avm/journal/journal.ts | 3 +- 4 files changed, 69 insertions(+), 15 deletions(-) diff --git a/noir-projects/aztec-nr/aztec/src/context/interface.nr b/noir-projects/aztec-nr/aztec/src/context/interface.nr index 7f72656252b..0ceb66a05a8 100644 --- a/noir-projects/aztec-nr/aztec/src/context/interface.nr +++ b/noir-projects/aztec-nr/aztec/src/context/interface.nr @@ -1,6 +1,6 @@ use dep::protocol_types::{abis::function_selector::FunctionSelector, address::{AztecAddress, EthAddress}, traits::Deserialize}; -use crate::hash::hash_args; +use crate::oracle::arguments; use crate::context::private_context::PrivateContext; use crate::context::public_context::PublicContext; use crate::context::avm_context::AvmContext; @@ -118,7 +118,6 @@ struct PublicCallInterface { } impl PublicCallInterface { - pub fn call(self, context: &mut PublicContext) -> T where T: Deserialize { let returns = context.call_public_function_with_packed_args( self.target_contract, @@ -232,18 +231,39 @@ impl AvmCallInterface { } pub fn enqueue(self, context: &mut PrivateContext) { - let args_hash = hash_args(self.args); - context.call_public_function_with_packed_args(self.target_contract, self.selector, args_hash, false, false) + // This packing is only here because PrivateContext's call_public* functions do not accept a slice for the args. + let args_hash = arguments::pack_arguments(self.args); + context.call_public_function_with_packed_args( + self.target_contract, + self.selector, + args_hash, + /*static=*/ false, + /*delegate=*/ false + ) } pub fn static_enqueue(self, context: &mut PrivateContext) { - let args_hash = hash_args(self.args); - context.call_public_function_with_packed_args(self.target_contract, self.selector, args_hash, true, false) + // This packing is only here because PrivateContext's call_public* functions do not accept a slice for the args. + let args_hash = arguments::pack_arguments(self.args); + context.call_public_function_with_packed_args( + self.target_contract, + self.selector, + args_hash, + /*static=*/ true, + /*delegate=*/ false + ) } pub fn delegate_enqueue(self, context: &mut PrivateContext) { - let args_hash = hash_args(self.args); - context.call_public_function_with_packed_args(self.target_contract, self.selector, args_hash, false, true) + // This packing is only here because PrivateContext's call_public* functions do not accept a slice for the args. + let args_hash = arguments::pack_arguments(self.args); + context.call_public_function_with_packed_args( + self.target_contract, + self.selector, + args_hash, + /*static=*/ false, + /*delegate=*/ true + ) } } @@ -276,17 +296,38 @@ impl AvmVoidCallInterface { } pub fn enqueue(self, context: &mut PrivateContext) { - let args_hash = hash_args(self.args); - context.call_public_function_with_packed_args(self.target_contract, self.selector, args_hash, false, false) + // This packing is only here because PrivateContext's call_public* functions do not accept a slice for the args. + let args_hash = arguments::pack_arguments(self.args); + context.call_public_function_with_packed_args( + self.target_contract, + self.selector, + args_hash, + /*static=*/ false, + /*delegate=*/ false + ) } pub fn static_enqueue(self, context: &mut PrivateContext) { - let args_hash = hash_args(self.args); - context.call_public_function_with_packed_args(self.target_contract, self.selector, args_hash, true, false) + // This packing is only here because PrivateContext's call_public* functions do not accept a slice for the args. + let args_hash = arguments::pack_arguments(self.args); + context.call_public_function_with_packed_args( + self.target_contract, + self.selector, + args_hash, + /*static=*/ true, + /*delegate=*/ false + ) } pub fn delegate_enqueue(self, context: &mut PrivateContext) { - let args_hash = hash_args(self.args); - context.call_public_function_with_packed_args(self.target_contract, self.selector, args_hash, false, true) + // This packing is only here because PrivateContext's call_public* functions do not accept a slice for the args. + let args_hash = arguments::pack_arguments(self.args); + context.call_public_function_with_packed_args( + self.target_contract, + self.selector, + args_hash, + /*static=*/ false, + /*delegate=*/ true + ) } } diff --git a/noir-projects/noir-contracts/contracts/avm_test_contract/src/main.nr b/noir-projects/noir-contracts/contracts/avm_test_contract/src/main.nr index 94d70614a13..e71861ffbef 100644 --- a/noir-projects/noir-contracts/contracts/avm_test_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/avm_test_contract/src/main.nr @@ -153,6 +153,12 @@ contract AvmTest { U128::from_integer(should_overflow) } + #[aztec(private)] + fn enqueue_public_from_private() { + AvmTest::at(context.this_address()).set_opcode_u8().static_enqueue(&mut context); + AvmTest::at(context.this_address()).set_read_storage_single(5).enqueue(&mut context); + } + /************************************************************************ * Hashing functions ************************************************************************/ diff --git a/yarn-project/end-to-end/src/e2e_avm_simulator.test.ts b/yarn-project/end-to-end/src/e2e_avm_simulator.test.ts index 56cca9370f4..4869cc90162 100644 --- a/yarn-project/end-to-end/src/e2e_avm_simulator.test.ts +++ b/yarn-project/end-to-end/src/e2e_avm_simulator.test.ts @@ -41,6 +41,12 @@ describe('e2e_avm_simulator', () => { }); }); + describe('From private', () => { + it('Should enqueue a public function correctly', async () => { + await avmContract.methods.enqueue_public_from_private().simulate(); + }); + }); + describe('Gas metering', () => { it('Tracks L2 gas usage on simulation', async () => { const request = await avmContract.methods.add_args_return(20n, 30n).create(); diff --git a/yarn-project/simulator/src/avm/journal/journal.ts b/yarn-project/simulator/src/avm/journal/journal.ts index 7bea5f1c42a..c43418d1e6d 100644 --- a/yarn-project/simulator/src/avm/journal/journal.ts +++ b/yarn-project/simulator/src/avm/journal/journal.ts @@ -119,7 +119,8 @@ export class AvmPersistableStateManager { contractStorageUpdateRequests: [], unencryptedLogsHashes: [], unencryptedLogs: [], - unencryptedLogPreimagesLength: new Fr(0), + // The length starts at 4 because it will always include the size. + unencryptedLogPreimagesLength: new Fr(4), allUnencryptedLogs: [], nestedExecutions: [], }; From 67fedf1a4a93aed9c1ee1e14a21f4b098dde995e Mon Sep 17 00:00:00 2001 From: Charlie Lye Date: Thu, 9 May 2024 15:41:43 +0100 Subject: [PATCH 11/11] feat: build-images as earthly. (#6194) * Converts our build images from Dockerfile to Earthfile. This means we now need to reference the registry image from the devcontainer. Also now means you need earthly to build the build images. * Enables docker-in-docker within our devcontainer. * ARM ci now uses earthly wrapper to pick up the env vars. * Running devcontainer more than once outside vscode will reuse existing container. * If on master we enable the pushing of inline cache. --- .devcontainer/dev/devcontainer.json | 20 +- .devcontainer/dev/docker-in-docker/NOTES.md | 16 + .devcontainer/dev/docker-in-docker/README.md | 53 ++ .../devcontainer-feature.json | 70 ++ .devcontainer/dev/docker-in-docker/install.sh | 624 ++++++++++++++++++ .github/workflows/ci-arm.yml | 4 +- CODEOWNERS | 3 +- build-images/Dockerfile | 351 ---------- build-images/Earthfile | 410 +++++++++++- build-images/Makefile | 58 -- build-images/README.md | 31 +- build-images/entrypoint.sh | 14 +- build-images/install-docker.sh | 624 ++++++++++++++++++ build-images/run.sh | 44 +- scripts/earthly-ci | 6 + 15 files changed, 1870 insertions(+), 458 deletions(-) create mode 100644 .devcontainer/dev/docker-in-docker/NOTES.md create mode 100644 .devcontainer/dev/docker-in-docker/README.md create mode 100644 .devcontainer/dev/docker-in-docker/devcontainer-feature.json create mode 100755 .devcontainer/dev/docker-in-docker/install.sh delete mode 100644 build-images/Dockerfile delete mode 100755 build-images/Makefile create mode 100755 build-images/install-docker.sh diff --git a/.devcontainer/dev/devcontainer.json b/.devcontainer/dev/devcontainer.json index 792ffdbc010..e5fb68ec02e 100644 --- a/.devcontainer/dev/devcontainer.json +++ b/.devcontainer/dev/devcontainer.json @@ -1,22 +1,10 @@ { "name": "Development", - "build": { - "dockerfile": "../../build-images/Dockerfile", - "context": "../../build-images", - "target": "devbox" + "image": "aztecprotocol/devbox:1.0", + "features": { + // Use custom fork with noble added to list of supported distros. + "./docker-in-docker": {} }, "containerUser": "aztec-dev", - // ubuntu:noble is currently not supported. - // Can possibly workaround cherry-picking from here: - // https://github.com/devcontainers/features/blob/main/src/docker-in-docker/install.sh - // - // "image": "aztecprotocol/codespace", - // "features": { - // "docker-in-docker": { - // "version": "latest", - // "moby": true, - // "dockerDashComposeVersion": "v1" - // } - // }, "mounts": ["source=devbox-home,target=/home/aztec-dev,type=volume"] } diff --git a/.devcontainer/dev/docker-in-docker/NOTES.md b/.devcontainer/dev/docker-in-docker/NOTES.md new file mode 100644 index 00000000000..b8156f8b69f --- /dev/null +++ b/.devcontainer/dev/docker-in-docker/NOTES.md @@ -0,0 +1,16 @@ +## Limitations + +This docker-in-docker Dev Container Feature is roughly based on the [official docker-in-docker wrapper script](https://github.com/moby/moby/blob/master/hack/dind) that is part of the [Moby project](https://mobyproject.org/). With this in mind: +* As the name implies, the Feature is expected to work when the host is running Docker (or the OSS Moby container engine it is built on). It may be possible to get running in other container engines, but it has not been tested with them. +* The host and the container must be running on the same chip architecture. You will not be able to use it with an emulated x86 image with Docker Desktop on an Apple Silicon Mac, like in this example: + ``` + FROM --platform=linux/amd64 mcr.microsoft.com/devcontainers/typescript-node:16 + ``` + See [Issue #219](https://github.com/devcontainers/features/issues/219) for more details. + + +## OS Support + +This Feature should work on recent versions of Debian/Ubuntu-based distributions with the `apt` package manager installed. + +`bash` is required to execute the `install.sh` script. diff --git a/.devcontainer/dev/docker-in-docker/README.md b/.devcontainer/dev/docker-in-docker/README.md new file mode 100644 index 00000000000..29e3105c60b --- /dev/null +++ b/.devcontainer/dev/docker-in-docker/README.md @@ -0,0 +1,53 @@ +# Docker (Docker-in-Docker) (docker-in-docker) + +**FORKED HERE TO SUPPORT NOBLE** + +Create child containers _inside_ a container, independent from the host's docker instance. Installs Docker extension in the container along with needed CLIs. + +## Example Usage + +```json +"features": { + "ghcr.io/devcontainers/features/docker-in-docker:2": {} +} +``` + +## Options + +| Options Id | Description | Type | Default Value | +| -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------- | ------------- | +| version | Select or enter a Docker/Moby Engine version. (Availability can vary by OS version.) | string | latest | +| moby | Install OSS Moby build instead of Docker CE | boolean | true | +| mobyBuildxVersion | Install a specific version of moby-buildx when using Moby | string | latest | +| dockerDashComposeVersion | Default version of Docker Compose (latest, v2 or none) | string | latest | +| azureDnsAutoDetection | Allow automatically setting the dockerd DNS server when the installation script detects it is running in Azure | boolean | true | +| dockerDefaultAddressPool | Define default address pools for Docker networks. e.g. base=192.168.0.0/16,size=24 | string | - | +| installDockerBuildx | Install Docker Buildx | boolean | true | +| installDockerComposeSwitch | Install Compose Switch (provided docker compose is available) which is a replacement to the Compose V1 docker-compose (python) executable. It translates the command line into Compose V2 docker compose then runs the latter. | boolean | true | + +## Customizations + +### VS Code Extensions + +- `ms-azuretools.vscode-docker` + +## Limitations + +This docker-in-docker Dev Container Feature is roughly based on the [official docker-in-docker wrapper script](https://github.com/moby/moby/blob/master/hack/dind) that is part of the [Moby project](https://mobyproject.org/). With this in mind: + +- As the name implies, the Feature is expected to work when the host is running Docker (or the OSS Moby container engine it is built on). It may be possible to get running in other container engines, but it has not been tested with them. +- The host and the container must be running on the same chip architecture. You will not be able to use it with an emulated x86 image with Docker Desktop on an Apple Silicon Mac, like in this example: + ``` + FROM --platform=linux/amd64 mcr.microsoft.com/devcontainers/typescript-node:16 + ``` + See [Issue #219](https://github.com/devcontainers/features/issues/219) for more details. + +## OS Support + +This Feature should work on recent versions of Debian/Ubuntu-based distributions with the `apt` package manager installed. + +`bash` is required to execute the `install.sh` script. + +--- + +_Note: This file was auto-generated from the [devcontainer-feature.json](https://github.com/devcontainers/features/blob/main/src/docker-in-docker/devcontainer-feature.json). Add additional notes to a `NOTES.md`._ diff --git a/.devcontainer/dev/docker-in-docker/devcontainer-feature.json b/.devcontainer/dev/docker-in-docker/devcontainer-feature.json new file mode 100644 index 00000000000..7b8b472245b --- /dev/null +++ b/.devcontainer/dev/docker-in-docker/devcontainer-feature.json @@ -0,0 +1,70 @@ +{ + "id": "docker-in-docker", + "version": "2.10.2", + "name": "Docker (Docker-in-Docker)", + "documentationURL": "https://github.com/devcontainers/features/tree/main/src/docker-in-docker", + "description": "Create child containers *inside* a container, independent from the host's docker instance. Installs Docker extension in the container along with needed CLIs.", + "options": { + "version": { + "type": "string", + "proposals": ["latest", "none", "20.10"], + "default": "latest", + "description": "Select or enter a Docker/Moby Engine version. (Availability can vary by OS version.)" + }, + "moby": { + "type": "boolean", + "default": true, + "description": "Install OSS Moby build instead of Docker CE" + }, + "mobyBuildxVersion": { + "type": "string", + "default": "latest", + "description": "Install a specific version of moby-buildx when using Moby" + }, + "dockerDashComposeVersion": { + "type": "string", + "enum": ["none", "latest", "v2"], + "default": "latest", + "description": "Default version of Docker Compose (latest, v2 or none)" + }, + "azureDnsAutoDetection": { + "type": "boolean", + "default": true, + "description": "Allow automatically setting the dockerd DNS server when the installation script detects it is running in Azure" + }, + "dockerDefaultAddressPool": { + "type": "string", + "default": "", + "proposals": [], + "description": "Define default address pools for Docker networks. e.g. base=192.168.0.0/16,size=24" + }, + "installDockerBuildx": { + "type": "boolean", + "default": true, + "description": "Install Docker Buildx" + }, + "installDockerComposeSwitch": { + "type": "boolean", + "default": true, + "description": "Install Compose Switch (provided docker compose is available) which is a replacement to the Compose V1 docker-compose (python) executable. It translates the command line into Compose V2 docker compose then runs the latter." + } + }, + "entrypoint": "/usr/local/share/docker-init.sh", + "privileged": true, + "containerEnv": { + "DOCKER_BUILDKIT": "1" + }, + "customizations": { + "vscode": { + "extensions": ["ms-azuretools.vscode-docker"] + } + }, + "mounts": [ + { + "source": "dind-var-lib-docker-${devcontainerId}", + "target": "/var/lib/docker", + "type": "volume" + } + ], + "installsAfter": ["ghcr.io/devcontainers/features/common-utils"] +} diff --git a/.devcontainer/dev/docker-in-docker/install.sh b/.devcontainer/dev/docker-in-docker/install.sh new file mode 100755 index 00000000000..4a433a02220 --- /dev/null +++ b/.devcontainer/dev/docker-in-docker/install.sh @@ -0,0 +1,624 @@ +#!/usr/bin/env bash +#------------------------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See https://go.microsoft.com/fwlink/?linkid=2090316 for license information. +#------------------------------------------------------------------------------------------------------------- +# +# Docs: https://github.com/microsoft/vscode-dev-containers/blob/main/script-library/docs/docker-in-docker.md +# Maintainer: The Dev Container spec maintainers + + +DOCKER_VERSION="${VERSION:-"latest"}" # The Docker/Moby Engine + CLI should match in version +USE_MOBY="${MOBY:-"true"}" +MOBY_BUILDX_VERSION="${MOBYBUILDXVERSION:-"latest"}" +DOCKER_DASH_COMPOSE_VERSION="${DOCKERDASHCOMPOSEVERSION:-"latest"}" #latest, v2 or none +AZURE_DNS_AUTO_DETECTION="${AZUREDNSAUTODETECTION:-"true"}" +DOCKER_DEFAULT_ADDRESS_POOL="${DOCKERDEFAULTADDRESSPOOL:-""}" +USERNAME="${USERNAME:-"${_REMOTE_USER:-"automatic"}"}" +INSTALL_DOCKER_BUILDX="${INSTALLDOCKERBUILDX:-"true"}" +INSTALL_DOCKER_COMPOSE_SWITCH="${INSTALLDOCKERCOMPOSESWITCH:-"true"}" +MICROSOFT_GPG_KEYS_URI="https://packages.microsoft.com/keys/microsoft.asc" +DOCKER_MOBY_ARCHIVE_VERSION_CODENAMES="bookworm buster bullseye bionic focal jammy noble" +DOCKER_LICENSED_ARCHIVE_VERSION_CODENAMES="bookworm buster bullseye bionic focal hirsute impish jammy noble" + +# Default: Exit on any failure. +set -e + +# Clean up +rm -rf /var/lib/apt/lists/* + +# Setup STDERR. +err() { + echo "(!) $*" >&2 +} + +if [ "$(id -u)" -ne 0 ]; then + err 'Script must be run as root. Use sudo, su, or add "USER root" to your Dockerfile before running this script.' + exit 1 +fi + +################### +# Helper Functions +# See: https://github.com/microsoft/vscode-dev-containers/blob/main/script-library/shared/utils.sh +################### + +# Determine the appropriate non-root user +if [ "${USERNAME}" = "auto" ] || [ "${USERNAME}" = "automatic" ]; then + USERNAME="" + POSSIBLE_USERS=("vscode" "node" "codespace" "$(awk -v val=1000 -F ":" '$3==val{print $1}' /etc/passwd)") + for CURRENT_USER in "${POSSIBLE_USERS[@]}"; do + if id -u ${CURRENT_USER} > /dev/null 2>&1; then + USERNAME=${CURRENT_USER} + break + fi + done + if [ "${USERNAME}" = "" ]; then + USERNAME=root + fi +elif [ "${USERNAME}" = "none" ] || ! id -u ${USERNAME} > /dev/null 2>&1; then + USERNAME=root +fi + +apt_get_update() +{ + if [ "$(find /var/lib/apt/lists/* | wc -l)" = "0" ]; then + echo "Running apt-get update..." + apt-get update -y + fi +} + +# Checks if packages are installed and installs them if not +check_packages() { + if ! dpkg -s "$@" > /dev/null 2>&1; then + apt_get_update + apt-get -y install --no-install-recommends "$@" + fi +} + +# Figure out correct version of a three part version number is not passed +find_version_from_git_tags() { + local variable_name=$1 + local requested_version=${!variable_name} + if [ "${requested_version}" = "none" ]; then return; fi + local repository=$2 + local prefix=${3:-"tags/v"} + local separator=${4:-"."} + local last_part_optional=${5:-"false"} + if [ "$(echo "${requested_version}" | grep -o "." | wc -l)" != "2" ]; then + local escaped_separator=${separator//./\\.} + local last_part + if [ "${last_part_optional}" = "true" ]; then + last_part="(${escaped_separator}[0-9]+)?" + else + last_part="${escaped_separator}[0-9]+" + fi + local regex="${prefix}\\K[0-9]+${escaped_separator}[0-9]+${last_part}$" + local version_list="$(git ls-remote --tags ${repository} | grep -oP "${regex}" | tr -d ' ' | tr "${separator}" "." | sort -rV)" + if [ "${requested_version}" = "latest" ] || [ "${requested_version}" = "current" ] || [ "${requested_version}" = "lts" ]; then + declare -g ${variable_name}="$(echo "${version_list}" | head -n 1)" + else + set +e + declare -g ${variable_name}="$(echo "${version_list}" | grep -E -m 1 "^${requested_version//./\\.}([\\.\\s]|$)")" + set -e + fi + fi + if [ -z "${!variable_name}" ] || ! echo "${version_list}" | grep "^${!variable_name//./\\.}$" > /dev/null 2>&1; then + err "Invalid ${variable_name} value: ${requested_version}\nValid values:\n${version_list}" >&2 + exit 1 + fi + echo "${variable_name}=${!variable_name}" +} + +# Use semver logic to decrement a version number then look for the closest match +find_prev_version_from_git_tags() { + local variable_name=$1 + local current_version=${!variable_name} + local repository=$2 + # Normally a "v" is used before the version number, but support alternate cases + local prefix=${3:-"tags/v"} + # Some repositories use "_" instead of "." for version number part separation, support that + local separator=${4:-"."} + # Some tools release versions that omit the last digit (e.g. go) + local last_part_optional=${5:-"false"} + # Some repositories may have tags that include a suffix (e.g. actions/node-versions) + local version_suffix_regex=$6 + # Try one break fix version number less if we get a failure. Use "set +e" since "set -e" can cause failures in valid scenarios. + set +e + major="$(echo "${current_version}" | grep -oE '^[0-9]+' || echo '')" + minor="$(echo "${current_version}" | grep -oP '^[0-9]+\.\K[0-9]+' || echo '')" + breakfix="$(echo "${current_version}" | grep -oP '^[0-9]+\.[0-9]+\.\K[0-9]+' 2>/dev/null || echo '')" + + if [ "${minor}" = "0" ] && [ "${breakfix}" = "0" ]; then + ((major=major-1)) + declare -g ${variable_name}="${major}" + # Look for latest version from previous major release + find_version_from_git_tags "${variable_name}" "${repository}" "${prefix}" "${separator}" "${last_part_optional}" + # Handle situations like Go's odd version pattern where "0" releases omit the last part + elif [ "${breakfix}" = "" ] || [ "${breakfix}" = "0" ]; then + ((minor=minor-1)) + declare -g ${variable_name}="${major}.${minor}" + # Look for latest version from previous minor release + find_version_from_git_tags "${variable_name}" "${repository}" "${prefix}" "${separator}" "${last_part_optional}" + else + ((breakfix=breakfix-1)) + if [ "${breakfix}" = "0" ] && [ "${last_part_optional}" = "true" ]; then + declare -g ${variable_name}="${major}.${minor}" + else + declare -g ${variable_name}="${major}.${minor}.${breakfix}" + fi + fi + set -e +} + +# Function to fetch the version released prior to the latest version +get_previous_version() { + local url=$1 + local repo_url=$2 + local variable_name=$3 + prev_version=${!variable_name} + + output=$(curl -s "$repo_url"); + message=$(echo "$output" | jq -r '.message') + + if [[ $message == "API rate limit exceeded"* ]]; then + echo -e "\nAn attempt to find latest version using GitHub Api Failed... \nReason: ${message}" + echo -e "\nAttempting to find latest version using GitHub tags." + find_prev_version_from_git_tags prev_version "$url" "tags/v" + declare -g ${variable_name}="${prev_version}" + else + echo -e "\nAttempting to find latest version using GitHub Api." + version=$(echo "$output" | jq -r '.tag_name') + declare -g ${variable_name}="${version#v}" + fi + echo "${variable_name}=${!variable_name}" +} + +get_github_api_repo_url() { + local url=$1 + echo "${url/https:\/\/github.com/https:\/\/api.github.com\/repos}/releases/latest" +} + +########################################### +# Start docker-in-docker installation +########################################### + +# Ensure apt is in non-interactive to avoid prompts +export DEBIAN_FRONTEND=noninteractive + + +# Source /etc/os-release to get OS info +. /etc/os-release +# Fetch host/container arch. +architecture="$(dpkg --print-architecture)" + +# Check if distro is supported +if [ "${USE_MOBY}" = "true" ]; then + if [[ "${DOCKER_MOBY_ARCHIVE_VERSION_CODENAMES}" != *"${VERSION_CODENAME}"* ]]; then + err "Unsupported distribution version '${VERSION_CODENAME}'. To resolve, either: (1) set feature option '\"moby\": false' , or (2) choose a compatible OS distribution" + err "Support distributions include: ${DOCKER_MOBY_ARCHIVE_VERSION_CODENAMES}" + exit 1 + fi + echo "Distro codename '${VERSION_CODENAME}' matched filter '${DOCKER_MOBY_ARCHIVE_VERSION_CODENAMES}'" +else + if [[ "${DOCKER_LICENSED_ARCHIVE_VERSION_CODENAMES}" != *"${VERSION_CODENAME}"* ]]; then + err "Unsupported distribution version '${VERSION_CODENAME}'. To resolve, please choose a compatible OS distribution" + err "Support distributions include: ${DOCKER_LICENSED_ARCHIVE_VERSION_CODENAMES}" + exit 1 + fi + echo "Distro codename '${VERSION_CODENAME}' matched filter '${DOCKER_LICENSED_ARCHIVE_VERSION_CODENAMES}'" +fi + +# Install dependencies +check_packages apt-transport-https curl ca-certificates pigz iptables gnupg2 dirmngr wget jq +if ! type git > /dev/null 2>&1; then + check_packages git +fi + +# Swap to legacy iptables for compatibility +if type iptables-legacy > /dev/null 2>&1; then + update-alternatives --set iptables /usr/sbin/iptables-legacy + update-alternatives --set ip6tables /usr/sbin/ip6tables-legacy +fi + + + +# Set up the necessary apt repos (either Microsoft's or Docker's) +if [ "${USE_MOBY}" = "true" ]; then + + # Name of open source engine/cli + engine_package_name="moby-engine" + cli_package_name="moby-cli" + + # Import key safely and import Microsoft apt repo + curl -sSL ${MICROSOFT_GPG_KEYS_URI} | gpg --dearmor > /usr/share/keyrings/microsoft-archive-keyring.gpg + echo "deb [arch=${architecture} signed-by=/usr/share/keyrings/microsoft-archive-keyring.gpg] https://packages.microsoft.com/repos/microsoft-${ID}-${VERSION_CODENAME}-prod ${VERSION_CODENAME} main" > /etc/apt/sources.list.d/microsoft.list +else + # Name of licensed engine/cli + engine_package_name="docker-ce" + cli_package_name="docker-ce-cli" + + # Import key safely and import Docker apt repo + curl -fsSL https://download.docker.com/linux/${ID}/gpg | gpg --dearmor > /usr/share/keyrings/docker-archive-keyring.gpg + echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/${ID} ${VERSION_CODENAME} stable" > /etc/apt/sources.list.d/docker.list +fi + +# Refresh apt lists +apt-get update + +# Soft version matching +if [ "${DOCKER_VERSION}" = "latest" ] || [ "${DOCKER_VERSION}" = "lts" ] || [ "${DOCKER_VERSION}" = "stable" ]; then + # Empty, meaning grab whatever "latest" is in apt repo + engine_version_suffix="" + cli_version_suffix="" +else + # Fetch a valid version from the apt-cache (eg: the Microsoft repo appends +azure, breakfix, etc...) + docker_version_dot_escaped="${DOCKER_VERSION//./\\.}" + docker_version_dot_plus_escaped="${docker_version_dot_escaped//+/\\+}" + # Regex needs to handle debian package version number format: https://www.systutorials.com/docs/linux/man/5-deb-version/ + docker_version_regex="^(.+:)?${docker_version_dot_plus_escaped}([\\.\\+ ~:-]|$)" + set +e # Don't exit if finding version fails - will handle gracefully + cli_version_suffix="=$(apt-cache madison ${cli_package_name} | awk -F"|" '{print $2}' | sed -e 's/^[ \t]*//' | grep -E -m 1 "${docker_version_regex}")" + engine_version_suffix="=$(apt-cache madison ${engine_package_name} | awk -F"|" '{print $2}' | sed -e 's/^[ \t]*//' | grep -E -m 1 "${docker_version_regex}")" + set -e + if [ -z "${engine_version_suffix}" ] || [ "${engine_version_suffix}" = "=" ] || [ -z "${cli_version_suffix}" ] || [ "${cli_version_suffix}" = "=" ] ; then + err "No full or partial Docker / Moby version match found for \"${DOCKER_VERSION}\" on OS ${ID} ${VERSION_CODENAME} (${architecture}). Available versions:" + apt-cache madison ${cli_package_name} | awk -F"|" '{print $2}' | grep -oP '^(.+:)?\K.+' + exit 1 + fi + echo "engine_version_suffix ${engine_version_suffix}" + echo "cli_version_suffix ${cli_version_suffix}" +fi + +# Version matching for moby-buildx +if [ "${USE_MOBY}" = "true" ]; then + if [ "${MOBY_BUILDX_VERSION}" = "latest" ]; then + # Empty, meaning grab whatever "latest" is in apt repo + buildx_version_suffix="" + else + buildx_version_dot_escaped="${MOBY_BUILDX_VERSION//./\\.}" + buildx_version_dot_plus_escaped="${buildx_version_dot_escaped//+/\\+}" + buildx_version_regex="^(.+:)?${buildx_version_dot_plus_escaped}([\\.\\+ ~:-]|$)" + set +e + buildx_version_suffix="=$(apt-cache madison moby-buildx | awk -F"|" '{print $2}' | sed -e 's/^[ \t]*//' | grep -E -m 1 "${buildx_version_regex}")" + set -e + if [ -z "${buildx_version_suffix}" ] || [ "${buildx_version_suffix}" = "=" ]; then + err "No full or partial moby-buildx version match found for \"${MOBY_BUILDX_VERSION}\" on OS ${ID} ${VERSION_CODENAME} (${architecture}). Available versions:" + apt-cache madison moby-buildx | awk -F"|" '{print $2}' | grep -oP '^(.+:)?\K.+' + exit 1 + fi + echo "buildx_version_suffix ${buildx_version_suffix}" + fi +fi + +# Install Docker / Moby CLI if not already installed +if type docker > /dev/null 2>&1 && type dockerd > /dev/null 2>&1; then + echo "Docker / Moby CLI and Engine already installed." +else + if [ "${USE_MOBY}" = "true" ]; then + # Install engine + set +e # Handle error gracefully + apt-get -y install --no-install-recommends moby-cli${cli_version_suffix} moby-buildx${buildx_version_suffix} moby-engine${engine_version_suffix} + exit_code=$? + set -e + + if [ ${exit_code} -ne 0 ]; then + err "Packages for moby not available in OS ${ID} ${VERSION_CODENAME} (${architecture}). To resolve, either: (1) set feature option '\"moby\": false' , or (2) choose a compatible OS version (eg: 'ubuntu-20.04')." + exit 1 + fi + + # Install compose + apt-get -y install --no-install-recommends moby-compose || err "Package moby-compose (Docker Compose v2) not available for OS ${ID} ${VERSION_CODENAME} (${architecture}). Skipping." + else + apt-get -y install --no-install-recommends docker-ce-cli${cli_version_suffix} docker-ce${engine_version_suffix} + # Install compose + apt-get -y install --no-install-recommends docker-compose-plugin || echo "(*) Package docker-compose-plugin (Docker Compose v2) not available for OS ${ID} ${VERSION_CODENAME} (${architecture}). Skipping." + fi +fi + +echo "Finished installing docker / moby!" + +docker_home="/usr/libexec/docker" +cli_plugins_dir="${docker_home}/cli-plugins" + +# fallback for docker-compose +fallback_compose(){ + local url=$1 + local repo_url=$(get_github_api_repo_url "$url") + echo -e "\n(!) Failed to fetch the latest artifacts for docker-compose v${compose_version}..." + get_previous_version "${url}" "${repo_url}" compose_version + echo -e "\nAttempting to install v${compose_version}" + curl -fsSL "https://github.com/docker/compose/releases/download/v${compose_version}/docker-compose-linux-${target_compose_arch}" -o ${docker_compose_path} +} + +# If 'docker-compose' command is to be included +if [ "${DOCKER_DASH_COMPOSE_VERSION}" != "none" ]; then + case "${architecture}" in + amd64) target_compose_arch=x86_64 ;; + arm64) target_compose_arch=aarch64 ;; + *) + echo "(!) Docker in docker does not support machine architecture '$architecture'. Please use an x86-64 or ARM64 machine." + exit 1 + esac + + docker_compose_path="/usr/local/bin/docker-compose" + if [ "${DOCKER_DASH_COMPOSE_VERSION}" = "v1" ]; then + err "The final Compose V1 release, version 1.29.2, was May 10, 2021. These packages haven't received any security updates since then. Use at your own risk." + INSTALL_DOCKER_COMPOSE_SWITCH="false" + + if [ "${target_compose_arch}" = "x86_64" ]; then + echo "(*) Installing docker compose v1..." + curl -fsSL "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-Linux-x86_64" -o ${docker_compose_path} + chmod +x ${docker_compose_path} + + # Download the SHA256 checksum + DOCKER_COMPOSE_SHA256="$(curl -sSL "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-Linux-x86_64.sha256" | awk '{print $1}')" + echo "${DOCKER_COMPOSE_SHA256} ${docker_compose_path}" > docker-compose.sha256sum + sha256sum -c docker-compose.sha256sum --ignore-missing + elif [ "${VERSION_CODENAME}" = "bookworm" ]; then + err "Docker compose v1 is unavailable for 'bookworm' on Arm64. Kindly switch to use v2" + exit 1 + else + # Use pip to get a version that runs on this architecture + check_packages python3-minimal python3-pip libffi-dev python3-venv + echo "(*) Installing docker compose v1 via pip..." + export PYTHONUSERBASE=/usr/local + pip3 install --disable-pip-version-check --no-cache-dir --user "Cython<3.0" pyyaml wheel docker-compose --no-build-isolation + fi + else + compose_version=${DOCKER_DASH_COMPOSE_VERSION#v} + docker_compose_url="https://github.com/docker/compose" + find_version_from_git_tags compose_version "$docker_compose_url" "tags/v" + echo "(*) Installing docker-compose ${compose_version}..." + curl -fsSL "https://github.com/docker/compose/releases/download/v${compose_version}/docker-compose-linux-${target_compose_arch}" -o ${docker_compose_path} || { + if [[ $DOCKER_DASH_COMPOSE_VERSION == "latest" ]]; then + fallback_compose "$docker_compose_url" + else + echo -e "Error: Failed to install docker-compose v${compose_version}" + fi + } + + chmod +x ${docker_compose_path} + + # Download the SHA256 checksum + DOCKER_COMPOSE_SHA256="$(curl -sSL "https://github.com/docker/compose/releases/download/v${compose_version}/docker-compose-linux-${target_compose_arch}.sha256" | awk '{print $1}')" + echo "${DOCKER_COMPOSE_SHA256} ${docker_compose_path}" > docker-compose.sha256sum + sha256sum -c docker-compose.sha256sum --ignore-missing + + mkdir -p ${cli_plugins_dir} + cp ${docker_compose_path} ${cli_plugins_dir} + fi +fi + +# fallback method for compose-switch +fallback_compose-switch() { + local url=$1 + local repo_url=$(get_github_api_repo_url "$url") + echo -e "\n(!) Failed to fetch the latest artifacts for compose-switch v${compose_switch_version}..." + get_previous_version "$url" "$repo_url" compose_switch_version + echo -e "\nAttempting to install v${compose_switch_version}" + curl -fsSL "https://github.com/docker/compose-switch/releases/download/v${compose_switch_version}/docker-compose-linux-${architecture}" -o /usr/local/bin/compose-switch +} + +# Install docker-compose switch if not already installed - https://github.com/docker/compose-switch#manual-installation +if [ "${INSTALL_DOCKER_COMPOSE_SWITCH}" = "true" ] && ! type compose-switch > /dev/null 2>&1; then + if type docker-compose > /dev/null 2>&1; then + echo "(*) Installing compose-switch..." + current_compose_path="$(which docker-compose)" + target_compose_path="$(dirname "${current_compose_path}")/docker-compose-v1" + compose_switch_version="latest" + compose_switch_url="https://github.com/docker/compose-switch" + find_version_from_git_tags compose_switch_version "$compose_switch_url" + curl -fsSL "https://github.com/docker/compose-switch/releases/download/v${compose_switch_version}/docker-compose-linux-${architecture}" -o /usr/local/bin/compose-switch || fallback_compose-switch "$compose_switch_url" + chmod +x /usr/local/bin/compose-switch + # TODO: Verify checksum once available: https://github.com/docker/compose-switch/issues/11 + # Setup v1 CLI as alternative in addition to compose-switch (which maps to v2) + mv "${current_compose_path}" "${target_compose_path}" + update-alternatives --install ${docker_compose_path} docker-compose /usr/local/bin/compose-switch 99 + update-alternatives --install ${docker_compose_path} docker-compose "${target_compose_path}" 1 + else + err "Skipping installation of compose-switch as docker compose is unavailable..." + fi +fi + +# If init file already exists, exit +if [ -f "/usr/local/share/docker-init.sh" ]; then + echo "/usr/local/share/docker-init.sh already exists, so exiting." + # Clean up + rm -rf /var/lib/apt/lists/* + exit 0 +fi +echo "docker-init doesn't exist, adding..." + +if ! cat /etc/group | grep -e "^docker:" > /dev/null 2>&1; then + groupadd -r docker +fi + +usermod -aG docker ${USERNAME} + +# fallback for docker/buildx +fallback_buildx() { + local url=$1 + local repo_url=$(get_github_api_repo_url "$url") + echo -e "\n(!) Failed to fetch the latest artifacts for docker buildx v${buildx_version}..." + get_previous_version "$url" "$repo_url" buildx_version + buildx_file_name="buildx-v${buildx_version}.linux-${architecture}" + echo -e "\nAttempting to install v${buildx_version}" + wget https://github.com/docker/buildx/releases/download/v${buildx_version}/${buildx_file_name} +} + +if [ "${INSTALL_DOCKER_BUILDX}" = "true" ]; then + buildx_version="latest" + docker_buildx_url="https://github.com/docker/buildx" + find_version_from_git_tags buildx_version "$docker_buildx_url" "refs/tags/v" + echo "(*) Installing buildx ${buildx_version}..." + buildx_file_name="buildx-v${buildx_version}.linux-${architecture}" + + cd /tmp + wget https://github.com/docker/buildx/releases/download/v${buildx_version}/${buildx_file_name} || fallback_buildx "$docker_buildx_url" + + docker_home="/usr/libexec/docker" + cli_plugins_dir="${docker_home}/cli-plugins" + + mkdir -p ${cli_plugins_dir} + mv ${buildx_file_name} ${cli_plugins_dir}/docker-buildx + chmod +x ${cli_plugins_dir}/docker-buildx + + chown -R "${USERNAME}:docker" "${docker_home}" + chmod -R g+r+w "${docker_home}" + find "${docker_home}" -type d -print0 | xargs -n 1 -0 chmod g+s +fi + +tee /usr/local/share/docker-init.sh > /dev/null \ +<< EOF +#!/bin/sh +#------------------------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See https://go.microsoft.com/fwlink/?linkid=2090316 for license information. +#------------------------------------------------------------------------------------------------------------- + +set -e + +AZURE_DNS_AUTO_DETECTION=${AZURE_DNS_AUTO_DETECTION} +DOCKER_DEFAULT_ADDRESS_POOL=${DOCKER_DEFAULT_ADDRESS_POOL} +EOF + +tee -a /usr/local/share/docker-init.sh > /dev/null \ +<< 'EOF' +dockerd_start="AZURE_DNS_AUTO_DETECTION=${AZURE_DNS_AUTO_DETECTION} DOCKER_DEFAULT_ADDRESS_POOL=${DOCKER_DEFAULT_ADDRESS_POOL} $(cat << 'INNEREOF' + # explicitly remove dockerd and containerd PID file to ensure that it can start properly if it was stopped uncleanly + find /run /var/run -iname 'docker*.pid' -delete || : + find /run /var/run -iname 'container*.pid' -delete || : + + # -- Start: dind wrapper script -- + # Maintained: https://github.com/moby/moby/blob/master/hack/dind + + export container=docker + + if [ -d /sys/kernel/security ] && ! mountpoint -q /sys/kernel/security; then + mount -t securityfs none /sys/kernel/security || { + echo >&2 'Could not mount /sys/kernel/security.' + echo >&2 'AppArmor detection and --privileged mode might break.' + } + fi + + # Mount /tmp (conditionally) + if ! mountpoint -q /tmp; then + mount -t tmpfs none /tmp + fi + + set_cgroup_nesting() + { + # cgroup v2: enable nesting + if [ -f /sys/fs/cgroup/cgroup.controllers ]; then + # move the processes from the root group to the /init group, + # otherwise writing subtree_control fails with EBUSY. + # An error during moving non-existent process (i.e., "cat") is ignored. + mkdir -p /sys/fs/cgroup/init + xargs -rn1 < /sys/fs/cgroup/cgroup.procs > /sys/fs/cgroup/init/cgroup.procs || : + # enable controllers + sed -e 's/ / +/g' -e 's/^/+/' < /sys/fs/cgroup/cgroup.controllers \ + > /sys/fs/cgroup/cgroup.subtree_control + fi + } + + # Set cgroup nesting, retrying if necessary + retry_cgroup_nesting=0 + + until [ "${retry_cgroup_nesting}" -eq "5" ]; + do + set +e + set_cgroup_nesting + + if [ $? -ne 0 ]; then + echo "(*) cgroup v2: Failed to enable nesting, retrying..." + else + break + fi + + retry_cgroup_nesting=`expr $retry_cgroup_nesting + 1` + set -e + done + + # -- End: dind wrapper script -- + + # Handle DNS + set +e + cat /etc/resolv.conf | grep -i 'internal.cloudapp.net' > /dev/null 2>&1 + if [ $? -eq 0 ] && [ "${AZURE_DNS_AUTO_DETECTION}" = "true" ] + then + echo "Setting dockerd Azure DNS." + CUSTOMDNS="--dns 168.63.129.16" + else + echo "Not setting dockerd DNS manually." + CUSTOMDNS="" + fi + set -e + + if [ -z "$DOCKER_DEFAULT_ADDRESS_POOL" ] + then + DEFAULT_ADDRESS_POOL="" + else + DEFAULT_ADDRESS_POOL="--default-address-pool $DOCKER_DEFAULT_ADDRESS_POOL" + fi + + # Start docker/moby engine + ( dockerd $CUSTOMDNS $DEFAULT_ADDRESS_POOL > /tmp/dockerd.log 2>&1 ) & +INNEREOF +)" + +sudo_if() { + COMMAND="$*" + + if [ "$(id -u)" -ne 0 ]; then + sudo $COMMAND + else + $COMMAND + fi +} + +retry_docker_start_count=0 +docker_ok="false" + +until [ "${docker_ok}" = "true" ] || [ "${retry_docker_start_count}" -eq "5" ]; +do + # Start using sudo if not invoked as root + if [ "$(id -u)" -ne 0 ]; then + sudo /bin/sh -c "${dockerd_start}" + else + eval "${dockerd_start}" + fi + + retry_count=0 + until [ "${docker_ok}" = "true" ] || [ "${retry_count}" -eq "5" ]; + do + sleep 1s + set +e + docker info > /dev/null 2>&1 && docker_ok="true" + set -e + + retry_count=`expr $retry_count + 1` + done + + if [ "${docker_ok}" != "true" ] && [ "${retry_docker_start_count}" != "4" ]; then + echo "(*) Failed to start docker, retrying..." + set +e + sudo_if pkill dockerd + sudo_if pkill containerd + set -e + fi + + retry_docker_start_count=`expr $retry_docker_start_count + 1` +done + +# Execute whatever commands were passed in (if any). This allows us +# to set this script to ENTRYPOINT while still executing the default CMD. +exec "$@" +EOF + +chmod +x /usr/local/share/docker-init.sh +chown ${USERNAME}:root /usr/local/share/docker-init.sh + +# Clean up +rm -rf /var/lib/apt/lists/* + +echo 'docker-in-docker-debian script has completed!' diff --git a/.github/workflows/ci-arm.yml b/.github/workflows/ci-arm.yml index 3317870ec5f..c750b142724 100644 --- a/.github/workflows/ci-arm.yml +++ b/.github/workflows/ci-arm.yml @@ -44,7 +44,7 @@ jobs: # prepare images locally, tagged by commit hash - name: "Build E2E Image" timeout-minutes: 40 - run: earthly ./yarn-project+export-e2e-test-images + run: earthly-ci ./yarn-project+export-e2e-test-images # all the end-to-end integration tests for aztec e2e: @@ -62,7 +62,7 @@ jobs: - name: Test working-directory: ./yarn-project/end-to-end/ timeout-minutes: 15 - run: earthly -P --no-output +uniswap-trade-on-l1-from-l2 + run: earthly-ci -P --no-output +uniswap-trade-on-l1-from-l2 notify: needs: [e2e] diff --git a/CODEOWNERS b/CODEOWNERS index cdd57834a49..37be432af89 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -1,5 +1,4 @@ -/build-system/ @charlielye -/build_manifest.yml @charlielye +/build-images/ @charlielye # Notify the AVM team of any changes to public oracle. /yarn-project/simulator/src/public/public_execution_context.ts @Maddiaa0 @fcarreiro @dbanks12 diff --git a/build-images/Dockerfile b/build-images/Dockerfile deleted file mode 100644 index 893c93fe4c0..00000000000 --- a/build-images/Dockerfile +++ /dev/null @@ -1,351 +0,0 @@ -######################################################################################################################## -# Build wasi-sdk. -FROM ubuntu:noble AS wasi-sdk-build -RUN apt update && apt install -y \ - clang \ - cmake \ - ninja-build \ - git \ - cargo -RUN git clone --depth 1 --recursive --branch wasi-sdk-22 \ - https://github.com/WebAssembly/wasi-sdk.git -RUN mkdir -p /wasi-sdk/build/install/opt/wasi-sdk -WORKDIR /wasi-sdk -ENV MAKEFLAGS="-j$(nproc)" -RUN make build/llvm.BUILT -RUN make build/wasi-libc.BUILT -RUN make build/compiler-rt.BUILT -RUN make build/libcxx.BUILT -RUN make build/config.BUILT -RUN make build/version.BUILT -RUN mv build/install/opt/wasi-sdk /opt/wasi-sdk -FROM ubuntu:noble AS wasi-sdk -COPY --from=wasi-sdk-build /opt/wasi-sdk /opt/wasi-sdk - -######################################################################################################################## -# Build osxcross. -FROM ubuntu:noble AS osxcross-build -RUN export DEBIAN_FRONTEND="noninteractive" \ - && apt-get update \ - && apt-get install --no-install-recommends -y \ - bash \ - binutils-multiarch-dev \ - build-essential \ - ca-certificates \ - clang \ - git \ - libbz2-dev \ - libmpc-dev \ - libmpfr-dev \ - libgmp-dev \ - liblzma-dev \ - libpsi3-dev \ - libssl-dev \ - libxml2-dev \ - libz-dev \ - lzma-dev \ - make \ - patch \ - python3 \ - uuid-dev \ - wget \ - xz-utils \ - zlib1g-dev \ - cmake \ - curl \ - && apt-get -y autoremove \ - && apt-get clean \ - && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* -WORKDIR /usr/src/osxcross -ARG OSX_CROSS_COMMIT="ff8d100f3f026b4ffbe4ce96d8aac4ce06f1278b" -RUN git clone https://github.com/tpoechtrager/osxcross.git . && git reset --hard $OSX_CROSS_COMMIT -ARG OSX_SDK="MacOSX14.0.sdk" -ARG OSX_SDK_URL="https://github.com/joseluisq/macosx-sdks/releases/download/14.0/${OSX_SDK}.tar.xz" -RUN curl -sSL "$OSX_SDK_URL" -o "./tarballs/$OSX_SDK.tar.xz" \ - && OSX_VERSION_MIN=14.0 UNATTENDED=1 ENABLE_COMPILER_RT_INSTALL=1 TARGET_DIR=/opt/osxcross ./build.sh \ - && rm -rf ./tarballs/$OSX_SDK.tar.xz /opt/osxcross/SDK/$OSX_SDK -FROM scratch AS osxcross -COPY --from=osxcross-build /opt/osxcross /opt/osxcross - -######################################################################################################################## -# Build foundry. -FROM ubuntu:noble AS foundry-build -RUN apt update && apt install -y git cargo -ARG TAG -RUN ulimit -n 65535 && \ - git clone --depth 1 --branch nightly-$TAG \ - https://github.com/foundry-rs/foundry.git && \ - cd foundry && cargo build --profile local && \ - mkdir -p /opt/foundry/bin && \ - for t in forge cast anvil chisel; do \ - mv ./target/local/$t /opt/foundry/bin/$t; \ - strip /opt/foundry/bin/$t; \ - done -FROM ubuntu:noble AS foundry -COPY --from=foundry-build /opt/foundry /opt/foundry -ENV PATH="/opt/foundry/bin:$PATH" - -######################################################################################################################## -# This image contains *just* what's needed to perform a full build of the aztec project. -# It acts as the base image for all CI builds, and we build on it to produce a developer box. -FROM ubuntu:noble as build -RUN apt update && \ - apt install -y \ - # Utils - curl \ - git \ - curl \ - wget \ - jq \ - gawk \ - unzip \ - netcat-openbsd \ - parallel \ - # C++ (clang=18, which we will move to. 16 is for current build.) - build-essential \ - cmake \ - ninja-build \ - clang \ - clang-16 \ - clang-format-16 \ - libc++-dev \ - libomp-dev \ - doxygen \ - # Node (18.19.1) - nodejs \ - npm \ - # Python (clang bindings for wasm bindgen.) - python3 \ - python3-clang \ - && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* - -# Install wasi-sdk. -COPY --from=aztecprotocol/wasi-sdk:22.0 /opt/wasi-sdk /opt/wasi-sdk - -# Install osxcross. Requires developer to mount SDK from their mac host. -COPY --from=aztecprotocol/osxcross:14.0 /opt/osxcross /opt/osxcross -ENV PATH="/opt/osxcross/bin:$PATH" -ENV LD_LIBRARY_PATH="/opt/osxcross/lib:$LD_LIBRARY_PATH" - -# Install foundry. -COPY --from=aztecprotocol/foundry:de33b6af53005037b463318d2628b5cfcaf39916 /opt/foundry /opt/foundry -ENV PATH="/opt/foundry/bin:$PATH" - -# Install rust and cross-compilers. Noir specifically uses 1.74.1. -# We add everyone write ownership so downstream boxes can write. -ENV RUSTUP_HOME=/opt/rust/rustup \ - CARGO_HOME=/opt/rust/cargo \ - PATH="/opt/rust/cargo/bin:$PATH" -RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain 1.74.1 && \ - rustup target add wasm32-unknown-unknown wasm32-wasi aarch64-apple-darwin && \ - chmod -R a+w /opt/rust - -# Install yq -RUN curl -sL https://github.com/mikefarah/yq/releases/download/v4.42.1/yq_linux_$(dpkg --print-architecture) \ - -o /usr/local/bin/yq && chmod +x /usr/local/bin/yq - -# Install yarn -RUN npm install --global yarn - -# Install solhint -RUN npm install --global solhint - -######################################################################################################################## -# We want to produce downstream images: codespace, devbox and sysbox. This image is the base image for each. -# It contains a suite of tools that developers might use to develop aztec. -FROM build as basebox -RUN yes | unminimize - -# Install stuff devs need. -RUN apt update && \ - apt install -y \ - zsh \ - fzf \ - libfuse2 \ - iproute2 \ - iputils-ping \ - telnet \ - lsb-release \ - tmux \ - vim \ - software-properties-common \ - gnupg \ - htop \ - cgroup-tools \ - neovim \ - sudo \ - clangd-16 \ - man \ - python3-blessed \ - && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* - -# Install earthly. -RUN wget https://github.com/earthly/earthly/releases/latest/download/earthly-linux-$(dpkg --print-architecture) -O /usr/local/bin/earthly && \ - chmod +x /usr/local/bin/earthly - -# Install gh (github cli). -RUN mkdir -p -m 755 /etc/apt/keyrings && wget -qO- https://cli.github.com/packages/githubcli-archive-keyring.gpg > /etc/apt/keyrings/githubcli-archive-keyring.gpg \ - && chmod go+r /etc/apt/keyrings/githubcli-archive-keyring.gpg \ - && echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" | tee /etc/apt/sources.list.d/github-cli.list > /dev/null \ - && apt update \ - && apt install gh -y - -# Install gt (graphite). -RUN npm install -g @withgraphite/graphite-cli@stable - -# Install aws cli. -RUN curl "https://awscli.amazonaws.com/awscli-exe-linux-$(uname -m).zip" -o "awscliv2.zip" && \ - unzip awscliv2.zip && \ - ./aws/install --bin-dir /usr/local/bin --install-dir /usr/local/aws-cli --update && \ - rm -rf aws awscliv2.zip - -# Install terraform. -RUN curl -fsSL https://releases.hashicorp.com/terraform/1.7.5/terraform_1.7.5_linux_$(dpkg --print-architecture).zip -o terraform.zip \ - && unzip terraform.zip -d /usr/local/bin \ - && chmod +x /usr/local/bin/terraform \ - && rm terraform.zip - -# fzf seems to not install this file for some reason. -COPY ./key-bindings.zsh /usr/share/doc/fzf/examples/key-bindings.zsh - -# Sets LANG explicitly. Ensures tmux shows unicode symbols. -# Sets RUSTUP_HOME. -# Adds foundry and cargo bin dirs to PATH. -COPY environment /etc/environment - -# Cargo home and bin path should be set within users home dir at login. -RUN echo 'export CARGO_HOME="$HOME/.cargo"' >> /etc/zsh/zshenv -RUN echo 'export PATH="$HOME/.cargo/bin:$PATH"' >> /etc/zsh/zshenv - -# sudo group can sudo without password. -RUN echo '%sudo ALL=(ALL) NOPASSWD: ALL' >> /etc/sudoers - -######################################################################################################################## -# This devbox container can be used to provide a full development environment. -# -# It can be used as a dev container: -# - Configuration in .devcontainer/devcontainer.json. -# - To run locally install "Dev Containers" plugin in vscode. -# - To run in GitHub codespaces, visit the repo in github, press '.', and open the terminal. -# -# It can be used independently: -# - The user should use the ./run.sh script to launch. -# - A persistent volume will be mounted to /home/aztec-dev. -# - It provides docker via the hosts docker instance, mounted at /var/lib/docker.sock. -# - It uses an entrypoint script at runtime to perform uid/gid alignment with the host and drop into user account. -FROM basebox as devbox - -# Install docker client. Will use mounted host docker socket. -RUN curl -fsSL https://download.docker.com/linux/ubuntu/gpg | gpg --batch --yes --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg \ - && echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" \ - | tee /etc/apt/sources.list.d/docker.list > /dev/null \ - && apt-get update && apt-get install -y docker-ce-cli -ADD https://raw.githubusercontent.com/docker/docker-ce/master/components/cli/contrib/completion/bash/docker /etc/bash_completion.d/docker.sh - -RUN apt install -y gosu -ENV TERM=xterm-256color -# Detect if the host machine is Mac, if so set an env var, and disable prompts vcs info for performance. -RUN <> /etc/zsh/zshrc -EOF -# Create the user we'll run as and become the user. -RUN useradd --shell /bin/zsh -G sudo -m aztec-dev -USER aztec-dev -WORKDIR /home/aztec-dev -# Add dotfiles. -COPY --chown=aztec-dev:aztec-dev home . -# The .npmrc config is set to install global bins here, update PATH. -ENV PATH=/home/aztec-dev/.npm-global/bin:$PATH -# Need to ensure correct permissions, under some conditions these would otherwise be created by root. -RUN mkdir .vscode-server .npm-global .ssh -# Switch back to root. Gives option for root runtime adjustments before becoming aztec-dev. -USER root -# Use as entrypoint when running in an environment that requires uid/gid alignment (e.g. vanilla linux docker). -COPY ./entrypoint.sh /entrypoint.sh -ENTRYPOINT ["/entrypoint.sh"] -CMD ["/bin/zsh"] - -######################################################################################################################## -# This sysbox container can be used to provide a full development environment. -# It's more advanced than devbox in that it uses nestybox's sysbox container runtime to provide more of a vm experience. -# It's used primarily by internal aztec developers who have sysboxes running on a powerful underlying mainframe. -# It provides better isolation and security guarantees than a plain devbox. -FROM basebox AS sysbox - -###################### START OF STOCK NESTYBOX SYSTEMD CONTAINER ############################### -# -# Systemd installation -# -RUN apt-get update && \ - apt-get install -y --no-install-recommends \ - systemd \ - systemd-sysv \ - libsystemd0 \ - ca-certificates \ - dbus \ - iptables \ - iproute2 \ - kmod \ - locales \ - sudo \ - udev && \ - \ - # Prevents journald from reading kernel messages from /dev/kmsg - echo "ReadKMsg=no" >> /etc/systemd/journald.conf && \ - \ - # Housekeeping - apt-get clean -y && \ - rm -rf \ - /var/cache/debconf/* \ - /var/lib/apt/lists/* \ - /var/log/* \ - /tmp/* \ - /var/tmp/* \ - /usr/share/local/* && \ - \ - # Create default 'ubuntu/ubuntu' user - echo "ubuntu:ubuntu" | chpasswd && adduser ubuntu sudo - -# Disable systemd services/units that are unnecessary within a container. -RUN systemctl mask systemd-udevd.service \ - systemd-udevd-kernel.socket \ - systemd-udevd-control.socket \ - systemd-modules-load.service \ - sys-kernel-config.mount \ - sys-kernel-debug.mount \ - sys-kernel-tracing.mount \ - e2scrub_reap.service - -# Make use of stopsignal (instead of sigterm) to stop systemd containers. -STOPSIGNAL SIGRTMIN+3 - -# Set systemd as entrypoint. -ENTRYPOINT [ "/sbin/init", "--log-level=err" ] - -###################### END OF STOCK NESTYBOX SYSTEMD CONTAINER ############################### - -# Install docker. -RUN curl -fsSL https://get.docker.com -o get-docker.sh && sh get-docker.sh \ - # Add user "ubuntu" to the Docker group - && usermod -a -G docker ubuntu -ADD https://raw.githubusercontent.com/docker/docker-ce/master/components/cli/contrib/completion/bash/docker /etc/bash_completion.d/docker.sh - -# Install sshd. -RUN apt install --no-install-recommends -y openssh-server \ - && rm -rf /var/lib/apt/lists/* \ - && mkdir /home/ubuntu/.ssh \ - && chown ubuntu:ubuntu /home/ubuntu/.ssh \ - && echo 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDagCvr/+CA1jmFaJf+e9+Kw6iwfhvaKOpfbGEl5zLgB+rum5L4Kga6Jow1gLQeMnAHfqc2IgpsU4t04c8PYApAt8AWNDL+KxMiFytfjKfJ2DZJA73CYkFnkfnMtU+ki+JG9dAHd6m7ShtCSzE5n6EDO2yWCVWQfqE3dcnpwrymSWkJYrbxzeOixiNZ4f1nD9ddvFvTWGB4l+et5SWgeIaYgJYDqTI2teRt9ytJiDGrCWXs9olHsCZOL6TEJPUQmNekwBkjMAZ4TmbBMjwbUlIxOpW2UxzlONcNn7IlRcGQg0Gdbkpo/zOlCNXsvacvnphDk5vKKaQj+aQiG916LU5P charlie@aztecprotocol.com' >> /home/ubuntu/.ssh/authorized_keys \ - && echo 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDb5OVc+9S9nXx3/34F7eLVXjoPgQ3YHSdlfhTb8WflAGmpKJTLxtAYngtDBvhKofH5HrjPPkBWxOHP9KOTo0jxUQSr0suMpggLLOHuIrCszJKXIVi7whnQ4p2RHyzyS2ANwmpxWZmYxfgamzYst9JIvQYJgAPjTFweKBsG/Lc03knJ/qgz9BHqDSZHweMTnhv1dJNhZRKy1Lxyl/CjXKF374i8qbzVWJMeDgLEH6C84vCeaH89KMmM9J0+T31uEqxzIhZxNmRz9v+x6cQAVJtGi9OIveGT9qUQwKXZsk6/zorzxV+NiIvTWHxIn9epX/FUjgUmb/jFvpbEjDkbIngj adomurad@localhost.localdomain' >> /home/ubuntu/.ssh/authorized_keys \ - && echo 'ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFKlUeOh9DyAL85NJ10LE+nyfi8oYm+CwxQ9JMaB6H+t root@mainframe' >> /home/ubuntu/.ssh/authorized_keys \ - && chown ubuntu:ubuntu /home/ubuntu/.ssh/authorized_keys - -# Install google authenticator for setting up 2fa. -RUN apt update && apt install -y libpam-google-authenticator - -EXPOSE 22 diff --git a/build-images/Earthfile b/build-images/Earthfile index f546ee73556..7bdc6934d84 100644 --- a/build-images/Earthfile +++ b/build-images/Earthfile @@ -1,4 +1,412 @@ VERSION 0.8 +base-build: + FROM ubuntu:noble + RUN export DEBIAN_FRONTEND="noninteractive" \ + && apt update && apt install --no-install-recommends -y \ + build-essential \ + ca-certificates \ + bash \ + clang \ + cmake \ + make \ + ninja-build \ + git \ + cargo \ + curl \ + python3 \ + wget \ + && apt-get -y autoremove \ + && apt-get clean \ + && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* + ARG TARGETARCH + SAVE IMAGE --push aztecprotocol/cache:base-build-1.0-$TARGETARCH + +######################################################################################################################## +# Build wasi-sdk. +wasi-sdk: + FROM +base-build + RUN git clone --depth 1 --recursive --branch wasi-sdk-22 https://github.com/WebAssembly/wasi-sdk.git \ + && mkdir -p /wasi-sdk/build/install/opt/wasi-sdk \ + && cd /wasi-sdk \ + && export MAKEFLAGS="-j$(nproc)" \ + && make build/llvm.BUILT \ + && make build/wasi-libc.BUILT \ + && make build/compiler-rt.BUILT \ + && make build/libcxx.BUILT \ + && make build/config.BUILT \ + && make build/version.BUILT \ + && mv build/install/opt/wasi-sdk /opt/wasi-sdk \ + && cd / && rm -rf /wasi-sdk + SAVE ARTIFACT /opt/wasi-sdk /opt/wasi-sdk + ARG TARGETARCH + SAVE IMAGE --push aztecprotocol/cache:wasi-sdk-22.0-$TARGETARCH + +######################################################################################################################## +# Build osxcross. +osxcross: + FROM +base-build + RUN apt update && apt-get install --no-install-recommends -y \ + binutils-multiarch-dev \ + libbz2-dev \ + libmpc-dev \ + libmpfr-dev \ + libgmp-dev \ + liblzma-dev \ + libpsi3-dev \ + libssl-dev \ + libxml2-dev \ + libz-dev \ + lzma-dev \ + patch \ + uuid-dev \ + xz-utils \ + zlib1g-dev \ + && apt-get -y autoremove \ + && apt-get clean \ + && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* + RUN git clone --depth=1 https://github.com/tpoechtrager/osxcross.git \ + && cd /osxcross \ + && git reset --hard ff8d100f3f026b4ffbe4ce96d8aac4ce06f1278b \ + && export OSX_SDK="MacOSX14.0.sdk" \ + && export OSX_SDK_URL="https://github.com/joseluisq/macosx-sdks/releases/download/14.0/${OSX_SDK}.tar.xz" \ + && curl -sSL "$OSX_SDK_URL" -o "./tarballs/$OSX_SDK.tar.xz" \ + && OSX_VERSION_MIN=14.0 UNATTENDED=1 ENABLE_COMPILER_RT_INSTALL=1 TARGET_DIR=/opt/osxcross ./build.sh \ + && rm -rf /osxcross /opt/osxcross/SDK/$OSX_SDK + SAVE ARTIFACT /opt/osxcross /opt/osxcross + ARG TARGETARCH + SAVE IMAGE --push aztecprotocol/cache:osxcross-14.0-$TARGETARCH + +######################################################################################################################## +# Build foundry. +foundry-build: + LET FOUNDRY_TAG = de33b6af53005037b463318d2628b5cfcaf39916 + FROM +base-build + RUN ulimit -n 65535 \ + && git clone --depth 1 --branch nightly-$FOUNDRY_TAG https://github.com/foundry-rs/foundry.git \ + && cd foundry \ + && cargo build --profile local \ + && mkdir -p /opt/foundry/bin \ + && for t in forge cast anvil chisel; do \ + mv ./target/local/$t /opt/foundry/bin/$t; \ + strip /opt/foundry/bin/$t; \ + done \ + && rm -rf /foundry + SAVE ARTIFACT /opt/foundry /opt/foundry + ARG TARGETARCH + SAVE IMAGE --push aztecprotocol/cache:foundry-build-$FOUNDRY_TAG-$TARGETARCH + +foundry: + BUILD +foundry-build + LET FOUNDRY_TAG = de33b6af53005037b463318d2628b5cfcaf39916 + ARG TARGETARCH + FROM ubuntu:noble + COPY +foundry-build/opt/foundry /opt/foundry + ENV PATH="/opt/foundry/bin:$PATH" + SAVE IMAGE --push aztecprotocol/foundry:$FOUNDRY_TAG-$TARGETARCH + +######################################################################################################################## +# This image contains *just* what's needed to perform a full build of the aztec project. +# It acts as the base image for all CI builds, and we build on it to produce a developer box. build: - FROM aztecprotocol/build:1.0 \ No newline at end of file + BUILD +wasi-sdk + BUILD +osxcross + BUILD +foundry + FROM +base-build + RUN apt update && \ + apt install -y \ + # Utils + curl \ + git \ + curl \ + wget \ + jq \ + gawk \ + unzip \ + netcat-openbsd \ + parallel \ + # C++ (clang=18, which we will move to. 16 is for current build.) + build-essential \ + cmake \ + ninja-build \ + clang \ + clang-16 \ + clang-format-16 \ + libc++-dev \ + libomp-dev \ + doxygen \ + # Node (18.19.1) + nodejs \ + npm \ + # Python (clang bindings for wasm bindgen.) + python3 \ + python3-clang \ + && apt-get -y autoremove \ + && apt-get clean \ + && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* + + # Install wasi-sdk. + COPY +wasi-sdk/opt/wasi-sdk /opt/wasi-sdk + + # Install osxcross. Requires developer to mount SDK from their mac host. + COPY +osxcross/opt/osxcross /opt/osxcross + ENV PATH="/opt/osxcross/bin:$PATH" + ENV LD_LIBRARY_PATH="/opt/osxcross/lib:$LD_LIBRARY_PATH" + + # Install foundry. + COPY +foundry-build/opt/foundry /opt/foundry + ENV PATH="/opt/foundry/bin:$PATH" + + # Install rust and cross-compilers. Noir specifically uses 1.74.1. + # We remove base-build's rust first. + # We give everyone write ownership so downstream boxes can write. + ENV RUSTUP_HOME=/opt/rust/rustup + ENV CARGO_HOME=/opt/rust/cargo + ENV PATH="/opt/rust/cargo/bin:$PATH" + RUN apt remove -y cargo rustc + RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain 1.74.1 && \ + rustup target add wasm32-unknown-unknown wasm32-wasi aarch64-apple-darwin && \ + chmod -R a+w /opt/rust + + # Install yarn + RUN npm install --global yarn + + # Install solhint + RUN npm install --global solhint + + # Install aws cli. + RUN curl "https://awscli.amazonaws.com/awscli-exe-linux-$(uname -m).zip" -o "awscliv2.zip" && \ + unzip awscliv2.zip && \ + ./aws/install --bin-dir /usr/local/bin --install-dir /usr/local/aws-cli --update && \ + rm -rf aws awscliv2.zip + + # Install terraform. + RUN curl -fsSL https://releases.hashicorp.com/terraform/1.7.5/terraform_1.7.5_linux_$(dpkg --print-architecture).zip -o terraform.zip \ + && unzip terraform.zip -d /usr/local/bin \ + && chmod +x /usr/local/bin/terraform \ + && rm terraform.zip + + ARG TARGETARCH + SAVE IMAGE --push aztecprotocol/build:1.0-$TARGETARCH + +######################################################################################################################## +# We want to produce downstream images: devbox and sysbox. This image is the base image for each. +# It contains a suite of tools that developers might use to develop aztec. +basebox: + BUILD +build + FROM +build + RUN yes | unminimize + + # Install stuff devs need. + RUN apt update && \ + apt install -y \ + zsh \ + fzf \ + libfuse2 \ + iproute2 \ + iputils-ping \ + telnet \ + lsb-release \ + tmux \ + vim \ + software-properties-common \ + gnupg \ + htop \ + cgroup-tools \ + neovim \ + sudo \ + clangd-16 \ + man \ + python3-blessed \ + && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* + + # Install earthly. + RUN wget https://github.com/earthly/earthly/releases/latest/download/earthly-linux-$(dpkg --print-architecture) -O /usr/local/bin/earthly && \ + chmod +x /usr/local/bin/earthly + + # Install gh (github cli). + RUN mkdir -p -m 755 /etc/apt/keyrings && wget -qO- https://cli.github.com/packages/githubcli-archive-keyring.gpg > /etc/apt/keyrings/githubcli-archive-keyring.gpg \ + && chmod go+r /etc/apt/keyrings/githubcli-archive-keyring.gpg \ + && echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" | tee /etc/apt/sources.list.d/github-cli.list > /dev/null \ + && apt update \ + && apt install gh -y + + # Install gt (graphite). + RUN npm install -g @withgraphite/graphite-cli@stable + + # fzf seems to not install this file for some reason. + COPY ./key-bindings.zsh /usr/share/doc/fzf/examples/key-bindings.zsh + + # Sets LANG explicitly. Ensures tmux shows unicode symbols. + ENV LANG=C.UTF-8 + # Ensure we get color terminal. + ENV TERM=xterm-256color + + # Cargo home and bin path should be set within users home dir at login. + RUN echo 'export CARGO_HOME="$HOME/.cargo"' >> /etc/zsh/zshenv + RUN echo 'export PATH="$HOME/.cargo/bin:$PATH"' >> /etc/zsh/zshenv + + # sudo group can sudo without password. + RUN echo '%sudo ALL=(ALL) NOPASSWD: ALL' >> /etc/sudoers + + ARG TARGETARCH + SAVE IMAGE --push aztecprotocol/cache:basebox-1.0-$TARGETARCH + +######################################################################################################################## +# This devbox container can be used to provide a full development environment. +# +# It can be used as a dev container: +# - Configuration in .devcontainer/devcontainer.json. +# - To run locally install "Dev Containers" plugin in vscode. +# - To run in GitHub codespaces, visit the repo in github, press '.', and open the terminal. +# +# It can be used independently: +# - The user should use the ./run.sh script to launch. +# - A persistent volume will be mounted to /home/aztec-dev. +# - It provides docker via the hosts docker instance, mounted at /var/lib/docker.sock. +# - It uses an entrypoint script at runtime to perform uid/gid alignment with the host and drop into user account. +devbox: + BUILD +basebox + FROM +basebox + + # Install gosu so we can start as root, adjust uid/gid, and then use gosu to become aztec-dev. + RUN apt install -y gosu + + # Detect if the host machine is Mac, if so set an env var, and disable prompts vcs info for performance. + RUN echo ' \ + if mount | grep -q /host_mark/Users; then \ + export HOST_OSTYPE=darwin; \ + export PROMPT_LEAN_VCS=0; \ + fi \ + ' >> /etc/zsh/zshrc + + # Create the user we'll run as (remove ubuntu first). + RUN userdel -r ubuntu && useradd --shell /bin/zsh -G sudo -m aztec-dev + WORKDIR /home/aztec-dev + + # Add dotfiles. + COPY --chown=aztec-dev:aztec-dev home . + + # The .npmrc config is set to install global bins here, update PATH. + ENV PATH=/home/aztec-dev/.npm-global/bin:$PATH + + # Need to ensure correct permissions, under some conditions these would otherwise be created by root. + RUN mkdir .vscode-server .npm-global .ssh && chown aztec-dev:aztec-dev .* + + # Install docker using docker-in-docker dev-container feature install script, modified to permit noble. + COPY install-docker.sh /install-docker.sh + RUN /install-docker.sh && rm /install-docker.sh + + # Use as entrypoint when running in an environment that requires uid/gid alignment (e.g. vanilla linux docker). + COPY ./entrypoint.sh /entrypoint.sh + ENTRYPOINT ["/entrypoint.sh"] + CMD ["/bin/zsh"] + + ARG TARGETARCH + SAVE IMAGE --push aztecprotocol/devbox:1.0-$TARGETARCH + # Save it without the arch tag as this is what's referenced in devcontainer.json + SAVE IMAGE aztecprotocol/devbox:1.0 + +devbox-manifest: + LET VERSION = 1.0 + ARG TARGETARCH + WAIT + BUILD +devbox + END + LOCALLY + RUN docker push aztecprotocol/devbox:$VERSION-$TARGETARCH + RUN docker manifest rm aztecprotocol/devbox:$VERSION || true + RUN docker manifest create aztecprotocol/devbox:$VERSION \ + --amend aztecprotocol/devbox:$VERSION-amd64 \ + --amend aztecprotocol/devbox:$VERSION-arm64 + RUN docker manifest push aztecprotocol/devbox:$VERSION + +######################################################################################################################## +# This sysbox container can be used to provide a full development environment. +# It's more advanced than devbox in that it uses nestybox's sysbox container runtime to provide more of a vm experience. +# It's used primarily by internal aztec developers who have sysboxes running on a powerful underlying mainframe. +# It provides better isolation and security guarantees than a plain devbox. +sysbox: + FROM +basebox + + ###################### START OF STOCK NESTYBOX SYSTEMD CONTAINER ############################### + # + # Systemd installation + # + RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + systemd \ + systemd-sysv \ + libsystemd0 \ + ca-certificates \ + dbus \ + iptables \ + iproute2 \ + kmod \ + locales \ + sudo \ + udev && \ + \ + # Prevents journald from reading kernel messages from /dev/kmsg + echo "ReadKMsg=no" >> /etc/systemd/journald.conf && \ + \ + # Housekeeping + apt-get clean -y && \ + rm -rf \ + /var/cache/debconf/* \ + /var/lib/apt/lists/* \ + /var/log/* \ + /tmp/* \ + /var/tmp/* \ + /usr/share/local/* && \ + \ + # Create default 'ubuntu/ubuntu' user + echo "ubuntu:ubuntu" | chpasswd && adduser ubuntu sudo + + # Disable systemd services/units that are unnecessary within a container. + RUN systemctl mask systemd-udevd.service \ + systemd-udevd-kernel.socket \ + systemd-udevd-control.socket \ + systemd-modules-load.service \ + sys-kernel-config.mount \ + sys-kernel-debug.mount \ + sys-kernel-tracing.mount \ + e2scrub_reap.service + + # Make use of stopsignal (instead of sigterm) to stop systemd containers. + STOPSIGNAL SIGRTMIN+3 + + # Set systemd as entrypoint. + ENTRYPOINT [ "/sbin/init", "--log-level=err" ] + + ###################### END OF STOCK NESTYBOX SYSTEMD CONTAINER ############################### + + # Install docker. + RUN curl -fsSL https://get.docker.com -o get-docker.sh && sh get-docker.sh \ + # Add user "ubuntu" to the Docker group + && usermod -a -G docker ubuntu + ADD https://raw.githubusercontent.com/docker/docker-ce/master/components/cli/contrib/completion/bash/docker /etc/bash_completion.d/docker.sh + + # Install sshd. + RUN apt install --no-install-recommends -y openssh-server \ + && rm -rf /var/lib/apt/lists/* \ + && mkdir /home/ubuntu/.ssh \ + && chown ubuntu:ubuntu /home/ubuntu/.ssh \ + && echo 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDagCvr/+CA1jmFaJf+e9+Kw6iwfhvaKOpfbGEl5zLgB+rum5L4Kga6Jow1gLQeMnAHfqc2IgpsU4t04c8PYApAt8AWNDL+KxMiFytfjKfJ2DZJA73CYkFnkfnMtU+ki+JG9dAHd6m7ShtCSzE5n6EDO2yWCVWQfqE3dcnpwrymSWkJYrbxzeOixiNZ4f1nD9ddvFvTWGB4l+et5SWgeIaYgJYDqTI2teRt9ytJiDGrCWXs9olHsCZOL6TEJPUQmNekwBkjMAZ4TmbBMjwbUlIxOpW2UxzlONcNn7IlRcGQg0Gdbkpo/zOlCNXsvacvnphDk5vKKaQj+aQiG916LU5P charlie@aztecprotocol.com' >> /home/ubuntu/.ssh/authorized_keys \ + && echo 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDb5OVc+9S9nXx3/34F7eLVXjoPgQ3YHSdlfhTb8WflAGmpKJTLxtAYngtDBvhKofH5HrjPPkBWxOHP9KOTo0jxUQSr0suMpggLLOHuIrCszJKXIVi7whnQ4p2RHyzyS2ANwmpxWZmYxfgamzYst9JIvQYJgAPjTFweKBsG/Lc03knJ/qgz9BHqDSZHweMTnhv1dJNhZRKy1Lxyl/CjXKF374i8qbzVWJMeDgLEH6C84vCeaH89KMmM9J0+T31uEqxzIhZxNmRz9v+x6cQAVJtGi9OIveGT9qUQwKXZsk6/zorzxV+NiIvTWHxIn9epX/FUjgUmb/jFvpbEjDkbIngj adomurad@localhost.localdomain' >> /home/ubuntu/.ssh/authorized_keys \ + && echo 'ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFKlUeOh9DyAL85NJ10LE+nyfi8oYm+CwxQ9JMaB6H+t root@mainframe' >> /home/ubuntu/.ssh/authorized_keys \ + && chown ubuntu:ubuntu /home/ubuntu/.ssh/authorized_keys + + # Install google authenticator for setting up 2fa. + RUN apt update && apt install -y libpam-google-authenticator + + # We login to sysbox via ssh. This loses env vars set with ENV, so add them here. + # Sets RUSTUP_HOME. + # Adds foundry and cargo bin dirs to PATH. + COPY environment /etc/environment + + EXPOSE 22 + + ARG TARGETARCH + SAVE IMAGE aztecprotocol/sysbox:1.0-$TARGETARCH + SAVE IMAGE aztecprotocol/sysbox:1.0 \ No newline at end of file diff --git a/build-images/Makefile b/build-images/Makefile deleted file mode 100755 index 24934a9fa0a..00000000000 --- a/build-images/Makefile +++ /dev/null @@ -1,58 +0,0 @@ -ARCH := $(shell uname -m | sed 's/aarch64/arm64/') -FOUNDRY_TAG := de33b6af53005037b463318d2628b5cfcaf39916 -VERSION := 1.0 - -wasi-sdk: - docker build -t aztecprotocol/wasi-sdk:$(ARCH)-22.0 --target wasi-sdk --push . - docker manifest create aztecprotocol/wasi-sdk:22.0 \ - --amend aztecprotocol/wasi-sdk:x86_64-22.0 \ - --amend aztecprotocol/wasi-sdk:arm64-22.0 - docker manifest push aztecprotocol/wasi-sdk:22.0 - -foundry: - docker build -t aztecprotocol/foundry:$(ARCH)-$(FOUNDRY_TAG) --build-arg TAG=$(FOUNDRY_TAG) --target foundry --push . - docker tag aztecprotocol/foundry:$(ARCH)-$(FOUNDRY_TAG) aztecprotocol/foundry:$(FOUNDRY_TAG) - docker manifest rm aztecprotocol/foundry:$(FOUNDRY_TAG) - docker manifest create aztecprotocol/foundry:$(FOUNDRY_TAG) \ - --amend aztecprotocol/foundry:x86_64-$(FOUNDRY_TAG) \ - --amend aztecprotocol/foundry:arm64-$(FOUNDRY_TAG) - docker manifest push aztecprotocol/foundry:$(FOUNDRY_TAG) - -osxcross: - docker build -t aztecprotocol/osxcross:$(ARCH)-14.0 --target osxcross --push . - docker manifest rm aztecprotocol/osxcross:14.0 - docker manifest create aztecprotocol/osxcross:14.0 \ - --amend aztecprotocol/osxcross:x86_64-14.0 \ - --amend aztecprotocol/osxcross:arm64-14.0 - docker manifest push aztecprotocol/osxcross:14.0 - -build: - docker build -t aztecprotocol/build:$(ARCH)-$(VERSION) --target build . - docker tag aztecprotocol/build:$(ARCH)-$(VERSION) aztecprotocol/build - -build-push: build - docker push aztecprotocol/build:$(ARCH)-$(VERSION) - docker manifest rm aztecprotocol/build:$(VERSION) - docker manifest create aztecprotocol/build:$(VERSION) \ - --amend aztecprotocol/build:x86_64-$(VERSION) \ - --amend aztecprotocol/build:arm64-$(VERSION) - docker manifest push aztecprotocol/build:$(VERSION) - -devbox: - docker build -t aztecprotocol/devbox:$(ARCH)-$(VERSION) --target devbox . - docker tag aztecprotocol/devbox:$(ARCH)-$(VERSION) aztecprotocol/devbox - -devbox-push: devbox - docker push aztecprotocol/devbox:$(ARCH)-$(VERSION) - docker manifest rm aztecprotocol/devbox:$(VERSION) - docker manifest create aztecprotocol/devbox:$(VERSION) \ - --amend aztecprotocol/devbox:x86_64-$(VERSION) \ - --amend aztecprotocol/devbox:arm64-$(VERSION) - docker manifest push aztecprotocol/devbox:$(VERSION) - -sysbox: - docker build -t aztecprotocol/sysbox --target sysbox . - -all: build devbox sysbox - -.PHONY: all build devbox sysbox diff --git a/build-images/README.md b/build-images/README.md index 2ff02e1393f..d2824ba4564 100644 --- a/build-images/README.md +++ b/build-images/README.md @@ -2,10 +2,6 @@ To ensure a consistent environment for developers, and ease of getting started, we provide a development container. -## Install Docker - -If you don't already have docker installed, follow this guide: https://docs.docker.com/engine/install - ## Visual Studio Code If you use vscode, the simplest thing to do is install the "Dev Containers" plugin, and open the repo. @@ -25,3 +21,30 @@ Your repo will be mounted at `/workspaces/aztec-packages`, and your home directo This is also compatible with GitHub codespaces. Visit the repo at `http://github.com/aztecprotocol/aztec-packages`. Press `.`, and open a terminal window. You will be prompted to create a new machine. You can then continue to work within the browser, or reopen the codespace in your local vscode. + +## Building the build image + +If for some reason you want to build the images such as devbox yourself, follow these steps: + +### Install Docker + +If you don't already have docker installed, follow this guide: https://docs.docker.com/engine/install + +### Install earthly + +We use earthly to build things, follow this guide: https://earthly.dev/get-earthly + +### Build The Dev Container + +If you want to build entirely from scratch, you can do: + +``` +$ earthly +devbox +``` + +This will take significant time and compute however, as it builds several toolchains from the ground up. +If you have a reasonable internet connection, leveraging the cache to avoid building maybe prefereable. + +``` +$ earthly --use-inline-cache +devbox +``` \ No newline at end of file diff --git a/build-images/entrypoint.sh b/build-images/entrypoint.sh index d6f36b79dd0..52b676dad3a 100755 --- a/build-images/entrypoint.sh +++ b/build-images/entrypoint.sh @@ -5,18 +5,6 @@ set -e [ -n "$LOCAL_GROUP_ID" ] && groupmod -g $LOCAL_GROUP_ID aztec-dev [ -n "$LOCAL_USER_ID" ] && usermod -u $LOCAL_USER_ID aztec-dev &> /dev/null -# Find the group id of the docker socket, add aztec-dev to that group, or create the group and add aztec-dev. -if [ -S /var/run/docker.sock ]; then - SOCKET_GID=$(stat -c %g /var/run/docker.sock) - EXISTING_GROUP=$(getent group $SOCKET_GID | cut -d: -f1) - if [ -z "$EXISTING_GROUP" ]; then - # No existing group with that gid, so create one called 'docker' and add the user to it. - groupadd -g $SOCKET_GID docker - usermod -aG docker aztec-dev - else - # A group with the desired gid already exists, add the user to it. - usermod -aG $EXISTING_GROUP aztec-dev - fi -fi +/usr/local/share/docker-init.sh &> /dev/null exec /usr/sbin/gosu aztec-dev "$@" \ No newline at end of file diff --git a/build-images/install-docker.sh b/build-images/install-docker.sh new file mode 100755 index 00000000000..4a433a02220 --- /dev/null +++ b/build-images/install-docker.sh @@ -0,0 +1,624 @@ +#!/usr/bin/env bash +#------------------------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See https://go.microsoft.com/fwlink/?linkid=2090316 for license information. +#------------------------------------------------------------------------------------------------------------- +# +# Docs: https://github.com/microsoft/vscode-dev-containers/blob/main/script-library/docs/docker-in-docker.md +# Maintainer: The Dev Container spec maintainers + + +DOCKER_VERSION="${VERSION:-"latest"}" # The Docker/Moby Engine + CLI should match in version +USE_MOBY="${MOBY:-"true"}" +MOBY_BUILDX_VERSION="${MOBYBUILDXVERSION:-"latest"}" +DOCKER_DASH_COMPOSE_VERSION="${DOCKERDASHCOMPOSEVERSION:-"latest"}" #latest, v2 or none +AZURE_DNS_AUTO_DETECTION="${AZUREDNSAUTODETECTION:-"true"}" +DOCKER_DEFAULT_ADDRESS_POOL="${DOCKERDEFAULTADDRESSPOOL:-""}" +USERNAME="${USERNAME:-"${_REMOTE_USER:-"automatic"}"}" +INSTALL_DOCKER_BUILDX="${INSTALLDOCKERBUILDX:-"true"}" +INSTALL_DOCKER_COMPOSE_SWITCH="${INSTALLDOCKERCOMPOSESWITCH:-"true"}" +MICROSOFT_GPG_KEYS_URI="https://packages.microsoft.com/keys/microsoft.asc" +DOCKER_MOBY_ARCHIVE_VERSION_CODENAMES="bookworm buster bullseye bionic focal jammy noble" +DOCKER_LICENSED_ARCHIVE_VERSION_CODENAMES="bookworm buster bullseye bionic focal hirsute impish jammy noble" + +# Default: Exit on any failure. +set -e + +# Clean up +rm -rf /var/lib/apt/lists/* + +# Setup STDERR. +err() { + echo "(!) $*" >&2 +} + +if [ "$(id -u)" -ne 0 ]; then + err 'Script must be run as root. Use sudo, su, or add "USER root" to your Dockerfile before running this script.' + exit 1 +fi + +################### +# Helper Functions +# See: https://github.com/microsoft/vscode-dev-containers/blob/main/script-library/shared/utils.sh +################### + +# Determine the appropriate non-root user +if [ "${USERNAME}" = "auto" ] || [ "${USERNAME}" = "automatic" ]; then + USERNAME="" + POSSIBLE_USERS=("vscode" "node" "codespace" "$(awk -v val=1000 -F ":" '$3==val{print $1}' /etc/passwd)") + for CURRENT_USER in "${POSSIBLE_USERS[@]}"; do + if id -u ${CURRENT_USER} > /dev/null 2>&1; then + USERNAME=${CURRENT_USER} + break + fi + done + if [ "${USERNAME}" = "" ]; then + USERNAME=root + fi +elif [ "${USERNAME}" = "none" ] || ! id -u ${USERNAME} > /dev/null 2>&1; then + USERNAME=root +fi + +apt_get_update() +{ + if [ "$(find /var/lib/apt/lists/* | wc -l)" = "0" ]; then + echo "Running apt-get update..." + apt-get update -y + fi +} + +# Checks if packages are installed and installs them if not +check_packages() { + if ! dpkg -s "$@" > /dev/null 2>&1; then + apt_get_update + apt-get -y install --no-install-recommends "$@" + fi +} + +# Figure out correct version of a three part version number is not passed +find_version_from_git_tags() { + local variable_name=$1 + local requested_version=${!variable_name} + if [ "${requested_version}" = "none" ]; then return; fi + local repository=$2 + local prefix=${3:-"tags/v"} + local separator=${4:-"."} + local last_part_optional=${5:-"false"} + if [ "$(echo "${requested_version}" | grep -o "." | wc -l)" != "2" ]; then + local escaped_separator=${separator//./\\.} + local last_part + if [ "${last_part_optional}" = "true" ]; then + last_part="(${escaped_separator}[0-9]+)?" + else + last_part="${escaped_separator}[0-9]+" + fi + local regex="${prefix}\\K[0-9]+${escaped_separator}[0-9]+${last_part}$" + local version_list="$(git ls-remote --tags ${repository} | grep -oP "${regex}" | tr -d ' ' | tr "${separator}" "." | sort -rV)" + if [ "${requested_version}" = "latest" ] || [ "${requested_version}" = "current" ] || [ "${requested_version}" = "lts" ]; then + declare -g ${variable_name}="$(echo "${version_list}" | head -n 1)" + else + set +e + declare -g ${variable_name}="$(echo "${version_list}" | grep -E -m 1 "^${requested_version//./\\.}([\\.\\s]|$)")" + set -e + fi + fi + if [ -z "${!variable_name}" ] || ! echo "${version_list}" | grep "^${!variable_name//./\\.}$" > /dev/null 2>&1; then + err "Invalid ${variable_name} value: ${requested_version}\nValid values:\n${version_list}" >&2 + exit 1 + fi + echo "${variable_name}=${!variable_name}" +} + +# Use semver logic to decrement a version number then look for the closest match +find_prev_version_from_git_tags() { + local variable_name=$1 + local current_version=${!variable_name} + local repository=$2 + # Normally a "v" is used before the version number, but support alternate cases + local prefix=${3:-"tags/v"} + # Some repositories use "_" instead of "." for version number part separation, support that + local separator=${4:-"."} + # Some tools release versions that omit the last digit (e.g. go) + local last_part_optional=${5:-"false"} + # Some repositories may have tags that include a suffix (e.g. actions/node-versions) + local version_suffix_regex=$6 + # Try one break fix version number less if we get a failure. Use "set +e" since "set -e" can cause failures in valid scenarios. + set +e + major="$(echo "${current_version}" | grep -oE '^[0-9]+' || echo '')" + minor="$(echo "${current_version}" | grep -oP '^[0-9]+\.\K[0-9]+' || echo '')" + breakfix="$(echo "${current_version}" | grep -oP '^[0-9]+\.[0-9]+\.\K[0-9]+' 2>/dev/null || echo '')" + + if [ "${minor}" = "0" ] && [ "${breakfix}" = "0" ]; then + ((major=major-1)) + declare -g ${variable_name}="${major}" + # Look for latest version from previous major release + find_version_from_git_tags "${variable_name}" "${repository}" "${prefix}" "${separator}" "${last_part_optional}" + # Handle situations like Go's odd version pattern where "0" releases omit the last part + elif [ "${breakfix}" = "" ] || [ "${breakfix}" = "0" ]; then + ((minor=minor-1)) + declare -g ${variable_name}="${major}.${minor}" + # Look for latest version from previous minor release + find_version_from_git_tags "${variable_name}" "${repository}" "${prefix}" "${separator}" "${last_part_optional}" + else + ((breakfix=breakfix-1)) + if [ "${breakfix}" = "0" ] && [ "${last_part_optional}" = "true" ]; then + declare -g ${variable_name}="${major}.${minor}" + else + declare -g ${variable_name}="${major}.${minor}.${breakfix}" + fi + fi + set -e +} + +# Function to fetch the version released prior to the latest version +get_previous_version() { + local url=$1 + local repo_url=$2 + local variable_name=$3 + prev_version=${!variable_name} + + output=$(curl -s "$repo_url"); + message=$(echo "$output" | jq -r '.message') + + if [[ $message == "API rate limit exceeded"* ]]; then + echo -e "\nAn attempt to find latest version using GitHub Api Failed... \nReason: ${message}" + echo -e "\nAttempting to find latest version using GitHub tags." + find_prev_version_from_git_tags prev_version "$url" "tags/v" + declare -g ${variable_name}="${prev_version}" + else + echo -e "\nAttempting to find latest version using GitHub Api." + version=$(echo "$output" | jq -r '.tag_name') + declare -g ${variable_name}="${version#v}" + fi + echo "${variable_name}=${!variable_name}" +} + +get_github_api_repo_url() { + local url=$1 + echo "${url/https:\/\/github.com/https:\/\/api.github.com\/repos}/releases/latest" +} + +########################################### +# Start docker-in-docker installation +########################################### + +# Ensure apt is in non-interactive to avoid prompts +export DEBIAN_FRONTEND=noninteractive + + +# Source /etc/os-release to get OS info +. /etc/os-release +# Fetch host/container arch. +architecture="$(dpkg --print-architecture)" + +# Check if distro is supported +if [ "${USE_MOBY}" = "true" ]; then + if [[ "${DOCKER_MOBY_ARCHIVE_VERSION_CODENAMES}" != *"${VERSION_CODENAME}"* ]]; then + err "Unsupported distribution version '${VERSION_CODENAME}'. To resolve, either: (1) set feature option '\"moby\": false' , or (2) choose a compatible OS distribution" + err "Support distributions include: ${DOCKER_MOBY_ARCHIVE_VERSION_CODENAMES}" + exit 1 + fi + echo "Distro codename '${VERSION_CODENAME}' matched filter '${DOCKER_MOBY_ARCHIVE_VERSION_CODENAMES}'" +else + if [[ "${DOCKER_LICENSED_ARCHIVE_VERSION_CODENAMES}" != *"${VERSION_CODENAME}"* ]]; then + err "Unsupported distribution version '${VERSION_CODENAME}'. To resolve, please choose a compatible OS distribution" + err "Support distributions include: ${DOCKER_LICENSED_ARCHIVE_VERSION_CODENAMES}" + exit 1 + fi + echo "Distro codename '${VERSION_CODENAME}' matched filter '${DOCKER_LICENSED_ARCHIVE_VERSION_CODENAMES}'" +fi + +# Install dependencies +check_packages apt-transport-https curl ca-certificates pigz iptables gnupg2 dirmngr wget jq +if ! type git > /dev/null 2>&1; then + check_packages git +fi + +# Swap to legacy iptables for compatibility +if type iptables-legacy > /dev/null 2>&1; then + update-alternatives --set iptables /usr/sbin/iptables-legacy + update-alternatives --set ip6tables /usr/sbin/ip6tables-legacy +fi + + + +# Set up the necessary apt repos (either Microsoft's or Docker's) +if [ "${USE_MOBY}" = "true" ]; then + + # Name of open source engine/cli + engine_package_name="moby-engine" + cli_package_name="moby-cli" + + # Import key safely and import Microsoft apt repo + curl -sSL ${MICROSOFT_GPG_KEYS_URI} | gpg --dearmor > /usr/share/keyrings/microsoft-archive-keyring.gpg + echo "deb [arch=${architecture} signed-by=/usr/share/keyrings/microsoft-archive-keyring.gpg] https://packages.microsoft.com/repos/microsoft-${ID}-${VERSION_CODENAME}-prod ${VERSION_CODENAME} main" > /etc/apt/sources.list.d/microsoft.list +else + # Name of licensed engine/cli + engine_package_name="docker-ce" + cli_package_name="docker-ce-cli" + + # Import key safely and import Docker apt repo + curl -fsSL https://download.docker.com/linux/${ID}/gpg | gpg --dearmor > /usr/share/keyrings/docker-archive-keyring.gpg + echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/${ID} ${VERSION_CODENAME} stable" > /etc/apt/sources.list.d/docker.list +fi + +# Refresh apt lists +apt-get update + +# Soft version matching +if [ "${DOCKER_VERSION}" = "latest" ] || [ "${DOCKER_VERSION}" = "lts" ] || [ "${DOCKER_VERSION}" = "stable" ]; then + # Empty, meaning grab whatever "latest" is in apt repo + engine_version_suffix="" + cli_version_suffix="" +else + # Fetch a valid version from the apt-cache (eg: the Microsoft repo appends +azure, breakfix, etc...) + docker_version_dot_escaped="${DOCKER_VERSION//./\\.}" + docker_version_dot_plus_escaped="${docker_version_dot_escaped//+/\\+}" + # Regex needs to handle debian package version number format: https://www.systutorials.com/docs/linux/man/5-deb-version/ + docker_version_regex="^(.+:)?${docker_version_dot_plus_escaped}([\\.\\+ ~:-]|$)" + set +e # Don't exit if finding version fails - will handle gracefully + cli_version_suffix="=$(apt-cache madison ${cli_package_name} | awk -F"|" '{print $2}' | sed -e 's/^[ \t]*//' | grep -E -m 1 "${docker_version_regex}")" + engine_version_suffix="=$(apt-cache madison ${engine_package_name} | awk -F"|" '{print $2}' | sed -e 's/^[ \t]*//' | grep -E -m 1 "${docker_version_regex}")" + set -e + if [ -z "${engine_version_suffix}" ] || [ "${engine_version_suffix}" = "=" ] || [ -z "${cli_version_suffix}" ] || [ "${cli_version_suffix}" = "=" ] ; then + err "No full or partial Docker / Moby version match found for \"${DOCKER_VERSION}\" on OS ${ID} ${VERSION_CODENAME} (${architecture}). Available versions:" + apt-cache madison ${cli_package_name} | awk -F"|" '{print $2}' | grep -oP '^(.+:)?\K.+' + exit 1 + fi + echo "engine_version_suffix ${engine_version_suffix}" + echo "cli_version_suffix ${cli_version_suffix}" +fi + +# Version matching for moby-buildx +if [ "${USE_MOBY}" = "true" ]; then + if [ "${MOBY_BUILDX_VERSION}" = "latest" ]; then + # Empty, meaning grab whatever "latest" is in apt repo + buildx_version_suffix="" + else + buildx_version_dot_escaped="${MOBY_BUILDX_VERSION//./\\.}" + buildx_version_dot_plus_escaped="${buildx_version_dot_escaped//+/\\+}" + buildx_version_regex="^(.+:)?${buildx_version_dot_plus_escaped}([\\.\\+ ~:-]|$)" + set +e + buildx_version_suffix="=$(apt-cache madison moby-buildx | awk -F"|" '{print $2}' | sed -e 's/^[ \t]*//' | grep -E -m 1 "${buildx_version_regex}")" + set -e + if [ -z "${buildx_version_suffix}" ] || [ "${buildx_version_suffix}" = "=" ]; then + err "No full or partial moby-buildx version match found for \"${MOBY_BUILDX_VERSION}\" on OS ${ID} ${VERSION_CODENAME} (${architecture}). Available versions:" + apt-cache madison moby-buildx | awk -F"|" '{print $2}' | grep -oP '^(.+:)?\K.+' + exit 1 + fi + echo "buildx_version_suffix ${buildx_version_suffix}" + fi +fi + +# Install Docker / Moby CLI if not already installed +if type docker > /dev/null 2>&1 && type dockerd > /dev/null 2>&1; then + echo "Docker / Moby CLI and Engine already installed." +else + if [ "${USE_MOBY}" = "true" ]; then + # Install engine + set +e # Handle error gracefully + apt-get -y install --no-install-recommends moby-cli${cli_version_suffix} moby-buildx${buildx_version_suffix} moby-engine${engine_version_suffix} + exit_code=$? + set -e + + if [ ${exit_code} -ne 0 ]; then + err "Packages for moby not available in OS ${ID} ${VERSION_CODENAME} (${architecture}). To resolve, either: (1) set feature option '\"moby\": false' , or (2) choose a compatible OS version (eg: 'ubuntu-20.04')." + exit 1 + fi + + # Install compose + apt-get -y install --no-install-recommends moby-compose || err "Package moby-compose (Docker Compose v2) not available for OS ${ID} ${VERSION_CODENAME} (${architecture}). Skipping." + else + apt-get -y install --no-install-recommends docker-ce-cli${cli_version_suffix} docker-ce${engine_version_suffix} + # Install compose + apt-get -y install --no-install-recommends docker-compose-plugin || echo "(*) Package docker-compose-plugin (Docker Compose v2) not available for OS ${ID} ${VERSION_CODENAME} (${architecture}). Skipping." + fi +fi + +echo "Finished installing docker / moby!" + +docker_home="/usr/libexec/docker" +cli_plugins_dir="${docker_home}/cli-plugins" + +# fallback for docker-compose +fallback_compose(){ + local url=$1 + local repo_url=$(get_github_api_repo_url "$url") + echo -e "\n(!) Failed to fetch the latest artifacts for docker-compose v${compose_version}..." + get_previous_version "${url}" "${repo_url}" compose_version + echo -e "\nAttempting to install v${compose_version}" + curl -fsSL "https://github.com/docker/compose/releases/download/v${compose_version}/docker-compose-linux-${target_compose_arch}" -o ${docker_compose_path} +} + +# If 'docker-compose' command is to be included +if [ "${DOCKER_DASH_COMPOSE_VERSION}" != "none" ]; then + case "${architecture}" in + amd64) target_compose_arch=x86_64 ;; + arm64) target_compose_arch=aarch64 ;; + *) + echo "(!) Docker in docker does not support machine architecture '$architecture'. Please use an x86-64 or ARM64 machine." + exit 1 + esac + + docker_compose_path="/usr/local/bin/docker-compose" + if [ "${DOCKER_DASH_COMPOSE_VERSION}" = "v1" ]; then + err "The final Compose V1 release, version 1.29.2, was May 10, 2021. These packages haven't received any security updates since then. Use at your own risk." + INSTALL_DOCKER_COMPOSE_SWITCH="false" + + if [ "${target_compose_arch}" = "x86_64" ]; then + echo "(*) Installing docker compose v1..." + curl -fsSL "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-Linux-x86_64" -o ${docker_compose_path} + chmod +x ${docker_compose_path} + + # Download the SHA256 checksum + DOCKER_COMPOSE_SHA256="$(curl -sSL "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-Linux-x86_64.sha256" | awk '{print $1}')" + echo "${DOCKER_COMPOSE_SHA256} ${docker_compose_path}" > docker-compose.sha256sum + sha256sum -c docker-compose.sha256sum --ignore-missing + elif [ "${VERSION_CODENAME}" = "bookworm" ]; then + err "Docker compose v1 is unavailable for 'bookworm' on Arm64. Kindly switch to use v2" + exit 1 + else + # Use pip to get a version that runs on this architecture + check_packages python3-minimal python3-pip libffi-dev python3-venv + echo "(*) Installing docker compose v1 via pip..." + export PYTHONUSERBASE=/usr/local + pip3 install --disable-pip-version-check --no-cache-dir --user "Cython<3.0" pyyaml wheel docker-compose --no-build-isolation + fi + else + compose_version=${DOCKER_DASH_COMPOSE_VERSION#v} + docker_compose_url="https://github.com/docker/compose" + find_version_from_git_tags compose_version "$docker_compose_url" "tags/v" + echo "(*) Installing docker-compose ${compose_version}..." + curl -fsSL "https://github.com/docker/compose/releases/download/v${compose_version}/docker-compose-linux-${target_compose_arch}" -o ${docker_compose_path} || { + if [[ $DOCKER_DASH_COMPOSE_VERSION == "latest" ]]; then + fallback_compose "$docker_compose_url" + else + echo -e "Error: Failed to install docker-compose v${compose_version}" + fi + } + + chmod +x ${docker_compose_path} + + # Download the SHA256 checksum + DOCKER_COMPOSE_SHA256="$(curl -sSL "https://github.com/docker/compose/releases/download/v${compose_version}/docker-compose-linux-${target_compose_arch}.sha256" | awk '{print $1}')" + echo "${DOCKER_COMPOSE_SHA256} ${docker_compose_path}" > docker-compose.sha256sum + sha256sum -c docker-compose.sha256sum --ignore-missing + + mkdir -p ${cli_plugins_dir} + cp ${docker_compose_path} ${cli_plugins_dir} + fi +fi + +# fallback method for compose-switch +fallback_compose-switch() { + local url=$1 + local repo_url=$(get_github_api_repo_url "$url") + echo -e "\n(!) Failed to fetch the latest artifacts for compose-switch v${compose_switch_version}..." + get_previous_version "$url" "$repo_url" compose_switch_version + echo -e "\nAttempting to install v${compose_switch_version}" + curl -fsSL "https://github.com/docker/compose-switch/releases/download/v${compose_switch_version}/docker-compose-linux-${architecture}" -o /usr/local/bin/compose-switch +} + +# Install docker-compose switch if not already installed - https://github.com/docker/compose-switch#manual-installation +if [ "${INSTALL_DOCKER_COMPOSE_SWITCH}" = "true" ] && ! type compose-switch > /dev/null 2>&1; then + if type docker-compose > /dev/null 2>&1; then + echo "(*) Installing compose-switch..." + current_compose_path="$(which docker-compose)" + target_compose_path="$(dirname "${current_compose_path}")/docker-compose-v1" + compose_switch_version="latest" + compose_switch_url="https://github.com/docker/compose-switch" + find_version_from_git_tags compose_switch_version "$compose_switch_url" + curl -fsSL "https://github.com/docker/compose-switch/releases/download/v${compose_switch_version}/docker-compose-linux-${architecture}" -o /usr/local/bin/compose-switch || fallback_compose-switch "$compose_switch_url" + chmod +x /usr/local/bin/compose-switch + # TODO: Verify checksum once available: https://github.com/docker/compose-switch/issues/11 + # Setup v1 CLI as alternative in addition to compose-switch (which maps to v2) + mv "${current_compose_path}" "${target_compose_path}" + update-alternatives --install ${docker_compose_path} docker-compose /usr/local/bin/compose-switch 99 + update-alternatives --install ${docker_compose_path} docker-compose "${target_compose_path}" 1 + else + err "Skipping installation of compose-switch as docker compose is unavailable..." + fi +fi + +# If init file already exists, exit +if [ -f "/usr/local/share/docker-init.sh" ]; then + echo "/usr/local/share/docker-init.sh already exists, so exiting." + # Clean up + rm -rf /var/lib/apt/lists/* + exit 0 +fi +echo "docker-init doesn't exist, adding..." + +if ! cat /etc/group | grep -e "^docker:" > /dev/null 2>&1; then + groupadd -r docker +fi + +usermod -aG docker ${USERNAME} + +# fallback for docker/buildx +fallback_buildx() { + local url=$1 + local repo_url=$(get_github_api_repo_url "$url") + echo -e "\n(!) Failed to fetch the latest artifacts for docker buildx v${buildx_version}..." + get_previous_version "$url" "$repo_url" buildx_version + buildx_file_name="buildx-v${buildx_version}.linux-${architecture}" + echo -e "\nAttempting to install v${buildx_version}" + wget https://github.com/docker/buildx/releases/download/v${buildx_version}/${buildx_file_name} +} + +if [ "${INSTALL_DOCKER_BUILDX}" = "true" ]; then + buildx_version="latest" + docker_buildx_url="https://github.com/docker/buildx" + find_version_from_git_tags buildx_version "$docker_buildx_url" "refs/tags/v" + echo "(*) Installing buildx ${buildx_version}..." + buildx_file_name="buildx-v${buildx_version}.linux-${architecture}" + + cd /tmp + wget https://github.com/docker/buildx/releases/download/v${buildx_version}/${buildx_file_name} || fallback_buildx "$docker_buildx_url" + + docker_home="/usr/libexec/docker" + cli_plugins_dir="${docker_home}/cli-plugins" + + mkdir -p ${cli_plugins_dir} + mv ${buildx_file_name} ${cli_plugins_dir}/docker-buildx + chmod +x ${cli_plugins_dir}/docker-buildx + + chown -R "${USERNAME}:docker" "${docker_home}" + chmod -R g+r+w "${docker_home}" + find "${docker_home}" -type d -print0 | xargs -n 1 -0 chmod g+s +fi + +tee /usr/local/share/docker-init.sh > /dev/null \ +<< EOF +#!/bin/sh +#------------------------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See https://go.microsoft.com/fwlink/?linkid=2090316 for license information. +#------------------------------------------------------------------------------------------------------------- + +set -e + +AZURE_DNS_AUTO_DETECTION=${AZURE_DNS_AUTO_DETECTION} +DOCKER_DEFAULT_ADDRESS_POOL=${DOCKER_DEFAULT_ADDRESS_POOL} +EOF + +tee -a /usr/local/share/docker-init.sh > /dev/null \ +<< 'EOF' +dockerd_start="AZURE_DNS_AUTO_DETECTION=${AZURE_DNS_AUTO_DETECTION} DOCKER_DEFAULT_ADDRESS_POOL=${DOCKER_DEFAULT_ADDRESS_POOL} $(cat << 'INNEREOF' + # explicitly remove dockerd and containerd PID file to ensure that it can start properly if it was stopped uncleanly + find /run /var/run -iname 'docker*.pid' -delete || : + find /run /var/run -iname 'container*.pid' -delete || : + + # -- Start: dind wrapper script -- + # Maintained: https://github.com/moby/moby/blob/master/hack/dind + + export container=docker + + if [ -d /sys/kernel/security ] && ! mountpoint -q /sys/kernel/security; then + mount -t securityfs none /sys/kernel/security || { + echo >&2 'Could not mount /sys/kernel/security.' + echo >&2 'AppArmor detection and --privileged mode might break.' + } + fi + + # Mount /tmp (conditionally) + if ! mountpoint -q /tmp; then + mount -t tmpfs none /tmp + fi + + set_cgroup_nesting() + { + # cgroup v2: enable nesting + if [ -f /sys/fs/cgroup/cgroup.controllers ]; then + # move the processes from the root group to the /init group, + # otherwise writing subtree_control fails with EBUSY. + # An error during moving non-existent process (i.e., "cat") is ignored. + mkdir -p /sys/fs/cgroup/init + xargs -rn1 < /sys/fs/cgroup/cgroup.procs > /sys/fs/cgroup/init/cgroup.procs || : + # enable controllers + sed -e 's/ / +/g' -e 's/^/+/' < /sys/fs/cgroup/cgroup.controllers \ + > /sys/fs/cgroup/cgroup.subtree_control + fi + } + + # Set cgroup nesting, retrying if necessary + retry_cgroup_nesting=0 + + until [ "${retry_cgroup_nesting}" -eq "5" ]; + do + set +e + set_cgroup_nesting + + if [ $? -ne 0 ]; then + echo "(*) cgroup v2: Failed to enable nesting, retrying..." + else + break + fi + + retry_cgroup_nesting=`expr $retry_cgroup_nesting + 1` + set -e + done + + # -- End: dind wrapper script -- + + # Handle DNS + set +e + cat /etc/resolv.conf | grep -i 'internal.cloudapp.net' > /dev/null 2>&1 + if [ $? -eq 0 ] && [ "${AZURE_DNS_AUTO_DETECTION}" = "true" ] + then + echo "Setting dockerd Azure DNS." + CUSTOMDNS="--dns 168.63.129.16" + else + echo "Not setting dockerd DNS manually." + CUSTOMDNS="" + fi + set -e + + if [ -z "$DOCKER_DEFAULT_ADDRESS_POOL" ] + then + DEFAULT_ADDRESS_POOL="" + else + DEFAULT_ADDRESS_POOL="--default-address-pool $DOCKER_DEFAULT_ADDRESS_POOL" + fi + + # Start docker/moby engine + ( dockerd $CUSTOMDNS $DEFAULT_ADDRESS_POOL > /tmp/dockerd.log 2>&1 ) & +INNEREOF +)" + +sudo_if() { + COMMAND="$*" + + if [ "$(id -u)" -ne 0 ]; then + sudo $COMMAND + else + $COMMAND + fi +} + +retry_docker_start_count=0 +docker_ok="false" + +until [ "${docker_ok}" = "true" ] || [ "${retry_docker_start_count}" -eq "5" ]; +do + # Start using sudo if not invoked as root + if [ "$(id -u)" -ne 0 ]; then + sudo /bin/sh -c "${dockerd_start}" + else + eval "${dockerd_start}" + fi + + retry_count=0 + until [ "${docker_ok}" = "true" ] || [ "${retry_count}" -eq "5" ]; + do + sleep 1s + set +e + docker info > /dev/null 2>&1 && docker_ok="true" + set -e + + retry_count=`expr $retry_count + 1` + done + + if [ "${docker_ok}" != "true" ] && [ "${retry_docker_start_count}" != "4" ]; then + echo "(*) Failed to start docker, retrying..." + set +e + sudo_if pkill dockerd + sudo_if pkill containerd + set -e + fi + + retry_docker_start_count=`expr $retry_docker_start_count + 1` +done + +# Execute whatever commands were passed in (if any). This allows us +# to set this script to ENTRYPOINT while still executing the default CMD. +exec "$@" +EOF + +chmod +x /usr/local/share/docker-init.sh +chown ${USERNAME}:root /usr/local/share/docker-init.sh + +# Clean up +rm -rf /var/lib/apt/lists/* + +echo 'docker-in-docker-debian script has completed!' diff --git a/build-images/run.sh b/build-images/run.sh index 97132414f76..2e54ba1ae90 100755 --- a/build-images/run.sh +++ b/build-images/run.sh @@ -2,6 +2,18 @@ set -eu cd $(dirname $0) +hostname=$(hostname) + +# Define next hostname based on this hostname for nesting. devbox, devbox1, etc. +if [[ $hostname == "devbox" ]]; then + hostname="devbox1" +elif [[ $hostname =~ ^devbox([0-9]+)$ ]]; then + num_suffix="${BASH_REMATCH[1]}" + new_num=$((num_suffix + 1)) + hostname="devbox$new_num" +else + hostname="devbox" +fi # On linux we need to perform uid/gid alignment to ensure files modified on the host have the correct owner. # The entrypoint.sh script picks up these environment variables and adjusts the aztec-dev user accordingly. @@ -10,14 +22,24 @@ if [[ "$OSTYPE" == "linux"* ]]; then ID_ARGS="-e LOCAL_USER_ID=$(id -u) -e LOCAL_GROUP_ID=$(id -g)" fi -docker run \ - -ti --rm \ - --hostname devbox \ - -e SSH_CONNECTION=' ' \ - ${ID_ARGS:-} \ - -w/workspaces/aztec-packages \ - -v$PWD/..:/workspaces/aztec-packages \ - -vdevbox-home:/home/aztec-dev \ - -v$HOME/.ssh/id_rsa:/home/aztec-dev/.ssh/id_rsa:ro \ - -v/var/run/docker.sock:/var/run/docker.sock \ - aztecprotocol/devbox +if docker ps -a --format '{{.Names}}' | grep -q '^aztec-devbox$'; then + # Container already exists. Exec into a new shell. + docker exec -ti --user aztec-dev aztec-devbox /bin/zsh +else + # We override the docker config dir to ensure we don't conflict with vscodes dev-container. + # They share the same home dir, but vscode will add some credentials config that it needs to its docker config. + docker run \ + -ti --rm \ + --name aztec-devbox \ + --hostname $hostname \ + -e SSH_CONNECTION=' ' \ + -e DOCKER_CONFIG=/home/aztec-dev/.docker-devbox \ + ${ID_ARGS:-} \ + -w/workspaces/aztec-packages \ + -v$PWD/..:/workspaces/aztec-packages \ + -vdevbox-home:/home/aztec-dev \ + -vdevbox-var-lib-docker:/var/lib/docker \ + -v$HOME/.ssh/id_rsa:/home/aztec-dev/.ssh/id_rsa:ro \ + --privileged \ + aztecprotocol/devbox:1.0 +fi \ No newline at end of file diff --git a/scripts/earthly-ci b/scripts/earthly-ci index e424c0a4201..fe625d87015 100755 --- a/scripts/earthly-ci +++ b/scripts/earthly-ci @@ -25,6 +25,12 @@ INCONSISTENT_GRAPH_STATE_COUNT=0 # Counter for 'inconsistent graph state' error MAX_ATTEMPTS=3 ATTEMPT_COUNT=0 +export EARTHLY_USE_INLINE_CACHE=true +if [ "$GITHUB_REF_NAME" == "master" ]; then + export EARTHLY_SAVE_INLINE_CACHE=true + export EARTHLY_PUSH=true +fi + # Handle earthly commands and retries while [ $ATTEMPT_COUNT -lt $MAX_ATTEMPTS ]; do if earthly $@ 2>&1 | tee $OUTPUT_FILE >&2 ; then