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