Skip to content

Commit 3899a9a

Browse files
committed
Add Montgomery <-> Edwards conversions
1 parent 73a7b95 commit 3899a9a

File tree

5 files changed

+104
-43
lines changed

5 files changed

+104
-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
@@ -542,6 +542,28 @@ impl EdwardsPoint {
542542
MontgomeryXpoint(u.to_bytes())
543543
}
544544

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

ed448-goldilocks/src/field/element.rs

Lines changed: 8 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+
Decaf448, DecafPoint, Ed448, EdwardsPoint, MontgomeryPoint,
77
curve::twedwards::extended::ExtendedPoint as TwistedExtendedPoint,
88
};
99
use elliptic_curve::{
@@ -197,7 +197,11 @@ 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+
element
201+
.0
202+
.map_to_curve_elligator2_curve448()
203+
.to_edwards()
204+
.to_edwards()
201205
}
202206

203207
fn map_to_subgroup(point: EdwardsPoint) -> EdwardsPoint {
@@ -377,7 +381,7 @@ impl FieldElement {
377381
(inv_sqrt_x * u, zero_u | is_res)
378382
}
379383

380-
pub(crate) fn map_to_curve_elligator2(&self) -> AffinePoint {
384+
pub(crate) fn map_to_curve_elligator2_curve448(&self) -> MontgomeryPoint {
381385
let mut t1 = self.square(); // 1. t1 = u^2
382386
t1 *= Self::Z; // 2. t1 = Z * t1 // Z * u^2
383387
let e1 = t1.ct_eq(&Self::MINUS_ONE); // 3. e1 = t1 == -1 // exceptional case: Z * u^2 == -1
@@ -397,7 +401,7 @@ impl FieldElement {
397401
let mut y = y2.sqrt(); // 17. y = sqrt(y2)
398402
let e3 = y.is_negative(); // 18. e3 = sgn0(y) == 1
399403
y.conditional_negate(e2 ^ e3); // y = CMOV(-y, y, e2 xor e3)
400-
AffinePoint { x, y }
404+
MontgomeryPoint::new(x, y)
401405
}
402406

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

ed448-goldilocks/src/montgomery/point.rs

Lines changed: 67 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;
89
use crate::field::FieldElement;
910

@@ -25,6 +26,43 @@ impl MontgomeryPoint {
2526
Self { x, y }
2627
}
2728

29+
/// Convert this point to an [`AffinePoint`]
30+
// https://www.rfc-editor.org/rfc/rfc7748#section-4.2
31+
pub fn to_edwards(&self) -> AffinePoint {
32+
let x = self.x;
33+
let y = self.y;
34+
let mut t0 = x.square(); // x^2
35+
let t1 = t0 + FieldElement::ONE; // x^2+1
36+
t0 -= FieldElement::ONE; // x^2-1
37+
let mut t2 = y.square(); // y^2
38+
t2 = t2.double(); // 2y^2
39+
let t3 = x.double(); // 2x
40+
41+
let mut t4 = t0 * y; // y(x^2-1)
42+
t4 = t4.double(); // 2y(x^2-1)
43+
let xNum = t4.double(); // xNum = 4y(x^2-1)
44+
45+
let mut t5 = t0.square(); // x^4-2x^2+1
46+
t4 = t5 + t2; // x^4-2x^2+1+2y^2
47+
let xDen = t4 + t2; // xDen = x^4-2x^2+1+4y^2
48+
49+
t5 *= x; // x^5-2x^3+x
50+
t4 = t2 * t3; // 4xy^2
51+
let yNum = t4 - t5; // yNum = -(x^5-2x^3+x-4xy^2)
52+
53+
t4 = t1 * t2; // 2x^2y^2+2y^2
54+
let yDen = t5 - t4; // yDen = x^5-2x^3+x-2x^2y^2-2y^2
55+
56+
let x = xNum * xDen.invert();
57+
let y = yNum * yDen.invert();
58+
59+
AffinePoint::conditional_select(
60+
&AffinePoint { x, y },
61+
&AffinePoint::IDENTITY,
62+
self.ct_eq(&Self::IDENTITY),
63+
)
64+
}
65+
2866
/// Convert the point to its form without the y-coordinate
2967
pub fn to_affine_x(&self) -> MontgomeryXpoint {
3068
MontgomeryXpoint(self.x.to_bytes())
@@ -155,6 +193,35 @@ impl From<MontgomeryPoint> for ProjectiveMontgomeryPoint {
155193
#[cfg(test)]
156194
mod tests {
157195
use super::*;
196+
use crate::{EdwardsPoint, MontgomeryScalar};
197+
198+
#[test]
199+
fn to_edwards() {
200+
let scalar = MontgomeryScalar::from(200u32);
201+
202+
// Montgomery scalar mul
203+
let montgomery_res = ProjectiveMontgomeryPoint::GENERATOR * scalar * scalar;
204+
// Goldilocks scalar mul
205+
let goldilocks_point = EdwardsPoint::GENERATOR * scalar.to_scalar() * scalar.to_scalar();
206+
207+
assert_eq!(goldilocks_point.to_montgomery(), montgomery_res.to_affine());
208+
}
209+
210+
#[test]
211+
fn identity_to_edwards() {
212+
let edwards = AffinePoint::IDENTITY;
213+
let montgomery = MontgomeryPoint::IDENTITY;
214+
215+
assert_eq!(montgomery.to_edwards(), edwards);
216+
}
217+
218+
#[test]
219+
fn identity_from_montgomery() {
220+
let edwards = EdwardsPoint::IDENTITY;
221+
let montgomery = MontgomeryPoint::IDENTITY;
222+
223+
assert_eq!(edwards.to_montgomery(), montgomery);
224+
}
158225

159226
#[test]
160227
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;
55
use crate::field::FieldElement;
66
use core::fmt;
@@ -91,13 +91,6 @@ impl MontgomeryXpoint {
9191
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
9292
]);
9393

94-
/// Convert this point to an [`EdwardsPoint`]
95-
pub fn to_edwards(&self, _sign: u8) -> Option<EdwardsPoint> {
96-
// We use the 4-isogeny to map to the Ed448.
97-
// This is different to Curve25519, where we use a birational map.
98-
todo!()
99-
}
100-
10194
/// Returns true if the point is one of the low order points
10295
pub fn is_low_order(&self) -> bool {
10396
(*self == LOW_A) || (*self == LOW_B) || (*self == LOW_C)
@@ -154,6 +147,11 @@ impl MontgomeryXpoint {
154147
pub fn to_extended(&self, sign: Choice) -> MontgomeryPoint {
155148
self.to_projective().to_extended_affine(sign)
156149
}
150+
151+
/// Convert this point to an [`AffinePoint`]
152+
pub fn to_edwards(&self, sign: Choice) -> AffinePoint {
153+
self.to_extended(sign).to_edwards()
154+
}
157155
}
158156

159157
impl ConstantTimeEq for ProjectiveMontgomeryXpoint {
@@ -304,6 +302,7 @@ impl ProjectiveMontgomeryXpoint {
304302
mod tests {
305303

306304
use super::*;
305+
use crate::EdwardsPoint;
307306

308307
#[test]
309308
fn test_montgomery_edwards() {

0 commit comments

Comments
 (0)