fancy_garbling/wire/
mod2.rs

1use crate::{HasModulus, WireLabel};
2use rand::{CryptoRng, Rng, RngCore};
3use subtle::ConditionallySelectable;
4use vectoreyes::{SimdBase, U8x16};
5
6impl HasModulus for WireMod2 {
7    fn modulus(&self) -> u16 {
8        2
9    }
10}
11
12/// Representation of a `mod-2` wire.
13#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
14#[derive(Debug, Clone, Copy, PartialEq, Default)]
15pub struct WireMod2 {
16    /// A 128-bit value.
17    pub(crate) val: U8x16,
18}
19
20impl core::ops::Add for WireMod2 {
21    type Output = Self;
22
23    #[allow(clippy::suspicious_arithmetic_impl)]
24    fn add(self, rhs: Self) -> Self::Output {
25        Self {
26            val: self.val ^ rhs.val,
27        }
28    }
29}
30
31impl core::ops::AddAssign for WireMod2 {
32    #[allow(clippy::suspicious_op_assign_impl)]
33    fn add_assign(&mut self, rhs: Self) {
34        self.val ^= rhs.val;
35    }
36}
37
38impl core::ops::Sub for WireMod2 {
39    type Output = Self;
40
41    fn sub(self, rhs: Self) -> Self::Output {
42        self + -rhs
43    }
44}
45
46impl core::ops::SubAssign for WireMod2 {
47    fn sub_assign(&mut self, rhs: Self) {
48        *self = *self - rhs;
49    }
50}
51
52impl core::ops::Neg for WireMod2 {
53    type Output = Self;
54
55    fn neg(self) -> Self::Output {
56        // Do nothing. Additive inverse is a no-op for mod 2.
57        self
58    }
59}
60
61impl core::ops::Mul<u16> for WireMod2 {
62    type Output = Self;
63
64    fn mul(self, rhs: u16) -> Self::Output {
65        if rhs & 1 == 0 {
66            Self {
67                val: Default::default(),
68            }
69        } else {
70            self
71        }
72    }
73}
74
75impl core::ops::MulAssign<u16> for WireMod2 {
76    fn mul_assign(&mut self, rhs: u16) {
77        if rhs & 1 == 0 {
78            self.val = Default::default();
79        }
80    }
81}
82
83impl ConditionallySelectable for WireMod2 {
84    fn conditional_select(a: &Self, b: &Self, choice: subtle::Choice) -> Self {
85        WireMod2::from_repr(
86            U8x16::conditional_select(&a.to_repr(), &b.to_repr(), choice),
87            2,
88        )
89    }
90}
91
92impl WireLabel for WireMod2 {
93    fn rand_delta<R: CryptoRng + RngCore>(rng: &mut R, q: u16) -> Self {
94        if q != 2 {
95            panic!("[WireMod2::rand_delta] Expected modulo 2. Got {}", q);
96        }
97        let mut w = Self::rand(rng, q);
98        w.val |= U8x16::set_lo(1);
99        w
100    }
101
102    fn digits(&self) -> Vec<u16> {
103        (0..128)
104            .map(|i| ((u128::from(self.val) >> i) as u16) & 1)
105            .collect()
106    }
107
108    fn to_repr(&self) -> U8x16 {
109        // This function converts a [`WireMod2`] into its [`U8x16`] representation.
110        // Since the value of a [`WireMod2`] is a 128b value, its directly returned
111        // as a [`U8x16`].
112        self.val
113    }
114
115    fn color(&self) -> u16 {
116        // This extracts the least-significant bit of the U8x16.
117        (self.val.extract::<0>() & 1) as u16
118    }
119
120    fn from_repr(inp: U8x16, q: u16) -> Self {
121        // This function converts a Block into its WireLabel representation
122        // by just setting the value of WireMod2 to the Block (i.e. the
123        // wire's 128b value).
124        if q != 2 {
125            panic!("[WireMod2::from_block] Expected modulo 2. Got {}", q);
126        }
127        Self { val: inp }
128    }
129
130    fn zero(q: u16) -> Self {
131        if q != 2 {
132            panic!("[WireMod2::zero] Expected modulo 2. Got {}", q);
133        }
134        Self::default()
135    }
136
137    fn rand<R: CryptoRng + RngCore>(rng: &mut R, q: u16) -> Self {
138        if q != 2 {
139            panic!("[WireMod2::rand] Expected modulo 2. Got {}", q);
140        }
141
142        Self { val: rng.r#gen() }
143    }
144
145    fn hash_to_mod(hash: U8x16, q: u16) -> Self {
146        if q != 2 {
147            panic!("[WireMod2::hash_to_mod] Expected modulo 2. Got {}", q);
148        }
149        Self::from_repr(hash, q)
150    }
151}
152
153#[cfg(test)]
154mod tests {
155    #[cfg(feature = "serde")]
156    #[test]
157    fn test_serialize_mod2() {
158        use crate::{WireLabel, WireMod2};
159        use rand::thread_rng;
160
161        let mut rng = thread_rng();
162        let w = WireMod2::rand(&mut rng, 2);
163        let serialized = serde_json::to_string(&w).unwrap();
164
165        let deserialized: WireMod2 = serde_json::from_str(&serialized).unwrap();
166
167        assert_eq!(w, deserialized);
168    }
169}