mirror of
https://github.com/vercel-labs/scriptc.git
synced 2026-10-23 06:10:02 +08:00
On x86-64 CPUs with the SHA extensions (and SSSE3 and SSE4.1), SHA-1 and SHA-256 process their blocks with SHA1RNDS4/SHA256RNDS2 and the message-schedule instructions, several blocks per call. The CPU check runs once and is cached; other CPUs, other architectures and wasm32 keep the portable blocks, and both give the same digests. createHash, crypto.hash, createHmac, pbkdf2, hkdf and every other caller of the two digests use the new path. sha-kernels.test.ts runs both block implementations over known vectors and every length from 0 to 1100 bytes and 1 MiB, whole and in 1-, 7-, 64- and 100-byte updates. Corpus 5763 compares the digests, HMAC, PBKDF2 and Hash.copy() with Node across block-boundary lengths and update sizes.
72 lines
1.9 KiB
TypeScript
72 lines
1.9 KiB
TypeScript
import { execFile } from "node:child_process";
|
|
import { mkdir } from "node:fs/promises";
|
|
import { join } from "node:path";
|
|
import { promisify } from "node:util";
|
|
import { beforeAll, expect, test } from "vitest";
|
|
|
|
const execFileAsync = promisify(execFile);
|
|
const testDir = import.meta.dirname;
|
|
const bin = join(testDir, "build", "test_sha_kernels");
|
|
|
|
// test_sha_kernels.c includes scr_lib.c, so it is not in this list.
|
|
const runtimeSources = [
|
|
"scr_shared.c",
|
|
"scr_bytes.c",
|
|
"scr_bytes.test.c",
|
|
"scr_bytes_io.c",
|
|
"scr_zlib.c",
|
|
"scr_hash.c",
|
|
"scr_string.c",
|
|
"scr_array.c",
|
|
"scr_map.c",
|
|
"scr_exception.c",
|
|
"scr_error.c",
|
|
"scr_number.c",
|
|
"scr_console.c",
|
|
"scr_closure.c",
|
|
"scr_ffi.c",
|
|
"scr_object.c",
|
|
"scr_union.c",
|
|
"scr_cycle.c",
|
|
"scr_alloc.c",
|
|
"scr_json.c",
|
|
"scr_inspect.c",
|
|
"scr_bigint.c",
|
|
"scr_async.c",
|
|
"scr_async_dyn.c",
|
|
"scr_child.c",
|
|
"scr_path.c",
|
|
"scr_url.c",
|
|
"scr_url_params.c",
|
|
];
|
|
|
|
// Compiled once with ASan, UBSan and the RC audit. The test runs the SHA-NI and portable
|
|
// SHA-1/SHA-256 blocks over the same inputs and checks known vectors.
|
|
beforeAll(async () => {
|
|
await mkdir(join(testDir, "build"), { recursive: true });
|
|
await execFileAsync("clang", [
|
|
"-std=c11",
|
|
"-O1",
|
|
"-Wall",
|
|
"-Wextra",
|
|
"-Wno-missing-field-initializers",
|
|
"-fsanitize=address,undefined",
|
|
"-DSCR_RC_AUDIT",
|
|
"-I",
|
|
join(testDir, "../src"),
|
|
"-o",
|
|
bin,
|
|
join(testDir, "test_sha_kernels.c"),
|
|
...runtimeSources.map((source) => join(testDir, "../src", source)),
|
|
"-lz",
|
|
...(process.platform === "linux" ? ["-D_GNU_SOURCE", "-lm"] : []),
|
|
]);
|
|
}, 300_000);
|
|
|
|
test("SHA-1 and SHA-256: the SHA-NI blocks match the portable blocks", async () => {
|
|
const { stderr } = await execFileAsync(bin, [], {
|
|
env: { ...process.env, UBSAN_OPTIONS: "halt_on_error=1" },
|
|
});
|
|
expect(stderr.trim().split("\n").pop()).toMatch(/^(\d+)\/\1 cases passed$/);
|
|
});
|