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, VerificationError::MissingKey},
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        VerificationError::MissingOpening,
23    },
24    types::{ConditionallySelectable, PeerIndex},
25    utils::IntoExactSizeIterator,
26};
27
28#[derive(Debug, Copy, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
29#[serde(bound = "C: Curve")]
30pub struct OpenPointShare<C: Curve> {
31    pub(crate) value: Point<C>,
32    pub(crate) mac: Point<C>,
33}
34
35impl<C: Curve> OpenPointShare<C> {
36    pub fn new(value: Point<C>, mac: Point<C>) -> Self {
37        Self { value, mac }
38    }
39
40    pub fn get_value(&self) -> &Point<C> {
41        &self.value
42    }
43
44    pub fn get_mac(&self) -> &Point<C> {
45        &self.mac
46    }
47}
48
49/// A share of a point on a curve, with its associated MACs and the keys for all
50/// other parties' shares.
51#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
52#[serde(bound = "C: Curve")]
53pub struct PointShare<C: Curve> {
54    pub(crate) value: Point<C>,          // X_i
55    pub(crate) macs: Box<[Point<C>]>,    // {MAC(x_i)_j} ∀j∈[1..n]∖{i}
56    pub(crate) keys: Box<[CurveKey<C>]>, // {(α_ij, β_ij)} ∀j∈[1..n]∖{i}
57}
58
59impl<C: Curve> PointShare<C> {
60    pub fn try_new(
61        value: Point<C>,
62        macs: Box<[Point<C>]>,
63        keys: Box<[CurveKey<C>]>,
64    ) -> Result<Self, PrimitiveError> {
65        if macs.is_empty() {
66            return Err(PrimitiveError::InvalidParameters(
67                "n_parties < 2".to_string(),
68            ));
69        }
70        if macs.len() != keys.len() {
71            return Err(PrimitiveError::SizeError(macs.len(), keys.len()));
72        }
73        /* NOTE: We assume length equality for macs & keys from this point on */
74        Ok(Self { value, macs, keys })
75    }
76
77    fn new(value: Point<C>, macs: Box<[Point<C>]>, keys: Box<[CurveKey<C>]>) -> Self {
78        Self { value, macs, keys }
79    }
80
81    pub fn zero_from_alphas(
82        alphas: impl ExactSizeIterator<Item = GlobalFieldKey<C::Scalar>>,
83    ) -> Self {
84        let n_peers = alphas.len();
85
86        let value = Point::identity();
87        let macs = vec![Point::<C>::identity(); n_peers].into_boxed_slice();
88        let keys = alphas
89            .map(|alpha| CurveKey::new(alpha, Point::identity()))
90            .collect();
91        PointShare::new(value, macs, keys)
92    }
93
94    pub fn get_value(&self) -> &Point<C> {
95        &self.value
96    }
97
98    #[inline]
99    pub fn value(self) -> Point<C> {
100        self.value
101    }
102
103    pub fn get_keys(&self) -> &[CurveKey<C>] {
104        &self.keys
105    }
106
107    pub fn get_key(&self, index: PeerIndex) -> Option<&CurveKey<C>> {
108        self.keys.get(index)
109    }
110
111    pub fn get_macs(&self) -> &[Point<C>] {
112        &self.macs
113    }
114
115    pub fn get_mac(&self, index: PeerIndex) -> Option<&Point<C>> {
116        self.macs.get(index)
117    }
118
119    #[inline]
120    pub fn get_alphas(&self) -> impl ExactSizeIterator<Item = GlobalCurveKey<C>> + '_ {
121        self.keys.iter().map(|key| key.get_alpha())
122    }
123}
124
125// --------------------
126// |   Verification   |
127// --------------------
128impl<C: Curve> VerifiableWith for PointShare<C> {
129    type VerificationData = ();
130    /// Check the MACs of the share received from another peer.
131    #[inline]
132    fn verify_from_peer_with(
133        &self,
134        open_share: &OpenPointShare<C>,
135        from_peer: PeerIndex,
136        _verification_data: (),
137    ) -> Result<(), PrimitiveError> {
138        self.get_key(from_peer)
139            .ok_or(MissingKey(from_peer))?
140            .verify_mac(open_share)
141            .map_err(|e| e.blame(from_peer).add_state(self))
142    }
143
144    /// Check the MACs of each share received from all other peers.
145    #[inline]
146    fn verify_with(
147        &self,
148        open_shares: &[OpenPointShare<C>],
149        _verification_data: (),
150    ) -> Result<(), PrimitiveError> {
151        izip_eq!(open_shares, &self.keys).enumerate().try_for_each(
152            |(from_peer, (open_share, key))| {
153                key.verify_mac(open_share)
154                    .map_err(|e| e.blame(from_peer).add_state(self))
155            },
156        )
157    }
158}
159
160// --------------------------------
161// |   Opening & Reconstruction   |
162// --------------------------------
163
164impl<C: Curve> Reconstructible for PointShare<C> {
165    type Opening = OpenPointShare<C>;
166    type Secret = Point<C>;
167
168    /// Open the share towards another peer.
169    fn open_to(&self, for_peer: PeerIndex) -> Result<OpenPointShare<C>, PrimitiveError> {
170        let mac = self
171            .get_mac(for_peer)
172            .ok_or(MissingOpening(for_peer))?
173            .to_owned();
174        Ok(OpenPointShare::new(self.get_value().to_owned(), mac))
175    }
176
177    /// Open the share towards all other peers.
178    fn open_to_all_others(&self) -> impl ExactSizeIterator<Item = OpenPointShare<C>> {
179        self.get_macs()
180            .iter()
181            .map(|mac| OpenPointShare::new(self.get_value().to_owned(), mac.to_owned()))
182    }
183
184    /// Reconstruct a secret from openings coming from all other parties.
185    fn reconstruct(&self, openings: &[OpenPointShare<C>]) -> Result<Self::Secret, PrimitiveError> {
186        if openings.len() != self.get_keys().len() {
187            return Err(PrimitiveError::SizeError(
188                openings.len(),
189                self.get_keys().len(),
190            ));
191        }
192
193        izip_eq!(openings, self.get_keys()).enumerate().try_fold(
194            self.get_value().to_owned(),
195            |acc, (i, (open_share, key))| {
196                key.verify_mac(open_share)
197                    .map_err(|e| e.blame(i).add_state(self))?;
198                Ok(acc + open_share.get_value())
199            },
200        )
201    }
202}
203
204// -------------------------
205// |   Random Generation   |
206// -------------------------
207
208fn compute_macs<C: Curve>(
209    all_unauth_shares: &[Point<C>],
210    all_keys: &[Box<[CurveKey<C>]>],
211) -> Vec<Box<[Point<C>]>> {
212    let mut all_key_iters = all_keys.iter().map(|k| k.iter()).collect::<Vec<_>>();
213    enumerate(all_unauth_shares.iter())
214        .map(|(i, my_unauth_share)| {
215            enumerate(all_key_iters.iter_mut())
216                .filter(|(j, _)| *j != i)
217                .map(|(_, keys_iter)| keys_iter.next().unwrap().compute_mac(my_unauth_share))
218                .collect()
219        })
220        .collect()
221}
222
223impl<C: Curve> Random for PointShare<C> {
224    fn random(_rng: impl CryptoRngCore) -> Self {
225        unimplemented!(
226            "Type {} does not support `random` since it needs to know `n_parties`. Use `random_with(..., n_parties)` instead.",
227            std::any::type_name::<Self>()
228        )
229    }
230
231    /// Generate one random field share per peer, with consistent MACs and keys across all peers.
232    fn random_n<Container: FromIterator<Self>>(
233        mut rng: impl CryptoRngCore,
234        n_parties: NParties,
235    ) -> Container {
236        let all_unauth_shares: Vec<_> = Point::random_n(&mut rng, n_parties);
237        let all_keys = (0..n_parties)
238            .map(|_| CurveKey::<C>::random_n(&mut rng, n_parties - 1))
239            .collect::<Vec<_>>();
240        let all_macs = compute_macs(&all_unauth_shares, &all_keys);
241        izip_eq!(all_unauth_shares, all_macs, all_keys)
242            .map(|(value, macs, keys)| PointShare { value, macs, keys })
243            .collect()
244    }
245}
246
247impl<C: Curve> RandomWith<NParties> for PointShare<C> {
248    /// Generate a random field share, with Macs and keys for all the other parties.
249    fn random_with(mut rng: impl CryptoRngCore, n_parties: NParties) -> Self {
250        PointShare {
251            value: Point::random(&mut rng),
252            macs: Point::<C>::random_n(&mut rng, n_parties - 1),
253            keys: CurveKey::<C>::random_n(&mut rng, n_parties - 1),
254        }
255    }
256}
257
258impl<C: Curve> RandomWith<(NParties, Point<C>)> for PointShare<C> {
259    /// Generate a random field share with a specific secret share as value and random macs & keys.
260    fn random_with(mut rng: impl CryptoRngCore, n_parties_value: (NParties, Point<C>)) -> Self {
261        let (n_parties, value) = n_parties_value;
262        PointShare {
263            value,
264            macs: Point::<C>::random_n(&mut rng, n_parties - 1),
265            keys: CurveKey::<C>::random_n(&mut rng, n_parties - 1),
266        }
267    }
268}
269
270impl<C: Curve> RandomWith<Point<C>> for PointShare<C> {
271    fn random_with(_rng: impl CryptoRngCore, _data: Point<C>) -> Self {
272        unimplemented!(
273            "Type {} does not support `random_with` since it needs to know `n_parties`. Use `random_n_with` instead.",
274            std::any::type_name::<Self>()
275        )
276    }
277
278    /// Secret share a value among n parties, generating an authenticated share for each
279    /// peer with consistent MACs and keys across all peers.
280    fn random_n_with<Container: FromIterator<Self>>(
281        mut rng: impl CryptoRngCore,
282        n_parties: NParties,
283        value: Point<C>,
284    ) -> Container {
285        let all_unauth_shares = value.to_additive_shares(n_parties, &mut rng);
286        let all_keys = (0..n_parties)
287            .map(|_| CurveKey::<C>::random_n(&mut rng, n_parties - 1))
288            .collect::<Vec<_>>();
289        let all_macs = compute_macs(&all_unauth_shares, &all_keys);
290        izip_eq!(all_unauth_shares, all_macs, all_keys)
291            .map(|(value, macs, keys)| PointShare { value, macs, keys })
292            .collect()
293    }
294
295    /// Generate a random field share with a specific secret share as value,
296    /// with consistent random MACs and keys across all peers.
297    fn random_n_with_each<Container: FromIterator<Self>>(
298        mut rng: impl CryptoRngCore,
299        all_unauth_shares: impl IntoExactSizeIterator<Item = Point<C>>,
300    ) -> Container {
301        let all_unauth_shares = all_unauth_shares.into_iter().collect::<Vec<_>>();
302        let n_parties = all_unauth_shares.len();
303        let all_keys = (0..n_parties)
304            .map(|_| CurveKey::<C>::random_n(&mut rng, n_parties - 1))
305            .collect::<Vec<_>>();
306        let all_macs = compute_macs(&all_unauth_shares, &all_keys);
307        izip_eq!(all_unauth_shares, all_macs, all_keys)
308            .map(|(value, macs, keys)| PointShare { value, macs, keys })
309            .collect()
310    }
311}
312
313impl<C: Curve> RandomWith<Vec<GlobalCurveKey<C>>> for PointShare<C> {
314    /// Generate a random field share from its global keys (alphas).
315    fn random_with(mut rng: impl CryptoRngCore, alphas: Vec<GlobalCurveKey<C>>) -> Self {
316        let n_other_parties = alphas.len();
317        PointShare {
318            value: Point::random(&mut rng),
319            macs: Point::<C>::random_n(&mut rng, n_other_parties),
320            keys: CurveKey::<C>::random_n_with_each(&mut rng, alphas),
321        }
322    }
323
324    /// Generate one random field share per peer from their global keys (alphas).
325    fn random_n_with_each<Container: FromIterator<Self>>(
326        mut rng: impl CryptoRngCore,
327        all_alphas: impl IntoExactSizeIterator<Item = Vec<GlobalCurveKey<C>>>,
328    ) -> Container {
329        let all_alphas = all_alphas.into_iter();
330        let all_unauth_shares: Vec<_> = Point::random_n(&mut rng, all_alphas.len());
331        let all_keys = all_alphas
332            .into_iter()
333            .map(|my_alphas| CurveKey::<C>::random_n_with_each(&mut rng, my_alphas))
334            .collect::<Vec<_>>();
335        let all_macs = compute_macs(&all_unauth_shares, &all_keys);
336        izip_eq!(all_unauth_shares, all_macs, all_keys)
337            .map(|(value, macs, keys)| PointShare { value, macs, keys })
338            .collect()
339    }
340}
341
342impl<C: Curve> RandomWith<(Point<C>, Vec<GlobalCurveKey<C>>)> for PointShare<C> {
343    /// Generate a random field share from its global keys (alphas) and its share
344    fn random_with(
345        mut rng: impl CryptoRngCore,
346        value_alphas: (Point<C>, Vec<GlobalCurveKey<C>>),
347    ) -> Self {
348        let (value, alphas) = value_alphas;
349        let n_other_parties = alphas.len();
350        PointShare {
351            value,
352            macs: Point::<C>::random_n(&mut rng, n_other_parties),
353            keys: CurveKey::<C>::random_n_with_each(&mut rng, alphas),
354        }
355    }
356
357    /// Generate one random field share per peer from their global keys (alphas).
358    fn random_n_with_each<Container: FromIterator<Self>>(
359        mut rng: impl CryptoRngCore,
360        unauth_shares_and_alphas: impl IntoIterator<Item = (Point<C>, Vec<GlobalCurveKey<C>>)>,
361    ) -> Container {
362        let (all_unauth_shares, all_keys): (Vec<_>, Vec<_>) = unauth_shares_and_alphas
363            .into_iter()
364            .map(|(value, my_alphas)| {
365                (
366                    value,
367                    CurveKey::<C>::random_n_with_each(&mut rng, my_alphas),
368                )
369            })
370            .unzip();
371        let all_macs = compute_macs(&all_unauth_shares, &all_keys);
372        izip_eq!(all_unauth_shares, all_macs, all_keys)
373            .map(|(value, macs, keys)| PointShare::new(value, macs, keys))
374            .collect()
375    }
376}
377
378impl<C: Curve> RandomWith<(Point<C>, Vec<Vec<GlobalCurveKey<C>>>)> for PointShare<C> {
379    fn random_with(
380        _source: impl CryptoRngCore,
381        _data: (Point<C>, Vec<Vec<GlobalCurveKey<C>>>),
382    ) -> Self {
383        unimplemented!(
384            "Cannot discern what alpha to use for this peer. Use `random_n_with` instead."
385        );
386    }
387
388    /// Generate a random field share per peer from a value to secret share and global keys
389    /// (alphas).
390    fn random_n_with<Container: FromIterator<Self>>(
391        mut rng: impl CryptoRngCore,
392        n_parties: usize,
393        secret_value_and_alphas: (Point<C>, Vec<Vec<GlobalCurveKey<C>>>),
394    ) -> Container {
395        let (secret_value, all_alphas) = secret_value_and_alphas;
396        assert_eq!(
397            all_alphas.len(),
398            n_parties,
399            "Number of alphas must match the number of parties"
400        );
401        let all_unauth_shares = secret_value.to_additive_shares(all_alphas.len(), &mut rng);
402        let all_keys = all_alphas
403            .into_iter()
404            .map(|my_alphas| CurveKey::<C>::random_n_with_each(&mut rng, my_alphas))
405            .collect::<Vec<_>>();
406        let all_macs = compute_macs(&all_unauth_shares, &all_keys);
407        izip_eq!(all_unauth_shares, all_macs, all_keys)
408            .map(|(value, macs, keys)| PointShare::new(value, macs, keys))
409            .collect()
410    }
411}
412
413// ------------------------------------
414// | Curve Arithmetic Implementations |
415// ------------------------------------
416
417// === Addition === //
418
419impl<C: Curve> Add for PointShare<C> {
420    type Output = PointShare<C>;
421
422    #[inline]
423    fn add(self, other: PointShare<C>) -> Self::Output {
424        PointShare {
425            value: self.value + other.value,
426            keys: izip_eq!(self.keys, other.keys)
427                .map(|(a, b)| a + b)
428                .collect(),
429            macs: izip_eq!(self.macs, other.macs)
430                .map(|(a, b)| a + b)
431                .collect(),
432        }
433    }
434}
435
436impl<'a, C: Curve> Add for &'a PointShare<C> {
437    type Output = PointShare<C>;
438
439    #[inline]
440    fn add(self, other: &'a PointShare<C>) -> Self::Output {
441        PointShare {
442            value: self.value + other.value,
443            macs: izip_eq!(&self.macs, &other.macs)
444                .map(|(a, b)| a + b)
445                .collect(),
446            keys: izip_eq!(&self.keys, &other.keys)
447                .map(|(a, b)| a + b)
448                .collect(),
449        }
450    }
451}
452
453impl<C: Curve> Add<PointShare<C>> for &PointShare<C> {
454    type Output = PointShare<C>;
455
456    #[inline]
457    fn add(self, other: PointShare<C>) -> Self::Output {
458        PointShare {
459            value: self.value + other.value,
460            macs: izip_eq!(&self.macs, other.macs)
461                .map(|(a, b)| a + b)
462                .collect(),
463            keys: izip_eq!(&self.keys, other.keys)
464                .map(|(a, b)| a + b)
465                .collect(),
466        }
467    }
468}
469
470impl<'a, C: Curve> Add<&'a PointShare<C>> for PointShare<C> {
471    type Output = PointShare<C>;
472
473    #[inline]
474    fn add(self, other: &'a PointShare<C>) -> Self::Output {
475        PointShare {
476            value: self.value + other.value,
477            macs: izip_eq!(self.macs, &other.macs)
478                .map(|(a, b)| a + b)
479                .collect(),
480            keys: izip_eq!(self.keys, &other.keys)
481                .map(|(a, b)| a + b)
482                .collect(),
483        }
484    }
485}
486
487// === AddAssign === //
488
489impl<C: Curve> AddAssign for PointShare<C> {
490    #[inline]
491    fn add_assign(&mut self, other: Self) {
492        self.value += other.value;
493        izip_eq!(&mut self.keys, other.keys).for_each(|(a, b)| *a += b);
494        izip_eq!(&mut self.macs, other.macs).for_each(|(a, b)| *a += b);
495    }
496}
497
498impl<'a, C: Curve> AddAssign<&'a PointShare<C>> for PointShare<C> {
499    #[inline]
500    fn add_assign(&mut self, other: &'a PointShare<C>) {
501        self.value += other.value;
502        izip_eq!(&mut self.keys, &other.keys).for_each(|(a, b)| *a += b);
503        izip_eq!(&mut self.macs, &other.macs).for_each(|(a, b)| *a += b);
504    }
505}
506
507// === Subtraction === //
508
509impl<C: Curve> Sub for PointShare<C> {
510    type Output = PointShare<C>;
511
512    #[inline]
513    fn sub(self, other: PointShare<C>) -> Self::Output {
514        PointShare {
515            value: self.value - other.value,
516            macs: izip_eq!(self.macs, other.macs)
517                .map(|(a, b)| a - b)
518                .collect(),
519            keys: izip_eq!(self.keys, other.keys)
520                .map(|(a, b)| a - b)
521                .collect(),
522        }
523    }
524}
525
526impl<'a, C: Curve> Sub<&'a PointShare<C>> for &'a PointShare<C> {
527    type Output = PointShare<C>;
528
529    #[inline]
530    fn sub(self, other: &'a PointShare<C>) -> Self::Output {
531        PointShare {
532            value: self.value - other.value,
533            macs: izip_eq!(&self.macs, &other.macs)
534                .map(|(a, b)| a - b)
535                .collect(),
536            keys: izip_eq!(&self.keys, &other.keys)
537                .map(|(a, b)| a - b)
538                .collect(),
539        }
540    }
541}
542
543impl<C: Curve> Sub<PointShare<C>> for &PointShare<C> {
544    type Output = PointShare<C>;
545
546    #[inline]
547    fn sub(self, other: PointShare<C>) -> Self::Output {
548        PointShare {
549            value: self.value - other.value,
550            macs: izip_eq!(&self.macs, other.macs)
551                .map(|(a, b)| a - b)
552                .collect(),
553            keys: izip_eq!(&self.keys, other.keys)
554                .map(|(a, b)| a - b)
555                .collect(),
556        }
557    }
558}
559
560impl<'a, C: Curve> Sub<&'a PointShare<C>> for PointShare<C> {
561    type Output = PointShare<C>;
562
563    #[inline]
564    fn sub(self, other: &'a PointShare<C>) -> Self::Output {
565        PointShare {
566            value: self.value - other.value,
567            macs: izip_eq!(self.macs, &other.macs)
568                .map(|(a, b)| a - b)
569                .collect(),
570            keys: izip_eq!(self.keys, &other.keys)
571                .map(|(a, b)| a - b)
572                .collect(),
573        }
574    }
575}
576// === SubAssign === //
577
578impl<C: Curve> SubAssign for PointShare<C> {
579    #[inline]
580    fn sub_assign(&mut self, other: Self) {
581        self.value -= other.value;
582        izip_eq!(&mut self.keys, other.keys).for_each(|(a, b)| *a -= b);
583        izip_eq!(&mut self.macs, other.macs).for_each(|(a, b)| *a -= b);
584    }
585}
586
587impl<'a, C: Curve> SubAssign<&'a PointShare<C>> for PointShare<C> {
588    #[inline]
589    fn sub_assign(&mut self, other: &'a PointShare<C>) {
590        self.value -= other.value;
591        izip_eq!(&mut self.keys, &other.keys).for_each(|(a, b)| *a -= b);
592        izip_eq!(&mut self.macs, &other.macs).for_each(|(a, b)| *a -= b);
593    }
594}
595
596// === Broadcast multiplication === //
597
598impl<C: Curve> Mul<ScalarAsExtension<C>> for PointShare<C> {
599    type Output = PointShare<C>;
600
601    #[inline]
602    fn mul(mut self, other: ScalarAsExtension<C>) -> Self::Output {
603        self.value *= other;
604        izip_eq!(&mut self.keys).for_each(|key| *key *= other);
605        izip_eq!(&mut self.macs).for_each(|mac| *mac *= other);
606        self
607    }
608}
609
610impl<'a, C: Curve> Mul<&'a ScalarAsExtension<C>> for PointShare<C> {
611    type Output = PointShare<C>;
612
613    #[inline]
614    fn mul(mut self, other: &'a ScalarAsExtension<C>) -> Self::Output {
615        self.value *= other;
616        izip_eq!(&mut self.keys).for_each(|key| *key *= other);
617        izip_eq!(&mut self.macs).for_each(|mac| *mac *= other);
618        self
619    }
620}
621
622impl<C: Curve> Mul<ScalarAsExtension<C>> for &PointShare<C> {
623    type Output = PointShare<C>;
624
625    #[inline]
626    fn mul(self, other: ScalarAsExtension<C>) -> Self::Output {
627        PointShare {
628            value: self.value * other,
629            keys: self.keys.iter().map(|key| key * other).collect(),
630            macs: self.macs.iter().map(|mac| mac * other).collect(),
631        }
632    }
633}
634
635impl<'a, C: Curve> Mul<&'a ScalarAsExtension<C>> for &'a PointShare<C> {
636    type Output = PointShare<C>;
637
638    #[inline]
639    fn mul(self, other: &'a ScalarAsExtension<C>) -> Self::Output {
640        PointShare {
641            value: self.value * other,
642            keys: self.keys.iter().map(|key| key * other).collect(),
643            macs: self.macs.iter().map(|mac| mac * other).collect(),
644        }
645    }
646}
647
648impl<C: Curve> Mul<Scalar<C>> for PointShare<C> {
649    type Output = PointShare<C>;
650
651    #[inline]
652    fn mul(mut self, other: Scalar<C>) -> Self::Output {
653        self.value *= other;
654        izip_eq!(&mut self.keys).for_each(|key| *key *= other);
655        izip_eq!(&mut self.macs).for_each(|mac| *mac *= other);
656        self
657    }
658}
659
660impl<'a, C: Curve> Mul<&'a Scalar<C>> for PointShare<C> {
661    type Output = PointShare<C>;
662
663    #[inline]
664    fn mul(mut self, other: &'a Scalar<C>) -> Self::Output {
665        self.value *= other;
666        izip_eq!(&mut self.keys).for_each(|key| *key *= other);
667        izip_eq!(&mut self.macs).for_each(|mac| *mac *= other);
668        self
669    }
670}
671
672impl<C: Curve> Mul<Scalar<C>> for &PointShare<C> {
673    type Output = PointShare<C>;
674
675    #[inline]
676    fn mul(self, other: Scalar<C>) -> Self::Output {
677        PointShare {
678            value: self.value * other,
679            keys: self.keys.iter().map(|key| key * other).collect(),
680            macs: self.macs.iter().map(|mac| mac * other).collect(),
681        }
682    }
683}
684
685impl<'a, C: Curve> Mul<&'a Scalar<C>> for &'a PointShare<C> {
686    type Output = PointShare<C>;
687
688    #[inline]
689    fn mul(self, other: &'a Scalar<C>) -> Self::Output {
690        PointShare {
691            value: self.value * other,
692            keys: self.keys.iter().map(|key| key * other).collect(),
693            macs: self.macs.iter().map(|mac| mac * other).collect(),
694        }
695    }
696}
697
698// === MulAssign === //
699
700impl<'a, C: Curve> MulAssign<&'a ScalarAsExtension<C>> for PointShare<C> {
701    #[inline]
702    fn mul_assign(&mut self, other: &'a ScalarAsExtension<C>) {
703        self.value *= other;
704        izip_eq!(&mut self.keys).for_each(|key| *key *= other);
705        izip_eq!(&mut self.macs).for_each(|mac| *mac *= other);
706    }
707}
708
709impl<'a, C: Curve> MulAssign<&'a Scalar<C>> for PointShare<C> {
710    #[inline]
711    fn mul_assign(&mut self, other: &'a Scalar<C>) {
712        self.value *= other;
713        izip_eq!(&mut self.keys).for_each(|key| *key *= other);
714        izip_eq!(&mut self.macs).for_each(|mac| *mac *= other);
715    }
716}
717
718// === Negation === //
719
720impl<C: Curve> Neg for PointShare<C> {
721    type Output = Self;
722
723    #[inline]
724    fn neg(self) -> Self::Output {
725        PointShare {
726            value: -self.value,
727            keys: self.keys.iter().map(|key| -key).collect(),
728            macs: self.macs.iter().map(|mac| -mac).collect(),
729        }
730    }
731}
732
733impl<C: Curve> Neg for &PointShare<C> {
734    type Output = PointShare<C>;
735
736    #[inline]
737    fn neg(self) -> Self::Output {
738        PointShare {
739            value: -self.value,
740            keys: self.keys.iter().map(|key| -key).collect(),
741            macs: self.macs.iter().map(|mac| -mac).collect(),
742        }
743    }
744}
745
746// === Constant addition / subtraction === //
747
748impl<C: Curve> AddPlaintext for PointShare<C> {
749    type AssociatedInformation = IsFirstPeer;
750
751    /// Adds a public constant to the secret shared value, updating the keys accordingly.
752    /// A designated peer (P_0) will modify its value, while the other peers will update their keys.
753    #[inline]
754    fn add_plaintext(&self, constant: &Point<C>, is_peer_zero: IsFirstPeer) -> Self {
755        let result = self.clone();
756        result.add_plaintext_owned(constant, is_peer_zero)
757    }
758
759    /// Adds a public constant to the secret shared value, updating the keys accordingly.
760    /// A designated peer (P_0) will modify its value, while the other peers will update their keys.
761    #[inline]
762    fn add_plaintext_owned(mut self, constant: &Point<C>, is_peer_zero: IsFirstPeer) -> Self {
763        if is_peer_zero {
764            self.value += constant;
765        } else {
766            let key0 = self.keys.get_mut(0).expect("Missing key 0");
767            key0.beta -= *key0.alpha * constant;
768        }
769        self
770    }
771}
772
773// === Constant time equality / select === //
774
775impl<C: Curve> ConditionallySelectable for PointShare<C> {
776    fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
777        PointShare {
778            value: Point::conditional_select(&a.value, &b.value, choice),
779            keys: izip_eq!(&a.keys, &b.keys)
780                .map(|(a, b)| CurveKey::conditional_select(a, b, choice))
781                .collect(),
782            macs: izip_eq!(&a.macs, &b.macs)
783                .map(|(a, b)| Point::conditional_select(a, b, choice))
784                .collect(),
785        }
786    }
787}
788
789impl<C: Curve> ConstantTimeEq for PointShare<C> {
790    #[inline]
791    fn ct_eq(&self, other: &Self) -> Choice {
792        self.value.ct_eq(&other.value)
793            & izip_eq!(&self.keys, &other.keys).fold(1.into(), |acc, (self_key, other_key)| {
794                acc & self_key.ct_eq(other_key)
795            })
796            & self.macs.ct_eq(&other.macs)
797    }
798}
799
800#[cfg(test)]
801mod tests {
802    use itertools::enumerate;
803
804    use super::*;
805    use crate::{
806        algebra::elliptic_curve::Curve25519Ristretto as C,
807        random::{self},
808        sharing::Verifiable,
809    };
810
811    // TODO: Generalize once PairwiseAuthenticatedShare trait is implemented.
812
813    //////////////////////////////////////////////////
814    // CHANGE ONLY THESE TO TEST ANOTHER SHARE TYPE //
815    pub type Value = Point<C>;
816    pub type Constant = Scalar<C>;
817    pub type Share = PointShare<C>;
818    pub type GlobalKey = GlobalCurveKey<C>;
819    //////////////////////////////////////////////////
820
821    pub const N_PARTIES: usize = 3;
822
823    #[test]
824    fn test_open_to() {
825        let mut rng = random::test_rng();
826        let local_share = Share::random_with(&mut rng, N_PARTIES);
827
828        for i in 0..N_PARTIES - 1 {
829            let open_share = local_share.open_to(i).unwrap();
830            assert_eq!(open_share.get_value(), &local_share.value);
831            assert_eq!(open_share.get_mac(), &local_share.macs[i]);
832        }
833    }
834
835    #[test]
836    fn test_random() {
837        let mut rng = random::test_rng();
838
839        // Generate a completely random share
840        let share = Share::random_with(&mut rng, N_PARTIES);
841        assert_eq!(share.get_macs().len(), N_PARTIES - 1);
842        assert_eq!(share.get_keys().len(), N_PARTIES - 1);
843
844        // Generate a share with a specific value
845        let value = &Value::random(&mut rng);
846        let share_with_value = Share::random_with(&mut rng, (N_PARTIES, value.to_owned()));
847        assert_eq!(share_with_value.get_value(), value);
848        assert_eq!(share_with_value.get_macs().len(), N_PARTIES - 1);
849        assert_eq!(share_with_value.get_keys().len(), N_PARTIES - 1);
850    }
851
852    #[test]
853    fn test_random_vec_and_reconstruct() {
854        let mut rng = random::test_rng();
855
856        // Generate a vector of random shares, one per party
857        let shares: Vec<_> = Share::random_n(&mut rng, N_PARTIES);
858        assert_eq!(shares.len(), N_PARTIES);
859        for share in &shares {
860            assert_eq!(share.get_macs().len(), N_PARTIES - 1);
861            assert_eq!(share.get_keys().len(), N_PARTIES - 1);
862        }
863        let unauthenticated_shares = shares
864            .iter()
865            .map(|s| s.get_value().to_owned())
866            .collect::<Vec<_>>();
867        let expected = Value::from_additive_shares(&unauthenticated_shares);
868        let reconstructed = Share::reconstruct_all(&shares).unwrap();
869        assert_eq!(reconstructed, expected);
870
871        // Secret share a value among n parties
872        let value = &Value::random(&mut rng);
873        let shares: Vec<_> = Share::random_n_with(&mut rng, N_PARTIES, value.to_owned());
874        assert_eq!(shares.len(), N_PARTIES);
875        for share in &shares {
876            assert_eq!(share.get_macs().len(), N_PARTIES - 1);
877            assert_eq!(share.get_keys().len(), N_PARTIES - 1);
878        }
879        let reconstructed = Share::reconstruct_all(&shares).unwrap();
880        assert_eq!(reconstructed, value.to_owned());
881    }
882
883    #[test]
884    fn test_random_vec_with_global_key_and_reconstruct() {
885        let mut rng = random::test_rng();
886
887        // Generate n authenticated shares from n global keys (alphas)
888        let alphas = Vec::<Vec<GlobalKey>>::random_with(&mut rng, N_PARTIES);
889        let shares_from_alphas: Vec<_> = Share::random_n_with_each(&mut rng, alphas.clone());
890        assert_eq!(shares_from_alphas.len(), N_PARTIES);
891        for (share_a, my_alphas) in izip_eq!(&shares_from_alphas, alphas) {
892            assert_eq!(share_a.get_macs().len(), N_PARTIES - 1);
893            assert_eq!(share_a.get_keys().len(), N_PARTIES - 1);
894            assert_eq!(share_a.get_alphas().collect::<Vec<_>>(), my_alphas);
895        }
896        Share::verify_all(&shares_from_alphas).unwrap(); // Verify all MACs
897
898        // Generate n authenticated shares from a value and n global keys (alphas)
899        let value = &Value::random(&mut rng);
900        let alphas = Vec::<Vec<GlobalKey>>::random_with(&mut rng, N_PARTIES);
901        let shares_from_value_and_alphas: Vec<_> =
902            Share::random_n_with(&mut rng, N_PARTIES, (value.to_owned(), alphas.clone()));
903        assert_eq!(shares_from_value_and_alphas.len(), N_PARTIES);
904        for (share_a, my_alphas) in izip_eq!(&shares_from_value_and_alphas, alphas) {
905            assert_eq!(share_a.get_macs().len(), N_PARTIES - 1);
906            assert_eq!(share_a.get_keys().len(), N_PARTIES - 1);
907            assert_eq!(share_a.get_alphas().collect::<Vec<_>>(), my_alphas);
908        }
909        let reconstructed = Share::reconstruct_all(&shares_from_value_and_alphas).unwrap();
910        assert_eq!(&reconstructed, value);
911
912        // Generate n authenticated shares from n unauthenticated shares and n global keys (alphas)
913        let value = Value::random(&mut rng);
914        let unauth_shares = value.to_additive_shares(N_PARTIES, &mut rng);
915        let alphas = Vec::<Vec<GlobalKey>>::random_with(&mut rng, N_PARTIES);
916        let shares_from_unauth_and_alphas: Vec<_> =
917            Share::random_n_with_each(&mut rng, izip_eq!(unauth_shares.clone(), alphas.clone()));
918        assert_eq!(shares_from_unauth_and_alphas.len(), N_PARTIES);
919        for (share_a, my_alphas) in izip_eq!(&shares_from_unauth_and_alphas, alphas) {
920            assert_eq!(share_a.get_macs().len(), N_PARTIES - 1);
921            assert_eq!(share_a.get_keys().len(), N_PARTIES - 1);
922            assert_eq!(share_a.get_alphas().collect::<Vec<_>>(), my_alphas);
923        }
924        let reconstructed = Share::reconstruct_all(&shares_from_unauth_and_alphas).unwrap();
925        assert_eq!(reconstructed, value);
926    }
927
928    #[test]
929    fn test_verify_mac() {
930        let mut rng = random::test_rng();
931
932        let shares: Vec<_> = Share::random_n(&mut rng, N_PARTIES);
933
934        // Verify each open separately
935        enumerate(shares.iter()).for_each(|(i, s_i)| {
936            enumerate(shares.iter())
937                .filter(|(j, _)| i != *j)
938                .for_each(|(j, s_j)| {
939                    let open_share = s_j.open_to(i - (i > j) as usize).unwrap();
940                    s_i.verify_from(&open_share, j - (j > i) as usize).unwrap();
941                });
942        });
943
944        // Verify all openings at once
945        Share::verify_all(&shares).unwrap();
946    }
947
948    #[test]
949    fn test_add() {
950        let mut rng = random::test_rng();
951
952        let alphas = Vec::<Vec<GlobalKey>>::random_with(&mut rng, N_PARTIES);
953        let a = &Value::random(&mut rng);
954        let b = &Value::random(&mut rng);
955
956        let shares_a: Vec<_> =
957            Share::random_n_with(&mut rng, N_PARTIES, (a.to_owned(), alphas.clone()));
958        let shares_b: Vec<_> = Share::random_n_with(&mut rng, N_PARTIES, (b.to_owned(), alphas));
959
960        // &a + &b
961        let shares_a_ref_plus_b_ref = izip_eq!(&shares_a, &shares_b)
962            .map(|(share_a, share_b)| share_a + share_b)
963            .collect::<Vec<_>>();
964        let reconstructed = Share::reconstruct_all(&shares_a_ref_plus_b_ref).unwrap();
965        assert_eq!(reconstructed, a + b);
966
967        // &a + b
968        let shares_a_ref_plus_b = izip_eq!(&shares_a, shares_b.clone())
969            .map(|(share_a, share_b)| share_a + share_b)
970            .collect::<Vec<_>>();
971        let reconstructed = Share::reconstruct_all(&shares_a_ref_plus_b).unwrap();
972        assert_eq!(reconstructed, a + b);
973
974        // a + &b
975        let shares_a_plus_b_ref = izip_eq!(shares_a.clone(), &shares_b)
976            .map(|(share_a, share_b)| share_a + share_b)
977            .collect::<Vec<_>>();
978        let reconstructed = Share::reconstruct_all(&shares_a_plus_b_ref).unwrap();
979        assert_eq!(reconstructed, a + b);
980
981        // a + b
982        let shares_a_plus_b = izip_eq!(shares_a.clone(), shares_b.clone())
983            .map(|(share_a, share_b)| share_a + share_b)
984            .collect::<Vec<_>>();
985        let reconstructed = Share::reconstruct_all(&shares_a_plus_b).unwrap();
986        assert_eq!(reconstructed, a + b);
987
988        // a += &b
989        let mut shares_a_add_assign_b_ref = shares_a.clone();
990        izip_eq!(&mut shares_a_add_assign_b_ref, &shares_b)
991            .for_each(|(share_a, share_b)| *share_a += share_b);
992        let reconstructed = Share::reconstruct_all(&shares_a_add_assign_b_ref).unwrap();
993        assert_eq!(reconstructed, a + b);
994
995        // a += b
996        let mut shares_a_add_assign_b = shares_a.clone();
997        izip_eq!(&mut shares_a_add_assign_b, shares_b)
998            .for_each(|(share_a, share_b)| *share_a += share_b);
999        let reconstructed = Share::reconstruct_all(&shares_a_add_assign_b).unwrap();
1000        assert_eq!(reconstructed, a + b);
1001    }
1002
1003    #[test]
1004    fn test_add_secret() {
1005        let mut rng = random::test_rng();
1006
1007        let a = &Value::random(&mut rng);
1008        let k = &Value::random(&mut rng);
1009
1010        let shares_a: Vec<_> = Share::random_n_with(&mut rng, N_PARTIES, a.to_owned());
1011
1012        // &a + k
1013        let shares_a_plus_k_ref = enumerate(shares_a.iter())
1014            .map(|(i, share_a)| share_a.add_plaintext(k, i == 0))
1015            .collect::<Vec<_>>();
1016        let reconstructed = Share::reconstruct_all(&shares_a_plus_k_ref).unwrap();
1017        assert_eq!(reconstructed, a + k);
1018
1019        // a + k
1020        let shares_a_plus_k = enumerate(shares_a)
1021            .map(|(i, share_a)| share_a.add_plaintext_owned(k, i == 0))
1022            .collect::<Vec<_>>();
1023        let reconstructed = Share::reconstruct_all(&shares_a_plus_k).unwrap();
1024        assert_eq!(reconstructed, a + k);
1025    }
1026
1027    #[test]
1028    fn test_mul_constant() {
1029        let mut rng = random::test_rng();
1030
1031        let a = &Value::random(&mut rng);
1032        let k = &Constant::random(&mut rng);
1033
1034        let shares_a: Vec<_> = Share::random_n_with(&mut rng, N_PARTIES, a.to_owned());
1035
1036        // a * &k
1037        let shares_a_times_k = izip_eq!(shares_a.clone())
1038            .map(|share_a| share_a * k)
1039            .collect::<Vec<_>>();
1040        let reconstructed = Share::reconstruct_all(&shares_a_times_k).unwrap();
1041        assert_eq!(reconstructed, a * k);
1042
1043        // a *= &k
1044        let mut shares_a_times_k_assign = shares_a.clone();
1045        izip_eq!(&mut shares_a_times_k_assign).for_each(|share_a| *share_a *= k);
1046        let reconstructed = Share::reconstruct_all(&shares_a_times_k_assign).unwrap();
1047        assert_eq!(reconstructed, a * k);
1048    }
1049
1050    #[test]
1051    fn test_sub() {
1052        let mut rng = random::test_rng();
1053        let alphas = Vec::<Vec<GlobalKey>>::random_with(&mut rng, N_PARTIES);
1054
1055        let a = &Value::random(&mut rng);
1056        let b = &Value::random(&mut rng);
1057
1058        let shares_a: Vec<_> =
1059            Share::random_n_with(&mut rng, N_PARTIES, (a.to_owned(), alphas.clone()));
1060        let shares_b: Vec<_> = Share::random_n_with(&mut rng, N_PARTIES, (b.to_owned(), alphas));
1061
1062        // &a - &b
1063        let shares_a_ref_minus_b_ref = izip_eq!(&shares_a, &shares_b)
1064            .map(|(share_a, share_b)| share_a - share_b)
1065            .collect::<Vec<_>>();
1066
1067        let reconstructed = Share::reconstruct_all(&shares_a_ref_minus_b_ref).unwrap();
1068        assert_eq!(reconstructed, a - b);
1069
1070        // &a - b
1071        let shares_a_ref_minus_b = izip_eq!(&shares_a, shares_b.clone())
1072            .map(|(share_a, share_b)| share_a - share_b)
1073            .collect::<Vec<_>>();
1074        let reconstructed = Share::reconstruct_all(&shares_a_ref_minus_b).unwrap();
1075        assert_eq!(reconstructed, a - b);
1076
1077        // a - &b
1078        let shares_a_minus_b_ref = izip_eq!(shares_a.clone(), &shares_b)
1079            .map(|(share_a, share_b)| share_a - share_b)
1080            .collect::<Vec<_>>();
1081        let reconstructed = Share::reconstruct_all(&shares_a_minus_b_ref).unwrap();
1082        assert_eq!(reconstructed, a - b);
1083
1084        // a - b
1085        let shares_a_minus_b = izip_eq!(shares_a.clone(), shares_b.clone())
1086            .map(|(share_a, share_b)| share_a - share_b)
1087            .collect::<Vec<_>>();
1088        let reconstructed = Share::reconstruct_all(&shares_a_minus_b).unwrap();
1089        assert_eq!(reconstructed, a - b);
1090
1091        // a -= &b
1092        let mut shares_a_sub_assign_b_ref = shares_a.clone();
1093        izip_eq!(&mut shares_a_sub_assign_b_ref, &shares_b)
1094            .for_each(|(share_a, share_b)| *share_a -= share_b);
1095        let reconstructed = Share::reconstruct_all(&shares_a_sub_assign_b_ref).unwrap();
1096        assert_eq!(reconstructed, a - b);
1097
1098        // a -= b
1099        let mut shares_a_sub_assign_b = shares_a.clone();
1100        izip_eq!(&mut shares_a_sub_assign_b, shares_b)
1101            .for_each(|(share_a, share_b)| *share_a -= share_b);
1102        let reconstructed = Share::reconstruct_all(&shares_a_sub_assign_b).unwrap();
1103        assert_eq!(reconstructed, a - b);
1104    }
1105
1106    #[test]
1107    fn test_neg() {
1108        let mut rng = random::test_rng();
1109
1110        let a = Value::random(&mut rng);
1111
1112        let shares_a: Vec<_> = Share::random_n_with(&mut rng, N_PARTIES, a.to_owned());
1113
1114        // - &a
1115        let shares_a_neg_ref = shares_a.iter().map(|share_a| -share_a).collect::<Vec<_>>();
1116        let reconstructed = Share::reconstruct_all(&shares_a_neg_ref).unwrap();
1117        assert_eq!(reconstructed, -a.to_owned());
1118
1119        // - a
1120        let shares_a_neg = shares_a
1121            .into_iter()
1122            .map(|share_a| -share_a)
1123            .collect::<Vec<_>>();
1124        let reconstructed = Share::reconstruct_all(&shares_a_neg).unwrap();
1125        assert_eq!(reconstructed, -a.to_owned());
1126    }
1127
1128    #[test]
1129    fn test_conditional_select() {
1130        let mut rng = random::test_rng();
1131
1132        let shares_a = Share::random_with(&mut rng, N_PARTIES);
1133        let shares_b = Share::random_with(&mut rng, N_PARTIES);
1134
1135        // Select shares_a
1136        let choice = Choice::from(0u8);
1137        let selected = Share::conditional_select(&shares_a, &shares_b, choice);
1138        assert_eq!(selected, shares_a);
1139
1140        // Select shares_b
1141        let choice = Choice::from(1u8);
1142        let selected = Share::conditional_select(&shares_a, &shares_b, choice);
1143        assert_eq!(selected, shares_b);
1144    }
1145
1146    #[test]
1147    fn test_ct_eq() {
1148        let mut rng = random::test_rng();
1149
1150        let shares_a = Share::random_with(&mut rng, N_PARTIES);
1151        let shares_b = Share::random_with(&mut rng, N_PARTIES);
1152
1153        // Check equality
1154        assert!(Into::<bool>::into(shares_a.ct_eq(&shares_a.clone())));
1155        assert!(Into::<bool>::into(shares_b.ct_eq(&shares_b.clone())));
1156        assert!(!Into::<bool>::into(shares_a.ct_eq(&shares_b)));
1157        assert!(!Into::<bool>::into(shares_b.ct_eq(&shares_a)));
1158    }
1159}