1 module dcrypt.ecc.curved25519.groupElement;
2 
3 public import dcrypt.ecc.curved25519.fieldElement;
4 import dcrypt.ecc.curved25519.base;
5 
6 @safe nothrow @nogc:
7 
8 /**
9  ge means group element.
10 
11  Here the group is the set of pairs (x,y) of field elements (see fe.h)
12  satisfying -x^2 + y^2 = 1 + d x^2y^2
13  where d = -121665/121666.
14 
15  Representations:
16  ge_p2 (projective): (X:Y:Z) satisfying x=X/Z, y=Y/Z
17  ge_p3 (extended): (X:Y:Z:T) satisfying x=X/Z, y=Y/Z, XY=ZT
18  ge_p1p1 (completed): ((X:Z),(Y:T)) satisfying x=X/Z, y=Y/T
19  ge_precomp (Duif): (y+x,y-x,2dxy)
20  */
21 
22 // #include "fe.h"
23 
24 /// ge_p2 (projective): (X:Y:Z) satisfying x=X/Z, y=Y/Z
25 public struct ge_p2 {
26 	@safe nothrow @nogc:
27 	enum ge_p2 zero = ge_p2(fe.zero, fe.one, fe.one);
28 	
29 	fe X = fe.zero;
30 	fe Y = fe.zero;
31 	fe Z = fe.one;
32 
33 	this(fe x, fe y, fe z) {
34 		X = x;
35 		Y = y;
36 		Z = z;
37 	}
38 
39 	@property
40 	ubyte[32] toBytes() const {
41 		ubyte[32] s;
42 		fe recip = Z.inverse;
43 		fe x = X * recip;
44 		fe y = Y * recip;
45 		
46 		s[0..32] = y.toBytes;
47 		s[31] ^= x.isNegative << 7;
48 		return s;
49 	}
50 
51 	/// Returns: r = 2*p
52 	ge_p1p1 dbl() const
53 	{
54 		fe t0;
55 		ge_p1p1 r;
56 
57 		r.X = X.sq;
58 		r.Z = Y.sq;
59 		r.T = Z.sq2;
60 		r.Y = X + Y;
61 		t0 = r.Y.sq;
62 		r.Y = r.Z + r.X;
63 		r.Z -= r.X;
64 		r.X = t0 - r.Y;
65 		r.T -= r.Z;
66 		
67 		return r;
68 	}
69 
70 }
71 
72 /// ge_p3 (extended): (X:Y:Z:T) satisfying x=X/Z, y=Y/Z, XY=ZT
73 public struct ge_p3 {
74 	@safe nothrow @nogc:
75 	enum ge_p3 zero = ge_p3(fe.zero, fe.one, fe.one, fe.zero);
76 
77 	fe X = fe.zero;
78 	fe Y = fe.one;
79 	fe Z = fe.one;
80 	fe T = fe.zero;
81 
82 	this(fe x, fe y, fe z, fe t) {
83 		X = x;
84 		Y = y;
85 		Z = z;
86 		T = t;
87 	}
88 
89 	ge_p2 opCast(G: ge_p2)() const {
90 		return ge_p2(X, Y, Z);
91 	}
92 
93 	ge_cached opCast(G: ge_cached)() const {
94 		return ge_cached(X+Y, Y-X, Z, T*d2);
95 	}
96 
97 	@property
98 	ubyte[32] toBytes() const {
99 		ubyte[32] s;
100 		fe recip = Z.inverse;
101 		fe x = X * recip;
102 		fe y = Y * recip;
103 		
104 		s[0..32] = y.toBytes;
105 		s[31] ^= x.isNegative << 7;
106 		return s;
107 	}
108 
109 
110 	/// Returns: r = 2*p
111 	ge_p1p1 dbl() const
112 	{
113 		return (cast(ge_p2) this).dbl();
114 	}
115 
116 	ge_p1p1 opBinary(string op, G)(auto ref const G rhs) const pure
117 		if ((op == "+" || op == "-") && (is(G == ge_cached) || is(G == ge_precomp)))
118 	{
119 		ge_p1p1 result;
120 		static if(is(G == ge_cached)) {
121 			static if(op == "+") {
122 				result = ge_add(this, rhs);
123 			} else static if(op == "-") {
124 				result = ge_sub(this, rhs);
125 			}
126 		} else {
127 			static if(op == "+") {
128 				result = ge_madd(this, rhs);
129 			} else static if(op == "-") {
130 				result = ge_msub(this, rhs);
131 			}
132 		}
133 
134 		return result;
135 	}
136 
137 }
138 
139 /// ge_p1p1 (completed): ((X:Z),(Y:T)) satisfying x=X/Z, y=Y/T
140 public struct ge_p1p1 {
141 	@safe nothrow @nogc:
142 	fe X;
143 	fe Y;
144 	fe Z;
145 	fe T;
146 
147 	this(fe x, fe y, fe z, fe t) {
148 		X = x;
149 		Y = y;
150 		Z = z;
151 		T = t;
152 	}
153 
154 	ge_p2 opCast(G: ge_p2)() const {
155 		return ge_p2(X*T, Y*Z, Z*T);
156 	}
157 
158 	ge_p3 opCast(G: ge_p3)() const {
159 		return ge_p3(X*T, Y*Z, Z*T, X*Y);
160 	}
161 
162 	ge_cached opCast(G: ge_cached)() const {
163 		//return ge_cached(X*T+Y*Z, Y*Z-X*T, Z*T, X*Y*d2);
164 		return cast(ge_cached) cast(ge_p3) this;
165 	}
166 }
167 
168 /// ge_precomp (Duif): (y+x,y-x,2dxy)
169 public struct ge_precomp {
170 	@safe nothrow @nogc:
171 	enum ge_precomp zero = ge_precomp(fe.one, fe.one, fe.zero);
172 
173 	fe yplusx = fe.one;
174 	fe yminusx = fe.one;
175 	fe xy2d = fe.zero;
176 
177 	this(fe yplusx, fe yminusx, fe xy2d) {
178 		this.yplusx = yplusx;
179 		this.yminusx = yminusx;
180 		this.xy2d = xy2d;
181 	}
182 
183 	this(in uint[] yplusx, in uint[] yminusx, in uint[] xy2d)
184 	in {
185 		assert(yplusx.length == 10);
186 		assert(yminusx.length == 10);
187 		assert(xy2d.length == 10);
188 	} body {
189 		this.yplusx = yplusx;
190 		this.yminusx = yminusx;
191 		this.xy2d = xy2d;
192 	}
193 }
194 
195 public struct ge_cached {
196 	@safe nothrow @nogc:
197 	fe YplusX;
198 	fe YminusX;
199 	fe Z;
200 	fe T2d;
201 
202 	this(fe yplusx, fe yminusx, fe z, fe t2d) {
203 		YplusX = yplusx;
204 		YminusX = yminusx;
205 		Z = z;
206 		T2d = t2d;
207 	}
208 };
209 
210 
211 /**
212  r = p + q
213  */
214 private ge_p1p1 ge_add(in ref ge_p3 p, in ref ge_cached q) pure
215 {
216 	ge_p1p1 r;
217 	fe t0;
218 	r.X = p.Y + p.X;
219 	r.Y = p.Y - p.X;
220 	r.Z = r.X * q.YplusX;
221 	r.Y *= q.YminusX;
222 	r.T = q.T2d * p.T;
223 	r.X = p.Z * q.Z;
224 	t0 = r.X + r.X;
225 	r.X = r.Z - r.Y;
226 	r.Y += r.Z;
227 	r.Z = t0 + r.T;
228 	r.T = t0 - r.T;
229 	return r;
230 }
231 
232 /**
233  r = p - q
234  */
235 private ge_p1p1 ge_sub(in ref ge_p3 p, in ref ge_cached q) pure
236 {
237 	ge_p1p1 r;
238 	fe t0;
239 	r.X = p.Y + p.X;
240 	r.Y = p.Y - p.X;
241 	r.Z = r.X * q.YminusX;
242 	r.Y *= q.YplusX;
243 	r.T = q.T2d * p.T;
244 	r.X = p.Z * q.Z;
245 	t0 = r.X + r.X;
246 	r.X = r.Z - r.Y;
247 	r.Y += r.Z;
248 	r.Z = t0 - r.T;
249 	r.T += t0;
250 	return r;
251 }
252 
253 /**
254  r = p + q
255  */
256 private ge_p1p1 ge_madd(in ref ge_p3 p, in ref ge_precomp q) pure
257 {
258 	ge_p1p1 r;
259 	fe t0;
260 	r.X = p.Y + p.X;
261 	r.Y = p.Y - p.X;
262 	r.Z = r.X * q.yplusx;
263 	r.Y *= q.yminusx;
264 	r.T = q.xy2d * p.T;
265 	t0 = p.Z + p.Z;
266 	r.X = r.Z - r.Y;
267 	r.Y += r.Z;
268 	r.Z = t0 + r.T;
269 	r.T = t0 - r.T;
270 
271 	return r;
272 }
273 
274 
275 /**
276  r = p - q
277  */
278 private ge_p1p1 ge_msub(in ref ge_p3 p, in ref ge_precomp q) pure
279 {
280 	ge_p1p1 r;
281 	fe t0;
282 	r.X = p.Y + p.X;
283 	r.Y = p.Y - p.X;
284 	r.Z = r.X * q.yminusx;
285 	r.Y *= q.yplusx;
286 	r.T = q.xy2d * p.T;
287 	t0 = p.Z + p.Z;
288 	r.X = r.Z - r.Y;
289 	r.Y += r.Z;
290 	r.Z = t0 - r.T;
291 	r.T += t0;
292 	return r;
293 }
294 
295 // TODO pre conditions
296 private void slide(byte[] r, in ubyte[] a)
297 {	
298 	for (uint i = 0; i < 256; ++i) {
299 		r[i] = 1 & (a[i >> 3] >> (i & 7));
300 	}
301 	
302 	for (uint i = 0; i < 256; ++i) {
303 		if (r[i]) {
304 			for (uint b = 1; b <= 6 && i + b < 256; ++b) {
305 				if (r[i + b]) {
306 					if (r[i] + (r[i + b] << b) <= 15) {
307 						r[i] += r[i + b] << b; r[i + b] = 0;
308 					} else if (r[i] - (r[i + b] << b) >= -15) {
309 						r[i] -= r[i + b] << b;
310 						for (uint k = i + b; k < 256; ++k) {
311 							if (!r[k]) {
312 								r[k] = 1;
313 								break;
314 							}
315 							r[k] = 0;
316 						}
317 					} else
318 						break;
319 				}
320 			}
321 		}
322 	}
323 	
324 }
325 
326 
327 /// calculates a * A + b * B
328 /// B is the Ed25519 base point (x,4/5) with x positive.
329 /// Params:
330 /// a = a[0]+256*a[1]+...+256^31 a[31].
331 /// b = b[0]+256*b[1]+...+256^31 b[31].
332 /// Returns: r = a * A + b * B
333 
334 ge_p2 ge_double_scalarmult_vartime(in ubyte[] a, in ref ge_p3 A, in ubyte[] b)
335 {
336 	byte[256] aslide, bslide;
337 
338 	ge_cached[8] Ai; /* A,3A,5A,7A,9A,11A,13A,15A */
339 	ge_p1p1 t;
340 	ge_p3 u;
341 	ge_p3 A2;
342 	ge_p2 r; /// result
343 	
344 	slide(aslide,a);
345 	slide(bslide, b);
346 	
347 	Ai[0] = cast(ge_cached) A;
348 	A2 = cast(ge_p3) A.dbl();
349 	foreach(i; 0..7) {
350 		Ai[i+1] = cast(ge_cached) (A2 + Ai[i]);
351 	}
352 	
353 	r = ge_p2.zero;
354 	
355 	int i;
356 	for (i = 255; i >= 0; --i) {
357 		if (aslide[i] || bslide[i]) break;
358 	}
359 	
360 	for (; i >= 0; --i) {
361 		t = r.dbl();
362 		u = cast(ge_p3) t;
363 		if (aslide[i] > 0) {
364 			t = u + Ai[aslide[i]/2];
365 		} else if (aslide[i] < 0) {
366 			t = u - Ai[(-aslide[i])/2];
367 		}
368 		
369 		u = cast(ge_p3) t;
370 		if (bslide[i] > 0) {
371 			t = u + Bi[bslide[i]/2];
372 		} else if (bslide[i] < 0) {
373 			t = u - Bi[(-bslide[i])/2];
374 		}
375 
376 		r = cast(ge_p2) t;
377 	}
378 
379 	return r;
380 }
381 
382 
383 
384 bool ge_frombytes_negate_vartime(ref ge_p3 h, in ubyte[] s)
385 in {
386 	assert(s.length == 32);
387 } body {
388 	fe u;
389 	fe v;
390 	fe v3;
391 	fe vxx;
392 	fe check;
393 	
394 	h.Y = fe.fromBytes(s);
395 	h.Z = fe.one;
396 	u = h.Y.sq;
397 	v = u * d;
398 	u -= h.Z;      /* u = y^2-1 */
399 	v += h.Z;       /* v = dy^2+1 */
400 
401 	v3 = v.cpow!3;	/* v3 = v^3 */
402 	h.X = u * v3.sq * v; /* x = uv^7 */
403 
404 	h.X = fe_pow22523(h.X); /* x = (uv^7)^((q-5)/8) */
405 	//h.X = h.X.cpow!22523;
406 	h.X *= v3;
407 	h.X *= u;    /* x = uv^3(uv^7)^((q-5)/8) */
408 
409 	vxx = h.X.sq;
410 	vxx *= v;
411 	check = vxx - u;    /* vx^2-u */
412 	if (check.isNonzero) {
413 		check = vxx + u;  /* vx^2+u */
414 		if (check.isNonzero) return false;
415 		h.X *= sqrtm1;
416 	}
417 	
418 	if (h.X.isNegative == (s[31] >> 7)) {
419 		h.X.negate();
420 	}
421 
422 	h.T = h.X * h.Y;
423 	return true;
424 }
425 
426 
427 /// Conditional move: t = u, if and only if b != 0.
428 void cmov(ref ge_precomp t, in ref ge_precomp u, in bool b)
429 in {
430 	assert(b == 0 || b == 1);
431 } body {
432 	fe_cmov(t.yplusx, u.yplusx, b);
433 	fe_cmov(t.yminusx, u.yminusx, b);
434 	fe_cmov(t.xy2d, u.xy2d, b);
435 }
436 
437 
438 /// Select ge_precomp from base table in constant time.
439 /// Params:
440 /// b = 
441 private ge_precomp select(in int pos, in byte b)
442 {
443 	ge_precomp minust;
444 	immutable bool bnegative = b < 0;
445 	immutable ubyte babs = cast(ubyte) (b - (cast(byte)((-cast(int)(bnegative)) & cast(ubyte)b) << 1)); // abs(b)
446 
447 	assert((b >= 0 && babs == b) || (b < 0 && babs == -b));
448 	
449 	ge_precomp t;
450 	cmov(t, base[pos][0], babs == 1);
451 	cmov(t, base[pos][1], babs == 2);
452 	cmov(t, base[pos][2], babs == 3);
453 	cmov(t, base[pos][3], babs == 4);
454 	cmov(t, base[pos][4], babs == 5);
455 	cmov(t, base[pos][5], babs == 6);
456 	cmov(t, base[pos][6], babs == 7);
457 	cmov(t, base[pos][7], babs == 8);
458 	minust.yplusx = t.yminusx;
459 	minust.yminusx = t.yplusx;
460 	minust.xy2d = -t.xy2d;
461 	cmov(t, minust, bnegative);
462 	return t;
463 }
464 
465 /**
466  h = a * B
467  where a = a[0]+256*a[1]+...+256^31 a[31]
468  B is the Ed25519 base point (x,4/5) with x positive.
469 
470  Preconditions:
471  a[31] <= 127
472  */
473 ge_p3 ge_scalarmult_base(in ubyte[] a)
474 in {
475 	assert(a.length == 32, "'a' is expected to be 32 bytes.");
476 	assert(a[31] <= 127);
477 } body {
478 	byte[64] e;
479 
480 	ge_p1p1 r;
481 	ge_p2 s;
482 	ge_precomp t;
483 	ge_p3 h;
484 	
485 	for (uint i = 0; i < 32; ++i) {
486 		e[2 * i + 0] = (a[i] >> 0) & 0x0F;
487 		e[2 * i + 1] = (a[i] >> 4) & 0x0F;
488 	}
489 	/* each e[i] is between 0 and 15 */
490 	/* e[63] is between 0 and 7 */
491 	
492 	byte carry = 0;
493 	for (uint i = 0; i < 63; ++i) {
494 		e[i] += carry;
495 		carry = cast(byte) (e[i] + 8);
496 		e[i] -= carry & 0xF0;
497 		carry >>= 4;
498 	}
499 	e[63] += carry;
500 	/* each e[i] is between -8 and 8 */
501 	
502 	h = ge_p3.zero;
503 	for (uint i = 1; i < 64; i += 2) {
504 		h = cast(ge_p3) (h + select(i / 2, e[i]));
505 	}
506 
507 	s = cast(ge_p2) h.dbl();
508 	s = cast(ge_p2) s.dbl();
509 	s = cast(ge_p2) s.dbl();
510 	h = cast(ge_p3) s.dbl();
511 		
512 	for (uint i = 0; i < 64; i += 2) {
513 		h = cast(ge_p3) (h + select(i / 2, e[i]));
514 	}
515 
516 	return h;
517 }
518 
519 
520 
521 // constants
522 private:
523 immutable fe d = [-10913610,13857413,-15372611,6949391,114729,-8787816,-6275908,-3247719,-18696448,-12055116];
524 immutable fe d2 = [-21827239,-5839606,-30745221,13898782,229458,15978800,-12551817,-6495438,29715968,9444199];
525 immutable fe sqrtm1 = [-32595792,-7943725,9377950,3500415,12389472,-272473,-25146209,-2005654,326686,11406482];
526 
527 /// 1B, 2B, ...
528 immutable ge_precomp[8] Bi = [
529 	ge_precomp(
530 		[ 25967493,-14356035,29566456,3660896,-12694345,4014787,27544626,-11754271,-6079156,2047605 ],
531 		[ -12545711,934262,-2722910,3049990,-727428,9406986,12720692,5043384,19500929,-15469378 ],
532 		[ -8738181,4489570,9688441,-14785194,10184609,-12363380,29287919,11864899,-24514362,-4438546 ],
533 		),
534 	ge_precomp(
535 		[ 15636291,-9688557,24204773,-7912398,616977,-16685262,27787600,-14772189,28944400,-1550024 ],
536 		[ 16568933,4717097,-11556148,-1102322,15682896,-11807043,16354577,-11775962,7689662,11199574 ],
537 		[ 30464156,-5976125,-11779434,-15670865,23220365,15915852,7512774,10017326,-17749093,-9920357 ],
538 		),
539 	ge_precomp(
540 		[ 10861363,11473154,27284546,1981175,-30064349,12577861,32867885,14515107,-15438304,10819380 ],
541 		[ 4708026,6336745,20377586,9066809,-11272109,6594696,-25653668,12483688,-12668491,5581306 ],
542 		[ 19563160,16186464,-29386857,4097519,10237984,-4348115,28542350,13850243,-23678021,-15815942 ],
543 		),
544 	ge_precomp(
545 		[ 5153746,9909285,1723747,-2777874,30523605,5516873,19480852,5230134,-23952439,-15175766 ],
546 		[ -30269007,-3463509,7665486,10083793,28475525,1649722,20654025,16520125,30598449,7715701 ],
547 		[ 28881845,14381568,9657904,3680757,-20181635,7843316,-31400660,1370708,29794553,-1409300 ],
548 		),
549 	ge_precomp(
550 		[ -22518993,-6692182,14201702,-8745502,-23510406,8844726,18474211,-1361450,-13062696,13821877 ],
551 		[ -6455177,-7839871,3374702,-4740862,-27098617,-10571707,31655028,-7212327,18853322,-14220951 ],
552 		[ 4566830,-12963868,-28974889,-12240689,-7602672,-2830569,-8514358,-10431137,2207753,-3209784 ],
553 		),
554 	ge_precomp(
555 		[ -25154831,-4185821,29681144,7868801,-6854661,-9423865,-12437364,-663000,-31111463,-16132436 ],
556 		[ 25576264,-2703214,7349804,-11814844,16472782,9300885,3844789,15725684,171356,6466918 ],
557 		[ 23103977,13316479,9739013,-16149481,817875,-15038942,8965339,-14088058,-30714912,16193877 ],
558 		),
559 	ge_precomp(
560 		[ -33521811,3180713,-2394130,14003687,-16903474,-16270840,17238398,4729455,-18074513,9256800 ],
561 		[ -25182317,-4174131,32336398,5036987,-21236817,11360617,22616405,9761698,-19827198,630305 ],
562 		[ -13720693,2639453,-24237460,-7406481,9494427,-5774029,-6554551,-15960994,-2449256,-14291300 ],
563 		),
564 	ge_precomp(
565 		[ -3151181,-5046075,9282714,6866145,-31907062,-863023,-18940575,15033784,25105118,-7894876 ],
566 		[ -24326370,15950226,-31801215,-14592823,-11662737,-5090925,1573892,-2625887,2198790,-15804619 ],
567 		[ -3099351,10324967,-2241613,7453183,-5446979,-2735503,-13812022,-16236442,-32461234,-12290683 ],
568 		)
569 ];