Skip to main content

primitives/sharing/authenticated/pairwise/
keys.rs

1use std::{
2    iter::Sum as IterSum,
3    mem::MaybeUninit,
4    ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign},
5    sync::Arc,
6};
7
8use serde::{Deserialize, Serialize};
9use subtle::{Choice, ConstantTimeEq};
10use typenum::{Prod, Sum, U1, U2, U3};
11use wincode::{
12    io::{Reader, Writer},
13    ReadResult,
14    SchemaRead,
15    SchemaWrite,
16    WriteResult,
17};
18
19use crate::{
20    algebra::{
21        elliptic_curve::{BaseField, Curve, Point, ScalarAsExtension, ScalarField},
22        field::{FieldElement, FieldExtension},
23    },
24    random::{CryptoRngCore, Random, RandomWith},
25    types::{
26        heap_array::{CurvePoints, FieldElements},
27        ConditionallySelectable,
28        HeapArray,
29        Positive,
30    },
31};
32
33// ============================================================
34// |                     GlobalKey                             |
35// ============================================================
36
37/// α, a global authentication key for field shares. Each party holds a
38/// global key α for each peer, and uses that α to authenticate all its field shares
39/// (alongside a local key β).
40pub type GlobalKey<A> = Arc<A>;
41
42/// Global authentication key for field shares. Alias for [`GlobalKey<FieldElement<F>>`].
43pub type GlobalFieldKey<F> = Arc<FieldElement<F>>;
44/// [`GlobalFieldKey`] for scalar field shares. Alias for [`GlobalFieldKey<ScalarField<C>>`].
45pub type GlobalScalarKey<C> = GlobalFieldKey<ScalarField<C>>;
46/// [`GlobalFieldKey`] for base field shares. Alias for [`GlobalFieldKey<BaseField<C>>`].
47pub type GlobalBaseKey<C> = GlobalFieldKey<BaseField<C>>;
48/// [`GlobalFieldKey`] for curve-point shares (MAC is computed over the scalar field).
49/// Alias for [`GlobalFieldKey<ScalarField<C>>`].
50pub type GlobalCurveKey<C> = GlobalFieldKey<ScalarField<C>>;
51
52// ============================================================
53// |               FieldShareKeyBase<A, B>                    |
54// ============================================================
55
56/// Generic authenticated key: a global key `alpha: A` and a local key `beta: B`,
57/// satisfying `MAC(x) = α · x + β`.
58///
59/// This is the base type for both:
60/// - [`FieldShareKey<F>`]    — single-value authenticated key
61/// - [`FieldShareKeys<F,M>`] — batched authenticated key (M values, shared α)
62// α and β, such that MAC(x) = α · x + β
63// In the context of VOLE, this corresponds to w = Δ · u + v
64#[derive(Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
65#[repr(C)]
66pub struct PairwiseAuthKey<A, B> {
67    pub alpha: GlobalKey<A>, // α, global key
68    pub beta: B,             // β, local key (single value or batch)
69}
70
71impl<A: std::fmt::Debug, B: std::fmt::Debug> std::fmt::Debug for PairwiseAuthKey<A, B> {
72    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
73        f.debug_struct("PairwiseAuthKey")
74            .field("alpha", &self.alpha)
75            .field("beta", &self.beta)
76            .finish()
77    }
78}
79
80impl<A, B> PairwiseAuthKey<A, B> {
81    /// Create a new [`PairwiseAuthKey`] with the given global key `alpha` and local key `beta`.
82    #[inline]
83    pub fn new(alpha: Arc<A>, beta: B) -> Self {
84        PairwiseAuthKey { alpha, beta }
85    }
86
87    /// Return a reference to the local key `beta`.
88    #[inline]
89    pub fn get_beta(&self) -> &B {
90        &self.beta
91    }
92
93    /// Return a reference to the global key `alpha`.
94    #[inline]
95    pub fn get_alpha(&self) -> &A {
96        &self.alpha
97    }
98
99    /// Return the value of the global key `alpha`.
100    #[inline]
101    pub fn alpha(&self) -> Arc<A> {
102        self.alpha.clone()
103    }
104}
105
106// --- Aliases --- //
107
108/// [`PairwiseAuthKey`] for a single field value.
109///
110/// See also [`FieldShareKeys<F, M>`] for the batched variant.
111///
112/// α and β, such that MAC(x) = α · x + β
113pub type FieldKey<F> = PairwiseAuthKey<FieldElement<F>, FieldElement<F>>;
114
115/// [`PairwiseAuthKey`] for a single scalar field element. Alias for
116/// [`FieldKey<ScalarField<C>>`].
117pub type ScalarKey<C> = FieldKey<ScalarField<C>>;
118/// [`PairwiseAuthKey`] for a single base field element. Alias for [`FieldKey<BaseField<C>>`].
119pub type BaseFieldKey<C> = FieldKey<BaseField<C>>;
120
121/// [`PairwiseAuthKey`] for a batch of `M` field values sharing a single global key.
122///
123/// See also [`FieldKey<F>`] for the single-value variant.
124///
125/// α and β₁…βₘ, such that MAC(xₜ) = α · xₜ + βₜ
126pub type FieldKeys<F, M> = PairwiseAuthKey<FieldElement<F>, FieldElements<F, M>>;
127
128/// [`PairwiseAuthKey`] for a batch of scalar field elements.
129pub type ScalarKeys<C, M> = FieldKeys<ScalarField<C>, M>;
130/// [`PairwiseAuthKey`] for a batch of base field elements.
131pub type BaseFieldKeys<C, M> = FieldKeys<BaseField<C>, M>;
132
133/// [`PairwiseAuthKey`] for a single curve point.
134pub type CurveKey<C> = PairwiseAuthKey<ScalarAsExtension<C>, Point<C>>;
135/// [`PairwiseAuthKey`] for `M` curve points.
136pub type CurveKeys<C, M> = PairwiseAuthKey<ScalarAsExtension<C>, CurvePoints<C, M>>;
137
138// ========================
139// |       Addition       |
140// ========================
141
142#[macros::op_variants(owned, borrowed, flipped)]
143impl<A: PartialEq, B> Add<&PairwiseAuthKey<A, B>> for PairwiseAuthKey<A, B>
144where
145    for<'a> B: Add<&'a B, Output = B>,
146{
147    type Output = PairwiseAuthKey<A, B>;
148
149    #[inline]
150    fn add(mut self, other: &PairwiseAuthKey<A, B>) -> Self::Output {
151        assert!(self.alpha == other.alpha, "alpha mismatch");
152        self.beta = self.beta + &other.beta;
153        self
154    }
155}
156
157#[macros::op_variants(owned)]
158impl<'a, A: PartialEq, B> AddAssign<&'a PairwiseAuthKey<A, B>> for PairwiseAuthKey<A, B>
159where
160    for<'b> B: AddAssign<&'b B>,
161{
162    #[inline]
163    fn add_assign(&mut self, other: &'a PairwiseAuthKey<A, B>) {
164        assert!(self.alpha == other.alpha, "alpha mismatch");
165        self.beta += &other.beta;
166    }
167}
168
169#[macros::op_variants(owned, borrowed, flipped)]
170impl<A: PartialEq, B> Sub<&PairwiseAuthKey<A, B>> for PairwiseAuthKey<A, B>
171where
172    for<'a> B: Sub<&'a B, Output = B>,
173{
174    type Output = PairwiseAuthKey<A, B>;
175
176    #[inline]
177    fn sub(self, other: &PairwiseAuthKey<A, B>) -> Self::Output {
178        assert!(self.alpha == other.alpha, "alpha mismatch");
179        PairwiseAuthKey {
180            alpha: self.alpha,
181            beta: self.beta - &other.beta,
182        }
183    }
184}
185
186#[macros::op_variants(owned)]
187impl<'a, A: PartialEq, B> SubAssign<&'a PairwiseAuthKey<A, B>> for PairwiseAuthKey<A, B>
188where
189    for<'b> B: SubAssign<&'b B>,
190{
191    #[inline]
192    fn sub_assign(&mut self, other: &'a PairwiseAuthKey<A, B>) {
193        assert!(self.alpha == other.alpha, "alpha mismatch");
194        self.beta -= &other.beta;
195    }
196}
197
198#[macros::op_variants(borrowed)]
199impl<A, B: Neg<Output = B>> Neg for PairwiseAuthKey<A, B> {
200    type Output = PairwiseAuthKey<A, B>;
201
202    #[inline]
203    fn neg(mut self) -> Self::Output {
204        self.beta = -self.beta;
205        self
206    }
207}
208
209impl<A: Default + PartialEq, B: Default> IterSum for PairwiseAuthKey<A, B>
210where
211    for<'a> B: Add<&'a B, Output = B>,
212{
213    fn sum<I: Iterator<Item = Self>>(mut iter: I) -> Self {
214        let first = iter.next().unwrap_or_default();
215        iter.fold(first, |acc, x| acc + &x)
216    }
217}
218
219// ========================
220// |   Multiplication     |
221// ========================
222
223impl<A, B, RHS, BPrime> Mul<RHS> for PairwiseAuthKey<A, B>
224where
225    B: Mul<RHS, Output = BPrime>,
226{
227    type Output = PairwiseAuthKey<A, BPrime>;
228    #[inline]
229    fn mul(self, other: RHS) -> Self::Output {
230        PairwiseAuthKey {
231            alpha: self.alpha,
232            beta: self.beta * other,
233        }
234    }
235}
236
237impl<A: Clone, B, RHS, BPrime> Mul<RHS> for &PairwiseAuthKey<A, B>
238where
239    for<'b> &'b B: Mul<RHS, Output = BPrime>,
240{
241    type Output = PairwiseAuthKey<A, BPrime>;
242    #[inline]
243    fn mul(self, other: RHS) -> Self::Output {
244        PairwiseAuthKey {
245            alpha: self.alpha.clone(),
246            beta: &self.beta * other,
247        }
248    }
249}
250
251impl<A, B, RHS> MulAssign<RHS> for PairwiseAuthKey<A, B>
252where
253    B: MulAssign<RHS>,
254{
255    #[inline]
256    fn mul_assign(&mut self, other: RHS) {
257        self.beta *= other;
258    }
259}
260
261// ========================
262// |   Random Generation  |
263// ========================
264
265impl<A: Random, B: Random> Random for PairwiseAuthKey<A, B> {
266    fn random(mut rng: impl CryptoRngCore) -> Self {
267        PairwiseAuthKey {
268            alpha: A::random(&mut rng).into(),
269            beta: B::random(&mut rng),
270        }
271    }
272}
273
274impl<A: Clone, B: Random> RandomWith<GlobalKey<A>> for PairwiseAuthKey<A, B> {
275    fn random_with(mut rng: impl CryptoRngCore, alpha: GlobalKey<A>) -> Self {
276        PairwiseAuthKey {
277            alpha,
278            beta: B::random(&mut rng),
279        }
280    }
281}
282
283// ---------------------------------------
284// |  Constant time Selection / Equality |
285// ---------------------------------------
286
287impl<A: ConstantTimeEq, B: ConstantTimeEq> ConstantTimeEq for PairwiseAuthKey<A, B> {
288    #[inline]
289    fn ct_eq(&self, other: &Self) -> Choice {
290        self.alpha.ct_eq(&other.alpha) & self.beta.ct_eq(&other.beta)
291    }
292}
293
294impl<A: ConditionallySelectable, B: ConditionallySelectable> ConditionallySelectable
295    for PairwiseAuthKey<A, B>
296{
297    #[inline]
298    fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
299        PairwiseAuthKey {
300            alpha: A::conditional_select(&a.alpha, &b.alpha, choice).into(),
301            beta: B::conditional_select(&a.beta, &b.beta, choice),
302        }
303    }
304}
305
306// ========================
307// |  SchemaWrite / Read  |
308// ========================
309
310impl<A: SchemaWrite<Src = A>, B: SchemaWrite<Src = B>> SchemaWrite for PairwiseAuthKey<A, B> {
311    type Src = Self;
312
313    fn size_of(src: &Self::Src) -> WriteResult<usize> {
314        Ok(A::size_of(&src.alpha)? + B::size_of(&src.beta)?)
315    }
316
317    fn write(writer: &mut impl Writer, src: &Self::Src) -> WriteResult<()> {
318        A::write(writer, &src.alpha)?;
319        B::write(writer, &src.beta)
320    }
321}
322
323impl<'de, A: SchemaRead<'de, Dst = A>, B: SchemaRead<'de, Dst = B>> SchemaRead<'de>
324    for PairwiseAuthKey<A, B>
325{
326    type Dst = Self;
327
328    fn read(reader: &mut impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
329        let mut alpha_uninit = MaybeUninit::<A>::uninit();
330        let mut beta_uninit = MaybeUninit::<B>::uninit();
331        A::read(reader, &mut alpha_uninit)?;
332        B::read(reader, &mut beta_uninit)?;
333        // SAFETY: both fields were initialized by the reads above
334        let alpha = unsafe { alpha_uninit.assume_init() }.into();
335        let beta = unsafe { beta_uninit.assume_init() };
336        dst.write(PairwiseAuthKey { alpha, beta });
337        Ok(())
338    }
339}
340
341// -----------------------
342// |   Split and Merge   |
343// -----------------------
344
345/// Generic split and merge operations on any batched key `PairwiseAuthKey<A, HeapArray<B, M>>`.
346/// Covers both `FieldShareKeys<F, M>` and `CurveKeys<C, M>`.
347impl<A: Clone, B: Copy, M: Positive> PairwiseAuthKey<A, HeapArray<B, M>> {
348    #[allow(clippy::type_complexity)]
349    /// Split a batched key into two smaller batched keys with the same global key `alpha` and
350    /// disjoint local keys `beta` (first `M1` values in the first key, next `M2` values in the
351    /// second key).
352    pub fn split<M1, M2>(
353        self,
354    ) -> (
355        PairwiseAuthKey<A, HeapArray<B, M1>>,
356        PairwiseAuthKey<A, HeapArray<B, M2>>,
357    )
358    where
359        M1: Positive,
360        M2: Positive + Add<M1, Output = M>,
361    {
362        let PairwiseAuthKey { alpha, beta } = self;
363        let (betas1, betas2) = beta.split::<M1, M2>();
364        (
365            PairwiseAuthKey::new(alpha.clone(), betas1),
366            PairwiseAuthKey::new(alpha, betas2),
367        )
368    }
369
370    pub fn split_last_pos<M1>(self) -> (PairwiseAuthKey<A, HeapArray<B, M1>>, PairwiseAuthKey<A, B>)
371    where
372        M1: Positive + Add<typenum::B1, Output = M>,
373    {
374        let PairwiseAuthKey { alpha, beta } = self;
375        let (betas1, beta2) = beta.split_last_pos();
376        (
377            PairwiseAuthKey::new(alpha.clone(), betas1),
378            PairwiseAuthKey::new(alpha, beta2),
379        )
380    }
381
382    #[allow(clippy::type_complexity)]
383    /// Split a batched key into two smaller batched keys with the same global key `alpha` and
384    /// disjoint local keys `beta` (first `M/2` values in the first key, next `M/2` values in the
385    /// second key).
386    pub fn split_halves<MDiv2>(
387        self,
388    ) -> (
389        PairwiseAuthKey<A, HeapArray<B, MDiv2>>,
390        PairwiseAuthKey<A, HeapArray<B, MDiv2>>,
391    )
392    where
393        MDiv2: Positive + Mul<U2, Output = M>,
394    {
395        let PairwiseAuthKey { alpha, beta } = self;
396        let (betas1, betas2) = beta.split_halves::<MDiv2>();
397        (
398            PairwiseAuthKey::new(alpha.clone(), betas1),
399            PairwiseAuthKey::new(alpha, betas2),
400        )
401    }
402
403    /// Merge two batched keys with the same global key `alpha` and disjoint local keys `beta`
404    /// (first `M/2` values in the first key, next `M/2` values in the second key) into a single
405    /// batched key with `M` values in the local key.
406    pub fn merge_halves(this: Self, other: Self) -> PairwiseAuthKey<A, HeapArray<B, Prod<M, U2>>>
407    where
408        M: Positive + Mul<U2, Output: Positive>,
409        A: PartialEq,
410    {
411        assert!(this.alpha == other.alpha, "alpha mismatch in merge_halves");
412        PairwiseAuthKey {
413            alpha: this.alpha,
414            beta: HeapArray::merge_halves(this.beta, other.beta),
415        }
416    }
417
418    #[allow(clippy::type_complexity)]
419    /// Split a batched key into three smaller batched keys with the same global key `alpha` and
420    /// disjoint local keys `beta` (first `M1` values in the first key, next `M2` values in the
421    /// second key, last `M3` values in the third key).
422    pub fn split3<M1, M2, M3>(
423        self,
424    ) -> (
425        PairwiseAuthKey<A, HeapArray<B, M1>>,
426        PairwiseAuthKey<A, HeapArray<B, M2>>,
427        PairwiseAuthKey<A, HeapArray<B, M3>>,
428    )
429    where
430        M1: Positive,
431        M2: Positive + Add<M1>,
432        M3: Positive + Add<Sum<M2, M1>, Output = M>,
433    {
434        let PairwiseAuthKey { alpha, beta } = self;
435        let (betas1, betas2, betas3) = beta.split3::<M1, M2, M3>();
436        (
437            PairwiseAuthKey::new(alpha.clone(), betas1),
438            PairwiseAuthKey::new(alpha.clone(), betas2),
439            PairwiseAuthKey::new(alpha, betas3),
440        )
441    }
442
443    #[allow(clippy::type_complexity)]
444    /// Split a batched key into three smaller batched keys with the same global key `alpha` and
445    /// disjoint local keys `beta` (first `M/3` values in the first key, next `M/3` values in the
446    /// second key, last `M/3` values in the third key).
447    pub fn split_thirds<MDiv3>(
448        self,
449    ) -> (
450        PairwiseAuthKey<A, HeapArray<B, MDiv3>>,
451        PairwiseAuthKey<A, HeapArray<B, MDiv3>>,
452        PairwiseAuthKey<A, HeapArray<B, MDiv3>>,
453    )
454    where
455        MDiv3: Positive + Mul<U3, Output = M>,
456    {
457        let PairwiseAuthKey { alpha, beta } = self;
458        let (betas1, betas2, betas3) = beta.split_thirds::<MDiv3>();
459        (
460            PairwiseAuthKey::new(alpha.clone(), betas1),
461            PairwiseAuthKey::new(alpha.clone(), betas2),
462            PairwiseAuthKey::new(alpha, betas3),
463        )
464    }
465
466    /// Merge three batched keys with the same global key `alpha` and disjoint local keys `beta`
467    /// (first `M/3` values in the first key, next `M/3` values in the second key, last `M/3` values
468    /// in the third key) into a single batched key with `M` values in the local key.
469    pub fn merge_thirds(
470        first: Self,
471        second: Self,
472        third: Self,
473    ) -> PairwiseAuthKey<A, HeapArray<B, Prod<M, U3>>>
474    where
475        M: Positive + Mul<U3, Output: Positive>,
476        A: PartialEq,
477    {
478        assert!(
479            first.alpha == second.alpha,
480            "alpha mismatch in merge_thirds"
481        );
482        assert!(first.alpha == third.alpha, "alpha mismatch in merge_thirds");
483        PairwiseAuthKey {
484            alpha: first.alpha,
485            beta: HeapArray::merge_thirds(first.beta, second.beta, third.beta),
486        }
487    }
488}
489
490// ------------------------
491// |   Iterate and Cast   |
492// ------------------------
493
494/// Convert a single-element key into a one-element batched key.
495/// Covers `From<FieldShareKey<F>> for FieldShareKeys<F, U1>` and
496/// `From<CurveKey<C>> for CurveKeys<C, U1>`.
497impl<A, T> From<PairwiseAuthKey<A, T>> for PairwiseAuthKey<A, HeapArray<T, U1>> {
498    fn from(key: PairwiseAuthKey<A, T>) -> Self {
499        PairwiseAuthKey {
500            alpha: key.alpha,
501            beta: HeapArray::from(key.beta),
502        }
503    }
504}
505
506pub struct FieldShareKeysIterator<F: FieldExtension, M: Positive> {
507    keys: FieldKeys<F, M>,
508    index: usize,
509}
510
511impl<F: FieldExtension, M: Positive> Iterator for FieldShareKeysIterator<F, M> {
512    type Item = FieldKey<F>;
513
514    fn next(&mut self) -> Option<Self::Item> {
515        if self.index < M::to_usize() {
516            let key = PairwiseAuthKey {
517                alpha: self.keys.alpha.clone(),
518                beta: self.keys.beta[self.index],
519            };
520            self.index += 1;
521            Some(key)
522        } else {
523            None
524        }
525    }
526}
527
528impl<F: FieldExtension, M: Positive> ExactSizeIterator for FieldShareKeysIterator<F, M> {
529    fn len(&self) -> usize {
530        M::to_usize()
531    }
532}
533
534impl<F: FieldExtension, M: Positive> IntoIterator for FieldKeys<F, M> {
535    type Item = FieldKey<F>;
536    type IntoIter = FieldShareKeysIterator<F, M>;
537
538    fn into_iter(self) -> Self::IntoIter {
539        FieldShareKeysIterator::<F, M> {
540            keys: self,
541            index: 0,
542        }
543    }
544}
545
546pub struct FieldShareKeyRef<'a, F>
547where
548    F: FieldExtension,
549{
550    pub alpha: GlobalFieldKey<F>,
551    pub beta: &'a FieldElement<F>,
552}
553
554impl<'a, F: FieldExtension> From<FieldShareKeyRef<'a, F>> for FieldKey<F> {
555    fn from(val: FieldShareKeyRef<'a, F>) -> Self {
556        PairwiseAuthKey {
557            alpha: val.alpha,
558            beta: *val.beta,
559        }
560    }
561}
562
563pub struct FieldShareKeysRefIterator<'a, F, M>
564where
565    F: FieldExtension,
566    M: Positive,
567{
568    keys: &'a FieldKeys<F, M>,
569    index: usize,
570}
571
572impl<F: FieldExtension, M: Positive> ExactSizeIterator for FieldShareKeysRefIterator<'_, F, M> {
573    fn len(&self) -> usize {
574        M::to_usize()
575    }
576}
577
578impl<'a, F: FieldExtension, M: Positive> Iterator for FieldShareKeysRefIterator<'a, F, M> {
579    type Item = FieldShareKeyRef<'a, F>;
580
581    fn next(&mut self) -> Option<Self::Item> {
582        if self.index < M::to_usize() {
583            let key = FieldShareKeyRef {
584                alpha: self.keys.alpha.clone(),
585                beta: &self.keys.beta[self.index],
586            };
587            self.index += 1;
588            Some(key)
589        } else {
590            None
591        }
592    }
593}
594
595impl<'a, F: FieldExtension, M: Positive> IntoIterator for &'a FieldKeys<F, M> {
596    type Item = FieldShareKeyRef<'a, F>;
597    type IntoIter = FieldShareKeysRefIterator<'a, F, M>;
598
599    fn into_iter(self) -> Self::IntoIter {
600        FieldShareKeysRefIterator {
601            keys: self,
602            index: 0,
603        }
604    }
605}
606
607// --- Type conversions --- //
608
609impl<C: Curve> From<ScalarKey<C>> for CurveKey<C> {
610    #[inline]
611    fn from(scalar_key: ScalarKey<C>) -> Self {
612        PairwiseAuthKey {
613            alpha: scalar_key.alpha,
614            beta: scalar_key.beta * Point::<C>::generator(),
615        }
616    }
617}
618
619impl<C: Curve, M: Positive> From<ScalarKeys<C, M>> for CurveKeys<C, M> {
620    #[inline]
621    fn from(scalar_key: ScalarKeys<C, M>) -> Self {
622        PairwiseAuthKey {
623            alpha: scalar_key.alpha,
624            beta: scalar_key.beta * &Point::<C>::generator(),
625        }
626    }
627}
628
629#[cfg(test)]
630mod tests {
631    use typenum::{U10, U8};
632
633    use super::*;
634    use crate::algebra::elliptic_curve::{Curve25519Ristretto as C, ScalarAsExtension};
635
636    type Fq = ScalarAsExtension<C>;
637
638    #[test]
639    fn test_addition() {
640        let alpha = GlobalFieldKey::new(Fq::from(3u32));
641        let key1 = PairwiseAuthKey {
642            alpha: alpha.clone(),
643            beta: Fq::from(10u32),
644        };
645        let key2 = PairwiseAuthKey {
646            alpha: alpha.clone(),
647            beta: Fq::from(7u32),
648        };
649        let expected_result = PairwiseAuthKey {
650            alpha,
651            beta: Fq::from(17u32),
652        };
653        assert_eq!(key1 + key2, expected_result);
654    }
655
656    #[test]
657    fn test_subtraction() {
658        let alpha = GlobalFieldKey::new(Fq::from(3u32));
659        let key1 = PairwiseAuthKey {
660            alpha: alpha.clone(),
661            beta: Fq::from(10u32),
662        };
663        let key2 = PairwiseAuthKey {
664            alpha: alpha.clone(),
665            beta: Fq::from(7u32),
666        };
667        let expected_result = PairwiseAuthKey {
668            alpha,
669            beta: Fq::from(3u32),
670        };
671        assert_eq!(key1 - key2, expected_result);
672    }
673
674    #[test]
675    fn test_multiplication() {
676        let alpha = GlobalFieldKey::new(Fq::from(3u32));
677        let key = PairwiseAuthKey {
678            alpha: alpha.clone(),
679            beta: Fq::from(10u32),
680        };
681        let scalar = Fq::from(3u32);
682        let expected_result = PairwiseAuthKey {
683            alpha,
684            beta: Fq::from(30u32),
685        };
686        assert_eq!(key * scalar, expected_result);
687    }
688
689    #[test]
690    fn test_negation() {
691        let key = PairwiseAuthKey {
692            alpha: GlobalFieldKey::new(Fq::from(5u32)),
693            beta: Fq::from(10u32),
694        };
695        let expected_result = PairwiseAuthKey {
696            alpha: GlobalFieldKey::new(Fq::from(5u32)),
697            beta: -Fq::from(10u32),
698        };
699        assert_eq!(-key, expected_result);
700    }
701
702    #[test]
703    fn test_batched_addition() {
704        let alpha = GlobalFieldKey::new(Fq::from(3u32));
705        let key1 = PairwiseAuthKey {
706            alpha: alpha.clone(),
707            beta: HeapArray::<_, U10>::from_fn(|_| Fq::from(10u32)),
708        };
709        let key2 = PairwiseAuthKey {
710            alpha: alpha.clone(),
711            beta: HeapArray::<_, U10>::from_fn(|_| Fq::from(7u32)),
712        };
713        let expected_result = PairwiseAuthKey {
714            alpha,
715            beta: HeapArray::<_, U10>::from_fn(|_| Fq::from(17u32)),
716        };
717        assert_eq!(key1 + key2, expected_result);
718    }
719
720    #[test]
721    fn test_batched_subtraction() {
722        let alpha = GlobalFieldKey::new(Fq::from(3u32));
723        let key1 = PairwiseAuthKey {
724            alpha: alpha.clone(),
725            beta: HeapArray::<_, U10>::from_fn(|_| Fq::from(10u32)),
726        };
727        let key2 = PairwiseAuthKey {
728            alpha: alpha.clone(),
729            beta: HeapArray::<_, U10>::from_fn(|_| Fq::from(7u32)),
730        };
731        let expected_result = PairwiseAuthKey {
732            alpha,
733            beta: HeapArray::<_, U10>::from_fn(|_| Fq::from(3u32)),
734        };
735        assert_eq!(key1 - key2, expected_result);
736    }
737
738    #[test]
739    fn test_batched_multiplication() {
740        let alpha = GlobalFieldKey::new(Fq::from(3u32));
741        let key = PairwiseAuthKey {
742            alpha: alpha.clone(),
743            beta: HeapArray::<_, U10>::from_fn(|_| Fq::from(10u32)),
744        };
745        let scalar = Fq::from(3u32);
746        let expected_result = PairwiseAuthKey {
747            alpha,
748            beta: HeapArray::<_, U10>::from_fn(|_| Fq::from(30u32)),
749        };
750        assert_eq!(key * &scalar, expected_result);
751    }
752
753    #[test]
754    fn test_batched_negation() {
755        let key = PairwiseAuthKey {
756            alpha: GlobalFieldKey::new(Fq::from(5u32)),
757            beta: HeapArray::<_, U8>::from_fn(|_| Fq::from(10u32)),
758        };
759        let expected_result = PairwiseAuthKey {
760            alpha: GlobalFieldKey::new(Fq::from(5u32)),
761            beta: -HeapArray::<_, U8>::from_fn(|_| Fq::from(10u32)),
762        };
763        assert_eq!(-key, expected_result);
764    }
765
766    // --- CurveKey (single point) tests --- //
767
768    mod curve_single {
769        use super::*;
770        use crate::algebra::elliptic_curve::Curve25519Ristretto as C;
771
772        type P = Point<C>;
773        type FrExt = ScalarAsExtension<C>;
774
775        #[test]
776        fn test_addition() {
777            let mut rng = rand::thread_rng();
778            let alpha = GlobalCurveKey::<C>::new(FrExt::random(&mut rng));
779            let beta1 = P::random(&mut rng);
780            let beta2 = P::random(&mut rng);
781            let key1 = CurveKey {
782                alpha: alpha.clone(),
783                beta: beta1,
784            };
785            let key2 = CurveKey {
786                alpha: alpha.clone(),
787                beta: beta2,
788            };
789            let expected = CurveKey {
790                alpha,
791                beta: beta1 + beta2,
792            };
793            assert_eq!(key1 + key2, expected);
794        }
795
796        #[test]
797        fn test_subtraction() {
798            let mut rng = rand::thread_rng();
799            let alpha = GlobalCurveKey::<C>::new(FrExt::random(&mut rng));
800            let beta1 = P::random(&mut rng);
801            let beta2 = P::random(&mut rng);
802            let key1 = CurveKey {
803                alpha: alpha.clone(),
804                beta: beta1,
805            };
806            let key2 = CurveKey {
807                alpha: alpha.clone(),
808                beta: beta2,
809            };
810            let expected = CurveKey {
811                alpha,
812                beta: beta1 - beta2,
813            };
814            assert_eq!(key1 - key2, expected);
815        }
816
817        #[test]
818        fn test_multiplication() {
819            let mut rng = rand::thread_rng();
820            let alpha = GlobalCurveKey::<C>::new(FrExt::random(&mut rng));
821            let beta1 = P::random(&mut rng);
822            let key = CurveKey {
823                alpha: alpha.clone(),
824                beta: beta1,
825            };
826            let scalar = FrExt::from(3u32);
827            let expected = CurveKey {
828                alpha,
829                beta: beta1 * scalar,
830            };
831            assert_eq!(key * scalar, expected);
832        }
833
834        #[test]
835        fn test_negation() {
836            let mut rng = rand::thread_rng();
837            let alpha = GlobalCurveKey::<C>::new(FrExt::random(&mut rng));
838            let beta1 = P::random(&mut rng);
839            let key = CurveKey {
840                alpha: alpha.clone(),
841                beta: beta1,
842            };
843            let expected = CurveKey {
844                alpha,
845                beta: -beta1,
846            };
847            assert_eq!(-key, expected);
848        }
849    }
850
851    // --- CurveKeys (batched) tests --- //
852
853    mod curve_batched {
854        use typenum::U8;
855
856        use super::*;
857        use crate::{
858            algebra::elliptic_curve::Curve25519Ristretto as C,
859            random::{self, Random},
860            types::heap_array::CurvePoints,
861        };
862
863        type FrExt = ScalarAsExtension<C>;
864        type Ps = CurvePoints<C, U8>;
865
866        #[test]
867        fn test_addition() {
868            let mut rng = random::test_rng();
869            let alpha = GlobalCurveKey::<C>::random(&mut rng);
870            let beta1 = Ps::random(&mut rng);
871            let beta2 = Ps::random(&mut rng);
872            let key1 = CurveKeys {
873                alpha: alpha.clone(),
874                beta: beta1.clone(),
875            };
876            let key2 = CurveKeys {
877                alpha: alpha.clone(),
878                beta: beta2.clone(),
879            };
880            let expected = CurveKeys {
881                alpha,
882                beta: beta1 + beta2,
883            };
884            assert_eq!(key1 + key2, expected);
885        }
886
887        #[test]
888        fn test_subtraction() {
889            let mut rng = random::test_rng();
890            let alpha = GlobalCurveKey::<C>::random(&mut rng);
891            let beta1 = Ps::random(&mut rng);
892            let beta2 = Ps::random(&mut rng);
893            let key1 = CurveKeys {
894                alpha: alpha.clone(),
895                beta: beta1.clone(),
896            };
897            let key2 = CurveKeys {
898                alpha: alpha.clone(),
899                beta: beta2.clone(),
900            };
901            let expected = CurveKeys {
902                alpha,
903                beta: beta1 - beta2,
904            };
905            assert_eq!(key1 - key2, expected);
906        }
907
908        #[test]
909        fn test_multiplication() {
910            let mut rng = random::test_rng();
911            let alpha = GlobalCurveKey::<C>::random(&mut rng);
912            let beta1 = Ps::random(&mut rng);
913            let key = CurveKeys {
914                alpha: alpha.clone(),
915                beta: beta1.clone(),
916            };
917            let scalar = FrExt::from(3u32);
918            let expected = CurveKeys {
919                alpha,
920                beta: beta1 * &scalar,
921            };
922            assert_eq!(key * &scalar, expected);
923        }
924
925        #[test]
926        fn test_negation() {
927            let mut rng = random::test_rng();
928            let alpha = GlobalCurveKey::<C>::random(&mut rng);
929            let beta1 = Ps::random(&mut rng);
930            let key = CurveKeys {
931                alpha: alpha.clone(),
932                beta: beta1.clone(),
933            };
934            let expected = CurveKeys {
935                alpha,
936                beta: -beta1,
937            };
938            assert_eq!(-key, expected);
939        }
940    }
941}