[ Index ] |
PHP Cross Reference of WordPress Trunk (Updated Daily) |
[Summary view] [Print] [Text view]
1 <?php 2 3 if (class_exists('ParagonIE_Sodium_Core_Curve25519', false)) { 4 return; 5 } 6 7 /** 8 * Class ParagonIE_Sodium_Core_Curve25519 9 * 10 * Implements Curve25519 core functions 11 * 12 * Based on the ref10 curve25519 code provided by libsodium 13 * 14 * @ref https://github.com/jedisct1/libsodium/blob/master/src/libsodium/crypto_core/curve25519/ref10/curve25519_ref10.c 15 */ 16 abstract class ParagonIE_Sodium_Core_Curve25519 extends ParagonIE_Sodium_Core_Curve25519_H 17 { 18 /** 19 * Get a field element of size 10 with a value of 0 20 * 21 * @internal You should not use this directly from another application 22 * 23 * @return ParagonIE_Sodium_Core_Curve25519_Fe 24 */ 25 public static function fe_0() 26 { 27 return ParagonIE_Sodium_Core_Curve25519_Fe::fromArray( 28 array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0) 29 ); 30 } 31 32 /** 33 * Get a field element of size 10 with a value of 1 34 * 35 * @internal You should not use this directly from another application 36 * 37 * @return ParagonIE_Sodium_Core_Curve25519_Fe 38 */ 39 public static function fe_1() 40 { 41 return ParagonIE_Sodium_Core_Curve25519_Fe::fromArray( 42 array(1, 0, 0, 0, 0, 0, 0, 0, 0, 0) 43 ); 44 } 45 46 /** 47 * Add two field elements. 48 * 49 * @internal You should not use this directly from another application 50 * 51 * @param ParagonIE_Sodium_Core_Curve25519_Fe $f 52 * @param ParagonIE_Sodium_Core_Curve25519_Fe $g 53 * @return ParagonIE_Sodium_Core_Curve25519_Fe 54 * @psalm-suppress MixedAssignment 55 * @psalm-suppress MixedOperand 56 */ 57 public static function fe_add( 58 ParagonIE_Sodium_Core_Curve25519_Fe $f, 59 ParagonIE_Sodium_Core_Curve25519_Fe $g 60 ) { 61 /** @var array<int, int> $arr */ 62 $arr = array(); 63 for ($i = 0; $i < 10; ++$i) { 64 $arr[$i] = (int) ($f[$i] + $g[$i]); 65 } 66 return ParagonIE_Sodium_Core_Curve25519_Fe::fromArray($arr); 67 } 68 69 /** 70 * Constant-time conditional move. 71 * 72 * @internal You should not use this directly from another application 73 * 74 * @param ParagonIE_Sodium_Core_Curve25519_Fe $f 75 * @param ParagonIE_Sodium_Core_Curve25519_Fe $g 76 * @param int $b 77 * @return ParagonIE_Sodium_Core_Curve25519_Fe 78 * @psalm-suppress MixedAssignment 79 */ 80 public static function fe_cmov( 81 ParagonIE_Sodium_Core_Curve25519_Fe $f, 82 ParagonIE_Sodium_Core_Curve25519_Fe $g, 83 $b = 0 84 ) { 85 /** @var array<int, int> $h */ 86 $h = array(); 87 $b *= -1; 88 for ($i = 0; $i < 10; ++$i) { 89 $x = (($f[$i] ^ $g[$i]) & $b); 90 $h[$i] = ($f[$i]) ^ $x; 91 } 92 return ParagonIE_Sodium_Core_Curve25519_Fe::fromArray($h); 93 } 94 95 /** 96 * Create a copy of a field element. 97 * 98 * @internal You should not use this directly from another application 99 * 100 * @param ParagonIE_Sodium_Core_Curve25519_Fe $f 101 * @return ParagonIE_Sodium_Core_Curve25519_Fe 102 */ 103 public static function fe_copy(ParagonIE_Sodium_Core_Curve25519_Fe $f) 104 { 105 $h = clone $f; 106 return $h; 107 } 108 109 /** 110 * Give: 32-byte string. 111 * Receive: A field element object to use for internal calculations. 112 * 113 * @internal You should not use this directly from another application 114 * 115 * @param string $s 116 * @return ParagonIE_Sodium_Core_Curve25519_Fe 117 * @throws RangeException 118 * @throws TypeError 119 */ 120 public static function fe_frombytes($s) 121 { 122 if (self::strlen($s) !== 32) { 123 throw new RangeException('Expected a 32-byte string.'); 124 } 125 $h0 = self::load_4($s); 126 $h1 = self::load_3(self::substr($s, 4, 3)) << 6; 127 $h2 = self::load_3(self::substr($s, 7, 3)) << 5; 128 $h3 = self::load_3(self::substr($s, 10, 3)) << 3; 129 $h4 = self::load_3(self::substr($s, 13, 3)) << 2; 130 $h5 = self::load_4(self::substr($s, 16, 4)); 131 $h6 = self::load_3(self::substr($s, 20, 3)) << 7; 132 $h7 = self::load_3(self::substr($s, 23, 3)) << 5; 133 $h8 = self::load_3(self::substr($s, 26, 3)) << 4; 134 $h9 = (self::load_3(self::substr($s, 29, 3)) & 8388607) << 2; 135 136 $carry9 = ($h9 + (1 << 24)) >> 25; 137 $h0 += self::mul($carry9, 19, 5); 138 $h9 -= $carry9 << 25; 139 $carry1 = ($h1 + (1 << 24)) >> 25; 140 $h2 += $carry1; 141 $h1 -= $carry1 << 25; 142 $carry3 = ($h3 + (1 << 24)) >> 25; 143 $h4 += $carry3; 144 $h3 -= $carry3 << 25; 145 $carry5 = ($h5 + (1 << 24)) >> 25; 146 $h6 += $carry5; 147 $h5 -= $carry5 << 25; 148 $carry7 = ($h7 + (1 << 24)) >> 25; 149 $h8 += $carry7; 150 $h7 -= $carry7 << 25; 151 152 $carry0 = ($h0 + (1 << 25)) >> 26; 153 $h1 += $carry0; 154 $h0 -= $carry0 << 26; 155 $carry2 = ($h2 + (1 << 25)) >> 26; 156 $h3 += $carry2; 157 $h2 -= $carry2 << 26; 158 $carry4 = ($h4 + (1 << 25)) >> 26; 159 $h5 += $carry4; 160 $h4 -= $carry4 << 26; 161 $carry6 = ($h6 + (1 << 25)) >> 26; 162 $h7 += $carry6; 163 $h6 -= $carry6 << 26; 164 $carry8 = ($h8 + (1 << 25)) >> 26; 165 $h9 += $carry8; 166 $h8 -= $carry8 << 26; 167 168 return ParagonIE_Sodium_Core_Curve25519_Fe::fromArray( 169 array( 170 (int) $h0, 171 (int) $h1, 172 (int) $h2, 173 (int) $h3, 174 (int) $h4, 175 (int) $h5, 176 (int) $h6, 177 (int) $h7, 178 (int) $h8, 179 (int) $h9 180 ) 181 ); 182 } 183 184 /** 185 * Convert a field element to a byte string. 186 * 187 * @internal You should not use this directly from another application 188 * 189 * @param ParagonIE_Sodium_Core_Curve25519_Fe $h 190 * @return string 191 */ 192 public static function fe_tobytes(ParagonIE_Sodium_Core_Curve25519_Fe $h) 193 { 194 $h0 = (int) $h[0]; 195 $h1 = (int) $h[1]; 196 $h2 = (int) $h[2]; 197 $h3 = (int) $h[3]; 198 $h4 = (int) $h[4]; 199 $h5 = (int) $h[5]; 200 $h6 = (int) $h[6]; 201 $h7 = (int) $h[7]; 202 $h8 = (int) $h[8]; 203 $h9 = (int) $h[9]; 204 205 $q = (self::mul($h9, 19, 5) + (1 << 24)) >> 25; 206 $q = ($h0 + $q) >> 26; 207 $q = ($h1 + $q) >> 25; 208 $q = ($h2 + $q) >> 26; 209 $q = ($h3 + $q) >> 25; 210 $q = ($h4 + $q) >> 26; 211 $q = ($h5 + $q) >> 25; 212 $q = ($h6 + $q) >> 26; 213 $q = ($h7 + $q) >> 25; 214 $q = ($h8 + $q) >> 26; 215 $q = ($h9 + $q) >> 25; 216 217 $h0 += self::mul($q, 19, 5); 218 219 $carry0 = $h0 >> 26; 220 $h1 += $carry0; 221 $h0 -= $carry0 << 26; 222 $carry1 = $h1 >> 25; 223 $h2 += $carry1; 224 $h1 -= $carry1 << 25; 225 $carry2 = $h2 >> 26; 226 $h3 += $carry2; 227 $h2 -= $carry2 << 26; 228 $carry3 = $h3 >> 25; 229 $h4 += $carry3; 230 $h3 -= $carry3 << 25; 231 $carry4 = $h4 >> 26; 232 $h5 += $carry4; 233 $h4 -= $carry4 << 26; 234 $carry5 = $h5 >> 25; 235 $h6 += $carry5; 236 $h5 -= $carry5 << 25; 237 $carry6 = $h6 >> 26; 238 $h7 += $carry6; 239 $h6 -= $carry6 << 26; 240 $carry7 = $h7 >> 25; 241 $h8 += $carry7; 242 $h7 -= $carry7 << 25; 243 $carry8 = $h8 >> 26; 244 $h9 += $carry8; 245 $h8 -= $carry8 << 26; 246 $carry9 = $h9 >> 25; 247 $h9 -= $carry9 << 25; 248 249 /** 250 * @var array<int, int> 251 */ 252 $s = array( 253 (int) (($h0 >> 0) & 0xff), 254 (int) (($h0 >> 8) & 0xff), 255 (int) (($h0 >> 16) & 0xff), 256 (int) ((($h0 >> 24) | ($h1 << 2)) & 0xff), 257 (int) (($h1 >> 6) & 0xff), 258 (int) (($h1 >> 14) & 0xff), 259 (int) ((($h1 >> 22) | ($h2 << 3)) & 0xff), 260 (int) (($h2 >> 5) & 0xff), 261 (int) (($h2 >> 13) & 0xff), 262 (int) ((($h2 >> 21) | ($h3 << 5)) & 0xff), 263 (int) (($h3 >> 3) & 0xff), 264 (int) (($h3 >> 11) & 0xff), 265 (int) ((($h3 >> 19) | ($h4 << 6)) & 0xff), 266 (int) (($h4 >> 2) & 0xff), 267 (int) (($h4 >> 10) & 0xff), 268 (int) (($h4 >> 18) & 0xff), 269 (int) (($h5 >> 0) & 0xff), 270 (int) (($h5 >> 8) & 0xff), 271 (int) (($h5 >> 16) & 0xff), 272 (int) ((($h5 >> 24) | ($h6 << 1)) & 0xff), 273 (int) (($h6 >> 7) & 0xff), 274 (int) (($h6 >> 15) & 0xff), 275 (int) ((($h6 >> 23) | ($h7 << 3)) & 0xff), 276 (int) (($h7 >> 5) & 0xff), 277 (int) (($h7 >> 13) & 0xff), 278 (int) ((($h7 >> 21) | ($h8 << 4)) & 0xff), 279 (int) (($h8 >> 4) & 0xff), 280 (int) (($h8 >> 12) & 0xff), 281 (int) ((($h8 >> 20) | ($h9 << 6)) & 0xff), 282 (int) (($h9 >> 2) & 0xff), 283 (int) (($h9 >> 10) & 0xff), 284 (int) (($h9 >> 18) & 0xff) 285 ); 286 return self::intArrayToString($s); 287 } 288 289 /** 290 * Is a field element negative? (1 = yes, 0 = no. Used in calculations.) 291 * 292 * @internal You should not use this directly from another application 293 * 294 * @param ParagonIE_Sodium_Core_Curve25519_Fe $f 295 * @return int 296 * @throws SodiumException 297 * @throws TypeError 298 */ 299 public static function fe_isnegative(ParagonIE_Sodium_Core_Curve25519_Fe $f) 300 { 301 $str = self::fe_tobytes($f); 302 return (int) (self::chrToInt($str[0]) & 1); 303 } 304 305 /** 306 * Returns 0 if this field element results in all NUL bytes. 307 * 308 * @internal You should not use this directly from another application 309 * 310 * @param ParagonIE_Sodium_Core_Curve25519_Fe $f 311 * @return bool 312 * @throws SodiumException 313 * @throws TypeError 314 */ 315 public static function fe_isnonzero(ParagonIE_Sodium_Core_Curve25519_Fe $f) 316 { 317 static $zero; 318 if ($zero === null) { 319 $zero = str_repeat("\x00", 32); 320 } 321 /** @var string $zero */ 322 /** @var string $str */ 323 $str = self::fe_tobytes($f); 324 return !self::verify_32($str, (string) $zero); 325 } 326 327 /** 328 * Multiply two field elements 329 * 330 * h = f * g 331 * 332 * @internal You should not use this directly from another application 333 * 334 * @security Is multiplication a source of timing leaks? If so, can we do 335 * anything to prevent that from happening? 336 * 337 * @param ParagonIE_Sodium_Core_Curve25519_Fe $f 338 * @param ParagonIE_Sodium_Core_Curve25519_Fe $g 339 * @return ParagonIE_Sodium_Core_Curve25519_Fe 340 */ 341 public static function fe_mul( 342 ParagonIE_Sodium_Core_Curve25519_Fe $f, 343 ParagonIE_Sodium_Core_Curve25519_Fe $g 344 ) { 345 // Ensure limbs aren't oversized. 346 $f = self::fe_normalize($f); 347 $g = self::fe_normalize($g); 348 $f0 = $f[0]; 349 $f1 = $f[1]; 350 $f2 = $f[2]; 351 $f3 = $f[3]; 352 $f4 = $f[4]; 353 $f5 = $f[5]; 354 $f6 = $f[6]; 355 $f7 = $f[7]; 356 $f8 = $f[8]; 357 $f9 = $f[9]; 358 $g0 = $g[0]; 359 $g1 = $g[1]; 360 $g2 = $g[2]; 361 $g3 = $g[3]; 362 $g4 = $g[4]; 363 $g5 = $g[5]; 364 $g6 = $g[6]; 365 $g7 = $g[7]; 366 $g8 = $g[8]; 367 $g9 = $g[9]; 368 $g1_19 = self::mul($g1, 19, 5); 369 $g2_19 = self::mul($g2, 19, 5); 370 $g3_19 = self::mul($g3, 19, 5); 371 $g4_19 = self::mul($g4, 19, 5); 372 $g5_19 = self::mul($g5, 19, 5); 373 $g6_19 = self::mul($g6, 19, 5); 374 $g7_19 = self::mul($g7, 19, 5); 375 $g8_19 = self::mul($g8, 19, 5); 376 $g9_19 = self::mul($g9, 19, 5); 377 $f1_2 = $f1 << 1; 378 $f3_2 = $f3 << 1; 379 $f5_2 = $f5 << 1; 380 $f7_2 = $f7 << 1; 381 $f9_2 = $f9 << 1; 382 $f0g0 = self::mul($f0, $g0, 26); 383 $f0g1 = self::mul($f0, $g1, 25); 384 $f0g2 = self::mul($f0, $g2, 26); 385 $f0g3 = self::mul($f0, $g3, 25); 386 $f0g4 = self::mul($f0, $g4, 26); 387 $f0g5 = self::mul($f0, $g5, 25); 388 $f0g6 = self::mul($f0, $g6, 26); 389 $f0g7 = self::mul($f0, $g7, 25); 390 $f0g8 = self::mul($f0, $g8, 26); 391 $f0g9 = self::mul($f0, $g9, 26); 392 $f1g0 = self::mul($f1, $g0, 26); 393 $f1g1_2 = self::mul($f1_2, $g1, 25); 394 $f1g2 = self::mul($f1, $g2, 26); 395 $f1g3_2 = self::mul($f1_2, $g3, 25); 396 $f1g4 = self::mul($f1, $g4, 26); 397 $f1g5_2 = self::mul($f1_2, $g5, 25); 398 $f1g6 = self::mul($f1, $g6, 26); 399 $f1g7_2 = self::mul($f1_2, $g7, 25); 400 $f1g8 = self::mul($f1, $g8, 26); 401 $f1g9_38 = self::mul($g9_19, $f1_2, 26); 402 $f2g0 = self::mul($f2, $g0, 26); 403 $f2g1 = self::mul($f2, $g1, 25); 404 $f2g2 = self::mul($f2, $g2, 26); 405 $f2g3 = self::mul($f2, $g3, 25); 406 $f2g4 = self::mul($f2, $g4, 26); 407 $f2g5 = self::mul($f2, $g5, 25); 408 $f2g6 = self::mul($f2, $g6, 26); 409 $f2g7 = self::mul($f2, $g7, 25); 410 $f2g8_19 = self::mul($g8_19, $f2, 26); 411 $f2g9_19 = self::mul($g9_19, $f2, 26); 412 $f3g0 = self::mul($f3, $g0, 26); 413 $f3g1_2 = self::mul($f3_2, $g1, 25); 414 $f3g2 = self::mul($f3, $g2, 26); 415 $f3g3_2 = self::mul($f3_2, $g3, 25); 416 $f3g4 = self::mul($f3, $g4, 26); 417 $f3g5_2 = self::mul($f3_2, $g5, 25); 418 $f3g6 = self::mul($f3, $g6, 26); 419 $f3g7_38 = self::mul($g7_19, $f3_2, 26); 420 $f3g8_19 = self::mul($g8_19, $f3, 25); 421 $f3g9_38 = self::mul($g9_19, $f3_2, 26); 422 $f4g0 = self::mul($f4, $g0, 26); 423 $f4g1 = self::mul($f4, $g1, 25); 424 $f4g2 = self::mul($f4, $g2, 26); 425 $f4g3 = self::mul($f4, $g3, 25); 426 $f4g4 = self::mul($f4, $g4, 26); 427 $f4g5 = self::mul($f4, $g5, 25); 428 $f4g6_19 = self::mul($g6_19, $f4, 26); 429 $f4g7_19 = self::mul($g7_19, $f4, 26); 430 $f4g8_19 = self::mul($g8_19, $f4, 26); 431 $f4g9_19 = self::mul($g9_19, $f4, 26); 432 $f5g0 = self::mul($f5, $g0, 26); 433 $f5g1_2 = self::mul($f5_2, $g1, 25); 434 $f5g2 = self::mul($f5, $g2, 26); 435 $f5g3_2 = self::mul($f5_2, $g3, 25); 436 $f5g4 = self::mul($f5, $g4, 26); 437 $f5g5_38 = self::mul($g5_19, $f5_2, 26); 438 $f5g6_19 = self::mul($g6_19, $f5, 25); 439 $f5g7_38 = self::mul($g7_19, $f5_2, 26); 440 $f5g8_19 = self::mul($g8_19, $f5, 25); 441 $f5g9_38 = self::mul($g9_19, $f5_2, 26); 442 $f6g0 = self::mul($f6, $g0, 26); 443 $f6g1 = self::mul($f6, $g1, 25); 444 $f6g2 = self::mul($f6, $g2, 26); 445 $f6g3 = self::mul($f6, $g3, 25); 446 $f6g4_19 = self::mul($g4_19, $f6, 26); 447 $f6g5_19 = self::mul($g5_19, $f6, 26); 448 $f6g6_19 = self::mul($g6_19, $f6, 26); 449 $f6g7_19 = self::mul($g7_19, $f6, 26); 450 $f6g8_19 = self::mul($g8_19, $f6, 26); 451 $f6g9_19 = self::mul($g9_19, $f6, 26); 452 $f7g0 = self::mul($f7, $g0, 26); 453 $f7g1_2 = self::mul($f7_2, $g1, 25); 454 $f7g2 = self::mul($f7, $g2, 26); 455 $f7g3_38 = self::mul($g3_19, $f7_2, 26); 456 $f7g4_19 = self::mul($g4_19, $f7, 26); 457 $f7g5_38 = self::mul($g5_19, $f7_2, 26); 458 $f7g6_19 = self::mul($g6_19, $f7, 25); 459 $f7g7_38 = self::mul($g7_19, $f7_2, 26); 460 $f7g8_19 = self::mul($g8_19, $f7, 25); 461 $f7g9_38 = self::mul($g9_19,$f7_2, 26); 462 $f8g0 = self::mul($f8, $g0, 26); 463 $f8g1 = self::mul($f8, $g1, 25); 464 $f8g2_19 = self::mul($g2_19, $f8, 26); 465 $f8g3_19 = self::mul($g3_19, $f8, 26); 466 $f8g4_19 = self::mul($g4_19, $f8, 26); 467 $f8g5_19 = self::mul($g5_19, $f8, 26); 468 $f8g6_19 = self::mul($g6_19, $f8, 26); 469 $f8g7_19 = self::mul($g7_19, $f8, 26); 470 $f8g8_19 = self::mul($g8_19, $f8, 26); 471 $f8g9_19 = self::mul($g9_19, $f8, 26); 472 $f9g0 = self::mul($f9, $g0, 26); 473 $f9g1_38 = self::mul($g1_19, $f9_2, 26); 474 $f9g2_19 = self::mul($g2_19, $f9, 25); 475 $f9g3_38 = self::mul($g3_19, $f9_2, 26); 476 $f9g4_19 = self::mul($g4_19, $f9, 25); 477 $f9g5_38 = self::mul($g5_19, $f9_2, 26); 478 $f9g6_19 = self::mul($g6_19, $f9, 25); 479 $f9g7_38 = self::mul($g7_19, $f9_2, 26); 480 $f9g8_19 = self::mul($g8_19, $f9, 25); 481 $f9g9_38 = self::mul($g9_19, $f9_2, 26); 482 483 $h0 = $f0g0 + $f1g9_38 + $f2g8_19 + $f3g7_38 + $f4g6_19 + $f5g5_38 + $f6g4_19 + $f7g3_38 + $f8g2_19 + $f9g1_38; 484 $h1 = $f0g1 + $f1g0 + $f2g9_19 + $f3g8_19 + $f4g7_19 + $f5g6_19 + $f6g5_19 + $f7g4_19 + $f8g3_19 + $f9g2_19; 485 $h2 = $f0g2 + $f1g1_2 + $f2g0 + $f3g9_38 + $f4g8_19 + $f5g7_38 + $f6g6_19 + $f7g5_38 + $f8g4_19 + $f9g3_38; 486 $h3 = $f0g3 + $f1g2 + $f2g1 + $f3g0 + $f4g9_19 + $f5g8_19 + $f6g7_19 + $f7g6_19 + $f8g5_19 + $f9g4_19; 487 $h4 = $f0g4 + $f1g3_2 + $f2g2 + $f3g1_2 + $f4g0 + $f5g9_38 + $f6g8_19 + $f7g7_38 + $f8g6_19 + $f9g5_38; 488 $h5 = $f0g5 + $f1g4 + $f2g3 + $f3g2 + $f4g1 + $f5g0 + $f6g9_19 + $f7g8_19 + $f8g7_19 + $f9g6_19; 489 $h6 = $f0g6 + $f1g5_2 + $f2g4 + $f3g3_2 + $f4g2 + $f5g1_2 + $f6g0 + $f7g9_38 + $f8g8_19 + $f9g7_38; 490 $h7 = $f0g7 + $f1g6 + $f2g5 + $f3g4 + $f4g3 + $f5g2 + $f6g1 + $f7g0 + $f8g9_19 + $f9g8_19; 491 $h8 = $f0g8 + $f1g7_2 + $f2g6 + $f3g5_2 + $f4g4 + $f5g3_2 + $f6g2 + $f7g1_2 + $f8g0 + $f9g9_38; 492 $h9 = $f0g9 + $f1g8 + $f2g7 + $f3g6 + $f4g5 + $f5g4 + $f6g3 + $f7g2 + $f8g1 + $f9g0 ; 493 494 $carry0 = ($h0 + (1 << 25)) >> 26; 495 $h1 += $carry0; 496 $h0 -= $carry0 << 26; 497 $carry4 = ($h4 + (1 << 25)) >> 26; 498 $h5 += $carry4; 499 $h4 -= $carry4 << 26; 500 501 $carry1 = ($h1 + (1 << 24)) >> 25; 502 $h2 += $carry1; 503 $h1 -= $carry1 << 25; 504 $carry5 = ($h5 + (1 << 24)) >> 25; 505 $h6 += $carry5; 506 $h5 -= $carry5 << 25; 507 508 $carry2 = ($h2 + (1 << 25)) >> 26; 509 $h3 += $carry2; 510 $h2 -= $carry2 << 26; 511 $carry6 = ($h6 + (1 << 25)) >> 26; 512 $h7 += $carry6; 513 $h6 -= $carry6 << 26; 514 515 $carry3 = ($h3 + (1 << 24)) >> 25; 516 $h4 += $carry3; 517 $h3 -= $carry3 << 25; 518 $carry7 = ($h7 + (1 << 24)) >> 25; 519 $h8 += $carry7; 520 $h7 -= $carry7 << 25; 521 522 $carry4 = ($h4 + (1 << 25)) >> 26; 523 $h5 += $carry4; 524 $h4 -= $carry4 << 26; 525 $carry8 = ($h8 + (1 << 25)) >> 26; 526 $h9 += $carry8; 527 $h8 -= $carry8 << 26; 528 529 $carry9 = ($h9 + (1 << 24)) >> 25; 530 $h0 += self::mul($carry9, 19, 5); 531 $h9 -= $carry9 << 25; 532 533 $carry0 = ($h0 + (1 << 25)) >> 26; 534 $h1 += $carry0; 535 $h0 -= $carry0 << 26; 536 537 return self::fe_normalize( 538 ParagonIE_Sodium_Core_Curve25519_Fe::fromArray( 539 array( 540 (int) $h0, 541 (int) $h1, 542 (int) $h2, 543 (int) $h3, 544 (int) $h4, 545 (int) $h5, 546 (int) $h6, 547 (int) $h7, 548 (int) $h8, 549 (int) $h9 550 ) 551 ) 552 ); 553 } 554 555 /** 556 * Get the negative values for each piece of the field element. 557 * 558 * h = -f 559 * 560 * @internal You should not use this directly from another application 561 * 562 * @param ParagonIE_Sodium_Core_Curve25519_Fe $f 563 * @return ParagonIE_Sodium_Core_Curve25519_Fe 564 * @psalm-suppress MixedAssignment 565 */ 566 public static function fe_neg(ParagonIE_Sodium_Core_Curve25519_Fe $f) 567 { 568 $h = new ParagonIE_Sodium_Core_Curve25519_Fe(); 569 for ($i = 0; $i < 10; ++$i) { 570 $h[$i] = -$f[$i]; 571 } 572 return self::fe_normalize($h); 573 } 574 575 /** 576 * Square a field element 577 * 578 * h = f * f 579 * 580 * @internal You should not use this directly from another application 581 * 582 * @param ParagonIE_Sodium_Core_Curve25519_Fe $f 583 * @return ParagonIE_Sodium_Core_Curve25519_Fe 584 */ 585 public static function fe_sq(ParagonIE_Sodium_Core_Curve25519_Fe $f) 586 { 587 $f = self::fe_normalize($f); 588 $f0 = (int) $f[0]; 589 $f1 = (int) $f[1]; 590 $f2 = (int) $f[2]; 591 $f3 = (int) $f[3]; 592 $f4 = (int) $f[4]; 593 $f5 = (int) $f[5]; 594 $f6 = (int) $f[6]; 595 $f7 = (int) $f[7]; 596 $f8 = (int) $f[8]; 597 $f9 = (int) $f[9]; 598 599 $f0_2 = $f0 << 1; 600 $f1_2 = $f1 << 1; 601 $f2_2 = $f2 << 1; 602 $f3_2 = $f3 << 1; 603 $f4_2 = $f4 << 1; 604 $f5_2 = $f5 << 1; 605 $f6_2 = $f6 << 1; 606 $f7_2 = $f7 << 1; 607 $f5_38 = self::mul($f5, 38, 6); 608 $f6_19 = self::mul($f6, 19, 5); 609 $f7_38 = self::mul($f7, 38, 6); 610 $f8_19 = self::mul($f8, 19, 5); 611 $f9_38 = self::mul($f9, 38, 6); 612 $f0f0 = self::mul($f0, $f0, 26); 613 $f0f1_2 = self::mul($f0_2, $f1, 26); 614 $f0f2_2 = self::mul($f0_2, $f2, 26); 615 $f0f3_2 = self::mul($f0_2, $f3, 26); 616 $f0f4_2 = self::mul($f0_2, $f4, 26); 617 $f0f5_2 = self::mul($f0_2, $f5, 26); 618 $f0f6_2 = self::mul($f0_2, $f6, 26); 619 $f0f7_2 = self::mul($f0_2, $f7, 26); 620 $f0f8_2 = self::mul($f0_2, $f8, 26); 621 $f0f9_2 = self::mul($f0_2, $f9, 26); 622 $f1f1_2 = self::mul($f1_2, $f1, 26); 623 $f1f2_2 = self::mul($f1_2, $f2, 26); 624 $f1f3_4 = self::mul($f1_2, $f3_2, 26); 625 $f1f4_2 = self::mul($f1_2, $f4, 26); 626 $f1f5_4 = self::mul($f1_2, $f5_2, 26); 627 $f1f6_2 = self::mul($f1_2, $f6, 26); 628 $f1f7_4 = self::mul($f1_2, $f7_2, 26); 629 $f1f8_2 = self::mul($f1_2, $f8, 26); 630 $f1f9_76 = self::mul($f9_38, $f1_2, 27); 631 $f2f2 = self::mul($f2, $f2, 27); 632 $f2f3_2 = self::mul($f2_2, $f3, 27); 633 $f2f4_2 = self::mul($f2_2, $f4, 27); 634 $f2f5_2 = self::mul($f2_2, $f5, 27); 635 $f2f6_2 = self::mul($f2_2, $f6, 27); 636 $f2f7_2 = self::mul($f2_2, $f7, 27); 637 $f2f8_38 = self::mul($f8_19, $f2_2, 27); 638 $f2f9_38 = self::mul($f9_38, $f2, 26); 639 $f3f3_2 = self::mul($f3_2, $f3, 26); 640 $f3f4_2 = self::mul($f3_2, $f4, 26); 641 $f3f5_4 = self::mul($f3_2, $f5_2, 26); 642 $f3f6_2 = self::mul($f3_2, $f6, 26); 643 $f3f7_76 = self::mul($f7_38, $f3_2, 26); 644 $f3f8_38 = self::mul($f8_19, $f3_2, 26); 645 $f3f9_76 = self::mul($f9_38, $f3_2, 26); 646 $f4f4 = self::mul($f4, $f4, 26); 647 $f4f5_2 = self::mul($f4_2, $f5, 26); 648 $f4f6_38 = self::mul($f6_19, $f4_2, 27); 649 $f4f7_38 = self::mul($f7_38, $f4, 26); 650 $f4f8_38 = self::mul($f8_19, $f4_2, 27); 651 $f4f9_38 = self::mul($f9_38, $f4, 26); 652 $f5f5_38 = self::mul($f5_38, $f5, 26); 653 $f5f6_38 = self::mul($f6_19, $f5_2, 26); 654 $f5f7_76 = self::mul($f7_38, $f5_2, 26); 655 $f5f8_38 = self::mul($f8_19, $f5_2, 26); 656 $f5f9_76 = self::mul($f9_38, $f5_2, 26); 657 $f6f6_19 = self::mul($f6_19, $f6, 26); 658 $f6f7_38 = self::mul($f7_38, $f6, 26); 659 $f6f8_38 = self::mul($f8_19, $f6_2, 27); 660 $f6f9_38 = self::mul($f9_38, $f6, 26); 661 $f7f7_38 = self::mul($f7_38, $f7, 26); 662 $f7f8_38 = self::mul($f8_19, $f7_2, 26); 663 $f7f9_76 = self::mul($f9_38, $f7_2, 26); 664 $f8f8_19 = self::mul($f8_19, $f8, 26); 665 $f8f9_38 = self::mul($f9_38, $f8, 26); 666 $f9f9_38 = self::mul($f9_38, $f9, 26); 667 $h0 = $f0f0 + $f1f9_76 + $f2f8_38 + $f3f7_76 + $f4f6_38 + $f5f5_38; 668 $h1 = $f0f1_2 + $f2f9_38 + $f3f8_38 + $f4f7_38 + $f5f6_38; 669 $h2 = $f0f2_2 + $f1f1_2 + $f3f9_76 + $f4f8_38 + $f5f7_76 + $f6f6_19; 670 $h3 = $f0f3_2 + $f1f2_2 + $f4f9_38 + $f5f8_38 + $f6f7_38; 671 $h4 = $f0f4_2 + $f1f3_4 + $f2f2 + $f5f9_76 + $f6f8_38 + $f7f7_38; 672 $h5 = $f0f5_2 + $f1f4_2 + $f2f3_2 + $f6f9_38 + $f7f8_38; 673 $h6 = $f0f6_2 + $f1f5_4 + $f2f4_2 + $f3f3_2 + $f7f9_76 + $f8f8_19; 674 $h7 = $f0f7_2 + $f1f6_2 + $f2f5_2 + $f3f4_2 + $f8f9_38; 675 $h8 = $f0f8_2 + $f1f7_4 + $f2f6_2 + $f3f5_4 + $f4f4 + $f9f9_38; 676 $h9 = $f0f9_2 + $f1f8_2 + $f2f7_2 + $f3f6_2 + $f4f5_2; 677 678 $carry0 = ($h0 + (1 << 25)) >> 26; 679 $h1 += $carry0; 680 $h0 -= $carry0 << 26; 681 $carry4 = ($h4 + (1 << 25)) >> 26; 682 $h5 += $carry4; 683 $h4 -= $carry4 << 26; 684 685 $carry1 = ($h1 + (1 << 24)) >> 25; 686 $h2 += $carry1; 687 $h1 -= $carry1 << 25; 688 $carry5 = ($h5 + (1 << 24)) >> 25; 689 $h6 += $carry5; 690 $h5 -= $carry5 << 25; 691 692 $carry2 = ($h2 + (1 << 25)) >> 26; 693 $h3 += $carry2; 694 $h2 -= $carry2 << 26; 695 $carry6 = ($h6 + (1 << 25)) >> 26; 696 $h7 += $carry6; 697 $h6 -= $carry6 << 26; 698 699 $carry3 = ($h3 + (1 << 24)) >> 25; 700 $h4 += $carry3; 701 $h3 -= $carry3 << 25; 702 $carry7 = ($h7 + (1 << 24)) >> 25; 703 $h8 += $carry7; 704 $h7 -= $carry7 << 25; 705 706 $carry4 = ($h4 + (1 << 25)) >> 26; 707 $h5 += $carry4; 708 $h4 -= $carry4 << 26; 709 $carry8 = ($h8 + (1 << 25)) >> 26; 710 $h9 += $carry8; 711 $h8 -= $carry8 << 26; 712 713 $carry9 = ($h9 + (1 << 24)) >> 25; 714 $h0 += self::mul($carry9, 19, 5); 715 $h9 -= $carry9 << 25; 716 717 $carry0 = ($h0 + (1 << 25)) >> 26; 718 $h1 += $carry0; 719 $h0 -= $carry0 << 26; 720 721 return self::fe_normalize( 722 ParagonIE_Sodium_Core_Curve25519_Fe::fromArray( 723 array( 724 (int) $h0, 725 (int) $h1, 726 (int) $h2, 727 (int) $h3, 728 (int) $h4, 729 (int) $h5, 730 (int) $h6, 731 (int) $h7, 732 (int) $h8, 733 (int) $h9 734 ) 735 ) 736 ); 737 } 738 739 740 /** 741 * Square and double a field element 742 * 743 * h = 2 * f * f 744 * 745 * @internal You should not use this directly from another application 746 * 747 * @param ParagonIE_Sodium_Core_Curve25519_Fe $f 748 * @return ParagonIE_Sodium_Core_Curve25519_Fe 749 */ 750 public static function fe_sq2(ParagonIE_Sodium_Core_Curve25519_Fe $f) 751 { 752 $f = self::fe_normalize($f); 753 $f0 = (int) $f[0]; 754 $f1 = (int) $f[1]; 755 $f2 = (int) $f[2]; 756 $f3 = (int) $f[3]; 757 $f4 = (int) $f[4]; 758 $f5 = (int) $f[5]; 759 $f6 = (int) $f[6]; 760 $f7 = (int) $f[7]; 761 $f8 = (int) $f[8]; 762 $f9 = (int) $f[9]; 763 764 $f0_2 = $f0 << 1; 765 $f1_2 = $f1 << 1; 766 $f2_2 = $f2 << 1; 767 $f3_2 = $f3 << 1; 768 $f4_2 = $f4 << 1; 769 $f5_2 = $f5 << 1; 770 $f6_2 = $f6 << 1; 771 $f7_2 = $f7 << 1; 772 $f5_38 = self::mul($f5, 38, 6); /* 1.959375*2^30 */ 773 $f6_19 = self::mul($f6, 19, 5); /* 1.959375*2^30 */ 774 $f7_38 = self::mul($f7, 38, 6); /* 1.959375*2^30 */ 775 $f8_19 = self::mul($f8, 19, 5); /* 1.959375*2^30 */ 776 $f9_38 = self::mul($f9, 38, 6); /* 1.959375*2^30 */ 777 $f0f0 = self::mul($f0, $f0, 24); 778 $f0f1_2 = self::mul($f0_2, $f1, 24); 779 $f0f2_2 = self::mul($f0_2, $f2, 24); 780 $f0f3_2 = self::mul($f0_2, $f3, 24); 781 $f0f4_2 = self::mul($f0_2, $f4, 24); 782 $f0f5_2 = self::mul($f0_2, $f5, 24); 783 $f0f6_2 = self::mul($f0_2, $f6, 24); 784 $f0f7_2 = self::mul($f0_2, $f7, 24); 785 $f0f8_2 = self::mul($f0_2, $f8, 24); 786 $f0f9_2 = self::mul($f0_2, $f9, 24); 787 $f1f1_2 = self::mul($f1_2, $f1, 24); 788 $f1f2_2 = self::mul($f1_2, $f2, 24); 789 $f1f3_4 = self::mul($f1_2, $f3_2, 24); 790 $f1f4_2 = self::mul($f1_2, $f4, 24); 791 $f1f5_4 = self::mul($f1_2, $f5_2, 24); 792 $f1f6_2 = self::mul($f1_2, $f6, 24); 793 $f1f7_4 = self::mul($f1_2, $f7_2, 24); 794 $f1f8_2 = self::mul($f1_2, $f8, 24); 795 $f1f9_76 = self::mul($f9_38, $f1_2, 24); 796 $f2f2 = self::mul($f2, $f2, 24); 797 $f2f3_2 = self::mul($f2_2, $f3, 24); 798 $f2f4_2 = self::mul($f2_2, $f4, 24); 799 $f2f5_2 = self::mul($f2_2, $f5, 24); 800 $f2f6_2 = self::mul($f2_2, $f6, 24); 801 $f2f7_2 = self::mul($f2_2, $f7, 24); 802 $f2f8_38 = self::mul($f8_19, $f2_2, 25); 803 $f2f9_38 = self::mul($f9_38, $f2, 24); 804 $f3f3_2 = self::mul($f3_2, $f3, 24); 805 $f3f4_2 = self::mul($f3_2, $f4, 24); 806 $f3f5_4 = self::mul($f3_2, $f5_2, 24); 807 $f3f6_2 = self::mul($f3_2, $f6, 24); 808 $f3f7_76 = self::mul($f7_38, $f3_2, 24); 809 $f3f8_38 = self::mul($f8_19, $f3_2, 24); 810 $f3f9_76 = self::mul($f9_38, $f3_2, 24); 811 $f4f4 = self::mul($f4, $f4, 24); 812 $f4f5_2 = self::mul($f4_2, $f5, 24); 813 $f4f6_38 = self::mul($f6_19, $f4_2, 25); 814 $f4f7_38 = self::mul($f7_38, $f4, 24); 815 $f4f8_38 = self::mul($f8_19, $f4_2, 25); 816 $f4f9_38 = self::mul($f9_38, $f4, 24); 817 $f5f5_38 = self::mul($f5_38, $f5, 24); 818 $f5f6_38 = self::mul($f6_19, $f5_2, 24); 819 $f5f7_76 = self::mul($f7_38, $f5_2, 24); 820 $f5f8_38 = self::mul($f8_19, $f5_2, 24); 821 $f5f9_76 = self::mul($f9_38, $f5_2, 24); 822 $f6f6_19 = self::mul($f6_19, $f6, 24); 823 $f6f7_38 = self::mul($f7_38, $f6, 24); 824 $f6f8_38 = self::mul($f8_19, $f6_2, 25); 825 $f6f9_38 = self::mul($f9_38, $f6, 24); 826 $f7f7_38 = self::mul($f7_38, $f7, 24); 827 $f7f8_38 = self::mul($f8_19, $f7_2, 24); 828 $f7f9_76 = self::mul($f9_38, $f7_2, 24); 829 $f8f8_19 = self::mul($f8_19, $f8, 24); 830 $f8f9_38 = self::mul($f9_38, $f8, 24); 831 $f9f9_38 = self::mul($f9_38, $f9, 24); 832 833 $h0 = (int) ($f0f0 + $f1f9_76 + $f2f8_38 + $f3f7_76 + $f4f6_38 + $f5f5_38) << 1; 834 $h1 = (int) ($f0f1_2 + $f2f9_38 + $f3f8_38 + $f4f7_38 + $f5f6_38) << 1; 835 $h2 = (int) ($f0f2_2 + $f1f1_2 + $f3f9_76 + $f4f8_38 + $f5f7_76 + $f6f6_19) << 1; 836 $h3 = (int) ($f0f3_2 + $f1f2_2 + $f4f9_38 + $f5f8_38 + $f6f7_38) << 1; 837 $h4 = (int) ($f0f4_2 + $f1f3_4 + $f2f2 + $f5f9_76 + $f6f8_38 + $f7f7_38) << 1; 838 $h5 = (int) ($f0f5_2 + $f1f4_2 + $f2f3_2 + $f6f9_38 + $f7f8_38) << 1; 839 $h6 = (int) ($f0f6_2 + $f1f5_4 + $f2f4_2 + $f3f3_2 + $f7f9_76 + $f8f8_19) << 1; 840 $h7 = (int) ($f0f7_2 + $f1f6_2 + $f2f5_2 + $f3f4_2 + $f8f9_38) << 1; 841 $h8 = (int) ($f0f8_2 + $f1f7_4 + $f2f6_2 + $f3f5_4 + $f4f4 + $f9f9_38) << 1; 842 $h9 = (int) ($f0f9_2 + $f1f8_2 + $f2f7_2 + $f3f6_2 + $f4f5_2) << 1; 843 844 $carry0 = ($h0 + (1 << 25)) >> 26; 845 $h1 += $carry0; 846 $h0 -= $carry0 << 26; 847 $carry4 = ($h4 + (1 << 25)) >> 26; 848 $h5 += $carry4; 849 $h4 -= $carry4 << 26; 850 851 $carry1 = ($h1 + (1 << 24)) >> 25; 852 $h2 += $carry1; 853 $h1 -= $carry1 << 25; 854 $carry5 = ($h5 + (1 << 24)) >> 25; 855 $h6 += $carry5; 856 $h5 -= $carry5 << 25; 857 858 $carry2 = ($h2 + (1 << 25)) >> 26; 859 $h3 += $carry2; 860 $h2 -= $carry2 << 26; 861 $carry6 = ($h6 + (1 << 25)) >> 26; 862 $h7 += $carry6; 863 $h6 -= $carry6 << 26; 864 865 $carry3 = ($h3 + (1 << 24)) >> 25; 866 $h4 += $carry3; 867 $h3 -= $carry3 << 25; 868 $carry7 = ($h7 + (1 << 24)) >> 25; 869 $h8 += $carry7; 870 $h7 -= $carry7 << 25; 871 872 $carry4 = ($h4 + (1 << 25)) >> 26; 873 $h5 += $carry4; 874 $h4 -= $carry4 << 26; 875 $carry8 = ($h8 + (1 << 25)) >> 26; 876 $h9 += $carry8; 877 $h8 -= $carry8 << 26; 878 879 $carry9 = ($h9 + (1 << 24)) >> 25; 880 $h0 += self::mul($carry9, 19, 5); 881 $h9 -= $carry9 << 25; 882 883 $carry0 = ($h0 + (1 << 25)) >> 26; 884 $h1 += $carry0; 885 $h0 -= $carry0 << 26; 886 887 return self::fe_normalize( 888 ParagonIE_Sodium_Core_Curve25519_Fe::fromArray( 889 array( 890 (int) $h0, 891 (int) $h1, 892 (int) $h2, 893 (int) $h3, 894 (int) $h4, 895 (int) $h5, 896 (int) $h6, 897 (int) $h7, 898 (int) $h8, 899 (int) $h9 900 ) 901 ) 902 ); 903 } 904 905 /** 906 * @internal You should not use this directly from another application 907 * 908 * @param ParagonIE_Sodium_Core_Curve25519_Fe $Z 909 * @return ParagonIE_Sodium_Core_Curve25519_Fe 910 */ 911 public static function fe_invert(ParagonIE_Sodium_Core_Curve25519_Fe $Z) 912 { 913 $z = clone $Z; 914 $t0 = self::fe_sq($z); 915 $t1 = self::fe_sq($t0); 916 $t1 = self::fe_sq($t1); 917 $t1 = self::fe_mul($z, $t1); 918 $t0 = self::fe_mul($t0, $t1); 919 $t2 = self::fe_sq($t0); 920 $t1 = self::fe_mul($t1, $t2); 921 $t2 = self::fe_sq($t1); 922 for ($i = 1; $i < 5; ++$i) { 923 $t2 = self::fe_sq($t2); 924 } 925 $t1 = self::fe_mul($t2, $t1); 926 $t2 = self::fe_sq($t1); 927 for ($i = 1; $i < 10; ++$i) { 928 $t2 = self::fe_sq($t2); 929 } 930 $t2 = self::fe_mul($t2, $t1); 931 $t3 = self::fe_sq($t2); 932 for ($i = 1; $i < 20; ++$i) { 933 $t3 = self::fe_sq($t3); 934 } 935 $t2 = self::fe_mul($t3, $t2); 936 $t2 = self::fe_sq($t2); 937 for ($i = 1; $i < 10; ++$i) { 938 $t2 = self::fe_sq($t2); 939 } 940 $t1 = self::fe_mul($t2, $t1); 941 $t2 = self::fe_sq($t1); 942 for ($i = 1; $i < 50; ++$i) { 943 $t2 = self::fe_sq($t2); 944 } 945 $t2 = self::fe_mul($t2, $t1); 946 $t3 = self::fe_sq($t2); 947 for ($i = 1; $i < 100; ++$i) { 948 $t3 = self::fe_sq($t3); 949 } 950 $t2 = self::fe_mul($t3, $t2); 951 $t2 = self::fe_sq($t2); 952 for ($i = 1; $i < 50; ++$i) { 953 $t2 = self::fe_sq($t2); 954 } 955 $t1 = self::fe_mul($t2, $t1); 956 $t1 = self::fe_sq($t1); 957 for ($i = 1; $i < 5; ++$i) { 958 $t1 = self::fe_sq($t1); 959 } 960 return self::fe_mul($t1, $t0); 961 } 962 963 /** 964 * @internal You should not use this directly from another application 965 * 966 * @ref https://github.com/jedisct1/libsodium/blob/68564326e1e9dc57ef03746f85734232d20ca6fb/src/libsodium/crypto_core/curve25519/ref10/curve25519_ref10.c#L1054-L1106 967 * 968 * @param ParagonIE_Sodium_Core_Curve25519_Fe $z 969 * @return ParagonIE_Sodium_Core_Curve25519_Fe 970 */ 971 public static function fe_pow22523(ParagonIE_Sodium_Core_Curve25519_Fe $z) 972 { 973 $z = self::fe_normalize($z); 974 # fe_sq(t0, z); 975 # fe_sq(t1, t0); 976 # fe_sq(t1, t1); 977 # fe_mul(t1, z, t1); 978 # fe_mul(t0, t0, t1); 979 # fe_sq(t0, t0); 980 # fe_mul(t0, t1, t0); 981 # fe_sq(t1, t0); 982 $t0 = self::fe_sq($z); 983 $t1 = self::fe_sq($t0); 984 $t1 = self::fe_sq($t1); 985 $t1 = self::fe_mul($z, $t1); 986 $t0 = self::fe_mul($t0, $t1); 987 $t0 = self::fe_sq($t0); 988 $t0 = self::fe_mul($t1, $t0); 989 $t1 = self::fe_sq($t0); 990 991 # for (i = 1; i < 5; ++i) { 992 # fe_sq(t1, t1); 993 # } 994 for ($i = 1; $i < 5; ++$i) { 995 $t1 = self::fe_sq($t1); 996 } 997 998 # fe_mul(t0, t1, t0); 999 # fe_sq(t1, t0); 1000 $t0 = self::fe_mul($t1, $t0); 1001 $t1 = self::fe_sq($t0); 1002 1003 # for (i = 1; i < 10; ++i) { 1004 # fe_sq(t1, t1); 1005 # } 1006 for ($i = 1; $i < 10; ++$i) { 1007 $t1 = self::fe_sq($t1); 1008 } 1009 1010 # fe_mul(t1, t1, t0); 1011 # fe_sq(t2, t1); 1012 $t1 = self::fe_mul($t1, $t0); 1013 $t2 = self::fe_sq($t1); 1014 1015 # for (i = 1; i < 20; ++i) { 1016 # fe_sq(t2, t2); 1017 # } 1018 for ($i = 1; $i < 20; ++$i) { 1019 $t2 = self::fe_sq($t2); 1020 } 1021 1022 # fe_mul(t1, t2, t1); 1023 # fe_sq(t1, t1); 1024 $t1 = self::fe_mul($t2, $t1); 1025 $t1 = self::fe_sq($t1); 1026 1027 # for (i = 1; i < 10; ++i) { 1028 # fe_sq(t1, t1); 1029 # } 1030 for ($i = 1; $i < 10; ++$i) { 1031 $t1 = self::fe_sq($t1); 1032 } 1033 1034 # fe_mul(t0, t1, t0); 1035 # fe_sq(t1, t0); 1036 $t0 = self::fe_mul($t1, $t0); 1037 $t1 = self::fe_sq($t0); 1038 1039 # for (i = 1; i < 50; ++i) { 1040 # fe_sq(t1, t1); 1041 # } 1042 for ($i = 1; $i < 50; ++$i) { 1043 $t1 = self::fe_sq($t1); 1044 } 1045 1046 # fe_mul(t1, t1, t0); 1047 # fe_sq(t2, t1); 1048 $t1 = self::fe_mul($t1, $t0); 1049 $t2 = self::fe_sq($t1); 1050 1051 # for (i = 1; i < 100; ++i) { 1052 # fe_sq(t2, t2); 1053 # } 1054 for ($i = 1; $i < 100; ++$i) { 1055 $t2 = self::fe_sq($t2); 1056 } 1057 1058 # fe_mul(t1, t2, t1); 1059 # fe_sq(t1, t1); 1060 $t1 = self::fe_mul($t2, $t1); 1061 $t1 = self::fe_sq($t1); 1062 1063 # for (i = 1; i < 50; ++i) { 1064 # fe_sq(t1, t1); 1065 # } 1066 for ($i = 1; $i < 50; ++$i) { 1067 $t1 = self::fe_sq($t1); 1068 } 1069 1070 # fe_mul(t0, t1, t0); 1071 # fe_sq(t0, t0); 1072 # fe_sq(t0, t0); 1073 # fe_mul(out, t0, z); 1074 $t0 = self::fe_mul($t1, $t0); 1075 $t0 = self::fe_sq($t0); 1076 $t0 = self::fe_sq($t0); 1077 return self::fe_mul($t0, $z); 1078 } 1079 1080 /** 1081 * Subtract two field elements. 1082 * 1083 * h = f - g 1084 * 1085 * Preconditions: 1086 * |f| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc. 1087 * |g| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc. 1088 * 1089 * Postconditions: 1090 * |h| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc. 1091 * 1092 * @internal You should not use this directly from another application 1093 * 1094 * @param ParagonIE_Sodium_Core_Curve25519_Fe $f 1095 * @param ParagonIE_Sodium_Core_Curve25519_Fe $g 1096 * @return ParagonIE_Sodium_Core_Curve25519_Fe 1097 * @psalm-suppress MixedOperand 1098 */ 1099 public static function fe_sub(ParagonIE_Sodium_Core_Curve25519_Fe $f, ParagonIE_Sodium_Core_Curve25519_Fe $g) 1100 { 1101 return self::fe_normalize( 1102 ParagonIE_Sodium_Core_Curve25519_Fe::fromArray( 1103 array( 1104 (int) ($f[0] - $g[0]), 1105 (int) ($f[1] - $g[1]), 1106 (int) ($f[2] - $g[2]), 1107 (int) ($f[3] - $g[3]), 1108 (int) ($f[4] - $g[4]), 1109 (int) ($f[5] - $g[5]), 1110 (int) ($f[6] - $g[6]), 1111 (int) ($f[7] - $g[7]), 1112 (int) ($f[8] - $g[8]), 1113 (int) ($f[9] - $g[9]) 1114 ) 1115 ) 1116 ); 1117 } 1118 1119 /** 1120 * Add two group elements. 1121 * 1122 * r = p + q 1123 * 1124 * @internal You should not use this directly from another application 1125 * 1126 * @param ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p 1127 * @param ParagonIE_Sodium_Core_Curve25519_Ge_Cached $q 1128 * @return ParagonIE_Sodium_Core_Curve25519_Ge_P1p1 1129 */ 1130 public static function ge_add( 1131 ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p, 1132 ParagonIE_Sodium_Core_Curve25519_Ge_Cached $q 1133 ) { 1134 $r = new ParagonIE_Sodium_Core_Curve25519_Ge_P1p1(); 1135 $r->X = self::fe_add($p->Y, $p->X); 1136 $r->Y = self::fe_sub($p->Y, $p->X); 1137 $r->Z = self::fe_mul($r->X, $q->YplusX); 1138 $r->Y = self::fe_mul($r->Y, $q->YminusX); 1139 $r->T = self::fe_mul($q->T2d, $p->T); 1140 $r->X = self::fe_mul($p->Z, $q->Z); 1141 $t0 = self::fe_add($r->X, $r->X); 1142 $r->X = self::fe_sub($r->Z, $r->Y); 1143 $r->Y = self::fe_add($r->Z, $r->Y); 1144 $r->Z = self::fe_add($t0, $r->T); 1145 $r->T = self::fe_sub($t0, $r->T); 1146 return $r; 1147 } 1148 1149 /** 1150 * @internal You should not use this directly from another application 1151 * 1152 * @ref https://github.com/jedisct1/libsodium/blob/157c4a80c13b117608aeae12178b2d38825f9f8f/src/libsodium/crypto_core/curve25519/ref10/curve25519_ref10.c#L1185-L1215 1153 * @param string $a 1154 * @return array<int, mixed> 1155 * @throws SodiumException 1156 * @throws TypeError 1157 */ 1158 public static function slide($a) 1159 { 1160 if (self::strlen($a) < 256) { 1161 if (self::strlen($a) < 16) { 1162 $a = str_pad($a, 256, '0', STR_PAD_RIGHT); 1163 } 1164 } 1165 /** @var array<int, int> $r */ 1166 $r = array(); 1167 1168 /** @var int $i */ 1169 for ($i = 0; $i < 256; ++$i) { 1170 $r[$i] = (int) ( 1171 1 & ( 1172 self::chrToInt($a[(int) ($i >> 3)]) 1173 >> 1174 ($i & 7) 1175 ) 1176 ); 1177 } 1178 1179 for ($i = 0;$i < 256;++$i) { 1180 if ($r[$i]) { 1181 for ($b = 1;$b <= 6 && $i + $b < 256;++$b) { 1182 if ($r[$i + $b]) { 1183 if ($r[$i] + ($r[$i + $b] << $b) <= 15) { 1184 $r[$i] += $r[$i + $b] << $b; 1185 $r[$i + $b] = 0; 1186 } elseif ($r[$i] - ($r[$i + $b] << $b) >= -15) { 1187 $r[$i] -= $r[$i + $b] << $b; 1188 for ($k = $i + $b; $k < 256; ++$k) { 1189 if (!$r[$k]) { 1190 $r[$k] = 1; 1191 break; 1192 } 1193 $r[$k] = 0; 1194 } 1195 } else { 1196 break; 1197 } 1198 } 1199 } 1200 } 1201 } 1202 return $r; 1203 } 1204 1205 /** 1206 * @internal You should not use this directly from another application 1207 * 1208 * @param string $s 1209 * @return ParagonIE_Sodium_Core_Curve25519_Ge_P3 1210 * @throws SodiumException 1211 * @throws TypeError 1212 */ 1213 public static function ge_frombytes_negate_vartime($s) 1214 { 1215 static $d = null; 1216 if (!$d) { 1217 $d = ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(self::$d); 1218 } 1219 1220 # fe_frombytes(h->Y,s); 1221 # fe_1(h->Z); 1222 $h = new ParagonIE_Sodium_Core_Curve25519_Ge_P3( 1223 self::fe_0(), 1224 self::fe_frombytes($s), 1225 self::fe_1() 1226 ); 1227 1228 # fe_sq(u,h->Y); 1229 # fe_mul(v,u,d); 1230 # fe_sub(u,u,h->Z); /* u = y^2-1 */ 1231 # fe_add(v,v,h->Z); /* v = dy^2+1 */ 1232 $u = self::fe_sq($h->Y); 1233 /** @var ParagonIE_Sodium_Core_Curve25519_Fe $d */ 1234 $v = self::fe_mul($u, $d); 1235 $u = self::fe_sub($u, $h->Z); /* u = y^2 - 1 */ 1236 $v = self::fe_add($v, $h->Z); /* v = dy^2 + 1 */ 1237 1238 # fe_sq(v3,v); 1239 # fe_mul(v3,v3,v); /* v3 = v^3 */ 1240 # fe_sq(h->X,v3); 1241 # fe_mul(h->X,h->X,v); 1242 # fe_mul(h->X,h->X,u); /* x = uv^7 */ 1243 $v3 = self::fe_sq($v); 1244 $v3 = self::fe_mul($v3, $v); /* v3 = v^3 */ 1245 $h->X = self::fe_sq($v3); 1246 $h->X = self::fe_mul($h->X, $v); 1247 $h->X = self::fe_mul($h->X, $u); /* x = uv^7 */ 1248 1249 # fe_pow22523(h->X,h->X); /* x = (uv^7)^((q-5)/8) */ 1250 # fe_mul(h->X,h->X,v3); 1251 # fe_mul(h->X,h->X,u); /* x = uv^3(uv^7)^((q-5)/8) */ 1252 $h->X = self::fe_pow22523($h->X); /* x = (uv^7)^((q-5)/8) */ 1253 $h->X = self::fe_mul($h->X, $v3); 1254 $h->X = self::fe_mul($h->X, $u); /* x = uv^3(uv^7)^((q-5)/8) */ 1255 1256 # fe_sq(vxx,h->X); 1257 # fe_mul(vxx,vxx,v); 1258 # fe_sub(check,vxx,u); /* vx^2-u */ 1259 $vxx = self::fe_sq($h->X); 1260 $vxx = self::fe_mul($vxx, $v); 1261 $check = self::fe_sub($vxx, $u); /* vx^2 - u */ 1262 1263 # if (fe_isnonzero(check)) { 1264 # fe_add(check,vxx,u); /* vx^2+u */ 1265 # if (fe_isnonzero(check)) { 1266 # return -1; 1267 # } 1268 # fe_mul(h->X,h->X,sqrtm1); 1269 # } 1270 if (self::fe_isnonzero($check)) { 1271 $check = self::fe_add($vxx, $u); /* vx^2 + u */ 1272 if (self::fe_isnonzero($check)) { 1273 throw new RangeException('Internal check failed.'); 1274 } 1275 $h->X = self::fe_mul( 1276 $h->X, 1277 ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(self::$sqrtm1) 1278 ); 1279 } 1280 1281 # if (fe_isnegative(h->X) == (s[31] >> 7)) { 1282 # fe_neg(h->X,h->X); 1283 # } 1284 $i = self::chrToInt($s[31]); 1285 if (self::fe_isnegative($h->X) === ($i >> 7)) { 1286 $h->X = self::fe_neg($h->X); 1287 } 1288 1289 # fe_mul(h->T,h->X,h->Y); 1290 $h->T = self::fe_mul($h->X, $h->Y); 1291 return $h; 1292 } 1293 1294 /** 1295 * @internal You should not use this directly from another application 1296 * 1297 * @param ParagonIE_Sodium_Core_Curve25519_Ge_P1p1 $R 1298 * @param ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p 1299 * @param ParagonIE_Sodium_Core_Curve25519_Ge_Precomp $q 1300 * @return ParagonIE_Sodium_Core_Curve25519_Ge_P1p1 1301 */ 1302 public static function ge_madd( 1303 ParagonIE_Sodium_Core_Curve25519_Ge_P1p1 $R, 1304 ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p, 1305 ParagonIE_Sodium_Core_Curve25519_Ge_Precomp $q 1306 ) { 1307 $r = clone $R; 1308 $r->X = self::fe_add($p->Y, $p->X); 1309 $r->Y = self::fe_sub($p->Y, $p->X); 1310 $r->Z = self::fe_mul($r->X, $q->yplusx); 1311 $r->Y = self::fe_mul($r->Y, $q->yminusx); 1312 $r->T = self::fe_mul($q->xy2d, $p->T); 1313 $t0 = self::fe_add(clone $p->Z, clone $p->Z); 1314 $r->X = self::fe_sub($r->Z, $r->Y); 1315 $r->Y = self::fe_add($r->Z, $r->Y); 1316 $r->Z = self::fe_add($t0, $r->T); 1317 $r->T = self::fe_sub($t0, $r->T); 1318 1319 return $r; 1320 } 1321 1322 /** 1323 * @internal You should not use this directly from another application 1324 * 1325 * @param ParagonIE_Sodium_Core_Curve25519_Ge_P1p1 $R 1326 * @param ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p 1327 * @param ParagonIE_Sodium_Core_Curve25519_Ge_Precomp $q 1328 * @return ParagonIE_Sodium_Core_Curve25519_Ge_P1p1 1329 */ 1330 public static function ge_msub( 1331 ParagonIE_Sodium_Core_Curve25519_Ge_P1p1 $R, 1332 ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p, 1333 ParagonIE_Sodium_Core_Curve25519_Ge_Precomp $q 1334 ) { 1335 $r = clone $R; 1336 1337 $r->X = self::fe_add($p->Y, $p->X); 1338 $r->Y = self::fe_sub($p->Y, $p->X); 1339 $r->Z = self::fe_mul($r->X, $q->yminusx); 1340 $r->Y = self::fe_mul($r->Y, $q->yplusx); 1341 $r->T = self::fe_mul($q->xy2d, $p->T); 1342 $t0 = self::fe_add($p->Z, $p->Z); 1343 $r->X = self::fe_sub($r->Z, $r->Y); 1344 $r->Y = self::fe_add($r->Z, $r->Y); 1345 $r->Z = self::fe_sub($t0, $r->T); 1346 $r->T = self::fe_add($t0, $r->T); 1347 1348 return $r; 1349 } 1350 1351 /** 1352 * @internal You should not use this directly from another application 1353 * 1354 * @param ParagonIE_Sodium_Core_Curve25519_Ge_P1p1 $p 1355 * @return ParagonIE_Sodium_Core_Curve25519_Ge_P2 1356 */ 1357 public static function ge_p1p1_to_p2(ParagonIE_Sodium_Core_Curve25519_Ge_P1p1 $p) 1358 { 1359 $r = new ParagonIE_Sodium_Core_Curve25519_Ge_P2(); 1360 $r->X = self::fe_mul($p->X, $p->T); 1361 $r->Y = self::fe_mul($p->Y, $p->Z); 1362 $r->Z = self::fe_mul($p->Z, $p->T); 1363 return $r; 1364 } 1365 1366 /** 1367 * @internal You should not use this directly from another application 1368 * 1369 * @param ParagonIE_Sodium_Core_Curve25519_Ge_P1p1 $p 1370 * @return ParagonIE_Sodium_Core_Curve25519_Ge_P3 1371 */ 1372 public static function ge_p1p1_to_p3(ParagonIE_Sodium_Core_Curve25519_Ge_P1p1 $p) 1373 { 1374 $r = new ParagonIE_Sodium_Core_Curve25519_Ge_P3(); 1375 $r->X = self::fe_mul($p->X, $p->T); 1376 $r->Y = self::fe_mul($p->Y, $p->Z); 1377 $r->Z = self::fe_mul($p->Z, $p->T); 1378 $r->T = self::fe_mul($p->X, $p->Y); 1379 return $r; 1380 } 1381 1382 /** 1383 * @internal You should not use this directly from another application 1384 * 1385 * @return ParagonIE_Sodium_Core_Curve25519_Ge_P2 1386 */ 1387 public static function ge_p2_0() 1388 { 1389 return new ParagonIE_Sodium_Core_Curve25519_Ge_P2( 1390 self::fe_0(), 1391 self::fe_1(), 1392 self::fe_1() 1393 ); 1394 } 1395 1396 /** 1397 * @internal You should not use this directly from another application 1398 * 1399 * @param ParagonIE_Sodium_Core_Curve25519_Ge_P2 $p 1400 * @return ParagonIE_Sodium_Core_Curve25519_Ge_P1p1 1401 */ 1402 public static function ge_p2_dbl(ParagonIE_Sodium_Core_Curve25519_Ge_P2 $p) 1403 { 1404 $r = new ParagonIE_Sodium_Core_Curve25519_Ge_P1p1(); 1405 1406 $r->X = self::fe_sq($p->X); 1407 $r->Z = self::fe_sq($p->Y); 1408 $r->T = self::fe_sq2($p->Z); 1409 $r->Y = self::fe_add($p->X, $p->Y); 1410 $t0 = self::fe_sq($r->Y); 1411 $r->Y = self::fe_add($r->Z, $r->X); 1412 $r->Z = self::fe_sub($r->Z, $r->X); 1413 $r->X = self::fe_sub($t0, $r->Y); 1414 $r->T = self::fe_sub($r->T, $r->Z); 1415 1416 return $r; 1417 } 1418 1419 /** 1420 * @internal You should not use this directly from another application 1421 * 1422 * @return ParagonIE_Sodium_Core_Curve25519_Ge_P3 1423 */ 1424 public static function ge_p3_0() 1425 { 1426 return new ParagonIE_Sodium_Core_Curve25519_Ge_P3( 1427 self::fe_0(), 1428 self::fe_1(), 1429 self::fe_1(), 1430 self::fe_0() 1431 ); 1432 } 1433 1434 /** 1435 * @internal You should not use this directly from another application 1436 * 1437 * @param ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p 1438 * @return ParagonIE_Sodium_Core_Curve25519_Ge_Cached 1439 */ 1440 public static function ge_p3_to_cached(ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p) 1441 { 1442 static $d2 = null; 1443 if ($d2 === null) { 1444 $d2 = ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(self::$d2); 1445 } 1446 /** @var ParagonIE_Sodium_Core_Curve25519_Fe $d2 */ 1447 $r = new ParagonIE_Sodium_Core_Curve25519_Ge_Cached(); 1448 $r->YplusX = self::fe_add($p->Y, $p->X); 1449 $r->YminusX = self::fe_sub($p->Y, $p->X); 1450 $r->Z = self::fe_copy($p->Z); 1451 $r->T2d = self::fe_mul($p->T, $d2); 1452 return $r; 1453 } 1454 1455 /** 1456 * @internal You should not use this directly from another application 1457 * 1458 * @param ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p 1459 * @return ParagonIE_Sodium_Core_Curve25519_Ge_P2 1460 */ 1461 public static function ge_p3_to_p2(ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p) 1462 { 1463 return new ParagonIE_Sodium_Core_Curve25519_Ge_P2( 1464 self::fe_copy($p->X), 1465 self::fe_copy($p->Y), 1466 self::fe_copy($p->Z) 1467 ); 1468 } 1469 1470 /** 1471 * @internal You should not use this directly from another application 1472 * 1473 * @param ParagonIE_Sodium_Core_Curve25519_Ge_P3 $h 1474 * @return string 1475 * @throws SodiumException 1476 * @throws TypeError 1477 */ 1478 public static function ge_p3_tobytes(ParagonIE_Sodium_Core_Curve25519_Ge_P3 $h) 1479 { 1480 $recip = self::fe_invert($h->Z); 1481 $x = self::fe_mul($h->X, $recip); 1482 $y = self::fe_mul($h->Y, $recip); 1483 $s = self::fe_tobytes($y); 1484 $s[31] = self::intToChr( 1485 self::chrToInt($s[31]) ^ (self::fe_isnegative($x) << 7) 1486 ); 1487 return $s; 1488 } 1489 1490 /** 1491 * @internal You should not use this directly from another application 1492 * 1493 * @param ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p 1494 * @return ParagonIE_Sodium_Core_Curve25519_Ge_P1p1 1495 */ 1496 public static function ge_p3_dbl(ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p) 1497 { 1498 $q = self::ge_p3_to_p2($p); 1499 return self::ge_p2_dbl($q); 1500 } 1501 1502 /** 1503 * @return ParagonIE_Sodium_Core_Curve25519_Ge_Precomp 1504 */ 1505 public static function ge_precomp_0() 1506 { 1507 return new ParagonIE_Sodium_Core_Curve25519_Ge_Precomp( 1508 self::fe_1(), 1509 self::fe_1(), 1510 self::fe_0() 1511 ); 1512 } 1513 1514 /** 1515 * @internal You should not use this directly from another application 1516 * 1517 * @param int $b 1518 * @param int $c 1519 * @return int 1520 */ 1521 public static function equal($b, $c) 1522 { 1523 return (int) ((($b ^ $c) - 1) >> 31) & 1; 1524 } 1525 1526 /** 1527 * @internal You should not use this directly from another application 1528 * 1529 * @param int|string $char 1530 * @return int (1 = yes, 0 = no) 1531 * @throws SodiumException 1532 * @throws TypeError 1533 */ 1534 public static function negative($char) 1535 { 1536 if (is_int($char)) { 1537 return ($char >> 63) & 1; 1538 } 1539 $x = self::chrToInt(self::substr($char, 0, 1)); 1540 return (int) ($x >> 63); 1541 } 1542 1543 /** 1544 * Conditional move 1545 * 1546 * @internal You should not use this directly from another application 1547 * 1548 * @param ParagonIE_Sodium_Core_Curve25519_Ge_Precomp $t 1549 * @param ParagonIE_Sodium_Core_Curve25519_Ge_Precomp $u 1550 * @param int $b 1551 * @return ParagonIE_Sodium_Core_Curve25519_Ge_Precomp 1552 */ 1553 public static function cmov( 1554 ParagonIE_Sodium_Core_Curve25519_Ge_Precomp $t, 1555 ParagonIE_Sodium_Core_Curve25519_Ge_Precomp $u, 1556 $b 1557 ) { 1558 if (!is_int($b)) { 1559 throw new InvalidArgumentException('Expected an integer.'); 1560 } 1561 return new ParagonIE_Sodium_Core_Curve25519_Ge_Precomp( 1562 self::fe_cmov($t->yplusx, $u->yplusx, $b), 1563 self::fe_cmov($t->yminusx, $u->yminusx, $b), 1564 self::fe_cmov($t->xy2d, $u->xy2d, $b) 1565 ); 1566 } 1567 1568 /** 1569 * @param ParagonIE_Sodium_Core_Curve25519_Ge_Cached $t 1570 * @param ParagonIE_Sodium_Core_Curve25519_Ge_Cached $u 1571 * @param int $b 1572 * @return ParagonIE_Sodium_Core_Curve25519_Ge_Cached 1573 */ 1574 public static function ge_cmov_cached( 1575 ParagonIE_Sodium_Core_Curve25519_Ge_Cached $t, 1576 ParagonIE_Sodium_Core_Curve25519_Ge_Cached $u, 1577 $b 1578 ) { 1579 $b &= 1; 1580 $ret = new ParagonIE_Sodium_Core_Curve25519_Ge_Cached(); 1581 $ret->YplusX = self::fe_cmov($t->YplusX, $u->YplusX, $b); 1582 $ret->YminusX = self::fe_cmov($t->YminusX, $u->YminusX, $b); 1583 $ret->Z = self::fe_cmov($t->Z, $u->Z, $b); 1584 $ret->T2d = self::fe_cmov($t->T2d, $u->T2d, $b); 1585 return $ret; 1586 } 1587 1588 /** 1589 * @param ParagonIE_Sodium_Core_Curve25519_Ge_Cached[] $cached 1590 * @param int $b 1591 * @return ParagonIE_Sodium_Core_Curve25519_Ge_Cached 1592 * @throws SodiumException 1593 */ 1594 public static function ge_cmov8_cached(array $cached, $b) 1595 { 1596 // const unsigned char bnegative = negative(b); 1597 // const unsigned char babs = b - (((-bnegative) & b) * ((signed char) 1 << 1)); 1598 $bnegative = self::negative($b); 1599 $babs = $b - (((-$bnegative) & $b) << 1); 1600 1601 // ge25519_cached_0(t); 1602 $t = new ParagonIE_Sodium_Core_Curve25519_Ge_Cached( 1603 self::fe_1(), 1604 self::fe_1(), 1605 self::fe_1(), 1606 self::fe_0() 1607 ); 1608 1609 // ge25519_cmov_cached(t, &cached[0], equal(babs, 1)); 1610 // ge25519_cmov_cached(t, &cached[1], equal(babs, 2)); 1611 // ge25519_cmov_cached(t, &cached[2], equal(babs, 3)); 1612 // ge25519_cmov_cached(t, &cached[3], equal(babs, 4)); 1613 // ge25519_cmov_cached(t, &cached[4], equal(babs, 5)); 1614 // ge25519_cmov_cached(t, &cached[5], equal(babs, 6)); 1615 // ge25519_cmov_cached(t, &cached[6], equal(babs, 7)); 1616 // ge25519_cmov_cached(t, &cached[7], equal(babs, 8)); 1617 for ($x = 0; $x < 8; ++$x) { 1618 $t = self::ge_cmov_cached($t, $cached[$x], self::equal($babs, $x + 1)); 1619 } 1620 1621 // fe25519_copy(minust.YplusX, t->YminusX); 1622 // fe25519_copy(minust.YminusX, t->YplusX); 1623 // fe25519_copy(minust.Z, t->Z); 1624 // fe25519_neg(minust.T2d, t->T2d); 1625 $minust = new ParagonIE_Sodium_Core_Curve25519_Ge_Cached( 1626 self::fe_copy($t->YminusX), 1627 self::fe_copy($t->YplusX), 1628 self::fe_copy($t->Z), 1629 self::fe_neg($t->T2d) 1630 ); 1631 return self::ge_cmov_cached($t, $minust, $bnegative); 1632 } 1633 1634 /** 1635 * @internal You should not use this directly from another application 1636 * 1637 * @param int $pos 1638 * @param int $b 1639 * @return ParagonIE_Sodium_Core_Curve25519_Ge_Precomp 1640 * @throws SodiumException 1641 * @throws TypeError 1642 * @psalm-suppress MixedArgument 1643 * @psalm-suppress MixedArrayAccess 1644 * @psalm-suppress MixedArrayOffset 1645 */ 1646 public static function ge_select($pos = 0, $b = 0) 1647 { 1648 static $base = null; 1649 if ($base === null) { 1650 $base = array(); 1651 /** @var int $i */ 1652 foreach (self::$base as $i => $bas) { 1653 for ($j = 0; $j < 8; ++$j) { 1654 $base[$i][$j] = new ParagonIE_Sodium_Core_Curve25519_Ge_Precomp( 1655 ParagonIE_Sodium_Core_Curve25519_Fe::fromArray($bas[$j][0]), 1656 ParagonIE_Sodium_Core_Curve25519_Fe::fromArray($bas[$j][1]), 1657 ParagonIE_Sodium_Core_Curve25519_Fe::fromArray($bas[$j][2]) 1658 ); 1659 } 1660 } 1661 } 1662 /** @var array<int, array<int, ParagonIE_Sodium_Core_Curve25519_Ge_Precomp>> $base */ 1663 if (!is_int($pos)) { 1664 throw new InvalidArgumentException('Position must be an integer'); 1665 } 1666 if ($pos < 0 || $pos > 31) { 1667 throw new RangeException('Position is out of range [0, 31]'); 1668 } 1669 1670 $bnegative = self::negative($b); 1671 $babs = $b - (((-$bnegative) & $b) << 1); 1672 1673 $t = self::ge_precomp_0(); 1674 for ($i = 0; $i < 8; ++$i) { 1675 $t = self::cmov( 1676 $t, 1677 $base[$pos][$i], 1678 self::equal($babs, $i + 1) 1679 ); 1680 } 1681 $minusT = new ParagonIE_Sodium_Core_Curve25519_Ge_Precomp( 1682 self::fe_copy($t->yminusx), 1683 self::fe_copy($t->yplusx), 1684 self::fe_neg($t->xy2d) 1685 ); 1686 return self::cmov($t, $minusT, $bnegative); 1687 } 1688 1689 /** 1690 * Subtract two group elements. 1691 * 1692 * r = p - q 1693 * 1694 * @internal You should not use this directly from another application 1695 * 1696 * @param ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p 1697 * @param ParagonIE_Sodium_Core_Curve25519_Ge_Cached $q 1698 * @return ParagonIE_Sodium_Core_Curve25519_Ge_P1p1 1699 */ 1700 public static function ge_sub( 1701 ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p, 1702 ParagonIE_Sodium_Core_Curve25519_Ge_Cached $q 1703 ) { 1704 $r = new ParagonIE_Sodium_Core_Curve25519_Ge_P1p1(); 1705 1706 $r->X = self::fe_add($p->Y, $p->X); 1707 $r->Y = self::fe_sub($p->Y, $p->X); 1708 $r->Z = self::fe_mul($r->X, $q->YminusX); 1709 $r->Y = self::fe_mul($r->Y, $q->YplusX); 1710 $r->T = self::fe_mul($q->T2d, $p->T); 1711 $r->X = self::fe_mul($p->Z, $q->Z); 1712 $t0 = self::fe_add($r->X, $r->X); 1713 $r->X = self::fe_sub($r->Z, $r->Y); 1714 $r->Y = self::fe_add($r->Z, $r->Y); 1715 $r->Z = self::fe_sub($t0, $r->T); 1716 $r->T = self::fe_add($t0, $r->T); 1717 1718 return $r; 1719 } 1720 1721 /** 1722 * Convert a group element to a byte string. 1723 * 1724 * @param ParagonIE_Sodium_Core_Curve25519_Ge_P2 $h 1725 * @return string 1726 * @throws SodiumException 1727 * @throws TypeError 1728 */ 1729 public static function ge_tobytes(ParagonIE_Sodium_Core_Curve25519_Ge_P2 $h) 1730 { 1731 $recip = self::fe_invert($h->Z); 1732 $x = self::fe_mul($h->X, $recip); 1733 $y = self::fe_mul($h->Y, $recip); 1734 $s = self::fe_tobytes($y); 1735 $s[31] = self::intToChr( 1736 self::chrToInt($s[31]) ^ (self::fe_isnegative($x) << 7) 1737 ); 1738 return $s; 1739 } 1740 1741 /** 1742 * @internal You should not use this directly from another application 1743 * 1744 * @param string $a 1745 * @param ParagonIE_Sodium_Core_Curve25519_Ge_P3 $A 1746 * @param string $b 1747 * @return ParagonIE_Sodium_Core_Curve25519_Ge_P2 1748 * @throws SodiumException 1749 * @throws TypeError 1750 * @psalm-suppress MixedArgument 1751 * @psalm-suppress MixedArrayAccess 1752 */ 1753 public static function ge_double_scalarmult_vartime( 1754 $a, 1755 ParagonIE_Sodium_Core_Curve25519_Ge_P3 $A, 1756 $b 1757 ) { 1758 /** @var array<int, ParagonIE_Sodium_Core_Curve25519_Ge_Cached> $Ai */ 1759 $Ai = array(); 1760 1761 /** @var array<int, ParagonIE_Sodium_Core_Curve25519_Ge_Precomp> $Bi */ 1762 static $Bi = array(); 1763 if (!$Bi) { 1764 for ($i = 0; $i < 8; ++$i) { 1765 $Bi[$i] = new ParagonIE_Sodium_Core_Curve25519_Ge_Precomp( 1766 ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(self::$base2[$i][0]), 1767 ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(self::$base2[$i][1]), 1768 ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(self::$base2[$i][2]) 1769 ); 1770 } 1771 } 1772 for ($i = 0; $i < 8; ++$i) { 1773 $Ai[$i] = new ParagonIE_Sodium_Core_Curve25519_Ge_Cached( 1774 self::fe_0(), 1775 self::fe_0(), 1776 self::fe_0(), 1777 self::fe_0() 1778 ); 1779 } 1780 1781 # slide(aslide,a); 1782 # slide(bslide,b); 1783 /** @var array<int, int> $aslide */ 1784 $aslide = self::slide($a); 1785 /** @var array<int, int> $bslide */ 1786 $bslide = self::slide($b); 1787 1788 # ge_p3_to_cached(&Ai[0],A); 1789 # ge_p3_dbl(&t,A); ge_p1p1_to_p3(&A2,&t); 1790 $Ai[0] = self::ge_p3_to_cached($A); 1791 $t = self::ge_p3_dbl($A); 1792 $A2 = self::ge_p1p1_to_p3($t); 1793 1794 # ge_add(&t,&A2,&Ai[0]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[1],&u); 1795 # ge_add(&t,&A2,&Ai[1]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[2],&u); 1796 # ge_add(&t,&A2,&Ai[2]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[3],&u); 1797 # ge_add(&t,&A2,&Ai[3]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[4],&u); 1798 # ge_add(&t,&A2,&Ai[4]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[5],&u); 1799 # ge_add(&t,&A2,&Ai[5]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[6],&u); 1800 # ge_add(&t,&A2,&Ai[6]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[7],&u); 1801 for ($i = 0; $i < 7; ++$i) { 1802 $t = self::ge_add($A2, $Ai[$i]); 1803 $u = self::ge_p1p1_to_p3($t); 1804 $Ai[$i + 1] = self::ge_p3_to_cached($u); 1805 } 1806 1807 # ge_p2_0(r); 1808 $r = self::ge_p2_0(); 1809 1810 # for (i = 255;i >= 0;--i) { 1811 # if (aslide[i] || bslide[i]) break; 1812 # } 1813 $i = 255; 1814 for (; $i >= 0; --$i) { 1815 if ($aslide[$i] || $bslide[$i]) { 1816 break; 1817 } 1818 } 1819 1820 # for (;i >= 0;--i) { 1821 for (; $i >= 0; --$i) { 1822 # ge_p2_dbl(&t,r); 1823 $t = self::ge_p2_dbl($r); 1824 1825 # if (aslide[i] > 0) { 1826 if ($aslide[$i] > 0) { 1827 # ge_p1p1_to_p3(&u,&t); 1828 # ge_add(&t,&u,&Ai[aslide[i]/2]); 1829 $u = self::ge_p1p1_to_p3($t); 1830 $t = self::ge_add( 1831 $u, 1832 $Ai[(int) floor($aslide[$i] / 2)] 1833 ); 1834 # } else if (aslide[i] < 0) { 1835 } elseif ($aslide[$i] < 0) { 1836 # ge_p1p1_to_p3(&u,&t); 1837 # ge_sub(&t,&u,&Ai[(-aslide[i])/2]); 1838 $u = self::ge_p1p1_to_p3($t); 1839 $t = self::ge_sub( 1840 $u, 1841 $Ai[(int) floor(-$aslide[$i] / 2)] 1842 ); 1843 } 1844 1845 # if (bslide[i] > 0) { 1846 if ($bslide[$i] > 0) { 1847 /** @var int $index */ 1848 $index = (int) floor($bslide[$i] / 2); 1849 # ge_p1p1_to_p3(&u,&t); 1850 # ge_madd(&t,&u,&Bi[bslide[i]/2]); 1851 $u = self::ge_p1p1_to_p3($t); 1852 $t = self::ge_madd($t, $u, $Bi[$index]); 1853 # } else if (bslide[i] < 0) { 1854 } elseif ($bslide[$i] < 0) { 1855 /** @var int $index */ 1856 $index = (int) floor(-$bslide[$i] / 2); 1857 # ge_p1p1_to_p3(&u,&t); 1858 # ge_msub(&t,&u,&Bi[(-bslide[i])/2]); 1859 $u = self::ge_p1p1_to_p3($t); 1860 $t = self::ge_msub($t, $u, $Bi[$index]); 1861 } 1862 # ge_p1p1_to_p2(r,&t); 1863 $r = self::ge_p1p1_to_p2($t); 1864 } 1865 return $r; 1866 } 1867 1868 /** 1869 * @internal You should not use this directly from another application 1870 * 1871 * @param string $a 1872 * @param ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p 1873 * @return ParagonIE_Sodium_Core_Curve25519_Ge_P3 1874 * @throws SodiumException 1875 * @throws TypeError 1876 * @psalm-suppress MixedAssignment 1877 * @psalm-suppress MixedOperand 1878 */ 1879 public static function ge_scalarmult($a, $p) 1880 { 1881 $e = array_fill(0, 64, 0); 1882 1883 /** @var ParagonIE_Sodium_Core_Curve25519_Ge_Cached[] $pi */ 1884 $pi = array(); 1885 1886 // ge25519_p3_to_cached(&pi[1 - 1], p); /* p */ 1887 $pi[0] = self::ge_p3_to_cached($p); 1888 1889 // ge25519_p3_dbl(&t2, p); 1890 // ge25519_p1p1_to_p3(&p2, &t2); 1891 // ge25519_p3_to_cached(&pi[2 - 1], &p2); /* 2p = 2*p */ 1892 $t2 = self::ge_p3_dbl($p); 1893 $p2 = self::ge_p1p1_to_p3($t2); 1894 $pi[1] = self::ge_p3_to_cached($p2); 1895 1896 // ge25519_add_cached(&t3, p, &pi[2 - 1]); 1897 // ge25519_p1p1_to_p3(&p3, &t3); 1898 // ge25519_p3_to_cached(&pi[3 - 1], &p3); /* 3p = 2p+p */ 1899 $t3 = self::ge_add($p, $pi[1]); 1900 $p3 = self::ge_p1p1_to_p3($t3); 1901 $pi[2] = self::ge_p3_to_cached($p3); 1902 1903 // ge25519_p3_dbl(&t4, &p2); 1904 // ge25519_p1p1_to_p3(&p4, &t4); 1905 // ge25519_p3_to_cached(&pi[4 - 1], &p4); /* 4p = 2*2p */ 1906 $t4 = self::ge_p3_dbl($p2); 1907 $p4 = self::ge_p1p1_to_p3($t4); 1908 $pi[3] = self::ge_p3_to_cached($p4); 1909 1910 // ge25519_add_cached(&t5, p, &pi[4 - 1]); 1911 // ge25519_p1p1_to_p3(&p5, &t5); 1912 // ge25519_p3_to_cached(&pi[5 - 1], &p5); /* 5p = 4p+p */ 1913 $t5 = self::ge_add($p, $pi[3]); 1914 $p5 = self::ge_p1p1_to_p3($t5); 1915 $pi[4] = self::ge_p3_to_cached($p5); 1916 1917 // ge25519_p3_dbl(&t6, &p3); 1918 // ge25519_p1p1_to_p3(&p6, &t6); 1919 // ge25519_p3_to_cached(&pi[6 - 1], &p6); /* 6p = 2*3p */ 1920 $t6 = self::ge_p3_dbl($p3); 1921 $p6 = self::ge_p1p1_to_p3($t6); 1922 $pi[5] = self::ge_p3_to_cached($p6); 1923 1924 // ge25519_add_cached(&t7, p, &pi[6 - 1]); 1925 // ge25519_p1p1_to_p3(&p7, &t7); 1926 // ge25519_p3_to_cached(&pi[7 - 1], &p7); /* 7p = 6p+p */ 1927 $t7 = self::ge_add($p, $pi[5]); 1928 $p7 = self::ge_p1p1_to_p3($t7); 1929 $pi[6] = self::ge_p3_to_cached($p7); 1930 1931 // ge25519_p3_dbl(&t8, &p4); 1932 // ge25519_p1p1_to_p3(&p8, &t8); 1933 // ge25519_p3_to_cached(&pi[8 - 1], &p8); /* 8p = 2*4p */ 1934 $t8 = self::ge_p3_dbl($p4); 1935 $p8 = self::ge_p1p1_to_p3($t8); 1936 $pi[7] = self::ge_p3_to_cached($p8); 1937 1938 1939 // for (i = 0; i < 32; ++i) { 1940 // e[2 * i + 0] = (a[i] >> 0) & 15; 1941 // e[2 * i + 1] = (a[i] >> 4) & 15; 1942 // } 1943 for ($i = 0; $i < 32; ++$i) { 1944 $e[($i << 1) ] = self::chrToInt($a[$i]) & 15; 1945 $e[($i << 1) + 1] = (self::chrToInt($a[$i]) >> 4) & 15; 1946 } 1947 // /* each e[i] is between 0 and 15 */ 1948 // /* e[63] is between 0 and 7 */ 1949 1950 // carry = 0; 1951 // for (i = 0; i < 63; ++i) { 1952 // e[i] += carry; 1953 // carry = e[i] + 8; 1954 // carry >>= 4; 1955 // e[i] -= carry * ((signed char) 1 << 4); 1956 // } 1957 $carry = 0; 1958 for ($i = 0; $i < 63; ++$i) { 1959 $e[$i] += $carry; 1960 $carry = $e[$i] + 8; 1961 $carry >>= 4; 1962 $e[$i] -= $carry << 4; 1963 } 1964 // e[63] += carry; 1965 // /* each e[i] is between -8 and 8 */ 1966 $e[63] += $carry; 1967 1968 // ge25519_p3_0(h); 1969 $h = self::ge_p3_0(); 1970 1971 // for (i = 63; i != 0; i--) { 1972 for ($i = 63; $i != 0; --$i) { 1973 // ge25519_cmov8_cached(&t, pi, e[i]); 1974 $t = self::ge_cmov8_cached($pi, $e[$i]); 1975 // ge25519_add_cached(&r, h, &t); 1976 $r = self::ge_add($h, $t); 1977 1978 // ge25519_p1p1_to_p2(&s, &r); 1979 // ge25519_p2_dbl(&r, &s); 1980 // ge25519_p1p1_to_p2(&s, &r); 1981 // ge25519_p2_dbl(&r, &s); 1982 // ge25519_p1p1_to_p2(&s, &r); 1983 // ge25519_p2_dbl(&r, &s); 1984 // ge25519_p1p1_to_p2(&s, &r); 1985 // ge25519_p2_dbl(&r, &s); 1986 $s = self::ge_p1p1_to_p2($r); 1987 $r = self::ge_p2_dbl($s); 1988 $s = self::ge_p1p1_to_p2($r); 1989 $r = self::ge_p2_dbl($s); 1990 $s = self::ge_p1p1_to_p2($r); 1991 $r = self::ge_p2_dbl($s); 1992 $s = self::ge_p1p1_to_p2($r); 1993 $r = self::ge_p2_dbl($s); 1994 1995 // ge25519_p1p1_to_p3(h, &r); /* *16 */ 1996 $h = self::ge_p1p1_to_p3($r); /* *16 */ 1997 } 1998 1999 // ge25519_cmov8_cached(&t, pi, e[i]); 2000 // ge25519_add_cached(&r, h, &t); 2001 // ge25519_p1p1_to_p3(h, &r); 2002 $t = self::ge_cmov8_cached($pi, $e[0]); 2003 $r = self::ge_add($h, $t); 2004 return self::ge_p1p1_to_p3($r); 2005 } 2006 2007 /** 2008 * @internal You should not use this directly from another application 2009 * 2010 * @param string $a 2011 * @return ParagonIE_Sodium_Core_Curve25519_Ge_P3 2012 * @throws SodiumException 2013 * @throws TypeError 2014 * @psalm-suppress MixedAssignment 2015 * @psalm-suppress MixedOperand 2016 */ 2017 public static function ge_scalarmult_base($a) 2018 { 2019 /** @var array<int, int> $e */ 2020 $e = array(); 2021 $r = new ParagonIE_Sodium_Core_Curve25519_Ge_P1p1(); 2022 2023 for ($i = 0; $i < 32; ++$i) { 2024 $dbl = (int) $i << 1; 2025 $e[$dbl] = (int) self::chrToInt($a[$i]) & 15; 2026 $e[$dbl + 1] = (int) (self::chrToInt($a[$i]) >> 4) & 15; 2027 } 2028 2029 $carry = 0; 2030 for ($i = 0; $i < 63; ++$i) { 2031 $e[$i] += $carry; 2032 $carry = $e[$i] + 8; 2033 $carry >>= 4; 2034 $e[$i] -= $carry << 4; 2035 } 2036 $e[63] += (int) $carry; 2037 2038 $h = self::ge_p3_0(); 2039 2040 for ($i = 1; $i < 64; $i += 2) { 2041 $t = self::ge_select((int) floor($i / 2), (int) $e[$i]); 2042 $r = self::ge_madd($r, $h, $t); 2043 $h = self::ge_p1p1_to_p3($r); 2044 } 2045 2046 $r = self::ge_p3_dbl($h); 2047 2048 $s = self::ge_p1p1_to_p2($r); 2049 $r = self::ge_p2_dbl($s); 2050 $s = self::ge_p1p1_to_p2($r); 2051 $r = self::ge_p2_dbl($s); 2052 $s = self::ge_p1p1_to_p2($r); 2053 $r = self::ge_p2_dbl($s); 2054 2055 $h = self::ge_p1p1_to_p3($r); 2056 2057 for ($i = 0; $i < 64; $i += 2) { 2058 $t = self::ge_select($i >> 1, (int) $e[$i]); 2059 $r = self::ge_madd($r, $h, $t); 2060 $h = self::ge_p1p1_to_p3($r); 2061 } 2062 return $h; 2063 } 2064 2065 /** 2066 * Calculates (ab + c) mod l 2067 * where l = 2^252 + 27742317777372353535851937790883648493 2068 * 2069 * @internal You should not use this directly from another application 2070 * 2071 * @param string $a 2072 * @param string $b 2073 * @param string $c 2074 * @return string 2075 * @throws TypeError 2076 */ 2077 public static function sc_muladd($a, $b, $c) 2078 { 2079 $a0 = 2097151 & self::load_3(self::substr($a, 0, 3)); 2080 $a1 = 2097151 & (self::load_4(self::substr($a, 2, 4)) >> 5); 2081 $a2 = 2097151 & (self::load_3(self::substr($a, 5, 3)) >> 2); 2082 $a3 = 2097151 & (self::load_4(self::substr($a, 7, 4)) >> 7); 2083 $a4 = 2097151 & (self::load_4(self::substr($a, 10, 4)) >> 4); 2084 $a5 = 2097151 & (self::load_3(self::substr($a, 13, 3)) >> 1); 2085 $a6 = 2097151 & (self::load_4(self::substr($a, 15, 4)) >> 6); 2086 $a7 = 2097151 & (self::load_3(self::substr($a, 18, 3)) >> 3); 2087 $a8 = 2097151 & self::load_3(self::substr($a, 21, 3)); 2088 $a9 = 2097151 & (self::load_4(self::substr($a, 23, 4)) >> 5); 2089 $a10 = 2097151 & (self::load_3(self::substr($a, 26, 3)) >> 2); 2090 $a11 = (self::load_4(self::substr($a, 28, 4)) >> 7); 2091 2092 $b0 = 2097151 & self::load_3(self::substr($b, 0, 3)); 2093 $b1 = 2097151 & (self::load_4(self::substr($b, 2, 4)) >> 5); 2094 $b2 = 2097151 & (self::load_3(self::substr($b, 5, 3)) >> 2); 2095 $b3 = 2097151 & (self::load_4(self::substr($b, 7, 4)) >> 7); 2096 $b4 = 2097151 & (self::load_4(self::substr($b, 10, 4)) >> 4); 2097 $b5 = 2097151 & (self::load_3(self::substr($b, 13, 3)) >> 1); 2098 $b6 = 2097151 & (self::load_4(self::substr($b, 15, 4)) >> 6); 2099 $b7 = 2097151 & (self::load_3(self::substr($b, 18, 3)) >> 3); 2100 $b8 = 2097151 & self::load_3(self::substr($b, 21, 3)); 2101 $b9 = 2097151 & (self::load_4(self::substr($b, 23, 4)) >> 5); 2102 $b10 = 2097151 & (self::load_3(self::substr($b, 26, 3)) >> 2); 2103 $b11 = (self::load_4(self::substr($b, 28, 4)) >> 7); 2104 2105 $c0 = 2097151 & self::load_3(self::substr($c, 0, 3)); 2106 $c1 = 2097151 & (self::load_4(self::substr($c, 2, 4)) >> 5); 2107 $c2 = 2097151 & (self::load_3(self::substr($c, 5, 3)) >> 2); 2108 $c3 = 2097151 & (self::load_4(self::substr($c, 7, 4)) >> 7); 2109 $c4 = 2097151 & (self::load_4(self::substr($c, 10, 4)) >> 4); 2110 $c5 = 2097151 & (self::load_3(self::substr($c, 13, 3)) >> 1); 2111 $c6 = 2097151 & (self::load_4(self::substr($c, 15, 4)) >> 6); 2112 $c7 = 2097151 & (self::load_3(self::substr($c, 18, 3)) >> 3); 2113 $c8 = 2097151 & self::load_3(self::substr($c, 21, 3)); 2114 $c9 = 2097151 & (self::load_4(self::substr($c, 23, 4)) >> 5); 2115 $c10 = 2097151 & (self::load_3(self::substr($c, 26, 3)) >> 2); 2116 $c11 = (self::load_4(self::substr($c, 28, 4)) >> 7); 2117 2118 /* Can't really avoid the pyramid here: */ 2119 $s0 = $c0 + self::mul($a0, $b0, 24); 2120 $s1 = $c1 + self::mul($a0, $b1, 24) + self::mul($a1, $b0, 24); 2121 $s2 = $c2 + self::mul($a0, $b2, 24) + self::mul($a1, $b1, 24) + self::mul($a2, $b0, 24); 2122 $s3 = $c3 + self::mul($a0, $b3, 24) + self::mul($a1, $b2, 24) + self::mul($a2, $b1, 24) + self::mul($a3, $b0, 24); 2123 $s4 = $c4 + self::mul($a0, $b4, 24) + self::mul($a1, $b3, 24) + self::mul($a2, $b2, 24) + self::mul($a3, $b1, 24) + 2124 self::mul($a4, $b0, 24); 2125 $s5 = $c5 + self::mul($a0, $b5, 24) + self::mul($a1, $b4, 24) + self::mul($a2, $b3, 24) + self::mul($a3, $b2, 24) + 2126 self::mul($a4, $b1, 24) + self::mul($a5, $b0, 24); 2127 $s6 = $c6 + self::mul($a0, $b6, 24) + self::mul($a1, $b5, 24) + self::mul($a2, $b4, 24) + self::mul($a3, $b3, 24) + 2128 self::mul($a4, $b2, 24) + self::mul($a5, $b1, 24) + self::mul($a6, $b0, 24); 2129 $s7 = $c7 + self::mul($a0, $b7, 24) + self::mul($a1, $b6, 24) + self::mul($a2, $b5, 24) + self::mul($a3, $b4, 24) + 2130 self::mul($a4, $b3, 24) + self::mul($a5, $b2, 24) + self::mul($a6, $b1, 24) + self::mul($a7, $b0, 24); 2131 $s8 = $c8 + self::mul($a0, $b8, 24) + self::mul($a1, $b7, 24) + self::mul($a2, $b6, 24) + self::mul($a3, $b5, 24) + 2132 self::mul($a4, $b4, 24) + self::mul($a5, $b3, 24) + self::mul($a6, $b2, 24) + self::mul($a7, $b1, 24) + 2133 self::mul($a8, $b0, 24); 2134 $s9 = $c9 + self::mul($a0, $b9, 24) + self::mul($a1, $b8, 24) + self::mul($a2, $b7, 24) + self::mul($a3, $b6, 24) + 2135 self::mul($a4, $b5, 24) + self::mul($a5, $b4, 24) + self::mul($a6, $b3, 24) + self::mul($a7, $b2, 24) + 2136 self::mul($a8, $b1, 24) + self::mul($a9, $b0, 24); 2137 $s10 = $c10 + self::mul($a0, $b10, 24) + self::mul($a1, $b9, 24) + self::mul($a2, $b8, 24) + self::mul($a3, $b7, 24) + 2138 self::mul($a4, $b6, 24) + self::mul($a5, $b5, 24) + self::mul($a6, $b4, 24) + self::mul($a7, $b3, 24) + 2139 self::mul($a8, $b2, 24) + self::mul($a9, $b1, 24) + self::mul($a10, $b0, 24); 2140 $s11 = $c11 + self::mul($a0, $b11, 24) + self::mul($a1, $b10, 24) + self::mul($a2, $b9, 24) + self::mul($a3, $b8, 24) + 2141 self::mul($a4, $b7, 24) + self::mul($a5, $b6, 24) + self::mul($a6, $b5, 24) + self::mul($a7, $b4, 24) + 2142 self::mul($a8, $b3, 24) + self::mul($a9, $b2, 24) + self::mul($a10, $b1, 24) + self::mul($a11, $b0, 24); 2143 $s12 = self::mul($a1, $b11, 24) + self::mul($a2, $b10, 24) + self::mul($a3, $b9, 24) + self::mul($a4, $b8, 24) + 2144 self::mul($a5, $b7, 24) + self::mul($a6, $b6, 24) + self::mul($a7, $b5, 24) + self::mul($a8, $b4, 24) + 2145 self::mul($a9, $b3, 24) + self::mul($a10, $b2, 24) + self::mul($a11, $b1, 24); 2146 $s13 = self::mul($a2, $b11, 24) + self::mul($a3, $b10, 24) + self::mul($a4, $b9, 24) + self::mul($a5, $b8, 24) + 2147 self::mul($a6, $b7, 24) + self::mul($a7, $b6, 24) + self::mul($a8, $b5, 24) + self::mul($a9, $b4, 24) + 2148 self::mul($a10, $b3, 24) + self::mul($a11, $b2, 24); 2149 $s14 = self::mul($a3, $b11, 24) + self::mul($a4, $b10, 24) + self::mul($a5, $b9, 24) + self::mul($a6, $b8, 24) + 2150 self::mul($a7, $b7, 24) + self::mul($a8, $b6, 24) + self::mul($a9, $b5, 24) + self::mul($a10, $b4, 24) + 2151 self::mul($a11, $b3, 24); 2152 $s15 = self::mul($a4, $b11, 24) + self::mul($a5, $b10, 24) + self::mul($a6, $b9, 24) + self::mul($a7, $b8, 24) + 2153 self::mul($a8, $b7, 24) + self::mul($a9, $b6, 24) + self::mul($a10, $b5, 24) + self::mul($a11, $b4, 24); 2154 $s16 = self::mul($a5, $b11, 24) + self::mul($a6, $b10, 24) + self::mul($a7, $b9, 24) + self::mul($a8, $b8, 24) + 2155 self::mul($a9, $b7, 24) + self::mul($a10, $b6, 24) + self::mul($a11, $b5, 24); 2156 $s17 = self::mul($a6, $b11, 24) + self::mul($a7, $b10, 24) + self::mul($a8, $b9, 24) + self::mul($a9, $b8, 24) + 2157 self::mul($a10, $b7, 24) + self::mul($a11, $b6, 24); 2158 $s18 = self::mul($a7, $b11, 24) + self::mul($a8, $b10, 24) + self::mul($a9, $b9, 24) + self::mul($a10, $b8, 24) + 2159 self::mul($a11, $b7, 24); 2160 $s19 = self::mul($a8, $b11, 24) + self::mul($a9, $b10, 24) + self::mul($a10, $b9, 24) + self::mul($a11, $b8, 24); 2161 $s20 = self::mul($a9, $b11, 24) + self::mul($a10, $b10, 24) + self::mul($a11, $b9, 24); 2162 $s21 = self::mul($a10, $b11, 24) + self::mul($a11, $b10, 24); 2163 $s22 = self::mul($a11, $b11, 24); 2164 $s23 = 0; 2165 2166 $carry0 = ($s0 + (1 << 20)) >> 21; 2167 $s1 += $carry0; 2168 $s0 -= $carry0 << 21; 2169 $carry2 = ($s2 + (1 << 20)) >> 21; 2170 $s3 += $carry2; 2171 $s2 -= $carry2 << 21; 2172 $carry4 = ($s4 + (1 << 20)) >> 21; 2173 $s5 += $carry4; 2174 $s4 -= $carry4 << 21; 2175 $carry6 = ($s6 + (1 << 20)) >> 21; 2176 $s7 += $carry6; 2177 $s6 -= $carry6 << 21; 2178 $carry8 = ($s8 + (1 << 20)) >> 21; 2179 $s9 += $carry8; 2180 $s8 -= $carry8 << 21; 2181 $carry10 = ($s10 + (1 << 20)) >> 21; 2182 $s11 += $carry10; 2183 $s10 -= $carry10 << 21; 2184 $carry12 = ($s12 + (1 << 20)) >> 21; 2185 $s13 += $carry12; 2186 $s12 -= $carry12 << 21; 2187 $carry14 = ($s14 + (1 << 20)) >> 21; 2188 $s15 += $carry14; 2189 $s14 -= $carry14 << 21; 2190 $carry16 = ($s16 + (1 << 20)) >> 21; 2191 $s17 += $carry16; 2192 $s16 -= $carry16 << 21; 2193 $carry18 = ($s18 + (1 << 20)) >> 21; 2194 $s19 += $carry18; 2195 $s18 -= $carry18 << 21; 2196 $carry20 = ($s20 + (1 << 20)) >> 21; 2197 $s21 += $carry20; 2198 $s20 -= $carry20 << 21; 2199 $carry22 = ($s22 + (1 << 20)) >> 21; 2200 $s23 += $carry22; 2201 $s22 -= $carry22 << 21; 2202 2203 $carry1 = ($s1 + (1 << 20)) >> 21; 2204 $s2 += $carry1; 2205 $s1 -= $carry1 << 21; 2206 $carry3 = ($s3 + (1 << 20)) >> 21; 2207 $s4 += $carry3; 2208 $s3 -= $carry3 << 21; 2209 $carry5 = ($s5 + (1 << 20)) >> 21; 2210 $s6 += $carry5; 2211 $s5 -= $carry5 << 21; 2212 $carry7 = ($s7 + (1 << 20)) >> 21; 2213 $s8 += $carry7; 2214 $s7 -= $carry7 << 21; 2215 $carry9 = ($s9 + (1 << 20)) >> 21; 2216 $s10 += $carry9; 2217 $s9 -= $carry9 << 21; 2218 $carry11 = ($s11 + (1 << 20)) >> 21; 2219 $s12 += $carry11; 2220 $s11 -= $carry11 << 21; 2221 $carry13 = ($s13 + (1 << 20)) >> 21; 2222 $s14 += $carry13; 2223 $s13 -= $carry13 << 21; 2224 $carry15 = ($s15 + (1 << 20)) >> 21; 2225 $s16 += $carry15; 2226 $s15 -= $carry15 << 21; 2227 $carry17 = ($s17 + (1 << 20)) >> 21; 2228 $s18 += $carry17; 2229 $s17 -= $carry17 << 21; 2230 $carry19 = ($s19 + (1 << 20)) >> 21; 2231 $s20 += $carry19; 2232 $s19 -= $carry19 << 21; 2233 $carry21 = ($s21 + (1 << 20)) >> 21; 2234 $s22 += $carry21; 2235 $s21 -= $carry21 << 21; 2236 2237 $s11 += self::mul($s23, 666643, 20); 2238 $s12 += self::mul($s23, 470296, 19); 2239 $s13 += self::mul($s23, 654183, 20); 2240 $s14 -= self::mul($s23, 997805, 20); 2241 $s15 += self::mul($s23, 136657, 18); 2242 $s16 -= self::mul($s23, 683901, 20); 2243 2244 $s10 += self::mul($s22, 666643, 20); 2245 $s11 += self::mul($s22, 470296, 19); 2246 $s12 += self::mul($s22, 654183, 20); 2247 $s13 -= self::mul($s22, 997805, 20); 2248 $s14 += self::mul($s22, 136657, 18); 2249 $s15 -= self::mul($s22, 683901, 20); 2250 2251 $s9 += self::mul($s21, 666643, 20); 2252 $s10 += self::mul($s21, 470296, 19); 2253 $s11 += self::mul($s21, 654183, 20); 2254 $s12 -= self::mul($s21, 997805, 20); 2255 $s13 += self::mul($s21, 136657, 18); 2256 $s14 -= self::mul($s21, 683901, 20); 2257 2258 $s8 += self::mul($s20, 666643, 20); 2259 $s9 += self::mul($s20, 470296, 19); 2260 $s10 += self::mul($s20, 654183, 20); 2261 $s11 -= self::mul($s20, 997805, 20); 2262 $s12 += self::mul($s20, 136657, 18); 2263 $s13 -= self::mul($s20, 683901, 20); 2264 2265 $s7 += self::mul($s19, 666643, 20); 2266 $s8 += self::mul($s19, 470296, 19); 2267 $s9 += self::mul($s19, 654183, 20); 2268 $s10 -= self::mul($s19, 997805, 20); 2269 $s11 += self::mul($s19, 136657, 18); 2270 $s12 -= self::mul($s19, 683901, 20); 2271 2272 $s6 += self::mul($s18, 666643, 20); 2273 $s7 += self::mul($s18, 470296, 19); 2274 $s8 += self::mul($s18, 654183, 20); 2275 $s9 -= self::mul($s18, 997805, 20); 2276 $s10 += self::mul($s18, 136657, 18); 2277 $s11 -= self::mul($s18, 683901, 20); 2278 2279 $carry6 = ($s6 + (1 << 20)) >> 21; 2280 $s7 += $carry6; 2281 $s6 -= $carry6 << 21; 2282 $carry8 = ($s8 + (1 << 20)) >> 21; 2283 $s9 += $carry8; 2284 $s8 -= $carry8 << 21; 2285 $carry10 = ($s10 + (1 << 20)) >> 21; 2286 $s11 += $carry10; 2287 $s10 -= $carry10 << 21; 2288 $carry12 = ($s12 + (1 << 20)) >> 21; 2289 $s13 += $carry12; 2290 $s12 -= $carry12 << 21; 2291 $carry14 = ($s14 + (1 << 20)) >> 21; 2292 $s15 += $carry14; 2293 $s14 -= $carry14 << 21; 2294 $carry16 = ($s16 + (1 << 20)) >> 21; 2295 $s17 += $carry16; 2296 $s16 -= $carry16 << 21; 2297 2298 $carry7 = ($s7 + (1 << 20)) >> 21; 2299 $s8 += $carry7; 2300 $s7 -= $carry7 << 21; 2301 $carry9 = ($s9 + (1 << 20)) >> 21; 2302 $s10 += $carry9; 2303 $s9 -= $carry9 << 21; 2304 $carry11 = ($s11 + (1 << 20)) >> 21; 2305 $s12 += $carry11; 2306 $s11 -= $carry11 << 21; 2307 $carry13 = ($s13 + (1 << 20)) >> 21; 2308 $s14 += $carry13; 2309 $s13 -= $carry13 << 21; 2310 $carry15 = ($s15 + (1 << 20)) >> 21; 2311 $s16 += $carry15; 2312 $s15 -= $carry15 << 21; 2313 2314 $s5 += self::mul($s17, 666643, 20); 2315 $s6 += self::mul($s17, 470296, 19); 2316 $s7 += self::mul($s17, 654183, 20); 2317 $s8 -= self::mul($s17, 997805, 20); 2318 $s9 += self::mul($s17, 136657, 18); 2319 $s10 -= self::mul($s17, 683901, 20); 2320 2321 $s4 += self::mul($s16, 666643, 20); 2322 $s5 += self::mul($s16, 470296, 19); 2323 $s6 += self::mul($s16, 654183, 20); 2324 $s7 -= self::mul($s16, 997805, 20); 2325 $s8 += self::mul($s16, 136657, 18); 2326 $s9 -= self::mul($s16, 683901, 20); 2327 2328 $s3 += self::mul($s15, 666643, 20); 2329 $s4 += self::mul($s15, 470296, 19); 2330 $s5 += self::mul($s15, 654183, 20); 2331 $s6 -= self::mul($s15, 997805, 20); 2332 $s7 += self::mul($s15, 136657, 18); 2333 $s8 -= self::mul($s15, 683901, 20); 2334 2335 $s2 += self::mul($s14, 666643, 20); 2336 $s3 += self::mul($s14, 470296, 19); 2337 $s4 += self::mul($s14, 654183, 20); 2338 $s5 -= self::mul($s14, 997805, 20); 2339 $s6 += self::mul($s14, 136657, 18); 2340 $s7 -= self::mul($s14, 683901, 20); 2341 2342 $s1 += self::mul($s13, 666643, 20); 2343 $s2 += self::mul($s13, 470296, 19); 2344 $s3 += self::mul($s13, 654183, 20); 2345 $s4 -= self::mul($s13, 997805, 20); 2346 $s5 += self::mul($s13, 136657, 18); 2347 $s6 -= self::mul($s13, 683901, 20); 2348 2349 $s0 += self::mul($s12, 666643, 20); 2350 $s1 += self::mul($s12, 470296, 19); 2351 $s2 += self::mul($s12, 654183, 20); 2352 $s3 -= self::mul($s12, 997805, 20); 2353 $s4 += self::mul($s12, 136657, 18); 2354 $s5 -= self::mul($s12, 683901, 20); 2355 $s12 = 0; 2356 2357 $carry0 = ($s0 + (1 << 20)) >> 21; 2358 $s1 += $carry0; 2359 $s0 -= $carry0 << 21; 2360 $carry2 = ($s2 + (1 << 20)) >> 21; 2361 $s3 += $carry2; 2362 $s2 -= $carry2 << 21; 2363 $carry4 = ($s4 + (1 << 20)) >> 21; 2364 $s5 += $carry4; 2365 $s4 -= $carry4 << 21; 2366 $carry6 = ($s6 + (1 << 20)) >> 21; 2367 $s7 += $carry6; 2368 $s6 -= $carry6 << 21; 2369 $carry8 = ($s8 + (1 << 20)) >> 21; 2370 $s9 += $carry8; 2371 $s8 -= $carry8 << 21; 2372 $carry10 = ($s10 + (1 << 20)) >> 21; 2373 $s11 += $carry10; 2374 $s10 -= $carry10 << 21; 2375 2376 $carry1 = ($s1 + (1 << 20)) >> 21; 2377 $s2 += $carry1; 2378 $s1 -= $carry1 << 21; 2379 $carry3 = ($s3 + (1 << 20)) >> 21; 2380 $s4 += $carry3; 2381 $s3 -= $carry3 << 21; 2382 $carry5 = ($s5 + (1 << 20)) >> 21; 2383 $s6 += $carry5; 2384 $s5 -= $carry5 << 21; 2385 $carry7 = ($s7 + (1 << 20)) >> 21; 2386 $s8 += $carry7; 2387 $s7 -= $carry7 << 21; 2388 $carry9 = ($s9 + (1 << 20)) >> 21; 2389 $s10 += $carry9; 2390 $s9 -= $carry9 << 21; 2391 $carry11 = ($s11 + (1 << 20)) >> 21; 2392 $s12 += $carry11; 2393 $s11 -= $carry11 << 21; 2394 2395 $s0 += self::mul($s12, 666643, 20); 2396 $s1 += self::mul($s12, 470296, 19); 2397 $s2 += self::mul($s12, 654183, 20); 2398 $s3 -= self::mul($s12, 997805, 20); 2399 $s4 += self::mul($s12, 136657, 18); 2400 $s5 -= self::mul($s12, 683901, 20); 2401 $s12 = 0; 2402 2403 $carry0 = $s0 >> 21; 2404 $s1 += $carry0; 2405 $s0 -= $carry0 << 21; 2406 $carry1 = $s1 >> 21; 2407 $s2 += $carry1; 2408 $s1 -= $carry1 << 21; 2409 $carry2 = $s2 >> 21; 2410 $s3 += $carry2; 2411 $s2 -= $carry2 << 21; 2412 $carry3 = $s3 >> 21; 2413 $s4 += $carry3; 2414 $s3 -= $carry3 << 21; 2415 $carry4 = $s4 >> 21; 2416 $s5 += $carry4; 2417 $s4 -= $carry4 << 21; 2418 $carry5 = $s5 >> 21; 2419 $s6 += $carry5; 2420 $s5 -= $carry5 << 21; 2421 $carry6 = $s6 >> 21; 2422 $s7 += $carry6; 2423 $s6 -= $carry6 << 21; 2424 $carry7 = $s7 >> 21; 2425 $s8 += $carry7; 2426 $s7 -= $carry7 << 21; 2427 $carry8 = $s8 >> 21; 2428 $s9 += $carry8; 2429 $s8 -= $carry8 << 21; 2430 $carry9 = $s9 >> 21; 2431 $s10 += $carry9; 2432 $s9 -= $carry9 << 21; 2433 $carry10 = $s10 >> 21; 2434 $s11 += $carry10; 2435 $s10 -= $carry10 << 21; 2436 $carry11 = $s11 >> 21; 2437 $s12 += $carry11; 2438 $s11 -= $carry11 << 21; 2439 2440 $s0 += self::mul($s12, 666643, 20); 2441 $s1 += self::mul($s12, 470296, 19); 2442 $s2 += self::mul($s12, 654183, 20); 2443 $s3 -= self::mul($s12, 997805, 20); 2444 $s4 += self::mul($s12, 136657, 18); 2445 $s5 -= self::mul($s12, 683901, 20); 2446 2447 $carry0 = $s0 >> 21; 2448 $s1 += $carry0; 2449 $s0 -= $carry0 << 21; 2450 $carry1 = $s1 >> 21; 2451 $s2 += $carry1; 2452 $s1 -= $carry1 << 21; 2453 $carry2 = $s2 >> 21; 2454 $s3 += $carry2; 2455 $s2 -= $carry2 << 21; 2456 $carry3 = $s3 >> 21; 2457 $s4 += $carry3; 2458 $s3 -= $carry3 << 21; 2459 $carry4 = $s4 >> 21; 2460 $s5 += $carry4; 2461 $s4 -= $carry4 << 21; 2462 $carry5 = $s5 >> 21; 2463 $s6 += $carry5; 2464 $s5 -= $carry5 << 21; 2465 $carry6 = $s6 >> 21; 2466 $s7 += $carry6; 2467 $s6 -= $carry6 << 21; 2468 $carry7 = $s7 >> 21; 2469 $s8 += $carry7; 2470 $s7 -= $carry7 << 21; 2471 $carry8 = $s8 >> 21; 2472 $s9 += $carry8; 2473 $s8 -= $carry8 << 21; 2474 $carry9 = $s9 >> 21; 2475 $s10 += $carry9; 2476 $s9 -= $carry9 << 21; 2477 $carry10 = $s10 >> 21; 2478 $s11 += $carry10; 2479 $s10 -= $carry10 << 21; 2480 2481 /** 2482 * @var array<int, int> 2483 */ 2484 $arr = array( 2485 (int) (0xff & ($s0 >> 0)), 2486 (int) (0xff & ($s0 >> 8)), 2487 (int) (0xff & (($s0 >> 16) | $s1 << 5)), 2488 (int) (0xff & ($s1 >> 3)), 2489 (int) (0xff & ($s1 >> 11)), 2490 (int) (0xff & (($s1 >> 19) | $s2 << 2)), 2491 (int) (0xff & ($s2 >> 6)), 2492 (int) (0xff & (($s2 >> 14) | $s3 << 7)), 2493 (int) (0xff & ($s3 >> 1)), 2494 (int) (0xff & ($s3 >> 9)), 2495 (int) (0xff & (($s3 >> 17) | $s4 << 4)), 2496 (int) (0xff & ($s4 >> 4)), 2497 (int) (0xff & ($s4 >> 12)), 2498 (int) (0xff & (($s4 >> 20) | $s5 << 1)), 2499 (int) (0xff & ($s5 >> 7)), 2500 (int) (0xff & (($s5 >> 15) | $s6 << 6)), 2501 (int) (0xff & ($s6 >> 2)), 2502 (int) (0xff & ($s6 >> 10)), 2503 (int) (0xff & (($s6 >> 18) | $s7 << 3)), 2504 (int) (0xff & ($s7 >> 5)), 2505 (int) (0xff & ($s7 >> 13)), 2506 (int) (0xff & ($s8 >> 0)), 2507 (int) (0xff & ($s8 >> 8)), 2508 (int) (0xff & (($s8 >> 16) | $s9 << 5)), 2509 (int) (0xff & ($s9 >> 3)), 2510 (int) (0xff & ($s9 >> 11)), 2511 (int) (0xff & (($s9 >> 19) | $s10 << 2)), 2512 (int) (0xff & ($s10 >> 6)), 2513 (int) (0xff & (($s10 >> 14) | $s11 << 7)), 2514 (int) (0xff & ($s11 >> 1)), 2515 (int) (0xff & ($s11 >> 9)), 2516 0xff & ($s11 >> 17) 2517 ); 2518 return self::intArrayToString($arr); 2519 } 2520 2521 /** 2522 * @internal You should not use this directly from another application 2523 * 2524 * @param string $s 2525 * @return string 2526 * @throws TypeError 2527 */ 2528 public static function sc_reduce($s) 2529 { 2530 $s0 = 2097151 & self::load_3(self::substr($s, 0, 3)); 2531 $s1 = 2097151 & (self::load_4(self::substr($s, 2, 4)) >> 5); 2532 $s2 = 2097151 & (self::load_3(self::substr($s, 5, 3)) >> 2); 2533 $s3 = 2097151 & (self::load_4(self::substr($s, 7, 4)) >> 7); 2534 $s4 = 2097151 & (self::load_4(self::substr($s, 10, 4)) >> 4); 2535 $s5 = 2097151 & (self::load_3(self::substr($s, 13, 3)) >> 1); 2536 $s6 = 2097151 & (self::load_4(self::substr($s, 15, 4)) >> 6); 2537 $s7 = 2097151 & (self::load_3(self::substr($s, 18, 4)) >> 3); 2538 $s8 = 2097151 & self::load_3(self::substr($s, 21, 3)); 2539 $s9 = 2097151 & (self::load_4(self::substr($s, 23, 4)) >> 5); 2540 $s10 = 2097151 & (self::load_3(self::substr($s, 26, 3)) >> 2); 2541 $s11 = 2097151 & (self::load_4(self::substr($s, 28, 4)) >> 7); 2542 $s12 = 2097151 & (self::load_4(self::substr($s, 31, 4)) >> 4); 2543 $s13 = 2097151 & (self::load_3(self::substr($s, 34, 3)) >> 1); 2544 $s14 = 2097151 & (self::load_4(self::substr($s, 36, 4)) >> 6); 2545 $s15 = 2097151 & (self::load_3(self::substr($s, 39, 4)) >> 3); 2546 $s16 = 2097151 & self::load_3(self::substr($s, 42, 3)); 2547 $s17 = 2097151 & (self::load_4(self::substr($s, 44, 4)) >> 5); 2548 $s18 = 2097151 & (self::load_3(self::substr($s, 47, 3)) >> 2); 2549 $s19 = 2097151 & (self::load_4(self::substr($s, 49, 4)) >> 7); 2550 $s20 = 2097151 & (self::load_4(self::substr($s, 52, 4)) >> 4); 2551 $s21 = 2097151 & (self::load_3(self::substr($s, 55, 3)) >> 1); 2552 $s22 = 2097151 & (self::load_4(self::substr($s, 57, 4)) >> 6); 2553 $s23 = 0x1fffffff & (self::load_4(self::substr($s, 60, 4)) >> 3); 2554 2555 $s11 += self::mul($s23, 666643, 20); 2556 $s12 += self::mul($s23, 470296, 19); 2557 $s13 += self::mul($s23, 654183, 20); 2558 $s14 -= self::mul($s23, 997805, 20); 2559 $s15 += self::mul($s23, 136657, 18); 2560 $s16 -= self::mul($s23, 683901, 20); 2561 2562 $s10 += self::mul($s22, 666643, 20); 2563 $s11 += self::mul($s22, 470296, 19); 2564 $s12 += self::mul($s22, 654183, 20); 2565 $s13 -= self::mul($s22, 997805, 20); 2566 $s14 += self::mul($s22, 136657, 18); 2567 $s15 -= self::mul($s22, 683901, 20); 2568 2569 $s9 += self::mul($s21, 666643, 20); 2570 $s10 += self::mul($s21, 470296, 19); 2571 $s11 += self::mul($s21, 654183, 20); 2572 $s12 -= self::mul($s21, 997805, 20); 2573 $s13 += self::mul($s21, 136657, 18); 2574 $s14 -= self::mul($s21, 683901, 20); 2575 2576 $s8 += self::mul($s20, 666643, 20); 2577 $s9 += self::mul($s20, 470296, 19); 2578 $s10 += self::mul($s20, 654183, 20); 2579 $s11 -= self::mul($s20, 997805, 20); 2580 $s12 += self::mul($s20, 136657, 18); 2581 $s13 -= self::mul($s20, 683901, 20); 2582 2583 $s7 += self::mul($s19, 666643, 20); 2584 $s8 += self::mul($s19, 470296, 19); 2585 $s9 += self::mul($s19, 654183, 20); 2586 $s10 -= self::mul($s19, 997805, 20); 2587 $s11 += self::mul($s19, 136657, 18); 2588 $s12 -= self::mul($s19, 683901, 20); 2589 2590 $s6 += self::mul($s18, 666643, 20); 2591 $s7 += self::mul($s18, 470296, 19); 2592 $s8 += self::mul($s18, 654183, 20); 2593 $s9 -= self::mul($s18, 997805, 20); 2594 $s10 += self::mul($s18, 136657, 18); 2595 $s11 -= self::mul($s18, 683901, 20); 2596 2597 $carry6 = ($s6 + (1 << 20)) >> 21; 2598 $s7 += $carry6; 2599 $s6 -= $carry6 << 21; 2600 $carry8 = ($s8 + (1 << 20)) >> 21; 2601 $s9 += $carry8; 2602 $s8 -= $carry8 << 21; 2603 $carry10 = ($s10 + (1 << 20)) >> 21; 2604 $s11 += $carry10; 2605 $s10 -= $carry10 << 21; 2606 $carry12 = ($s12 + (1 << 20)) >> 21; 2607 $s13 += $carry12; 2608 $s12 -= $carry12 << 21; 2609 $carry14 = ($s14 + (1 << 20)) >> 21; 2610 $s15 += $carry14; 2611 $s14 -= $carry14 << 21; 2612 $carry16 = ($s16 + (1 << 20)) >> 21; 2613 $s17 += $carry16; 2614 $s16 -= $carry16 << 21; 2615 2616 $carry7 = ($s7 + (1 << 20)) >> 21; 2617 $s8 += $carry7; 2618 $s7 -= $carry7 << 21; 2619 $carry9 = ($s9 + (1 << 20)) >> 21; 2620 $s10 += $carry9; 2621 $s9 -= $carry9 << 21; 2622 $carry11 = ($s11 + (1 << 20)) >> 21; 2623 $s12 += $carry11; 2624 $s11 -= $carry11 << 21; 2625 $carry13 = ($s13 + (1 << 20)) >> 21; 2626 $s14 += $carry13; 2627 $s13 -= $carry13 << 21; 2628 $carry15 = ($s15 + (1 << 20)) >> 21; 2629 $s16 += $carry15; 2630 $s15 -= $carry15 << 21; 2631 2632 $s5 += self::mul($s17, 666643, 20); 2633 $s6 += self::mul($s17, 470296, 19); 2634 $s7 += self::mul($s17, 654183, 20); 2635 $s8 -= self::mul($s17, 997805, 20); 2636 $s9 += self::mul($s17, 136657, 18); 2637 $s10 -= self::mul($s17, 683901, 20); 2638 2639 $s4 += self::mul($s16, 666643, 20); 2640 $s5 += self::mul($s16, 470296, 19); 2641 $s6 += self::mul($s16, 654183, 20); 2642 $s7 -= self::mul($s16, 997805, 20); 2643 $s8 += self::mul($s16, 136657, 18); 2644 $s9 -= self::mul($s16, 683901, 20); 2645 2646 $s3 += self::mul($s15, 666643, 20); 2647 $s4 += self::mul($s15, 470296, 19); 2648 $s5 += self::mul($s15, 654183, 20); 2649 $s6 -= self::mul($s15, 997805, 20); 2650 $s7 += self::mul($s15, 136657, 18); 2651 $s8 -= self::mul($s15, 683901, 20); 2652 2653 $s2 += self::mul($s14, 666643, 20); 2654 $s3 += self::mul($s14, 470296, 19); 2655 $s4 += self::mul($s14, 654183, 20); 2656 $s5 -= self::mul($s14, 997805, 20); 2657 $s6 += self::mul($s14, 136657, 18); 2658 $s7 -= self::mul($s14, 683901, 20); 2659 2660 $s1 += self::mul($s13, 666643, 20); 2661 $s2 += self::mul($s13, 470296, 19); 2662 $s3 += self::mul($s13, 654183, 20); 2663 $s4 -= self::mul($s13, 997805, 20); 2664 $s5 += self::mul($s13, 136657, 18); 2665 $s6 -= self::mul($s13, 683901, 20); 2666 2667 $s0 += self::mul($s12, 666643, 20); 2668 $s1 += self::mul($s12, 470296, 19); 2669 $s2 += self::mul($s12, 654183, 20); 2670 $s3 -= self::mul($s12, 997805, 20); 2671 $s4 += self::mul($s12, 136657, 18); 2672 $s5 -= self::mul($s12, 683901, 20); 2673 $s12 = 0; 2674 2675 $carry0 = ($s0 + (1 << 20)) >> 21; 2676 $s1 += $carry0; 2677 $s0 -= $carry0 << 21; 2678 $carry2 = ($s2 + (1 << 20)) >> 21; 2679 $s3 += $carry2; 2680 $s2 -= $carry2 << 21; 2681 $carry4 = ($s4 + (1 << 20)) >> 21; 2682 $s5 += $carry4; 2683 $s4 -= $carry4 << 21; 2684 $carry6 = ($s6 + (1 << 20)) >> 21; 2685 $s7 += $carry6; 2686 $s6 -= $carry6 << 21; 2687 $carry8 = ($s8 + (1 << 20)) >> 21; 2688 $s9 += $carry8; 2689 $s8 -= $carry8 << 21; 2690 $carry10 = ($s10 + (1 << 20)) >> 21; 2691 $s11 += $carry10; 2692 $s10 -= $carry10 << 21; 2693 2694 $carry1 = ($s1 + (1 << 20)) >> 21; 2695 $s2 += $carry1; 2696 $s1 -= $carry1 << 21; 2697 $carry3 = ($s3 + (1 << 20)) >> 21; 2698 $s4 += $carry3; 2699 $s3 -= $carry3 << 21; 2700 $carry5 = ($s5 + (1 << 20)) >> 21; 2701 $s6 += $carry5; 2702 $s5 -= $carry5 << 21; 2703 $carry7 = ($s7 + (1 << 20)) >> 21; 2704 $s8 += $carry7; 2705 $s7 -= $carry7 << 21; 2706 $carry9 = ($s9 + (1 << 20)) >> 21; 2707 $s10 += $carry9; 2708 $s9 -= $carry9 << 21; 2709 $carry11 = ($s11 + (1 << 20)) >> 21; 2710 $s12 += $carry11; 2711 $s11 -= $carry11 << 21; 2712 2713 $s0 += self::mul($s12, 666643, 20); 2714 $s1 += self::mul($s12, 470296, 19); 2715 $s2 += self::mul($s12, 654183, 20); 2716 $s3 -= self::mul($s12, 997805, 20); 2717 $s4 += self::mul($s12, 136657, 18); 2718 $s5 -= self::mul($s12, 683901, 20); 2719 $s12 = 0; 2720 2721 $carry0 = $s0 >> 21; 2722 $s1 += $carry0; 2723 $s0 -= $carry0 << 21; 2724 $carry1 = $s1 >> 21; 2725 $s2 += $carry1; 2726 $s1 -= $carry1 << 21; 2727 $carry2 = $s2 >> 21; 2728 $s3 += $carry2; 2729 $s2 -= $carry2 << 21; 2730 $carry3 = $s3 >> 21; 2731 $s4 += $carry3; 2732 $s3 -= $carry3 << 21; 2733 $carry4 = $s4 >> 21; 2734 $s5 += $carry4; 2735 $s4 -= $carry4 << 21; 2736 $carry5 = $s5 >> 21; 2737 $s6 += $carry5; 2738 $s5 -= $carry5 << 21; 2739 $carry6 = $s6 >> 21; 2740 $s7 += $carry6; 2741 $s6 -= $carry6 << 21; 2742 $carry7 = $s7 >> 21; 2743 $s8 += $carry7; 2744 $s7 -= $carry7 << 21; 2745 $carry8 = $s8 >> 21; 2746 $s9 += $carry8; 2747 $s8 -= $carry8 << 21; 2748 $carry9 = $s9 >> 21; 2749 $s10 += $carry9; 2750 $s9 -= $carry9 << 21; 2751 $carry10 = $s10 >> 21; 2752 $s11 += $carry10; 2753 $s10 -= $carry10 << 21; 2754 $carry11 = $s11 >> 21; 2755 $s12 += $carry11; 2756 $s11 -= $carry11 << 21; 2757 2758 $s0 += self::mul($s12, 666643, 20); 2759 $s1 += self::mul($s12, 470296, 19); 2760 $s2 += self::mul($s12, 654183, 20); 2761 $s3 -= self::mul($s12, 997805, 20); 2762 $s4 += self::mul($s12, 136657, 18); 2763 $s5 -= self::mul($s12, 683901, 20); 2764 2765 $carry0 = $s0 >> 21; 2766 $s1 += $carry0; 2767 $s0 -= $carry0 << 21; 2768 $carry1 = $s1 >> 21; 2769 $s2 += $carry1; 2770 $s1 -= $carry1 << 21; 2771 $carry2 = $s2 >> 21; 2772 $s3 += $carry2; 2773 $s2 -= $carry2 << 21; 2774 $carry3 = $s3 >> 21; 2775 $s4 += $carry3; 2776 $s3 -= $carry3 << 21; 2777 $carry4 = $s4 >> 21; 2778 $s5 += $carry4; 2779 $s4 -= $carry4 << 21; 2780 $carry5 = $s5 >> 21; 2781 $s6 += $carry5; 2782 $s5 -= $carry5 << 21; 2783 $carry6 = $s6 >> 21; 2784 $s7 += $carry6; 2785 $s6 -= $carry6 << 21; 2786 $carry7 = $s7 >> 21; 2787 $s8 += $carry7; 2788 $s7 -= $carry7 << 21; 2789 $carry8 = $s8 >> 21; 2790 $s9 += $carry8; 2791 $s8 -= $carry8 << 21; 2792 $carry9 = $s9 >> 21; 2793 $s10 += $carry9; 2794 $s9 -= $carry9 << 21; 2795 $carry10 = $s10 >> 21; 2796 $s11 += $carry10; 2797 $s10 -= $carry10 << 21; 2798 2799 /** 2800 * @var array<int, int> 2801 */ <