Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
bbapi_chonk.cpp
Go to the documentation of this file.
14
15namespace bb::bbapi {
16
18{
19 BB_BENCH_NAME(MSGPACK_SCHEMA_NAME);
20
21 request.ivc_in_progress = std::make_shared<Chonk>(num_circuits);
22
23 request.ivc_stack_depth = 0;
24 return Response{};
25}
26
28{
29 BB_BENCH_NAME(MSGPACK_SCHEMA_NAME);
30 if (!request.ivc_in_progress) {
31 throw_or_abort("Chonk not started. Call ChonkStart first.");
32 }
33
34 request.loaded_circuit_name = circuit.name;
35 request.loaded_circuit_constraints = acir_format::circuit_buf_to_acir_format(std::move(circuit.bytecode));
36 request.loaded_circuit_vk = circuit.verification_key;
37
38 info("ChonkLoad - loaded circuit '", request.loaded_circuit_name, "'");
39
40 return Response{};
41}
42
44{
45 BB_BENCH_NAME(MSGPACK_SCHEMA_NAME);
46 if (!request.ivc_in_progress) {
47 throw_or_abort("Chonk not started. Call ChonkStart first.");
48 }
49
50 if (!request.loaded_circuit_constraints.has_value()) {
51 throw_or_abort("No circuit loaded. Call ChonkLoad first.");
52 }
53
55 acir_format::AcirProgram program{ std::move(request.loaded_circuit_constraints.value()), std::move(witness_data) };
56
57 const acir_format::ProgramMetadata metadata{ .ivc = request.ivc_in_progress };
58 auto circuit = acir_format::create_circuit<IVCBase::ClientCircuit>(program, metadata);
59
61
62 if (request.vk_policy == VkPolicy::RECOMPUTE) {
63 precomputed_vk = nullptr;
64 } else if (request.vk_policy == VkPolicy::DEFAULT || request.vk_policy == VkPolicy::CHECK) {
65 if (!request.loaded_circuit_vk.empty()) {
66 validate_vk_size<Chonk::MegaVerificationKey>(request.loaded_circuit_vk);
67 precomputed_vk = from_buffer<std::shared_ptr<Chonk::MegaVerificationKey>>(request.loaded_circuit_vk);
68
69 if (request.vk_policy == VkPolicy::CHECK) {
70 auto prover_instance = std::make_shared<Chonk::ProverInstance>(circuit);
71 auto computed_vk = std::make_shared<Chonk::MegaVerificationKey>(prover_instance->get_precomputed());
72
73 // Dereference to compare VK contents
74 if (*precomputed_vk != *computed_vk) {
75 throw_or_abort("VK check failed for circuit '" + request.loaded_circuit_name +
76 "': provided VK does not match computed VK");
77 }
78 }
79 }
80 } else {
81 throw_or_abort("Invalid VK policy. Valid options: default, check, recompute");
82 }
83
84 info("ChonkAccumulate - accumulating circuit '", request.loaded_circuit_name, "'");
85 request.ivc_in_progress->accumulate(circuit, precomputed_vk);
86 request.ivc_stack_depth++;
87
88 request.loaded_circuit_constraints.reset();
89 request.loaded_circuit_vk.clear();
90
91 return Response{};
92}
93
95{
96 BB_BENCH_NAME(MSGPACK_SCHEMA_NAME);
97 if (!request.ivc_in_progress) {
98 throw_or_abort("Chonk not started. Call ChonkStart first.");
99 }
100
101 if (request.ivc_stack_depth == 0) {
102 throw_or_abort("No circuits accumulated. Call ChonkAccumulate first.");
103 }
104
105 info("ChonkProve - generating proof for ", request.ivc_stack_depth, " accumulated circuits");
106
107 // Call prove and verify using the appropriate IVC type
108 Response response;
109 bool verification_passed = false;
110
111 info("ChonkProve - using Chonk");
112 auto chonk = std::dynamic_pointer_cast<Chonk>(request.ivc_in_progress);
113 auto proof = chonk->prove();
114 auto vk_and_hash = chonk->get_hiding_kernel_vk_and_hash();
115
116 // We verify this proof. Another bb call to verify has some overhead of loading VK/proof/SRS,
117 // and it is mysterious if this transaction fails later in the lifecycle.
118 info("ChonkProve - verifying the generated proof as a sanity check");
119 ChonkNativeVerifier verifier(vk_and_hash);
120 verification_passed = verifier.verify(proof);
121
122 if (!verification_passed) {
123 throw_or_abort("Failed to verify the generated proof!");
124 }
125
126 response.proof = ChonkProof{ std::move(proof.mega_proof), std::move(proof.goblin_proof) };
127
128 request.ivc_in_progress.reset();
129 request.ivc_stack_depth = 0;
130
131 return response;
132}
133
135{
136 BB_BENCH_NAME(MSGPACK_SCHEMA_NAME);
137
139 validate_vk_size<VerificationKey>(vk);
140
141 // Deserialize the hiding kernel verification key directly from buffer
142 auto hiding_kernel_vk = std::make_shared<VerificationKey>(from_buffer<VerificationKey>(vk));
143
144 // Validate proof size using VK's num_public_inputs before expensive verification
145 const size_t expected_proof_size =
146 static_cast<size_t>(hiding_kernel_vk->num_public_inputs) + ChonkProof::PROOF_LENGTH_WITHOUT_PUB_INPUTS;
147 if (proof.size() != expected_proof_size) {
148 throw_or_abort("proof has wrong size: expected " + std::to_string(expected_proof_size) + ", got " +
149 std::to_string(proof.size()));
150 }
151
152 // Verify the proof using ChonkNativeVerifier
153 auto vk_and_hash = std::make_shared<ChonkNativeVerifier::VKAndHash>(hiding_kernel_vk);
154 ChonkNativeVerifier verifier(vk_and_hash);
155 const bool verified = verifier.verify(proof);
156
157 return { .valid = verified };
158}
159
160static std::shared_ptr<Chonk::ProverInstance> get_acir_program_prover_instance(acir_format::AcirProgram& program)
161{
162 Chonk::ClientCircuit builder = acir_format::create_circuit<Chonk::ClientCircuit>(program);
163
164 // Construct the verification key via the prover-constructed proving key with the proper trace settings
166}
167
169{
170 BB_BENCH_NAME(MSGPACK_SCHEMA_NAME);
171 info("ChonkComputeVk - deriving MegaVerificationKey for circuit '", circuit.name, "'");
172
173 auto constraint_system = acir_format::circuit_buf_to_acir_format(std::move(circuit.bytecode));
174
175 acir_format::AcirProgram program{ constraint_system, /*witness=*/{} };
176 std::shared_ptr<Chonk::ProverInstance> prover_instance = get_acir_program_prover_instance(program);
177 auto verification_key = std::make_shared<Chonk::MegaVerificationKey>(prover_instance->get_precomputed());
178
179 info("ChonkComputeVk - VK derived, size: ", to_buffer(*verification_key).size(), " bytes");
180
181 return { .bytes = to_buffer(*verification_key), .fields = verification_key->to_field_elements() };
182}
183
185{
186 BB_BENCH_NAME(MSGPACK_SCHEMA_NAME);
188 /*witness=*/{} };
189
190 std::shared_ptr<Chonk::ProverInstance> prover_instance = get_acir_program_prover_instance(program);
191 auto computed_vk = std::make_shared<Chonk::MegaVerificationKey>(prover_instance->get_precomputed());
192
193 if (circuit.verification_key.empty()) {
194 info("FAIL: Expected precomputed vk for function ", circuit.name);
195 throw_or_abort("Missing precomputed VK");
196 }
197
198 validate_vk_size<Chonk::MegaVerificationKey>(circuit.verification_key);
199
200 // Deserialize directly from buffer
201 auto precomputed_vk = from_buffer<std::shared_ptr<Chonk::MegaVerificationKey>>(circuit.verification_key);
202
203 Response response;
204 response.valid = true;
205 if (*computed_vk != *precomputed_vk) {
206 response.valid = false;
207 response.actual_vk = to_buffer(computed_vk);
208 }
209 return response;
210}
211
213{
214 BB_BENCH_NAME(MSGPACK_SCHEMA_NAME);
215 Response response;
216
217 const auto constraint_system = acir_format::circuit_buf_to_acir_format(std::move(circuit.bytecode));
218 acir_format::AcirProgram program{ constraint_system, {} };
219
220 // Get IVC constraints if any
221 const auto& ivc_constraints = constraint_system.hn_recursion_constraints;
222
223 // Create metadata with appropriate IVC context
225 .ivc = ivc_constraints.empty() ? nullptr : acir_format::create_mock_chonk_from_constraints(ivc_constraints),
226 .collect_gates_per_opcode = include_gates_per_opcode
227 };
228
229 // Create and finalize circuit
230 auto builder = acir_format::create_circuit<MegaCircuitBuilder>(program, metadata);
231 builder.finalize_circuit(/*ensure_nonzero=*/true);
232
233 // Set response values
234 response.acir_opcodes = program.constraints.num_acir_opcodes;
235 response.circuit_size = static_cast<uint32_t>(builder.num_gates());
236
237 // Optionally include gates per opcode
238 if (include_gates_per_opcode) {
239 response.gates_per_opcode = std::vector<uint32_t>(program.constraints.gates_per_opcode.begin(),
240 program.constraints.gates_per_opcode.end());
241 }
242
243 // Log circuit details
244 info("ChonkStats - circuit: ",
245 circuit.name,
246 ", acir_opcodes: ",
247 response.acir_opcodes,
248 ", circuit_size: ",
249 response.circuit_size);
250
251 // Print execution trace details
252 builder.blocks.summarize();
253
254 return response;
255}
256
258{
259 BB_BENCH_NAME(MSGPACK_SCHEMA_NAME);
260 return { .compressed_proof = ProofCompressor::compress_chonk_proof(proof) };
261}
262
264{
265 BB_BENCH_NAME(MSGPACK_SCHEMA_NAME);
266 size_t mega_num_pub = ProofCompressor::compressed_mega_num_public_inputs(compressed_proof.size());
267 return { .proof = ProofCompressor::decompress_chonk_proof(compressed_proof, mega_num_pub) };
268}
269
270} // namespace bb::bbapi
#define BB_BENCH_NAME(name)
Definition bb_bench.hpp:225
Chonk-specific command definitions for the Barretenberg RPC API.
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
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) &&
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)