Skip to content

Commit 55b6ba2

Browse files
authored
fix(bb-prover): create structure for AVM vk (#8233)
Apologies for duplicating code! I tried putting a generic on the "base" classes, but (1) generics don't play well with static methods (e.g., fromBuffer) and (2) you still need to pass the value for the VK size (on top of the type). I think most of this duplication can be avoided if you just accept some type unsafety and save things as `Fr[]` instead of tuples with size. PS: There might be still work to do to align the "num public inputs" etc indices, and the vk hash.
1 parent 97e5e25 commit 55b6ba2

File tree

11 files changed

+182
-33
lines changed

11 files changed

+182
-33
lines changed

barretenberg/cpp/src/barretenberg/vm/aztec_constants.hpp

+1
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
#define HEADER_LENGTH 24
3434
#define PUBLIC_CIRCUIT_PUBLIC_INPUTS_LENGTH 691
3535
#define PUBLIC_CONTEXT_INPUTS_LENGTH 42
36+
#define AVM_VERIFICATION_KEY_LENGTH_IN_FIELDS 66
3637
#define SENDER_SELECTOR 0
3738
#define ADDRESS_SELECTOR 1
3839
#define STORAGE_ADDRESS_SELECTOR 1

noir-projects/noir-protocol-circuits/crates/types/src/constants.nr

+6
Original file line numberDiff line numberDiff line change
@@ -290,6 +290,12 @@ global NESTED_RECURSIVE_PROOF_LENGTH = 439;
290290
global TUBE_PROOF_LENGTH = RECURSIVE_PROOF_LENGTH; // in the future these can differ
291291

292292
global VERIFICATION_KEY_LENGTH_IN_FIELDS = 128;
293+
// VK is composed of
294+
// - circuit size encoded as a fr field element (32 bytes)
295+
// - num of inputs encoded as a fr field element (32 bytes)
296+
// - 16 affine elements (curve base field fq) encoded as fr elements takes (16 * 4 * 32 bytes)
297+
// 16 above refers to the constant AvmFlavor::NUM_PRECOMPUTED_ENTITIES
298+
global AVM_VERIFICATION_KEY_LENGTH_IN_FIELDS = 2 + 16 * 4;
293299

294300
/**
295301
* Enumerate the hash_indices which are used for pedersen hashing.

yarn-project/bb-prover/src/avm_proving.test.ts

+5-12
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import {
22
AvmCircuitInputs,
3+
AvmVerificationKeyData,
34
AztecAddress,
45
ContractStorageRead,
56
ContractStorageUpdateRequest,
@@ -49,7 +50,7 @@ import path from 'path';
4950
import { PublicSideEffectTrace } from '../../simulator/src/public/side_effect_trace.js';
5051
import { SerializableContractInstance } from '../../types/src/contracts/contract_instance.js';
5152
import { type BBSuccess, BB_RESULT, generateAvmProof, verifyAvmProof } from './bb/execute.js';
52-
import { extractVkData } from './verification_key/verification_key_data.js';
53+
import { extractAvmVkData } from './verification_key/verification_key_data.js';
5354

5455
const TIMEOUT = 60_000;
5556
const TIMESTAMP = new Fr(99833);
@@ -279,18 +280,10 @@ const proveAndVerifyAvmTestContract = async (
279280
const proofRes = await generateAvmProof(bbPath, bbWorkingDirectory, avmCircuitInputs, logger);
280281
expect(proofRes.status).toEqual(BB_RESULT.SUCCESS);
281282

282-
// Then we test VK extraction.
283+
// Then we test VK extraction and serialization.
283284
const succeededRes = proofRes as BBSuccess;
284-
const verificationKey = await extractVkData(succeededRes.vkPath!);
285-
286-
// VK is composed of
287-
// - circuit size encoded as a fr field element (32 bytes)
288-
// - num of inputs encoded as a fr field element (32 bytes)
289-
// - 16 affine elements (curve base field fq) encoded as fr elements takes (16 * 4 * 32 bytes)
290-
// 16 above refers to the constant AvmFlavor::NUM_PRECOMPUTED_ENTITIES
291-
// Total number of bytes = 2112
292-
const NUM_PRECOMPUTED_ENTITIES = 16;
293-
expect(verificationKey.keyAsBytes).toHaveLength(NUM_PRECOMPUTED_ENTITIES * 4 * 32 + 2 * 32);
285+
const vkData = await extractAvmVkData(succeededRes.vkPath!);
286+
AvmVerificationKeyData.fromBuffer(vkData.toBuffer());
294287

295288
// Then we verify.
296289
const rawVkPath = path.join(succeededRes.vkPath!, 'vk');

yarn-project/bb-prover/src/prover/bb_prover.ts

+9-8
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/* eslint-disable require-await */
22
import {
3-
type ProofAndVerificationKey,
3+
type AvmProofAndVerificationKey,
44
type PublicInputsAndRecursiveProof,
55
type PublicKernelNonTailRequest,
66
type PublicKernelTailRequest,
@@ -11,6 +11,7 @@ import { type CircuitProvingStats, type CircuitWitnessGenerationStats } from '@a
1111
import {
1212
AGGREGATION_OBJECT_LENGTH,
1313
type AvmCircuitInputs,
14+
type AvmVerificationKeyData,
1415
type BaseOrMergeRollupPublicInputs,
1516
type BaseParityInputs,
1617
type BaseRollupInputs,
@@ -94,7 +95,7 @@ import type { ACVMConfig, BBConfig } from '../config.js';
9495
import { ProverInstrumentation } from '../instrumentation.js';
9596
import { PublicKernelArtifactMapping } from '../mappings/mappings.js';
9697
import { mapProtocolArtifactNameToCircuitName } from '../stats.js';
97-
import { extractVkData } from '../verification_key/verification_key_data.js';
98+
import { extractAvmVkData, extractVkData } from '../verification_key/verification_key_data.js';
9899

99100
const logger = createDebugLogger('aztec:bb-prover');
100101

@@ -202,7 +203,7 @@ export class BBNativeRollupProver implements ServerCircuitProver {
202203
@trackSpan('BBNativeRollupProver.getAvmProof', inputs => ({
203204
[Attributes.APP_CIRCUIT_NAME]: inputs.functionName,
204205
}))
205-
public async getAvmProof(inputs: AvmCircuitInputs): Promise<ProofAndVerificationKey> {
206+
public async getAvmProof(inputs: AvmCircuitInputs): Promise<AvmProofAndVerificationKey> {
206207
const proofAndVk = await this.createAvmProof(inputs);
207208
await this.verifyAvmProof(proofAndVk.proof, proofAndVk.verificationKey);
208209
return proofAndVk;
@@ -626,14 +627,14 @@ export class BBNativeRollupProver implements ServerCircuitProver {
626627
return provingResult;
627628
}
628629

629-
private async createAvmProof(input: AvmCircuitInputs): Promise<ProofAndVerificationKey> {
630-
const operation = async (bbWorkingDirectory: string): Promise<ProofAndVerificationKey> => {
630+
private async createAvmProof(input: AvmCircuitInputs): Promise<AvmProofAndVerificationKey> {
631+
const operation = async (bbWorkingDirectory: string): Promise<AvmProofAndVerificationKey> => {
631632
const provingResult = await this.generateAvmProofWithBB(input, bbWorkingDirectory);
632633

633634
const rawProof = await fs.readFile(provingResult.proofPath!);
634635
// TODO(https://github.com/AztecProtocol/aztec-packages/issues/6773): this VK data format is wrong.
635636
// In particular, the number of public inputs, etc will be wrong.
636-
const verificationKey = await extractVkData(provingResult.vkPath!);
637+
const verificationKey = await extractAvmVkData(provingResult.vkPath!);
637638
const proof = new Proof(rawProof, verificationKey.numPublicInputs);
638639

639640
const circuitType = 'avm-circuit' as const;
@@ -765,7 +766,7 @@ export class BBNativeRollupProver implements ServerCircuitProver {
765766
return await this.verifyWithKey(verificationKey, proof);
766767
}
767768

768-
public async verifyAvmProof(proof: Proof, verificationKey: VerificationKeyData) {
769+
public async verifyAvmProof(proof: Proof, verificationKey: AvmVerificationKeyData) {
769770
return await this.verifyWithKeyInternal(proof, verificationKey, verifyAvmProof);
770771
}
771772

@@ -775,7 +776,7 @@ export class BBNativeRollupProver implements ServerCircuitProver {
775776

776777
private async verifyWithKeyInternal(
777778
proof: Proof,
778-
verificationKey: VerificationKeyData,
779+
verificationKey: { keyAsBytes: Buffer },
779780
verificationFunction: VerificationFunction,
780781
) {
781782
const operation = async (bbWorkingDirectory: string) => {

yarn-project/bb-prover/src/test/test_circuit_prover.ts

+4-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import {
2-
type ProofAndVerificationKey,
2+
type AvmProofAndVerificationKey,
33
type PublicInputsAndRecursiveProof,
44
type PublicKernelNonTailRequest,
55
type PublicKernelTailRequest,
@@ -8,6 +8,7 @@ import {
88
} from '@aztec/circuit-types';
99
import {
1010
type AvmCircuitInputs,
11+
AvmVerificationKeyData,
1112
type BaseOrMergeRollupPublicInputs,
1213
type BaseParityInputs,
1314
type BaseRollupInputs,
@@ -475,12 +476,12 @@ export class TestCircuitProver implements ServerCircuitProver {
475476
);
476477
}
477478

478-
public async getAvmProof(_inputs: AvmCircuitInputs): Promise<ProofAndVerificationKey> {
479+
public async getAvmProof(_inputs: AvmCircuitInputs): Promise<AvmProofAndVerificationKey> {
479480
// We can't simulate the AVM because we don't have enough context to do so (e.g., DBs).
480481
// We just return an empty proof and VK data.
481482
this.logger.debug('Skipping AVM simulation in TestCircuitProver.');
482483
await this.delay();
483-
return { proof: makeEmptyProof(), verificationKey: VerificationKeyData.makeFake() };
484+
return { proof: makeEmptyProof(), verificationKey: AvmVerificationKeyData.makeFake() };
484485
}
485486

486487
private async delay(): Promise<void> {

yarn-project/bb-prover/src/verification_key/verification_key_data.ts

+23-1
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
11
import {
2+
AVM_VERIFICATION_KEY_LENGTH_IN_FIELDS,
3+
AvmVerificationKeyAsFields,
4+
AvmVerificationKeyData,
25
Fr,
3-
type VERIFICATION_KEY_LENGTH_IN_FIELDS,
6+
VERIFICATION_KEY_LENGTH_IN_FIELDS,
47
VerificationKeyAsFields,
58
VerificationKeyData,
69
} from '@aztec/circuits.js';
710
import { type Tuple } from '@aztec/foundation/serialize';
811

12+
import { strict as assert } from 'assert';
913
import * as fs from 'fs/promises';
1014
import * as path from 'path';
1115

@@ -25,7 +29,25 @@ export async function extractVkData(vkDirectoryPath: string): Promise<Verificati
2529
const fields = fieldsJson.map(Fr.fromString);
2630
// The first item is the hash, this is not part of the actual VK
2731
const vkHash = fields[0];
32+
assert(fields.length === VERIFICATION_KEY_LENGTH_IN_FIELDS, 'Invalid verification key length');
2833
const vkAsFields = new VerificationKeyAsFields(fields as Tuple<Fr, typeof VERIFICATION_KEY_LENGTH_IN_FIELDS>, vkHash);
2934
const vk = new VerificationKeyData(vkAsFields, rawBinary);
3035
return vk;
3136
}
37+
38+
// TODO: This was adapted from the above function. A refactor might be needed.
39+
export async function extractAvmVkData(vkDirectoryPath: string): Promise<AvmVerificationKeyData> {
40+
const [rawFields, rawBinary] = await Promise.all([
41+
fs.readFile(path.join(vkDirectoryPath, VK_FIELDS_FILENAME), { encoding: 'utf-8' }),
42+
fs.readFile(path.join(vkDirectoryPath, VK_FILENAME)),
43+
]);
44+
const fieldsJson = JSON.parse(rawFields);
45+
const fields = fieldsJson.map(Fr.fromString);
46+
// The first item is the hash, this is not part of the actual VK
47+
// TODO: is the above actually the case?
48+
const vkHash = fields[0];
49+
assert(fields.length === AVM_VERIFICATION_KEY_LENGTH_IN_FIELDS, 'Invalid AVM verification key length');
50+
const vkAsFields = new AvmVerificationKeyAsFields(fields, vkHash);
51+
const vk = new AvmVerificationKeyData(vkAsFields, rawBinary);
52+
return vk;
53+
}

yarn-project/circuit-types/src/interfaces/proving-job.ts

+4-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import {
22
type AvmCircuitInputs,
3+
type AvmVerificationKeyData,
34
type BaseOrMergeRollupPublicInputs,
45
type BaseParityInputs,
56
type BaseRollupInputs,
@@ -25,9 +26,9 @@ import {
2526

2627
import type { PublicKernelNonTailRequest, PublicKernelTailRequest } from '../tx/processed_tx.js';
2728

28-
export type ProofAndVerificationKey = {
29+
export type AvmProofAndVerificationKey = {
2930
proof: Proof;
30-
verificationKey: VerificationKeyData;
31+
verificationKey: AvmVerificationKeyData;
3132
};
3233

3334
export type PublicInputsAndRecursiveProof<T> = {
@@ -133,7 +134,7 @@ export type ProvingRequest =
133134

134135
export type ProvingRequestPublicInputs = {
135136
[ProvingRequestType.PRIVATE_KERNEL_EMPTY]: PublicInputsAndRecursiveProof<KernelCircuitPublicInputs>;
136-
[ProvingRequestType.PUBLIC_VM]: ProofAndVerificationKey;
137+
[ProvingRequestType.PUBLIC_VM]: AvmProofAndVerificationKey;
137138

138139
[ProvingRequestType.PUBLIC_KERNEL_NON_TAIL]: PublicInputsAndRecursiveProof<PublicKernelCircuitPublicInputs>;
139140
[ProvingRequestType.PUBLIC_KERNEL_TAIL]: PublicInputsAndRecursiveProof<KernelCircuitPublicInputs>;

yarn-project/circuit-types/src/interfaces/server_circuit_prover.ts

+6-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import {
2-
type ProofAndVerificationKey,
2+
type AvmProofAndVerificationKey,
33
type PublicInputsAndRecursiveProof,
44
type PublicInputsAndTubeProof,
55
type PublicKernelNonTailRequest,
@@ -149,7 +149,11 @@ export interface ServerCircuitProver {
149149
* Create a proof for the AVM circuit.
150150
* @param inputs - Inputs to the AVM circuit.
151151
*/
152-
getAvmProof(inputs: AvmCircuitInputs, signal?: AbortSignal, epochNumber?: number): Promise<ProofAndVerificationKey>;
152+
getAvmProof(
153+
inputs: AvmCircuitInputs,
154+
signal?: AbortSignal,
155+
epochNumber?: number,
156+
): Promise<AvmProofAndVerificationKey>;
153157
}
154158

155159
/**

yarn-project/circuits.js/src/constants.gen.ts

+1
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,7 @@ export const RECURSIVE_PROOF_LENGTH = 439;
202202
export const NESTED_RECURSIVE_PROOF_LENGTH = 439;
203203
export const TUBE_PROOF_LENGTH = 439;
204204
export const VERIFICATION_KEY_LENGTH_IN_FIELDS = 128;
205+
export const AVM_VERIFICATION_KEY_LENGTH_IN_FIELDS = 66;
205206
export const SENDER_SELECTOR = 0;
206207
export const ADDRESS_SELECTOR = 1;
207208
export const STORAGE_ADDRESS_SELECTOR = 1;

0 commit comments

Comments
 (0)