arcium-primitives 0.4.0

Arcium primitives
Documentation
use std::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign};

use serde::{Deserialize, Serialize};
use subtle::{Choice, ConstantTimeEq};

use super::{OpenPointShares, ScalarKeys};
use crate::{
    algebra::elliptic_curve::{Curve, Point, Scalar, ScalarAsExtension},
    errors::PrimitiveError,
    random::{CryptoRngCore, Random, RandomWith},
    sharing::GlobalCurveKey,
    types::{
        heap_array::curve_arrays::{CurvePoints, Scalars, ScalarsAsExtension},
        ConditionallySelectable,
        Positive,
    },
};

#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
#[serde(bound = "C: Curve, M: Positive")]
pub struct CurveKeys<C: Curve, M: Positive> {
    pub(crate) alpha: GlobalCurveKey<C>,
    pub(crate) betas: CurvePoints<C, M>,
}

impl<C: Curve, M: Positive> CurveKeys<C, M> {
    pub fn new(alpha: GlobalCurveKey<C>, betas: CurvePoints<C, M>) -> Self {
        CurveKeys { alpha, betas }
    }

    pub fn get_alpha(&self) -> GlobalCurveKey<C> {
        self.alpha.clone()
    }

    pub fn get_alpha_value(&self) -> ScalarAsExtension<C> {
        *self.alpha
    }

    pub fn get_betas(&self) -> &CurvePoints<C, M> {
        &self.betas
    }

    /* === Verification === */

    pub fn compute_mac(&self, values: &CurvePoints<C, M>) -> CurvePoints<C, M> {
        values * *self.alpha + &self.betas
    }

    #[inline]
    pub fn verify_mac(&self, open_shares: &OpenPointShares<C, M>) -> Result<(), PrimitiveError> {
        let computed_macs = self.compute_mac(open_shares.get_value());
        bool::from(computed_macs.ct_eq(open_shares.get_mac()))
            .then_some(())
            .ok_or_else(|| {
                PrimitiveError::WrongMAC(serde_json::to_string(open_shares.get_mac()).unwrap())
            })
    }
}

impl<C: Curve, M: Positive> ConditionallySelectable for CurveKeys<C, M> {
    fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
        CurveKeys {
            alpha: GlobalCurveKey::<C>::conditional_select(&a.alpha, &b.alpha, choice),
            betas: CurvePoints::conditional_select(&a.betas, &b.betas, choice),
        }
    }
}

// -------------------------
// |   Random Generation   |
// -------------------------

impl<C: Curve, M: Positive> Random for CurveKeys<C, M> {
    fn random(mut rng: impl CryptoRngCore) -> Self {
        let alpha = GlobalCurveKey::<C>::random(&mut rng);
        let betas = CurvePoints::random(&mut rng);
        CurveKeys { alpha, betas }
    }
}

impl<C: Curve, M: Positive> RandomWith<GlobalCurveKey<C>> for CurveKeys<C, M> {
    fn random_with(mut rng: impl CryptoRngCore, alpha: GlobalCurveKey<C>) -> Self {
        CurveKeys {
            alpha,
            betas: CurvePoints::random(&mut rng),
        }
    }
}

// ------------------------------------
// | Curve Arithmetic Implementations |
// ------------------------------------

// === Addition === //

#[macros::op_variants(owned, borrowed, flipped_commutative)]
impl<'a, C: Curve, M: Positive> Add<&'a CurveKeys<C, M>> for CurveKeys<C, M> {
    type Output = CurveKeys<C, M>;

    #[inline]
    fn add(mut self, other: &'a CurveKeys<C, M>) -> Self::Output {
        assert_eq!(self.alpha, other.alpha);
        self.betas += &other.betas;
        self
    }
}

#[macros::op_variants(owned)]
impl<'a, C: Curve, M: Positive> AddAssign<&'a CurveKeys<C, M>> for CurveKeys<C, M> {
    #[inline]
    fn add_assign(&mut self, rhs: &'a CurveKeys<C, M>) {
        assert_eq!(self.alpha, rhs.alpha);
        self.betas += &rhs.betas;
    }
}

// === Subtraction === //

#[macros::op_variants(owned, borrowed, flipped)]
impl<'a, C: Curve, M: Positive> Sub<&'a CurveKeys<C, M>> for CurveKeys<C, M> {
    type Output = CurveKeys<C, M>;

    #[inline]
    fn sub(mut self, other: &'a CurveKeys<C, M>) -> Self::Output {
        assert_eq!(self.alpha, other.alpha);
        self.betas -= &other.betas;
        self
    }
}

#[macros::op_variants(owned)]
impl<'a, C: Curve, M: Positive> SubAssign<&'a CurveKeys<C, M>> for CurveKeys<C, M> {
    #[inline]
    fn sub_assign(&mut self, rhs: &'a CurveKeys<C, M>) {
        assert_eq!(self.alpha, rhs.alpha);
        self.betas -= &rhs.betas;
    }
}

// === (Scalar) Multiplication === //

#[macros::op_variants(owned, borrowed)]
impl<'a, C: Curve, M: Positive> Mul<&'a ScalarAsExtension<C>> for CurveKeys<C, M> {
    type Output = CurveKeys<C, M>;

    #[inline]
    fn mul(mut self, other: &'a ScalarAsExtension<C>) -> Self::Output {
        self.betas *= other;
        self
    }
}

#[macros::op_variants(owned, borrowed)]
impl<'a, C: Curve, M: Positive> Mul<&'a Scalar<C>> for CurveKeys<C, M> {
    type Output = CurveKeys<C, M>;

    #[inline]
    fn mul(mut self, other: &'a Scalar<C>) -> Self::Output {
        self.betas *= other;
        self
    }
}

#[macros::op_variants(owned, borrowed)]
impl<'a, C: Curve, M: Positive> Mul<&'a ScalarsAsExtension<C, M>> for CurveKeys<C, M> {
    type Output = CurveKeys<C, M>;

    #[inline]
    fn mul(mut self, other: &'a ScalarsAsExtension<C, M>) -> Self::Output {
        self.betas *= other;
        self
    }
}

#[macros::op_variants(owned, borrowed)]
impl<'a, C: Curve, M: Positive> Mul<&'a Scalars<C, M>> for CurveKeys<C, M> {
    type Output = CurveKeys<C, M>;

    #[inline]
    fn mul(mut self, other: &'a Scalars<C, M>) -> Self::Output {
        self.betas *= other;
        self
    }
}

// === MulAssign === //

#[macros::op_variants(owned)]
impl<'a, C: Curve, M: Positive> MulAssign<&'a ScalarAsExtension<C>> for CurveKeys<C, M> {
    #[inline]
    fn mul_assign(&mut self, rhs: &'a ScalarAsExtension<C>) {
        self.betas *= rhs;
    }
}

#[macros::op_variants(owned)]
impl<'a, C: Curve, M: Positive> MulAssign<&'a Scalar<C>> for CurveKeys<C, M> {
    #[inline]
    fn mul_assign(&mut self, rhs: &'a Scalar<C>) {
        self.betas *= rhs;
    }
}

#[macros::op_variants(owned)]
impl<'a, C: Curve, M: Positive> MulAssign<&'a ScalarsAsExtension<C, M>> for CurveKeys<C, M> {
    #[inline]
    fn mul_assign(&mut self, rhs: &'a ScalarsAsExtension<C, M>) {
        self.betas *= rhs;
    }
}

#[macros::op_variants(owned)]
impl<'a, C: Curve, M: Positive> MulAssign<&'a Scalars<C, M>> for CurveKeys<C, M> {
    #[inline]
    fn mul_assign(&mut self, rhs: &'a Scalars<C, M>) {
        self.betas *= rhs;
    }
}
// === Negation === //

#[macros::op_variants(borrowed)]
impl<C: Curve, M: Positive> Neg for CurveKeys<C, M> {
    type Output = CurveKeys<C, M>;

    #[inline]
    fn neg(self) -> Self::Output {
        CurveKeys {
            alpha: self.alpha,
            betas: -self.betas,
        }
    }
}

// === Equality === //

impl<C: Curve, M: Positive> ConstantTimeEq for CurveKeys<C, M> {
    #[inline]
    fn ct_eq(&self, other: &Self) -> Choice {
        self.alpha.ct_eq(&other.alpha) & self.betas.ct_eq(&other.betas)
    }
}

// === Type conversions === //

impl<C: Curve, M: Positive> From<ScalarKeys<C, M>> for CurveKeys<C, M> {
    #[inline]
    fn from(scalar_key: ScalarKeys<C, M>) -> Self {
        CurveKeys {
            alpha: scalar_key.alpha,
            betas: scalar_key.betas * Point::<C>::generator(),
        }
    }
}

#[cfg(test)]
mod tests {
    use typenum::U8;

    use super::*;
    use crate::{
        algebra::elliptic_curve::Curve25519Ristretto as C,
        random::{self, Random},
    };
    pub type FrExt = ScalarAsExtension<C>;
    pub type Ps = CurvePoints<C, U8>;

    #[test]
    fn test_addition() {
        let mut rng = random::test_rng();
        let alpha = GlobalCurveKey::<C>::random(&mut rng);
        let beta1 = Ps::random(&mut rng);
        let beta2 = Ps::random(&mut rng);

        let key1 = CurveKeys {
            alpha: alpha.clone(),
            betas: beta1.clone(),
        };
        let key2 = CurveKeys {
            alpha: alpha.clone(),
            betas: beta2.clone(),
        };
        let expected_result = CurveKeys {
            alpha,
            betas: beta1 + beta2,
        };
        assert_eq!(key1 + key2, expected_result);
    }

    #[test]
    fn test_subtraction() {
        let mut rng = random::test_rng();
        let alpha = GlobalCurveKey::<C>::random(&mut rng);
        let beta1 = Ps::random(&mut rng);
        let beta2 = Ps::random(&mut rng);

        let key1 = CurveKeys {
            alpha: alpha.clone(),
            betas: beta1.clone(),
        };
        let key2 = CurveKeys {
            alpha: alpha.clone(),
            betas: beta2.clone(),
        };
        let expected_result = CurveKeys {
            alpha,
            betas: beta1 - beta2,
        };
        assert_eq!(key1 - key2, expected_result);
    }

    #[test]
    fn test_multiplication() {
        let mut rng = random::test_rng();
        let alpha = GlobalCurveKey::<C>::random(&mut rng);
        let beta1 = Ps::random(&mut rng);

        let key = CurveKeys {
            alpha: alpha.clone(),
            betas: beta1.clone(),
        };
        let scalar = FrExt::from(3u32);
        let expected_result = CurveKeys {
            alpha,
            betas: beta1 * scalar,
        };
        assert_eq!(key * scalar, expected_result);
    }

    #[test]
    fn test_negation() {
        let mut rng = random::test_rng();
        let alpha = GlobalCurveKey::<C>::random(&mut rng);
        let beta1 = Ps::random(&mut rng);

        let key = CurveKeys {
            alpha: alpha.clone(),
            betas: beta1.clone(),
        };
        let expected_result = CurveKeys {
            alpha,
            betas: -beta1,
        };
        assert_eq!(-key, expected_result);
    }
}