Skip to content

Commit

Permalink
Add separate epoch verifier to L1 contract
Browse files Browse the repository at this point in the history
  • Loading branch information
spalladino committed Sep 27, 2024
1 parent 3c0cf02 commit 7a11c7b
Show file tree
Hide file tree
Showing 9 changed files with 126 additions and 95 deletions.
28 changes: 22 additions & 6 deletions l1-contracts/src/core/Rollup.sol
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ contract Rollup is Leonidas, IRollup, ITestRollup {
IProofCommitmentEscrow public immutable PROOF_COMMITMENT_ESCROW;
uint256 public immutable VERSION;
IFeeJuicePortal public immutable FEE_JUICE_PORTAL;
IVerifier public verifier;
IVerifier public blockProofVerifier;

ChainTips public tips;
DataStructures.EpochProofClaim public proofClaim;
Expand All @@ -80,14 +80,19 @@ contract Rollup is Leonidas, IRollup, ITestRollup {
// Testing only. This should be removed eventually.
uint256 private assumeProvenThroughBlockNumber;

// Listed at the end of the contract to avoid changing storage slots
// TODO(palla/prover) Drop blockProofVerifier and move this verifier to that slot
IVerifier public epochProofVerifier;

constructor(
IRegistry _registry,
IFeeJuicePortal _fpcJuicePortal,
bytes32 _vkTreeRoot,
address _ares,
address[] memory _validators
) Leonidas(_ares) {
verifier = new MockVerifier();
blockProofVerifier = new MockVerifier();
epochProofVerifier = new MockVerifier();
REGISTRY = _registry;
FEE_JUICE_PORTAL = _fpcJuicePortal;
PROOF_COMMITMENT_ESCROW = new MockProofCommitmentEscrow();
Expand Down Expand Up @@ -144,8 +149,19 @@ contract Rollup is Leonidas, IRollup, ITestRollup {
*
* @param _verifier - The new verifier contract
*/
function setVerifier(address _verifier) external override(ITestRollup) onlyOwner {
verifier = IVerifier(_verifier);
function setBlockVerifier(address _verifier) external override(ITestRollup) onlyOwner {
blockProofVerifier = IVerifier(_verifier);
}

/**
* @notice Set the verifier contract
*
* @dev This is only needed for testing, and should be removed
*
* @param _verifier - The new verifier contract
*/
function setEpochVerifier(address _verifier) external override(ITestRollup) onlyOwner {
epochProofVerifier = IVerifier(_verifier);
}

/**
Expand Down Expand Up @@ -410,7 +426,7 @@ contract Rollup is Leonidas, IRollup, ITestRollup {
publicInputs[i + 91] = part;
}

if (!verifier.verify(_proof, publicInputs)) {
if (!blockProofVerifier.verify(_proof, publicInputs)) {
revert Errors.Rollup__InvalidProof();
}

Expand Down Expand Up @@ -484,7 +500,7 @@ contract Rollup is Leonidas, IRollup, ITestRollup {
bytes32[] memory publicInputs =
getEpochProofPublicInputs(_epochSize, _args, _fees, _aggregationObject);

if (!verifier.verify(_proof, publicInputs)) {
if (!epochProofVerifier.verify(_proof, publicInputs)) {
revert Errors.Rollup__InvalidProof();
}

Expand Down
3 changes: 2 additions & 1 deletion l1-contracts/src/core/interfaces/IRollup.sol
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ import {DataStructures} from "@aztec/core/libraries/DataStructures.sol";
import {Timestamp, Slot, Epoch} from "@aztec/core/libraries/TimeMath.sol";

interface ITestRollup {
function setVerifier(address _verifier) external;
function setBlockVerifier(address _verifier) external;
function setEpochVerifier(address _verifier) external;
function setVkTreeRoot(bytes32 _vkTreeRoot) external;
function setAssumeProvenThroughBlockNumber(uint256 blockNumber) external;
}
Expand Down
12 changes: 6 additions & 6 deletions yarn-project/bb-prover/src/honk.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,16 @@ const UltraKeccakHonkCircuits = [
'BlockRootRollupFinalArtifact',
'RootRollupArtifact',
] as const satisfies ProtocolArtifact[];
type UltraKeccakHonkCircuits = (typeof UltraKeccakHonkCircuits)[number];
type UltraHonkCircuits = Exclude<ProtocolArtifact, UltraKeccakHonkCircuits>;
export type UltraKeccakHonkProtocolArtifact = (typeof UltraKeccakHonkCircuits)[number];
export type UltraHonkProtocolArtifact = Exclude<ProtocolArtifact, UltraKeccakHonkProtocolArtifact>;

export function getUltraHonkFlavorForCircuit(artifact: UltraKeccakHonkCircuits): 'ultra_keccak_honk';
export function getUltraHonkFlavorForCircuit(artifact: UltraHonkCircuits): 'ultra_honk';
export function getUltraHonkFlavorForCircuit(artifact: UltraKeccakHonkProtocolArtifact): 'ultra_keccak_honk';
export function getUltraHonkFlavorForCircuit(artifact: UltraHonkProtocolArtifact): 'ultra_honk';
export function getUltraHonkFlavorForCircuit(artifact: ProtocolArtifact): UltraHonkFlavor;
export function getUltraHonkFlavorForCircuit(artifact: ProtocolArtifact): UltraHonkFlavor {
return isUltraKeccakHonkCircuit(artifact) ? 'ultra_keccak_honk' : 'ultra_honk';
}

function isUltraKeccakHonkCircuit(artifact: ProtocolArtifact): artifact is UltraKeccakHonkCircuits {
return UltraKeccakHonkCircuits.includes(artifact as UltraKeccakHonkCircuits);
function isUltraKeccakHonkCircuit(artifact: ProtocolArtifact): artifact is UltraKeccakHonkProtocolArtifact {
return UltraKeccakHonkCircuits.includes(artifact as UltraKeccakHonkProtocolArtifact);
}
1 change: 1 addition & 0 deletions yarn-project/bb-prover/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@ export * from './test/index.js';
export * from './verifier/index.js';
export * from './config.js';
export * from './bb/execute.js';
export * from './honk.js';

export { type ClientProtocolCircuitVerifier } from '@aztec/circuit-types';
4 changes: 2 additions & 2 deletions yarn-project/bb-prover/src/verifier/bb_verifier.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import {
verifyProof,
} from '../bb/execute.js';
import { type BBConfig } from '../config.js';
import { getUltraHonkFlavorForCircuit } from '../honk.js';
import { type UltraKeccakHonkProtocolArtifact, getUltraHonkFlavorForCircuit } from '../honk.js';
import { mapProtocolArtifactNameToCircuitName } from '../stats.js';
import { extractVkData } from '../verification_key/verification_key_data.js';

Expand Down Expand Up @@ -127,7 +127,7 @@ export class BBCircuitVerifier implements ClientProtocolCircuitVerifier {
await runInDirectory(this.config.bbWorkingDirectory, operation, this.config.bbSkipCleanup);
}

public async generateSolidityContract(circuit: ProtocolArtifact, contractName: string) {
public async generateSolidityContract(circuit: UltraKeccakHonkProtocolArtifact, contractName: string) {
const result = await generateContractForCircuit(
this.config.bbBinaryPath,
this.config.bbWorkingDirectory,
Expand Down
64 changes: 23 additions & 41 deletions yarn-project/cli/src/cmds/l1/deploy_l1_verifier.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { createCompatibleClient } from '@aztec/aztec.js';
import { createEthereumChain, createL1Clients, deployL1Contract } from '@aztec/ethereum';
import { compileContract, createEthereumChain, createL1Clients, deployL1Contract } from '@aztec/ethereum';
import { type DebugLogger, type LogFn } from '@aztec/foundation/log';

import { InvalidOptionArgumentError } from 'commander';
Expand All @@ -24,51 +24,14 @@ export async function deployUltraHonkVerifier(
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore - Importing bb-prover even in devDeps results in a circular dependency error through @aztec/simulator. Need to ignore because this line doesn't cause an error in a dev environment
const { BBCircuitVerifier } = await import('@aztec/bb-prover');

const circuitVerifier = await BBCircuitVerifier.new({ bbBinaryPath, bbWorkingDirectory });
const contractSrc = await circuitVerifier.generateSolidityContract(
'BlockRootRollupFinalArtifact',
'UltraHonkVerifier.sol',
);
log('Generated UltraHonkVerifier contract');

const input = {
language: 'Solidity',
sources: {
'UltraHonkVerifier.sol': {
content: contractSrc,
},
},
settings: {
// we require the optimizer
optimizer: {
enabled: true,
runs: 200,
},
evmVersion: 'paris',
outputSelection: {
'*': {
'*': ['evm.bytecode.object', 'abi'],
},
},
},
};

const output = JSON.parse(solc.compile(JSON.stringify(input)));
log('Compiled UltraHonkVerifier');

const abi = output.contracts['UltraHonkVerifier.sol']['HonkVerifier'].abi;
const bytecode: string = output.contracts['UltraHonkVerifier.sol']['HonkVerifier'].evm.bytecode.object;
const verifier = await BBCircuitVerifier.new({ bbBinaryPath, bbWorkingDirectory });

const { publicClient, walletClient } = createL1Clients(
ethRpcUrl,
privateKey ?? mnemonic,
createEthereumChain(ethRpcUrl, l1ChainId).chainInfo,
);

const { address: verifierAddress } = await deployL1Contract(walletClient, publicClient, abi, `0x${bytecode}`);
log(`Deployed HonkVerifier at ${verifierAddress.toString()}`);

const pxe = await createCompatibleClient(pxeRpcUrl, debugLogger);
const { l1ContractAddresses } = await pxe.getNodeInfo();

Expand All @@ -80,7 +43,25 @@ export async function deployUltraHonkVerifier(
client: walletClient,
});

await rollup.write.setVerifier([verifierAddress.toString()]);
// REFACTOR: Extract this method to a common package. We need a package that deals with L1
// but also has a reference to L1 artifacts and bb-prover.
const setupVerifier = async (
artifact: Parameters<(typeof verifier)['generateSolidityContract']>[0], // Cannot properly import the type here due to the hack above
method: 'setBlockVerifier' | 'setEpochVerifier',
) => {
const contract = await verifier.generateSolidityContract(artifact, 'UltraHonkVerifier.sol');
log(`Generated UltraHonkVerifier contract for ${artifact}`);
const { abi, bytecode } = compileContract('UltraHonkVerifier.sol', 'HonkVerifier', contract, solc);
log(`Compiled UltraHonkVerifier contract for ${artifact}`);
const { address: verifierAddress } = await deployL1Contract(walletClient, publicClient, abi, bytecode);
log(`Deployed real ${artifact} verifier at ${verifierAddress}`);
await rollup.write[method]([verifierAddress.toString()]);
log(`Set ${artifact} verifier in ${rollup.address} rollup contract to ${verifierAddress}`);
};

await setupVerifier('BlockRootRollupFinalArtifact', 'setBlockVerifier');
await setupVerifier('RootRollupArtifact', 'setEpochVerifier');

log(`Rollup accepts only real proofs now`);
}

Expand Down Expand Up @@ -117,6 +98,7 @@ export async function deployMockVerifier(
client: walletClient,
});

await rollup.write.setVerifier([mockVerifierAddress.toString()]);
await rollup.write.setBlockVerifier([mockVerifierAddress.toString()]);
await rollup.write.setEpochVerifier([mockVerifierAddress.toString()]);
log(`Rollup accepts only fake proofs now`);
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import { getLogger, setupL1Contracts, startAnvil } from '../fixtures/utils.js';
/**
* Regenerate this test's fixture with
* AZTEC_GENERATE_TEST_DATA=1 yarn workspace @aztec/end-to-end test e2e_prover
* TODO(palla/prover): Migrate to root rollup
*/
describe('proof_verification', () => {
let proof: Proof;
Expand Down
64 changes: 25 additions & 39 deletions yarn-project/end-to-end/src/e2e_prover/e2e_prover_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,13 @@ import {
createDebugLogger,
deployL1Contract,
} from '@aztec/aztec.js';
import { BBCircuitVerifier, type ClientProtocolCircuitVerifier, TestCircuitVerifier } from '@aztec/bb-prover';
import {
BBCircuitVerifier,
type ClientProtocolCircuitVerifier,
TestCircuitVerifier,
type UltraKeccakHonkProtocolArtifact,
} from '@aztec/bb-prover';
import { compileContract } from '@aztec/ethereum';
import { RollupAbi } from '@aztec/l1-artifacts';
import { TokenContract } from '@aztec/noir-contracts.js';
import { type ProverNode, type ProverNodeConfig, createProverNode } from '@aztec/prover-node';
Expand Down Expand Up @@ -359,51 +365,31 @@ export class FullProverTest {
throw new Error('No verifier');
}

const verifier = this.circuitProofVerifier as BBCircuitVerifier;
const { walletClient, publicClient, l1ContractAddresses } = this.context.deployL1ContractsValues;

const contract = await (this.circuitProofVerifier as BBCircuitVerifier).generateSolidityContract(
'BlockRootRollupFinalArtifact',
'UltraHonkVerifier.sol',
);

const input = {
language: 'Solidity',
sources: {
'UltraHonkVerifier.sol': {
content: contract,
},
},
settings: {
// we require the optimizer
optimizer: {
enabled: true,
runs: 200,
},
evmVersion: 'paris',
outputSelection: {
'*': {
'*': ['evm.bytecode.object', 'abi'],
},
},
},
};

const output = JSON.parse(solc.compile(JSON.stringify(input)));

const abi = output.contracts['UltraHonkVerifier.sol']['HonkVerifier'].abi;
const bytecode: string = output.contracts['UltraHonkVerifier.sol']['HonkVerifier'].evm.bytecode.object;

const { address: verifierAddress } = await deployL1Contract(walletClient, publicClient, abi, `0x${bytecode}`);

this.logger.info(`Deployed Real verifier at ${verifierAddress}`);

const rollup = getContract({
abi: RollupAbi,
address: l1ContractAddresses.rollupAddress.toString(),
client: walletClient,
});

await rollup.write.setVerifier([verifierAddress.toString()]);
// REFACTOR: Extract this method to a common package. We need a package that deals with L1
// but also has a reference to L1 artifacts and bb-prover.
const setupVerifier = async (
artifact: UltraKeccakHonkProtocolArtifact,
method: 'setBlockVerifier' | 'setEpochVerifier',
) => {
const contract = await verifier.generateSolidityContract(artifact, 'UltraHonkVerifier.sol');
const { abi, bytecode } = compileContract('UltraHonkVerifier.sol', 'HonkVerifier', contract, solc);
const { address: verifierAddress } = await deployL1Contract(walletClient, publicClient, abi, bytecode);
this.logger.info(`Deployed real ${artifact} verifier at ${verifierAddress}`);

await rollup.write[method]([verifierAddress.toString()]);
};

await setupVerifier('BlockRootRollupFinalArtifact', 'setBlockVerifier');
await setupVerifier('RootRollupArtifact', 'setEpochVerifier');

this.logger.info('Rollup only accepts valid proofs now');
}
}
44 changes: 44 additions & 0 deletions yarn-project/ethereum/src/deploy_l1_contracts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -361,6 +361,50 @@ class L1Deployer {
}
}

/**
* Compiles a contract source code using the provided solc compiler.
* @param fileName - Contract file name (eg UltraHonkVerifier.sol)
* @param contractName - Contract name within the file (eg HonkVerifier)
* @param source - Source code to compile
* @param solc - Solc instance
* @returns ABI and bytecode of the compiled contract
*/
export function compileContract(
fileName: string,
contractName: string,
source: string,
solc: { compile: (source: string) => string },
): { abi: Narrow<Abi | readonly unknown[]>; bytecode: Hex } {
const input = {
language: 'Solidity',
sources: {
[fileName]: {
content: source,
},
},
settings: {
// we require the optimizer
optimizer: {
enabled: true,
runs: 200,
},
evmVersion: 'paris',
outputSelection: {
'*': {
'*': ['evm.bytecode.object', 'abi'],
},
},
},
};

const output = JSON.parse(solc.compile(JSON.stringify(input)));

const abi = output.contracts[fileName][contractName].abi;
const bytecode: `0x${string}` = `0x${output.contracts[fileName][contractName].evm.bytecode.object}`;

return { abi, bytecode };
}

// docs:start:deployL1Contract
/**
* Helper function to deploy ETH contracts.
Expand Down

0 comments on commit 7a11c7b

Please sign in to comment.