Skip to main content

fancy_garbling/
circuit.rs

1//! DSL for creating circuits compatible with fancy-garbling in the old-fashioned way,
2//! where you create a circuit for a computation then garble it.
3
4use crate::{
5    dummy::{Dummy, DummyVal},
6    fancy::Fancy,
7    informer::Informer,
8};
9use swanky_channel::Channel;
10use swanky_error::Result;
11
12mod binary;
13pub use binary::{BinaryCircuit, BinaryGate};
14
15/// Trait for executing computations directly over a [`Fancy`] object.
16///
17/// # Example
18/// Below is a simple example of computing an add gate over an arbitrary
19/// modulus. The computation is defined in `execute` by directly calling
20/// operations on the underlying [`Fancy`] backend. We also need to track how
21/// many inputs the computation takes, and the moduli of those inputs; these are
22/// given in the `ninputs` and `modulus` methods, respectively.
23/// ```
24/// # use fancy_garbling::{FancyArithmetic, circuit::CircuitExecutor};
25/// # use swanky_channel::Channel;
26/// # use swanky_error::Result;
27/// struct AddCircuit(u16);
28/// impl<F: FancyArithmetic> CircuitExecutor<F> for AddCircuit {
29///     fn execute(
30///         &self,
31///         backend: &mut F,
32///         inputs: &[F::Item],
33///         channel: &mut Channel,
34///     ) -> Result<Vec<F::Item>> {
35///         let output = backend.add(&inputs[0], &inputs[1]);
36///         Ok(vec![output])
37///     }
38///
39///     fn ninputs(&self) -> usize {
40///         2
41///     }
42///
43///     fn modulus(&self, _: usize) -> u16 {
44///         2
45///     }
46/// }
47/// ```
48pub trait CircuitExecutor<F: Fancy> {
49    /// Execute a circuit on a given [`Fancy`] backend using the provided inputs.
50    fn execute(
51        &self,
52        backend: &mut F,
53        inputs: &[F::Item],
54        channel: &mut Channel,
55    ) -> Result<Vec<F::Item>>;
56    /// The number of inputs to provide to [`CircuitExecutor::execute`].
57    fn ninputs(&self) -> usize;
58    /// The modulus for input `i`.
59    fn modulus(&self, i: usize) -> u16;
60}
61
62/// Trait to display circuit evaluation costs
63///
64/// Blanket implementation available for all circuits
65/// that can be evaluated with an `Informer`
66pub trait CircuitInfo {
67    /// Print circuit info
68    fn print_info(&self) -> swanky_error::Result<()>;
69}
70
71impl<C: CircuitExecutor<Informer<Dummy>>> CircuitInfo for C {
72    fn print_info(&self) -> swanky_error::Result<()> {
73        let mut informer = crate::informer::Informer::new(Dummy::new());
74
75        // encode inputs as InformerVals
76        let inputs = Channel::with(std::io::empty(), |channel| {
77            (0..self.ninputs())
78                .map(|i| informer.encode(0, self.modulus(i), channel))
79                .collect::<swanky_error::Result<Vec<DummyVal>>>()
80        })?;
81
82        Channel::with(std::io::empty(), |c| {
83            self.execute(&mut informer, &inputs, c)
84        })?;
85        println!("{}", informer.stats());
86        Ok(())
87    }
88}
89
90pub mod circuits {
91    //! A collection of test circuits.
92
93    pub mod fancy {
94        //! Circuits that test [`Fancy`].
95
96        use crate::{Fancy, circuit::CircuitExecutor};
97        use swanky_channel::Channel;
98        use swanky_error::Result;
99
100        /// Circuit for testing [`Fancy::outputs`].
101        pub struct TestBinaryOutputs(pub usize);
102        impl<F: Fancy> CircuitExecutor<F> for TestBinaryOutputs {
103            fn execute(
104                &self,
105                backend: &mut F,
106                inputs: &[<F as Fancy>::Item],
107                channel: &mut Channel,
108            ) -> Result<Vec<<F as Fancy>::Item>> {
109                backend.outputs(inputs, channel)?;
110                Ok(inputs.to_vec())
111            }
112
113            fn ninputs(&self) -> usize {
114                self.0
115            }
116
117            fn modulus(&self, _: usize) -> u16 {
118                2
119            }
120        }
121
122        /// Circuit for testing [`Fancy::constant`].
123        pub struct TestBinaryConstant;
124        impl<F: Fancy> CircuitExecutor<F> for TestBinaryConstant {
125            fn execute(
126                &self,
127                backend: &mut F,
128                _inputs: &[F::Item],
129                channel: &mut Channel,
130            ) -> Result<Vec<F::Item>> {
131                let outputs = vec![
132                    backend.constant(0, 2, channel)?,
133                    backend.constant(1, 2, channel)?,
134                ];
135                backend.outputs(&outputs, channel)?;
136                Ok(outputs)
137            }
138
139            fn ninputs(&self) -> usize {
140                0
141            }
142
143            fn modulus(&self, _: usize) -> u16 {
144                2
145            }
146        }
147    }
148
149    pub mod binary {
150        //! Circuits that test [`FancyBinary`].
151
152        use crate::{BinaryBundle, BundleGadgets, FancyBinary, circuit::CircuitExecutor};
153        use swanky_channel::Channel;
154        use swanky_error::Result;
155
156        /// Circuit for testing [`FancyBinary::negate`].
157        pub struct TestNegateGate;
158        impl<F: FancyBinary> CircuitExecutor<F> for TestNegateGate {
159            fn execute(
160                &self,
161                backend: &mut F,
162                inputs: &[<F as crate::Fancy>::Item],
163                channel: &mut Channel,
164            ) -> Result<Vec<<F as crate::Fancy>::Item>> {
165                let output = backend.negate(&inputs[0]);
166                backend.output(&output, channel)?;
167                Ok(vec![output])
168            }
169
170            fn ninputs(&self) -> usize {
171                1
172            }
173
174            fn modulus(&self, _: usize) -> u16 {
175                2
176            }
177        }
178
179        /// Circuit for testing [`FancyBinary::and`].
180        pub struct TestAndGate;
181        impl<F: FancyBinary> CircuitExecutor<F> for TestAndGate {
182            fn execute(
183                &self,
184                backend: &mut F,
185                inputs: &[F::Item],
186                channel: &mut Channel,
187            ) -> Result<Vec<F::Item>> {
188                let output = backend.and(&inputs[0], &inputs[1], channel)?;
189                backend.output(&output, channel)?;
190                Ok(vec![output])
191            }
192
193            fn ninputs(&self) -> usize {
194                2
195            }
196
197            fn modulus(&self, _: usize) -> u16 {
198                2
199            }
200        }
201
202        /// Circuit for testing [`FancyBinary::and_many`].
203        pub struct TestAndGateFanN(pub usize);
204        impl<F: FancyBinary> CircuitExecutor<F> for TestAndGateFanN {
205            fn execute(
206                &self,
207                backend: &mut F,
208                inputs: &[F::Item],
209                channel: &mut Channel,
210            ) -> Result<Vec<F::Item>> {
211                let output = backend.and_many(inputs, channel)?;
212                backend.output(&output, channel)?;
213                Ok(vec![output])
214            }
215
216            fn ninputs(&self) -> usize {
217                self.0
218            }
219
220            fn modulus(&self, _: usize) -> u16 {
221                2
222            }
223        }
224
225        /// Circuit for testing [`FancyBinary::or_many`].
226        pub struct TestOrGateFanN(pub usize);
227        impl<F: FancyBinary> CircuitExecutor<F> for TestOrGateFanN {
228            fn execute(
229                &self,
230                backend: &mut F,
231                inputs: &[F::Item],
232                channel: &mut Channel,
233            ) -> Result<Vec<F::Item>> {
234                let output = backend.or_many(inputs, channel)?;
235                backend.output(&output, channel)?;
236                Ok(vec![output])
237            }
238
239            fn ninputs(&self) -> usize {
240                self.0
241            }
242
243            fn modulus(&self, _: usize) -> u16 {
244                2
245            }
246        }
247
248        /// Circuit for testing [`FancyBinary::xor_many`].
249        pub struct TestXorGateFanN(pub usize);
250        impl<F: FancyBinary> CircuitExecutor<F> for TestXorGateFanN {
251            fn execute(
252                &self,
253                backend: &mut F,
254                inputs: &[F::Item],
255                channel: &mut Channel,
256            ) -> Result<Vec<F::Item>> {
257                let output = backend.xor_many(inputs);
258                backend.output(&output, channel)?;
259                Ok(vec![output])
260            }
261
262            fn ninputs(&self) -> usize {
263                self.0
264            }
265
266            fn modulus(&self, _: usize) -> u16 {
267                2
268            }
269        }
270
271        /// Circuit for testing [`FancyBinary::negate`] over a [`BinaryBundle`].
272        pub struct TestBinaryNegate(pub usize);
273        impl<F: FancyBinary> CircuitExecutor<F> for TestBinaryNegate {
274            fn execute(
275                &self,
276                backend: &mut F,
277                inputs: &[<F as crate::Fancy>::Item],
278                channel: &mut Channel,
279            ) -> Result<Vec<<F as crate::Fancy>::Item>> {
280                let not =
281                    BinaryBundle::new(inputs.iter().map(|x| backend.negate(x)).collect::<Vec<_>>());
282                backend.output_bundle(&not, channel)?;
283                Ok(not.wires().to_vec())
284            }
285
286            fn ninputs(&self) -> usize {
287                self.0
288            }
289
290            fn modulus(&self, _: usize) -> u16 {
291                2
292            }
293        }
294    }
295
296    pub mod arithmetic {
297        //! Circuits that test [`FancyArithmetic`].
298
299        use crate::{FancyArithmetic, circuit::CircuitExecutor};
300        use swanky_channel::Channel;
301        use swanky_error::Result;
302
303        /// Circuit for testing [`FancyArithmetic::add`].
304        pub struct TestAddition(pub u16);
305        impl<F: FancyArithmetic> CircuitExecutor<F> for TestAddition {
306            fn execute(
307                &self,
308                backend: &mut F,
309                inputs: &[F::Item],
310                _: &mut Channel,
311            ) -> swanky_error::Result<Vec<F::Item>> {
312                let output = backend.add(&inputs[0], &inputs[1]);
313                Ok(vec![output])
314            }
315
316            fn ninputs(&self) -> usize {
317                2
318            }
319
320            fn modulus(&self, _: usize) -> u16 {
321                self.0
322            }
323        }
324
325        /// Circuit for testing [`FancyArithmetic::add_many`].
326        pub struct TestAddMany(pub u16, pub usize);
327        impl<F: FancyArithmetic> CircuitExecutor<F> for TestAddMany {
328            fn execute(
329                &self,
330                backend: &mut F,
331                inputs: &[F::Item],
332                channel: &mut Channel,
333            ) -> Result<Vec<F::Item>> {
334                let output = backend.add_many(inputs);
335                backend.output(&output, channel)?;
336                Ok(vec![output])
337            }
338
339            fn ninputs(&self) -> usize {
340                self.1
341            }
342
343            fn modulus(&self, _: usize) -> u16 {
344                self.0
345            }
346        }
347
348        /// Circuit for testing [`FancyArithmetic::sub`].
349        pub struct TestSubtraction(pub u16);
350        impl<F: FancyArithmetic> CircuitExecutor<F> for TestSubtraction {
351            fn execute(
352                &self,
353                backend: &mut F,
354                inputs: &[F::Item],
355                _: &mut Channel,
356            ) -> swanky_error::Result<Vec<F::Item>> {
357                let z = backend.sub(&inputs[0], &inputs[1]);
358                Ok(vec![z])
359            }
360
361            fn ninputs(&self) -> usize {
362                2
363            }
364
365            fn modulus(&self, _: usize) -> u16 {
366                self.0
367            }
368        }
369
370        /// Circuit for testing [`FancyArithmetic::mul`].
371        pub struct TestMulGate(pub u16);
372        impl<F: FancyArithmetic> CircuitExecutor<F> for TestMulGate {
373            fn execute(
374                &self,
375                backend: &mut F,
376                inputs: &[F::Item],
377                channel: &mut Channel,
378            ) -> Result<Vec<F::Item>> {
379                let output = backend.mul(&inputs[0], &inputs[1], channel)?;
380                backend.output(&output, channel)?;
381                Ok(vec![output])
382            }
383
384            fn ninputs(&self) -> usize {
385                2
386            }
387
388            fn modulus(&self, _: usize) -> u16 {
389                self.0
390            }
391        }
392
393        /// Circuit for testing [`FancyArithmetic::mul`] using two different moduli
394        /// for the inputs.
395        pub struct TestMulGateUnequalMods(pub [u16; 2]);
396        impl<F: FancyArithmetic> CircuitExecutor<F> for TestMulGateUnequalMods {
397            fn execute(
398                &self,
399                backend: &mut F,
400                inputs: &[F::Item],
401                channel: &mut Channel,
402            ) -> Result<Vec<F::Item>> {
403                let output = backend.mul(&inputs[0], &inputs[1], channel)?;
404                backend.output(&output, channel)?;
405                Ok(vec![output])
406            }
407
408            fn ninputs(&self) -> usize {
409                2
410            }
411
412            fn modulus(&self, i: usize) -> u16 {
413                self.0[i]
414            }
415        }
416
417        /// Circuit for testing [`FancyArithmetic::cmul`].
418        pub struct TestCmul(pub u16, pub u16);
419        impl<F: FancyArithmetic> CircuitExecutor<F> for TestCmul {
420            fn execute(
421                &self,
422                backend: &mut F,
423                inputs: &[<F as crate::Fancy>::Item],
424                channel: &mut Channel,
425            ) -> Result<Vec<<F as crate::Fancy>::Item>> {
426                let output = backend.cmul(&inputs[0], self.1);
427                backend.output(&output, channel)?;
428                Ok(vec![output])
429            }
430
431            fn ninputs(&self) -> usize {
432                1
433            }
434
435            fn modulus(&self, _: usize) -> u16 {
436                self.0
437            }
438        }
439
440        /// Circuit for testing constant gates.
441        pub struct TestConstants(pub u16, pub u16);
442        impl<F: FancyArithmetic> CircuitExecutor<F> for TestConstants {
443            fn execute(
444                &self,
445                backend: &mut F,
446                inputs: &[F::Item],
447                channel: &mut Channel,
448            ) -> Result<Vec<F::Item>> {
449                let constant = backend.constant(self.1, self.0, channel)?;
450                let output = backend.add(&inputs[0], &constant);
451                backend.output(&output, channel)?;
452                Ok(vec![output])
453            }
454
455            fn ninputs(&self) -> usize {
456                1
457            }
458
459            fn modulus(&self, _: usize) -> u16 {
460                self.0
461            }
462        }
463    }
464
465    pub mod proj {
466        //! Circuits that test [`FancyProj`].
467
468        use crate::{FancyArithmetic, FancyProj, circuit::CircuitExecutor};
469        use swanky_channel::Channel;
470        use swanky_error::Result;
471
472        /// Circuit for testing [`FancyProj::proj`].
473        pub struct TestProj(pub u16);
474        impl<F: FancyProj> CircuitExecutor<F> for TestProj {
475            fn execute(
476                &self,
477                backend: &mut F,
478                inputs: &[<F as crate::Fancy>::Item],
479                channel: &mut Channel,
480            ) -> Result<Vec<<F as crate::Fancy>::Item>> {
481                let tab = (0..self.0).map(|i| (i + 1) % self.0).collect();
482                let output = backend.proj(&inputs[0], self.0, Some(tab), channel)?;
483                backend.output(&output, channel)?;
484                Ok(vec![output])
485            }
486
487            fn ninputs(&self) -> usize {
488                1
489            }
490
491            fn modulus(&self, _: usize) -> u16 {
492                self.0
493            }
494        }
495
496        /// Circuit for testing [`FancyProj::proj`] using a custom truth table.
497        pub struct TestProjRand(pub u16, pub Vec<u16>);
498        impl<F: FancyProj> CircuitExecutor<F> for TestProjRand {
499            fn execute(
500                &self,
501                backend: &mut F,
502                inputs: &[<F as crate::Fancy>::Item],
503                channel: &mut Channel,
504            ) -> Result<Vec<<F as crate::Fancy>::Item>> {
505                let output = backend.proj(&inputs[0], self.0, Some(self.1.clone()), channel)?;
506                backend.output(&output, channel)?;
507                Ok(vec![output])
508            }
509
510            fn ninputs(&self) -> usize {
511                1
512            }
513
514            fn modulus(&self, _: usize) -> u16 {
515                self.0
516            }
517        }
518
519        /// Circuit for testing [`FancyProj::mod_change`].
520        pub struct TestModChange(pub u16, pub u16);
521        impl<F: FancyProj> CircuitExecutor<F> for TestModChange {
522            fn execute(
523                &self,
524                backend: &mut F,
525                inputs: &[F::Item],
526                channel: &mut Channel,
527            ) -> Result<Vec<F::Item>> {
528                let y = backend.mod_change(&inputs[0], self.1, channel)?;
529                let z = backend.mod_change(&y, self.0, channel)?;
530                backend.output(&z, channel)?;
531                Ok(vec![z])
532            }
533
534            fn ninputs(&self) -> usize {
535                1
536            }
537
538            fn modulus(&self, _: usize) -> u16 {
539                self.0
540            }
541        }
542
543        /// Circuit for testing [`FancyProj::mod_change`] followed by
544        /// [`FancyArithmetic::add_many`].
545        pub struct TestAddManyModChange(pub usize);
546        impl<F: FancyProj + FancyArithmetic> CircuitExecutor<F> for TestAddManyModChange {
547            fn execute(
548                &self,
549                backend: &mut F,
550                inputs: &[F::Item],
551                channel: &mut Channel,
552            ) -> Result<Vec<F::Item>> {
553                let wires = inputs
554                    .iter()
555                    .map(|x| backend.mod_change(x, self.0 as u16 + 1, channel))
556                    .collect::<Result<Vec<_>>>()?;
557                let output = backend.add_many(&wires);
558                backend.output(&output, channel)?;
559                Ok(vec![output])
560            }
561
562            fn ninputs(&self) -> usize {
563                self.0
564            }
565
566            fn modulus(&self, _: usize) -> u16 {
567                2
568            }
569        }
570    }
571
572    pub mod bundle_gadgets {
573        //! Circuits that test [`BundleGadgets`].
574
575        use crate::{BinaryBundle, BundleGadgets, CrtBundle, circuit::CircuitExecutor};
576        use swanky_channel::Channel;
577        use swanky_error::Result;
578
579        /// Circuit for testing [`CrtBundle`]s.
580        pub struct TestBundleInputOutput(pub Vec<u16>);
581        impl<F: BundleGadgets> CircuitExecutor<F> for TestBundleInputOutput {
582            fn execute(
583                &self,
584                backend: &mut F,
585                inputs: &[F::Item],
586                channel: &mut Channel,
587            ) -> Result<Vec<F::Item>> {
588                let output = CrtBundle::new(inputs.to_vec());
589                backend.output_bundle(&output, channel)?;
590                Ok(output.wires().to_vec())
591            }
592
593            fn ninputs(&self) -> usize {
594                self.0.len()
595            }
596
597            fn modulus(&self, i: usize) -> u16 {
598                self.0[i]
599            }
600        }
601
602        /// Circuit for testing [`BundleGadgets::shift_extend`].
603        pub struct TestShiftExtend(pub usize, pub usize);
604        impl<F: BundleGadgets> CircuitExecutor<F> for TestShiftExtend {
605            fn execute(
606                &self,
607                backend: &mut F,
608                inputs: &[<F as crate::Fancy>::Item],
609                channel: &mut Channel,
610            ) -> Result<Vec<<F as crate::Fancy>::Item>> {
611                let x = BinaryBundle::new(inputs.to_vec());
612                let z = backend.shift_extend(&x, self.1, channel)?;
613                backend.output_bundle(&z, channel)?;
614                Ok(z.wires().to_vec())
615            }
616
617            fn ninputs(&self) -> usize {
618                self.0
619            }
620
621            fn modulus(&self, _: usize) -> u16 {
622                2
623            }
624        }
625    }
626
627    pub mod crt_gadgets {
628        //! Circuits that test [`CrtGadgets`].
629
630        use crate::{CrtBundle, CrtGadgets, circuit::CircuitExecutor};
631        use swanky_channel::Channel;
632        use swanky_error::Result;
633
634        /// Circuit for testing [`CrtGadgets::crt_add`].
635        pub struct TestCrtAddition(pub Vec<u16>);
636        impl<F: CrtGadgets> CircuitExecutor<F> for TestCrtAddition {
637            fn execute(
638                &self,
639                backend: &mut F,
640                inputs: &[F::Item],
641                channel: &mut Channel,
642            ) -> Result<Vec<F::Item>> {
643                let x = CrtBundle::new(inputs[..self.0.len()].to_vec());
644                let y = CrtBundle::new(inputs[self.0.len()..].to_vec());
645                let z = backend.crt_add(&x, &y);
646                backend.output_bundle(&z, channel)?;
647                Ok(z.wires().to_vec())
648            }
649
650            fn ninputs(&self) -> usize {
651                self.0.len() * 2
652            }
653
654            fn modulus(&self, i: usize) -> u16 {
655                self.0[i % self.0.len()]
656            }
657        }
658
659        /// Circuit for testing [`CrtGadgets::crt_sub`].
660        pub struct TestCrtSubtraction(pub Vec<u16>);
661        impl<F: CrtGadgets> CircuitExecutor<F> for TestCrtSubtraction {
662            fn execute(
663                &self,
664                backend: &mut F,
665                inputs: &[F::Item],
666                channel: &mut Channel,
667            ) -> Result<Vec<F::Item>> {
668                let x = CrtBundle::new(inputs[..self.0.len()].to_vec());
669                let y = CrtBundle::new(inputs[self.0.len()..].to_vec());
670                let z = backend.crt_sub(&x, &y);
671                backend.output_bundle(&z, channel)?;
672                Ok(z.wires().to_vec())
673            }
674
675            fn ninputs(&self) -> usize {
676                self.0.len() * 2
677            }
678
679            fn modulus(&self, i: usize) -> u16 {
680                self.0[i % self.0.len()]
681            }
682        }
683
684        /// Circuit for testing [`CrtGadgets::crt_cmul`].
685        pub struct TestCrtCmul(pub Vec<u16>, pub u128);
686        impl<F: CrtGadgets> CircuitExecutor<F> for TestCrtCmul {
687            fn execute(
688                &self,
689                backend: &mut F,
690                inputs: &[F::Item],
691                channel: &mut Channel,
692            ) -> Result<Vec<F::Item>> {
693                let x = CrtBundle::new(inputs.to_vec());
694                let z = backend.crt_cmul(&x, self.1);
695                backend.output_bundle(&z, channel)?;
696                Ok(z.wires().to_vec())
697            }
698
699            fn ninputs(&self) -> usize {
700                self.0.len()
701            }
702
703            fn modulus(&self, i: usize) -> u16 {
704                self.0[i]
705            }
706        }
707    }
708
709    pub mod arithmetic_bundle_gadgets {
710        //! Circuits that test [`ArithmeticBundleGadgets`].
711
712        use crate::{ArithmeticBundleGadgets, BundleGadgets, CrtBundle, circuit::CircuitExecutor};
713        use swanky_channel::Channel;
714        use swanky_error::Result;
715
716        /// Circuit for testing [`ArithmeticBundleGadgets::mul_bundles`].
717        pub struct TestCrtMultiplication(pub Vec<u16>);
718        impl<F: ArithmeticBundleGadgets> CircuitExecutor<F> for TestCrtMultiplication {
719            fn execute(
720                &self,
721                backend: &mut F,
722                inputs: &[F::Item],
723                channel: &mut Channel,
724            ) -> Result<Vec<F::Item>> {
725                let x = CrtBundle::new(inputs[..self.0.len()].to_vec());
726                let y = CrtBundle::new(inputs[self.0.len()..].to_vec());
727                let z = backend.mul_bundles(&x, &y, channel)?;
728                backend.output_bundle(&z, channel)?;
729                Ok(z.wires().to_vec())
730            }
731
732            fn ninputs(&self) -> usize {
733                self.0.len() * 2
734            }
735
736            fn modulus(&self, i: usize) -> u16 {
737                self.0[i % self.0.len()]
738            }
739        }
740
741        /// Circuit for testing [`ArithmeticBundleGadgets::mask`].
742        pub struct TestMask(pub Vec<u16>);
743        impl<F: ArithmeticBundleGadgets> CircuitExecutor<F> for TestMask {
744            fn execute(
745                &self,
746                backend: &mut F,
747                inputs: &[F::Item],
748                channel: &mut Channel,
749            ) -> Result<Vec<F::Item>> {
750                let b = &inputs[0];
751                let x = CrtBundle::new(inputs[1..self.0.len() + 1].to_vec());
752                let z = backend.mask(b, &x, channel)?;
753                backend.output_bundle(&z, channel)?;
754                Ok(z.wires().to_vec())
755            }
756
757            fn ninputs(&self) -> usize {
758                self.0.len() + 1
759            }
760
761            fn modulus(&self, i: usize) -> u16 {
762                if i == 0 { 2 } else { self.0[i - 1] }
763            }
764        }
765    }
766
767    pub mod crt_proj_gadgets {
768        //! Circuits for testing [`CrtProjGadgets`].
769
770        use crate::{CrtBundle, CrtProjGadgets, circuit::CircuitExecutor};
771        use swanky_channel::Channel;
772        use swanky_error::Result;
773
774        /// Circuit for testing [`CrtProjGadgets::crt_cexp`].
775        pub struct TestCrtCexp(pub Vec<u16>, pub u16);
776        impl<F: CrtProjGadgets> CircuitExecutor<F> for TestCrtCexp {
777            fn execute(
778                &self,
779                backend: &mut F,
780                inputs: &[F::Item],
781                channel: &mut Channel,
782            ) -> Result<Vec<F::Item>> {
783                let x = CrtBundle::new(inputs.to_vec());
784                let z = backend.crt_cexp(&x, self.1, channel)?;
785                backend.output_bundle(&z, channel)?;
786                Ok(z.wires().to_vec())
787            }
788
789            fn ninputs(&self) -> usize {
790                self.0.len()
791            }
792
793            fn modulus(&self, i: usize) -> u16 {
794                self.0[i]
795            }
796        }
797
798        /// Circuit for testing [`CrtProjGadgets::crt_div`].
799        pub struct TestCrtDivision(pub Vec<u16>);
800        impl<F: CrtProjGadgets> CircuitExecutor<F> for TestCrtDivision {
801            fn execute(
802                &self,
803                backend: &mut F,
804                inputs: &[F::Item],
805                channel: &mut Channel,
806            ) -> Result<Vec<F::Item>> {
807                let x = CrtBundle::new(inputs[..self.0.len()].to_vec());
808                let y = CrtBundle::new(inputs[self.0.len()..].to_vec());
809                let z = backend.crt_div(&x, &y, channel)?;
810                backend.output_bundle(&z, channel)?;
811                Ok(z.wires().to_vec())
812            }
813
814            fn ninputs(&self) -> usize {
815                self.0.len() * 2
816            }
817
818            fn modulus(&self, i: usize) -> u16 {
819                self.0[i % self.0.len()]
820            }
821        }
822
823        /// Circuit for testing [`CrtProjGadgets::crt_rem`].
824        pub struct TestCrtRemainder(pub Vec<u16>, pub u16);
825        impl<F: CrtProjGadgets> CircuitExecutor<F> for TestCrtRemainder {
826            fn execute(
827                &self,
828                backend: &mut F,
829                inputs: &[F::Item],
830                channel: &mut Channel,
831            ) -> Result<Vec<F::Item>> {
832                let x = CrtBundle::new(inputs.to_vec());
833                let z = backend.crt_rem(&x, self.1, channel)?;
834                backend.output_bundle(&z, channel)?;
835                Ok(z.wires().to_vec())
836            }
837
838            fn ninputs(&self) -> usize {
839                self.0.len()
840            }
841
842            fn modulus(&self, i: usize) -> u16 {
843                self.0[i]
844            }
845        }
846
847        /// Circuit for testing multiple CRT operations.
848        pub struct TestComplexGadget(pub Vec<u16>, pub usize);
849        impl<F: CrtProjGadgets> CircuitExecutor<F> for TestComplexGadget {
850            fn execute(
851                &self,
852                backend: &mut F,
853                inputs: &[<F as crate::Fancy>::Item],
854                channel: &mut Channel,
855            ) -> Result<Vec<<F as crate::Fancy>::Item>> {
856                let inputs = inputs
857                    .chunks_exact(self.0.len())
858                    .map(|x| CrtBundle::new(x.to_vec()))
859                    .collect::<Vec<_>>();
860                let mut outputs = Vec::with_capacity(inputs.len());
861                for x in inputs.iter() {
862                    let c = backend.crt_constant_bundle(1, x.composite_modulus(), channel)?;
863                    let y = backend.crt_mul(x, &c, channel)?;
864                    let z = backend.crt_relu(&y, "100%", None, channel)?;
865                    outputs.push(z);
866                }
867                backend.crt_outputs(&outputs, channel)?;
868                Ok(outputs
869                    .iter()
870                    .map(|out| out.wires().to_vec())
871                    .collect::<Vec<_>>()
872                    .concat())
873            }
874
875            fn ninputs(&self) -> usize {
876                self.1
877            }
878
879            fn modulus(&self, i: usize) -> u16 {
880                self.0[i % self.0.len()]
881            }
882        }
883
884        /// Circuit for testing [`CrtProjGadgets::crt_relu`].
885        pub struct TestRelu(pub Vec<u16>);
886        impl<F: CrtProjGadgets> CircuitExecutor<F> for TestRelu {
887            fn execute(
888                &self,
889                backend: &mut F,
890                inputs: &[<F as crate::Fancy>::Item],
891                channel: &mut Channel,
892            ) -> Result<Vec<<F as crate::Fancy>::Item>> {
893                let x = CrtBundle::new(inputs.to_vec());
894                let z = backend.crt_relu(&x, "100%", None, channel)?;
895                backend.output_bundle(&z, channel)?;
896                Ok(z.wires().to_vec())
897            }
898
899            fn ninputs(&self) -> usize {
900                self.0.len()
901            }
902
903            fn modulus(&self, i: usize) -> u16 {
904                self.0[i]
905            }
906        }
907
908        /// Circuit for testing [`CrtProjGadgets::crt_sgn`].
909        pub struct TestSgn(pub Vec<u16>);
910        impl<F: CrtProjGadgets> CircuitExecutor<F> for TestSgn {
911            fn execute(
912                &self,
913                backend: &mut F,
914                inputs: &[<F as crate::Fancy>::Item],
915                channel: &mut Channel,
916            ) -> Result<Vec<<F as crate::Fancy>::Item>> {
917                let x = CrtBundle::new(inputs.to_vec());
918                let z = backend.crt_sgn(&x, "100%", None, channel)?;
919                backend.output_bundle(&z, channel)?;
920                Ok(z.wires().to_vec())
921            }
922
923            fn ninputs(&self) -> usize {
924                self.0.len()
925            }
926
927            fn modulus(&self, i: usize) -> u16 {
928                self.0[i]
929            }
930        }
931
932        /// Circuit for testing [`CrtProjGadgets::crt_lt`].
933        pub struct TestLeq(pub Vec<u16>);
934        impl<F: CrtProjGadgets> CircuitExecutor<F> for TestLeq {
935            fn execute(
936                &self,
937                backend: &mut F,
938                inputs: &[<F as crate::Fancy>::Item],
939                channel: &mut Channel,
940            ) -> Result<Vec<<F as crate::Fancy>::Item>> {
941                let x = CrtBundle::new(inputs[..self.0.len()].to_vec());
942                let y = CrtBundle::new(inputs[self.0.len()..].to_vec());
943                let z = backend.crt_lt(&x, &y, "100%", channel)?;
944                backend.output(&z, channel)?;
945                Ok(vec![z])
946            }
947
948            fn ninputs(&self) -> usize {
949                self.0.len() * 2
950            }
951
952            fn modulus(&self, i: usize) -> u16 {
953                self.0[i % self.0.len()]
954            }
955        }
956
957        /// Circuit for testing [`CrtProjGadgets::crt_max`].
958        pub struct TestMax(pub Vec<u16>, pub usize);
959        impl<F: CrtProjGadgets> CircuitExecutor<F> for TestMax {
960            fn execute(
961                &self,
962                backend: &mut F,
963                inputs: &[<F as crate::Fancy>::Item],
964                channel: &mut Channel,
965            ) -> Result<Vec<<F as crate::Fancy>::Item>> {
966                let xs = inputs
967                    .chunks_exact(self.0.len())
968                    .map(|v| CrtBundle::new(v.to_vec()))
969                    .collect::<Vec<_>>();
970                let z = backend.crt_max(&xs, "100%", channel)?;
971                backend.output_bundle(&z, channel)?;
972                Ok(z.wires().to_vec())
973            }
974
975            fn ninputs(&self) -> usize {
976                self.0.len() * self.1
977            }
978
979            fn modulus(&self, i: usize) -> u16 {
980                self.0[i % self.0.len()]
981            }
982        }
983
984        /// Circuit for testing [`CrtProjGadgets::crt_to_pmr`].
985        pub struct TestCrtToPmr(pub Vec<u16>);
986        impl<F: CrtProjGadgets> CircuitExecutor<F> for TestCrtToPmr {
987            fn execute(
988                &self,
989                backend: &mut F,
990                inputs: &[<F as crate::Fancy>::Item],
991                channel: &mut Channel,
992            ) -> Result<Vec<<F as crate::Fancy>::Item>> {
993                let x = CrtBundle::new(inputs.to_vec());
994                let z = backend.crt_to_pmr(&x, channel)?;
995                backend.output_bundle(&z, channel)?;
996                Ok(z.wires().to_vec())
997            }
998
999            fn ninputs(&self) -> usize {
1000                self.0.len()
1001            }
1002
1003            fn modulus(&self, i: usize) -> u16 {
1004                self.0[i]
1005            }
1006        }
1007
1008        /// Circuit for testing [`CrtProjGadgets::pmr_lt`].
1009        pub struct TestPmrLessThan(pub Vec<u16>);
1010        impl<F: CrtProjGadgets> CircuitExecutor<F> for TestPmrLessThan {
1011            fn execute(
1012                &self,
1013                backend: &mut F,
1014                inputs: &[<F as crate::Fancy>::Item],
1015                channel: &mut Channel,
1016            ) -> Result<Vec<<F as crate::Fancy>::Item>> {
1017                let x = CrtBundle::new(inputs[..self.0.len()].to_vec());
1018                let y = CrtBundle::new(inputs[self.0.len()..].to_vec());
1019                let z = backend.pmr_lt(&x, &y, channel)?;
1020                backend.output(&z, channel)?;
1021                Ok(vec![z])
1022            }
1023
1024            fn ninputs(&self) -> usize {
1025                self.0.len() * 2
1026            }
1027
1028            fn modulus(&self, i: usize) -> u16 {
1029                self.0[i % self.0.len()]
1030            }
1031        }
1032
1033        /// Circuit for testing [`CrtProjGadgets::pmr_geq`].
1034        pub struct TestPmrGreaterThanOrEqual(pub Vec<u16>);
1035        impl<F: CrtProjGadgets> CircuitExecutor<F> for TestPmrGreaterThanOrEqual {
1036            fn execute(
1037                &self,
1038                backend: &mut F,
1039                inputs: &[<F as crate::Fancy>::Item],
1040                channel: &mut Channel,
1041            ) -> Result<Vec<<F as crate::Fancy>::Item>> {
1042                let x = CrtBundle::new(inputs[..self.0.len()].to_vec());
1043                let y = CrtBundle::new(inputs[self.0.len()..].to_vec());
1044                let z = backend.pmr_geq(&x, &y, channel)?;
1045                backend.output(&z, channel)?;
1046                Ok(vec![z])
1047            }
1048
1049            fn ninputs(&self) -> usize {
1050                self.0.len() * 2
1051            }
1052
1053            fn modulus(&self, i: usize) -> u16 {
1054                self.0[i % self.0.len()]
1055            }
1056        }
1057    }
1058
1059    pub mod arithmetic_proj_bundle_gadgets {
1060        //! Circuits for testing [`ArithmeticProjBundleGadgets`].
1061
1062        use crate::{
1063            ArithmeticProjBundleGadgets, Bundle, BundleGadgets, CrtBundle, circuit::CircuitExecutor,
1064        };
1065        use swanky_channel::Channel;
1066        use swanky_error::Result;
1067
1068        /// Circuit for testing [`ArithmeticProjBundleGadgets::eq_bundles`].
1069        pub struct TestEqBundles(pub Vec<u16>);
1070        impl<F: ArithmeticProjBundleGadgets> CircuitExecutor<F> for TestEqBundles {
1071            fn execute(
1072                &self,
1073                backend: &mut F,
1074                inputs: &[F::Item],
1075                channel: &mut Channel,
1076            ) -> Result<Vec<F::Item>> {
1077                let x = CrtBundle::new(inputs[..self.0.len()].to_vec());
1078                let y = CrtBundle::new(inputs[self.0.len()..].to_vec());
1079                let z = backend.eq_bundles(&x, &y, channel)?;
1080                backend.output(&z, channel)?;
1081                Ok(vec![z])
1082            }
1083
1084            fn ninputs(&self) -> usize {
1085                self.0.len() * 2
1086            }
1087
1088            fn modulus(&self, i: usize) -> u16 {
1089                self.0[i % self.0.len()]
1090            }
1091        }
1092
1093        /// Circuit for testing [`ArithmeticProjBundleGadgets::mixed_radix_addition`].
1094        pub struct TestMixedRadixAddition(pub Vec<u16>, pub usize);
1095        impl<F: ArithmeticProjBundleGadgets> CircuitExecutor<F> for TestMixedRadixAddition {
1096            fn execute(
1097                &self,
1098                backend: &mut F,
1099                inputs: &[<F as crate::Fancy>::Item],
1100                channel: &mut Channel,
1101            ) -> Result<Vec<<F as crate::Fancy>::Item>> {
1102                let xs = inputs
1103                    .chunks_exact(self.0.len())
1104                    .map(|v| Bundle::new(v.to_vec()))
1105                    .collect::<Vec<_>>();
1106                let z = backend.mixed_radix_addition(&xs, channel)?;
1107                backend.output_bundle(&z, channel)?;
1108                Ok(z.wires().to_vec())
1109            }
1110
1111            fn ninputs(&self) -> usize {
1112                self.1 * self.0.len()
1113            }
1114
1115            fn modulus(&self, i: usize) -> u16 {
1116                self.0[i % self.0.len()]
1117            }
1118        }
1119
1120        /// Circuit for testing [`ArithmeticProjBundleGadgets::mixed_radix_addition_msb_only`].
1121        pub struct TestMixedRadixAdditionMSBOnly(pub Vec<u16>, pub usize);
1122        impl<F: ArithmeticProjBundleGadgets> CircuitExecutor<F> for TestMixedRadixAdditionMSBOnly {
1123            fn execute(
1124                &self,
1125                backend: &mut F,
1126                inputs: &[<F as crate::Fancy>::Item],
1127                channel: &mut Channel,
1128            ) -> Result<Vec<<F as crate::Fancy>::Item>> {
1129                let xs = inputs
1130                    .chunks_exact(self.0.len())
1131                    .map(|v| Bundle::new(v.to_vec()))
1132                    .collect::<Vec<_>>();
1133                let z = backend.mixed_radix_addition_msb_only(&xs, channel)?;
1134                backend.output(&z, channel)?;
1135                Ok(vec![z])
1136            }
1137
1138            fn ninputs(&self) -> usize {
1139                self.0.len() * self.1
1140            }
1141
1142            fn modulus(&self, i: usize) -> u16 {
1143                self.0[i % self.0.len()]
1144            }
1145        }
1146    }
1147
1148    pub mod binary_gadgets {
1149        //! Circuits that test [`BinaryGadgets`].
1150
1151        use crate::{BinaryBundle, BinaryGadgets, circuit::CircuitExecutor};
1152        use swanky_channel::Channel;
1153        use swanky_error::Result;
1154
1155        /// Circuit for testing [`BinaryGadgets::bin_constant_bundle`].
1156        pub struct TestConstantBundle(pub u128, pub usize);
1157        impl<F: BinaryGadgets> CircuitExecutor<F> for TestConstantBundle {
1158            fn execute(
1159                &self,
1160                backend: &mut F,
1161                _inputs: &[<F as crate::Fancy>::Item],
1162                channel: &mut Channel,
1163            ) -> Result<Vec<<F as crate::Fancy>::Item>> {
1164                let value = backend.bin_constant_bundle(self.0, self.1, channel)?;
1165                backend.output_bundle(&value, channel)?;
1166                Ok(value.wires().to_vec())
1167            }
1168
1169            fn ninputs(&self) -> usize {
1170                0
1171            }
1172
1173            fn modulus(&self, _: usize) -> u16 {
1174                2
1175            }
1176        }
1177
1178        /// Circuit for testing [`BinaryGadgets::bin_and`].
1179        pub struct TestBinaryAnd(pub usize);
1180        impl<F: BinaryGadgets> CircuitExecutor<F> for TestBinaryAnd {
1181            fn execute(
1182                &self,
1183                backend: &mut F,
1184                inputs: &[<F as crate::Fancy>::Item],
1185                channel: &mut Channel,
1186            ) -> Result<Vec<<F as crate::Fancy>::Item>> {
1187                let x = BinaryBundle::new(inputs[..self.0].to_vec());
1188                let y = BinaryBundle::new(inputs[self.0..].to_vec());
1189                let z = backend.bin_and(&x, &y, channel)?;
1190                backend.output_bundle(&z, channel)?;
1191                Ok(z.wires().to_vec())
1192            }
1193
1194            fn ninputs(&self) -> usize {
1195                self.0 * 2
1196            }
1197
1198            fn modulus(&self, _: usize) -> u16 {
1199                2
1200            }
1201        }
1202
1203        /// Circuit for testing [`BinaryGadgets::bin_addition`].
1204        pub struct TestBinaryAddition(pub usize);
1205        impl<F: BinaryGadgets> CircuitExecutor<F> for TestBinaryAddition {
1206            fn execute(
1207                &self,
1208                backend: &mut F,
1209                inputs: &[<F as crate::Fancy>::Item],
1210                channel: &mut Channel,
1211            ) -> Result<Vec<<F as crate::Fancy>::Item>> {
1212                let x = BinaryBundle::new(inputs[..self.0].to_vec());
1213                let y = BinaryBundle::new(inputs[self.0..].to_vec());
1214                let (z, carry) = backend.bin_addition(&x, &y, channel)?;
1215                backend.output(&carry, channel)?;
1216                backend.output_bundle(&z, channel)?;
1217                Ok([vec![carry], z.wires().to_vec()].concat())
1218            }
1219
1220            fn ninputs(&self) -> usize {
1221                self.0 * 2
1222            }
1223
1224            fn modulus(&self, _: usize) -> u16 {
1225                2
1226            }
1227        }
1228
1229        /// Circuit for testing [`BinaryGadgets::bin_addition_no_carry`].
1230        pub struct TestBinaryAdditionNoCarry(pub usize);
1231        impl<F: BinaryGadgets> CircuitExecutor<F> for TestBinaryAdditionNoCarry {
1232            fn execute(
1233                &self,
1234                backend: &mut F,
1235                inputs: &[<F as crate::Fancy>::Item],
1236                channel: &mut Channel,
1237            ) -> Result<Vec<<F as crate::Fancy>::Item>> {
1238                let x = BinaryBundle::new(inputs[..self.0].to_vec());
1239                let y = BinaryBundle::new(inputs[self.0..].to_vec());
1240                let z = backend.bin_addition_no_carry(&x, &y, channel)?;
1241                backend.output_bundle(&z, channel)?;
1242                Ok(z.wires().to_vec())
1243            }
1244
1245            fn ninputs(&self) -> usize {
1246                self.0 * 2
1247            }
1248
1249            fn modulus(&self, _: usize) -> u16 {
1250                2
1251            }
1252        }
1253
1254        /// Circuit for testing [`BinaryGadgets::bin_subtraction`].
1255        pub struct TestBinarySubtraction(pub usize);
1256        impl<F: BinaryGadgets> CircuitExecutor<F> for TestBinarySubtraction {
1257            fn execute(
1258                &self,
1259                backend: &mut F,
1260                inputs: &[<F as crate::Fancy>::Item],
1261                channel: &mut Channel,
1262            ) -> Result<Vec<<F as crate::Fancy>::Item>> {
1263                assert_eq!(inputs.len(), <Self as CircuitExecutor<F>>::ninputs(self));
1264
1265                let x = BinaryBundle::new(inputs[..self.0].to_vec());
1266                let y = BinaryBundle::new(inputs[self.0..].to_vec());
1267                let (z, underflow) = backend.bin_subtraction(&x, &y, channel)?;
1268                backend.output(&underflow, channel)?;
1269                backend.output_bundle(&z, channel)?;
1270                Ok([vec![underflow], z.wires().to_vec()].concat())
1271            }
1272
1273            fn ninputs(&self) -> usize {
1274                self.0 * 2
1275            }
1276
1277            fn modulus(&self, _: usize) -> u16 {
1278                2
1279            }
1280        }
1281
1282        /// Circuit for testing [`BinaryGadgets::bin_mul`].
1283        pub struct TestBinaryMultiplication(pub usize);
1284        impl<F: BinaryGadgets> CircuitExecutor<F> for TestBinaryMultiplication {
1285            fn execute(
1286                &self,
1287                backend: &mut F,
1288                inputs: &[<F as crate::Fancy>::Item],
1289                channel: &mut Channel,
1290            ) -> Result<Vec<<F as crate::Fancy>::Item>> {
1291                let x = BinaryBundle::new(inputs[..self.0].to_vec());
1292                let y = BinaryBundle::new(inputs[self.0..].to_vec());
1293                let z = backend.bin_mul(&x, &y, channel)?;
1294                backend.output_bundle(&z, channel)?;
1295                Ok(z.wires().to_vec())
1296            }
1297
1298            fn ninputs(&self) -> usize {
1299                self.0 * 2
1300            }
1301
1302            fn modulus(&self, _: usize) -> u16 {
1303                2
1304            }
1305        }
1306
1307        /// Circuit for testing [`BinaryGadgets::bin_multiplication_lower_half`].
1308        pub struct TestBinaryMultiplicationLowerHalf(pub usize);
1309        impl<F: BinaryGadgets> CircuitExecutor<F> for TestBinaryMultiplicationLowerHalf {
1310            fn execute(
1311                &self,
1312                backend: &mut F,
1313                inputs: &[<F as crate::Fancy>::Item],
1314                channel: &mut Channel,
1315            ) -> Result<Vec<<F as crate::Fancy>::Item>> {
1316                let x = BinaryBundle::new(inputs[..self.0].to_vec());
1317                let y = BinaryBundle::new(inputs[self.0..].to_vec());
1318                let z = backend.bin_multiplication_lower_half(&x, &y, channel)?;
1319                backend.output_bundle(&z, channel)?;
1320                Ok(z.wires().to_vec())
1321            }
1322
1323            fn ninputs(&self) -> usize {
1324                self.0 * 2
1325            }
1326
1327            fn modulus(&self, _: usize) -> u16 {
1328                2
1329            }
1330        }
1331
1332        /// Circuit for testing [`BinaryGadgets::bin_div`].
1333        pub struct TestBinaryDivision(pub usize);
1334        impl<F: BinaryGadgets> CircuitExecutor<F> for TestBinaryDivision {
1335            fn execute(
1336                &self,
1337                backend: &mut F,
1338                inputs: &[<F as crate::Fancy>::Item],
1339                channel: &mut Channel,
1340            ) -> Result<Vec<<F as crate::Fancy>::Item>> {
1341                let x = BinaryBundle::new(inputs[..self.0].to_vec());
1342                let y = BinaryBundle::new(inputs[self.0..].to_vec());
1343                let z = backend.bin_div(&x, &y, channel)?;
1344                backend.output_bundle(&z, channel)?;
1345                Ok(z.wires().to_vec())
1346            }
1347
1348            fn ninputs(&self) -> usize {
1349                self.0 * 2
1350            }
1351
1352            fn modulus(&self, _: usize) -> u16 {
1353                2
1354            }
1355        }
1356
1357        /// Circuit for testing [`BinaryGadgets::bin_lt`].
1358        pub struct TestBinaryLessThan(pub usize);
1359        impl<F: BinaryGadgets> CircuitExecutor<F> for TestBinaryLessThan {
1360            fn execute(
1361                &self,
1362                backend: &mut F,
1363                inputs: &[<F as crate::Fancy>::Item],
1364                channel: &mut Channel,
1365            ) -> Result<Vec<<F as crate::Fancy>::Item>> {
1366                let x = BinaryBundle::new(inputs[..self.0].to_vec());
1367                let y = BinaryBundle::new(inputs[self.0..].to_vec());
1368                let z = backend.bin_lt(&x, &y, channel)?;
1369                backend.output(&z, channel)?;
1370                Ok(vec![z])
1371            }
1372
1373            fn ninputs(&self) -> usize {
1374                self.0 * 2
1375            }
1376
1377            fn modulus(&self, _: usize) -> u16 {
1378                2
1379            }
1380        }
1381
1382        /// Circuit for testing [`BinaryGadgets::bin_lt_signed`].
1383        pub struct TestBinaryLessThanSigned(pub usize);
1384        impl<F: BinaryGadgets> CircuitExecutor<F> for TestBinaryLessThanSigned {
1385            fn execute(
1386                &self,
1387                backend: &mut F,
1388                inputs: &[<F as crate::Fancy>::Item],
1389                channel: &mut Channel,
1390            ) -> Result<Vec<<F as crate::Fancy>::Item>> {
1391                let x = BinaryBundle::new(inputs[..self.0].to_vec());
1392                let y = BinaryBundle::new(inputs[self.0..].to_vec());
1393                let z = backend.bin_lt_signed(&x, &y, channel)?;
1394                backend.output(&z, channel)?;
1395                Ok(vec![z])
1396            }
1397
1398            fn ninputs(&self) -> usize {
1399                self.0 * 2
1400            }
1401
1402            fn modulus(&self, _: usize) -> u16 {
1403                2
1404            }
1405        }
1406
1407        /// Circuit for testing [`BinaryGadgets::bin_rsa`].
1408        pub struct TestBinaryArithmeticRightShift(pub usize, pub usize);
1409        impl<F: BinaryGadgets> CircuitExecutor<F> for TestBinaryArithmeticRightShift {
1410            fn execute(
1411                &self,
1412                backend: &mut F,
1413                inputs: &[<F as crate::Fancy>::Item],
1414                channel: &mut Channel,
1415            ) -> Result<Vec<<F as crate::Fancy>::Item>> {
1416                let x = BinaryBundle::new(inputs.to_vec());
1417                let z = backend.bin_rsa(&x, self.1);
1418                backend.output_bundle(&z, channel)?;
1419                Ok(z.wires().to_vec())
1420            }
1421
1422            fn ninputs(&self) -> usize {
1423                self.0
1424            }
1425
1426            fn modulus(&self, _: usize) -> u16 {
1427                2
1428            }
1429        }
1430
1431        /// Circuit for testing [`BinaryGadgets::bin_rsl`].
1432        pub struct TestBinaryLogicalRightShift(pub usize, pub usize);
1433        impl<F: BinaryGadgets> CircuitExecutor<F> for TestBinaryLogicalRightShift {
1434            fn execute(
1435                &self,
1436                backend: &mut F,
1437                inputs: &[<F as crate::Fancy>::Item],
1438                channel: &mut Channel,
1439            ) -> Result<Vec<<F as crate::Fancy>::Item>> {
1440                let x = BinaryBundle::new(inputs.to_vec());
1441                let z = backend.bin_rsl(&x, self.1, channel)?;
1442                backend.output_bundle(&z, channel)?;
1443                Ok(z.wires().to_vec())
1444            }
1445
1446            fn ninputs(&self) -> usize {
1447                self.0
1448            }
1449
1450            fn modulus(&self, _: usize) -> u16 {
1451                2
1452            }
1453        }
1454
1455        /// Circuit for testing [`BinaryGadgets::bin_eq_bundles`].
1456        pub struct TestBinaryEqBundles(pub usize);
1457        impl<F: BinaryGadgets> CircuitExecutor<F> for TestBinaryEqBundles {
1458            fn execute(
1459                &self,
1460                backend: &mut F,
1461                inputs: &[<F as crate::Fancy>::Item],
1462                channel: &mut Channel,
1463            ) -> Result<Vec<<F as crate::Fancy>::Item>> {
1464                let x = BinaryBundle::new(inputs[..self.0].to_vec());
1465                let y = BinaryBundle::new(inputs[self.0..].to_vec());
1466                let z = backend.bin_eq_bundles(&x, &y, channel)?;
1467                backend.output(&z, channel)?;
1468                Ok(vec![z])
1469            }
1470
1471            fn ninputs(&self) -> usize {
1472                self.0 * 2
1473            }
1474
1475            fn modulus(&self, _: usize) -> u16 {
1476                2
1477            }
1478        }
1479
1480        /// Circuit for testing [`BinaryGadgets::bin_abs`].
1481        pub struct TestBinaryAbs(pub usize);
1482        impl<F: BinaryGadgets> CircuitExecutor<F> for TestBinaryAbs {
1483            fn execute(
1484                &self,
1485                backend: &mut F,
1486                inputs: &[<F as crate::Fancy>::Item],
1487                channel: &mut Channel,
1488            ) -> Result<Vec<<F as crate::Fancy>::Item>> {
1489                let x = BinaryBundle::new(inputs.to_vec());
1490                let z = backend.bin_abs(&x, channel)?;
1491                backend.output_bundle(&z, channel)?;
1492                Ok(z.wires().to_vec())
1493            }
1494
1495            fn ninputs(&self) -> usize {
1496                self.0
1497            }
1498
1499            fn modulus(&self, _: usize) -> u16 {
1500                2
1501            }
1502        }
1503
1504        /// Circuit for testing [`BinaryGadgets::bin_twos_complement`].
1505        pub struct TestBinaryTwosComplement(pub usize);
1506        impl<F: BinaryGadgets> CircuitExecutor<F> for TestBinaryTwosComplement {
1507            fn execute(
1508                &self,
1509                backend: &mut F,
1510                inputs: &[<F as crate::Fancy>::Item],
1511                channel: &mut Channel,
1512            ) -> Result<Vec<<F as crate::Fancy>::Item>> {
1513                assert_eq!(inputs.len(), <Self as CircuitExecutor<F>>::ninputs(self));
1514
1515                let x = BinaryBundle::new(inputs.to_vec());
1516                let z = backend.bin_twos_complement(&x, channel)?;
1517                backend.output_bundle(&z, channel)?;
1518                Ok(z.wires().to_vec())
1519            }
1520
1521            fn ninputs(&self) -> usize {
1522                self.0
1523            }
1524
1525            fn modulus(&self, _: usize) -> u16 {
1526                2
1527            }
1528        }
1529
1530        /// Circuit for testing [`BinaryGadgets::bin_demux`].
1531        pub struct TestBinaryDemux(pub usize);
1532        impl<F: BinaryGadgets> CircuitExecutor<F> for TestBinaryDemux {
1533            fn execute(
1534                &self,
1535                backend: &mut F,
1536                inputs: &[<F as crate::Fancy>::Item],
1537                channel: &mut Channel,
1538            ) -> Result<Vec<<F as crate::Fancy>::Item>> {
1539                let x = BinaryBundle::new(inputs.to_vec());
1540                let output = backend.bin_demux(&x, channel)?;
1541                backend.outputs(&output, channel)?;
1542                Ok(output)
1543            }
1544
1545            fn ninputs(&self) -> usize {
1546                self.0
1547            }
1548
1549            fn modulus(&self, _: usize) -> u16 {
1550                2
1551            }
1552        }
1553
1554        /// Circuit for testing [`BinaryGadgets::bin_max`].
1555        pub struct TestBinaryMax(pub usize, pub usize);
1556        impl<F: BinaryGadgets> CircuitExecutor<F> for TestBinaryMax {
1557            fn execute(
1558                &self,
1559                backend: &mut F,
1560                inputs: &[<F as crate::Fancy>::Item],
1561                channel: &mut Channel,
1562            ) -> Result<Vec<<F as crate::Fancy>::Item>> {
1563                let xs = inputs
1564                    .chunks_exact(self.0)
1565                    .map(|v| BinaryBundle::new(v.to_vec()))
1566                    .collect::<Vec<_>>();
1567                let z = backend.bin_max(&xs, channel)?;
1568                backend.output_bundle(&z, channel)?;
1569                Ok(z.wires().to_vec())
1570            }
1571
1572            fn ninputs(&self) -> usize {
1573                self.0 * self.1
1574            }
1575
1576            fn modulus(&self, _: usize) -> u16 {
1577                2
1578            }
1579        }
1580    }
1581}
1582
1583#[cfg(test)]
1584mod fancy_binary {
1585    use crate::{circuit::circuits, dummy::Dummy, util::RngExt};
1586    use rand::thread_rng;
1587
1588    #[test]
1589    fn and_gate_fan_n() {
1590        let mut rng = thread_rng();
1591        let n = 2 + (rng.gen_usize() % 200);
1592        let c = circuits::binary::TestAndGateFanN(n);
1593
1594        for _ in 0..16 {
1595            let inputs = (0..n).map(|_| rng.gen_bool() as u16).collect::<Vec<_>>();
1596            let expected = inputs.iter().fold(1, |acc, &x| x & acc);
1597            let output = Dummy::eval(&c, &inputs).unwrap()[0];
1598            assert_eq!(output, expected);
1599        }
1600    }
1601
1602    #[test]
1603    fn binary_constant_gates() {
1604        let c = circuits::fancy::TestBinaryConstant;
1605        let inputs = [];
1606        let expected_0 = 0;
1607        let output_0: u16 = Dummy::eval(&c, &inputs).unwrap()[0];
1608        assert_eq!(output_0, expected_0);
1609        let expected_1 = 1;
1610        let output_1 = Dummy::eval(&c, &inputs).unwrap()[1];
1611        assert_eq!(output_1, expected_1);
1612    }
1613
1614    #[test]
1615    fn or_gate_fan_n() {
1616        let mut rng = thread_rng();
1617        let n = 2 + (rng.gen_usize() % 200);
1618        let c = circuits::binary::TestOrGateFanN(n);
1619
1620        for _ in 0..16 {
1621            let inputs = (0..n).map(|_| rng.gen_bool() as u16).collect::<Vec<_>>();
1622            let expected = inputs.iter().fold(0, |acc, &x| x | acc);
1623            let output = Dummy::eval(&c, &inputs).unwrap()[0];
1624            assert_eq!(output, expected);
1625        }
1626    }
1627
1628    #[test]
1629    fn xor_gate_fan_n() {
1630        let mut rng = thread_rng();
1631        let n = 2 + (rng.gen_usize() % 200);
1632        let c = circuits::binary::TestXorGateFanN(n);
1633
1634        for _ in 0..16 {
1635            let inputs = (0..n).map(|_| rng.gen_bool() as u16).collect::<Vec<_>>();
1636            let expected = inputs.iter().fold(0, |acc, &x| x ^ acc);
1637            let output = Dummy::eval(&c, &inputs).unwrap()[0];
1638            assert_eq!(output, expected);
1639        }
1640    }
1641
1642    #[test]
1643    fn binary_half_gate() {
1644        let mut rng = thread_rng();
1645        let c = circuits::binary::TestAndGate;
1646
1647        for _ in 0..16 {
1648            let x = rng.gen_bool() as u16;
1649            let y = rng.gen_bool() as u16;
1650            let output = Dummy::eval(&c, &[x, y]).unwrap()[0];
1651            assert_eq!(output, x * y % 2);
1652        }
1653    }
1654}
1655
1656#[cfg(test)]
1657mod fancy_arithmetic {
1658    use crate::{circuit::circuits, dummy::Dummy, util::RngExt};
1659    use rand::thread_rng;
1660
1661    #[test]
1662    fn constants() {
1663        let mut rng = thread_rng();
1664        let q = rng.gen_modulus();
1665        let c = rng.gen_u16() % q;
1666        let circ = circuits::arithmetic::TestConstants(q, c);
1667
1668        for _ in 0..64 {
1669            let x = rng.gen_u16() % q;
1670            let output = Dummy::eval(&circ, &[x]).unwrap()[0];
1671            assert_eq!(output, (x + c) % q);
1672        }
1673    }
1674
1675    #[test]
1676    fn arithmetic_half_gate() {
1677        let mut rng = thread_rng();
1678        let q = rng.gen_prime();
1679        let c = circuits::arithmetic::TestMulGate(q);
1680
1681        for _ in 0..16 {
1682            let x = rng.gen_u16() % q;
1683            let y = rng.gen_u16() % q;
1684            let output = Dummy::eval(&c, &[x, y]).unwrap()[0];
1685            assert_eq!(output, x * y % q);
1686        }
1687    }
1688}
1689
1690#[cfg(test)]
1691mod fancy_proj {
1692    use crate::{
1693        circuit::{CircuitExecutor, circuits},
1694        dummy::Dummy,
1695        util::RngExt,
1696    };
1697    use rand::thread_rng;
1698
1699    #[test]
1700    fn mod_change() {
1701        let mut rng = thread_rng();
1702        let p = rng.gen_prime();
1703        let q = rng.gen_prime();
1704        let c = circuits::proj::TestModChange(p, q);
1705
1706        for _ in 0..16 {
1707            let x = rng.gen_u16() % p;
1708            let output = Dummy::eval(&c, &[x]).unwrap()[0];
1709            assert_eq!(output, x % q);
1710        }
1711    }
1712
1713    #[test]
1714    fn add_many_mod_change() {
1715        let mut rng = thread_rng();
1716        let n = 113;
1717        let c = circuits::proj::TestAddManyModChange(n);
1718
1719        for _ in 0..64 {
1720            let inputs = (0
1721                ..<circuits::proj::TestAddManyModChange as CircuitExecutor<Dummy>>::ninputs(&c))
1722                .map(|i| {
1723                    rng.gen_u16()
1724                        % <circuits::proj::TestAddManyModChange as CircuitExecutor<Dummy>>::modulus(
1725                            &c, i,
1726                        )
1727                })
1728                .collect::<Vec<_>>();
1729            let expected: u16 = inputs.iter().sum();
1730            let output = Dummy::eval(&c, &inputs).unwrap()[0];
1731            assert_eq!(output, expected);
1732        }
1733    }
1734}
1735
1736#[cfg(test)]
1737mod bundle_gadgets {
1738    use crate::{
1739        circuit::circuits,
1740        dummy::Dummy,
1741        util::{RngExt, crt_factor, crt_inv_factor, factor, u128_from_bits, u128_to_bits},
1742    };
1743    use rand::thread_rng;
1744
1745    #[test]
1746    fn test_bundle_input_output() {
1747        let mut rng = thread_rng();
1748        let q = rng.gen_usable_composite_modulus();
1749        let c = circuits::bundle_gadgets::TestBundleInputOutput(factor(q));
1750
1751        for _ in 0..16 {
1752            let x = rng.gen_u128() % q;
1753            let y = Dummy::eval(&c, &crt_factor(x, q)).unwrap();
1754            let output = crt_inv_factor(&y, q);
1755            assert_eq!(output, x);
1756        }
1757    }
1758
1759    #[test]
1760    fn test_shift_extend() {
1761        let mut rng = thread_rng();
1762        let nbits = 64;
1763        let q = 1 << nbits;
1764
1765        for _ in 0..16 {
1766            let shift_size = rng.gen_usize() % nbits;
1767            let x = rng.gen_u128() % q;
1768            let c = circuits::bundle_gadgets::TestShiftExtend(nbits, shift_size);
1769
1770            let inputs = u128_to_bits(x, nbits);
1771            let output = Dummy::eval(&c, &inputs).unwrap();
1772            assert_eq!(u128_from_bits(&output), x << shift_size);
1773        }
1774    }
1775}
1776
1777#[cfg(test)]
1778mod crt_gadgets {
1779    use rand::thread_rng;
1780
1781    use crate::{
1782        circuit::circuits,
1783        dummy::Dummy,
1784        util::{self, RngExt, crt_factor, crt_inv_factor, factor},
1785    };
1786
1787    #[test]
1788    fn test_addition() {
1789        let mut rng = thread_rng();
1790        let q = rng.gen_usable_composite_modulus();
1791        let c = circuits::crt_gadgets::TestCrtAddition(factor(q));
1792
1793        for _ in 0..16 {
1794            let x = rng.gen_u128() % q;
1795            let y = rng.gen_u128() % q;
1796            let mut inputs = crt_factor(x, q);
1797            inputs.extend(crt_factor(y, q));
1798            let z = Dummy::eval(&c, &inputs).unwrap();
1799            let output = crt_inv_factor(&z, q);
1800            assert_eq!(output, (x + y) % q);
1801        }
1802    }
1803
1804    #[test]
1805    fn test_subtraction() {
1806        let mut rng = thread_rng();
1807        let q = rng.gen_usable_composite_modulus();
1808        let c = circuits::crt_gadgets::TestCrtSubtraction(util::factor(q));
1809
1810        for _ in 0..16 {
1811            let x = rng.gen_u128() % q;
1812            let y = rng.gen_u128() % q;
1813            let mut inputs = crt_factor(x, q);
1814            inputs.extend(crt_factor(y, q));
1815            let z = Dummy::eval(&c, &inputs).unwrap();
1816            let output = crt_inv_factor(&z, q);
1817            assert_eq!(output, (x + q - y) % q);
1818        }
1819    }
1820
1821    #[test]
1822    fn test_cmul() {
1823        let mut rng = thread_rng();
1824        let q = util::modulus_with_width(16);
1825        let y = rng.gen_u128() % q;
1826        let c = circuits::crt_gadgets::TestCrtCmul(util::factor(q), y);
1827
1828        for _ in 0..16 {
1829            let x = rng.gen_u128() % q;
1830            let z = Dummy::eval(&c, &crt_factor(x, q)).unwrap();
1831            let output = crt_inv_factor(&z, q);
1832            assert_eq!(output, (x * y) % q);
1833        }
1834    }
1835}
1836
1837#[cfg(test)]
1838mod arithmetic_bundle_gadgets {
1839    use rand::thread_rng;
1840
1841    use crate::{
1842        circuit::circuits,
1843        dummy::Dummy,
1844        util::{RngExt, crt_factor, crt_inv_factor, factor},
1845    };
1846
1847    #[test]
1848    fn test_multiplication() {
1849        let mut rng = thread_rng();
1850        let q = rng.gen_usable_composite_modulus();
1851        let c = circuits::arithmetic_bundle_gadgets::TestCrtMultiplication(factor(q));
1852
1853        for _ in 0..16 {
1854            let x = rng.gen_u64() as u128 % q;
1855            let y = rng.gen_u64() as u128 % q;
1856            let mut inputs = crt_factor(x, q);
1857            inputs.extend(crt_factor(y, q));
1858            let z = Dummy::eval(&c, &inputs).unwrap();
1859            let output = crt_inv_factor(&z, q);
1860            assert_eq!(output, (x * y) % q);
1861        }
1862    }
1863
1864    #[test]
1865    fn test_mask() {
1866        let mut rng = thread_rng();
1867        let q = rng.gen_usable_composite_modulus();
1868        let c = circuits::arithmetic_bundle_gadgets::TestMask(factor(q));
1869
1870        for _ in 0..16 {
1871            let b = rng.gen_bool();
1872            let x = rng.gen_u128() % q;
1873
1874            let mut inputs = vec![b as u16];
1875            inputs.extend(crt_factor(x, q));
1876            let z = Dummy::eval(&c, &inputs).unwrap();
1877            let output = crt_inv_factor(&z, q);
1878            if b {
1879                assert_eq!(output, x);
1880            } else {
1881                assert_eq!(output, 0);
1882            }
1883        }
1884    }
1885}
1886
1887#[cfg(test)]
1888mod crt_proj_gadgets {
1889    use crate::{
1890        circuit::circuits,
1891        dummy::Dummy,
1892        util::{RngExt, crt_factor, crt_inv_factor, factor, modulus_with_width, product},
1893    };
1894    use rand::thread_rng;
1895
1896    #[test]
1897    fn test_cexp() {
1898        let mut rng = thread_rng();
1899        let q = modulus_with_width(10);
1900        let y = rng.gen_u16() % 10;
1901        let c = circuits::crt_proj_gadgets::TestCrtCexp(factor(q), y);
1902
1903        for _ in 0..64 {
1904            let x = rng.gen_u16() as u128 % q;
1905            let z = Dummy::eval(&c, &crt_factor(x, q)).unwrap();
1906            let output = crt_inv_factor(&z, q);
1907            assert_eq!(output, x.pow(y as u32) % q);
1908        }
1909    }
1910
1911    #[test]
1912    #[ignore]
1913    fn test_division() {
1914        let mut rng = thread_rng();
1915
1916        for _ in 0..16 {
1917            let qs = rng.gen_usable_factors();
1918            let n = qs.len();
1919            let q = crate::util::product(&qs);
1920            let c = circuits::crt_proj_gadgets::TestCrtDivision(factor(q));
1921
1922            let q_ = crate::util::product(&qs[..n - 1]);
1923            let pt_x = rng.gen_u128() % q_;
1924            let pt_y = rng.gen_u128() % q_;
1925
1926            let mut inputs = crt_factor(pt_x, q);
1927            inputs.extend(crt_factor(pt_y, q));
1928            let z = Dummy::eval(&c, &inputs).unwrap();
1929            let output = crt_inv_factor(&z, q);
1930            assert_eq!(output, pt_x / pt_y);
1931        }
1932    }
1933
1934    #[test]
1935    fn test_remainder() {
1936        let mut rng = thread_rng();
1937        let ps = rng.gen_usable_factors();
1938        let q = ps.iter().fold(1, |acc, &x| (x as u128) * acc);
1939        let p = ps[rng.gen_u16() as usize % ps.len()];
1940        let c = circuits::crt_proj_gadgets::TestCrtRemainder(ps, p);
1941
1942        for _ in 0..64 {
1943            let x = rng.gen_u128() % q;
1944            let z = Dummy::eval(&c, &crt_factor(x, q)).unwrap();
1945            let output = crt_inv_factor(&z, q);
1946            assert_eq!(output, x % p as u128);
1947        }
1948    }
1949
1950    #[test]
1951    fn test_relu() {
1952        let mut rng = thread_rng();
1953        let q = modulus_with_width(10);
1954        let c = circuits::crt_proj_gadgets::TestRelu(factor(q));
1955
1956        for _ in 0..128 {
1957            let input = rng.gen_u128() % q;
1958            let expected = if input < q / 2 { input } else { 0 };
1959            let z = Dummy::eval(&c, &crt_factor(input, q)).unwrap();
1960            let output = crt_inv_factor(&z, q);
1961            assert_eq!(output, expected);
1962        }
1963    }
1964
1965    #[test]
1966    fn test_sgn() {
1967        let mut rng = thread_rng();
1968        let q = modulus_with_width(10);
1969        let c = circuits::crt_proj_gadgets::TestSgn(factor(q));
1970
1971        for _ in 0..128 {
1972            let input = rng.gen_u128() % q;
1973            let expected = if input < q / 2 { 1 } else { q - 1 };
1974            let z = Dummy::eval(&c, &crt_factor(input, q)).unwrap();
1975            let output = crt_inv_factor(&z, q);
1976            assert_eq!(output, expected);
1977        }
1978    }
1979
1980    #[test]
1981    fn test_leq() {
1982        let mut rng = thread_rng();
1983        let q = modulus_with_width(10);
1984        let c = circuits::crt_proj_gadgets::TestLeq(factor(q));
1985
1986        // Let's have at least one test where they are surely equal.
1987        let x = rng.gen_u128() % q / 2;
1988        let mut inputs = crt_factor(x, q);
1989        inputs.extend(crt_factor(x, q));
1990        let output = Dummy::eval(&c, &inputs).unwrap()[0];
1991        assert_eq!(output, (x < x) as u16);
1992
1993        for _ in 0..64 {
1994            let x = rng.gen_u128() % q / 2;
1995            let y = rng.gen_u128() % q / 2;
1996            let mut inputs = crt_factor(x, q);
1997            inputs.extend(crt_factor(y, q));
1998            let output = Dummy::eval(&c, &inputs).unwrap()[0];
1999            assert_eq!(output, (x < y) as u16);
2000        }
2001    }
2002
2003    #[test]
2004    fn test_max() {
2005        let mut rng = thread_rng();
2006        let q = modulus_with_width(10);
2007        let n = 10;
2008        let c = circuits::crt_proj_gadgets::TestMax(factor(q), n);
2009
2010        for _ in 0..16 {
2011            let inputs = (0..n).map(|_| rng.gen_u128() % (q / 2)).collect::<Vec<_>>();
2012            let expected = *inputs.iter().max().unwrap();
2013
2014            let inputs = inputs
2015                .into_iter()
2016                .flat_map(|x| crt_factor(x, q))
2017                .collect::<Vec<_>>();
2018            let z = Dummy::eval(&c, &inputs).unwrap();
2019            let output = crt_inv_factor(&z, q);
2020            assert_eq!(output, expected);
2021        }
2022    }
2023
2024    #[test]
2025    fn test_crt_to_pmr() {
2026        fn to_pmr_pt(x: u128, ps: &[u16]) -> Vec<u16> {
2027            let mut ds = vec![0; ps.len()];
2028            let mut q = 1;
2029            for i in 0..ps.len() {
2030                let p = ps[i] as u128;
2031                ds[i] = ((x / q) % p) as u16;
2032                q *= p;
2033            }
2034            ds
2035        }
2036
2037        let mut rng = rand::thread_rng();
2038        for _ in 0..8 {
2039            let ps = rng.gen_usable_factors();
2040            let q = product(&ps);
2041
2042            let input = rng.gen_u128() % q;
2043            let expected = to_pmr_pt(input, &ps);
2044            let c = circuits::crt_proj_gadgets::TestCrtToPmr(ps);
2045            let output = Dummy::eval(&c, &crt_factor(input, q)).unwrap();
2046            assert_eq!(output, expected);
2047        }
2048    }
2049
2050    #[test]
2051    fn test_pmr_lt() {
2052        let mut rng = rand::thread_rng();
2053        for _ in 0..8 {
2054            let qs = rng.gen_usable_factors();
2055            let n = qs.len();
2056            let q = product(&qs);
2057            let q_ = product(&qs[..n - 1]);
2058            let pt_x = rng.gen_u128() % q_;
2059            let pt_y = rng.gen_u128() % q_;
2060            let c = circuits::crt_proj_gadgets::TestPmrLessThan(qs);
2061            let mut inputs = crt_factor(pt_x, q);
2062            inputs.extend(crt_factor(pt_y, q));
2063            let output = Dummy::eval(&c, &inputs).unwrap()[0];
2064            if pt_x < pt_y {
2065                assert_eq!(output, 1);
2066            } else {
2067                assert_eq!(output, 0);
2068            }
2069        }
2070    }
2071
2072    #[test]
2073    fn test_pmr_geq() {
2074        let mut rng = rand::thread_rng();
2075        for _ in 0..8 {
2076            let qs = rng.gen_usable_factors();
2077            let n = qs.len();
2078            let q = product(&qs);
2079            let q_ = product(&qs[..n - 1]);
2080            let pt_x = rng.gen_u128() % q_;
2081            let pt_y = rng.gen_u128() % q_;
2082            let c = circuits::crt_proj_gadgets::TestPmrGreaterThanOrEqual(qs);
2083            let mut inputs = crt_factor(pt_x, q);
2084            inputs.extend(crt_factor(pt_y, q));
2085            let output = Dummy::eval(&c, &inputs).unwrap()[0];
2086            if pt_x >= pt_y {
2087                assert_eq!(output, 1);
2088            } else {
2089                assert_eq!(output, 0);
2090            }
2091        }
2092    }
2093}
2094
2095#[cfg(test)]
2096mod arithmetic_proj_bundle_gadgets {
2097    use rand::thread_rng;
2098
2099    use crate::{
2100        circuit::circuits,
2101        dummy::Dummy,
2102        util::{RngExt, as_mixed_radix, crt_factor, factor, from_mixed_radix, product},
2103    };
2104
2105    #[test]
2106    fn test_eq_bundles() {
2107        let mut rng = thread_rng();
2108        let q = rng.gen_usable_composite_modulus();
2109        let c = circuits::arithmetic_proj_bundle_gadgets::TestEqBundles(factor(q));
2110
2111        // Let's have at least one test where they are surely equal.
2112        let x = rng.gen_u128() % q;
2113        let mut inputs = crt_factor(x, q);
2114        inputs.extend(crt_factor(x, q));
2115        let output = Dummy::eval(&c, &inputs).unwrap()[0];
2116        assert_eq!(output, (x == x) as u16);
2117
2118        for _ in 0..64 {
2119            let x = rng.gen_u128() % q;
2120            let y = rng.gen_u128() % q;
2121            let mut inputs = crt_factor(x, q);
2122            inputs.extend(crt_factor(y, q));
2123            let output = Dummy::eval(&c, &inputs).unwrap()[0];
2124            assert_eq!(output, (x == y) as u16);
2125        }
2126    }
2127
2128    #[test]
2129    fn test_mixed_radix_addition() {
2130        let mut rng = thread_rng();
2131        let nargs = 2 + rng.gen_usize() % 100;
2132        let moduli = (0..7).map(|_| rng.gen_modulus()).collect::<Vec<_>>();
2133        let q: u128 = moduli.iter().map(|&q| q as u128).product();
2134        let circ =
2135            circuits::arithmetic_proj_bundle_gadgets::TestMixedRadixAddition(moduli.clone(), nargs);
2136
2137        // Test maximum overflow.
2138        let mut inputs = Vec::new();
2139        for _ in 0..nargs {
2140            inputs.extend(as_mixed_radix(q - 1, &moduli).iter());
2141        }
2142        let output = Dummy::eval(&circ, &inputs).unwrap();
2143        assert_eq!(
2144            from_mixed_radix(&output, &moduli),
2145            (q - 1) * (nargs as u128) % q
2146        );
2147
2148        // Test random values.
2149        for _ in 0..4 {
2150            let mut expected = 0;
2151            let mut inputs = Vec::new();
2152            for _ in 0..nargs {
2153                let x = rng.gen_u128() % q;
2154                expected = (expected + x) % q;
2155                inputs.extend(as_mixed_radix(x, &moduli).iter());
2156            }
2157            let output = Dummy::eval(&circ, &inputs).unwrap();
2158            assert_eq!(from_mixed_radix(&output, &moduli), expected);
2159        }
2160    }
2161
2162    #[test]
2163    fn test_mixed_radix_addition_msb_only() {
2164        let mut rng = thread_rng();
2165        let nargs = 2 + rng.gen_usize() % 10;
2166        let moduli = (0..7).map(|_| rng.gen_modulus()).collect::<Vec<_>>();
2167        let q = product(&moduli);
2168        let circ = circuits::arithmetic_proj_bundle_gadgets::TestMixedRadixAdditionMSBOnly(
2169            moduli.clone(),
2170            nargs,
2171        );
2172
2173        // Test maximum overflow.
2174        let mut inputs = Vec::new();
2175        for _ in 0..nargs {
2176            inputs.extend(as_mixed_radix(q - 1, &moduli).iter());
2177        }
2178        let output = Dummy::eval(&circ, &inputs).unwrap()[0];
2179        assert_eq!(
2180            output,
2181            *as_mixed_radix((q - 1) * (nargs as u128) % q, &moduli)
2182                .last()
2183                .unwrap()
2184        );
2185
2186        // Test random values.
2187        for _ in 0..4 {
2188            let mut expected = 0;
2189            let mut inputs = Vec::new();
2190            for _ in 0..nargs {
2191                let x = rng.gen_u128() % q;
2192                expected = (expected + x) % q;
2193                inputs.extend(as_mixed_radix(x, &moduli).iter());
2194            }
2195            let output = Dummy::eval(&circ, &inputs).unwrap()[0];
2196            assert_eq!(output, *as_mixed_radix(expected, &moduli).last().unwrap());
2197        }
2198    }
2199}
2200
2201#[cfg(test)]
2202mod binary_gadgets {
2203    use rand::thread_rng;
2204
2205    use crate::{
2206        circuit::circuits,
2207        dummy::Dummy,
2208        util::{self, RngExt},
2209    };
2210
2211    #[test]
2212    fn test_binary_addition() {
2213        let mut rng = thread_rng();
2214        let nbits = 64;
2215        let q = 1 << 64;
2216        let c = circuits::binary_gadgets::TestBinaryAddition(nbits);
2217
2218        for _ in 0..16 {
2219            let x = rng.gen_u128() % q;
2220            let y = rng.gen_u128() % q;
2221            let mut inputs = util::u128_to_bits(x, nbits);
2222            inputs.extend(util::u128_to_bits(y, nbits));
2223            let output = Dummy::eval(&c, &inputs).unwrap();
2224            assert_eq!(util::u128_from_bits(&output[1..]), (x + y) % q);
2225            assert_eq!(output[0], (x + y >= q) as u16);
2226        }
2227    }
2228
2229    #[test]
2230    fn test_binary_subtraction() {
2231        let mut rng = thread_rng();
2232        let nbits = 64;
2233        let q = 1 << nbits;
2234        let c = circuits::binary_gadgets::TestBinarySubtraction(nbits);
2235
2236        for _ in 0..16 {
2237            let x = rng.gen_u128() % q;
2238            let y = rng.gen_u128() % q;
2239            let mut inputs = util::u128_to_bits(x, nbits);
2240            inputs.extend(util::u128_to_bits(y, nbits));
2241            let output = Dummy::eval(&c, &inputs).unwrap();
2242            assert_eq!(
2243                util::u128_from_bits(&output[1..]),
2244                x.overflowing_sub(y).0 % q
2245            );
2246            assert_eq!(output[0], (y != 0 && x >= y) as u16);
2247        }
2248    }
2249
2250    #[test]
2251    fn test_binary_lt() {
2252        let mut rng = thread_rng();
2253        let nbits = 64;
2254        let q = 1 << nbits;
2255        let c = circuits::binary_gadgets::TestBinaryLessThan(nbits);
2256
2257        for _ in 0..16 {
2258            let x = rng.gen_u128() % q;
2259            let y = rng.gen_u128() % q;
2260            let mut inputs = util::u128_to_bits(x, nbits);
2261            inputs.extend(util::u128_to_bits(y, nbits));
2262            let output = Dummy::eval(&c, &inputs).unwrap();
2263            assert_eq!(util::u128_from_bits(&output) > 0, x < y);
2264        }
2265    }
2266
2267    #[test]
2268    fn test_binary_lt_signed() {
2269        let mut rng = thread_rng();
2270        let nbits = 16;
2271        let q = 1 << nbits;
2272        let c = circuits::binary_gadgets::TestBinaryLessThanSigned(nbits);
2273
2274        for _ in 0..16 {
2275            let x = rng.gen_u128() % q;
2276            let y = rng.gen_u128() % q;
2277            let mut inputs = util::u128_to_bits(x, nbits);
2278            inputs.extend(util::u128_to_bits(y, nbits));
2279            let output = Dummy::eval(&c, &inputs).unwrap();
2280            assert_eq!(output.len(), 1);
2281            assert_eq!(output[0] > 0, (x as i16) < (y as i16));
2282        }
2283    }
2284
2285    #[test]
2286    fn test_binary_multiplication_lower_half() {
2287        let mut rng = thread_rng();
2288        let nbits = 64;
2289        let q = 1 << nbits;
2290        let c = circuits::binary_gadgets::TestBinaryMultiplicationLowerHalf(nbits);
2291
2292        for _ in 0..16 {
2293            let x = rng.gen_u128() % q;
2294            let y = rng.gen_u128() % q;
2295            let mut inputs = util::u128_to_bits(x, nbits);
2296            inputs.extend(util::u128_to_bits(y, nbits));
2297            let output = Dummy::eval(&c, &inputs).unwrap();
2298            assert_eq!(util::u128_from_bits(&output), (x * y) % q);
2299        }
2300    }
2301
2302    #[test]
2303    fn test_binary_multiplication() {
2304        let mut rng = thread_rng();
2305        let nbits = 64;
2306        let q = 1 << 64;
2307        let c = circuits::binary_gadgets::TestBinaryMultiplication(nbits);
2308
2309        for _ in 0..16 {
2310            let x = rng.gen_u128() % q;
2311            let y = rng.gen_u128() % q;
2312            let mut inputs = util::u128_to_bits(x, nbits);
2313            inputs.extend(util::u128_to_bits(y, nbits));
2314            let output = Dummy::eval(&c, &inputs).unwrap();
2315            assert_eq!(util::u128_from_bits(&output), x * y);
2316        }
2317    }
2318
2319    #[test]
2320    fn test_binary_division() {
2321        let mut rng = thread_rng();
2322        let nbits = 64;
2323        let q = 1 << nbits;
2324        let c = circuits::binary_gadgets::TestBinaryDivision(nbits);
2325
2326        for _ in 0..16 {
2327            let x = rng.gen_u128() % q;
2328            let mut y = rng.gen_u128() % q;
2329            while y == 0 {
2330                y = rng.gen_u128() % q;
2331            }
2332            let mut inputs = util::u128_to_bits(x, nbits);
2333            inputs.extend(util::u128_to_bits(y, nbits));
2334            let output = Dummy::eval(&c, &inputs).unwrap();
2335            assert_eq!(util::u128_from_bits(&output), x / y);
2336        }
2337    }
2338
2339    #[test]
2340    fn test_bin_abs() {
2341        let mut rng = thread_rng();
2342        let nbits = 64;
2343        let q = 1 << nbits;
2344        let c = circuits::binary_gadgets::TestBinaryAbs(nbits);
2345
2346        for _ in 0..16 {
2347            let x = rng.gen_u128() % q;
2348            let output = Dummy::eval(&c, &util::u128_to_bits(x, nbits)).unwrap();
2349            assert_eq!(
2350                util::u128_from_bits(&output),
2351                if x >> (nbits - 1) > 0 {
2352                    ((!x) + 1) & ((1 << nbits) - 1)
2353                } else {
2354                    x
2355                }
2356            );
2357        }
2358    }
2359
2360    #[test]
2361    fn test_binary_eq() {
2362        let mut rng = thread_rng();
2363        let nbits = 64;
2364        let q = 1 << nbits;
2365        let c = circuits::binary_gadgets::TestBinaryEqBundles(nbits);
2366
2367        for _ in 0..16 {
2368            let x = rng.gen_u128() % q;
2369            let y = rng.gen_u128() % q;
2370            let mut inputs = util::u128_to_bits(x, nbits);
2371            inputs.extend(util::u128_to_bits(y, nbits));
2372            let output = Dummy::eval(&c, &inputs).unwrap();
2373            assert_eq!(output[0], (x == y) as u16);
2374        }
2375    }
2376
2377    #[test]
2378    fn test_binary_rsa() {
2379        let mut rng = thread_rng();
2380        let nbits = 64;
2381        let q = 1 << nbits;
2382
2383        for _ in 0..16 {
2384            let x = rng.gen_u128() % q;
2385            let shift_size = rng.gen_usize() % nbits;
2386            let c = circuits::binary_gadgets::TestBinaryArithmeticRightShift(nbits, shift_size);
2387            let output = Dummy::eval(&c, &util::u128_to_bits(x, nbits)).unwrap();
2388            assert_eq!(
2389                util::u128_from_bits(&output) as i64,
2390                (x as i64) >> shift_size
2391            );
2392        }
2393    }
2394
2395    #[test]
2396    fn test_binary_rsl() {
2397        let mut rng = thread_rng();
2398        let nbits = 64;
2399        let q = 1 << nbits;
2400
2401        for _ in 0..16 {
2402            let x = rng.gen_u128() % q;
2403            let shift_size = rng.gen_usize() % nbits;
2404            let c = circuits::binary_gadgets::TestBinaryLogicalRightShift(nbits, shift_size);
2405            let output = Dummy::eval(&c, &util::u128_to_bits(x, nbits)).unwrap();
2406            assert_eq!(util::u128_from_bits(&output), x >> shift_size);
2407        }
2408    }
2409
2410    #[test]
2411    fn test_bin_demux() {
2412        let mut rng = thread_rng();
2413        let nbits = 8;
2414        let q = 1 << nbits;
2415        let c = circuits::binary_gadgets::TestBinaryDemux(nbits);
2416
2417        for _ in 0..16 {
2418            let x = rng.gen_u128() % q;
2419            let output = Dummy::eval(&c, &util::u128_to_bits(x, nbits)).unwrap();
2420            for (i, y) in output.into_iter().enumerate() {
2421                if i as u128 == x {
2422                    assert_eq!(y, 1);
2423                } else {
2424                    assert_eq!(y, 0);
2425                }
2426            }
2427        }
2428    }
2429
2430    #[test]
2431    fn test_bin_twos_complement() {
2432        let mut rng = thread_rng();
2433        let nbits = 64;
2434        let q = 1 << nbits;
2435        let c = circuits::binary_gadgets::TestBinaryTwosComplement(nbits);
2436
2437        for _ in 0..16 {
2438            let x = rng.gen_u128() % q;
2439            let output = Dummy::eval(&c, &util::u128_to_bits(x, nbits)).unwrap();
2440            assert_eq!(util::u128_from_bits(&output), (((!x) % q) + 1) % q);
2441        }
2442    }
2443
2444    #[test]
2445    fn test_binary_max() {
2446        let mut rng = thread_rng();
2447        let n = 10;
2448        let nbits = 16;
2449        let q = 1 << nbits;
2450        let c = circuits::binary_gadgets::TestBinaryMax(nbits, n);
2451
2452        for _ in 0..16 {
2453            let inputs = (0..n).map(|_| rng.gen_u128() % q).collect::<Vec<_>>();
2454            let expected = *inputs.iter().max().unwrap();
2455
2456            let inputs = inputs
2457                .into_iter()
2458                .flat_map(|x| util::u128_to_bits(x, nbits))
2459                .collect::<Vec<_>>();
2460            let z = Dummy::eval(&c, &inputs).unwrap();
2461            let output = util::u128_from_bits(&z);
2462            assert_eq!(output, expected);
2463        }
2464    }
2465}