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};
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/// A share of a point on a curve, with its associated MACs and the keys for all
53/// other parties' shares.
54#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
55#[serde(bound = "C: Curve")]
56pub struct PointShare<C: Curve> {
57    pub(crate) value: Point<C>,          // X_i
58    pub(crate) macs: Box<[Point<C>]>,    // {MAC(x_i)_j} ∀j∈[1..n]∖{i}
59    pub(crate) keys: Box<[CurveKey<C>]>, // {(α_ij, β_ij)} ∀j∈[1..n]∖{i}
60}
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        /* NOTE: We assume length equality for macs & keys from this point on */
75        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
126// --------------------
127// |   Verification   |
128// --------------------
129impl<C: Curve> VerifiableWith for PointShare<C> {
130    type VerificationData = ();
131    /// Check the MACs of the share received from another peer.
132    #[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    /// Check the MACs of each share received from all other peers.
146    #[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
161// --------------------------------
162// |   Opening & Reconstruction   |
163// --------------------------------
164
165impl<C: Curve> Reconstructible for PointShare<C> {
166    type Opening = OpenPointShare<C>;
167    type Secret = Point<C>;
168
169    /// Open the share towards another peer.
170    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    /// Open the share towards all other peers.
179    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    /// Reconstruct a secret from openings coming from all other parties.
186    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
202// -------------------------
203// |   Random Generation   |
204// -------------------------
205
206fn 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    /// Generate one random field share per peer, with consistent MACs and keys across all peers.
230    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    /// Generate a random field share, with Macs and keys for all the other parties.
247    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    /// Generate a random field share with a specific secret share as value and random macs & keys.
258    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    /// Secret share a value among n parties, generating an authenticated share for each
277    /// peer with consistent MACs and keys across all peers.
278    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    /// Generate a random field share with a specific secret share as value,
294    /// with consistent random MACs and keys across all peers.
295    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    /// Generate a random field share from its global keys (alphas).
313    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    /// Generate one random field share per peer from their global keys (alphas).
323    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    /// Generate a random field share from its global keys (alphas) and its share
342    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    /// Generate one random field share per peer from their global keys (alphas).
356    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    /// Generate a random field share per peer from a value to secret share and global keys
387    /// (alphas).
388    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// ------------------------------------
412// | Curve Arithmetic Implementations |
413// ------------------------------------
414
415// === Addition === //
416
417#[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// === Subtraction === //
446
447#[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// === Broadcast multiplication === //
476
477#[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// === MulAssign === //
504
505#[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// === Negation === //
526
527#[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
541// === Constant addition / subtraction === //
542
543impl<C: Curve> AddPlaintext for PointShare<C> {
544    type AssociatedInformation = IsFirstPeer;
545
546    /// Adds a public constant to the secret shared value, updating the keys accordingly.
547    /// A designated peer (P_0) will modify its value, while the other peers will update their keys.
548    #[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    /// Adds a public constant to the secret shared value, updating the keys accordingly.
555    /// A designated peer (P_0) will modify its value, while the other peers will update their keys.
556    #[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
568// === Constant time equality / select === //
569
570impl<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    // TODO: Generalize once PairwiseAuthenticatedShare trait is implemented.
607
608    //////////////////////////////////////////////////
609    // CHANGE ONLY THESE TO TEST ANOTHER SHARE TYPE //
610    pub type Value = Point<C>;
611    pub type Constant = Scalar<C>;
612    pub type Share = PointShare<C>;
613    pub type GlobalKey = GlobalCurveKey<C>;
614    //////////////////////////////////////////////////
615
616    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        // Generate a completely random share
635        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        // Generate a share with a specific value
640        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        // Generate a vector of random shares, one per party
652        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        // Secret share a value among n parties
667        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        // Generate n authenticated shares from n global keys (alphas)
683        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(); // Verify all MACs
692
693        // Generate n authenticated shares from a value and n global keys (alphas)
694        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        // Generate n authenticated shares from n unauthenticated shares and n global keys (alphas)
708        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        // Verify each open separately
730        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        // Verify all openings at once
740        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        // &a + &b
756        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        // &a + b
763        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        // a + &b
770        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        // a + b
777        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        // a += &b
784        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        // a += b
791        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        // &a + k
808        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        // a + k
815        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        // a * &k
832        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        // a *= &k
839        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        // &a - &b
858        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        // &a - b
866        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        // a - &b
873        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        // a - b
880        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        // a -= &b
887        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        // a -= b
894        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        // - &a
910        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        // - a
915        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        // Select shares_a
931        let choice = Choice::from(0u8);
932        let selected = Share::conditional_select(&shares_a, &shares_b, choice);
933        assert_eq!(selected, shares_a);
934
935        // Select shares_b
936        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        // Check equality
949        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}