1
- use crate :: field:: { ConstMontyType , FieldElement } ;
1
+ use crate :: field:: FieldElement ;
2
2
use core:: borrow:: Borrow ;
3
3
use core:: iter:: Sum ;
4
4
use core:: ops:: { Add , AddAssign , Mul , MulAssign , Neg , Sub , SubAssign } ;
5
5
use elliptic_curve:: CurveGroup ;
6
- use elliptic_curve:: bigint:: U448 ;
7
6
use subtle:: { Choice , ConditionallySelectable } ;
8
7
9
8
use super :: { MontgomeryPoint , MontgomeryScalar , ProjectiveMontgomeryPoint } ;
10
9
11
10
impl Add < & ProjectiveMontgomeryPoint > for & ProjectiveMontgomeryPoint {
12
11
type Output = ProjectiveMontgomeryPoint ;
13
12
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".
15
15
fn add ( self , rhs : & ProjectiveMontgomeryPoint ) -> Self :: Output {
16
- const S : FieldElement = FieldElement ( ConstMontyType :: new ( & U448 :: from_u64 ( 3 ) ) ) ;
17
-
18
16
let ( x1, y1, z1) = ( self . U , self . V , self . W ) ;
19
17
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;
36
18
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 }
42
45
}
43
46
}
44
47
@@ -51,8 +54,38 @@ define_add_variants!(
51
54
impl Add < & MontgomeryPoint > for & ProjectiveMontgomeryPoint {
52
55
type Output = ProjectiveMontgomeryPoint ;
53
56
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 }
56
89
}
57
90
}
58
91
@@ -66,7 +99,7 @@ impl Add<&ProjectiveMontgomeryPoint> for &MontgomeryPoint {
66
99
type Output = ProjectiveMontgomeryPoint ;
67
100
68
101
fn add ( self , other : & ProjectiveMontgomeryPoint ) -> ProjectiveMontgomeryPoint {
69
- * other + * self
102
+ other + self
70
103
}
71
104
}
72
105
@@ -111,9 +144,9 @@ impl Mul<&MontgomeryScalar> for &ProjectiveMontgomeryPoint {
111
144
let mut p = ProjectiveMontgomeryPoint :: IDENTITY ;
112
145
let bits = scalar. bits ( ) ;
113
146
114
- for s in ( 0 ..448 ) . rev ( ) {
147
+ for index in ( 0 ..448 ) . rev ( ) {
115
148
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 ) ) ;
117
150
}
118
151
119
152
p
@@ -264,3 +297,20 @@ where
264
297
iter. fold ( Self :: IDENTITY , |acc, item| acc + item. borrow ( ) )
265
298
}
266
299
}
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
+ }
0 commit comments