Skip to main content

fancy_garbling/garble/
binary_and.rs

1use crate::{WireLabel, WireMod2, hash_wires, util::tweak2};
2use fancy_traits::HasModulus;
3use subtle::ConditionallySelectable;
4use vectoreyes::U8x16;
5
6/// The [`BinaryWireLabel`] provides the subroutines to implement AND gates
7/// for the garbler and evaluator in [`fancy_traits::FancyBinary`].
8pub trait BinaryWireLabel: WireLabel + ConditionallySelectable {
9    /// Garbles an 'and' gate given two input wires and the delta.
10    ///
11    /// Outputs a tuple consisting of the two gates (that should be transfered to the evaluator)
12    /// and the next wirelabel for the garbler.
13    fn garble_and_gate(gate_num: usize, A: &Self, B: &Self, delta: &Self) -> (U8x16, U8x16, Self);
14
15    /// Evaluates an 'and' gate given two inputs wires and two half-gates from the garbler.
16    ///
17    /// Outputs C = A & B
18    fn evaluate_and_gate(gate_num: usize, A: &Self, B: &Self, gate0: &U8x16, gate1: &U8x16)
19    -> Self;
20}
21
22impl BinaryWireLabel for WireMod2 {
23    fn garble_and_gate(gate_num: usize, A: &Self, B: &Self, delta: &Self) -> (U8x16, U8x16, Self) {
24        let q = A.modulus();
25        let D = delta;
26
27        let r = B.color(); // secret value known only to the garbler (ev knows r+b)
28
29        let g = tweak2(gate_num as u64, 0);
30
31        // X = H(A+aD) + arD such that a + A.color == 0
32        let alpha = A.color(); // alpha = -A.color
33        let X1 = *A + *D * alpha;
34
35        // Y = H(B + bD) + (b + r)A such that b + B.color == 0
36        let beta = (q - B.color()) % q;
37        let Y1 = *B + *D * beta;
38
39        let AD = *A + *D;
40        let BD = *B + *D;
41
42        // idx is always boolean for binary gates, so it can be represented as a `u8`
43        let a_selector = (A.color() as u8).into();
44        let b_selector = (B.color() as u8).into();
45
46        let B = Self::conditional_select(&BD, B, b_selector);
47        let newA = Self::conditional_select(&AD, A, a_selector);
48        let idx = u8::conditional_select(&(r as u8), &0u8, a_selector);
49
50        let [hashA, hashB, hashX, hashY] = hash_wires([&newA, &B, &X1, &Y1], g);
51
52        let X = Self::hash_to_mod(hashX, q) + *D * (alpha * r % q);
53        let Y = Self::hash_to_mod(hashY, q);
54
55        let gate0 =
56            hashA ^ U8x16::conditional_select(&X.to_repr(), &(X + *D).to_repr(), idx.into());
57        let gate1 = hashB ^ (Y + *A).to_repr();
58
59        (gate0, gate1, X + Y)
60    }
61
62    fn evaluate_and_gate(
63        gate_num: usize,
64        A: &Self,
65        B: &Self,
66        gate0: &U8x16,
67        gate1: &U8x16,
68    ) -> Self {
69        let g = tweak2(gate_num as u64, 0);
70
71        let [hashA, hashB] = hash_wires([A, B], g);
72
73        // garbler's half gate
74        let L = Self::from_repr(
75            U8x16::conditional_select(&hashA, &(hashA ^ *gate0), (A.color() as u8).into()),
76            2,
77        );
78
79        // evaluator's half gate
80        let R = Self::from_repr(
81            U8x16::conditional_select(&hashB, &(hashB ^ *gate1), (B.color() as u8).into()),
82            2,
83        );
84
85        L + R + *A * B.color()
86    }
87}