Skip to content

Commit 9f43d0d

Browse files
committed
Add full-coordinate MontgomeryPoint skeleton
1 parent 41cb285 commit 9f43d0d

File tree

4 files changed

+278
-6
lines changed

4 files changed

+278
-6
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: 207 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,207 @@
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+
let UW = self.U * other.W;
120+
let WU = self.W * other.U;
121+
122+
let VW = self.V * other.W;
123+
let WV = self.W * other.V;
124+
125+
(UW.ct_eq(&WU)) & (VW.ct_eq(&WV))
126+
}
127+
}
128+
129+
impl Default for ProjectiveMontgomeryPoint {
130+
fn default() -> Self {
131+
Self::IDENTITY
132+
}
133+
}
134+
135+
impl PartialEq for ProjectiveMontgomeryPoint {
136+
fn eq(&self, other: &Self) -> bool {
137+
self.ct_eq(other).into()
138+
}
139+
}
140+
141+
impl From<&ProjectiveMontgomeryPoint> for MontgomeryPoint {
142+
fn from(value: &ProjectiveMontgomeryPoint) -> Self {
143+
let W_inv = value.W.invert();
144+
let x = value.U * W_inv;
145+
let y = value.V * W_inv;
146+
147+
MontgomeryPoint { x, y }
148+
}
149+
}
150+
151+
impl From<ProjectiveMontgomeryPoint> for MontgomeryPoint {
152+
fn from(value: ProjectiveMontgomeryPoint) -> Self {
153+
(&value).into()
154+
}
155+
}
156+
157+
impl From<&ProjectiveMontgomeryPoint> for ProjectiveMontgomeryXpoint {
158+
fn from(value: &ProjectiveMontgomeryPoint) -> Self {
159+
ProjectiveMontgomeryXpoint::conditional_select(
160+
&ProjectiveMontgomeryXpoint {
161+
U: value.U,
162+
W: value.W,
163+
},
164+
&ProjectiveMontgomeryXpoint::IDENTITY,
165+
value.ct_eq(&ProjectiveMontgomeryPoint::IDENTITY),
166+
)
167+
}
168+
}
169+
170+
impl From<ProjectiveMontgomeryPoint> for ProjectiveMontgomeryXpoint {
171+
fn from(value: ProjectiveMontgomeryPoint) -> Self {
172+
(&value).into()
173+
}
174+
}
175+
176+
impl From<&ProjectiveMontgomeryPoint> for MontgomeryXpoint {
177+
fn from(value: &ProjectiveMontgomeryPoint) -> Self {
178+
ProjectiveMontgomeryXpoint::from(value).to_affine()
179+
}
180+
}
181+
182+
impl From<ProjectiveMontgomeryPoint> for MontgomeryXpoint {
183+
fn from(value: ProjectiveMontgomeryPoint) -> Self {
184+
(&value).into()
185+
}
186+
}
187+
188+
#[cfg(test)]
189+
mod tests {
190+
use super::*;
191+
192+
#[test]
193+
fn to_projective_x() {
194+
let x_identity = ProjectiveMontgomeryXpoint::IDENTITY;
195+
let identity = ProjectiveMontgomeryPoint::IDENTITY;
196+
197+
assert_eq!(ProjectiveMontgomeryXpoint::from(identity), x_identity);
198+
}
199+
200+
#[test]
201+
fn to_affine_x() {
202+
let x_identity = ProjectiveMontgomeryXpoint::IDENTITY.to_affine();
203+
let identity = MontgomeryXpoint::from(ProjectiveMontgomeryPoint::IDENTITY);
204+
205+
assert_eq!(identity, x_identity);
206+
}
207+
}

ed448-goldilocks/src/montgomery/x.rs

Lines changed: 62 additions & 5 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 {
@@ -113,13 +114,12 @@ impl MontgomeryXpoint {
113114

114115
/// Compute the Y-coordinate
115116
pub fn y(&self, sign: Choice) -> [u8; 56] {
116-
self.y_internal(sign).to_bytes()
117+
Self::y_internal(&FieldElement::from_bytes(&self.0), sign).to_bytes()
117118
}
118119

119120
// See https://www.rfc-editor.org/rfc/rfc7748#section-1.
120-
pub(super) fn y_internal(&self, sign: Choice) -> FieldElement {
121+
pub(super) fn y_internal(u: &FieldElement, sign: Choice) -> FieldElement {
121122
// v^2 = u^3 + A*u^2 + u
122-
let u = FieldElement::from_bytes(&self.0);
123123
let uu = u.square();
124124
let vv = uu * u + FieldElement::J * uu + u;
125125

@@ -159,6 +159,19 @@ impl MontgomeryXpoint {
159159
W: FieldElement::ONE,
160160
}
161161
}
162+
163+
/// Convert the point to projective form including the y-coordinate
164+
pub fn to_extended_projective(&self, sign: Choice) -> ProjectiveMontgomeryPoint {
165+
self.to_projective().to_extended(sign)
166+
}
167+
168+
/// Convert the point to its form including the y-coordinate
169+
pub fn to_extended(&self, sign: Choice) -> MontgomeryPoint {
170+
let x = FieldElement::from_bytes(&self.0);
171+
let y = Self::y_internal(&x, sign);
172+
173+
MontgomeryPoint::new(x, y)
174+
}
162175
}
163176

164177
impl ConstantTimeEq for ProjectiveMontgomeryXpoint {
@@ -255,6 +268,17 @@ impl ProjectiveMontgomeryXpoint {
255268
W: FieldElement::ONE,
256269
};
257270

271+
// See https://www.rfc-editor.org/rfc/rfc7748#section-1.
272+
fn y(&self, sign: Choice) -> FieldElement {
273+
// v^2 = u^3 + A*u^2 + u
274+
let u_sq = self.U.square();
275+
let v_sq = u_sq * self.U + FieldElement::J * u_sq + self.U;
276+
277+
let mut v = v_sq.sqrt();
278+
v.conditional_negate(v.is_negative() ^ sign);
279+
v
280+
}
281+
258282
/// Double this point
259283
// https://eprint.iacr.org/2020/1338.pdf (2.2)
260284
pub fn double(&self) -> Self {
@@ -274,6 +298,23 @@ impl ProjectiveMontgomeryXpoint {
274298
let x = self.U * self.W.invert();
275299
MontgomeryXpoint(x.to_bytes())
276300
}
301+
302+
/// Convert the point to affine form including the y-coordinate
303+
pub fn to_extended_affine(&self, sign: Choice) -> MontgomeryPoint {
304+
let x = self.U * self.W.invert();
305+
let y = self.y(sign);
306+
307+
MontgomeryPoint::new(x, y)
308+
}
309+
310+
/// Convert the point to its form including the y-coordinate
311+
pub fn to_extended(&self, sign: Choice) -> ProjectiveMontgomeryPoint {
312+
ProjectiveMontgomeryPoint::conditional_select(
313+
&ProjectiveMontgomeryPoint::new(self.U, self.y(sign), self.W),
314+
&ProjectiveMontgomeryPoint::IDENTITY,
315+
self.ct_eq(&Self::IDENTITY),
316+
)
317+
}
277318
}
278319

279320
#[cfg(test)]
@@ -295,4 +336,20 @@ mod tests {
295336
montgomery_res.to_affine()
296337
);
297338
}
339+
340+
#[test]
341+
fn to_extended() {
342+
let x_identity = ProjectiveMontgomeryXpoint::IDENTITY;
343+
let identity = ProjectiveMontgomeryPoint::IDENTITY;
344+
345+
assert_eq!(x_identity.to_extended(Choice::from(1)), identity);
346+
}
347+
348+
#[test]
349+
fn to_extended_affine() {
350+
let x_identity = ProjectiveMontgomeryXpoint::IDENTITY.to_affine();
351+
let identity = MontgomeryPoint::from(ProjectiveMontgomeryPoint::IDENTITY);
352+
353+
assert_eq!(x_identity.to_extended(Choice::from(1)), identity);
354+
}
298355
}

0 commit comments

Comments
 (0)