14 | * An element $t$, entries $t[0] \dots t[9]$, represents the integer 15 | * $t[0]+2^{26} t[1]+2^{51} t[2]+2^{77} t[3]+2^{102} t[4]+\dots+2^{230} t[9]$. 16 | * Bounds on each $t[i]$ vary depending on context. 17 | *
18 | * Reviewed/commented by Bloody Rookie (nemproject@gmx.de) 19 | */ 20 | public class Ed25519FieldElement extends FieldElement { 21 | /** 22 | * Variable is package private for encoding. 23 | */ 24 | protected final int[] t; 25 | 26 | /** 27 | * Creates a field element. 28 | * 29 | * @param f The underlying field, must be the finite field with $p = 2^{255} - 19$ elements 30 | * @param t The $2^{25.5}$ bit representation of the field element. 31 | */ 32 | public Ed25519FieldElement(Ed25519Field f, int[] t) { 33 | super(f); 34 | if (t.length != 10) 35 | throw new IllegalArgumentException("Invalid radix-2^51 representation"); 36 | this.t = t; 37 | } 38 | 39 | private static final byte[] ZERO = new byte[32]; 40 | 41 | /** 42 | * Gets a value indicating whether the field element is non-zero. 43 | * 44 | * @return 1 if it is non-zero, 0 otherwise. 45 | */ 46 | public boolean isNonZero() { 47 | final byte[] s = toByteArray(); 48 | return Utils.equal(s, ZERO) == 0; 49 | } 50 | 51 | /** 52 | * $h = f + g$ 53 | *
54 | * TODO-CR BR: $h$ is allocated via new, probably not a good idea. Do we need the copying into temp variables if we do that? 55 | *
56 | * Preconditions: 57 | *
61 | * Postconditions: 62 | *
81 | * Can overlap $h$ with $f$ or $g$. 82 | *
83 | * TODO-CR BR: See above. 84 | *
85 | * Preconditions: 86 | *
90 | * Postconditions: 91 | *
110 | * TODO-CR BR: see above. 111 | *
112 | * Preconditions: 113 | *
116 | * Postconditions: 117 | *
134 | * Can overlap $h$ with $f$ or $g$. 135 | *
136 | * Preconditions: 137 | *
143 | * Postconditions: 144 | *
148 | * Notes on implementation strategy: 149 | *
150 | * Using schoolbook multiplication. Karatsuba would save a little in some 151 | * cost models. 152 | *
153 | * Most multiplications by 2 and 19 are 32-bit precomputations; cheaper than 154 | * 64-bit postcomputations. 155 | *
156 | * There is one remaining multiplication by 19 in the carry chain; one *19 157 | * precomputation can be merged into this, but the resulting data flow is 158 | * considerably less clean. 159 | *
160 | * There are 12 carries below. 10 of them are 2-way parallelizable and 161 | * vectorizable. Can get away with 11 carries, but then data flow is much 162 | * deeper. 163 | *
164 | * With tighter constraints on inputs can squeeze carries into int32. 165 | * 166 | * @param val The field element to multiply. 167 | * @return The (reasonably reduced) field element this * val. 168 | */ 169 | public FieldElement multiply(FieldElement val) { 170 | int[] g = ((Ed25519FieldElement)val).t; 171 | long x1; 172 | long x2; 173 | long x3; 174 | long x4; 175 | long x5; 176 | long x6; 177 | long x7; 178 | long x8; 179 | long x9; 180 | long x10; 181 | long x11; 182 | long x12; 183 | long x13; 184 | long x14; 185 | long x15; 186 | long x16; 187 | long x17; 188 | long x18; 189 | long x19; 190 | long x20; 191 | long x21; 192 | long x22; 193 | long x23; 194 | long x24; 195 | long x25; 196 | long x26; 197 | long x27; 198 | long x28; 199 | long x29; 200 | long x30; 201 | long x31; 202 | long x32; 203 | long x33; 204 | long x34; 205 | long x35; 206 | long x36; 207 | long x37; 208 | long x38; 209 | long x39; 210 | long x40; 211 | long x41; 212 | long x42; 213 | long x43; 214 | long x44; 215 | long x45; 216 | long x46; 217 | long x47; 218 | long x48; 219 | long x49; 220 | long x50; 221 | long x51; 222 | long x52; 223 | long x53; 224 | long x54; 225 | long x55; 226 | long x56; 227 | long x57; 228 | long x58; 229 | long x59; 230 | long x60; 231 | long x61; 232 | long x62; 233 | long x63; 234 | long x64; 235 | long x65; 236 | long x66; 237 | long x67; 238 | long x68; 239 | long x69; 240 | long x70; 241 | long x71; 242 | long x72; 243 | long x73; 244 | long x74; 245 | long x75; 246 | long x76; 247 | long x77; 248 | long x78; 249 | long x79; 250 | long x80; 251 | long x81; 252 | long x82; 253 | long x83; 254 | long x84; 255 | long x85; 256 | long x86; 257 | long x87; 258 | long x88; 259 | long x89; 260 | long x90; 261 | long x91; 262 | long x92; 263 | long x93; 264 | long x94; 265 | long x95; 266 | long x96; 267 | long x97; 268 | long x98; 269 | long x99; 270 | long x100; 271 | long x101; 272 | long x102; 273 | int x103; 274 | long x104; 275 | long x105; 276 | long x106; 277 | long x107; 278 | long x108; 279 | long x109; 280 | long x110; 281 | long x111; 282 | long x112; 283 | long x113; 284 | long x114; 285 | int x115; 286 | long x116; 287 | long x117; 288 | int x118; 289 | long x119; 290 | long x120; 291 | int x121; 292 | long x122; 293 | long x123; 294 | int x124; 295 | long x125; 296 | long x126; 297 | int x127; 298 | long x128; 299 | long x129; 300 | int x130; 301 | long x131; 302 | long x132; 303 | int x133; 304 | long x134; 305 | long x135; 306 | int x136; 307 | long x137; 308 | long x138; 309 | int x139; 310 | long x140; 311 | long x141; 312 | int x142; 313 | int x143; 314 | int x144; 315 | byte x145; 316 | int x146; 317 | int x147; 318 | x1 = ((long)(t[9]) * ((g[9]) * (byte) 0x26)); 319 | x2 = ((long)(t[9]) * ((g[8]) * (byte) 0x13)); 320 | x3 = ((long)(t[9]) * ((g[7]) * (byte) 0x26)); 321 | x4 = ((long)(t[9]) * ((g[6]) * (byte) 0x13)); 322 | x5 = ((long)(t[9]) * ((g[5]) * (byte) 0x26)); 323 | x6 = ((long)(t[9]) * ((g[4]) * (byte) 0x13)); 324 | x7 = ((long)(t[9]) * ((g[3]) * (byte) 0x26)); 325 | x8 = ((long)(t[9]) * ((g[2]) * (byte) 0x13)); 326 | x9 = ((long)(t[9]) * ((g[1]) * (byte) 0x26)); 327 | x10 = ((long)(t[8]) * ((g[9]) * (byte) 0x13)); 328 | x11 = ((long)(t[8]) * ((g[8]) * (byte) 0x13)); 329 | x12 = ((long)(t[8]) * ((g[7]) * (byte) 0x13)); 330 | x13 = ((long)(t[8]) * ((g[6]) * (byte) 0x13)); 331 | x14 = ((long)(t[8]) * ((g[5]) * (byte) 0x13)); 332 | x15 = ((long)(t[8]) * ((g[4]) * (byte) 0x13)); 333 | x16 = ((long)(t[8]) * ((g[3]) * (byte) 0x13)); 334 | x17 = ((long)(t[8]) * ((g[2]) * (byte) 0x13)); 335 | x18 = ((long)(t[7]) * ((g[9]) * (byte) 0x26)); 336 | x19 = ((long)(t[7]) * ((g[8]) * (byte) 0x13)); 337 | x20 = ((long)(t[7]) * ((g[7]) * (byte) 0x26)); 338 | x21 = ((long)(t[7]) * ((g[6]) * (byte) 0x13)); 339 | x22 = ((long)(t[7]) * ((g[5]) * (byte) 0x26)); 340 | x23 = ((long)(t[7]) * ((g[4]) * (byte) 0x13)); 341 | x24 = ((long)(t[7]) * ((g[3]) * (byte) 0x26)); 342 | x25 = ((long)(t[6]) * ((g[9]) * (byte) 0x13)); 343 | x26 = ((long)(t[6]) * ((g[8]) * (byte) 0x13)); 344 | x27 = ((long)(t[6]) * ((g[7]) * (byte) 0x13)); 345 | x28 = ((long)(t[6]) * ((g[6]) * (byte) 0x13)); 346 | x29 = ((long)(t[6]) * ((g[5]) * (byte) 0x13)); 347 | x30 = ((long)(t[6]) * ((g[4]) * (byte) 0x13)); 348 | x31 = ((long)(t[5]) * ((g[9]) * (byte) 0x26)); 349 | x32 = ((long)(t[5]) * ((g[8]) * (byte) 0x13)); 350 | x33 = ((long)(t[5]) * ((g[7]) * (byte) 0x26)); 351 | x34 = ((long)(t[5]) * ((g[6]) * (byte) 0x13)); 352 | x35 = ((long)(t[5]) * ((g[5]) * (byte) 0x26)); 353 | x36 = ((long)(t[4]) * ((g[9]) * (byte) 0x13)); 354 | x37 = ((long)(t[4]) * ((g[8]) * (byte) 0x13)); 355 | x38 = ((long)(t[4]) * ((g[7]) * (byte) 0x13)); 356 | x39 = ((long)(t[4]) * ((g[6]) * (byte) 0x13)); 357 | x40 = ((long)(t[3]) * ((g[9]) * (byte) 0x26)); 358 | x41 = ((long)(t[3]) * ((g[8]) * (byte) 0x13)); 359 | x42 = ((long)(t[3]) * ((g[7]) * (byte) 0x26)); 360 | x43 = ((long)(t[2]) * ((g[9]) * (byte) 0x13)); 361 | x44 = ((long)(t[2]) * ((g[8]) * (byte) 0x13)); 362 | x45 = ((long)(t[1]) * ((g[9]) * (byte) 0x26)); 363 | x46 = ((long)(t[9]) * (g[0])); 364 | x47 = ((long)(t[8]) * (g[1])); 365 | x48 = ((long)(t[8]) * (g[0])); 366 | x49 = ((long)(t[7]) * (g[2])); 367 | x50 = ((long)(t[7]) * ((g[1]) * 0x2)); 368 | x51 = ((long)(t[7]) * (g[0])); 369 | x52 = ((long)(t[6]) * (g[3])); 370 | x53 = ((long)(t[6]) * (g[2])); 371 | x54 = ((long)(t[6]) * (g[1])); 372 | x55 = ((long)(t[6]) * (g[0])); 373 | x56 = ((long)(t[5]) * (g[4])); 374 | x57 = ((long)(t[5]) * ((g[3]) * 0x2)); 375 | x58 = ((long)(t[5]) * (g[2])); 376 | x59 = ((long)(t[5]) * ((g[1]) * 0x2)); 377 | x60 = ((long)(t[5]) * (g[0])); 378 | x61 = ((long)(t[4]) * (g[5])); 379 | x62 = ((long)(t[4]) * (g[4])); 380 | x63 = ((long)(t[4]) * (g[3])); 381 | x64 = ((long)(t[4]) * (g[2])); 382 | x65 = ((long)(t[4]) * (g[1])); 383 | x66 = ((long)(t[4]) * (g[0])); 384 | x67 = ((long)(t[3]) * (g[6])); 385 | x68 = ((long)(t[3]) * ((g[5]) * 0x2)); 386 | x69 = ((long)(t[3]) * (g[4])); 387 | x70 = ((long)(t[3]) * ((g[3]) * 0x2)); 388 | x71 = ((long)(t[3]) * (g[2])); 389 | x72 = ((long)(t[3]) * ((g[1]) * 0x2)); 390 | x73 = ((long)(t[3]) * (g[0])); 391 | x74 = ((long)(t[2]) * (g[7])); 392 | x75 = ((long)(t[2]) * (g[6])); 393 | x76 = ((long)(t[2]) * (g[5])); 394 | x77 = ((long)(t[2]) * (g[4])); 395 | x78 = ((long)(t[2]) * (g[3])); 396 | x79 = ((long)(t[2]) * (g[2])); 397 | x80 = ((long)(t[2]) * (g[1])); 398 | x81 = ((long)(t[2]) * (g[0])); 399 | x82 = ((long)(t[1]) * (g[8])); 400 | x83 = ((long)(t[1]) * ((g[7]) * 0x2)); 401 | x84 = ((long)(t[1]) * (g[6])); 402 | x85 = ((long)(t[1]) * ((g[5]) * 0x2)); 403 | x86 = ((long)(t[1]) * (g[4])); 404 | x87 = ((long)(t[1]) * ((g[3]) * 0x2)); 405 | x88 = ((long)(t[1]) * (g[2])); 406 | x89 = ((long)(t[1]) * ((g[1]) * 0x2)); 407 | x90 = ((long)(t[1]) * (g[0])); 408 | x91 = ((long)(t[0]) * (g[9])); 409 | x92 = ((long)(t[0]) * (g[8])); 410 | x93 = ((long)(t[0]) * (g[7])); 411 | x94 = ((long)(t[0]) * (g[6])); 412 | x95 = ((long)(t[0]) * (g[5])); 413 | x96 = ((long)(t[0]) * (g[4])); 414 | x97 = ((long)(t[0]) * (g[3])); 415 | x98 = ((long)(t[0]) * (g[2])); 416 | x99 = ((long)(t[0]) * (g[1])); 417 | x100 = ((long)(t[0]) * (g[0])); 418 | x101 = (x100 + (x45 + (x44 + (x42 + (x39 + (x35 + (x30 + (x24 + (x17 + x9))))))))); 419 | x102 = (x101 >> 26); 420 | x103 = (int)(x101 & 0x3ffffff); 421 | x104 = (x91 + (x82 + (x74 + (x67 + (x61 + (x56 + (x52 + (x49 + (x47 + x46))))))))); 422 | x105 = (x92 + (x83 + (x75 + (x68 + (x62 + (x57 + (x53 + (x50 + (x48 + x1))))))))); 423 | x106 = (x93 + (x84 + (x76 + (x69 + (x63 + (x58 + (x54 + (x51 + (x10 + x2))))))))); 424 | x107 = (x94 + (x85 + (x77 + (x70 + (x64 + (x59 + (x55 + (x18 + (x11 + x3))))))))); 425 | x108 = (x95 + (x86 + (x78 + (x71 + (x65 + (x60 + (x25 + (x19 + (x12 + x4))))))))); 426 | x109 = (x96 + (x87 + (x79 + (x72 + (x66 + (x31 + (x26 + (x20 + (x13 + x5))))))))); 427 | x110 = (x97 + (x88 + (x80 + (x73 + (x36 + (x32 + (x27 + (x21 + (x14 + x6))))))))); 428 | x111 = (x98 + (x89 + (x81 + (x40 + (x37 + (x33 + (x28 + (x22 + (x15 + x7))))))))); 429 | x112 = (x99 + (x90 + (x43 + (x41 + (x38 + (x34 + (x29 + (x23 + (x16 + x8))))))))); 430 | x113 = (x102 + x112); 431 | x114 = (x113 >> 25); 432 | x115 = (int)(x113 & 0x1ffffff); 433 | x116 = (x114 + x111); 434 | x117 = (x116 >> 26); 435 | x118 = (int)(x116 & 0x3ffffff); 436 | x119 = (x117 + x110); 437 | x120 = (x119 >> 25); 438 | x121 = (int)(x119 & 0x1ffffff); 439 | x122 = (x120 + x109); 440 | x123 = (x122 >> 26); 441 | x124 = (int)(x122 & 0x3ffffff); 442 | x125 = (x123 + x108); 443 | x126 = (x125 >> 25); 444 | x127 = (int)(x125 & 0x1ffffff); 445 | x128 = (x126 + x107); 446 | x129 = (x128 >> 26); 447 | x130 = (int)(x128 & 0x3ffffff); 448 | x131 = (x129 + x106); 449 | x132 = (x131 >> 25); 450 | x133 = (int)(x131 & 0x1ffffff); 451 | x134 = (x132 + x105); 452 | x135 = (x134 >> 26); 453 | x136 = (int)(x134 & 0x3ffffff); 454 | x137 = (x135 + x104); 455 | x138 = (x137 >> 25); 456 | x139 = (int)(x137 & 0x1ffffff); 457 | x140 = (x138 * (byte) 0x13); 458 | x141 = (x103 + x140); 459 | x142 = (int)(x141 >> 26); 460 | x143 = (int)(x141 & 0x3ffffff); 461 | x144 = (x142 + x115); 462 | x145 = (byte)(x144 >> 25); 463 | x146 = (x144 & 0x1ffffff); 464 | x147 = (x145 + x118); 465 | int[] out1 = new int[10]; 466 | out1[0] = x143; 467 | out1[1] = x146; 468 | out1[2] = x147; 469 | out1[3] = x121; 470 | out1[4] = x124; 471 | out1[5] = x127; 472 | out1[6] = x130; 473 | out1[7] = x133; 474 | out1[8] = x136; 475 | out1[9] = x139; 476 | return new Ed25519FieldElement(f, out1); 477 | } 478 | 479 | /** 480 | * $h = f * f$ 481 | *
482 | * Can overlap $h$ with $f$. 483 | *
484 | * Preconditions: 485 | *
488 | * Postconditions: 489 | *
492 | * See {@link #multiply(FieldElement)} for discussion 493 | * of implementation strategy. 494 | * 495 | * @return The (reasonably reduced) square of this field element. 496 | */ 497 | public FieldElement square() { 498 | int f0 = t[0]; 499 | int f1 = t[1]; 500 | int f2 = t[2]; 501 | int f3 = t[3]; 502 | int f4 = t[4]; 503 | int f5 = t[5]; 504 | int f6 = t[6]; 505 | int f7 = t[7]; 506 | int f8 = t[8]; 507 | int f9 = t[9]; 508 | int f0_2 = 2 * f0; 509 | int f1_2 = 2 * f1; 510 | int f2_2 = 2 * f2; 511 | int f3_2 = 2 * f3; 512 | int f4_2 = 2 * f4; 513 | int f5_2 = 2 * f5; 514 | int f6_2 = 2 * f6; 515 | int f7_2 = 2 * f7; 516 | int f5_38 = 38 * f5; /* 1.959375*2^30 */ 517 | int f6_19 = 19 * f6; /* 1.959375*2^30 */ 518 | int f7_38 = 38 * f7; /* 1.959375*2^30 */ 519 | int f8_19 = 19 * f8; /* 1.959375*2^30 */ 520 | int f9_38 = 38 * f9; /* 1.959375*2^30 */ 521 | long f0f0 = f0 * (long) f0; 522 | long f0f1_2 = f0_2 * (long) f1; 523 | long f0f2_2 = f0_2 * (long) f2; 524 | long f0f3_2 = f0_2 * (long) f3; 525 | long f0f4_2 = f0_2 * (long) f4; 526 | long f0f5_2 = f0_2 * (long) f5; 527 | long f0f6_2 = f0_2 * (long) f6; 528 | long f0f7_2 = f0_2 * (long) f7; 529 | long f0f8_2 = f0_2 * (long) f8; 530 | long f0f9_2 = f0_2 * (long) f9; 531 | long f1f1_2 = f1_2 * (long) f1; 532 | long f1f2_2 = f1_2 * (long) f2; 533 | long f1f3_4 = f1_2 * (long) f3_2; 534 | long f1f4_2 = f1_2 * (long) f4; 535 | long f1f5_4 = f1_2 * (long) f5_2; 536 | long f1f6_2 = f1_2 * (long) f6; 537 | long f1f7_4 = f1_2 * (long) f7_2; 538 | long f1f8_2 = f1_2 * (long) f8; 539 | long f1f9_76 = f1_2 * (long) f9_38; 540 | long f2f2 = f2 * (long) f2; 541 | long f2f3_2 = f2_2 * (long) f3; 542 | long f2f4_2 = f2_2 * (long) f4; 543 | long f2f5_2 = f2_2 * (long) f5; 544 | long f2f6_2 = f2_2 * (long) f6; 545 | long f2f7_2 = f2_2 * (long) f7; 546 | long f2f8_38 = f2_2 * (long) f8_19; 547 | long f2f9_38 = f2 * (long) f9_38; 548 | long f3f3_2 = f3_2 * (long) f3; 549 | long f3f4_2 = f3_2 * (long) f4; 550 | long f3f5_4 = f3_2 * (long) f5_2; 551 | long f3f6_2 = f3_2 * (long) f6; 552 | long f3f7_76 = f3_2 * (long) f7_38; 553 | long f3f8_38 = f3_2 * (long) f8_19; 554 | long f3f9_76 = f3_2 * (long) f9_38; 555 | long f4f4 = f4 * (long) f4; 556 | long f4f5_2 = f4_2 * (long) f5; 557 | long f4f6_38 = f4_2 * (long) f6_19; 558 | long f4f7_38 = f4 * (long) f7_38; 559 | long f4f8_38 = f4_2 * (long) f8_19; 560 | long f4f9_38 = f4 * (long) f9_38; 561 | long f5f5_38 = f5 * (long) f5_38; 562 | long f5f6_38 = f5_2 * (long) f6_19; 563 | long f5f7_76 = f5_2 * (long) f7_38; 564 | long f5f8_38 = f5_2 * (long) f8_19; 565 | long f5f9_76 = f5_2 * (long) f9_38; 566 | long f6f6_19 = f6 * (long) f6_19; 567 | long f6f7_38 = f6 * (long) f7_38; 568 | long f6f8_38 = f6_2 * (long) f8_19; 569 | long f6f9_38 = f6 * (long) f9_38; 570 | long f7f7_38 = f7 * (long) f7_38; 571 | long f7f8_38 = f7_2 * (long) f8_19; 572 | long f7f9_76 = f7_2 * (long) f9_38; 573 | long f8f8_19 = f8 * (long) f8_19; 574 | long f8f9_38 = f8 * (long) f9_38; 575 | long f9f9_38 = f9 * (long) f9_38; 576 | 577 | /** 578 | * Same procedure as in multiply, but this time we have a higher symmetry leading to less summands. 579 | * e.g. f1f9_76 really stands for f1 * 2^26 * f9 * 2^230 + f9 * 2^230 + f1 * 2^26 congruent 2 * 2 * 19 * f1 * f9 2^0 modulo p. 580 | */ 581 | long h0 = f0f0 + f1f9_76 + f2f8_38 + f3f7_76 + f4f6_38 + f5f5_38; 582 | long h1 = f0f1_2 + f2f9_38 + f3f8_38 + f4f7_38 + f5f6_38; 583 | long h2 = f0f2_2 + f1f1_2 + f3f9_76 + f4f8_38 + f5f7_76 + f6f6_19; 584 | long h3 = f0f3_2 + f1f2_2 + f4f9_38 + f5f8_38 + f6f7_38; 585 | long h4 = f0f4_2 + f1f3_4 + f2f2 + f5f9_76 + f6f8_38 + f7f7_38; 586 | long h5 = f0f5_2 + f1f4_2 + f2f3_2 + f6f9_38 + f7f8_38; 587 | long h6 = f0f6_2 + f1f5_4 + f2f4_2 + f3f3_2 + f7f9_76 + f8f8_19; 588 | long h7 = f0f7_2 + f1f6_2 + f2f5_2 + f3f4_2 + f8f9_38; 589 | long h8 = f0f8_2 + f1f7_4 + f2f6_2 + f3f5_4 + f4f4 + f9f9_38; 590 | long h9 = f0f9_2 + f1f8_2 + f2f7_2 + f3f6_2 + f4f5_2; 591 | long carry0; 592 | long carry1; 593 | long carry2; 594 | long carry3; 595 | long carry4; 596 | long carry5; 597 | long carry6; 598 | long carry7; 599 | long carry8; 600 | long carry9; 601 | 602 | carry0 = (h0 + (long) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26; 603 | carry4 = (h4 + (long) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26; 604 | 605 | carry1 = (h1 + (long) (1<<24)) >> 25; h2 += carry1; h1 -= carry1 << 25; 606 | carry5 = (h5 + (long) (1<<24)) >> 25; h6 += carry5; h5 -= carry5 << 25; 607 | 608 | carry2 = (h2 + (long) (1<<25)) >> 26; h3 += carry2; h2 -= carry2 << 26; 609 | carry6 = (h6 + (long) (1<<25)) >> 26; h7 += carry6; h6 -= carry6 << 26; 610 | 611 | carry3 = (h3 + (long) (1<<24)) >> 25; h4 += carry3; h3 -= carry3 << 25; 612 | carry7 = (h7 + (long) (1<<24)) >> 25; h8 += carry7; h7 -= carry7 << 25; 613 | 614 | carry4 = (h4 + (long) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26; 615 | carry8 = (h8 + (long) (1<<25)) >> 26; h9 += carry8; h8 -= carry8 << 26; 616 | 617 | carry9 = (h9 + (long) (1<<24)) >> 25; h0 += carry9 * 19; h9 -= carry9 << 25; 618 | 619 | carry0 = (h0 + (long) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26; 620 | 621 | int[] h = new int[10]; 622 | h[0] = (int) h0; 623 | h[1] = (int) h1; 624 | h[2] = (int) h2; 625 | h[3] = (int) h3; 626 | h[4] = (int) h4; 627 | h[5] = (int) h5; 628 | h[6] = (int) h6; 629 | h[7] = (int) h7; 630 | h[8] = (int) h8; 631 | h[9] = (int) h9; 632 | return new Ed25519FieldElement(f, h); 633 | } 634 | 635 | /** 636 | * $h = 2 * f * f$ 637 | *
638 | * Can overlap $h$ with $f$. 639 | *
640 | * Preconditions: 641 | *
644 | * Postconditions: 645 | *
648 | * See {@link #multiply(FieldElement)} for discussion 649 | * of implementation strategy. 650 | * 651 | * @return The (reasonably reduced) square of this field element times 2. 652 | */ 653 | public FieldElement squareAndDouble() { 654 | int f0 = t[0]; 655 | int f1 = t[1]; 656 | int f2 = t[2]; 657 | int f3 = t[3]; 658 | int f4 = t[4]; 659 | int f5 = t[5]; 660 | int f6 = t[6]; 661 | int f7 = t[7]; 662 | int f8 = t[8]; 663 | int f9 = t[9]; 664 | int f0_2 = 2 * f0; 665 | int f1_2 = 2 * f1; 666 | int f2_2 = 2 * f2; 667 | int f3_2 = 2 * f3; 668 | int f4_2 = 2 * f4; 669 | int f5_2 = 2 * f5; 670 | int f6_2 = 2 * f6; 671 | int f7_2 = 2 * f7; 672 | int f5_38 = 38 * f5; /* 1.959375*2^30 */ 673 | int f6_19 = 19 * f6; /* 1.959375*2^30 */ 674 | int f7_38 = 38 * f7; /* 1.959375*2^30 */ 675 | int f8_19 = 19 * f8; /* 1.959375*2^30 */ 676 | int f9_38 = 38 * f9; /* 1.959375*2^30 */ 677 | long f0f0 = f0 * (long) f0; 678 | long f0f1_2 = f0_2 * (long) f1; 679 | long f0f2_2 = f0_2 * (long) f2; 680 | long f0f3_2 = f0_2 * (long) f3; 681 | long f0f4_2 = f0_2 * (long) f4; 682 | long f0f5_2 = f0_2 * (long) f5; 683 | long f0f6_2 = f0_2 * (long) f6; 684 | long f0f7_2 = f0_2 * (long) f7; 685 | long f0f8_2 = f0_2 * (long) f8; 686 | long f0f9_2 = f0_2 * (long) f9; 687 | long f1f1_2 = f1_2 * (long) f1; 688 | long f1f2_2 = f1_2 * (long) f2; 689 | long f1f3_4 = f1_2 * (long) f3_2; 690 | long f1f4_2 = f1_2 * (long) f4; 691 | long f1f5_4 = f1_2 * (long) f5_2; 692 | long f1f6_2 = f1_2 * (long) f6; 693 | long f1f7_4 = f1_2 * (long) f7_2; 694 | long f1f8_2 = f1_2 * (long) f8; 695 | long f1f9_76 = f1_2 * (long) f9_38; 696 | long f2f2 = f2 * (long) f2; 697 | long f2f3_2 = f2_2 * (long) f3; 698 | long f2f4_2 = f2_2 * (long) f4; 699 | long f2f5_2 = f2_2 * (long) f5; 700 | long f2f6_2 = f2_2 * (long) f6; 701 | long f2f7_2 = f2_2 * (long) f7; 702 | long f2f8_38 = f2_2 * (long) f8_19; 703 | long f2f9_38 = f2 * (long) f9_38; 704 | long f3f3_2 = f3_2 * (long) f3; 705 | long f3f4_2 = f3_2 * (long) f4; 706 | long f3f5_4 = f3_2 * (long) f5_2; 707 | long f3f6_2 = f3_2 * (long) f6; 708 | long f3f7_76 = f3_2 * (long) f7_38; 709 | long f3f8_38 = f3_2 * (long) f8_19; 710 | long f3f9_76 = f3_2 * (long) f9_38; 711 | long f4f4 = f4 * (long) f4; 712 | long f4f5_2 = f4_2 * (long) f5; 713 | long f4f6_38 = f4_2 * (long) f6_19; 714 | long f4f7_38 = f4 * (long) f7_38; 715 | long f4f8_38 = f4_2 * (long) f8_19; 716 | long f4f9_38 = f4 * (long) f9_38; 717 | long f5f5_38 = f5 * (long) f5_38; 718 | long f5f6_38 = f5_2 * (long) f6_19; 719 | long f5f7_76 = f5_2 * (long) f7_38; 720 | long f5f8_38 = f5_2 * (long) f8_19; 721 | long f5f9_76 = f5_2 * (long) f9_38; 722 | long f6f6_19 = f6 * (long) f6_19; 723 | long f6f7_38 = f6 * (long) f7_38; 724 | long f6f8_38 = f6_2 * (long) f8_19; 725 | long f6f9_38 = f6 * (long) f9_38; 726 | long f7f7_38 = f7 * (long) f7_38; 727 | long f7f8_38 = f7_2 * (long) f8_19; 728 | long f7f9_76 = f7_2 * (long) f9_38; 729 | long f8f8_19 = f8 * (long) f8_19; 730 | long f8f9_38 = f8 * (long) f9_38; 731 | long f9f9_38 = f9 * (long) f9_38; 732 | long h0 = f0f0 + f1f9_76 + f2f8_38 + f3f7_76 + f4f6_38 + f5f5_38; 733 | long h1 = f0f1_2 + f2f9_38 + f3f8_38 + f4f7_38 + f5f6_38; 734 | long h2 = f0f2_2 + f1f1_2 + f3f9_76 + f4f8_38 + f5f7_76 + f6f6_19; 735 | long h3 = f0f3_2 + f1f2_2 + f4f9_38 + f5f8_38 + f6f7_38; 736 | long h4 = f0f4_2 + f1f3_4 + f2f2 + f5f9_76 + f6f8_38 + f7f7_38; 737 | long h5 = f0f5_2 + f1f4_2 + f2f3_2 + f6f9_38 + f7f8_38; 738 | long h6 = f0f6_2 + f1f5_4 + f2f4_2 + f3f3_2 + f7f9_76 + f8f8_19; 739 | long h7 = f0f7_2 + f1f6_2 + f2f5_2 + f3f4_2 + f8f9_38; 740 | long h8 = f0f8_2 + f1f7_4 + f2f6_2 + f3f5_4 + f4f4 + f9f9_38; 741 | long h9 = f0f9_2 + f1f8_2 + f2f7_2 + f3f6_2 + f4f5_2; 742 | long carry0; 743 | long carry1; 744 | long carry2; 745 | long carry3; 746 | long carry4; 747 | long carry5; 748 | long carry6; 749 | long carry7; 750 | long carry8; 751 | long carry9; 752 | 753 | h0 += h0; 754 | h1 += h1; 755 | h2 += h2; 756 | h3 += h3; 757 | h4 += h4; 758 | h5 += h5; 759 | h6 += h6; 760 | h7 += h7; 761 | h8 += h8; 762 | h9 += h9; 763 | 764 | carry0 = (h0 + (long) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26; 765 | carry4 = (h4 + (long) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26; 766 | 767 | carry1 = (h1 + (long) (1<<24)) >> 25; h2 += carry1; h1 -= carry1 << 25; 768 | carry5 = (h5 + (long) (1<<24)) >> 25; h6 += carry5; h5 -= carry5 << 25; 769 | 770 | carry2 = (h2 + (long) (1<<25)) >> 26; h3 += carry2; h2 -= carry2 << 26; 771 | carry6 = (h6 + (long) (1<<25)) >> 26; h7 += carry6; h6 -= carry6 << 26; 772 | 773 | carry3 = (h3 + (long) (1<<24)) >> 25; h4 += carry3; h3 -= carry3 << 25; 774 | carry7 = (h7 + (long) (1<<24)) >> 25; h8 += carry7; h7 -= carry7 << 25; 775 | 776 | carry4 = (h4 + (long) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26; 777 | carry8 = (h8 + (long) (1<<25)) >> 26; h9 += carry8; h8 -= carry8 << 26; 778 | 779 | carry9 = (h9 + (long) (1<<24)) >> 25; h0 += carry9 * 19; h9 -= carry9 << 25; 780 | 781 | carry0 = (h0 + (long) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26; 782 | 783 | int[] h = new int[10]; 784 | h[0] = (int) h0; 785 | h[1] = (int) h1; 786 | h[2] = (int) h2; 787 | h[3] = (int) h3; 788 | h[4] = (int) h4; 789 | h[5] = (int) h5; 790 | h[6] = (int) h6; 791 | h[7] = (int) h7; 792 | h[8] = (int) h8; 793 | h[9] = (int) h9; 794 | return new Ed25519FieldElement(f, h); 795 | } 796 | 797 | /** 798 | * Invert this field element. 799 | *
800 | * The inverse is found via Fermat's little theorem:
801 | * $a^p \cong a \mod p$ and therefore $a^{(p-2)} \cong a^{-1} \mod p$
802 | *
803 | * @return The inverse of this field element.
804 | */
805 | public FieldElement invert() {
806 | FieldElement t0, t1, t2, t3;
807 |
808 | // 2 == 2 * 1
809 | t0 = square();
810 |
811 | // 4 == 2 * 2
812 | t1 = t0.square();
813 |
814 | // 8 == 2 * 4
815 | t1 = t1.square();
816 |
817 | // 9 == 8 + 1
818 | t1 = multiply(t1);
819 |
820 | // 11 == 9 + 2
821 | t0 = t0.multiply(t1);
822 |
823 | // 22 == 2 * 11
824 | t2 = t0.square();
825 |
826 | // 31 == 22 + 9
827 | t1 = t1.multiply(t2);
828 |
829 | // 2^6 - 2^1
830 | t2 = t1.square();
831 |
832 | // 2^10 - 2^5
833 | for (int i = 1; i < 5; ++i) {
834 | t2 = t2.square();
835 | }
836 |
837 | // 2^10 - 2^0
838 | t1 = t2.multiply(t1);
839 |
840 | // 2^11 - 2^1
841 | t2 = t1.square();
842 |
843 | // 2^20 - 2^10
844 | for (int i = 1; i < 10; ++i) {
845 | t2 = t2.square();
846 | }
847 |
848 | // 2^20 - 2^0
849 | t2 = t2.multiply(t1);
850 |
851 | // 2^21 - 2^1
852 | t3 = t2.square();
853 |
854 | // 2^40 - 2^20
855 | for (int i = 1; i < 20; ++i) {
856 | t3 = t3.square();
857 | }
858 |
859 | // 2^40 - 2^0
860 | t2 = t3.multiply(t2);
861 |
862 | // 2^41 - 2^1
863 | t2 = t2.square();
864 |
865 | // 2^50 - 2^10
866 | for (int i = 1; i < 10; ++i) {
867 | t2 = t2.square();
868 | }
869 |
870 | // 2^50 - 2^0
871 | t1 = t2.multiply(t1);
872 |
873 | // 2^51 - 2^1
874 | t2 = t1.square();
875 |
876 | // 2^100 - 2^50
877 | for (int i = 1; i < 50; ++i) {
878 | t2 = t2.square();
879 | }
880 |
881 | // 2^100 - 2^0
882 | t2 = t2.multiply(t1);
883 |
884 | // 2^101 - 2^1
885 | t3 = t2.square();
886 |
887 | // 2^200 - 2^100
888 | for (int i = 1; i < 100; ++i) {
889 | t3 = t3.square();
890 | }
891 |
892 | // 2^200 - 2^0
893 | t2 = t3.multiply(t2);
894 |
895 | // 2^201 - 2^1
896 | t2 = t2.square();
897 |
898 | // 2^250 - 2^50
899 | for (int i = 1; i < 50; ++i) {
900 | t2 = t2.square();
901 | }
902 |
903 | // 2^250 - 2^0
904 | t1 = t2.multiply(t1);
905 |
906 | // 2^251 - 2^1
907 | t1 = t1.square();
908 |
909 | // 2^255 - 2^5
910 | for (int i = 1; i < 5; ++i) {
911 | t1 = t1.square();
912 | }
913 |
914 | // 2^255 - 21
915 | return t1.multiply(t0);
916 | }
917 |
918 | /**
919 | * Gets this field element to the power of $(2^{252} - 3)$.
920 | * This is a helper function for calculating the square root.
921 | *
922 | * TODO-CR BR: I think it makes sense to have a sqrt function. 923 | * 924 | * @return This field element to the power of $(2^{252} - 3)$. 925 | */ 926 | public FieldElement pow22523() { 927 | FieldElement t0, t1, t2; 928 | 929 | // 2 == 2 * 1 930 | t0 = square(); 931 | 932 | // 4 == 2 * 2 933 | t1 = t0.square(); 934 | 935 | // 8 == 2 * 4 936 | t1 = t1.square(); 937 | 938 | // z9 = z1*z8 939 | t1 = multiply(t1); 940 | 941 | // 11 == 9 + 2 942 | t0 = t0.multiply(t1); 943 | 944 | // 22 == 2 * 11 945 | t0 = t0.square(); 946 | 947 | // 31 == 22 + 9 948 | t0 = t1.multiply(t0); 949 | 950 | // 2^6 - 2^1 951 | t1 = t0.square(); 952 | 953 | // 2^10 - 2^5 954 | for (int i = 1; i < 5; ++i) { 955 | t1 = t1.square(); 956 | } 957 | 958 | // 2^10 - 2^0 959 | t0 = t1.multiply(t0); 960 | 961 | // 2^11 - 2^1 962 | t1 = t0.square(); 963 | 964 | // 2^20 - 2^10 965 | for (int i = 1; i < 10; ++i) { 966 | t1 = t1.square(); 967 | } 968 | 969 | // 2^20 - 2^0 970 | t1 = t1.multiply(t0); 971 | 972 | // 2^21 - 2^1 973 | t2 = t1.square(); 974 | 975 | // 2^40 - 2^20 976 | for (int i = 1; i < 20; ++i) { 977 | t2 = t2.square(); 978 | } 979 | 980 | // 2^40 - 2^0 981 | t1 = t2.multiply(t1); 982 | 983 | // 2^41 - 2^1 984 | t1 = t1.square(); 985 | 986 | // 2^50 - 2^10 987 | for (int i = 1; i < 10; ++i) { 988 | t1 = t1.square(); 989 | } 990 | 991 | // 2^50 - 2^0 992 | t0 = t1.multiply(t0); 993 | 994 | // 2^51 - 2^1 995 | t1 = t0.square(); 996 | 997 | // 2^100 - 2^50 998 | for (int i = 1; i < 50; ++i) { 999 | t1 = t1.square(); 1000 | } 1001 | 1002 | // 2^100 - 2^0 1003 | t1 = t1.multiply(t0); 1004 | 1005 | // 2^101 - 2^1 1006 | t2 = t1.square(); 1007 | 1008 | // 2^200 - 2^100 1009 | for (int i = 1; i < 100; ++i) { 1010 | t2 = t2.square(); 1011 | } 1012 | 1013 | // 2^200 - 2^0 1014 | t1 = t2.multiply(t1); 1015 | 1016 | // 2^201 - 2^1 1017 | t1 = t1.square(); 1018 | 1019 | // 2^250 - 2^50 1020 | for (int i = 1; i < 50; ++i) { 1021 | t1 = t1.square(); 1022 | } 1023 | 1024 | // 2^250 - 2^0 1025 | t0 = t1.multiply(t0); 1026 | 1027 | // 2^251 - 2^1 1028 | t0 = t0.square(); 1029 | 1030 | // 2^252 - 2^2 1031 | t0 = t0.square(); 1032 | 1033 | // 2^252 - 3 1034 | return multiply(t0); 1035 | } 1036 | 1037 | /** 1038 | * Constant-time conditional move. Well, actually it is a conditional copy. 1039 | * Logic is inspired by the SUPERCOP implementation at: 1040 | * https://github.com/floodyberry/supercop/blob/master/crypto_sign/ed25519/ref10/fe_cmov.c 1041 | * 1042 | * @param val the other field element. 1043 | * @param b must be 0 or 1, otherwise results are undefined. 1044 | * @return a copy of this if $b == 0$, or a copy of val if $b == 1$. 1045 | */ 1046 | @Override 1047 | public FieldElement cmov(FieldElement val, int b) { 1048 | Ed25519FieldElement that = (Ed25519FieldElement) val; 1049 | b = -b; 1050 | int[] result = new int[10]; 1051 | for (int i = 0; i < 10; i++) { 1052 | result[i] = this.t[i]; 1053 | int x = this.t[i] ^ that.t[i]; 1054 | x &= b; 1055 | result[i] ^= x; 1056 | } 1057 | return new Ed25519FieldElement(this.f, result); 1058 | } 1059 | 1060 | @Override 1061 | public FieldElement carry() { 1062 | int x1; 1063 | int x2; 1064 | int x3; 1065 | int x4; 1066 | int x5; 1067 | int x6; 1068 | int x7; 1069 | int x8; 1070 | int x9; 1071 | int x10; 1072 | int x11; 1073 | int x12; 1074 | int x13; 1075 | int x14; 1076 | int x15; 1077 | int x16; 1078 | int x17; 1079 | int x18; 1080 | int x19; 1081 | int x20; 1082 | int x21; 1083 | int x22; 1084 | x1 = (this.t[0]); 1085 | x2 = ((x1 >>> 26) + (this.t[1])); 1086 | x3 = ((x2 >>> 25) + (this.t[2])); 1087 | x4 = ((x3 >>> 26) + (this.t[3])); 1088 | x5 = ((x4 >>> 25) + (this.t[4])); 1089 | x6 = ((x5 >>> 26) + (this.t[5])); 1090 | x7 = ((x6 >>> 25) + (this.t[6])); 1091 | x8 = ((x7 >>> 26) + (this.t[7])); 1092 | x9 = ((x8 >>> 25) + (this.t[8])); 1093 | x10 = ((x9 >>> 26) + (this.t[9])); 1094 | x11 = ((x1 & 0x3ffffff) + ((x10 >> 25) * (byte) 0x13)); 1095 | x12 = ((byte)(x11 >>> 26) + (x2 & 0x1ffffff)); 1096 | x13 = (x11 & 0x3ffffff); 1097 | x14 = (x12 & 0x1ffffff); 1098 | x15 = ((byte)(x12 >>> 25) + (x3 & 0x3ffffff)); 1099 | x16 = (x4 & 0x1ffffff); 1100 | x17 = (x5 & 0x3ffffff); 1101 | x18 = (x6 & 0x1ffffff); 1102 | x19 = (x7 & 0x3ffffff); 1103 | x20 = (x8 & 0x1ffffff); 1104 | x21 = (x9 & 0x3ffffff); 1105 | x22 = (x10 & 0x1ffffff); 1106 | int[] out1 = new int[10]; 1107 | out1[0] = x13; 1108 | out1[1] = x14; 1109 | out1[2] = x15; 1110 | out1[3] = x16; 1111 | out1[4] = x17; 1112 | out1[5] = x18; 1113 | out1[6] = x19; 1114 | out1[7] = x20; 1115 | out1[8] = x21; 1116 | out1[9] = x22; 1117 | return new Ed25519FieldElement(this.f, out1); 1118 | } 1119 | 1120 | @Override 1121 | public int hashCode() { 1122 | return Arrays.hashCode(t); 1123 | } 1124 | 1125 | @Override 1126 | public boolean equals(Object obj) { 1127 | if (!(obj instanceof Ed25519FieldElement)) 1128 | return false; 1129 | Ed25519FieldElement fe = (Ed25519FieldElement) obj; 1130 | return 1==Utils.equal(toByteArray(), fe.toByteArray()); 1131 | } 1132 | 1133 | @Override 1134 | public String toString() { 1135 | // return "[Ed25519FieldElement val="+Utils.bytesToHex(toByteArray())+"]"; 1136 | StringBuilder sb = new StringBuilder(); 1137 | for (int i : t) sb.append(i & 0xFFFF_FFFFL).append(" "); 1138 | return sb.toString(); 1139 | } 1140 | } 1141 | -------------------------------------------------------------------------------- /java/src/main/java/io/github/muntashirakon/crypto/ed25519/Ed25519LittleEndianEncoding.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021 Muntashir Al-Islam 3 | * 4 | * Licensed according to the LICENSE file in this repository. 5 | */ 6 | 7 | package io.github.muntashirakon.crypto.ed25519; 8 | 9 | /** 10 | * Helper class for encoding/decoding from/to the 32 byte representation. 11 | *
12 | * Reviewed/commented by Bloody Rookie (nemproject@gmx.de) 13 | */ 14 | public class Ed25519LittleEndianEncoding { 15 | protected Ed25519Field f; 16 | 17 | public synchronized void setField(Ed25519Field f) { 18 | if (this.f != null) 19 | throw new IllegalStateException("already set"); 20 | this.f = f; 21 | } 22 | 23 | /** 24 | * Encodes a given field element in its 32 byte representation. This is done in two steps: 25 | *
29 | * The idea for the modulo $p$ reduction algorithm is as follows: 30 | *
31 | *37 | * Then $q = [2^{-255} * (h + 19 * 2^{-25} * h_9 + 1/2)]$ where $[x] = floor(x)$. 38 | *
39 | *41 | * We begin with some very raw estimation for the bounds of some expressions: 42 | *
43 | * $$ 44 | * \begin{equation} 45 | * |h| \lt 2^{230} * 2^{30} = 2^{260} \Rightarrow |r + q * p| \lt 2^{260} \Rightarrow |q| \lt 2^{10}. \\ 46 | * \Rightarrow -1/4 \le a := 19^2 * 2^{-255} * q \lt 1/4. \\ 47 | * |h - 2^{230} * h_9| = |h_0 + \dots + 2^{204} * h_8| \lt 2^{204} * 2^{30} = 2^{234}. \\ 48 | * \Rightarrow -1/4 \le b := 19 * 2^{-255} * (h - 2^{230} * h_9) \lt 1/4 49 | * \end{equation} 50 | * $$ 51 | *
52 | * Therefore $0 \lt 1/2 - a - b \lt 1$. 53 | *
54 | * Set $x := r + 19 * 2^{-255} * r + 1/2 - a - b$. Then: 55 | *
56 | * $$ 57 | * 0 \le x \lt 255 - 20 + 19 + 1 = 2^{255} \\ 58 | * \Rightarrow 0 \le 2^{-255} * x \lt 1. 59 | * $$ 60 | *
61 | * Since $q$ is an integer we have 62 | *
63 | * $$ 64 | * [q + 2^{-255} * x] = q \quad (1) 65 | * $$ 66 | *
67 | * Have a closer look at $x$: 68 | *
69 | * $$ 70 | * \begin{align} 71 | * x &= h - q * (2^{255} - 19) + 19 * 2^{-255} * (h - q * (2^{255} - 19)) + 1/2 - 19^2 * 2^{-255} * q - 19 * 2^{-255} * (h - 2^{230} * h_9) \\ 72 | * &= h - q * 2^{255} + 19 * q + 19 * 2^{-255} * h - 19 * q + 19^2 * 2^{-255} * q + 1/2 - 19^2 * 2^{-255} * q - 19 * 2^{-255} * h + 19 * 2^{-25} * h_9 \\ 73 | * &= h + 19 * 2^{-25} * h_9 + 1/2 - q^{255}. 74 | * \end{align} 75 | * $$ 76 | *
77 | * Inserting the expression for $x$ into $(1)$ we get the desired expression for $q$. 78 | */ 79 | public byte[] encode(FieldElement x) { 80 | int[] h = ((Ed25519FieldElement)x).t; 81 | int h0 = h[0]; 82 | int h1 = h[1]; 83 | int h2 = h[2]; 84 | int h3 = h[3]; 85 | int h4 = h[4]; 86 | int h5 = h[5]; 87 | int h6 = h[6]; 88 | int h7 = h[7]; 89 | int h8 = h[8]; 90 | int h9 = h[9]; 91 | int q; 92 | int carry0; 93 | int carry1; 94 | int carry2; 95 | int carry3; 96 | int carry4; 97 | int carry5; 98 | int carry6; 99 | int carry7; 100 | int carry8; 101 | int carry9; 102 | 103 | // Step 1: 104 | // Calculate q 105 | q = (19 * h9 + (1 << 24)) >> 25; 106 | q = (h0 + q) >> 26; 107 | q = (h1 + q) >> 25; 108 | q = (h2 + q) >> 26; 109 | q = (h3 + q) >> 25; 110 | q = (h4 + q) >> 26; 111 | q = (h5 + q) >> 25; 112 | q = (h6 + q) >> 26; 113 | q = (h7 + q) >> 25; 114 | q = (h8 + q) >> 26; 115 | q = (h9 + q) >> 25; 116 | 117 | // r = h - q * p = h - 2^255 * q + 19 * q 118 | // First add 19 * q then discard the bit 255 119 | h0 += 19 * q; 120 | 121 | carry0 = h0 >> 26; h1 += carry0; h0 -= carry0 << 26; 122 | carry1 = h1 >> 25; h2 += carry1; h1 -= carry1 << 25; 123 | carry2 = h2 >> 26; h3 += carry2; h2 -= carry2 << 26; 124 | carry3 = h3 >> 25; h4 += carry3; h3 -= carry3 << 25; 125 | carry4 = h4 >> 26; h5 += carry4; h4 -= carry4 << 26; 126 | carry5 = h5 >> 25; h6 += carry5; h5 -= carry5 << 25; 127 | carry6 = h6 >> 26; h7 += carry6; h6 -= carry6 << 26; 128 | carry7 = h7 >> 25; h8 += carry7; h7 -= carry7 << 25; 129 | carry8 = h8 >> 26; h9 += carry8; h8 -= carry8 << 26; 130 | carry9 = h9 >> 25; h9 -= carry9 << 25; 131 | 132 | // Step 2 (straight forward conversion): 133 | byte[] s = new byte[32]; 134 | s[0] = (byte) h0; 135 | s[1] = (byte) (h0 >> 8); 136 | s[2] = (byte) (h0 >> 16); 137 | s[3] = (byte) ((h0 >> 24) | (h1 << 2)); 138 | s[4] = (byte) (h1 >> 6); 139 | s[5] = (byte) (h1 >> 14); 140 | s[6] = (byte) ((h1 >> 22) | (h2 << 3)); 141 | s[7] = (byte) (h2 >> 5); 142 | s[8] = (byte) (h2 >> 13); 143 | s[9] = (byte) ((h2 >> 21) | (h3 << 5)); 144 | s[10] = (byte) (h3 >> 3); 145 | s[11] = (byte) (h3 >> 11); 146 | s[12] = (byte) ((h3 >> 19) | (h4 << 6)); 147 | s[13] = (byte) (h4 >> 2); 148 | s[14] = (byte) (h4 >> 10); 149 | s[15] = (byte) (h4 >> 18); 150 | s[16] = (byte) h5; 151 | s[17] = (byte) (h5 >> 8); 152 | s[18] = (byte) (h5 >> 16); 153 | s[19] = (byte) ((h5 >> 24) | (h6 << 1)); 154 | s[20] = (byte) (h6 >> 7); 155 | s[21] = (byte) (h6 >> 15); 156 | s[22] = (byte) ((h6 >> 23) | (h7 << 3)); 157 | s[23] = (byte) (h7 >> 5); 158 | s[24] = (byte) (h7 >> 13); 159 | s[25] = (byte) ((h7 >> 21) | (h8 << 4)); 160 | s[26] = (byte) (h8 >> 4); 161 | s[27] = (byte) (h8 >> 12); 162 | s[28] = (byte) ((h8 >> 20) | (h9 << 6)); 163 | s[29] = (byte) (h9 >> 2); 164 | s[30] = (byte) (h9 >> 10); 165 | s[31] = (byte) (h9 >> 18); 166 | return s; 167 | } 168 | 169 | static int load_3(byte[] in, int offset) { 170 | int result = in[offset++] & 0xff; 171 | result |= (in[offset++] & 0xff) << 8; 172 | result |= (in[offset] & 0xff) << 16; 173 | return result; 174 | } 175 | 176 | static long load_4(byte[] in, int offset) { 177 | int result = in[offset++] & 0xff; 178 | result |= (in[offset++] & 0xff) << 8; 179 | result |= (in[offset++] & 0xff) << 16; 180 | result |= in[offset] << 24; 181 | return ((long)result) & 0xffffffffL; 182 | } 183 | 184 | /** 185 | * Decodes a given field element in its 10 byte $2^{25.5}$ representation. 186 | * 187 | * @param in The 32 byte representation. 188 | * @return The field element in its $2^{25.5}$ bit representation. 189 | */ 190 | public FieldElement decode(byte[] in) { 191 | long h0 = load_4(in, 0); 192 | long h1 = load_3(in, 4) << 6; 193 | long h2 = load_3(in, 7) << 5; 194 | long h3 = load_3(in, 10) << 3; 195 | long h4 = load_3(in, 13) << 2; 196 | long h5 = load_4(in, 16); 197 | long h6 = load_3(in, 20) << 7; 198 | long h7 = load_3(in, 23) << 5; 199 | long h8 = load_3(in, 26) << 4; 200 | long h9 = (load_3(in, 29) & 0x7FFFFF) << 2; 201 | long carry0; 202 | long carry1; 203 | long carry2; 204 | long carry3; 205 | long carry4; 206 | long carry5; 207 | long carry6; 208 | long carry7; 209 | long carry8; 210 | long carry9; 211 | 212 | // Remember: 2^255 congruent 19 modulo p 213 | carry9 = (h9 + (long) (1<<24)) >> 25; h0 += carry9 * 19; h9 -= carry9 << 25; 214 | carry1 = (h1 + (long) (1<<24)) >> 25; h2 += carry1; h1 -= carry1 << 25; 215 | carry3 = (h3 + (long) (1<<24)) >> 25; h4 += carry3; h3 -= carry3 << 25; 216 | carry5 = (h5 + (long) (1<<24)) >> 25; h6 += carry5; h5 -= carry5 << 25; 217 | carry7 = (h7 + (long) (1<<24)) >> 25; h8 += carry7; h7 -= carry7 << 25; 218 | 219 | carry0 = (h0 + (long) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26; 220 | carry2 = (h2 + (long) (1<<25)) >> 26; h3 += carry2; h2 -= carry2 << 26; 221 | carry4 = (h4 + (long) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26; 222 | carry6 = (h6 + (long) (1<<25)) >> 26; h7 += carry6; h6 -= carry6 << 26; 223 | carry8 = (h8 + (long) (1<<25)) >> 26; h9 += carry8; h8 -= carry8 << 26; 224 | 225 | int[] h = new int[10]; 226 | h[0] = (int) h0; 227 | h[1] = (int) h1; 228 | h[2] = (int) h2; 229 | h[3] = (int) h3; 230 | h[4] = (int) h4; 231 | h[5] = (int) h5; 232 | h[6] = (int) h6; 233 | h[7] = (int) h7; 234 | h[8] = (int) h8; 235 | h[9] = (int) h9; 236 | return new Ed25519FieldElement(f, h); 237 | } 238 | 239 | /** 240 | * Is the FieldElement negative in this encoding? 241 | *
242 | * Return true if $x$ is in $\{1,3,5,\dots,q-2\}$
243 | * Return false if $x$ is in $\{0,2,4,\dots,q-1\}$
244 | *
245 | * Preconditions: 246 | *
16 | * $q = 2^{252} + 27742317777372353535851937790883648493$. 17 | *
18 | * Reviewed/commented by Bloody Rookie (nemproject@gmx.de) 19 | */ 20 | public class Ed25519ScalarOps { 21 | 22 | /** 23 | * Reduction modulo the group order $q$. 24 | *
25 | * Input: 26 | * $s[0]+256*s[1]+\dots+256^{63}*s[63] = s$ 27 | *
28 | * Output: 29 | * $s[0]+256*s[1]+\dots+256^{31}*s[31] = s \bmod q$ 30 | * where $q = 2^{252} + 27742317777372353535851937790883648493$. 31 | */ 32 | public byte[] reduce(byte[] s) { 33 | // s0,..., s22 have 21 bits, s23 has 29 bits 34 | long s0 = 0x1FFFFF & load_3(s, 0); 35 | long s1 = 0x1FFFFF & (load_4(s, 2) >> 5); 36 | long s2 = 0x1FFFFF & (load_3(s, 5) >> 2); 37 | long s3 = 0x1FFFFF & (load_4(s, 7) >> 7); 38 | long s4 = 0x1FFFFF & (load_4(s, 10) >> 4); 39 | long s5 = 0x1FFFFF & (load_3(s, 13) >> 1); 40 | long s6 = 0x1FFFFF & (load_4(s, 15) >> 6); 41 | long s7 = 0x1FFFFF & (load_3(s, 18) >> 3); 42 | long s8 = 0x1FFFFF & load_3(s, 21); 43 | long s9 = 0x1FFFFF & (load_4(s, 23) >> 5); 44 | long s10 = 0x1FFFFF & (load_3(s, 26) >> 2); 45 | long s11 = 0x1FFFFF & (load_4(s, 28) >> 7); 46 | long s12 = 0x1FFFFF & (load_4(s, 31) >> 4); 47 | long s13 = 0x1FFFFF & (load_3(s, 34) >> 1); 48 | long s14 = 0x1FFFFF & (load_4(s, 36) >> 6); 49 | long s15 = 0x1FFFFF & (load_3(s, 39) >> 3); 50 | long s16 = 0x1FFFFF & load_3(s, 42); 51 | long s17 = 0x1FFFFF & (load_4(s, 44) >> 5); 52 | long s18 = 0x1FFFFF & (load_3(s, 47) >> 2); 53 | long s19 = 0x1FFFFF & (load_4(s, 49) >> 7); 54 | long s20 = 0x1FFFFF & (load_4(s, 52) >> 4); 55 | long s21 = 0x1FFFFF & (load_3(s, 55) >> 1); 56 | long s22 = 0x1FFFFF & (load_4(s, 57) >> 6); 57 | long s23 = (load_4(s, 60) >> 3); 58 | long carry0; 59 | long carry1; 60 | long carry2; 61 | long carry3; 62 | long carry4; 63 | long carry5; 64 | long carry6; 65 | long carry7; 66 | long carry8; 67 | long carry9; 68 | long carry10; 69 | long carry11; 70 | long carry12; 71 | long carry13; 72 | long carry14; 73 | long carry15; 74 | long carry16; 75 | 76 | /** 77 | * Lots of magic numbers :) 78 | * To understand what's going on below, note that 79 | * 80 | * (1) q = 2^252 + q0 where q0 = 27742317777372353535851937790883648493. 81 | * (2) s11 is the coefficient of 2^(11*21), s23 is the coefficient of 2^(^23*21) and 2^252 = 2^((23-11) * 21)). 82 | * (3) 2^252 congruent -q0 modulo q. 83 | * (4) -q0 = 666643 * 2^0 + 470296 * 2^21 + 654183 * 2^(2*21) - 997805 * 2^(3*21) + 136657 * 2^(4*21) - 683901 * 2^(5*21) 84 | * 85 | * Thus 86 | * s23 * 2^(23*11) = s23 * 2^(12*21) * 2^(11*21) = s3 * 2^252 * 2^(11*21) congruent 87 | * s23 * (666643 * 2^0 + 470296 * 2^21 + 654183 * 2^(2*21) - 997805 * 2^(3*21) + 136657 * 2^(4*21) - 683901 * 2^(5*21)) * 2^(11*21) modulo q = 88 | * s23 * (666643 * 2^(11*21) + 470296 * 2^(12*21) + 654183 * 2^(13*21) - 997805 * 2^(14*21) + 136657 * 2^(15*21) - 683901 * 2^(16*21)). 89 | * 90 | * The same procedure is then applied for s22,...,s18. 91 | */ 92 | s11 += s23 * 666643; 93 | s12 += s23 * 470296; 94 | s13 += s23 * 654183; 95 | s14 -= s23 * 997805; 96 | s15 += s23 * 136657; 97 | s16 -= s23 * 683901; 98 | // not used again 99 | //s23 = 0; 100 | 101 | s10 += s22 * 666643; 102 | s11 += s22 * 470296; 103 | s12 += s22 * 654183; 104 | s13 -= s22 * 997805; 105 | s14 += s22 * 136657; 106 | s15 -= s22 * 683901; 107 | // not used again 108 | //s22 = 0; 109 | 110 | s9 += s21 * 666643; 111 | s10 += s21 * 470296; 112 | s11 += s21 * 654183; 113 | s12 -= s21 * 997805; 114 | s13 += s21 * 136657; 115 | s14 -= s21 * 683901; 116 | // not used again 117 | //s21 = 0; 118 | 119 | s8 += s20 * 666643; 120 | s9 += s20 * 470296; 121 | s10 += s20 * 654183; 122 | s11 -= s20 * 997805; 123 | s12 += s20 * 136657; 124 | s13 -= s20 * 683901; 125 | // not used again 126 | //s20 = 0; 127 | 128 | s7 += s19 * 666643; 129 | s8 += s19 * 470296; 130 | s9 += s19 * 654183; 131 | s10 -= s19 * 997805; 132 | s11 += s19 * 136657; 133 | s12 -= s19 * 683901; 134 | // not used again 135 | //s19 = 0; 136 | 137 | s6 += s18 * 666643; 138 | s7 += s18 * 470296; 139 | s8 += s18 * 654183; 140 | s9 -= s18 * 997805; 141 | s10 += s18 * 136657; 142 | s11 -= s18 * 683901; 143 | // not used again 144 | //s18 = 0; 145 | 146 | /** 147 | * Time to reduce the coefficient in order not to get an overflow. 148 | */ 149 | carry6 = (s6 + (1<<20)) >> 21; s7 += carry6; s6 -= carry6 << 21; 150 | carry8 = (s8 + (1<<20)) >> 21; s9 += carry8; s8 -= carry8 << 21; 151 | carry10 = (s10 + (1<<20)) >> 21; s11 += carry10; s10 -= carry10 << 21; 152 | carry12 = (s12 + (1<<20)) >> 21; s13 += carry12; s12 -= carry12 << 21; 153 | carry14 = (s14 + (1<<20)) >> 21; s15 += carry14; s14 -= carry14 << 21; 154 | carry16 = (s16 + (1<<20)) >> 21; s17 += carry16; s16 -= carry16 << 21; 155 | 156 | carry7 = (s7 + (1<<20)) >> 21; s8 += carry7; s7 -= carry7 << 21; 157 | carry9 = (s9 + (1<<20)) >> 21; s10 += carry9; s9 -= carry9 << 21; 158 | carry11 = (s11 + (1<<20)) >> 21; s12 += carry11; s11 -= carry11 << 21; 159 | carry13 = (s13 + (1<<20)) >> 21; s14 += carry13; s13 -= carry13 << 21; 160 | carry15 = (s15 + (1<<20)) >> 21; s16 += carry15; s15 -= carry15 << 21; 161 | 162 | /** 163 | * Continue with above procedure. 164 | */ 165 | s5 += s17 * 666643; 166 | s6 += s17 * 470296; 167 | s7 += s17 * 654183; 168 | s8 -= s17 * 997805; 169 | s9 += s17 * 136657; 170 | s10 -= s17 * 683901; 171 | // not used again 172 | //s17 = 0; 173 | 174 | s4 += s16 * 666643; 175 | s5 += s16 * 470296; 176 | s6 += s16 * 654183; 177 | s7 -= s16 * 997805; 178 | s8 += s16 * 136657; 179 | s9 -= s16 * 683901; 180 | // not used again 181 | //s16 = 0; 182 | 183 | s3 += s15 * 666643; 184 | s4 += s15 * 470296; 185 | s5 += s15 * 654183; 186 | s6 -= s15 * 997805; 187 | s7 += s15 * 136657; 188 | s8 -= s15 * 683901; 189 | // not used again 190 | //s15 = 0; 191 | 192 | s2 += s14 * 666643; 193 | s3 += s14 * 470296; 194 | s4 += s14 * 654183; 195 | s5 -= s14 * 997805; 196 | s6 += s14 * 136657; 197 | s7 -= s14 * 683901; 198 | // not used again 199 | //s14 = 0; 200 | 201 | s1 += s13 * 666643; 202 | s2 += s13 * 470296; 203 | s3 += s13 * 654183; 204 | s4 -= s13 * 997805; 205 | s5 += s13 * 136657; 206 | s6 -= s13 * 683901; 207 | // not used again 208 | //s13 = 0; 209 | 210 | s0 += s12 * 666643; 211 | s1 += s12 * 470296; 212 | s2 += s12 * 654183; 213 | s3 -= s12 * 997805; 214 | s4 += s12 * 136657; 215 | s5 -= s12 * 683901; 216 | // set below 217 | //s12 = 0; 218 | 219 | /** 220 | * Reduce coefficients again. 221 | */ 222 | carry0 = (s0 + (1<<20)) >> 21; s1 += carry0; s0 -= carry0 << 21; 223 | carry2 = (s2 + (1<<20)) >> 21; s3 += carry2; s2 -= carry2 << 21; 224 | carry4 = (s4 + (1<<20)) >> 21; s5 += carry4; s4 -= carry4 << 21; 225 | carry6 = (s6 + (1<<20)) >> 21; s7 += carry6; s6 -= carry6 << 21; 226 | carry8 = (s8 + (1<<20)) >> 21; s9 += carry8; s8 -= carry8 << 21; 227 | carry10 = (s10 + (1<<20)) >> 21; s11 += carry10; s10 -= carry10 << 21; 228 | 229 | carry1 = (s1 + (1<<20)) >> 21; s2 += carry1; s1 -= carry1 << 21; 230 | carry3 = (s3 + (1<<20)) >> 21; s4 += carry3; s3 -= carry3 << 21; 231 | carry5 = (s5 + (1<<20)) >> 21; s6 += carry5; s5 -= carry5 << 21; 232 | carry7 = (s7 + (1<<20)) >> 21; s8 += carry7; s7 -= carry7 << 21; 233 | carry9 = (s9 + (1<<20)) >> 21; s10 += carry9; s9 -= carry9 << 21; 234 | //carry11 = (s11 + (1<<20)) >> 21; s12 += carry11; s11 -= carry11 << 21; 235 | carry11 = (s11 + (1<<20)) >> 21; s12 = carry11; s11 -= carry11 << 21; 236 | 237 | s0 += s12 * 666643; 238 | s1 += s12 * 470296; 239 | s2 += s12 * 654183; 240 | s3 -= s12 * 997805; 241 | s4 += s12 * 136657; 242 | s5 -= s12 * 683901; 243 | // set below 244 | //s12 = 0; 245 | 246 | carry0 = s0 >> 21; s1 += carry0; s0 -= carry0 << 21; 247 | carry1 = s1 >> 21; s2 += carry1; s1 -= carry1 << 21; 248 | carry2 = s2 >> 21; s3 += carry2; s2 -= carry2 << 21; 249 | carry3 = s3 >> 21; s4 += carry3; s3 -= carry3 << 21; 250 | carry4 = s4 >> 21; s5 += carry4; s4 -= carry4 << 21; 251 | carry5 = s5 >> 21; s6 += carry5; s5 -= carry5 << 21; 252 | carry6 = s6 >> 21; s7 += carry6; s6 -= carry6 << 21; 253 | carry7 = s7 >> 21; s8 += carry7; s7 -= carry7 << 21; 254 | carry8 = s8 >> 21; s9 += carry8; s8 -= carry8 << 21; 255 | carry9 = s9 >> 21; s10 += carry9; s9 -= carry9 << 21; 256 | carry10 = s10 >> 21; s11 += carry10; s10 -= carry10 << 21; 257 | //carry11 = s11 >> 21; s12 += carry11; s11 -= carry11 << 21; 258 | carry11 = s11 >> 21; s12 = carry11; s11 -= carry11 << 21; 259 | 260 | // TODO-CR BR: Is it really needed to do it TWO times? (it doesn't hurt, just a question). 261 | s0 += s12 * 666643; 262 | s1 += s12 * 470296; 263 | s2 += s12 * 654183; 264 | s3 -= s12 * 997805; 265 | s4 += s12 * 136657; 266 | s5 -= s12 * 683901; 267 | // not used again 268 | //s12 = 0; 269 | 270 | carry0 = s0 >> 21; s1 += carry0; s0 -= carry0 << 21; 271 | carry1 = s1 >> 21; s2 += carry1; s1 -= carry1 << 21; 272 | carry2 = s2 >> 21; s3 += carry2; s2 -= carry2 << 21; 273 | carry3 = s3 >> 21; s4 += carry3; s3 -= carry3 << 21; 274 | carry4 = s4 >> 21; s5 += carry4; s4 -= carry4 << 21; 275 | carry5 = s5 >> 21; s6 += carry5; s5 -= carry5 << 21; 276 | carry6 = s6 >> 21; s7 += carry6; s6 -= carry6 << 21; 277 | carry7 = s7 >> 21; s8 += carry7; s7 -= carry7 << 21; 278 | carry8 = s8 >> 21; s9 += carry8; s8 -= carry8 << 21; 279 | carry9 = s9 >> 21; s10 += carry9; s9 -= carry9 << 21; 280 | carry10 = s10 >> 21; s11 += carry10; s10 -= carry10 << 21; 281 | 282 | // s0, ..., s11 got 21 bits each. 283 | byte[] result = new byte[32]; 284 | result[0] = (byte) s0; 285 | result[1] = (byte) (s0 >> 8); 286 | result[2] = (byte) ((s0 >> 16) | (s1 << 5)); 287 | result[3] = (byte) (s1 >> 3); 288 | result[4] = (byte) (s1 >> 11); 289 | result[5] = (byte) ((s1 >> 19) | (s2 << 2)); 290 | result[6] = (byte) (s2 >> 6); 291 | result[7] = (byte) ((s2 >> 14) | (s3 << 7)); 292 | result[8] = (byte) (s3 >> 1); 293 | result[9] = (byte) (s3 >> 9); 294 | result[10] = (byte) ((s3 >> 17) | (s4 << 4)); 295 | result[11] = (byte) (s4 >> 4); 296 | result[12] = (byte) (s4 >> 12); 297 | result[13] = (byte) ((s4 >> 20) | (s5 << 1)); 298 | result[14] = (byte) (s5 >> 7); 299 | result[15] = (byte) ((s5 >> 15) | (s6 << 6)); 300 | result[16] = (byte) (s6 >> 2); 301 | result[17] = (byte) (s6 >> 10); 302 | result[18] = (byte) ((s6 >> 18) | (s7 << 3)); 303 | result[19] = (byte) (s7 >> 5); 304 | result[20] = (byte) (s7 >> 13); 305 | result[21] = (byte) s8; 306 | result[22] = (byte) (s8 >> 8); 307 | result[23] = (byte) ((s8 >> 16) | (s9 << 5)); 308 | result[24] = (byte) (s9 >> 3); 309 | result[25] = (byte) (s9 >> 11); 310 | result[26] = (byte) ((s9 >> 19) | (s10 << 2)); 311 | result[27] = (byte) (s10 >> 6); 312 | result[28] = (byte) ((s10 >> 14) | (s11 << 7)); 313 | result[29] = (byte) (s11 >> 1); 314 | result[30] = (byte) (s11 >> 9); 315 | result[31] = (byte) (s11 >> 17); 316 | return result; 317 | } 318 | 319 | 320 | /** 321 | * $(ab+c) \bmod q$ 322 | *
323 | * Input: 324 | *
329 | * Output: 330 | * $result[0]+256*result[1]+\dots+256^{31}*result[31] = (ab+c) \bmod q$ 331 | * where $q = 2^{252} + 27742317777372353535851937790883648493$. 332 | *
333 | * See the comments in {@link #reduce(byte[])} for an explanation of the algorithm.
334 | */
335 | public byte[] multiplyAndAdd(byte[] a, byte[] b, byte[] c) {
336 | long a0 = 0x1FFFFF & load_3(a, 0);
337 | long a1 = 0x1FFFFF & (load_4(a, 2) >> 5);
338 | long a2 = 0x1FFFFF & (load_3(a, 5) >> 2);
339 | long a3 = 0x1FFFFF & (load_4(a, 7) >> 7);
340 | long a4 = 0x1FFFFF & (load_4(a, 10) >> 4);
341 | long a5 = 0x1FFFFF & (load_3(a, 13) >> 1);
342 | long a6 = 0x1FFFFF & (load_4(a, 15) >> 6);
343 | long a7 = 0x1FFFFF & (load_3(a, 18) >> 3);
344 | long a8 = 0x1FFFFF & load_3(a, 21);
345 | long a9 = 0x1FFFFF & (load_4(a, 23) >> 5);
346 | long a10 = 0x1FFFFF & (load_3(a, 26) >> 2);
347 | long a11 = (load_4(a, 28) >> 7);
348 | long b0 = 0x1FFFFF & load_3(b, 0);
349 | long b1 = 0x1FFFFF & (load_4(b, 2) >> 5);
350 | long b2 = 0x1FFFFF & (load_3(b, 5) >> 2);
351 | long b3 = 0x1FFFFF & (load_4(b, 7) >> 7);
352 | long b4 = 0x1FFFFF & (load_4(b, 10) >> 4);
353 | long b5 = 0x1FFFFF & (load_3(b, 13) >> 1);
354 | long b6 = 0x1FFFFF & (load_4(b, 15) >> 6);
355 | long b7 = 0x1FFFFF & (load_3(b, 18) >> 3);
356 | long b8 = 0x1FFFFF & load_3(b, 21);
357 | long b9 = 0x1FFFFF & (load_4(b, 23) >> 5);
358 | long b10 = 0x1FFFFF & (load_3(b, 26) >> 2);
359 | long b11 = (load_4(b, 28) >> 7);
360 | long c0 = 0x1FFFFF & load_3(c, 0);
361 | long c1 = 0x1FFFFF & (load_4(c, 2) >> 5);
362 | long c2 = 0x1FFFFF & (load_3(c, 5) >> 2);
363 | long c3 = 0x1FFFFF & (load_4(c, 7) >> 7);
364 | long c4 = 0x1FFFFF & (load_4(c, 10) >> 4);
365 | long c5 = 0x1FFFFF & (load_3(c, 13) >> 1);
366 | long c6 = 0x1FFFFF & (load_4(c, 15) >> 6);
367 | long c7 = 0x1FFFFF & (load_3(c, 18) >> 3);
368 | long c8 = 0x1FFFFF & load_3(c, 21);
369 | long c9 = 0x1FFFFF & (load_4(c, 23) >> 5);
370 | long c10 = 0x1FFFFF & (load_3(c, 26) >> 2);
371 | long c11 = (load_4(c, 28) >> 7);
372 | long s0;
373 | long s1;
374 | long s2;
375 | long s3;
376 | long s4;
377 | long s5;
378 | long s6;
379 | long s7;
380 | long s8;
381 | long s9;
382 | long s10;
383 | long s11;
384 | long s12;
385 | long s13;
386 | long s14;
387 | long s15;
388 | long s16;
389 | long s17;
390 | long s18;
391 | long s19;
392 | long s20;
393 | long s21;
394 | long s22;
395 | long s23;
396 | long carry0;
397 | long carry1;
398 | long carry2;
399 | long carry3;
400 | long carry4;
401 | long carry5;
402 | long carry6;
403 | long carry7;
404 | long carry8;
405 | long carry9;
406 | long carry10;
407 | long carry11;
408 | long carry12;
409 | long carry13;
410 | long carry14;
411 | long carry15;
412 | long carry16;
413 | long carry17;
414 | long carry18;
415 | long carry19;
416 | long carry20;
417 | long carry21;
418 | long carry22;
419 |
420 | s0 = c0 + a0*b0;
421 | s1 = c1 + a0*b1 + a1*b0;
422 | s2 = c2 + a0*b2 + a1*b1 + a2*b0;
423 | s3 = c3 + a0*b3 + a1*b2 + a2*b1 + a3*b0;
424 | s4 = c4 + a0*b4 + a1*b3 + a2*b2 + a3*b1 + a4*b0;
425 | s5 = c5 + a0*b5 + a1*b4 + a2*b3 + a3*b2 + a4*b1 + a5*b0;
426 | s6 = c6 + a0*b6 + a1*b5 + a2*b4 + a3*b3 + a4*b2 + a5*b1 + a6*b0;
427 | s7 = c7 + a0*b7 + a1*b6 + a2*b5 + a3*b4 + a4*b3 + a5*b2 + a6*b1 + a7*b0;
428 | s8 = c8 + a0*b8 + a1*b7 + a2*b6 + a3*b5 + a4*b4 + a5*b3 + a6*b2 + a7*b1 + a8*b0;
429 | s9 = c9 + a0*b9 + a1*b8 + a2*b7 + a3*b6 + a4*b5 + a5*b4 + a6*b3 + a7*b2 + a8*b1 + a9*b0;
430 | s10 = c10 + a0*b10 + a1*b9 + a2*b8 + a3*b7 + a4*b6 + a5*b5 + a6*b4 + a7*b3 + a8*b2 + a9*b1 + a10*b0;
431 | s11 = c11 + a0*b11 + a1*b10 + a2*b9 + a3*b8 + a4*b7 + a5*b6 + a6*b5 + a7*b4 + a8*b3 + a9*b2 + a10*b1 + a11*b0;
432 | s12 = a1*b11 + a2*b10 + a3*b9 + a4*b8 + a5*b7 + a6*b6 + a7*b5 + a8*b4 + a9*b3 + a10*b2 + a11*b1;
433 | s13 = a2*b11 + a3*b10 + a4*b9 + a5*b8 + a6*b7 + a7*b6 + a8*b5 + a9*b4 + a10*b3 + a11*b2;
434 | s14 = a3*b11 + a4*b10 + a5*b9 + a6*b8 + a7*b7 + a8*b6 + a9*b5 + a10*b4 + a11*b3;
435 | s15 = a4*b11 + a5*b10 + a6*b9 + a7*b8 + a8*b7 + a9*b6 + a10*b5 + a11*b4;
436 | s16 = a5*b11 + a6*b10 + a7*b9 + a8*b8 + a9*b7 + a10*b6 + a11*b5;
437 | s17 = a6*b11 + a7*b10 + a8*b9 + a9*b8 + a10*b7 + a11*b6;
438 | s18 = a7*b11 + a8*b10 + a9*b9 + a10*b8 + a11*b7;
439 | s19 = a8*b11 + a9*b10 + a10*b9 + a11*b8;
440 | s20 = a9*b11 + a10*b10 + a11*b9;
441 | s21 = a10*b11 + a11*b10;
442 | s22 = a11*b11;
443 | // set below
444 | //s23 = 0;
445 |
446 | carry0 = (s0 + (1<<20)) >> 21; s1 += carry0; s0 -= carry0 << 21;
447 | carry2 = (s2 + (1<<20)) >> 21; s3 += carry2; s2 -= carry2 << 21;
448 | carry4 = (s4 + (1<<20)) >> 21; s5 += carry4; s4 -= carry4 << 21;
449 | carry6 = (s6 + (1<<20)) >> 21; s7 += carry6; s6 -= carry6 << 21;
450 | carry8 = (s8 + (1<<20)) >> 21; s9 += carry8; s8 -= carry8 << 21;
451 | carry10 = (s10 + (1<<20)) >> 21; s11 += carry10; s10 -= carry10 << 21;
452 | carry12 = (s12 + (1<<20)) >> 21; s13 += carry12; s12 -= carry12 << 21;
453 | carry14 = (s14 + (1<<20)) >> 21; s15 += carry14; s14 -= carry14 << 21;
454 | carry16 = (s16 + (1<<20)) >> 21; s17 += carry16; s16 -= carry16 << 21;
455 | carry18 = (s18 + (1<<20)) >> 21; s19 += carry18; s18 -= carry18 << 21;
456 | carry20 = (s20 + (1<<20)) >> 21; s21 += carry20; s20 -= carry20 << 21;
457 | //carry22 = (s22 + (1<<20)) >> 21; s23 += carry22; s22 -= carry22 << 21;
458 | carry22 = (s22 + (1<<20)) >> 21; s23 = carry22; s22 -= carry22 << 21;
459 |
460 | carry1 = (s1 + (1<<20)) >> 21; s2 += carry1; s1 -= carry1 << 21;
461 | carry3 = (s3 + (1<<20)) >> 21; s4 += carry3; s3 -= carry3 << 21;
462 | carry5 = (s5 + (1<<20)) >> 21; s6 += carry5; s5 -= carry5 << 21;
463 | carry7 = (s7 + (1<<20)) >> 21; s8 += carry7; s7 -= carry7 << 21;
464 | carry9 = (s9 + (1<<20)) >> 21; s10 += carry9; s9 -= carry9 << 21;
465 | carry11 = (s11 + (1<<20)) >> 21; s12 += carry11; s11 -= carry11 << 21;
466 | carry13 = (s13 + (1<<20)) >> 21; s14 += carry13; s13 -= carry13 << 21;
467 | carry15 = (s15 + (1<<20)) >> 21; s16 += carry15; s15 -= carry15 << 21;
468 | carry17 = (s17 + (1<<20)) >> 21; s18 += carry17; s17 -= carry17 << 21;
469 | carry19 = (s19 + (1<<20)) >> 21; s20 += carry19; s19 -= carry19 << 21;
470 | carry21 = (s21 + (1<<20)) >> 21; s22 += carry21; s21 -= carry21 << 21;
471 |
472 | s11 += s23 * 666643;
473 | s12 += s23 * 470296;
474 | s13 += s23 * 654183;
475 | s14 -= s23 * 997805;
476 | s15 += s23 * 136657;
477 | s16 -= s23 * 683901;
478 | // not used again
479 | //s23 = 0;
480 |
481 | s10 += s22 * 666643;
482 | s11 += s22 * 470296;
483 | s12 += s22 * 654183;
484 | s13 -= s22 * 997805;
485 | s14 += s22 * 136657;
486 | s15 -= s22 * 683901;
487 | // not used again
488 | //s22 = 0;
489 |
490 | s9 += s21 * 666643;
491 | s10 += s21 * 470296;
492 | s11 += s21 * 654183;
493 | s12 -= s21 * 997805;
494 | s13 += s21 * 136657;
495 | s14 -= s21 * 683901;
496 | // not used again
497 | //s21 = 0;
498 |
499 | s8 += s20 * 666643;
500 | s9 += s20 * 470296;
501 | s10 += s20 * 654183;
502 | s11 -= s20 * 997805;
503 | s12 += s20 * 136657;
504 | s13 -= s20 * 683901;
505 | // not used again
506 | //s20 = 0;
507 |
508 | s7 += s19 * 666643;
509 | s8 += s19 * 470296;
510 | s9 += s19 * 654183;
511 | s10 -= s19 * 997805;
512 | s11 += s19 * 136657;
513 | s12 -= s19 * 683901;
514 | // not used again
515 | //s19 = 0;
516 |
517 | s6 += s18 * 666643;
518 | s7 += s18 * 470296;
519 | s8 += s18 * 654183;
520 | s9 -= s18 * 997805;
521 | s10 += s18 * 136657;
522 | s11 -= s18 * 683901;
523 | // not used again
524 | //s18 = 0;
525 |
526 | carry6 = (s6 + (1<<20)) >> 21; s7 += carry6; s6 -= carry6 << 21;
527 | carry8 = (s8 + (1<<20)) >> 21; s9 += carry8; s8 -= carry8 << 21;
528 | carry10 = (s10 + (1<<20)) >> 21; s11 += carry10; s10 -= carry10 << 21;
529 | carry12 = (s12 + (1<<20)) >> 21; s13 += carry12; s12 -= carry12 << 21;
530 | carry14 = (s14 + (1<<20)) >> 21; s15 += carry14; s14 -= carry14 << 21;
531 | carry16 = (s16 + (1<<20)) >> 21; s17 += carry16; s16 -= carry16 << 21;
532 |
533 | carry7 = (s7 + (1<<20)) >> 21; s8 += carry7; s7 -= carry7 << 21;
534 | carry9 = (s9 + (1<<20)) >> 21; s10 += carry9; s9 -= carry9 << 21;
535 | carry11 = (s11 + (1<<20)) >> 21; s12 += carry11; s11 -= carry11 << 21;
536 | carry13 = (s13 + (1<<20)) >> 21; s14 += carry13; s13 -= carry13 << 21;
537 | carry15 = (s15 + (1<<20)) >> 21; s16 += carry15; s15 -= carry15 << 21;
538 |
539 | s5 += s17 * 666643;
540 | s6 += s17 * 470296;
541 | s7 += s17 * 654183;
542 | s8 -= s17 * 997805;
543 | s9 += s17 * 136657;
544 | s10 -= s17 * 683901;
545 | // not used again
546 | //s17 = 0;
547 |
548 | s4 += s16 * 666643;
549 | s5 += s16 * 470296;
550 | s6 += s16 * 654183;
551 | s7 -= s16 * 997805;
552 | s8 += s16 * 136657;
553 | s9 -= s16 * 683901;
554 | // not used again
555 | //s16 = 0;
556 |
557 | s3 += s15 * 666643;
558 | s4 += s15 * 470296;
559 | s5 += s15 * 654183;
560 | s6 -= s15 * 997805;
561 | s7 += s15 * 136657;
562 | s8 -= s15 * 683901;
563 | // not used again
564 | //s15 = 0;
565 |
566 | s2 += s14 * 666643;
567 | s3 += s14 * 470296;
568 | s4 += s14 * 654183;
569 | s5 -= s14 * 997805;
570 | s6 += s14 * 136657;
571 | s7 -= s14 * 683901;
572 | // not used again
573 | //s14 = 0;
574 |
575 | s1 += s13 * 666643;
576 | s2 += s13 * 470296;
577 | s3 += s13 * 654183;
578 | s4 -= s13 * 997805;
579 | s5 += s13 * 136657;
580 | s6 -= s13 * 683901;
581 | // not used again
582 | //s13 = 0;
583 |
584 | s0 += s12 * 666643;
585 | s1 += s12 * 470296;
586 | s2 += s12 * 654183;
587 | s3 -= s12 * 997805;
588 | s4 += s12 * 136657;
589 | s5 -= s12 * 683901;
590 | // set below
591 | //s12 = 0;
592 |
593 | carry0 = (s0 + (1<<20)) >> 21; s1 += carry0; s0 -= carry0 << 21;
594 | carry2 = (s2 + (1<<20)) >> 21; s3 += carry2; s2 -= carry2 << 21;
595 | carry4 = (s4 + (1<<20)) >> 21; s5 += carry4; s4 -= carry4 << 21;
596 | carry6 = (s6 + (1<<20)) >> 21; s7 += carry6; s6 -= carry6 << 21;
597 | carry8 = (s8 + (1<<20)) >> 21; s9 += carry8; s8 -= carry8 << 21;
598 | carry10 = (s10 + (1<<20)) >> 21; s11 += carry10; s10 -= carry10 << 21;
599 |
600 | carry1 = (s1 + (1<<20)) >> 21; s2 += carry1; s1 -= carry1 << 21;
601 | carry3 = (s3 + (1<<20)) >> 21; s4 += carry3; s3 -= carry3 << 21;
602 | carry5 = (s5 + (1<<20)) >> 21; s6 += carry5; s5 -= carry5 << 21;
603 | carry7 = (s7 + (1<<20)) >> 21; s8 += carry7; s7 -= carry7 << 21;
604 | carry9 = (s9 + (1<<20)) >> 21; s10 += carry9; s9 -= carry9 << 21;
605 | //carry11 = (s11 + (1<<20)) >> 21; s12 += carry11; s11 -= carry11 << 21;
606 | carry11 = (s11 + (1<<20)) >> 21; s12 = carry11; s11 -= carry11 << 21;
607 |
608 | s0 += s12 * 666643;
609 | s1 += s12 * 470296;
610 | s2 += s12 * 654183;
611 | s3 -= s12 * 997805;
612 | s4 += s12 * 136657;
613 | s5 -= s12 * 683901;
614 | // set below
615 | //s12 = 0;
616 |
617 | carry0 = s0 >> 21; s1 += carry0; s0 -= carry0 << 21;
618 | carry1 = s1 >> 21; s2 += carry1; s1 -= carry1 << 21;
619 | carry2 = s2 >> 21; s3 += carry2; s2 -= carry2 << 21;
620 | carry3 = s3 >> 21; s4 += carry3; s3 -= carry3 << 21;
621 | carry4 = s4 >> 21; s5 += carry4; s4 -= carry4 << 21;
622 | carry5 = s5 >> 21; s6 += carry5; s5 -= carry5 << 21;
623 | carry6 = s6 >> 21; s7 += carry6; s6 -= carry6 << 21;
624 | carry7 = s7 >> 21; s8 += carry7; s7 -= carry7 << 21;
625 | carry8 = s8 >> 21; s9 += carry8; s8 -= carry8 << 21;
626 | carry9 = s9 >> 21; s10 += carry9; s9 -= carry9 << 21;
627 | carry10 = s10 >> 21; s11 += carry10; s10 -= carry10 << 21;
628 | //carry11 = s11 >> 21; s12 += carry11; s11 -= carry11 << 21;
629 | carry11 = s11 >> 21; s12 = carry11; s11 -= carry11 << 21;
630 |
631 | s0 += s12 * 666643;
632 | s1 += s12 * 470296;
633 | s2 += s12 * 654183;
634 | s3 -= s12 * 997805;
635 | s4 += s12 * 136657;
636 | s5 -= s12 * 683901;
637 | // not used again
638 | //s12 = 0;
639 |
640 | carry0 = s0 >> 21; s1 += carry0; s0 -= carry0 << 21;
641 | carry1 = s1 >> 21; s2 += carry1; s1 -= carry1 << 21;
642 | carry2 = s2 >> 21; s3 += carry2; s2 -= carry2 << 21;
643 | carry3 = s3 >> 21; s4 += carry3; s3 -= carry3 << 21;
644 | carry4 = s4 >> 21; s5 += carry4; s4 -= carry4 << 21;
645 | carry5 = s5 >> 21; s6 += carry5; s5 -= carry5 << 21;
646 | carry6 = s6 >> 21; s7 += carry6; s6 -= carry6 << 21;
647 | carry7 = s7 >> 21; s8 += carry7; s7 -= carry7 << 21;
648 | carry8 = s8 >> 21; s9 += carry8; s8 -= carry8 << 21;
649 | carry9 = s9 >> 21; s10 += carry9; s9 -= carry9 << 21;
650 | carry10 = s10 >> 21; s11 += carry10; s10 -= carry10 << 21;
651 |
652 | byte[] result = new byte[32];
653 | result[0] = (byte) s0;
654 | result[1] = (byte) (s0 >> 8);
655 | result[2] = (byte) ((s0 >> 16) | (s1 << 5));
656 | result[3] = (byte) (s1 >> 3);
657 | result[4] = (byte) (s1 >> 11);
658 | result[5] = (byte) ((s1 >> 19) | (s2 << 2));
659 | result[6] = (byte) (s2 >> 6);
660 | result[7] = (byte) ((s2 >> 14) | (s3 << 7));
661 | result[8] = (byte) (s3 >> 1);
662 | result[9] = (byte) (s3 >> 9);
663 | result[10] = (byte) ((s3 >> 17) | (s4 << 4));
664 | result[11] = (byte) (s4 >> 4);
665 | result[12] = (byte) (s4 >> 12);
666 | result[13] = (byte) ((s4 >> 20) | (s5 << 1));
667 | result[14] = (byte) (s5 >> 7);
668 | result[15] = (byte) ((s5 >> 15) | (s6 << 6));
669 | result[16] = (byte) (s6 >> 2);
670 | result[17] = (byte) (s6 >> 10);
671 | result[18] = (byte) ((s6 >> 18) | (s7 << 3));
672 | result[19] = (byte) (s7 >> 5);
673 | result[20] = (byte) (s7 >> 13);
674 | result[21] = (byte) s8;
675 | result[22] = (byte) (s8 >> 8);
676 | result[23] = (byte) ((s8 >> 16) | (s9 << 5));
677 | result[24] = (byte) (s9 >> 3);
678 | result[25] = (byte) (s9 >> 11);
679 | result[26] = (byte) ((s9 >> 19) | (s10 << 2));
680 | result[27] = (byte) (s10 >> 6);
681 | result[28] = (byte) ((s10 >> 14) | (s11 << 7));
682 | result[29] = (byte) (s11 >> 1);
683 | result[30] = (byte) (s11 >> 9);
684 | result[31] = (byte) (s11 >> 17);
685 | return result;
686 | }
687 | }
688 |
--------------------------------------------------------------------------------
/java/src/main/java/io/github/muntashirakon/crypto/ed25519/FieldElement.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2021 Muntashir Al-Islam
3 | *
4 | * Licensed according to the LICENSE file in this repository.
5 | */
6 |
7 | package io.github.muntashirakon.crypto.ed25519;
8 |
9 | import java.io.Serializable;
10 |
11 | public abstract class FieldElement implements Serializable {
12 | private static final long serialVersionUID = 1239527465875676L;
13 |
14 | protected final Ed25519Field f;
15 |
16 | public FieldElement(Ed25519Field f) {
17 | if (null == f) {
18 | throw new IllegalArgumentException("field cannot be null");
19 | }
20 | this.f = f;
21 | }
22 |
23 | /**
24 | * Encode a FieldElement in its $(b-1)$-bit encoding.
25 | * @return the $(b-1)$-bit encoding of this FieldElement.
26 | */
27 | public byte[] toByteArray() {
28 | return f.getEncoding().encode(this);
29 | }
30 |
31 | public abstract boolean isNonZero();
32 |
33 | public boolean isNegative() {
34 | return f.getEncoding().isNegative(this);
35 | }
36 |
37 | public abstract FieldElement add(FieldElement val);
38 |
39 | public FieldElement addOne() {
40 | return add(f.ONE);
41 | }
42 |
43 | public abstract FieldElement subtract(FieldElement val);
44 |
45 | public FieldElement subtractOne() {
46 | return subtract(f.ONE);
47 | }
48 |
49 | public abstract FieldElement negate();
50 |
51 | public FieldElement divide(FieldElement val) {
52 | return multiply(val.invert());
53 | }
54 |
55 | public abstract FieldElement multiply(FieldElement val);
56 |
57 | public abstract FieldElement square();
58 |
59 | public abstract FieldElement squareAndDouble();
60 |
61 | public abstract FieldElement invert();
62 |
63 | public abstract FieldElement pow22523();
64 |
65 | public abstract FieldElement cmov(FieldElement val, final int b);
66 |
67 | public abstract FieldElement carry();
68 |
69 | @Override
70 | public abstract boolean equals(Object o);
71 |
72 | @Override
73 | public abstract int hashCode();
74 | }
75 |
--------------------------------------------------------------------------------
/java/src/main/java/io/github/muntashirakon/crypto/ed25519/Utils.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2021 Muntashir Al-Islam
3 | *
4 | * Licensed according to the LICENSE file in this repository.
5 | */
6 |
7 | package io.github.muntashirakon.crypto.ed25519;
8 |
9 | /**
10 | * Basic utilities for Ed25519.
11 | * Not for external use, not maintained as a public API.
12 | */
13 | public class Utils {
14 | /**
15 | * Constant-time byte comparison.
16 | * @param b a byte
17 | * @param c a byte
18 | * @return 1 if b and c are equal, 0 otherwise.
19 | */
20 | public static int equal(int b, int c) {
21 | int result = 0;
22 | int xor = b ^ c;
23 | for (int i = 0; i < 8; i++) {
24 | result |= xor >> i;
25 | }
26 | return (result ^ 0x01) & 0x01;
27 | }
28 |
29 | /**
30 | * Constant-time byte[] comparison.
31 | * @param b a byte[]
32 | * @param c a byte[]
33 | * @return 1 if b and c are equal, 0 otherwise.
34 | */
35 | public static int equal(byte[] b, byte[] c) {
36 | int result = 0;
37 | for (int i = 0; i < 32; i++) {
38 | result |= b[i] ^ c[i];
39 | }
40 |
41 | return equal(result, 0);
42 | }
43 |
44 | /**
45 | * Constant-time determine if byte is negative.
46 | * @param b the byte to check.
47 | * @return 1 if the byte is negative, 0 otherwise.
48 | */
49 | public static int negative(int b) {
50 | return (b >> 8) & 1;
51 | }
52 |
53 | /**
54 | * Get the i'th bit of a byte array.
55 | * @param h the byte array.
56 | * @param i the bit index.
57 | * @return 0 or 1, the value of the i'th bit in h
58 | */
59 | public static int bit(byte[] h, int i) {
60 | return (h[i >> 3] >> (i & 7)) & 1;
61 | }
62 |
63 | /**
64 | * Converts a hex string to bytes.
65 | * @param s the hex string to be converted.
66 | * @return the byte[]
67 | */
68 | public static byte[] hexToBytes(String s) {
69 | int len = s.length();
70 | if (len % 2 != 0) {
71 | throw new IllegalArgumentException("Hex string must have an even length");
72 | }
73 | byte[] data = new byte[len / 2];
74 | for (int i = 0; i < len; i += 2) {
75 | data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
76 | + Character.digit(s.charAt(i+1), 16));
77 | }
78 | return data;
79 | }
80 |
81 | /**
82 | * Converts bytes to a hex string.
83 | * @param raw the byte[] to be converted.
84 | * @return the hex representation as a string.
85 | */
86 | public static String bytesToHex(byte[] raw) {
87 | if ( raw == null ) {
88 | return null;
89 | }
90 | final StringBuilder hex = new StringBuilder(2 * raw.length);
91 | for (final byte b : raw) {
92 | hex.append(Character.forDigit((b & 0xF0) >> 4, 16))
93 | .append(Character.forDigit((b & 0x0F), 16));
94 | }
95 | return hex.toString();
96 | }
97 |
98 | }
99 |
--------------------------------------------------------------------------------
/java/src/main/java/io/github/muntashirakon/crypto/spake2/Spake2Context.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2021 Muntashir Al-Islam
3 | *
4 | * Licensed according to the LICENSE file in this repository.
5 | */
6 |
7 | package io.github.muntashirakon.crypto.spake2;
8 |
9 | import java.security.MessageDigest;
10 | import java.security.NoSuchAlgorithmException;
11 | import java.security.SecureRandom;
12 | import java.util.Arrays;
13 |
14 | import javax.security.auth.Destroyable;
15 |
16 | import io.github.muntashirakon.crypto.ed25519.Curve;
17 | import io.github.muntashirakon.crypto.ed25519.Ed25519;
18 | import io.github.muntashirakon.crypto.ed25519.Ed25519CurveParameterSpec;
19 | import io.github.muntashirakon.crypto.ed25519.Ed25519Field;
20 | import io.github.muntashirakon.crypto.ed25519.Ed25519ScalarOps;
21 | import io.github.muntashirakon.crypto.ed25519.FieldElement;
22 | import io.github.muntashirakon.crypto.ed25519.GroupElement;
23 | import io.github.muntashirakon.crypto.ed25519.Utils;
24 |
25 | @SuppressWarnings("unused")
26 | public class Spake2Context implements Destroyable {
27 | /**
28 | * Maximum message size in bytes
29 | */
30 | public static final int MAX_MSG_SIZE = 32;
31 | /**
32 | * Maximum key size in bytes
33 | */
34 | public static final int MAX_KEY_SIZE = 64;
35 |
36 | private static byte[] intToByteArray(int[] ints) {
37 | byte[] bytes = new byte[ints.length];
38 | for (int i = 0; i < bytes.length; ++i) {
39 | bytes[i] = (byte) ints[i];
40 | }
41 | return bytes;
42 | }
43 |
44 | // Package private for testing purposes
45 | static GroupElement[] getGEFromTable(Curve curve, int[] intTable) {
46 | byte[] table = intToByteArray(intTable);
47 | Ed25519Field f = curve.getField();
48 | GroupElement[] ge = new GroupElement[table.length / (3 * 32)];
49 | byte[] bytes = new byte[32];
50 | for (int i = 0; i < ge.length; ++i) {
51 | System.arraycopy(table, i * 96, bytes, 0, 32);
52 | FieldElement ypx = f.fromByteArray(bytes);
53 | System.arraycopy(table, i * 96 + 32, bytes, 0, 32);
54 | FieldElement ymx = f.fromByteArray(bytes);
55 | System.arraycopy(table, i * 96 + 64, bytes, 0, 32);
56 | FieldElement xy2d = f.fromByteArray(bytes);
57 | ge[i] = GroupElement.precomp(curve, ypx, ymx, xy2d);
58 | }
59 | return ge;
60 | }
61 |
62 | // https://datatracker.ietf.org/doc/html/draft-ietf-kitten-krb-spake-preauth-01#appendix-B
63 | private static final String SEED_N = "edwards25519 point generation seed (N)";
64 | private static final String SEED_M = "edwards25519 point generation seed (M)";
65 |
66 | private static final int[] PRECOMP_TABLE_N = new int[]{
67 | 0x43, 0xFE, 0xA4, 0xBE, 0x26, 0x95, 0xFF, 0x8A, 0xDD, 0xD3, 0x71, 0x28, 0x63, 0x86, 0x31,
68 | 0xB0, 0x32, 0x02, 0xA5, 0xD1, 0x95, 0x80, 0x6A, 0xCF, 0xFB, 0x4C, 0x07, 0xFC, 0xB6, 0x3B,
69 | 0x24, 0x67, 0xF0, 0xC7, 0x1A, 0x57, 0x9F, 0x66, 0x1D, 0x6A, 0x55, 0x97, 0x8B, 0xC1, 0x05,
70 | 0x07, 0xB3, 0x70, 0x47, 0x78, 0x14, 0xAA, 0x77, 0xDD, 0x66, 0x4B, 0xE6, 0x17, 0x2D, 0x27,
71 | 0x1B, 0x3B, 0x6A, 0x0A, 0x81, 0x39, 0x04, 0x13, 0x80, 0x6B, 0x54, 0x7E, 0x26, 0xF3, 0xB0,
72 | 0xA2, 0xCA, 0x96, 0x32, 0x8E, 0x98, 0x44, 0x30, 0xFF, 0x8C, 0x2D, 0x67, 0x77, 0x16, 0xF1,
73 | 0xE9, 0x96, 0x8B, 0x33, 0x06, 0x61, 0xFB, 0x78, 0x6B, 0xFB, 0xD8, 0x00, 0x66, 0x8B, 0x17,
74 | 0x5A, 0x26, 0x2D, 0x71, 0xCD, 0x03, 0xA0, 0x14, 0x93, 0xB3, 0xFF, 0xED, 0x68, 0x29, 0xE4,
75 | 0x84, 0x37, 0x81, 0xBB, 0xCD, 0x06, 0x30, 0x40, 0xC2, 0x95, 0xBB, 0xCC, 0xFB, 0x1F, 0x88,
76 | 0x00, 0xA9, 0xC5, 0x3D, 0x15, 0x41, 0x2B, 0x19, 0x00, 0x46, 0x1A, 0xFB, 0x25, 0xE4, 0x8D,
77 | 0x87, 0x0C, 0xEF, 0x3F, 0xC9, 0xBB, 0xCD, 0x2F, 0xDE, 0x78, 0x7F, 0xA8, 0x5C, 0xA8, 0xF3,
78 | 0x4D, 0x18, 0xE9, 0xF4, 0x80, 0x8C, 0x6C, 0x1F, 0x5B, 0xFF, 0xFD, 0x33, 0xDF, 0x6E, 0xFC,
79 | 0xE1, 0xA2, 0x1E, 0xF2, 0xC1, 0xA8, 0x2E, 0x60, 0x50, 0x2B, 0x1C, 0x7B, 0x5C, 0x00, 0xCC,
80 | 0x18, 0x35, 0x4C, 0x36, 0xF8, 0x19, 0xC9, 0x07, 0xF4, 0x99, 0xB9, 0x88, 0xEF, 0x58, 0x71,
81 | 0x33, 0xCB, 0x98, 0x9C, 0xC6, 0xF3, 0x5E, 0x21, 0x68, 0xAC, 0x8C, 0xA0, 0x2A, 0x0A, 0xAA,
82 | 0xB1, 0x9C, 0xDE, 0x59, 0x43, 0xAB, 0x7B, 0x1A, 0x9E, 0x62, 0x8A, 0xFF, 0xA5, 0x5D, 0x6E,
83 | 0x77, 0xC9, 0x73, 0xED, 0x77, 0x08, 0x00, 0xFC, 0xC1, 0x21, 0xE7, 0x5D, 0xFE, 0x48, 0xD4,
84 | 0x3C, 0x8D, 0x18, 0x5C, 0xE6, 0xCB, 0x41, 0xC7, 0x61, 0x03, 0x23, 0x53, 0x96, 0x08, 0x26,
85 | 0xC3, 0x7C, 0x0B, 0x8E, 0x55, 0xC4, 0xF9, 0x21, 0x44, 0x72, 0x56, 0xBE, 0xA3, 0xF0, 0x37,
86 | 0xF1, 0x25, 0x54, 0xA6, 0x3B, 0xB1, 0x4D, 0xF9, 0x8B, 0xE4, 0x1F, 0x77, 0x28, 0x39, 0x9C,
87 | 0x83, 0x9B, 0xC3, 0xE4, 0xAA, 0x46, 0x8F, 0x14, 0x14, 0x6B, 0x9E, 0x8C, 0x9C, 0xF6, 0x3D,
88 | 0x9D, 0xDC, 0x5C, 0xC3, 0x61, 0x64, 0x15, 0xAE, 0xD1, 0x2A, 0x2E, 0x88, 0xF5, 0x8F, 0x0C,
89 | 0xB5, 0x50, 0x39, 0x29, 0x51, 0x6A, 0xCE, 0x29, 0x7C, 0x99, 0x42, 0xF3, 0xCE, 0xCF, 0x83,
90 | 0x29, 0x27, 0xD6, 0x8B, 0x20, 0x27, 0x79, 0x62, 0xF4, 0x71, 0xD1, 0xBA, 0x68, 0x8C, 0x31,
91 | 0x32, 0xAC, 0xE6, 0x16, 0xF7, 0x8F, 0x18, 0x70, 0x75, 0x11, 0x81, 0xDA, 0x82, 0xD1, 0x69,
92 | 0xC8, 0x2E, 0xB2, 0xBE, 0x0E, 0x5B, 0x73, 0xAB, 0x2A, 0x37, 0x6E, 0x2C, 0x1D, 0x69, 0xEA,
93 | 0x9D, 0x0D, 0x92, 0x96, 0xC9, 0xDD, 0x14, 0xEF, 0x0D, 0x2B, 0x96, 0xD0, 0xCF, 0x43, 0xC8,
94 | 0x48, 0xDD, 0x69, 0x78, 0x2F, 0x6B, 0xAD, 0x5C, 0xEB, 0x38, 0x6E, 0xC3, 0x1D, 0xC9, 0xB2,
95 | 0xE4, 0xAC, 0x7F, 0x88, 0x9E, 0x83, 0x5E, 0xB1, 0xC8, 0x4C, 0x7E, 0x13, 0x8E, 0x92, 0x95,
96 | 0x51, 0x8E, 0x3D, 0x91, 0x92, 0x0D, 0xFC, 0xB6, 0x64, 0x82, 0xC8, 0xAD, 0x0A, 0xE5, 0x52,
97 | 0xB5, 0x33, 0x3F, 0x52, 0x77, 0x9E, 0x1F, 0xEA, 0x93, 0x83, 0xBD, 0x38, 0xB5, 0x4F, 0xD1,
98 | 0x9E, 0x56, 0xDA, 0x9E, 0x6B, 0x6A, 0xDA, 0x00, 0xC5, 0x1B, 0xEC, 0x7B, 0xE2, 0x8B, 0x78,
99 | 0x86, 0x61, 0x66, 0x29, 0xDE, 0x54, 0xA9, 0xCF, 0xC8, 0x59, 0x66, 0xCF, 0xB5, 0xA2, 0x61,
100 | 0x99, 0x81, 0x6D, 0xD1, 0xAE, 0xAD, 0xE3, 0xC6, 0x09, 0x84, 0x5D, 0xF0, 0x82, 0xB7, 0x05,
101 | 0x34, 0x39, 0x67, 0x75, 0x75, 0x92, 0x90, 0x39, 0xB7, 0x10, 0x78, 0x43, 0xB0, 0xB6, 0x78,
102 | 0xD9, 0x0B, 0xF6, 0x4C, 0xE8, 0xF2, 0x8B, 0x0D, 0x69, 0xC4, 0x5D, 0x40, 0xDD, 0xBC, 0xC5,
103 | 0x82, 0x35, 0x30, 0x6E, 0xA9, 0x4F, 0x2E, 0x5F, 0x7A, 0x08, 0x9E, 0xFE, 0x44, 0xAE, 0xB9,
104 | 0x81, 0x13, 0x0C, 0x75, 0x77, 0xE5, 0x48, 0x54, 0x38, 0x8F, 0x8F, 0x87, 0x9B, 0xA8, 0xEF,
105 | 0x62, 0x60, 0x56, 0x90, 0x9F, 0x08, 0x6A, 0x5D, 0xF5, 0xF5, 0xE3, 0x6E, 0xAA, 0xC8, 0x34,
106 | 0x1B, 0xBF, 0xFD, 0x65, 0xCD, 0x61, 0x93, 0xCF, 0x6E, 0x2C, 0x97, 0x22, 0x7A, 0x23, 0x91,
107 | 0x02, 0xF6, 0x1E, 0x3E, 0x21, 0xC6, 0xEB, 0x66, 0xCC, 0x2D, 0x29, 0x6F, 0x41, 0x9D, 0xFF,
108 | 0x50, 0x06, 0x49, 0x90, 0xB1, 0x58, 0x91, 0x3C, 0x23, 0xD6, 0xC3, 0xCC, 0x19, 0xE0, 0x43,
109 | 0xC1, 0xBA, 0xEA, 0xAD, 0xED, 0x04, 0x3D, 0xF0, 0x2E, 0x6E, 0xEF, 0xF2, 0xD2, 0x28, 0xA5,
110 | 0xE3, 0x13, 0xCB, 0xBE, 0xEE, 0xE6, 0xC4, 0x23, 0xE0, 0xEA, 0xAF, 0xB3, 0xEF, 0x87, 0x83,
111 | 0x51, 0xC2, 0x5A, 0xCC, 0xC5, 0x38, 0xA5, 0xA1, 0xE5, 0xF5, 0x0A, 0x77, 0x46, 0xF1, 0xA0,
112 | 0x6A, 0x27, 0xFC, 0xB8, 0xA1, 0x37, 0x62, 0x21, 0x47, 0xD1, 0xCE, 0x24, 0xB6, 0x84, 0x3E,
113 | 0x73, 0xFA, 0x11, 0x10, 0x43, 0xB7, 0x1E, 0x4E, 0x4E, 0xB3, 0xF7, 0xE7, 0x15, 0x1F, 0xD7,
114 | 0xE9, 0x37, 0x90, 0x76, 0x65, 0xDA, 0xA3, 0xB7, 0x7A, 0x66, 0x90, 0x47, 0x9F, 0xCF, 0xAB,
115 | 0x9D, 0x64, 0xE6, 0x75, 0xAB, 0xEE, 0xBF, 0x07, 0xF0, 0xAC, 0xE3, 0x50, 0xBC, 0x78, 0x86,
116 | 0x25, 0x41, 0x26, 0x27, 0x53, 0xE4, 0xF8, 0x12, 0xE6, 0x89, 0x7B, 0x19, 0x7E, 0xC3, 0x1C,
117 | 0x39, 0x91, 0x04, 0xF6, 0xC3, 0x70, 0x28, 0xE3, 0xA6, 0x18, 0xC8, 0xB9, 0xB4, 0xF0, 0x6A,
118 | 0x88, 0xD6, 0x6A, 0xA8, 0xFE, 0x56, 0x63, 0xF4, 0x23, 0xEB, 0x2E, 0x62, 0x21, 0x54, 0x16,
119 | 0xD4, 0xFC, 0x72, 0xB7, 0xBF, 0x10, 0x13, 0xE3, 0x04, 0x81, 0x1B, 0x4B, 0xF6, 0x2A, 0x1A,
120 | 0x02, 0xE2, 0xD6, 0x59, 0x3F, 0x1D, 0x33, 0xCA, 0xC5, 0xBE, 0x85, 0x93, 0xDA, 0xB4, 0xA4,
121 | 0xB9, 0x77, 0x5E, 0x37, 0xB4, 0x82, 0x1E, 0x2B, 0x14, 0x03, 0xB3, 0x06, 0x9E, 0x99, 0x46,
122 | 0xB0, 0x2F, 0x52, 0xE7, 0x03, 0x76, 0x5C, 0x19, 0xC0, 0xF7, 0x94, 0xC5, 0x97, 0x1B, 0xE3,
123 | 0xF4, 0xA0, 0x2D, 0xE5, 0x11, 0xA2, 0x9A, 0x5C, 0xFA, 0x2A, 0x55, 0x00, 0x9F, 0xC6, 0xAA,
124 | 0x69, 0xDD, 0x38, 0xBB, 0x28, 0x78, 0x24, 0xB0, 0x18, 0x16, 0xD6, 0x38, 0x65, 0x2F, 0xEE,
125 | 0x6A, 0xC2, 0x7A, 0x56, 0xA7, 0x7B, 0xE7, 0xEE, 0xC0, 0xC7, 0x5D, 0x0A, 0x43, 0x42, 0x03,
126 | 0x59, 0x54, 0x4B, 0x1B, 0x2C, 0xDD, 0xCA, 0x2C, 0x4B, 0x9C, 0x45, 0xD6, 0xDC, 0x51, 0xF0,
127 | 0xF7, 0xE0, 0x1B, 0x4B, 0xD0, 0xFF, 0xF5, 0x1A, 0x05, 0xC3, 0xBE, 0xC0, 0xFE, 0x17, 0x7D,
128 | 0x39, 0xD2, 0x8B, 0x67, 0x9F, 0xD8, 0x7B, 0xF7, 0x7E, 0x64, 0x68, 0x05, 0x21, 0xF4, 0x22,
129 | 0x72, 0x9D, 0xE5, 0xE0, 0x15, 0xB9, 0xA7, 0x80, 0xD9, 0x39, 0x7A, 0xAD, 0xCA, 0x6C, 0x07,
130 | 0x9A, 0x8F, 0xFD, 0x97, 0xB7, 0x50, 0x04, 0x69, 0xD8, 0x01, 0xDD, 0x77, 0x18, 0xA6, 0x60,
131 | 0x1E, 0x86, 0x88, 0x2D, 0x2D, 0xCA, 0xA9, 0xC6, 0xB6, 0x49, 0xAD, 0x15, 0x84, 0xEA, 0xAD,
132 | 0x3F, 0x0A, 0xF8, 0xCD, 0xD1, 0x4B, 0xFD, 0xA8, 0x71, 0xCB, 0xA7, 0xB5, 0xD1, 0xBC, 0x51,
133 | 0x4B, 0x01, 0x09, 0xD3, 0x36, 0xD2, 0x0A, 0xCF, 0x82, 0x72, 0x94, 0xAB, 0xEF, 0x95, 0x6F,
134 | 0x46, 0x34, 0xD8, 0xA5, 0x32, 0x27, 0xFD, 0x5B, 0xEC, 0x21, 0xA5, 0x7C, 0x21, 0xAB, 0xFE,
135 | 0xFC, 0xA6, 0x60, 0x2B, 0x05, 0x17, 0x84, 0xFE, 0xFA, 0x65, 0x21, 0x87, 0x5D, 0xC0, 0x8E,
136 | 0xC2, 0x01, 0xE5, 0x9E, 0xE5, 0x1D, 0x6D, 0x4A, 0xF0, 0x09, 0x4B, 0x0D, 0xE9, 0x9D, 0xA6,
137 | 0xA4, 0xCB, 0x56, 0xFB, 0xCC, 0x55, 0x84, 0x0E, 0x20, 0x6E, 0x2F, 0x5F, 0x7C, 0x49, 0xCA,
138 | 0x46, 0xF6, 0x16, 0x15, 0x7D, 0xE7, 0xF9, 0x73, 0xDD, 0x86, 0xFD, 0xA5, 0x01, 0xE5, 0x68,
139 | 0x5F, 0x0B, 0xA0, 0xBE, 0x38, 0xBF, 0xF5, 0x00, 0x95, 0xE4, 0xF7, 0xC7, 0xA3, 0xE8, 0x8B,
140 | 0x8B, 0xBE, 0xCA, 0x83, 0x9D, 0x66, 0xA7, 0x42, 0x15, 0xBD, 0x6A, 0x74, 0x81, 0xA0, 0xBA,
141 | 0xC4, 0xD4, 0xF0, 0x83, 0xE6, 0x24, 0x7E, 0x2C, 0x12, 0x57, 0x2E, 0x2E, 0x9B, 0xDB, 0xCA,
142 | 0x04, 0x38, 0x9A, 0x49, 0xAB, 0x82, 0x7D, 0x23, 0xB4, 0xC1, 0x1E, 0xCC, 0xC6, 0x55, 0x37,
143 | 0x41, 0x4B, 0x0C, 0xE5, 0xB5, 0x7D, 0xDE, 0xAB, 0xF5, 0xA9, 0xDF, 0x16, 0x0D, 0xE4, 0x9A,
144 | 0x0B, 0xA4, 0x6D, 0x14, 0x3E, 0x55, 0xB3, 0xE7, 0x67, 0x25, 0x8E, 0x31, 0xAF, 0x35, 0x81,
145 | 0x50, 0x3E, 0x5F, 0xAD, 0xAC, 0x76, 0x12, 0x01, 0x3B, 0xBC, 0x94, 0x21, 0xE4, 0x46, 0x5F,
146 | 0x15, 0x51, 0x84, 0x9F, 0x06, 0x1E, 0x79, 0xC8, 0xB8, 0xF8, 0x45, 0x53, 0x5D, 0xC1, 0x60,
147 | 0x01, 0xA2, 0xDF, 0xE5, 0x69, 0x87, 0x21, 0x19, 0x45, 0xB4, 0x53, 0x91, 0x69, 0x05, 0x4C,
148 | 0x3E, 0x45, 0x93, 0x97, 0x2F, 0xE1, 0x24, 0xD0, 0xD6, 0xB3, 0x12, 0xBE, 0x5B, 0xC6, 0x63,
149 | 0x11, 0xD0, 0x23, 0xF9, 0x51, 0x9B, 0xD2, 0xFA, 0xF1, 0x7B, 0x02, 0x71, 0x5E, 0xA3, 0x3C,
150 | 0xF7, 0x71, 0x41, 0xD6, 0x72, 0x90, 0x25, 0x85, 0x82, 0x75, 0x17, 0xF5, 0x31, 0x9B, 0xC8,
151 | 0x60, 0xEE, 0xAD, 0xB4, 0xF6, 0x81, 0x75, 0x95, 0xDE, 0x7D, 0xB3, 0x14, 0x82, 0x9A, 0x69,
152 | 0x21, 0x42, 0x11, 0x01, 0x13, 0x1F, 0xEC, 0xD9, 0x93, 0xA9, 0x6B, 0x07, 0xB4, 0xCE, 0xE8,
153 | 0xEE, 0xF6, 0x16, 0xB0, 0xCF, 0x71, 0xA8, 0x68, 0x9E, 0xDD, 0xD6, 0x0C, 0xA0, 0x4D, 0xFE,
154 | 0xEA, 0x95, 0xAA, 0x3D, 0x3B, 0x58, 0x74, 0xAC, 0x76, 0xA7, 0x2E, 0x66, 0x42, 0x94, 0xB0,
155 | 0xAD, 0x45, 0x12, 0xFD, 0x26, 0x6C, 0x2A, 0xFE, 0xC1, 0x98, 0x5B, 0xFB, 0x31, 0x88, 0xE1,
156 | 0xD2, 0xF1, 0x3B, 0x56, 0xB3, 0x49, 0x97, 0x34, 0x61, 0xD3, 0xE9, 0x52, 0x06, 0x10, 0xAB,
157 | 0x40, 0xC0, 0xC7, 0x72, 0x4D, 0xB8, 0xFF, 0x68, 0x3B, 0x54, 0x72, 0x4C, 0xFE, 0xBA, 0x01,
158 | 0x0C, 0x77, 0xBF, 0x94, 0x5D, 0xC8, 0x70, 0x82, 0x79, 0x70, 0x01, 0x2C, 0xFE, 0x52, 0x44,
159 | 0xA2, 0x0E, 0x59, 0xFA, 0x57, 0x39, 0x48, 0xE6, 0xC1, 0xC3, 0xC1, 0x44, 0x13, 0xD2, 0xC9,
160 | 0x7F, 0xE3, 0x80, 0x91, 0x4E, 0x4F, 0x5A, 0x20, 0x9F, 0x1F, 0x70, 0x43, 0x61, 0x6B, 0x0B,
161 | 0x08, 0x7B, 0xB0, 0x83, 0x18, 0xA7, 0x61, 0x46, 0x21, 0x78, 0xD1, 0x9A, 0xC6, 0xC3, 0xE6,
162 | 0x59, 0xDF, 0x0A, 0x4D, 0xE2, 0x35, 0x31, 0x9F, 0x3A, 0x08, 0x86, 0xE8, 0x08, 0xC4, 0x60,
163 | };
164 |
165 | private static final int[] PRECOMP_TABLE_M = new int[]{
166 | 0x22, 0x81, 0xE2, 0x10, 0x8E, 0xCF, 0xC8, 0xEE, 0x61, 0xC5, 0xAF, 0x20, 0x39, 0x8B, 0x9D,
167 | 0xC8, 0xC6, 0xCD, 0x8A, 0x1B, 0x61, 0x7A, 0xCA, 0x71, 0xE0, 0x6B, 0x02, 0x20, 0x31, 0x67,
168 | 0x41, 0x74, 0x7F, 0x33, 0x1B, 0x86, 0x5E, 0xEC, 0xEA, 0x6C, 0x0B, 0x00, 0x2B, 0x44, 0xED,
169 | 0xAC, 0x38, 0xF0, 0xDB, 0x74, 0x3C, 0x74, 0xE5, 0x14, 0x54, 0x35, 0xBE, 0x33, 0x87, 0x16,
170 | 0xDF, 0x75, 0x62, 0x69, 0x9F, 0x80, 0x69, 0x41, 0x2F, 0x5B, 0xF3, 0x5A, 0xD8, 0x22, 0x94,
171 | 0x18, 0x7B, 0x00, 0xDF, 0x75, 0x27, 0x4C, 0x8F, 0x7D, 0x9F, 0x7B, 0x66, 0x37, 0xC2, 0x5D,
172 | 0x3E, 0xA8, 0xE0, 0x53, 0x1E, 0x09, 0x61, 0x35, 0x5B, 0xA6, 0x9C, 0x02, 0x4F, 0x6B, 0x8A,
173 | 0x7C, 0x82, 0x9A, 0x78, 0x81, 0xB4, 0xB0, 0xB5, 0xFD, 0x1F, 0x19, 0x57, 0x5F, 0xF0, 0x47,
174 | 0x0D, 0x8A, 0x50, 0x3C, 0xCF, 0xDF, 0x86, 0x62, 0x48, 0x23, 0xFC, 0x24, 0xD9, 0xA7, 0x12,
175 | 0x00, 0xB4, 0x5E, 0x7C, 0xDA, 0x08, 0x8A, 0x68, 0x37, 0x2C, 0x81, 0x06, 0x07, 0x42, 0x41,
176 | 0x44, 0x94, 0x7E, 0x4D, 0x83, 0xC0, 0x62, 0xA5, 0x87, 0x58, 0x9E, 0xD3, 0x1F, 0x9E, 0x5F,
177 | 0xC3, 0xF1, 0x0B, 0xD6, 0x87, 0xAE, 0xDC, 0x62, 0x6F, 0x8E, 0x8E, 0x9E, 0x09, 0x19, 0xE4,
178 | 0x8A, 0x8D, 0x66, 0xA9, 0x96, 0x4D, 0x4E, 0x21, 0xEF, 0x6E, 0x2E, 0x66, 0xAB, 0x3F, 0xDE,
179 | 0xCD, 0x85, 0x32, 0x31, 0x3E, 0x4C, 0x48, 0x30, 0xFC, 0x80, 0x7A, 0xCC, 0xD9, 0x5B, 0x6C,
180 | 0xC8, 0xB1, 0x5B, 0xA4, 0x8C, 0x1F, 0x0A, 0xB7, 0xEF, 0x5A, 0x24, 0x20, 0x58, 0x67, 0xE9,
181 | 0x65, 0x8B, 0x79, 0x2E, 0xD0, 0xAC, 0xCC, 0x55, 0x71, 0x53, 0xEA, 0x69, 0x06, 0x2F, 0x88,
182 | 0xC6, 0x38, 0x08, 0x7B, 0x2F, 0xC2, 0x40, 0xE3, 0x6B, 0xEF, 0x22, 0x1E, 0xAE, 0x58, 0x81,
183 | 0x6B, 0x0E, 0xF2, 0xA7, 0xC5, 0xA2, 0x11, 0x5B, 0x59, 0x4B, 0x71, 0x08, 0x80, 0x0E, 0x04,
184 | 0x65, 0x20, 0x4C, 0x61, 0xB4, 0x2F, 0x54, 0xF2, 0xED, 0xE6, 0x19, 0x0A, 0x1F, 0x84, 0xE2,
185 | 0x87, 0x69, 0x39, 0x75, 0xDE, 0x04, 0x6C, 0x10, 0x8D, 0x7E, 0x73, 0xD5, 0xF2, 0x85, 0x86,
186 | 0x48, 0xBB, 0xC5, 0x1B, 0x8C, 0xE4, 0x1F, 0xD5, 0x97, 0x35, 0x5F, 0x18, 0x94, 0xAD, 0xA3,
187 | 0x50, 0x65, 0xDC, 0x7D, 0x33, 0x9C, 0x3A, 0xE6, 0xA4, 0x6A, 0x83, 0xD3, 0x21, 0x09, 0x88,
188 | 0xB8, 0x78, 0x36, 0xBF, 0xE9, 0xBA, 0xA6, 0xB7, 0x5F, 0xBF, 0xFA, 0x71, 0x94, 0xC5, 0x50,
189 | 0x49, 0x13, 0x98, 0x6F, 0xA1, 0xBB, 0x41, 0xAE, 0x41, 0xF2, 0xD0, 0x11, 0x33, 0x87, 0xC1,
190 | 0xF6, 0xB2, 0x9F, 0x33, 0xC8, 0x30, 0x90, 0x4D, 0x9E, 0x67, 0xED, 0x6A, 0xEC, 0xAE, 0x44,
191 | 0xD2, 0x48, 0x22, 0x77, 0x3B, 0xE6, 0xF4, 0x6D, 0x71, 0xF7, 0x4A, 0x88, 0x9A, 0x49, 0x96,
192 | 0x29, 0xFC, 0x29, 0x8B, 0xF7, 0x2D, 0xD7, 0xC9, 0x6D, 0xB1, 0xDC, 0xEA, 0x26, 0xF5, 0x23,
193 | 0x1C, 0x61, 0xD5, 0xFD, 0xE2, 0x23, 0xAC, 0xC4, 0xD4, 0x17, 0x0B, 0xF7, 0x11, 0x07, 0x08,
194 | 0x7D, 0x9E, 0xD3, 0xC7, 0x3F, 0xAA, 0x2C, 0x90, 0xFC, 0xDF, 0xAC, 0xC5, 0x83, 0x69, 0xC3,
195 | 0xD1, 0xA7, 0x37, 0x01, 0xC4, 0x62, 0x16, 0xB7, 0xBE, 0x98, 0x36, 0x9F, 0x32, 0x56, 0x24,
196 | 0xBE, 0x34, 0x45, 0x25, 0xCE, 0x51, 0xF2, 0x41, 0x19, 0x17, 0x46, 0xDE, 0x9D, 0x0F, 0x63,
197 | 0xA8, 0xE9, 0x33, 0xE2, 0xE9, 0x75, 0x00, 0x6E, 0x31, 0xFE, 0x4D, 0x5C, 0x0F, 0x43, 0x6C,
198 | 0xA7, 0x5E, 0xE3, 0xF0, 0xB5, 0x1E, 0xC6, 0xE6, 0x4E, 0xD3, 0x43, 0x5B, 0xC5, 0x1D, 0xA7,
199 | 0x30, 0x03, 0xF0, 0x64, 0x9C, 0x1D, 0xEC, 0xA1, 0xED, 0xA1, 0x5C, 0x5F, 0x75, 0x2C, 0x63,
200 | 0x9F, 0x00, 0x11, 0xB4, 0xB6, 0xA5, 0xFE, 0xDF, 0x9A, 0xA0, 0xFE, 0x66, 0xD3, 0x15, 0x42,
201 | 0xB5, 0xF7, 0xFC, 0xE0, 0xD4, 0x17, 0x20, 0x89, 0xB2, 0x96, 0xF9, 0x4A, 0x9C, 0xD4, 0x68,
202 | 0x15, 0x86, 0xD5, 0x21, 0x4C, 0xBE, 0xE5, 0x8C, 0xFC, 0xA2, 0x91, 0x69, 0xF4, 0xC0, 0x51,
203 | 0xF8, 0xB9, 0x40, 0x64, 0x91, 0x86, 0xBA, 0xEE, 0x1F, 0xB6, 0x26, 0x19, 0xB6, 0xEE, 0xA0,
204 | 0x8B, 0x7A, 0x4C, 0x45, 0x1A, 0x02, 0x65, 0x57, 0x63, 0xF8, 0x85, 0xAA, 0xBF, 0x2E, 0x04,
205 | 0x26, 0x74, 0xB2, 0x53, 0x56, 0x00, 0x38, 0x1D, 0xF7, 0xCE, 0x7C, 0x78, 0x2C, 0x7F, 0xDB,
206 | 0xF0, 0x76, 0x5C, 0x83, 0x2E, 0xDB, 0x8B, 0x3C, 0x16, 0xB7, 0xC7, 0x89, 0x76, 0x67, 0x12,
207 | 0x1F, 0x2B, 0x09, 0x9C, 0x99, 0x80, 0x14, 0x77, 0xAF, 0x37, 0x7A, 0xE8, 0x4D, 0x52, 0x8A,
208 | 0xE1, 0x60, 0xD4, 0x3B, 0xA8, 0x6C, 0x43, 0x44, 0xD8, 0x63, 0x76, 0xFC, 0x37, 0xAA, 0x13,
209 | 0x26, 0xB8, 0x5A, 0x66, 0x58, 0x09, 0xE4, 0xC2, 0x04, 0x03, 0xCD, 0x11, 0xBA, 0x0C, 0xE4,
210 | 0x16, 0x80, 0x2A, 0xE9, 0xF1, 0x4D, 0xD7, 0x0B, 0x4E, 0xF6, 0xC2, 0x35, 0x12, 0xC3, 0xAD,
211 | 0xC3, 0xFE, 0x50, 0x01, 0x19, 0x80, 0x1A, 0x9E, 0xC3, 0x3E, 0xEB, 0xD8, 0x19, 0xA2, 0x1D,
212 | 0x29, 0xCA, 0xEA, 0xC8, 0xBB, 0xD9, 0xDD, 0xAC, 0x00, 0xC4, 0xE8, 0x57, 0x56, 0x0A, 0x7D,
213 | 0x55, 0x9D, 0x1F, 0xCE, 0xBB, 0xC4, 0x38, 0x28, 0xD7, 0xE1, 0x06, 0x11, 0xD3, 0x24, 0x06,
214 | 0x70, 0x46, 0xEC, 0x48, 0xC9, 0x7D, 0x06, 0x41, 0x7C, 0x3D, 0x89, 0x1E, 0xD1, 0x98, 0xAF,
215 | 0x12, 0x0E, 0x57, 0x09, 0x17, 0xA6, 0x09, 0xA2, 0xFA, 0xAE, 0x8A, 0x03, 0x60, 0xA5, 0x4E,
216 | 0x13, 0x1B, 0x22, 0xC3, 0xD5, 0x61, 0xDA, 0x03, 0xA2, 0x04, 0x71, 0xD1, 0xE6, 0x82, 0xB1,
217 | 0x9E, 0x95, 0x39, 0x34, 0x1E, 0x0D, 0x6F, 0x2D, 0x2E, 0x69, 0x3A, 0x86, 0x89, 0x5C, 0x81,
218 | 0xF7, 0xBE, 0xDA, 0xB1, 0xC6, 0xB8, 0x5F, 0x0B, 0x48, 0xF6, 0x02, 0x67, 0xD4, 0x78, 0x81,
219 | 0x59, 0x62, 0xCA, 0xC7, 0x0C, 0x56, 0x2C, 0x18, 0x18, 0xA6, 0x7E, 0x46, 0xDB, 0xBA, 0xAC,
220 | 0x79, 0x9E, 0x6D, 0x40, 0xFF, 0x29, 0x26, 0x50, 0x90, 0x7A, 0x69, 0x40, 0xE2, 0xDA, 0xD1,
221 | 0x0F, 0x68, 0xC9, 0xD0, 0xEF, 0x93, 0x17, 0x6F, 0xDB, 0x45, 0x13, 0x26, 0x8D, 0x61, 0x62,
222 | 0x50, 0x2A, 0x7B, 0x84, 0x17, 0xF3, 0x98, 0x52, 0x14, 0x82, 0xDF, 0xC3, 0x4F, 0xA5, 0x62,
223 | 0x82, 0x3F, 0xA2, 0x0B, 0x6C, 0x5A, 0x0C, 0x86, 0x4F, 0x3B, 0x07, 0x08, 0xCE, 0xFA, 0x2A,
224 | 0x7B, 0x2A, 0x63, 0x64, 0xAD, 0x3A, 0xB6, 0x5E, 0xE4, 0xC9, 0xAC, 0x0E, 0xF9, 0x14, 0x51,
225 | 0x21, 0xE1, 0x72, 0x1E, 0x23, 0x1F, 0xCF, 0x62, 0xFB, 0xF6, 0x62, 0x82, 0x78, 0x2A, 0x2D,
226 | 0xF5, 0x88, 0x02, 0xDE, 0x67, 0x63, 0xC2, 0x63, 0x7B, 0xA0, 0xF2, 0xF3, 0x07, 0x98, 0xF5,
227 | 0x23, 0xEF, 0x96, 0x02, 0xCF, 0x13, 0xB6, 0xA2, 0xB1, 0xC3, 0xE3, 0xC2, 0x55, 0x72, 0xC0,
228 | 0x03, 0x74, 0x4D, 0xD3, 0xF6, 0xF4, 0x5D, 0x1F, 0x60, 0x13, 0xD2, 0x06, 0x77, 0x6B, 0x84,
229 | 0x14, 0x10, 0xA7, 0xEF, 0x54, 0x66, 0x73, 0xFA, 0xF4, 0x5B, 0xF1, 0x1E, 0xE3, 0x0C, 0x73,
230 | 0x0E, 0xB3, 0xB7, 0xAC, 0xC3, 0x9D, 0xDC, 0x9B, 0x30, 0xE4, 0x45, 0x4A, 0xA3, 0xF7, 0xE1,
231 | 0xC5, 0xCC, 0x54, 0x55, 0x54, 0xFB, 0x3E, 0xD4, 0x73, 0xEB, 0xBC, 0xAD, 0xC9, 0xA4, 0xEB,
232 | 0xC0, 0x37, 0xF9, 0xED, 0x6B, 0x51, 0x6E, 0x19, 0x25, 0xC4, 0xAD, 0xE6, 0x26, 0xF7, 0x5B,
233 | 0x41, 0x2F, 0xAA, 0xD0, 0x12, 0xFC, 0x30, 0xAB, 0xCA, 0xB6, 0x4E, 0xDC, 0x62, 0x9F, 0x49,
234 | 0x9E, 0xC2, 0x28, 0x4D, 0x8C, 0x7C, 0xEB, 0xA0, 0xD3, 0xC7, 0x17, 0xE8, 0x6B, 0x1F, 0xB0,
235 | 0x11, 0x09, 0xD0, 0x08, 0x80, 0x22, 0xC9, 0x88, 0xC6, 0xD2, 0x1D, 0xD1, 0x69, 0xD8, 0x6B,
236 | 0x67, 0x80, 0x29, 0x69, 0x46, 0x42, 0x91, 0x7F, 0x9F, 0x9F, 0x3A, 0x81, 0x94, 0x5F, 0xE3,
237 | 0x7D, 0xEE, 0xF2, 0xAF, 0xB1, 0xAC, 0x9C, 0x7B, 0x21, 0x3A, 0x71, 0x03, 0xCF, 0x74, 0x1C,
238 | 0x61, 0xB8, 0x71, 0xB0, 0xE7, 0xDE, 0xD9, 0x2D, 0xE4, 0xB6, 0xE0, 0xF5, 0x0F, 0x45, 0x1F,
239 | 0x3A, 0x51, 0x6B, 0x6C, 0x06, 0x8E, 0x69, 0x6A, 0x93, 0x50, 0x27, 0x68, 0x9C, 0x54, 0x02,
240 | 0x0E, 0x41, 0xC8, 0xE3, 0xF1, 0x36, 0x26, 0x60, 0x35, 0x75, 0x0F, 0xAF, 0x2E, 0x9F, 0x7E,
241 | 0x4E, 0x4B, 0x6D, 0x07, 0x90, 0x23, 0x7C, 0xC7, 0x4F, 0x46, 0xC3, 0x1B, 0xA7, 0xA8, 0x52,
242 | 0x8B, 0x47, 0xC3, 0x37, 0x35, 0xD3, 0x60, 0xF3, 0x83, 0x29, 0x41, 0x63, 0xF1, 0xB5, 0xB4,
243 | 0xDF, 0x69, 0x4A, 0x3D, 0xC8, 0xDF, 0xD9, 0x27, 0xD8, 0xA9, 0xA2, 0x72, 0xBB, 0xE4, 0xE6,
244 | 0x3E, 0x18, 0x9F, 0x5E, 0x21, 0x8A, 0xC4, 0x0E, 0xB8, 0x14, 0x9F, 0x62, 0x3F, 0x61, 0x43,
245 | 0x76, 0x53, 0xBB, 0xB2, 0x70, 0x25, 0x34, 0x0F, 0xEC, 0x7F, 0x6B, 0xD9, 0x7D, 0x50, 0xFF,
246 | 0x23, 0x7D, 0xF6, 0x18, 0x9D, 0x4A, 0xD5, 0x19, 0xFF, 0x1B, 0x7F, 0xFB, 0xF4, 0x96, 0x53,
247 | 0x27, 0xCC, 0x7B, 0x91, 0x63, 0xE8, 0xB6, 0x46, 0xCA, 0x47, 0x99, 0xCD, 0x41, 0x49, 0x9A,
248 | 0xA4, 0xF9, 0x50, 0x11, 0x72, 0xC1, 0x59, 0x3E, 0x09, 0xB6, 0xA7, 0x1E, 0xF6, 0xEF, 0xCB,
249 | 0x79, 0xA5, 0x0D, 0xAB, 0x38, 0x9D, 0xF2, 0x30, 0x74, 0xE1, 0x41, 0xE5, 0x46, 0x34, 0x77,
250 | 0x3A, 0x92, 0x6D, 0xD2, 0x09, 0xDB, 0xDD, 0xF7, 0x0D, 0xBB, 0x83, 0x24, 0x8A, 0xFB, 0x5B,
251 | 0x53, 0xFD, 0x00, 0xED, 0x5A, 0xC3, 0xFD, 0x3E, 0x5E, 0xA7, 0x7E, 0x1E, 0x2A, 0x86, 0xD0,
252 | 0x06, 0x9A, 0x06, 0x7E, 0xB2, 0xDB, 0x8B, 0xD6, 0x0E, 0xCC, 0x57, 0x67, 0x5B, 0x48, 0xF6,
253 | 0x5F, 0x27, 0x5C, 0xBD, 0xEB, 0x75, 0x2B, 0x7C, 0x38, 0x74, 0x1A, 0xE2, 0x5E, 0x2C, 0x3C,
254 | 0x8A, 0xCC, 0x06, 0x4A, 0xD5, 0x88, 0xE2, 0x71, 0x05, 0x14, 0xE2, 0xC5, 0x6C, 0xF7, 0xC6,
255 | 0xCF, 0x20, 0xD0, 0xB9, 0x4C, 0x65, 0x72, 0x23, 0x29, 0x6C, 0xF6, 0xC7, 0x2C, 0xC5, 0xAA,
256 | 0xF6, 0xE9, 0xF1, 0xF9, 0xF3, 0x3C, 0xA2, 0x3A, 0xD3, 0x2B, 0x2A, 0x71, 0x15, 0x16, 0xFD,
257 | 0xAD, 0xFC, 0xE6, 0xF2, 0xBD, 0xA8, 0xC9, 0x97, 0xE8, 0x21, 0x1A, 0x73, 0x3A, 0xEE, 0x48,
258 | 0x71, 0xB7, 0x23, 0x16, 0xE6, 0x4A, 0xD0, 0xAD, 0x3E, 0x76, 0x5A, 0x87, 0x08, 0x18, 0xDD,
259 | 0xCC, 0x4F, 0x3F, 0x06, 0x6A, 0x71, 0x0D, 0x28, 0xC6, 0x90, 0xA3, 0x51, 0x72, 0xA7, 0xDD,
260 | 0x1D, 0x10, 0xAC, 0xF6, 0x4B, 0xE2, 0xAF, 0x57, 0xFF, 0xBD, 0x93, 0xA8, 0x87, 0xD9, 0x75,
261 | 0xE1, 0x30, 0x95, 0xE4, 0x2A, 0x47, 0xBE, 0xA7, 0x76, 0x8C, 0x0F, 0xF2, 0x0E, 0x62, 0x60,
262 | };
263 |
264 | static final GroupElement[] SPAKE_N_SMALL_PRECOMP;
265 | static final GroupElement[] SPAKE_M_SMALL_PRECOMP;
266 |
267 | static {
268 | Ed25519CurveParameterSpec spec = Ed25519.getSpec();
269 | SPAKE_N_SMALL_PRECOMP = getGEFromTable(spec.getCurve(), PRECOMP_TABLE_N);
270 | SPAKE_M_SMALL_PRECOMP = getGEFromTable(spec.getCurve(), PRECOMP_TABLE_M);
271 | }
272 |
273 | private final byte[] myName;
274 | private final byte[] theirName;
275 | private final Spake2Role myRole;
276 | private final byte[] privateKey = new byte[32];
277 | private final byte[] myMsg = new byte[32];
278 | private final byte[] passwordScalar = new byte[32];
279 | private final byte[] passwordHash = new byte[64];
280 | private final Ed25519CurveParameterSpec curveSpec;
281 |
282 | private State state;
283 | private boolean disablePasswordScalarHack;
284 | private boolean isDestroyed = false;
285 |
286 | public Spake2Context(Spake2Role myRole,
287 | final byte[] myName,
288 | final byte[] theirName) {
289 | this.myRole = myRole;
290 | this.myName = new byte[myName.length];
291 | this.theirName = new byte[theirName.length];
292 | this.state = State.Init;
293 |
294 | System.arraycopy(myName, 0, this.myName, 0, myName.length);
295 | System.arraycopy(theirName, 0, this.theirName, 0, theirName.length);
296 |
297 | curveSpec = Ed25519.getSpec();
298 | }
299 |
300 | public void setDisablePasswordScalarHack(boolean disablePasswordScalarHack) {
301 | this.disablePasswordScalarHack = disablePasswordScalarHack;
302 | }
303 |
304 | public boolean isDisablePasswordScalarHack() {
305 | return disablePasswordScalarHack;
306 | }
307 |
308 | public Spake2Role getMyRole() {
309 | return myRole;
310 | }
311 |
312 | public byte[] getMyMsg() {
313 | return myMsg;
314 | }
315 |
316 | public byte[] getMyName() {
317 | return myName;
318 | }
319 |
320 | public byte[] getTheirName() {
321 | return theirName;
322 | }
323 |
324 | @Override
325 | public boolean isDestroyed() {
326 | return isDestroyed;
327 | }
328 |
329 | @Override
330 | public void destroy() {
331 | isDestroyed = true;
332 | Arrays.fill(privateKey, (byte) 0);
333 | Arrays.fill(myMsg, (byte) 0);
334 | Arrays.fill(passwordScalar, (byte) 0);
335 | Arrays.fill(passwordHash, (byte) 0);
336 | }
337 |
338 | /**
339 | * @param password Shared password.
340 | * @return A message of size {@link #MAX_MSG_SIZE}.
341 | * @throws IllegalArgumentException If SHA-512 is unavailable for some reason.
342 | * @throws IllegalStateException If the message has already been generated.
343 | */
344 | public byte[] generateMessage(final byte[] password) throws IllegalArgumentException, IllegalStateException {
345 | byte[] privateKey = new byte[64];
346 | new SecureRandom().nextBytes(privateKey);
347 | System.out.printf("PVKEY(%s): %s%n", myRole, Utils.bytesToHex(privateKey));
348 | return generateMessage(password, privateKey);
349 | }
350 |
351 | // Package private method for testing purposes
352 | byte[] generateMessage(final byte[] password, byte[] privateKey) throws IllegalArgumentException, IllegalStateException {
353 | if (isDestroyed) {
354 | throw new IllegalStateException("The context was destroyed.");
355 | }
356 | if (this.state != State.Init) {
357 | throw new IllegalStateException("Invalid state: " + this.state);
358 | }
359 |
360 | Ed25519ScalarOps scalarOps = curveSpec.getScalarOps();
361 |
362 | System.arraycopy(scalarOps.reduce(privateKey), 0, privateKey, 0, 32);
363 | // Multiply by the cofactor (eight) so that we'll clear it when operating on
364 | // the peer's point later in the protocol.
365 | leftShift3(privateKey);
366 | System.arraycopy(privateKey, 0, this.privateKey, 0, this.privateKey.length);
367 |
368 | final GroupElement P = curveSpec.getB().scalarMultiply(this.privateKey);
369 |
370 | byte[] passwordTmp = getHash("SHA-512", password); // 64 byte
371 | System.arraycopy(passwordTmp, 0, this.passwordHash, 0, this.passwordHash.length);
372 |
373 | /**
374 | * Due to a copy-paste error, the call to {@link #leftShift3(byte[])} was omitted after reducing it, just above.
375 | * This meant that {@link #passwordScalar} was not a multiple of eight to clear the cofactor and thus three bits
376 | * of the password hash would leak. In order to fix this in a unilateral way, points of small order are added to
377 | * the mask point such as that it is in the prime-order subgroup. Since the ephemeral scalar is a multiple of
378 | * eight, these points will cancel out when calculating the shared secret.
379 | *
380 | * Adding points of small order is the same as adding multiples of the prime order to the password scalar. Since
381 | * that's faster, this what is done below. {@link #l} is a large prime, thus, odd, thus the LSB is one. So,
382 | * adding it will flip the LSB. Adding twice, it will flip the next bit, and so on for all the bottom three bits.
383 | */
384 | Scalar passwordScalar = new Scalar(scalarOps.reduce(passwordTmp));
385 |
386 | /**
387 | * passwordScalar is the result of scalar reducing and thus is, at most, $l-1$. In the following, we may add
388 | * $l+2×l+4×l$ for a max value of $8×l-1$. That is less than $2^256$ as required.
389 | */
390 |
391 | if (!this.disablePasswordScalarHack) {
392 | Scalar order = new Scalar(l);
393 | Scalar tmp = new Scalar();
394 | tmp.copy(order.cmov(tmp, isEqual(passwordScalar.getByte(0) & 1, 1)));
395 | passwordScalar.copy(passwordScalar.add(tmp));
396 | order.copy(order.dbl());
397 |
398 | tmp.reset();
399 | tmp.copy(order.cmov(tmp, isEqual(passwordScalar.getByte(0) & 2, 2)));
400 | passwordScalar.copy(passwordScalar.add(tmp));
401 | order.copy(order.dbl());
402 |
403 | tmp.reset();
404 | tmp.copy(order.cmov(tmp, isEqual(passwordScalar.getByte(0) & 4, 4)));
405 | passwordScalar.copy(passwordScalar.add(tmp));
406 |
407 | assert ((passwordScalar.getByte(0) & 7) == 0);
408 | }
409 |
410 | System.arraycopy(passwordScalar.getBytes(), 0, this.passwordScalar, 0, this.passwordScalar.length);
411 |
412 | // mask = h(password) * {
332 | private S first;
333 | private T second;
334 |
335 | public Pair(S first, T second) {
336 | this.first = first;
337 | this.second = second;
338 | }
339 | }
340 | }
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ":java"
2 | include ":android"
3 | rootProject.name = "Spake2"
4 |
--------------------------------------------------------------------------------