Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions barretenberg/cpp/pil/vm2/constants_gen.pil
Original file line number Diff line number Diff line change
Expand Up @@ -165,9 +165,9 @@ namespace constants;
pol UPDATES_DELAYED_PUBLIC_MUTABLE_METADATA_BIT_SIZE = 144;
pol GRUMPKIN_ONE_X = 1;
pol GRUMPKIN_ONE_Y = 17631683881184975370165255887551781615748388533673675138860;
pol DOM_SEP__NOTE_HASH_NONCE = 1721808740;
pol DOM_SEP__UNIQUE_NOTE_HASH = 226850429;
pol DOM_SEP__SILOED_NOTE_HASH = 3361878420;
pol DOM_SEP__UNIQUE_NOTE_HASH = 226850429;
pol DOM_SEP__NOTE_HASH_NONCE = 1721808740;
pol DOM_SEP__SILOED_NULLIFIER = 57496191;
pol DOM_SEP__PUBLIC_LEAF_SLOT = 1247650290;
pol DOM_SEP__PUBLIC_STORAGE_MAP_SLOT = 4015149901;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -257,9 +257,9 @@
#define UPDATES_DELAYED_PUBLIC_MUTABLE_VALUES_LEN 3
#define UPDATES_DELAYED_PUBLIC_MUTABLE_METADATA_BIT_SIZE 144
#define DEFAULT_MAX_DEBUG_LOG_MEMORY_READS 125000
#define DOM_SEP__NOTE_HASH_NONCE 1721808740UL
#define DOM_SEP__UNIQUE_NOTE_HASH 226850429UL
#define DOM_SEP__SILOED_NOTE_HASH 3361878420UL
#define DOM_SEP__UNIQUE_NOTE_HASH 226850429UL
#define DOM_SEP__NOTE_HASH_NONCE 1721808740UL
#define DOM_SEP__SILOED_NULLIFIER 57496191UL
#define DOM_SEP__PUBLIC_LEAF_SLOT 1247650290UL
#define DOM_SEP__PUBLIC_STORAGE_MAP_SLOT 4015149901UL
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -611,6 +611,12 @@ pub global RECURSIVE_ROLLUP_HONK_PROOF_LENGTH: u32 =
RECURSIVE_PROOF_LENGTH + IPA_CLAIM_SIZE + IPA_PROOF_LENGTH;
pub global NESTED_RECURSIVE_ROLLUP_HONK_PROOF_LENGTH: u32 = RECURSIVE_ROLLUP_HONK_PROOF_LENGTH;
pub global CHONK_PROOF_LENGTH: u32 = 1632;
// Sub-proof sizes within a Chonk proof (must match C++ ChonkProof::from_field_elements split)
// Verified: 407 + 28 + 42 + 608 + 64 + 483 = 1632
pub global CHONK_MEGA_ZK_PROOF_LENGTH_WITHOUT_PUB_INPUTS: u32 = 407;
pub global CHONK_MERGE_PROOF_LENGTH: u32 = 42;
pub global CHONK_ECCVM_PROOF_LENGTH: u32 = 608;
pub global CHONK_TRANSLATOR_PROOF_LENGTH: u32 = 483;

pub global ULTRA_VK_LENGTH_IN_FIELDS: u32 = 115; // size of an Ultra verification key
pub global MEGA_VK_LENGTH_IN_FIELDS: u32 = 127; // size of a Mega verification key
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ unconstrained fn packed_delayed_public_mutable_values_match_typescript() {
let pre_value = MockStruct { a: 1, b: 2 };
let post_value = MockStruct { a: 3, b: 4 };

let sdc = ScheduledDelayChange::<0u64>::new(Option::some(1), Option::some(50), 2);
let sdc = ScheduledDelayChange::<0_u64>::new(Option::some(1), Option::some(50), 2);
let svc = ScheduledValueChange::new(pre_value, post_value, 50);
let dpmv = DelayedPublicMutableValues::new(svc, sdc);

Expand Down
3 changes: 2 additions & 1 deletion yarn-project/bb-prover/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@
"./client": "./dest/prover/client/bb_private_kernel_prover.js",
"./verifier": "./dest/verifier/index.js",
"./test": "./dest/test/index.js",
"./config": "./dest/config.js"
"./config": "./dest/config.js",
"./debug": "./dest/bb/bb_js_debug.js"
},
"bin": {
"bb-cli": "./dest/bb/index.js"
Expand Down
295 changes: 295 additions & 0 deletions yarn-project/bb-prover/src/bb/bb_js_backend.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,295 @@
import { type BackendOptions, BackendType, Barretenberg, type ChonkProof } from '@aztec/bb.js';
import {
CHONK_ECCVM_PROOF_LENGTH,
CHONK_MEGA_ZK_PROOF_LENGTH_WITHOUT_PUB_INPUTS,
CHONK_MERGE_PROOF_LENGTH,
CHONK_TRANSLATOR_PROOF_LENGTH,
HIDING_KERNEL_IO_PUBLIC_INPUTS_SIZE,
IPA_PROOF_LENGTH,
} from '@aztec/constants';
import type { LogFn, Logger } from '@aztec/foundation/log';
import { Timer } from '@aztec/foundation/timer';

import type { UltraHonkFlavor } from '../honk.js';

/**
* Maps UltraHonkFlavor to the bb.js ProofSystemSettings.
* All server-side proofs use disableZk: true.
*/
function getProofSettings(flavor: UltraHonkFlavor) {
const base = { disableZk: true, optimizedSolidityVerifier: false };
switch (flavor) {
case 'ultra_honk':
return { ...base, oracleHashType: 'poseidon2' as const, ipaAccumulation: false };
case 'ultra_keccak_honk':
return { ...base, oracleHashType: 'keccak' as const, ipaAccumulation: false };
case 'ultra_starknet_honk':
return { ...base, oracleHashType: 'starknet' as const, ipaAccumulation: false };
case 'ultra_rollup_honk':
return { ...base, oracleHashType: 'poseidon2' as const, ipaAccumulation: true };
}
}

/** Result of a successful proof generation via bb.js. */
export type BBJsProofResult = {
/** Proof fields as 32-byte Uint8Arrays. */
proofFields: Uint8Array[];
/** Public input fields as 32-byte Uint8Arrays. */
publicInputFields: Uint8Array[];
/** Duration of the proving operation in ms. */
durationMs: number;
};

/** Public API surface of a bb.js instance, used by the factory and debug wrapper. */
export interface BBJsApi {
generateProof(
circuitName: string,
bytecode: Uint8Array,
verificationKey: Uint8Array,
witness: Uint8Array,
flavor: UltraHonkFlavor,
): Promise<BBJsProofResult>;
verifyProof(
proofFields: Uint8Array[],
verificationKey: Uint8Array,
publicInputFields: Uint8Array[],
flavor: UltraHonkFlavor,
): Promise<{ verified: boolean; durationMs: number }>;
verifyChonkProof(
fieldsWithPublicInputs: Uint8Array[],
verificationKey: Uint8Array,
numCustomPublicInputs: number,
): Promise<{ verified: boolean; durationMs: number }>;
computeGateCount(
circuitName: string,
bytecode: Uint8Array,
flavor: UltraHonkFlavor | 'mega_honk',
): Promise<{ circuitSize: number; durationMs: number }>;
generateContract(verificationKey: Uint8Array): Promise<{ solidityCode: string; durationMs: number }>;
destroy(): Promise<void>;
}

/**
* Thin wrapper around a single Barretenberg instance.
* Each instance spawns its own bb process via the NativeUnixSocket backend.
*/
export class BBJsInstance implements BBJsApi {
private constructor(private api: Barretenberg) {}

/** Creates a new Barretenberg instance connected to a fresh bb process. */
static async create(bbPath: string, logger?: LogFn, threads?: number): Promise<BBJsInstance> {
const options: BackendOptions = {
bbPath,
backend: BackendType.NativeUnixSocket,
logger,
};
if (threads !== undefined) {
options.threads = threads;
}
const api = await Barretenberg.new(options);
return new BBJsInstance(api);
}

/**
* Generate an UltraHonk proof for a circuit.
* @param circuitName - Identifier for the circuit (used by bb internally).
* @param bytecode - Uncompressed ACIR bytecode.
* @param verificationKey - The circuit's verification key bytes.
* @param witness - Uncompressed witness bytes.
* @param flavor - The UltraHonk flavor to use.
*/
async generateProof(
circuitName: string,
bytecode: Uint8Array,
verificationKey: Uint8Array,
witness: Uint8Array,
flavor: UltraHonkFlavor,
): Promise<BBJsProofResult> {
const timer = new Timer();
const result = await this.api.circuitProve({
circuit: {
name: circuitName,
bytecode,
verificationKey,
},
witness,
settings: getProofSettings(flavor),
});
return {
proofFields: result.proof,
publicInputFields: result.publicInputs,
durationMs: timer.ms(),
};
}

/**
* Verify an UltraHonk proof.
* @param proofFields - Proof fields as 32-byte Uint8Arrays.
* @param verificationKey - The VK bytes.
* @param publicInputFields - Public input fields as 32-byte Uint8Arrays.
* @param flavor - The UltraHonk flavor.
* @returns Whether the proof is valid.
*/
async verifyProof(
proofFields: Uint8Array[],
verificationKey: Uint8Array,
publicInputFields: Uint8Array[],
flavor: UltraHonkFlavor,
): Promise<{ verified: boolean; durationMs: number }> {
const timer = new Timer();
const result = await this.api.circuitVerify({
verificationKey,
publicInputs: publicInputFields,
proof: proofFields,
settings: getProofSettings(flavor),
});
return { verified: result.verified, durationMs: timer.ms() };
}

/**
* Compute circuit gate count / circuit size.
* @param circuitName - Identifier for the circuit.
* @param bytecode - Uncompressed ACIR bytecode.
* @param flavor - 'mega_honk' for chonk circuits, or an UltraHonk flavor.
* @returns The dyadic circuit size (next power of 2 of gate count).
*/
async computeGateCount(
circuitName: string,
bytecode: Uint8Array,
flavor: UltraHonkFlavor | 'mega_honk',
): Promise<{ circuitSize: number; durationMs: number }> {
const timer = new Timer();
if (flavor === 'mega_honk') {
const result = await this.api.chonkStats({
circuit: { name: circuitName, bytecode },
includeGatesPerOpcode: false,
});
return { circuitSize: result.circuitSize, durationMs: timer.ms() };
}
const result = await this.api.circuitStats({
circuit: { name: circuitName, bytecode, verificationKey: new Uint8Array(0) },
includeGatesPerOpcode: false,
settings: getProofSettings(flavor),
});
return { circuitSize: result.numGatesDyadic, durationMs: timer.ms() };
}

/**
* Generate a Solidity verifier contract from a verification key.
* @param verificationKey - The VK bytes.
* @returns The Solidity source code.
*/
async generateContract(verificationKey: Uint8Array): Promise<{ solidityCode: string; durationMs: number }> {
const timer = new Timer();
const result = await this.api.circuitWriteSolidityVerifier({
verificationKey,
settings: {
ipaAccumulation: false,
oracleHashType: 'poseidon2',
disableZk: true,
optimizedSolidityVerifier: false,
},
});
return { solidityCode: result.solidityCode, durationMs: timer.ms() };
}

/**
* Verify a Chonk (IVC) proof by splitting flat fields into the structured ChonkProof format.
* Mirrors C++ ChonkProof::from_field_elements() logic.
* @param fieldsWithPublicInputs - Flat proof fields as 32-byte Uint8Arrays (public inputs prepended).
* @param verificationKey - The VK bytes.
* @param numCustomPublicInputs - Number of custom public inputs beyond HidingKernelIO.
*/
async verifyChonkProof(
fieldsWithPublicInputs: Uint8Array[],
verificationKey: Uint8Array,
numCustomPublicInputs: number,
): Promise<{ verified: boolean; durationMs: number }> {
const timer = new Timer();
const proof = splitChonkProofToStructured(fieldsWithPublicInputs, numCustomPublicInputs);
const result = await this.api.chonkVerify({ proof, vk: verificationKey });
return { verified: result.valid, durationMs: timer.ms() };
}

/** Destroy this instance and kill the underlying bb process. */
async destroy(): Promise<void> {
await this.api.destroy();
}
}

/**
* Factory for managing BBJsInstance lifecycle.
* Provides fresh instances for proving (each spawns a new bb process)
* and can pool instances for verification.
*/
export class BBJsProverFactory {
constructor(
private bbPath: string,
private logger?: Logger,
private threads?: number,
private debugDir?: string,
) {}

/**
* Run an operation with a fresh Barretenberg instance.
* The instance is created before the operation and destroyed after.
* Suitable for proving where process startup is negligible relative to proof time.
*/
async withFreshInstance<T>(fn: (instance: BBJsApi) => Promise<T>): Promise<T> {
const logFn = this.logger ? (msg: string) => this.logger!.verbose(`bb.js - ${msg}`) : undefined;
const raw = await BBJsInstance.create(this.bbPath, logFn, this.threads);
const instance = await this.maybeWrapDebug(raw);
try {
return await fn(instance);
} finally {
await instance.destroy();
}
}

/**
* Run a verification operation.
* Currently creates a fresh instance per call (matches current behavior of spawning bb per verification).
* Can be extended to use a pool if needed.
*/
withVerifierInstance<T>(fn: (instance: BBJsApi) => Promise<T>): Promise<T> {
return this.withFreshInstance(fn);
}

/** Wrap the instance in a debug wrapper if debugDir is configured. */
private async maybeWrapDebug(instance: BBJsInstance): Promise<BBJsApi> {
if (this.debugDir && this.logger) {
const { DebugBBJsInstance } = await import('./bb_js_debug.js');
return new DebugBBJsInstance(instance, this.debugDir, this.bbPath, this.logger);
}
return instance;
}
}

/**
* Split a flat Chonk proof field array into the structured ChonkProof format expected by bb.js chonkVerify.
* Mirrors C++ ChonkProof::from_field_elements() in barretenberg/cpp/src/barretenberg/chonk/chonk_proof.cpp.
*/
function splitChonkProofToStructured(fields: Uint8Array[], numCustomPublicInputs: number): ChonkProof {
let offset = 0;

const megaSize =
CHONK_MEGA_ZK_PROOF_LENGTH_WITHOUT_PUB_INPUTS + HIDING_KERNEL_IO_PUBLIC_INPUTS_SIZE + numCustomPublicInputs;
const megaProof = fields.slice(offset, offset + megaSize);
offset += megaSize;

const mergeProof = fields.slice(offset, offset + CHONK_MERGE_PROOF_LENGTH);
offset += CHONK_MERGE_PROOF_LENGTH;

const eccvmProof = fields.slice(offset, offset + CHONK_ECCVM_PROOF_LENGTH);
offset += CHONK_ECCVM_PROOF_LENGTH;

const ipaProof = fields.slice(offset, offset + IPA_PROOF_LENGTH);
offset += IPA_PROOF_LENGTH;

const translatorProof = fields.slice(offset, offset + CHONK_TRANSLATOR_PROOF_LENGTH);

return {
megaProof,
goblinProof: { mergeProof, eccvmProof, ipaProof, translatorProof },
};
}
Loading
Loading