#[path = "../conformance_common.rs"]
mod common;
use bao_engine::context::JsContext;
use common::{eval_string, make_ctx, run_checks};
const ARGON2_PRELUDE: &str = r#"
var results = [];
function check(label, fn) {
try {
var ok = fn();
results.push(label + ":" + (ok === true ? "PASS" : ("FAIL" + (ok === false ? "" : ":" + ok))));
} catch (e) { results.push(label + ":ERROR:" + (e && e.message ? e.message : e)); }
}
// Port of upstream expectNodeError(fn, ctor, code, message): asserts
// instanceof ctor, .code and .message verbatim; returns true on pass, a
// mismatch description otherwise (surfaced in the FAIL line).
function expectNodeError(fn, ctor, code, message) {
var e;
var threw = false;
try { fn(); } catch (caught) { e = caught; threw = true; }
if (!threw) return "no-throw";
var problems = [];
if (!(e instanceof ctor)) problems.push("ctor:" + ((e && e.constructor && e.constructor.name) ? e.constructor.name : String(e)));
if (!e || e.code !== code) problems.push("code:" + (e ? String(e.code) : "n/a"));
if (!e || e.message !== message) problems.push("message:<" + (e ? String(e.message) : "n/a") + ">");
return problems.length === 0 ? true : problems.join(" / ");
}
// Upstream's error tests call BOTH faces (crypto.argon2 with a callback and
// crypto.argon2Sync) and expect the identical node error from each.
function expectNodeErrorBoth(parameters, ctor, code, message) {
var a = expectNodeError(function() { crypto.argon2("argon2id", parameters, function() {}); }, ctor, code, message);
var s = expectNodeError(function() { crypto.argon2Sync("argon2id", parameters); }, ctor, code, message);
return (a === true && s === true) ? true : ("async{" + a + "} sync{" + s + "}");
}
var crypto = require('crypto');
var message = Buffer.alloc(32, 0x01);
var nonce = Buffer.alloc(16, 0x02);
var secret = Buffer.alloc(8, 0x03);
var associatedData = Buffer.alloc(12, 0x04);
var defaults = { message: message, nonce: nonce, parallelism: 1, tagLength: 64, memory: 8, passes: 3 };
// [algorithm, overrides, expectedHex, expectedTagLength] — same parameter
// sets and expected outputs as upstream (which mirrors Node's
// test/js/node/test/parallel/test-crypto-argon2.js vectors; outputs
// generated by Node.js v26.3.0).
var vectors = [
["argon2d", { secret: secret, associatedData: associatedData, parallelism: 4, tagLength: 32, memory: 32 },
"512b391b6f1162975371d30919734294f868e3be3984f3c1a13a4db9fabe4acb", 32],
["argon2i", { secret: secret, associatedData: associatedData, parallelism: 4, tagLength: 32, memory: 32 },
"c814d9d1dc7f37aa13f0d77f2494bda1c8de6b016dd388d29952a4c4672b6ce8", 32],
["argon2id", { secret: secret, associatedData: associatedData, parallelism: 4, tagLength: 32, memory: 32 },
"0d640df58d78766c08c037a34a8b53c9d01ef0452d75b65eb52520e96b01e659", 32],
["argon2d", { message: "1234567890", nonce: "saltsalt" },
"d16ad773b1c6400d3193bc3e66271603e9de72bace20af3f89c236f5434cdec9" +
"9072ddfc6b9c77ea9f386c0e8d7cb0c37cec6ec3277a22c92d5be58ef67c7eaa", 64],
["argon2id", { message: "", parallelism: 4, tagLength: 32, memory: 32 },
"0a34f1abde67086c82e785eaf17c68382259a264f4e61b91cd2763cb75ac189a", 32],
["argon2d", { message: "1234567890", nonce: "saltsalt", parallelism: 2, memory: 4096 },
"491760c694fe6a7c94ab4e6a6344b55115565a6dbb3e078567b3f75c92a6dc5d" +
"03e823078bfa9811e7be1cc94fa2d9d167ab316aada7d846845ac288aa7e07c7", 64],
["argon2i", { parallelism: 4, tagLength: 32, memory: 32 },
"a9a7510e6db4d588ba3414cd0e094d480d683f97b9ccb612a544fe8ef65ba8e0", 32],
["argon2id", { parallelism: 4, tagLength: 32, memory: 32 },
"03aab965c12001c9d7d0d2de33192c0494b684bb148196d73c1df1acaf6d0c2e", 32],
["argon2d", { message: "1234567890", nonce: "saltsalt", parallelism: 2, tagLength: 128, memory: 4096 },
"4e644cec0ff484c60f220e807147bb9fa2d5085e1ffb4071a8b606446d97e3b5" +
"57c985d85fca2e6dc7f08b8a2398f79fbf48a642b810c5e2406fe5f5ed959864" +
"30c73c4ddfda92ea9b6d43dce62078ada1529c4217ae75968f0412140dc00204" +
"74360ba67e43bef4b790cac30a8fe7f3de8efdaaee5bc44617b39f18bb950c5c", 128],
["argon2id", {},
"509fa5d06cdeb30aa3ae36410116bdbd98da46bbe034d50810ba8518de408678" +
"49ffdc2d57c5562abe837602ac0035c612fab842582e00009bd7733f4e6fd49e", 64],
["argon2id", { passes: 1, tagLength: 4 }, "6e76a640", 4],
];
"#;
fn pump_until_quiescent(ctx: &mut JsContext, deadline_ms: u64) {
let deadline =
std::time::Instant::now() + std::time::Duration::from_millis(deadline_ms);
while std::time::Instant::now() < deadline {
let mut cxm = ctx.cx();
if !bun_runtime::timers::drain_and_check(&mut cxm) {
return;
}
std::thread::sleep(std::time::Duration::from_millis(1));
}
}
fn bundle(body: &str) -> String {
format!("{prelude}\n{body}", prelude = ARGON2_PRELUDE, body = body)
}
#[test]
fn argon2_conformance_exports_shape() {
let mut ctx = make_ctx();
run_checks(
&mut ctx,
&bundle(
r#"
check("exports_argon2_is_function", function() { return typeof crypto.argon2 === "function"; });
check("exports_argon2Sync_is_function", function() { return typeof crypto.argon2Sync === "function"; });
check("exports_argon2_arity_is_3", function() { return crypto.argon2.length === 3; });
check("exports_argon2Sync_arity_is_2", function() { return crypto.argon2Sync.length === 2; });
results.join("|")
"#,
),
);
bun_runtime::shutdown_thread_sm();
}
#[test]
fn argon2_conformance_vectors_sync() {
let mut ctx = make_ctx();
run_checks(
&mut ctx,
&bundle(
r#"
function vectorSyncCheck(i) {
var v = vectors[i];
var parameters = Object.assign({}, defaults, v[1]);
var syncResult = crypto.argon2Sync(v[0], parameters);
if (Buffer.isBuffer(syncResult) !== true) return "not-a-buffer:" + typeof syncResult;
var hex = syncResult.toString("hex");
if (hex !== v[2]) return "hex<" + hex + ">";
if (syncResult.length !== v[3]) return "len:" + syncResult.length + " want:" + v[3];
return true;
}
check("vector_01_argon2d_secret_ad", function() { return vectorSyncCheck(0); });
check("vector_02_argon2i_secret_ad", function() { return vectorSyncCheck(1); });
check("vector_03_argon2id_secret_ad", function() { return vectorSyncCheck(2); });
check("vector_04_argon2d_string_message_nonce", function() { return vectorSyncCheck(3); });
check("vector_05_argon2id_empty_message", function() { return vectorSyncCheck(4); });
check("vector_06_argon2d_string_io_mem4096", function() { return vectorSyncCheck(5); });
check("vector_07_argon2i_minimal", function() { return vectorSyncCheck(6); });
check("vector_08_argon2id_minimal", function() { return vectorSyncCheck(7); });
check("vector_09_argon2d_taglength_128", function() { return vectorSyncCheck(8); });
check("vector_10_argon2id_all_defaults", function() { return vectorSyncCheck(9); });
check("vector_11_argon2id_taglength_4", function() { return vectorSyncCheck(10); });
results.join("|")
"#,
),
);
bun_runtime::shutdown_thread_sm();
}
#[test]
fn argon2_conformance_vectors_async() {
let mut ctx = make_ctx();
let out = eval_string(
&mut ctx,
&bundle(
r#"
globalThis.__av = {};
for (var i = 0; i < vectors.length; i++) {
(function(idx) {
var v = vectors[idx];
var parameters = Object.assign({}, defaults, v[1]);
crypto.argon2(v[0], parameters, function(err, result) {
if (err) { globalThis.__av[idx] = "ERR:" + err.message; return; }
globalThis.__av[idx] = (Buffer.isBuffer(result) ? "BUF:" : "NOTBUF:") + result.toString("hex");
});
})(i);
}
"scheduled"
"#,
),
);
assert_eq!(out, "scheduled");
pump_until_quiescent(&mut ctx, 30_000);
run_checks(
&mut ctx,
&bundle(
r#"
function vectorAsyncCheck(i) {
var got = globalThis.__av[i];
if (got === undefined) return "callback-never-delivered";
var want = "BUF:" + vectors[i][2];
return got === want ? true : "got<" + got + ">";
}
check("vector_01_argon2d_secret_ad_async", function() { return vectorAsyncCheck(0); });
check("vector_02_argon2i_secret_ad_async", function() { return vectorAsyncCheck(1); });
check("vector_03_argon2id_secret_ad_async", function() { return vectorAsyncCheck(2); });
check("vector_04_argon2d_string_message_nonce_async", function() { return vectorAsyncCheck(3); });
check("vector_05_argon2id_empty_message_async", function() { return vectorAsyncCheck(4); });
check("vector_06_argon2d_string_io_mem4096_async", function() { return vectorAsyncCheck(5); });
check("vector_07_argon2i_minimal_async", function() { return vectorAsyncCheck(6); });
check("vector_08_argon2id_minimal_async", function() { return vectorAsyncCheck(7); });
check("vector_09_argon2d_taglength_128_async", function() { return vectorAsyncCheck(8); });
check("vector_10_argon2id_all_defaults_async", function() { return vectorAsyncCheck(9); });
check("vector_11_argon2id_taglength_4_async", function() { return vectorAsyncCheck(10); });
results.join("|")
"#,
),
);
bun_runtime::shutdown_thread_sm();
}
#[test]
fn argon2_conformance_omitted_vs_explicit_empty() {
let mut ctx = make_ctx();
run_checks(
&mut ctx,
&bundle(
r#"
check("omitted_secret_ad_equals_explicit_empty", function() {
var omitted = crypto.argon2Sync("argon2id", defaults).toString("hex");
var explicitEmpty = crypto.argon2Sync("argon2id", {
...defaults,
secret: Buffer.alloc(0),
associatedData: Buffer.alloc(0),
}).toString("hex");
return omitted === explicitEmpty ? true : ("omitted<" + omitted + "> explicit<" + explicitEmpty + ">");
});
results.join("|")
"#,
),
);
bun_runtime::shutdown_thread_sm();
}
#[test]
fn argon2_conformance_arraybuffer_and_offset_views() {
let mut ctx = make_ctx();
run_checks(
&mut ctx,
&bundle(
r#"
var base = crypto.argon2Sync("argon2id", { ...defaults, tagLength: 32 }).toString("hex");
var asArrayBuffer = message.buffer.slice(message.byteOffset, message.byteOffset + message.byteLength);
check("arraybuffer_message_matches_view", function() {
var hex = crypto.argon2Sync("argon2id", { ...defaults, tagLength: 32, message: asArrayBuffer }).toString("hex");
return hex === base ? true : "hex<" + hex + "> base<" + base + ">";
});
// A view whose byteOffset is non-zero must hash only the view's range.
var padded = Buffer.concat([Buffer.alloc(5, 0xee), message]);
check("offset_view_hashes_only_view_range", function() {
var hex = crypto.argon2Sync("argon2id", { ...defaults, tagLength: 32, message: padded.subarray(5) }).toString("hex");
return hex === base ? true : "hex<" + hex + "> base<" + base + ">";
});
results.join("|")
"#,
),
);
bun_runtime::shutdown_thread_sm();
}
#[test]
fn argon2_conformance_async_callback_null_copied_inputs() {
let mut ctx = make_ctx();
let out = eval_string(
&mut ctx,
&bundle(
r#"
var parameters = { ...defaults, tagLength: 32 };
var expected = crypto.argon2Sync("argon2id", parameters).toString("hex");
var mutableMessage = Buffer.from(message);
var mutableNonce = Buffer.from(nonce);
globalThis.__cb = { done: false, errKind: "unset", isBuf: false, hex: null, expected: expected };
crypto.argon2("argon2id", { ...parameters, message: mutableMessage, nonce: mutableNonce }, function(err, result) {
globalThis.__cb.done = true;
globalThis.__cb.errKind = (err === null) ? "null" : ("non-null:" + (err === undefined ? "undefined" : String(err && err.message)));
globalThis.__cb.isBuf = result ? Buffer.isBuffer(result) : false;
globalThis.__cb.hex = result ? result.toString("hex") : null;
});
// Clobbering the inputs after the call must not affect the job.
mutableMessage.fill(0xff);
mutableNonce.fill(0xff);
"scheduled"
"#,
),
);
assert_eq!(out, "scheduled");
pump_until_quiescent(&mut ctx, 30_000);
run_checks(
&mut ctx,
&bundle(
r#"
check("async_callback_delivered", function() { return globalThis.__cb.done === true; });
// Upstream: expect(err).toBeNull() — Node calls back with (null, Buffer).
check("async_callback_err_is_null", function() {
return globalThis.__cb.errKind === "null" ? true : "err-was-" + globalThis.__cb.errKind;
});
check("async_callback_result_is_buffer", function() { return globalThis.__cb.isBuf === true; });
check("async_callback_result_matches_sync", function() {
return globalThis.__cb.hex === globalThis.__cb.expected ? true : "hex<" + globalThis.__cb.hex + "> want<" + globalThis.__cb.expected + ">";
});
results.join("|")
"#,
),
);
bun_runtime::shutdown_thread_sm();
}
#[test]
fn argon2_conformance_concurrent_async_jobs() {
let mut ctx = make_ctx();
let out = eval_string(
&mut ctx,
&bundle(
r#"
var parameters = { ...defaults, parallelism: 4, tagLength: 32, memory: 32 };
var algorithms = ["argon2d", "argon2i", "argon2id"];
globalThis.__cc = {};
for (var i = 0; i < algorithms.length; i++) {
(function(idx) {
crypto.argon2(algorithms[idx], parameters, function(err, result) {
if (err) { globalThis.__cc[idx] = "ERR:" + err.message; return; }
globalThis.__cc[idx] = (Buffer.isBuffer(result) ? "BUF:" : "NOTBUF:") + result.toString("hex");
});
})(i);
}
"scheduled"
"#,
),
);
assert_eq!(out, "scheduled");
pump_until_quiescent(&mut ctx, 30_000);
run_checks(
&mut ctx,
&bundle(
r#"
var parameters = { ...defaults, parallelism: 4, tagLength: 32, memory: 32 };
var algorithms = ["argon2d", "argon2i", "argon2id"];
function ccCheck(i) {
var got = globalThis.__cc[i];
if (got === undefined) return "callback-never-delivered";
var want = "BUF:" + crypto.argon2Sync(algorithms[i], parameters).toString("hex");
return got === want ? true : "got<" + got + "> want<" + want + ">";
}
check("concurrent_argon2d_completed", function() { return ccCheck(0); });
check("concurrent_argon2i_completed", function() { return ccCheck(1); });
check("concurrent_argon2id_completed", function() { return ccCheck(2); });
results.join("|")
"#,
),
);
bun_runtime::shutdown_thread_sm();
}
#[test]
fn argon2_conformance_out_of_range_errors() {
let mut ctx = make_ctx();
run_checks(
&mut ctx,
&bundle(
r#"
function outOfRangeCheck(overrides, errorMessage) {
var parameters = Object.assign({}, defaults, overrides);
return expectNodeErrorBoth(parameters, RangeError, "ERR_OUT_OF_RANGE", errorMessage);
}
check("out_of_range_nonce_byte_length_7", function() {
return outOfRangeCheck({ nonce: nonce.subarray(0, 7) },
'The value of "parameters.nonce.byteLength" is out of range. It must be >= 8 && <= 4294967295. Received 7');
});
check("out_of_range_tag_length_3", function() {
return outOfRangeCheck({ tagLength: 3 },
'The value of "parameters.tagLength" is out of range. It must be >= 4 && <= 4294967295. Received 3');
});
check("out_of_range_tag_length_2p32", function() {
return outOfRangeCheck({ tagLength: 2 ** 32 },
'The value of "parameters.tagLength" is out of range. It must be >= 4 && <= 4294967295. Received 4294967296');
});
check("out_of_range_passes_0", function() {
return outOfRangeCheck({ passes: 0 },
'The value of "parameters.passes" is out of range. It must be >= 1 && <= 4294967295. Received 0');
});
check("out_of_range_passes_2p32", function() {
return outOfRangeCheck({ passes: 2 ** 32 },
'The value of "parameters.passes" is out of range. It must be >= 1 && <= 4294967295. Received 4294967296');
});
check("out_of_range_parallelism_0", function() {
return outOfRangeCheck({ parallelism: 0 },
'The value of "parameters.parallelism" is out of range. It must be >= 1 && <= 16777215. Received 0');
});
check("out_of_range_parallelism_2p24", function() {
return outOfRangeCheck({ parallelism: 2 ** 24 },
'The value of "parameters.parallelism" is out of range. It must be >= 1 && <= 16777215. Received 16777216');
});
check("out_of_range_memory_below_8x_parallelism", function() {
return outOfRangeCheck({ parallelism: 4, memory: 16 },
'The value of "parameters.memory" is out of range. It must be >= 32 && <= 4294967295. Received 16');
});
check("out_of_range_memory_2p32", function() {
return outOfRangeCheck({ memory: 2 ** 32 },
'The value of "parameters.memory" is out of range. It must be >= 8 && <= 4294967295. Received 4294967296');
});
results.join("|")
"#,
),
);
bun_runtime::shutdown_thread_sm();
}
#[test]
fn argon2_conformance_missing_parameters() {
let mut ctx = make_ctx();
run_checks(
&mut ctx,
&bundle(
r#"
var bufferTypesMessage =
"must be of type string or an instance of ArrayBuffer, Buffer, TypedArray, or DataView. Received undefined";
var cases = {
message: 'The "parameters.message" property ' + bufferTypesMessage,
nonce: 'The "parameters.nonce" property ' + bufferTypesMessage,
parallelism: 'The "parameters.parallelism" property must be of type number. Received undefined',
tagLength: 'The "parameters.tagLength" property must be of type number. Received undefined',
memory: 'The "parameters.memory" property must be of type number. Received undefined',
passes: 'The "parameters.passes" property must be of type number. Received undefined',
};
function missingParamsCheck(key, errorMessage) {
var parameters = Object.assign({}, defaults);
delete parameters[key];
return expectNodeErrorBoth(parameters, TypeError, "ERR_INVALID_ARG_TYPE", errorMessage);
}
check("missing_message", function() { return missingParamsCheck("message", cases.message); });
check("missing_nonce", function() { return missingParamsCheck("nonce", cases.nonce); });
check("missing_parallelism", function() { return missingParamsCheck("parallelism", cases.parallelism); });
check("missing_tagLength", function() { return missingParamsCheck("tagLength", cases.tagLength); });
check("missing_memory", function() { return missingParamsCheck("memory", cases.memory); });
check("missing_passes", function() { return missingParamsCheck("passes", cases.passes); });
results.join("|")
"#,
),
);
bun_runtime::shutdown_thread_sm();
}
#[test]
fn argon2_conformance_invalid_algorithm_params_callback() {
let mut ctx = make_ctx();
run_checks(
&mut ctx,
&bundle(
r#"
check("rejects_invalid_algorithm_params_callback", function() {
var r1 = expectNodeError(function() { crypto.argon2Sync("argon2x", defaults); },
TypeError, "ERR_INVALID_ARG_VALUE",
"The argument 'algorithm' must be one of: 'argon2d', 'argon2i', 'argon2id'. Received 'argon2x'");
var r2 = expectNodeError(function() { crypto.argon2Sync(5, defaults); },
TypeError, "ERR_INVALID_ARG_TYPE",
'The "algorithm" argument must be of type string. Received type number (5)');
var r3 = expectNodeError(function() { crypto.argon2(); },
TypeError, "ERR_INVALID_ARG_TYPE",
'The "algorithm" argument must be of type string. Received undefined');
var r4 = expectNodeError(function() { crypto.argon2Sync("argon2id", null); },
TypeError, "ERR_INVALID_ARG_TYPE",
'The "parameters" argument must be of type object. Received null');
// Parameters are validated before the callback, like node.
var r5 = expectNodeError(function() { crypto.argon2("argon2id", null, null); },
TypeError, "ERR_INVALID_ARG_TYPE",
'The "parameters" argument must be of type object. Received null');
var r6 = expectNodeError(function() { crypto.argon2("argon2id", defaults, null); },
TypeError, "ERR_INVALID_ARG_TYPE",
'The "callback" argument must be of type function. Received null');
var r7 = expectNodeError(function() { crypto.argon2("argon2id", defaults, {}); },
TypeError, "ERR_INVALID_ARG_TYPE",
'The "callback" argument must be of type function. Received an instance of Object');
var bad = [];
if (r1 !== true) bad.push("algorithm-one-of{" + r1 + "}");
if (r2 !== true) bad.push("algorithm-number{" + r2 + "}");
if (r3 !== true) bad.push("no-args{" + r3 + "}");
if (r4 !== true) bad.push("sync-null-params{" + r4 + "}");
if (r5 !== true) bad.push("async-null-params{" + r5 + "}");
if (r6 !== true) bad.push("null-callback{" + r6 + "}");
if (r7 !== true) bad.push("object-callback{" + r7 + "}");
return bad.length === 0 ? true : bad.join(" / ");
});
results.join("|")
"#,
),
);
bun_runtime::shutdown_thread_sm();
}
#[test]
fn argon2_conformance_wrong_typed_secret_and_ad() {
let mut ctx = make_ctx();
run_checks(
&mut ctx,
&bundle(
r#"
var expectedWrongType = function(name) {
return 'The "' + name + '" property must be of type string or an instance of ArrayBuffer, Buffer, TypedArray, or DataView. Received type number (42)';
};
check("rejects_wrong_typed_secret_and_associated_data", function() {
var s = expectNodeError(function() { crypto.argon2Sync("argon2id", { ...defaults, secret: 42 }); },
TypeError, "ERR_INVALID_ARG_TYPE", expectedWrongType("parameters.secret"));
var a = expectNodeError(function() { crypto.argon2Sync("argon2id", { ...defaults, associatedData: 42 }); },
TypeError, "ERR_INVALID_ARG_TYPE", expectedWrongType("parameters.associatedData"));
return (s === true && a === true) ? true : ("secret{" + s + "} associatedData{" + a + "}");
});
results.join("|")
"#,
),
);
bun_runtime::shutdown_thread_sm();
}
#[test]
fn argon2_conformance_detached_message() {
let mut ctx = make_ctx();
run_checks(
&mut ctx,
&bundle(
r#"
// Matches the empty-string-message vector.
var emptyMessageHash = "0a34f1abde67086c82e785eaf17c68382259a264f4e61b91cd2763cb75ac189a";
var base = { ...defaults, parallelism: 4, tagLength: 32, memory: 32 };
var detached = new ArrayBuffer(32);
detached.transfer();
check("detached_message_hashes_as_empty", function() {
var hex = crypto.argon2Sync("argon2id", { ...base, message: detached }).toString("hex");
return hex === emptyMessageHash ? true : "hex<" + hex + ">";
});
var viewBuffer = new ArrayBuffer(32);
var detachedView = new Uint8Array(viewBuffer);
viewBuffer.transfer();
check("detached_view_hashes_as_empty", function() {
var hex = crypto.argon2Sync("argon2id", { ...base, message: detachedView }).toString("hex");
return hex === emptyMessageHash ? true : "hex<" + hex + ">";
});
// A detached nonce has byteLength 0 and fails the >= 8 check.
var detachedNonce = new ArrayBuffer(16);
detachedNonce.transfer();
check("detached_nonce_fails_min_8", function() {
return expectNodeError(function() { crypto.argon2Sync("argon2id", { ...base, nonce: detachedNonce }); },
RangeError, "ERR_OUT_OF_RANGE",
'The value of "parameters.nonce.byteLength" is out of range. It must be >= 8 && <= 4294967295. Received 0');
});
results.join("|")
"#,
),
);
bun_runtime::shutdown_thread_sm();
}
#[test]
fn argon2_conformance_shared_array_buffer() {
let mut ctx = make_ctx();
run_checks(
&mut ctx,
&bundle(
r#"
// Matches the plain-Buffer vector above with the same bytes.
var expected = "03aab965c12001c9d7d0d2de33192c0494b684bb148196d73c1df1acaf6d0c2e";
var sabMessage = new SharedArrayBuffer(32);
new Uint8Array(sabMessage).fill(0x01);
var sabNonce = new SharedArrayBuffer(16);
new Uint8Array(sabNonce).fill(0x02);
var parameters = { parallelism: 4, tagLength: 32, memory: 32, passes: 3 };
check("shared_array_buffer_plain", function() {
var hex = crypto.argon2Sync("argon2id", { ...parameters, message: sabMessage, nonce: sabNonce }).toString("hex");
return hex === expected ? true : "hex<" + hex + ">";
});
check("shared_array_buffer_views", function() {
var hex = crypto.argon2Sync("argon2id", {
...parameters,
message: new Uint8Array(sabMessage),
nonce: new Uint8Array(sabNonce),
}).toString("hex");
return hex === expected ? true : "hex<" + hex + ">";
});
results.join("|")
"#,
),
);
bun_runtime::shutdown_thread_sm();
}
#[test]
fn argon2_conformance_alloc_limit_sync() {
let mut ctx = make_ctx();
run_checks(
&mut ctx,
&bundle(
r#"
var base = { message: "pw", nonce: "saltsalt", parallelism: 1, tagLength: 32, memory: 8, passes: 1 };
check("alloc_limit_sync_memory_is_catchable_error", function() {
try {
crypto.argon2Sync("argon2id", { ...base, memory: 4194305 }); // 4 GiB + 1 KiB > 4 GiB bound
return "no-error";
} catch (e) {
return e.message === "Argon2 derivation failed" ? true : "message<" + e.message + ">";
}
});
check("alloc_limit_within_limit_derives_32", function() {
return crypto.argon2Sync("argon2id", base).length === 32;
});
results.join("|")
"#,
),
);
bun_runtime::shutdown_thread_sm();
}
#[test]
fn argon2_conformance_alloc_limit_async() {
let mut ctx = make_ctx();
let out = eval_string(
&mut ctx,
&bundle(
r#"
globalThis.__al = { done: false, msg: null };
crypto.argon2("argon2id", { message: "pw", nonce: "saltsalt", parallelism: 1, tagLength: 32, memory: 4194305, passes: 1 }, function(err) {
globalThis.__al.done = true;
globalThis.__al.msg = err === null ? "no error" : err.message;
});
"scheduled"
"#,
),
);
assert_eq!(out, "scheduled");
pump_until_quiescent(&mut ctx, 30_000);
run_checks(
&mut ctx,
&bundle(
r#"
check("alloc_limit_async_memory_is_catchable_error", function() {
if (globalThis.__al.done !== true) return "callback-never-delivered";
return globalThis.__al.msg === "Argon2 derivation failed" ? true : "msg<" + globalThis.__al.msg + ">";
});
results.join("|")
"#,
),
);
bun_runtime::shutdown_thread_sm();
}