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
}
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),
}
}
}
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),
}
}
}
#[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;
}
}
#[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;
}
}
#[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
}
}
#[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;
}
}
#[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,
}
}
}
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)
}
}
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);
}
}