Skip to content

Commit b120a04

Browse files
committed
Reduce unnecessary conversions to ExtensiblePoint and back
1 parent 879ec56 commit b120a04

File tree

10 files changed

+217
-218
lines changed

10 files changed

+217
-218
lines changed

ed448-goldilocks/src/curve/scalar_mul/double_and_add.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
use crate::curve::twedwards::extended::ExtendedPoint;
2+
use crate::curve::twedwards::extensible::ExtensiblePoint;
23
use subtle::{Choice, ConditionallySelectable};
34

45
/// Traditional double and add algorithm
5-
pub(crate) fn double_and_add(point: &ExtendedPoint, s_bits: [bool; 448]) -> ExtendedPoint {
6-
let mut result = ExtendedPoint::IDENTITY;
6+
pub(crate) fn double_and_add(point: &ExtendedPoint, s_bits: [bool; 448]) -> ExtensiblePoint {
7+
let mut result = ExtensiblePoint::IDENTITY;
78

89
// NB, we reverse here, so we are going from MSB to LSB
910
// XXX: Would be great if subtle had a From<u32> for Choice. But maybe that is not it's purpose?
@@ -12,7 +13,7 @@ pub(crate) fn double_and_add(point: &ExtendedPoint, s_bits: [bool; 448]) -> Exte
1213

1314
let mut p = ExtendedPoint::IDENTITY;
1415
p.conditional_assign(point, Choice::from(bit as u8));
15-
result = result.add(&p);
16+
result = result.to_extended().add_extended(&p);
1617
}
1718

1819
result

ed448-goldilocks/src/curve/scalar_mul/variable_base.rs

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use crate::EdwardsScalar;
55
use crate::curve::twedwards::{extended::ExtendedPoint, extensible::ExtensiblePoint};
66
use subtle::{Choice, ConditionallyNegatable};
77

8-
pub fn variable_base(point: &ExtendedPoint, s: &EdwardsScalar) -> ExtendedPoint {
8+
pub fn variable_base(point: &ExtendedPoint, s: &EdwardsScalar) -> ExtensiblePoint {
99
let mut result = ExtensiblePoint::IDENTITY;
1010

1111
// Recode Scalar
@@ -28,10 +28,10 @@ pub fn variable_base(point: &ExtendedPoint, s: &EdwardsScalar) -> ExtendedPoint
2828
let mut neg_P = lookup.select(abs_value);
2929
neg_P.conditional_negate(Choice::from((sign) as u8));
3030

31-
result = result.add_projective_niels(&neg_P);
31+
result = result.to_extended().add_projective_niels(&neg_P);
3232
}
3333

34-
result.to_extended()
34+
result
3535
}
3636

3737
#[cfg(test)]
@@ -55,7 +55,7 @@ mod test {
5555
assert_eq!(got, got2);
5656

5757
// Lets see if this is conserved over the isogenies
58-
let edwards_point = twisted_point.to_untwisted();
58+
let edwards_point = twisted_point.to_extensible().to_untwisted();
5959
let got_untwisted_point = edwards_point.scalar_mul(&scalar);
6060
let expected_untwisted_point = got.to_untwisted();
6161
assert_eq!(got_untwisted_point, expected_untwisted_point);
@@ -69,9 +69,8 @@ mod test {
6969
let exp = variable_base(&x, &EdwardsScalar::from(1u8));
7070
assert!(x == exp);
7171
// Test that 2 * (P + P) = 4 * P
72-
let x_ext = x.to_extensible();
73-
let expected_two_x = x_ext.add_extensible(&x_ext).double();
72+
let expected_two_x = x.add_extended(&x).double();
7473
let got = variable_base(&x, &EdwardsScalar::from(4u8));
75-
assert!(expected_two_x.to_extended() == got);
74+
assert!(expected_two_x == got);
7675
}
7776
}

ed448-goldilocks/src/curve/scalar_mul/window/wnaf.rs

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,14 @@ pub struct LookupTable([ProjectiveNielsPoint; 8]);
66

77
/// Precomputes odd multiples of the point passed in
88
impl From<&ExtendedPoint> for LookupTable {
9-
fn from(point: &ExtendedPoint) -> LookupTable {
10-
let P = point.to_extensible();
11-
9+
fn from(P: &ExtendedPoint) -> LookupTable {
1210
let mut table = [P.to_projective_niels(); 8];
1311

1412
for i in 1..8 {
15-
table[i] = P.add_projective_niels(&table[i - 1]).to_projective_niels();
13+
table[i] = P
14+
.add_projective_niels(&table[i - 1])
15+
.to_extended()
16+
.to_projective_niels();
1617
}
1718

1819
LookupTable(table)
@@ -42,11 +43,8 @@ fn test_lookup() {
4243
let mut expected_point = ExtendedPoint::IDENTITY;
4344
for i in 0..8 {
4445
let selected_point = points.select(i);
45-
assert_eq!(selected_point.to_extended(), expected_point);
46+
assert_eq!(selected_point.to_extensible(), expected_point);
4647

47-
expected_point = expected_point
48-
.to_extensible()
49-
.add_extended(&p)
50-
.to_extended();
48+
expected_point = expected_point.add_extended(&p).to_extended();
5149
}
5250
}

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

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -121,13 +121,14 @@ impl AffineNielsPoint {
121121
&& (self.td == other.td)
122122
}
123123

124-
/// Converts an AffineNielsPoint to an ExtendedPoint
125-
pub(crate) fn to_extended(self) -> ExtendedPoint {
126-
ExtendedPoint {
124+
/// Converts an AffineNielsPoint to an ExtensiblePoint
125+
pub(crate) fn to_extensible(self) -> ExtensiblePoint {
126+
ExtensiblePoint {
127127
X: self.y_plus_x - self.y_minus_x,
128128
Y: self.y_minus_x + self.y_plus_x,
129129
Z: FieldElement::ONE,
130-
T: self.y_plus_x * self.y_minus_x,
130+
T1: self.y_plus_x,
131+
T2: self.y_minus_x,
131132
}
132133
}
133134
}
@@ -140,7 +141,7 @@ mod tests {
140141
#[test]
141142
fn test_negation() {
142143
use crate::TWISTED_EDWARDS_BASE_POINT;
143-
let a = TWISTED_EDWARDS_BASE_POINT.to_affine();
144+
let a = TWISTED_EDWARDS_BASE_POINT.to_extensible().to_affine();
144145
assert!(a.is_on_curve());
145146

146147
let neg_a = a.negate();

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

Lines changed: 107 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
#![allow(non_snake_case)]
22
#![allow(dead_code)]
33

4-
use crate::curve::twedwards::affine::AffinePoint;
4+
use crate::curve::twedwards::affine::AffineNielsPoint;
55
use crate::curve::twedwards::extensible::ExtensiblePoint;
6-
use crate::edwards::EdwardsPoint as EdwardsExtendedPoint;
6+
use crate::curve::twedwards::projective::ProjectiveNielsPoint;
77
use crate::field::FieldElement;
88
use subtle::{Choice, ConditionallySelectable, ConstantTimeEq};
99

@@ -43,6 +43,11 @@ impl PartialEq for ExtendedPoint {
4343
self.ct_eq(other).into()
4444
}
4545
}
46+
impl PartialEq<ExtensiblePoint> for ExtendedPoint {
47+
fn eq(&self, other: &ExtensiblePoint) -> bool {
48+
self.to_extensible().ct_eq(other).into()
49+
}
50+
}
4651
impl Eq for ExtendedPoint {}
4752

4853
impl Default for ExtendedPoint {
@@ -69,14 +74,90 @@ impl ExtendedPoint {
6974
T: FieldElement::ZERO,
7075
};
7176

72-
/// Doubles an extended point
73-
pub(crate) fn double(&self) -> ExtendedPoint {
74-
self.to_extensible().double().to_extended()
77+
/// Adds an extensible point to an extended point
78+
/// Returns an extensible point
79+
/// (3.1) https://iacr.org/archive/asiacrypt2008/53500329/53500329.pdf
80+
pub fn add_extended(&self, other: &ExtendedPoint) -> ExtensiblePoint {
81+
let A = self.X * other.X;
82+
let B = self.Y * other.Y;
83+
let C = self.T * other.T * FieldElement::TWISTED_D;
84+
let D = self.Z * other.Z;
85+
let E = (self.X + self.Y) * (other.X + other.Y) - A - B;
86+
let F = D - C;
87+
let G = D + C;
88+
let H = B + A;
89+
ExtensiblePoint {
90+
X: E * F,
91+
Y: G * H,
92+
T1: E,
93+
T2: H,
94+
Z: F * G,
95+
}
96+
}
97+
98+
/// Subtracts an extensible point from an extended point
99+
/// Returns an extensible point
100+
/// This is a direct modification of the addition formula to the negation of `other`
101+
pub fn sub_extended(&self, other: &ExtendedPoint) -> ExtensiblePoint {
102+
let A = self.X * other.X;
103+
let B = self.Y * other.Y;
104+
let C = self.T * other.T * FieldElement::TWISTED_D;
105+
let D = self.Z * other.Z;
106+
let E = (self.X + self.Y) * (other.Y - other.X) + A - B;
107+
let F = D + C;
108+
let G = D - C;
109+
let H = B - A;
110+
ExtensiblePoint {
111+
X: E * F,
112+
Y: G * H,
113+
T1: E,
114+
T2: H,
115+
Z: F * G,
116+
}
117+
}
118+
119+
/// Adds an extensible point to an AffineNiels point
120+
/// Returns an Extensible point
121+
pub fn add_affine_niels(&self, other: AffineNielsPoint) -> ExtensiblePoint {
122+
let A = other.y_minus_x * (self.Y - self.X);
123+
let B = other.y_plus_x * (self.X + self.Y);
124+
let C = other.td * self.T;
125+
let D = B + A;
126+
let E = B - A;
127+
let F = self.Z - C;
128+
let G = self.Z + C;
129+
ExtensiblePoint {
130+
X: E * F,
131+
Y: G * D,
132+
Z: F * G,
133+
T1: E,
134+
T2: D,
135+
}
75136
}
76137

77-
/// Adds an extended point to itself
78-
pub(crate) fn add(&self, other: &ExtendedPoint) -> ExtendedPoint {
79-
self.to_extensible().add_extended(other).to_extended()
138+
/// Adds an extensible point to a ProjectiveNiels point
139+
/// Returns an extensible point
140+
/// (3.1)[Last set of formulas] https://iacr.org/archive/asiacrypt2008/53500329/53500329.pdf
141+
/// This differs from the formula above by a factor of 2. Saving 1 Double
142+
/// Cost 8M
143+
pub fn add_projective_niels(&self, other: &ProjectiveNielsPoint) -> ExtensiblePoint {
144+
// This is the only step which makes it different than adding an AffineNielsPoint
145+
let Z = self.Z * other.Z;
146+
147+
let A = (self.Y - self.X) * other.Y_minus_X;
148+
let B = (self.Y + self.X) * other.Y_plus_X;
149+
let C = other.Td * self.T;
150+
let D = B + A;
151+
let E = B - A;
152+
let F = Z - C;
153+
let G = Z + C;
154+
ExtensiblePoint {
155+
X: E * F,
156+
Y: G * D,
157+
Z: F * G,
158+
T1: E,
159+
T2: D,
160+
}
80161
}
81162

82163
/// Converts an ExtendedPoint to an ExtensiblePoint
@@ -90,53 +171,16 @@ impl ExtendedPoint {
90171
}
91172
}
92173

93-
/// Converts an extended point to Affine co-ordinates
94-
pub(crate) fn to_affine(self) -> AffinePoint {
95-
// Points to consider:
96-
// - All points where Z=0, translate to (0,0)
97-
// - The identity point has z=1, so it is not a problem
98-
99-
let INV_Z = self.Z.invert();
100-
101-
let x = self.X * INV_Z;
102-
let y = self.Y * INV_Z;
103-
104-
AffinePoint { x, y }
105-
}
106-
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 {
111-
// Convert to affine now, then derive extended version later
112-
let affine = self.to_affine();
113-
let x = affine.x;
114-
let y = affine.y;
115-
116-
// 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();
121-
122-
// 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();
126-
127-
EdwardsExtendedPoint {
128-
X: new_x,
129-
Y: new_y,
130-
Z: FieldElement::ONE,
131-
T: new_x * new_y,
174+
/// Converts an Extensible point to a ProjectiveNiels Point
175+
pub fn to_projective_niels(self) -> ProjectiveNielsPoint {
176+
ProjectiveNielsPoint {
177+
Y_plus_X: self.X + self.Y,
178+
Y_minus_X: self.Y - self.X,
179+
Z: self.Z.double(),
180+
Td: self.T * FieldElement::TWO_TIMES_TWISTED_D,
132181
}
133182
}
134183

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-
140184
/// Checks if the point is on the curve
141185
pub(crate) fn is_on_curve(&self) -> Choice {
142186
let XY = self.X * self.Y;
@@ -178,6 +222,7 @@ impl ExtendedPoint {
178222
#[cfg(test)]
179223
mod tests {
180224
use super::*;
225+
use crate::curve::twedwards::affine::AffinePoint;
181226
use crate::{GOLDILOCKS_BASE_POINT, TWISTED_EDWARDS_BASE_POINT};
182227

183228
fn hex_to_field(hex: &'static str) -> FieldElement {
@@ -196,7 +241,7 @@ mod tests {
196241
let y = hex_to_field(
197242
"ae05e9634ad7048db359d6205086c2b0036ed7a035884dd7b7e36d728ad8c4b80d6565833a2a3098bbbcb2bed1cda06bdaeafbcdea9386ed",
198243
);
199-
let a = AffinePoint { x, y }.to_extended();
244+
let a = AffinePoint { x, y }.to_extensible();
200245
let twist_a = a.to_untwisted().to_twisted();
201246
assert_eq!(twist_a, a.double().double())
202247
}
@@ -220,28 +265,28 @@ mod tests {
220265
#[test]
221266
fn test_point_add() {
222267
let a = TWISTED_EDWARDS_BASE_POINT;
223-
let b = a.double();
268+
let b = a.to_extensible().double().to_extended();
224269

225270
// A + B = B + A = C
226-
let c_1 = a.to_extensible().add_extended(&b).to_extended();
227-
let c_2 = b.to_extensible().add_extended(&a).to_extended();
271+
let c_1 = a.add_extended(&b).to_extended();
272+
let c_2 = b.add_extended(&a).to_extended();
228273
assert!(c_1 == c_2);
229274

230275
// Adding identity point should not change result
231-
let c = c_1.to_extensible().add_extended(&ExtendedPoint::IDENTITY);
232-
assert!(c.to_extended() == c_1);
276+
let c = c_1.add_extended(&ExtendedPoint::IDENTITY);
277+
assert!(c == c_1);
233278
}
234279

235280
#[test]
236281
fn test_point_sub() {
237282
let a = TWISTED_EDWARDS_BASE_POINT;
238-
let b = a.double();
283+
let b = a.to_extensible().double().to_extended();
239284

240285
// A - B = C
241-
let c_1 = a.to_extensible().sub_extended(&b).to_extended();
286+
let c_1 = a.sub_extended(&b).to_extended();
242287

243288
// -B + A = C
244-
let c_2 = b.negate().to_extensible().add_extended(&a).to_extended();
289+
let c_2 = b.negate().add_extended(&a).to_extended();
245290
assert!(c_1 == c_2);
246291
}
247292

@@ -250,6 +295,6 @@ mod tests {
250295
let a = TWISTED_EDWARDS_BASE_POINT;
251296
let neg_a = a.negate();
252297

253-
assert!(a.to_extensible().add_extended(&neg_a) == ExtensiblePoint::IDENTITY);
298+
assert!(a.add_extended(&neg_a) == ExtensiblePoint::IDENTITY);
254299
}
255300
}

0 commit comments

Comments
 (0)