| [ 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 321 /** @var bool The original value of ParagonIE_Sodium_Compat::$fastMult */ 322 $orig = ParagonIE_Sodium_Compat::$fastMult; 323 324 // Set ParagonIE_Sodium_Compat::$fastMult to true to speed up verification. 325 ParagonIE_Sodium_Compat::$fastMult = true; 326 327 /** @var ParagonIE_Sodium_Core_Curve25519_Ge_P3 $A */ 328 $A = self::ge_frombytes_negate_vartime($pk); 329 if (!self::is_on_main_subgroup($A)) { 330 throw new SodiumException('Public key is not on a member of the main subgroup'); 331 } 332 333 /** @var string $hDigest */ 334 $hDigest = hash( 335 'sha512', 336 self::substr($sig, 0, 32) . 337 self::substr($pk, 0, 32) . 338 $message, 339 true 340 ); 341 342 /** @var string $h */ 343 $h = self::sc_reduce($hDigest) . self::substr($hDigest, 32); 344 345 /** @var ParagonIE_Sodium_Core_Curve25519_Ge_P2 $R */ 346 $R = self::ge_double_scalarmult_vartime( 347 $h, 348 $A, 349 self::substr($sig, 32) 350 ); 351 352 /** @var string $rcheck */ 353 $rcheck = self::ge_tobytes($R); 354 355 // Reset ParagonIE_Sodium_Compat::$fastMult to what it was before. 356 ParagonIE_Sodium_Compat::$fastMult = $orig; 357 358 return self::verify_32($rcheck, self::substr($sig, 0, 32)); 359 } 360 361 /** 362 * @internal You should not use this directly from another application 363 * 364 * @param string $S 365 * @return bool 366 * @throws SodiumException 367 * @throws TypeError 368 */ 369 public static function check_S_lt_L($S) 370 { 371 if (self::strlen($S) < 32) { 372 throw new SodiumException('Signature must be 32 bytes'); 373 } 374 $L = array( 375 0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, 376 0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14, 377 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 378 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10 379 ); 380 $c = 0; 381 $n = 1; 382 $i = 32; 383 384 /** @var array<int, int> $L */ 385 do { 386 --$i; 387 $x = self::chrToInt($S[$i]); 388 $c |= ( 389 (($x - $L[$i]) >> 8) & $n 390 ); 391 $n &= ( 392 (($x ^ $L[$i]) - 1) >> 8 393 ); 394 } while ($i !== 0); 395 396 return $c === 0; 397 } 398 399 /** 400 * @param string $R 401 * @return bool 402 * @throws SodiumException 403 * @throws TypeError 404 */ 405 public static function small_order($R) 406 { 407 /** @var array<int, array<int, int>> $blocklist */ 408 $blocklist = array( 409 /* 0 (order 4) */ 410 array( 411 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 412 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 413 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 414 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 415 ), 416 /* 1 (order 1) */ 417 array( 418 0x01, 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 /* 2707385501144840649318225287225658788936804267575313519463743609750303402022 (order 8) */ 424 array( 425 0x26, 0xe8, 0x95, 0x8f, 0xc2, 0xb2, 0x27, 0xb0, 426 0x45, 0xc3, 0xf4, 0x89, 0xf2, 0xef, 0x98, 0xf0, 427 0xd5, 0xdf, 0xac, 0x05, 0xd3, 0xc6, 0x33, 0x39, 428 0xb1, 0x38, 0x02, 0x88, 0x6d, 0x53, 0xfc, 0x05 429 ), 430 /* 55188659117513257062467267217118295137698188065244968500265048394206261417927 (order 8) */ 431 array( 432 0xc7, 0x17, 0x6a, 0x70, 0x3d, 0x4d, 0xd8, 0x4f, 433 0xba, 0x3c, 0x0b, 0x76, 0x0d, 0x10, 0x67, 0x0f, 434 0x2a, 0x20, 0x53, 0xfa, 0x2c, 0x39, 0xcc, 0xc6, 435 0x4e, 0xc7, 0xfd, 0x77, 0x92, 0xac, 0x03, 0x7a 436 ), 437 /* p-1 (order 2) */ 438 array( 439 0x13, 0xe8, 0x95, 0x8f, 0xc2, 0xb2, 0x27, 0xb0, 440 0x45, 0xc3, 0xf4, 0x89, 0xf2, 0xef, 0x98, 0xf0, 441 0xd5, 0xdf, 0xac, 0x05, 0xd3, 0xc6, 0x33, 0x39, 442 0xb1, 0x38, 0x02, 0x88, 0x6d, 0x53, 0xfc, 0x85 443 ), 444 /* p (order 4) */ 445 array( 446 0xb4, 0x17, 0x6a, 0x70, 0x3d, 0x4d, 0xd8, 0x4f, 447 0xba, 0x3c, 0x0b, 0x76, 0x0d, 0x10, 0x67, 0x0f, 448 0x2a, 0x20, 0x53, 0xfa, 0x2c, 0x39, 0xcc, 0xc6, 449 0x4e, 0xc7, 0xfd, 0x77, 0x92, 0xac, 0x03, 0xfa 450 ), 451 /* p+1 (order 1) */ 452 array( 453 0xec, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 454 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 455 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 456 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f 457 ), 458 /* p+2707385501144840649318225287225658788936804267575313519463743609750303402022 (order 8) */ 459 array( 460 0xed, 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+55188659117513257062467267217118295137698188065244968500265048394206261417927 (order 8) */ 466 array( 467 0xee, 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 /* 2p-1 (order 2) */ 473 array( 474 0xd9, 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, 0xff 478 ), 479 /* 2p (order 4) */ 480 array( 481 0xda, 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+1 (order 1) */ 487 array( 488 0xdb, 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 ); 494 /** @var int $countBlocklist */ 495 $countBlocklist = count($blocklist); 496 497 for ($i = 0; $i < $countBlocklist; ++$i) { 498 $c = 0; 499 for ($j = 0; $j < 32; ++$j) { 500 $c |= self::chrToInt($R[$j]) ^ (int) $blocklist[$i][$j]; 501 } 502 if ($c === 0) { 503 return true; 504 } 505 } 506 return false; 507 } 508 509 /** 510 * @param string $s 511 * @return string 512 * @throws SodiumException 513 */ 514 public static function scalar_complement($s) 515 { 516 $t_ = self::L . str_repeat("\x00", 32); 517 sodium_increment($t_); 518 $s_ = $s . str_repeat("\x00", 32); 519 ParagonIE_Sodium_Compat::sub($t_, $s_); 520 return self::sc_reduce($t_); 521 } 522 523 /** 524 * @return string 525 * @throws SodiumException 526 */ 527 public static function scalar_random() 528 { 529 do { 530 $r = ParagonIE_Sodium_Compat::randombytes_buf(self::SCALAR_BYTES); 531 $r[self::SCALAR_BYTES - 1] = self::intToChr( 532 self::chrToInt($r[self::SCALAR_BYTES - 1]) & 0x1f 533 ); 534 } while ( 535 !self::check_S_lt_L($r) || ParagonIE_Sodium_Compat::is_zero($r) 536 ); 537 return $r; 538 } 539 540 /** 541 * @param string $s 542 * @return string 543 * @throws SodiumException 544 */ 545 public static function scalar_negate($s) 546 { 547 $t_ = self::L . str_repeat("\x00", 32) ; 548 $s_ = $s . str_repeat("\x00", 32) ; 549 ParagonIE_Sodium_Compat::sub($t_, $s_); 550 return self::sc_reduce($t_); 551 } 552 553 /** 554 * @param string $a 555 * @param string $b 556 * @return string 557 * @throws SodiumException 558 */ 559 public static function scalar_add($a, $b) 560 { 561 $a_ = $a . str_repeat("\x00", 32); 562 $b_ = $b . str_repeat("\x00", 32); 563 ParagonIE_Sodium_Compat::add($a_, $b_); 564 return self::sc_reduce($a_); 565 } 566 567 /** 568 * @param string $x 569 * @param string $y 570 * @return string 571 * @throws SodiumException 572 */ 573 public static function scalar_sub($x, $y) 574 { 575 $yn = self::scalar_negate($y); 576 return self::scalar_add($x, $yn); 577 } 578 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
| Generated : Thu Feb 26 08:20:04 2026 | Cross-referenced by PHPXref |