Skip to content

Commit 27f97a3

Browse files
committed
Add Montgomery <-> Edwards conversions
1 parent d171bd7 commit 27f97a3

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
@@ -550,6 +550,28 @@ impl EdwardsPoint {
550550
MontgomeryXpoint(u.to_bytes())
551551
}
552552

553+
/// Convert this point to [`MontgomeryPoint`]
554+
// See https://www.rfc-editor.org/rfc/rfc7748#section-4.2 4-isogeny maps
555+
pub fn to_montgomery(&self) -> MontgomeryPoint {
556+
// u = y^2/x^2
557+
// v = (2 - x^2 - y^2)*y/x^3
558+
559+
let affine = self.to_affine();
560+
561+
// TODO: optimize to a single inversion.
562+
let xx = affine.x.square();
563+
let yy = affine.y.square();
564+
565+
let u = yy * xx.invert();
566+
let v = (FieldElement::TWO - xx - yy) * affine.y * (xx * affine.x).invert();
567+
568+
MontgomeryPoint::conditional_select(
569+
&MontgomeryPoint::new(u, v),
570+
&MontgomeryPoint::IDENTITY,
571+
self.ct_eq(&Self::IDENTITY),
572+
)
573+
}
574+
553575
/// Generic scalar multiplication to compute s*P
554576
pub fn scalar_mul(&self, scalar: &EdwardsScalar) -> Self {
555577
// 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 {
@@ -188,6 +233,35 @@ impl From<ProjectiveMontgomeryPoint> for MontgomeryXpoint {
188233
#[cfg(test)]
189234
mod tests {
190235
use super::*;
236+
use crate::{EdwardsPoint, MontgomeryScalar};
237+
238+
#[test]
239+
fn to_edwards() {
240+
let scalar = MontgomeryScalar::from(200u32);
241+
242+
// Montgomery scalar mul
243+
let montgomery_res = ProjectiveMontgomeryPoint::GENERATOR * scalar * scalar;
244+
// Goldilocks scalar mul
245+
let goldilocks_point = EdwardsPoint::GENERATOR * scalar.to_scalar() * scalar.to_scalar();
246+
247+
assert_eq!(goldilocks_point.to_montgomery(), montgomery_res.into());
248+
}
249+
250+
#[test]
251+
fn identity_to_edwards() {
252+
let edwards = AffinePoint::IDENTITY;
253+
let montgomery = MontgomeryPoint::IDENTITY;
254+
255+
assert_eq!(AffinePoint::from(montgomery), edwards);
256+
}
257+
258+
#[test]
259+
fn identity_from_montgomery() {
260+
let edwards = EdwardsPoint::IDENTITY;
261+
let montgomery = MontgomeryPoint::IDENTITY;
262+
263+
assert_eq!(edwards.to_montgomery(), montgomery);
264+
}
191265

192266
#[test]
193267
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)
@@ -171,6 +164,11 @@ impl MontgomeryXpoint {
171164

172165
MontgomeryPoint::new(x, y)
173166
}
167+
168+
/// Convert this point to an [`AffinePoint`]
169+
pub fn to_edwards(&self, sign: Choice) -> AffinePoint {
170+
self.to_extended(sign).into()
171+
}
174172
}
175173

176174
impl ConstantTimeEq for ProjectiveMontgomeryXpoint {
@@ -320,6 +318,7 @@ impl ProjectiveMontgomeryXpoint {
320318
mod tests {
321319

322320
use super::*;
321+
use crate::EdwardsPoint;
323322

324323
#[test]
325324
fn test_montgomery_edwards() {

0 commit comments

Comments
 (0)