Skip to content

Commit 1f20b19

Browse files
committed
Add arithmetic operations to Montgomery
1 parent 2f5f221 commit 1f20b19

File tree

3 files changed

+334
-0
lines changed

3 files changed

+334
-0
lines changed

ed448-goldilocks/src/field/element.rs

Lines changed: 5 additions & 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
)));
@@ -319,6 +320,10 @@ impl FieldElement {
319320
Self(self.0.double())
320321
}
321322

323+
pub fn triple(&self) -> Self {
324+
self.double() + self
325+
}
326+
322327
/// Computes the inverse square root of a field element
323328
/// Returns the result and a boolean to indicate whether self
324329
/// was a Quadratic residue

ed448-goldilocks/src/montgomery.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
#![allow(non_snake_case)]
1212

13+
mod ops;
1314
mod point;
1415
mod scalar;
1516
mod x;
Lines changed: 328 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,328 @@
1+
use crate::ProjectiveMontgomeryXpoint;
2+
use crate::field::{ConstMontyType, FieldElement};
3+
use core::borrow::Borrow;
4+
use core::iter::Sum;
5+
use core::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign};
6+
use elliptic_curve::bigint::U448;
7+
8+
use super::{MontgomeryPoint, MontgomeryScalar, MontgomeryXpoint, ProjectiveMontgomeryPoint};
9+
10+
impl Add<&ProjectiveMontgomeryPoint> for &ProjectiveMontgomeryPoint {
11+
type Output = ProjectiveMontgomeryPoint;
12+
13+
// See Complete Addition Law for Montgomery Curves - Algorithm 1.
14+
// With "Trade-Off Technique".
15+
fn add(self, rhs: &ProjectiveMontgomeryPoint) -> Self::Output {
16+
let (x1, y1, z1) = (self.U, self.V, self.W);
17+
let (x2, y2, z2) = (rhs.U, rhs.V, rhs.W);
18+
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 }
45+
}
46+
}
47+
48+
define_add_variants!(
49+
LHS = ProjectiveMontgomeryPoint,
50+
RHS = ProjectiveMontgomeryPoint,
51+
Output = ProjectiveMontgomeryPoint
52+
);
53+
54+
impl Add<&MontgomeryPoint> for &ProjectiveMontgomeryPoint {
55+
type Output = ProjectiveMontgomeryPoint;
56+
57+
// See Complete Addition Law for Montgomery Curves - Algorithm 2.
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 }
89+
}
90+
}
91+
92+
define_add_variants!(
93+
LHS = ProjectiveMontgomeryPoint,
94+
RHS = MontgomeryPoint,
95+
Output = ProjectiveMontgomeryPoint
96+
);
97+
98+
impl Add<&ProjectiveMontgomeryPoint> for &MontgomeryPoint {
99+
type Output = ProjectiveMontgomeryPoint;
100+
101+
fn add(self, other: &ProjectiveMontgomeryPoint) -> ProjectiveMontgomeryPoint {
102+
other + self
103+
}
104+
}
105+
106+
define_add_variants!(
107+
LHS = MontgomeryPoint,
108+
RHS = ProjectiveMontgomeryPoint,
109+
Output = ProjectiveMontgomeryPoint
110+
);
111+
112+
impl<'b> AddAssign<&'b ProjectiveMontgomeryPoint> for ProjectiveMontgomeryPoint {
113+
fn add_assign(&mut self, rhs: &'b Self) {
114+
*self = *self + rhs;
115+
}
116+
}
117+
118+
define_add_assign_variants!(
119+
LHS = ProjectiveMontgomeryPoint,
120+
RHS = ProjectiveMontgomeryPoint
121+
);
122+
123+
impl AddAssign<&MontgomeryPoint> for ProjectiveMontgomeryPoint {
124+
fn add_assign(&mut self, rhs: &MontgomeryPoint) {
125+
*self += Self::from(*rhs);
126+
}
127+
}
128+
129+
define_add_assign_variants!(LHS = ProjectiveMontgomeryPoint, RHS = MontgomeryPoint);
130+
131+
impl AddAssign<&ProjectiveMontgomeryPoint> for MontgomeryPoint {
132+
fn add_assign(&mut self, rhs: &ProjectiveMontgomeryPoint) {
133+
*self = (ProjectiveMontgomeryPoint::from(*self) + rhs).into();
134+
}
135+
}
136+
137+
define_add_assign_variants!(LHS = MontgomeryPoint, RHS = ProjectiveMontgomeryPoint);
138+
139+
impl Mul<&MontgomeryScalar> for &ProjectiveMontgomeryPoint {
140+
type Output = ProjectiveMontgomeryPoint;
141+
142+
#[inline]
143+
fn mul(self, scalar: &MontgomeryScalar) -> ProjectiveMontgomeryPoint {
144+
MontgomeryPoint::from(self) * scalar
145+
}
146+
}
147+
148+
define_mul_variants!(
149+
LHS = ProjectiveMontgomeryPoint,
150+
RHS = MontgomeryScalar,
151+
Output = ProjectiveMontgomeryPoint
152+
);
153+
154+
impl Mul<&MontgomeryScalar> for &MontgomeryPoint {
155+
type Output = ProjectiveMontgomeryPoint;
156+
157+
// Montgomery curves and their arithmetic - Algorithm 6
158+
// https://eprint.iacr.org/2017/212.pdf
159+
fn mul(self, rhs: &MontgomeryScalar) -> ProjectiveMontgomeryPoint {
160+
pub const A2: FieldElement = FieldElement(ConstMontyType::new(&U448::from_u64(312652)));
161+
162+
let MontgomeryPoint { x: xP, y: yP } = self;
163+
let (
164+
ProjectiveMontgomeryXpoint { U: xQ, W: zQ },
165+
ProjectiveMontgomeryXpoint { U: xD, W: zD },
166+
) = MontgomeryXpoint::from(self).mul_internal(rhs);
167+
168+
let v1 = xP * zQ;
169+
let v2 = xQ + v1;
170+
let v3 = xQ - v1;
171+
let v3 = v3.square();
172+
let v3 = v3 * xD;
173+
let v1 = A2 * zQ;
174+
let v2 = v2 + v1;
175+
let v4 = xP * xQ;
176+
let v4 = v4 + zQ;
177+
let v2 = v2 * v4;
178+
let v1 = v1 * zQ;
179+
let v2 = v2 - v1;
180+
let v2 = v2 * zD;
181+
let y = v2 - v3;
182+
let v1 = FieldElement::TWO * yP;
183+
let v1 = v1 * zQ;
184+
let v1 = v1 * zD;
185+
let x = v1 * xQ;
186+
let z = v1 * zQ;
187+
188+
ProjectiveMontgomeryPoint { U: x, V: y, W: z }
189+
}
190+
}
191+
192+
define_mul_variants!(
193+
LHS = MontgomeryPoint,
194+
RHS = MontgomeryScalar,
195+
Output = ProjectiveMontgomeryPoint
196+
);
197+
198+
impl<'b> MulAssign<&'b MontgomeryScalar> for ProjectiveMontgomeryPoint {
199+
fn mul_assign(&mut self, scalar: &'b MontgomeryScalar) {
200+
let result = *self * scalar;
201+
*self = result;
202+
}
203+
}
204+
205+
define_mul_assign_variants!(LHS = ProjectiveMontgomeryPoint, RHS = MontgomeryScalar);
206+
207+
impl Neg for &ProjectiveMontgomeryPoint {
208+
type Output = ProjectiveMontgomeryPoint;
209+
210+
fn neg(self) -> ProjectiveMontgomeryPoint {
211+
ProjectiveMontgomeryPoint {
212+
U: self.U,
213+
V: -self.V,
214+
W: self.W,
215+
}
216+
}
217+
}
218+
219+
impl Neg for ProjectiveMontgomeryPoint {
220+
type Output = Self;
221+
222+
fn neg(self) -> Self {
223+
-&self
224+
}
225+
}
226+
227+
impl Sub<&ProjectiveMontgomeryPoint> for &ProjectiveMontgomeryPoint {
228+
type Output = ProjectiveMontgomeryPoint;
229+
230+
fn sub(self, other: &ProjectiveMontgomeryPoint) -> ProjectiveMontgomeryPoint {
231+
self.add(&other.neg())
232+
}
233+
}
234+
235+
define_sub_variants!(
236+
LHS = ProjectiveMontgomeryPoint,
237+
RHS = ProjectiveMontgomeryPoint,
238+
Output = ProjectiveMontgomeryPoint
239+
);
240+
241+
impl Sub<&MontgomeryPoint> for &ProjectiveMontgomeryPoint {
242+
type Output = ProjectiveMontgomeryPoint;
243+
244+
fn sub(self, other: &MontgomeryPoint) -> ProjectiveMontgomeryPoint {
245+
*self - ProjectiveMontgomeryPoint::from(*other)
246+
}
247+
}
248+
249+
define_sub_variants!(
250+
LHS = ProjectiveMontgomeryPoint,
251+
RHS = MontgomeryPoint,
252+
Output = ProjectiveMontgomeryPoint
253+
);
254+
255+
impl Sub<&ProjectiveMontgomeryPoint> for &MontgomeryPoint {
256+
type Output = ProjectiveMontgomeryPoint;
257+
258+
fn sub(self, other: &ProjectiveMontgomeryPoint) -> ProjectiveMontgomeryPoint {
259+
*self - other
260+
}
261+
}
262+
263+
define_sub_variants!(
264+
LHS = MontgomeryPoint,
265+
RHS = ProjectiveMontgomeryPoint,
266+
Output = ProjectiveMontgomeryPoint
267+
);
268+
269+
impl<'b> SubAssign<&'b Self> for ProjectiveMontgomeryPoint {
270+
fn sub_assign(&mut self, _rhs: &'b Self) {
271+
*self = *self - _rhs;
272+
}
273+
}
274+
275+
define_sub_assign_variants!(
276+
LHS = ProjectiveMontgomeryPoint,
277+
RHS = ProjectiveMontgomeryPoint
278+
);
279+
280+
impl SubAssign<&MontgomeryPoint> for ProjectiveMontgomeryPoint {
281+
fn sub_assign(&mut self, rhs: &MontgomeryPoint) {
282+
*self -= ProjectiveMontgomeryPoint::from(*rhs);
283+
}
284+
}
285+
286+
define_sub_assign_variants!(LHS = ProjectiveMontgomeryPoint, RHS = MontgomeryPoint);
287+
288+
impl SubAssign<&ProjectiveMontgomeryPoint> for MontgomeryPoint {
289+
fn sub_assign(&mut self, rhs: &ProjectiveMontgomeryPoint) {
290+
*self = (ProjectiveMontgomeryPoint::from(*self) - rhs).into();
291+
}
292+
}
293+
294+
define_sub_assign_variants!(LHS = MontgomeryPoint, RHS = ProjectiveMontgomeryPoint);
295+
296+
impl<T> Sum<T> for ProjectiveMontgomeryPoint
297+
where
298+
T: Borrow<Self>,
299+
{
300+
fn sum<I>(iter: I) -> Self
301+
where
302+
I: Iterator<Item = T>,
303+
{
304+
iter.fold(Self::IDENTITY, |acc, item| acc + item.borrow())
305+
}
306+
}
307+
308+
#[cfg(test)]
309+
mod test {
310+
use elliptic_curve::Field;
311+
use rand_core::OsRng;
312+
313+
use super::*;
314+
315+
#[test]
316+
fn mixed_addition() {
317+
let p1 = ProjectiveMontgomeryPoint::GENERATOR
318+
* MontgomeryScalar::try_from_rng(&mut OsRng).unwrap();
319+
let p2 = ProjectiveMontgomeryPoint::GENERATOR
320+
* MontgomeryScalar::try_from_rng(&mut OsRng).unwrap();
321+
let p3 = p1 + p2;
322+
323+
assert_eq!(
324+
MontgomeryPoint::from(p3),
325+
(MontgomeryPoint::from(p1) + p2).into()
326+
);
327+
}
328+
}

0 commit comments

Comments
 (0)