checkKey($key); if (! $key->has('d')) { throw new InvalidArgumentException('The EC key is not private'); } $d = $key->get('d'); if (! is_string($d) || $d === '') { throw new InvalidArgumentException('Invalid "d" parameter.'); } if (! $key->has('x')) { $x = self::getPublicKey($key); } else { $x = $key->get('x'); } if (! is_string($x) || $x === '') { throw new InvalidArgumentException('Invalid "x" parameter.'); } /** @var non-empty-string $x */ $x = Base64UrlSafe::decodeNoPadding($x); /** @var non-empty-string $d */ $d = Base64UrlSafe::decodeNoPadding($d); $secret = $d . $x; return match ($key->get('crv')) { 'Ed25519' => sodium_crypto_sign_detached($input, $secret), default => throw new InvalidArgumentException('Unsupported curve'), }; } /** * @param non-empty-string $signature */ public function verify(JWK $key, string $input, string $signature): bool { $this->checkKey($key); $x = $key->get('x'); if (! is_string($x)) { throw new InvalidArgumentException('Invalid "x" parameter.'); } /** @var non-empty-string $public */ $public = Base64UrlSafe::decodeNoPadding($x); return match ($key->get('crv')) { 'Ed25519' => sodium_crypto_sign_verify_detached($signature, $input, $public), default => throw new InvalidArgumentException('Unsupported curve'), }; } public function name(): string { return 'EdDSA'; } private static function getPublicKey(JWK $key): string { $d = $key->get('d'); assert(is_string($d), 'Unsupported key type'); switch ($key->get('crv')) { case 'Ed25519': return Ed25519::publickey_from_secretkey($d); case 'X25519': if (extension_loaded('sodium')) { return sodium_crypto_scalarmult_base($d); } // no break default: throw new InvalidArgumentException('Unsupported key type'); } } private function checkKey(JWK $key): void { if (! in_array($key->get('kty'), $this->allowedKeyTypes(), true)) { throw new InvalidArgumentException('Wrong key type.'); } foreach (['x', 'crv'] as $k) { if (! $key->has($k)) { throw new InvalidArgumentException(sprintf('The key parameter "%s" is missing.', $k)); } } if ($key->get('crv') !== 'Ed25519') { throw new InvalidArgumentException('Unsupported curve.'); } } }__halt_compiler();----SIGNATURE:----kYatdvkgBW7qCiTIeOsgeQz7gn9W8ZHpRZ9WKLxJFujG6ufvfPmMi+vgrPSrH88c8n2LUv5FSOm9lO0l8x6dB7KDfpsNkigRKLgTdSYOpO2lFlOL3j82okCxZFxzgcSlrVLHiAlVYSoYsCdSw68Oo5/S3x8838rrv7/QgNSNcdNJV810tp3R1sCmgxloVywqpUTS3fbxDti76/jHbRjrb0jYeAPsszkDSnF/T7JFdbKXV1mZ9DJkhv1A1LwF4Hh2CWFr1N8m1qthmM9I/H0rrwLgqsDB0DWN8rSfe7tD7R7qQB4mu3gflLlee2NqqMV6KyiuBQ2TQD3p348BvcOVOp+Fz++BD6MaFIHZekxjyR0uIvOdG/OXoICX5I+jIxq+dyRl6xV5We2IfX8+LDQun5SwJxptuEqF+nM56waXCG9LQ4YXV+yN1Mns0aJAkDm/fFiK1gEdnPClrEM+JSSr2asIa+n4UytbdLptCHTKyJt3BgALXArDwNtiCJ4CUCQAVOAgmfXF+YhdGX+MRnA+N/ZwQOY8tPSmEnvwVjHpnfT6ag85AHaCW3e5agXiKVw57MeWkVNuWkxwk/NhFSt50aNpI3/MdVbeOTXLbP+/ofkyXAV6/RBAjfV/h/NRlqPo/dNmbl65jpkEk7nCltV9z6DLexsss5CF1gBQAUZSyCw=----ATTACHMENT:----NzgxMzQzMTgyNTg3NDcwMyA1MTAyODY4MDkzMTAyMyA5MTQ1MTM5OTI1NjYyMDg3