barretenberg
Loading...
Searching...
No Matches
acir_to_constraint_buf.hpp
1#pragma once
2#include "acir_format.hpp"
3#include "barretenberg/common/container.hpp"
4#include "barretenberg/common/throw_or_abort.hpp"
5#include "barretenberg/dsl/acir_format/blake2s_constraint.hpp"
6#include "barretenberg/dsl/acir_format/block_constraint.hpp"
7#include "barretenberg/dsl/acir_format/ecdsa_secp256k1.hpp"
8#include "barretenberg/dsl/acir_format/hash_to_field.hpp"
9#include "barretenberg/dsl/acir_format/keccak_constraint.hpp"
10#include "barretenberg/dsl/acir_format/logic_constraint.hpp"
11#include "barretenberg/dsl/acir_format/pedersen.hpp"
12#include "barretenberg/dsl/acir_format/range_constraint.hpp"
13#include "barretenberg/dsl/acir_format/recursion_constraint.hpp"
14#include "barretenberg/dsl/acir_format/schnorr_verify.hpp"
15#include "barretenberg/dsl/acir_format/sha256_constraint.hpp"
16#include "barretenberg/proof_system/arithmetization/gate_data.hpp"
17#include "serde/index.hpp"
18#include <iterator>
19
20namespace acir_format {
21
22poly_triple serialize_arithmetic_gate(Circuit::Expression const& arg)
23{
24 poly_triple pt{
25 .a = 0,
26 .b = 0,
27 .c = 0,
28 .q_m = 0,
29 .q_l = 0,
30 .q_r = 0,
31 .q_o = 0,
32 .q_c = 0,
33 };
34 // Think this never longer than 1?
35 for (const auto& e : arg.mul_terms) {
36 uint256_t qm(std::get<0>(e));
37 uint32_t a = std::get<1>(e).value;
38 uint32_t b = std::get<2>(e).value;
39 pt.q_m = qm;
40 pt.a = a;
41 pt.b = b;
42 }
43 for (const auto& e : arg.linear_combinations) {
44 barretenberg::fr x(uint256_t(std::get<0>(e)));
45 uint32_t witness = std::get<1>(e).value;
46
47 if (pt.a == 0 || pt.a == witness) {
48 pt.a = witness;
49 pt.q_l = x;
50 } else if (pt.b == 0 || pt.b == witness) {
51 pt.b = witness;
52 pt.q_r = x;
53 } else if (pt.c == 0 || pt.c == witness) {
54 pt.c = witness;
55 pt.q_o = x;
56 } else {
57 throw_or_abort("Cannot assign linear term to a constrain of width 3");
58 }
59 }
60 pt.q_c = uint256_t(arg.q_c);
61 return pt;
62}
63
64void handle_arithmetic(Circuit::Opcode::Arithmetic const& arg, acir_format& af)
65{
66 af.constraints.push_back(serialize_arithmetic_gate(arg.value));
67}
68
69void handle_blackbox_func_call(Circuit::Opcode::BlackBoxFuncCall const& arg, acir_format& af)
70{
71 std::visit(
72 [&](auto&& arg) {
73 using T = std::decay_t<decltype(arg)>;
74 if constexpr (std::is_same_v<T, Circuit::BlackBoxFuncCall::AND>) {
75 af.logic_constraints.push_back(LogicConstraint{
76 .a = arg.lhs.witness.value,
77 .b = arg.rhs.witness.value,
78 .result = arg.output.value,
79 .num_bits = arg.lhs.num_bits,
80 .is_xor_gate = false,
81 });
82 } else if constexpr (std::is_same_v<T, Circuit::BlackBoxFuncCall::XOR>) {
83 af.logic_constraints.push_back(LogicConstraint{
84 .a = arg.lhs.witness.value,
85 .b = arg.rhs.witness.value,
86 .result = arg.output.value,
87 .num_bits = arg.lhs.num_bits,
88 .is_xor_gate = true,
89 });
90 } else if constexpr (std::is_same_v<T, Circuit::BlackBoxFuncCall::RANGE>) {
91 af.range_constraints.push_back(RangeConstraint{
92 .witness = arg.input.witness.value,
93 .num_bits = arg.input.num_bits,
94 });
95 } else if constexpr (std::is_same_v<T, Circuit::BlackBoxFuncCall::SHA256>) {
96 af.sha256_constraints.push_back(Sha256Constraint{
97 .inputs = map(arg.inputs,
98 [](auto& e) {
99 return Sha256Input{
100 .witness = e.witness.value,
101 .num_bits = e.num_bits,
102 };
103 }),
104 .result = map(arg.outputs, [](auto& e) { return e.value; }),
105 });
106 } else if constexpr (std::is_same_v<T, Circuit::BlackBoxFuncCall::Blake2s>) {
107 af.blake2s_constraints.push_back(Blake2sConstraint{
108 .inputs = map(arg.inputs,
109 [](auto& e) {
110 return Blake2sInput{
111 .witness = e.witness.value,
112 .num_bits = e.num_bits,
113 };
114 }),
115 .result = map(arg.outputs, [](auto& e) { return e.value; }),
116 });
117 } else if constexpr (std::is_same_v<T, Circuit::BlackBoxFuncCall::SchnorrVerify>) {
118 af.schnorr_constraints.push_back(SchnorrConstraint{
119 .message = map(arg.message, [](auto& e) { return e.witness.value; }),
120 .public_key_x = arg.public_key_x.witness.value,
121 .public_key_y = arg.public_key_y.witness.value,
122 .result = arg.output.value,
123 .signature = map(arg.signature, [](auto& e) { return e.witness.value; }),
124 });
125 } else if constexpr (std::is_same_v<T, Circuit::BlackBoxFuncCall::PedersenCommitment>) {
126 af.pedersen_constraints.push_back(PedersenConstraint{
127 .scalars = map(arg.inputs, [](auto& e) { return e.witness.value; }),
128 .hash_index = arg.domain_separator,
129 .result_x = arg.outputs[0].value,
130 .result_y = arg.outputs[1].value,
131 });
132 } else if constexpr (std::is_same_v<T, Circuit::BlackBoxFuncCall::PedersenHash>) {
133 af.pedersen_hash_constraints.push_back(PedersenHashConstraint{
134 .scalars = map(arg.inputs, [](auto& e) { return e.witness.value; }),
135 .hash_index = arg.domain_separator,
136 .result = arg.output.value,
137 });
138 } else if constexpr (std::is_same_v<T, Circuit::BlackBoxFuncCall::HashToField128Security>) {
139 af.hash_to_field_constraints.push_back(HashToFieldConstraint{
140 .inputs = map(arg.inputs,
141 [](auto& e) {
142 return HashToFieldInput{
143 .witness = e.witness.value,
144 .num_bits = e.num_bits,
145 };
146 }),
147 .result = arg.output.value,
148 });
149 } else if constexpr (std::is_same_v<T, Circuit::BlackBoxFuncCall::EcdsaSecp256k1>) {
150 af.ecdsa_k1_constraints.push_back(EcdsaSecp256k1Constraint{
151 .hashed_message = map(arg.hashed_message, [](auto& e) { return e.witness.value; }),
152 .signature = map(arg.signature, [](auto& e) { return e.witness.value; }),
153 .pub_x_indices = map(arg.public_key_x, [](auto& e) { return e.witness.value; }),
154 .pub_y_indices = map(arg.public_key_y, [](auto& e) { return e.witness.value; }),
155 .result = arg.output.value,
156 });
157 } else if constexpr (std::is_same_v<T, Circuit::BlackBoxFuncCall::EcdsaSecp256r1>) {
158 af.ecdsa_r1_constraints.push_back(EcdsaSecp256r1Constraint{
159 .hashed_message = map(arg.hashed_message, [](auto& e) { return e.witness.value; }),
160 .pub_x_indices = map(arg.public_key_x, [](auto& e) { return e.witness.value; }),
161 .pub_y_indices = map(arg.public_key_y, [](auto& e) { return e.witness.value; }),
162 .result = arg.output.value,
163 .signature = map(arg.signature, [](auto& e) { return e.witness.value; }),
164 });
165 } else if constexpr (std::is_same_v<T, Circuit::BlackBoxFuncCall::FixedBaseScalarMul>) {
166 af.fixed_base_scalar_mul_constraints.push_back(FixedBaseScalarMul{
167 .low = arg.low.witness.value,
168 .high = arg.high.witness.value,
169 .pub_key_x = arg.outputs[0].value,
170 .pub_key_y = arg.outputs[1].value,
171 });
172 } else if constexpr (std::is_same_v<T, Circuit::BlackBoxFuncCall::Keccak256>) {
173 af.keccak_constraints.push_back(KeccakConstraint{
174 .inputs = map(arg.inputs,
175 [](auto& e) {
176 return HashInput{
177 .witness = e.witness.value,
178 .num_bits = e.num_bits,
179 };
180 }),
181 .result = map(arg.outputs, [](auto& e) { return e.value; }),
182 });
183 } else if constexpr (std::is_same_v<T, Circuit::BlackBoxFuncCall::Keccak256VariableLength>) {
184 af.keccak_var_constraints.push_back(KeccakVarConstraint{
185 .inputs = map(arg.inputs,
186 [](auto& e) {
187 return HashInput{
188 .witness = e.witness.value,
189 .num_bits = e.num_bits,
190 };
191 }),
192 .result = map(arg.outputs, [](auto& e) { return e.value; }),
193 .var_message_size = arg.var_message_size.witness.value,
194 });
195 } else if constexpr (std::is_same_v<T, Circuit::BlackBoxFuncCall::RecursiveAggregation>) {
196 auto c = RecursionConstraint{
197 .key = map(arg.verification_key, [](auto& e) { return e.witness.value; }),
198 .proof = map(arg.proof, [](auto& e) { return e.witness.value; }),
199 .public_inputs = map(arg.public_inputs, [](auto& e) { return e.witness.value; }),
200 .key_hash = arg.key_hash.witness.value,
201 .input_aggregation_object = {},
202 .output_aggregation_object = {},
203 .nested_aggregation_object = {},
204 };
205 if (arg.input_aggregation_object.has_value()) {
206 for (size_t i = 0; i < RecursionConstraint::AGGREGATION_OBJECT_SIZE; ++i) {
207 c.input_aggregation_object[i] = (*arg.input_aggregation_object)[i].witness.value;
208 }
209 }
210 for (size_t i = 0; i < RecursionConstraint::AGGREGATION_OBJECT_SIZE; ++i) {
211 c.output_aggregation_object[i] = arg.output_aggregation_object[i].value;
212 }
213 af.recursion_constraints.push_back(c);
214 }
215 },
216 arg.value.value);
217}
218
219BlockConstraint handle_memory_init(Circuit::Opcode::MemoryInit const& mem_init)
220{
221 BlockConstraint block{ .init = {}, .trace = {}, .type = BlockType::ROM };
222 std::vector<poly_triple> init;
223 std::vector<MemOp> trace;
224
225 auto len = mem_init.init.size();
226 for (size_t i = 0; i < len; ++i) {
227 block.init.push_back(poly_triple{
228 .a = mem_init.init[i].value,
229 .b = 0,
230 .c = 0,
231 .q_m = 0,
232 .q_l = 1,
233 .q_r = 0,
234 .q_o = 0,
235 .q_c = 0,
236 });
237 }
238 return block;
239}
240
241bool is_rom(Circuit::MemOp const& mem_op)
242{
243 return mem_op.operation.mul_terms.size() == 0 && mem_op.operation.linear_combinations.size() == 0 &&
244 uint256_t(mem_op.operation.q_c) == 0;
245}
246
247void handle_memory_op(Circuit::Opcode::MemoryOp const& mem_op, BlockConstraint& block)
248{
249 uint8_t access_type = 1;
250 if (is_rom(mem_op.op)) {
251 access_type = 0;
252 }
253 if (block.type == BlockType::ROM && access_type == 1) {
254 block.type = BlockType::RAM;
255 }
256
257 MemOp acir_mem_op = MemOp{ .access_type = access_type,
258 .index = serialize_arithmetic_gate(mem_op.op.index),
259 .value = serialize_arithmetic_gate(mem_op.op.value) };
260 block.trace.push_back(acir_mem_op);
261}
262
263acir_format circuit_buf_to_acir_format(std::vector<uint8_t> const& buf)
264{
265 auto circuit = Circuit::Circuit::bincodeDeserialize(buf);
266
267 acir_format af;
268 // TODO(https://github.com/AztecProtocol/barretenberg/issues/816): this +1 seems to be accounting for the const 0 at
269 // the first index in variables
270 af.varnum = circuit.current_witness_index + 1;
271 af.public_inputs = join({ map(circuit.public_parameters.value, [](auto e) { return e.value; }),
272 map(circuit.return_values.value, [](auto e) { return e.value; }) });
273 std::map<uint32_t, BlockConstraint> block_id_to_block_constraint;
274 for (auto gate : circuit.opcodes) {
275 std::visit(
276 [&](auto&& arg) {
277 using T = std::decay_t<decltype(arg)>;
278 if constexpr (std::is_same_v<T, Circuit::Opcode::Arithmetic>) {
279 handle_arithmetic(arg, af);
280 } else if constexpr (std::is_same_v<T, Circuit::Opcode::BlackBoxFuncCall>) {
281 handle_blackbox_func_call(arg, af);
282 } else if constexpr (std::is_same_v<T, Circuit::Opcode::MemoryInit>) {
283 auto block = handle_memory_init(arg);
284 uint32_t block_id = arg.block_id.value;
285 block_id_to_block_constraint[block_id] = block;
286 } else if constexpr (std::is_same_v<T, Circuit::Opcode::MemoryOp>) {
287 auto block = block_id_to_block_constraint.find(arg.block_id.value);
288 if (block == block_id_to_block_constraint.end()) {
289 throw_or_abort("unitialized MemoryOp");
290 }
291 handle_memory_op(arg, block->second);
292 }
293 },
294 gate.value);
295 }
296 for (const auto& [block_id, block] : block_id_to_block_constraint) {
297 if (!block.trace.empty()) {
298 af.block_constraints.push_back(block);
299 }
300 }
301 return af;
302}
303
304WitnessVector witness_buf_to_witness_data(std::vector<uint8_t> const& buf)
305{
306 auto w = WitnessMap::WitnessMap::bincodeDeserialize(buf);
307 WitnessVector wv;
308 size_t index = 1;
309 for (auto& e : w.value) {
310 while (index < e.first.value) {
311 wv.push_back(barretenberg::fr(0)); // TODO(https://github.com/AztecProtocol/barretenberg/issues/816)?
312 index++;
313 }
314 wv.push_back(barretenberg::fr(uint256_t(e.second)));
315 index++;
316 }
317 return wv;
318}
319
320} // namespace acir_format
Definition: uint256.hpp:25
Definition: acir.hpp:210
Definition: acir.hpp:798
Definition: acir.hpp:810
Definition: acir.hpp:818
Definition: acir.hpp:852
Definition: acir.hpp:842