Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
bbapi_client_ivc.cpp
Go to the documentation of this file.
13
14namespace bb::bbapi {
15
17{
18 request.ivc_in_progress = std::make_shared<ClientIVC>(num_circuits, request.trace_settings);
19 request.ivc_stack_depth = 0;
20 return Response{};
21}
22
24{
25 if (!request.ivc_in_progress) {
26 throw_or_abort("ClientIVC not started. Call ClientIvcStart first.");
27 }
28
29 request.loaded_circuit_name = circuit.name;
30 request.loaded_circuit_constraints = acir_format::circuit_buf_to_acir_format(std::move(circuit.bytecode));
31 request.loaded_circuit_vk = circuit.verification_key;
32
33 info("ClientIvcLoad - loaded circuit '", request.loaded_circuit_name, "'");
34
35 return Response{};
36}
37
39{
40 if (!request.ivc_in_progress) {
41 throw_or_abort("ClientIVC not started. Call ClientIvcStart first.");
42 }
43
44 if (!request.loaded_circuit_constraints.has_value()) {
45 throw_or_abort("No circuit loaded. Call ClientIvcLoad first.");
46 }
47
49 acir_format::AcirProgram program{ std::move(request.loaded_circuit_constraints.value()), std::move(witness_data) };
50
51 const acir_format::ProgramMetadata metadata{ request.ivc_in_progress };
52 auto circuit = acir_format::create_circuit<ClientIVC::ClientCircuit>(program, metadata);
53
55 if (!request.loaded_circuit_vk.empty()) {
56 precomputed_vk = from_buffer<std::shared_ptr<ClientIVC::MegaVerificationKey>>(request.loaded_circuit_vk);
57 }
58
59 info("ClientIvcAccumulate - accumulating circuit '", request.loaded_circuit_name, "'");
60 request.ivc_in_progress->accumulate(circuit, precomputed_vk);
61 request.ivc_stack_depth++;
62
63 request.loaded_circuit_constraints.reset();
64 request.loaded_circuit_vk.clear();
65
66 return Response{};
67}
68
70{
71 if (!request.ivc_in_progress) {
72 throw_or_abort("ClientIVC not started. Call ClientIvcStart first.");
73 }
74
75 if (request.ivc_stack_depth == 0) {
76 throw_or_abort("No circuits accumulated. Call ClientIvcAccumulate first.");
77 }
78
79 info("ClientIvcProve - generating proof for ", request.ivc_stack_depth, " accumulated circuits");
80 ClientIVC::Proof proof = request.ivc_in_progress->prove();
81 // We verify this proof. Another bb call to verify has some overhead of loading VK/proof/SRS,
82 // and it is mysterious if this transaction fails later in the lifecycle.
83 info("ClientIvcProve - verifying the generated proof as a sanity check");
84 if (!request.ivc_in_progress->verify(proof)) {
85 throw_or_abort("Failed to verify the generated proof!");
86 }
87
88 request.ivc_in_progress.reset();
89 request.ivc_stack_depth = 0;
90
91 Response response;
92 response.proof = std::move(proof);
93 return response;
94}
95
97{
98 // Deserialize the verification key from the byte buffer
99 const auto verification_key = from_buffer<ClientIVC::VerificationKey>(vk);
100
101 // Verify the proof using ClientIVC's static verify method
102 const bool verified = ClientIVC::verify(proof, verification_key);
103
104 return { .valid = verified };
105}
106
107static std::shared_ptr<ClientIVC::DeciderProvingKey> get_acir_program_decider_proving_key(
108 const BBApiRequest& request, acir_format::AcirProgram& program)
109{
110 ClientIVC::ClientCircuit builder = acir_format::create_circuit<ClientIVC::ClientCircuit>(program);
111
112 // Construct the verification key via the prover-constructed proving key with the proper trace settings
114}
115
117{
118 info("ClientIvcComputeStandaloneVk - deriving VK for circuit '", circuit.name, "'");
119
120 auto constraint_system = acir_format::circuit_buf_to_acir_format(std::move(circuit.bytecode));
121
122 acir_format::AcirProgram program{ constraint_system, /*witness=*/{} };
123 std::shared_ptr<ClientIVC::DeciderProvingKey> proving_key = get_acir_program_decider_proving_key(request, program);
124 auto verification_key = std::make_shared<ClientIVC::MegaVerificationKey>(proving_key->get_precomputed());
125
126 return { .bytes = to_buffer(*verification_key), .fields = verification_key->to_field_elements() };
127}
128
130{
131 info("ClientIvcComputeIvcVk - deriving IVC VK for circuit '", circuit.name, "'");
132
133 auto standalone_vk_response = bbapi::ClientIvcComputeStandaloneVk{
134 .circuit{ .name = "standalone_circuit", .bytecode = std::move(circuit.bytecode) }
135 }.execute({ .trace_settings = {} });
136
137 auto mega_vk = from_buffer<ClientIVC::MegaVerificationKey>(standalone_vk_response.bytes);
143 Response response;
144 response.bytes = to_buffer(civc_vk);
145
146 info("ClientIvcComputeIvcVk - IVC VK derived, size: ", response.bytes.size(), " bytes");
147
148 return response;
149}
150
152{
154 /*witness=*/{} };
155
156 std::shared_ptr<ClientIVC::DeciderProvingKey> proving_key = get_acir_program_decider_proving_key(request, program);
157 auto computed_vk = std::make_shared<ClientIVC::MegaVerificationKey>(proving_key->get_precomputed());
158
159 if (circuit.verification_key.empty()) {
160 info("FAIL: Expected precomputed vk for function ", circuit.name);
161 throw_or_abort("Missing precomputed VK");
162 }
163
164 auto precomputed_vk = from_buffer<std::shared_ptr<ClientIVC::MegaVerificationKey>>(circuit.verification_key);
165
166 Response response;
167 response.valid = true;
168 std::string error_message = "Precomputed vk does not match computed vk for function " + circuit.name;
169 if (!msgpack::msgpack_check_eq(*computed_vk, *precomputed_vk, error_message)) {
170 response.valid = false;
171 response.actual_vk = to_buffer(computed_vk);
172 }
173 return response;
174}
175
177{
178 Response response;
179
180 const auto constraint_system = acir_format::circuit_buf_to_acir_format(std::move(circuit.bytecode));
181 acir_format::AcirProgram program{ constraint_system };
182
183 // Get IVC constraints if any
184 const auto& ivc_constraints = constraint_system.pg_recursion_constraints;
185
186 // Create metadata with appropriate IVC context
188 .ivc = ivc_constraints.empty() ? nullptr
189 : create_mock_ivc_from_constraints(ivc_constraints, request.trace_settings),
190 .collect_gates_per_opcode = include_gates_per_opcode
191 };
192
193 // Create and finalize circuit
194 auto builder = acir_format::create_circuit<MegaCircuitBuilder>(program, metadata);
195 builder.finalize_circuit(/*ensure_nonzero=*/true);
196
197 // Set response values
198 response.acir_opcodes = static_cast<uint32_t>(program.constraints.num_acir_opcodes);
199 response.circuit_size = static_cast<uint32_t>(builder.num_gates);
200
201 // Optionally include gates per opcode
202 if (include_gates_per_opcode) {
203 response.gates_per_opcode = std::vector<uint32_t>(program.constraints.gates_per_opcode.begin(),
204 program.constraints.gates_per_opcode.end());
205 }
206
207 // Log circuit details
208 info("ClientIvcStats - circuit: ",
209 circuit.name,
210 ", acir_opcodes: ",
211 response.acir_opcodes,
212 ", circuit_size: ",
213 response.circuit_size);
214
215 // Print structured execution trace details
216 builder.blocks.set_fixed_block_sizes(request.trace_settings);
217 builder.blocks.summarize();
218
219 return response;
220}
221
222} // namespace bb::bbapi
ClientIVC-specific command definitions for the Barretenberg RPC API.
static bool verify(const Proof &proof, const VerificationKey &vk)
void info(Args... args)
Definition log.hpp:70
#define BB_UNUSED
AluTraceBuilder builder
Definition alu.test.cpp:123
WitnessVector witness_buf_to_witness_data(std::vector< uint8_t > &&buf)
Converts from the ACIR-native WitnessStack format to Barretenberg's internal WitnessVector format.
AcirFormat circuit_buf_to_acir_format(std::vector< uint8_t > &&buf)
bb::SlabVector< bb::fr > WitnessVector
VerifierCommitmentKey< Curve > vk
bool msgpack_check_eq(const T &v1, const T &v2, const std::string_view &error_message)
Ensures that two msgpack objects are equal by applying the msgpack method to both and comparing the r...
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
std::vector< uint8_t > to_buffer(T const &value)
std::shared_ptr< ClientIVC > ivc
A full proof for the IVC scheme containing a Mega proof showing correctness of the hiding circuit (wh...
std::shared_ptr< MegaVerificationKey > mega
std::string name
Human-readable name for the circuit.
Empty response indicating successful circuit accumulation.
Response execute(BBApiRequest &request) &&
bool valid
True if the precomputed VK matches the circuit.
Response execute(const BBApiRequest &request={}) &&
Contains the computed IVC verification key.
std::vector< uint8_t > bytes
Serialized IVC verification key in binary format.
Response execute(const BBApiRequest &request={}) &&
Contains the computed verification key in multiple formats.
Compute standalone verification key for a circuit.
Response execute(const BBApiRequest &request={}) &&
Empty response indicating successful circuit loading.
Response execute(BBApiRequest &request) &&
Contains the generated IVC proof.
ClientIVC::Proof 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)
std::vector< uint32_t > gates_per_opcode
Optional: gate counts per opcode.
uint32_t acir_opcodes
Number of ACIR opcodes.
Response execute(BBApiRequest &request) &&
Contains the verification result.
Response execute(const BBApiRequest &request={}) &&
void throw_or_abort(std::string const &err)