generic-ec-curves 0.3.0

Elliptic curves for `generic-ec` crate
Documentation
use core::ops::Mul;

use elliptic_curve::bigint::{ArrayEncoding, ByteArray, U256, U384, U512};
use elliptic_curve::{Curve, CurveArithmetic, Field, Group, ScalarPrimitive};
use generic_ec_core::{
    Additive, CurveGenerator, FromUniformBytes, IntegerEncoding, Invertible, Multiplicative, One,
    Reduce, SamplableVartime, Zero,
};
use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption};
use zeroize::DefaultIsZeroes;

/// Scalar wrapper
pub struct RustCryptoScalar<E: CurveArithmetic>(pub E::Scalar);

impl<E: CurveArithmetic> Additive for RustCryptoScalar<E> {
    fn add(a: &Self, b: &Self) -> Self {
        Self(a.0 + b.0)
    }

    fn sub(a: &Self, b: &Self) -> Self {
        Self(a.0 - b.0)
    }

    fn negate(x: &Self) -> Self {
        Self(-x.0)
    }
}

impl<E: CurveArithmetic> Multiplicative<RustCryptoScalar<E>> for RustCryptoScalar<E> {
    type Output = RustCryptoScalar<E>;

    fn mul(a: &Self, b: &RustCryptoScalar<E>) -> Self::Output {
        Self(a.0 * b.0)
    }
}

impl<E> Multiplicative<super::RustCryptoPoint<E>> for RustCryptoScalar<E>
where
    E: CurveArithmetic,
    for<'a> &'a E::ProjectivePoint: Mul<&'a E::Scalar, Output = E::ProjectivePoint>,
{
    type Output = super::RustCryptoPoint<E>;

    fn mul(a: &Self, b: &super::RustCryptoPoint<E>) -> Self::Output {
        super::RustCryptoPoint(b.0 * a.0)
    }
}

impl<E> Multiplicative<CurveGenerator> for RustCryptoScalar<E>
where
    E: CurveArithmetic,
    for<'a> &'a E::ProjectivePoint: Mul<&'a E::Scalar, Output = E::ProjectivePoint>,
{
    type Output = super::RustCryptoPoint<E>;

    fn mul(a: &Self, _b: &CurveGenerator) -> Self::Output {
        super::RustCryptoPoint(E::ProjectivePoint::generator() * a.0)
    }
}

impl<E: CurveArithmetic> Invertible for RustCryptoScalar<E> {
    fn invert(x: &Self) -> CtOption<Self> {
        x.0.invert().map(Self)
    }
}

impl<E: CurveArithmetic> Zero for RustCryptoScalar<E> {
    fn zero() -> Self {
        Self(E::Scalar::ZERO)
    }

    fn is_zero(x: &Self) -> subtle::Choice {
        x.0.is_zero()
    }
}

impl<E: CurveArithmetic> One for RustCryptoScalar<E> {
    fn one() -> Self {
        Self(E::Scalar::ONE)
    }

    fn is_one(x: &Self) -> Choice {
        x.0.ct_eq(&E::Scalar::ONE)
    }
}

#[cfg(feature = "secp256k1")]
impl FromUniformBytes for RustCryptoScalar<k256::Secp256k1> {
    /// 48 bytes
    ///
    /// `L = ceil((ceil(log2(q)) + k) / 8) = ceil((256 + 128) / 8) = 48` bytes are enough to
    /// guarantee the uniform distribution
    type Bytes = [u8; 48];
    fn from_uniform_bytes(bytes: &Self::Bytes) -> Self {
        let mut bytes_be = [0u8; 64];
        bytes_be[64 - 48..].copy_from_slice(bytes);
        <Self as Reduce<64>>::from_be_array_mod_order(&bytes_be)
    }
}
#[cfg(feature = "secp256r1")]
impl FromUniformBytes for RustCryptoScalar<p256::NistP256> {
    /// 48 bytes
    ///
    /// `L = ceil((ceil(log2(q)) + k) / 8) = ceil((256 + 128) / 8) = 48` bytes are enough to
    /// guarantee the uniform distribution
    type Bytes = [u8; 48];
    fn from_uniform_bytes(bytes: &Self::Bytes) -> Self {
        BytesModOrder::from_be_bytes_mod_order(bytes)
    }
}
#[cfg(feature = "secp384r1")]
impl FromUniformBytes for RustCryptoScalar<p384::NistP384> {
    /// 64 bytes
    ///
    /// `L = ceil((ceil(log2(q)) + k) / 8) = ceil((384 + 128) / 8) = 64` bytes are enough to
    /// guarantee the uniform distribution
    type Bytes = [u8; 64];
    fn from_uniform_bytes(bytes: &Self::Bytes) -> Self {
        BytesModOrder::from_be_bytes_mod_order(bytes)
    }
}
#[cfg(feature = "stark")]
impl FromUniformBytes for RustCryptoScalar<stark_curve::StarkCurve> {
    /// 48 bytes
    ///
    /// `L = ceil((ceil(log2(q)) + k) / 8) = ceil((256 + 128) / 8) = 48` bytes are enough to
    /// guarantee the uniform distribution
    type Bytes = [u8; 48];
    fn from_uniform_bytes(bytes: &Self::Bytes) -> Self {
        BytesModOrder::from_be_bytes_mod_order(bytes)
    }
}

impl<E: CurveArithmetic> SamplableVartime for RustCryptoScalar<E> {
    fn random_vartime(rng: &mut impl rand_core::RngCore) -> Self {
        use elliptic_curve::PrimeField;

        let mut bytes: <E::Scalar as PrimeField>::Repr = Default::default();
        loop {
            rng.fill_bytes(bytes.as_mut());

            if let Some(scalar) = <E::Scalar as PrimeField>::from_repr_vartime(bytes.clone()) {
                break Self(scalar);
            }
        }
    }
}

impl<E: CurveArithmetic> Default for RustCryptoScalar<E> {
    fn default() -> Self {
        Self(Default::default())
    }
}

impl<E: CurveArithmetic> Clone for RustCryptoScalar<E> {
    fn clone(&self) -> Self {
        *self
    }
}

impl<E: CurveArithmetic> Copy for RustCryptoScalar<E> {}

impl<E> DefaultIsZeroes for RustCryptoScalar<E>
where
    E: CurveArithmetic,
    E::Scalar: DefaultIsZeroes,
{
}

impl<E> PartialEq for RustCryptoScalar<E>
where
    E: CurveArithmetic,
    E::Scalar: PartialEq,
{
    fn eq(&self, other: &Self) -> bool {
        self.0 == other.0
    }
}

impl<E> Eq for RustCryptoScalar<E>
where
    E: CurveArithmetic,
    E::Scalar: Eq,
{
}

impl<E> ConstantTimeEq for RustCryptoScalar<E>
where
    E: CurveArithmetic,
    E::Scalar: ConstantTimeEq,
{
    fn ct_eq(&self, other: &Self) -> Choice {
        self.0.ct_eq(&other.0)
    }
}

impl<E> ConditionallySelectable for RustCryptoScalar<E>
where
    E: CurveArithmetic,
    E::Scalar: ConditionallySelectable,
{
    fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
        Self(E::Scalar::conditional_select(&a.0, &b.0, choice))
    }
}

impl<E: CurveArithmetic + Curve> IntegerEncoding for RustCryptoScalar<E>
where
    for<'s> ScalarPrimitive<E>: From<&'s E::Scalar>,
    E::Scalar: elliptic_curve::ops::Reduce<E::Uint>,
    Self: BytesModOrder,
{
    type Bytes = ByteArray<E::Uint>;

    fn to_be_bytes(&self) -> Self::Bytes {
        let scalar_core = ScalarPrimitive::<E>::from(&self.0);
        let uint = scalar_core.as_uint();
        uint.to_be_byte_array()
    }

    fn to_le_bytes(&self) -> Self::Bytes {
        let scalar_core = ScalarPrimitive::<E>::from(&self.0);
        let uint = scalar_core.as_uint();
        uint.to_le_byte_array()
    }

    fn from_be_bytes_exact(bytes: &Self::Bytes) -> Option<Self> {
        let uint = E::Uint::from_be_byte_array(bytes.clone());
        let scalar_core: Option<ScalarPrimitive<E>> = ScalarPrimitive::<E>::new(uint).into();
        Some(Self(E::Scalar::from(scalar_core?)))
    }

    fn from_le_bytes_exact(bytes: &Self::Bytes) -> Option<Self> {
        let uint = E::Uint::from_le_byte_array(bytes.clone());
        let scalar_core: Option<ScalarPrimitive<E>> = ScalarPrimitive::<E>::new(uint).into();
        Some(Self(E::Scalar::from(scalar_core?)))
    }

    fn from_be_bytes_mod_order(bytes: &[u8]) -> Self {
        <Self as BytesModOrder>::from_be_bytes_mod_order(bytes)
    }
    fn from_le_bytes_mod_order(bytes: &[u8]) -> Self {
        <Self as BytesModOrder>::from_le_bytes_mod_order(bytes)
    }
}

impl<E: CurveArithmetic + Curve> Reduce<32> for RustCryptoScalar<E>
where
    E::Scalar: elliptic_curve::ops::Reduce<U256>,
{
    fn from_be_array_mod_order(bytes: &[u8; 32]) -> Self {
        Self(elliptic_curve::ops::Reduce::<U256>::reduce(
            U256::from_be_byte_array((*bytes).into()),
        ))
    }
    fn from_le_array_mod_order(bytes: &[u8; 32]) -> Self {
        Self(elliptic_curve::ops::Reduce::<U256>::reduce(
            U256::from_le_byte_array((*bytes).into()),
        ))
    }
}

impl<E: CurveArithmetic + Curve> Reduce<64> for RustCryptoScalar<E>
where
    E::Scalar: elliptic_curve::ops::Reduce<U512>,
{
    fn from_be_array_mod_order(bytes: &[u8; 64]) -> Self {
        Self(elliptic_curve::ops::Reduce::<U512>::reduce(
            U512::from_be_byte_array((*bytes).into()),
        ))
    }
    fn from_le_array_mod_order(bytes: &[u8; 64]) -> Self {
        Self(elliptic_curve::ops::Reduce::<U512>::reduce(
            U512::from_le_byte_array((*bytes).into()),
        ))
    }
}

impl<E: CurveArithmetic + Curve> Reduce<48> for RustCryptoScalar<E>
where
    E::Scalar: elliptic_curve::ops::Reduce<U384>,
{
    fn from_be_array_mod_order(bytes: &[u8; 48]) -> Self {
        Self(elliptic_curve::ops::Reduce::<U384>::reduce(
            U384::from_be_byte_array((*bytes).into()),
        ))
    }
    fn from_le_array_mod_order(bytes: &[u8; 48]) -> Self {
        Self(elliptic_curve::ops::Reduce::<U384>::reduce(
            U384::from_le_byte_array((*bytes).into()),
        ))
    }
}

/// Choice of algorithm for computing bytes mod curve order. Efficient algorithm
/// is different for different curves.
pub(super) trait BytesModOrder {
    fn from_be_bytes_mod_order(bytes: &[u8]) -> Self;
    fn from_le_bytes_mod_order(bytes: &[u8]) -> Self;
}

#[cfg(feature = "secp256k1")]
impl BytesModOrder for RustCryptoScalar<k256::Secp256k1> {
    fn from_be_bytes_mod_order(bytes: &[u8]) -> Self {
        crate::utils::scalar_from_be_bytes_mod_order_reducing_32_64(bytes, &Self(k256::Scalar::ONE))
    }
    fn from_le_bytes_mod_order(bytes: &[u8]) -> Self {
        crate::utils::scalar_from_le_bytes_mod_order_reducing_32_64(bytes, &Self(k256::Scalar::ONE))
    }
}
#[cfg(feature = "secp256r1")]
impl BytesModOrder for RustCryptoScalar<p256::NistP256> {
    fn from_be_bytes_mod_order(bytes: &[u8]) -> Self {
        crate::utils::scalar_from_be_bytes_mod_order_reducing::<_, 32>(
            bytes,
            &Self(p256::Scalar::ONE),
        )
    }
    fn from_le_bytes_mod_order(bytes: &[u8]) -> Self {
        crate::utils::scalar_from_le_bytes_mod_order_reducing::<_, 32>(
            bytes,
            &Self(p256::Scalar::ONE),
        )
    }
}
#[cfg(feature = "secp384r1")]
impl BytesModOrder for RustCryptoScalar<p384::NistP384> {
    fn from_be_bytes_mod_order(bytes: &[u8]) -> Self {
        crate::utils::scalar_from_be_bytes_mod_order_reducing::<_, 48>(
            bytes,
            &Self(p384::Scalar::ONE),
        )
    }
    fn from_le_bytes_mod_order(bytes: &[u8]) -> Self {
        crate::utils::scalar_from_le_bytes_mod_order_reducing::<_, 48>(
            bytes,
            &Self(p384::Scalar::ONE),
        )
    }
}
#[cfg(feature = "stark")]
impl BytesModOrder for RustCryptoScalar<stark_curve::StarkCurve> {
    fn from_be_bytes_mod_order(bytes: &[u8]) -> Self {
        crate::utils::scalar_from_be_bytes_mod_order_reducing::<_, 32>(
            bytes,
            &Self(stark_curve::Scalar::ONE),
        )
    }
    fn from_le_bytes_mod_order(bytes: &[u8]) -> Self {
        crate::utils::scalar_from_le_bytes_mod_order_reducing::<_, 32>(
            bytes,
            &Self(stark_curve::Scalar::ONE),
        )
    }
}