perf(crypto): derive Argon2id via argon2idAsync (unfreeze unlock UI)
deriveKeyBytes now calls NobleArgon2.argon2idAsync instead of the sync argon2id, so it yields to the event loop periodically and the busy/unlock spinner keeps animating instead of freezing ~0.65 s during login, register, and master-pw rotation. Same result (both RFC-9106-verified); all callers already await deriveKeyBytes so no call-site changes. - Re-vendored js/argon2.js to export argon2idAsync alongside argon2id (re-bundled from @noble/hashes@2.2.0; both variants pass the RFC 9106 §5.3 vector). 27KB → 29KB. - Added a sync/async parity test. 63/63 green. - Closes the last open item of CODE_AUDIT §1.2. NOTE: argon2.js grew — run BuildAssets to re-embed it before the next Delphi build. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+47
-2
@@ -1,4 +1,4 @@
|
||||
/* @noble/hashes argon2id v2.2.0 — vendored bundle (esbuild IIFE). Verified against RFC 9106 §5.3. Do not edit by hand; re-bundle from @noble/hashes@2.2.0. */
|
||||
/* @noble/hashes argon2id (sync+async) v2.2.0 — vendored bundle (esbuild IIFE). Verified against RFC 9106 §5.3. Do not edit by hand; re-bundle from @noble/hashes@2.2.0. */
|
||||
(() => {
|
||||
var __defProp = Object.defineProperty;
|
||||
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
||||
@@ -90,6 +90,8 @@
|
||||
return arr;
|
||||
}
|
||||
var swap32IfBE = isLE ? (u) => u : byteSwap32;
|
||||
var nextTick = async () => {
|
||||
};
|
||||
function utf8ToBytes(str) {
|
||||
if (typeof str !== "string")
|
||||
throw new TypeError("string expected");
|
||||
@@ -951,7 +953,50 @@
|
||||
return argon2Output(B, p, laneLen, dkLen);
|
||||
}
|
||||
var argon2id = (password, salt, opts) => argon2(AT.Argon2id, password, salt, opts);
|
||||
async function argon2Async(type, password, salt, opts) {
|
||||
const { mP, p, t, version, B, laneLen, lanes, segmentLen, dkLen, perBlock, asyncTick } = argon2Init(password, salt, type, opts);
|
||||
const address = new Uint32Array(3 * 256);
|
||||
address[256 + 6] = mP;
|
||||
address[256 + 8] = t;
|
||||
address[256 + 10] = type;
|
||||
let ts = Date.now();
|
||||
for (let r = 0; r < t; r++) {
|
||||
const needXor = r !== 0 && version === 19;
|
||||
address[256 + 0] = r;
|
||||
for (let s = 0; s < ARGON2_SYNC_POINTS; s++) {
|
||||
address[256 + 4] = s;
|
||||
const dataIndependent = type == AT.Argon2i || type == AT.Argon2id && r === 0 && s < 2;
|
||||
for (let l = 0; l < p; l++) {
|
||||
address[256 + 2] = l;
|
||||
address[256 + 12] = 0;
|
||||
let startPos = 0;
|
||||
if (r === 0 && s === 0) {
|
||||
startPos = 2;
|
||||
if (dataIndependent) {
|
||||
address[256 + 12]++;
|
||||
block(address, 256, 2 * 256, 0, false);
|
||||
block(address, 0, 2 * 256, 0, false);
|
||||
}
|
||||
}
|
||||
let offset = l * laneLen + s * segmentLen + startPos;
|
||||
let prev = offset % laneLen ? offset - 1 : offset + laneLen - 1;
|
||||
for (let index = startPos; index < segmentLen; index++, offset++, prev++) {
|
||||
perBlock();
|
||||
processBlock(B, address, l, r, s, index, laneLen, segmentLen, lanes, offset, prev, dataIndependent, needXor);
|
||||
const diff = Date.now() - ts;
|
||||
if (!(diff >= 0 && diff < asyncTick)) {
|
||||
await nextTick();
|
||||
ts += diff;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
clean(address);
|
||||
return argon2Output(B, p, laneLen, dkLen);
|
||||
}
|
||||
var argon2idAsync = (password, salt, opts) => argon2Async(AT.Argon2id, password, salt, opts);
|
||||
|
||||
// entry.js
|
||||
globalThis.NobleArgon2 = { argon2id };
|
||||
globalThis.NobleArgon2 = { argon2id, argon2idAsync };
|
||||
})();
|
||||
|
||||
Reference in New Issue
Block a user