Skip to content

Commit a81a1f8

Browse files
committed
Add full-coordinate MontgomeryPoint skeleton
1 parent fa1b45d commit a81a1f8

File tree

4 files changed

+256
-3
lines changed

4 files changed

+256
-3
lines changed

ed448-goldilocks/src/lib.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,9 @@ pub use edwards::{
6060
WideEdwardsScalarBytes,
6161
};
6262
pub use field::{MODULUS_LIMBS, ORDER, Scalar, WIDE_ORDER};
63-
pub use montgomery::{MontgomeryXpoint, ProjectiveMontgomeryXpoint};
63+
pub use montgomery::{
64+
MontgomeryPoint, MontgomeryXpoint, ProjectiveMontgomeryPoint, ProjectiveMontgomeryXpoint,
65+
};
6466
#[cfg(feature = "signing")]
6567
pub use sign::*;
6668

@@ -169,3 +171,7 @@ impl elliptic_curve::CurveArithmetic for Decaf448 {
169171
impl GroupDigest for Decaf448 {
170172
type K = U28;
171173
}
174+
175+
/// Curve448 curve.
176+
#[derive(Copy, Clone, Debug, Default, Eq, PartialEq, Ord, PartialOrd, Hash)]
177+
pub struct Curve448;

ed448-goldilocks/src/montgomery.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010

1111
#![allow(non_snake_case)]
1212

13+
mod point;
1314
mod x;
1415

16+
pub use point::{MontgomeryPoint, ProjectiveMontgomeryPoint};
1517
pub use x::{MontgomeryXpoint, ProjectiveMontgomeryXpoint};
Lines changed: 201 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,201 @@
1+
use elliptic_curve::bigint::U448;
2+
use subtle::Choice;
3+
use subtle::ConditionallySelectable;
4+
use subtle::ConstantTimeEq;
5+
6+
use super::{MontgomeryXpoint, ProjectiveMontgomeryXpoint};
7+
use crate::field::{ConstMontyType, FieldElement};
8+
9+
/// A point in Montgomery form including the y-coordinate.
10+
#[derive(Copy, Clone, Debug, Default, Eq)]
11+
pub struct MontgomeryPoint {
12+
pub(super) x: FieldElement,
13+
pub(super) y: FieldElement,
14+
}
15+
16+
impl MontgomeryPoint {
17+
/// The identity element of the group: the point at infinity.
18+
pub const IDENTITY: Self = Self {
19+
x: FieldElement::ZERO,
20+
y: FieldElement::ONE,
21+
};
22+
23+
pub(crate) fn new(x: FieldElement, y: FieldElement) -> Self {
24+
Self { x, y }
25+
}
26+
}
27+
28+
impl ConditionallySelectable for MontgomeryPoint {
29+
fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
30+
Self {
31+
x: FieldElement::conditional_select(&a.x, &b.x, choice),
32+
y: FieldElement::conditional_select(&a.y, &b.y, choice),
33+
}
34+
}
35+
}
36+
37+
impl ConstantTimeEq for MontgomeryPoint {
38+
fn ct_eq(&self, other: &Self) -> Choice {
39+
self.x.ct_eq(&other.x) & self.y.ct_eq(&other.y)
40+
}
41+
}
42+
43+
impl PartialEq for MontgomeryPoint {
44+
fn eq(&self, other: &Self) -> bool {
45+
self.ct_eq(other).into()
46+
}
47+
}
48+
49+
impl From<&MontgomeryPoint> for ProjectiveMontgomeryPoint {
50+
fn from(value: &MontgomeryPoint) -> Self {
51+
ProjectiveMontgomeryPoint {
52+
U: value.x,
53+
V: value.y,
54+
W: FieldElement::ONE,
55+
}
56+
}
57+
}
58+
59+
impl From<MontgomeryPoint> for ProjectiveMontgomeryPoint {
60+
fn from(value: MontgomeryPoint) -> Self {
61+
(&value).into()
62+
}
63+
}
64+
65+
impl From<&MontgomeryPoint> for MontgomeryXpoint {
66+
fn from(value: &MontgomeryPoint) -> Self {
67+
MontgomeryXpoint(value.x.to_bytes())
68+
}
69+
}
70+
71+
impl From<MontgomeryPoint> for MontgomeryXpoint {
72+
fn from(value: MontgomeryPoint) -> Self {
73+
(&value).into()
74+
}
75+
}
76+
77+
/// A Projective point in Montgomery form including the y-coordinate.
78+
#[derive(Copy, Clone, Debug, Eq)]
79+
pub struct ProjectiveMontgomeryPoint {
80+
pub(super) U: FieldElement,
81+
pub(super) V: FieldElement,
82+
pub(super) W: FieldElement,
83+
}
84+
85+
impl ProjectiveMontgomeryPoint {
86+
/// The identity element of the group: the point at infinity.
87+
pub const IDENTITY: Self = Self {
88+
U: FieldElement::ZERO,
89+
V: FieldElement::ONE,
90+
W: FieldElement::ZERO,
91+
};
92+
93+
/// The generator point
94+
pub const GENERATOR: Self = Self {
95+
U: FieldElement(ConstMontyType::new(&U448::from_u64(5))),
96+
V: FieldElement(ConstMontyType::new(&U448::from_be_hex(
97+
"7d235d1295f5b1f66c98ab6e58326fcecbae5d34f55545d060f75dc28df3f6edb8027e2346430d211312c4b150677af76fd7223d457b5b1a",
98+
))),
99+
W: FieldElement::ONE,
100+
};
101+
102+
pub(crate) fn new(U: FieldElement, V: FieldElement, W: FieldElement) -> Self {
103+
Self { U, V, W }
104+
}
105+
}
106+
107+
impl ConditionallySelectable for ProjectiveMontgomeryPoint {
108+
fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
109+
Self {
110+
U: FieldElement::conditional_select(&a.U, &b.U, choice),
111+
V: FieldElement::conditional_select(&a.V, &b.V, choice),
112+
W: FieldElement::conditional_select(&a.W, &b.W, choice),
113+
}
114+
}
115+
}
116+
117+
impl ConstantTimeEq for ProjectiveMontgomeryPoint {
118+
fn ct_eq(&self, other: &Self) -> Choice {
119+
self.U.ct_eq(&other.U) & self.V.ct_eq(&other.V) & self.W.ct_eq(&other.W)
120+
}
121+
}
122+
123+
impl Default for ProjectiveMontgomeryPoint {
124+
fn default() -> Self {
125+
Self::IDENTITY
126+
}
127+
}
128+
129+
impl PartialEq for ProjectiveMontgomeryPoint {
130+
fn eq(&self, other: &Self) -> bool {
131+
self.ct_eq(other).into()
132+
}
133+
}
134+
135+
impl From<&ProjectiveMontgomeryPoint> for MontgomeryPoint {
136+
fn from(value: &ProjectiveMontgomeryPoint) -> Self {
137+
let W_inv = value.W.invert();
138+
let x = value.U * W_inv;
139+
let y = value.V * W_inv;
140+
141+
MontgomeryPoint { x, y }
142+
}
143+
}
144+
145+
impl From<ProjectiveMontgomeryPoint> for MontgomeryPoint {
146+
fn from(value: ProjectiveMontgomeryPoint) -> Self {
147+
(&value).into()
148+
}
149+
}
150+
151+
impl From<&ProjectiveMontgomeryPoint> for ProjectiveMontgomeryXpoint {
152+
fn from(value: &ProjectiveMontgomeryPoint) -> Self {
153+
ProjectiveMontgomeryXpoint::conditional_select(
154+
&ProjectiveMontgomeryXpoint {
155+
U: value.U,
156+
W: value.W,
157+
},
158+
&ProjectiveMontgomeryXpoint::IDENTITY,
159+
value.ct_eq(&ProjectiveMontgomeryPoint::IDENTITY),
160+
)
161+
}
162+
}
163+
164+
impl From<ProjectiveMontgomeryPoint> for ProjectiveMontgomeryXpoint {
165+
fn from(value: ProjectiveMontgomeryPoint) -> Self {
166+
(&value).into()
167+
}
168+
}
169+
170+
impl From<&ProjectiveMontgomeryPoint> for MontgomeryXpoint {
171+
fn from(value: &ProjectiveMontgomeryPoint) -> Self {
172+
ProjectiveMontgomeryXpoint::from(value).to_affine()
173+
}
174+
}
175+
176+
impl From<ProjectiveMontgomeryPoint> for MontgomeryXpoint {
177+
fn from(value: ProjectiveMontgomeryPoint) -> Self {
178+
(&value).into()
179+
}
180+
}
181+
182+
#[cfg(test)]
183+
mod tests {
184+
use super::*;
185+
186+
#[test]
187+
fn to_projective_x() {
188+
let x_identity = ProjectiveMontgomeryXpoint::IDENTITY;
189+
let identity = ProjectiveMontgomeryPoint::IDENTITY;
190+
191+
assert_eq!(ProjectiveMontgomeryXpoint::from(identity), x_identity);
192+
}
193+
194+
#[test]
195+
fn to_affine_x() {
196+
let x_identity = ProjectiveMontgomeryXpoint::IDENTITY.to_affine();
197+
let identity = MontgomeryXpoint::from(ProjectiveMontgomeryPoint::IDENTITY);
198+
199+
assert_eq!(identity, x_identity);
200+
}
201+
}

ed448-goldilocks/src/montgomery/x.rs

Lines changed: 46 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
// use crate::constants::A_PLUS_TWO_OVER_FOUR;
2+
use super::{MontgomeryPoint, ProjectiveMontgomeryPoint};
23
use crate::EdwardsScalar;
34
use crate::edwards::extended::EdwardsPoint;
45
use crate::field::{ConstMontyType, FieldElement};
@@ -65,8 +66,8 @@ impl Eq for MontgomeryXpoint {}
6566
/// A Projective point in Montgomery form
6667
#[derive(Copy, Clone, Debug, Eq)]
6768
pub struct ProjectiveMontgomeryXpoint {
68-
U: FieldElement,
69-
W: FieldElement,
69+
pub(super) U: FieldElement,
70+
pub(super) W: FieldElement,
7071
}
7172

7273
impl Mul<&EdwardsScalar> for &MontgomeryXpoint {
@@ -147,6 +148,16 @@ impl MontgomeryXpoint {
147148
W: FieldElement::ONE,
148149
}
149150
}
151+
152+
/// Convert the point to projective form including the y-coordinate
153+
pub fn to_extended_projective(&self, sign: Choice) -> ProjectiveMontgomeryPoint {
154+
self.to_projective().to_extended(sign)
155+
}
156+
157+
/// Convert the point to its form including the y-coordinate
158+
pub fn to_extended(&self, sign: Choice) -> MontgomeryPoint {
159+
self.to_projective().to_extended_affine(sign)
160+
}
150161
}
151162

152163
impl ConstantTimeEq for ProjectiveMontgomeryXpoint {
@@ -274,6 +285,23 @@ impl ProjectiveMontgomeryXpoint {
274285
let x = self.U * self.W.invert();
275286
MontgomeryXpoint(x.to_bytes())
276287
}
288+
289+
/// Convert the point to affine form including the y-coordinate
290+
pub fn to_extended_affine(&self, sign: Choice) -> MontgomeryPoint {
291+
let x = self.U * self.W.invert();
292+
let y = self.y(sign);
293+
294+
MontgomeryPoint::new(x, y)
295+
}
296+
297+
/// Convert the point to its form including the y-coordinate
298+
pub fn to_extended(&self, sign: Choice) -> ProjectiveMontgomeryPoint {
299+
ProjectiveMontgomeryPoint::conditional_select(
300+
&ProjectiveMontgomeryPoint::new(self.U, self.y(sign), self.W),
301+
&ProjectiveMontgomeryPoint::IDENTITY,
302+
self.ct_eq(&Self::IDENTITY),
303+
)
304+
}
277305
}
278306

279307
#[cfg(test)]
@@ -295,4 +323,20 @@ mod tests {
295323
montgomery_res.to_affine()
296324
);
297325
}
326+
327+
#[test]
328+
fn to_extended() {
329+
let x_identity = ProjectiveMontgomeryXpoint::IDENTITY;
330+
let identity = ProjectiveMontgomeryPoint::IDENTITY;
331+
332+
assert_eq!(x_identity.to_extended(Choice::from(1)), identity);
333+
}
334+
335+
#[test]
336+
fn to_extended_affine() {
337+
let x_identity = ProjectiveMontgomeryXpoint::IDENTITY.to_affine();
338+
let identity = MontgomeryPoint::from(ProjectiveMontgomeryPoint::IDENTITY);
339+
340+
assert_eq!(x_identity.to_extended(Choice::from(1)), identity);
341+
}
298342
}

0 commit comments

Comments
 (0)