| [ Index ] |
PHP Cross Reference of WordPress Trunk (Updated Daily) |
[Summary view] [Print] [Text view]
1 <?php 2 3 if (class_exists('ParagonIE_Sodium_Core_Ed25519', false)) { 4 return; 5 } 6 if (!class_exists('ParagonIE_Sodium_Core_Curve25519', false)) { 7 require_once dirname(__FILE__) . '/Curve25519.php'; 8 } 9 10 /** 11 * Class ParagonIE_Sodium_Core_Ed25519 12 */ 13 abstract class ParagonIE_Sodium_Core_Ed25519 extends ParagonIE_Sodium_Core_Curve25519 14 { 15 const KEYPAIR_BYTES = 96; 16 const SEED_BYTES = 32; 17 const SCALAR_BYTES = 32; 18 19 /** 20 * @internal You should not use this directly from another application 21 * 22 * @return string (96 bytes) 23 * @throws Exception 24 * @throws SodiumException 25 * @throws TypeError 26 */ 27 public static function keypair() 28 { 29 $seed = random_bytes(self::SEED_BYTES); 30 $pk = ''; 31 $sk = ''; 32 self::seed_keypair($pk, $sk, $seed); 33 return $sk . $pk; 34 } 35 36 /** 37 * @internal You should not use this directly from another application 38 * 39 * @param string $pk 40 * @param string $sk 41 * @param string $seed 42 * @return string 43 * @throws SodiumException 44 * @throws TypeError 45 */ 46 public static function seed_keypair(&$pk, &$sk, $seed) 47 { 48 if (self::strlen($seed) !== self::SEED_BYTES) { 49 throw new SodiumException('crypto_sign keypair seed must be 32 bytes long'); 50 } 51 52 /** @var string $pk */ 53 $pk = self::publickey_from_secretkey($seed); 54 $sk = $seed . $pk; 55 return $sk; 56 } 57 58 /** 59 * @internal You should not use this directly from another application 60 * 61 * @param string $keypair 62 * @return string 63 * @throws TypeError 64 */ 65 public static function secretkey($keypair) 66 { 67 if (self::strlen($keypair) !== self::KEYPAIR_BYTES) { 68 throw new SodiumException('crypto_sign keypair must be 96 bytes long'); 69 } 70 return self::substr($keypair, 0, 64); 71 } 72 73 /** 74 * @internal You should not use this directly from another application 75 * 76 * @param string $keypair 77 * @return string 78 * @throws TypeError 79 */ 80 public static function publickey($keypair) 81 { 82 if (self::strlen($keypair) !== self::KEYPAIR_BYTES) { 83 throw new SodiumException('crypto_sign keypair must be 96 bytes long'); 84 } 85 return self::substr($keypair, 64, 32); 86 } 87 88 /** 89 * @internal You should not use this directly from another application 90 * 91 * @param string $sk 92 * @return string 93 * @throws SodiumException 94 * @throws TypeError 95 */ 96 public static function publickey_from_secretkey($sk) 97 { 98 /** @var string $sk */ 99 $sk = hash('sha512', self::substr($sk, 0, 32), true); 100 $sk[0] = self::intToChr( 101 self::chrToInt($sk[0]) & 248 102 ); 103 $sk[31] = self::intToChr( 104 (self::chrToInt($sk[31]) & 63) | 64 105 ); 106 return self::sk_to_pk($sk); 107 } 108 109 /** 110 * Returns TRUE if $A represents a point on the order of the Edwards25519 prime order subgroup. 111 * Returns FALSE if $A is on a different subgroup. 112 * 113 * @param ParagonIE_Sodium_Core_Curve25519_Ge_P3 $A 114 * @return bool 115 * 116 * @throws SodiumException 117 */ 118 public static function is_on_main_subgroup(ParagonIE_Sodium_Core_Curve25519_Ge_P3 $A) 119 { 120 $p1 = self::ge_mul_l($A); 121 $t = self::fe_sub($p1->Y, $p1->Z); 122 return !self::fe_isnonzero($p1->X) && !self::fe_isnonzero($t); 123 } 124 125 /** 126 * @param string $pk 127 * @return string 128 * @throws SodiumException 129 * @throws TypeError 130 */ 131 public static function pk_to_curve25519($pk) 132 { 133 if (self::small_order($pk)) { 134 throw new SodiumException('Public key is on a small order'); 135 } 136 $A = self::ge_frombytes_negate_vartime(self::substr($pk, 0, 32)); 137 if (!self::is_on_main_subgroup($A)) { 138 throw new SodiumException('Public key is not on a member of the main subgroup'); 139 } 140 141 # fe_1(one_minus_y); 142 # fe_sub(one_minus_y, one_minus_y, A.Y); 143 # fe_invert(one_minus_y, one_minus_y); 144 $one_minux_y = self::fe_invert( 145 self::fe_sub( 146 self::fe_1(), 147 $A->Y 148 ) 149 ); 150 151 # fe_1(x); 152 # fe_add(x, x, A.Y); 153 # fe_mul(x, x, one_minus_y); 154 $x = self::fe_mul( 155 self::fe_add(self::fe_1(), $A->Y), 156 $one_minux_y 157 ); 158 159 # fe_tobytes(curve25519_pk, x); 160 return self::fe_tobytes($x); 161 } 162 163 /** 164 * @internal You should not use this directly from another application 165 * 166 * @param string $sk 167 * @return string 168 * @throws SodiumException 169 * @throws TypeError 170 */ 171 public static function sk_to_pk($sk) 172 { 173 return self::ge_p3_tobytes( 174 self::ge_scalarmult_base( 175 self::substr($sk, 0, 32) 176 ) 177 ); 178 } 179 180 /** 181 * @internal You should not use this directly from another application 182 * 183 * @param string $message 184 * @param string $sk 185 * @return string 186 * @throws SodiumException 187 * @throws TypeError 188 */ 189 public static function sign($message, $sk) 190 { 191 /** @var string $signature */ 192 $signature = self::sign_detached($message, $sk); 193 return $signature . $message; 194 } 195 196 /** 197 * @internal You should not use this directly from another application 198 * 199 * @param string $message A signed message 200 * @param string $pk Public key 201 * @return string Message (without signature) 202 * @throws SodiumException 203 * @throws TypeError 204 */ 205 public static function sign_open($message, $pk) 206 { 207 /** @var string $signature */ 208 $signature = self::substr($message, 0, 64); 209 210 /** @var string $message */ 211 $message = self::substr($message, 64); 212 213 if (self::verify_detached($signature, $message, $pk)) { 214 return $message; 215 } 216 throw new SodiumException('Invalid signature'); 217 } 218 219 /** 220 * @internal You should not use this directly from another application 221 * 222 * @param string $message 223 * @param string $sk 224 * @return string 225 * @throws SodiumException 226 * @throws TypeError 227 */ 228 public static function sign_detached($message, $sk) 229 { 230 if (self::strlen($sk) !== 64) { 231 throw new SodiumException('Argument 2 must be CRYPTO_SIGN_SECRETKEYBYTES long'); 232 } 233 # crypto_hash_sha512(az, sk, 32); 234 $az = hash('sha512', self::substr($sk, 0, 32), true); 235 236 # az[0] &= 248; 237 # az[31] &= 63; 238 # az[31] |= 64; 239 $az[0] = self::intToChr(self::chrToInt($az[0]) & 248); 240 $az[31] = self::intToChr((self::chrToInt($az[31]) & 63) | 64); 241 242 # crypto_hash_sha512_init(&hs); 243 # crypto_hash_sha512_update(&hs, az + 32, 32); 244 # crypto_hash_sha512_update(&hs, m, mlen); 245 # crypto_hash_sha512_final(&hs, nonce); 246 $hs = hash_init('sha512'); 247 hash_update($hs, self::substr($az, 32, 32)); 248 hash_update($hs, $message); 249 $nonceHash = hash_final($hs, true); 250 251 # memmove(sig + 32, sk + 32, 32); 252 $pk = self::substr($sk, 32, 32); 253 254 # sc_reduce(nonce); 255 # ge_scalarmult_base(&R, nonce); 256 # ge_p3_tobytes(sig, &R); 257 $nonce = self::sc_reduce($nonceHash) . self::substr($nonceHash, 32); 258 $sig = self::ge_p3_tobytes( 259 self::ge_scalarmult_base($nonce) 260 ); 261 262 # crypto_hash_sha512_init(&hs); 263 # crypto_hash_sha512_update(&hs, sig, 64); 264 # crypto_hash_sha512_update(&hs, m, mlen); 265 # crypto_hash_sha512_final(&hs, hram); 266 $hs = hash_init('sha512'); 267 hash_update($hs, self::substr($sig, 0, 32)); 268 hash_update($hs, self::substr($pk, 0, 32)); 269 hash_update($hs, $message); 270 $hramHash = hash_final($hs, true); 271 272 # sc_reduce(hram); 273 # sc_muladd(sig + 32, hram, az, nonce); 274 $hram = self::sc_reduce($hramHash); 275 $sigAfter = self::sc_muladd($hram, $az, $nonce); 276 $sig = self::substr($sig, 0, 32) . self::substr($sigAfter, 0, 32); 277 278 try { 279 ParagonIE_Sodium_Compat::memzero($az); 280 } catch (SodiumException $ex) { 281 $az = null; 282 } 283 return $sig; 284 } 285 286 /** 287 * @internal You should not use this directly from another application 288 * 289 * @param string $sig 290 * @param string $message 291 * @param string $pk 292 * @return bool 293 * @throws SodiumException 294 * @throws TypeError 295 */ 296 public static function verify_detached($sig, $message, $pk) 297 { 298 if (self::strlen($sig) !== 64) { 299 throw new SodiumException('Argument 1 must be CRYPTO_SIGN_BYTES long'); 300 } 301 if (self::strlen($pk) !== 32) { 302 throw new SodiumException('Argument 3 must be CRYPTO_SIGN_PUBLICKEYBYTES long'); 303 } 304 if ((self::chrToInt($sig[63]) & 240) && self::check_S_lt_L(self::substr($sig, 32, 32))) { 305 throw new SodiumException('S >= L - Invalid signature'); 306 } 307 if (self::small_order($sig)) { 308 throw new SodiumException('Signature is on too small of an order'); 309 } 310 if ((self::chrToInt($sig[63]) & 224) !== 0) { 311 throw new SodiumException('Invalid signature'); 312 } 313 $d = 0; 314 for ($i = 0; $i < 32; ++$i) { 315 $d |= self::chrToInt($pk[$i]); 316 } 317 if ($d === 0) { 318 throw new SodiumException('All zero public key'); 319 } 320 if (self::small_order($pk)) { 321 throw new SodiumException('Public key has small order'); 322 } 323 324 /** @var bool The original value of ParagonIE_Sodium_Compat::$fastMult */ 325 $orig = ParagonIE_Sodium_Compat::$fastMult; 326 327 // Set ParagonIE_Sodium_Compat::$fastMult to true to speed up verification. 328 ParagonIE_Sodium_Compat::$fastMult = true; 329 try { 330 /** @var ParagonIE_Sodium_Core_Curve25519_Ge_P3 $A */ 331 $A = self::ge_frombytes_negate_vartime($pk); 332 if (!self::is_on_main_subgroup($A)) { 333 throw new SodiumException('Public key is not on a member of the main subgroup'); 334 } 335 336 /** @var string $hDigest */ 337 $hDigest = hash( 338 'sha512', 339 self::substr($sig, 0, 32) . 340 self::substr($pk, 0, 32) . 341 $message, 342 true 343 ); 344 345 /** @var string $h */ 346 $h = self::sc_reduce($hDigest) . self::substr($hDigest, 32); 347 348 /** @var ParagonIE_Sodium_Core_Curve25519_Ge_P2 $R */ 349 $R = self::ge_double_scalarmult_vartime( 350 $h, 351 $A, 352 self::substr($sig, 32) 353 ); 354 355 /** @var string $rcheck */ 356 $rcheck = self::ge_tobytes($R); 357 } catch (Exception $ex) { 358 ParagonIE_Sodium_Compat::$fastMult = $orig; 359 throw $ex; 360 } 361 362 // Reset ParagonIE_Sodium_Compat::$fastMult to what it was before. 363 ParagonIE_Sodium_Compat::$fastMult = $orig; 364 365 return self::verify_32($rcheck, self::substr($sig, 0, 32)); 366 } 367 368 /** 369 * @internal You should not use this directly from another application 370 * 371 * @param string $S 372 * @return bool 373 * @throws SodiumException 374 * @throws TypeError 375 */ 376 public static function check_S_lt_L($S) 377 { 378 if (self::strlen($S) < 32) { 379 throw new SodiumException('Signature must be 32 bytes'); 380 } 381 $L = array( 382 0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, 383 0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14, 384 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 385 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10 386 ); 387 $c = 0; 388 $n = 1; 389 $i = 32; 390 391 /** @var array<int, int> $L */ 392 do { 393 --$i; 394 $x = self::chrToInt($S[$i]); 395 $c |= ( 396 (($x - $L[$i]) >> 8) & $n 397 ); 398 $n &= ( 399 (($x ^ $L[$i]) - 1) >> 8 400 ); 401 } while ($i !== 0); 402 403 return $c === 0; 404 } 405 406 /** 407 * @param string $R 408 * @return bool 409 * @throws SodiumException 410 * @throws TypeError 411 */ 412 public static function small_order($R) 413 { 414 /** @var array<int, array<int, int>> $blocklist */ 415 $blocklist = array( 416 /* 0 (order 4) */ 417 array( 418 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 419 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 420 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 421 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 422 ), 423 /* 1 (order 1) */ 424 array( 425 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 426 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 427 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 428 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 429 ), 430 /* 2707385501144840649318225287225658788936804267575313519463743609750303402022 (order 8) */ 431 array( 432 0x26, 0xe8, 0x95, 0x8f, 0xc2, 0xb2, 0x27, 0xb0, 433 0x45, 0xc3, 0xf4, 0x89, 0xf2, 0xef, 0x98, 0xf0, 434 0xd5, 0xdf, 0xac, 0x05, 0xd3, 0xc6, 0x33, 0x39, 435 0xb1, 0x38, 0x02, 0x88, 0x6d, 0x53, 0xfc, 0x05 436 ), 437 /* 55188659117513257062467267217118295137698188065244968500265048394206261417927 (order 8) */ 438 array( 439 0xc7, 0x17, 0x6a, 0x70, 0x3d, 0x4d, 0xd8, 0x4f, 440 0xba, 0x3c, 0x0b, 0x76, 0x0d, 0x10, 0x67, 0x0f, 441 0x2a, 0x20, 0x53, 0xfa, 0x2c, 0x39, 0xcc, 0xc6, 442 0x4e, 0xc7, 0xfd, 0x77, 0x92, 0xac, 0x03, 0x7a 443 ), 444 /* p-1 (order 2) */ 445 array( 446 0x13, 0xe8, 0x95, 0x8f, 0xc2, 0xb2, 0x27, 0xb0, 447 0x45, 0xc3, 0xf4, 0x89, 0xf2, 0xef, 0x98, 0xf0, 448 0xd5, 0xdf, 0xac, 0x05, 0xd3, 0xc6, 0x33, 0x39, 449 0xb1, 0x38, 0x02, 0x88, 0x6d, 0x53, 0xfc, 0x85 450 ), 451 /* p (order 4) */ 452 array( 453 0xb4, 0x17, 0x6a, 0x70, 0x3d, 0x4d, 0xd8, 0x4f, 454 0xba, 0x3c, 0x0b, 0x76, 0x0d, 0x10, 0x67, 0x0f, 455 0x2a, 0x20, 0x53, 0xfa, 0x2c, 0x39, 0xcc, 0xc6, 456 0x4e, 0xc7, 0xfd, 0x77, 0x92, 0xac, 0x03, 0xfa 457 ), 458 /* p+1 (order 1) */ 459 array( 460 0xec, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 461 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 462 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 463 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f 464 ), 465 /* p+2707385501144840649318225287225658788936804267575313519463743609750303402022 (order 8) */ 466 array( 467 0xed, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 468 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 469 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 470 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f 471 ), 472 /* p+55188659117513257062467267217118295137698188065244968500265048394206261417927 (order 8) */ 473 array( 474 0xee, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 475 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 476 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 477 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f 478 ), 479 /* 2p-1 (order 2) */ 480 array( 481 0xd9, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 482 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 483 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 484 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff 485 ), 486 /* 2p (order 4) */ 487 array( 488 0xda, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 489 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 490 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 491 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff 492 ), 493 /* 2p+1 (order 1) */ 494 array( 495 0xdb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 496 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 497 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 498 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff 499 ) 500 ); 501 /** @var int $countBlocklist */ 502 $countBlocklist = count($blocklist); 503 504 for ($i = 0; $i < $countBlocklist; ++$i) { 505 $c = 0; 506 for ($j = 0; $j < 32; ++$j) { 507 $c |= self::chrToInt($R[$j]) ^ (int) $blocklist[$i][$j]; 508 } 509 if ($c === 0) { 510 return true; 511 } 512 } 513 return false; 514 } 515 516 /** 517 * @param string $s 518 * @return string 519 * @throws SodiumException 520 */ 521 public static function scalar_complement($s) 522 { 523 $t_ = self::L . str_repeat("\x00", 32); 524 sodium_increment($t_); 525 $s_ = $s . str_repeat("\x00", 32); 526 ParagonIE_Sodium_Compat::sub($t_, $s_); 527 return self::sc_reduce($t_); 528 } 529 530 /** 531 * @return string 532 * @throws SodiumException 533 */ 534 public static function scalar_random() 535 { 536 do { 537 $r = ParagonIE_Sodium_Compat::randombytes_buf(self::SCALAR_BYTES); 538 $r[self::SCALAR_BYTES - 1] = self::intToChr( 539 self::chrToInt($r[self::SCALAR_BYTES - 1]) & 0x1f 540 ); 541 } while ( 542 !self::check_S_lt_L($r) || ParagonIE_Sodium_Compat::is_zero($r) 543 ); 544 return $r; 545 } 546 547 /** 548 * @param string $s 549 * @return string 550 * @throws SodiumException 551 */ 552 public static function scalar_negate($s) 553 { 554 $t_ = self::L . str_repeat("\x00", 32) ; 555 $s_ = $s . str_repeat("\x00", 32) ; 556 ParagonIE_Sodium_Compat::sub($t_, $s_); 557 return self::sc_reduce($t_); 558 } 559 560 /** 561 * @param string $a 562 * @param string $b 563 * @return string 564 * @throws SodiumException 565 */ 566 public static function scalar_add($a, $b) 567 { 568 $a_ = $a . str_repeat("\x00", 32); 569 $b_ = $b . str_repeat("\x00", 32); 570 ParagonIE_Sodium_Compat::add($a_, $b_); 571 return self::sc_reduce($a_); 572 } 573 574 /** 575 * @param string $x 576 * @param string $y 577 * @return string 578 * @throws SodiumException 579 */ 580 public static function scalar_sub($x, $y) 581 { 582 $yn = self::scalar_negate($y); 583 return self::scalar_add($x, $yn); 584 } 585 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
| Generated : Sat Nov 14 08:20:01 2026 | Cross-referenced by PHPXref |