Skip to content

Commit 5524cdd

Browse files
authored
ed448-goldilocks: optimize Edwards isogeny map (#1316)
See also #1349
1 parent 999e0c9 commit 5524cdd

File tree

3 files changed

+38
-41
lines changed

3 files changed

+38
-41
lines changed

ed448-goldilocks/src/curve/twedwards/extended.rs

Lines changed: 19 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -104,25 +104,33 @@ impl ExtendedPoint {
104104
AffinePoint { x, y }
105105
}
106106

107-
/// Edwards_Isogeny is derived from the doubling formula
108-
/// XXX: There is a duplicate method in the twisted edwards module to compute the dual isogeny
109-
/// XXX: Not much point trying to make it generic I think. So what we can do is optimise each respective isogeny method for a=1 or a = -1 (currently, I just made it really slow and simple)
110-
fn edwards_isogeny(&self, a: FieldElement) -> EdwardsExtendedPoint {
107+
/// Uses a 2-isogeny to map the point to the Ed448-Goldilocks
108+
// (2. Algorithm 2) https://eprint.iacr.org/2008/522.pdf
109+
pub fn to_untwisted(self) -> EdwardsExtendedPoint {
110+
// x = 2xy / (y^2 + a*x^2)
111+
// y = (y^2 - a*x^2) / (2 - y^2 - a*x^2)
112+
111113
// Convert to affine now, then derive extended version later
112114
let affine = self.to_affine();
113115
let x = affine.x;
114116
let y = affine.y;
115117

118+
let yy = y.square();
119+
let xx = x.square();
120+
let axx = -xx;
121+
let yy_plus_axx = yy + axx;
122+
116123
// Compute x
117-
let xy = x * y;
118-
let x_numerator = xy.double();
119-
let x_denom = y.square() - (a * x.square());
120-
let new_x = x_numerator * x_denom.invert();
124+
let x_numerator = (x * y).double();
125+
let x_denom = yy - axx;
121126

122127
// Compute y
123-
let y_numerator = y.square() + (a * x.square());
124-
let y_denom = (FieldElement::ONE + FieldElement::ONE) - y.square() - (a * x.square());
125-
let new_y = y_numerator * y_denom.invert();
128+
let y_numerator = yy_plus_axx;
129+
let y_denom = FieldElement::TWO - yy_plus_axx;
130+
131+
let common_denom = (x_denom * y_denom).invert();
132+
let new_x = x_numerator * y_denom * common_denom;
133+
let new_y = y_numerator * x_denom * common_denom;
126134

127135
EdwardsExtendedPoint {
128136
X: new_x,
@@ -132,11 +140,6 @@ impl ExtendedPoint {
132140
}
133141
}
134142

135-
/// Uses a 2-isogeny to map the point to the Ed448-Goldilocks
136-
pub fn to_untwisted(self) -> EdwardsExtendedPoint {
137-
self.edwards_isogeny(FieldElement::MINUS_ONE)
138-
}
139-
140143
/// Checks if the point is on the curve
141144
pub(crate) fn is_on_curve(&self) -> Choice {
142145
let XY = self.X * self.Y;

ed448-goldilocks/src/edwards/extended.rs

Lines changed: 18 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -669,38 +669,31 @@ impl EdwardsPoint {
669669
AffinePoint { x, y }
670670
}
671671

672-
/// Edwards_Isogeny is derived from the doubling formula
673-
/// XXX: There is a duplicate method in the twisted edwards module to compute the dual isogeny
674-
/// XXX: Not much point trying to make it generic I think. So what we can do is optimise each respective isogeny method for a=1 or a = -1 (currently, I just made it really slow and simple)
675-
fn edwards_isogeny(&self, a: FieldElement) -> TwistedExtendedPoint {
676-
// Convert to affine now, then derive extended version later
677-
let affine = self.to_affine();
678-
let x = affine.x;
679-
let y = affine.y;
680-
681-
// Compute x
682-
let xy = x * y;
683-
let x_numerator = xy.double();
684-
let x_denom = y.square() - (a * x.square());
685-
let new_x = x_numerator * x_denom.invert();
686-
687-
// Compute y
688-
let y_numerator = y.square() + (a * x.square());
689-
let y_denom = (FieldElement::ONE + FieldElement::ONE) - y.square() - (a * x.square());
690-
let new_y = y_numerator * y_denom.invert();
672+
// Copied from https://github.com/otrv4/libgoldilocks/blob/d07cb5b423995bae1155702aa949846c95d855c1/src/goldilocks.c#L980-L994.
673+
pub(crate) fn to_twisted(self) -> TwistedExtendedPoint {
674+
let c = self.X.square();
675+
let a = self.Y.square();
676+
let d = c + a;
677+
let t = self.Y + self.X;
678+
let b = t.square();
679+
let b = b - d;
680+
let t = a - c;
681+
let x = self.Z.square();
682+
let z = x.double();
683+
let a = z - d;
684+
let new_x = a * b;
685+
let new_z = t * a;
686+
let new_y = t * d;
687+
let new_t = b * d;
691688

692689
TwistedExtendedPoint {
693690
X: new_x,
694691
Y: new_y,
695-
Z: FieldElement::ONE,
696-
T: new_x * new_y,
692+
Z: new_z,
693+
T: new_t,
697694
}
698695
}
699696

700-
pub(crate) fn to_twisted(self) -> TwistedExtendedPoint {
701-
self.edwards_isogeny(FieldElement::ONE)
702-
}
703-
704697
/// Compute the negation of this point's `x`-coordinate.
705698
pub fn negate(&self) -> Self {
706699
EdwardsPoint {

ed448-goldilocks/src/field/element.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,7 @@ impl FieldElement {
246246
"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000262a8",
247247
)));
248248
pub const ONE: Self = Self(ConstMontyType::new(&U448::ONE));
249+
pub const TWO: Self = Self(ConstMontyType::new(&U448::from_u64(2)));
249250
pub const TWISTED_D: Self = Self(ConstMontyType::new(&U448::from_be_hex(
250251
"fffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffffffffffffffffffffffffffffffffffffffffffffffff6755",
251252
)));

0 commit comments

Comments
 (0)