Skip to content

Commit ee42599

Browse files
committed
Add full-coordinate MontgomeryPoint skeleton
1 parent b57c288 commit ee42599

File tree

4 files changed

+262
-3
lines changed

4 files changed

+262
-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: 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: 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)