@tacet/js
v0.4.2
Published
Timing side-channel detection for JavaScript/TypeScript (WASM)
Maintainers
Readme
This is a WASM-based implementation that works in Node.js, Bun, and Deno.
Note: Browsers are not supported because they lack high-precision timers (due to Spectre mitigations).
Installation
# npm
npm install @tacet/js
# bun
bun add @tacet/js
# deno/jsr
deno add jsr:@tacet/jsQuick Start
import { TimingOracle, AttackerModelValues, OutcomeValues } from "@tacet/js";
import crypto from "crypto";
// Test your cryptographic function
const result = TimingOracle.forAttacker(AttackerModelValues.AdjacentNetwork)
.timeBudget(30_000) // 30 seconds
.test(
{
baseline: () => Buffer.alloc(32, 0), // All zeros
sample: () => crypto.randomBytes(32), // Random data
},
(input) => myCryptoFunction(input)
);
// Handle the result
switch (result.outcome) {
case OutcomeValues.Pass:
console.log(`No leak detected: P(leak) = ${result.leakProbability}`);
break;
case OutcomeValues.Fail:
console.error(`Timing leak detected! Exploitability: ${result.exploitability}`);
process.exit(1);
break;
case OutcomeValues.Inconclusive:
console.warn(`Inconclusive: ${result.inconclusiveReason}`);
break;
}Attacker Models
Choose your attacker model based on your threat scenario. Cycle-based thresholds use a 5 GHz reference frequency (conservative).
| Model | Threshold | Use Case |
|-------|-----------|----------|
| SharedHardware | 0.4 ns (~2 cycles @ 5 GHz) | SGX, cross-VM, containers |
| PostQuantum | 2.0 ns (~10 cycles @ 5 GHz) | ML-KEM, ML-DSA, lattice crypto |
| AdjacentNetwork | 100 ns | LAN, HTTP/2 APIs |
| RemoteNetwork | 50 μs | Internet-facing services |
| Research | 0 | Detect any difference |
API Reference
TimingOracle
Builder-pattern API for timing tests:
const oracle = TimingOracle.forAttacker(AttackerModelValues.AdjacentNetwork)
.timeBudget(30_000) // Max time in ms
.maxSamples(100_000) // Max samples to collect
.passThreshold(0.05) // P(leak) threshold for Pass
.failThreshold(0.95); // P(leak) threshold for FailTimingTestResult
The result object contains:
outcome: "pass" | "fail" | "inconclusive" | "unmeasurable"leakProbability: Posterior probability of a timing leakeffectNs: Estimated timing difference in nanosecondsexploitability: "negligible" | "possibleLan" | "likelyLan" | "possibleRemote"quality: "excellent" | "good" | "poor" | "tooNoisy"
Low-Level API
For advanced usage, you can use the low-level functions directly:
import {
collectSamples,
calibrateSamples,
analyze,
defaultConfig,
} from "@tacet/js";
// Collect timing samples
const samples = collectSamples(inputPair, measureFn, 5000);
// Calibrate and analyze
const calibration = calibrateSamples(
samples.baselineSamples,
samples.sampleSamples,
samples.nsPerTick,
defaultConfig()
);
const result = analyze(calibration, defaultConfig());License
MPL-2.0
