arcium-primitives 0.8.0

Arcium primitives
Documentation
use std::hash::Hash;

use derive_more::derive::Display;
use elliptic_curve::{
    group::{self, GroupEncoding},
    ops::{Invert, MulByGenerator},
    scalar::{FromUintUnchecked, IsHigh},
    Curve as EllipticCurve,
    FieldBytes,
    ScalarPrimitive,
};
use ff::PrimeField;
use hybrid_array::{Array, ArraySize};
use subtle::{ConditionallySelectable, ConstantTimeEq, CtOption};

use crate::algebra::{
    field::{FieldElement, FieldExtension, SubfieldElement},
    uniform_bytes::FromUniformBytes,
};

// Defines a curve that can be encoded and decoded into bytes.
// This is a reduced version of the elliptic_curve::CurveArithmetic trait that is suitable for our
// MPC purposes. In particular, we removed the AffinePoint type.
pub trait Curve: EllipticCurve + Hash {
    /// Name of the curve, used for domain separation.
    const NAME: &'static str;
    /// Whether this curve uses big-endian for its scalar encoding natively.
    const SCALAR_BIG_ENDIAN: bool;
    /// Whether this curve uses big-endian for its point encoding natively.
    const POINT_BIG_ENDIAN: bool;

    const BASE_FIELD_BIG_ENDIAN: bool;
    /// Elliptic curve point in projective coordinates.
    ///
    /// Note: the following bounds are provided by [`group::Group`]:
    /// - `'static`
    /// - [`Copy`]
    /// - [`Clone`]
    /// - [`Debug`]
    /// - [`Eq`]
    /// - [`Sized`]
    /// - [`Send`]
    /// - [`Sync`]
    type Point: ConditionallySelectable
        + ConstantTimeEq
        + Default
        // Implemented differently for Dalek
        // + DefaultIsZeroes

        // These require Affine Repr
        // + LinearCombination<[(Self::ProjectivePoint, Self::Scalar)]>
        // + LinearCombination<[(Self::ProjectivePoint, Self::Scalar); 2]>
        + MulByGenerator
        + group::Group<Scalar = Self::Scalar>
        + GroupEncoding
        + Hash
        + ToCoordinates<BaseFieldElement = BaseFieldElement<Self>>
        + FromCoordinates<
            BaseFieldElement = BaseFieldElement<Self>,
            NumCoordinates = <Self::Point as ToCoordinates>::NumCoordinates,
        >;

    /// Scalar field modulo this curve's order.
    ///
    /// Note: the following bounds are provided by [`ff::Field`]:
    /// - `'static`
    /// - [`Copy`]
    /// - [`Clone`]
    /// - [`ConditionallySelectable`]
    /// - [`ConstantTimeEq`]
    /// - [`Debug`]
    /// - [`Default`]
    /// - [`Send`]
    /// - [`Sync`]
    type Scalar: AsRef<Self::Scalar>
        // + DefaultIsZeroes
        + From<ScalarPrimitive<Self>>
        + FromUintUnchecked<Uint = Self::Uint>
        + Into<FieldBytes<Self>>
        + Into<ScalarPrimitive<Self>>
        + Into<Self::Uint>
        + Invert<Output = CtOption<Self::Scalar>>
        + FromUniformBytes
        + IsHigh
        + PartialOrd
        + PrimeField
        + FieldExtension<Subfield = Self::Scalar>
        + Hash;

    type BaseField: PrimeField + FieldExtension + FromUniformBytes + Hash;

    fn hash_to_curve(bytes: &[u8]) -> Self::Point;
}

/// Construction of a point from coordinates in the representation chosen by the implementor
/// (e.g. extended Edwards [X, Y, Z, T] for Curve25519, projective Weierstrass [X, Y, Z] for
/// P-384).
pub trait FromCoordinates: Sized {
    type BaseFieldElement;
    /// Number of coordinates in the chosen representation.
    type NumCoordinates: ArraySize;

    /// Attempts to construct a point from its coordinates. Returns `None` if the coordinates do
    /// not encode a valid point.
    fn from_coordinates(
        coordinates: Array<Self::BaseFieldElement, Self::NumCoordinates>,
    ) -> Option<Self>;
}

#[derive(Debug, Display)]
pub struct PointAtInfinityError;

/// Conversion of a point to coordinates in the representation chosen by the implementor.
/// The representation must be canonical: all nodes must obtain identical coordinates for the
/// same point (required for MAC checks).
pub trait ToCoordinates {
    type BaseFieldElement;
    /// Number of coordinates in the chosen representation.
    type NumCoordinates: ArraySize;

    fn to_coordinates(
        self,
    ) -> Result<Array<Self::BaseFieldElement, Self::NumCoordinates>, PointAtInfinityError>;
}

/// The scalar field of the curve.
pub type ScalarField<C> = <C as Curve>::Scalar;
/// The base field (coordinates of the points) of the curve.
pub type BaseField<C> = <C as Curve>::BaseField;

/// The scalar field of the curve as a subfield element.
pub type Scalar<C> = SubfieldElement<ScalarField<C>>;
/// The base field of the curve as a subfield element.
pub type BaseFieldElement<C> = SubfieldElement<BaseField<C>>;

/// The scalar field of the curve as a field extension element.
pub type ScalarAsExtension<C> = FieldElement<<C as Curve>::Scalar>;
/// The base field of the curve as a field extension element.
pub type BaseFieldAsExtension<C> = FieldElement<BaseField<C>>;

/// The number of coordinates in the point representation chosen by the curve's point type.
pub type NumCoordinates<C> = <<C as Curve>::Point as ToCoordinates>::NumCoordinates;
/// The coordinates of a point, in the representation chosen by the curve's point type.
pub type PointCoordinates<C> = Array<BaseFieldElement<C>, NumCoordinates<C>>;