fancy_garbling/wire.rs
1//! Wirelabels for use in garbled circuits.
2//!
3//! This module contains a [`WireLabel`] trait, alongside various instantiations
4//! of this trait. The [`WireLabel`] trait is the core underlying primitive used
5//! in garbled circuits, and represents an encoding of the value on any given
6//! wire of the circuit.
7
8use crate::util;
9use fancy_traits::HasModulus;
10use rand::CryptoRng;
11use subtle::ConditionallySelectable;
12use swanky_cr_hash::TweakableCircularCorrelationRobustHash;
13use vectoreyes::{
14 U8x16,
15 array_utils::{ArrayUnrolledExt, ArrayUnrolledOps, UnrollableArraySize},
16};
17
18mod all;
19pub use all::AllWire;
20mod mod2;
21pub use mod2::WireMod2;
22mod mod3;
23pub use mod3::WireMod3;
24mod modq;
25pub use modq::WireModQ;
26mod npaths_tab;
27
28/// Hash a batch of wires, using the same tweak for each wire.
29pub fn hash_wires<const Q: usize, W: WireLabel>(wires: [&W; Q], tweak: u128) -> [U8x16; Q]
30where
31 ArrayUnrolledOps: UnrollableArraySize<Q>,
32{
33 let batch = wires.array_map(|x| x.to_repr());
34 TweakableCircularCorrelationRobustHash::fixed_key().hash_many(batch, tweak)
35}
36
37/// A marker trait indicating that the given [`WireLabel`] instantiation
38/// supports arithmetic operations.
39pub trait ArithmeticWireLabel: WireLabel {}
40
41/// The [`BinaryWireLabel`] provides the subroutines to implement AND gates
42/// for the garbler and evaluator in [`fancy_traits::FancyBinary`].
43pub trait BinaryWireLabel: WireLabel + ConditionallySelectable {
44 /// Garbles an 'and' gate given two input wires and the delta.
45 ///
46 /// Outputs a tuple consisting of the two gates (that should be transfered to the evaluator)
47 /// and the next wirelabel for the garbler.
48 fn garble_and_gate(gate_num: usize, A: &Self, B: &Self, delta: &Self) -> (U8x16, U8x16, Self);
49
50 /// Evaluates an 'and' gate given two inputs wires and two half-gates from the garbler.
51 ///
52 /// Outputs C = A & B
53 fn evaluate_and_gate(gate_num: usize, A: &Self, B: &Self, gate0: &U8x16, gate1: &U8x16)
54 -> Self;
55}
56
57/// A trait that defines a wirelabel as used in garbled circuits.
58///
59/// At its core, a [`WireLabel`] is a way of encoding values, and operating on
60/// those encoded values.
61pub trait WireLabel:
62 Clone
63 + core::fmt::Debug
64 + core::default::Default
65 + HasModulus
66 + core::ops::Add<Output = Self>
67 + core::ops::AddAssign
68 + core::ops::Sub<Output = Self>
69 + core::ops::SubAssign
70 + core::ops::Neg<Output = Self>
71 + core::ops::Mul<u16, Output = Self>
72 + core::ops::MulAssign<u16>
73{
74 /// Converts a [`WireLabel`] into its [`U8x16`] representation.
75 fn to_repr(&self) -> U8x16;
76
77 /// The color digit of the wire.
78 fn color(&self) -> u16;
79
80 /// Converts a [`U8x16`] into its [`WireLabel`] representation, based on the
81 /// modulus `q`.
82 ///
83 /// # Panics
84 /// This panics if `q` does not align with the modulus supported by the
85 /// [`WireLabel`].
86 fn from_repr(inp: U8x16, q: u16) -> Self;
87
88 /// A random [`WireLabel`] `mod q`, with the first digit set to `1`.
89 ///
90 /// # Panics
91 /// This panics if `q` does not align with the modulus supported by the
92 /// [`WireLabel`].
93 fn rand_delta<R: CryptoRng>(rng: &mut R, q: u16) -> Self;
94
95 /// A random [`WireLabel`] `mod q`.
96 ///
97 /// # Panics
98 /// This panics if `q` does not align with the modulus supported by the
99 /// [`WireLabel`].
100 fn rand<R: CryptoRng>(rng: &mut R, q: u16) -> Self;
101
102 /// Converts a hashed block into a valid wire of the given modulus `q`.
103 ///
104 /// # Panics
105 /// This panics if `q` does not align with the modulus supported by the
106 /// [`WireLabel`].
107 fn hash_to_mod(hash: U8x16, q: u16) -> Self;
108
109 /// Computes the hash of the [`WireLabel`].
110 fn hash(&self, tweak: u128) -> U8x16 {
111 TweakableCircularCorrelationRobustHash::fixed_key().hash(self.to_repr(), tweak)
112 }
113
114 /// Computes a [`WireLabel`] for `x % q`, returning both the zero
115 /// [`WireLabel`] as well as the [`WireLabel`] for `x % q`.
116 fn constant<RNG: CryptoRng>(x: u16, q: u16, delta: &Self, rng: &mut RNG) -> (Self, Self) {
117 let zero = Self::rand(rng, q);
118 let wire = zero.clone() + delta.clone() * x;
119 (zero, wire)
120 }
121}
122
123fn _unrank(inp: u128, q: u16) -> Vec<u16> {
124 let mut x = inp;
125 let ndigits = util::digits_per_u128(q);
126 let npaths_tab = npaths_tab::lookup(q);
127 x %= npaths_tab[ndigits - 1] * q as u128;
128
129 let mut ds = vec![0; ndigits];
130 for i in (0..ndigits).rev() {
131 let npaths = npaths_tab[i];
132
133 if q <= 23 {
134 // linear search
135 let mut acc = 0;
136 for j in 0..q {
137 acc += npaths;
138 if acc > x {
139 x -= acc - npaths;
140 ds[i] = j;
141 break;
142 }
143 }
144 } else {
145 // naive division
146 let d = x / npaths;
147 ds[i] = d as u16;
148 x -= d * npaths;
149 }
150 // } else {
151 // // binary search
152 // let mut low = 0;
153 // let mut high = q;
154 // loop {
155 // let cur = (low + high) / 2;
156 // let l = npaths * cur as u128;
157 // let r = npaths * (cur as u128 + 1);
158 // if x >= l && x < r {
159 // x -= l;
160 // ds[i] = cur;
161 // break;
162 // }
163 // if x < l {
164 // high = cur;
165 // } else {
166 // // x >= r
167 // low = cur;
168 // }
169 // }
170 // }
171 }
172 ds
173}