Skip to main content

primitives/sharing/authenticated/pairwise/
mod.rs

1pub mod keys;
2pub mod open_share;
3pub mod share;
4
5use std::any::{Any, TypeId};
6
7pub use keys::*;
8pub use open_share::*;
9pub use share::*;
10
11use crate::{
12    algebra::field::{
13        binary::{Gf2_128, Gf2_128Field},
14        FieldElement,
15        FieldExtension,
16    },
17    random::{BaseRng, Random, RandomWith, Seed, SeedableRng},
18};
19
20/// A trait for secret shares that hold keys for pairwise authentication.
21pub trait PairwiseAuthenticated: RandomWith<Vec<Self::GlobalAuthKey>> {
22    /// Global keys used to authenticate the shares of all other parties.
23    type GlobalAuthKey: Random + Clone + Any;
24
25    /// Get the global keys used to authenticate the shares of every other party.
26    fn get_global_keys(&self) -> impl ExactSizeIterator<Item = Self::GlobalAuthKey>;
27
28    /// Deal global keys used to authenticate the shares of all parties.
29    fn deal_global_keys(
30        n_parties: usize,
31        seed: Seed,
32        compatibility: bool,
33    ) -> Vec<Vec<Self::GlobalAuthKey>> {
34        let rng = if compatibility {
35            BaseRng::from_seed(seed)
36        } else {
37            BaseRng::from_tagged_seed(seed, std::any::type_name::<Self::GlobalAuthKey>())
38        };
39        let mut alphas: Vec<Vec<Self::GlobalAuthKey>> =
40            Vec::<Self::GlobalAuthKey>::random_n_with(rng, n_parties, n_parties - 1);
41        if !compatibility {
42            // Both binary backends get the DPF shape: the bit backend (Gf2_128 keys) and the
43            // Gf2_128Field MPC-field backend, so dealer material stays interchangeable with real
44            // preprocessing. Each call is a no-op unless the key type matches its field.
45            force_binary_lsb_constraint::<Self::GlobalAuthKey, Gf2_128>(&mut alphas, n_parties);
46            force_binary_lsb_constraint::<Self::GlobalAuthKey, Gf2_128Field>(
47                &mut alphas,
48                n_parties,
49            );
50        }
51        alphas
52    }
53}
54
55/// Forces the per-pair invariant DPF/SPFSS requires of binary global MAC keys, if the key type is
56/// `GlobalFieldKey<F>` (no-op otherwise):
57///
58///   lsb(Δ_ij) = 0 if i < j, else 1
59///
60/// where Δ_ij is the key party i holds for party j. This implies the 2-party condition
61/// lsb(Δ_01 ⊕ Δ_10) = 1 and generalizes it for n > 2.
62///
63/// Only valid for char-2 fields: the fix-up flips the low bit by adding one, which is an XOR.
64fn force_binary_lsb_constraint<K: Any, F: FieldExtension>(alphas: &mut [Vec<K>], n_parties: usize) {
65    if TypeId::of::<K>() != TypeId::of::<GlobalFieldKey<F>>() {
66        return;
67    }
68    for (i, alphas_i) in alphas.iter_mut().enumerate() {
69        for j in 0..n_parties {
70            if i == j {
71                continue;
72            }
73            let pos = if j < i { j } else { j - 1 };
74            let target_lsb = u8::from(i > j);
75            let key: &mut GlobalFieldKey<F> = (&mut alphas_i[pos] as &mut dyn Any)
76                .downcast_mut()
77                .expect("TypeId guarantees this cast");
78            let current = key.inner();
79            if current.to_le_bytes()[0] & 1 != target_lsb {
80                *key = GlobalFieldKey::<F>::new(FieldElement::new(current + F::from(1u128)));
81            }
82        }
83    }
84}
85
86#[cfg(test)]
87mod tests {
88    use super::*;
89    use crate::sharing::FieldShare;
90
91    fn assert_lsb_constraint<F: FieldExtension>()
92    where
93        FieldShare<F>: PairwiseAuthenticated<GlobalAuthKey = GlobalFieldKey<F>>,
94    {
95        let n_parties = 4;
96        let seed = Seed::default();
97        let alphas = FieldShare::<F>::deal_global_keys(n_parties, seed, false);
98        for (i, alphas_i) in alphas.iter().enumerate() {
99            for j in 0..n_parties {
100                if i == j {
101                    continue;
102                }
103                let pos = if j < i { j } else { j - 1 };
104                let lsb = alphas_i[pos].inner().to_le_bytes()[0] & 1;
105                assert_eq!(lsb, u8::from(i > j), "lsb(Δ_{i}{j}) violates the DPF shape");
106            }
107        }
108    }
109
110    #[test]
111    fn binary_global_keys_have_dpf_lsb_shape() {
112        assert_lsb_constraint::<Gf2_128>();
113        assert_lsb_constraint::<Gf2_128Field>();
114    }
115}