diff options
Diffstat (limited to 'vendor/paragonie/sodium_compat/src/Core/Ed25519.php')
-rw-r--r-- | vendor/paragonie/sodium_compat/src/Core/Ed25519.php | 551 |
1 files changed, 551 insertions, 0 deletions
diff --git a/vendor/paragonie/sodium_compat/src/Core/Ed25519.php b/vendor/paragonie/sodium_compat/src/Core/Ed25519.php new file mode 100644 index 0000000..c29f493 --- /dev/null +++ b/vendor/paragonie/sodium_compat/src/Core/Ed25519.php @@ -0,0 +1,551 @@ +<?php
+
+if (class_exists('ParagonIE_Sodium_Core_Ed25519', false)) {
+ return;
+}
+
+/**
+ * Class ParagonIE_Sodium_Core_Ed25519
+ */
+abstract class ParagonIE_Sodium_Core_Ed25519 extends ParagonIE_Sodium_Core_Curve25519
+{
+ const KEYPAIR_BYTES = 96;
+ const SEED_BYTES = 32;
+ const SCALAR_BYTES = 32;
+
+ /**
+ * @internal You should not use this directly from another application
+ *
+ * @return string (96 bytes)
+ * @throws Exception
+ * @throws SodiumException
+ * @throws TypeError
+ */
+ public static function keypair()
+ {
+ $seed = random_bytes(self::SEED_BYTES);
+ $pk = '';
+ $sk = '';
+ self::seed_keypair($pk, $sk, $seed);
+ return $sk . $pk;
+ }
+
+ /**
+ * @internal You should not use this directly from another application
+ *
+ * @param string $pk
+ * @param string $sk
+ * @param string $seed
+ * @return string
+ * @throws SodiumException
+ * @throws TypeError
+ */
+ public static function seed_keypair(&$pk, &$sk, $seed)
+ {
+ if (self::strlen($seed) !== self::SEED_BYTES) {
+ throw new RangeException('crypto_sign keypair seed must be 32 bytes long');
+ }
+
+ /** @var string $pk */
+ $pk = self::publickey_from_secretkey($seed);
+ $sk = $seed . $pk;
+ return $sk;
+ }
+
+ /**
+ * @internal You should not use this directly from another application
+ *
+ * @param string $keypair
+ * @return string
+ * @throws TypeError
+ */
+ public static function secretkey($keypair)
+ {
+ if (self::strlen($keypair) !== self::KEYPAIR_BYTES) {
+ throw new RangeException('crypto_sign keypair must be 96 bytes long');
+ }
+ return self::substr($keypair, 0, 64);
+ }
+
+ /**
+ * @internal You should not use this directly from another application
+ *
+ * @param string $keypair
+ * @return string
+ * @throws TypeError
+ */
+ public static function publickey($keypair)
+ {
+ if (self::strlen($keypair) !== self::KEYPAIR_BYTES) {
+ throw new RangeException('crypto_sign keypair must be 96 bytes long');
+ }
+ return self::substr($keypair, 64, 32);
+ }
+
+ /**
+ * @internal You should not use this directly from another application
+ *
+ * @param string $sk
+ * @return string
+ * @throws SodiumException
+ * @throws TypeError
+ */
+ public static function publickey_from_secretkey($sk)
+ {
+ /** @var string $sk */
+ $sk = hash('sha512', self::substr($sk, 0, 32), true);
+ $sk[0] = self::intToChr(
+ self::chrToInt($sk[0]) & 248
+ );
+ $sk[31] = self::intToChr(
+ (self::chrToInt($sk[31]) & 63) | 64
+ );
+ return self::sk_to_pk($sk);
+ }
+
+ /**
+ * @param string $pk
+ * @return string
+ * @throws SodiumException
+ * @throws TypeError
+ */
+ public static function pk_to_curve25519($pk)
+ {
+ if (self::small_order($pk)) {
+ throw new SodiumException('Public key is on a small order');
+ }
+ $A = self::ge_frombytes_negate_vartime(self::substr($pk, 0, 32));
+ $p1 = self::ge_mul_l($A);
+ if (!self::fe_isnonzero($p1->X)) {
+ throw new SodiumException('Unexpected zero result');
+ }
+
+ # fe_1(one_minus_y);
+ # fe_sub(one_minus_y, one_minus_y, A.Y);
+ # fe_invert(one_minus_y, one_minus_y);
+ $one_minux_y = self::fe_invert(
+ self::fe_sub(
+ self::fe_1(),
+ $A->Y
+ )
+ );
+
+ # fe_1(x);
+ # fe_add(x, x, A.Y);
+ # fe_mul(x, x, one_minus_y);
+ $x = self::fe_mul(
+ self::fe_add(self::fe_1(), $A->Y),
+ $one_minux_y
+ );
+
+ # fe_tobytes(curve25519_pk, x);
+ return self::fe_tobytes($x);
+ }
+
+ /**
+ * @internal You should not use this directly from another application
+ *
+ * @param string $sk
+ * @return string
+ * @throws SodiumException
+ * @throws TypeError
+ */
+ public static function sk_to_pk($sk)
+ {
+ return self::ge_p3_tobytes(
+ self::ge_scalarmult_base(
+ self::substr($sk, 0, 32)
+ )
+ );
+ }
+
+ /**
+ * @internal You should not use this directly from another application
+ *
+ * @param string $message
+ * @param string $sk
+ * @return string
+ * @throws SodiumException
+ * @throws TypeError
+ */
+ public static function sign($message, $sk)
+ {
+ /** @var string $signature */
+ $signature = self::sign_detached($message, $sk);
+ return $signature . $message;
+ }
+
+ /**
+ * @internal You should not use this directly from another application
+ *
+ * @param string $message A signed message
+ * @param string $pk Public key
+ * @return string Message (without signature)
+ * @throws SodiumException
+ * @throws TypeError
+ */
+ public static function sign_open($message, $pk)
+ {
+ /** @var string $signature */
+ $signature = self::substr($message, 0, 64);
+
+ /** @var string $message */
+ $message = self::substr($message, 64);
+
+ if (self::verify_detached($signature, $message, $pk)) {
+ return $message;
+ }
+ throw new SodiumException('Invalid signature');
+ }
+
+ /**
+ * @internal You should not use this directly from another application
+ *
+ * @param string $message
+ * @param string $sk
+ * @return string
+ * @throws SodiumException
+ * @throws TypeError
+ */
+ public static function sign_detached($message, $sk)
+ {
+ # crypto_hash_sha512(az, sk, 32);
+ $az = hash('sha512', self::substr($sk, 0, 32), true);
+
+ # az[0] &= 248;
+ # az[31] &= 63;
+ # az[31] |= 64;
+ $az[0] = self::intToChr(self::chrToInt($az[0]) & 248);
+ $az[31] = self::intToChr((self::chrToInt($az[31]) & 63) | 64);
+
+ # crypto_hash_sha512_init(&hs);
+ # crypto_hash_sha512_update(&hs, az + 32, 32);
+ # crypto_hash_sha512_update(&hs, m, mlen);
+ # crypto_hash_sha512_final(&hs, nonce);
+ $hs = hash_init('sha512');
+ hash_update($hs, self::substr($az, 32, 32));
+ hash_update($hs, $message);
+ $nonceHash = hash_final($hs, true);
+
+ # memmove(sig + 32, sk + 32, 32);
+ $pk = self::substr($sk, 32, 32);
+
+ # sc_reduce(nonce);
+ # ge_scalarmult_base(&R, nonce);
+ # ge_p3_tobytes(sig, &R);
+ $nonce = self::sc_reduce($nonceHash) . self::substr($nonceHash, 32);
+ $sig = self::ge_p3_tobytes(
+ self::ge_scalarmult_base($nonce)
+ );
+
+ # crypto_hash_sha512_init(&hs);
+ # crypto_hash_sha512_update(&hs, sig, 64);
+ # crypto_hash_sha512_update(&hs, m, mlen);
+ # crypto_hash_sha512_final(&hs, hram);
+ $hs = hash_init('sha512');
+ hash_update($hs, self::substr($sig, 0, 32));
+ hash_update($hs, self::substr($pk, 0, 32));
+ hash_update($hs, $message);
+ $hramHash = hash_final($hs, true);
+
+ # sc_reduce(hram);
+ # sc_muladd(sig + 32, hram, az, nonce);
+ $hram = self::sc_reduce($hramHash);
+ $sigAfter = self::sc_muladd($hram, $az, $nonce);
+ $sig = self::substr($sig, 0, 32) . self::substr($sigAfter, 0, 32);
+
+ try {
+ ParagonIE_Sodium_Compat::memzero($az);
+ } catch (SodiumException $ex) {
+ $az = null;
+ }
+ return $sig;
+ }
+
+ /**
+ * @internal You should not use this directly from another application
+ *
+ * @param string $sig
+ * @param string $message
+ * @param string $pk
+ * @return bool
+ * @throws SodiumException
+ * @throws TypeError
+ */
+ public static function verify_detached($sig, $message, $pk)
+ {
+ if (self::strlen($sig) < 64) {
+ throw new SodiumException('Signature is too short');
+ }
+ if ((self::chrToInt($sig[63]) & 240) && self::check_S_lt_L(self::substr($sig, 32, 32))) {
+ throw new SodiumException('S < L - Invalid signature');
+ }
+ if (self::small_order($sig)) {
+ throw new SodiumException('Signature is on too small of an order');
+ }
+ if ((self::chrToInt($sig[63]) & 224) !== 0) {
+ throw new SodiumException('Invalid signature');
+ }
+ $d = 0;
+ for ($i = 0; $i < 32; ++$i) {
+ $d |= self::chrToInt($pk[$i]);
+ }
+ if ($d === 0) {
+ throw new SodiumException('All zero public key');
+ }
+
+ /** @var bool The original value of ParagonIE_Sodium_Compat::$fastMult */
+ $orig = ParagonIE_Sodium_Compat::$fastMult;
+
+ // Set ParagonIE_Sodium_Compat::$fastMult to true to speed up verification.
+ ParagonIE_Sodium_Compat::$fastMult = true;
+
+ /** @var ParagonIE_Sodium_Core_Curve25519_Ge_P3 $A */
+ $A = self::ge_frombytes_negate_vartime($pk);
+
+ /** @var string $hDigest */
+ $hDigest = hash(
+ 'sha512',
+ self::substr($sig, 0, 32) .
+ self::substr($pk, 0, 32) .
+ $message,
+ true
+ );
+
+ /** @var string $h */
+ $h = self::sc_reduce($hDigest) . self::substr($hDigest, 32);
+
+ /** @var ParagonIE_Sodium_Core_Curve25519_Ge_P2 $R */
+ $R = self::ge_double_scalarmult_vartime(
+ $h,
+ $A,
+ self::substr($sig, 32)
+ );
+
+ /** @var string $rcheck */
+ $rcheck = self::ge_tobytes($R);
+
+ // Reset ParagonIE_Sodium_Compat::$fastMult to what it was before.
+ ParagonIE_Sodium_Compat::$fastMult = $orig;
+
+ return self::verify_32($rcheck, self::substr($sig, 0, 32));
+ }
+
+ /**
+ * @internal You should not use this directly from another application
+ *
+ * @param string $S
+ * @return bool
+ * @throws SodiumException
+ * @throws TypeError
+ */
+ public static function check_S_lt_L($S)
+ {
+ if (self::strlen($S) < 32) {
+ throw new SodiumException('Signature must be 32 bytes');
+ }
+ $L = array(
+ 0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58,
+ 0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10
+ );
+ $c = 0;
+ $n = 1;
+ $i = 32;
+
+ /** @var array<int, int> $L */
+ do {
+ --$i;
+ $x = self::chrToInt($S[$i]);
+ $c |= (
+ (($x - $L[$i]) >> 8) & $n
+ );
+ $n &= (
+ (($x ^ $L[$i]) - 1) >> 8
+ );
+ } while ($i !== 0);
+
+ return $c === 0;
+ }
+
+ /**
+ * @param string $R
+ * @return bool
+ * @throws SodiumException
+ * @throws TypeError
+ */
+ public static function small_order($R)
+ {
+ /** @var array<int, array<int, int>> $blocklist */
+ $blocklist = array(
+ /* 0 (order 4) */
+ array(
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+ ),
+ /* 1 (order 1) */
+ array(
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+ ),
+ /* 2707385501144840649318225287225658788936804267575313519463743609750303402022 (order 8) */
+ array(
+ 0x26, 0xe8, 0x95, 0x8f, 0xc2, 0xb2, 0x27, 0xb0,
+ 0x45, 0xc3, 0xf4, 0x89, 0xf2, 0xef, 0x98, 0xf0,
+ 0xd5, 0xdf, 0xac, 0x05, 0xd3, 0xc6, 0x33, 0x39,
+ 0xb1, 0x38, 0x02, 0x88, 0x6d, 0x53, 0xfc, 0x05
+ ),
+ /* 55188659117513257062467267217118295137698188065244968500265048394206261417927 (order 8) */
+ array(
+ 0xc7, 0x17, 0x6a, 0x70, 0x3d, 0x4d, 0xd8, 0x4f,
+ 0xba, 0x3c, 0x0b, 0x76, 0x0d, 0x10, 0x67, 0x0f,
+ 0x2a, 0x20, 0x53, 0xfa, 0x2c, 0x39, 0xcc, 0xc6,
+ 0x4e, 0xc7, 0xfd, 0x77, 0x92, 0xac, 0x03, 0x7a
+ ),
+ /* p-1 (order 2) */
+ array(
+ 0x13, 0xe8, 0x95, 0x8f, 0xc2, 0xb2, 0x27, 0xb0,
+ 0x45, 0xc3, 0xf4, 0x89, 0xf2, 0xef, 0x98, 0xf0,
+ 0xd5, 0xdf, 0xac, 0x05, 0xd3, 0xc6, 0x33, 0x39,
+ 0xb1, 0x38, 0x02, 0x88, 0x6d, 0x53, 0xfc, 0x85
+ ),
+ /* p (order 4) */
+ array(
+ 0xb4, 0x17, 0x6a, 0x70, 0x3d, 0x4d, 0xd8, 0x4f,
+ 0xba, 0x3c, 0x0b, 0x76, 0x0d, 0x10, 0x67, 0x0f,
+ 0x2a, 0x20, 0x53, 0xfa, 0x2c, 0x39, 0xcc, 0xc6,
+ 0x4e, 0xc7, 0xfd, 0x77, 0x92, 0xac, 0x03, 0xfa
+ ),
+ /* p+1 (order 1) */
+ array(
+ 0xec, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f
+ ),
+ /* p+2707385501144840649318225287225658788936804267575313519463743609750303402022 (order 8) */
+ array(
+ 0xed, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f
+ ),
+ /* p+55188659117513257062467267217118295137698188065244968500265048394206261417927 (order 8) */
+ array(
+ 0xee, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f
+ ),
+ /* 2p-1 (order 2) */
+ array(
+ 0xd9, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+ ),
+ /* 2p (order 4) */
+ array(
+ 0xda, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+ ),
+ /* 2p+1 (order 1) */
+ array(
+ 0xdb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+ )
+ );
+ /** @var int $countBlocklist */
+ $countBlocklist = count($blocklist);
+
+ for ($i = 0; $i < $countBlocklist; ++$i) {
+ $c = 0;
+ for ($j = 0; $j < 32; ++$j) {
+ $c |= self::chrToInt($R[$j]) ^ (int) $blocklist[$i][$j];
+ }
+ if ($c === 0) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * @param string $s
+ * @return string
+ * @throws SodiumException
+ */
+ public static function scalar_complement($s)
+ {
+ $t_ = self::L . str_repeat("\x00", 32);
+ sodium_increment($t_);
+ $s_ = $s . str_repeat("\x00", 32);
+ ParagonIE_Sodium_Compat::sub($t_, $s_);
+ return self::sc_reduce($t_);
+ }
+
+ /**
+ * @return string
+ * @throws SodiumException
+ */
+ public static function scalar_random()
+ {
+ do {
+ $r = ParagonIE_Sodium_Compat::randombytes_buf(self::SCALAR_BYTES);
+ $r[self::SCALAR_BYTES - 1] = self::intToChr(
+ self::chrToInt($r[self::SCALAR_BYTES - 1]) & 0x1f
+ );
+ } while (
+ !self::check_S_lt_L($r) || ParagonIE_Sodium_Compat::is_zero($r)
+ );
+ return $r;
+ }
+
+ /**
+ * @param string $s
+ * @return string
+ * @throws SodiumException
+ */
+ public static function scalar_negate($s)
+ {
+ $t_ = self::L . str_repeat("\x00", 32) ;
+ $s_ = $s . str_repeat("\x00", 32) ;
+ ParagonIE_Sodium_Compat::sub($t_, $s_);
+ return self::sc_reduce($t_);
+ }
+
+ /**
+ * @param string $a
+ * @param string $b
+ * @return string
+ * @throws SodiumException
+ */
+ public static function scalar_add($a, $b)
+ {
+ $a_ = $a . str_repeat("\x00", 32);
+ $b_ = $b . str_repeat("\x00", 32);
+ ParagonIE_Sodium_Compat::add($a_, $b_);
+ return self::sc_reduce($a_);
+ }
+
+ /**
+ * @param string $x
+ * @param string $y
+ * @return string
+ * @throws SodiumException
+ */
+ public static function scalar_sub($x, $y)
+ {
+ $yn = self::scalar_negate($y);
+ return self::scalar_add($x, $yn);
+ }
+}
|