pasta_curves/arithmetic/
curves.rs

1//! This module contains the `Curve`/`CurveAffine` abstractions that allow us to
2//! write code that generalizes over a pair of groups.
3
4#[cfg(feature = "alloc")]
5use group::prime::{PrimeCurve, PrimeCurveAffine};
6#[cfg(feature = "alloc")]
7use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption};
8
9#[cfg(feature = "alloc")]
10use alloc::boxed::Box;
11#[cfg(feature = "alloc")]
12use core::ops::{Add, Mul, Sub};
13
14/// This trait is a common interface for dealing with elements of an elliptic
15/// curve group in a "projective" form, where that arithmetic is usually more
16/// efficient.
17///
18/// Requires the `alloc` feature flag because of `hash_to_curve`.
19#[cfg(feature = "alloc")]
20#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
21pub trait CurveExt:
22    PrimeCurve<Affine = <Self as CurveExt>::AffineExt>
23    + group::Group<Scalar = <Self as CurveExt>::ScalarExt>
24    + Default
25    + ConditionallySelectable
26    + ConstantTimeEq
27    + From<<Self as PrimeCurve>::Affine>
28{
29    /// The scalar field of this elliptic curve.
30    type ScalarExt: ff::WithSmallOrderMulGroup<3>;
31    /// The base field over which this elliptic curve is constructed.
32    type Base: ff::WithSmallOrderMulGroup<3>;
33    /// The affine version of the curve
34    type AffineExt: CurveAffine<CurveExt = Self, ScalarExt = <Self as CurveExt>::ScalarExt>
35        + Mul<Self::ScalarExt, Output = Self>
36        + for<'r> Mul<Self::ScalarExt, Output = Self>;
37
38    /// CURVE_ID used for hash-to-curve.
39    const CURVE_ID: &'static str;
40
41    /// Apply the curve endomorphism by multiplying the x-coordinate
42    /// by an element of multiplicative order 3.
43    fn endo(&self) -> Self;
44
45    /// Return the Jacobian coordinates of this point.
46    fn jacobian_coordinates(&self) -> (Self::Base, Self::Base, Self::Base);
47
48    /// Requests a hasher that accepts messages and returns near-uniformly
49    /// distributed elements in the group, given domain prefix `domain_prefix`.
50    ///
51    /// This method is suitable for use as a random oracle.
52    ///
53    /// # Example
54    ///
55    /// ```
56    /// use pasta_curves::arithmetic::CurveExt;
57    /// fn pedersen_commitment<C: CurveExt>(
58    ///     x: C::ScalarExt,
59    ///     r: C::ScalarExt,
60    /// ) -> C::Affine {
61    ///     let hasher = C::hash_to_curve("z.cash:example_pedersen_commitment");
62    ///     let g = hasher(b"g");
63    ///     let h = hasher(b"h");
64    ///     (g * x + &(h * r)).to_affine()
65    /// }
66    /// ```
67    fn hash_to_curve<'a>(domain_prefix: &'a str) -> Box<dyn Fn(&[u8]) -> Self + 'a>;
68
69    /// Returns whether or not this element is on the curve; should
70    /// always be true unless an "unchecked" API was used.
71    fn is_on_curve(&self) -> Choice;
72
73    /// Returns the curve constant a.
74    fn a() -> Self::Base;
75
76    /// Returns the curve constant b.
77    fn b() -> Self::Base;
78
79    /// Obtains a point given Jacobian coordinates $X : Y : Z$, failing
80    /// if the coordinates are not on the curve.
81    fn new_jacobian(x: Self::Base, y: Self::Base, z: Self::Base) -> CtOption<Self>;
82}
83
84/// This trait is the affine counterpart to `Curve` and is used for
85/// serialization, storage in memory, and inspection of $x$ and $y$ coordinates.
86///
87/// Requires the `alloc` feature flag because of `hash_to_curve` on [`CurveExt`].
88#[cfg(feature = "alloc")]
89#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
90pub trait CurveAffine:
91    PrimeCurveAffine<
92        Scalar = <Self as CurveAffine>::ScalarExt,
93        Curve = <Self as CurveAffine>::CurveExt,
94    > + Default
95    + Add<Output = <Self as PrimeCurveAffine>::Curve>
96    + Sub<Output = <Self as PrimeCurveAffine>::Curve>
97    + ConditionallySelectable
98    + ConstantTimeEq
99    + From<<Self as PrimeCurveAffine>::Curve>
100{
101    /// The scalar field of this elliptic curve.
102    type ScalarExt: ff::WithSmallOrderMulGroup<3> + Ord;
103    /// The base field over which this elliptic curve is constructed.
104    type Base: ff::WithSmallOrderMulGroup<3> + Ord;
105    /// The projective form of the curve
106    type CurveExt: CurveExt<AffineExt = Self, ScalarExt = <Self as CurveAffine>::ScalarExt>;
107
108    /// Gets the coordinates of this point.
109    ///
110    /// Returns None if this is the identity.
111    fn coordinates(&self) -> CtOption<Coordinates<Self>>;
112
113    /// Obtains a point given $(x, y)$, failing if it is not on the
114    /// curve.
115    fn from_xy(x: Self::Base, y: Self::Base) -> CtOption<Self>;
116
117    /// Returns whether or not this element is on the curve; should
118    /// always be true unless an "unchecked" API was used.
119    fn is_on_curve(&self) -> Choice;
120
121    /// Returns the curve constant $a$.
122    fn a() -> Self::Base;
123
124    /// Returns the curve constant $b$.
125    fn b() -> Self::Base;
126}
127
128/// The affine coordinates of a point on an elliptic curve.
129#[cfg(feature = "alloc")]
130#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
131#[derive(Clone, Copy, Debug, Default)]
132pub struct Coordinates<C: CurveAffine> {
133    pub(crate) x: C::Base,
134    pub(crate) y: C::Base,
135}
136
137#[cfg(feature = "alloc")]
138impl<C: CurveAffine> Coordinates<C> {
139    /// Obtains a `Coordinates` value given $(x, y)$, failing if it is not on the curve.
140    pub fn from_xy(x: C::Base, y: C::Base) -> CtOption<Self> {
141        // We use CurveAffine::from_xy to validate the coordinates.
142        C::from_xy(x, y).map(|_| Coordinates { x, y })
143    }
144    /// Returns the x-coordinate.
145    ///
146    /// Equivalent to `Coordinates::u`.
147    pub fn x(&self) -> &C::Base {
148        &self.x
149    }
150
151    /// Returns the y-coordinate.
152    ///
153    /// Equivalent to `Coordinates::v`.
154    pub fn y(&self) -> &C::Base {
155        &self.y
156    }
157
158    /// Returns the u-coordinate.
159    ///
160    /// Equivalent to `Coordinates::x`.
161    pub fn u(&self) -> &C::Base {
162        &self.x
163    }
164
165    /// Returns the v-coordinate.
166    ///
167    /// Equivalent to `Coordinates::y`.
168    pub fn v(&self) -> &C::Base {
169        &self.y
170    }
171}
172
173#[cfg(feature = "alloc")]
174impl<C: CurveAffine> ConditionallySelectable for Coordinates<C> {
175    fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
176        Coordinates {
177            x: C::Base::conditional_select(&a.x, &b.x, choice),
178            y: C::Base::conditional_select(&a.y, &b.y, choice),
179        }
180    }
181}