1use std::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign};
2
3use itertools::enumerate;
4use serde::{Deserialize, Serialize};
5use subtle::{Choice, ConstantTimeEq};
6use wincode::{SchemaRead, SchemaWrite};
7
8use super::GlobalCurveKey;
9use crate::{
10 algebra::elliptic_curve::{Curve, Point, Scalar, ScalarAsExtension},
11 errors::PrimitiveError,
12 izip_eq,
13 random::{CryptoRngCore, Random, RandomWith},
14 sharing::{
15 authenticated::NParties,
16 unauthenticated::AdditiveShares,
17 AddPlaintext,
18 CurveKey,
19 GlobalFieldKey,
20 IsFirstPeer,
21 Reconstructible,
22 VerifiableWith,
23 },
24 types::{CollectAll, ConditionallySelectable, PeerIndex},
25 utils::IntoExactSizeIterator,
26};
27
28#[derive(
29 Debug, Copy, Clone, Default, PartialEq, Eq, Serialize, Deserialize, SchemaRead, SchemaWrite,
30)]
31#[serde(bound = "C: Curve")]
32#[repr(C)]
33pub struct OpenPointShare<C: Curve> {
34 pub(crate) value: Point<C>,
35 pub(crate) mac: Point<C>,
36}
37
38impl<C: Curve> OpenPointShare<C> {
39 pub fn new(value: Point<C>, mac: Point<C>) -> Self {
40 Self { value, mac }
41 }
42
43 pub fn get_value(&self) -> &Point<C> {
44 &self.value
45 }
46
47 pub fn get_mac(&self) -> &Point<C> {
48 &self.mac
49 }
50}
51
52#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
55#[serde(bound = "C: Curve")]
56pub struct PointShare<C: Curve> {
57 pub(crate) value: Point<C>, pub(crate) macs: Box<[Point<C>]>, pub(crate) keys: Box<[CurveKey<C>]>, }
61
62impl<C: Curve> PointShare<C> {
63 pub fn try_new(
64 value: Point<C>,
65 macs: Box<[Point<C>]>,
66 keys: Box<[CurveKey<C>]>,
67 ) -> Result<Self, PrimitiveError> {
68 if macs.is_empty() {
69 return Err(PrimitiveError::MinimumLength(2, 0));
70 }
71 if macs.len() != keys.len() {
72 return Err(PrimitiveError::InvalidSize(keys.len(), macs.len()));
73 }
74 Ok(Self { value, macs, keys })
76 }
77
78 fn new(value: Point<C>, macs: Box<[Point<C>]>, keys: Box<[CurveKey<C>]>) -> Self {
79 Self { value, macs, keys }
80 }
81
82 pub fn zero_from_alphas(
83 alphas: impl ExactSizeIterator<Item = GlobalFieldKey<C::Scalar>>,
84 ) -> Self {
85 let n_peers = alphas.len();
86
87 let value = Point::identity();
88 let macs = vec![Point::<C>::identity(); n_peers].into_boxed_slice();
89 let keys = alphas
90 .map(|alpha| CurveKey::new(alpha, Point::identity()))
91 .collect();
92 PointShare::new(value, macs, keys)
93 }
94
95 pub fn get_value(&self) -> &Point<C> {
96 &self.value
97 }
98
99 #[inline]
100 pub fn value(self) -> Point<C> {
101 self.value
102 }
103
104 pub fn get_keys(&self) -> &[CurveKey<C>] {
105 &self.keys
106 }
107
108 pub fn get_key(&self, index: PeerIndex) -> Option<&CurveKey<C>> {
109 self.keys.get(index)
110 }
111
112 pub fn get_macs(&self) -> &[Point<C>] {
113 &self.macs
114 }
115
116 pub fn get_mac(&self, index: PeerIndex) -> Option<&Point<C>> {
117 self.macs.get(index)
118 }
119
120 #[inline]
121 pub fn get_alphas(&self) -> impl ExactSizeIterator<Item = GlobalCurveKey<C>> + '_ {
122 self.keys.iter().map(|key| key.get_alpha())
123 }
124}
125
126impl<C: Curve> VerifiableWith for PointShare<C> {
130 type VerificationData = ();
131 #[inline]
133 fn verify_from_peer_with(
134 &self,
135 open_share: &OpenPointShare<C>,
136 peer: PeerIndex,
137 _verification_data: (),
138 ) -> Result<(), PrimitiveError> {
139 self.get_key(peer)
140 .ok_or(PrimitiveError::InvalidPeerIndex(peer, self.keys.len()))?
141 .verify_mac(open_share)
142 .map_err(|e| e.blame(peer))
143 }
144
145 #[inline]
147 fn verify_with(
148 &self,
149 open_shares: &[OpenPointShare<C>],
150 _verification_data: (),
151 ) -> Result<(), PrimitiveError> {
152 enumerate(izip_eq!(open_shares, &self.keys))
153 .map(|(from_peer, (open_share, key))| {
154 key.verify_mac(open_share).map_err(|e| e.blame(from_peer))
155 })
156 .collect_errors()?;
157 Ok(())
158 }
159}
160
161impl<C: Curve> Reconstructible for PointShare<C> {
166 type Opening = OpenPointShare<C>;
167 type Secret = Point<C>;
168
169 fn open_to(&self, for_peer: PeerIndex) -> Result<OpenPointShare<C>, PrimitiveError> {
171 let mac = self
172 .get_mac(for_peer)
173 .ok_or(PrimitiveError::InvalidPeerIndex(for_peer, self.macs.len()))?
174 .to_owned();
175 Ok(OpenPointShare::new(self.get_value().to_owned(), mac))
176 }
177
178 fn open_to_all_others(&self) -> impl ExactSizeIterator<Item = OpenPointShare<C>> {
180 self.get_macs()
181 .iter()
182 .map(|mac| OpenPointShare::new(self.get_value().to_owned(), mac.to_owned()))
183 }
184
185 fn reconstruct(&self, openings: &[OpenPointShare<C>]) -> Result<Self::Secret, PrimitiveError> {
187 if openings.len() != self.get_keys().len() {
188 return Err(PrimitiveError::InvalidSize(
189 self.get_keys().len(),
190 openings.len(),
191 ));
192 }
193 self.verify_with(openings, ())?;
194 Ok(openings
195 .iter()
196 .fold(self.get_value().to_owned(), |acc, open_share| {
197 acc + open_share.get_value()
198 }))
199 }
200}
201
202fn compute_macs<C: Curve>(
207 all_unauth_shares: &[Point<C>],
208 all_keys: &[Box<[CurveKey<C>]>],
209) -> Vec<Box<[Point<C>]>> {
210 let mut all_key_iters = all_keys.iter().map(|k| k.iter()).collect::<Vec<_>>();
211 enumerate(all_unauth_shares.iter())
212 .map(|(i, my_unauth_share)| {
213 enumerate(all_key_iters.iter_mut())
214 .filter(|(j, _)| *j != i)
215 .map(|(_, keys_iter)| keys_iter.next().unwrap().compute_mac(my_unauth_share))
216 .collect()
217 })
218 .collect()
219}
220
221impl<C: Curve> Random for PointShare<C> {
222 fn random(_rng: impl CryptoRngCore) -> Self {
223 unimplemented!(
224 "Type {} does not support `random` since it needs to know `n_parties`. Use `random_with(..., n_parties)` instead.",
225 std::any::type_name::<Self>()
226 )
227 }
228
229 fn random_n<Container: FromIterator<Self>>(
231 mut rng: impl CryptoRngCore,
232 n_parties: NParties,
233 ) -> Container {
234 let all_unauth_shares: Vec<_> = Point::random_n(&mut rng, n_parties);
235 let all_keys = (0..n_parties)
236 .map(|_| CurveKey::<C>::random_n(&mut rng, n_parties - 1))
237 .collect::<Vec<_>>();
238 let all_macs = compute_macs(&all_unauth_shares, &all_keys);
239 izip_eq!(all_unauth_shares, all_macs, all_keys)
240 .map(|(value, macs, keys)| PointShare { value, macs, keys })
241 .collect()
242 }
243}
244
245impl<C: Curve> RandomWith<NParties> for PointShare<C> {
246 fn random_with(mut rng: impl CryptoRngCore, n_parties: NParties) -> Self {
248 PointShare {
249 value: Point::random(&mut rng),
250 macs: Point::<C>::random_n(&mut rng, n_parties - 1),
251 keys: CurveKey::<C>::random_n(&mut rng, n_parties - 1),
252 }
253 }
254}
255
256impl<C: Curve> RandomWith<(NParties, Point<C>)> for PointShare<C> {
257 fn random_with(mut rng: impl CryptoRngCore, n_parties_value: (NParties, Point<C>)) -> Self {
259 let (n_parties, value) = n_parties_value;
260 PointShare {
261 value,
262 macs: Point::<C>::random_n(&mut rng, n_parties - 1),
263 keys: CurveKey::<C>::random_n(&mut rng, n_parties - 1),
264 }
265 }
266}
267
268impl<C: Curve> RandomWith<Point<C>> for PointShare<C> {
269 fn random_with(_rng: impl CryptoRngCore, _data: Point<C>) -> Self {
270 unimplemented!(
271 "Type {} does not support `random_with` since it needs to know `n_parties`. Use `random_n_with` instead.",
272 std::any::type_name::<Self>()
273 )
274 }
275
276 fn random_n_with<Container: FromIterator<Self>>(
279 mut rng: impl CryptoRngCore,
280 n_parties: NParties,
281 value: Point<C>,
282 ) -> Container {
283 let all_unauth_shares = value.to_additive_shares(n_parties, &mut rng);
284 let all_keys = (0..n_parties)
285 .map(|_| CurveKey::<C>::random_n(&mut rng, n_parties - 1))
286 .collect::<Vec<_>>();
287 let all_macs = compute_macs(&all_unauth_shares, &all_keys);
288 izip_eq!(all_unauth_shares, all_macs, all_keys)
289 .map(|(value, macs, keys)| PointShare { value, macs, keys })
290 .collect()
291 }
292
293 fn random_n_with_each<Container: FromIterator<Self>>(
296 mut rng: impl CryptoRngCore,
297 all_unauth_shares: impl IntoExactSizeIterator<Item = Point<C>>,
298 ) -> Container {
299 let all_unauth_shares = all_unauth_shares.into_iter().collect::<Vec<_>>();
300 let n_parties = all_unauth_shares.len();
301 let all_keys = (0..n_parties)
302 .map(|_| CurveKey::<C>::random_n(&mut rng, n_parties - 1))
303 .collect::<Vec<_>>();
304 let all_macs = compute_macs(&all_unauth_shares, &all_keys);
305 izip_eq!(all_unauth_shares, all_macs, all_keys)
306 .map(|(value, macs, keys)| PointShare { value, macs, keys })
307 .collect()
308 }
309}
310
311impl<C: Curve> RandomWith<Vec<GlobalCurveKey<C>>> for PointShare<C> {
312 fn random_with(mut rng: impl CryptoRngCore, alphas: Vec<GlobalCurveKey<C>>) -> Self {
314 let n_other_parties = alphas.len();
315 PointShare {
316 value: Point::random(&mut rng),
317 macs: Point::<C>::random_n(&mut rng, n_other_parties),
318 keys: CurveKey::<C>::random_n_with_each(&mut rng, alphas),
319 }
320 }
321
322 fn random_n_with_each<Container: FromIterator<Self>>(
324 mut rng: impl CryptoRngCore,
325 all_alphas: impl IntoExactSizeIterator<Item = Vec<GlobalCurveKey<C>>>,
326 ) -> Container {
327 let all_alphas = all_alphas.into_iter();
328 let all_unauth_shares: Vec<_> = Point::random_n(&mut rng, all_alphas.len());
329 let all_keys = all_alphas
330 .into_iter()
331 .map(|my_alphas| CurveKey::<C>::random_n_with_each(&mut rng, my_alphas))
332 .collect::<Vec<_>>();
333 let all_macs = compute_macs(&all_unauth_shares, &all_keys);
334 izip_eq!(all_unauth_shares, all_macs, all_keys)
335 .map(|(value, macs, keys)| PointShare { value, macs, keys })
336 .collect()
337 }
338}
339
340impl<C: Curve> RandomWith<(Point<C>, Vec<GlobalCurveKey<C>>)> for PointShare<C> {
341 fn random_with(
343 mut rng: impl CryptoRngCore,
344 value_alphas: (Point<C>, Vec<GlobalCurveKey<C>>),
345 ) -> Self {
346 let (value, alphas) = value_alphas;
347 let n_other_parties = alphas.len();
348 PointShare {
349 value,
350 macs: Point::<C>::random_n(&mut rng, n_other_parties),
351 keys: CurveKey::<C>::random_n_with_each(&mut rng, alphas),
352 }
353 }
354
355 fn random_n_with_each<Container: FromIterator<Self>>(
357 mut rng: impl CryptoRngCore,
358 unauth_shares_and_alphas: impl IntoIterator<Item = (Point<C>, Vec<GlobalCurveKey<C>>)>,
359 ) -> Container {
360 let (all_unauth_shares, all_keys): (Vec<_>, Vec<_>) = unauth_shares_and_alphas
361 .into_iter()
362 .map(|(value, my_alphas)| {
363 (
364 value,
365 CurveKey::<C>::random_n_with_each(&mut rng, my_alphas),
366 )
367 })
368 .unzip();
369 let all_macs = compute_macs(&all_unauth_shares, &all_keys);
370 izip_eq!(all_unauth_shares, all_macs, all_keys)
371 .map(|(value, macs, keys)| PointShare::new(value, macs, keys))
372 .collect()
373 }
374}
375
376impl<C: Curve> RandomWith<(Point<C>, Vec<Vec<GlobalCurveKey<C>>>)> for PointShare<C> {
377 fn random_with(
378 _source: impl CryptoRngCore,
379 _data: (Point<C>, Vec<Vec<GlobalCurveKey<C>>>),
380 ) -> Self {
381 unimplemented!(
382 "Cannot discern what alpha to use for this peer. Use `random_n_with` instead."
383 );
384 }
385
386 fn random_n_with<Container: FromIterator<Self>>(
389 mut rng: impl CryptoRngCore,
390 n_parties: usize,
391 secret_value_and_alphas: (Point<C>, Vec<Vec<GlobalCurveKey<C>>>),
392 ) -> Container {
393 let (secret_value, all_alphas) = secret_value_and_alphas;
394 assert_eq!(
395 all_alphas.len(),
396 n_parties,
397 "Number of alphas must match the number of parties"
398 );
399 let all_unauth_shares = secret_value.to_additive_shares(all_alphas.len(), &mut rng);
400 let all_keys = all_alphas
401 .into_iter()
402 .map(|my_alphas| CurveKey::<C>::random_n_with_each(&mut rng, my_alphas))
403 .collect::<Vec<_>>();
404 let all_macs = compute_macs(&all_unauth_shares, &all_keys);
405 izip_eq!(all_unauth_shares, all_macs, all_keys)
406 .map(|(value, macs, keys)| PointShare::new(value, macs, keys))
407 .collect()
408 }
409}
410
411#[macros::op_variants(owned, borrowed, flipped_commutative)]
418impl<'a, C: Curve> Add<&'a PointShare<C>> for PointShare<C> {
419 type Output = PointShare<C>;
420
421 #[inline]
422 fn add(self, other: &'a PointShare<C>) -> Self::Output {
423 PointShare {
424 value: self.value + other.value,
425 macs: izip_eq!(self.macs, &other.macs)
426 .map(|(a, b)| a + b)
427 .collect(),
428 keys: izip_eq!(self.keys, &other.keys)
429 .map(|(a, b)| a + b)
430 .collect(),
431 }
432 }
433}
434
435#[macros::op_variants(owned)]
436impl<'a, C: Curve> AddAssign<&'a PointShare<C>> for PointShare<C> {
437 #[inline]
438 fn add_assign(&mut self, other: &'a PointShare<C>) {
439 self.value += other.value;
440 izip_eq!(&mut self.keys, &other.keys).for_each(|(a, b)| *a += b);
441 izip_eq!(&mut self.macs, &other.macs).for_each(|(a, b)| *a += b);
442 }
443}
444
445#[macros::op_variants(owned, borrowed, flipped)]
448impl<'a, C: Curve> Sub<&'a PointShare<C>> for PointShare<C> {
449 type Output = PointShare<C>;
450
451 #[inline]
452 fn sub(self, other: &'a PointShare<C>) -> Self::Output {
453 PointShare {
454 value: self.value - other.value,
455 macs: izip_eq!(self.macs, &other.macs)
456 .map(|(a, b)| a - b)
457 .collect(),
458 keys: izip_eq!(self.keys, &other.keys)
459 .map(|(a, b)| a - b)
460 .collect(),
461 }
462 }
463}
464
465#[macros::op_variants(owned)]
466impl<'a, C: Curve> SubAssign<&'a PointShare<C>> for PointShare<C> {
467 #[inline]
468 fn sub_assign(&mut self, other: &'a PointShare<C>) {
469 self.value -= other.value;
470 izip_eq!(&mut self.keys, &other.keys).for_each(|(a, b)| *a -= b);
471 izip_eq!(&mut self.macs, &other.macs).for_each(|(a, b)| *a -= b);
472 }
473}
474
475#[macros::op_variants(owned, borrowed, flipped)]
478impl<'a, C: Curve> Mul<&'a ScalarAsExtension<C>> for PointShare<C> {
479 type Output = PointShare<C>;
480
481 #[inline]
482 fn mul(mut self, other: &'a ScalarAsExtension<C>) -> Self::Output {
483 self.value *= other;
484 izip_eq!(&mut self.keys).for_each(|key| *key *= other);
485 izip_eq!(&mut self.macs).for_each(|mac| *mac *= other);
486 self
487 }
488}
489
490#[macros::op_variants(owned, borrowed, flipped)]
491impl<'a, C: Curve> Mul<&'a Scalar<C>> for PointShare<C> {
492 type Output = PointShare<C>;
493
494 #[inline]
495 fn mul(mut self, other: &'a Scalar<C>) -> Self::Output {
496 self.value *= other;
497 izip_eq!(&mut self.keys).for_each(|key| *key *= other);
498 izip_eq!(&mut self.macs).for_each(|mac| *mac *= other);
499 self
500 }
501}
502
503#[macros::op_variants(owned)]
506impl<'a, C: Curve> MulAssign<&'a ScalarAsExtension<C>> for PointShare<C> {
507 #[inline]
508 fn mul_assign(&mut self, other: &'a ScalarAsExtension<C>) {
509 self.value *= other;
510 izip_eq!(&mut self.keys).for_each(|key| *key *= other);
511 izip_eq!(&mut self.macs).for_each(|mac| *mac *= other);
512 }
513}
514
515#[macros::op_variants(owned)]
516impl<'a, C: Curve> MulAssign<&'a Scalar<C>> for PointShare<C> {
517 #[inline]
518 fn mul_assign(&mut self, other: &'a Scalar<C>) {
519 self.value *= other;
520 izip_eq!(&mut self.keys).for_each(|key| *key *= other);
521 izip_eq!(&mut self.macs).for_each(|mac| *mac *= other);
522 }
523}
524
525#[macros::op_variants(borrowed)]
528impl<C: Curve> Neg for PointShare<C> {
529 type Output = PointShare<C>;
530
531 #[inline]
532 fn neg(self) -> Self::Output {
533 PointShare {
534 value: -self.value,
535 keys: self.keys.iter().map(|key| -key).collect(),
536 macs: self.macs.iter().map(|mac| -mac).collect(),
537 }
538 }
539}
540
541impl<C: Curve> AddPlaintext for PointShare<C> {
544 type AssociatedInformation = IsFirstPeer;
545
546 #[inline]
549 fn add_plaintext(&self, constant: &Point<C>, is_peer_zero: IsFirstPeer) -> Self {
550 let result = self.clone();
551 result.add_plaintext_owned(constant, is_peer_zero)
552 }
553
554 #[inline]
557 fn add_plaintext_owned(mut self, constant: &Point<C>, is_peer_zero: IsFirstPeer) -> Self {
558 if is_peer_zero {
559 self.value += constant;
560 } else {
561 let key0 = self.keys.get_mut(0).expect("Missing key 0");
562 key0.beta -= *key0.alpha * constant;
563 }
564 self
565 }
566}
567
568impl<C: Curve> ConditionallySelectable for PointShare<C> {
571 fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
572 PointShare {
573 value: Point::conditional_select(&a.value, &b.value, choice),
574 keys: izip_eq!(&a.keys, &b.keys)
575 .map(|(a, b)| CurveKey::conditional_select(a, b, choice))
576 .collect(),
577 macs: izip_eq!(&a.macs, &b.macs)
578 .map(|(a, b)| Point::conditional_select(a, b, choice))
579 .collect(),
580 }
581 }
582}
583
584impl<C: Curve> ConstantTimeEq for PointShare<C> {
585 #[inline]
586 fn ct_eq(&self, other: &Self) -> Choice {
587 self.value.ct_eq(&other.value)
588 & izip_eq!(&self.keys, &other.keys).fold(1.into(), |acc, (self_key, other_key)| {
589 acc & self_key.ct_eq(other_key)
590 })
591 & self.macs.ct_eq(&other.macs)
592 }
593}
594
595#[cfg(test)]
596mod tests {
597 use itertools::enumerate;
598
599 use super::*;
600 use crate::{
601 algebra::elliptic_curve::Curve25519Ristretto as C,
602 random::{self},
603 sharing::Verifiable,
604 };
605
606 pub type Value = Point<C>;
611 pub type Constant = Scalar<C>;
612 pub type Share = PointShare<C>;
613 pub type GlobalKey = GlobalCurveKey<C>;
614 pub const N_PARTIES: usize = 3;
617
618 #[test]
619 fn test_open_to() {
620 let mut rng = random::test_rng();
621 let local_share = Share::random_with(&mut rng, N_PARTIES);
622
623 for i in 0..N_PARTIES - 1 {
624 let open_share = local_share.open_to(i).unwrap();
625 assert_eq!(open_share.get_value(), &local_share.value);
626 assert_eq!(open_share.get_mac(), &local_share.macs[i]);
627 }
628 }
629
630 #[test]
631 fn test_random() {
632 let mut rng = random::test_rng();
633
634 let share = Share::random_with(&mut rng, N_PARTIES);
636 assert_eq!(share.get_macs().len(), N_PARTIES - 1);
637 assert_eq!(share.get_keys().len(), N_PARTIES - 1);
638
639 let value = &Value::random(&mut rng);
641 let share_with_value = Share::random_with(&mut rng, (N_PARTIES, value.to_owned()));
642 assert_eq!(share_with_value.get_value(), value);
643 assert_eq!(share_with_value.get_macs().len(), N_PARTIES - 1);
644 assert_eq!(share_with_value.get_keys().len(), N_PARTIES - 1);
645 }
646
647 #[test]
648 fn test_random_vec_and_reconstruct() {
649 let mut rng = random::test_rng();
650
651 let shares: Vec<_> = Share::random_n(&mut rng, N_PARTIES);
653 assert_eq!(shares.len(), N_PARTIES);
654 for share in &shares {
655 assert_eq!(share.get_macs().len(), N_PARTIES - 1);
656 assert_eq!(share.get_keys().len(), N_PARTIES - 1);
657 }
658 let unauthenticated_shares = shares
659 .iter()
660 .map(|s| s.get_value().to_owned())
661 .collect::<Vec<_>>();
662 let expected = Value::from_additive_shares(&unauthenticated_shares);
663 let reconstructed = Share::reconstruct_all(&shares).unwrap();
664 assert_eq!(reconstructed, expected);
665
666 let value = &Value::random(&mut rng);
668 let shares: Vec<_> = Share::random_n_with(&mut rng, N_PARTIES, value.to_owned());
669 assert_eq!(shares.len(), N_PARTIES);
670 for share in &shares {
671 assert_eq!(share.get_macs().len(), N_PARTIES - 1);
672 assert_eq!(share.get_keys().len(), N_PARTIES - 1);
673 }
674 let reconstructed = Share::reconstruct_all(&shares).unwrap();
675 assert_eq!(reconstructed, value.to_owned());
676 }
677
678 #[test]
679 fn test_random_vec_with_global_key_and_reconstruct() {
680 let mut rng = random::test_rng();
681
682 let alphas = Vec::<Vec<GlobalKey>>::random_with(&mut rng, N_PARTIES);
684 let shares_from_alphas: Vec<_> = Share::random_n_with_each(&mut rng, alphas.clone());
685 assert_eq!(shares_from_alphas.len(), N_PARTIES);
686 for (share_a, my_alphas) in izip_eq!(&shares_from_alphas, alphas) {
687 assert_eq!(share_a.get_macs().len(), N_PARTIES - 1);
688 assert_eq!(share_a.get_keys().len(), N_PARTIES - 1);
689 assert_eq!(share_a.get_alphas().collect::<Vec<_>>(), my_alphas);
690 }
691 Share::verify_all(&shares_from_alphas).unwrap(); let value = &Value::random(&mut rng);
695 let alphas = Vec::<Vec<GlobalKey>>::random_with(&mut rng, N_PARTIES);
696 let shares_from_value_and_alphas: Vec<_> =
697 Share::random_n_with(&mut rng, N_PARTIES, (value.to_owned(), alphas.clone()));
698 assert_eq!(shares_from_value_and_alphas.len(), N_PARTIES);
699 for (share_a, my_alphas) in izip_eq!(&shares_from_value_and_alphas, alphas) {
700 assert_eq!(share_a.get_macs().len(), N_PARTIES - 1);
701 assert_eq!(share_a.get_keys().len(), N_PARTIES - 1);
702 assert_eq!(share_a.get_alphas().collect::<Vec<_>>(), my_alphas);
703 }
704 let reconstructed = Share::reconstruct_all(&shares_from_value_and_alphas).unwrap();
705 assert_eq!(&reconstructed, value);
706
707 let value = Value::random(&mut rng);
709 let unauth_shares = value.to_additive_shares(N_PARTIES, &mut rng);
710 let alphas = Vec::<Vec<GlobalKey>>::random_with(&mut rng, N_PARTIES);
711 let shares_from_unauth_and_alphas: Vec<_> =
712 Share::random_n_with_each(&mut rng, izip_eq!(unauth_shares.clone(), alphas.clone()));
713 assert_eq!(shares_from_unauth_and_alphas.len(), N_PARTIES);
714 for (share_a, my_alphas) in izip_eq!(&shares_from_unauth_and_alphas, alphas) {
715 assert_eq!(share_a.get_macs().len(), N_PARTIES - 1);
716 assert_eq!(share_a.get_keys().len(), N_PARTIES - 1);
717 assert_eq!(share_a.get_alphas().collect::<Vec<_>>(), my_alphas);
718 }
719 let reconstructed = Share::reconstruct_all(&shares_from_unauth_and_alphas).unwrap();
720 assert_eq!(reconstructed, value);
721 }
722
723 #[test]
724 fn test_verify_mac() {
725 let mut rng = random::test_rng();
726
727 let shares: Vec<_> = Share::random_n(&mut rng, N_PARTIES);
728
729 enumerate(shares.iter()).for_each(|(i, s_i)| {
731 enumerate(shares.iter())
732 .filter(|(j, _)| i != *j)
733 .for_each(|(j, s_j)| {
734 let open_share = s_j.open_to(i - (i > j) as usize).unwrap();
735 s_i.verify_from(&open_share, j - (j > i) as usize).unwrap();
736 });
737 });
738
739 Share::verify_all(&shares).unwrap();
741 }
742
743 #[test]
744 fn test_add() {
745 let mut rng = random::test_rng();
746
747 let alphas = Vec::<Vec<GlobalKey>>::random_with(&mut rng, N_PARTIES);
748 let a = &Value::random(&mut rng);
749 let b = &Value::random(&mut rng);
750
751 let shares_a: Vec<_> =
752 Share::random_n_with(&mut rng, N_PARTIES, (a.to_owned(), alphas.clone()));
753 let shares_b: Vec<_> = Share::random_n_with(&mut rng, N_PARTIES, (b.to_owned(), alphas));
754
755 let shares_a_ref_plus_b_ref = izip_eq!(&shares_a, &shares_b)
757 .map(|(share_a, share_b)| share_a + share_b)
758 .collect::<Vec<_>>();
759 let reconstructed = Share::reconstruct_all(&shares_a_ref_plus_b_ref).unwrap();
760 assert_eq!(reconstructed, a + b);
761
762 let shares_a_ref_plus_b = izip_eq!(&shares_a, shares_b.clone())
764 .map(|(share_a, share_b)| share_a + share_b)
765 .collect::<Vec<_>>();
766 let reconstructed = Share::reconstruct_all(&shares_a_ref_plus_b).unwrap();
767 assert_eq!(reconstructed, a + b);
768
769 let shares_a_plus_b_ref = izip_eq!(shares_a.clone(), &shares_b)
771 .map(|(share_a, share_b)| share_a + share_b)
772 .collect::<Vec<_>>();
773 let reconstructed = Share::reconstruct_all(&shares_a_plus_b_ref).unwrap();
774 assert_eq!(reconstructed, a + b);
775
776 let shares_a_plus_b = izip_eq!(shares_a.clone(), shares_b.clone())
778 .map(|(share_a, share_b)| share_a + share_b)
779 .collect::<Vec<_>>();
780 let reconstructed = Share::reconstruct_all(&shares_a_plus_b).unwrap();
781 assert_eq!(reconstructed, a + b);
782
783 let mut shares_a_add_assign_b_ref = shares_a.clone();
785 izip_eq!(&mut shares_a_add_assign_b_ref, &shares_b)
786 .for_each(|(share_a, share_b)| *share_a += share_b);
787 let reconstructed = Share::reconstruct_all(&shares_a_add_assign_b_ref).unwrap();
788 assert_eq!(reconstructed, a + b);
789
790 let mut shares_a_add_assign_b = shares_a.clone();
792 izip_eq!(&mut shares_a_add_assign_b, shares_b)
793 .for_each(|(share_a, share_b)| *share_a += share_b);
794 let reconstructed = Share::reconstruct_all(&shares_a_add_assign_b).unwrap();
795 assert_eq!(reconstructed, a + b);
796 }
797
798 #[test]
799 fn test_add_secret() {
800 let mut rng = random::test_rng();
801
802 let a = &Value::random(&mut rng);
803 let k = &Value::random(&mut rng);
804
805 let shares_a: Vec<_> = Share::random_n_with(&mut rng, N_PARTIES, a.to_owned());
806
807 let shares_a_plus_k_ref = enumerate(shares_a.iter())
809 .map(|(i, share_a)| share_a.add_plaintext(k, i == 0))
810 .collect::<Vec<_>>();
811 let reconstructed = Share::reconstruct_all(&shares_a_plus_k_ref).unwrap();
812 assert_eq!(reconstructed, a + k);
813
814 let shares_a_plus_k = enumerate(shares_a)
816 .map(|(i, share_a)| share_a.add_plaintext_owned(k, i == 0))
817 .collect::<Vec<_>>();
818 let reconstructed = Share::reconstruct_all(&shares_a_plus_k).unwrap();
819 assert_eq!(reconstructed, a + k);
820 }
821
822 #[test]
823 fn test_mul_constant() {
824 let mut rng = random::test_rng();
825
826 let a = &Value::random(&mut rng);
827 let k = &Constant::random(&mut rng);
828
829 let shares_a: Vec<_> = Share::random_n_with(&mut rng, N_PARTIES, a.to_owned());
830
831 let shares_a_times_k = izip_eq!(shares_a.clone())
833 .map(|share_a| share_a * k)
834 .collect::<Vec<_>>();
835 let reconstructed = Share::reconstruct_all(&shares_a_times_k).unwrap();
836 assert_eq!(reconstructed, a * k);
837
838 let mut shares_a_times_k_assign = shares_a.clone();
840 izip_eq!(&mut shares_a_times_k_assign).for_each(|share_a| *share_a *= k);
841 let reconstructed = Share::reconstruct_all(&shares_a_times_k_assign).unwrap();
842 assert_eq!(reconstructed, a * k);
843 }
844
845 #[test]
846 fn test_sub() {
847 let mut rng = random::test_rng();
848 let alphas = Vec::<Vec<GlobalKey>>::random_with(&mut rng, N_PARTIES);
849
850 let a = &Value::random(&mut rng);
851 let b = &Value::random(&mut rng);
852
853 let shares_a: Vec<_> =
854 Share::random_n_with(&mut rng, N_PARTIES, (a.to_owned(), alphas.clone()));
855 let shares_b: Vec<_> = Share::random_n_with(&mut rng, N_PARTIES, (b.to_owned(), alphas));
856
857 let shares_a_ref_minus_b_ref = izip_eq!(&shares_a, &shares_b)
859 .map(|(share_a, share_b)| share_a - share_b)
860 .collect::<Vec<_>>();
861
862 let reconstructed = Share::reconstruct_all(&shares_a_ref_minus_b_ref).unwrap();
863 assert_eq!(reconstructed, a - b);
864
865 let shares_a_ref_minus_b = izip_eq!(&shares_a, shares_b.clone())
867 .map(|(share_a, share_b)| share_a - share_b)
868 .collect::<Vec<_>>();
869 let reconstructed = Share::reconstruct_all(&shares_a_ref_minus_b).unwrap();
870 assert_eq!(reconstructed, a - b);
871
872 let shares_a_minus_b_ref = izip_eq!(shares_a.clone(), &shares_b)
874 .map(|(share_a, share_b)| share_a - share_b)
875 .collect::<Vec<_>>();
876 let reconstructed = Share::reconstruct_all(&shares_a_minus_b_ref).unwrap();
877 assert_eq!(reconstructed, a - b);
878
879 let shares_a_minus_b = izip_eq!(shares_a.clone(), shares_b.clone())
881 .map(|(share_a, share_b)| share_a - share_b)
882 .collect::<Vec<_>>();
883 let reconstructed = Share::reconstruct_all(&shares_a_minus_b).unwrap();
884 assert_eq!(reconstructed, a - b);
885
886 let mut shares_a_sub_assign_b_ref = shares_a.clone();
888 izip_eq!(&mut shares_a_sub_assign_b_ref, &shares_b)
889 .for_each(|(share_a, share_b)| *share_a -= share_b);
890 let reconstructed = Share::reconstruct_all(&shares_a_sub_assign_b_ref).unwrap();
891 assert_eq!(reconstructed, a - b);
892
893 let mut shares_a_sub_assign_b = shares_a.clone();
895 izip_eq!(&mut shares_a_sub_assign_b, shares_b)
896 .for_each(|(share_a, share_b)| *share_a -= share_b);
897 let reconstructed = Share::reconstruct_all(&shares_a_sub_assign_b).unwrap();
898 assert_eq!(reconstructed, a - b);
899 }
900
901 #[test]
902 fn test_neg() {
903 let mut rng = random::test_rng();
904
905 let a = Value::random(&mut rng);
906
907 let shares_a: Vec<_> = Share::random_n_with(&mut rng, N_PARTIES, a.to_owned());
908
909 let shares_a_neg_ref = shares_a.iter().map(|share_a| -share_a).collect::<Vec<_>>();
911 let reconstructed = Share::reconstruct_all(&shares_a_neg_ref).unwrap();
912 assert_eq!(reconstructed, -a.to_owned());
913
914 let shares_a_neg = shares_a
916 .into_iter()
917 .map(|share_a| -share_a)
918 .collect::<Vec<_>>();
919 let reconstructed = Share::reconstruct_all(&shares_a_neg).unwrap();
920 assert_eq!(reconstructed, -a.to_owned());
921 }
922
923 #[test]
924 fn test_conditional_select() {
925 let mut rng = random::test_rng();
926
927 let shares_a = Share::random_with(&mut rng, N_PARTIES);
928 let shares_b = Share::random_with(&mut rng, N_PARTIES);
929
930 let choice = Choice::from(0u8);
932 let selected = Share::conditional_select(&shares_a, &shares_b, choice);
933 assert_eq!(selected, shares_a);
934
935 let choice = Choice::from(1u8);
937 let selected = Share::conditional_select(&shares_a, &shares_b, choice);
938 assert_eq!(selected, shares_b);
939 }
940
941 #[test]
942 fn test_ct_eq() {
943 let mut rng = random::test_rng();
944
945 let shares_a = Share::random_with(&mut rng, N_PARTIES);
946 let shares_b = Share::random_with(&mut rng, N_PARTIES);
947
948 assert!(Into::<bool>::into(shares_a.ct_eq(&shares_a.clone())));
950 assert!(Into::<bool>::into(shares_b.ct_eq(&shares_b.clone())));
951 assert!(!Into::<bool>::into(shares_a.ct_eq(&shares_b)));
952 assert!(!Into::<bool>::into(shares_b.ct_eq(&shares_a)));
953 }
954}