Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
bbapi_chonk.cpp
Go to the documentation of this file.
15
16namespace bb::bbapi {
17
19{
20 BB_BENCH_NAME(MSGPACK_SCHEMA_NAME);
21
22 request.ivc_in_progress = std::make_shared<Chonk>(num_circuits);
23
24 request.ivc_stack_depth = 0;
25 return Response{};
26}
27
29{
30 BB_BENCH_NAME(MSGPACK_SCHEMA_NAME);
31 if (!request.ivc_in_progress) {
32 throw_or_abort("Chonk not started. Call ChonkStart first.");
33 }
34
35 request.loaded_circuit_name = circuit.name;
36 request.loaded_circuit_constraints = acir_format::circuit_buf_to_acir_format(std::move(circuit.bytecode));
37 request.loaded_circuit_vk = circuit.verification_key;
38
39 info("ChonkLoad - loaded circuit '", request.loaded_circuit_name, "'");
40
41 return Response{};
42}
43
45{
46 BB_BENCH_NAME(MSGPACK_SCHEMA_NAME);
47 if (!request.ivc_in_progress) {
48 throw_or_abort("Chonk not started. Call ChonkStart first.");
49 }
50
51 if (!request.loaded_circuit_constraints.has_value()) {
52 throw_or_abort("No circuit loaded. Call ChonkLoad first.");
53 }
54
56 acir_format::AcirProgram program{ std::move(request.loaded_circuit_constraints.value()), std::move(witness_data) };
57
58 const acir_format::ProgramMetadata metadata{ .ivc = request.ivc_in_progress };
59 auto circuit = acir_format::create_circuit<IVCBase::ClientCircuit>(program, metadata);
60
62
63 if (request.vk_policy == VkPolicy::RECOMPUTE) {
64 precomputed_vk = nullptr;
65 } else if (request.vk_policy == VkPolicy::DEFAULT || request.vk_policy == VkPolicy::CHECK) {
66 if (!request.loaded_circuit_vk.empty()) {
67 validate_vk_size<Chonk::MegaVerificationKey>(request.loaded_circuit_vk);
68 precomputed_vk = from_buffer<std::shared_ptr<Chonk::MegaVerificationKey>>(request.loaded_circuit_vk);
69
70 if (request.vk_policy == VkPolicy::CHECK) {
71 auto prover_instance = std::make_shared<Chonk::ProverInstance>(circuit);
72 auto computed_vk = std::make_shared<Chonk::MegaVerificationKey>(prover_instance->get_precomputed());
73
74 // Dereference to compare VK contents
75 if (*precomputed_vk != *computed_vk) {
76 throw_or_abort("VK check failed for circuit '" + request.loaded_circuit_name +
77 "': provided VK does not match computed VK");
78 }
79 }
80 }
81 } else {
82 throw_or_abort("Invalid VK policy. Valid options: default, check, recompute");
83 }
84
85 info("ChonkAccumulate - accumulating circuit '", request.loaded_circuit_name, "'");
86 request.ivc_in_progress->accumulate(circuit, precomputed_vk);
87 request.ivc_stack_depth++;
88
89 request.loaded_circuit_constraints.reset();
90 request.loaded_circuit_vk.clear();
91
92 return Response{};
93}
94
96{
97 BB_BENCH_NAME(MSGPACK_SCHEMA_NAME);
98 if (!request.ivc_in_progress) {
99 throw_or_abort("Chonk not started. Call ChonkStart first.");
100 }
101
102 if (request.ivc_stack_depth == 0) {
103 throw_or_abort("No circuits accumulated. Call ChonkAccumulate first.");
104 }
105
106 info("ChonkProve - generating proof for ", request.ivc_stack_depth, " accumulated circuits");
107
108 // Call prove and verify using the appropriate IVC type
109 Response response;
110 bool verification_passed = false;
111
112 info("ChonkProve - using Chonk");
113 auto chonk = std::dynamic_pointer_cast<Chonk>(request.ivc_in_progress);
114 auto proof = chonk->prove();
115 auto vk_and_hash = chonk->get_hiding_kernel_vk_and_hash();
116
117 // We verify this proof. Another bb call to verify has some overhead of loading VK/proof/SRS,
118 // and it is mysterious if this transaction fails later in the lifecycle.
119 info("ChonkProve - verifying the generated proof as a sanity check");
120 ChonkNativeVerifier verifier(vk_and_hash);
121 verification_passed = verifier.verify(proof);
122
123 if (!verification_passed) {
124 throw_or_abort("Failed to verify the generated proof!");
125 }
126
127 response.proof = ChonkProof{ std::move(proof.mega_proof), std::move(proof.goblin_proof) };
128
129 request.ivc_in_progress.reset();
130 request.ivc_stack_depth = 0;
131
132 return response;
133}
134
136{
137 BB_BENCH_NAME(MSGPACK_SCHEMA_NAME);
138
140 validate_vk_size<VerificationKey>(vk);
141
142 // Deserialize the hiding kernel verification key directly from buffer
143 auto hiding_kernel_vk = std::make_shared<VerificationKey>(from_buffer<VerificationKey>(vk));
144
145 // Validate proof size using VK's num_public_inputs before expensive verification
146 const size_t expected_proof_size =
147 static_cast<size_t>(hiding_kernel_vk->num_public_inputs) + ChonkProof::PROOF_LENGTH_WITHOUT_PUB_INPUTS;
148 if (proof.size() != expected_proof_size) {
149 throw_or_abort("proof has wrong size: expected " + std::to_string(expected_proof_size) + ", got " +
150 std::to_string(proof.size()));
151 }
152
153 // Verify the proof using ChonkNativeVerifier
154 auto vk_and_hash = std::make_shared<ChonkNativeVerifier::VKAndHash>(hiding_kernel_vk);
155 ChonkNativeVerifier verifier(vk_and_hash);
156 const bool verified = verifier.verify(proof);
157
158 return { .valid = verified };
159}
160
162{
163 BB_BENCH_NAME(MSGPACK_SCHEMA_NAME);
164
165 if (proofs.size() != vks.size()) {
166 throw_or_abort("ChonkBatchVerify: proofs.size() (" + std::to_string(proofs.size()) + ") != vks.size() (" +
167 std::to_string(vks.size()) + ")");
168 }
169 if (proofs.empty()) {
170 throw_or_abort("ChonkBatchVerify: no proofs provided");
171 }
172
174
176 inputs.reserve(proofs.size());
177
178 for (size_t i = 0; i < proofs.size(); ++i) {
179 validate_vk_size<VerificationKey>(vks[i]);
180 auto hiding_kernel_vk = std::make_shared<VerificationKey>(from_buffer<VerificationKey>(vks[i]));
181
182 const size_t expected_proof_size =
183 static_cast<size_t>(hiding_kernel_vk->num_public_inputs) + ChonkProof::PROOF_LENGTH_WITHOUT_PUB_INPUTS;
184 if (proofs[i].size() != expected_proof_size) {
185 throw_or_abort("ChonkBatchVerify: proof[" + std::to_string(i) + "] has wrong size: expected " +
186 std::to_string(expected_proof_size) + ", got " + std::to_string(proofs[i].size()));
187 }
188
189 auto vk_and_hash = std::make_shared<ChonkNativeVerifier::VKAndHash>(hiding_kernel_vk);
190 inputs.push_back({ .proof = std::move(proofs[i]), .vk_and_hash = std::move(vk_and_hash) });
191 }
192
193 const bool verified = ChonkBatchVerifier::verify(inputs);
194
195 return { .valid = verified };
196}
197
198static std::shared_ptr<Chonk::ProverInstance> get_acir_program_prover_instance(acir_format::AcirProgram& program)
199{
200 Chonk::ClientCircuit builder = acir_format::create_circuit<Chonk::ClientCircuit>(program);
201
202 // Construct the verification key via the prover-constructed proving key with the proper trace settings
204}
205
207{
208 BB_BENCH_NAME(MSGPACK_SCHEMA_NAME);
209 info("ChonkComputeVk - deriving MegaVerificationKey for circuit '", circuit.name, "'");
210
211 auto constraint_system = acir_format::circuit_buf_to_acir_format(std::move(circuit.bytecode));
212
213 acir_format::AcirProgram program{ constraint_system, /*witness=*/{} };
214 std::shared_ptr<Chonk::ProverInstance> prover_instance = get_acir_program_prover_instance(program);
215 auto verification_key = std::make_shared<Chonk::MegaVerificationKey>(prover_instance->get_precomputed());
216
217 info("ChonkComputeVk - VK derived, size: ", to_buffer(*verification_key).size(), " bytes");
218
219 return { .bytes = to_buffer(*verification_key), .fields = verification_key->to_field_elements() };
220}
221
223{
224 BB_BENCH_NAME(MSGPACK_SCHEMA_NAME);
226 /*witness=*/{} };
227
228 std::shared_ptr<Chonk::ProverInstance> prover_instance = get_acir_program_prover_instance(program);
229 auto computed_vk = std::make_shared<Chonk::MegaVerificationKey>(prover_instance->get_precomputed());
230
231 if (circuit.verification_key.empty()) {
232 info("FAIL: Expected precomputed vk for function ", circuit.name);
233 throw_or_abort("Missing precomputed VK");
234 }
235
236 validate_vk_size<Chonk::MegaVerificationKey>(circuit.verification_key);
237
238 // Deserialize directly from buffer
239 auto precomputed_vk = from_buffer<std::shared_ptr<Chonk::MegaVerificationKey>>(circuit.verification_key);
240
241 Response response;
242 response.valid = true;
243 if (*computed_vk != *precomputed_vk) {
244 response.valid = false;
245 response.actual_vk = to_buffer(computed_vk);
246 }
247 return response;
248}
249
251{
252 BB_BENCH_NAME(MSGPACK_SCHEMA_NAME);
253 Response response;
254
255 const auto constraint_system = acir_format::circuit_buf_to_acir_format(std::move(circuit.bytecode));
256 acir_format::AcirProgram program{ constraint_system, {} };
257
258 // Get IVC constraints if any
259 const auto& ivc_constraints = constraint_system.hn_recursion_constraints;
260
261 // Create metadata with appropriate IVC context
263 .ivc = ivc_constraints.empty() ? nullptr : acir_format::create_mock_chonk_from_constraints(ivc_constraints),
264 .collect_gates_per_opcode = include_gates_per_opcode
265 };
266
267 // Create and finalize circuit
268 auto builder = acir_format::create_circuit<MegaCircuitBuilder>(program, metadata);
269 builder.finalize_circuit(/*ensure_nonzero=*/true);
270
271 // Set response values
272 response.acir_opcodes = program.constraints.num_acir_opcodes;
273 response.circuit_size = static_cast<uint32_t>(builder.num_gates());
274
275 // Optionally include gates per opcode
276 if (include_gates_per_opcode) {
277 response.gates_per_opcode = std::vector<uint32_t>(program.constraints.gates_per_opcode.begin(),
278 program.constraints.gates_per_opcode.end());
279 }
280
281 // Log circuit details
282 info("ChonkStats - circuit: ",
283 circuit.name,
284 ", acir_opcodes: ",
285 response.acir_opcodes,
286 ", circuit_size: ",
287 response.circuit_size);
288
289 // Print execution trace details
290 builder.blocks.summarize();
291
292 return response;
293}
294
296{
297 BB_BENCH_NAME(MSGPACK_SCHEMA_NAME);
298 return { .compressed_proof = ProofCompressor::compress_chonk_proof(proof) };
299}
300
302{
303 BB_BENCH_NAME(MSGPACK_SCHEMA_NAME);
304 size_t mega_num_pub = ProofCompressor::compressed_mega_num_public_inputs(compressed_proof.size());
305 return { .proof = ProofCompressor::decompress_chonk_proof(compressed_proof, mega_num_pub) };
306}
307
308} // namespace bb::bbapi
#define BB_BENCH_NAME(name)
Definition bb_bench.hpp:225
Chonk-specific command definitions for the Barretenberg RPC API.
static bool verify(std::span< const Input > inputs)
Verify multiple Chonk proofs with batched IPA verification.
Flavor::VerificationKey MegaVerificationKey
Definition chonk.hpp:43
Verifier for Chonk IVC proofs (both native and recursive).
Output verify(const Proof &proof)
Verify a Chonk proof.
Base Native verification key class.
Definition flavor.hpp:135
static std::vector< uint8_t > compress_chonk_proof(const ChonkProof &proof)
static ChonkProof decompress_chonk_proof(const std::vector< uint8_t > &compressed, size_t mega_num_public_inputs)
static size_t compressed_mega_num_public_inputs(size_t compressed_bytes)
Derive mega_num_public_inputs from compressed proof size.
#define info(...)
Definition log.hpp:93
AluTraceBuilder builder
Definition alu.test.cpp:124
AvmProvingInputs inputs
WitnessVector witness_buf_to_witness_vector(std::vector< uint8_t > &&buf)
Convert a buffer representing a witness vector into Barretenberg's internal WitnessVector format.
std::shared_ptr< Chonk > create_mock_chonk_from_constraints(const std::vector< RecursionConstraint > &constraints)
Create a Chonk instance with mocked state corresponding to a set of IVC recursion constraints.
std::vector< bb::fr > WitnessVector
AcirFormat circuit_buf_to_acir_format(std::vector< uint8_t > &&buf)
Convert a buffer representing a circuit into Barretenberg's internal AcirFormat representation.
VerifierCommitmentKey< Curve > vk
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
std::string to_string(bb::avm2::ValueTag tag)
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.
std::shared_ptr< bb::IVCBase > ivc
static constexpr size_t PROOF_LENGTH_WITHOUT_PUB_INPUTS
The size of a Chonk proof without backend-added public inputs.
Empty response indicating successful circuit accumulation.
Response execute(BBApiRequest &request) &&
Response execute(const BBApiRequest &request={}) &&
Contains the validation result.
bool valid
True if the precomputed VK matches the circuit.
Response execute(const BBApiRequest &request={}) &&
Response execute(const BBApiRequest &request={}) &&
Contains the computed verification key in multiple formats.
Response execute(const BBApiRequest &request={}) &&
Response execute(const BBApiRequest &request={}) &&
Empty response indicating successful circuit loading.
Response execute(BBApiRequest &request) &&
Contains the generated IVC proof.
ChonkProof proof
Complete IVC proof for all accumulated circuits.
Response execute(BBApiRequest &request) &&
Empty response indicating successful initialization.
Response execute(BBApiRequest &request) &&
Contains gate count information.
uint32_t circuit_size
Circuit size (total number of gates)
uint32_t acir_opcodes
Number of ACIR opcodes.
std::vector< uint32_t > gates_per_opcode
Optional: gate counts per opcode.
Response execute(BBApiRequest &request) &&
Contains the verification result.
Response execute(const BBApiRequest &request={}) &&
void throw_or_abort(std::string const &err)