Skip to content

Commit

Permalink
feat: benchmark private proving
Browse files Browse the repository at this point in the history
  • Loading branch information
alexghr committed May 15, 2024
1 parent 8f6fa34 commit 35733a6
Show file tree
Hide file tree
Showing 15 changed files with 346 additions and 232 deletions.
37 changes: 35 additions & 2 deletions yarn-project/bb-prover/src/prover/bb_native_proof_creator.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { type AppCircuitProofOutput, type KernelProofOutput, type ProofCreator } from '@aztec/circuit-types';
import { type CircuitProvingStats, type CircuitWitnessGenerationStats } from '@aztec/circuit-types/stats';
import {
Fr,
NESTED_RECURSIVE_PROOF_LENGTH,
Expand All @@ -18,6 +19,7 @@ import { siloNoteHash } from '@aztec/circuits.js/hash';
import { randomBytes } from '@aztec/foundation/crypto';
import { createDebugLogger } from '@aztec/foundation/log';
import { type Tuple } from '@aztec/foundation/serialize';
import { Timer } from '@aztec/foundation/timer';
import {
ClientCircuitArtifacts,
type ClientProtocolArtifact,
Expand Down Expand Up @@ -47,6 +49,7 @@ import {
generateProof,
verifyProof,
} from '../bb/execute.js';
import { mapProtocolArtifactNameToCircuitName } from '../stats.js';
import {
AGGREGATION_OBJECT_SIZE,
CIRCUIT_PUBLIC_INPUTS_INDEX,
Expand Down Expand Up @@ -128,13 +131,14 @@ export class BBNativeProofCreator implements ProofCreator {
public async createAppCircuitProof(
partialWitness: Map<number, ACVMField>,
bytecode: Buffer,
appCircuitName?: string,
): Promise<AppCircuitProofOutput> {
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 proofOutput = await this.createProof(directory, partialWitness, bytecode, 'App');
const proofOutput = await this.createProof(directory, partialWitness, bytecode, 'App', appCircuitName);
if (proofOutput.proof.proof.length != RECURSIVE_PROOF_LENGTH) {
throw new Error(`Incorrect proof length`);
}
Expand Down Expand Up @@ -286,9 +290,16 @@ export class BBNativeProofCreator implements ProofCreator {
this.log.debug(`Generating witness for ${circuitType}`);
const compiledCircuit: NoirCompiledCircuit = ClientCircuitArtifacts[circuitType];

const timer = new Timer();
const outputWitness = await this.simulator.simulateCircuit(inputs, compiledCircuit);

this.log.debug(`Generated witness for ${circuitType}`);
this.log.debug(`Generated witness for ${circuitType}`, {
eventName: 'circuit-witness-generation',
circuitName: mapProtocolArtifactNameToCircuitName(circuitType),
duration: timer.ms(),
inputSize: inputs.size * Fr.SIZE_IN_BYTES,
outputSize: outputWitness.size * Fr.SIZE_IN_BYTES,
} satisfies CircuitWitnessGenerationStats);

const publicInputs = PrivateKernelArtifactMapping[circuitType].convertOutputs(outputWitness) as T;

Expand Down Expand Up @@ -316,6 +327,7 @@ export class BBNativeProofCreator implements ProofCreator {
partialWitness: WitnessMap,
bytecode: Buffer,
circuitType: ClientProtocolArtifact | 'App',
appCircuitName?: string,
): Promise<{
proof: RecursiveProof<typeof RECURSIVE_PROOF_LENGTH> | RecursiveProof<typeof NESTED_RECURSIVE_PROOF_LENGTH>;
verificationKey: VerificationKeyAsFields;
Expand Down Expand Up @@ -345,11 +357,32 @@ export class BBNativeProofCreator implements ProofCreator {
if (circuitType === 'App') {
const vkData = await this.convertVk(directory);
const proof = await this.readProofAsFields<typeof RECURSIVE_PROOF_LENGTH>(directory, circuitType, vkData);

this.log.debug(`Generated proof`, {
eventName: 'circuit-proving',
circuitName: 'private-app-circuit',
duration: provingResult.duration,
inputSize: partialWitness.size * Fr.SIZE_IN_BYTES,
proofSize: proof.binaryProof.buffer.byteLength,
appCircuitName,
circuitSize: vkData.circuitSize,
} as CircuitProvingStats);

return { proof, verificationKey: new VerificationKeyAsFields(vkData.keyAsFields, vkData.hash) };
}

const vkData = await this.updateVerificationKeyAfterProof(directory, circuitType);
const proof = await this.readProofAsFields<typeof NESTED_RECURSIVE_PROOF_LENGTH>(directory, circuitType, vkData);

this.log.debug(`Generated proof`, {
circuitName: mapProtocolArtifactNameToCircuitName(circuitType),
duration: provingResult.duration,
eventName: 'circuit-proving',
inputSize: partialWitness.size * Fr.SIZE_IN_BYTES,
proofSize: proof.binaryProof.buffer.byteLength,
circuitSize: vkData.circuitSize,
} as CircuitProvingStats);

return { proof, verificationKey: new VerificationKeyAsFields(vkData.keyAsFields, vkData.hash) };
}

Expand Down
79 changes: 40 additions & 39 deletions yarn-project/bb-prover/src/prover/bb_prover.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
type ServerCircuitProver,
makePublicInputsAndProof,
} from '@aztec/circuit-types';
import { type CircuitProvingStats, type CircuitWitnessGenerationStats } from '@aztec/circuit-types/stats';
import {
type BaseOrMergeRollupPublicInputs,
type BaseParityInputs,
Expand Down Expand Up @@ -65,7 +66,7 @@ import {
verifyProof,
} from '../bb/execute.js';
import { PublicKernelArtifactMapping } from '../mappings/mappings.js';
import { circuitTypeToCircuitName, emitCircuitProvingStats, emitCircuitWitnessGenerationStats } from '../stats.js';
import { mapProtocolArtifactNameToCircuitName } from '../stats.js';
import {
AGGREGATION_OBJECT_SIZE,
CIRCUIT_PUBLIC_INPUTS_INDEX,
Expand Down Expand Up @@ -267,13 +268,13 @@ export class BBNativeRollupProver implements ServerCircuitProver {

const timer = new Timer();
const outputWitness = await simulator.simulateCircuit(witnessMap, artifact);
emitCircuitWitnessGenerationStats(
circuitTypeToCircuitName(circuitType),
timer.ms(),
witnessMap.size * Fr.SIZE_IN_BYTES,
outputWitness.size * Fr.SIZE_IN_BYTES,
logger,
);
logger.debug(`Generated witness`, {
circuitName: mapProtocolArtifactNameToCircuitName(circuitType),
duration: timer.ms(),
inputSize: witnessMap.size * Fr.SIZE_IN_BYTES,
outputSize: outputWitness.size * Fr.SIZE_IN_BYTES,
eventName: 'circuit-witness-generation',
} satisfies CircuitWitnessGenerationStats);

// Now prove the circuit from the generated witness
logger.debug(`Proving ${circuitType}...`);
Expand All @@ -293,24 +294,22 @@ export class BBNativeRollupProver implements ServerCircuitProver {
}

// Ensure our vk cache is up to date
await this.updateVerificationKeyAfterProof(provingResult.vkPath!, circuitType);
const vkData = await this.updateVerificationKeyAfterProof(provingResult.vkPath!, circuitType);

// Read the proof and then cleanup up our temporary directory
const proof = await fs.readFile(`${provingResult.proofPath!}/${PROOF_FILENAME}`);

// does not include reading the proof from disk above because duration comes from the bb wrapper
emitCircuitProvingStats(
circuitTypeToCircuitName(circuitType),
provingResult.duration,
witnessMap.size * Fr.SIZE_IN_BYTES,
outputWitness.size * Fr.SIZE_IN_BYTES,
proof.length,
logger,
);

await fs.rm(bbWorkingDirectory, { recursive: true, force: true });

logger.info(`Generated proof for ${circuitType} in ${provingResult.duration} ms, size: ${proof.length} fields`);
logger.info(`Generated proof for ${circuitType} in ${provingResult.duration} ms, size: ${proof.length} fields`, {
circuitName: mapProtocolArtifactNameToCircuitName(circuitType),
// does not include reading the proof from disk
duration: provingResult.duration,
proofSize: proof.length,
eventName: 'circuit-proving',
inputSize: witnessMap.size * Fr.SIZE_IN_BYTES,
circuitSize: vkData.circuitSize,
} satisfies CircuitProvingStats);

return [outputWitness, new Proof(proof)];
}
Expand Down Expand Up @@ -352,13 +351,13 @@ export class BBNativeRollupProver implements ServerCircuitProver {
const timer = new Timer();
const outputWitness = await simulator.simulateCircuit(witnessMap, artifact);

emitCircuitWitnessGenerationStats(
circuitTypeToCircuitName(circuitType),
timer.ms(),
witnessMap.size * Fr.SIZE_IN_BYTES,
outputWitness.size * Fr.SIZE_IN_BYTES,
logger,
);
logger.debug(`Generated witness`, {
circuitName: mapProtocolArtifactNameToCircuitName(circuitType),
duration: timer.ms(),
inputSize: witnessMap.size * Fr.SIZE_IN_BYTES,
outputSize: outputWitness.size * Fr.SIZE_IN_BYTES,
eventName: 'circuit-witness-generation',
} satisfies CircuitWitnessGenerationStats);

const outputType = convertOutput(outputWitness);

Expand All @@ -380,22 +379,21 @@ export class BBNativeRollupProver implements ServerCircuitProver {
}

// Ensure our vk cache is up to date
await this.updateVerificationKeyAfterProof(provingResult.vkPath!, circuitType);
const vkData = await this.updateVerificationKeyAfterProof(provingResult.vkPath!, circuitType);

// Read the proof and then cleanup up our temporary directory
const proof = await this.readProofAsFields<PROOF_LENGTH>(provingResult.proofPath!, circuitType);

logger.info(
`Generated proof for ${circuitType} in ${provingResult.duration} ms, size: ${proof.proof.length} fields`,
);

emitCircuitProvingStats(
circuitTypeToCircuitName(circuitType),
provingResult.duration,
witnessMap.size * Fr.SIZE_IN_BYTES,
outputWitness.size * Fr.SIZE_IN_BYTES,
proof.binaryProof.buffer.length,
logger,
{
circuitName: mapProtocolArtifactNameToCircuitName(circuitType),
circuitSize: vkData.circuitSize,
duration: provingResult.duration,
inputSize: witnessMap.size * Fr.SIZE_IN_BYTES,
proofSize: proof.binaryProof.buffer.length,
eventName: 'circuit-proving',
} satisfies CircuitProvingStats,
);

return [outputType, proof];
Expand Down Expand Up @@ -515,13 +513,16 @@ export class BBNativeRollupProver implements ServerCircuitProver {
* @param filePath - The directory containing the verification key data files
* @param circuitType - The type of circuit to which the verification key corresponds
*/
private async updateVerificationKeyAfterProof(filePath: string, circuitType: ServerProtocolArtifact) {
private async updateVerificationKeyAfterProof(
filePath: string,
circuitType: ServerProtocolArtifact,
): Promise<VerificationKeyData> {
let promise = this.verificationKeys.get(circuitType);
if (!promise) {
promise = this.convertVk(filePath);
this.verificationKeys.set(circuitType, promise);
}
await promise;
return promise;
}

/**
Expand Down
59 changes: 15 additions & 44 deletions yarn-project/bb-prover/src/stats.ts
Original file line number Diff line number Diff line change
@@ -1,45 +1,6 @@
import { type PublicKernelRequest, PublicKernelType } from '@aztec/circuit-types';
import type { CircuitName, CircuitProvingStats, CircuitWitnessGenerationStats } from '@aztec/circuit-types/stats';
import { type Logger } from '@aztec/foundation/log';
import { type ServerProtocolArtifact } from '@aztec/noir-protocol-circuits-types';

export function emitCircuitWitnessGenerationStats(
circuitName: CircuitName,
duration: number,
inputSize: number,
outputSize: number,
logger: Logger,
) {
const stats: CircuitWitnessGenerationStats = {
eventName: 'circuit-witness-generation',
circuitName,
inputSize,
outputSize,
duration,
};

logger.debug('Circuit witness generation stats', stats);
}

export function emitCircuitProvingStats(
circuitName: CircuitName,
duration: number,
inputSize: number,
outputSize: number,
proofSize: number,
logger: Logger,
) {
const stats: CircuitProvingStats = {
eventName: 'circuit-proving',
circuitName,
duration,
inputSize,
outputSize,
proofSize,
};

logger.debug('Circuit proving stats', stats);
}
import type { CircuitName } from '@aztec/circuit-types/stats';
import { type ClientProtocolArtifact, type ServerProtocolArtifact } from '@aztec/noir-protocol-circuits-types';

export function mapPublicKernelToCircuitName(kernelType: PublicKernelRequest['type']): CircuitName {
switch (kernelType) {
Expand All @@ -56,8 +17,10 @@ export function mapPublicKernelToCircuitName(kernelType: PublicKernelRequest['ty
}
}

export function circuitTypeToCircuitName(circuitType: ServerProtocolArtifact): CircuitName {
switch (circuitType) {
export function mapProtocolArtifactNameToCircuitName(
artifact: ServerProtocolArtifact | ClientProtocolArtifact,
): CircuitName {
switch (artifact) {
case 'BaseParityArtifact':
return 'base-parity';
case 'RootParityArtifact':
Expand All @@ -76,7 +39,15 @@ export function circuitTypeToCircuitName(circuitType: ServerProtocolArtifact): C
return 'public-kernel-teardown';
case 'PublicKernelTailArtifact':
return 'public-kernel-tail';
case 'PrivateKernelInitArtifact':
return 'private-kernel-init';
case 'PrivateKernelInnerArtifact':
return 'private-kernel-inner';
case 'PrivateKernelTailArtifact':
return 'private-kernel-tail';
case 'PrivateKernelTailToPublicArtifact':
return 'private-kernel-tail-to-public';
default:
throw new Error(`Unknown circuit type: ${circuitType}`);
throw new Error(`Unknown circuit type: ${artifact}`);
}
}
7 changes: 6 additions & 1 deletion yarn-project/circuit-types/src/interfaces/proof_creator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,12 @@ export interface ProofCreator {
*
* @param partialWitness - The witness produced via circuit simulation
* @param bytecode - The circuit bytecode in gzipped bincode format
* @param appCircuitName - Optionally specify the name of the app circuit
* @returns A Promise resolving to a Proof object
*/
createAppCircuitProof(partialWitness: WitnessMap, bytecode: Buffer): Promise<AppCircuitProofOutput>;
createAppCircuitProof(
partialWitness: WitnessMap,
bytecode: Buffer,
appCircuitName?: string,
): Promise<AppCircuitProofOutput>;
}
Loading

0 comments on commit 35733a6

Please sign in to comment.