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