Skip to content

Commit 0ad5214

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

File tree

2 files changed

+125
-36
lines changed

2 files changed

+125
-36
lines changed

ed448-goldilocks/src/montgomery/ops.rs

Lines changed: 83 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -8,37 +8,44 @@ use subtle::{Choice, ConditionallySelectable};
88

99
use super::{MontgomeryPoint, MontgomeryScalar, ProjectiveMontgomeryPoint};
1010

11+
#[allow(non_upper_case_globals)]
12+
const s: FieldElement = FieldElement(ConstMontyType::new(&U448::from_u64(3)));
13+
1114
impl Add<&ProjectiveMontgomeryPoint> for &ProjectiveMontgomeryPoint {
1215
type Output = ProjectiveMontgomeryPoint;
1316

14-
// Copied from https://github.com/armfazh/redox-ecc/blob/5a8c09c5ef9fe6a8d2c749d05eca011c6d661599/src/montgomery/point.rs#L80-L104.
17+
// See Complete Addition Law for Montgomery Curves - Algorithm 1.
18+
// With "Trade-Off Technique".
1519
fn add(self, rhs: &ProjectiveMontgomeryPoint) -> Self::Output {
16-
const S: FieldElement = FieldElement(ConstMontyType::new(&U448::from_u64(3)));
17-
1820
let (x1, y1, z1) = (self.U, self.V, self.W);
1921
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;
3622

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

@@ -51,8 +58,38 @@ define_add_variants!(
5158
impl Add<&MontgomeryPoint> for &ProjectiveMontgomeryPoint {
5259
type Output = ProjectiveMontgomeryPoint;
5360

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

@@ -66,7 +103,7 @@ impl Add<&ProjectiveMontgomeryPoint> for &MontgomeryPoint {
66103
type Output = ProjectiveMontgomeryPoint;
67104

68105
fn add(self, other: &ProjectiveMontgomeryPoint) -> ProjectiveMontgomeryPoint {
69-
*other + *self
106+
other + self
70107
}
71108
}
72109

@@ -111,9 +148,9 @@ impl Mul<&MontgomeryScalar> for &ProjectiveMontgomeryPoint {
111148
let mut p = ProjectiveMontgomeryPoint::IDENTITY;
112149
let bits = scalar.bits();
113150

114-
for s in (0..448).rev() {
151+
for index in (0..448).rev() {
115152
p = p + p;
116-
p.conditional_assign(&(p + self), Choice::from(bits[s] as u8));
153+
p.conditional_assign(&(p + self), Choice::from(bits[index] as u8));
117154
}
118155

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

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(
@@ -281,7 +277,46 @@ impl Group for ProjectiveMontgomeryPoint {
281277
}
282278

283279
fn double(&self) -> Self {
284-
self.double()
280+
self + self
281+
282+
// TODO: figure out why this doesn't work.
283+
// See Complete Addition Law for Montgomery Curves - Algorithm 3.
284+
// const A_MINUS_1: FieldElement = FieldElement(ConstMontyType::new(&U448::from_u64(156325)));
285+
286+
// let (x, y, z) = (self.U, self.V, self.W);
287+
288+
// let t0 = x.square();
289+
// let t1 = y.square();
290+
// let t2 = z.square();
291+
// let t3 = (x + y).square();
292+
// let t4 = (y + z).square();
293+
// let t5 = (x + z).square();
294+
// let t6 = t1 + t2;
295+
// let t7 = (t0 - t2).double();
296+
// let t8 = A_MINUS_1 * t0;
297+
// let t9 = t0 - t1;
298+
// let t10 = FieldElement::J * (t5 - t2) + t0 + t9;
299+
// let t11 = t5 + t8;
300+
// let t12 = t10 - t6.double();
301+
// let SU_ = t3 - t6;
302+
// let SU = -SU_ + t7;
303+
// let RT_ = t4 - t11;
304+
// let RT = t4 + t12;
305+
// let WS_ = t11 - t9;
306+
// let WS = WS_ + t7;
307+
// let TV_ = t12 - t10 + t8;
308+
// let TV = t5 + t10;
309+
// let UW_ = SU - WS;
310+
// let RV = RT_ + TV;
311+
// let C = RT * SU_;
312+
// let D = RT_ * SU;
313+
// let E = TV * WS_;
314+
// let F = TV_ * WS;
315+
// let X = C + D;
316+
// let Y = E + F;
317+
// let Z = UW_.double() * RV + C - D + E - F;
318+
319+
// Self { U: X, V: Y, W: Z }
285320
}
286321
}
287322

0 commit comments

Comments
 (0)