Skip to main content

primitives/sharing/unauthenticated/
additive_shares.rs

1use std::ops::{Add, SubAssign};
2
3use serde::{de::DeserializeOwned, Serialize};
4
5use crate::{
6    algebra::field::{FieldExtension, SubfieldElement},
7    errors::PrimitiveError,
8    random::{CryptoRngCore, Random},
9    sharing::{PlaintextOps, Reconstructible},
10    types::{Element, HeapArray, PeerIndex, Positive},
11};
12
13/// A trait for additive secret sharing schemes.
14pub trait AdditiveShares:
15    Sized + Clone + Random + for<'a> Add<&'a Self, Output = Self> + for<'s> SubAssign<&'s Self>
16{
17    /// Split a secret into `n` additive shares.
18    fn to_additive_shares(&self, n_parties: usize, mut rng: impl CryptoRngCore) -> Vec<Self> {
19        let mut last_share = self.clone();
20        let mut shares = (0..n_parties - 1)
21            .map(|_| {
22                let share = Self::random(&mut rng);
23                last_share -= &share;
24                share
25            })
26            .collect::<Vec<_>>();
27        shares.push(last_share);
28        shares
29    }
30
31    /// Reconstruct a secret from `n` additive shares.
32    fn from_additive_shares<S: std::borrow::Borrow<Self>>(shares: &[S]) -> Self {
33        let mut shares_iter = shares.iter();
34        let first = shares_iter
35            .next()
36            .expect("At least one share is required for reconstruction.");
37        shares_iter.fold(first.borrow().clone(), |acc, share| acc + share.borrow())
38    }
39}
40
41impl<T: AdditiveShares + Serialize + DeserializeOwned + PartialEq + Send + Sync + 'static>
42    Reconstructible for T
43{
44    type Opening = T;
45    type Value = T;
46
47    fn open_to(&self, _peer_index: PeerIndex) -> Result<Self::Opening, PrimitiveError> {
48        Ok(self.to_owned())
49    }
50
51    fn open_to_all_others(&self) -> impl ExactSizeIterator<Item = Self::Opening> {
52        if true {
53            unimplemented!("No info about number of parties to open to");
54        } else {
55            std::iter::empty()
56        }
57    }
58
59    fn reconstruct(&self, openings: Vec<Self::Opening>) -> Result<Self::Value, PrimitiveError> {
60        Ok(openings
61            .iter()
62            .fold(self.to_owned(), |acc, opening| acc + opening))
63    }
64
65    fn reconstruct_all<S: std::borrow::Borrow<Self>>(
66        shares: Vec<S>,
67    ) -> Result<Self::Value, PrimitiveError> {
68        Ok(Self::from_additive_shares(&shares))
69    }
70}
71
72impl<
73        T: Element
74            + Clone
75            + Random
76            + for<'b> derive_more::SubAssign<&'b T>
77            + for<'b> derive_more::Add<&'b T, Output = T>,
78        M: Positive,
79    > AdditiveShares for HeapArray<T, M>
80{
81}
82
83/// Adding a public constant to an unauthenticated additive share: only the first peer folds the
84/// constant into its share (`x_0 ± c`); every other peer's share is unchanged, so the sum shifts
85/// by exactly `c`.
86impl<F: FieldExtension> PlaintextOps<SubfieldElement<F>> for SubfieldElement<F> {
87    #[inline]
88    fn add_plaintext(self, ptx: &Self, is_first_peer: bool) -> Self {
89        if is_first_peer {
90            self + ptx
91        } else {
92            self
93        }
94    }
95
96    #[inline]
97    fn sub_plaintext(self, ptx: &Self, is_first_peer: bool) -> Self {
98        if is_first_peer {
99            self - ptx
100        } else {
101            self
102        }
103    }
104}