Skip to main content

primitives/sharing/unauthenticated/
additive_shares.rs

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