[ Index ]

PHP Cross Reference of WordPress

title

Body

[close]

/wp-includes/sodium_compat/src/Core/ -> Ed25519.php (source)

   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  }


Generated: Fri Apr 26 01:00:03 2024 Cross-referenced by PHPXref 0.7.1