Skip to content

Commit 8c6327a

Browse files
committed
Add Montgomery <-> Edwards conversions
1 parent 1f20b19 commit 8c6327a

File tree

5 files changed

+107
-43
lines changed

5 files changed

+107
-43
lines changed

ed448-goldilocks/src/edwards/affine.rs

Lines changed: 0 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -69,37 +69,6 @@ impl AffinePoint {
6969
y: FieldElement::ONE,
7070
};
7171

72-
pub(crate) fn isogeny(&self) -> Self {
73-
let x = self.x;
74-
let y = self.y;
75-
let mut t0 = x.square(); // x^2
76-
let t1 = t0 + FieldElement::ONE; // x^2+1
77-
t0 -= FieldElement::ONE; // x^2-1
78-
let mut t2 = y.square(); // y^2
79-
t2 = t2.double(); // 2y^2
80-
let t3 = x.double(); // 2x
81-
82-
let mut t4 = t0 * y; // y(x^2-1)
83-
t4 = t4.double(); // 2y(x^2-1)
84-
let xNum = t4.double(); // xNum = 4y(x^2-1)
85-
86-
let mut t5 = t0.square(); // x^4-2x^2+1
87-
t4 = t5 + t2; // x^4-2x^2+1+2y^2
88-
let xDen = t4 + t2; // xDen = x^4-2x^2+1+4y^2
89-
90-
t5 *= x; // x^5-2x^3+x
91-
t4 = t2 * t3; // 4xy^2
92-
let yNum = t4 - t5; // yNum = -(x^5-2x^3+x-4xy^2)
93-
94-
t4 = t1 * t2; // 2x^2y^2+2y^2
95-
let yDen = t5 - t4; // yDen = x^5-2x^3+x-2x^2y^2-2y^2
96-
97-
Self {
98-
x: xNum * xDen.invert(),
99-
y: yNum * yDen.invert(),
100-
}
101-
}
102-
10372
/// Convert to edwards extended point
10473
pub fn to_edwards(&self) -> EdwardsPoint {
10574
EdwardsPoint {

ed448-goldilocks/src/edwards/extended.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -541,6 +541,28 @@ impl EdwardsPoint {
541541
MontgomeryXpoint(u.to_bytes())
542542
}
543543

544+
/// Convert this point to [`MontgomeryPoint`]
545+
// See https://www.rfc-editor.org/rfc/rfc7748#section-4.2 4-isogeny maps
546+
pub fn to_montgomery(&self) -> MontgomeryPoint {
547+
// u = y^2/x^2
548+
// v = (2 - x^2 - y^2)*y/x^3
549+
550+
let affine = self.to_affine();
551+
552+
// TODO: optimize to a single inversion.
553+
let xx = affine.x.square();
554+
let yy = affine.y.square();
555+
556+
let u = yy * xx.invert();
557+
let v = (FieldElement::TWO - xx - yy) * affine.y * (xx * affine.x).invert();
558+
559+
MontgomeryPoint::conditional_select(
560+
&MontgomeryPoint::new(u, v),
561+
&MontgomeryPoint::IDENTITY,
562+
self.ct_eq(&Self::IDENTITY),
563+
)
564+
}
565+
544566
/// Generic scalar multiplication to compute s*P
545567
pub fn scalar_mul(&self, scalar: &EdwardsScalar) -> Self {
546568
// Compute floor(s/4)

ed448-goldilocks/src/field/element.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use core::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign};
33

44
use super::ConstMontyType;
55
use crate::{
6-
AffinePoint, Decaf448, DecafPoint, Ed448, EdwardsPoint,
6+
AffinePoint, Decaf448, DecafPoint, Ed448, EdwardsPoint, MontgomeryPoint,
77
curve::twedwards::extended::ExtendedPoint as TwistedExtendedPoint,
88
};
99
use elliptic_curve::{
@@ -197,7 +197,7 @@ impl MapToCurve for Ed448 {
197197
type FieldElement = Ed448FieldElement;
198198

199199
fn map_to_curve(element: Ed448FieldElement) -> Self::CurvePoint {
200-
element.0.map_to_curve_elligator2().isogeny().to_edwards()
200+
AffinePoint::from(element.0.map_to_curve_elligator2_curve448()).to_edwards()
201201
}
202202

203203
fn map_to_subgroup(point: EdwardsPoint) -> EdwardsPoint {
@@ -373,7 +373,7 @@ impl FieldElement {
373373
(inv_sqrt_x * u, zero_u | is_res)
374374
}
375375

376-
pub(crate) fn map_to_curve_elligator2(&self) -> AffinePoint {
376+
pub(crate) fn map_to_curve_elligator2_curve448(&self) -> MontgomeryPoint {
377377
let mut t1 = self.square(); // 1. t1 = u^2
378378
t1 *= Self::Z; // 2. t1 = Z * t1 // Z * u^2
379379
let e1 = t1.ct_eq(&Self::MINUS_ONE); // 3. e1 = t1 == -1 // exceptional case: Z * u^2 == -1
@@ -393,7 +393,7 @@ impl FieldElement {
393393
let mut y = y2.sqrt(); // 17. y = sqrt(y2)
394394
let e3 = y.is_negative(); // 18. e3 = sgn0(y) == 1
395395
y.conditional_negate(e2 ^ e3); // y = CMOV(-y, y, e2 xor e3)
396-
AffinePoint { x, y }
396+
MontgomeryPoint::new(x, y)
397397
}
398398

399399
// See https://www.shiftleft.org/papers/decaf/decaf.pdf#section.A.3.

ed448-goldilocks/src/montgomery/point.rs

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use subtle::ConditionallySelectable;
44
use subtle::ConstantTimeEq;
55

66
use super::{MontgomeryXpoint, ProjectiveMontgomeryXpoint};
7+
use crate::AffinePoint;
78
use crate::field::{ConstMontyType, FieldElement};
89

910
/// A point in Montgomery form including the y-coordinate.
@@ -74,6 +75,50 @@ impl From<MontgomeryPoint> for MontgomeryXpoint {
7475
}
7576
}
7677

78+
impl From<&MontgomeryPoint> for AffinePoint {
79+
// https://www.rfc-editor.org/rfc/rfc7748#section-4.2
80+
fn from(value: &MontgomeryPoint) -> AffinePoint {
81+
let x = value.x;
82+
let y = value.y;
83+
let mut t0 = x.square(); // x^2
84+
let t1 = t0 + FieldElement::ONE; // x^2+1
85+
t0 -= FieldElement::ONE; // x^2-1
86+
let mut t2 = y.square(); // y^2
87+
t2 = t2.double(); // 2y^2
88+
let t3 = x.double(); // 2x
89+
90+
let mut t4 = t0 * y; // y(x^2-1)
91+
t4 = t4.double(); // 2y(x^2-1)
92+
let xNum = t4.double(); // xNum = 4y(x^2-1)
93+
94+
let mut t5 = t0.square(); // x^4-2x^2+1
95+
t4 = t5 + t2; // x^4-2x^2+1+2y^2
96+
let xDen = t4 + t2; // xDen = x^4-2x^2+1+4y^2
97+
98+
t5 *= x; // x^5-2x^3+x
99+
t4 = t2 * t3; // 4xy^2
100+
let yNum = t4 - t5; // yNum = -(x^5-2x^3+x-4xy^2)
101+
102+
t4 = t1 * t2; // 2x^2y^2+2y^2
103+
let yDen = t5 - t4; // yDen = x^5-2x^3+x-2x^2y^2-2y^2
104+
105+
let x = xNum * xDen.invert();
106+
let y = yNum * yDen.invert();
107+
108+
AffinePoint::conditional_select(
109+
&AffinePoint { x, y },
110+
&AffinePoint::IDENTITY,
111+
value.ct_eq(&MontgomeryPoint::IDENTITY),
112+
)
113+
}
114+
}
115+
116+
impl From<MontgomeryPoint> for AffinePoint {
117+
fn from(value: MontgomeryPoint) -> Self {
118+
(&value).into()
119+
}
120+
}
121+
77122
/// A Projective point in Montgomery form including the y-coordinate.
78123
#[derive(Copy, Clone, Debug, Eq)]
79124
pub struct ProjectiveMontgomeryPoint {
@@ -182,6 +227,35 @@ impl From<ProjectiveMontgomeryPoint> for MontgomeryXpoint {
182227
#[cfg(test)]
183228
mod tests {
184229
use super::*;
230+
use crate::{EdwardsPoint, MontgomeryScalar};
231+
232+
#[test]
233+
fn to_edwards() {
234+
let scalar = MontgomeryScalar::from(200u32);
235+
236+
// Montgomery scalar mul
237+
let montgomery_res = ProjectiveMontgomeryPoint::GENERATOR * scalar * scalar;
238+
// Goldilocks scalar mul
239+
let goldilocks_point = EdwardsPoint::GENERATOR * scalar.to_scalar() * scalar.to_scalar();
240+
241+
assert_eq!(goldilocks_point.to_montgomery(), montgomery_res.into());
242+
}
243+
244+
#[test]
245+
fn identity_to_edwards() {
246+
let edwards = AffinePoint::IDENTITY;
247+
let montgomery = MontgomeryPoint::IDENTITY;
248+
249+
assert_eq!(AffinePoint::from(montgomery), edwards);
250+
}
251+
252+
#[test]
253+
fn identity_from_montgomery() {
254+
let edwards = EdwardsPoint::IDENTITY;
255+
let montgomery = MontgomeryPoint::IDENTITY;
256+
257+
assert_eq!(edwards.to_montgomery(), montgomery);
258+
}
185259

186260
#[test]
187261
fn to_projective_x() {

ed448-goldilocks/src/montgomery/x.rs

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// use crate::constants::A_PLUS_TWO_OVER_FOUR;
22
use super::{MontgomeryPoint, MontgomeryScalar, ProjectiveMontgomeryPoint};
3-
use crate::edwards::extended::EdwardsPoint;
3+
use crate::AffinePoint;
44
use crate::field::{ConstMontyType, FieldElement};
55
use core::fmt;
66
use core::ops::Mul;
@@ -94,13 +94,6 @@ impl MontgomeryXpoint {
9494
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
9595
]);
9696

97-
/// Convert this point to an [`EdwardsPoint`]
98-
pub fn to_edwards(&self, _sign: u8) -> Option<EdwardsPoint> {
99-
// We use the 4-isogeny to map to the Ed448.
100-
// This is different to Curve25519, where we use a birational map.
101-
todo!()
102-
}
103-
10497
/// Returns true if the point is one of the low order points
10598
pub fn is_low_order(&self) -> bool {
10699
(*self == Self::LOW_A) || (*self == Self::LOW_B) || (*self == Self::LOW_C)
@@ -157,6 +150,11 @@ impl MontgomeryXpoint {
157150
pub fn to_extended(&self, sign: Choice) -> MontgomeryPoint {
158151
self.to_projective().to_extended_affine(sign)
159152
}
153+
154+
/// Convert this point to an [`AffinePoint`]
155+
pub fn to_edwards(&self, sign: Choice) -> AffinePoint {
156+
self.to_extended(sign).into()
157+
}
160158
}
161159

162160
impl ConstantTimeEq for ProjectiveMontgomeryXpoint {
@@ -307,6 +305,7 @@ impl ProjectiveMontgomeryXpoint {
307305
mod tests {
308306

309307
use super::*;
308+
use crate::EdwardsPoint;
310309

311310
#[test]
312311
fn test_montgomery_edwards() {

0 commit comments

Comments
 (0)