Skip to content

Commit 79e7a0f

Browse files
committed
Implement improved algorithms from paper
Paper: Complete Addition Law for Montgomery Curves
1 parent 9ff8b0a commit 79e7a0f

File tree

3 files changed

+127
-38
lines changed

3 files changed

+127
-38
lines changed

ed448-goldilocks/src/field/element.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -356,6 +356,10 @@ impl FieldElement {
356356
Self(self.0.double())
357357
}
358358

359+
pub fn triple(&self) -> Self {
360+
self.double() + self
361+
}
362+
359363
/// Computes the inverse square root of a field element
360364
/// Returns the result and a boolean to indicate whether self
361365
/// was a Quadratic residue

ed448-goldilocks/src/montgomery/ops.rs

Lines changed: 81 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,47 @@
1-
use crate::field::{ConstMontyType, FieldElement};
1+
use crate::field::FieldElement;
22
use core::borrow::Borrow;
33
use core::iter::Sum;
44
use core::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign};
55
use elliptic_curve::CurveGroup;
6-
use elliptic_curve::bigint::U448;
76
use subtle::{Choice, ConditionallySelectable};
87

98
use super::{MontgomeryPoint, MontgomeryScalar, ProjectiveMontgomeryPoint};
109

1110
impl Add<&ProjectiveMontgomeryPoint> for &ProjectiveMontgomeryPoint {
1211
type Output = ProjectiveMontgomeryPoint;
1312

14-
// Copied from https://github.com/armfazh/redox-ecc/blob/5a8c09c5ef9fe6a8d2c749d05eca011c6d661599/src/montgomery/point.rs#L80-L104.
13+
// See Complete Addition Law for Montgomery Curves - Algorithm 1.
14+
// With "Trade-Off Technique".
1515
fn add(self, rhs: &ProjectiveMontgomeryPoint) -> Self::Output {
16-
const S: FieldElement = FieldElement(ConstMontyType::new(&U448::from_u64(3)));
17-
1816
let (x1, y1, z1) = (self.U, self.V, self.W);
1917
let (x2, y2, z2) = (rhs.U, rhs.V, rhs.W);
20-
let (a_ec, s_ec) = (FieldElement::J, S);
21-
let (t0, t1, t2) = (x1 * x2, y1 * y2, z1 * z2);
22-
let (t3, t4) = (x1 * y2, x2 * y1);
23-
let (t5, t6) = (y1 * z2, y2 * z1);
24-
let (t7, t8) = (x1 * z2, x2 * z1);
25-
let t9 = t7 + t8;
26-
let ta = t9 + (t0 * a_ec);
27-
let rr = t5 + t6;
28-
let tt = ta - t1;
29-
let vv = t9 * a_ec + t0.double() + t0 + t2;
30-
let ss = (t3 - t4) * s_ec + t0 - t2;
31-
let uu = (t7 - t8) * s_ec - t3 - t4;
32-
let ww = (t5 - t6) * s_ec + ta + t1;
33-
let x3 = rr * ss - tt * uu;
34-
let y3 = tt * ww - vv * ss;
35-
let z3 = vv * uu - rr * ww;
3618

37-
ProjectiveMontgomeryPoint {
38-
U: x3,
39-
V: y3,
40-
W: z3,
41-
}
19+
let t0 = x1 * x2;
20+
let t1 = y1 * y2;
21+
let t2 = z1 * z2;
22+
let t3 = x1 * y2;
23+
let t4 = x2 * y1;
24+
let t5 = y1 * z2;
25+
let t6 = y2 * z1;
26+
let t7 = x1 * z2;
27+
let t8 = x2 * z1;
28+
let t9 = t7 + t8;
29+
let t10 = t9 + FieldElement::J * t0;
30+
let R = t5 + t6;
31+
let T = t10 - t1;
32+
let V = FieldElement::J * t9 + t0.triple() + t2;
33+
let S = (t3 - t4).triple() + t0 - t2;
34+
let U = (t7 - t8).triple() - t3 - t4;
35+
let W = (t5 - t6).triple() + t10 + t1;
36+
let C = (R + T) * (S - U);
37+
let D = (R - T) * (S + U);
38+
let E = (T + V) * (W - S);
39+
let F = (T - V) * (W + S);
40+
let X = C + D;
41+
let Y = E + F;
42+
let Z = (U - W).double() * (R + V) + C - D + E - F;
43+
44+
ProjectiveMontgomeryPoint { U: X, V: Y, W: Z }
4245
}
4346
}
4447

@@ -51,8 +54,38 @@ define_add_variants!(
5154
impl Add<&MontgomeryPoint> for &ProjectiveMontgomeryPoint {
5255
type Output = ProjectiveMontgomeryPoint;
5356

54-
fn add(self, other: &MontgomeryPoint) -> ProjectiveMontgomeryPoint {
55-
*self + *other
57+
// See Complete Addition Law for Montgomery Curves - Algorithm 1.
58+
// With "Trade-Off Technique".
59+
fn add(self, rhs: &MontgomeryPoint) -> ProjectiveMontgomeryPoint {
60+
let (x1, y1, z1) = (self.U, self.V, self.W);
61+
let (x2, y2) = (rhs.x, rhs.y);
62+
63+
let t0 = x1 * x2;
64+
let t1 = y1 * y2;
65+
let t2 = z1;
66+
let t3 = x1 * y2;
67+
let t4 = x2 * y1;
68+
let t5 = y1;
69+
let t6 = y2 * z1;
70+
let t7 = x1;
71+
let t8 = x2 * z1;
72+
let t9 = t7 + t8;
73+
let t10 = t9 + FieldElement::J * t0;
74+
let R = t5 + t6;
75+
let T = t10 - t1;
76+
let V = FieldElement::J * t9 + t0.triple() + t2;
77+
let S = (t3 - t4).triple() + t0 - t2;
78+
let U = (t7 - t8).triple() - t3 - t4;
79+
let W = (t5 - t6).triple() + t10 + t1;
80+
let C = (R + T) * (S - U);
81+
let D = (R - T) * (S + U);
82+
let E = (T + V) * (W - S);
83+
let F = (T - V) * (W + S);
84+
let X = C + D;
85+
let Y = E + F;
86+
let Z = (U - W).double() * (R + V) + C - D + E - F;
87+
88+
ProjectiveMontgomeryPoint { U: X, V: Y, W: Z }
5689
}
5790
}
5891

@@ -66,7 +99,7 @@ impl Add<&ProjectiveMontgomeryPoint> for &MontgomeryPoint {
6699
type Output = ProjectiveMontgomeryPoint;
67100

68101
fn add(self, other: &ProjectiveMontgomeryPoint) -> ProjectiveMontgomeryPoint {
69-
*other + *self
102+
other + self
70103
}
71104
}
72105

@@ -111,9 +144,9 @@ impl Mul<&MontgomeryScalar> for &ProjectiveMontgomeryPoint {
111144
let mut p = ProjectiveMontgomeryPoint::IDENTITY;
112145
let bits = scalar.bits();
113146

114-
for s in (0..448).rev() {
147+
for index in (0..448).rev() {
115148
p = p + p;
116-
p.conditional_assign(&(p + self), Choice::from(bits[s] as u8));
149+
p.conditional_assign(&(p + self), Choice::from(bits[index] as u8));
117150
}
118151

119152
p
@@ -264,3 +297,20 @@ where
264297
iter.fold(Self::IDENTITY, |acc, item| acc + item.borrow())
265298
}
266299
}
300+
301+
#[cfg(test)]
302+
mod test {
303+
use elliptic_curve::Group;
304+
use rand_core::OsRng;
305+
306+
use super::*;
307+
308+
#[test]
309+
fn mixed_addition() {
310+
let p1 = ProjectiveMontgomeryPoint::try_from_rng(&mut OsRng).unwrap();
311+
let p2 = ProjectiveMontgomeryPoint::try_from_rng(&mut OsRng).unwrap();
312+
let p3 = p1 + p2;
313+
314+
assert_eq!(p3.to_affine(), (p1.to_affine() + p2).to_affine());
315+
}
316+
}

ed448-goldilocks/src/montgomery/point.rs

Lines changed: 42 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,8 @@ use super::{
2525
/// A point in Montgomery form including the y-coordinate.
2626
#[derive(Copy, Clone, Debug, Default)]
2727
pub struct MontgomeryPoint {
28-
x: FieldElement,
29-
y: FieldElement,
28+
pub(super) x: FieldElement,
29+
pub(super) y: FieldElement,
3030
}
3131

3232
impl MontgomeryPoint {
@@ -160,10 +160,6 @@ impl ProjectiveMontgomeryPoint {
160160
Self { U, V, W }
161161
}
162162

163-
fn double(&self) -> Self {
164-
self + self
165-
}
166-
167163
/// Convert the point to its form without the y-coordinate
168164
pub fn to_projective_x(&self) -> ProjectiveMontgomeryXpoint {
169165
ProjectiveMontgomeryXpoint::conditional_select(
@@ -280,8 +276,47 @@ impl Group for ProjectiveMontgomeryPoint {
280276
self.ct_eq(&Self::IDENTITY)
281277
}
282278

279+
// See Complete Addition Law for Montgomery Curves - Algorithm 3.
280+
// Slightly corrected from the derivation in the same paper.
283281
fn double(&self) -> Self {
284-
self.double()
282+
const A_MINUS_1: FieldElement = FieldElement(ConstMontyType::new(&U448::from_u64(156325)));
283+
284+
let (x, y, z) = (self.U, self.V, self.W);
285+
286+
let t0 = x.square();
287+
let t1 = y.square();
288+
let t2 = z.square();
289+
let t3 = (x + y).square();
290+
let t4 = (y + z).square();
291+
let t5 = (x + z).square();
292+
let t6 = t1 + t2;
293+
let t7 = (t0 - t2).double();
294+
let t8 = A_MINUS_1 * t0;
295+
let t9 = t0 - t1;
296+
let t10 = FieldElement::J * (t5 - t2) + t0 + t9;
297+
let t11 = t5 + t8;
298+
let t13 = t6.double(); // corrected - replaces t12
299+
300+
let S_MINUS_U = t3 - t6;
301+
let S_PLUS_U = -S_MINUS_U + t7;
302+
let R_MINUS_T = t4 - t11;
303+
let R_PLUS_T = t4 - t13 + t11; // corrected
304+
let W_MINUS_S = t11 - t9;
305+
let W_PLUS_S = W_MINUS_S + t7;
306+
let T_MINUS_V = t11 - t10 - t13 + t8; // corrected
307+
let T_PLUS_V = t5 + t10;
308+
let U_MINUS_W = S_PLUS_U - W_PLUS_S;
309+
let R_PLUS_V = R_MINUS_T + T_PLUS_V;
310+
311+
let C = R_PLUS_T * S_MINUS_U;
312+
let D = R_MINUS_T * S_PLUS_U;
313+
let E = T_PLUS_V * W_MINUS_S;
314+
let F = T_MINUS_V * W_PLUS_S;
315+
let X = C + D;
316+
let Y = E + F;
317+
let Z = U_MINUS_W.double() * R_PLUS_V + C - D + E - F;
318+
319+
Self { U: X, V: Y, W: Z }
285320
}
286321
}
287322

0 commit comments

Comments
 (0)