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