-
Notifications
You must be signed in to change notification settings - Fork 32
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add extension traits for exposing coordinates of curve points #49
base: curveaffine
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.16.8/dist/katex.min.css" integrity="sha384-GvrOXuhMATgEsSwCs4smul74iXGOixntILdUW9XmUC6+HX0sLNAK3q71HotJqlAn" crossorigin="anonymous"> | ||
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.16.8/dist/katex.min.js" integrity="sha384-cpW21h6RZv/phavutF+AuVYrr+dA8xD9zs6FwLpaCct6O9ctzYFfFr4dgmgccOTx" crossorigin="anonymous"></script> | ||
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.16.8/dist/contrib/auto-render.min.js" integrity="sha384-+VBxd3r6XgURycqtZ117nYw44OOcIax56Z4dCRWbxyPt0Koah1uHoK0o4+/RRE05" crossorigin="anonymous"></script> | ||
<script> | ||
document.addEventListener("DOMContentLoaded", function() { | ||
renderMathInElement(document.body, { | ||
delimiters: [ | ||
{left: "$$", right: "$$", display: true}, | ||
{left: "\\(", right: "\\)", display: false}, | ||
{left: "$", right: "$", display: false}, | ||
{left: "\\[", right: "\\]", display: true} | ||
] | ||
}); | ||
}); | ||
</script> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,206 @@ | ||
//! Extension traits and structs that provide generic access to the coordinates of | ||
//! elliptic curve points. | ||
//! | ||
//! Coordinates are meaningless without the context of the curve equation that constrains | ||
//! them. To safely expose them in a generic context, we use extension traits to restrict | ||
//! the scope of the generic curve parameter; this ensures that the code can only be used | ||
//! with curve implementations that explicitly expose their use of a specific curve model. | ||
|
||
use subtle::{Choice, ConditionallySelectable, CtOption}; | ||
|
||
use crate::CurveAffine; | ||
|
||
// | ||
// Twisted Edwards curve | ||
// | ||
|
||
/// An affine elliptic curve point on a twisted Edwards curve | ||
/// $a \cdot x^2 + y^2 = 1 + d \cdot x^2 \cdot y^2$. | ||
pub trait TwistedEdwardsPoint: CurveAffine + Default + ConditionallySelectable { | ||
/// Field element type used in the curve equation. | ||
type Base: Copy + ConditionallySelectable; | ||
|
||
/// The parameter $a$ in the twisted Edwards curve equation. | ||
/// | ||
/// When $a = 1$, this reduces to an ordinary Edwards curve. | ||
const A: Self::Base; | ||
|
||
/// The parameter $d$ in the twisted Edwards curve equation. | ||
const D: Self::Base; | ||
Comment on lines
+17
to
+29
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not yet sure whether this trait should include the model parts as well, or whether that should be via an extension trait of the fn foo<C: Curve>() where C::Affine: TwistedEdwardsPoint {} However, if we're not going to expose model-related APIs on the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Question: is there a specific reason that From an API perspective, I think that'd mean writing There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
This is somewhat an artifact of the trait approach we've taken in the What I was suggesting above was that we would effectively do this split, by way of having an extension trait of So if we wanted to expose the projective representation, it would likely instead be an extension trait to the extension trait, which starts making the trait hierarchy quite complex, and we'd need a way to convey and manage that complexity. I'm not against
The core method that the current trait needs is So if we do split out a curve-only trait, we'd split this trait in the middle: have There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think I understand. I'm all for keeping it simple. Do you think there's an easy way to have to two representations for an Edwards point? This has affine but curve25519-dalek needs XYZT There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
@str4d FWIW, in the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
@rozbb to clarify, it needs to expose the coordinates of XYZT? If not and it just needs to use such points, that is already the case before this PR, and the idea behind the difference between the
If you want to expose the XYZT coordinates at all, then you can do that with concrete methods in
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is the main one (and also one of the main integration points with the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @str4d you're right, we don't need to expose our specific representation. Any equivalent one should do, at least for a first draft |
||
|
||
/// Obtains a point given $(x, y)$, failing if it is not on the curve. | ||
fn from_bare_coordinates(x: Self::Base, y: Self::Base) -> CtOption<Self>; | ||
|
||
/// Obtains a point given its coordinates. | ||
fn from_coordinates(coords: TwistedEdwardsCoordinates<Self>) -> Self; | ||
|
||
/// Returns the coordinates of this point. | ||
/// | ||
/// For twisted Edwards curves, the identity has valid coordinates on the curve, so | ||
/// this method is infallible. | ||
fn coordinates(&self) -> TwistedEdwardsCoordinates<Self>; | ||
} | ||
|
||
/// The affine coordinates for a [`TwistedEdwardsPoint`]. | ||
#[derive(Clone, Copy, Debug, Default)] | ||
pub struct TwistedEdwardsCoordinates<P: TwistedEdwardsPoint> { | ||
x: P::Base, | ||
y: P::Base, | ||
} | ||
|
||
impl<P: TwistedEdwardsPoint> TwistedEdwardsCoordinates<P> { | ||
/// Obtains a `TwistedEdwardsCoordinates` value given $(x, y)$, failing if it is not | ||
/// on the curve. | ||
pub fn from_coordinates(x: P::Base, y: P::Base) -> CtOption<Self> { | ||
// We use `P::from_bare_coordinates` to validate the coordinates. | ||
P::from_bare_coordinates(x, y).map(|_| TwistedEdwardsCoordinates { x, y }) | ||
} | ||
|
||
/// Returns the x-coordinate. | ||
pub fn x(&self) -> P::Base { | ||
self.x | ||
} | ||
|
||
/// Returns the y-coordinate. | ||
pub fn y(&self) -> P::Base { | ||
self.y | ||
} | ||
} | ||
|
||
impl<P: TwistedEdwardsPoint> ConditionallySelectable for TwistedEdwardsCoordinates<P> { | ||
fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { | ||
TwistedEdwardsCoordinates { | ||
x: P::Base::conditional_select(&a.x, &b.x, choice), | ||
y: P::Base::conditional_select(&a.y, &b.y, choice), | ||
} | ||
} | ||
} | ||
|
||
// | ||
// Montgomery curve | ||
// | ||
|
||
/// An affine elliptic curve point on a Montgomery curve | ||
/// $B \cdot v^2 = u^3 + A \cdot u^2 + u$. | ||
/// | ||
/// For these curves, it is required that $B \cdot (A^2 - 4) ≠ 0$, which implies that | ||
/// $A ≠ ±2$ and $B ≠ 0$. | ||
pub trait MontgomeryPoint: CurveAffine + Default + ConditionallySelectable { | ||
/// Field element type used in the curve equation. | ||
type Base: Copy + ConditionallySelectable; | ||
|
||
/// The parameter $A$ in the Montgomery curve equation. | ||
const A: Self::Base; | ||
|
||
/// The parameter $B$ in the Montgomery curve equation. | ||
const B: Self::Base; | ||
|
||
/// Obtains a point given $(u, v)$, failing if it is not on the curve. | ||
fn from_bare_coordinates(u: Self::Base, v: Self::Base) -> CtOption<Self>; | ||
|
||
/// Obtains a point given its coordinates. | ||
fn from_coordinates(coords: MontgomeryCoordinates<Self>) -> Self; | ||
|
||
/// Returns the coordinates of this point. | ||
/// | ||
/// Returns `None` if this is the identity. | ||
fn coordinates(&self) -> CtOption<MontgomeryCoordinates<Self>>; | ||
} | ||
|
||
/// The affine coordinates for a [`MontgomeryCoordinates`]. | ||
#[derive(Clone, Copy, Debug, Default)] | ||
pub struct MontgomeryCoordinates<P: MontgomeryPoint> { | ||
u: P::Base, | ||
v: P::Base, | ||
} | ||
|
||
impl<P: MontgomeryPoint> MontgomeryCoordinates<P> { | ||
/// Obtains a `MontgomeryCoordinates` value given $(u, v)$, failing if it is not on | ||
/// the curve. | ||
pub fn from_coordinates(u: P::Base, v: P::Base) -> CtOption<Self> { | ||
// We use `P::from_bare_coordinates` to validate the coordinates. | ||
P::from_bare_coordinates(u, v).map(|_| MontgomeryCoordinates { u, v }) | ||
} | ||
|
||
/// Returns the u-coordinate. | ||
pub fn u(&self) -> P::Base { | ||
self.u | ||
} | ||
|
||
/// Returns the v-coordinate. | ||
pub fn v(&self) -> P::Base { | ||
self.v | ||
} | ||
} | ||
|
||
impl<P: MontgomeryPoint> ConditionallySelectable for MontgomeryCoordinates<P> { | ||
fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { | ||
MontgomeryCoordinates { | ||
u: P::Base::conditional_select(&a.u, &b.u, choice), | ||
v: P::Base::conditional_select(&a.v, &b.v, choice), | ||
} | ||
} | ||
} | ||
|
||
// | ||
// Short Weierstrass curve | ||
// | ||
|
||
/// An affine elliptic curve point on a short Weierstrass curve | ||
/// $y^2 = x^3 + a \cdot x + b$. | ||
pub trait ShortWeierstrassPoint: CurveAffine + Default + ConditionallySelectable { | ||
/// Field element type used in the curve equation. | ||
type Base: Copy + ConditionallySelectable; | ||
|
||
/// The parameter $a$ in the short Weierstrass curve equation. | ||
const A: Self::Base; | ||
|
||
/// The parameter $b$ in the short Weierstrass curve equation. | ||
const B: Self::Base; | ||
|
||
/// Obtains a point given $(x, y)$, failing if it is not on the curve. | ||
fn from_bare_coordinates(x: Self::Base, y: Self::Base) -> CtOption<Self>; | ||
|
||
/// Obtains a point given its coordinates. | ||
fn from_coordinates(coords: ShortWeierstrassCoordinates<Self>) -> Self; | ||
|
||
/// Returns the coordinates of this point. | ||
/// | ||
/// Returns `None` if this is the identity. | ||
fn coordinates(&self) -> CtOption<ShortWeierstrassCoordinates<Self>>; | ||
} | ||
|
||
/// The affine coordinates for a [`ShortWeierstrassCoordinates`]. | ||
#[derive(Clone, Copy, Debug, Default)] | ||
pub struct ShortWeierstrassCoordinates<P: ShortWeierstrassPoint> { | ||
x: P::Base, | ||
y: P::Base, | ||
} | ||
|
||
impl<P: ShortWeierstrassPoint> ShortWeierstrassCoordinates<P> { | ||
/// Obtains a `ShortWeierstrassCoordinates` value given $(x, y)$, failing if it is not | ||
/// on the curve. | ||
pub fn from_coordinates(x: P::Base, y: P::Base) -> CtOption<Self> { | ||
// We use `P::from_bare_coordinates` to validate the coordinates. | ||
P::from_bare_coordinates(x, y).map(|_| ShortWeierstrassCoordinates { x, y }) | ||
} | ||
|
||
/// Returns the x-coordinate. | ||
pub fn x(&self) -> P::Base { | ||
self.x | ||
} | ||
|
||
/// Returns the y-coordinate. | ||
pub fn y(&self) -> P::Base { | ||
self.y | ||
} | ||
} | ||
|
||
impl<P: ShortWeierstrassPoint> ConditionallySelectable for ShortWeierstrassCoordinates<P> { | ||
fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { | ||
ShortWeierstrassCoordinates { | ||
x: P::Base::conditional_select(&a.x, &b.x, choice), | ||
y: P::Base::conditional_select(&a.y, &b.y, choice), | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, following the existing
group
crate conventions (given that we use the one trait to represent both the curve and points on the curve), we should probably name this: