2020-11-12 20:13:13 +00:00
|
|
|
//! This module contains the `Curve`/`CurveAffine` abstractions that allow us to
|
|
|
|
|
//! write code that generalizes over a pair of groups.
|
2020-08-22 20:15:39 +00:00
|
|
|
|
2021-12-22 05:41:04 +00:00
|
|
|
#[cfg(feature = "alloc")]
|
2021-02-22 19:02:53 +00:00
|
|
|
use group::prime::{PrimeCurve, PrimeCurveAffine};
|
2021-12-22 05:41:04 +00:00
|
|
|
#[cfg(feature = "alloc")]
|
2020-08-22 20:15:39 +00:00
|
|
|
use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption};
|
|
|
|
|
|
2021-12-22 05:41:04 +00:00
|
|
|
#[cfg(feature = "alloc")]
|
2022-11-24 09:41:35 +00:00
|
|
|
use super::FieldExt;
|
2020-08-22 20:15:39 +00:00
|
|
|
|
2021-12-22 05:41:04 +00:00
|
|
|
#[cfg(feature = "alloc")]
|
|
|
|
|
use alloc::boxed::Box;
|
|
|
|
|
#[cfg(feature = "alloc")]
|
|
|
|
|
use core::ops::{Add, Mul, Sub};
|
2021-01-12 15:22:35 +00:00
|
|
|
|
2020-08-22 20:15:39 +00:00
|
|
|
/// This trait is a common interface for dealing with elements of an elliptic
|
2021-01-13 13:24:47 +00:00
|
|
|
/// curve group in a "projective" form, where that arithmetic is usually more
|
2020-08-22 20:15:39 +00:00
|
|
|
/// efficient.
|
2021-09-20 16:44:11 +00:00
|
|
|
///
|
2021-12-22 05:41:04 +00:00
|
|
|
/// Requires the `alloc` feature flag because of `hash_to_curve`.
|
|
|
|
|
#[cfg(feature = "alloc")]
|
|
|
|
|
#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
|
2021-02-22 19:02:53 +00:00
|
|
|
pub trait CurveExt:
|
2021-02-22 22:47:57 +00:00
|
|
|
PrimeCurve<Affine = <Self as CurveExt>::AffineExt>
|
2021-02-22 19:02:53 +00:00
|
|
|
+ group::Group<Scalar = <Self as CurveExt>::ScalarExt>
|
2020-08-22 20:15:39 +00:00
|
|
|
+ Default
|
|
|
|
|
+ ConditionallySelectable
|
|
|
|
|
+ ConstantTimeEq
|
2021-02-22 19:02:53 +00:00
|
|
|
+ From<<Self as PrimeCurve>::Affine>
|
2020-08-22 20:15:39 +00:00
|
|
|
{
|
|
|
|
|
/// The scalar field of this elliptic curve.
|
2021-02-22 19:02:53 +00:00
|
|
|
type ScalarExt: FieldExt;
|
2020-08-22 20:15:39 +00:00
|
|
|
/// The base field over which this elliptic curve is constructed.
|
2020-11-13 00:08:08 +00:00
|
|
|
type Base: FieldExt;
|
2021-02-22 22:47:57 +00:00
|
|
|
/// The affine version of the curve
|
|
|
|
|
type AffineExt: CurveAffine<CurveExt = Self, ScalarExt = <Self as CurveExt>::ScalarExt>
|
|
|
|
|
+ Mul<Self::ScalarExt, Output = Self>
|
|
|
|
|
+ for<'r> Mul<Self::ScalarExt, Output = Self>;
|
2020-08-22 20:15:39 +00:00
|
|
|
|
2021-02-22 23:30:05 +00:00
|
|
|
/// CURVE_ID used for hash-to-curve.
|
|
|
|
|
const CURVE_ID: &'static str;
|
|
|
|
|
|
2020-08-22 20:15:39 +00:00
|
|
|
/// Apply the curve endomorphism by multiplying the x-coordinate
|
|
|
|
|
/// by an element of multiplicative order 3.
|
|
|
|
|
fn endo(&self) -> Self;
|
|
|
|
|
|
2021-01-13 13:24:47 +00:00
|
|
|
/// Return the Jacobian coordinates of this point.
|
|
|
|
|
fn jacobian_coordinates(&self) -> (Self::Base, Self::Base, Self::Base);
|
|
|
|
|
|
2021-02-02 18:36:06 +00:00
|
|
|
/// Requests a hasher that accepts messages and returns near-uniformly
|
2021-02-02 19:39:58 +00:00
|
|
|
/// distributed elements in the group, given domain prefix `domain_prefix`.
|
2021-02-02 18:36:06 +00:00
|
|
|
///
|
|
|
|
|
/// This method is suitable for use as a random oracle.
|
2021-02-02 19:39:58 +00:00
|
|
|
///
|
|
|
|
|
/// # Example
|
|
|
|
|
///
|
|
|
|
|
/// ```
|
2021-03-03 21:46:11 +00:00
|
|
|
/// use pasta_curves::arithmetic::CurveExt;
|
2021-02-22 19:02:53 +00:00
|
|
|
/// fn pedersen_commitment<C: CurveExt>(
|
|
|
|
|
/// x: C::ScalarExt,
|
|
|
|
|
/// r: C::ScalarExt,
|
2021-02-22 18:58:50 +00:00
|
|
|
/// ) -> C::Affine {
|
|
|
|
|
/// let hasher = C::hash_to_curve("z.cash:example_pedersen_commitment");
|
2021-02-02 19:39:58 +00:00
|
|
|
/// let g = hasher(b"g");
|
|
|
|
|
/// let h = hasher(b"h");
|
2021-02-04 15:09:08 +00:00
|
|
|
/// (g * x + &(h * r)).to_affine()
|
2021-02-02 19:39:58 +00:00
|
|
|
/// }
|
|
|
|
|
/// ```
|
2021-02-22 17:15:30 +00:00
|
|
|
fn hash_to_curve<'a>(domain_prefix: &'a str) -> Box<dyn Fn(&[u8]) -> Self + 'a>;
|
2021-02-02 18:36:06 +00:00
|
|
|
|
2020-08-22 20:15:39 +00:00
|
|
|
/// 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;
|
|
|
|
|
|
2021-01-13 13:24:47 +00:00
|
|
|
/// Returns the curve constant a.
|
|
|
|
|
fn a() -> Self::Base;
|
|
|
|
|
|
|
|
|
|
/// Returns the curve constant b.
|
2020-08-22 20:15:39 +00:00
|
|
|
fn b() -> Self::Base;
|
2021-01-13 13:24:47 +00:00
|
|
|
|
|
|
|
|
/// 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<Self>;
|
2020-08-22 20:15:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// This trait is the affine counterpart to `Curve` and is used for
|
|
|
|
|
/// serialization, storage in memory, and inspection of $x$ and $y$ coordinates.
|
2021-12-22 05:41:04 +00:00
|
|
|
///
|
|
|
|
|
/// Requires the `alloc` feature flag because of `hash_to_curve` on [`CurveExt`].
|
|
|
|
|
#[cfg(feature = "alloc")]
|
|
|
|
|
#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
|
2020-08-22 20:15:39 +00:00
|
|
|
pub trait CurveAffine:
|
2021-02-22 22:47:57 +00:00
|
|
|
PrimeCurveAffine<
|
|
|
|
|
Scalar = <Self as CurveAffine>::ScalarExt,
|
|
|
|
|
Curve = <Self as CurveAffine>::CurveExt,
|
|
|
|
|
> + Default
|
2021-02-22 19:02:53 +00:00
|
|
|
+ Add<Output = <Self as PrimeCurveAffine>::Curve>
|
|
|
|
|
+ Sub<Output = <Self as PrimeCurveAffine>::Curve>
|
2020-08-22 20:15:39 +00:00
|
|
|
+ ConditionallySelectable
|
|
|
|
|
+ ConstantTimeEq
|
2021-02-22 19:02:53 +00:00
|
|
|
+ From<<Self as PrimeCurveAffine>::Curve>
|
2020-08-22 20:15:39 +00:00
|
|
|
{
|
|
|
|
|
/// The scalar field of this elliptic curve.
|
2021-02-22 19:02:53 +00:00
|
|
|
type ScalarExt: FieldExt;
|
2020-08-22 20:15:39 +00:00
|
|
|
/// The base field over which this elliptic curve is constructed.
|
2020-11-13 00:08:08 +00:00
|
|
|
type Base: FieldExt;
|
2021-02-22 22:47:57 +00:00
|
|
|
/// The projective form of the curve
|
|
|
|
|
type CurveExt: CurveExt<AffineExt = Self, ScalarExt = <Self as CurveAffine>::ScalarExt>;
|
2020-08-22 20:15:39 +00:00
|
|
|
|
2021-04-17 21:21:18 +00:00
|
|
|
/// Gets the coordinates of this point.
|
|
|
|
|
///
|
|
|
|
|
/// Returns None if this is the identity.
|
|
|
|
|
fn coordinates(&self) -> CtOption<Coordinates<Self>>;
|
2020-08-22 20:15:39 +00:00
|
|
|
|
|
|
|
|
/// Obtains a point given $(x, y)$, failing if it is not on the
|
|
|
|
|
/// curve.
|
|
|
|
|
fn from_xy(x: Self::Base, y: Self::Base) -> CtOption<Self>;
|
|
|
|
|
|
|
|
|
|
/// 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;
|
|
|
|
|
|
2021-01-13 13:24:47 +00:00
|
|
|
/// Returns the curve constant $a$.
|
|
|
|
|
fn a() -> Self::Base;
|
|
|
|
|
|
|
|
|
|
/// Returns the curve constant $b$.
|
2020-08-22 20:15:39 +00:00
|
|
|
fn b() -> Self::Base;
|
|
|
|
|
}
|
2021-04-17 21:21:18 +00:00
|
|
|
|
|
|
|
|
/// The affine coordinates of a point on an elliptic curve.
|
2021-12-22 05:41:04 +00:00
|
|
|
#[cfg(feature = "alloc")]
|
|
|
|
|
#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
|
2021-04-17 21:21:18 +00:00
|
|
|
#[derive(Clone, Copy, Debug, Default)]
|
|
|
|
|
pub struct Coordinates<C: CurveAffine> {
|
2022-03-12 14:42:57 +00:00
|
|
|
pub(crate) x: C::Base,
|
|
|
|
|
pub(crate) y: C::Base,
|
2021-04-17 21:21:18 +00:00
|
|
|
}
|
|
|
|
|
|
2021-12-22 05:41:04 +00:00
|
|
|
#[cfg(feature = "alloc")]
|
2021-04-17 21:21:18 +00:00
|
|
|
impl<C: CurveAffine> Coordinates<C> {
|
2022-03-12 14:46:43 +00:00
|
|
|
/// Obtains a `Coordinates` value given $(x, y)$, failing if it is not on the curve.
|
|
|
|
|
pub fn from_xy(x: C::Base, y: C::Base) -> CtOption<Self> {
|
|
|
|
|
// We use CurveAffine::from_xy to validate the coordinates.
|
|
|
|
|
C::from_xy(x, y).map(|_| Coordinates { x, y })
|
|
|
|
|
}
|
2021-04-17 21:21:18 +00:00
|
|
|
/// 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
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-22 05:41:04 +00:00
|
|
|
#[cfg(feature = "alloc")]
|
2021-04-17 21:21:18 +00:00
|
|
|
impl<C: CurveAffine> ConditionallySelectable for Coordinates<C> {
|
|
|
|
|
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),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|