fancy_garbling/fancy.rs
1//! Traits for representing specific kinds of garbled circuit computations.
2//!
3//! The core trait of this module is [`Fancy`], which represents the basic set
4//! of operations possible by a garbled circuit. There are also extension
5//! traits, in particular [`FancyBinary`] and [`FancyArithmetic`] that further
6//! extend the core [`Fancy`] trait to provide binary and arithmetic operations,
7//! respectively.
8
9use swanky_channel::Channel;
10use swanky_error::Result;
11
12mod binary;
13mod bundle;
14mod crt;
15pub use binary::{BinaryBundle, BinaryGadgets};
16pub use bundle::Bundle;
17pub use crt::{CrtBundle, CrtGadgets};
18
19/// An object that has a modulus.
20pub trait HasModulus {
21 /// The modulus of the wire.
22 fn modulus(&self) -> u16;
23}
24
25/// The `Fancy` trait is the core trait for writing circuits.
26///
27/// The trait contains an associated type, [`Fancy::Item`], which defines the
28/// underlying wire representation, alongside a [`Fancy::constant`] method for
29/// creating constant (public) wires.
30///
31/// This trait can be further extended to support binary, arithmetic, and/or
32/// projections by using the [`FancyBinary`], [`FancyArithmetic`], or
33/// [`FancyProj`] extension traits, respectively. The [`FancyEncode`] trait
34/// allows for encoding values into wires, and the [`FancyOutput`] trait allows
35/// for converting wires into their underlying plaintext representation.
36pub trait Fancy {
37 /// The underlying wire representation of this [`Fancy`] object.
38 type Item: Clone + core::fmt::Debug + HasModulus;
39
40 /// Encode a constant `x` with modulus `q`.
41 fn constant(&mut self, x: u16, q: u16, channel: &mut Channel) -> Result<Self::Item>;
42}
43
44/// Extension trait for [`Fancy`] that provides encoding and receiving operations.
45pub trait FancyEncode: Fancy {
46 /// Encode many wires for known values.
47 fn encode_many(
48 &mut self,
49 values: &[u16],
50 moduli: &[u16],
51 channel: &mut Channel,
52 ) -> Result<Vec<Self::Item>>;
53
54 /// Receive many wires for unknown values.
55 fn receive_many(&mut self, moduli: &[u16], channel: &mut Channel) -> Result<Vec<Self::Item>>;
56
57 /// Encode a wire for a known value.
58 fn encode(&mut self, value: u16, modulus: u16, channel: &mut Channel) -> Result<Self::Item> {
59 let xs = self.encode_many(&[value], &[modulus], channel)?;
60 Ok(xs[0].clone())
61 }
62
63 /// Receive a wire for an unknown value.
64 fn receive(&mut self, modulus: u16, channel: &mut Channel) -> Result<Self::Item> {
65 let xs = self.receive_many(&[modulus], channel)?;
66 Ok(xs[0].clone())
67 }
68}
69
70/// Extension trait for [`Fancy`] that provides output operations.
71pub trait FancyOutput: Fancy {
72 /// Output the value associated with wire `x`.
73 ///
74 /// Some [`Fancy`] implementers don't actually *return* output, but they
75 /// need to be involved in the process, so they can return `None`.
76 fn output(&mut self, x: &Self::Item, channel: &mut Channel) -> Result<Option<u16>>;
77
78 /// Output the values associated with a slice of wires.
79 ///
80 /// Some [`Fancy`] implementers don't actually *return* output, but they
81 /// need to be involved in the process, so they can return `None`.
82 fn outputs(&mut self, xs: &[Self::Item], channel: &mut Channel) -> Result<Option<Vec<u16>>> {
83 let mut zs = Vec::with_capacity(xs.len());
84 for x in xs.iter() {
85 zs.push(self.output(x, channel)?);
86 }
87 Ok(zs.into_iter().collect())
88 }
89}
90
91/// Extension trait for [`Fancy`] that provides binary operations.
92pub trait FancyBinary: Fancy {
93 /// Binary XOR.
94 fn xor(&mut self, x: &Self::Item, y: &Self::Item) -> Self::Item;
95
96 /// Binary AND.
97 fn and(&mut self, x: &Self::Item, y: &Self::Item, channel: &mut Channel) -> Result<Self::Item>;
98
99 /// Binary negation.
100 fn negate(&mut self, x: &Self::Item) -> Self::Item;
101
102 /// Binary OR.
103 fn or(&mut self, x: &Self::Item, y: &Self::Item, channel: &mut Channel) -> Result<Self::Item> {
104 let notx = self.negate(x);
105 let noty = self.negate(y);
106 let z = self.and(¬x, ¬y, channel)?;
107 Ok(self.negate(&z))
108 }
109}
110
111/// Extension trait for [`Fancy`] that provides arithmetic operations.
112pub trait FancyArithmetic: Fancy {
113 /// Add `x` and `y`.
114 ///
115 /// # Panics
116 /// This panics if `x` and `y` do not have equal moduli.
117 fn add(&mut self, x: &Self::Item, y: &Self::Item) -> Self::Item;
118
119 /// Subtract `x` and `y`.
120 ///
121 /// # Panics
122 /// This panics if `x` and `y` do not have equal moduli.
123 fn sub(&mut self, x: &Self::Item, y: &Self::Item) -> Self::Item;
124
125 /// Multiply `x` with the constant `c`.
126 fn cmul(&mut self, x: &Self::Item, c: u16) -> Self::Item;
127
128 /// Multiply `x` and `y`.
129 fn mul(&mut self, x: &Self::Item, y: &Self::Item, channel: &mut Channel) -> Result<Self::Item>;
130}
131
132/// Extension trait for [`Fancy`] that provides a projection gate, alongside
133/// methods that utilize projection gates.
134///
135/// # Security Warning
136/// In its current form, using projection gates in arithmetic garbling is
137/// **insecure**.
138pub trait FancyProj: Fancy {
139 /// Project `x` according to the truth table `tt`. Resulting wire has
140 /// modulus `q`.
141 ///
142 /// Optional `tt` is useful for hiding the gate from the evaluator.
143 ///
144 /// # Panics
145 /// This may panic in certain implementations if `tt` is `None` when it
146 /// should be `Some`. In addition, it may panic if `tt` is improperly
147 /// formed: either the length of `tt` is smaller than `x`s modulus, or the
148 /// values in `tt` are larger than `q`.
149 fn proj(
150 &mut self,
151 x: &Self::Item,
152 q: u16,
153 tt: Option<Vec<u16>>,
154 channel: &mut Channel,
155 ) -> Result<Self::Item>;
156}
157
158macro_rules! check_binary {
159 ($x:ident) => {
160 assert_eq!($x.modulus(), 2);
161 };
162}
163
164pub(crate) use check_binary;