Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat!: Separate public inputs from proof in acir composer #2618

Closed
wants to merge 45 commits into from
Closed
Show file tree
Hide file tree
Changes from 22 commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
5035024
temporary: add methods to split the proof and take in public inputs s…
kevaundray Oct 2, 2023
2b438db
modify c-binds to use those methods
kevaundray Oct 2, 2023
934a578
modify browser test app to account for separate public inputs
kevaundray Oct 2, 2023
75b9dc7
modify bb binary to account for separate public inputs
kevaundray Oct 2, 2023
65acca8
modify bb.js node binary to account for separate public inputs
kevaundray Oct 2, 2023
902520a
exports.json file was regenerated
kevaundray Oct 2, 2023
8dadcfa
regenerate api file -- unfortunately my linter changed lines in the f…
kevaundray Oct 2, 2023
6376452
formatter
kevaundray Oct 2, 2023
06e2ad7
add code to not read the public inputs file if there are no public in…
kevaundray Oct 2, 2023
ab683a1
temporarily switch args
kevaundray Oct 2, 2023
adc2357
put publicInputs in serializeProofIntoFields
kevaundray Oct 2, 2023
4a026aa
modify binary to account for new cbind api
kevaundray Oct 2, 2023
f6af120
always put public inputs vector first
kevaundray Oct 2, 2023
06ea909
regenerate exports.json
kevaundray Oct 2, 2023
93218e7
conditionally read the public inputs
kevaundray Oct 2, 2023
7aa3855
typo
kevaundray Oct 2, 2023
0c6ca7f
yarn
kevaundray Oct 2, 2023
0df922c
put in separate PR
kevaundray Oct 2, 2023
0e3bfa7
cleanup bb
kevaundray Oct 2, 2023
b463a8a
cleanup bb.js binary
kevaundray Oct 2, 2023
23d2067
remove _splitted methods
kevaundray Oct 2, 2023
4461139
modify bb binary; since we removed _splitted methods
kevaundray Oct 2, 2023
c2a6773
Update barretenberg/acir_tests/run_acir_tests_browser.sh
kevaundray Oct 2, 2023
b4233da
formatting fix
kevaundray Oct 2, 2023
362552a
change outwards facing API to not mention proofWithoutPublicInputs
kevaundray Oct 3, 2023
8576164
using proof instead of proof_without_public_inputs in cbinds
kevaundray Oct 3, 2023
51714c8
redo bindings
kevaundray Oct 3, 2023
a811d36
modify binaries
kevaundray Oct 3, 2023
2d07550
linter
kevaundray Oct 3, 2023
0b49345
multi:
kevaundray Oct 3, 2023
b669013
bb: -public_inputs -> _public_inputs
kevaundray Oct 3, 2023
aeea25e
lint
kevaundray Oct 3, 2023
dab3ec3
add get_file_size method
kevaundray Oct 3, 2023
2b60a6c
use get_file_size instead of passing number of public inputs
kevaundray Oct 3, 2023
24d0bc6
do not pass vk to proofAsFields
kevaundray Oct 3, 2023
7f539fe
use methods in container to refactor
kevaundray Oct 3, 2023
c62a6cd
change c-style cast and add back comment
kevaundray Oct 3, 2023
21e67bd
tellg returns 0 for empty file, if there was an error reading it, rea…
kevaundray Oct 3, 2023
4a369ab
inline splitVector and remove concatenate vector
kevaundray Oct 3, 2023
c7b5102
reduce diff
kevaundray Oct 3, 2023
00a19ba
Merge branch 'master' into kw/separate-public-inputs
kevaundray Oct 3, 2023
fc6aefd
better variable name
kevaundray Oct 3, 2023
0cafaa8
Merge remote-tracking branch 'origin/master' into kw/separate-public-…
kevaundray Oct 12, 2023
036d1f3
fix merge
kevaundray Oct 12, 2023
fe50733
deduplicate public witness indices
kevaundray Oct 12, 2023
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/acir_tests/browser-test-app/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,14 @@ async function runTest(
);

const acirComposer = await api.acirNewAcirComposer(CIRCUIT_SIZE);
const proof = await api.acirCreateProof(
const [publicInputs, proofWithOutPublicInputs] = await api.acirCreateProof(
kevaundray marked this conversation as resolved.
Show resolved Hide resolved
acirComposer,
bytecode,
witness,
true
);
debug(`verifying...`);
const verified = await api.acirVerifyProof(acirComposer, proof, true);
const verified = await api.acirVerifyProof(acirComposer, publicInputs, proofWithOutPublicInputs, true);
debug(`verified: ${verified}`);

await api.destroy();
Expand Down
1 change: 1 addition & 0 deletions barretenberg/acir_tests/run_acir_tests_browser.sh
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ THREAD_MODEL=${THREAD_MODEL:-mt}

# TODO: Currently webkit doesn't seem to have shared memory so is a single threaded test regardless of THREAD_MODEL!
echo "Testing thread model: $THREAD_MODEL"

kevaundray marked this conversation as resolved.
Show resolved Hide resolved
(cd browser-test-app && yarn serve:dest:$THREAD_MODEL) > /dev/null 2>&1 &
sleep 1
VERBOSE=1 BIN=./headless-test/bb.js.browser ./run_acir_tests.sh $@
Expand Down
67 changes: 53 additions & 14 deletions barretenberg/cpp/src/barretenberg/bb/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include <barretenberg/dsl/acir_format/acir_to_constraint_buf.hpp>
#include <barretenberg/dsl/acir_proofs/acir_composer.hpp>
#include <barretenberg/srs/global_crs.hpp>
#include <cstddef>
#include <iostream>
#include <stdexcept>
#include <string>
Expand Down Expand Up @@ -38,6 +39,28 @@ acir_format::acir_format get_constraint_system(std::string const& bytecode_path)
return acir_format::circuit_buf_to_acir_format(bytecode);
}

std::vector<uint8_t> read_public_inputs(std::string const& public_inputs_path, size_t num_public_inputs)
{
// If the number of public inputs is 0, then read_file will trigger a failure
// because the file will be empty.
if (num_public_inputs == 0) {
return {};
}
return read_file(public_inputs_path);
}

// When given a proof path, we simply append "-public_inputs" to it.
// to derive a file path for the public inputs.
//
// The alternative is to have the user pass in a path for their proof
// and a path for their public inputs. This is more verbose and
// its likely that the user will want their public inputs to be
// in the same directory as their proof.
std::string public_inputs_path_from_proof_path(std::string const& proof_path)
{
return proof_path + "-public_inputs";
kevaundray marked this conversation as resolved.
Show resolved Hide resolved
}

/**
* @brief Proves and Verifies an ACIR circuit
*
Expand All @@ -56,8 +79,10 @@ bool proveAndVerify(const std::string& bytecodePath, const std::string& witnessP
auto acir_composer = new acir_proofs::AcirComposer(MAX_CIRCUIT_SIZE, verbose);
auto constraint_system = get_constraint_system(bytecodePath);
auto witness = get_witness(witnessPath);
auto proof = acir_composer->create_proof(srs::get_crs_factory(), constraint_system, witness, recursive);
auto verified = acir_composer->verify_proof(proof, recursive);
auto [public_inputs, proof_without_public_inputs] =
acir_composer->create_proof(srs::get_crs_factory(), constraint_system, witness, recursive);

auto verified = acir_composer->verify_proof(public_inputs, proof_without_public_inputs, recursive);

vinfo("verified: ", verified);
return verified;
Expand All @@ -73,24 +98,29 @@ bool proveAndVerify(const std::string& bytecodePath, const std::string& witnessP
* @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 outputPath Path to write the proof to
* @param outputProofPath Path to write the proof to - The proof does not contain public inputs
*/
void prove(const std::string& bytecodePath,
const std::string& witnessPath,
bool recursive,
const std::string& outputPath)
const std::string& outputProofPath)
{
auto acir_composer = new acir_proofs::AcirComposer(MAX_CIRCUIT_SIZE, verbose);
auto constraint_system = get_constraint_system(bytecodePath);
auto witness = get_witness(witnessPath);
auto proof = acir_composer->create_proof(srs::get_crs_factory(), constraint_system, witness, recursive);
auto [public_inputs, proof_without_public_inputs] =
acir_composer->create_proof(srs::get_crs_factory(), constraint_system, witness, recursive);

if (outputPath == "-") {
writeRawBytesToStdout(proof);
vinfo("proof written to stdout");
if (outputProofPath == "-") {
writeRawBytesToStdout(public_inputs);
writeRawBytesToStdout(proof_without_public_inputs);
vinfo("proof and public inputs written to stdout");
} else {
write_file(outputPath, proof);
vinfo("proof written to: ", outputPath);
auto outputPublicInputsPath = public_inputs_path_from_proof_path(outputProofPath);
write_file(outputPublicInputsPath, public_inputs);
write_file(outputProofPath, proof_without_public_inputs);
vinfo("proof written to: ", outputProofPath);
vinfo("public inputs written to: ", outputPublicInputsPath);
}
}

Expand Down Expand Up @@ -123,7 +153,7 @@ void gateCount(const std::string& bytecodePath)
* - proc_exit: A boolean value is returned indicating whether the proof is valid.
* an exit code of 0 will be returned for success and 1 for failure.
*
* @param proof_path Path to the file containing the serialized proof
* @param proof_path Path to the file containing the serialized proof without public inputs preprended
* @param recursive Whether to use recursive proof generation of non-recursive
* @param vk_path Path to the file containing the serialized verification key
* @return true If the proof is valid
Expand All @@ -134,7 +164,11 @@ bool verify(const std::string& proof_path, bool recursive, const std::string& vk
auto acir_composer = new acir_proofs::AcirComposer(MAX_CIRCUIT_SIZE, verbose);
auto vk_data = from_buffer<plonk::verification_key_data>(read_file(vk_path));
acir_composer->load_verification_key(barretenberg::srs::get_crs_factory(), std::move(vk_data));
auto verified = acir_composer->verify_proof(read_file(proof_path), recursive);

auto public_inputs_path = public_inputs_path_from_proof_path(proof_path);
std::vector<uint8_t> public_inputs = read_public_inputs(public_inputs_path, vk_data.num_public_inputs);
auto proof_without_public_inputs = read_file(proof_path);
auto verified = acir_composer->verify_proof(public_inputs, proof_without_public_inputs, recursive);

vinfo("verified: ", verified);

Expand Down Expand Up @@ -223,9 +257,14 @@ void contract(const std::string& output_path, const std::string& vk_path)
*/
void proofAsFields(const std::string& proof_path, std::string const& vk_path, const std::string& output_path)
{
auto acir_composer = new acir_proofs::AcirComposer(MAX_CIRCUIT_SIZE, verbose);
auto vk_data = from_buffer<plonk::verification_key_data>(read_file(vk_path));
auto data = acir_composer->serialize_proof_into_fields(read_file(proof_path), vk_data.num_public_inputs);

auto public_inputs_path = public_inputs_path_from_proof_path(proof_path);
auto proof = read_file(proof_path);
std::vector<uint8_t> public_inputs = read_public_inputs(public_inputs_path, vk_data.num_public_inputs);

auto acir_composer = new acir_proofs::AcirComposer(MAX_CIRCUIT_SIZE, verbose);
auto data = acir_composer->serialize_proof_into_fields(public_inputs, proof, vk_data.num_public_inputs);
auto json = format("[", join(map(data, [](auto fr) { return format("\"", fr, "\""); })), "]");

if (output_path == "-") {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,60 @@ AcirComposer::AcirComposer(size_t size_hint, bool verbose)
, verbose_(verbose)
{}

/**
* @brief Splits a vector into two vectors,
* the first containing the first 32 * k elements, and the second containing
* the rest.
*
* @param original - The original vector to split
* @param k - The number of 32 bytes to remove
* @return std::pair<std::vector<uint8_t>, std::vector<uint8_t>>
*/
std::pair<std::vector<uint8_t>, std::vector<uint8_t>> splitVector(std::vector<uint8_t>& original, uint32_t k)
kevaundray marked this conversation as resolved.
Show resolved Hide resolved
{
uint32_t elementsToRemove = 32 * k;

if (original.size() < elementsToRemove) {
throw_or_abort("Not enough elements in the original vector");
}
auto elementsToRemoveLong = static_cast<long>(elementsToRemove);
std::vector<uint8_t> removed(original.begin(), original.begin() + elementsToRemoveLong);
original = std::vector<uint8_t>(original.begin() + elementsToRemoveLong, original.end());

return { original, removed };
}

/**
* @brief Splits the proof into two vectors.
*
* Barretenberg returns a proof that is concatenated with the public inputs.
* This function splits the proof into two vectors, one containing the public inputs,
* and the other containing the proof without the public inputs.
*
* @param proof - proof with the public inputs preprended
* @param num_public_inputs - the number of public inputs prepended to the proof
* @return std::pair<std::vector<uint8_t>, std::vector<uint8_t>>
*/
std::pair<std::vector<uint8_t>, std::vector<uint8_t>> split_proof(std::vector<uint8_t>& proof,
uint32_t num_public_inputs)
{
auto [proof_without_public_inputs, public_inputs] = splitVector(proof, num_public_inputs);
return { public_inputs, proof_without_public_inputs };
}

std::vector<uint8_t> concatenateVectors(const std::vector<uint8_t>& firstVector,
const std::vector<uint8_t>& secondVector)
{
std::vector<uint8_t> concatenatedVector;

concatenatedVector.reserve(firstVector.size() + secondVector.size());

concatenatedVector.insert(concatenatedVector.end(), firstVector.begin(), firstVector.end());
concatenatedVector.insert(concatenatedVector.end(), secondVector.begin(), secondVector.end());

return concatenatedVector;
}

void AcirComposer::create_circuit(acir_format::acir_format& constraint_system)
{
builder_ = acir_format::create_circuit(constraint_system, size_hint_);
Expand Down Expand Up @@ -52,7 +106,7 @@ void AcirComposer::init_proving_key(
proving_key_ = composer_.compute_proving_key(builder_);
}

std::vector<uint8_t> AcirComposer::create_proof(
std::pair<std::vector<uint8_t>, std::vector<uint8_t>> AcirComposer::create_proof(
std::shared_ptr<barretenberg::srs::factories::CrsFactory<curve::BN254>> const& crs_factory,
acir_format::acir_format& constraint_system,
acir_format::WitnessVector& witness,
Expand Down Expand Up @@ -97,7 +151,9 @@ std::vector<uint8_t> AcirComposer::create_proof(
proof = prover.construct_proof().proof_data;
}
vinfo("done.");
return proof;

auto num_public_inputs = static_cast<uint32_t>(constraint_system.public_inputs.size());
return split_proof(proof, num_public_inputs);
}

std::shared_ptr<proof_system::plonk::verification_key> AcirComposer::init_verification_key()
Expand All @@ -117,8 +173,13 @@ void AcirComposer::load_verification_key(
composer_ = acir_format::Composer(proving_key_, verification_key_);
}

bool AcirComposer::verify_proof(std::vector<uint8_t> const& proof, bool is_recursive)
bool AcirComposer::verify_proof(std::vector<uint8_t> const& public_inputs,
std::vector<uint8_t> const& proof_without_public_inputs,
bool is_recursive)
{

auto proof = concatenateVectors(public_inputs, proof_without_public_inputs);

if (!verification_key_) {
vinfo("computing verification key...");
verification_key_ = composer_.compute_verification_key(builder_);
Expand Down Expand Up @@ -152,9 +213,12 @@ std::string AcirComposer::get_solidity_verifier()
* @param proof
* @param num_inner_public_inputs - number of public inputs on the proof being serialized
*/
std::vector<barretenberg::fr> AcirComposer::serialize_proof_into_fields(std::vector<uint8_t> const& proof,
size_t num_inner_public_inputs)
std::vector<barretenberg::fr> AcirComposer::serialize_proof_into_fields(
kevaundray marked this conversation as resolved.
Show resolved Hide resolved
std::vector<uint8_t> const& public_inputs,
std::vector<uint8_t> const& proof_without_public_inputs,
size_t num_inner_public_inputs) // TODO: remove this, can be derived from public_inputs
{
auto proof = concatenateVectors(public_inputs, proof_without_public_inputs);
transcript::StandardTranscript transcript(proof,
acir_format::Composer::create_manifest(num_inner_public_inputs),
transcript::HashType::PlookupPedersenBlake3s,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ class AcirComposer {
void init_proving_key(std::shared_ptr<barretenberg::srs::factories::CrsFactory<curve::BN254>> const& crs_factory,
acir_format::acir_format& constraint_system);

std::vector<uint8_t> create_proof(
std::pair<std::vector<uint8_t>, std::vector<uint8_t>> create_proof(
std::shared_ptr<barretenberg::srs::factories::CrsFactory<curve::BN254>> const& crs_factory,
acir_format::acir_format& constraint_system,
acir_format::WitnessVector& witness,
Expand All @@ -29,13 +29,14 @@ class AcirComposer {

std::shared_ptr<proof_system::plonk::verification_key> init_verification_key();

bool verify_proof(std::vector<uint8_t> const& proof, bool is_recursive);
bool verify_proof(std::vector<uint8_t> const& public_inputs, std::vector<uint8_t> const& proof, bool is_recursive);

std::string get_solidity_verifier();
size_t get_exact_circuit_size() { return exact_circuit_size_; };
size_t get_total_circuit_size() { return total_circuit_size_; };

std::vector<barretenberg::fr> serialize_proof_into_fields(std::vector<uint8_t> const& proof,
std::vector<barretenberg::fr> serialize_proof_into_fields(std::vector<uint8_t> const& public_inputs,
std::vector<uint8_t> const& proof_without_public_inputs,
size_t num_inner_public_inputs);

std::vector<barretenberg::fr> serialize_verification_key_into_fields();
Expand Down
23 changes: 15 additions & 8 deletions barretenberg/cpp/src/barretenberg/dsl/acir_proofs/c_bind.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,15 +42,17 @@ WASM_EXPORT void acir_create_proof(in_ptr acir_composer_ptr,
uint8_t const* acir_vec,
uint8_t const* witness_vec,
bool const* is_recursive,
uint8_t** out)
uint8_t** out_public_inputs,
uint8_t** out_proof_without_public_inputs)
{
auto acir_composer = reinterpret_cast<acir_proofs::AcirComposer*>(*acir_composer_ptr);
auto constraint_system = acir_format::circuit_buf_to_acir_format(from_buffer<std::vector<uint8_t>>(acir_vec));
auto witness = acir_format::witness_buf_to_witness_data(from_buffer<std::vector<uint8_t>>(witness_vec));

auto proof_data =
auto [public_inputs, proof_without_public_inputs] =
acir_composer->create_proof(barretenberg::srs::get_crs_factory(), constraint_system, witness, *is_recursive);
*out = to_heap_buffer(proof_data);
*out_public_inputs = to_heap_buffer(public_inputs);
*out_proof_without_public_inputs = to_heap_buffer(proof_without_public_inputs);
}

WASM_EXPORT void acir_load_verification_key(in_ptr acir_composer_ptr, uint8_t const* vk_buf)
Expand All @@ -75,13 +77,15 @@ WASM_EXPORT void acir_get_verification_key(in_ptr acir_composer_ptr, uint8_t** o
}

WASM_EXPORT void acir_verify_proof(in_ptr acir_composer_ptr,
uint8_t const* proof_buf,
uint8_t const* public_inputs_buf,
uint8_t const* proof_without_public_inputs_buf,
bool const* is_recursive,
bool* result)
{
auto acir_composer = reinterpret_cast<acir_proofs::AcirComposer*>(*acir_composer_ptr);
auto proof = from_buffer<std::vector<uint8_t>>(proof_buf);
*result = acir_composer->verify_proof(proof, *is_recursive);
auto public_inputs = from_buffer<std::vector<uint8_t>>(public_inputs_buf);
auto proof_without_public_inputs = from_buffer<std::vector<uint8_t>>(proof_without_public_inputs_buf);
*result = acir_composer->verify_proof(public_inputs, proof_without_public_inputs, *is_recursive);
}

WASM_EXPORT void acir_get_solidity_verifier(in_ptr acir_composer_ptr, out_str_buf out)
Expand All @@ -92,13 +96,16 @@ WASM_EXPORT void acir_get_solidity_verifier(in_ptr acir_composer_ptr, out_str_bu
}

WASM_EXPORT void acir_serialize_proof_into_fields(in_ptr acir_composer_ptr,
uint8_t const* public_inputs_buf,
uint8_t const* proof_buf,
uint32_t const* num_inner_public_inputs,
fr::vec_out_buf out)
{
auto acir_composer = reinterpret_cast<acir_proofs::AcirComposer*>(*acir_composer_ptr);
auto proof = from_buffer<std::vector<uint8_t>>(proof_buf);
auto proof_as_fields = acir_composer->serialize_proof_into_fields(proof, ntohl(*num_inner_public_inputs));
auto public_inputs = from_buffer<std::vector<uint8_t>>(proof_buf);
auto proof = from_buffer<std::vector<uint8_t>>(public_inputs_buf);
auto proof_as_fields =
acir_composer->serialize_proof_into_fields(public_inputs, proof, ntohl(*num_inner_public_inputs));

*out = to_heap_buffer(proof_as_fields);
}
Expand Down
11 changes: 7 additions & 4 deletions barretenberg/cpp/src/barretenberg/dsl/acir_proofs/c_bind.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,11 @@ WASM_EXPORT void acir_init_proving_key(in_ptr acir_composer_ptr, uint8_t const*
* to pass it in everytime.
*/
WASM_EXPORT void acir_create_proof(in_ptr acir_composer_ptr,
uint8_t const* constraint_system_buf,
uint8_t const* witness_buf,
uint8_t const* acir_vec,
uint8_t const* witness_vec,
bool const* is_recursive,
uint8_t** out);
uint8_t** out_public_inputs,
uint8_t** out_proof_without_public_inputs);

WASM_EXPORT void acir_load_verification_key(in_ptr acir_composer_ptr, uint8_t const* vk_buf);

Expand All @@ -39,13 +40,15 @@ WASM_EXPORT void acir_init_verification_key(in_ptr acir_composer_ptr);
WASM_EXPORT void acir_get_verification_key(in_ptr acir_composer_ptr, uint8_t** out);

WASM_EXPORT void acir_verify_proof(in_ptr acir_composer_ptr,
uint8_t const* proof_buf,
uint8_t const* public_inputs_buf,
uint8_t const* proof_without_public_inputs_buf,
bool const* is_recursive,
bool* result);

WASM_EXPORT void acir_get_solidity_verifier(in_ptr acir_composer_ptr, out_str_buf out);

WASM_EXPORT void acir_serialize_proof_into_fields(in_ptr acir_composer_ptr,
uint8_t const* public_inputs_buf,
uint8_t const* proof_buf,
uint32_t const* num_inner_public_inputs,
fr::vec_out_buf out);
Expand Down
Loading