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