1#![feature(array_try_map, array_try_from_fn)]
10#![allow(clippy::module_inception)]
11
12pub mod arithmetic;
13pub mod bitwise;
14pub mod blake3;
15pub mod builder;
16pub mod collatz;
17pub mod keccakf;
18pub mod lasso;
19mod pack;
20pub mod plain_lookup;
21pub mod sha256;
22pub mod transparent;
23pub mod u32fib;
24pub mod unconstrained;
25pub mod vision;
26
27#[cfg(test)]
28mod tests {
29 use binius_core::{
30 constraint_system::{
31 self,
32 channel::{validate_witness, Boundary, FlushDirection},
33 },
34 fiat_shamir::HasherChallenger,
35 oracle::ShiftVariant,
36 polynomial::ArithCircuitPoly,
37 tower::CanonicalTowerFamily,
38 };
39 use binius_field::{
40 arch::OptimalUnderlier, as_packed_field::PackedType, underlier::WithUnderlier,
41 BinaryField128b, BinaryField64b, BinaryField8b, Field,
42 };
43 use binius_hal::make_portable_backend;
44 use binius_hash::compress::Groestl256ByteCompression;
45 use binius_macros::arith_expr;
46 use binius_math::{
47 CompositionPoly, DefaultEvaluationDomainFactory, IsomorphicEvaluationDomainFactory,
48 };
49 use groestl_crypto::Groestl256;
50
51 type B128 = BinaryField128b;
52 type B64 = BinaryField64b;
53
54 use crate::builder::{
55 types::{F, U},
56 ConstraintSystemBuilder,
57 };
58
59 #[test]
60 fn test_boundaries() {
61 let allocator = bumpalo::Bump::new();
63 let mut builder = ConstraintSystemBuilder::new_with_witness(&allocator);
64
65 let log_size = PackedType::<U, BinaryField8b>::LOG_WIDTH + 2;
66
67 let channel_id = builder.add_channel();
68
69 let push_boundaries = Boundary {
70 values: vec![F::from_underlier(6)],
71 channel_id,
72 direction: FlushDirection::Push,
73 multiplicity: 1,
74 };
75
76 let pull_boundaries = Boundary {
77 values: vec![F::ONE],
78 channel_id,
79 direction: FlushDirection::Pull,
80 multiplicity: 1,
81 };
82
83 let boundaries = vec![pull_boundaries, push_boundaries];
84
85 let even = builder.add_committed("even", log_size, 3);
86
87 let half = builder.add_committed("half", log_size, 3);
88
89 let odd = builder.add_committed("odd", log_size, 3);
90
91 let output = builder.add_committed("output", log_size, 3);
92
93 let mut even_counter = 0;
94
95 let mut odd_counter = 0;
96
97 if let Some(witness) = builder.witness() {
98 let mut current = 6;
99
100 let mut even = witness.new_column::<BinaryField8b>(even);
101
102 let even_u8 = even.as_mut_slice::<u8>();
103
104 let mut half = witness.new_column::<BinaryField8b>(half);
105
106 let half_u8 = half.as_mut_slice::<u8>();
107
108 let mut odd = witness.new_column::<BinaryField8b>(odd);
109
110 let odd_u8 = odd.as_mut_slice::<u8>();
111
112 let mut output = witness.new_column::<BinaryField8b>(output);
113
114 let output_u8 = output.as_mut_slice::<u8>();
115
116 while current != 1 {
117 if current & 1 == 0 {
118 even_u8[even_counter] = current;
119 half_u8[even_counter] = current / 2;
120 current = half_u8[even_counter];
121 even_counter += 1;
122 } else {
123 odd_u8[odd_counter] = current;
124 output_u8[odd_counter] = 3 * current + 1;
125 current = output_u8[odd_counter];
126 odd_counter += 1;
127 }
128 }
129 }
130
131 builder
132 .flush(FlushDirection::Pull, channel_id, even_counter, [even])
133 .unwrap();
134 builder
135 .flush(FlushDirection::Push, channel_id, even_counter, [half])
136 .unwrap();
137 builder
138 .flush(FlushDirection::Pull, channel_id, odd_counter, [odd])
139 .unwrap();
140 builder
141 .flush(FlushDirection::Push, channel_id, odd_counter, [output])
142 .unwrap();
143
144 let witness = builder
145 .take_witness()
146 .expect("builder created with witness");
147
148 let constraint_system = builder.build().unwrap();
149
150 let domain_factory = DefaultEvaluationDomainFactory::default();
151 let backend = make_portable_backend();
152
153 let proof = constraint_system::prove::<
154 U,
155 CanonicalTowerFamily,
156 _,
157 Groestl256,
158 Groestl256ByteCompression,
159 HasherChallenger<Groestl256>,
160 _,
161 >(&constraint_system, 1, 10, &boundaries, witness, &domain_factory, &backend)
162 .unwrap();
163
164 constraint_system::verify::<
165 U,
166 CanonicalTowerFamily,
167 Groestl256,
168 Groestl256ByteCompression,
169 HasherChallenger<Groestl256>,
170 >(&constraint_system, 1, 10, &boundaries, proof)
171 .unwrap();
172 }
173
174 #[test]
175 #[ignore]
176 fn test_composite_circuit() {
177 let backend = make_portable_backend();
178 let allocator = bumpalo::Bump::new();
179 let mut builder = ConstraintSystemBuilder::new_with_witness(&allocator);
180 let n_vars = 8;
181 let log_inv_rate = 1;
182 let security_bits = 30;
183 let comp_1 = arith_expr!(B128[x, y] = x*y*y*0x85 +x*x*y*0x9 + y + 0x123);
184 let comp_2 =
185 arith_expr!(B128[x, y, z] = x*z*y*0x81115 +x*y*0x98888 + y*z + z*z*z*z*z*z + 0x155523);
186 let comp_3 = arith_expr!(B128[a, b, c, d, e, f] = e*f*f + a*b*c*2 + d*0x999 + 0x123);
187 let comp_4 = arith_expr!(B128[a, b] = a*(b+a));
188
189 let column_x = builder.add_committed("x", n_vars, 7);
190 let column_y = builder.add_committed("y", n_vars, 7);
191 let column_comp_1 = builder
192 .add_composite_mle("comp1", n_vars, [column_x, column_y], comp_1.clone())
193 .unwrap();
194
195 let column_shift = builder
196 .add_shifted(
197 "shift",
198 column_comp_1,
199 (1 << n_vars) - 1,
200 n_vars,
201 ShiftVariant::CircularLeft,
202 )
203 .unwrap();
204
205 let column_comp_2 = builder
206 .add_composite_mle(
207 "comp2",
208 n_vars,
209 [column_y, column_comp_1, column_shift],
210 comp_2.clone(),
211 )
212 .unwrap();
213
214 let column_z = builder.add_committed("z", n_vars + 1, 6);
215 let column_packed = builder.add_packed("packed", column_z, 1).unwrap();
216
217 let column_comp_3 = builder
218 .add_composite_mle(
219 "comp3",
220 n_vars,
221 [
222 column_x,
223 column_x,
224 column_comp_1,
225 column_shift,
226 column_comp_2,
227 column_packed,
228 ],
229 comp_3.clone(),
230 )
231 .unwrap();
232
233 let column_comp_4 = builder
234 .add_composite_mle(
235 "comp4",
236 n_vars,
237 [
238 column_comp_2,
239 column_comp_3,
240 column_x,
241 column_shift,
242 column_y,
243 ],
244 comp_4.clone(),
245 )
246 .unwrap();
247
248 let channel = builder.add_channel();
250 builder
251 .send(
252 channel,
253 1 << n_vars,
254 vec![
255 column_x,
256 column_y,
257 column_comp_1,
258 column_shift,
259 column_comp_2,
260 column_packed,
261 column_comp_3,
262 ],
263 )
264 .unwrap();
265 builder
266 .receive(
267 channel,
268 1 << n_vars,
269 vec![
270 column_x,
271 column_y,
272 column_comp_1,
273 column_shift,
274 column_comp_2,
275 column_packed,
276 column_comp_3,
277 ],
278 )
279 .unwrap();
280
281 let values_x = (0..(1 << n_vars))
282 .map(|i| B128::from(i as u128))
283 .collect::<Vec<_>>();
284 let values_y = (0..(1 << n_vars))
285 .map(|i| B128::from(i * i))
286 .collect::<Vec<_>>();
287
288 let arith_poly_1 = ArithCircuitPoly::new(comp_1);
289 let values_comp_1 = (0..(1 << n_vars))
290 .map(|i| arith_poly_1.evaluate(&[values_x[i], values_y[i]]).unwrap())
291 .collect::<Vec<_>>();
292
293 let mut values_shift = values_comp_1.clone();
294 let first = values_shift.remove(0);
295 values_shift.push(first);
296
297 let arith_poly_2 = ArithCircuitPoly::new(comp_2);
298 let values_comp_2 = (0..(1 << n_vars))
299 .map(|i| {
300 arith_poly_2
301 .evaluate(&[values_y[i], values_comp_1[i], values_shift[i]])
302 .unwrap()
303 })
304 .collect::<Vec<_>>();
305
306 let values_z = (0..(1 << (n_vars + 1)))
307 .map(|i| B64::from(i * i / 8 + i % 10_u64))
308 .collect::<Vec<_>>();
309 let values_packed = (0..(1 << n_vars))
310 .map(|i| {
311 B128::from(
312 ((values_z[2 * i + 1].val() as u128) << 64) + values_z[2 * i].val() as u128,
313 )
314 })
315 .collect::<Vec<_>>();
316
317 let arith_poly_3 = ArithCircuitPoly::new(comp_3);
318 let values_comp_3 = (0..(1 << n_vars))
319 .map(|i| {
320 arith_poly_3
321 .evaluate(&[
322 values_x[i],
323 values_x[i],
324 values_comp_1[i],
325 values_shift[i],
326 values_comp_2[i],
327 values_packed[i],
328 ])
329 .unwrap()
330 })
331 .collect::<Vec<_>>();
332
333 let arith_poly_4 = ArithCircuitPoly::new(comp_4);
334 let values_comp_4 = (0..(1 << n_vars))
335 .map(|i| {
336 arith_poly_4
337 .evaluate(&[values_comp_2[i], values_comp_3[i]])
338 .unwrap()
339 })
340 .collect::<Vec<_>>();
341
342 let mut add_witness_col_b128 = |oracle_id: usize, values: &[B128]| {
343 builder
344 .witness()
345 .unwrap()
346 .new_column::<B128>(oracle_id)
347 .as_mut_slice()
348 .copy_from_slice(values);
349 };
350 add_witness_col_b128(column_x, &values_x);
351 add_witness_col_b128(column_y, &values_y);
352 add_witness_col_b128(column_comp_1, &values_comp_1);
353 add_witness_col_b128(column_shift, &values_shift);
354 add_witness_col_b128(column_comp_2, &values_comp_2);
355 add_witness_col_b128(column_packed, &values_packed);
356 add_witness_col_b128(column_comp_3, &values_comp_3);
357 add_witness_col_b128(column_comp_4, &values_comp_4);
358 builder
359 .witness()
360 .unwrap()
361 .new_column::<B64>(column_z)
362 .as_mut_slice()
363 .copy_from_slice(&values_z);
364
365 let witness = builder.take_witness().unwrap();
366 let constraint_system = builder.build().unwrap();
367
368 validate_witness(&witness, &[], &[], 1).unwrap();
369
370 let domain_factory = IsomorphicEvaluationDomainFactory::<BinaryField8b>::default();
371 let proof = binius_core::constraint_system::prove::<
372 OptimalUnderlier,
373 CanonicalTowerFamily,
374 _,
375 groestl_crypto::Groestl256,
376 Groestl256ByteCompression,
377 HasherChallenger<groestl_crypto::Groestl256>,
378 _,
379 >(
380 &constraint_system,
381 log_inv_rate,
382 security_bits,
383 &[],
384 witness,
385 &domain_factory,
386 &backend,
387 )
388 .unwrap();
389
390 binius_core::constraint_system::verify::<
391 OptimalUnderlier,
392 CanonicalTowerFamily,
393 groestl_crypto::Groestl256,
394 Groestl256ByteCompression,
395 HasherChallenger<groestl_crypto::Groestl256>,
396 >(&constraint_system, log_inv_rate, security_bits, &[], proof)
397 .unwrap();
398 }
399}