primitives/sharing/authenticated/batched/
curve_shares.rs

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