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