Skip to content

Commit

Permalink
adding c_bind.cpp, index.ts, main.ts functions for ultra honk prove, …
Browse files Browse the repository at this point in the history
…verify, write_vk
  • Loading branch information
lucasxia01 committed Apr 30, 2024
1 parent d1fdb40 commit 2b4046e
Show file tree
Hide file tree
Showing 4 changed files with 204 additions and 4 deletions.
2 changes: 2 additions & 0 deletions barretenberg/acir_tests/Dockerfile.bb.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ COPY . .
ENV VERBOSE=1
# Run double_verify_proof through bb.js on node to check 512k support.
RUN BIN=../ts/dest/node/main.js FLOW=prove_then_verify ./run_acir_tests.sh double_verify_proof
# RUn a single arbitrary test for separate prove and verify for UltraHonk
RUN BIN=../ts/dest/node/main.js FLOW=prove_then_verify_ultra_honk ./run_acir_tests.sh double_verify_proof
# Run a single arbitrary test not involving recursion through bb.js for UltraHonk
RUN BIN=../ts/dest/node/main.js FLOW=prove_and_verify_ultra_honk ./run_acir_tests.sh 6_array
# Run a single arbitrary test not involving recursion through bb.js for GoblinUltraHonk
Expand Down
26 changes: 24 additions & 2 deletions barretenberg/cpp/src/barretenberg/dsl/acir_proofs/c_bind.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -204,8 +204,30 @@ WASM_EXPORT void acir_prove_ultra_honk(uint8_t const* acir_vec, uint8_t const* w
*out = to_heap_buffer(to_buffer</*include_size=*/true>(proof));
}

WASM_EXPORT void acir_verify_proof(uint8_t const* proof_buf, bool* result)
WASM_EXPORT void acir_verify_ultra_honk(uint8_t const* proof_buf, uint8_t const* vk_buf, bool* result)
{
using VerificationKey = UltraFlavor::VerificationKey;
using VerifierCommitmentKey = bb::VerifierCommitmentKey<curve::BN254>;
using Verifier = UltraVerifier_<UltraFlavor>;

auto proof = from_buffer<std::vector<bb::fr>>(proof_buf);
auto verification_key = std::make_shared<VerificationKey>(from_buffer<VerificationKey>(read_file(vk_path)));
auto verification_key = std::make_shared<VerificationKey>(from_buffer<VerificationKey>(vk_buf));
verification_key->pcs_verification_key = std::make_shared<VerifierCommitmentKey>();

Verifier verifier{ verification_key };

*result = verifier.verify_proof(proof);
}

WASM_EXPORT void acir_write_vk_ultra_honk(uint8_t const* acir_vec, uint8_t** out)
{
using ProverInstance = ProverInstance_<UltraFlavor>;
using VerificationKey = UltraFlavor::VerificationKey;

auto constraint_system = acir_format::circuit_buf_to_acir_format(from_buffer<std::vector<uint8_t>>(acir_vec));
auto builder = acir_format::create_circuit<UltraCircuitBuilder>(constraint_system, 0, {});

ProverInstance prover_inst(builder);
VerificationKey vk(prover_inst.proving_key);
*out = to_heap_buffer(to_buffer(vk));
}
72 changes: 72 additions & 0 deletions barretenberg/ts/src/barretenberg_api/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -567,6 +567,42 @@ export class BarretenbergApi {
const out = result.map((r, i) => outTypes[i].fromBuffer(r));
return out as any;
}

async acirProveUltraHonk(constraintSystemBuf: Uint8Array, witnessBuf: Uint8Array): Promise<Uint8Array> {
const inArgs = [constraintSystemBuf, witnessBuf].map(serializeBufferable);
const outTypes: OutputType[] = [BufferDeserializer()];
const result = await this.wasm.callWasmExport(
'acir_prove_ultra_honk',
inArgs,
outTypes.map(t => t.SIZE_IN_BYTES),
);
const out = result.map((r, i) => outTypes[i].fromBuffer(r));
return out[0];
}

async acirVerifyUltraHonk(proofBuf: Uint8Array, vkBuf: Uint8Array): Promise<boolean> {
const inArgs = [proofBuf, vkBuf].map(serializeBufferable);
const outTypes: OutputType[] = [BoolDeserializer()];
const result = await this.wasm.callWasmExport(
'acir_verify_ultra_honk',
inArgs,
outTypes.map(t => t.SIZE_IN_BYTES),
);
const out = result.map((r, i) => outTypes[i].fromBuffer(r));
return out[0];
}

async acirWriteVkUltraHonk(constraintSystemBuf: Uint8Array): Promise<Uint8Array> {
const inArgs = [constraintSystemBuf].map(serializeBufferable);
const outTypes: OutputType[] = [BufferDeserializer()];
const result = await this.wasm.callWasmExport(
'acir_write_vk_ultra_honk',
inArgs,
outTypes.map(t => t.SIZE_IN_BYTES),
);
const out = result.map((r, i) => outTypes[i].fromBuffer(r));
return out[0];
}
}
export class BarretenbergApiSync {
constructor(protected wasm: BarretenbergWasm) {}
Expand Down Expand Up @@ -1111,4 +1147,40 @@ export class BarretenbergApiSync {
const out = result.map((r, i) => outTypes[i].fromBuffer(r));
return out as any;
}

acirUltraHonkProve(constraintSystemBuf: Uint8Array, witnessBuf: Uint8Array): Uint8Array {
const inArgs = [constraintSystemBuf, witnessBuf].map(serializeBufferable);
const outTypes: OutputType[] = [BufferDeserializer()];
const result = this.wasm.callWasmExport(
'acir_prove_ultra_honk',
inArgs,
outTypes.map(t => t.SIZE_IN_BYTES),
);
const out = result.map((r, i) => outTypes[i].fromBuffer(r));
return out[0];
}

acirVerifyUltraHonk(proofBuf: Uint8Array, vkBuf: Uint8Array): boolean {
const inArgs = [proofBuf, vkBuf].map(serializeBufferable);
const outTypes: OutputType[] = [BoolDeserializer()];
const result = this.wasm.callWasmExport(
'acir_verify_ultra_honk',
inArgs,
outTypes.map(t => t.SIZE_IN_BYTES),
);
const out = result.map((r, i) => outTypes[i].fromBuffer(r));
return out[0];
}

acirWriteVkUltraHonk(constraintSystemBuf: Uint8Array): Uint8Array {
const inArgs = [constraintSystemBuf].map(serializeBufferable);
const outTypes: OutputType[] = [BufferDeserializer()];
const result = this.wasm.callWasmExport(
'acir_write_vk_ultra_honk',
inArgs,
outTypes.map(t => t.SIZE_IN_BYTES),
);
const out = result.map((r, i) => outTypes[i].fromBuffer(r));
return out[0];
}
}
108 changes: 106 additions & 2 deletions barretenberg/ts/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,32 @@ async function init(bytecodePath: string, crsPath: string, subgroupSizeOverride
return { api, acirComposer, circuitSize, subgroupSize };
}

async function initUltraHonk(bytecodePath: string, crsPath: string, subgroupSizeOverride = -1) {
const api = await Barretenberg.new({ threads });

const circuitSize = await getGates(bytecodePath, api);
// TODO(https://github.com/AztecProtocol/barretenberg/issues/811): remove subgroupSizeOverride hack for goblin
const subgroupSize = Math.max(subgroupSizeOverride, Math.pow(2, Math.ceil(Math.log2(circuitSize))));
if (subgroupSize > MAX_CIRCUIT_SIZE) {
throw new Error(`Circuit size of ${subgroupSize} exceeds max supported of ${MAX_CIRCUIT_SIZE}`);
}

debug(`circuit size: ${circuitSize}`);
debug(`subgroup size: ${subgroupSize}`);
debug('loading crs...');
// Plus 1 needed! (Move +1 into Crs?)
const crs = await Crs.new(subgroupSize + 1, crsPath);

// Important to init slab allocator as first thing, to ensure maximum memory efficiency.
await api.commonInitSlabAllocator(subgroupSize);

// Load CRS into wasm global CRS state.
// TODO: Make RawBuffer be default behavior, and have a specific Vector type for when wanting length prefixed.
await api.srsInitSrs(new RawBuffer(crs.getG1Data()), crs.numPoints, new RawBuffer(crs.getG2Data()));

return { api, circuitSize, subgroupSize };
}

async function initGoblin(bytecodePath: string, crsPath: string) {
// TODO(https://github.com/AztecProtocol/barretenberg/issues/811): remove this subgroup size hack
const hardcodedGrumpkinSubgroupSizeHack = 262144;
Expand Down Expand Up @@ -358,10 +384,56 @@ export async function vkAsFields(vkPath: string, vkeyOutputPath: string) {
}
}

// export async function proveHonk(bytecodePath: string, witnessPath: string, outputPath: string) {
export async function proveUltraHonk(bytecodePath: string, witnessPath: string, crsPath: string, outputPath: string) {
const { api } = await initUltraHonk(bytecodePath, crsPath);
try {
debug(`creating proof...`);
const bytecode = getBytecode(bytecodePath);
const witness = getWitness(witnessPath);
const proof = await api.acirProveUltraHonk(bytecode, witness);
debug(`done.`);

if (outputPath === '-') {
process.stdout.write(proof);
debug(`proof written to stdout`);
} else {
writeFileSync(outputPath, proof);
debug(`proof written to: ${outputPath}`);
}
} finally {
await api.destroy();
}
}

export async function writeVkUltraHonk(bytecodePath: string, crsPath: string, outputPath: string) {
const { api } = await initUltraHonk(bytecodePath, crsPath);
try {
const bytecode = getBytecode(bytecodePath);
debug('initing verification key...');
const vk = await api.acirWriteVkUltraHonk(bytecode);

// }
if (outputPath === '-') {
process.stdout.write(vk);
debug(`vk written to stdout`);
} else {
writeFileSync(outputPath, vk);
debug(`vk written to: ${outputPath}`);
}
} finally {
await api.destroy();
}
}

export async function verifyUltraHonk(proofPath: string, vkPath: string) {
const { api, acirComposer } = await initLite();
try {
const verified = await api.acirVerifyUltraHonk(readFileSync(proofPath), new RawBuffer(readFileSync(vkPath)));
debug(`verified: ${verified}`);
return verified;
} finally {
await api.destroy();
}
}
const program = new Command();

program.option('-v, --verbose', 'enable verbose logging', false);
Expand Down Expand Up @@ -509,4 +581,36 @@ program
acvmInfo(outputPath);
});

program
.command('prove_ultra_honk')
.description('Generate a proof and write it to a file.')
.option('-b, --bytecode-path <path>', 'Specify the bytecode path', './target/acir.gz')
.option('-w, --witness-path <path>', 'Specify the witness path', './target/witness.gz')
.option('-o, --output-path <path>', 'Specify the proof output path', './proofs/proof')
.action(async ({ bytecodePath, witnessPath, outputPath, crsPath }) => {
handleGlobalOptions();
await proveUltraHonk(bytecodePath, witnessPath, crsPath, outputPath);
});

program
.command('write_vk_ultra_honk')
.description('Output verification key.')
.option('-b, --bytecode-path <path>', 'Specify the bytecode path', './target/acir.gz')
.requiredOption('-o, --output-path <path>', 'Specify the path to write the key')
.action(async ({ bytecodePath, outputPath, crsPath }) => {
handleGlobalOptions();
await writeVkUltraHonk(bytecodePath, crsPath, outputPath);
});

program
.command('verify_ultra_honk')
.description('Verify a proof. Process exists with success or failure code.')
.requiredOption('-p, --proof-path <path>', 'Specify the path to the proof')
.requiredOption('-k, --vk <path>', 'path to a verification key. avoids recomputation.')
.action(async ({ proofPath, vk }) => {
handleGlobalOptions();
const result = await verifyUltraHonk(proofPath, vk);
process.exit(result ? 0 : 1);
});

program.name('bb.js').parse(process.argv);

0 comments on commit 2b4046e

Please sign in to comment.