Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
bbapi_ultra_honk.cpp
Go to the documentation of this file.
4#include "barretenberg/bbapi/generated/bb_types.hpp"
16
17namespace bb::bbapi {
18
19namespace {
20
21template <typename IO> acir_format::ProgramMetadata _create_program_metadata()
22{
23 return acir_format::ProgramMetadata{ .has_ipa_claim = IO::HasIPA };
24}
25
26template <typename Flavor, typename IO, typename Circuit = typename Flavor::CircuitBuilder>
27Circuit _compute_circuit(std::vector<uint8_t>&& bytecode, std::vector<uint8_t>&& witness)
28{
29 const acir_format::ProgramMetadata metadata = _create_program_metadata<IO>();
31 if (!witness.empty()) {
32 program.witness = acir_format::witness_buf_to_witness_vector(std::move(witness));
33 }
34 return acir_format::create_circuit<Circuit>(program, metadata);
35}
36
37template <typename Flavor, typename IO>
38std::shared_ptr<ProverInstance_<Flavor>> _compute_prover_instance(std::vector<uint8_t>&& bytecode,
39 std::vector<uint8_t>&& witness)
40{
41 auto initial_time = std::chrono::high_resolution_clock::now();
42 typename Flavor::CircuitBuilder builder = _compute_circuit<Flavor, IO>(std::move(bytecode), std::move(witness));
44 auto final_time = std::chrono::high_resolution_clock::now();
45 auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(final_time - initial_time);
46 info("CircuitProve: Proving key computed in ", duration.count(), " ms");
47
48 if constexpr (IO::HasIPA) {
49 BB_ASSERT(!prover_instance->ipa_proof.empty(),
50 "RollupIO circuit expected IPA proof but none was provided. "
51 "Ensure the circuit includes IPA accumulation data.");
52 } else {
53 BB_ASSERT(prover_instance->ipa_proof.empty(),
54 "Non-rollup circuit should not have IPA proof. "
55 "Use ipa_accumulation=true in settings for rollup circuits.");
56 }
57 return prover_instance;
58}
59
60template <typename Flavor, typename IO>
61wire::CircuitProveResponse _prove(std::vector<uint8_t>&& bytecode,
62 std::vector<uint8_t>&& witness,
63 std::vector<uint8_t>&& vk_bytes)
64{
65 using Proof = typename Flavor::Transcript::Proof;
67
68 auto prover_instance = _compute_prover_instance<Flavor, IO>(std::move(bytecode), std::move(witness));
69
70 std::shared_ptr<VerificationKey> vk;
71 if (vk_bytes.empty()) {
72 info("WARNING: computing verification key while proving. Pass in a precomputed vk for better performance.");
73 vk = std::make_shared<VerificationKey>(prover_instance->get_precomputed());
74 } else {
75 validate_vk_size<VerificationKey>(vk_bytes);
76 vk = std::make_shared<VerificationKey>(from_buffer<VerificationKey>(vk_bytes));
77 }
78
79 UltraProver_<Flavor> prover{ prover_instance, vk };
80 Proof full_proof = prover.construct_proof();
81
82 size_t num_public_inputs = prover.num_public_inputs();
83 BB_ASSERT_GTE(num_public_inputs, IO::PUBLIC_INPUTS_SIZE, "Public inputs should contain the expected IO structure.");
84 size_t num_inner_public_inputs = num_public_inputs - IO::PUBLIC_INPUTS_SIZE;
85
86 wire::CircuitComputeVkResponse vk_response;
87 if (vk_bytes.empty()) {
88 vk_response = { .bytes = to_buffer(*vk),
90 .hash = to_buffer(vk->hash()) };
91 }
92
93 std::vector<uint256_t> public_inputs{ full_proof.begin(),
94 full_proof.begin() + static_cast<std::ptrdiff_t>(num_inner_public_inputs) };
95 std::vector<uint256_t> proof{ full_proof.begin() + static_cast<std::ptrdiff_t>(num_inner_public_inputs),
96 full_proof.end() };
97 return { .public_inputs = uint256_vec_to_wire(public_inputs),
98 .proof = uint256_vec_to_wire(proof),
99 .vk = std::move(vk_response) };
100}
101
102template <typename Flavor, typename IO>
103bool _verify(const std::vector<uint8_t>& vk_bytes,
104 const std::vector<uint256_t>& public_inputs,
105 const std::vector<uint256_t>& proof)
106{
108 using VKAndHash = typename Flavor::VKAndHash;
109 using Verifier = UltraVerifier_<Flavor, IO>;
110
111 const size_t expected_vk_size = VerificationKey::calc_num_data_types() * sizeof(bb::fr);
112 if (vk_bytes.size() != expected_vk_size) {
113 info(
114 "Proof verification failed: invalid VK size. Expected ", expected_vk_size, " bytes, got ", vk_bytes.size());
115 return false;
116 }
117
118 std::shared_ptr<VerificationKey> vk = std::make_shared<VerificationKey>(from_buffer<VerificationKey>(vk_bytes));
119 auto vk_and_hash = std::make_shared<VKAndHash>(vk);
120 Verifier verifier{ vk_and_hash };
121
122 const size_t log_n = verifier.compute_log_n();
123 const size_t expected_size = ProofLength::Honk<Flavor>::template expected_proof_size<IO>(log_n);
124 if (proof.size() != expected_size) {
125 info("Proof verification failed: invalid proof size. Expected ", expected_size, ", got ", proof.size());
126 return false;
127 }
128
129 auto complete_proof = concatenate_proof<Flavor>(public_inputs, proof);
130 bool verified = verifier.verify_proof(complete_proof).result;
131 if (verified) {
132 info("Proof verified successfully");
133 } else {
134 info("Proof verification failed");
135 }
136 return verified;
137}
138
139template <typename Flavor, typename IO>
140wire::CircuitInfoResponse _stats(std::vector<uint8_t>&& bytecode, bool include_gates_per_opcode)
141{
142 using Circuit = typename Flavor::CircuitBuilder;
144
145 acir_format::ProgramMetadata metadata = _create_program_metadata<IO>();
146 metadata.collect_gates_per_opcode = include_gates_per_opcode;
147
148 wire::CircuitInfoResponse response;
149 response.num_acir_opcodes = static_cast<uint32_t>(constraint_system.num_acir_opcodes);
150
151 acir_format::AcirProgram program{ std::move(constraint_system), {} };
152 auto builder = acir_format::create_circuit<Circuit>(program, metadata);
153 builder.finalize_circuit();
154
155 response.num_gates = static_cast<uint32_t>(builder.get_finalized_total_circuit_size());
156 response.num_gates_dyadic = static_cast<uint32_t>(builder.get_circuit_subgroup_size(response.num_gates));
157 response.gates_per_opcode =
158 std::vector<uint32_t>(program.constraints.gates_per_opcode.begin(), program.constraints.gates_per_opcode.end());
159 return response;
160}
161
162} // namespace
163
164wire::CircuitProveResponse handle_circuit_prove(BBApiRequest& /*ctx*/, wire::CircuitProve&& cmd)
165{
166 BB_BENCH_NAME("CircuitProve");
167 return dispatch_by_settings(cmd.settings, [&]<typename Flavor, typename IO>() {
168 return _prove<Flavor, IO>(
169 std::move(cmd.circuit.bytecode), std::move(cmd.witness), std::move(cmd.circuit.verification_key));
170 });
171}
172
173wire::CircuitComputeVkResponse handle_circuit_compute_vk(BBApiRequest& /*ctx*/, wire::CircuitComputeVk&& cmd)
174{
175 BB_BENCH_NAME("CircuitComputeVk");
176 return dispatch_by_settings(cmd.settings, [&]<typename Flavor, typename IO>() {
177 auto prover_instance = _compute_prover_instance<Flavor, IO>(std::move(cmd.circuit.bytecode), {});
178 auto vk = std::make_shared<typename Flavor::VerificationKey>(prover_instance->get_precomputed());
179 return wire::CircuitComputeVkResponse{ .bytes = to_buffer(*vk),
181 .hash = to_buffer(vk->hash()) };
182 });
183}
184
185wire::CircuitInfoResponse handle_circuit_stats(BBApiRequest& /*ctx*/, wire::CircuitStats&& cmd)
186{
187 BB_BENCH_NAME("CircuitStats");
188 return dispatch_by_settings(cmd.settings, [&]<typename Flavor, typename IO>() {
189 return _stats<Flavor, IO>(std::move(cmd.circuit.bytecode), cmd.include_gates_per_opcode);
190 });
191}
192
193wire::CircuitVerifyResponse handle_circuit_verify(BBApiRequest& /*ctx*/, wire::CircuitVerify&& cmd)
194{
195 BB_BENCH_NAME("CircuitVerify");
196 auto pi_domain = uint256_vec_from_wire(cmd.public_inputs);
197 auto proof_domain = uint256_vec_from_wire(cmd.proof);
198 bool verified = dispatch_by_settings(cmd.settings, [&]<typename Flavor, typename IO>() {
199 return _verify<Flavor, IO>(cmd.verification_key, pi_domain, proof_domain);
200 });
201 return { .verified = verified };
202}
203
204wire::VkAsFieldsResponse handle_vk_as_fields(BBApiRequest& /*ctx*/, wire::VkAsFields&& cmd)
205{
206 BB_BENCH_NAME("VkAsFields");
208 validate_vk_size<VK>(cmd.verification_key);
209 auto vk = from_buffer<VK>(cmd.verification_key);
210 return { .fields = fr_vec_to_wire(vk.to_field_elements()) };
211}
212
213wire::MegaVkAsFieldsResponse handle_mega_vk_as_fields(BBApiRequest& /*ctx*/, wire::MegaVkAsFields&& cmd)
214{
215 BB_BENCH_NAME("MegaVkAsFields");
217 validate_vk_size<VK>(cmd.verification_key);
218 auto vk = from_buffer<VK>(cmd.verification_key);
219 return { .fields = fr_vec_to_wire(vk.to_field_elements()) };
220}
221
222wire::CircuitWriteSolidityVerifierResponse handle_circuit_write_solidity_verifier(
223 BBApiRequest& /*ctx*/, wire::CircuitWriteSolidityVerifier&& cmd)
224{
225 BB_BENCH_NAME("CircuitWriteSolidityVerifier");
227 validate_vk_size<VK>(cmd.verification_key);
228 auto vk = std::make_shared<VK>(from_buffer<VK>(cmd.verification_key));
229
230 std::string contract = cmd.settings.disable_zk ? get_honk_solidity_verifier(vk) : get_honk_zk_solidity_verifier(vk);
231#ifndef __wasm__
232 if (cmd.settings.optimized_solidity_verifier) {
233 contract = cmd.settings.disable_zk ? get_optimized_honk_solidity_verifier(vk)
235 }
236#endif
237 return { .solidity_code = std::move(contract) };
238}
239
240} // namespace bb::bbapi
#define BB_ASSERT(expression,...)
Definition assert.hpp:70
#define BB_ASSERT_GTE(left, right,...)
Definition assert.hpp:128
std::shared_ptr< Napi::ThreadSafeFunction > bytecode
#define BB_BENCH_NAME(name)
Definition bb_bench.hpp:264
Non-template handler declarations for the bb service.
Shared type definitions for the Barretenberg RPC API.
Wire <-> domain conversion helpers for the bbapi handlers.
ECCVMCircuitBuilder CircuitBuilder
FixedVKAndHash_< PrecomputedEntities< Commitment >, BF, ECCVMHardcodedVKAndHash > VerificationKey
The verification key stores commitments to the precomputed polynomials used by the verifier.
Base Native verification key class.
Definition flavor.hpp:137
static constexpr size_t calc_num_data_types()
Calculate the number of field elements needed for serialization.
Definition flavor.hpp:202
#define info(...)
Definition log.hpp:93
AluTraceBuilder builder
Definition alu.test.cpp:124
std::string get_honk_solidity_verifier(auto const &verification_key)
std::string get_optimized_honk_solidity_verifier(auto const &verification_key)
std::string get_honk_zk_solidity_verifier(auto const &verification_key)
std::string get_optimized_honk_zk_solidity_verifier(auto const &verification_key)
WitnessVector witness_buf_to_witness_vector(std::vector< uint8_t > &&buf)
Convert a buffer representing a witness vector into Barretenberg's internal WitnessVector format.
AcirFormat circuit_buf_to_acir_format(std::vector< uint8_t > &&buf)
Convert a buffer representing a circuit into Barretenberg's internal AcirFormat representation.
wire::CircuitProveResponse handle_circuit_prove(BBApiRequest &ctx, wire::CircuitProve &&cmd)
std::vector< Uint256 > uint256_vec_to_wire(const std::vector< bb::numeric::uint256_t > &d)
wire::MegaVkAsFieldsResponse handle_mega_vk_as_fields(BBApiRequest &ctx, wire::MegaVkAsFields &&cmd)
auto dispatch_by_settings(const Settings &settings, Operation &&operation)
Dispatch to the correct Flavor and IO type based on proof system settings.
std::vector< uint256_t > vk_to_uint256_fields(const VK &vk)
Convert VK to uint256 field elements, handling flavor-specific return types.
std::vector< Fr > fr_vec_to_wire(const std::vector< bb::fr > &d)
wire::VkAsFieldsResponse handle_vk_as_fields(BBApiRequest &ctx, wire::VkAsFields &&cmd)
std::vector< bb::numeric::uint256_t > uint256_vec_from_wire(const std::vector< Uint256 > &w)
wire::CircuitInfoResponse handle_circuit_stats(BBApiRequest &ctx, wire::CircuitStats &&cmd)
wire::CircuitVerifyResponse handle_circuit_verify(BBApiRequest &ctx, wire::CircuitVerify &&cmd)
wire::CircuitComputeVkResponse handle_circuit_compute_vk(BBApiRequest &ctx, wire::CircuitComputeVk &&cmd)
wire::CircuitWriteSolidityVerifierResponse handle_circuit_write_solidity_verifier(BBApiRequest &ctx, wire::CircuitWriteSolidityVerifier &&cmd)
field< Bn254FrParams > fr
Definition fr.hpp:155
VerifierCommitmentKey< Curve > vk
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
std::vector< uint8_t > to_buffer(T const &value)
Struct containing both the constraints to be added to the circuit and the witness vector.
Metadata required to create a circuit.