Skip to main content

fancy_garbling/wire/
mod2.rs

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