diff --git a/barretenberg/acir_tests/flows/all_cmds.sh b/barretenberg/acir_tests/flows/all_cmds.sh index a65159351edf..233e2bfd77e8 100755 --- a/barretenberg/acir_tests/flows/all_cmds.sh +++ b/barretenberg/acir_tests/flows/all_cmds.sh @@ -7,9 +7,9 @@ FLAGS="-c $CRS_PATH $VFLAG" # Test we can perform the proof/verify flow. $BIN gates $FLAGS $BFLAG > /dev/null -$BIN prove -o proof $FLAGS $BFLAG -$BIN write_vk -o vk $FLAGS $BFLAG $BIN write_pk -o pk $FLAGS $BFLAG +$BIN prove -o proof -i pk $FLAGS $BFLAG +$BIN write_vk -o vk $FLAGS $BFLAG $BIN verify -k vk -p proof $FLAGS # Check supplemental functions. diff --git a/barretenberg/acir_tests/flows/write_pk_prove_then_verify.sh b/barretenberg/acir_tests/flows/write_pk_prove_then_verify.sh new file mode 100755 index 000000000000..6e4e6185f7a3 --- /dev/null +++ b/barretenberg/acir_tests/flows/write_pk_prove_then_verify.sh @@ -0,0 +1,13 @@ +#!/bin/sh +set -eu + +VFLAG=${VERBOSE:+-v} +BFLAG="-b ./target/acir.gz" +FLAGS="-c $CRS_PATH $VFLAG" + +# Test we can perform the proof/verify flow. +# This ensures we test independent pk construction through real/garbage witness data paths. +$BIN write_pk -o pk $FLAGS $BFLAG +$BIN prove -o proof -i pk $FLAGS $BFLAG +$BIN write_vk -o vk $FLAGS $BFLAG +$BIN verify -k vk -p proof $FLAGS diff --git a/barretenberg/cpp/src/barretenberg/bb/main.cpp b/barretenberg/cpp/src/barretenberg/bb/main.cpp index 0cc46d9dd24e..71e1657a8d2d 100644 --- a/barretenberg/cpp/src/barretenberg/bb/main.cpp +++ b/barretenberg/cpp/src/barretenberg/bb/main.cpp @@ -106,11 +106,13 @@ bool proveAndVerify(const std::string& bytecodePath, const std::string& witnessP * - Filesystem: The proof is written to the path specified by outputPath * * @param bytecodePath Path to the file containing the serialized circuit +// * @param pkPath Path to the file containing the serialized proving key * @param witnessPath Path to the file containing the serialized witness * @param recursive Whether to use recursive proof generation of non-recursive * @param outputPath Path to write the proof to */ void prove(const std::string& bytecodePath, + const std::string& pk_path, const std::string& witnessPath, bool recursive, const std::string& outputPath) @@ -118,6 +120,13 @@ void prove(const std::string& bytecodePath, auto constraint_system = get_constraint_system(bytecodePath); auto witness = get_witness(witnessPath); auto acir_composer = init(constraint_system); + + if (!pk_path.empty()) { + info("loading proving key from: ", pk_path); + auto pk_data = from_buffer(read_file(pk_path)); + acir_composer.load_proving_key(std::move(pk_data)); + } + auto proof = acir_composer.create_proof(constraint_system, witness, recursive); if (outputPath == "-") { @@ -380,7 +389,7 @@ int main(int argc, char* argv[]) std::string witness_path = get_option(args, "-w", "./target/witness.gz"); std::string proof_path = get_option(args, "-p", "./proofs/proof"); std::string vk_path = get_option(args, "-k", "./target/vk"); - std::string pk_path = get_option(args, "-r", "./target/pk"); + std::string pk_path = get_option(args, "-i", "./target/pk"); CRS_PATH = get_option(args, "-c", "./crs"); bool recursive = flag_present(args, "-r") || flag_present(args, "--recursive"); @@ -400,7 +409,10 @@ int main(int argc, char* argv[]) } if (command == "prove") { std::string output_path = get_option(args, "-o", "./proofs/proof"); - prove(bytecode_path, witness_path, recursive, output_path); + + // Overwriting pk, as we want to use a default value of an empty string when we are not *reading* a pk + std::string pk_path = get_option(args, "-i", ""); + prove(bytecode_path, pk_path, witness_path, recursive, output_path); } else if (command == "gates") { gateCount(bytecode_path); } else if (command == "verify") { diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/acir_composer.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/acir_composer.cpp index 0dc4a1177353..8c0c8a9cc58c 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/acir_composer.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/acir_composer.cpp @@ -41,6 +41,12 @@ std::shared_ptr AcirComposer::init_proving_key return proving_key_; } +void AcirComposer::load_proving_key(proof_system::plonk::proving_key_data&& data) +{ + proving_key_ = std::make_shared( + std::move(data), srs::get_crs_factory()->get_prover_crs(data.circuit_size)); +} + std::vector AcirComposer::create_proof(acir_format::acir_format& constraint_system, acir_format::WitnessVector& witness, bool is_recursive) diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/acir_composer.hpp b/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/acir_composer.hpp index db78f067a22a..6cdcd31fe66e 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/acir_composer.hpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/acir_composer.hpp @@ -15,6 +15,7 @@ class AcirComposer { void create_circuit(acir_format::acir_format& constraint_system); std::shared_ptr init_proving_key(acir_format::acir_format& constraint_system); + void load_proving_key(proof_system::plonk::proving_key_data&& data); std::vector create_proof(acir_format::acir_format& constraint_system, acir_format::WitnessVector& witness, 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 b92213f9724d..c7718a7f1c8f 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/c_bind.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/c_bind.cpp @@ -39,6 +39,14 @@ WASM_EXPORT void acir_init_proving_key(in_ptr acir_composer_ptr, uint8_t const* acir_composer->init_proving_key(constraint_system); } +WASM_EXPORT void acir_load_proving_key(in_ptr acir_composer_ptr, uint8_t const* pk_buf) +{ + auto acir_composer = reinterpret_cast(*acir_composer_ptr); + auto pk_data = from_buffer(pk_buf); + + acir_composer->load_proving_key(std::move(pk_data)); +} + WASM_EXPORT void acir_create_proof(in_ptr acir_composer_ptr, uint8_t const* acir_vec, uint8_t const* witness_vec, 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 5ffa298b2fc0..4478ca3b6f7a 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/c_bind.hpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/c_bind.hpp @@ -21,6 +21,8 @@ WASM_EXPORT void acir_create_circuit(in_ptr acir_composer_ptr, WASM_EXPORT void acir_init_proving_key(in_ptr acir_composer_ptr, uint8_t const* constraint_system_buf); +WASM_EXPORT void acir_load_proving_key(in_ptr acir_composer_ptr, uint8_t const* pk_buf); + /** * It would have been nice to just hold onto the constraint_system in the acir_composer, but we can't waste the * memory. Being able to reuse the underlying Composer would help as well. But, given the situation, we just have diff --git a/barretenberg/ts/src/barretenberg_api/index.ts b/barretenberg/ts/src/barretenberg_api/index.ts index ea1aac55dadc..5fdb9db25b16 100644 --- a/barretenberg/ts/src/barretenberg_api/index.ts +++ b/barretenberg/ts/src/barretenberg_api/index.ts @@ -328,6 +328,18 @@ export class BarretenbergApi { return; } + async acirLoadProvingKey(acirComposerPtr: Ptr, pkBuf: Uint8Array): Promise { + const inArgs = [acirComposerPtr, pkBuf].map(serializeBufferable); + const outTypes: OutputType[] = []; + const result = await this.wasm.callWasmExport( + 'acir_load_proving_key', + inArgs, + outTypes.map(t => t.SIZE_IN_BYTES), + ); + const out = result.map((r, i) => outTypes[i].fromBuffer(r)); + return; + } + async acirCreateProof( acirComposerPtr: Ptr, constraintSystemBuf: Uint8Array, @@ -761,6 +773,18 @@ export class BarretenbergApiSync { return; } + acirLoadProvingKey(acirComposerPtr: Ptr, pkBuf: Uint8Array): void { + const inArgs = [acirComposerPtr, pkBuf].map(serializeBufferable); + const outTypes: OutputType[] = []; + const result = this.wasm.callWasmExport( + 'acir_load_proving_key', + inArgs, + outTypes.map(t => t.SIZE_IN_BYTES), + ); + const out = result.map((r, i) => outTypes[i].fromBuffer(r)); + return; + } + acirCreateProof( acirComposerPtr: Ptr, constraintSystemBuf: Uint8Array, diff --git a/barretenberg/ts/src/main.ts b/barretenberg/ts/src/main.ts index 016c8a63c04c..89213453e868 100755 --- a/barretenberg/ts/src/main.ts +++ b/barretenberg/ts/src/main.ts @@ -114,6 +114,7 @@ export async function proveAndVerify(bytecodePath: string, witnessPath: string, export async function prove( bytecodePath: string, + pkPath: string, witnessPath: string, crsPath: string, isRecursive: boolean, @@ -124,6 +125,12 @@ export async function prove( debug(`creating proof...`); const bytecode = getBytecode(bytecodePath); const witness = getWitness(witnessPath); + + if (pkPath != '') { + debug(`loading proving key from ${pkPath}...`); + await api.acirLoadProvingKey(acirComposer, new RawBuffer(readFileSync(pkPath))); + } + const proof = await api.acirCreateProof(acirComposer, bytecode, witness, isRecursive); debug(`done.`); @@ -316,12 +323,13 @@ program .command('prove') .description('Generate a proof and write it to a file.') .option('-b, --bytecode-path ', 'Specify the bytecode path', './target/acir.gz') + .option('-i, --proving-key-path ', 'Read proving key from file', '') .option('-w, --witness-path ', 'Specify the witness path', './target/witness.gz') .option('-r, --recursive', 'prove using recursive prover', false) .option('-o, --output-path ', 'Specify the proof output path', './proofs/proof') - .action(async ({ bytecodePath, witnessPath, recursive, outputPath, crsPath }) => { + .action(async ({ bytecodePath, provingKeyPath, witnessPath, recursive, outputPath, crsPath }) => { handleGlobalOptions(); - await prove(bytecodePath, witnessPath, crsPath, recursive, outputPath); + await prove(bytecodePath, provingKeyPath, witnessPath, crsPath, recursive, outputPath); }); program