Skip to content
6 changes: 3 additions & 3 deletions barretenberg/cpp/src/barretenberg/bb/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ std::string honk_vk_to_json(std::vector<bb::fr>& data)
*
* @param bytecodePath Path to the file containing the serialized circuit
* @param witnessPath Path to the file containing the serialized witness
* @param recursive Whether to use recursive proof generation of non-recursive
* @param recursive Whether to use recursive proof generation or non-recursive
* @return true if the proof is valid
* @return false if the proof is invalid
*/
Expand Down Expand Up @@ -215,7 +215,7 @@ void prove_tube(const std::string& output_path)
std::string vkPath = output_path + "/client_ivc_vk";
std::string proofPath = output_path + "/client_ivc_proof";

// Note: this could be decreased once we optimise the size of the ClientIVC recursiveve rifier
// Note: this could be decreased once we optimise the size of the ClientIVC recursive verifier
init_bn254_crs(1 << 25);
init_grumpkin_crs(1 << 18);

Expand All @@ -224,7 +224,7 @@ void prove_tube(const std::string& output_path)
auto vk = from_buffer<ClientIVC::VerificationKey>(read_file(vkPath));

// We don't serialise and deserialise the Grumkin SRS so initialise with circuit_size + 1 to be able to recursively
// IPA. The + 1 is to satisfy IPA verification key requirements.
// verify IPA. The + 1 is to satisfy IPA verification key requirements.
// TODO(https://github.com/AztecProtocol/barretenberg/issues/1025)
vk.eccvm->pcs_verification_key = std::make_shared<GrumpkinVk>(vk.eccvm->circuit_size + 1);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -487,7 +487,7 @@ void process_ivc_recursion_constraints(MegaCircuitBuilder& builder,
ivc->instantiate_stdlib_verification_queue(builder, stdlib_verification_keys);

// Connect the public_input witnesses in each constraint to the corresponding public input witnesses in the internal
// verification queue. This ensures that the witnesses utlized in constraints generated based on acir are properly
// verification queue. This ensures that the witnesses utilized in constraints generated based on acir are properly
// connected to the constraints generated herein via the ivc scheme (e.g. recursive verifications).
for (auto [constraint, queue_entry] :
zip_view(constraints.ivc_recursion_constraints, ivc->stdlib_verification_queue)) {
Expand Down
20 changes: 20 additions & 0 deletions barretenberg/cpp/src/barretenberg/dsl/acir_proofs/c_bind.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -453,3 +453,23 @@ WASM_EXPORT void acir_vk_as_fields_mega_honk(uint8_t const* vk_buf, fr::vec_out_
std::vector<bb::fr> vkey_as_fields = verification_key->to_field_elements();
*out_vkey = to_heap_buffer(vkey_as_fields);
}

WASM_EXPORT void acir_gates_aztec_client(uint8_t const* acir_stack, uint8_t** out)
{

std::vector<std::vector<uint8_t>> acirs = from_buffer<std::vector<std::vector<uint8_t>>>(acir_stack);
std::vector<uint32_t> totals;

TraceSettings trace_settings{ E2E_FULL_TEST_STRUCTURE };
auto ivc = std::make_shared<ClientIVC>(trace_settings);
const acir_format::ProgramMetadata metadata{ ivc };
for (auto& bincode : acirs) {
acir_format::AcirProgram program{ acir_format::circuit_buf_to_acir_format(bincode, /*honk_recursion=*/0) };
auto builder = acir_format::create_circuit(program, metadata);
builder.finalize_circuit(/*ensure_nonzero=*/true);
totals.push_back(static_cast<uint32_t>(builder.get_finalized_total_circuit_size()));
}
auto totalsBytes = to_buffer<false>(totals);

*out = to_heap_buffer(totals);
}
4 changes: 3 additions & 1 deletion barretenberg/cpp/src/barretenberg/dsl/acir_proofs/c_bind.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -113,4 +113,6 @@ WASM_EXPORT void acir_proof_as_fields_ultra_honk(uint8_t const* proof_buf, fr::v

WASM_EXPORT void acir_vk_as_fields_ultra_honk(uint8_t const* vk_buf, fr::vec_out_buf out_vkey);

WASM_EXPORT void acir_vk_as_fields_mega_honk(uint8_t const* vk_buf, fr::vec_out_buf out_vkey);
WASM_EXPORT void acir_vk_as_fields_mega_honk(uint8_t const* vk_buf, fr::vec_out_buf out_vkey);

WASM_EXPORT void acir_gates_aztec_client(uint8_t const* acir_stack, uint8_t** out);
14 changes: 14 additions & 0 deletions barretenberg/exports.json
Original file line number Diff line number Diff line change
Expand Up @@ -530,6 +530,20 @@
],
"isAsync": false
},
{
"functionName": "acir_gates_client_ivc",
"inArgs": [
{
"name": "acir_stack",
"type": "const uint8_t *"
},
{
"name": "totals",
"type": "uint8_t **"
}
],
"isAsync": false
},
{
"functionName": "acir_new_acir_composer",
"inArgs": [
Expand Down
6 changes: 6 additions & 0 deletions barretenberg/ts/src/barretenberg/backend.ts
Original file line number Diff line number Diff line change
Expand Up @@ -391,6 +391,12 @@ export class AztecClientBackend {
return this.api.acirProveAndVerifyAztecClient(this.acirMsgpack, witnessMsgpack);
}

async gates(): Promise<number[]> {
// call function on API
await this.instantiate();
return this.api.acirGatesAztecClient(this.acirMsgpack);
}

async destroy(): Promise<void> {
if (!this.api) {
return;
Expand Down
37 changes: 37 additions & 0 deletions barretenberg/ts/src/barretenberg_api/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,28 @@ import {
OutputType,
} from '../serialize/index.js';
import { Fr, Fq, Point, Buffer32, Buffer128, Ptr } from '../types/index.js';
function parseBigEndianU32Array(buffer: Uint8Array, hasSizePrefix = false): number[] {
const dv = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength);

let offset = 0;
let count = buffer.byteLength >>> 2; // default is entire buffer length / 4

if (hasSizePrefix) {
// Read the first 4 bytes as the size (big-endian).
count = dv.getUint32(0, /* littleEndian= */ false);
offset = 4;
}

const out: number[] = new Array(count);
for (let i = 0; i < count; i++) {
out[i] = dv.getUint32(offset, false);
offset += 4;
}

return out;
}
import createDebug from 'debug';
const log = createDebug('index-ts');

export class BarretenbergApi {
constructor(protected wasm: BarretenbergWasmWorker | BarretenbergWasmMain) {}
Expand Down Expand Up @@ -357,6 +379,21 @@ export class BarretenbergApi {
return out as [number, number];
}

async acirGatesAztecClient(
// cf acirProveAztecClient
acirVec: Uint8Array[],
): Promise<number[]> {
const inArgs = [acirVec].map(serializeBufferable);
const outTypes: OutputType[] = [BufferDeserializer()];
const resultBuffer = await this.wasm.callWasmExport(
'acir_gates_aztec_client',
inArgs,
outTypes.map(t => t.SIZE_IN_BYTES),
);

return parseBigEndianU32Array(resultBuffer[0], /*hasSizePrefix=*/ true);
}

async acirNewAcirComposer(sizeHint: number): Promise<Ptr> {
const inArgs = [sizeHint].map(serializeBufferable);
const outTypes: OutputType[] = [Ptr];
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import { AztecClientBackend } from '@aztec/bb.js';

import { jest } from '@jest/globals';

/* eslint-disable camelcase */
import createDebug from 'debug';
import { ungzip } from 'pako';

import {
MOCK_MAX_COMMITMENTS_PER_TX,
Expand Down Expand Up @@ -65,6 +68,7 @@ describe('Client IVC Integration', () => {
MockPrivateKernelInitCircuit.bytecode,
MockPrivateKernelTailCircuit.bytecode,
];

logger('built bytecode array');
const witnessStack = [appWitnessGenResult.witness, initWitnessGenResult.witness, tailWitnessGenResult.witness];
logger('built witness stack');
Expand All @@ -75,6 +79,25 @@ describe('Client IVC Integration', () => {
expect(verifyResult).toEqual(true);
});

it('Should generate an array of gate numbers for the stack of programs being proved by ClientIVC', async () => {
// Create ACIR bytecodes
const bytecodes = [
MockAppCreatorCircuit.bytecode,
MockPrivateKernelInitCircuit.bytecode,
MockPrivateKernelTailCircuit.bytecode,
];

// Initialize AztecClientBackend with the given bytecodes
const backend = new AztecClientBackend(bytecodes.map(base64ToUint8Array).map((arr: Uint8Array) => ungzip(arr)));

// Compute the numbers of gates in each circuit
const gateNumbers = await backend.gates();
await backend.destroy();
logger('Gate numbers for each circuit:', gateNumbers);
// STARTER: add a test here instantiate an AztecClientBackend with the above bytecodes, call gates, and check they're correct (maybe just
// eyeball against logs to start... better is to make another test that actually pins the sizes since the mock protocol circuits are
// intended not to change, though for sure there will be some friction, and such test should actually just be located in barretenberg/ts)
});
// This test will verify a client IVC proof of a more complex tx:
// 1. Run a mock app that creates two commitments
// 2. Run the init kernel to process the app run
Expand Down Expand Up @@ -142,3 +165,6 @@ describe('Client IVC Integration', () => {
expect(verifyResult).toEqual(true);
});
});
function base64ToUint8Array(base64: string): Uint8Array {
return Uint8Array.from(atob(base64), c => c.charCodeAt(0));
}