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    FancyArithmetic, FancyBinary, check_binary, derive_binary,
6    dummy::{Dummy, DummyVal},
7    errors::{CircuitBuilderError, DummyError, FancyError},
8    fancy::{BinaryBundle, CrtBundle, Fancy, FancyInput, HasModulus},
9    informer::Informer,
10};
11use itertools::Itertools;
12use std::{collections::HashMap, fmt::Display};
13
14/// The index and modulus of a gate in a circuit.
15#[derive(Clone, Copy, Debug, PartialEq)]
16#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
17pub struct CircuitRef {
18    pub(crate) ix: usize,
19    pub(crate) modulus: u16,
20}
21
22impl std::fmt::Display for CircuitRef {
23    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
24        write!(f, "[{} | {}]", self.ix, self.modulus)
25    }
26}
27
28impl HasModulus for CircuitRef {
29    fn modulus(&self) -> u16 {
30        self.modulus
31    }
32}
33
34/// Static representation of arithmetic computation supported by fancy garbling.
35#[derive(Clone, Debug, PartialEq)]
36#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
37pub struct ArithmeticCircuit {
38    pub(crate) gates: Vec<ArithmeticGate>,
39    pub(crate) gate_moduli: Vec<u16>,
40    pub(crate) garbler_input_refs: Vec<CircuitRef>,
41    pub(crate) evaluator_input_refs: Vec<CircuitRef>,
42    pub(crate) const_refs: Vec<CircuitRef>,
43    pub(crate) output_refs: Vec<CircuitRef>,
44    pub(crate) num_nonfree_gates: usize,
45}
46
47/// Static representation of binary computation supported by fancy garbling.
48#[derive(Clone, Debug, PartialEq)]
49#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
50pub struct BinaryCircuit {
51    pub(crate) gates: Vec<BinaryGate>,
52    pub(crate) garbler_input_refs: Vec<CircuitRef>,
53    pub(crate) evaluator_input_refs: Vec<CircuitRef>,
54    pub(crate) const_refs: Vec<CircuitRef>,
55    pub(crate) output_refs: Vec<CircuitRef>,
56    pub(crate) num_nonfree_gates: usize,
57}
58
59/// Arithmetic computation supported by fancy garbling.
60///
61/// `id` represents the gate number. `out` gives the output wire index; if `out
62/// = None`, then we use the gate index as the output wire index.
63#[derive(Clone, Debug, PartialEq)]
64#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
65pub enum ArithmeticGate {
66    /// Input of garbler
67    GarblerInput {
68        /// Gate number
69        id: usize,
70    },
71    /// Input of evaluator
72    EvaluatorInput {
73        /// Gate number
74        id: usize,
75    },
76    /// Constant value
77    Constant {
78        /// Value of constant
79        val: u16,
80    },
81    /// Add gate
82    Add {
83        /// Reference to input 1
84        xref: CircuitRef,
85
86        /// Reference to input 2
87        yref: CircuitRef,
88
89        /// Output wire index
90        out: Option<usize>,
91    },
92    /// Sub gate
93    Sub {
94        /// Reference to input 1
95        xref: CircuitRef,
96
97        /// Reference to input 2
98        yref: CircuitRef,
99
100        /// Output wire index
101        out: Option<usize>,
102    },
103    /// Constant multiplication gate
104    Cmul {
105        /// Reference to input 1
106        xref: CircuitRef,
107
108        /// Constant to muiltiply by
109        c: u16,
110
111        /// Output wire index
112        out: Option<usize>,
113    },
114    /// Multiplication gate
115    Mul {
116        /// Reference to input 1
117        xref: CircuitRef,
118
119        /// Reference to input 2
120        yref: CircuitRef,
121
122        /// Gate number
123        id: usize,
124
125        /// Output wire index
126        out: Option<usize>,
127    },
128    /// Projection gate
129    Proj {
130        /// Reference to input 1
131        xref: CircuitRef,
132
133        /// Projection truth table
134        tt: Vec<u16>,
135
136        /// Gate number
137        id: usize,
138
139        /// Output wire index
140        out: Option<usize>,
141    },
142}
143
144/// Binary computation supported by fancy garbling.
145///
146/// `id` represents the gate number. `out` gives the output wire index; if `out
147/// = None`, then we use the gate index as the output wire index.
148#[derive(Clone, Debug, PartialEq)]
149#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
150pub enum BinaryGate {
151    /// Input of garbler
152    GarblerInput {
153        /// Gate number
154        id: usize,
155    },
156    /// Input of evaluator
157    EvaluatorInput {
158        /// Gate number
159        id: usize,
160    },
161    /// Constant value
162    Constant {
163        /// Value of constant
164        val: u16,
165    },
166
167    /// Xor gate
168    Xor {
169        /// Reference to input 1
170        xref: CircuitRef,
171
172        /// Reference to input 2
173        yref: CircuitRef,
174
175        /// Output wire index
176        out: Option<usize>,
177    },
178    /// And gate
179    And {
180        /// Reference to input 1
181        xref: CircuitRef,
182
183        /// Reference to input 2
184        yref: CircuitRef,
185
186        /// Gate number
187        id: usize,
188
189        /// Output wire index
190        out: Option<usize>,
191    },
192    /// Not gate
193    Inv {
194        /// Reference to input
195        xref: CircuitRef,
196
197        /// Output wire index
198        out: Option<usize>,
199    },
200}
201
202impl std::fmt::Display for ArithmeticGate {
203    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
204        match self {
205            Self::GarblerInput { id } => write!(f, "GarblerInput {}", id),
206            Self::EvaluatorInput { id } => write!(f, "EvaluatorInput {}", id),
207            Self::Constant { val } => write!(f, "Constant {}", val),
208            Self::Add { xref, yref, out } => write!(f, "Add ( {}, {}, {:?} )", xref, yref, out),
209            Self::Sub { xref, yref, out } => write!(f, "Sub ( {}, {}, {:?} )", xref, yref, out),
210            Self::Cmul { xref, c, out } => write!(f, "Cmul ( {}, {}, {:?} )", xref, c, out),
211            Self::Mul {
212                xref,
213                yref,
214                id,
215                out,
216            } => write!(f, "Mul ( {}, {}, {}, {:?} )", xref, yref, id, out),
217            Self::Proj { xref, tt, id, out } => {
218                write!(f, "Proj ( {}, {:?}, {}, {:?} )", xref, tt, id, out)
219            }
220        }
221    }
222}
223
224impl std::fmt::Display for BinaryGate {
225    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
226        match self {
227            Self::GarblerInput { id } => write!(f, "GarblerInput {}", id),
228            Self::EvaluatorInput { id } => write!(f, "EvaluatorInput {}", id),
229            Self::Constant { val } => write!(f, "Constant {}", val),
230            Self::Xor { xref, yref, out } => write!(f, "Xor ( {}, {}, {:?} )", xref, yref, out),
231            Self::And {
232                xref,
233                yref,
234                id,
235                out,
236            } => write!(f, "And ( {}, {}, {}, {:?} )", xref, yref, id, out),
237            Self::Inv { xref, out } => write!(f, "Inv ( {}, {:?} )", xref, out),
238        }
239    }
240}
241
242/// Trait to display circuit evaluation costs
243///
244/// Blanket implementation available for all circuits
245/// that can be evaluated with an `Informer`
246pub trait CircuitInfo {
247    /// Print circuit info
248    fn print_info(&self) -> Result<(), DummyError>;
249}
250
251impl<C: EvaluableCircuit<Informer<Dummy>>> CircuitInfo for C {
252    fn print_info(&self) -> Result<(), DummyError> {
253        let mut informer = crate::informer::Informer::new(Dummy::new());
254
255        // encode inputs as InformerVals
256        let gb = self
257            .get_garbler_input_refs()
258            .iter()
259            .map(|r| informer.encode(0, r.modulus()))
260            .collect::<Result<Vec<DummyVal>, DummyError>>()?;
261        let ev = self
262            .get_evaluator_input_refs()
263            .iter()
264            .map(|r| informer.encode(0, r.modulus()))
265            .collect::<Result<Vec<DummyVal>, DummyError>>()?;
266
267        let _outputs = self.eval(&mut informer, &gb, &ev)?;
268        println!("{}", informer.stats());
269        Ok(())
270    }
271}
272
273/// A Circuit that can be evaluated by a given Fancy object
274///
275/// Supertrait ensures that circuit can be built by `CircuitBuilder`
276pub trait EvaluableCircuit<F: Fancy>: CircuitType {
277    /// Function to evaluate the circuit
278    fn eval(
279        &self,
280        f: &mut F,
281        garbler_inputs: &[F::Item],
282        evaluator_inputs: &[F::Item],
283    ) -> Result<Option<Vec<u16>>, F::Error>;
284}
285
286impl<F: FancyArithmetic> EvaluableCircuit<F> for ArithmeticCircuit {
287    fn eval(
288        &self,
289        f: &mut F,
290        garbler_inputs: &[F::Item],
291        evaluator_inputs: &[F::Item],
292    ) -> Result<Option<Vec<u16>>, F::Error> {
293        let mut cache: Vec<Option<F::Item>> = vec![None; self.gates.len()];
294        for (i, gate) in self.gates.iter().enumerate() {
295            let q = self.modulus(i);
296            let (zref_, val) = match *gate {
297                ArithmeticGate::GarblerInput { id } => (None, garbler_inputs[id].clone()),
298                ArithmeticGate::EvaluatorInput { id } => {
299                    assert!(
300                        id < evaluator_inputs.len(),
301                        "id={} ev_inps.len()={}",
302                        id,
303                        evaluator_inputs.len()
304                    );
305                    (None, evaluator_inputs[id].clone())
306                }
307                ArithmeticGate::Constant { val } => (None, f.constant(val, q)?),
308                ArithmeticGate::Add { xref, yref, out } => (
309                    out,
310                    f.add(
311                        cache[xref.ix]
312                            .as_ref()
313                            .ok_or_else(|| F::Error::from(FancyError::UninitializedValue))?,
314                        cache[yref.ix]
315                            .as_ref()
316                            .ok_or_else(|| F::Error::from(FancyError::UninitializedValue))?,
317                    )?,
318                ),
319                ArithmeticGate::Sub { xref, yref, out } => (
320                    out,
321                    f.sub(
322                        cache[xref.ix]
323                            .as_ref()
324                            .ok_or_else(|| F::Error::from(FancyError::UninitializedValue))?,
325                        cache[yref.ix]
326                            .as_ref()
327                            .ok_or_else(|| F::Error::from(FancyError::UninitializedValue))?,
328                    )?,
329                ),
330                ArithmeticGate::Cmul { xref, c, out } => (
331                    out,
332                    f.cmul(
333                        cache[xref.ix]
334                            .as_ref()
335                            .ok_or_else(|| F::Error::from(FancyError::UninitializedValue))?,
336                        c,
337                    )?,
338                ),
339                ArithmeticGate::Proj {
340                    xref, ref tt, out, ..
341                } => (
342                    out,
343                    f.proj(
344                        cache[xref.ix]
345                            .as_ref()
346                            .ok_or_else(|| F::Error::from(FancyError::UninitializedValue))?,
347                        q,
348                        Some(tt.to_vec()),
349                    )?,
350                ),
351                ArithmeticGate::Mul {
352                    xref, yref, out, ..
353                } => (
354                    out,
355                    f.mul(
356                        cache[xref.ix]
357                            .as_ref()
358                            .ok_or_else(|| F::Error::from(FancyError::UninitializedValue))?,
359                        cache[yref.ix]
360                            .as_ref()
361                            .ok_or_else(|| F::Error::from(FancyError::UninitializedValue))?,
362                    )?,
363                ),
364            };
365            cache[zref_.unwrap_or(i)] = Some(val);
366        }
367        let mut outputs = Vec::with_capacity(self.noutputs());
368        for r in self.get_output_refs().iter() {
369            let r = cache[r.ix]
370                .as_ref()
371                .ok_or_else(|| F::Error::from(FancyError::UninitializedValue))?;
372            let out = f.output(r)?;
373            outputs.push(out);
374        }
375        Ok(outputs.into_iter().collect())
376    }
377}
378
379impl<F: FancyBinary> EvaluableCircuit<F> for BinaryCircuit {
380    fn eval(
381        &self,
382        f: &mut F,
383        garbler_inputs: &[F::Item],
384        evaluator_inputs: &[F::Item],
385    ) -> Result<Option<Vec<u16>>, F::Error> {
386        let mut cache: Vec<Option<F::Item>> = vec![None; self.gates.len()];
387        for (i, gate) in self.gates.iter().enumerate() {
388            let q = 2;
389            let (zref_, val) = match *gate {
390                BinaryGate::GarblerInput { id } => (None, garbler_inputs[id].clone()),
391                BinaryGate::EvaluatorInput { id } => {
392                    assert!(
393                        id < evaluator_inputs.len(),
394                        "id={} ev_inps.len()={}",
395                        id,
396                        evaluator_inputs.len()
397                    );
398                    (None, evaluator_inputs[id].clone())
399                }
400                BinaryGate::Constant { val } => (None, f.constant(val, q)?),
401                BinaryGate::Inv { xref, out } => (
402                    out,
403                    f.negate(
404                        cache[xref.ix]
405                            .as_ref()
406                            .ok_or_else(|| F::Error::from(FancyError::UninitializedValue))?,
407                    )?,
408                ),
409                BinaryGate::Xor { xref, yref, out } => (
410                    out,
411                    f.xor(
412                        cache[xref.ix]
413                            .as_ref()
414                            .ok_or_else(|| F::Error::from(FancyError::UninitializedValue))?,
415                        cache[yref.ix]
416                            .as_ref()
417                            .ok_or_else(|| F::Error::from(FancyError::UninitializedValue))?,
418                    )?,
419                ),
420                BinaryGate::And {
421                    xref, yref, out, ..
422                } => (
423                    out,
424                    f.and(
425                        cache[xref.ix]
426                            .as_ref()
427                            .ok_or_else(|| F::Error::from(FancyError::UninitializedValue))?,
428                        cache[yref.ix]
429                            .as_ref()
430                            .ok_or_else(|| F::Error::from(FancyError::UninitializedValue))?,
431                    )?,
432                ),
433            };
434            cache[zref_.unwrap_or(i)] = Some(val);
435        }
436        let mut outputs = Vec::with_capacity(self.noutputs());
437        for r in self.get_output_refs().iter() {
438            let r = cache[r.ix]
439                .as_ref()
440                .ok_or_else(|| F::Error::from(FancyError::UninitializedValue))?;
441            let out = f.output(r)?;
442            outputs.push(out);
443        }
444        Ok(outputs.into_iter().collect())
445    }
446}
447
448/// Trait representing circuit gates that can be used in `CircuitType`
449pub trait GateType: Display {
450    /// Generate constant gate
451    fn make_constant(val: u16) -> Self;
452
453    /// Generate garbler input gate
454    fn make_garbler_input(id: usize) -> Self;
455
456    /// Generate evaluator input gate
457    fn make_evaluator_input(id: usize) -> Self;
458}
459
460impl GateType for BinaryGate {
461    fn make_constant(val: u16) -> Self {
462        Self::Constant { val }
463    }
464
465    fn make_garbler_input(id: usize) -> Self {
466        Self::GarblerInput { id }
467    }
468
469    fn make_evaluator_input(id: usize) -> Self {
470        Self::EvaluatorInput { id }
471    }
472}
473
474impl GateType for ArithmeticGate {
475    fn make_constant(val: u16) -> Self {
476        Self::Constant { val }
477    }
478
479    fn make_garbler_input(id: usize) -> Self {
480        Self::GarblerInput { id }
481    }
482
483    fn make_evaluator_input(id: usize) -> Self {
484        Self::EvaluatorInput { id }
485    }
486}
487
488/// Trait representing circuits that can be built by `CircuitBuilder`
489pub trait CircuitType: Clone {
490    /// Gates that the circuit is composed of
491    type Gate: GateType;
492
493    /// Increase number of nonfree gates
494    fn increment_nonfree_gates(&mut self);
495
496    /// Make a new `Circuit` object.
497    fn new(ngates: Option<usize>) -> Self;
498
499    /// Get all output refs
500    fn get_output_refs(&self) -> &[CircuitRef];
501
502    /// Get all garbler input refs
503    fn get_garbler_input_refs(&self) -> &[CircuitRef];
504
505    /// Get all evaluator input refs
506    fn get_evaluator_input_refs(&self) -> &[CircuitRef];
507
508    /// Get number of nonfree gates
509    fn get_num_nonfree_gates(&self) -> usize;
510
511    /// Add a gate
512    fn push_gates(&mut self, gate: Self::Gate);
513
514    /// Add a constant ref
515    fn push_const_ref(&mut self, xref: CircuitRef);
516
517    /// Add an output ref
518    fn push_output_ref(&mut self, xref: CircuitRef);
519
520    /// Add a garbler input ref
521    fn push_garbler_input_ref(&mut self, xref: CircuitRef);
522
523    /// Add an evaluator input ref
524    fn push_evaluator_input_ref(&mut self, xref: CircuitRef);
525
526    /// Add wire moulus
527    fn push_modulus(&mut self, modulus: u16);
528
529    /// Return the modulus of the garbler input indexed by `i`.
530    fn garbler_input_mod(&self, i: usize) -> u16;
531
532    /// Return the modulus of the evaluator input indexed by `i`.
533    fn evaluator_input_mod(&self, i: usize) -> u16;
534
535    /// Return the number of garbler inputs.
536    #[inline]
537    fn num_garbler_inputs(&self) -> usize {
538        self.get_garbler_input_refs().len()
539    }
540
541    /// Return the number of evaluator inputs.
542    #[inline]
543    fn num_evaluator_inputs(&self) -> usize {
544        self.get_evaluator_input_refs().len()
545    }
546
547    /// Return the number of outputs.
548    #[inline]
549    fn noutputs(&self) -> usize {
550        self.get_output_refs().len()
551    }
552}
553
554/// Evaluate the circuit in plaintext.
555pub fn eval_plain<C: EvaluableCircuit<Dummy>>(
556    circuit: &C,
557    garbler_inputs: &[u16],
558    evaluator_inputs: &[u16],
559) -> Result<Vec<u16>, DummyError> {
560    let mut dummy = crate::dummy::Dummy::new();
561
562    if garbler_inputs.len() != circuit.num_garbler_inputs() {
563        return Err(DummyError::NotEnoughGarblerInputs);
564    }
565
566    if evaluator_inputs.len() != circuit.num_evaluator_inputs() {
567        return Err(DummyError::NotEnoughEvaluatorInputs);
568    }
569
570    // encode inputs as DummyVals
571    let gb = garbler_inputs
572        .iter()
573        .zip(circuit.get_garbler_input_refs().iter())
574        .map(|(x, r)| DummyVal::new(*x, r.modulus()))
575        .collect_vec();
576    let ev = evaluator_inputs
577        .iter()
578        .zip(circuit.get_evaluator_input_refs().iter())
579        .map(|(x, r)| DummyVal::new(*x, r.modulus()))
580        .collect_vec();
581
582    let outputs = circuit.eval(&mut dummy, &gb, &ev)?;
583    Ok(outputs.expect("dummy will always return Some(u16) output"))
584}
585
586impl CircuitType for BinaryCircuit {
587    type Gate = BinaryGate;
588
589    fn new(ngates: Option<usize>) -> Self {
590        let gates = Vec::with_capacity(ngates.unwrap_or(0));
591        Self {
592            gates,
593            garbler_input_refs: Vec::new(),
594            evaluator_input_refs: Vec::new(),
595            const_refs: Vec::new(),
596            output_refs: Vec::new(),
597            num_nonfree_gates: 0,
598        }
599    }
600
601    fn push_gates(&mut self, gate: Self::Gate) {
602        self.gates.push(gate)
603    }
604
605    fn push_const_ref(&mut self, xref: CircuitRef) {
606        self.const_refs.push(xref)
607    }
608
609    fn push_output_ref(&mut self, xref: CircuitRef) {
610        self.output_refs.push(xref)
611    }
612
613    fn push_garbler_input_ref(&mut self, xref: CircuitRef) {
614        self.garbler_input_refs.push(xref)
615    }
616
617    fn push_modulus(&mut self, modulus: u16) {
618        assert_eq!(modulus, 2);
619    }
620
621    fn push_evaluator_input_ref(&mut self, xref: CircuitRef) {
622        self.evaluator_input_refs.push(xref)
623    }
624
625    fn increment_nonfree_gates(&mut self) {
626        self.num_nonfree_gates += 1;
627    }
628
629    fn get_num_nonfree_gates(&self) -> usize {
630        self.num_nonfree_gates
631    }
632
633    fn get_output_refs(&self) -> &[CircuitRef] {
634        &self.output_refs
635    }
636
637    fn get_garbler_input_refs(&self) -> &[CircuitRef] {
638        &self.garbler_input_refs
639    }
640
641    fn get_evaluator_input_refs(&self) -> &[CircuitRef] {
642        &self.evaluator_input_refs
643    }
644
645    fn garbler_input_mod(&self, _: usize) -> u16 {
646        2
647    }
648
649    fn evaluator_input_mod(&self, _: usize) -> u16 {
650        2
651    }
652}
653
654impl CircuitType for ArithmeticCircuit {
655    type Gate = ArithmeticGate;
656
657    fn new(ngates: Option<usize>) -> ArithmeticCircuit {
658        let gates = Vec::with_capacity(ngates.unwrap_or(0));
659        ArithmeticCircuit {
660            gates,
661            garbler_input_refs: Vec::new(),
662            evaluator_input_refs: Vec::new(),
663            const_refs: Vec::new(),
664            output_refs: Vec::new(),
665            gate_moduli: Vec::new(),
666            num_nonfree_gates: 0,
667        }
668    }
669
670    fn push_gates(&mut self, gate: Self::Gate) {
671        self.gates.push(gate)
672    }
673
674    fn push_const_ref(&mut self, xref: CircuitRef) {
675        self.const_refs.push(xref)
676    }
677
678    fn push_output_ref(&mut self, xref: CircuitRef) {
679        self.output_refs.push(xref)
680    }
681
682    fn push_garbler_input_ref(&mut self, xref: CircuitRef) {
683        self.garbler_input_refs.push(xref)
684    }
685
686    fn push_modulus(&mut self, modulus: u16) {
687        self.gate_moduli.push(modulus)
688    }
689
690    fn push_evaluator_input_ref(&mut self, xref: CircuitRef) {
691        self.evaluator_input_refs.push(xref)
692    }
693
694    fn increment_nonfree_gates(&mut self) {
695        self.num_nonfree_gates += 1;
696    }
697
698    fn get_num_nonfree_gates(&self) -> usize {
699        self.num_nonfree_gates
700    }
701
702    fn get_output_refs(&self) -> &[CircuitRef] {
703        &self.output_refs
704    }
705
706    fn get_garbler_input_refs(&self) -> &[CircuitRef] {
707        &self.garbler_input_refs
708    }
709
710    fn get_evaluator_input_refs(&self) -> &[CircuitRef] {
711        &self.evaluator_input_refs
712    }
713
714    fn garbler_input_mod(&self, i: usize) -> u16 {
715        let r = self.garbler_input_refs[i];
716        r.modulus()
717    }
718
719    fn evaluator_input_mod(&self, i: usize) -> u16 {
720        let r = self.evaluator_input_refs[i];
721        r.modulus()
722    }
723}
724
725impl ArithmeticCircuit {
726    /// Return the modulus of the gate indexed by `i`.
727    #[inline]
728    pub fn modulus(&self, i: usize) -> u16 {
729        self.gate_moduli[i]
730    }
731}
732
733/// CircuitBuilder is used to build circuits.
734pub struct CircuitBuilder<Circuit> {
735    next_ref_ix: usize,
736    next_garbler_input_id: usize,
737    next_evaluator_input_id: usize,
738    const_map: HashMap<(u16, u16), CircuitRef>,
739    circ: Circuit,
740}
741
742impl FancyBinary for CircuitBuilder<BinaryCircuit> {
743    fn xor(&mut self, xref: &Self::Item, yref: &Self::Item) -> Result<Self::Item, Self::Error> {
744        let gate = BinaryGate::Xor {
745            xref: *xref,
746            yref: *yref,
747            out: None,
748        };
749
750        Ok(self.gate(gate, xref.modulus()))
751    }
752
753    fn negate(&mut self, xref: &Self::Item) -> Result<Self::Item, Self::Error> {
754        let gate = BinaryGate::Inv {
755            xref: *xref,
756            out: None,
757        };
758        Ok(self.gate(gate, xref.modulus()))
759    }
760
761    fn and(&mut self, xref: &Self::Item, yref: &Self::Item) -> Result<Self::Item, Self::Error> {
762        let gate = BinaryGate::And {
763            xref: *xref,
764            yref: *yref,
765            id: self.get_next_ciphertext_id(),
766            out: None,
767        };
768
769        Ok(self.gate(gate, xref.modulus()))
770    }
771}
772
773// We can construct an arithmetic circuit out of binary operations
774derive_binary!(CircuitBuilder<ArithmeticCircuit>);
775
776impl FancyArithmetic for CircuitBuilder<ArithmeticCircuit> {
777    fn add(&mut self, xref: &CircuitRef, yref: &CircuitRef) -> Result<CircuitRef, Self::Error> {
778        if xref.modulus() != yref.modulus() {
779            return Err(Self::Error::from(FancyError::UnequalModuli));
780        }
781        let gate = ArithmeticGate::Add {
782            xref: *xref,
783            yref: *yref,
784            out: None,
785        };
786        Ok(self.gate(gate, xref.modulus()))
787    }
788
789    fn sub(&mut self, xref: &CircuitRef, yref: &CircuitRef) -> Result<CircuitRef, Self::Error> {
790        if xref.modulus() != yref.modulus() {
791            return Err(Self::Error::from(FancyError::UnequalModuli));
792        }
793        let gate = ArithmeticGate::Sub {
794            xref: *xref,
795            yref: *yref,
796            out: None,
797        };
798        Ok(self.gate(gate, xref.modulus()))
799    }
800
801    fn cmul(&mut self, xref: &CircuitRef, c: u16) -> Result<CircuitRef, Self::Error> {
802        Ok(self.gate(
803            ArithmeticGate::Cmul {
804                xref: *xref,
805                c,
806                out: None,
807            },
808            xref.modulus(),
809        ))
810    }
811
812    fn proj(
813        &mut self,
814        xref: &CircuitRef,
815        output_modulus: u16,
816        tt: Option<Vec<u16>>,
817    ) -> Result<CircuitRef, Self::Error> {
818        let tt = tt.ok_or_else(|| Self::Error::from(FancyError::NoTruthTable))?;
819        if tt.len() < xref.modulus() as usize || !tt.iter().all(|&x| x < output_modulus) {
820            return Err(Self::Error::from(FancyError::InvalidTruthTable));
821        }
822        let gate = ArithmeticGate::Proj {
823            xref: *xref,
824            tt: tt.to_vec(),
825            id: self.get_next_ciphertext_id(),
826            out: None,
827        };
828        Ok(self.gate(gate, output_modulus))
829    }
830
831    fn mul(&mut self, xref: &CircuitRef, yref: &CircuitRef) -> Result<CircuitRef, Self::Error> {
832        if xref.modulus() < yref.modulus() {
833            return self.mul(yref, xref);
834        }
835
836        let gate = ArithmeticGate::Mul {
837            xref: *xref,
838            yref: *yref,
839            id: self.get_next_ciphertext_id(),
840            out: None,
841        };
842
843        Ok(self.gate(gate, xref.modulus()))
844    }
845}
846
847impl<Circuit: CircuitType> Fancy for CircuitBuilder<Circuit> {
848    type Item = CircuitRef;
849    type Error = CircuitBuilderError;
850
851    fn constant(&mut self, val: u16, modulus: u16) -> Result<CircuitRef, Self::Error> {
852        match self.const_map.get(&(val, modulus)) {
853            Some(&r) => Ok(r),
854            None => {
855                let gate = Circuit::Gate::make_constant(val);
856                let r = self.gate(gate, modulus);
857                self.const_map.insert((val, modulus), r);
858                self.circ.push_const_ref(r);
859                Ok(r)
860            }
861        }
862    }
863
864    fn output(&mut self, xref: &CircuitRef) -> Result<Option<u16>, Self::Error> {
865        println!("output called");
866        self.circ.push_output_ref(*xref);
867        Ok(None)
868    }
869}
870
871impl<Circuit: CircuitType> CircuitBuilder<Circuit> {
872    /// Make a new `CircuitBuilder`.
873    pub fn new() -> Self {
874        CircuitBuilder {
875            next_ref_ix: 0,
876            next_garbler_input_id: 0,
877            next_evaluator_input_id: 0,
878            const_map: HashMap::new(),
879            circ: Circuit::new(None),
880        }
881    }
882
883    /// Finish circuit building, outputting the resulting circuit.
884    pub fn finish(self) -> Circuit {
885        self.circ
886    }
887
888    fn get_next_garbler_input_id(&mut self) -> usize {
889        let current = self.next_garbler_input_id;
890        self.next_garbler_input_id += 1;
891        current
892    }
893
894    fn get_next_evaluator_input_id(&mut self) -> usize {
895        let current = self.next_evaluator_input_id;
896        self.next_evaluator_input_id += 1;
897        current
898    }
899
900    fn get_next_ciphertext_id(&mut self) -> usize {
901        let current = self.circ.get_num_nonfree_gates();
902        self.circ.increment_nonfree_gates();
903        current
904    }
905
906    fn get_next_ref_ix(&mut self) -> usize {
907        let current = self.next_ref_ix;
908        self.next_ref_ix += 1;
909        current
910    }
911
912    fn gate(&mut self, gate: Circuit::Gate, modulus: u16) -> CircuitRef {
913        self.circ.push_gates(gate);
914        self.circ.push_modulus(modulus);
915        let ix = self.get_next_ref_ix();
916        CircuitRef { ix, modulus }
917    }
918
919    /// Get CircuitRef for a garbler input wire.
920    pub fn garbler_input(&mut self, modulus: u16) -> CircuitRef {
921        let id = self.get_next_garbler_input_id();
922        let r = self.gate(Circuit::Gate::make_garbler_input(id), modulus);
923        self.circ.push_garbler_input_ref(r);
924        r
925    }
926
927    /// Get CircuitRef for an evaluator input wire.
928    pub fn evaluator_input(&mut self, modulus: u16) -> CircuitRef {
929        let id = self.get_next_evaluator_input_id();
930        let r = self.gate(Circuit::Gate::make_evaluator_input(id), modulus);
931        self.circ.push_evaluator_input_ref(r);
932        r
933    }
934
935    /// Get a vec of CircuitRefs for garbler inputs.
936    pub fn garbler_inputs(&mut self, mods: &[u16]) -> Vec<CircuitRef> {
937        mods.iter().map(|q| self.garbler_input(*q)).collect()
938    }
939
940    /// Get a vec of CircuitRefs for garbler inputs.
941    pub fn evaluator_inputs(&mut self, mods: &[u16]) -> Vec<CircuitRef> {
942        mods.iter().map(|q| self.evaluator_input(*q)).collect()
943    }
944
945    /// Get a CrtBundle for the garbler using composite modulus Q
946    pub fn crt_garbler_input(&mut self, modulus: u128) -> CrtBundle<CircuitRef> {
947        CrtBundle::new(self.garbler_inputs(&crate::util::factor(modulus)))
948    }
949
950    /// Get a CrtBundle for the evaluator using composite modulus Q
951    pub fn crt_evaluator_input(&mut self, modulus: u128) -> CrtBundle<CircuitRef> {
952        CrtBundle::new(self.evaluator_inputs(&crate::util::factor(modulus)))
953    }
954
955    /// Get a BinaryBundle for the garbler with n bits.
956    pub fn bin_garbler_input(&mut self, nbits: usize) -> BinaryBundle<CircuitRef> {
957        BinaryBundle::new(self.garbler_inputs(&vec![2; nbits]))
958    }
959
960    /// Get a BinaryBundle for the evaluator with n bits.
961    pub fn bin_evaluator_input(&mut self, nbits: usize) -> BinaryBundle<CircuitRef> {
962        BinaryBundle::new(self.evaluator_inputs(&vec![2; nbits]))
963    }
964}
965
966#[cfg(test)]
967mod plaintext {
968    use super::*;
969    use crate::util::RngExt;
970    use itertools::Itertools;
971    use rand::thread_rng;
972
973    #[test] // {{{ and_gate_fan_n
974    fn and_gate_fan_n() {
975        let mut rng = thread_rng();
976
977        let mut b = CircuitBuilder::<BinaryCircuit>::new();
978        let n = 2 + (rng.gen_usize() % 200);
979        let inps = b.evaluator_inputs(&vec![2; n]);
980        let z = b.and_many(&inps).unwrap();
981        b.output(&z).unwrap();
982        let c = b.finish();
983
984        for _ in 0..16 {
985            let mut inps: Vec<u16> = Vec::new();
986            for _ in 0..n {
987                inps.push(rng.gen_bool() as u16);
988            }
989            let res = inps.iter().fold(1, |acc, &x| x & acc);
990            let out = eval_plain(&c, &[], &inps).unwrap()[0];
991            if out != res {
992                println!("{:?} {} {}", inps, out, res);
993                panic!("incorrect output n={}", n);
994            }
995        }
996    }
997    //}}}
998    #[test] // {{{ or_gate_fan_n
999    fn or_gate_fan_n() {
1000        let mut rng = thread_rng();
1001        let mut b: CircuitBuilder<BinaryCircuit> = CircuitBuilder::new();
1002        let n = 2 + (rng.gen_usize() % 200);
1003        let inps = b.evaluator_inputs(&vec![2; n]);
1004        let z = b.or_many(&inps).unwrap();
1005        b.output(&z).unwrap();
1006        let c = b.finish();
1007
1008        for _ in 0..16 {
1009            let mut inps: Vec<u16> = Vec::new();
1010            for _ in 0..n {
1011                inps.push(rng.gen_bool() as u16);
1012            }
1013            let res = inps.iter().fold(0, |acc, &x| x | acc);
1014            let out = eval_plain(&c, &[], &inps).unwrap()[0];
1015            if out != res {
1016                println!("{:?} {} {}", inps, out, res);
1017                panic!();
1018            }
1019        }
1020    }
1021
1022    #[test] // {{{ or_gate_fan_n_arithmetic
1023    fn or_gate_fan_n_arithmetic() {
1024        let mut rng = thread_rng();
1025        let mut b: CircuitBuilder<ArithmeticCircuit> = CircuitBuilder::new();
1026        let n = 2 + (rng.gen_usize() % 200);
1027        let inps = b.evaluator_inputs(&vec![2; n]);
1028        let z = b.or_many(&inps).unwrap();
1029        b.output(&z).unwrap();
1030        let c = b.finish();
1031
1032        for _ in 0..16 {
1033            let mut inps: Vec<u16> = Vec::new();
1034            for _ in 0..n {
1035                inps.push(rng.gen_bool() as u16);
1036            }
1037            let res = inps.iter().fold(0, |acc, &x| x | acc);
1038            let out = eval_plain(&c, &[], &inps).unwrap()[0];
1039            if out != res {
1040                println!("{:?} {} {}", inps, out, res);
1041                panic!();
1042            }
1043        }
1044    }
1045    //}}}
1046    #[test] // {{{ half_gate
1047    fn binary_half_gate() {
1048        let mut rng = thread_rng();
1049        let mut b = CircuitBuilder::<BinaryCircuit>::new();
1050        let q = 2;
1051        let x = b.garbler_input(q);
1052        let y = b.evaluator_input(q);
1053        let z = b.and(&x, &y).unwrap();
1054        b.output(&z).unwrap();
1055        let c = b.finish();
1056        for _ in 0..16 {
1057            let x = rng.gen_u16() % q;
1058            let y = rng.gen_u16() % q;
1059            let out = eval_plain(&c, &[x], &[y]).unwrap();
1060            assert_eq!(out[0], x * y % q);
1061        }
1062    }
1063    #[test] // {{{ half_gate
1064    fn arithmetic_half_gate() {
1065        let mut rng = thread_rng();
1066        let mut b = CircuitBuilder::new();
1067        let q = rng.gen_prime();
1068        let x = b.garbler_input(q);
1069        let y = b.evaluator_input(q);
1070        let z = b.mul(&x, &y).unwrap();
1071        b.output(&z).unwrap();
1072        let c = b.finish();
1073        for _ in 0..16 {
1074            let x = rng.gen_u16() % q;
1075            let y = rng.gen_u16() % q;
1076            let out = eval_plain(&c, &[x], &[y]).unwrap();
1077            assert_eq!(out[0], x * y % q);
1078        }
1079    }
1080    //}}}
1081    #[test] // mod_change {{{
1082    fn mod_change() {
1083        let mut rng = thread_rng();
1084        let mut b = CircuitBuilder::new();
1085        let p = rng.gen_prime();
1086        let q = rng.gen_prime();
1087        let x = b.garbler_input(p);
1088        let y = b.mod_change(&x, q).unwrap();
1089        let z = b.mod_change(&y, p).unwrap();
1090        b.output(&z).unwrap();
1091        let c = b.finish();
1092        for _ in 0..16 {
1093            let x = rng.gen_u16() % p;
1094            let out = eval_plain(&c, &[x], &[]).unwrap();
1095            assert_eq!(out[0], x % q);
1096        }
1097    }
1098    //}}}
1099    #[test] // add_many_mod_change {{{
1100    fn add_many_mod_change() {
1101        let mut b = CircuitBuilder::new();
1102        let n = 113;
1103        let args = b.garbler_inputs(&vec![2; n]);
1104        let wires = args
1105            .iter()
1106            .map(|x| b.mod_change(x, n as u16 + 1).unwrap())
1107            .collect_vec();
1108        let s = b.add_many(&wires).unwrap();
1109        b.output(&s).unwrap();
1110        let c = b.finish();
1111
1112        let mut rng = thread_rng();
1113        for _ in 0..64 {
1114            let inps = (0..c.num_garbler_inputs())
1115                .map(|i| rng.gen_u16() % c.garbler_input_mod(i))
1116                .collect_vec();
1117            let s: u16 = inps.iter().sum();
1118            println!("{:?}, sum={}", inps, s);
1119            let out = eval_plain(&c, &inps, &[]).unwrap();
1120            assert_eq!(out[0], s);
1121        }
1122    }
1123    // }}}
1124    #[test] // constants {{{
1125    fn constants() {
1126        let mut b = CircuitBuilder::new();
1127        let mut rng = thread_rng();
1128
1129        let q = rng.gen_modulus();
1130        let c = rng.gen_u16() % q;
1131
1132        let x = b.evaluator_input(q);
1133        let y = b.constant(c, q).unwrap();
1134        let z = b.add(&x, &y).unwrap();
1135        b.output(&z).unwrap();
1136
1137        let circ = b.finish();
1138
1139        for _ in 0..64 {
1140            let x = rng.gen_u16() % q;
1141            let z = eval_plain(&circ, &[], &[x]).unwrap();
1142            assert_eq!(z[0], (x + c) % q);
1143        }
1144    }
1145    //}}}
1146}
1147
1148#[cfg(test)]
1149mod bundle {
1150    use super::*;
1151    use crate::{
1152        fancy::{ArithmeticBundleGadgets, BinaryGadgets, BundleGadgets, CrtGadgets},
1153        util::{self, RngExt, crt_factor, crt_inv_factor},
1154    };
1155    use itertools::Itertools;
1156    use rand::thread_rng;
1157
1158    #[test] // bundle input and output {{{
1159    fn test_bundle_input_output() {
1160        let mut rng = thread_rng();
1161        let q = rng.gen_usable_composite_modulus();
1162
1163        let mut b = CircuitBuilder::new();
1164        let x = b.crt_garbler_input(q);
1165        println!("{:?} wires", x.wires().len());
1166        b.output_bundle(&x).unwrap();
1167
1168        let c: ArithmeticCircuit = b.finish();
1169
1170        println!("{:?}", c.output_refs);
1171
1172        for _ in 0..16 {
1173            let x = rng.gen_u128() % q;
1174            let res = eval_plain(&c, &crt_factor(x, q), &[]).unwrap();
1175            println!("{:?}", res);
1176            let z = crt_inv_factor(&res, q);
1177            assert_eq!(x, z);
1178        }
1179    }
1180
1181    //}}}
1182    #[test] // bundle addition {{{
1183    fn test_addition() {
1184        let mut rng = thread_rng();
1185        let q = rng.gen_usable_composite_modulus();
1186
1187        let mut b = CircuitBuilder::new();
1188        let x = b.crt_garbler_input(q);
1189        let y = b.crt_evaluator_input(q);
1190        let z = b.crt_add(&x, &y).unwrap();
1191        b.output_bundle(&z).unwrap();
1192        let c = b.finish();
1193
1194        for _ in 0..16 {
1195            let x = rng.gen_u128() % q;
1196            let y = rng.gen_u128() % q;
1197            let res = eval_plain(&c, &crt_factor(x, q), &crt_factor(y, q)).unwrap();
1198            let z = crt_inv_factor(&res, q);
1199            assert_eq!(z, (x + y) % q);
1200        }
1201    }
1202    //}}}
1203    #[test] // bundle subtraction {{{
1204    fn test_subtraction() {
1205        let mut rng = thread_rng();
1206        let q = rng.gen_usable_composite_modulus();
1207
1208        let mut b = CircuitBuilder::new();
1209        let x = b.crt_garbler_input(q);
1210        let y = b.crt_evaluator_input(q);
1211        let z = b.sub_bundles(&x, &y).unwrap();
1212        b.output_bundle(&z).unwrap();
1213        let c = b.finish();
1214
1215        for _ in 0..16 {
1216            let x = rng.gen_u128() % q;
1217            let y = rng.gen_u128() % q;
1218            let res = eval_plain(&c, &crt_factor(x, q), &crt_factor(y, q)).unwrap();
1219            let z = crt_inv_factor(&res, q);
1220            assert_eq!(z, (x + q - y) % q);
1221        }
1222    }
1223    //}}}
1224    #[test] // bundle cmul {{{
1225    fn test_cmul() {
1226        let mut rng = thread_rng();
1227        let q = util::modulus_with_width(16);
1228
1229        let mut b = CircuitBuilder::new();
1230        let x = b.crt_garbler_input(q);
1231        let y = rng.gen_u128() % q;
1232        let z = b.crt_cmul(&x, y).unwrap();
1233        b.output_bundle(&z).unwrap();
1234        let c = b.finish();
1235
1236        for _ in 0..16 {
1237            let x = rng.gen_u128() % q;
1238            let res = eval_plain(&c, &crt_factor(x, q), &[]).unwrap();
1239            let z = crt_inv_factor(&res, q);
1240            assert_eq!(z, (x * y) % q);
1241        }
1242    }
1243    //}}}
1244    #[test] // bundle multiplication {{{
1245    fn test_multiplication() {
1246        let mut rng = thread_rng();
1247        let q = rng.gen_usable_composite_modulus();
1248
1249        let mut b = CircuitBuilder::new();
1250        let x = b.crt_garbler_input(q);
1251        let y = b.crt_evaluator_input(q);
1252        let z = b.mul_bundles(&x, &y).unwrap();
1253        b.output_bundle(&z).unwrap();
1254        let c = b.finish();
1255
1256        for _ in 0..16 {
1257            let x = rng.gen_u64() as u128 % q;
1258            let y = rng.gen_u64() as u128 % q;
1259            let res = eval_plain(&c, &crt_factor(x, q), &crt_factor(y, q)).unwrap();
1260            let z = crt_inv_factor(&res, q);
1261            assert_eq!(z, (x * y) % q);
1262        }
1263    }
1264    // }}}
1265    #[test] // bundle cexp {{{
1266    fn test_cexp() {
1267        let mut rng = thread_rng();
1268        let q = util::modulus_with_width(10);
1269        let y = rng.gen_u16() % 10;
1270
1271        let mut b = CircuitBuilder::new();
1272        let x = b.crt_garbler_input(q);
1273        let z = b.crt_cexp(&x, y).unwrap();
1274        b.output_bundle(&z).unwrap();
1275        let c = b.finish();
1276
1277        for _ in 0..64 {
1278            let x = rng.gen_u16() as u128 % q;
1279            let should_be = x.pow(y as u32) % q;
1280            let res = eval_plain(&c, &crt_factor(x, q), &[]).unwrap();
1281            let z = crt_inv_factor(&res, q);
1282            assert_eq!(z, should_be);
1283        }
1284    }
1285    // }}}
1286    #[test] // bundle remainder {{{
1287    fn test_remainder() {
1288        let mut rng = thread_rng();
1289        let ps = rng.gen_usable_factors();
1290        let q = ps.iter().fold(1, |acc, &x| (x as u128) * acc);
1291        let p = ps[rng.gen_u16() as usize % ps.len()];
1292
1293        let mut b = CircuitBuilder::new();
1294        let x = b.crt_garbler_input(q);
1295        let z = b.crt_rem(&x, p).unwrap();
1296        b.output_bundle(&z).unwrap();
1297        let c = b.finish();
1298
1299        for _ in 0..64 {
1300            let x = rng.gen_u128() % q;
1301            let should_be = x % p as u128;
1302            let res = eval_plain(&c, &crt_factor(x, q), &[]).unwrap();
1303            let z = crt_inv_factor(&res, q);
1304            assert_eq!(z, should_be);
1305        }
1306    }
1307    //}}}
1308    #[test] // bundle equality {{{
1309    fn test_equality() {
1310        let mut rng = thread_rng();
1311        let q = rng.gen_usable_composite_modulus();
1312
1313        let mut b = CircuitBuilder::new();
1314        let x = b.crt_garbler_input(q);
1315        let y = b.crt_evaluator_input(q);
1316        let z = b.eq_bundles(&x, &y).unwrap();
1317        b.output(&z).unwrap();
1318        let c = b.finish();
1319
1320        // lets have at least one test where they are surely equal
1321        let x = rng.gen_u128() % q;
1322        let res = eval_plain(&c, &crt_factor(x, q), &crt_factor(x, q)).unwrap();
1323        assert_eq!(res, &[(x == x) as u16]);
1324
1325        for _ in 0..64 {
1326            let x = rng.gen_u128() % q;
1327            let y = rng.gen_u128() % q;
1328            let res = eval_plain(&c, &crt_factor(x, q), &crt_factor(y, q)).unwrap();
1329            assert_eq!(res, &[(x == y) as u16]);
1330        }
1331    }
1332    //}}}
1333    #[test] // bundle mixed_radix_addition {{{
1334    fn test_mixed_radix_addition() {
1335        let mut rng = thread_rng();
1336
1337        let nargs = 2 + rng.gen_usize() % 100;
1338        let mods = (0..7).map(|_| rng.gen_modulus()).collect_vec();
1339
1340        let mut b = CircuitBuilder::new();
1341        let xs = (0..nargs)
1342            .map(|_| crate::fancy::Bundle::new(b.evaluator_inputs(&mods)))
1343            .collect_vec();
1344        let z = b.mixed_radix_addition(&xs).unwrap();
1345        b.output_bundle(&z).unwrap();
1346        let circ = b.finish();
1347
1348        let Q: u128 = mods.iter().map(|&q| q as u128).product();
1349
1350        // test maximum overflow
1351        let mut ds = Vec::new();
1352        for _ in 0..nargs {
1353            ds.extend(util::as_mixed_radix(Q - 1, &mods).iter());
1354        }
1355        let res = eval_plain(&circ, &[], &ds).unwrap();
1356        assert_eq!(
1357            util::from_mixed_radix(&res, &mods),
1358            (Q - 1) * (nargs as u128) % Q
1359        );
1360
1361        // test random values
1362        for _ in 0..4 {
1363            let mut should_be = 0;
1364            let mut ds = Vec::new();
1365            for _ in 0..nargs {
1366                let x = rng.gen_u128() % Q;
1367                should_be = (should_be + x) % Q;
1368                ds.extend(util::as_mixed_radix(x, &mods).iter());
1369            }
1370            let res = eval_plain(&circ, &[], &ds).unwrap();
1371            assert_eq!(util::from_mixed_radix(&res, &mods), should_be);
1372        }
1373    }
1374    //}}}
1375    #[test] // bundle relu {{{
1376    fn test_relu() {
1377        let mut rng = thread_rng();
1378        let q = util::modulus_with_width(10);
1379        println!("q={}", q);
1380
1381        let mut b = CircuitBuilder::new();
1382        let x = b.crt_garbler_input(q);
1383        let z = b.crt_relu(&x, "100%", None).unwrap();
1384        b.output_bundle(&z).unwrap();
1385        let c = b.finish();
1386
1387        for _ in 0..128 {
1388            let pt = rng.gen_u128() % q;
1389            let should_be = if pt < q / 2 { pt } else { 0 };
1390            let res = eval_plain(&c, &crt_factor(pt, q), &[]).unwrap();
1391            let z = crt_inv_factor(&res, q);
1392            assert_eq!(z, should_be);
1393        }
1394    }
1395    //}}}
1396    #[test] // bundle sgn {{{
1397    fn test_sgn() {
1398        let mut rng = thread_rng();
1399        let q = util::modulus_with_width(10);
1400        println!("q={}", q);
1401
1402        let mut b = CircuitBuilder::new();
1403        let x = b.crt_garbler_input(q);
1404        let z = b.crt_sgn(&x, "100%", None).unwrap();
1405        b.output_bundle(&z).unwrap();
1406        let c = b.finish();
1407
1408        for _ in 0..128 {
1409            let pt = rng.gen_u128() % q;
1410            let should_be = if pt < q / 2 { 1 } else { q - 1 };
1411            let res = eval_plain(&c, &crt_factor(pt, q), &[]).unwrap();
1412            let z = crt_inv_factor(&res, q);
1413            assert_eq!(z, should_be);
1414        }
1415    }
1416    //}}}
1417    #[test] // bundle leq {{{
1418    fn test_leq() {
1419        let mut rng = thread_rng();
1420        let q = util::modulus_with_width(10);
1421
1422        let mut b = CircuitBuilder::new();
1423        let x = b.crt_garbler_input(q);
1424        let y = b.crt_evaluator_input(q);
1425        let z = b.crt_lt(&x, &y, "100%").unwrap();
1426        b.output(&z).unwrap();
1427        let c = b.finish();
1428
1429        // lets have at least one test where they are surely equal
1430        let x = rng.gen_u128() % q / 2;
1431        let res = eval_plain(&c, &crt_factor(x, q), &crt_factor(x, q)).unwrap();
1432        assert_eq!(res, &[(x < x) as u16], "x={}", x);
1433
1434        for _ in 0..64 {
1435            let x = rng.gen_u128() % q / 2;
1436            let y = rng.gen_u128() % q / 2;
1437            let res = eval_plain(&c, &crt_factor(x, q), &crt_factor(y, q)).unwrap();
1438            assert_eq!(res, &[(x < y) as u16], "x={} y={}", x, y);
1439        }
1440    }
1441    //}}}
1442    #[test] // bundle max {{{
1443    fn test_max() {
1444        let mut rng = thread_rng();
1445        let q = util::modulus_with_width(10);
1446        let n = 10;
1447        println!("n={} q={}", n, q);
1448
1449        let mut b = CircuitBuilder::new();
1450        let xs = (0..n).map(|_| b.crt_garbler_input(q)).collect_vec();
1451        let z = b.crt_max(&xs, "100%").unwrap();
1452        b.output_bundle(&z).unwrap();
1453        let c = b.finish();
1454
1455        for _ in 0..16 {
1456            let inps = (0..n).map(|_| rng.gen_u128() % (q / 2)).collect_vec();
1457            println!("{:?}", inps);
1458            let should_be = *inps.iter().max().unwrap();
1459
1460            let enc_inps = inps
1461                .into_iter()
1462                .flat_map(|x| crt_factor(x, q))
1463                .collect_vec();
1464            let res = eval_plain(&c, &enc_inps, &[]).unwrap();
1465            let z = crt_inv_factor(&res, q);
1466            assert_eq!(z, should_be);
1467        }
1468    }
1469    //}}}
1470    #[test] // binary addition {{{
1471    fn test_binary_addition() {
1472        let mut rng = thread_rng();
1473        let n = 2 + (rng.gen_usize() % 10);
1474        let q = 2;
1475        let Q = util::product(&vec![q; n]);
1476        println!("n={} q={} Q={}", n, q, Q);
1477
1478        let mut b = CircuitBuilder::<BinaryCircuit>::new();
1479        let x = b.bin_garbler_input(n);
1480        let y = b.bin_evaluator_input(n);
1481        let (zs, carry) = b.bin_addition(&x, &y).unwrap();
1482        b.output(&carry).unwrap();
1483        b.output_bundle(&zs).unwrap();
1484        let c = b.finish();
1485
1486        for _ in 0..16 {
1487            let x = rng.gen_u128() % Q;
1488            let y = rng.gen_u128() % Q;
1489            println!("x={} y={}", x, y);
1490            let res_should_be = (x + y) % Q;
1491            let carry_should_be = (x + y >= Q) as u16;
1492            let res = eval_plain(&c, &util::u128_to_bits(x, n), &util::u128_to_bits(y, n)).unwrap();
1493            assert_eq!(util::u128_from_bits(&res[1..]), res_should_be);
1494            assert_eq!(res[0], carry_should_be);
1495        }
1496    }
1497    //}}}
1498    #[test] // binary demux {{{
1499    fn test_bin_demux() {
1500        let mut rng = thread_rng();
1501        let nbits = 1 + (rng.gen_usize() % 7);
1502        let Q = 1 << nbits as u128;
1503
1504        let mut b = CircuitBuilder::<BinaryCircuit>::new();
1505        let x = b.bin_garbler_input(nbits);
1506        let d = b.bin_demux(&x).unwrap();
1507        b.outputs(&d).unwrap();
1508        let c = b.finish();
1509
1510        for _ in 0..16 {
1511            let x = rng.gen_u128() % Q;
1512            println!("x={}", x);
1513            let mut should_be = vec![0; Q as usize];
1514            should_be[x as usize] = 1;
1515
1516            let res = eval_plain(&c, &util::u128_to_bits(x, nbits), &[]).unwrap();
1517
1518            for (i, y) in res.into_iter().enumerate() {
1519                if i as u128 == x {
1520                    assert_eq!(y, 1);
1521                } else {
1522                    assert_eq!(y, 0);
1523                }
1524            }
1525        }
1526    }
1527    //}}}
1528}