LibWeb: Add ML-DSA test

This represents 1600+ subtests, including the worker tests.
This commit is contained in:
Tete17
2025-11-25 19:59:00 +01:00
committed by Jelle Raaijmakers
parent 006428db7a
commit 4868a118a5
Notes: github-actions[bot] 2025-12-10 20:27:51 +00:00
16 changed files with 3474 additions and 0 deletions

View File

@@ -0,0 +1,17 @@
<!doctype html>
<meta charset=utf-8>
<title>WebCryptoAPI: generateKey() for Failures</title>
<meta name="timeout" content="long">
<script>
self.GLOBAL = {
isWindow: function() { return true; },
isWorker: function() { return false; },
isShadowRealm: function() { return false; },
};
</script>
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
<script src="../util/helpers.js"></script>
<script src="failures.js"></script>
<div id=log></div>
<script src="../../WebCryptoAPI/generateKey/failures_ML-DSA.tentative.https.any.js"></script>

View File

@@ -0,0 +1,5 @@
// META: title=WebCryptoAPI: generateKey() for Failures
// META: timeout=long
// META: script=../util/helpers.js
// META: script=failures.js
run_test(["ML-DSA-44", "ML-DSA-65", "ML-DSA-87"]);

View File

@@ -0,0 +1,18 @@
<!doctype html>
<meta charset=utf-8>
<title>WebCryptoAPI: generateKey() Successful Calls</title>
<meta name="timeout" content="long">
<script>
self.GLOBAL = {
isWindow: function() { return true; },
isWorker: function() { return false; },
isShadowRealm: function() { return false; },
};
</script>
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
<script src="../util/helpers.js"></script>
<script src="../../common/subset-tests.js"></script>
<script src="successes.js"></script>
<div id=log></div>
<script src="../../WebCryptoAPI/generateKey/successes_ML-DSA.tentative.https.any.js"></script>

View File

@@ -0,0 +1,6 @@
// META: title=WebCryptoAPI: generateKey() Successful Calls
// META: timeout=long
// META: script=../util/helpers.js
// META: script=/common/subset-tests.js
// META: script=successes.js
run_test(["ML-DSA-44", "ML-DSA-65", "ML-DSA-87"]);

View File

@@ -0,0 +1,222 @@
var subtle = crypto.subtle;
function runTests(algorithmName) {
var algorithm = { name: algorithmName };
var data = keyData[algorithmName];
var jwkData = {
jwk: { kty: data.jwk.kty, alg: data.jwk.alg, pub: data.jwk.pub },
};
[true, false].forEach(function (extractable) {
// Test public keys first
allValidUsages(data.publicUsages, true).forEach(function (usages) {
['spki', 'jwk', 'raw-public'].forEach(function (format) {
if (format === 'jwk') {
// Not all fields used for public keys
testFormat(
format,
algorithm,
jwkData,
algorithmName,
usages,
extractable
);
} else {
testFormat(
format,
algorithm,
data,
algorithmName,
usages,
extractable
);
}
});
});
// Next, test private keys
allValidUsages(data.privateUsages).forEach(function (usages) {
['pkcs8', 'jwk', 'raw-seed'].forEach(function (format) {
testFormat(format, algorithm, data, algorithmName, usages, extractable);
});
});
});
}
// Test importKey with a given key format and other parameters. If
// extrable is true, export the key and verify that it matches the input.
function testFormat(format, algorithm, keyData, keySize, usages, extractable) {
[algorithm, algorithm.name].forEach((alg) => {
promise_test(function (test) {
return subtle
.importKey(format, keyData[format], alg, extractable, usages)
.then(
function (key) {
assert_equals(
key.constructor,
CryptoKey,
'Imported a CryptoKey object'
);
assert_goodCryptoKey(
key,
algorithm,
extractable,
usages,
format === 'pkcs8' ||
format === 'raw-seed' ||
(format === 'jwk' && keyData[format].priv)
? 'private'
: 'public'
);
if (!extractable) {
return;
}
return subtle.exportKey(format, key).then(
function (result) {
if (format !== 'jwk') {
assert_true(
equalBuffers(keyData[format], result),
'Round trip works'
);
} else {
assert_true(
equalJwk(keyData[format], result),
'Round trip works'
);
}
},
function (err) {
assert_unreached(
'Threw an unexpected error: ' + err.toString()
);
}
);
},
function (err) {
assert_unreached('Threw an unexpected error: ' + err.toString());
}
);
}, 'Good parameters: ' +
keySize.toString() +
' bits ' +
parameterString(format, keyData[format], alg, extractable, usages));
});
}
// Helper methods follow:
// Are two array buffers the same?
function equalBuffers(a, b) {
if (a.byteLength !== b.byteLength) {
return false;
}
var aBytes = new Uint8Array(a);
var bBytes = new Uint8Array(b);
for (var i = 0; i < a.byteLength; i++) {
if (aBytes[i] !== bBytes[i]) {
return false;
}
}
return true;
}
// Are two Jwk objects "the same"? That is, does the object returned include
// matching values for each property that was expected? It's okay if the
// returned object has extra methods; they aren't checked.
function equalJwk(expected, got) {
var fields = Object.keys(expected);
var fieldName;
for (var i = 0; i < fields.length; i++) {
fieldName = fields[i];
if (!(fieldName in got)) {
return false;
}
if (expected[fieldName] !== got[fieldName]) {
return false;
}
}
return true;
}
// Convert method parameters to a string to uniquely name each test
function parameterString(format, data, algorithm, extractable, usages) {
if ('byteLength' in data) {
data = 'buffer(' + data.byteLength.toString() + ')';
} else {
data = 'object(' + Object.keys(data).join(', ') + ')';
}
var result =
'(' +
objectToString(format) +
', ' +
objectToString(data) +
', ' +
objectToString(algorithm) +
', ' +
objectToString(extractable) +
', ' +
objectToString(usages) +
')';
return result;
}
// Character representation of any object we may use as a parameter.
function objectToString(obj) {
var keyValuePairs = [];
if (Array.isArray(obj)) {
return (
'[' +
obj
.map(function (elem) {
return objectToString(elem);
})
.join(', ') +
']'
);
} else if (typeof obj === 'object') {
Object.keys(obj)
.sort()
.forEach(function (keyName) {
keyValuePairs.push(keyName + ': ' + objectToString(obj[keyName]));
});
return '{' + keyValuePairs.join(', ') + '}';
} else if (typeof obj === 'undefined') {
return 'undefined';
} else {
return obj.toString();
}
var keyValuePairs = [];
Object.keys(obj)
.sort()
.forEach(function (keyName) {
var value = obj[keyName];
if (typeof value === 'object') {
value = objectToString(value);
} else if (typeof value === 'array') {
value =
'[' +
value
.map(function (elem) {
return objectToString(elem);
})
.join(', ') +
']';
} else {
value = value.toString();
}
keyValuePairs.push(keyName + ': ' + value);
});
return '{' + keyValuePairs.join(', ') + '}';
}

View File

@@ -0,0 +1,18 @@
<!doctype html>
<meta charset=utf-8>
<title>WebCryptoAPI: importKey() for ML-DSA keys</title>
<meta name="timeout" content="long">
<script>
self.GLOBAL = {
isWindow: function() { return true; },
isWorker: function() { return false; },
isShadowRealm: function() { return false; },
};
</script>
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
<script src="../util/helpers.js"></script>
<script src="ML-DSA_importKey_fixtures.js"></script>
<script src="ML-DSA_importKey.js"></script>
<div id=log></div>
<script src="../../WebCryptoAPI/import_export/ML-DSA_importKey.tentative.https.any.js"></script>

View File

@@ -0,0 +1,9 @@
// META: title=WebCryptoAPI: importKey() for ML-DSA keys
// META: timeout=long
// META: script=../util/helpers.js
// META: script=ML-DSA_importKey_fixtures.js
// META: script=ML-DSA_importKey.js
runTests("ML-DSA-44");
runTests("ML-DSA-65");
runTests("ML-DSA-87");

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,757 @@
function run_test() {
setup({ explicit_done: true });
var subtle = self.crypto.subtle; // Change to test prefixed implementations
// When are all these tests really done? When all the promises they use have resolved.
var all_promises = [];
// Source file [algorithm_name]_vectors.js provides the getTestVectors method
// for the algorithm that drives these tests.
var testVectors = getTestVectors();
var invalidTestVectors = getInvalidTestVectors();
// Test verification first, because signing tests rely on that working
testVectors.forEach(function (vector) {
var promise = importVectorKeys(vector, ['verify'], ['sign']).then(
function (vectors) {
var algorithm = vector.algorithmName;
promise_test(function (test) {
var operation = subtle
.verify(algorithm, vector.publicKey, vector.signature, vector.data)
.then(
function (is_verified) {
assert_true(is_verified, 'Signature verified');
},
function (err) {
assert_unreached(
'Verification should not throw error ' +
vector.name +
': ' +
err.message +
"'"
);
}
);
return operation;
}, vector.name + ' verification');
},
function (err) {
// We need a failed test if the importVectorKey operation fails, so
// we know we never tested verification.
promise_test(function (test) {
assert_unreached(
'importVectorKeys failed for ' +
vector.name +
". Message: ''" +
err.message +
"''"
);
}, 'importVectorKeys step: ' + vector.name + ' verification');
}
);
all_promises.push(promise);
});
// Test verification with an altered buffer after call
testVectors.forEach(function (vector) {
var promise = importVectorKeys(vector, ['verify'], ['sign']).then(
function (vectors) {
var algorithm = vector.algorithmName;
promise_test(function (test) {
var signature = copyBuffer(vector.signature);
var operation = subtle
.verify(algorithm, vector.publicKey, signature, vector.data)
.then(
function (is_verified) {
assert_true(is_verified, 'Signature verified');
},
function (err) {
assert_unreached(
'Verification should not throw error ' +
vector.name +
': ' +
err.message +
"'"
);
}
);
signature[0] = 255 - signature[0];
return operation;
}, vector.name + ' verification with altered signature after call');
},
function (err) {
promise_test(function (test) {
assert_unreached(
'importVectorKeys failed for ' +
vector.name +
". Message: ''" +
err.message +
"''"
);
}, 'importVectorKeys step: ' +
vector.name +
' verification with altered signature after call');
}
);
all_promises.push(promise);
});
// Check for successful verification even if plaintext is altered after call.
testVectors.forEach(function (vector) {
var promise = importVectorKeys(vector, ['verify'], ['sign']).then(
function (vectors) {
var algorithm = vector.algorithmName;
promise_test(function (test) {
var plaintext = copyBuffer(vector.data);
var operation = subtle
.verify(algorithm, vector.publicKey, vector.signature, plaintext)
.then(
function (is_verified) {
assert_true(is_verified, 'Signature verified');
},
function (err) {
assert_unreached(
'Verification should not throw error ' +
vector.name +
': ' +
err.message +
"'"
);
}
);
plaintext[0] = 255 - plaintext[0];
return operation;
}, vector.name + ' with altered plaintext after call');
},
function (err) {
promise_test(function (test) {
assert_unreached(
'importVectorKeys failed for ' +
vector.name +
". Message: ''" +
err.message +
"''"
);
}, 'importVectorKeys step: ' +
vector.name +
' with altered plaintext after call');
}
);
all_promises.push(promise);
});
// Check for failures due to using privateKey to verify.
testVectors.forEach(function (vector) {
var promise = importVectorKeys(vector, ['verify'], ['sign']).then(
function (vectors) {
var algorithm = vector.algorithmName;
promise_test(function (test) {
return subtle
.verify(algorithm, vector.privateKey, vector.signature, vector.data)
.then(
function (plaintext) {
assert_unreached(
'Should have thrown error for using privateKey to verify in ' +
vector.name +
': ' +
err.message +
"'"
);
},
function (err) {
assert_equals(
err.name,
'InvalidAccessError',
"Should throw InvalidAccessError instead of '" +
err.message +
"'"
);
}
);
}, vector.name + ' using privateKey to verify');
},
function (err) {
promise_test(function (test) {
assert_unreached(
'importVectorKeys failed for ' +
vector.name +
". Message: ''" +
err.message +
"''"
);
}, 'importVectorKeys step: ' +
vector.name +
' using privateKey to verify');
}
);
all_promises.push(promise);
});
// Check for failures due to using publicKey to sign.
testVectors.forEach(function (vector) {
var promise = importVectorKeys(vector, ['verify'], ['sign']).then(
function (vectors) {
var algorithm = vector.algorithmName;
promise_test(function (test) {
return subtle.sign(algorithm, vector.publicKey, vector.data).then(
function (signature) {
assert_unreached(
'Should have thrown error for using publicKey to sign in ' +
vector.name +
': ' +
err.message +
"'"
);
},
function (err) {
assert_equals(
err.name,
'InvalidAccessError',
"Should throw InvalidAccessError instead of '" +
err.message +
"'"
);
}
);
}, vector.name + ' using publicKey to sign');
},
function (err) {
promise_test(function (test) {
assert_unreached(
'importVectorKeys failed for ' +
vector.name +
". Message: ''" +
err.message +
"''"
);
}, 'importVectorKeys step: ' +
vector.name +
' using publicKey to sign');
}
);
all_promises.push(promise);
});
// Check for failures due to no "verify" usage.
testVectors.forEach(function (originalVector) {
var vector = Object.assign({}, originalVector);
var promise = importVectorKeys(vector, [], ['sign']).then(
function (vectors) {
var algorithm = vector.algorithmName;
promise_test(function (test) {
return subtle
.verify(algorithm, vector.publicKey, vector.signature, vector.data)
.then(
function (plaintext) {
assert_unreached(
'Should have thrown error for no verify usage in ' +
vector.name +
': ' +
err.message +
"'"
);
},
function (err) {
assert_equals(
err.name,
'InvalidAccessError',
"Should throw InvalidAccessError instead of '" +
err.message +
"'"
);
}
);
}, vector.name + ' no verify usage');
},
function (err) {
promise_test(function (test) {
assert_unreached(
'importVectorKeys failed for ' +
vector.name +
". Message: ''" +
err.message +
"''"
);
}, 'importVectorKeys step: ' + vector.name + ' no verify usage');
}
);
all_promises.push(promise);
});
// Check for successful signing and verification.
testVectors.forEach(function (vector) {
var promise = importVectorKeys(vector, ['verify'], ['sign']).then(
function (vectors) {
var algorithm = vector.algorithmName;
promise_test(function (test) {
return subtle.sign(algorithm, vector.privateKey, vector.data).then(
function (signature) {
// Can we verify the signature?
return subtle
.verify(algorithm, vector.publicKey, signature, vector.data)
.then(
function (is_verified) {
assert_true(is_verified, 'Round trip verification works');
return signature;
},
function (err) {
assert_unreached(
'verify error for test ' +
vector.name +
': ' +
err.message +
"'"
);
}
);
},
function (err) {
assert_unreached(
'sign error for test ' + vector.name + ": '" + err.message + "'"
);
}
);
}, vector.name + ' round trip');
},
function (err) {
// We need a failed test if the importVectorKey operation fails, so
// we know we never tested signing or verifying
promise_test(function (test) {
assert_unreached(
'importVectorKeys failed for ' +
vector.name +
". Message: ''" +
err.message +
"''"
);
}, 'importVectorKeys step: ' + vector.name + ' round trip');
}
);
all_promises.push(promise);
});
// Test signing with the wrong algorithm
testVectors.forEach(function (vector) {
// Want to get the key for the wrong algorithm
var promise = subtle
.generateKey({ name: 'HMAC', hash: 'SHA-1' }, false, ['sign', 'verify'])
.then(
function (wrongKey) {
var algorithm = vector.algorithmName;
return importVectorKeys(vector, ['verify'], ['sign']).then(
function (vectors) {
promise_test(function (test) {
var operation = subtle
.sign(algorithm, wrongKey, vector.data)
.then(
function (signature) {
assert_unreached(
'Signing should not have succeeded for ' + vector.name
);
},
function (err) {
assert_equals(
err.name,
'InvalidAccessError',
"Should have thrown InvalidAccessError instead of '" +
err.message +
"'"
);
}
);
return operation;
}, vector.name + ' signing with wrong algorithm name');
},
function (err) {
// We need a failed test if the importVectorKey operation fails, so
// we know we never tested verification.
promise_test(function (test) {
assert_unreached(
'importVectorKeys failed for ' +
vector.name +
". Message: ''" +
err.message +
"''"
);
}, 'importVectorKeys step: ' +
vector.name +
' signing with wrong algorithm name');
}
);
},
function (err) {
promise_test(function (test) {
assert_unreached(
'Generate wrong key for test ' +
vector.name +
" failed: '" +
err.message +
"'"
);
}, 'generate wrong key step: ' +
vector.name +
' signing with wrong algorithm name');
}
);
all_promises.push(promise);
});
// Test verification with the wrong algorithm
testVectors.forEach(function (vector) {
// Want to get the key for the wrong algorithm
var promise = subtle
.generateKey({ name: 'HMAC', hash: 'SHA-1' }, false, ['sign', 'verify'])
.then(
function (wrongKey) {
return importVectorKeys(vector, ['verify'], ['sign']).then(
function (vectors) {
var algorithm = vector.algorithmName;
promise_test(function (test) {
var operation = subtle
.verify(algorithm, wrongKey, vector.signature, vector.data)
.then(
function (signature) {
assert_unreached(
'Verifying should not have succeeded for ' + vector.name
);
},
function (err) {
assert_equals(
err.name,
'InvalidAccessError',
"Should have thrown InvalidAccessError instead of '" +
err.message +
"'"
);
}
);
return operation;
}, vector.name + ' verifying with wrong algorithm name');
},
function (err) {
// We need a failed test if the importVectorKey operation fails, so
// we know we never tested verification.
promise_test(function (test) {
assert_unreached(
'importVectorKeys failed for ' +
vector.name +
". Message: ''" +
err.message +
"''"
);
}, 'importVectorKeys step: ' +
vector.name +
' verifying with wrong algorithm name');
}
);
},
function (err) {
promise_test(function (test) {
assert_unreached(
'Generate wrong key for test ' +
vector.name +
" failed: '" +
err.message +
"'"
);
}, 'generate wrong key step: ' +
vector.name +
' verifying with wrong algorithm name');
}
);
all_promises.push(promise);
});
// Test verification fails with wrong signature
testVectors.forEach(function (vector) {
var promise = importVectorKeys(vector, ['verify'], ['sign']).then(
function (vectors) {
var algorithm = vector.algorithmName;
var signature = copyBuffer(vector.signature);
signature[0] = 255 - signature[0];
promise_test(function (test) {
var operation = subtle
.verify(algorithm, vector.publicKey, signature, vector.data)
.then(
function (is_verified) {
assert_false(is_verified, 'Signature NOT verified');
},
function (err) {
assert_unreached(
'Verification should not throw error ' +
vector.name +
': ' +
err.message +
"'"
);
}
);
return operation;
}, vector.name + ' verification failure due to altered signature');
},
function (err) {
// We need a failed test if the importVectorKey operation fails, so
// we know we never tested verification.
promise_test(function (test) {
assert_unreached(
'importVectorKeys failed for ' +
vector.name +
". Message: ''" +
err.message +
"''"
);
}, 'importVectorKeys step: ' +
vector.name +
' verification failure due to altered signature');
}
);
all_promises.push(promise);
});
// Test verification fails with short (odd length) signature
testVectors.forEach(function (vector) {
var promise = importVectorKeys(vector, ['verify'], ['sign']).then(
function (vectors) {
var algorithm = vector.algorithmName;
var signature = vector.signature.slice(1); // Skip the first byte
promise_test(function (test) {
var operation = subtle
.verify(algorithm, vector.publicKey, signature, vector.data)
.then(
function (is_verified) {
assert_false(is_verified, 'Signature NOT verified');
},
function (err) {
assert_unreached(
'Verification should not throw error ' +
vector.name +
': ' +
err.message +
"'"
);
}
);
return operation;
}, vector.name + ' verification failure due to shortened signature');
},
function (err) {
// We need a failed test if the importVectorKey operation fails, so
// we know we never tested verification.
promise_test(function (test) {
assert_unreached(
'importVectorKeys failed for ' +
vector.name +
". Message: ''" +
err.message +
"''"
);
}, 'importVectorKeys step: ' +
vector.name +
' verification failure due to shortened signature');
}
);
all_promises.push(promise);
});
// Test verification fails with wrong plaintext
testVectors.forEach(function (vector) {
var promise = importVectorKeys(vector, ['verify'], ['sign']).then(
function (vectors) {
var algorithm = vector.algorithmName;
var plaintext = copyBuffer(vector.data);
plaintext[0] = 255 - plaintext[0];
promise_test(function (test) {
var operation = subtle
.verify(algorithm, vector.publicKey, vector.signature, plaintext)
.then(
function (is_verified) {
assert_false(is_verified, 'Signature NOT verified');
},
function (err) {
assert_unreached(
'Verification should not throw error ' +
vector.name +
': ' +
err.message +
"'"
);
}
);
return operation;
}, vector.name + ' verification failure due to altered plaintext');
},
function (err) {
// We need a failed test if the importVectorKey operation fails, so
// we know we never tested verification.
promise_test(function (test) {
assert_unreached(
'importVectorKeys failed for ' +
vector.name +
". Message: ''" +
err.message +
"''"
);
}, 'importVectorKeys step: ' +
vector.name +
' verification failure due to altered plaintext');
}
);
all_promises.push(promise);
});
// Test invalid signatures
invalidTestVectors.forEach(function (vector) {
var promise = importVectorKeys(vector, ['verify'], ['sign']).then(
function (vectors) {
var algorithm = vector.algorithmName;
promise_test(function (test) {
var operation = subtle
.verify(algorithm, vector.publicKey, vector.signature, vector.data)
.then(
function (is_verified) {
assert_false(is_verified, 'Signature unexpectedly verified');
},
function (err) {
assert_unreached(
'Verification should not throw error ' +
vector.name +
': ' +
err.message +
"'"
);
}
);
return operation;
}, vector.name + ' verification');
},
function (err) {
// We need a failed test if the importVectorKey operation fails, so
// we know we never tested verification.
promise_test(function (test) {
assert_unreached(
'importVectorKeys failed for ' +
vector.name +
". Message: ''" +
err.message +
"''"
);
}, 'importVectorKeys step: ' + vector.name + ' verification');
}
);
all_promises.push(promise);
});
promise_test(function () {
return Promise.all(all_promises)
.then(function () {
done();
})
.catch(function () {
done();
});
}, 'setup');
// A test vector has all needed fields for signing and verifying, EXCEPT that the
// key field may be null. This function replaces that null with the Correct
// CryptoKey object.
//
// Returns a Promise that yields an updated vector on success.
function importVectorKeys(vector, publicKeyUsages, privateKeyUsages) {
var publicPromise, privatePromise;
if (vector.publicKey !== null) {
publicPromise = new Promise(function (resolve, reject) {
resolve(vector);
});
} else {
publicPromise = subtle
.importKey(
vector.publicKeyFormat,
vector.publicKeyBuffer,
{ name: vector.algorithmName },
false,
publicKeyUsages
)
.then(function (key) {
vector.publicKey = key;
return vector;
}); // Returns a copy of the sourceBuffer it is sent.
}
if (vector.privateKey !== null) {
privatePromise = new Promise(function (resolve, reject) {
resolve(vector);
});
} else {
privatePromise = subtle
.importKey(
vector.privateKeyFormat,
vector.privateKeyBuffer,
{ name: vector.algorithmName },
false,
privateKeyUsages
)
.then(function (key) {
vector.privateKey = key;
return vector;
});
}
return Promise.all([publicPromise, privatePromise]);
}
// Returns a copy of the sourceBuffer it is sent.
function copyBuffer(sourceBuffer) {
var source = new Uint8Array(sourceBuffer);
var copy = new Uint8Array(sourceBuffer.byteLength);
for (var i = 0; i < source.byteLength; i++) {
copy[i] = source[i];
}
return copy;
}
function equalBuffers(a, b) {
if (a.byteLength !== b.byteLength) {
return false;
}
var aBytes = new Uint8Array(a);
var bBytes = new Uint8Array(b);
for (var i = 0; i < a.byteLength; i++) {
if (aBytes[i] !== bBytes[i]) {
return false;
}
}
return true;
}
return;
}

View File

@@ -0,0 +1,17 @@
<!doctype html>
<meta charset=utf-8>
<title>WebCryptoAPI: sign() and verify() Using ML-DSA</title>
<meta name="timeout" content="long">
<script>
self.GLOBAL = {
isWindow: function() { return true; },
isWorker: function() { return false; },
isShadowRealm: function() { return false; },
};
</script>
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
<script src="mldsa_vectors.js"></script>
<script src="mldsa.js"></script>
<div id=log></div>
<script src="../../WebCryptoAPI/sign_verify/mldsa.tentative.https.any.js"></script>

View File

@@ -0,0 +1,6 @@
// META: title=WebCryptoAPI: sign() and verify() Using ML-DSA
// META: script=mldsa_vectors.js
// META: script=mldsa.js
// META: timeout=long
run_test();

File diff suppressed because it is too large Load Diff