diff --git a/barretenberg/acir_tests/Dockerfile.bb.js b/barretenberg/acir_tests/Dockerfile.bb.js index e0838949964..ebafd7da88c 100644 --- a/barretenberg/acir_tests/Dockerfile.bb.js +++ b/barretenberg/acir_tests/Dockerfile.bb.js @@ -16,8 +16,12 @@ 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 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 BIN=../ts/dest/node/main.js FLOW=prove_then_verify_ultra_honk ./run_acir_tests.sh nested_array_dynamic +# Run a single arbitrary test not involving recursion through bb.js for Plonk +RUN BIN=../ts/dest/node/main.js FLOW=prove_and_verify ./run_acir_tests.sh poseidon_bn254_hash # Run a single arbitrary test not involving recursion through bb.js for GoblinUltraHonk +RUN BIN=../ts/dest/node/main.js FLOW=prove_and_verify_ultra_honk ./run_acir_tests.sh closures_mut_ref +# Run a single arbitrary test for separate prove and verify for UltraHonk RUN BIN=../ts/dest/node/main.js FLOW=prove_and_verify_goblin_ultra_honk ./run_acir_tests.sh 6_array # Run a single arbitrary test not involving recursion through bb.js for full Goblin RUN BIN=../ts/dest/node/main.js FLOW=prove_and_verify_goblin ./run_acir_tests.sh 6_array diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/c_bind.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/c_bind.cpp index c867bd24847..8e1a602a576 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/c_bind.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/c_bind.cpp @@ -191,3 +191,43 @@ WASM_EXPORT void acir_serialize_verification_key_into_fields(in_ptr acir_compose *out_vkey = to_heap_buffer(vkey_as_fields); write(out_key_hash, vk_hash); } + +WASM_EXPORT void acir_prove_ultra_honk(uint8_t const* acir_vec, uint8_t const* witness_vec, uint8_t** out) +{ + auto constraint_system = acir_format::circuit_buf_to_acir_format(from_buffer>(acir_vec)); + auto witness = acir_format::witness_buf_to_witness_data(from_buffer>(witness_vec)); + + auto builder = acir_format::create_circuit(constraint_system, 0, witness); + + UltraProver prover{ builder }; + auto proof = prover.construct_proof(); + *out = to_heap_buffer(to_buffer(proof)); +} + +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; + using Verifier = UltraVerifier_; + + auto proof = from_buffer>(from_buffer>(proof_buf)); + auto verification_key = std::make_shared(from_buffer(vk_buf)); + verification_key->pcs_verification_key = std::make_shared(); + + 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_; + using VerificationKey = UltraFlavor::VerificationKey; + + auto constraint_system = acir_format::circuit_buf_to_acir_format(from_buffer>(acir_vec)); + auto builder = acir_format::create_circuit(constraint_system, 0, {}); + + ProverInstance prover_inst(builder); + VerificationKey vk(prover_inst.proving_key); + *out = to_heap_buffer(to_buffer(vk)); +} \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/c_bind.hpp b/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/c_bind.hpp index 1c624c96ef3..8d1f060a74e 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/c_bind.hpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/c_bind.hpp @@ -84,4 +84,6 @@ WASM_EXPORT void acir_serialize_proof_into_fields(in_ptr acir_composer_ptr, WASM_EXPORT void acir_serialize_verification_key_into_fields(in_ptr acir_composer_ptr, fr::vec_out_buf out_vkey, - fr::out_buf out_key_hash); \ No newline at end of file + fr::out_buf out_key_hash); + +WASM_EXPORT void acir_prove_ultra_honk(uint8_t const* acir_vec, uint8_t const* witness_vec, uint8_t** out); \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_verifier.cpp b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_verifier.cpp index aa3cb7f19fa..6b9e01b7069 100644 --- a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_verifier.cpp @@ -123,7 +123,7 @@ bool ECCVMVerifier::verify_proof(const HonkProof& proof) const size_t log_circuit_size = numeric::get_msb(circuit_size); auto sumcheck = SumcheckVerifier(log_circuit_size, transcript); FF alpha = transcript->template get_challenge("Sumcheck:alpha"); - std::vector gate_challenges(numeric::get_msb(key->circuit_size)); + std::vector gate_challenges(static_cast(numeric::get_msb(key->circuit_size))); for (size_t idx = 0; idx < gate_challenges.size(); idx++) { gate_challenges[idx] = transcript->template get_challenge("Sumcheck:gate_challenge_" + std::to_string(idx)); } diff --git a/barretenberg/cpp/src/barretenberg/flavor/flavor.hpp b/barretenberg/cpp/src/barretenberg/flavor/flavor.hpp index 36838486100..b3be9e6483f 100644 --- a/barretenberg/cpp/src/barretenberg/flavor/flavor.hpp +++ b/barretenberg/cpp/src/barretenberg/flavor/flavor.hpp @@ -85,9 +85,9 @@ namespace bb { */ class PrecomputedEntitiesBase { public: - size_t circuit_size; - size_t log_circuit_size; - size_t num_public_inputs; + uint64_t circuit_size; + uint64_t log_circuit_size; + uint64_t num_public_inputs; CircuitType circuit_type; // TODO(#392) }; @@ -181,7 +181,7 @@ template class VerificationKey_ : public PrecomputedCommitments { public: std::shared_ptr pcs_verification_key; - size_t pub_inputs_offset = 0; + uint64_t pub_inputs_offset = 0; VerificationKey_() = default; VerificationKey_(const size_t circuit_size, const size_t num_public_inputs) diff --git a/barretenberg/cpp/src/barretenberg/protogalaxy/decider_verifier.cpp b/barretenberg/cpp/src/barretenberg/protogalaxy/decider_verifier.cpp index e217028e27b..541df9ccaa5 100644 --- a/barretenberg/cpp/src/barretenberg/protogalaxy/decider_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/protogalaxy/decider_verifier.cpp @@ -35,8 +35,8 @@ template bool DeciderVerifier_::verify_proof(const Hon VerifierCommitments commitments{ accumulator->verification_key, accumulator->witness_commitments }; - auto sumcheck = - SumcheckVerifier(accumulator->verification_key->log_circuit_size, transcript, accumulator->target_sum); + auto sumcheck = SumcheckVerifier( + static_cast(accumulator->verification_key->log_circuit_size), transcript, accumulator->target_sum); auto [multivariate_challenge, claimed_evaluations, sumcheck_verified] = sumcheck.verify(accumulator->relation_parameters, accumulator->alphas, accumulator->gate_challenges); diff --git a/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_verifier.cpp b/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_verifier.cpp index f086c1d5b29..6111b0df426 100644 --- a/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_verifier.cpp @@ -26,7 +26,7 @@ void ProtoGalaxyVerifier_::prepare_for_folding(const std::vec if (!inst->is_accumulator) { receive_and_finalise_instance(inst, domain_separator); inst->target_sum = 0; - inst->gate_challenges = std::vector(inst->verification_key->log_circuit_size, 0); + inst->gate_challenges = std::vector(static_cast(inst->verification_key->log_circuit_size), 0); } index++; @@ -45,11 +45,12 @@ std::shared_ptr ProtoGalaxyVerifier_template get_challenge("delta"); auto accumulator = get_accumulator(); - auto deltas = compute_round_challenge_pows(accumulator->verification_key->log_circuit_size, delta); + auto deltas = + compute_round_challenge_pows(static_cast(accumulator->verification_key->log_circuit_size), delta); - std::vector perturbator_coeffs(accumulator->verification_key->log_circuit_size + 1, 0); + std::vector perturbator_coeffs(static_cast(accumulator->verification_key->log_circuit_size) + 1, 0); if (accumulator->is_accumulator) { - for (size_t idx = 1; idx <= accumulator->verification_key->log_circuit_size; idx++) { + for (size_t idx = 1; idx <= static_cast(accumulator->verification_key->log_circuit_size); idx++) { perturbator_coeffs[idx] = transcript->template receive_from_prover("perturbator_" + std::to_string(idx)); } @@ -112,7 +113,8 @@ std::shared_ptr ProtoGalaxyVerifier_verification_key->num_public_inputs = accumulator->verification_key->num_public_inputs; - next_accumulator->public_inputs = std::vector(next_accumulator->verification_key->num_public_inputs, 0); + next_accumulator->public_inputs = + std::vector(static_cast(next_accumulator->verification_key->num_public_inputs), 0); size_t public_input_idx = 0; for (auto& public_input : next_accumulator->public_inputs) { size_t inst = 0; diff --git a/barretenberg/cpp/src/barretenberg/stdlib/honk_recursion/verifier/decider_recursive_verifier.cpp b/barretenberg/cpp/src/barretenberg/stdlib/honk_recursion/verifier/decider_recursive_verifier.cpp index 325f0647206..506d36f5c63 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/honk_recursion/verifier/decider_recursive_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/honk_recursion/verifier/decider_recursive_verifier.cpp @@ -24,7 +24,8 @@ std::array DeciderRecursiveVerifier_:: VerifierCommitments commitments{ accumulator->verification_key, accumulator->witness_commitments }; - auto sumcheck = Sumcheck(accumulator->verification_key->log_circuit_size, transcript, accumulator->target_sum); + auto sumcheck = Sumcheck( + static_cast(accumulator->verification_key->log_circuit_size), transcript, accumulator->target_sum); auto [multivariate_challenge, claimed_evaluations, sumcheck_verified] = sumcheck.verify(accumulator->relation_parameters, accumulator->alphas, accumulator->gate_challenges); diff --git a/barretenberg/cpp/src/barretenberg/stdlib/honk_recursion/verifier/protogalaxy_recursive_verifier.cpp b/barretenberg/cpp/src/barretenberg/stdlib/honk_recursion/verifier/protogalaxy_recursive_verifier.cpp index 2e2d2454610..3f27a79e2c5 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/honk_recursion/verifier/protogalaxy_recursive_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/honk_recursion/verifier/protogalaxy_recursive_verifier.cpp @@ -78,11 +78,12 @@ void ProtoGalaxyRecursiveVerifier_::receive_and_finalise_inst transcript->template receive_from_prover(domain_separator + "_" + labels.z_lookup); // Compute correction terms for grand products - const FF public_input_delta = compute_public_input_delta(inst->public_inputs, - beta, - gamma, - inst->verification_key->circuit_size, - inst->verification_key->pub_inputs_offset); + const FF public_input_delta = + compute_public_input_delta(inst->public_inputs, + beta, + gamma, + inst->verification_key->circuit_size, + static_cast(inst->verification_key->pub_inputs_offset)); const FF lookup_grand_product_delta = compute_lookup_grand_product_delta(beta, gamma, inst->verification_key->circuit_size); inst->relation_parameters = @@ -105,7 +106,7 @@ template void ProtoGalaxyRecursiveVerifier_is_accumulator) { receive_and_finalise_instance(inst, domain_separator); inst->target_sum = 0; - inst->gate_challenges = std::vector(inst->verification_key->log_circuit_size, 0); + inst->gate_challenges = std::vector(static_cast(inst->verification_key->log_circuit_size), 0); } index++; @@ -128,11 +129,12 @@ std::shared_ptr ProtoGalaxyRecursiveVerifi auto delta = transcript->template get_challenge("delta"); auto accumulator = get_accumulator(); - auto deltas = compute_round_challenge_pows(accumulator->verification_key->log_circuit_size, delta); + auto deltas = + compute_round_challenge_pows(static_cast(accumulator->verification_key->log_circuit_size), delta); - std::vector perturbator_coeffs(accumulator->verification_key->log_circuit_size + 1, 0); + std::vector perturbator_coeffs(static_cast(accumulator->verification_key->log_circuit_size) + 1, 0); if (accumulator->is_accumulator) { - for (size_t idx = 1; idx <= accumulator->verification_key->log_circuit_size; idx++) { + for (size_t idx = 1; idx <= static_cast(accumulator->verification_key->log_circuit_size); idx++) { perturbator_coeffs[idx] = transcript->template receive_from_prover("perturbator_" + std::to_string(idx)); } @@ -200,7 +202,8 @@ std::shared_ptr ProtoGalaxyRecursiveVerifi comm_idx++; } - next_accumulator->public_inputs = std::vector(next_accumulator->verification_key->num_public_inputs, 0); + next_accumulator->public_inputs = + std::vector(static_cast(next_accumulator->verification_key->num_public_inputs), 0); size_t public_input_idx = 0; for (auto& public_input : next_accumulator->public_inputs) { size_t inst = 0; diff --git a/barretenberg/cpp/src/barretenberg/stdlib/honk_recursion/verifier/recursive_verifier_instance.hpp b/barretenberg/cpp/src/barretenberg/stdlib/honk_recursion/verifier/recursive_verifier_instance.hpp index 16ccfe6c4e5..bc5a7721cae 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/honk_recursion/verifier/recursive_verifier_instance.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/honk_recursion/verifier/recursive_verifier_instance.hpp @@ -49,7 +49,7 @@ template class RecursiveVerifierInstance_ { : verification_key(std::make_shared(instance->verification_key->circuit_size, instance->verification_key->num_public_inputs)) , is_accumulator(bool(instance->is_accumulator)) - , public_inputs(std::vector(instance->verification_key->num_public_inputs)) + , public_inputs(std::vector(static_cast(instance->verification_key->num_public_inputs))) { verification_key->pub_inputs_offset = instance->verification_key->pub_inputs_offset; @@ -113,7 +113,7 @@ template class RecursiveVerifierInstance_ { VerifierInstance inst(inst_verification_key); inst.is_accumulator = is_accumulator; - inst.public_inputs = std::vector(verification_key->num_public_inputs); + inst.public_inputs = std::vector(static_cast(verification_key->num_public_inputs)); for (auto [public_input, inst_public_input] : zip_view(public_inputs, inst.public_inputs)) { inst_public_input = public_input.get_value(); } diff --git a/barretenberg/cpp/src/barretenberg/stdlib_circuit_builders/ultra_flavor.hpp b/barretenberg/cpp/src/barretenberg/stdlib_circuit_builders/ultra_flavor.hpp index 74333675a3a..fe5dca553f4 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib_circuit_builders/ultra_flavor.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib_circuit_builders/ultra_flavor.hpp @@ -459,9 +459,9 @@ class UltraFlavor { } } // TODO(https://github.com/AztecProtocol/barretenberg/issues/964): Clean the boilerplate up. - VerificationKey(const size_t circuit_size, - const size_t num_public_inputs, - const size_t pub_inputs_offset, + VerificationKey(const uint64_t circuit_size, + const uint64_t num_public_inputs, + const uint64_t pub_inputs_offset, const Commitment& q_m, const Commitment& q_c, const Commitment& q_l, diff --git a/barretenberg/cpp/src/barretenberg/translator_vm/goblin_translator_verifier.cpp b/barretenberg/cpp/src/barretenberg/translator_vm/goblin_translator_verifier.cpp index 36c08b036ef..5607769937d 100644 --- a/barretenberg/cpp/src/barretenberg/translator_vm/goblin_translator_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/translator_vm/goblin_translator_verifier.cpp @@ -234,7 +234,7 @@ bool GoblinTranslatorVerifier::verify_proof(const HonkProof& proof) const size_t log_circuit_size = numeric::get_msb(circuit_size); auto sumcheck = SumcheckVerifier(log_circuit_size, transcript); FF alpha = transcript->template get_challenge("Sumcheck:alpha"); - std::vector gate_challenges(numeric::get_msb(key->circuit_size)); + std::vector gate_challenges(static_cast(numeric::get_msb(key->circuit_size))); for (size_t idx = 0; idx < gate_challenges.size(); idx++) { gate_challenges[idx] = transcript->template get_challenge("Sumcheck:gate_challenge_" + std::to_string(idx)); } diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/oink_verifier.cpp b/barretenberg/cpp/src/barretenberg/ultra_honk/oink_verifier.cpp index 6f565be827c..27b91e2a190 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/oink_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/oink_verifier.cpp @@ -124,8 +124,11 @@ template void OinkVerifier::execute_log_derivativ */ template void OinkVerifier::execute_grand_product_computation_round() { - const FF public_input_delta = compute_public_input_delta( - public_inputs, relation_parameters.beta, relation_parameters.gamma, key->circuit_size, key->pub_inputs_offset); + const FF public_input_delta = compute_public_input_delta(public_inputs, + relation_parameters.beta, + relation_parameters.gamma, + key->circuit_size, + static_cast(key->pub_inputs_offset)); const FF lookup_grand_product_delta = compute_lookup_grand_product_delta(relation_parameters.beta, relation_parameters.gamma, key->circuit_size); diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_verifier.cpp b/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_verifier.cpp index 1d16e1c8c42..25caf88611f 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_verifier.cpp @@ -57,7 +57,7 @@ template bool UltraVerifier_::verify_proof(const HonkP } // Execute Sumcheck Verifier - const size_t log_circuit_size = numeric::get_msb(key->circuit_size); + const size_t log_circuit_size = static_cast(numeric::get_msb(key->circuit_size)); auto sumcheck = SumcheckVerifier(log_circuit_size, transcript); auto gate_challenges = std::vector(log_circuit_size); diff --git a/barretenberg/ts/src/barretenberg_api/index.ts b/barretenberg/ts/src/barretenberg_api/index.ts index bdd35960e7e..44b10c57d8d 100644 --- a/barretenberg/ts/src/barretenberg_api/index.ts +++ b/barretenberg/ts/src/barretenberg_api/index.ts @@ -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 { + 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 { + 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 { + 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) {} @@ -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]; + } } diff --git a/barretenberg/ts/src/main.ts b/barretenberg/ts/src/main.ts index 6a7d7922f52..2060523db76 100755 --- a/barretenberg/ts/src/main.ts +++ b/barretenberg/ts/src/main.ts @@ -358,6 +358,56 @@ export async function vkAsFields(vkPath: string, vkeyOutputPath: string) { } } +export async function proveUltraHonk(bytecodePath: string, witnessPath: string, crsPath: string, outputPath: string) { + const { api } = await init(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 init(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 } = 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); @@ -505,4 +555,36 @@ program acvmInfo(outputPath); }); +program + .command('prove_ultra_honk') + .description('Generate a proof and write it to a file.') + .option('-b, --bytecode-path ', 'Specify the bytecode path', './target/acir.gz') + .option('-w, --witness-path ', 'Specify the witness path', './target/witness.gz') + .option('-o, --output-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 ', 'Specify the bytecode path', './target/acir.gz') + .requiredOption('-o, --output-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 ', 'Specify the path to the proof') + .requiredOption('-k, --vk ', '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);