Skip to main content

primitives/sharing/authenticated/
curve_share.rs

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/// A share of a point on a curve, with its associated MACs and the keys for all
49/// other parties' shares.
50#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
51#[serde(bound = "C: Curve")]
52pub struct PointShare<C: Curve> {
53    pub(crate) value: Point<C>,          // X_i
54    pub(crate) macs: Box<[Point<C>]>,    // {MAC(x_i)_j} ∀j∈[1..n]∖{i}
55    pub(crate) keys: Box<[CurveKey<C>]>, // {(α_ij, β_ij)} ∀j∈[1..n]∖{i}
56}
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        /* NOTE: We assume length equality for macs & keys from this point on */
71        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
122// --------------------
123// |   Verification   |
124// --------------------
125impl<C: Curve> VerifiableWith for PointShare<C> {
126    type VerificationData = ();
127    /// Check the MACs of the share received from another peer.
128    #[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    /// Check the MACs of each share received from all other peers.
142    #[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
157// --------------------------------
158// |   Opening & Reconstruction   |
159// --------------------------------
160
161impl<C: Curve> Reconstructible for PointShare<C> {
162    type Opening = OpenPointShare<C>;
163    type Secret = Point<C>;
164
165    /// Open the share towards another peer.
166    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    /// Open the share towards all other peers.
175    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    /// Reconstruct a secret from openings coming from all other parties.
182    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
198// -------------------------
199// |   Random Generation   |
200// -------------------------
201
202fn 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    /// Generate one random field share per peer, with consistent MACs and keys across all peers.
226    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    /// Generate a random field share, with Macs and keys for all the other parties.
243    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    /// Generate a random field share with a specific secret share as value and random macs & keys.
254    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    /// Secret share a value among n parties, generating an authenticated share for each
273    /// peer with consistent MACs and keys across all peers.
274    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    /// Generate a random field share with a specific secret share as value,
290    /// with consistent random MACs and keys across all peers.
291    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    /// Generate a random field share from its global keys (alphas).
309    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    /// Generate one random field share per peer from their global keys (alphas).
319    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    /// Generate a random field share from its global keys (alphas) and its share
338    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    /// Generate one random field share per peer from their global keys (alphas).
352    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    /// Generate a random field share per peer from a value to secret share and global keys
383    /// (alphas).
384    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// ------------------------------------
408// | Curve Arithmetic Implementations |
409// ------------------------------------
410
411// === Addition === //
412
413#[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// === Subtraction === //
442
443#[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// === Broadcast multiplication === //
472
473#[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// === MulAssign === //
500
501#[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// === Negation === //
522
523#[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
537// === Constant addition / subtraction === //
538
539impl<C: Curve> AddPlaintext for PointShare<C> {
540    type AssociatedInformation = IsFirstPeer;
541
542    /// Adds a public constant to the secret shared value, updating the keys accordingly.
543    /// A designated peer (P_0) will modify its value, while the other peers will update their keys.
544    #[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    /// Adds a public constant to the secret shared value, updating the keys accordingly.
551    /// A designated peer (P_0) will modify its value, while the other peers will update their keys.
552    #[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
564// === Constant time equality / select === //
565
566impl<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    // TODO: Generalize once PairwiseAuthenticatedShare trait is implemented.
603
604    //////////////////////////////////////////////////
605    // CHANGE ONLY THESE TO TEST ANOTHER SHARE TYPE //
606    pub type Value = Point<C>;
607    pub type Constant = Scalar<C>;
608    pub type Share = PointShare<C>;
609    pub type GlobalKey = GlobalCurveKey<C>;
610    //////////////////////////////////////////////////
611
612    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        // Generate a completely random share
631        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        // Generate a share with a specific value
636        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        // Generate a vector of random shares, one per party
648        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        // Secret share a value among n parties
663        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        // Generate n authenticated shares from n global keys (alphas)
679        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(); // Verify all MACs
688
689        // Generate n authenticated shares from a value and n global keys (alphas)
690        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        // Generate n authenticated shares from n unauthenticated shares and n global keys (alphas)
704        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        // Verify each open separately
726        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        // Verify all openings at once
736        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        // &a + &b
752        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        // &a + b
759        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        // a + &b
766        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        // a + b
773        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        // a += &b
780        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        // a += b
787        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        // &a + k
804        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        // a + k
811        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        // a * &k
828        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        // a *= &k
835        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        // &a - &b
854        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        // &a - b
862        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        // a - &b
869        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        // a - b
876        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        // a -= &b
883        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        // a -= b
890        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        // - &a
906        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        // - a
911        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        // Select shares_a
927        let choice = Choice::from(0u8);
928        let selected = Share::conditional_select(&shares_a, &shares_b, choice);
929        assert_eq!(selected, shares_a);
930
931        // Select shares_b
932        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        // Check equality
945        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}