Skip to content

Commit

Permalink
fix(bb-prover): create structure for AVM vk
Browse files Browse the repository at this point in the history
  • Loading branch information
fcarreiro committed Aug 27, 2024
1 parent 5929a42 commit 4ad20a6
Show file tree
Hide file tree
Showing 11 changed files with 188 additions and 19 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#include "barretenberg/vm/avm/generated/flavor.hpp"
#include "barretenberg/vm/avm/tests/helpers.test.hpp"
#include "barretenberg/vm/avm/trace/helper.hpp"
#include "barretenberg/vm/aztec_constants.hpp"
#include "barretenberg/vm/constants.hpp"
#include "common.test.hpp"

namespace tests_avm {

using namespace bb;

TEST(AvmTests, VerificationKeySizeMatches)
{
srs::init_crs_factory("../srs_db/ignition");

auto circuit_builder = AvmCircuitBuilder();
circuit_builder.set_trace({});

AvmComposer composer = AvmComposer();
AvmVerifier verifier = composer.create_verifier(circuit_builder);

EXPECT_EQ(verifier.key->size(), AVM_VERIFICATION_KEY_LENGTH_IN_FIELDS);
}

} // namespace tests_avm
1 change: 1 addition & 0 deletions barretenberg/cpp/src/barretenberg/vm/aztec_constants.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
#define HEADER_LENGTH 24
#define PUBLIC_CIRCUIT_PUBLIC_INPUTS_LENGTH 691
#define PUBLIC_CONTEXT_INPUTS_LENGTH 42
#define AVM_VERIFICATION_KEY_LENGTH_IN_FIELDS 16
#define SENDER_SELECTOR 0
#define ADDRESS_SELECTOR 1
#define STORAGE_ADDRESS_SELECTOR 1
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,7 @@ global NESTED_RECURSIVE_PROOF_LENGTH = 439;
global TUBE_PROOF_LENGTH = RECURSIVE_PROOF_LENGTH; // in the future these can differ

global VERIFICATION_KEY_LENGTH_IN_FIELDS = 128;
global AVM_VERIFICATION_KEY_LENGTH_IN_FIELDS = 16;

/**
* Enumerate the hash_indices which are used for pedersen hashing.
Expand Down
17 changes: 9 additions & 8 deletions yarn-project/bb-prover/src/prover/bb_prover.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* eslint-disable require-await */
import {
type ProofAndVerificationKey,
type AvmProofAndVerificationKey,
type PublicInputsAndRecursiveProof,
type PublicKernelNonTailRequest,
type PublicKernelTailRequest,
Expand All @@ -11,6 +11,7 @@ import { type CircuitProvingStats, type CircuitWitnessGenerationStats } from '@a
import {
AGGREGATION_OBJECT_LENGTH,
type AvmCircuitInputs,
type AvmVerificationKeyData,
type BaseOrMergeRollupPublicInputs,
type BaseParityInputs,
type BaseRollupInputs,
Expand Down Expand Up @@ -94,7 +95,7 @@ import type { ACVMConfig, BBConfig } from '../config.js';
import { ProverInstrumentation } from '../instrumentation.js';
import { PublicKernelArtifactMapping } from '../mappings/mappings.js';
import { mapProtocolArtifactNameToCircuitName } from '../stats.js';
import { extractVkData } from '../verification_key/verification_key_data.js';
import { extractAvmVkData, extractVkData } from '../verification_key/verification_key_data.js';

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

Expand Down Expand Up @@ -202,7 +203,7 @@ export class BBNativeRollupProver implements ServerCircuitProver {
@trackSpan('BBNativeRollupProver.getAvmProof', inputs => ({
[Attributes.APP_CIRCUIT_NAME]: inputs.functionName,
}))
public async getAvmProof(inputs: AvmCircuitInputs): Promise<ProofAndVerificationKey> {
public async getAvmProof(inputs: AvmCircuitInputs): Promise<AvmProofAndVerificationKey> {
const proofAndVk = await this.createAvmProof(inputs);
await this.verifyAvmProof(proofAndVk.proof, proofAndVk.verificationKey);
return proofAndVk;
Expand Down Expand Up @@ -626,14 +627,14 @@ export class BBNativeRollupProver implements ServerCircuitProver {
return provingResult;
}

private async createAvmProof(input: AvmCircuitInputs): Promise<ProofAndVerificationKey> {
const operation = async (bbWorkingDirectory: string): Promise<ProofAndVerificationKey> => {
private async createAvmProof(input: AvmCircuitInputs): Promise<AvmProofAndVerificationKey> {
const operation = async (bbWorkingDirectory: string): Promise<AvmProofAndVerificationKey> => {
const provingResult = await this.generateAvmProofWithBB(input, bbWorkingDirectory);

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

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

public async verifyAvmProof(proof: Proof, verificationKey: VerificationKeyData) {
public async verifyAvmProof(proof: Proof, verificationKey: AvmVerificationKeyData) {
return await this.verifyWithKeyInternal(proof, verificationKey, verifyAvmProof);
}

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

private async verifyWithKeyInternal(
proof: Proof,
verificationKey: VerificationKeyData,
verificationKey: { keyAsBytes: Buffer },
verificationFunction: VerificationFunction,
) {
const operation = async (bbWorkingDirectory: string) => {
Expand Down
7 changes: 4 additions & 3 deletions yarn-project/bb-prover/src/test/test_circuit_prover.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {
type ProofAndVerificationKey,
type AvmProofAndVerificationKey,
type PublicInputsAndRecursiveProof,
type PublicKernelNonTailRequest,
type PublicKernelTailRequest,
Expand All @@ -8,6 +8,7 @@ import {
} from '@aztec/circuit-types';
import {
type AvmCircuitInputs,
AvmVerificationKeyData,
type BaseOrMergeRollupPublicInputs,
type BaseParityInputs,
type BaseRollupInputs,
Expand Down Expand Up @@ -475,12 +476,12 @@ export class TestCircuitProver implements ServerCircuitProver {
);
}

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

private async delay(): Promise<void> {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import {
type AVM_VERIFICATION_KEY_LENGTH_IN_FIELDS,
AvmVerificationKeyAsFields,
AvmVerificationKeyData,
Fr,
type VERIFICATION_KEY_LENGTH_IN_FIELDS,
VerificationKeyAsFields,
Expand Down Expand Up @@ -29,3 +32,20 @@ export async function extractVkData(vkDirectoryPath: string): Promise<Verificati
const vk = new VerificationKeyData(vkAsFields, rawBinary);
return vk;
}

export async function extractAvmVkData(vkDirectoryPath: string): Promise<AvmVerificationKeyData> {
const [rawFields, rawBinary] = await Promise.all([
fs.readFile(path.join(vkDirectoryPath, VK_FIELDS_FILENAME), { encoding: 'utf-8' }),
fs.readFile(path.join(vkDirectoryPath, VK_FILENAME)),
]);
const fieldsJson = JSON.parse(rawFields);
const fields = fieldsJson.map(Fr.fromString);
// The first item is the hash, this is not part of the actual VK
const vkHash = fields[0];
const vkAsFields = new AvmVerificationKeyAsFields(
fields as Tuple<Fr, typeof AVM_VERIFICATION_KEY_LENGTH_IN_FIELDS>,
vkHash,
);
const vk = new AvmVerificationKeyData(vkAsFields, rawBinary);
return vk;
}
7 changes: 4 additions & 3 deletions yarn-project/circuit-types/src/interfaces/proving-job.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import {
type AvmCircuitInputs,
type AvmVerificationKeyData,
type BaseOrMergeRollupPublicInputs,
type BaseParityInputs,
type BaseRollupInputs,
Expand All @@ -25,9 +26,9 @@ import {

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

export type ProofAndVerificationKey = {
export type AvmProofAndVerificationKey = {
proof: Proof;
verificationKey: VerificationKeyData;
verificationKey: AvmVerificationKeyData;
};

export type PublicInputsAndRecursiveProof<T> = {
Expand Down Expand Up @@ -133,7 +134,7 @@ export type ProvingRequest =

export type ProvingRequestPublicInputs = {
[ProvingRequestType.PRIVATE_KERNEL_EMPTY]: PublicInputsAndRecursiveProof<KernelCircuitPublicInputs>;
[ProvingRequestType.PUBLIC_VM]: ProofAndVerificationKey;
[ProvingRequestType.PUBLIC_VM]: AvmProofAndVerificationKey;

[ProvingRequestType.PUBLIC_KERNEL_NON_TAIL]: PublicInputsAndRecursiveProof<PublicKernelCircuitPublicInputs>;
[ProvingRequestType.PUBLIC_KERNEL_TAIL]: PublicInputsAndRecursiveProof<KernelCircuitPublicInputs>;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {
type ProofAndVerificationKey,
type AvmProofAndVerificationKey,
type PublicInputsAndRecursiveProof,
type PublicInputsAndTubeProof,
type PublicKernelNonTailRequest,
Expand Down Expand Up @@ -149,7 +149,11 @@ export interface ServerCircuitProver {
* Create a proof for the AVM circuit.
* @param inputs - Inputs to the AVM circuit.
*/
getAvmProof(inputs: AvmCircuitInputs, signal?: AbortSignal, epochNumber?: number): Promise<ProofAndVerificationKey>;
getAvmProof(
inputs: AvmCircuitInputs,
signal?: AbortSignal,
epochNumber?: number,
): Promise<AvmProofAndVerificationKey>;
}

/**
Expand Down
1 change: 1 addition & 0 deletions yarn-project/circuits.js/src/constants.gen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,7 @@ export const RECURSIVE_PROOF_LENGTH = 439;
export const NESTED_RECURSIVE_PROOF_LENGTH = 439;
export const TUBE_PROOF_LENGTH = 439;
export const VERIFICATION_KEY_LENGTH_IN_FIELDS = 128;
export const AVM_VERIFICATION_KEY_LENGTH_IN_FIELDS = 16;
export const SENDER_SELECTOR = 0;
export const ADDRESS_SELECTOR = 1;
export const STORAGE_ADDRESS_SELECTOR = 1;
Expand Down
112 changes: 111 additions & 1 deletion yarn-project/circuits.js/src/structs/verification_key.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { times } from '@aztec/foundation/collection';
import { Fq, Fr } from '@aztec/foundation/fields';
import { BufferReader, type Tuple, serializeToBuffer } from '@aztec/foundation/serialize';

import { VERIFICATION_KEY_LENGTH_IN_FIELDS } from '../constants.gen.js';
import { AVM_VERIFICATION_KEY_LENGTH_IN_FIELDS, VERIFICATION_KEY_LENGTH_IN_FIELDS } from '../constants.gen.js';
import { CircuitType } from './shared.js';

/**
Expand Down Expand Up @@ -135,6 +135,68 @@ export class VerificationKeyAsFields {
}
}

/**
* Provides a 'fields' representation of the AVM's verification key
*/
export class AvmVerificationKeyAsFields {
constructor(public key: Tuple<Fr, typeof AVM_VERIFICATION_KEY_LENGTH_IN_FIELDS>, public hash: Fr) {}

public get numPublicInputs() {
return Number(this.key[CIRCUIT_PUBLIC_INPUTS_INDEX]);
}

public get circuitSize() {
return Number(this.key[CIRCUIT_SIZE_INDEX]);
}

public get isRecursive() {
return this.key[CIRCUIT_RECURSIVE_INDEX] == Fr.ONE;
}

/**
* Serialize as a buffer.
* @returns The buffer.
*/
toBuffer() {
return serializeToBuffer(this.key, this.hash);
}
toFields() {
return [...this.key, this.hash];
}

/**
* Deserializes from a buffer or reader, corresponding to a write in cpp.
* @param buffer - Buffer to read from.
* @returns The AvmVerificationKeyAsFields.
*/
static fromBuffer(buffer: Buffer | BufferReader): AvmVerificationKeyAsFields {
const reader = BufferReader.asReader(buffer);
return new AvmVerificationKeyAsFields(
reader.readArray(AVM_VERIFICATION_KEY_LENGTH_IN_FIELDS, Fr),
reader.readObject(Fr),
);
}

/**
* Builds a fake verification key that should be accepted by circuits.
* @returns A fake verification key.
*/
static makeFake(seed = 1): AvmVerificationKeyAsFields {
return new AvmVerificationKeyAsFields(
makeTuple(AVM_VERIFICATION_KEY_LENGTH_IN_FIELDS, Fr.random, seed),
Fr.random(),
);
}

/**
* Builds an 'empty' verification key
* @returns An 'empty' verification key
*/
static makeEmpty(): AvmVerificationKeyAsFields {
return new AvmVerificationKeyAsFields(makeTuple(AVM_VERIFICATION_KEY_LENGTH_IN_FIELDS, Fr.zero), Fr.zero());
}
}

export class VerificationKey {
constructor(
/**
Expand Down Expand Up @@ -257,3 +319,51 @@ export class VerificationKeyData {
return VerificationKeyData.fromBuffer(this.toBuffer());
}
}

export class AvmVerificationKeyData {
constructor(public readonly keyAsFields: AvmVerificationKeyAsFields, public readonly keyAsBytes: Buffer) {}

public get numPublicInputs() {
return this.keyAsFields.numPublicInputs;
}

public get circuitSize() {
return this.keyAsFields.circuitSize;
}

public get isRecursive() {
return this.keyAsFields.isRecursive;
}

static makeFake(): AvmVerificationKeyData {
return new AvmVerificationKeyData(AvmVerificationKeyAsFields.makeFake(), VerificationKey.makeFake().toBuffer());
}

/**
* Serialize as a buffer.
* @returns The buffer.
*/
toBuffer() {
return serializeToBuffer(this.keyAsFields, this.keyAsBytes.length, this.keyAsBytes);
}

toString() {
return this.toBuffer().toString('hex');
}

static fromBuffer(buffer: Buffer | BufferReader): AvmVerificationKeyData {
const reader = BufferReader.asReader(buffer);
const verificationKeyAsFields = reader.readObject(AvmVerificationKeyAsFields);
const length = reader.readNumber();
const bytes = reader.readBytes(length);
return new AvmVerificationKeyData(verificationKeyAsFields, bytes);
}

static fromString(str: string): AvmVerificationKeyData {
return AvmVerificationKeyData.fromBuffer(Buffer.from(str, 'hex'));
}

public clone() {
return AvmVerificationKeyData.fromBuffer(this.toBuffer());
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {
type ProofAndVerificationKey,
type AvmProofAndVerificationKey,
type ProvingJob,
type ProvingJobSource,
type ProvingRequest,
Expand Down Expand Up @@ -408,7 +408,11 @@ export class MemoryProvingQueue implements ServerCircuitProver, ProvingJobSource
/**
* Creates an AVM proof.
*/
getAvmProof(inputs: AvmCircuitInputs, signal?: AbortSignal, epochNumber?: number): Promise<ProofAndVerificationKey> {
getAvmProof(
inputs: AvmCircuitInputs,
signal?: AbortSignal,
epochNumber?: number,
): Promise<AvmProofAndVerificationKey> {
return this.enqueue({ type: ProvingRequestType.PUBLIC_VM, inputs }, signal, epochNumber);
}

Expand Down

0 comments on commit 4ad20a6

Please sign in to comment.