crypto: support Ed448 and ML-DSA context parameter in Web Cryptography

PR-URL: https://github.com/nodejs/node/pull/59570
Reviewed-By: James M Snell <jasnell@gmail.com>
This commit is contained in:
Filip Skokan authored and Node.js GitHub Bot committed 2025-09-07 13:17:42 +00:00
1 parent 3837993b65
commit 0124e0e0d7
21 files changed
+362 -206

No files matched your search

+48
View File
@@ -4288,6 +4288,54 @@ std::optional<EVP_PKEY_CTX*> EVPMDCtxPointer::verifyInit(
return ctx;
}
std::optional<EVP_PKEY_CTX*> EVPMDCtxPointer::signInitWithContext(
const EVPKeyPointer& key,
const Digest& digest,
const Buffer<const unsigned char>& context_string) {
#ifdef OSSL_SIGNATURE_PARAM_CONTEXT_STRING
EVP_PKEY_CTX* ctx = nullptr;
const OSSL_PARAM params[] = {
OSSL_PARAM_construct_octet_string(
OSSL_SIGNATURE_PARAM_CONTEXT_STRING,
const_cast<unsigned char*>(context_string.data),
context_string.len),
OSSL_PARAM_END};
if (!EVP_DigestSignInit_ex(
ctx_.get(), &ctx, nullptr, nullptr, nullptr, key.get(), params)) {
return std::nullopt;
}
return ctx;
#else
return std::nullopt;
#endif
}
std::optional<EVP_PKEY_CTX*> EVPMDCtxPointer::verifyInitWithContext(
const EVPKeyPointer& key,
const Digest& digest,
const Buffer<const unsigned char>& context_string) {
#ifdef OSSL_SIGNATURE_PARAM_CONTEXT_STRING
EVP_PKEY_CTX* ctx = nullptr;
const OSSL_PARAM params[] = {
OSSL_PARAM_construct_octet_string(
OSSL_SIGNATURE_PARAM_CONTEXT_STRING,
const_cast<unsigned char*>(context_string.data),
context_string.len),
OSSL_PARAM_END};
if (!EVP_DigestVerifyInit_ex(
ctx_.get(), &ctx, nullptr, nullptr, nullptr, key.get(), params)) {
return std::nullopt;
}
return ctx;
#else
return std::nullopt;
#endif
}
DataPointer EVPMDCtxPointer::signOneShot(
const Buffer<const unsigned char>& buf) const {
if (!ctx_) return {};
+9
View File
@@ -1409,6 +1409,15 @@ class EVPMDCtxPointer final {
std::optional<EVP_PKEY_CTX*> verifyInit(const EVPKeyPointer& key,
const Digest& digest);
std::optional<EVP_PKEY_CTX*> signInitWithContext(
const EVPKeyPointer& key,
const Digest& digest,
const Buffer<const unsigned char>& context_string);
std::optional<EVP_PKEY_CTX*> verifyInitWithContext(
const EVPKeyPointer& key,
const Digest& digest,
const Buffer<const unsigned char>& context_string);
DataPointer signOneShot(const Buffer<const unsigned char>& buf) const;
DataPointer sign(const Buffer<const unsigned char>& buf) const;
bool verify(const Buffer<const unsigned char>& buf,
+8 -36
View File
@@ -1342,7 +1342,7 @@ changes:
<!--lint disable maximum-line-length remark-lint-->
* `algorithm` {string|Algorithm|RsaPssParams|EcdsaParams|Ed448Params|ContextParams|KmacParams}
* `algorithm` {string|Algorithm|RsaPssParams|EcdsaParams|ContextParams|KmacParams}
* `key` {CryptoKey}
* `data` {ArrayBuffer|TypedArray|DataView|Buffer}
* Returns: {Promise} Fulfills with an {ArrayBuffer} upon success.
@@ -1463,7 +1463,7 @@ changes:
<!--lint disable maximum-line-length remark-lint-->
* `algorithm` {string|Algorithm|RsaPssParams|EcdsaParams|Ed448Params|ContextParams}
* `algorithm` {string|Algorithm|RsaPssParams|EcdsaParams|ContextParams|KmacParams}
* `key` {CryptoKey}
* `signature` {ArrayBuffer|TypedArray|DataView|Buffer}
* `data` {ArrayBuffer|TypedArray|DataView|Buffer}
@@ -1830,20 +1830,23 @@ added: v24.7.0
added: v24.7.0
-->
* Type: {string} Must be `'ML-DSA-44'`[^modern-algos], `'ML-DSA-65'`[^modern-algos], or `'ML-DSA-87'`[^modern-algos].
* Type: {string} Must be `Ed448`[^secure-curves], `'ML-DSA-44'`[^modern-algos],
`'ML-DSA-65'`[^modern-algos], or `'ML-DSA-87'`[^modern-algos].
#### `contextParams.context`
<!-- YAML
added: v24.7.0
changes:
- version: REPLACEME
pr-url: https://github.com/nodejs/node/pull/59570
description: Non-empty context is now supported.
-->
* Type: {ArrayBuffer|TypedArray|DataView|Buffer|undefined}
The `context` member represents the optional context data to associate with
the message.
The Node.js Web Crypto API implementation only supports zero-length context
which is equivalent to not providing context at all.
### Class: `CShakeParams`
@@ -2024,37 +2027,6 @@ added: v15.0.0
* Type: {string} Must be one of `'P-256'`, `'P-384'`, `'P-521'`.
### Class: `Ed448Params`
<!-- YAML
added: v15.0.0
-->
#### `ed448Params.name`
<!-- YAML
added:
- v18.4.0
- v16.17.0
-->
* Type: {string} Must be `'Ed448'`[^secure-curves].
#### `ed448Params.context`
<!-- YAML
added:
- v18.4.0
- v16.17.0
-->
* Type: {ArrayBuffer|TypedArray|DataView|Buffer|undefined}
The `context` member represents the optional context data to associate with
the message.
The Node.js Web Crypto API implementation only supports zero-length context
which is equivalent to not providing context at all.
### Class: `EncapsulatedBits`
<!-- YAML
+1
View File
@@ -359,6 +359,7 @@ function eddsaSignVerify(key, data, algorithm, signature) {
undefined,
undefined,
undefined,
algorithm.name === 'Ed448' ? algorithm.context : undefined,
signature));
}
+1
View File
@@ -302,6 +302,7 @@ function ecdsaSignVerify(key, data, { name, hash }, signature) {
undefined, // Salt length, not used with ECDSA
undefined, // PSS Padding, not used with ECDSA
kSigEncP1363,
undefined,
signature));
}
+1
View File
@@ -303,6 +303,7 @@ function mlDsaSignVerify(key, data, algorithm, signature) {
undefined,
undefined,
undefined,
algorithm.context,
signature));
}
+1
View File
@@ -355,6 +355,7 @@ function rsaSignVerify(key, data, { saltLength }, signature) {
saltLength,
key[kAlgorithm].name === 'RSA-PSS' ? RSA_PKCS1_PSS_PADDING : undefined,
undefined,
undefined,
signature);
});
}
+4 -1
View File
@@ -171,7 +171,9 @@ function signOneShot(algorithm, data, key, callback) {
algorithm,
pssSaltLength,
rsaPadding,
dsaSigEnc);
dsaSigEnc,
undefined,
undefined);
if (!callback) {
const { 0: err, 1: signature } = job.run();
@@ -276,6 +278,7 @@ function verifyOneShot(algorithm, data, key, signature, callback) {
pssSaltLength,
rsaPadding,
dsaSigEnc,
undefined,
signature);
if (!callback) {
+2 -3
View File
@@ -268,8 +268,8 @@ const kAlgorithmDefinitions = {
'generateKey': null,
'exportKey': null,
'importKey': null,
'sign': 'Ed448Params',
'verify': 'Ed448Params',
'sign': 'ContextParams',
'verify': 'ContextParams',
},
'HKDF': {
'importKey': null,
@@ -494,7 +494,6 @@ const simpleAlgorithmDictionaries = {
salt: 'BufferSource',
info: 'BufferSource',
},
Ed448Params: { context: 'BufferSource' },
ContextParams: { context: 'BufferSource' },
Pbkdf2Params: { hash: 'HashAlgorithmIdentifier', salt: 'BufferSource' },
RsaOaepParams: { label: 'BufferSource' },
+21 -13
View File
@@ -19,6 +19,7 @@ const {
MathTrunc,
Number,
NumberIsFinite,
NumberParseInt,
ObjectPrototypeHasOwnProperty,
ObjectPrototypeIsPrototypeOf,
SafeArrayIterator,
@@ -304,13 +305,12 @@ function createDictionaryConverter(name, dictionaries) {
const context = `'${key}' of '${name}'${
opts.context ? ` (${opts.context})` : ''
}`;
const { converter, validator } = member;
const idlMemberValue = converter(esMemberValue, {
const idlMemberValue = member.converter(esMemberValue, {
__proto__: null,
...opts,
context,
});
validator?.(idlMemberValue, esDict);
member.validator?.(idlMemberValue, esDict);
setOwnProperty(idlDict, key, idlMemberValue);
} else if (member.required) {
throw makeException(
@@ -769,17 +769,25 @@ converters.EcdhKeyDeriveParams = createDictionaryConverter(
},
]);
for (const name of ['Ed448Params', 'ContextParams']) {
converters[name] = createDictionaryConverter(
name, [
...new SafeArrayIterator(dictAlgorithm),
{
key: 'context',
converter: converters.BufferSource,
validator: validateZeroLength(`${name}.context`),
converters.ContextParams = createDictionaryConverter(
'ContextParams', [
...new SafeArrayIterator(dictAlgorithm),
{
key: 'context',
converter: converters.BufferSource,
validator(V, dict) {
let { 0: major, 1: minor } = process.versions.openssl.split('.');
major = NumberParseInt(major, 10);
minor = NumberParseInt(minor, 10);
if (major > 3 || (major === 3 && minor >= 2)) {
this.validator = undefined;
} else {
this.validator = validateZeroLength('ContextParams.context');
this.validator(V, dict);
}
},
]);
}
},
]);
converters.Argon2Params = createDictionaryConverter(
'Argon2Params', [
+65 -7
View File
@@ -199,6 +199,10 @@ void CheckThrow(Environment* env, SignBase::Error error) {
case SignBase::Error::MalformedSignature:
return THROW_ERR_CRYPTO_OPERATION_FAILED(env, "Malformed signature");
case SignBase::Error::ContextUnsupported:
return THROW_ERR_CRYPTO_OPERATION_FAILED(
env, "Context parameter is unsupported");
case SignBase::Error::Init:
case SignBase::Error::Update:
case SignBase::Error::PrivateKey:
@@ -231,6 +235,24 @@ void CheckThrow(Environment* env, SignBase::Error error) {
bool UseP1363Encoding(const EVPKeyPointer& key, const DSASigEnc dsa_encoding) {
return key.isSigVariant() && dsa_encoding == DSASigEnc::P1363;
}
bool SupportsContextString(const EVPKeyPointer& key) {
#if OPENSSL_VERSION_NUMBER < 0x3020000fL
return false;
#else
switch (key.id()) {
case EVP_PKEY_ED448:
#if OPENSSL_WITH_PQC
case EVP_PKEY_ML_DSA_44:
case EVP_PKEY_ML_DSA_65:
case EVP_PKEY_ML_DSA_87:
#endif
return true;
default:
return false;
}
#endif
}
} // namespace
SignBase::Error SignBase::Init(const char* digest) {
@@ -534,7 +556,8 @@ SignConfiguration::SignConfiguration(SignConfiguration&& other) noexcept
flags(other.flags),
padding(other.padding),
salt_length(other.salt_length),
dsa_encoding(other.dsa_encoding) {}
dsa_encoding(other.dsa_encoding),
context_string(std::move(other.context_string)) {}
SignConfiguration& SignConfiguration::operator=(
SignConfiguration&& other) noexcept {
@@ -548,6 +571,7 @@ void SignConfiguration::MemoryInfo(MemoryTracker* tracker) const {
if (job_mode == kCryptoJobAsync) {
tracker->TrackFieldWithSize("data", data.size());
tracker->TrackFieldWithSize("signature", signature.size());
tracker->TrackFieldWithSize("context_string", context_string.size());
}
}
@@ -615,8 +639,20 @@ Maybe<void> SignTraits::AdditionalConfig(
}
}
if (!args[offset + 10]->IsUndefined()) { // Context string
ArrayBufferOrViewContents<char> context_string(args[offset + 10]);
if (context_string.size() > 255) [[unlikely]] {
THROW_ERR_OUT_OF_RANGE(env, "context string must be at most 255 bytes");
return Nothing<void>();
}
params->flags |= SignConfiguration::kHasContextString;
params->context_string = mode == kCryptoJobAsync
? context_string.ToCopy()
: context_string.ToByteSource();
}
if (params->mode == SignConfiguration::Mode::Verify) {
ArrayBufferOrViewContents<char> signature(args[offset + 10]);
ArrayBufferOrViewContents<char> signature(args[offset + 11]);
if (!signature.CheckSizeInt32()) [[unlikely]] {
THROW_ERR_OUT_OF_RANGE(env, "signature is too big");
return Nothing<void>();
@@ -647,12 +683,34 @@ bool SignTraits::DeriveBits(Environment* env,
return false;
const auto& key = params.key.GetAsymmetricKey();
bool has_context = (params.flags & SignConfiguration::kHasContextString &&
params.context_string.size() > 0);
if (has_context && !SupportsContextString(key)) {
if (can_throw) crypto::CheckThrow(env, SignBase::Error::ContextUnsupported);
return false;
}
auto ctx = ([&] {
switch (params.mode) {
case SignConfiguration::Mode::Sign:
return context.signInit(key, params.digest);
case SignConfiguration::Mode::Verify:
return context.verifyInit(key, params.digest);
if (has_context) {
ncrypto::Buffer<const unsigned char> context_buf{
.data = params.context_string.data<unsigned char>(),
.len = params.context_string.size(),
};
switch (params.mode) {
case SignConfiguration::Mode::Sign:
return context.signInitWithContext(key, params.digest, context_buf);
case SignConfiguration::Mode::Verify:
return context.verifyInitWithContext(key, params.digest, context_buf);
}
} else {
switch (params.mode) {
case SignConfiguration::Mode::Sign:
return context.signInit(key, params.digest);
case SignConfiguration::Mode::Verify:
return context.verifyInit(key, params.digest);
}
}
UNREACHABLE();
})();
+5 -2
View File
@@ -25,7 +25,8 @@ class SignBase : public BaseObject {
Update,
PrivateKey,
PublicKey,
MalformedSignature
MalformedSignature,
ContextUnsupported,
};
SignBase(Environment* env, v8::Local<v8::Object> wrap);
@@ -99,7 +100,8 @@ struct SignConfiguration final : public MemoryRetainer {
enum Flags {
kHasNone = 0,
kHasSaltLength = 1,
kHasPadding = 2
kHasPadding = 2,
kHasContextString = 4
};
CryptoJobMode job_mode;
@@ -112,6 +114,7 @@ struct SignConfiguration final : public MemoryRetainer {
int padding = 0;
int salt_length = 0;
DSASigEnc dsa_encoding = DSASigEnc::DER;
ByteSource context_string;
SignConfiguration() = default;
+30 -15
View File
@@ -28,18 +28,23 @@ module.exports = function() {
'b219e30a1beea8fe869082d99fc8282f9050d024e59eaf0730ba9db70a', 'hex');
// For verification tests.
// eslint-disable @stylistic/js/max-len
const signatures = {
'Ed25519': Buffer.from(
'3d90de5e5743dfc28225bfadb341b116cbf8a3f1ceedbf4adc350ef5d3471843a418' +
'614dcb6e614862614cf7af1496f9340b3c844ea4dceab1d3d155eb7ecc00', 'hex'),
'Ed448': Buffer.from(
'76897e8c50ac6b1132735c09c55f506c0149d2677c75664f8bc10b826fbd9df0a03c' +
'd986bce8339e64c7d1720ea9361784dc73837765ac2980c0dac0814a8bc187d1c9c9' +
'07c5dcc07956f85b70930fe42de764177217cb2d52bab7c1debe0ca89ccecbcd63f7' +
'025a2a5a572b9d23b0642f00', 'hex')
'Ed25519': {
// Ed25519 does not support context
'0': Buffer.from('3d90de5e5743dfc28225bfadb341b116cbf8a3f1ceedbf4adc350ef5d3471843a418614dcb6e614862614cf7af1496f9340b3c844ea4dceab1d3d155eb7ecc00', 'hex'),
},
'Ed448': {
'0': Buffer.from('76897e8c50ac6b1132735c09c55f506c0149d2677c75664f8bc10b826fbd9df0a03cd986bce8339e64c7d1720ea9361784dc73837765ac2980c0dac0814a8bc187d1c9c907c5dcc07956f85b70930fe42de764177217cb2d52bab7c1debe0ca89ccecbcd63f7025a2a5a572b9d23b0642f00', 'hex'),
'32': Buffer.from('0294186f0305dd3a2d5ac86eeb7e73c05d419e84152c2341ae24e55c3889e878f4acb537f3651a50b0b1c26739721b168499337537c92727003480be61fc23f519ed772ebf2977f6bda5259235ded904959227beaf0adfbd28288358854e9abe089dc8075998993b86280b0bd89bdacc3c00', 'hex'),
'255': Buffer.from('6dfef748ab53ca856b3ffd84c62ae167c2737dfe4eae89c6c1edc0adc685b73f8170eacd723ec76fb31318ebe47c908722000129b2e9806e8040a4d4d90ac1d1b539199e33553300dcdf4989e4b77c835b53f4ee0d114845ad97047ad0d112e05304b38f5836bbe024a6f700a368d9910100', 'hex'),
}
}
// eslint-disable @stylistic/js/max-len
const algorithms = ['Ed25519'];
const contexts = [new Uint8Array(0), new Uint8Array(32), new Uint8Array(255)];
if (!process.features.openssl_is_boringssl) {
algorithms.push('Ed448')
@@ -47,13 +52,23 @@ module.exports = function() {
common.printSkipMessage(`Skipping unsupported Ed448 test cases`);
}
const vectors = algorithms.map((algorithm) => ({
publicKeyBuffer: spki[algorithm],
privateKeyBuffer: pkcs8[algorithm],
name: algorithm,
data,
signature: signatures[algorithm],
}));
const vectors = [];
for (const algorithm of algorithms) {
for (const context of contexts) {
if (algorithm === 'Ed25519' && context.byteLength !== 0) {
continue;
}
vectors.push({
publicKeyBuffer: spki[algorithm],
privateKeyBuffer: pkcs8[algorithm],
name: algorithm,
context: algorithm === 'Ed25519' ? undefined : context,
data,
signature: signatures[algorithm][context.byteLength],
})
}
}
return vectors;
}
+31 -13
View File
@@ -24,24 +24,42 @@ module.exports = function() {
'b219e30a1beea8fe869082d99fc8282f9050d024e59eaf0730ba9db70a', 'hex');
// For verification tests.
// eslint-disable @stylistic/js/max-len
const signatures = {
// eslint-disable-next-line @stylistic/js/max-len
'ML-DSA-44': Buffer.from('f4d00cfbf585bc0178c62de0a37a3e3a2593a8fb4ea7147ae35c3020e0084b0a1ec21f6523695ca7e14a267083b95f56e9423b3487fb09be59c84f1ea80c8ec573e8e8d2eaa9a52dd7739295f6614fc705a2dc9b0122f9d32b731b3743d8bb44f47c5a4488cbaabbd44bc3aad0bbad9fa9ca6d29c4c3cf6a87f1c8654b2fd7c955f2721d0da7e39a01a7fa39b1b1a0c603da985a4b02e6951bb7b5ab0943fdb199defbdea65f64b619ab3334337a67b4547efa7e6e132f18b8abbe66875fc3f9fa95d9d4613f55356dfdb2357c7b7556560695aae35dbfa69d2c259ba7966dad1640fa6fefdfdcdee71aaf2a35784b19f8f6118ecb5a8f174bda4589f13dbfd21b5d90a68bca5c31a270ab3aecf9ac549568396396b40b2fba1e5e1500a9f127eb5d08685be93a4298f03351715a917e1cbedd4db605389b69448c06607d7f38a25746f9d1acae6c7827b620ea6e8526fce50e6ec4cdef1a7a154fb52db77cd3b0c4de8e54f43426fc9342aa4b9077dbc62b30a71af3eab48ccd83dd84122bdae87173bd9520c6caba46d8184340cb34da8a97803a21a670714096efc925f6920df3dd8b29aea13788040328192c44245275c562ffec15cbdca5bfd5a3514080353872b8d88bf4ecc58b6db8d16d00d16e13d536eb91df584c8aa8ac560f752c1d5b0c7247d628f4a569a6a3810562d1364055f3cef73f1b2f51a0f2595f50a3a09840c59a497f3cd837aa29f64f28b635fd0500b4b62766987c99cc5d3c79b01178a7fd2f84d588858905a74da8b725d094a7c255a12be113cd7907d44ebbabdae92ae21d9affb25dbd08524fa5fffa513d772df135bdd8bc99e48af30ea46567f8336cdb546cb2db23817b23c0915b5da6e56a83cf19ab742faf7eefc9f95e22ca95d0587b3dcc580cd2a932b884e0d7b6e72124cdcdd6f49caa63e4f85aac04825ffefcf223f4537ab04cb718dc18ba72993aa51d4d712e9a42fe3e1834e6c70b19762a5895ee4fe1e2329dadd053d296bc18084bac81431280433f8b73d3d7a63f9a9ce7a09b90698e467517382bd0d3e305e212381065bd2e01d6ac4b30a9ddb95f9af7b9724fe3e38d97b6324d90dae256fe389b3b835b63a47d80da3e9389b8970d58ff5b8bdc62c6984c86ae7629b9b6e728e87341515d2420275d00a5a65d9bd512af1b1d47fa84e422d6757a9a70244d0aa64ca818d5259f9efb80e5d251a6e1c4e1768ec9c77c6822246d2cbe18ed72b7877cf95002ebf4aefd93caacc5e130dedd3b35c782fb75a57ed29bf6dce66041e13ebeb54e98ea35eeaa6b32e943f6a7b668d5ecd563fa03be46151d863e9747cb1c355c2e3cb0b7627172e1ecaa50d295ed93ac0529d606b8c4c8285d9dce0c9b061ad93a12dc1832710bf1e4c5799fc0b7383c8055ea14a9a039d3f1ed8334741b7ec8bf2d8f7b1d6ad9db22b44a170aed2d358e5a20fc19e1ada04c390ec7647c49bde13924a9650dcc356d45acdbbcad1b2ec21a5eb835689dc958078e3c41898bad8989c5d816bbf403babe96661215e68e59f0ba747e433a3073afb957ba3ae3a435666dc287c2def5aba859674b181c522a6a54ed613faadcd26729725fffaed54692634b13908dd52db47d441306d8f31aafe6b1146cc736290ab4f8e01d54f10525a1454b5a49d389451d071076d8cac0b8d09ddbe44e2f5648a617cc075da438014eeb1c3bb3de26a2d1a332f82b1cdf11544e9f459334cd61e94d9ba2ba57b2db7e9d22b86950e2a2ef5bc5ecee6efb60d5123a7507b6fb73f2ffeab60c9a70de6098427aabaf8fd29f32335e2d14964b56d5bc86361fe01ab0ea6278579b4e7c3866c9e79ce006997a74d7964be9a632b376df797fb593ded91c802959792b3c38fc92186ae2eeb38dae94181f15c8a4abb5e1740c8eb3460fc88de5ca6a558a81381b29e2fafd2bca4dcabdaa4e45c9cd334614757c6a7be7788c93e27b6fe8a4135db82312274c57e98f06f8114e11ba5a4354cae97d44ae4f5b4682e34f955d5535b859a6cb59028feb0309470177163da3a7c1a76fb37f021f16678cdcb07bd2b49b0c77211560e02bc08446e0af3d1c7f736cf620a0a79d2a849117cf1af585e26b4984c157f5012557f96d41dabf98d1533c31df28bb8a43183e592d890bc111c0a94db3d081c34bd6c003cca0abef79bb8c95c62c6647de01e47962874a68b671042e315e6f192175ace030aa9b76ffa9f4e199c6a4f56453a2b312477eafa4c383ad2429fa453ac15bfde030532fa2e26cb200e3c7b7061f076fe28dda68cc07e7c58ccdc22fd164cf5643238d9a39945da27372f600b80f88d641734a1f8f5e4e47d0cdfc083139198f42908d766f308a3409f56b853dda9c4eeef87f9e772bc8a1a3d5f7c4ebf865a722d5181da636297161f8a7e23d54b8523e2b52c17ddcf8f388032e4b8780a5698dda7fcca8fb6fdeb5e4328d6a886da5015bd58087a0cc43a72f5b88a78a7a12b0daaf470ed049e170b8b03ef8620b654e744859bba5d5543f1e823eacb59511230aff547900091a37227c9021549e4eb954c2b7b587764fc88dcd224067d9639cbc8c3fcbef71651d4273f21f5813626c710c12f16cd0757b3d8b8ed19b474e53072207502b66faaf756fa8846304fbb20ece8ce87cb71dd8344d7b10c7e516fc3eec7854e6048a893bd456421402994612a52fef16a97ab642edd69c30b1cbbe0f8e73b8f12db6574f7c9c7de94cbd698688060de7a63c8247aa3b95bbabbfdbdab7fa637e5404123ebafba52383c459621c154a2a23eec97382eb531b2ca83cdf075ee5bd54ba3bc3e19dc3ccfff08e5e61e8b49b080809a57db3548845ae9f5e15fa10024e2b86b283259aa11f3620d5104561fc32afffe54526c5f26e1c941928fed2fc4ad247ae0f590484265589cf0ead253f0a9fd50ae2d8cf02deab6a0f715148f905274186f0c30743e3542bd6ee93563f596c43baa6e0b99be127d722fe17299af2716365a7e72ebc20eb811291ce489b739ad2d3f79a4e81a2090cf81b7a45ff782ba3655bc717e0f80e4a276c0c3db48036c67d1e95797e2c7c9e183a861e28c9604f3e2187e470cd0b37a7d2e78b3415f6391b7fa04c492edc03c5a728507f234fb6fa885ab1939f64291a2058538bf83cc7cc3ea785774332d92b816c76d8d99b94fb8c237113a24b90768b2314aeba2846a645e623834a3a947856e7c85eddd63a1865700d8ad5e36521fa1f90478601a557ce111bc7eed0b7542ff6e8e887e2253db793abed45581fbe9ff0a3100308102026616a7a858f9e9fa1b0e10e2254607f84b1b3b9c2cce4e7fe08162b31384354627b8296a5b4c6e3e6f1f6f7020a191c213b686f8491929c9faae3fb000000000000000000000000000000000f1d3040', 'hex'),
// eslint-disable-next-line @stylistic/js/max-len
'ML-DSA-65': Buffer.from('0d7f54a113bc87e6be6abc34282a0abf0dd12e8b3ef64f338d62be9986eff721776a3ba2992b069c8c2d15e0b948f2615a7a71ba42650abcddf147f50e6ff7de01aea560ead3b540ca1754b4749ad345f750d75c379804b7893cdfd059345297c8776fca5378ebbe1ee1fceadae9bcd01baf39c8f01e8791730e7e1e5d0efdfae2acdb34e6be09a258b83eb29da9e48506c5d1029d1b7157b103fa4fd77c8b305a0e4f2dc82b68936254bf3a345143920f67bada15d3038f76c160281085a666aba741ee44b12ed4018e9a41d77c642bfefd658255ef560958575c338635d140bf73c2daf923f26898fdf45fd48ec24c4ecb8adbef15bcec7ef5302fb58ce6a16628bae20a55c497c0897f86f0ec22323b96e1bce5e0cd7c608aed5706a2c73d5d4d05cc637f86320a8eac06b8e26a13874bcaa9131db6c9e237841df21789a47fe48a13895575b77e141e3285197b5a16f19a00bccb1d384ae026a17d64a55152188b88a682562340f667a19dc3bd6b5592d39e8b7b408c1ecbf768628038fa4333a475a72c03f3cd8aef346b1910724a47ed915ff1b2bc71ae17f127b903c679b103026c2aeda967b0d6497a30790e2507cc79bb78e9326f66c8d015f20baab3311a7b436c357356f20cb03209bc82863004597439d0905d73eb6213d14ef4505879e5ac3f4988956d5483bd0665d0d9b3e9353de68e7108dd0a6af6d23422fe193294419c3887571b7470d206f23cd059895ed5a53cdaa6ec94969b43eb9c98ae53b909a4162d6230717b3105dd4d511a40b9817a71e037df02d95c508df1a392aa40d9516811bd520442c00b8377023cce3f1462e50636813ba1e4350942c435743939cb540d4688d0db69885ec2d2e3d37a408030737dc8fbd42cf19df941fa5f8b532cbf839ab13b940b5b37200b900d27681ad97a4f92c256c29d63888302b076665d5b9c2ce219fcb12f80dce2b94e6001dcf3f662e01f905694a78ca5e2afdf8ab7cc1fb72e04521d9998662d423936d5ad359ab44091b53467406b7c306c0a0ad2e480c968f2d9e4f392ecf983fd2a4ad198bd701d09a1e2efc5c313999ceb83695d99a5ef25daf159d26f4c0ffbe3c2ae03cde0962cbf1a4e6a98dfc660922c2a399190abcf933a73f68d491c4ad8806cc450bf23d4e1c1377f6168a3c4df5b6bf8e1cb4be11bda24b6d9c113ed4d40fc2dba9f541d97739b5e40e915be1e10eb01c30ef609b6eaaf5d570f886d031df36fb7614080dfc088e821d1ac4fc50a48c5dd7ca6f08c7ac280bfcca640cf738f08f7da29639341e396a46d7204cc514d9c8dbc213b967657f4a67a29458947687b55ecf26d833239a7c0915f10334befa61b74372a8e1f4adf44906ea6395e15dda5e4b2d2005d574a943abd9d224c7f904298e2b1e249ab33d93089f239de6ce6b0c2e1b856940b7b08ccf1f98a65dfb3fc615457e2ba436bc63cce72510757380a5c07d56b47c93430b6bf9a89e5f6e1721d7d50b7417432471dc2ee0b02430fe71f4122c0e3363db446e4f7ad21cee944f3e6072fc1fa57d175329707f52c51f97eb287d7af70ef91c0632ad5b89929507a2d01609993c2ff8bb991e232b554430cbc0ae4f6b3225013e1fd0f8e0a485f7b55c1f96dc0fb6b395ce104d9c3d780567cc9f7bcda296f665a5eca11a94fd1d0f35d10e0b017880e16f31de961f7b5fabafadd1c99c80cf7535e7df7b807fde38b530ee527234983e25eace30c4be8fe18edc58ae53ad79a145ee0700be63b636a18a4eedfab826383a9e5d9f2b7e490c6bbcc3ec0f37ee44b8e301091c6636cf212e3519b706919af41b872d6b4778cca8ca3373f62dbd8f68b59ca29467c63e10b886a18d2a32864ebca2ebb2f602b736ac8587d544d74d9aacbe6e436646ffccf2ca3da2121af8b3431b523e09a538bdd07ad3cd4c71a76cfcb67273f277e18094ca9730d06af60c354824abc84f623e1727a4f43c7021ca18d463c5aa1c53cd4adb77f13156103ac0907f6487689bf5eb2202a6ace8c9f55b5a285311d2e243090ce07e9cd2bcd253edc4ca57c1c42383184ef08d3f7b4ddc05fee25e8d72a6fa0dbe545dd3240edfc8081fa49542bc23d426ad286010920ad92b0fbae5833523a94ae59b87d90e1ae4cb504f06512b9c0c47d854750b45bb01a0a2788c51d808748f6cfab177fdd943965187fabc8419292f45f57718f709228a9d51dc43e21ed3af2bc5cf8ba75a4d22203a77662a71675b15bf91d3c7074657948b43e87837449bfc5eab1fb1fa9f8f91df5669b4957eceb02d013b0c04b493444ef673a103f630923c9ecc5c2cfb9fe40c1877fb9a67e54f7f0ea0c49d0a624220eea68bbe0e23d20092ae73a8a0f7749cf85499dbf4846308a190bf9ce68fb712a20db6910923eba88f42e93e76230bdbfa9890b6bce07a5ecffc396cbb314d3152bf1677a26a0245fd8373a1288d97e713d2326194e2e26990ef413a1076035e7e04be3d07cbf9403ce9f8b7f10c70badf62efd144324c1d37ead93ea94edff937b0d62820baeca5f56cdf30487097f5058ed3d74639543b1c160d6e876021c96feceff84bb2b1588c72f5f9a6a843b85d9b78da39a085f258296538467ae9568d23d9006e768445f9752ee754dc5ddf9b44998e90dae1a5c720d0abd3e81b750ff8a689547998a45b5a6155b462e8ed38c7b6c44bb81e64630449191a38ddff8eacb3f0cc675bd84aeb6acba135a65d2e7233e6b3d59f57d5a1bdf215a3a847a96306a203ff4a564524e03526fe3c35906fac3316cd19cbf39fa9b3a37bf2624c4f7eab0b98d43b967598349e7b0e69ae7a110aa5614e68afde1ac453bd8b02a39307c6423339d49df4a1d7c3042d0bd34ab9c36894eacaf1872ac70f0691dfec0ace938d17f1f61c7a0b6a12542f0d5e0438d2f0c69dc4f0a2eb5eebc56155954d97855a5e95d133663f29402279d39e41750c0667a721cee486847913d383940419dc9fbc118d1f608abf2f2ca244a7486d1ca2e883958a0d36e290edeea0e5dc8b44f22a6ae7efacec2ee642e8417d5b6338d58ef540b5438a2de2589e3c911d93570d1f7043da7f04f6a97c64af34f25a99c57662ddc27264d5fd880d6538a81661b8e83ce0f00e41a09dedc2dcf0935842b46c7b0560f0fef6c7e45d20de5566cd68c4bea75af56f68ec6f8061b59bad47d346c02d4ba89ed92ebe9276090a70f119faf4038cac4d655682285dd53707d00063f89f97dcda0e370a2b83bb6c8d9a4db2dc85efbf93d76b007de3566ae416a817d1fe9d7383451b8789d4892a4144befbf784a837dda4963cd20cca292273121b370cd1d0dbdc9e42aee99ea7c833779cd1fcd570f2c502c791ce06b082ca2f820eb75fa2b5ca072c915e3bdbc6eaa3cce642e1001fcca516c6635ee21c4a921af590d50d5127da0acb8ea48d11ea777192a540e588855acfe2ab0aa23e7743da7dddf11cb5fd7c3b0536b1dde5156b2968420b58d502d5Line truncated
// eslint-disable-next-line @stylistic/js/max-len
'ML-DSA-87': Buffer.from('737897d83f7fb82c704f4660c16c544212f3d3d280b3390c43d356c281aca7a3c90637a5dea83bf3504e593b178b17ec38a8175507a6c28b80c21cee28146af2161af60fb123420578e0576fbb9d579631efda9a4304c0ed67572d393d813155024ceab089c1cf1d0a5e9716948312f70b4a7deff76853f5cdf29737160901c14ac2f24ea4c7f819d86fa9758b8ca6aa6ffcfcd6d60f90ce31d31cd9d88586b9a38a22402be7c89c9d57c2b194179011c4fd185a5bd737032c1e54da0108f355130ffecae3f39a47148dacafdf25f9590bf6c8fdd9d9b7cdfe30607a235993c59631f29fe01453e2fd61cd4e8e3be21ddffa054c5e91fec88ecd531090ce21d68b7b11888ae9372fe2dabdb00ea311bfa564f86de46c61f284a246e420dd8056f021448a2fa6dfa2391e5beb6ef0a5a28180dcdf20e00dff4f9628a99054ce72061b0359cc67d4329545faea8943d90bb0f85bcdc88ef2acfd72056d2b5fbfed40034f2d344a395434d604a336c1e418e2598d07e8611f9c28c23bd2771c4d4dd5f820f197b50e58bfea502f6a53893d7fe6a7460a62b8ee892d17dedf606cf61fd5f27e002230bd15f0e3d5d951df3c54228c20d58fe5e5d072a1869bdeba1d90cf019c6bc3fb0df24a11894bb3a2d279c67d3a6d4342e0e2913861bd3f684bce8ffccbd6358dc0778c02896b719d675b584621edceabec3a8e679686363825e6bcdf6579ec67ecafdf23d6e23b747e340fc0982422865b8002590f9e35c8332ac47be5c4be6eeac3ee4ba79574f7c0aee0fac0e5cc7a9b7288814c36b10e2dbc900acee6841c386fec11c69580a87244fc9f995f6adec68b308b28eaa17129c1edfcbb8592b4bfdf6604afbf1f206010b47e92d08d830052d109f0265213fffd6ecc47aef5bd6f4d5fc19d2b06924cb96309945168f382977e9f6a2f59237b4a91bdde2d00453df0e7c516b7a53b0b8582aaa7ad8af9f40723d09a247b653ee48999148b5c160a25f5e9cbbdb53642429909a5af11c6f36db3fe8f8916f36f565fdbcd863565a6dd63b974304b6aaeddf91decc981d21cc93c11d8f76dfeca8444b6b882ff59be214fb1ae9fd90108f65d4f533031c35bbc552950b1a96f4be7ea9cd167231d7a7fbbb203d34bd764dab3ed2eeaba3419ae3674f7f01347427b84ddb5b86969e57e6bbf86b61bbda8fe830f357d12d15eea0df7d5fa2d641b03077f058719bf11819f0eb1dd921b783b9c648b5b3cad3d22e9442e514e9eef96d53c1de328dbb79eb801974b88e179d98d28bcc75469a2be46ae9fcafbfdb22d302ad2b535d7c09d06cc5ce1a50a569dbb13debeee5cbdd3341d06d8be28681c7716b466284efb4bb1b316b72f50c85c2a260c68231e2c516265f156e5f5ac735b9a420878db52950cdfcf21dcd9da62e41a4e117386b624f638ed51b4d2e156573b6a327698bd41a3d036414b201b0a31d818fcdce9c1e4d55def388fff5fcf5110b680e5ba3808f244dccf7fb01e8197ba3c3a3a2be74f44551f5bc03f77ca5010d1c9d8020fcc7c354e3ce9fa25d4900943f564695da56a6e4388d1bc69a68d413fc80e5913d22d2414b081052c216afc67ecce4ed126a8e0762191558cbbdd8d4150af7bae41f4941ed42fdae4fed9a40d70a0159d4a8ae48006022dccb6b4ae05dd484c065dbcce9b253b40d1eb542073fac64dca11b6e1196c5b50fb33d6bb831b9977602bc9d43c80713a5d714116e62fda8e9aa2c790e8d5adbf8025dbfa5f80bb92b661d45fb972eafa25303f1db7839efab7271ae41ce9f7c28a7cb8349a3eb2734c6b13caab678d53eb742fbe84f53b8ec89e6c155ddb0a4908799372123023f4c8d6f97d30fb70ff2d192be0928fdfabb9aedd04f944b2c7e0ef143390a20a5d5ea93d3a8f425470666dbf8733a2e2564f27e1878b2805d71069e55b225e3d133a7cccbe0db3f2b14ee77d717bcef348df09259efe12bfef08cbb0e8d58f08bf10c6a7b0c2820b442c06209e9b8134aa20d05e8e2c763a8b88b5d4ec544aeb1ccd9468901f6ccfc20eb632a75d051a0295590e02f5ded6efb33e54479b7e1104062ccb73bb5bcea1da9d4d659e1ed40a42ec13a6f27606a002097565264954625103e921886df888740b7166640132b428a97062241d083cf8b4892c159902a9cf35921df2966b50f6f31209773d1bd10c61d14409cf1e90a7d06d3fa226a865fb241299a859b8dcc898b4bb1dcf65ea17353a130e71ad184e9e89f0676e666352ff4614d8a7046588d97038a449ec426b67c9ee3101b8091efdd10867366cdcdff3581c0e973ab6ed71c984b33a58c2e3a865ab1bd055e629a21fb07a8a23e998f2db958ccbc89fd1b3512330f2cc69c3d74e16f8848556011881701b213dd39e123aca241c7231052a7bfd4738fd69bbfcd0ab74276907c1be3f75311e395a485d15b592d16d22c33ebf91d64e81d500ea23d53f130804ea1cf51c4bf2b0474f4f62264ac7bd90e6e9dda4d2b627b1e8043dfae64c6920a4f9a14ef15826996035af30cfa59a6a2411c61d16938004e2ae2ec72c32825a44c3200853fce28e36620fd0c71121346aff28e19218899f8e894fd6e477571f2a5c6c850104495a89cdc0998496b979b038f65ebd15ffc477ef22e943358de58612bc734d06bf8b77fac755b64f4c71966c699c43c5c38b7fd647a8b82cf354b1da4d31c9e918e146a997f2b4fc612e2ec73ab8e017728308e589efe326d4a14eeb55de34849938446911b9f3c62ee51992da1ea284650e0fd6f6078301a46948abd7d6ec2ca9ee202f26b9aab99fc29271697d8565a5147631ddbc9295c44812262a9c39cf0df4e08c52749823bd51d117d6cc106d74fe329c658c1034dd7d9a2f073fdf8bec519aa4a2f9caf8d0d719cb37138a0383b263c1c28a8b15c1d18a63e366a9892299b507da6bc9926672289a4f9f679e645db6c85e1cc1f4e6f9581984b2f72283a8efa471614e3e3d4a58921bd0d5feb85dc9cccfe4a7eda2be3d8118b2f4ca35ef6824e1a2d09162fc81791c2e30fba9368022ce8e01e1601944f05a0771b2d3c970f88841389b11eff76c853570c66022c3d35c4e94714277cad948c1a2b3273c6b3d675f9606b8b1a5d1848a8fbaf0f6e108b0029b6fe2ca230cf0e5a24049616db1b5bbaa0116308fe5948c45a4569fb5e3aa0bc5ebfeeffec460935477ce1c06dab0a1e7012859435e9887052293ad68a92df2b498b07dc991f16d04dd96bff885bb49a381b27c7e3701aefedaac8472f9d547da1aa8e226db691fe48c0593c8824803e564f57bf6b1c927742c909666b07f92f77236a2268a6148b517c1d2dea60321ff1baa5f47c5dfc000c8abc1c78384e1d6ad67dd343ad5ca3577b254d0ff85f12953f2100e6ec07d3c87d8cb79538cc75aa60fb936823009a55a1e7642a18efb94ec2eb44724f5b492263070a3e5481d091820459691507ccca318ffdfa4a0f5bc079e4c6a0fd41e715Line truncated
'ML-DSA-44': {
'0': Buffer.from('f4d00cfbf585bc0178c62de0a37a3e3a2593a8fb4ea7147ae35c3020e0084b0a1ec21f6523695ca7e14a267083b95f56e9423b3487fb09be59c84f1ea80c8ec573e8e8d2eaa9a52dd7739295f6614fc705a2dc9b0122f9d32b731b3743d8bb44f47c5a4488cbaabbd44bc3aad0bbad9fa9ca6d29c4c3cf6a87f1c8654b2fd7c955f2721d0da7e39a01a7fa39b1b1a0c603da985a4b02e6951bb7b5ab0943fdb199defbdea65f64b619ab3334337a67b4547efa7e6e132f18b8abbe66875fc3f9fa95d9d4613f55356dfdb2357c7b7556560695aae35dbfa69d2c259ba7966dad1640fa6fefdfdcdee71aaf2a35784b19f8f6118ecb5a8f174bda4589f13dbfd21b5d90a68bca5c31a270ab3aecf9ac549568396396b40b2fba1e5e1500a9f127eb5d08685be93a4298f03351715a917e1cbedd4db605389b69448c06607d7f38a25746f9d1acae6c7827b620ea6e8526fce50e6ec4cdef1a7a154fb52db77cd3b0c4de8e54f43426fc9342aa4b9077dbc62b30a71af3eab48ccd83dd84122bdae87173bd9520c6caba46d8184340cb34da8a97803a21a670714096efc925f6920df3dd8b29aea13788040328192c44245275c562ffec15cbdca5bfd5a3514080353872b8d88bf4ecc58b6db8d16d00d16e13d536eb91df584c8aa8ac560f752c1d5b0c7247d628f4a569a6a3810562d1364055f3cef73f1b2f51a0f2595f50a3a09840c59a497f3cd837aa29f64f28b635fd0500b4b62766987c99cc5d3c79b01178a7fd2f84d588858905a74da8b725d094a7c255a12be113cd7907d44ebbabdae92ae21d9affb25dbd08524fa5fffa513d772df135bdd8bc99e48af30ea46567f8336cdb546cb2db23817b23c0915b5da6e56a83cf19ab742faf7eefc9f95e22ca95d0587b3dcc580cd2a932b884e0d7b6e72124cdcdd6f49caa63e4f85aac04825ffefcf223f4537ab04cb718dc18ba72993aa51d4d712e9a42fe3e1834e6c70b19762a5895ee4fe1e2329dadd053d296bc18084bac81431280433f8b73d3d7a63f9a9ce7a09b90698e467517382bd0d3e305e212381065bd2e01d6ac4b30a9ddb95f9af7b9724fe3e38d97b6324d90dae256fe389b3b835b63a47d80da3e9389b8970d58ff5b8bdc62c6984c86ae7629b9b6e728e87341515d2420275d00a5a65d9bd512af1b1d47fa84e422d6757a9a70244d0aa64ca818d5259f9efb80e5d251a6e1c4e1768ec9c77c6822246d2cbe18ed72b7877cf95002ebf4aefd93caacc5e130dedd3b35c782fb75a57ed29bf6dce66041e13ebeb54e98ea35eeaa6b32e943f6a7b668d5ecd563fa03be46151d863e9747cb1c355c2e3cb0b7627172e1ecaa50d295ed93ac0529d606b8c4c8285d9dce0c9b061ad93a12dc1832710bf1e4c5799fc0b7383c8055ea14a9a039d3f1ed8334741b7ec8bf2d8f7b1d6ad9db22b44a170aed2d358e5a20fc19e1ada04c390ec7647c49bde13924a9650dcc356d45acdbbcad1b2ec21a5eb835689dc958078e3c41898bad8989c5d816bbf403babe96661215e68e59f0ba747e433a3073afb957ba3ae3a435666dc287c2def5aba859674b181c522a6a54ed613faadcd26729725fffaed54692634b13908dd52db47d441306d8f31aafe6b1146cc736290ab4f8e01d54f10525a1454b5a49d389451d071076d8cac0b8d09ddbe44e2f5648a617cc075da438014eeb1c3bb3de26a2d1a332f82b1cdf11544e9f459334cd61e94d9ba2ba57b2db7e9d22b86950e2a2ef5bc5ecee6efb60d5123a7507b6fb73f2ffeab60c9a70de6098427aabaf8fd29f32335e2d14964b56d5bc86361fe01ab0ea6278579b4e7c3866c9e79ce006997a74d7964be9a632b376df797fb593ded91c802959792b3c38fc92186ae2eeb38dae94181f15c8a4abb5e1740c8eb3460fc88de5ca6a558a81381b29e2fafd2bca4dcabdaa4e45c9cd334614757c6a7be7788c93e27b6fe8a4135db82312274c57e98f06f8114e11ba5a4354cae97d44ae4f5b4682e34f955d5535b859a6cb59028feb0309470177163da3a7c1a76fb37f021f16678cdcb07bd2b49b0c77211560e02bc08446e0af3d1c7f736cf620a0a79d2a849117cf1af585e26b4984c157f5012557f96d41dabf98d1533c31df28bb8a43183e592d890bc111c0a94db3d081c34bd6c003cca0abef79bb8c95c62c6647de01e47962874a68b671042e315e6f192175ace030aa9b76ffa9f4e199c6a4f56453a2b312477eafa4c383ad2429fa453ac15bfde030532fa2e26cb200e3c7b7061f076fe28dda68cc07e7c58ccdc22fd164cf5643238d9a39945da27372f600b80f88d641734a1f8f5e4e47d0cdfc083139198f42908d766f308a3409f56b853dda9c4eeef87f9e772bc8a1a3d5f7c4ebf865a722d5181da636297161f8a7e23d54b8523e2b52c17ddcf8f388032e4b8780a5698dda7fcca8fb6fdeb5e4328d6a886da5015bd58087a0cc43a72f5b88a78a7a12b0daaf470ed049e170b8b03ef8620b654e744859bba5d5543f1e823eacb59511230aff547900091a37227c9021549e4eb954c2b7b587764fc88dcd224067d9639cbc8c3fcbef71651d4273f21f5813626c710c12f16cd0757b3d8b8ed19b474e53072207502b66faaf756fa8846304fbb20ece8ce87cb71dd8344d7b10c7e516fc3eec7854e6048a893bd456421402994612a52fef16a97ab642edd69c30b1cbbe0f8e73b8f12db6574f7c9c7de94cbd698688060de7a63c8247aa3b95bbabbfdbdab7fa637e5404123ebafba52383c459621c154a2a23eec97382eb531b2ca83cdf075ee5bd54ba3bc3e19dc3ccfff08e5e61e8b49b080809a57db3548845ae9f5e15fa10024e2b86b283259aa11f3620d5104561fc32afffe54526c5f26e1c941928fed2fc4ad247ae0f590484265589cf0ead253f0a9fd50ae2d8cf02deab6a0f715148f905274186f0c30743e3542bd6ee93563f596c43baa6e0b99be127d722fe17299af2716365a7e72ebc20eb811291ce489b739ad2d3f79a4e81a2090cf81b7a45ff782ba3655bc717e0f80e4a276c0c3db48036c67d1e95797e2c7c9e183a861e28c9604f3e2187e470cd0b37a7d2e78b3415f6391b7fa04c492edc03c5a728507f234fb6fa885ab1939f64291a2058538bf83cc7cc3ea785774332d92b816c76d8d99b94fb8c237113a24b90768b2314aeba2846a645e623834a3a947856e7c85eddd63a1865700d8ad5e36521fa1f90478601a557ce111bc7eed0b7542ff6e8e887e2253db793abed45581fbe9ff0a3100308102026616a7a858f9e9fa1b0e10e2254607f84b1b3b9c2cce4e7fe08162b31384354627b8296a5b4c6e3e6f1f6f7020a191c213b686f8491929c9faae3fb000000000000000000000000000000000f1d3040', 'hex'),
'32': Buffer.from('e56d552be53ef82fcaf03c5ff1c03a85aa7e75c06550f69b3b3601d113e13d41d7295f01b12ae3f845afb41deb93b33ddd7115c4a8ec189afe3f492457815e34e748ba984c02c6074f5bee9fd58a538a83f89526b155fcbe6b0a727b0a7aacef43256da9c99ef2c12dea789f5febb3675215e69feabb0730cdd0a7b073abf09494792662e7d00216ce232b1f36fc5674bb66e802d4ef80c62ac434c50dac9f57ca72c0114eaa30bf6bd682d179995820adfa39f6e4343f3dd79cc1fcbacc68e7b266bb6ac4c018061ccece342b2a989876c26bbaadccab1fd55dc97e86fa780eb3c766f8ba123340dbd957109c8fe9e51a30fc8dad6d26f18504eb89d811d0905f00a655f493dc1f10abeae207d84f22cf2da24b7c0c4e466755e85d43e0f0bb56a25a3640ef0f6caf039be3ab3fd0126247ca6d76b4832a94193cd42dc5481b2056cf55f898ef0f1aef3b4d5532a38da147f8d974b053af7b127fbc03f3ec78ccf3910cc6c7936fbc757a00b56677c1aeeda9de85836eabc59cd94da0c15539600946506bd9c3a616f222f50b4a51df73eb285ff4ebbd40437c46567269d05807c07bf411f6caeab86f5a2f66cd3287dc56b1174e64f0dad39f2c25b3df50323961d71110c8f09d2e7a828a50a793271705dab9a8b85540465226eadf360af191b53dec2cda8e46f639e39ee3ceebcf3ae0d40aa31aed434108a92160d4e4d9d5a198c5702447157f67572086ad039232e213c36fd46c7870c0ea73517df44206b8a52239e2f4fa9ee53d81d1c46c3280bf9ba0c54ff4ba3e8d2b30add9e63328cf5e929d92d2023b066eb83d6666d4e9bba44b767125af5ecdf56d37c1a187798d108d78b5c5795861016ce7e89244f8d8579f0c85e88cfa723378b4d3271a26c4f0353ee9137acb98114f0318e130d476c47375497c8adda2cff0d1529a74d1c7a5b8e33362e81103a29defe1031bc68ef4b43735a19a9ba8531b2fe3689814be2003641fd853fce71b4a3043e8041825ac7e36a3bc8126e6b3913b24a15f5325d30466eac044c8d0b2fb6be2e3a4300c61b9d70b1f6a9b3087b7b9c9b5c567e2927f2c59123f763eb0490feb616de6d9536733918ba5a5d51a0cf1893fbb0f0ef5e00dd3ef9d08bd7b5fb1f5a583af8795e23f3fda459588905fb555a09d5f592f78fbaccecdca9ffa25339959e998823a3f6530e36683130c2927c373596e2a559e865d8cba7a4eca9b7ecb465fa331e9076a5d1ce876344c6c8cc12c8a58e7ddd9914987f5ba9c3ea60c527ea373f0ca5705f5395b73fa163c72fa32ffab6f6e5694be6b922c11d388546b66edf134238869e797e5360d3fc330ecace00b4d96a189f07fda42a9ba1b3c538c92c3b2c2cdd7bcf0beb29f2cd32d94b6059177c472e8615dbf4be5d1f82584826ac0ecc6735fc13affa54a46f4cc244e89fb7bdb08c7b5fc40160977d3b78c5ada8b1fa2a917dec6d68236dae100523114a4547a1e02d5646c615919a9e755f8db7d8a554adf8967d77b841ecc4c50f36e7888aa3a4c549a8d4524dff3b69c70711a485c3dbe98fea69b13000bea4c482f1fc4b8dc6897023595441e7ed836f5bfad7b5651bc33682446ecb9a435b494686e7f2798462348523bcc5d836e9611ddc74b360ec58058e6c74a391070f6bce962f9ae7fdbd21bd904bf7af9ff23c18d4ac1399ada61df17ab57e496b70fd3454805cdd91ea0cfe4f619ea54640ae72149e0d2fec0469375fbd4c3e662173be145a21df606a68760e12d717e702b83d582399bd05fc81b575a9872b846a27ba19953b29ee69ba8301488861673df757e4eec64bfdee753b8ab8eaca2aa410ec0465ecb5d88b3b6861464faf4359840fb6adf61d404b9f34a9a1805084825ea5cd172b0366987fee376a079d10dfc34d4857b3b1a102693a1f4bd91dab19565b36710749200a073b78944c3352a19618f74fecaa952435bc4c292924b879723c03567e5173f88be414c6948576c353e044257c68ab9dcc5cbae1d82291e2d93b299de0f248620ba1e436f906a7011b35ecf63f9e6901e9ae2bb6a9619f705af2245823d59083033ee5b95b5d5e8cac28c3fc0594b38c34ce2241b462da9e70471c670d0a53ff84ef00f626f5bbe9e687652557b6595850cee478f76be444fa2eb1d0988edbfc5ffdfb432d2c77e0086de35456e74062758e76092965ff0c9cf639843797840ecad2eb0955638f949ecc5171c23b77d2d274a3ee92d82c9c2f58c4a03af60091061ba59818d6aed13e983075751bf9919490f591392391ce5ad2baa801bf8a645c7b89f30e34f46b5916bcdbc124345847dd5a01be839ccd7bad00252fa8c6051145a1fcda7aa1ee5d72b8b0c0325edefbf161b13dd631a90bc52013cf2ee085bec0b932c41085fa79f62f02079a313a80368dc59f32449bd5ac8fb8a95b7fcb0f6ecc53518c0e29c5bd39d13b13e0b53b55c425592d206e4ca55c86e86b5c86fb81056561136c5020b39d53f93fdb1aec5468eac8f35338caacc291716f3008d653a07755a5133d78d7ff1ac19c235ade58f7dafc219750486baeafcdf62544e2505e821e468fc011020a37a656d79f071b90251f04ad56d167fc42c4d3c0ddf05ceba79893a915e5524e4fcd9a8124cbedebc214a5b196f3681dc82b27a81818166529465e7dedc7ae716df1c8e501eabf2fd63fd083b20ec92b31c271710f75a01ff016bd8dbf3fefeaec7885ba37d0fe14ddc1eca683adc42be9af05373303ef59ec4005a99c60d360a1c84f3c0279348034f621045dcd08d6444be5f816f6bca632fbc4600eaaf41e42c65673acacedc497d34d8f83556a6645f7fadc1913390565adc2831b3eac583ccc95126fd35691003fd507af3dfee4eaf794e1304cbc37e3a9ac4f043c8544b20ef73748c84b8f462f122a925d9d82af5979f1e9274efa01f3287108d9b6acbc97b80023f800f913068bcb32e4b17fea268fa8440c96e81f8ace36ec40553d083cdd8793767ff402179e58c02611ba2d172f0502b7cdc0981d7eafea9d693348024212ba3ebd656eb96709cf5e8706a8c69cceb90c4aeca0415c3c3c50faaf4227e700b0c9195647a6b2da9cbebf7fa611fa4b5250529ec24724a3081ffcc03889710e686ac19df1001995a4ab2c8eb1b9345c4330fa54d9912594e34820275754235c9bdcb2871483913402b20276de5c1091baa30086439479a7fcd8d9ca804db4f5bb0f440e1baafc1914029d6191aab6339ea283bdc6a83cb3dd82f36d7094871a95d2b63499199aebd58413d262c395d5e687e8f9a9faeb6bad2dce3061e2f314245567b83878d919699a2acafc8cadae5edf4f809191b1d364764a9adbec3c7d0d6f8181b343565698291929db2bcd6e1f30000000000000000000010283746', 'hex'),
'255': Buffer.from('e67db820b32400bac18c859b7cd87505173a608cdcb1db6e3b4908f0e91e6633765efdcf4fbc709229e53152b12142eb75de5cdbac8a4df3c201a45e877e1c39f9d73de7fad5ffddad247e282b02c3ef7ef0c88d80e0b333f3cdc46be83f6debf741c957551a23ce130663769278303d85e57718d94c5e64dbd4ca2190de74a3294088768b0c5858097f350cc9b7bf6e8ef4a592ec54deedf9c51d6cc5bb9e57d2fd093b3cb6adf8cb11a3e0dc35168068425f305b9b1800893e6bfcf7ae126730408cb84e602f3748ae5390c3360911a1fcc3b89f7c4603c1fda490123264ba50650fce4cb69186cc35606771c7b06ffb967d8105703f15ce890a51b8b73b6552eca4aa2e2867f52c321a8845a7c79a055ed70e1d56f2c5fe0cf6d44bc7d8f8c993e853060dd7f4616f5944b7709b83579ebf454e4317a2ccdd45f817521aca189c137fdc3e2e67db198d42785cb6efc61916e92cfb127ef84e82835b88becdb11328e0bd9a1209c18eb54cd72f6ce36fa8aeb52378cd2b038d0055b7ce9ad725a77e94977cc39e1b3f4a300cfd01ec8dbfab901b36f8af215b10555428001ac17abb582c5741c59104514b082e0fa5f5f0217d12aa0902718144794cde6915fe46edf28c3748569c81e4945177ac8529861deb7851618442ba1671913652e3ab46410d9b855cba8858ac74b21a7d62060849e7532b528fa73b8eca858e213c284237bcfdbe6f1ee36eb753ee0d57c0efacecf68db978b3cb73680c9a300365bea64f12ad11a08001beddd8f929c8626c9cc44445209289e0d7191dd2f4c5e53fb1702a2b1c8aed47183492f994a0bf01e220bd1f7b1ea89a5da42fe963924432193b9adde2f8bd744c5a918c653d02532ac19f734db69bf38df2054bc291fb4fc037cb794e32917fabc8de9ce62c8c5ff5e52203e0d842e41faf6c69e33aaa41f1cad6581d17297ff8bbd3c04e25abfd3bed45ba8f31dad27d07ca794c8adf57f52a8e6bce11cdcff01fa2fc2d083e00943d2d50d6e6b639d287acde04467052526caad24b82f708da98f4a40167930a127bef8556974390281275839e994cc5461af766c582a4d537b9b07a8b95684ea556c9eff84ba5913079d537b13efd6e130789b055309390cb63e7372053fe6ffc2a75fde889faf34c8e21c72b164f7634cabd397f5c91a0b42860c985da38e3463741e7a143b231da96bce7597735ba502f4ee9a488a49a74e554c2de53b30d8da0475c057f85beeb5331deafda905e7e9b15959b274e286cff894b4967b5728ffdbeca92b57efc59b2532b0beb03c60af74b91d98f22e55c740db5b7c7b38f88ea4f53103b50a27d0f1518033705fcc6645d720aca43c557d5a991821e5fc5683e99b407d4f2e41cc8934a6a4504553d0a435ca3f853b60061f5389e96bf6730ee61f7931881a1e7baa1dcb314f3ff5f92cf0970283c4279993fa261f1f8db2b0353ebc16ff12f935550f6ace2768bae24648c599bd84ef5d2876eb0e867e75293c500fffad1669e01c8e8323c10fd1288058d14a2462b6453ee06651436ad46e1d84c02b783a6edd461d52d30c8eaacb1ce62c0491656dbf3330e7beacd92a877ce6fd423fefb45a91af4a880b261cb00afcfc53a2ecd0206b211bb038006366c8881224749cc9077d17887c6e4eb766a8ebda45d5c390d95d0bedb81d62bccdda3d86dafbdbf7ca444f204b7531877337831142226d686b75d35c33bdfae128b26b7ce54e910cf939ee6523ac3944f3a29a30f40aa52d446644025afd681f7cb408a3f4df59b14d53578a8ecdb353300ab78edd9093b3c371c0842cf9c27c274ca3704038df23b68c6d3a83a019874d4c96a1a4365d882b912ca0fe53d24d4542e9e74d644ace27012e01eebe8e09a2affdcfc9b920423e53a4e79f8dcdda4f5357d905e92630568d77c17c77ad793eebf2172c43728973b4ee125781b7fb93f6e3ef1aeb32d8c465cc9f91cb5ddbf5f2961f6d0652a50aa29235ce5769dbc07caefa52ebe317764caf5733577c74b39f04fd8af215b82f1d8091b40aa3f7ae8b019fd670f6d47e5905202c2301166e77810717303c347eaf9d365d4f9f9a014612aa949cb9a4783ceb533b6b0aeb31b148b3ba6f052336e9b83ed0be3b1052ceda3f133d8bc64c3f6d54cb182bafd2376930299a246bc6c3f9c1eb734c36a3b201cbb543c2787a1451bae5ed7be9b06de944973ba20ecc891c3267e8cf17301bf34877cba0575616a551b9b60460ac8696ceefb34b8bcaf17f035e26bb00f57bd85d652e6c260fcde67386dafce568594a4d8d049a0d44d4771d7bf5aadd9bb23f2d6e3260bd2bf6993b2129d09f9ad8531fe09c6470086b13ddc7930a0e4f1c2e391591b215b9245bec729785973531bbf4ae7592ca85a09944a502c76567aeb77616dbc545f8ac60c42457b4ec5d46dba82faaec6ca8bf8e60e75256ba9d88ff2a754d1e550c64401f798139c74c57cafef419082fb706c0a29252fc8c6fa1d1c9b46a23e74554c8aadb6db25bf9228bbfd16f05fcb75a8718a38a64efe49e0b48b936381d1ce67415153863517c2edca7bc41ce49f557b582ae9545ac4e82cab37bc1716a85a3a7518b055f936c451651ee500146d024b6077f6ba7cb2a3b9b58ae57ff11472b8efc83c6ef3a9490d68657db2c82ba37bdbc6bd5af6431f6ecf65cd18a5d15fc4b3f35761e85c91599fb696284908c5347baf3e5855da9fbb01a5f870047c263300a7c8a3b8a0caeb0149b420efef6866d7dafa54789562f471c0c048a68d03a5e56d8454747c0b28ee9af8331f6de245aa6ab80555f75dc4dc968f672e78fe87c4e81732a4aeaffb2d6d0c59857931dad3d175765a35c96d2c9298392a2a42759d3694f446196664f13135610da1d7f478668944e62317c5c4b0d8602734008b9469818b27d08e8daa83b625bd5dc62d9b9fa25b84e25e05373fa2775f10ecef32bc229f164d60eb775e5ff80529dc86b12d9f9a5a369c91b5a2b12ed55722332b556ca6553858eefd540515fc693ab2ed449e79bf91fa10da8a479398b16287a67946fd67b1e7199bccb5c8960696f16cf60061a18518c76222523cc0ca3097604c1cfdd9edc0ed7d370ead2536b4acdcb68e030fa6c0ddde598a9842a9a8db4c84baffced016a71ba0252937abd46e73b8723e29ed69322f3fa021117ba4e9d8686ce55c5f69509907e9f7d0e397de65183ab993fe652ad5dd14a952effdfeabe3116a3b15887de9208981acca48d9e2c83d56a7619c8910fe414557d2d4f38600d72c03090b161c343e4f5e616568717f9ba9b0b2bec9cbdbdf03122123292a5d838b8eb0d0dbdde6ec0b2c383a4148777c7ea7aaafd4dadfe8eaf2fd0c1241595a797e818f9195b0c3c6cc0000000000000017273a49', 'hex'),
},
'ML-DSA-65': {
'0': Buffer.from('0d7f54a113bc87e6be6abc34282a0abf0dd12e8b3ef64f338d62be9986eff721776a3ba2992b069c8c2d15e0b948f2615a7a71ba42650abcddf147f50e6ff7de01aea560ead3b540ca1754b4749ad345f750d75c379804b7893cdfd059345297c8776fca5378ebbe1ee1fceadae9bcd01baf39c8f01e8791730e7e1e5d0efdfae2acdb34e6be09a258b83eb29da9e48506c5d1029d1b7157b103fa4fd77c8b305a0e4f2dc82b68936254bf3a345143920f67bada15d3038f76c160281085a666aba741ee44b12ed4018e9a41d77c642bfefd658255ef560958575c338635d140bf73c2daf923f26898fdf45fd48ec24c4ecb8adbef15bcec7ef5302fb58ce6a16628bae20a55c497c0897f86f0ec22323b96e1bce5e0cd7c608aed5706a2c73d5d4d05cc637f86320a8eac06b8e26a13874bcaa9131db6c9e237841df21789a47fe48a13895575b77e141e3285197b5a16f19a00bccb1d384ae026a17d64a55152188b88a682562340f667a19dc3bd6b5592d39e8b7b408c1ecbf768628038fa4333a475a72c03f3cd8aef346b1910724a47ed915ff1b2bc71ae17f127b903c679b103026c2aeda967b0d6497a30790e2507cc79bb78e9326f66c8d015f20baab3311a7b436c357356f20cb03209bc82863004597439d0905d73eb6213d14ef4505879e5ac3f4988956d5483bd0665d0d9b3e9353de68e7108dd0a6af6d23422fe193294419c3887571b7470d206f23cd059895ed5a53cdaa6ec94969b43eb9c98ae53b909a4162d6230717b3105dd4d511a40b9817a71e037df02d95c508df1a392aa40d9516811bd520442c00b8377023cce3f1462e50636813ba1e4350942c435743939cb540d4688d0db69885ec2d2e3d37a408030737dc8fbd42cf19df941fa5f8b532cbf839ab13b940b5b37200b900d27681ad97a4f92c256c29d63888302b076665d5b9c2ce219fcb12f80dce2b94e6001dcf3f662e01f905694a78ca5e2afdf8ab7cc1fb72e04521d9998662d423936d5ad359ab44091b53467406b7c306c0a0ad2e480c968f2d9e4f392ecf983fd2a4ad198bd701d09a1e2efc5c313999ceb83695d99a5ef25daf159d26f4c0ffbe3c2ae03cde0962cbf1a4e6a98dfc660922c2a399190abcf933a73f68d491c4ad8806cc450bf23d4e1c1377f6168a3c4df5b6bf8e1cb4be11bda24b6d9c113ed4d40fc2dba9f541d97739b5e40e915be1e10eb01c30ef609b6eaaf5d570f886d031df36fb7614080dfc088e821d1ac4fc50a48c5dd7ca6f08c7ac280bfcca640cf738f08f7da29639341e396a46d7204cc514d9c8dbc213b967657f4a67a29458947687b55ecf26d833239a7c0915f10334befa61b74372a8e1f4adf44906ea6395e15dda5e4b2d2005d574a943abd9d224c7f904298e2b1e249ab33d93089f239de6ce6b0c2e1b856940b7b08ccf1f98a65dfb3fc615457e2ba436bc63cce72510757380a5c07d56b47c93430b6bf9a89e5f6e1721d7d50b7417432471dc2ee0b02430fe71f4122c0e3363db446e4f7ad21cee944f3e6072fc1fa57d175329707f52c51f97eb287d7af70ef91c0632ad5b89929507a2d01609993c2ff8bb991e232b554430cbc0ae4f6b3225013e1fd0f8e0a485f7b55c1f96dc0fb6b395ce104d9c3d780567cc9f7bcda296f665a5eca11a94fd1d0f35d10e0b017880e16f31de961f7b5fabafadd1c99c80cf7535e7df7b807fde38b530ee527234983e25eace30c4be8fe18edc58ae53ad79a145ee0700be63b636a18a4eedfab826383a9e5d9f2b7e490c6bbcc3ec0f37ee44b8e301091c6636cf212e3519b706919af41b872d6b4778cca8ca3373f62dbd8f68b59ca29467c63e10b886a18d2a32864ebca2ebb2f602b736ac8587d544d74d9aacbe6e436646ffccf2ca3da2121af8b3431b523e09a538bdd07ad3cd4c71a76cfcb67273f277e18094ca9730d06af60c354824abc84f623e1727a4f43c7021ca18d463c5aa1c53cd4adb77f13156103ac0907f6487689bf5eb2202a6ace8c9f55b5a285311d2e243090ce07e9cd2bcd253edc4ca57c1c42383184ef08d3f7b4ddc05fee25e8d72a6fa0dbe545dd3240edfc8081fa49542bc23d426ad286010920ad92b0fbae5833523a94ae59b87d90e1ae4cb504f06512b9c0c47d854750b45bb01a0a2788c51d808748f6cfab177fdd943965187fabc8419292f45f57718f709228a9d51dc43e21ed3af2bc5cf8ba75a4d22203a77662a71675b15bf91d3c7074657948b43e87837449bfc5eab1fb1fa9f8f91df5669b4957eceb02d013b0c04b493444ef673a103f630923c9ecc5c2cfb9fe40c1877fb9a67e54f7f0ea0c49d0a624220eea68bbe0e23d20092ae73a8a0f7749cf85499dbf4846308a190bf9ce68fb712a20db6910923eba88f42e93e76230bdbfa9890b6bce07a5ecffc396cbb314d3152bf1677a26a0245fd8373a1288d97e713d2326194e2e26990ef413a1076035e7e04be3d07cbf9403ce9f8b7f10c70badf62efd144324c1d37ead93ea94edff937b0d62820baeca5f56cdf30487097f5058ed3d74639543b1c160d6e876021c96feceff84bb2b1588c72f5f9a6a843b85d9b78da39a085f258296538467ae9568d23d9006e768445f9752ee754dc5ddf9b44998e90dae1a5c720d0abd3e81b750ff8a689547998a45b5a6155b462e8ed38c7b6c44bb81e64630449191a38ddff8eacb3f0cc675bd84aeb6acba135a65d2e7233e6b3d59f57d5a1bdf215a3a847a96306a203ff4a564524e03526fe3c35906fac3316cd19cbf39fa9b3a37bf2624c4f7eab0b98d43b967598349e7b0e69ae7a110aa5614e68afde1ac453bd8b02a39307c6423339d49df4a1d7c3042d0bd34ab9c36894eacaf1872ac70f0691dfec0ace938d17f1f61c7a0b6a12542f0d5e0438d2f0c69dc4f0a2eb5eebc56155954d97855a5e95d133663f29402279d39e41750c0667a721cee486847913d383940419dc9fbc118d1f608abf2f2ca244a7486d1ca2e883958a0d36e290edeea0e5dc8b44f22a6ae7efacec2ee642e8417d5b6338d58ef540b5438a2de2589e3c911d93570d1f7043da7f04f6a97c64af34f25a99c57662ddc27264d5fd880d6538a81661b8e83ce0f00e41a09dedc2dcf0935842b46c7b0560f0fef6c7e45d20de5566cd68c4bea75af56f68ec6f8061b59bad47d346c02d4ba89ed92ebe9276090a70f119faf4038cac4d655682285dd53707d00063f89f97dcda0e370a2b83bb6c8d9a4db2dc85efbf93d76b007de3566ae416a817d1fe9d7383451b8789d4892a4144befbf784a837dda4963cd20cca292273121b370cd1d0dbdc9e42aee99ea7c833779cd1fcd570f2c502c791ce06b082ca2f820eb75fa2b5ca072c915e3bdbc6eaa3cce642e1001fcca516c6635ee21c4a921af590d50d5127da0acb8ea48d11ea777192a540e588855acfe2ab0aa23e7743da7dddf11cb5fd7c3b0536b1dde5156b2968420b58d502d546781cLine truncated
'32': Buffer.from('34c49811f27a21de491ed9288fcce6a591c5b4aff9f3d1cb67f212aeb910135ff19cc89cfaabb4a508e591ddf305b80f140cd2f2f892ced0d238f0b03581f807daa5aa0567cf3f2d3c748927709ac09043ce595eaa6928cb3d123c6808ec8f3a5a4a9c1390762989a4211db131ddf1ec373d6ebbc4c608a234cc3ac36f6df46956e86e6bc4b7ea301830956a1a8e8093c9c8b0be931a035cfdb0268899ca46ef6af9c0ccb34d35eafde088911aead7ead030cf5730541c77d940570b2ee44c639cd842e8a32cbd069247638f7d14bbeacd4e91465ae18ac8a1a89f7e8876f25c55e137c35ea121ffde4c6e97dff482cc1f324fd540a4ea9ef82fd6f2bc2f1e3c008d92b9e60444fc466e662c72e31837a3aa284e5837976a44e195709c4adcca031a7364e0d1f0a717eb97d8dedd52d63a32fb45b092a00bbc96a4d3c1ebcd5404fa5e994cd1ade18eb8c62f593db313f26703b7548ff62e1df9e8c39656ce4cfc469135da288053e24dd91525603ff709b68cd860ec170de6e4618d9732159eb9f05ad9c1f35295d4cbec9a7c2879c6de7a4c4227ae00515925ca2c63ea5d8665d1b3bef741a08ee344358f849e122889845a3c2d1502251da2f7f71123ec05f1fc500e8175a30b3d7535f0a8d108ef98e4c9786bb6940b34dacc70f9b000ecbd61f6d823f6843c49aefc21f7578847d708a9aefd175ad9b691b47d35a81ef57c7c37dc1e9bd30665807b43cdc2d7a7c810a5838e38296ba7cc1c751ffb63b312d05e8ac59fdf774ef3776f7d4be274c212ecf6b2a5083cf2ddd81783843f20082d65caa1b325344e9613ba556506928b6c309146468e7c8ec364c826b78d64f62aed0868087dff1dc5cb68adb2570b8b62eda8a9b1e909c2ba794450dc4fb51f187fdc94d0f9a32b48827782f3d18ae0f929aaebe13cee56d69cfa12be13c5cc4c696d899ed6ef3c5bfe38e0b385ed3237eff3b6408e1ea15c14a8e604b92687355ce54235c7ae914808af76317fca840399eef3c9dd53c920ac41826043d0ed29324f4cea7e1997e0f65c57bd223f2599234e2f3b0d5f31ef87eede1f8e1ede82bb48592bfe3b3c3b89618a5609ab8b2e3e4fb88086ab9a225998ba598263bfe58c9a4df0578735e45d5b273422c60b078b6136b45ad9669ec55be9035ba7986541c71ed8c94f3997fa1f3adf7d8c33460df758a6b21dde70d1d36fe63dac677cc559115d042643c06760a5e0cfab1491d081fd3fe562cffe13d02c76a96e35bb367ae2d39bcf53a0549e8137dc63027ddc1c941af4836adcc260e4f105c9f24c1318173edfb5d8c0795ccce74340b89cec6f3de970946436af1502a5a15981b4c1365b58c35ad4aa7edd0f7c7b125746932b927ea870a1c01fdb65c133c3979d5b85ba03f0f0f675fec2af591aaf40f241888507e83346e3b8397aae022ed18f42d31ed7ebb2be6a7b06852784a2a6b3845759495f17b5a77d508d0be908f0ac56afe414b992ef0712ef5e46cc0f9b265a4b6629a9bcb10fd6fc8a26690e18c61a3e5b5ed90ed476fe869949ead0c174b7b33d5d69f2f1f98f5028420215fa9d1c7798d5678b222a81f36e9380a75b40fa55af5d26b42e9a073def2a339bccd00292f58b85047f56193a81ded86fcdf8c16990291a6fae73f80ed5a93c5e87a09a7e650676fe05f870a91ec0a9a3ed58105e3b333a621e01c9c6fa8968ea2b1599dbcd58375dc8f6a20bee91f6838016f1e4f3423f435a6d89385a13809ba73b76a7cd17ff6f9145b8832e69c1a130134c3642a18fc1f7dc65db535f5de4b9f1090766734188d719546b10d8b2bd3d57c307de52203c9bb5d7ca21886d0b9f396b10be28e23a821bfe49a01eff258c05f88c8b564b97e75d2769b76b47a8e5c51cf468ccb613ceae4f5f4274578a756d3a2092b7e0724184cdb97657aee74704c6e7480aa1fd9003bc9f1875cab70f5e8dbb53e90cf5fd10910fe9713191214d007b01171d1f933ea228f8407fa6ccc0e4437c8865c182818b4923b23ade3f9bcd86179e75229e1524cb57d2b817825dc11f79cd038860d4f0da07f73ad46ff0d69b349d7997a12a68755a80bf7152508416cf89a1c6f0cb153a32161110b5615e8339cab6c24c7bc382c10a4ae0a9f6c49464b74afb6c2eb8448ceaa22c5b2754c0f845b0db26c2880616dbb78b15f0e3d367777fbebf155c2dfd5104ddd0f5fc82f262ecabe43d30ecbfb87faa5381e99df54cb186ffd46b7d450e37a83918fb647f74a0be7d5152ca443ecc0e770ccb9cbcf8aaddb0cc5757e076badf685063adc6d58097a74097e6c9ba0fa7c3900c0302a99da34acb3eca163bd924b303dbf4b8a276a13028169605a4ae6da397c3f6a2d0548a87a3336f56dee9369c1332a957190d1bef3ae0808c497f83b9c961cfd2c98042bd3ba86d177725aa4f2a41c85640663356a9460d57de8cb8b457c3b2f00651c7684bc4f3d8ba1a3a5ec69250bb264d6dc79bb327233abdf7f90f104481aa0b67594027f2a3a605c447227cb7d262e52691f5d23628df5987bed2bcddb585d61b7eb8ddc0b05a0ba47535e8e91dc161123779e73ad01e897c41cb1e7f31703b588bb7dc94fa7bf88692d957f07971ff7a0b5aad6737922dae0cf1ba91e256ad465914a03a67da820cccc3ecc4e4692d7a8b3a6829de2cd4a5600910e3ae8754dcfcfa726355b1726256ca4d88880cfea74a51ea4d6ed2d94cbb23e57e03e17973c9a3a58960ac01675c68fc05cbc8207b7c7c1c730cf9af46ed61c31df08bde7073e9451d62d8a7c19aa823cb8b134d9512daf6bc6f7cea3c58a7be864c43768980c7f4c0ef57216bd67c58bfd56549e7b42cfa6f455bf726ee7f56c0e36cc734267fc92755d2167b4eae5a58064ec061b30f6869606afe2602fe7871399d5c6ba8e5d2332b1aa8fa0b673c3cf077acae94a366027917b31266d18da6b6935e552be4c47bfaaf3640901e0b24680bd2def909b1c16be8d04b890b894c53497b194737f329afd4dd31b4177d5857859a7870c37423f1bd41838dd87fd3c4304274bcad050269ba813212a3c73b0442e097673ff76ff79c5bfece3761e0ac59601eb04ddd444bd2bef8c7d5052ea27c66579b80edda000bc71391636e06c1b309f5c9be7ec006b895bcc2b24f0e029f17376d9b3d0e7cd0f9fa178012156d5c2d06059984149fcfc5a97839568223ec9d484761d1cd908d5bc8c74b0cd520d74a23cc39ee1ead0478b83322fcc6844f80f528a4cebd6d7d5895fe4b635bd2bbd0f8395a3e1c289103a556ff5d1f03438d0e6b852c7feb8a59f201efa477f15830b0b113bd0e7e388dee9edd4aaffa881d39a9120fbadf177fa02b55329d65ce5037e3cc61cfe47f366c6331adc95abbef4923a1f5f9a152313acb930b6844699bf269c356e7980e6d59b444a711503c4095d9b91a06adcfd86cf5bfc69a28a50202e56d8afd34fe255ac19d267085b85ebc0d193ba6acc398c916b23da30dd494Line truncated
'255': Buffer.from('99ffa062d3265f6914fd4b9374d82dade48b9166689dbae45e225eef7a254c06537a3c8d223d2aa8812ae21bbac4333c29a03b0827a59e43330966a6f67312757c2954b470cd6888dd49c79eb5b35d4f5a469241cd7795a713d7eda6a1404dbf46b1797e4ca2bbd17039c21932d8cb4d2a7f1a0ae1474670103b7fc38e4e0e663ab5f061f740324026f034e8707f36c66deae7fd61a04c9b8971e96efc5a8bd304db98bce632729ca6bc6d96635002221f8faca012357975f025f500493114d007b90761e33a42e0aa83111e987cc93c07a0665e033300cb06ed1b3e54dfc7bdc95a9e6464aa034a41c51637b54013e87b652675823a2ab9a0cce4689eda5fb26f58f7fc9177fe76ae08fd567d8fe9b82c64ef0d7f99642bcc36dfa3771f86f653b1931f0b7b9c6146969417c3a83537e28ee9471be0d53eea6a8f3f4e2c416b5705b7ae694291a821335e46c32bb1cca12313b0c17c7e93f557285e5a719d8149723180989579c319a4ab44f569e8a8fe4d29991ea4a43fa8c7faa1a3f5bfd1efa7f5de899cf7690f0d195d617004841b3e6d23f305a04d8b2ae52af65a433f230b5731291aed76265c04b4eeb4306e7701e0fa3bbff497abfef5a70157e32a8cbfbb707da0196849ef7b0804b7de388d3034acb79e95a231f900c533f486fee724324c9bc7f6f2c487c07df9555e2f18d57df2995e1fd2ae217d38f8f2a825ec9241dc7d6d42612cdf53b7f171dd35ce31e0dd93e148f83e30dc66093f26366ca96b53e7829df2297b626d9ed82680e583cddb7bd53d3ab9ad311147854b57b41fd3150dcf32004d1a11395fffeb0c2f94073116fdc61b933628522f4c2710885faa482ef0d0c265a76b322d11fa753faeee6826cf7b642f48d3914462c232ceab191f405e035a901428d150b5f0d0359bcd050298237bf7f1945bad3f4dc734ded5cb4bb59a2df8a27d478d1e11f8667055b2ee658eb167bdc91521fea217d53a2b67660ec2d94454959fedcefb69afe906aa43bfba4436061a35a3d7d94113b76fee0d2fbae0803073aa51536cf16e2ee0d80b3436a4a42b758236befef1ccb7fa8855b0b86b6602fbcd9c59e1a5e07932a0305842f734485594747ba42f1b94c43c47ca75c832b90a148f34d8c388280e435911cbf5d645e33487113a00b2ae12b6766e0e6267476cff2cc8a7fec1c45bce6d56ce59263547fd5269b07870a27d4b94015aff55aab2b5b4d392e9b5aa91ae3c1d7a4e3b7d28a166353338048a4dd47482eb2f4e51c5a615cb6d477221b4a4d1b65fac3e487afafc91b70d505baed7ea1445c2479b1b5853bf38aae67c406049d4c5b755c004ca26311bdb77c5310d4a53a4f464f4fd41f4331c004de3b6468b9d6e6932cc1cf81e00790a5c57b4402e76a5eb7f9a071815ddc295bc73feb411088d94387aa3d16556311ca03990ba6fa4d59277e30afc3a04658775080152aa60a4e87a64077a5d432dd184dac5f516cfa61e1751c6a51874096db2cac6647eddf9a97a438f290ebdf402cfb3ca86b5d8beae27a583302b7eff05cc9ea70d07813acb01664992cd6945d043e97f751d19e1647b2a20c5829e85acf4410dd4cca15561fc51bbb45bea894143ac7a884f68a306c35ab32371fb698dc5d9bb09bed31e0b6a9e61321594e989fa31360ca098c0df35f6732a35d6d070e536eae7e2c4c12e35e6b55d0931f12127b2758c6aee3ce204146b670c82c886febd49f96068e69a4124fe9393301d41afafdc47ae1b59c9525bff7dc413093a2ab6b1d0b55ecf8327641b6301d05cd5ca6cf1d85d1c919f554755c555b7fcf55df9e5696034f0cfc96e6399af5818b92fe91d45c8833b74a03c956773677922a1a2b46017e4f87eb701105e43fe10ea15fad6c52bc11472e45e6968afeb04231bb5c625c63fa9b128f21060041eed1d45fbeb1a2c9f9a895a92cb4a592fa24ef208923089cb44ab4740184bd1534994b969497f8a0f9bcf0d1994d84ca3ef0f2f93cc048adcbd2caf33e296bf850bcf1da9c77a596bf699e410970a64cecb0a6ec0ecbe148f14b7084b3f85e862666c5e4bc43beb61f03d5b63f867caf120f06e3341edab53b0f9200ba1f6ba387540513c315bbaa95d6dace515967217b12b56a402adeac9eb8cb00873bf330a2c3bf78cfb28135146953fa0c38eba016e4e0c22a58abec38d30f9153a37a9a36a6fa57b25ef1ac5178583f2223c5fcb45926575e41324ebfc7f12538dd808d6c1a0583b41fff0882a08416b075931916786bc381b3ad3cb8392fb18efeab02a2cc185f9e01953d0f61e62d452a34d869af69c97c47e97633d32be2b9f0fe17bfee1dafe55518a293158422ba9784b86f76c047956b642cea69b5d9554c7f5af6f3f1f9f07a02d9a5767b0edb3d858ab0d9431c3ee2f1026db9bb99f35af83fd0353a44845ec9d6e4722c0d3f45dee4b8bf1efc4b9c9a24d4bf0cf3b5ba4d7b1d9a21f7384b9c387669c49d6347009db487a67d8e66677f9d3692fffe893536da8f5142c37647a364117ff3734aef555c637d75908debcee0f9b34030bcdf75b1d2b232783bdfd994a330aa73f7328410606373cce5c9a8b6df35973082153c94e920ce80f4febf4c39066d8ba1247286e572d3714300ccebe747cfe2014f5bd241de55ff9105a1df3d1e40fcfabae07c8583200ae9b396684322176cbda7de672dcf47ec77b0120f36637367e1ab04ac00151ef1557fecf0ea8265ad5dbc10c6c1a59a9e57b3b982571f26358ed715cdcb5f4e8f38d7c7e434c5e210cbfc9f92cd9715cb49a9140e7bc3bfeaad070fda0da6d3ae50d5dd673e255896f370303b0816736841b751112389bed5c49ca45fdb138678bf258ca6c9cdeb35e3d8c31228d8a2dcedce0c058614a735d80e190136f1ca475e3ba699ea8dfd5a33b1e54045696faecea7925fe1c52ae4bbcad8a83971ad68fd9da91693b6b1bb59de3d65ba5ab9fc6ff3aa98f8b62d3ad4bf4b5998a7b54ea3418d1d95f0feaea350e591c63bcb4f5366732ee78cb24026f5e982d7d77e25f4ea1f1e88db074d7738ee8799050450776cc8001697a5844cfb4d0ab815a560151d927495465c12004f22668f37dfedb2a7a64b8ee446c78b1d6b8be6f87b5f21643ac8bda3bfae21cb2a6665147ccb0bc27f0e6ae990af7e2f3e58c251b1219461dc2a9f3c704b6538e2ceba6361518d199368b96c719e3402013b3f664ea703aa08b71136e6fc53c2e86e74c967e3833dd2f938a68dc8ece18dfea1999a835a3a1488a188909956e9da42091095bad9a7b2321d441d5cabced6b8d2f33162a774a04cae9c79165ab75d277402b1a4ebbe86c1ca4dbb2a1e14fd24e42aaea0fa11710f48d0617889e454712979994b8025a3755ff8ebe3a921528a558830bd5be336fe1834740ecace39901b37aa714686c32b569c9ff347430d985338081c43f54da309dc162d7b765376a208521173d19b2438dd4f5dcabec437c42a3e3c0f6e9323Line truncated
},
'ML-DSA-87': {
'0': Buffer.from('737897d83f7fb82c704f4660c16c544212f3d3d280b3390c43d356c281aca7a3c90637a5dea83bf3504e593b178b17ec38a8175507a6c28b80c21cee28146af2161af60fb123420578e0576fbb9d579631efda9a4304c0ed67572d393d813155024ceab089c1cf1d0a5e9716948312f70b4a7deff76853f5cdf29737160901c14ac2f24ea4c7f819d86fa9758b8ca6aa6ffcfcd6d60f90ce31d31cd9d88586b9a38a22402be7c89c9d57c2b194179011c4fd185a5bd737032c1e54da0108f355130ffecae3f39a47148dacafdf25f9590bf6c8fdd9d9b7cdfe30607a235993c59631f29fe01453e2fd61cd4e8e3be21ddffa054c5e91fec88ecd531090ce21d68b7b11888ae9372fe2dabdb00ea311bfa564f86de46c61f284a246e420dd8056f021448a2fa6dfa2391e5beb6ef0a5a28180dcdf20e00dff4f9628a99054ce72061b0359cc67d4329545faea8943d90bb0f85bcdc88ef2acfd72056d2b5fbfed40034f2d344a395434d604a336c1e418e2598d07e8611f9c28c23bd2771c4d4dd5f820f197b50e58bfea502f6a53893d7fe6a7460a62b8ee892d17dedf606cf61fd5f27e002230bd15f0e3d5d951df3c54228c20d58fe5e5d072a1869bdeba1d90cf019c6bc3fb0df24a11894bb3a2d279c67d3a6d4342e0e2913861bd3f684bce8ffccbd6358dc0778c02896b719d675b584621edceabec3a8e679686363825e6bcdf6579ec67ecafdf23d6e23b747e340fc0982422865b8002590f9e35c8332ac47be5c4be6eeac3ee4ba79574f7c0aee0fac0e5cc7a9b7288814c36b10e2dbc900acee6841c386fec11c69580a87244fc9f995f6adec68b308b28eaa17129c1edfcbb8592b4bfdf6604afbf1f206010b47e92d08d830052d109f0265213fffd6ecc47aef5bd6f4d5fc19d2b06924cb96309945168f382977e9f6a2f59237b4a91bdde2d00453df0e7c516b7a53b0b8582aaa7ad8af9f40723d09a247b653ee48999148b5c160a25f5e9cbbdb53642429909a5af11c6f36db3fe8f8916f36f565fdbcd863565a6dd63b974304b6aaeddf91decc981d21cc93c11d8f76dfeca8444b6b882ff59be214fb1ae9fd90108f65d4f533031c35bbc552950b1a96f4be7ea9cd167231d7a7fbbb203d34bd764dab3ed2eeaba3419ae3674f7f01347427b84ddb5b86969e57e6bbf86b61bbda8fe830f357d12d15eea0df7d5fa2d641b03077f058719bf11819f0eb1dd921b783b9c648b5b3cad3d22e9442e514e9eef96d53c1de328dbb79eb801974b88e179d98d28bcc75469a2be46ae9fcafbfdb22d302ad2b535d7c09d06cc5ce1a50a569dbb13debeee5cbdd3341d06d8be28681c7716b466284efb4bb1b316b72f50c85c2a260c68231e2c516265f156e5f5ac735b9a420878db52950cdfcf21dcd9da62e41a4e117386b624f638ed51b4d2e156573b6a327698bd41a3d036414b201b0a31d818fcdce9c1e4d55def388fff5fcf5110b680e5ba3808f244dccf7fb01e8197ba3c3a3a2be74f44551f5bc03f77ca5010d1c9d8020fcc7c354e3ce9fa25d4900943f564695da56a6e4388d1bc69a68d413fc80e5913d22d2414b081052c216afc67ecce4ed126a8e0762191558cbbdd8d4150af7bae41f4941ed42fdae4fed9a40d70a0159d4a8ae48006022dccb6b4ae05dd484c065dbcce9b253b40d1eb542073fac64dca11b6e1196c5b50fb33d6bb831b9977602bc9d43c80713a5d714116e62fda8e9aa2c790e8d5adbf8025dbfa5f80bb92b661d45fb972eafa25303f1db7839efab7271ae41ce9f7c28a7cb8349a3eb2734c6b13caab678d53eb742fbe84f53b8ec89e6c155ddb0a4908799372123023f4c8d6f97d30fb70ff2d192be0928fdfabb9aedd04f944b2c7e0ef143390a20a5d5ea93d3a8f425470666dbf8733a2e2564f27e1878b2805d71069e55b225e3d133a7cccbe0db3f2b14ee77d717bcef348df09259efe12bfef08cbb0e8d58f08bf10c6a7b0c2820b442c06209e9b8134aa20d05e8e2c763a8b88b5d4ec544aeb1ccd9468901f6ccfc20eb632a75d051a0295590e02f5ded6efb33e54479b7e1104062ccb73bb5bcea1da9d4d659e1ed40a42ec13a6f27606a002097565264954625103e921886df888740b7166640132b428a97062241d083cf8b4892c159902a9cf35921df2966b50f6f31209773d1bd10c61d14409cf1e90a7d06d3fa226a865fb241299a859b8dcc898b4bb1dcf65ea17353a130e71ad184e9e89f0676e666352ff4614d8a7046588d97038a449ec426b67c9ee3101b8091efdd10867366cdcdff3581c0e973ab6ed71c984b33a58c2e3a865ab1bd055e629a21fb07a8a23e998f2db958ccbc89fd1b3512330f2cc69c3d74e16f8848556011881701b213dd39e123aca241c7231052a7bfd4738fd69bbfcd0ab74276907c1be3f75311e395a485d15b592d16d22c33ebf91d64e81d500ea23d53f130804ea1cf51c4bf2b0474f4f62264ac7bd90e6e9dda4d2b627b1e8043dfae64c6920a4f9a14ef15826996035af30cfa59a6a2411c61d16938004e2ae2ec72c32825a44c3200853fce28e36620fd0c71121346aff28e19218899f8e894fd6e477571f2a5c6c850104495a89cdc0998496b979b038f65ebd15ffc477ef22e943358de58612bc734d06bf8b77fac755b64f4c71966c699c43c5c38b7fd647a8b82cf354b1da4d31c9e918e146a997f2b4fc612e2ec73ab8e017728308e589efe326d4a14eeb55de34849938446911b9f3c62ee51992da1ea284650e0fd6f6078301a46948abd7d6ec2ca9ee202f26b9aab99fc29271697d8565a5147631ddbc9295c44812262a9c39cf0df4e08c52749823bd51d117d6cc106d74fe329c658c1034dd7d9a2f073fdf8bec519aa4a2f9caf8d0d719cb37138a0383b263c1c28a8b15c1d18a63e366a9892299b507da6bc9926672289a4f9f679e645db6c85e1cc1f4e6f9581984b2f72283a8efa471614e3e3d4a58921bd0d5feb85dc9cccfe4a7eda2be3d8118b2f4ca35ef6824e1a2d09162fc81791c2e30fba9368022ce8e01e1601944f05a0771b2d3c970f88841389b11eff76c853570c66022c3d35c4e94714277cad948c1a2b3273c6b3d675f9606b8b1a5d1848a8fbaf0f6e108b0029b6fe2ca230cf0e5a24049616db1b5bbaa0116308fe5948c45a4569fb5e3aa0bc5ebfeeffec460935477ce1c06dab0a1e7012859435e9887052293ad68a92df2b498b07dc991f16d04dd96bff885bb49a381b27c7e3701aefedaac8472f9d547da1aa8e226db691fe48c0593c8824803e564f57bf6b1c927742c909666b07f92f77236a2268a6148b517c1d2dea60321ff1baa5f47c5dfc000c8abc1c78384e1d6ad67dd343ad5ca3577b254d0ff85f12953f2100e6ec07d3c87d8cb79538cc75aa60fb936823009a55a1e7642a18efb94ec2eb44724f5b492263070a3e5481d091820459691507ccca318ffdfa4a0f5bc079e4c6a0fd41e715d0a7aaLine truncated
'32': Buffer.from('7554eaeb3eb62cdb8897b2abf30cad518c84235e7490c4893715b5a71f245db7701eaae951bc3eb4d761c3b830925400aae0dc09d9f615825effb51b2f1a8a602cc1543c3458c788fa6ef3ae5d3f1da66736d27cd6f664da96b5902406120766ef03d3f41811eb48c5403ee8adf6c61ddbf247ac8e842cff47931ffce5e67b0a9a9b357ea20c7bb5401560b97929b4b123f42e4005ac70fd92becffa2b039c76a098a1af5eaf34e470ad139d847c473649363e591eb2eb9ecde114fe7478e65aba5c2d695d032f8df8f218e24334381eb908c560a4621248e497cecc18a0e7ae5dd50db41c79cfd02a53ef174030653aeff88cd398dc98019fb7f67844810ec394ea9b26ca04b336bc2f4a96b6d20ae799093bb29ca542b8e54baeb40f9209ea44e93c95df684ef22df67f1c96a8a5ff61d1228fb1824a7b2a78d74f13805af747d7019d2fadcdcacc3c4036cd87d08a59f2dd4bf5435559eb6cf113a4c1c9754bc55f6157e2f9e03653402b770d80ea3b739d42fe02e672816d36acbd7ae188ea19fa193f1249bb29e44070fc0897cf59c7f274513dc4bd682c87f2931de928b9759a8dba0258eaa1eabb09e16a0b828b20f26c6076f7afc6dd02b418fe8bf6d0533afd2913e3e40d6393b954a1a66ef15cdf3ae8562eda300072ac100142881528661fb5a475be59106fde287d7908e629c7c57d74d6a119319d342fc0b9b1fedec9fa6a38cc7d4392ab548342a0d6c18a32df0c8f0912a69a0bbf5589c5e9dcc1d5b269b6c28f58cb8bf2e51930a93d7db08202409eb4389ccee83b7f0db0b4100d2ec3a26ce5b8ebf12127f7afd6c5c6e4cfc4847bd3c14b0c98c06167d8e919bb7cfb526f83ef2d5c2235da7d7f7d3186f06efcbaf3ea189ab76b57ed2490604a016487768e6a33f93b0eaaa906c515a1f980d4acf699f1af216b12efc4b181059f80e793478489421dad69daeae78e784b2490a067f167ef2dc62206ba41ac60c775a38599e1767b47b5fe1039fb00d1d6667418aa7c5a8e771a0060d6c1f2e6cedf3a2f353ae6e830c6c35307c5ca264269a5a5af657b13f93dfcb289c3000403efa13128ec607198cb628b990967ba98818ffe92537e3c6e6f972dd4b01506852ffe9c827654c326339b96a284d2aff37eebc96c95dc0a33b2027ddc004f04be0abe978ff555a0d93fc6bd7e698416dcb731406266c95d56be9bbc890ee0eb5bcd1482e59f5db764adbfb5c7d2c922f0c0bd7b3901741bcbf69d83f0eac2c66931431f362277f555e7a21cf1164a0dcfaf95f608bd659be99f74d1fad669c28005bc0fcf4da88d97c61852896a3871a1ce12ea7c52324c0197536aca7c7f53d729b96b77b27d9e544b84030aca0dc3a016fd67b8144dccb2479b43ba0e01abb68b1ba6bda593a9be218751c79e424c004cae6dc9a4c96d0d19dd71adfcf74718abe53996e4d9a5fad2ab586ccbca30a2f14837c0a7b85c72ad6058b6df6214b9fc33627226087ed21266e090f4abf72809597ff03300c60d6b2a5ff55fe40228b89aa4e79deca5be3a8d5a96713caf9ebf041d71ba3f5cb10b0eb6914abe09a61fd38ecbf33d753b3bafa95b039a3569962cf30e5b219ec69846c5d9e1ba64e54ccf2badb2da40287d3cf38b4c0022d395577145f362b986cb6232a4de1612e5c642c9af4176ee1d450c5e981e5866763ff2fa32763a8c5e94faad319c8e46378f54d8e0c1ff5deec10c30153acfa98c1583a7e3053500ec418dae4239db0f1886a89d51067884b413ef7a8f662a5b2365c3e8f4e7824a92a399a677f07cf093f44073cec95968ee467aa9b1a1ddc54eecfd5415ec184dc67de117cbd33d572885495cbec0ef59a80a16f7fdddde7f868fa5913793d2069fb6ed2fe479777b4e75ed71887bedce922dcbb13188a97b6fe07de8ee13b03d36aeb02d9c177f1b5b9926ef9fe9186768a370c924b87ae08fe96d7664916792b01ea2bd0a73c4e1abb82eb3e38bdb087263f597018a8174e38452baabd1a7468d789c8b40f4eb48054bdffc7241e93b2f002e861786ec1d8a401f37c0600e7ddcbed90d452a0883b271c16497462695e5e73f9d8fa95f85de5d1edf8996b2b421353fb2fb9785f2edd11d5b9384c5aaaa4732ca3e4bf51137699c96e9d48112c7891494fe7c58fd07817224fffc5ff6cbdc8f305fbc14afb37bd62807183ed04ff22a92389e6d8daef4e5b5c9697e1472f913acc148d2101ba70afbb8fd5c238906b790a485b5ff8ffa0c073371de870dc8dd1a4b9890676f4bda2ef2581025d4e43e44b666753981d270a62aa0626744ccd5cfd990df501bba5a6a145b9e46fc61a69ed64e0306b131e6975a50a03524f39979448e3a2007969642b18da991fa10b3749933d42f3a508f96f5ef7434dfe23d39347d6ff7225b4deebf29e19e460314877f2ea2065e2b1240af958102b2c22098dc9fd25a28998d39d7bdc0dfc5e5e7fe8ab2d37f68a44699952f3c1b74ac33c0f090d95a9177cf55dde7caf6ff694737eb0f5254ec180512d0cab315ca234ddac722c8f7a3825da5e772343ee8d0fdb032ec254f01583612182ae24c91b4d1f6a6b3c0f0fef7b893d57eba53eab229f86c8e89f818a63d44b9fee654229ad72855cd59078cd02d11f529def91630291d1a0691b1b6113933e903c639046a791d975a191a0dccfa2a1a76bb77e0b8cb685407a5e9565d281d3e37f6f6f0cffe0a7e3a1ccf664b407ac99a3a3ec2a86f9b02306e28fda6290296b402b0d6f4cba8333e9ed381be63a47ad73d5cc2bb8a469cf9a46f07b6079c47951ab6db5a3a1b9b6d84b2ebd54408924ff8b83b256e7a80200f07f6e279bce167f5cdae5a4a98980fbffe052716ad224b48756de49cf46e95e8157d14a935805711a6ba3476739d839004cd544b8a5ee404bb9d4d601c5abf3ef2cbac481bedd529d23beb10aafbc9fc1245b0a93755adcc1542c9c154969bf33be24deffb1b87b0031360e9f03c10f3ee57e8d0a93476e0e92d9597107f06fd694cfac42f5fcae4dc3ad9c1ca23a6dc7d43933ae9f605e16693acb420059a39e5b13060bc4ef6eefe0e1f61ff129ff0b39acfa6aa0b1e055e8eda96622013652c8c8ba4ba3669a7bda7b45c9c6bc433803b9eee845d78c8b1678d2c6df4eea08a5fc3f149c2b3bd6960da7b8cc5d5adfd35f368a5b989c5287f1679f80e358ecd101c10a4420a829e900f6eace3b07df2a3cd041abf3f1bb6f9a19de933ec90f297f593b9a473d06eb9d96f55dbd36701e6efdf998decdbf475ff784d61739ac2785bd5755e9649a4d146c9ff53c93e05132e9d2769e2f3b76162a7c83caa57c3fc505f1fea21c4149fe9e1f04af341e403d5c472cb272133ae662fab0e739c59964ea0fb9e93289f27d29db256716a850c64bb8f1dab89fcd689f3b1119416edf85471be5cfaa2b6080faaa536d547030d4fc25a42cf8425ab8598e5b606c7976e4db32ff5f209528824d962de9e9056e4e610daLine truncated
'255': Buffer.from('2bb3de782ae4acd5acaf6216adce3c61f32a09f504630acbb662001c55cd7ec306958e441e792e8178bae8158f5659033c142a5146310d5346af90859bbf5f5d3a86cfb66a8b7767bebae88ee97bd6abfc20e277b4ea9e590e5d03d4c59a247fbf1acdd967c9666995b0a7f5aac3c8af521df73a1d3ee5e765923b80d14f7082bf2c1a9f11db44e6e398766f787ebf2f962de7f0e1145267bf06d811fde6536df440a225b47c2efdbb3869b09010850d79a823d70c40756caed0c86d35c90fdcf1e1986af2a3abfd01b8ec2c1f559c41245b9782538482e57a15fa3dc3d07ef05b63738a0f840b02915ef020d7a98ca0e547303898b97d9207e8e66b4d6ca6e2485eca40d25236034b41ccadb34ffbc160937930349fcd1748818a64a3a715a5ae8cc22cc013eee99914e9eb49e87bd6c490a9ddc7c695eea6fe5c5c3297259fe90aafa914024b001ce013c0f91a508a7c6574a5bc8651be11a27d01c43968040f9228457337b6bf573420dc1f58471cbe438a80f5034a318668a5d8adf108e25455ca7356898ca1813897dc5bc1cbe77fc55391e9b4a6fbcb800aa2c15fb69f60adcea09aa91519d8cae537a32c365099b9e05adcb646154bbb528cecfb662a14a0964a3a09eb01d214bd56509d977a99fe3f8a59d669a9f29fb43f006873328694a1f8f5b0fa768eb5c43cf8b7f9c3a81e5f746dcaef2025668fb4d2e178e7fc001c4c8a3f63afa97d9afd28f95327375c6949969701f3a6d892960364e4e7ad1c2c0953a68b320cb578c8487dae11a5ed701be7a806a7936b6719c754839432fe5202923e04a12d799fca3fe9f732492005636cd81f7f3f02a6e403269dfadd9d4ba4f7fbbbe42a5efc34cc8adff9dd32806da221ceafee0931042fbdbf79b69e3d703a7b1d8502dff993d82ab70ca1e6ffe49934de3833cfa91e78ac31c4644eac45b8b56fca083270e64496cae65173535b85c484e0cf42cc8e4b4985cd5c086e74f71e4a382c85a2bf991083607c669f2d6cc5dd72c73295230a387b894db2ff4b75f5f631a11ea4889d6680f076a7d8d7ee34557fc84d428bee2d9b977d38806748d616878ee94308f1d54e38b929165783f31fd9164e0ee18f7b73124951e0601e34649728c626dd4c46497d9b9e871489ab0c3234d9a2ad7dbfea53b436924f34a7c3a55b879791fb9466b8914cb0b28cf9d8d6164861b0df9ca0a2f321a3f157e624da63d459e75a0d8619b6c218e168c7649bb45f3d98eb0a77a296ef29cad7bbbb7380802514cfd64b53d681313274226c1e9221e51e02c2a7e1ef286de0986ed5aa2e8d5c8f0f23237cdebaf9e4a7906d8daab59216b38988e3a418e1b77929a5e14c007631b43ae81b85961ecf8f86b54ed61e4471dd2e81625eb646ecc4e0ad087a43270c086d5643bec009e070b17220c992d6bb8637abf72ed87666bd0da6f1a70bf1d53e3ed9e6bde33328f5b911d02cd2eaa187914a9b14464ef83ed0707bc4d26564cbe6d74c1861d874af5a407112f1cec82bd0ed2a18466f643bd3b8737c1f9f18e4e8a66505da3b494c33216d747189839b18cf4a4437184a61daa3ebb42754bc735f2a959c682947e868e45e5f766f9acc6641e0285c7e21e9008a19a2f18c8c80833d4f53775d0aa591d395328ed247bece539ab8cd87e2e59687c369b4dbb5ffc23a5e14eeb784981ad473649c3829de844b0f241522be87d75d6b75a091e4f7a8a7209906b0f66eabc38fe963b653f36cabd4fb96f368507691cda21a248ab6a33f1ec3008855105c4a8f3c7f370f7620d9a74c006f5accbe8b63767b461a4cbbb0440b5be11f4c072df4592bffd1a429d0caec8a5169521b6f29b5927a4a0b036feb885c00ef57798f9ff457c527ab8e2ad58afd7ff915e0a5186b0501c2a449cae701fc8b0c76456cc5acf789c0fd2f032f7c07cfa7c9af20f09486b1a211d4d1ef022aae9ff4942e8bfece817617c2cc8586ee017f460025a902f1489348c05a6c2f8ec1d8fe758e74dd31c8ff473d38566b3e8f566e4db1c28fd1e97de913319ad5b87c264b192c2239e17846a1bee0c007a6638c7d7356750aa9ae4b3c1f603e131b0f9f0297ba03c58c8956b70e3c3e8cee81e152847519e6a5b89fd49baac8f755ae8761ebf59cc8222e71608ab0e4e9338e6ff043f0921074fae172c7824189b96a23c43c8d4776b3094c5a2d0b7ea2897632e1c175aa9d38094ec662dcd614f6bdbd626caf6af2fae49fd7def2e48c779ef16f5281f35e50e242c9f012bab8c7887c8393a6b346544f3c39fbdf8345b307da185b690ebcd4c2825d5a3c8660fe40aa2fc52aca9c659327e110b65736e66794769d89f7cfc2aa673e2897d9b384ec5897c93d2439a9b35a9bad5681a2b2cf8683e03a674d51a42f349972febaf3d9dccac893b99ae19799224ddf69d52278d718ac41b2fdfff9a1b15a7a295427216df318359691d3ba296f3d7b0746ab7b057acb83c27b0bd266afa558d22f5bce9e5123502b411d4cbe7a7b48d84d0b6fcd6a6c6d7ec38d8c6c64e63ca0a7e44fe2b9907de930673b810878a443dc2df6177884393beb320196d828ad28f6613c933afeaa68ef25d79607cf3fdcf6183f6a9a9e2dfc74a0d7879d18b89be12a80f9e10db35be16b3b9dca55b0ae55e09b6644dcfb4b2f0267627bbd4d0ff38d78cc3745d2242acd10b2c5a1e8010ba32e4224448258a327d209095ab84371e0831dc89bf185600fe76c0b90d9f008fd4ffddef577042dc01b3326a1745a9fc1740a138e1366a59be1a6aaa7b383603d3c5c864bb54fabcb1b390e1116734c3e735e420da766f7530f50f33e46006ae926cab670c487887ca6460f6d1e7cfba8dbdba62e9199b421f5197ec61f104ffe8eba492cadf68d271685f02aa29a320d13193ee18924ad60e976ec49646b15e5a37f56238e4140ee4062058217ade45d23ac0c5998b0ca140bcad97f69ad7b19d4d89d5a7342c168d0d0b942fc58749f4158d5d1d39c5ea3099a51a0a842c685de2a0a03c90ad2ed3e49903b2f968b98f43d1638c94376d3dae5aaabdd233c64497b42ec01447f991e41a8722436adf00da3dfe2e91fcacea03668afa36d013ba9688df5d0eeb89d0d0e528d3bbc4fb6c9195b64b1442aca52a9d2177f546d295c1ef7cbd4595904ee772d235e98fc3a314ebb289b23adfa3221fac59a19ea78ba0e6581c2f1ba94658a592b096a2120abf8c714861c0d2bdf9ff3cb3c0868dcc2cc17b75db2f6285e412b522561c763f9d84bba4a193f5073c06d28b66e25b17b5bae87809dc6a79fb7b47782dbfb2eac5128a4f40bc0f24648b57b793bc8d829873875be2fc0622f01112de9435a69f673b1f750217ca217800ae217380658e1d13c96fa26d255290ebb73da0ded1d201aa03d17b55f9d650aadd8ab067517fbeccb9fde92d9f6e208f93e465bc08f6833968809e8766de72da7f9ed58629ca46279e13622220019fd86b399e2a4ee6f60ea253Line truncated
},
}
// eslint-enable @stylistic/js/max-len
const algorithms = ['ML-DSA-44', 'ML-DSA-65', 'ML-DSA-87'];
const contexts = [new Uint8Array(0), new Uint8Array(32), new Uint8Array(255)];
const vectors = algorithms.map((algorithm) => ({
publicKeyPem: spki[algorithm],
privateKeyPem: pkcs8[algorithm],
name: algorithm,
data,
signature: signatures[algorithm],
}));
const vectors = [];
for (const algorithm of algorithms) {
for (const context of contexts) {
vectors.push({
publicKeyPem: spki[algorithm],
privateKeyPem: pkcs8[algorithm],
name: algorithm,
context,
data,
signature: signatures[algorithm][context.byteLength],
})
}
}
return vectors;
}
+1 -26
View File
@@ -5,9 +5,8 @@ const RSA_KEY_GEN = {
publicExponent: new Uint8Array([1, 0, 1])
};
const [ECDH, X448, X25519] = await Promise.all([
const [ECDH, X25519] = await Promise.all([
subtle.generateKey({ name: 'ECDH', namedCurve: 'P-256' }, false, ['deriveBits', 'deriveKey']),
subtle.generateKey('X448', false, ['deriveBits', 'deriveKey']),
subtle.generateKey('X25519', false, ['deriveBits', 'deriveKey']),
]);
@@ -34,10 +33,6 @@ export const vectors = {
[true, 'Ed25519'],
[true, 'Ed448'],
[true, { name: 'Ed448', context: Buffer.alloc(0) }],
[false, { name: 'Ed448', context: Buffer.alloc(1) }],
[true, 'RSASSA-PKCS1-v1_5'],
[true, { name: 'RSA-PSS', saltLength: 32 }],
@@ -64,9 +59,7 @@ export const vectors = {
[false, 'HKDF'],
[false, 'PBKDF2'],
[true, 'X25519'],
[true, 'X448'],
[true, 'Ed25519'],
[true, 'Ed448'],
[true, { name: 'HMAC', hash: 'SHA-256' }],
[true, { name: 'HMAC', hash: 'SHA-256', length: 256 }],
[false, { name: 'HMAC', hash: 'SHA-256', length: 25 }],
@@ -116,15 +109,6 @@ export const vectors = {
[true,
{ name: 'X25519', public: X25519.publicKey },
'HKDF'],
[true,
{ name: 'X448', public: X448.publicKey },
{ name: 'AES-CBC', length: 128 }],
[true,
{ name: 'X448', public: X448.publicKey },
{ name: 'HMAC', hash: 'SHA-256' }],
[true,
{ name: 'X448', public: X448.publicKey },
'HKDF'],
[true,
{ name: 'ECDH', public: ECDH.publicKey },
{ name: 'AES-CBC', length: 128 }],
@@ -159,27 +143,18 @@ export const vectors = {
[true,
{ name: 'ECDH', public: ECDH.publicKey }],
[false, { name: 'ECDH', public: X448.publicKey }],
[false, { name: 'ECDH', public: ECDH.privateKey }],
[false, 'ECDH'],
[true, { name: 'X25519', public: X25519.publicKey }],
[false, { name: 'X25519', public: X448.publicKey }],
[false, { name: 'X25519', public: X25519.privateKey }],
[false, 'X25519'],
[true, { name: 'X448', public: X448.publicKey }],
[false, { name: 'X448', public: X25519.publicKey }],
[false, { name: 'X448', public: X448.privateKey }],
[false, 'X448'],
],
'importKey': [
[false, 'SHA-1'],
[false, 'Invalid'],
[true, 'X25519'],
[true, 'X448'],
[true, 'Ed25519'],
[true, 'Ed448'],
[true, { name: 'HMAC', hash: 'SHA-256' }],
[true, { name: 'HMAC', hash: 'SHA-256', length: 256 }],
[false, { name: 'HMAC', hash: 'SHA-256', length: 25 }],
@@ -32,6 +32,12 @@ export const vectors = {
[pqc, 'ML-DSA-44'],
[pqc, 'ML-DSA-65'],
[pqc, 'ML-DSA-87'],
[pqc, { name: 'ML-DSA-44', context: Buffer.alloc(0) }],
[pqc, { name: 'ML-DSA-65', context: Buffer.alloc(0) }],
[pqc, { name: 'ML-DSA-87', context: Buffer.alloc(0) }],
[pqc, { name: 'ML-DSA-44', context: Buffer.alloc(32) }],
[pqc, { name: 'ML-DSA-65', context: Buffer.alloc(32) }],
[pqc, { name: 'ML-DSA-87', context: Buffer.alloc(32) }],
[false, 'Argon2d'],
[false, 'Argon2i'],
[false, 'Argon2id'],
+11
View File
@@ -1,14 +1,25 @@
import { hasOpenSSL } from '../../common/crypto.js'
const supportsContext = hasOpenSSL(3, 2);
const { subtle } = globalThis.crypto;
const boringSSL = process.features.openssl_is_boringssl;
const X25519 = await subtle.generateKey('X25519', false, ['deriveBits', 'deriveKey']);
let X448;
let Ed448;
if (!boringSSL) {
X448 = await subtle.generateKey('X448', false, ['deriveBits', 'deriveKey'])
Ed448 = await subtle.generateKey('Ed448', false, ['sign', 'verify'])
}
export const vectors = {
'sign': [
[!boringSSL, 'Ed448'],
[!boringSSL, { name: 'Ed448', context: Buffer.alloc(0) }],
[!boringSSL && supportsContext, { name: 'Ed448', context: Buffer.alloc(32) }],
],
'generateKey': [
[!boringSSL, 'X448'],
[!boringSSL, 'Ed448'],
@@ -5,12 +5,18 @@ const common = require('../common');
if (!common.hasCrypto)
common.skip('missing crypto');
const { hasOpenSSL } = require('../common/crypto');
const assert = require('assert');
const crypto = require('crypto');
const { subtle } = globalThis.crypto;
const vectors = require('../fixtures/crypto/eddsa')();
const supportsContext = hasOpenSSL(3, 2);
async function testVerify({ name,
context,
publicKeyBuffer,
privateKeyBuffer,
signature,
@@ -63,43 +69,62 @@ async function testVerify({ name,
['sign']),
]);
assert(await subtle.verify({ name }, publicKey, signature, data));
assert(await subtle.verify({ name, context }, publicKey, signature, data));
if (context?.byteLength !== undefined) {
if (supportsContext) {
assert(!(await subtle.verify({ name, context: crypto.randomBytes(30) }, publicKey, signature, data)));
}
if (context.byteLength === 0) {
assert(await subtle.verify({ name }, publicKey, signature, data));
}
}
// Test verification with altered buffers
const copy = Buffer.from(data);
const sigcopy = Buffer.from(signature);
const p = subtle.verify({ name }, publicKey, sigcopy, copy);
const p = subtle.verify({ name, context }, publicKey, sigcopy, copy);
copy[0] = 255 - copy[0];
sigcopy[0] = 255 - sigcopy[0];
assert(await p);
// Test failure when using wrong key
await assert.rejects(
subtle.verify({ name }, privateKey, signature, data), {
subtle.verify({ name, context }, privateKey, signature, data), {
message: /Unable to use this key to verify/
});
await assert.rejects(
subtle.verify({ name }, noVerifyPublicKey, signature, data), {
subtle.verify({ name, context }, noVerifyPublicKey, signature, data), {
message: /Unable to use this key to verify/
});
// Test failure when using the wrong algorithms
await assert.rejects(
subtle.verify({ name }, hmacKey, signature, data), {
subtle.verify({ name, context }, hmacKey, signature, data), {
message: /Unable to use this key to verify/
});
await assert.rejects(
subtle.verify({ name }, rsaKeys.publicKey, signature, data), {
subtle.verify({ name, context }, rsaKeys.publicKey, signature, data), {
message: /Unable to use this key to verify/
});
await assert.rejects(
subtle.verify({ name }, ecKeys.publicKey, signature, data), {
subtle.verify({ name, context }, ecKeys.publicKey, signature, data), {
message: /Unable to use this key to verify/
});
if (name === 'Ed448' && supportsContext) {
// Test failure when too long context
await assert.rejects(
subtle.verify({ name, context: new Uint8Array(256) }, publicKey, signature, data), (err) => {
assert.strictEqual(err.name, 'OperationError');
assert.strictEqual(err.cause.code, 'ERR_OUT_OF_RANGE');
assert.strictEqual(err.cause.message, 'context string must be at most 255 bytes');
return true;
});
}
// Test failure when signature is altered
{
const copy = Buffer.from(signature);
@@ -120,11 +145,12 @@ async function testVerify({ name,
{
const copy = Buffer.from(data);
copy[0] = 255 - copy[0];
assert(!(await subtle.verify({ name }, publicKey, signature, copy)));
assert(!(await subtle.verify({ name, context }, publicKey, signature, copy)));
}
}
async function testSign({ name,
context,
publicKeyBuffer,
privateKeyBuffer,
signature,
@@ -171,46 +197,66 @@ async function testSign({ name,
]);
{
const sig = await subtle.sign({ name }, privateKey, data);
const sig = await subtle.sign({ name, context }, privateKey, data);
assert.strictEqual(sig.byteLength, signature.byteLength);
assert(await subtle.verify({ name }, publicKey, sig, data));
assert(await subtle.verify({ name, context }, publicKey, sig, data));
if (context?.byteLength !== undefined) {
if (supportsContext) {
assert(!(await subtle.verify({ name, context: crypto.randomBytes(30) }, publicKey, signature, data)));
}
if (context.byteLength === 0) {
assert(await subtle.verify({ name }, publicKey, signature, data));
}
}
}
{
const copy = Buffer.from(data);
const p = subtle.sign({ name }, privateKey, copy);
const p = subtle.sign({ name, context }, privateKey, copy);
copy[0] = 255 - copy[0];
const sig = await p;
assert(await subtle.verify({ name }, publicKey, sig, data));
assert(await subtle.verify({ name, context }, publicKey, sig, data));
}
// Test failure when using wrong key
await assert.rejects(
subtle.sign({ name }, publicKey, data), {
subtle.sign({ name, context }, publicKey, data), {
message: /Unable to use this key to sign/
});
// Test failure when using the wrong algorithms
await assert.rejects(
subtle.sign({ name }, hmacKey, data), {
subtle.sign({ name, context }, hmacKey, data), {
message: /Unable to use this key to sign/
});
await assert.rejects(
subtle.sign({ name }, rsaKeys.privateKey, data), {
subtle.sign({ name, context }, rsaKeys.privateKey, data), {
message: /Unable to use this key to sign/
});
await assert.rejects(
subtle.sign({ name }, ecKeys.privateKey, data), {
subtle.sign({ name, context }, ecKeys.privateKey, data), {
message: /Unable to use this key to sign/
});
if (name === 'Ed448' && supportsContext) {
// Test failure when too long context
await assert.rejects(
subtle.sign({ name, context: new Uint8Array(256) }, privateKey, data), (err) => {
assert.strictEqual(err.name, 'OperationError');
assert.strictEqual(err.cause.code, 'ERR_OUT_OF_RANGE');
assert.strictEqual(err.cause.message, 'context string must be at most 255 bytes');
return true;
});
}
}
(async function() {
const variations = [];
vectors.forEach((vector) => {
if (!supportsContext && vector.context?.byteLength) return;
variations.push(testVerify(vector));
variations.push(testSign(vector));
});
@@ -218,35 +264,16 @@ async function testSign({ name,
await Promise.all(variations);
})().then(common.mustCall());
// Ed448 context
if (!process.features.openssl_is_boringssl) {
const vector = vectors.find(({ name }) => name === 'Ed448');
Promise.all([
subtle.importKey(
'pkcs8',
vector.privateKeyBuffer,
{ name: 'Ed448' },
false,
['sign']),
subtle.importKey(
'spki',
vector.publicKeyBuffer,
{ name: 'Ed448' },
false,
['verify']),
]).then(async ([privateKey, publicKey]) => {
const sig = await subtle.sign({ name: 'Ed448', context: Buffer.alloc(0) }, privateKey, vector.data);
assert.deepStrictEqual(Buffer.from(sig), vector.signature);
assert.strictEqual(
await subtle.verify({ name: 'Ed448', context: Buffer.alloc(0) }, publicKey, sig, vector.data), true);
if (!supportsContext) {
assert.rejects(async () => {
const kp = await subtle.generateKey('Ed448', false, ['sign', 'verify']);
const data = crypto.randomBytes(32);
await subtle.sign({ name: 'Ed448', context: new Uint8Array(32) }, kp.privateKey, data);
}, { name: /OperationError|NotSupportedError/ }).then(common.mustCall());
await assert.rejects(subtle.sign({ name: 'Ed448', context: Buffer.alloc(1) }, privateKey, vector.data), {
message: /Non zero-length Ed448Params\.context is not supported/
});
await assert.rejects(subtle.verify({ name: 'Ed448', context: Buffer.alloc(1) }, publicKey, sig, vector.data), {
message: /Non zero-length Ed448Params\.context is not supported/
});
}).then(common.mustCall());
} else {
common.printSkipMessage('Skipping unsupported Ed448 test case');
assert.rejects(async () => {
const kp = await subtle.generateKey('Ed448', false, ['sign', 'verify']);
const data = crypto.randomBytes(32);
await subtle.verify({ name: 'Ed448', context: new Uint8Array(32) }, kp.publicKey, data, data);
}, { name: /OperationError|NotSupportedError/ }).then(common.mustCall());
}
@@ -17,6 +17,7 @@ const { subtle } = globalThis.crypto;
const vectors = require('../fixtures/crypto/ml-dsa')();
async function testVerify({ name,
context,
publicKeyPem,
privateKeyPem,
signature,
@@ -57,54 +58,67 @@ async function testVerify({ name,
['sign']),
]);
assert(await subtle.verify({ name }, publicKey, signature, data));
assert(await subtle.verify({ name, context }, publicKey, signature, data));
assert(!(await subtle.verify({ name, context: crypto.randomBytes(30) }, publicKey, signature, data)));
if (context.byteLength === 0) {
assert(await subtle.verify({ name }, publicKey, signature, data));
}
// Test verification with altered buffers
const copy = Buffer.from(data);
const sigcopy = Buffer.from(signature);
const p = subtle.verify({ name }, publicKey, sigcopy, copy);
const p = subtle.verify({ name, context }, publicKey, sigcopy, copy);
copy[0] = 255 - copy[0];
sigcopy[0] = 255 - sigcopy[0];
assert(await p);
// Test failure when using wrong key
await assert.rejects(
subtle.verify({ name }, privateKey, signature, data), {
subtle.verify({ name, context }, privateKey, signature, data), {
message: /Unable to use this key to verify/
});
await assert.rejects(
subtle.verify({ name }, noVerifyPublicKey, signature, data), {
subtle.verify({ name, context }, noVerifyPublicKey, signature, data), {
message: /Unable to use this key to verify/
});
// Test failure when using the wrong algorithms
await assert.rejects(
subtle.verify({ name }, hmacKey, signature, data), {
subtle.verify({ name, context }, hmacKey, signature, data), {
message: /Unable to use this key to verify/
});
await assert.rejects(
subtle.verify({ name }, rsaKeys.publicKey, signature, data), {
subtle.verify({ name, context }, rsaKeys.publicKey, signature, data), {
message: /Unable to use this key to verify/
});
await assert.rejects(
subtle.verify({ name }, ecKeys.publicKey, signature, data), {
subtle.verify({ name, context }, ecKeys.publicKey, signature, data), {
message: /Unable to use this key to verify/
});
// Test failure when too long context
await assert.rejects(
subtle.verify({ name, context: new Uint8Array(256) }, publicKey, signature, data), (err) => {
assert.strictEqual(err.name, 'OperationError');
assert.strictEqual(err.cause.code, 'ERR_OUT_OF_RANGE');
assert.strictEqual(err.cause.message, 'context string must be at most 255 bytes');
return true;
});
// Test failure when signature is altered
{
const copy = Buffer.from(signature);
copy[0] = 255 - copy[0];
assert(!(await subtle.verify(
{ name },
{ name, context },
publicKey,
copy,
data)));
assert(!(await subtle.verify(
{ name },
{ name, context },
publicKey,
copy.slice(1),
data)));
@@ -114,11 +128,12 @@ async function testVerify({ name,
{
const copy = Buffer.from(data);
copy[0] = 255 - copy[0];
assert(!(await subtle.verify({ name }, publicKey, signature, copy)));
assert(!(await subtle.verify({ name, context }, publicKey, signature, copy)));
}
}
async function testSign({ name,
context,
publicKeyPem,
privateKeyPem,
signature,
@@ -157,40 +172,49 @@ async function testSign({ name,
]);
{
const sig = await subtle.sign({ name }, privateKey, data);
const sig = await subtle.sign({ name, context }, privateKey, data);
assert.strictEqual(sig.byteLength, signature.byteLength);
assert(await subtle.verify({ name }, publicKey, sig, data));
assert(await subtle.verify({ name, context }, publicKey, sig, data));
}
{
const copy = Buffer.from(data);
const p = subtle.sign({ name }, privateKey, copy);
const p = subtle.sign({ name, context }, privateKey, copy);
copy[0] = 255 - copy[0];
const sig = await p;
assert(await subtle.verify({ name }, publicKey, sig, data));
assert(await subtle.verify({ name, context }, publicKey, sig, data));
}
// Test failure when using wrong key
await assert.rejects(
subtle.sign({ name }, publicKey, data), {
subtle.sign({ name, context }, publicKey, data), {
message: /Unable to use this key to sign/
});
// Test failure when using the wrong algorithms
await assert.rejects(
subtle.sign({ name }, hmacKey, data), {
subtle.sign({ name, context }, hmacKey, data), {
message: /Unable to use this key to sign/
});
await assert.rejects(
subtle.sign({ name }, rsaKeys.privateKey, data), {
subtle.sign({ name, context }, rsaKeys.privateKey, data), {
message: /Unable to use this key to sign/
});
await assert.rejects(
subtle.sign({ name }, ecKeys.privateKey, data), {
subtle.sign({ name, context }, ecKeys.privateKey, data), {
message: /Unable to use this key to sign/
});
// Test failure when too long context
await assert.rejects(
subtle.sign({ name, context: new Uint8Array(256) }, privateKey, data), (err) => {
assert.strictEqual(err.name, 'OperationError');
assert.strictEqual(err.cause.code, 'ERR_OUT_OF_RANGE');
assert.strictEqual(err.cause.message, 'context string must be at most 255 bytes');
return true;
});
}
(async function() {
@@ -203,26 +227,3 @@ async function testSign({ name,
await Promise.all(variations);
})().then(common.mustCall());
// ContextParams context not supported
{
const vector = vectors[0];
const name = vector.name;
const publicKey = crypto.createPublicKey(vector.publicKeyPem)
.toCryptoKey(vector.name, false, ['verify']);
const privateKey = crypto.createPrivateKey(vector.privateKeyPem)
.toCryptoKey(vector.name, false, ['sign']);
(async () => {
const sig = await subtle.sign({ name, context: Buffer.alloc(0) }, privateKey, vector.data);
assert.strictEqual(
await subtle.verify({ name, context: Buffer.alloc(0) }, publicKey, sig, vector.data), true);
await assert.rejects(subtle.sign({ name, context: Buffer.alloc(1) }, privateKey, vector.data), {
message: /Non zero-length ContextParams\.context is not supported/
});
await assert.rejects(subtle.verify({ name, context: Buffer.alloc(1) }, publicKey, sig, vector.data), {
message: /Non zero-length ContextParams\.context is not supported/
});
})().then(common.mustCall());
}
+2 -2
View File
@@ -507,12 +507,12 @@ const opts = { prefix, context };
}).then(common.mustCall());
}
// Ed448Params
// ContextParams
{
for (const good of [
{ name: 'Ed448', context: new Uint8Array() },
{ name: 'Ed448' },
]) {
assert.deepStrictEqual(converters.Ed448Params({ ...good, filtered: 'out' }, opts), good);
assert.deepStrictEqual(converters.ContextParams({ ...good, filtered: 'out' }, opts), good);
}
}
-1
View File
@@ -122,7 +122,6 @@ const customTypesMap = {
'HmacImportParams': 'webcrypto.html#class-hmacimportparams',
'EcdsaParams': 'webcrypto.html#class-ecdsaparams',
'RsaPssParams': 'webcrypto.html#class-rsapssparams',
'Ed448Params': 'webcrypto.html#class-ed448params',
'ContextParams': 'webcrypto.html#class-contextparams',
'CShakeParams': 'webcrypto.html#class-cshakeparams',
'KmacImportParams': 'webcrypto.html#class-kmacimportparams',