1 package org.bouncycastle.math.ec.rfc8032; 2 3 import java.security.SecureRandom; 4 5 import org.bouncycastle.crypto.Xof; 6 import org.bouncycastle.crypto.digests.SHAKEDigest; 7 import org.bouncycastle.math.ec.rfc7748.X448; 8 import org.bouncycastle.math.ec.rfc7748.X448Field; 9 import org.bouncycastle.math.raw.Nat; 10 import org.bouncycastle.util.Arrays; 11 12 public abstract class Ed448 13 { 14 // x^2 + y^2 == 1 - 39081 * x^2 * y^2 15 16 public static final class Algorithm 17 { 18 public static final int Ed448 = 0; 19 public static final int Ed448ph = 1; 20 } 21 22 private static class F extends X448Field {}; 23 24 private static final long M26L = 0x03FFFFFFL; 25 private static final long M28L = 0x0FFFFFFFL; 26 private static final long M32L = 0xFFFFFFFFL; 27 28 private static final int COORD_INTS = 14; 29 private static final int POINT_BYTES = COORD_INTS * 4 + 1; 30 private static final int SCALAR_INTS = 14; 31 private static final int SCALAR_BYTES = SCALAR_INTS * 4 + 1; 32 33 public static final int PREHASH_SIZE = 64; 34 public static final int PUBLIC_KEY_SIZE = POINT_BYTES; 35 public static final int SECRET_KEY_SIZE = 57; 36 public static final int SIGNATURE_SIZE = POINT_BYTES + SCALAR_BYTES; 37 38 // "SigEd448" 39 private static final byte[] DOM4_PREFIX = new byte[]{ 0x53, 0x69, 0x67, 0x45, 0x64, 0x34, 0x34, 0x38 }; 40 41 private static final int[] P = new int[] { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 42 0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF }; 43 private static final int[] L = new int[] { 0xAB5844F3, 0x2378C292, 0x8DC58F55, 0x216CC272, 0xAED63690, 0xC44EDB49, 0x7CCA23E9, 44 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x3FFFFFFF }; 45 46 private static final int L_0 = 0x04A7BB0D; // L_0:26/24 47 private static final int L_1 = 0x0873D6D5; // L_1:27/23 48 private static final int L_2 = 0x0A70AADC; // L_2:27/26 49 private static final int L_3 = 0x03D8D723; // L_3:26/-- 50 private static final int L_4 = 0x096FDE93; // L_4:27/25 51 private static final int L_5 = 0x0B65129C; // L_5:27/26 52 private static final int L_6 = 0x063BB124; // L_6:27/-- 53 private static final int L_7 = 0x08335DC1; // L_7:27/22 54 55 private static final int L4_0 = 0x029EEC34; // L4_0:25/24 56 private static final int L4_1 = 0x01CF5B55; // L4_1:25/-- 57 private static final int L4_2 = 0x09C2AB72; // L4_2:27/25 58 private static final int L4_3 = 0x0F635C8E; // L4_3:28/-- 59 private static final int L4_4 = 0x05BF7A4C; // L4_4:26/25 60 private static final int L4_5 = 0x0D944A72; // L4_5:28/-- 61 private static final int L4_6 = 0x08EEC492; // L4_6:27/24 62 private static final int L4_7 = 0x20CD7705; // L4_7:29/24 63 64 private static final int[] B_x = new int[] { 0x070CC05E, 0x026A82BC, 0x00938E26, 0x080E18B0, 0x0511433B, 0x0F72AB66, 0x0412AE1A, 65 0x0A3D3A46, 0x0A6DE324, 0x00F1767E, 0x04657047, 0x036DA9E1, 0x05A622BF, 0x0ED221D1, 0x066BED0D, 0x04F1970C }; 66 private static final int[] B_y = new int[] { 0x0230FA14, 0x008795BF, 0x07C8AD98, 0x0132C4ED, 0x09C4FDBD, 0x01CE67C3, 0x073AD3FF, 67 0x005A0C2D, 0x07789C1E, 0x0A398408, 0x0A73736C, 0x0C7624BE, 0x003756C9, 0x02488762, 0x016EB6BC, 0x0693F467 }; 68 private static final int C_d = -39081; 69 70 private static final int WNAF_WIDTH_BASE = 7; 71 72 private static final int PRECOMP_BLOCKS = 5; 73 private static final int PRECOMP_TEETH = 5; 74 private static final int PRECOMP_SPACING = 18; 75 private static final int PRECOMP_POINTS = 1 << (PRECOMP_TEETH - 1); 76 private static final int PRECOMP_MASK = PRECOMP_POINTS - 1; 77 78 private static final Object precompLock = new Object(); 79 // TODO[ed448] Convert to PointPrecomp 80 private static PointExt[] precompBaseTable = null; 81 private static int[] precompBase = null; 82 83 private static class PointExt 84 { 85 int[] x = F.create(); 86 int[] y = F.create(); 87 int[] z = F.create(); 88 } 89 90 private static class PointPrecomp 91 { 92 int[] x = F.create(); 93 int[] y = F.create(); 94 } 95 calculateS(byte[] r, byte[] k, byte[] s)96 private static byte[] calculateS(byte[] r, byte[] k, byte[] s) 97 { 98 int[] t = new int[SCALAR_INTS * 2]; decodeScalar(r, 0, t); 99 int[] u = new int[SCALAR_INTS]; decodeScalar(k, 0, u); 100 int[] v = new int[SCALAR_INTS]; decodeScalar(s, 0, v); 101 102 Nat.mulAddTo(SCALAR_INTS, u, v, t); 103 104 byte[] result = new byte[SCALAR_BYTES * 2]; 105 for (int i = 0; i < t.length; ++i) 106 { 107 encode32(t[i], result, i * 4); 108 } 109 return reduceScalar(result); 110 } 111 checkContextVar(byte[] ctx)112 private static boolean checkContextVar(byte[] ctx) 113 { 114 return ctx != null && ctx.length < 256; 115 } 116 checkPoint(int[] x, int[] y)117 private static int checkPoint(int[] x, int[] y) 118 { 119 int[] t = F.create(); 120 int[] u = F.create(); 121 int[] v = F.create(); 122 123 F.sqr(x, u); 124 F.sqr(y, v); 125 F.mul(u, v, t); 126 F.add(u, v, u); 127 F.mul(t, -C_d, t); 128 F.subOne(t); 129 F.add(t, u, t); 130 F.normalize(t); 131 132 return F.isZero(t); 133 } 134 checkPoint(int[] x, int[] y, int[] z)135 private static int checkPoint(int[] x, int[] y, int[] z) 136 { 137 int[] t = F.create(); 138 int[] u = F.create(); 139 int[] v = F.create(); 140 int[] w = F.create(); 141 142 F.sqr(x, u); 143 F.sqr(y, v); 144 F.sqr(z, w); 145 F.mul(u, v, t); 146 F.add(u, v, u); 147 F.mul(u, w, u); 148 F.sqr(w, w); 149 F.mul(t, -C_d, t); 150 F.sub(t, w, t); 151 F.add(t, u, t); 152 F.normalize(t); 153 154 return F.isZero(t); 155 } 156 checkPointVar(byte[] p)157 private static boolean checkPointVar(byte[] p) 158 { 159 if ((p[POINT_BYTES - 1] & 0x7F) != 0x00) 160 { 161 return false; 162 } 163 164 int[] t = new int[COORD_INTS]; 165 decode32(p, 0, t, 0, COORD_INTS); 166 return !Nat.gte(COORD_INTS, t, P); 167 } 168 checkScalarVar(byte[] s, int[] n)169 private static boolean checkScalarVar(byte[] s, int[] n) 170 { 171 if (s[SCALAR_BYTES - 1] != 0x00) 172 { 173 return false; 174 } 175 176 decodeScalar(s, 0, n); 177 return !Nat.gte(SCALAR_INTS, n, L); 178 } 179 copy(byte[] buf, int off, int len)180 private static byte[] copy(byte[] buf, int off, int len) 181 { 182 byte[] result = new byte[len]; 183 System.arraycopy(buf, off, result, 0, len); 184 return result; 185 } 186 createPrehash()187 public static Xof createPrehash() 188 { 189 return createXof(); 190 } 191 createXof()192 private static Xof createXof() 193 { 194 return new SHAKEDigest(256); 195 } 196 decode16(byte[] bs, int off)197 private static int decode16(byte[] bs, int off) 198 { 199 int n = bs[off] & 0xFF; 200 n |= (bs[++off] & 0xFF) << 8; 201 return n; 202 } 203 decode24(byte[] bs, int off)204 private static int decode24(byte[] bs, int off) 205 { 206 int n = bs[ off] & 0xFF; 207 n |= (bs[++off] & 0xFF) << 8; 208 n |= (bs[++off] & 0xFF) << 16; 209 return n; 210 } 211 decode32(byte[] bs, int off)212 private static int decode32(byte[] bs, int off) 213 { 214 int n = bs[off] & 0xFF; 215 n |= (bs[++off] & 0xFF) << 8; 216 n |= (bs[++off] & 0xFF) << 16; 217 n |= bs[++off] << 24; 218 return n; 219 } 220 decode32(byte[] bs, int bsOff, int[] n, int nOff, int nLen)221 private static void decode32(byte[] bs, int bsOff, int[] n, int nOff, int nLen) 222 { 223 for (int i = 0; i < nLen; ++i) 224 { 225 n[nOff + i] = decode32(bs, bsOff + i * 4); 226 } 227 } 228 decodePointVar(byte[] p, int pOff, boolean negate, PointExt r)229 private static boolean decodePointVar(byte[] p, int pOff, boolean negate, PointExt r) 230 { 231 byte[] py = copy(p, pOff, POINT_BYTES); 232 if (!checkPointVar(py)) 233 { 234 return false; 235 } 236 237 int x_0 = (py[POINT_BYTES - 1] & 0x80) >>> 7; 238 py[POINT_BYTES - 1] &= 0x7F; 239 240 F.decode(py, 0, r.y); 241 242 int[] u = F.create(); 243 int[] v = F.create(); 244 245 F.sqr(r.y, u); 246 F.mul(u, -C_d, v); 247 F.negate(u, u); 248 F.addOne(u); 249 F.addOne(v); 250 251 if (!F.sqrtRatioVar(u, v, r.x)) 252 { 253 return false; 254 } 255 256 F.normalize(r.x); 257 if (x_0 == 1 && F.isZeroVar(r.x)) 258 { 259 return false; 260 } 261 262 if (negate ^ (x_0 != (r.x[0] & 1))) 263 { 264 F.negate(r.x, r.x); 265 } 266 267 pointExtendXY(r); 268 return true; 269 } 270 decodeScalar(byte[] k, int kOff, int[] n)271 private static void decodeScalar(byte[] k, int kOff, int[] n) 272 { 273 // assert k[kOff + SCALAR_BYTES - 1] == 0x00; 274 275 decode32(k, kOff, n, 0, SCALAR_INTS); 276 } 277 dom4(Xof d, byte phflag, byte[] ctx)278 private static void dom4(Xof d, byte phflag, byte[] ctx) 279 { 280 int n = DOM4_PREFIX.length; 281 byte[] t = new byte[n + 2 + ctx.length]; 282 System.arraycopy(DOM4_PREFIX, 0, t, 0, n); 283 t[n] = phflag; 284 t[n + 1] = (byte)ctx.length; 285 System.arraycopy(ctx, 0, t, n + 2, ctx.length); 286 287 d.update(t, 0, t.length); 288 } 289 encode24(int n, byte[] bs, int off)290 private static void encode24(int n, byte[] bs, int off) 291 { 292 bs[ off] = (byte)(n ); 293 bs[++off] = (byte)(n >>> 8); 294 bs[++off] = (byte)(n >>> 16); 295 } 296 encode32(int n, byte[] bs, int off)297 private static void encode32(int n, byte[] bs, int off) 298 { 299 bs[ off] = (byte)(n ); 300 bs[++off] = (byte)(n >>> 8); 301 bs[++off] = (byte)(n >>> 16); 302 bs[++off] = (byte)(n >>> 24); 303 } 304 encode56(long n, byte[] bs, int off)305 private static void encode56(long n, byte[] bs, int off) 306 { 307 encode32((int)n, bs, off); 308 encode24((int)(n >>> 32), bs, off + 4); 309 } 310 encodePoint(PointExt p, byte[] r, int rOff)311 private static int encodePoint(PointExt p, byte[] r, int rOff) 312 { 313 int[] x = F.create(); 314 int[] y = F.create(); 315 316 F.inv(p.z, y); 317 F.mul(p.x, y, x); 318 F.mul(p.y, y, y); 319 F.normalize(x); 320 F.normalize(y); 321 322 int result = checkPoint(x, y); 323 324 F.encode(y, r, rOff); 325 r[rOff + POINT_BYTES - 1] = (byte)((x[0] & 1) << 7); 326 327 return result; 328 } 329 generatePrivateKey(SecureRandom random, byte[] k)330 public static void generatePrivateKey(SecureRandom random, byte[] k) 331 { 332 random.nextBytes(k); 333 } 334 generatePublicKey(byte[] sk, int skOff, byte[] pk, int pkOff)335 public static void generatePublicKey(byte[] sk, int skOff, byte[] pk, int pkOff) 336 { 337 Xof d = createXof(); 338 byte[] h = new byte[SCALAR_BYTES * 2]; 339 340 d.update(sk, skOff, SECRET_KEY_SIZE); 341 d.doFinal(h, 0, h.length); 342 343 byte[] s = new byte[SCALAR_BYTES]; 344 pruneScalar(h, 0, s); 345 346 scalarMultBaseEncoded(s, pk, pkOff); 347 } 348 getWindow4(int[] x, int n)349 private static int getWindow4(int[] x, int n) 350 { 351 int w = n >>> 3, b = (n & 7) << 2; 352 return (x[w] >>> b) & 15; 353 } 354 getWnafVar(int[] n, int width)355 private static byte[] getWnafVar(int[] n, int width) 356 { 357 // assert 0 <= n[SCALAR_INTS - 1] && n[SCALAR_INTS - 1] <= L[SCALAR_INTS - 1]; 358 // assert 2 <= width && width <= 8; 359 360 int[] t = new int[SCALAR_INTS * 2]; 361 { 362 int tPos = t.length, c = 0; 363 int i = SCALAR_INTS; 364 while (--i >= 0) 365 { 366 int next = n[i]; 367 t[--tPos] = (next >>> 16) | (c << 16); 368 t[--tPos] = c = next; 369 } 370 } 371 372 byte[] ws = new byte[447]; 373 374 final int lead = 32 - width; 375 376 int j = 0, carry = 0; 377 for (int i = 0; i < t.length; ++i, j -= 16) 378 { 379 int word = t[i]; 380 while (j < 16) 381 { 382 int word16 = word >>> j; 383 int bit = word16 & 1; 384 385 if (bit == carry) 386 { 387 ++j; 388 continue; 389 } 390 391 int digit = (word16 | 1) << lead; 392 carry = digit >>> 31; 393 394 ws[(i << 4) + j] = (byte)(digit >> lead); 395 396 j += width; 397 } 398 } 399 400 // assert carry == 0; 401 402 return ws; 403 } 404 implSign(Xof d, byte[] h, byte[] s, byte[] pk, int pkOff, byte[] ctx, byte phflag, byte[] m, int mOff, int mLen, byte[] sig, int sigOff)405 private static void implSign(Xof d, byte[] h, byte[] s, byte[] pk, int pkOff, byte[] ctx, byte phflag, 406 byte[] m, int mOff, int mLen, byte[] sig, int sigOff) 407 { 408 dom4(d, phflag, ctx); 409 d.update(h, SCALAR_BYTES, SCALAR_BYTES); 410 d.update(m, mOff, mLen); 411 d.doFinal(h, 0, h.length); 412 413 byte[] r = reduceScalar(h); 414 byte[] R = new byte[POINT_BYTES]; 415 scalarMultBaseEncoded(r, R, 0); 416 417 dom4(d, phflag, ctx); 418 d.update(R, 0, POINT_BYTES); 419 d.update(pk, pkOff, POINT_BYTES); 420 d.update(m, mOff, mLen); 421 d.doFinal(h, 0, h.length); 422 423 byte[] k = reduceScalar(h); 424 byte[] S = calculateS(r, k, s); 425 426 System.arraycopy(R, 0, sig, sigOff, POINT_BYTES); 427 System.arraycopy(S, 0, sig, sigOff + POINT_BYTES, SCALAR_BYTES); 428 } 429 implSign(byte[] sk, int skOff, byte[] ctx, byte phflag, byte[] m, int mOff, int mLen, byte[] sig, int sigOff)430 private static void implSign(byte[] sk, int skOff, byte[] ctx, byte phflag, byte[] m, int mOff, int mLen, 431 byte[] sig, int sigOff) 432 { 433 if (!checkContextVar(ctx)) 434 { 435 throw new IllegalArgumentException("ctx"); 436 } 437 438 Xof d = createXof(); 439 byte[] h = new byte[SCALAR_BYTES * 2]; 440 441 d.update(sk, skOff, SECRET_KEY_SIZE); 442 d.doFinal(h, 0, h.length); 443 444 byte[] s = new byte[SCALAR_BYTES]; 445 pruneScalar(h, 0, s); 446 447 byte[] pk = new byte[POINT_BYTES]; 448 scalarMultBaseEncoded(s, pk, 0); 449 450 implSign(d, h, s, pk, 0, ctx, phflag, m, mOff, mLen, sig, sigOff); 451 } 452 implSign(byte[] sk, int skOff, byte[] pk, int pkOff, byte[] ctx, byte phflag, byte[] m, int mOff, int mLen, byte[] sig, int sigOff)453 private static void implSign(byte[] sk, int skOff, byte[] pk, int pkOff, byte[] ctx, byte phflag, 454 byte[] m, int mOff, int mLen, byte[] sig, int sigOff) 455 { 456 if (!checkContextVar(ctx)) 457 { 458 throw new IllegalArgumentException("ctx"); 459 } 460 461 Xof d = createXof(); 462 byte[] h = new byte[SCALAR_BYTES * 2]; 463 464 d.update(sk, skOff, SECRET_KEY_SIZE); 465 d.doFinal(h, 0, h.length); 466 467 byte[] s = new byte[SCALAR_BYTES]; 468 pruneScalar(h, 0, s); 469 470 implSign(d, h, s, pk, pkOff, ctx, phflag, m, mOff, mLen, sig, sigOff); 471 } 472 implVerify(byte[] sig, int sigOff, byte[] pk, int pkOff, byte[] ctx, byte phflag, byte[] m, int mOff, int mLen)473 private static boolean implVerify(byte[] sig, int sigOff, byte[] pk, int pkOff, byte[] ctx, byte phflag, 474 byte[] m, int mOff, int mLen) 475 { 476 if (!checkContextVar(ctx)) 477 { 478 throw new IllegalArgumentException("ctx"); 479 } 480 481 byte[] R = copy(sig, sigOff, POINT_BYTES); 482 byte[] S = copy(sig, sigOff + POINT_BYTES, SCALAR_BYTES); 483 484 if (!checkPointVar(R)) 485 { 486 return false; 487 } 488 489 int[] nS = new int[SCALAR_INTS]; 490 if (!checkScalarVar(S, nS)) 491 { 492 return false; 493 } 494 495 PointExt pA = new PointExt(); 496 if (!decodePointVar(pk, pkOff, true, pA)) 497 { 498 return false; 499 } 500 501 Xof d = createXof(); 502 byte[] h = new byte[SCALAR_BYTES * 2]; 503 504 dom4(d, phflag, ctx); 505 d.update(R, 0, POINT_BYTES); 506 d.update(pk, pkOff, POINT_BYTES); 507 d.update(m, mOff, mLen); 508 d.doFinal(h, 0, h.length); 509 510 byte[] k = reduceScalar(h); 511 512 int[] nA = new int[SCALAR_INTS]; 513 decodeScalar(k, 0, nA); 514 515 PointExt pR = new PointExt(); 516 scalarMultStrausVar(nS, nA, pA, pR); 517 518 byte[] check = new byte[POINT_BYTES]; 519 return 0 != encodePoint(pR, check, 0) && Arrays.areEqual(check, R); 520 } 521 isNeutralElementVar(int[] x, int[] y, int[] z)522 private static boolean isNeutralElementVar(int[] x, int[] y, int[] z) 523 { 524 return F.isZeroVar(x) && F.areEqualVar(y, z); 525 } 526 pointAdd(PointExt p, PointExt r)527 private static void pointAdd(PointExt p, PointExt r) 528 { 529 int[] a = F.create(); 530 int[] b = F.create(); 531 int[] c = F.create(); 532 int[] d = F.create(); 533 int[] e = F.create(); 534 int[] f = F.create(); 535 int[] g = F.create(); 536 int[] h = F.create(); 537 538 F.mul(p.z, r.z, a); 539 F.sqr(a, b); 540 F.mul(p.x, r.x, c); 541 F.mul(p.y, r.y, d); 542 F.mul(c, d, e); 543 F.mul(e, -C_d, e); 544 // F.apm(b, e, f, g); 545 F.add(b, e, f); 546 F.sub(b, e, g); 547 F.add(p.x, p.y, b); 548 F.add(r.x, r.y, e); 549 F.mul(b, e, h); 550 // F.apm(d, c, b, e); 551 F.add(d, c, b); 552 F.sub(d, c, e); 553 F.carry(b); 554 F.sub(h, b, h); 555 F.mul(h, a, h); 556 F.mul(e, a, e); 557 F.mul(f, h, r.x); 558 F.mul(e, g, r.y); 559 F.mul(f, g, r.z); 560 } 561 pointAddVar(boolean negate, PointExt p, PointExt r)562 private static void pointAddVar(boolean negate, PointExt p, PointExt r) 563 { 564 int[] a = F.create(); 565 int[] b = F.create(); 566 int[] c = F.create(); 567 int[] d = F.create(); 568 int[] e = F.create(); 569 int[] f = F.create(); 570 int[] g = F.create(); 571 int[] h = F.create(); 572 573 int[] nb, ne, nf, ng; 574 if (negate) 575 { 576 nb = e; ne = b; nf = g; ng = f; 577 F.sub(p.y, p.x, h); 578 } 579 else 580 { 581 nb = b; ne = e; nf = f; ng = g; 582 F.add(p.y, p.x, h); 583 } 584 585 F.mul(p.z, r.z, a); 586 F.sqr(a, b); 587 F.mul(p.x, r.x, c); 588 F.mul(p.y, r.y, d); 589 F.mul(c, d, e); 590 F.mul(e, -C_d, e); 591 // F.apm(b, e, f, g); 592 F.add(b, e, nf); 593 F.sub(b, e, ng); 594 F.add(r.x, r.y, e); 595 F.mul(h, e, h); 596 // F.apm(d, c, b, e); 597 F.add(d, c, nb); 598 F.sub(d, c, ne); 599 F.carry(nb); 600 F.sub(h, b, h); 601 F.mul(h, a, h); 602 F.mul(e, a, e); 603 F.mul(f, h, r.x); 604 F.mul(e, g, r.y); 605 F.mul(f, g, r.z); 606 } 607 pointAddPrecomp(PointPrecomp p, PointExt r)608 private static void pointAddPrecomp(PointPrecomp p, PointExt r) 609 { 610 int[] b = F.create(); 611 int[] c = F.create(); 612 int[] d = F.create(); 613 int[] e = F.create(); 614 int[] f = F.create(); 615 int[] g = F.create(); 616 int[] h = F.create(); 617 618 F.sqr(r.z, b); 619 F.mul(p.x, r.x, c); 620 F.mul(p.y, r.y, d); 621 F.mul(c, d, e); 622 F.mul(e, -C_d, e); 623 // F.apm(b, e, f, g); 624 F.add(b, e, f); 625 F.sub(b, e, g); 626 F.add(p.x, p.y, b); 627 F.add(r.x, r.y, e); 628 F.mul(b, e, h); 629 // F.apm(d, c, b, e); 630 F.add(d, c, b); 631 F.sub(d, c, e); 632 F.carry(b); 633 F.sub(h, b, h); 634 F.mul(h, r.z, h); 635 F.mul(e, r.z, e); 636 F.mul(f, h, r.x); 637 F.mul(e, g, r.y); 638 F.mul(f, g, r.z); 639 } 640 pointCopy(PointExt p)641 private static PointExt pointCopy(PointExt p) 642 { 643 PointExt r = new PointExt(); 644 pointCopy(p, r); 645 return r; 646 } 647 pointCopy(PointExt p, PointExt r)648 private static void pointCopy(PointExt p, PointExt r) 649 { 650 F.copy(p.x, 0, r.x, 0); 651 F.copy(p.y, 0, r.y, 0); 652 F.copy(p.z, 0, r.z, 0); 653 } 654 pointDouble(PointExt r)655 private static void pointDouble(PointExt r) 656 { 657 int[] b = F.create(); 658 int[] c = F.create(); 659 int[] d = F.create(); 660 int[] e = F.create(); 661 int[] h = F.create(); 662 int[] j = F.create(); 663 664 F.add(r.x, r.y, b); 665 F.sqr(b, b); 666 F.sqr(r.x, c); 667 F.sqr(r.y, d); 668 F.add(c, d, e); 669 F.carry(e); 670 F.sqr(r.z, h); 671 F.add(h, h, h); 672 F.carry(h); 673 F.sub(e, h, j); 674 F.sub(b, e, b); 675 F.sub(c, d, c); 676 F.mul(b, j, r.x); 677 F.mul(e, c, r.y); 678 F.mul(e, j, r.z); 679 } 680 pointExtendXY(PointExt p)681 private static void pointExtendXY(PointExt p) 682 { 683 F.one(p.z); 684 } 685 pointLookup(int block, int index, PointPrecomp p)686 private static void pointLookup(int block, int index, PointPrecomp p) 687 { 688 // assert 0 <= block && block < PRECOMP_BLOCKS; 689 // assert 0 <= index && index < PRECOMP_POINTS; 690 691 int off = block * PRECOMP_POINTS * 2 * F.SIZE; 692 693 for (int i = 0; i < PRECOMP_POINTS; ++i) 694 { 695 int cond = ((i ^ index) - 1) >> 31; 696 F.cmov(cond, precompBase, off, p.x, 0); off += F.SIZE; 697 F.cmov(cond, precompBase, off, p.y, 0); off += F.SIZE; 698 } 699 } 700 pointLookup(int[] x, int n, int[] table, PointExt r)701 private static void pointLookup(int[] x, int n, int[] table, PointExt r) 702 { 703 // TODO This method is currently hardcoded to 4-bit windows and 8 precomputed points 704 705 int w = getWindow4(x, n); 706 707 int sign = (w >>> (4 - 1)) ^ 1; 708 int abs = (w ^ -sign) & 7; 709 710 // assert sign == 0 || sign == 1; 711 // assert 0 <= abs && abs < 8; 712 713 for (int i = 0, off = 0; i < 8; ++i) 714 { 715 int cond = ((i ^ abs) - 1) >> 31; 716 F.cmov(cond, table, off, r.x, 0); off += F.SIZE; 717 F.cmov(cond, table, off, r.y, 0); off += F.SIZE; 718 F.cmov(cond, table, off, r.z, 0); off += F.SIZE; 719 } 720 721 F.cnegate(sign, r.x); 722 } 723 pointPrecompute(PointExt p, int count)724 private static int[] pointPrecompute(PointExt p, int count) 725 { 726 // assert count > 0; 727 728 PointExt q = pointCopy(p); 729 PointExt d = pointCopy(q); 730 pointDouble(d); 731 732 int[] table = F.createTable(count * 3); 733 int off = 0; 734 735 int i = 0; 736 for (;;) 737 { 738 F.copy(q.x, 0, table, off); off += F.SIZE; 739 F.copy(q.y, 0, table, off); off += F.SIZE; 740 F.copy(q.z, 0, table, off); off += F.SIZE; 741 742 if (++i == count) 743 { 744 break; 745 } 746 747 pointAdd(d, q); 748 } 749 750 return table; 751 } 752 pointPrecomputeVar(PointExt p, int count)753 private static PointExt[] pointPrecomputeVar(PointExt p, int count) 754 { 755 // assert count > 0; 756 757 PointExt d = pointCopy(p); 758 pointDouble(d); 759 760 PointExt[] table = new PointExt[count]; 761 table[0] = pointCopy(p); 762 for (int i = 1; i < count; ++i) 763 { 764 table[i] = pointCopy(table[i - 1]); 765 pointAddVar(false, d, table[i]); 766 } 767 return table; 768 } 769 pointSetNeutral(PointExt p)770 private static void pointSetNeutral(PointExt p) 771 { 772 F.zero(p.x); 773 F.one(p.y); 774 F.one(p.z); 775 } 776 precompute()777 public static void precompute() 778 { 779 synchronized (precompLock) 780 { 781 if (precompBase != null) 782 { 783 return; 784 } 785 786 PointExt p = new PointExt(); 787 F.copy(B_x, 0, p.x, 0); 788 F.copy(B_y, 0, p.y, 0); 789 pointExtendXY(p); 790 791 precompBaseTable = pointPrecomputeVar(p, 1 << (WNAF_WIDTH_BASE - 2)); 792 793 precompBase = F.createTable(PRECOMP_BLOCKS * PRECOMP_POINTS * 2); 794 795 int off = 0; 796 for (int b = 0; b < PRECOMP_BLOCKS; ++b) 797 { 798 PointExt[] ds = new PointExt[PRECOMP_TEETH]; 799 800 PointExt sum = new PointExt(); 801 pointSetNeutral(sum); 802 803 for (int t = 0; t < PRECOMP_TEETH; ++t) 804 { 805 pointAddVar(true, p, sum); 806 pointDouble(p); 807 808 ds[t] = pointCopy(p); 809 810 if (b + t != PRECOMP_BLOCKS + PRECOMP_TEETH - 2) 811 { 812 for (int s = 1; s < PRECOMP_SPACING; ++s) 813 { 814 pointDouble(p); 815 } 816 } 817 } 818 819 PointExt[] points = new PointExt[PRECOMP_POINTS]; 820 int k = 0; 821 points[k++] = sum; 822 823 for (int t = 0; t < (PRECOMP_TEETH - 1); ++t) 824 { 825 int size = 1 << t; 826 for (int j = 0; j < size; ++j, ++k) 827 { 828 points[k] = pointCopy(points[k - size]); 829 pointAddVar(false, ds[t], points[k]); 830 } 831 } 832 833 // assert k == PRECOMP_POINTS; 834 835 int[] cs = F.createTable(PRECOMP_POINTS); 836 837 // TODO[ed448] A single batch inversion across all blocks? 838 { 839 int[] u = F.create(); 840 F.copy(points[0].z, 0, u, 0); 841 F.copy(u, 0, cs, 0); 842 843 int i = 0; 844 while (++i < PRECOMP_POINTS) 845 { 846 F.mul(u, points[i].z, u); 847 F.copy(u, 0, cs, i * F.SIZE); 848 } 849 850 F.invVar(u, u); 851 --i; 852 853 int[] t = F.create(); 854 855 while (i > 0) 856 { 857 int j = i--; 858 F.copy(cs, i * F.SIZE, t, 0); 859 F.mul(t, u, t); 860 F.copy(t, 0, cs, j * F.SIZE); 861 F.mul(u, points[j].z, u); 862 } 863 864 F.copy(u, 0, cs, 0); 865 } 866 867 for (int i = 0; i < PRECOMP_POINTS; ++i) 868 { 869 PointExt q = points[i]; 870 871 // F.invVar(q.z, q.z); 872 F.copy(cs, i * F.SIZE, q.z, 0); 873 874 F.mul(q.x, q.z, q.x); 875 F.mul(q.y, q.z, q.y); 876 877 // F.normalize(q.x); 878 // F.normalize(q.y); 879 880 F.copy(q.x, 0, precompBase, off); off += F.SIZE; 881 F.copy(q.y, 0, precompBase, off); off += F.SIZE; 882 } 883 } 884 885 // assert off == precompBase.length; 886 } 887 } 888 pruneScalar(byte[] n, int nOff, byte[] r)889 private static void pruneScalar(byte[] n, int nOff, byte[] r) 890 { 891 System.arraycopy(n, nOff, r, 0, SCALAR_BYTES - 1); 892 893 r[0] &= 0xFC; 894 r[SCALAR_BYTES - 2] |= 0x80; 895 r[SCALAR_BYTES - 1] = 0x00; 896 } 897 reduceScalar(byte[] n)898 private static byte[] reduceScalar(byte[] n) 899 { 900 long x00 = decode32(n, 0) & M32L; // x00:32/-- 901 long x01 = (decode24(n, 4) << 4) & M32L; // x01:28/-- 902 long x02 = decode32(n, 7) & M32L; // x02:32/-- 903 long x03 = (decode24(n, 11) << 4) & M32L; // x03:28/-- 904 long x04 = decode32(n, 14) & M32L; // x04:32/-- 905 long x05 = (decode24(n, 18) << 4) & M32L; // x05:28/-- 906 long x06 = decode32(n, 21) & M32L; // x06:32/-- 907 long x07 = (decode24(n, 25) << 4) & M32L; // x07:28/-- 908 long x08 = decode32(n, 28) & M32L; // x08:32/-- 909 long x09 = (decode24(n, 32) << 4) & M32L; // x09:28/-- 910 long x10 = decode32(n, 35) & M32L; // x10:32/-- 911 long x11 = (decode24(n, 39) << 4) & M32L; // x11:28/-- 912 long x12 = decode32(n, 42) & M32L; // x12:32/-- 913 long x13 = (decode24(n, 46) << 4) & M32L; // x13:28/-- 914 long x14 = decode32(n, 49) & M32L; // x14:32/-- 915 long x15 = (decode24(n, 53) << 4) & M32L; // x15:28/-- 916 long x16 = decode32(n, 56) & M32L; // x16:32/-- 917 long x17 = (decode24(n, 60) << 4) & M32L; // x17:28/-- 918 long x18 = decode32(n, 63) & M32L; // x18:32/-- 919 long x19 = (decode24(n, 67) << 4) & M32L; // x19:28/-- 920 long x20 = decode32(n, 70) & M32L; // x20:32/-- 921 long x21 = (decode24(n, 74) << 4) & M32L; // x21:28/-- 922 long x22 = decode32(n, 77) & M32L; // x22:32/-- 923 long x23 = (decode24(n, 81) << 4) & M32L; // x23:28/-- 924 long x24 = decode32(n, 84) & M32L; // x24:32/-- 925 long x25 = (decode24(n, 88) << 4) & M32L; // x25:28/-- 926 long x26 = decode32(n, 91) & M32L; // x26:32/-- 927 long x27 = (decode24(n, 95) << 4) & M32L; // x27:28/-- 928 long x28 = decode32(n, 98) & M32L; // x28:32/-- 929 long x29 = (decode24(n, 102) << 4) & M32L; // x29:28/-- 930 long x30 = decode32(n, 105) & M32L; // x30:32/-- 931 long x31 = (decode24(n, 109) << 4) & M32L; // x31:28/-- 932 long x32 = decode16(n, 112) & M32L; // x32:16/-- 933 934 // x32 += (x31 >>> 28); x31 &= M28L; 935 x16 += x32 * L4_0; // x16:42/-- 936 x17 += x32 * L4_1; // x17:41/28 937 x18 += x32 * L4_2; // x18:43/42 938 x19 += x32 * L4_3; // x19:44/28 939 x20 += x32 * L4_4; // x20:43/-- 940 x21 += x32 * L4_5; // x21:44/28 941 x22 += x32 * L4_6; // x22:43/41 942 x23 += x32 * L4_7; // x23:45/41 943 944 x31 += (x30 >>> 28); x30 &= M28L; // x31:28/--, x30:28/-- 945 x15 += x31 * L4_0; // x15:54/-- 946 x16 += x31 * L4_1; // x16:53/42 947 x17 += x31 * L4_2; // x17:55/54 948 x18 += x31 * L4_3; // x18:56/44 949 x19 += x31 * L4_4; // x19:55/-- 950 x20 += x31 * L4_5; // x20:56/43 951 x21 += x31 * L4_6; // x21:55/53 952 x22 += x31 * L4_7; // x22:57/53 953 954 // x30 += (x29 >>> 28); x29 &= M28L; 955 x14 += x30 * L4_0; // x14:54/-- 956 x15 += x30 * L4_1; // x15:54/53 957 x16 += x30 * L4_2; // x16:56/-- 958 x17 += x30 * L4_3; // x17:57/-- 959 x18 += x30 * L4_4; // x18:56/55 960 x19 += x30 * L4_5; // x19:56/55 961 x20 += x30 * L4_6; // x20:57/-- 962 x21 += x30 * L4_7; // x21:57/56 963 964 x29 += (x28 >>> 28); x28 &= M28L; // x29:28/--, x28:28/-- 965 x13 += x29 * L4_0; // x13:54/-- 966 x14 += x29 * L4_1; // x14:54/53 967 x15 += x29 * L4_2; // x15:56/-- 968 x16 += x29 * L4_3; // x16:57/-- 969 x17 += x29 * L4_4; // x17:57/55 970 x18 += x29 * L4_5; // x18:57/55 971 x19 += x29 * L4_6; // x19:57/52 972 x20 += x29 * L4_7; // x20:58/52 973 974 // x28 += (x27 >>> 28); x27 &= M28L; 975 x12 += x28 * L4_0; // x12:54/-- 976 x13 += x28 * L4_1; // x13:54/53 977 x14 += x28 * L4_2; // x14:56/-- 978 x15 += x28 * L4_3; // x15:57/-- 979 x16 += x28 * L4_4; // x16:57/55 980 x17 += x28 * L4_5; // x17:58/-- 981 x18 += x28 * L4_6; // x18:58/-- 982 x19 += x28 * L4_7; // x19:58/53 983 984 x27 += (x26 >>> 28); x26 &= M28L; // x27:28/--, x26:28/-- 985 x11 += x27 * L4_0; // x11:54/-- 986 x12 += x27 * L4_1; // x12:54/53 987 x13 += x27 * L4_2; // x13:56/-- 988 x14 += x27 * L4_3; // x14:57/-- 989 x15 += x27 * L4_4; // x15:57/55 990 x16 += x27 * L4_5; // x16:58/-- 991 x17 += x27 * L4_6; // x17:58/56 992 x18 += x27 * L4_7; // x18:59/-- 993 994 // x26 += (x25 >>> 28); x25 &= M28L; 995 x10 += x26 * L4_0; // x10:54/-- 996 x11 += x26 * L4_1; // x11:54/53 997 x12 += x26 * L4_2; // x12:56/-- 998 x13 += x26 * L4_3; // x13:57/-- 999 x14 += x26 * L4_4; // x14:57/55 1000 x15 += x26 * L4_5; // x15:58/-- 1001 x16 += x26 * L4_6; // x16:58/56 1002 x17 += x26 * L4_7; // x17:59/-- 1003 1004 x25 += (x24 >>> 28); x24 &= M28L; // x25:28/--, x24:28/-- 1005 x09 += x25 * L4_0; // x09:54/-- 1006 x10 += x25 * L4_1; // x10:54/53 1007 x11 += x25 * L4_2; // x11:56/-- 1008 x12 += x25 * L4_3; // x12:57/-- 1009 x13 += x25 * L4_4; // x13:57/55 1010 x14 += x25 * L4_5; // x14:58/-- 1011 x15 += x25 * L4_6; // x15:58/56 1012 x16 += x25 * L4_7; // x16:59/-- 1013 1014 x21 += (x20 >>> 28); x20 &= M28L; // x21:58/--, x20:28/-- 1015 x22 += (x21 >>> 28); x21 &= M28L; // x22:57/54, x21:28/-- 1016 x23 += (x22 >>> 28); x22 &= M28L; // x23:45/42, x22:28/-- 1017 x24 += (x23 >>> 28); x23 &= M28L; // x24:28/18, x23:28/-- 1018 1019 x08 += x24 * L4_0; // x08:54/-- 1020 x09 += x24 * L4_1; // x09:55/-- 1021 x10 += x24 * L4_2; // x10:56/46 1022 x11 += x24 * L4_3; // x11:57/46 1023 x12 += x24 * L4_4; // x12:57/55 1024 x13 += x24 * L4_5; // x13:58/-- 1025 x14 += x24 * L4_6; // x14:58/56 1026 x15 += x24 * L4_7; // x15:59/-- 1027 1028 x07 += x23 * L4_0; // x07:54/-- 1029 x08 += x23 * L4_1; // x08:54/53 1030 x09 += x23 * L4_2; // x09:56/53 1031 x10 += x23 * L4_3; // x10:57/46 1032 x11 += x23 * L4_4; // x11:57/55 1033 x12 += x23 * L4_5; // x12:58/-- 1034 x13 += x23 * L4_6; // x13:58/56 1035 x14 += x23 * L4_7; // x14:59/-- 1036 1037 x06 += x22 * L4_0; // x06:54/-- 1038 x07 += x22 * L4_1; // x07:54/53 1039 x08 += x22 * L4_2; // x08:56/-- 1040 x09 += x22 * L4_3; // x09:57/53 1041 x10 += x22 * L4_4; // x10:57/55 1042 x11 += x22 * L4_5; // x11:58/-- 1043 x12 += x22 * L4_6; // x12:58/56 1044 x13 += x22 * L4_7; // x13:59/-- 1045 1046 x18 += (x17 >>> 28); x17 &= M28L; // x18:59/31, x17:28/-- 1047 x19 += (x18 >>> 28); x18 &= M28L; // x19:58/54, x18:28/-- 1048 x20 += (x19 >>> 28); x19 &= M28L; // x20:30/29, x19:28/-- 1049 x21 += (x20 >>> 28); x20 &= M28L; // x21:28/03, x20:28/-- 1050 1051 x05 += x21 * L4_0; // x05:54/-- 1052 x06 += x21 * L4_1; // x06:55/-- 1053 x07 += x21 * L4_2; // x07:56/31 1054 x08 += x21 * L4_3; // x08:57/31 1055 x09 += x21 * L4_4; // x09:57/56 1056 x10 += x21 * L4_5; // x10:58/-- 1057 x11 += x21 * L4_6; // x11:58/56 1058 x12 += x21 * L4_7; // x12:59/-- 1059 1060 x04 += x20 * L4_0; // x04:54/-- 1061 x05 += x20 * L4_1; // x05:54/53 1062 x06 += x20 * L4_2; // x06:56/53 1063 x07 += x20 * L4_3; // x07:57/31 1064 x08 += x20 * L4_4; // x08:57/55 1065 x09 += x20 * L4_5; // x09:58/-- 1066 x10 += x20 * L4_6; // x10:58/56 1067 x11 += x20 * L4_7; // x11:59/-- 1068 1069 x03 += x19 * L4_0; // x03:54/-- 1070 x04 += x19 * L4_1; // x04:54/53 1071 x05 += x19 * L4_2; // x05:56/-- 1072 x06 += x19 * L4_3; // x06:57/53 1073 x07 += x19 * L4_4; // x07:57/55 1074 x08 += x19 * L4_5; // x08:58/-- 1075 x09 += x19 * L4_6; // x09:58/56 1076 x10 += x19 * L4_7; // x10:59/-- 1077 1078 x15 += (x14 >>> 28); x14 &= M28L; // x15:59/31, x14:28/-- 1079 x16 += (x15 >>> 28); x15 &= M28L; // x16:59/32, x15:28/-- 1080 x17 += (x16 >>> 28); x16 &= M28L; // x17:31/29, x16:28/-- 1081 x18 += (x17 >>> 28); x17 &= M28L; // x18:28/04, x17:28/-- 1082 1083 x02 += x18 * L4_0; // x02:54/-- 1084 x03 += x18 * L4_1; // x03:55/-- 1085 x04 += x18 * L4_2; // x04:56/32 1086 x05 += x18 * L4_3; // x05:57/32 1087 x06 += x18 * L4_4; // x06:57/56 1088 x07 += x18 * L4_5; // x07:58/-- 1089 x08 += x18 * L4_6; // x08:58/56 1090 x09 += x18 * L4_7; // x09:59/-- 1091 1092 x01 += x17 * L4_0; // x01:54/-- 1093 x02 += x17 * L4_1; // x02:54/53 1094 x03 += x17 * L4_2; // x03:56/53 1095 x04 += x17 * L4_3; // x04:57/32 1096 x05 += x17 * L4_4; // x05:57/55 1097 x06 += x17 * L4_5; // x06:58/-- 1098 x07 += x17 * L4_6; // x07:58/56 1099 x08 += x17 * L4_7; // x08:59/-- 1100 1101 x16 *= 4; 1102 x16 += (x15 >>> 26); x15 &= M26L; 1103 x16 += 1; // x16:30/01 1104 1105 x00 += x16 * L_0; 1106 x01 += x16 * L_1; 1107 x02 += x16 * L_2; 1108 x03 += x16 * L_3; 1109 x04 += x16 * L_4; 1110 x05 += x16 * L_5; 1111 x06 += x16 * L_6; 1112 x07 += x16 * L_7; 1113 1114 x01 += (x00 >>> 28); x00 &= M28L; 1115 x02 += (x01 >>> 28); x01 &= M28L; 1116 x03 += (x02 >>> 28); x02 &= M28L; 1117 x04 += (x03 >>> 28); x03 &= M28L; 1118 x05 += (x04 >>> 28); x04 &= M28L; 1119 x06 += (x05 >>> 28); x05 &= M28L; 1120 x07 += (x06 >>> 28); x06 &= M28L; 1121 x08 += (x07 >>> 28); x07 &= M28L; 1122 x09 += (x08 >>> 28); x08 &= M28L; 1123 x10 += (x09 >>> 28); x09 &= M28L; 1124 x11 += (x10 >>> 28); x10 &= M28L; 1125 x12 += (x11 >>> 28); x11 &= M28L; 1126 x13 += (x12 >>> 28); x12 &= M28L; 1127 x14 += (x13 >>> 28); x13 &= M28L; 1128 x15 += (x14 >>> 28); x14 &= M28L; 1129 x16 = (x15 >>> 26); x15 &= M26L; 1130 1131 x16 -= 1; 1132 1133 // assert x16 == 0L || x16 == -1L; 1134 1135 x00 -= x16 & L_0; 1136 x01 -= x16 & L_1; 1137 x02 -= x16 & L_2; 1138 x03 -= x16 & L_3; 1139 x04 -= x16 & L_4; 1140 x05 -= x16 & L_5; 1141 x06 -= x16 & L_6; 1142 x07 -= x16 & L_7; 1143 1144 x01 += (x00 >> 28); x00 &= M28L; 1145 x02 += (x01 >> 28); x01 &= M28L; 1146 x03 += (x02 >> 28); x02 &= M28L; 1147 x04 += (x03 >> 28); x03 &= M28L; 1148 x05 += (x04 >> 28); x04 &= M28L; 1149 x06 += (x05 >> 28); x05 &= M28L; 1150 x07 += (x06 >> 28); x06 &= M28L; 1151 x08 += (x07 >> 28); x07 &= M28L; 1152 x09 += (x08 >> 28); x08 &= M28L; 1153 x10 += (x09 >> 28); x09 &= M28L; 1154 x11 += (x10 >> 28); x10 &= M28L; 1155 x12 += (x11 >> 28); x11 &= M28L; 1156 x13 += (x12 >> 28); x12 &= M28L; 1157 x14 += (x13 >> 28); x13 &= M28L; 1158 x15 += (x14 >> 28); x14 &= M28L; 1159 1160 // assert x15 >>> 26 == 0L; 1161 1162 byte[] r = new byte[SCALAR_BYTES]; 1163 encode56(x00 | (x01 << 28), r, 0); 1164 encode56(x02 | (x03 << 28), r, 7); 1165 encode56(x04 | (x05 << 28), r, 14); 1166 encode56(x06 | (x07 << 28), r, 21); 1167 encode56(x08 | (x09 << 28), r, 28); 1168 encode56(x10 | (x11 << 28), r, 35); 1169 encode56(x12 | (x13 << 28), r, 42); 1170 encode56(x14 | (x15 << 28), r, 49); 1171 // r[SCALAR_BYTES - 1] = 0; 1172 return r; 1173 } 1174 scalarMult(byte[] k, PointExt p, PointExt r)1175 private static void scalarMult(byte[] k, PointExt p, PointExt r) 1176 { 1177 int[] n = new int[SCALAR_INTS]; 1178 decodeScalar(k, 0, n); 1179 1180 // assert 0 == (n[0] & 3); 1181 // assert 1 == n[SCALAR_INTS - 1] >>> 31; 1182 1183 Nat.shiftDownBits(SCALAR_INTS, n, 2, 0); 1184 1185 // Recode the scalar into signed-digit form 1186 { 1187 //int c1 = 1188 Nat.cadd(SCALAR_INTS, ~n[0] & 1, n, L, n); //assert c1 == 0; 1189 //int c2 = 1190 Nat.shiftDownBit(SCALAR_INTS, n, 1); //assert c2 == (1 << 31); 1191 } 1192 1193 int[] table = pointPrecompute(p, 8); 1194 PointExt q = new PointExt(); 1195 1196 pointLookup(n, 111, table, r); 1197 1198 for (int w = 110; w >= 0; --w) 1199 { 1200 for (int i = 0; i < 4; ++i) 1201 { 1202 pointDouble(r); 1203 } 1204 1205 pointLookup(n, w, table, q); 1206 pointAdd(q, r); 1207 } 1208 1209 for (int i = 0; i < 2; ++i) 1210 { 1211 pointDouble(r); 1212 } 1213 } 1214 scalarMultBase(byte[] k, PointExt r)1215 private static void scalarMultBase(byte[] k, PointExt r) 1216 { 1217 precompute(); 1218 1219 int[] n = new int[SCALAR_INTS + 1]; 1220 decodeScalar(k, 0, n); 1221 1222 // Recode the scalar into signed-digit form 1223 { 1224 n[SCALAR_INTS] = 4 + Nat.cadd(SCALAR_INTS, ~n[0] & 1, n, L, n); 1225 //int c = 1226 Nat.shiftDownBit(n.length, n, 0); 1227 //assert c == (1 << 31); 1228 } 1229 1230 PointPrecomp p = new PointPrecomp(); 1231 1232 pointSetNeutral(r); 1233 1234 int cOff = PRECOMP_SPACING - 1; 1235 for (;;) 1236 { 1237 int tPos = cOff; 1238 1239 for (int b = 0; b < PRECOMP_BLOCKS; ++b) 1240 { 1241 int w = 0; 1242 for (int t = 0; t < PRECOMP_TEETH; ++t) 1243 { 1244 int tBit = n[tPos >>> 5] >>> (tPos & 0x1F); 1245 w &= ~(1 << t); 1246 w ^= (tBit << t); 1247 tPos += PRECOMP_SPACING; 1248 } 1249 1250 int sign = (w >>> (PRECOMP_TEETH - 1)) & 1; 1251 int abs = (w ^ -sign) & PRECOMP_MASK; 1252 1253 // assert sign == 0 || sign == 1; 1254 // assert 0 <= abs && abs < PRECOMP_POINTS; 1255 1256 pointLookup(b, abs, p); 1257 1258 F.cnegate(sign, p.x); 1259 1260 pointAddPrecomp(p, r); 1261 } 1262 1263 if (--cOff < 0) 1264 { 1265 break; 1266 } 1267 1268 pointDouble(r); 1269 } 1270 } 1271 scalarMultBaseEncoded(byte[] k, byte[] r, int rOff)1272 private static void scalarMultBaseEncoded(byte[] k, byte[] r, int rOff) 1273 { 1274 PointExt p = new PointExt(); 1275 scalarMultBase(k, p); 1276 if (0 == encodePoint(p, r, rOff)) 1277 { 1278 throw new IllegalStateException(); 1279 } 1280 } 1281 1282 /** 1283 * NOTE: Only for use by X448 1284 */ scalarMultBaseXY(X448.Friend friend, byte[] k, int kOff, int[] x, int[] y)1285 public static void scalarMultBaseXY(X448.Friend friend, byte[] k, int kOff, int[] x, int[] y) 1286 { 1287 if (null == friend) 1288 { 1289 throw new NullPointerException("This method is only for use by X448"); 1290 } 1291 1292 byte[] n = new byte[SCALAR_BYTES]; 1293 pruneScalar(k, kOff, n); 1294 1295 PointExt p = new PointExt(); 1296 scalarMultBase(n, p); 1297 if (0 == checkPoint(p.x, p.y, p.z)) 1298 { 1299 throw new IllegalStateException(); 1300 } 1301 F.copy(p.x, 0, x, 0); 1302 F.copy(p.y, 0, y, 0); 1303 } 1304 scalarMultOrderVar(PointExt p, PointExt r)1305 private static void scalarMultOrderVar(PointExt p, PointExt r) 1306 { 1307 final int width = 5; 1308 1309 byte[] ws_p = getWnafVar(L, width); 1310 1311 PointExt[] tp = pointPrecomputeVar(p, 1 << (width - 2)); 1312 1313 pointSetNeutral(r); 1314 1315 for (int bit = 446;;) 1316 { 1317 int wp = ws_p[bit]; 1318 if (wp != 0) 1319 { 1320 int sign = wp >> 31; 1321 int index = (wp ^ sign) >>> 1; 1322 1323 pointAddVar((sign != 0), tp[index], r); 1324 } 1325 1326 if (--bit < 0) 1327 { 1328 break; 1329 } 1330 1331 pointDouble(r); 1332 } 1333 } 1334 scalarMultStrausVar(int[] nb, int[] np, PointExt p, PointExt r)1335 private static void scalarMultStrausVar(int[] nb, int[] np, PointExt p, PointExt r) 1336 { 1337 precompute(); 1338 1339 final int width = 5; 1340 1341 byte[] ws_b = getWnafVar(nb, WNAF_WIDTH_BASE); 1342 byte[] ws_p = getWnafVar(np, width); 1343 1344 PointExt[] tp = pointPrecomputeVar(p, 1 << (width - 2)); 1345 1346 pointSetNeutral(r); 1347 1348 for (int bit = 446;;) 1349 { 1350 int wb = ws_b[bit]; 1351 if (wb != 0) 1352 { 1353 int sign = wb >> 31; 1354 int index = (wb ^ sign) >>> 1; 1355 1356 pointAddVar((sign != 0), precompBaseTable[index], r); 1357 } 1358 1359 int wp = ws_p[bit]; 1360 if (wp != 0) 1361 { 1362 int sign = wp >> 31; 1363 int index = (wp ^ sign) >>> 1; 1364 1365 pointAddVar((sign != 0), tp[index], r); 1366 } 1367 1368 if (--bit < 0) 1369 { 1370 break; 1371 } 1372 1373 pointDouble(r); 1374 } 1375 } 1376 sign(byte[] sk, int skOff, byte[] ctx, byte[] m, int mOff, int mLen, byte[] sig, int sigOff)1377 public static void sign(byte[] sk, int skOff, byte[] ctx, byte[] m, int mOff, int mLen, byte[] sig, int sigOff) 1378 { 1379 byte phflag = 0x00; 1380 1381 implSign(sk, skOff, ctx, phflag, m, mOff, mLen, sig, sigOff); 1382 } 1383 sign(byte[] sk, int skOff, byte[] pk, int pkOff, byte[] ctx, byte[] m, int mOff, int mLen, byte[] sig, int sigOff)1384 public static void sign(byte[] sk, int skOff, byte[] pk, int pkOff, byte[] ctx, byte[] m, int mOff, int mLen, byte[] sig, int sigOff) 1385 { 1386 byte phflag = 0x00; 1387 1388 implSign(sk, skOff, pk, pkOff, ctx, phflag, m, mOff, mLen, sig, sigOff); 1389 } 1390 signPrehash(byte[] sk, int skOff, byte[] ctx, byte[] ph, int phOff, byte[] sig, int sigOff)1391 public static void signPrehash(byte[] sk, int skOff, byte[] ctx, byte[] ph, int phOff, byte[] sig, int sigOff) 1392 { 1393 byte phflag = 0x01; 1394 1395 implSign(sk, skOff, ctx, phflag, ph, phOff, PREHASH_SIZE, sig, sigOff); 1396 } 1397 signPrehash(byte[] sk, int skOff, byte[] pk, int pkOff, byte[] ctx, byte[] ph, int phOff, byte[] sig, int sigOff)1398 public static void signPrehash(byte[] sk, int skOff, byte[] pk, int pkOff, byte[] ctx, byte[] ph, int phOff, byte[] sig, int sigOff) 1399 { 1400 byte phflag = 0x01; 1401 1402 implSign(sk, skOff, pk, pkOff, ctx, phflag, ph, phOff, PREHASH_SIZE, sig, sigOff); 1403 } 1404 signPrehash(byte[] sk, int skOff, byte[] ctx, Xof ph, byte[] sig, int sigOff)1405 public static void signPrehash(byte[] sk, int skOff, byte[] ctx, Xof ph, byte[] sig, int sigOff) 1406 { 1407 byte[] m = new byte[PREHASH_SIZE]; 1408 if (PREHASH_SIZE != ph.doFinal(m, 0, PREHASH_SIZE)) 1409 { 1410 throw new IllegalArgumentException("ph"); 1411 } 1412 1413 byte phflag = 0x01; 1414 1415 implSign(sk, skOff, ctx, phflag, m, 0, m.length, sig, sigOff); 1416 } 1417 signPrehash(byte[] sk, int skOff, byte[] pk, int pkOff, byte[] ctx, Xof ph, byte[] sig, int sigOff)1418 public static void signPrehash(byte[] sk, int skOff, byte[] pk, int pkOff, byte[] ctx, Xof ph, byte[] sig, int sigOff) 1419 { 1420 byte[] m = new byte[PREHASH_SIZE]; 1421 if (PREHASH_SIZE != ph.doFinal(m, 0, PREHASH_SIZE)) 1422 { 1423 throw new IllegalArgumentException("ph"); 1424 } 1425 1426 byte phflag = 0x01; 1427 1428 implSign(sk, skOff, pk, pkOff, ctx, phflag, m, 0, m.length, sig, sigOff); 1429 } 1430 validatePublicKeyFull(byte[] pk, int pkOff)1431 public static boolean validatePublicKeyFull(byte[] pk, int pkOff) 1432 { 1433 PointExt p = new PointExt(); 1434 if (!decodePointVar(pk, pkOff, false, p)) 1435 { 1436 return false; 1437 } 1438 1439 F.normalize(p.x); 1440 F.normalize(p.y); 1441 F.normalize(p.z); 1442 1443 if (isNeutralElementVar(p.x, p.y, p.z)) 1444 { 1445 return false; 1446 } 1447 1448 PointExt r = new PointExt(); 1449 scalarMultOrderVar(p, r); 1450 1451 F.normalize(r.x); 1452 F.normalize(r.y); 1453 F.normalize(r.z); 1454 1455 return isNeutralElementVar(r.x, r.y, r.z); 1456 } 1457 validatePublicKeyPartial(byte[] pk, int pkOff)1458 public static boolean validatePublicKeyPartial(byte[] pk, int pkOff) 1459 { 1460 PointExt p = new PointExt(); 1461 return decodePointVar(pk, pkOff, false, p); 1462 } 1463 verify(byte[] sig, int sigOff, byte[] pk, int pkOff, byte[] ctx, byte[] m, int mOff, int mLen)1464 public static boolean verify(byte[] sig, int sigOff, byte[] pk, int pkOff, byte[] ctx, byte[] m, int mOff, int mLen) 1465 { 1466 byte phflag = 0x00; 1467 1468 return implVerify(sig, sigOff, pk, pkOff, ctx, phflag, m, mOff, mLen); 1469 } 1470 verifyPrehash(byte[] sig, int sigOff, byte[] pk, int pkOff, byte[] ctx, byte[] ph, int phOff)1471 public static boolean verifyPrehash(byte[] sig, int sigOff, byte[] pk, int pkOff, byte[] ctx, byte[] ph, int phOff) 1472 { 1473 byte phflag = 0x01; 1474 1475 return implVerify(sig, sigOff, pk, pkOff, ctx, phflag, ph, phOff, PREHASH_SIZE); 1476 } 1477 verifyPrehash(byte[] sig, int sigOff, byte[] pk, int pkOff, byte[] ctx, Xof ph)1478 public static boolean verifyPrehash(byte[] sig, int sigOff, byte[] pk, int pkOff, byte[] ctx, Xof ph) 1479 { 1480 byte[] m = new byte[PREHASH_SIZE]; 1481 if (PREHASH_SIZE != ph.doFinal(m, 0, PREHASH_SIZE)) 1482 { 1483 throw new IllegalArgumentException("ph"); 1484 } 1485 1486 byte phflag = 0x01; 1487 1488 return implVerify(sig, sigOff, pk, pkOff, ctx, phflag, m, 0, m.length); 1489 } 1490 } 1491