Skip to content

Commit c870bf0

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

File tree

3 files changed

+89
-8
lines changed

3 files changed

+89
-8
lines changed

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/montgomery/point.rs

Lines changed: 60 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,36 @@ 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 u = self.x;
33+
let v = self.y;
34+
35+
let u_sq = self.x.square();
36+
let u_sq_minus_1 = u_sq - FieldElement::ONE;
37+
let u_sq_minus_1_sq = u_sq_minus_1.square();
38+
let v_sq_2 = v.square().double();
39+
let v_sq_4 = v_sq_2.double();
40+
41+
let xn = v.double().double() * u_sq_minus_1;
42+
let xd = u_sq_minus_1_sq + v_sq_4;
43+
44+
let yn = -u * (u_sq_minus_1_sq - v_sq_4);
45+
let yd = u * u_sq_minus_1_sq - v_sq_2 * (u_sq + FieldElement::ONE);
46+
47+
let d = (xd * yd).invert();
48+
49+
let x = xn * yd * d;
50+
let y = yn * xd * d;
51+
52+
AffinePoint::conditional_select(
53+
&AffinePoint { x, y },
54+
&AffinePoint::IDENTITY,
55+
self.ct_eq(&Self::IDENTITY),
56+
)
57+
}
58+
2859
/// Convert the point to its form without the y-coordinate
2960
pub fn to_affine_x(&self) -> MontgomeryXpoint {
3061
MontgomeryXpoint(self.x.to_bytes())
@@ -155,6 +186,35 @@ impl From<MontgomeryPoint> for ProjectiveMontgomeryPoint {
155186
#[cfg(test)]
156187
mod tests {
157188
use super::*;
189+
use crate::{EdwardsPoint, MontgomeryScalar};
190+
191+
#[test]
192+
fn to_edwards() {
193+
let scalar = MontgomeryScalar::from(200u32);
194+
195+
// Montgomery scalar mul
196+
let montgomery_res = ProjectiveMontgomeryPoint::GENERATOR * scalar * scalar;
197+
// Goldilocks scalar mul
198+
let goldilocks_point = EdwardsPoint::GENERATOR * scalar.to_scalar() * scalar.to_scalar();
199+
200+
assert_eq!(goldilocks_point.to_montgomery(), montgomery_res.to_affine());
201+
}
202+
203+
#[test]
204+
fn identity_to_edwards() {
205+
let edwards = AffinePoint::IDENTITY;
206+
let montgomery = MontgomeryPoint::IDENTITY;
207+
208+
assert_eq!(montgomery.to_edwards(), edwards);
209+
}
210+
211+
#[test]
212+
fn identity_from_montgomery() {
213+
let edwards = EdwardsPoint::IDENTITY;
214+
let montgomery = MontgomeryPoint::IDENTITY;
215+
216+
assert_eq!(edwards.to_montgomery(), montgomery);
217+
}
158218

159219
#[test]
160220
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)