//! This module contains the `Curve`/`CurveAffine` abstractions that allow us to //! write code that generalizes over a pair of groups. #[cfg(feature = "std")] use group::prime::{PrimeCurve, PrimeCurveAffine}; #[cfg(feature = "std")] use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}; #[cfg(feature = "std")] use super::{FieldExt, Group}; #[cfg(feature = "std")] use std::{ boxed::Box, ops::{Add, Mul, Sub}, }; /// This trait is a common interface for dealing with elements of an elliptic /// curve group in a "projective" form, where that arithmetic is usually more /// efficient. /// /// Currently requires the `std` feature flag because of `hash_to_curve`, and /// `CurveAffine::{read, write}`. #[cfg(feature = "std")] #[cfg_attr(docsrs, doc(cfg(feature = "std")))] pub trait CurveExt: PrimeCurve::AffineExt> + group::Group::ScalarExt> + Default + ConditionallySelectable + ConstantTimeEq + From<::Affine> + Group::Scalar> { /// The scalar field of this elliptic curve. type ScalarExt: FieldExt; /// The base field over which this elliptic curve is constructed. type Base: FieldExt; /// The affine version of the curve type AffineExt: CurveAffine::ScalarExt> + Mul + for<'r> Mul; /// CURVE_ID used for hash-to-curve. const CURVE_ID: &'static str; /// Apply the curve endomorphism by multiplying the x-coordinate /// by an element of multiplicative order 3. fn endo(&self) -> Self; /// Return the Jacobian coordinates of this point. fn jacobian_coordinates(&self) -> (Self::Base, Self::Base, Self::Base); /// Requests a hasher that accepts messages and returns near-uniformly /// distributed elements in the group, given domain prefix `domain_prefix`. /// /// This method is suitable for use as a random oracle. /// /// # Example /// /// ``` /// use pasta_curves::arithmetic::CurveExt; /// fn pedersen_commitment( /// x: C::ScalarExt, /// r: C::ScalarExt, /// ) -> C::Affine { /// let hasher = C::hash_to_curve("z.cash:example_pedersen_commitment"); /// let g = hasher(b"g"); /// let h = hasher(b"h"); /// (g * x + &(h * r)).to_affine() /// } /// ``` fn hash_to_curve<'a>(domain_prefix: &'a str) -> Box Self + 'a>; /// Returns whether or not this element is on the curve; should /// always be true unless an "unchecked" API was used. fn is_on_curve(&self) -> Choice; /// Returns the curve constant a. fn a() -> Self::Base; /// Returns the curve constant b. fn b() -> Self::Base; /// Obtains a point given Jacobian coordinates $X : Y : Z$, failing /// if the coordinates are not on the curve. fn new_jacobian(x: Self::Base, y: Self::Base, z: Self::Base) -> CtOption; } /// This trait is the affine counterpart to `Curve` and is used for /// serialization, storage in memory, and inspection of $x$ and $y$ coordinates. #[cfg(feature = "std")] #[cfg_attr(docsrs, doc(cfg(feature = "std")))] pub trait CurveAffine: PrimeCurveAffine< Scalar = ::ScalarExt, Curve = ::CurveExt, > + Default + Add::Curve> + Sub::Curve> + ConditionallySelectable + ConstantTimeEq + From<::Curve> { /// The scalar field of this elliptic curve. type ScalarExt: FieldExt; /// The base field over which this elliptic curve is constructed. type Base: FieldExt; /// The projective form of the curve type CurveExt: CurveExt::ScalarExt>; /// Gets the coordinates of this point. /// /// Returns None if this is the identity. fn coordinates(&self) -> CtOption>; /// Obtains a point given $(x, y)$, failing if it is not on the /// curve. fn from_xy(x: Self::Base, y: Self::Base) -> CtOption; /// Returns whether or not this element is on the curve; should /// always be true unless an "unchecked" API was used. fn is_on_curve(&self) -> Choice; /// Returns the curve constant $a$. fn a() -> Self::Base; /// Returns the curve constant $b$. fn b() -> Self::Base; } /// The affine coordinates of a point on an elliptic curve. #[cfg(feature = "std")] #[cfg_attr(docsrs, doc(cfg(feature = "std")))] #[derive(Clone, Copy, Debug, Default)] pub struct Coordinates { pub(crate) x: C::Base, pub(crate) y: C::Base, } #[cfg(feature = "std")] impl Coordinates { /// Returns the x-coordinate. /// /// Equivalent to `Coordinates::u`. pub fn x(&self) -> &C::Base { &self.x } /// Returns the y-coordinate. /// /// Equivalent to `Coordinates::v`. pub fn y(&self) -> &C::Base { &self.y } /// Returns the u-coordinate. /// /// Equivalent to `Coordinates::x`. pub fn u(&self) -> &C::Base { &self.x } /// Returns the v-coordinate. /// /// Equivalent to `Coordinates::y`. pub fn v(&self) -> &C::Base { &self.y } } #[cfg(feature = "std")] impl ConditionallySelectable for Coordinates { fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { Coordinates { x: C::Base::conditional_select(&a.x, &b.x, choice), y: C::Base::conditional_select(&a.y, &b.y, choice), } } }