primitives/sharing/
mod.rs1pub mod authenticated;
3pub mod unauthenticated;
4
5use std::{borrow::Borrow, sync::Arc};
6
7pub use authenticated::*;
8use itertools::{enumerate, izip};
9use serde::{de::DeserializeOwned, Serialize};
10use wincode::{SchemaRead, SchemaWrite};
11
12use crate::{
13 algebra::ops::transpose::transpose,
14 errors::PrimitiveError,
15 types::PeerIndex,
16 utils::TakeExact,
17};
18
19pub trait Reconstructible: Sized {
24 type Value: Serialize
26 + DeserializeOwned
27 + for<'de> SchemaRead<'de, Dst = Self::Value>
28 + SchemaWrite<Src = Self::Value>
29 + Clone
30 + PartialEq
31 + Send
32 + Sync
33 + 'static;
34 type Opening: Serialize
36 + DeserializeOwned
37 + for<'de> SchemaRead<'de, Dst = Self::Opening>
38 + SchemaWrite<Src = Self::Opening>
39 + Clone
40 + Send
41 + Sync
42 + 'static;
43
44 fn open_to(&self, peer_index: PeerIndex) -> Result<Self::Opening, PrimitiveError>;
46
47 fn open_to_all_others(&self) -> impl ExactSizeIterator<Item = Self::Opening>;
50
51 fn reconstruct(&self, openings: Vec<Self::Opening>) -> Result<Self::Value, PrimitiveError>;
53
54 fn reconstruct_all<T: Borrow<Self>>(shares: Vec<T>) -> Result<Self::Value, PrimitiveError> {
58 let n_parties = shares.len();
59 if n_parties < 2 {
60 return Err(PrimitiveError::MinimumLength(2, n_parties));
61 }
62 let mut all_openings = shares
64 .iter()
65 .map(|share| share.borrow().open_to_all_others())
66 .collect::<Vec<_>>();
67 enumerate(shares.iter())
69 .map(|(i, share)| {
70 let my_openings = enumerate(all_openings.iter_mut())
71 .take_exact(n_parties)
72 .filter(|(j, _)| i != *j)
73 .map(|(_, opening)| opening.next())
74 .collect::<Option<Vec<_>>>()
75 .ok_or_else(|| PrimitiveError::InvalidPeerIndex(i, shares.len() - 1))?;
76 share.borrow().reconstruct(my_openings)
77 })
78 .reduce(|previous, current| match (previous, current) {
80 (Ok(prev), Ok(curr)) => match prev == curr {
81 true => Ok(prev),
82 false => Err(PrimitiveError::WrongOpening(
83 serde_json::to_string(&prev).unwrap(),
84 serde_json::to_string(&curr).unwrap(),
85 )),
86 },
87 (Err(e), _) | (_, Err(e)) => Err(e),
88 })
89 .unwrap() }
91}
92
93impl<T: Reconstructible<Opening: Clone>> Reconstructible for Vec<T> {
94 type Opening = Vec<T::Opening>;
95 type Value = Vec<T::Value>;
96
97 fn open_to(&self, peer_index: PeerIndex) -> Result<Self::Opening, PrimitiveError> {
98 self.iter().map(|share| share.open_to(peer_index)).collect()
99 }
100
101 fn open_to_all_others(&self) -> impl ExactSizeIterator<Item = Self::Opening> {
102 let all_openings: Vec<Vec<_>> = self
103 .iter()
104 .map(|share| share.open_to_all_others().collect())
105 .collect();
106
107 transpose(all_openings).into_iter()
108 }
109
110 fn reconstruct(&self, openings: Vec<Self::Opening>) -> Result<Self::Value, PrimitiveError> {
111 if openings.is_empty() {
112 return Err(PrimitiveError::MinimumLength(1, 0));
113 }
114
115 if openings[0].len() != self.len() {
116 return Err(PrimitiveError::InvalidParameters(
117 "Number of openings must match number of shares.".to_string(),
118 ));
119 }
120
121 let mut reconstructed = Vec::with_capacity(self.len());
123 for (i, share) in self.iter().enumerate() {
124 let my_openings: Vec<_> = openings
125 .iter()
126 .map(|opening| opening.get(i).cloned())
127 .collect::<Option<Vec<_>>>()
128 .ok_or_else(|| {
129 PrimitiveError::InvalidParameters(
130 "Opening is missing for some share.".to_string(),
131 )
132 })?;
133 reconstructed.push(share.reconstruct(my_openings)?);
134 }
135 Ok(reconstructed)
136 }
137}
138
139impl<T: Reconstructible<Opening: Clone>> Reconstructible for Arc<[T]> {
140 type Opening = Arc<[T::Opening]>;
141 type Value = Arc<[T::Value]>;
142
143 fn open_to(&self, peer_index: PeerIndex) -> Result<Self::Opening, PrimitiveError> {
144 self.iter().map(|share| share.open_to(peer_index)).collect()
145 }
146
147 fn open_to_all_others(&self) -> impl ExactSizeIterator<Item = Self::Opening> {
148 let all_openings: Vec<Vec<_>> = self
149 .iter()
150 .map(|share| share.open_to_all_others().collect())
151 .collect();
152
153 transpose(all_openings)
154 .into_iter()
155 .map(Arc::from)
156 .collect::<Vec<_>>()
157 .into_iter()
158 }
159
160 fn reconstruct(&self, openings: Vec<Self::Opening>) -> Result<Self::Value, PrimitiveError> {
161 if openings.is_empty() {
162 return Err(PrimitiveError::MinimumLength(1, 0));
163 }
164
165 if openings[0].len() != self.len() {
166 return Err(PrimitiveError::InvalidParameters(
167 "Number of openings must match number of shares.".to_string(),
168 ));
169 }
170
171 let mut reconstructed = Vec::with_capacity(self.len());
173 for (i, share) in self.iter().enumerate() {
174 let my_openings: Vec<_> = openings
175 .iter()
176 .map(|opening| opening.get(i).cloned())
177 .collect::<Option<Vec<_>>>()
178 .ok_or_else(|| {
179 PrimitiveError::InvalidParameters(
180 "Opening is missing for some share.".to_string(),
181 )
182 })?;
183 reconstructed.push(share.reconstruct(my_openings)?);
184 }
185
186 Ok(reconstructed.into())
187 }
188}
189
190impl<T: Reconstructible, S: Reconstructible> Reconstructible for (T, S) {
191 type Opening = (T::Opening, S::Opening);
192 type Value = (T::Value, S::Value);
193
194 fn open_to(&self, peer_index: PeerIndex) -> Result<Self::Opening, PrimitiveError> {
195 Ok((self.0.open_to(peer_index)?, self.1.open_to(peer_index)?))
196 }
197
198 fn open_to_all_others(&self) -> impl ExactSizeIterator<Item = Self::Opening> {
199 let all_openings_t: Vec<_> = self.0.open_to_all_others().collect();
200 let all_openings_s: Vec<_> = self.1.open_to_all_others().collect();
201 izip!(all_openings_t, all_openings_s).map(|(o1, o2)| (o1, o2))
202 }
203
204 fn reconstruct(&self, openings: Vec<Self::Opening>) -> Result<Self::Value, PrimitiveError> {
205 let (openings_t, openings_s): (Vec<_>, Vec<_>) = openings.into_iter().unzip();
206 Ok((
207 self.0.reconstruct(openings_t)?,
208 self.1.reconstruct(openings_s)?,
209 ))
210 }
211}
212
213pub trait PlaintextOps: Reconstructible + Clone {
216 fn add_plaintext(self, ptx: &Self::Value, is_first_peer: bool) -> Self;
218
219 fn sub_plaintext(self, ptx: &Self::Value, is_first_peer: bool) -> Self;
221}
222
223#[cfg(test)]
224mod tests {
225 use super::*;
226 use crate::{
227 algebra::elliptic_curve::Curve25519Ristretto,
228 random::Random,
229 sharing::ScalarShares,
230 };
231
232 #[test]
233 fn test_reconstruct_vec() {
234 let n_parties = 3;
235 let mut rng = crate::random::test_rng();
236
237 let scalar_shares: Vec<_> =
238 ScalarShares::<Curve25519Ristretto, typenum::U5>::random_n(&mut rng, n_parties);
239 let scalar_shares = scalar_shares
240 .into_iter()
241 .map(|s| s.into_iter().collect::<Vec<_>>())
242 .collect::<Vec<_>>();
243
244 let reconstructed =
245 Vec::<ScalarShare<Curve25519Ristretto>>::reconstruct_all(scalar_shares.clone())
246 .unwrap();
247 let expected = (0..5)
248 .map(|i| {
249 ScalarShare::<Curve25519Ristretto>::reconstruct_all(
250 scalar_shares.iter().map(|v| v[i].clone()).collect(),
251 )
252 .unwrap()
253 })
254 .collect::<Vec<_>>();
255 assert_eq!(reconstructed, expected);
256 }
257
258 #[test]
259 fn test_reconstruct_tuple() {
260 let n_parties = 3;
261 let mut rng = crate::random::test_rng();
262
263 let scalar_shares: Vec<_> =
264 ScalarShare::<Curve25519Ristretto>::random_n(&mut rng, n_parties);
265 let base_field_shares: Vec<_> =
266 BaseFieldShare::<Curve25519Ristretto>::random_n(&mut rng, n_parties);
267
268 let shares: Vec<(
269 ScalarShare<Curve25519Ristretto>,
270 BaseFieldShare<Curve25519Ristretto>,
271 )> = izip!(&scalar_shares, &base_field_shares)
272 .map(|(s, b)| (s.clone(), b.clone()))
273 .collect();
274
275 let reconstructed = <(
276 ScalarShare<Curve25519Ristretto>,
277 BaseFieldShare<Curve25519Ristretto>,
278 )>::reconstruct_all(shares)
279 .unwrap();
280
281 assert_eq!(
282 reconstructed.0,
283 ScalarShare::<Curve25519Ristretto>::reconstruct_all(scalar_shares).unwrap()
284 );
285 assert_eq!(
286 reconstructed.1,
287 BaseFieldShare::<Curve25519Ristretto>::reconstruct_all(base_field_shares).unwrap()
288 );
289 }
290}