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 ];