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: honk flows exposed through wasm #6096

Merged
merged 10 commits into from
May 3, 2024
4 changes: 3 additions & 1 deletion barretenberg/acir_tests/Dockerfile.bb.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@ 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_and_verify_ultra_honk ./run_acir_tests.sh
# RUn a single arbitrary test for separate prove and verify for UltraHonk
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

RUn -> Run

RUN BIN=../ts/dest/node/main.js FLOW=prove_then_verify_ultra_honk ./run_acir_tests.sh
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

currently runs all for safety. Can change to not

# Run a single arbitrary test not involving recursion through bb.js for GoblinUltraHonk
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
Expand Down
40 changes: 40 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 @@ -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);
}

Copy link
Contributor Author

@lucasxia01 lucasxia01 May 2, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

core changes: adding functions that are callable by js that expose honk functionality

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<std::vector<uint8_t>>(acir_vec));
auto witness = acir_format::witness_buf_to_witness_data(from_buffer<std::vector<uint8_t>>(witness_vec));

auto builder = acir_format::create_circuit<UltraCircuitBuilder>(constraint_system, 0, witness);

UltraProver prover{ builder };
auto proof = prover.construct_proof();
*out = to_heap_buffer(to_buffer</*include_size=*/true>(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<curve::BN254>;
using Verifier = UltraVerifier_<UltraFlavor>;

auto proof = from_buffer<std::vector<bb::fr>>(from_buffer<std::vector<uint8_t>>(proof_buf));
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));
}
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 @@ -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);
fr::out_buf out_key_hash);

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not sure why I don't have to add the other 2 functions in the hpp, but there aren't any errors from missing them

WASM_EXPORT void acir_prove_ultra_honk(uint8_t const* acir_vec, uint8_t const* witness_vec, uint8_t** out);
2 changes: 1 addition & 1 deletion barretenberg/cpp/src/barretenberg/eccvm/eccvm_verifier.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<Flavor>(log_circuit_size, transcript);
FF alpha = transcript->template get_challenge<FF>("Sumcheck:alpha");
std::vector<FF> gate_challenges(numeric::get_msb(key->circuit_size));
std::vector<FF> gate_challenges(static_cast<size_t>(numeric::get_msb(key->circuit_size)));
for (size_t idx = 0; idx < gate_challenges.size(); idx++) {
gate_challenges[idx] = transcript->template get_challenge<FF>("Sumcheck:gate_challenge_" + std::to_string(idx));
}
Expand Down
8 changes: 4 additions & 4 deletions barretenberg/cpp/src/barretenberg/flavor/flavor.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

had to change these to serializable types (uint64_t), but this led to many compile errors relating to implicit conversions losing precision, so I had to add many static_casts as a temporary fix. The long term fix should be using uint32_t/uint64_t instead of size_t by default in most places that aren't accessing memory

uint64_t log_circuit_size;
uint64_t num_public_inputs;
CircuitType circuit_type; // TODO(#392)
};

Expand Down Expand Up @@ -181,7 +181,7 @@ template <typename PrecomputedCommitments, typename VerifierCommitmentKey>
class VerificationKey_ : public PrecomputedCommitments {
public:
std::shared_ptr<VerifierCommitmentKey> 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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ template <typename Flavor> bool DeciderVerifier_<Flavor>::verify_proof(const Hon

VerifierCommitments commitments{ accumulator->verification_key, accumulator->witness_commitments };

auto sumcheck =
SumcheckVerifier<Flavor>(accumulator->verification_key->log_circuit_size, transcript, accumulator->target_sum);
auto sumcheck = SumcheckVerifier<Flavor>(
static_cast<size_t>(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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ void ProtoGalaxyVerifier_<VerifierInstances>::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<FF>(inst->verification_key->log_circuit_size, 0);
inst->gate_challenges = std::vector<FF>(static_cast<size_t>(inst->verification_key->log_circuit_size), 0);
Copy link
Contributor Author

@lucasxia01 lucasxia01 May 2, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

adding static_cast<size_t> to fix compile errors

}
index++;

Expand All @@ -45,11 +45,12 @@ std::shared_ptr<typename VerifierInstances::Instance> ProtoGalaxyVerifier_<Verif

auto delta = transcript->template get_challenge<FF>("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<size_t>(accumulator->verification_key->log_circuit_size), delta);

std::vector<FF> perturbator_coeffs(accumulator->verification_key->log_circuit_size + 1, 0);
std::vector<FF> perturbator_coeffs(static_cast<size_t>(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<size_t>(accumulator->verification_key->log_circuit_size); idx++) {
perturbator_coeffs[idx] =
transcript->template receive_from_prover<FF>("perturbator_" + std::to_string(idx));
}
Expand Down Expand Up @@ -112,7 +113,8 @@ std::shared_ptr<typename VerifierInstances::Instance> ProtoGalaxyVerifier_<Verif
vk_idx++;
}
next_accumulator->verification_key->num_public_inputs = accumulator->verification_key->num_public_inputs;
next_accumulator->public_inputs = std::vector<FF>(next_accumulator->verification_key->num_public_inputs, 0);
next_accumulator->public_inputs =
std::vector<FF>(static_cast<size_t>(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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ std::array<typename Flavor::GroupElement, 2> DeciderRecursiveVerifier_<Flavor>::

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<size_t>(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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,11 +78,12 @@ void ProtoGalaxyRecursiveVerifier_<VerifierInstances>::receive_and_finalise_inst
transcript->template receive_from_prover<Commitment>(domain_separator + "_" + labels.z_lookup);

// Compute correction terms for grand products
const FF public_input_delta = compute_public_input_delta<Flavor>(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<Flavor>(inst->public_inputs,
beta,
gamma,
inst->verification_key->circuit_size,
static_cast<size_t>(inst->verification_key->pub_inputs_offset));
const FF lookup_grand_product_delta =
compute_lookup_grand_product_delta<FF>(beta, gamma, inst->verification_key->circuit_size);
inst->relation_parameters =
Expand All @@ -105,7 +106,7 @@ template <class VerifierInstances> void ProtoGalaxyRecursiveVerifier_<VerifierIn
if (!inst->is_accumulator) {
receive_and_finalise_instance(inst, domain_separator);
inst->target_sum = 0;
inst->gate_challenges = std::vector<FF>(inst->verification_key->log_circuit_size, 0);
inst->gate_challenges = std::vector<FF>(static_cast<size_t>(inst->verification_key->log_circuit_size), 0);
}
index++;

Expand All @@ -128,11 +129,12 @@ std::shared_ptr<typename VerifierInstances::Instance> ProtoGalaxyRecursiveVerifi

auto delta = transcript->template get_challenge<FF>("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<size_t>(accumulator->verification_key->log_circuit_size), delta);

std::vector<FF> perturbator_coeffs(accumulator->verification_key->log_circuit_size + 1, 0);
std::vector<FF> perturbator_coeffs(static_cast<size_t>(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<size_t>(accumulator->verification_key->log_circuit_size); idx++) {
perturbator_coeffs[idx] =
transcript->template receive_from_prover<FF>("perturbator_" + std::to_string(idx));
}
Expand Down Expand Up @@ -200,7 +202,8 @@ std::shared_ptr<typename VerifierInstances::Instance> ProtoGalaxyRecursiveVerifi
comm_idx++;
}

next_accumulator->public_inputs = std::vector<FF>(next_accumulator->verification_key->num_public_inputs, 0);
next_accumulator->public_inputs =
std::vector<FF>(static_cast<size_t>(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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ template <IsRecursiveFlavor Flavor> class RecursiveVerifierInstance_ {
: verification_key(std::make_shared<VerificationKey>(instance->verification_key->circuit_size,
instance->verification_key->num_public_inputs))
, is_accumulator(bool(instance->is_accumulator))
, public_inputs(std::vector<FF>(instance->verification_key->num_public_inputs))
, public_inputs(std::vector<FF>(static_cast<size_t>(instance->verification_key->num_public_inputs)))
{

verification_key->pub_inputs_offset = instance->verification_key->pub_inputs_offset;
Expand Down Expand Up @@ -113,7 +113,7 @@ template <IsRecursiveFlavor Flavor> class RecursiveVerifierInstance_ {
VerifierInstance inst(inst_verification_key);
inst.is_accumulator = is_accumulator;

inst.public_inputs = std::vector<NativeFF>(verification_key->num_public_inputs);
inst.public_inputs = std::vector<NativeFF>(static_cast<size_t>(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();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<Flavor>(log_circuit_size, transcript);
FF alpha = transcript->template get_challenge<FF>("Sumcheck:alpha");
std::vector<FF> gate_challenges(numeric::get_msb(key->circuit_size));
std::vector<FF> gate_challenges(static_cast<size_t>(numeric::get_msb(key->circuit_size)));
for (size_t idx = 0; idx < gate_challenges.size(); idx++) {
gate_challenges[idx] = transcript->template get_challenge<FF>("Sumcheck:gate_challenge_" + std::to_string(idx));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -124,8 +124,11 @@ template <IsUltraFlavor Flavor> void OinkVerifier<Flavor>::execute_log_derivativ
*/
template <IsUltraFlavor Flavor> void OinkVerifier<Flavor>::execute_grand_product_computation_round()
{
const FF public_input_delta = compute_public_input_delta<Flavor>(
public_inputs, relation_parameters.beta, relation_parameters.gamma, key->circuit_size, key->pub_inputs_offset);
const FF public_input_delta = compute_public_input_delta<Flavor>(public_inputs,
relation_parameters.beta,
relation_parameters.gamma,
key->circuit_size,
static_cast<size_t>(key->pub_inputs_offset));
const FF lookup_grand_product_delta =
compute_lookup_grand_product_delta<FF>(relation_parameters.beta, relation_parameters.gamma, key->circuit_size);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ template <typename Flavor> bool UltraVerifier_<Flavor>::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<size_t>(numeric::get_msb(key->circuit_size));
auto sumcheck = SumcheckVerifier<Flavor>(log_circuit_size, transcript);

auto gate_challenges = std::vector<FF>(log_circuit_size);
Expand Down
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;
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

core change: adding the functions to the bb api

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];
}
}
Loading
Loading