paulmillr/awasm-noble
GitHub: paulmillr/awasm-noble
提供可审计的加密散列和加密算法的WebAssembly实现。
Stars: 31 | Forks: 4
# AWASM 高贵
可审计的加密散列和加密算法的 WebAssembly 实现。
- 🔒 可审计:从 JS 源代码生成的可重复的二进制文件
- 🔻 可摇树:未使用的代码被排除在构建之外
- 🏎 快速:[BLAKE3 6-10 GB/s](#speed),ChaCha20 6.4 GB/s
- 🔍 可靠:来自 noble 包的测试,零化测试
- 4️⃣ 不同的后端:wasm (SIMD)、线程化 wasm (web workers)、JS、运行时
- 🎫 模块:根据应用需求在后端之间切换
- 🔗 默认同步,可选异步方法
- 🦘 包含 SHA、RIPEMD、BLAKE、PBKDF、Scrypt、Argon2、Salsa、ChaCha、AES
- 🪶 轻量级
### 该库属于 _awasm_
- **可重复构建:** 确定的跨平台构建
- **可审计的编译器:** 合理大小的 JS-to-WASM 编译器
- **同步执行:** 可选异步版本
- 最小依赖,PGP 签名发布和透明的 NPM 构建
- 所有库:
[awasm-noble](https://github.com/paulmillr/awasm-noble),
[awasm-compiler](https://github.com/paulmillr/awasm-compiler)
- [查看项目主页](https://paulmillr.com/awasm/) 了解项目背后的动机
## 使用方法
```
import { sha224, sha256, sha384, sha512, sha512_224, sha512_256 } from '@awasm/noble';
import { md5, ripemd160, sha1 } from '@awasm/noble';
import { blake224, blake256, blake384, blake512,
blake2b, blake2s, blake3 } from '@awasm/noble';
import { keccak_224, keccak_256, keccak_384, keccak_512,
sha3_224, sha3_256, sha3_384, sha3_512,
shake128, shake128_32, shake256, shake256_64 } from '@awasm/noble';
import { argon2d, argon2i, argon2id, scrypt } from '@awasm/noble';
import { pbkdf2 } from '@awasm/noble/kdf.js';
import { hmac } from '@awasm/noble/hmac.js';
import { hkdf } from '@awasm/noble/hkdf.js';
import {
chacha20poly1305, xchacha20poly1305, xsalsa20poly1305, gcm, gcmsiv,
aessiv, ctr, cbc, cfb, ofb, ecb, aeskw, aeskwp,
cmac, chacha20, xchacha20, salsa20, xsalsa20, chacha8, ghash, polyval, poly1305,
} from '@awasm/noble';
blake3(new Uint8Array([0xca, 0xfe]));
```
* [使用方法](#usage)
+ [接口](#interface)
+ [后端:wasm、wasm_threads、js、noble、webcrypto、运行时](#backends-wasm-wasm_threads-js-noble-webcrypto-runtime)
+ [Noble 平台](#noble-platform)
+ [模块](#stubs)
+ [线程](#threads)
+ [流](#streaming)
+ [异步](#async)
+ [零分配](#zero-allocation)
* [示例](#examples)
+ [使用 XChaCha20Poly1305 加密](#encrypt-with-xchacha20poly1305)
+ [使用 AES 加密](#encrypt-with-aes)
+ [自动管理的 nonce](#auto-managed-nonce)
+ [具有进度的异步加密算法](#async-ciphers-with-progress)
+ [流加密算法](#streaming-ciphers)
+ [Scrypt、Argon、PBKDF](#scrypt-argon-pbkdf)
+ [MAC](#macs)
+ [WebCrypto 散列 + KDF/MAC](#webcrypto-hashes--kdfmac)
+ [WebCrypto 加密算法](#webcrypto-ciphers)
* [内部结构](#internals)
+ [为什么一个包包含散列和加密算法?](#why-one-package-for-hashes--ciphers)
+ [与 noble 的区别](#differences-from-noble)
+ [Deno 和 Web Workers](#deno-and-web-workers)
+ [贡献](#contributing)
* [速度](#speed)
+ [wasm_threads](#wasm_threads)
+ [wasm (无线程)](#wasm-no-threads)
* [许可证](#license)
### 接口
散列可以通过以下方式调用:
```
import { blake3 } from '@awasm/noble';
const msg = new Uint8Array(64);
const msg1 = msg;
const msg2 = msg;
const opts = {};
blake3(msg);
blake3(msg, opts);
await blake3.async(msg);
blake3.chunks([msg.slice(0, 32), msg.slice(32, 64)]);
blake3.parallel([msg1, msg2]);
blake3.create().update(msg1).update(msg2).digest();
```
加密算法具有以下接口:
```
import { chacha20poly1305 } from '@awasm/noble';
const key = new Uint8Array(32);
const nonce = new Uint8Array(12);
const data = new Uint8Array([1, 2, 3]);
const cipher = chacha20poly1305(key, nonce /*, ...optionalArgs */);
const encrypted = cipher.encrypt(data); // sync
cipher.decrypt(encrypted);
await chacha20poly1305(key, nonce).encrypt.async(data); // async
await chacha20poly1305(key, nonce).decrypt.async(encrypted);
const enc = chacha20poly1305(key, nonce).encrypt.create();
enc.update(data);
const streamed = enc.finish(); // streaming
const dec = chacha20poly1305(key, nonce).decrypt.create();
dec.update(streamed.data);
dec.finish(streamed.tag);
```
MAC (`poly1305` / `ghash` / `polyval` / `cmac`) 类似于散列,具有额外的 `key` 选项:
`mac(msg, key|{ key })`, `mac.chunks(...)`, `mac.parallel(...)`, `mac.create(...)`。
KDF 是 `kdf(password, salt, opts?)` 和 `kdf.async(...)`。
### 后端:wasm、wasm_threads、js、noble、webcrypto、运行时
```
import { sha256 } from '@awasm/noble'; // wasm
import { sha256 as sha256wasm_threads } from '@awasm/noble/wasm_threads.js';
import { sha256 as sha256js } from '@awasm/noble/js.js';
import { sha256 as sha256noble } from '@awasm/noble/noble.js';
import { sha256 as sha256wc } from '@awasm/noble/webcrypto.js';
import { sha256 as sha256rn } from '@awasm/noble/runtime.js';
for (const hash of [sha256, sha256wasm_threads, sha256js, sha256noble, sha256rn]) {
console.log(hash(new Uint8Array([1, 2, 3])));
}
for (const hash of [sha256wc]) {
console.log(await hash.async(new Uint8Array([1, 2, 3])));
}
```
从 1 个源代码生成 4 个后端,由 awasm-compiler:
1. **wasm:** 包含 base64 字符串中的 wasm 二进制文件的 JS 文件。需要 `wasm-unsafe-eval` CORS 策略才能工作。
- 查看节点.js 和 vercel 的示例,了解适当的头信息
2. **wasm_threads:** 与 wasm 相同,但由于使用 web workers 而更快。需要 `Cross-Origin-Opener-Policy: same-origin` 和 `Cross-Origin-Embedder-Policy: require-corp` CORS 策略才能工作。
- 查看节点.js 和 vercel 的示例,了解适当的头信息
3. **js:** 不包含 WASM 的 JS 文件。自动应用额外的优化(如循环展开),使一切变得更快。
4. **运行时:** 慢慢执行源代码。捆绑包大小很小,适用于调试。依赖于 `@awasm/compiler`
此外,**noble** 包装 `@noble/hashes` 和 `@noble/ciphers`,**webcrypto** 包装内置的 `WebCrypto` 方法。WebCrypto 仅支持异步。
### Noble 平台
`@awasm/noble/noble.js` 平台是 `@noble/hashes` 和 `@noble/ciphers` 的静态包装器。这些库经过实战测试和独立审计。包装器为它们提供了与编译后端相同的 awasm API,包括 `.chunks(...)`, `.parallel(...)`, `out`, `outPos` 和模块。
`@awasm/noble` 将 `@noble/hashes` 和 `@noble/ciphers` 作为可选的依赖项,因此仅安装 `@awasm/noble` 不会将它们拉入。仅在导入 noble 平台时安装它们:
```
npm install @awasm/noble @noble/hashes @noble/ciphers
```
```
import { sha256 } from '@awasm/noble/noble.js';
const msgs = [new Uint8Array([1, 2, 3]), new Uint8Array([4, 5, 6])];
console.log(sha256.parallel(msgs));
```
这对于想要 awasm API 但不强制使用 WASM 的库很有用。库可以导出模块,将 noble 作为默认选项安装,并允许应用程序在性能重要时切换到更快的 wasm/js/wasm_threads 平台。
```
{
"dependencies": {
"@awasm/noble": "^0.1.2"
},
"peerDependencies": {
"@noble/ciphers": "~2.2.0",
"@noble/hashes": "~2.2.0"
}
}
```
```
// inside a library
import { sha256, chacha20poly1305 } from '@awasm/noble/stub.js';
import { sha256 as nobleSha256, chacha20poly1305 as nobleChaCha } from '@awasm/noble/noble.js';
sha256.install(nobleSha256, { onlyMissing: true });
chacha20poly1305.install(nobleChaCha, { onlyMissing: true });
export { sha256, chacha20poly1305 };
```
```
// inside an application that wants a faster backend
import { sha256 } from 'my-library';
import { sha256 as wasmSha256 } from '@awasm/noble/wasm_threads.js';
sha256.install(wasmSha256);
console.log(sha256.parallel([new Uint8Array([1, 2, 3])]));
```
### 模块
模块允许使用一个高级函数调用,同时根据需要切换内部后端。
想象一下,你有一个高级库(“awasm-react”)。在那里使用 wasm 方法并不是一个好主意,因为库的用户可能不想使用 wasm。
相反,你使用模块,其中(默认)包含 wasm。然后用户可以随时将环境切换到 JS、WebCrypto 或其他后端。
```
import { sha256 } from '@awasm/noble/stub.js';
function hash() {
console.log(sha256(new Uint8Array([1, 2, 3]))); // generic
}
// Switch to WASM
import { sha256 as sha256wasm } from '@awasm/noble';
sha256.install(sha256wasm);
hash();
// Switch to JS
import { sha256 as sha256js } from '@awasm/noble/js.js';
sha256.install(sha256js);
hash();
// Switch to WebCrypto
import { sha256 as sha256Web } from '@awasm/noble/webcrypto.js';
if (await sha256Web.isSupported()) {
sha256.install(sha256Web);
console.log(await sha256.async(new Uint8Array([1, 2, 3]))); // generic
}
```
`install(impl, { onlyMissing: true })` 仅在模块为空时安装。
这旨在为安装默认后端的同时保留应用程序已选择的实现。
### 线程
```
import { blake3 } from '@awasm/noble/wasm_threads.js';
import { xchacha20poly1305 } from '@awasm/noble/wasm_threads.js';
import { sha256 } from '@awasm/noble/wasm_threads.js';
import { deepStrictEqual } from 'node:assert';
blake3(new Uint8Array(1024 * 1024 * 1024)); // 1gb
deepStrictEqual(sha256.parallel([new Uint8Array([1, 2, 3]), new Uint8Array([4, 5, 6])]), [
sha256(new Uint8Array([1, 2, 3])),
sha256(new Uint8Array([4, 5, 6])),
]);
```
```
// Benchmark blake3
import { blake3 } from '@awasm/noble/wasm_threads.js';
async function main() {
function hex(bytes) {
return Array.from(bytes).map(byte => byte.toString(16).padStart(2, '0')).join('');
}
// warm-up JIT
for (let i = 0; i < 20; i++) {
blake3.parallel([new Uint8Array(1024 * 1024)]);
await Promise.resolve();
}
// benchmark
for (let i = 0; i < 5; i++) {
const input = new Uint8Array(1024 * 1024 * 1024).fill(i); // 1GB of 0x00, 0x01, 0x02...
const start = Date.now();
const res = blake3(input); // or blake3.create().update().digest()
console.log('hashed 1gb in', Date.now() - start, 'ms, result:', hex(res));
}
}
main();
```
默认后端(WASM)使用 SIMD 进行并行执行。
`wasm_threads` 也使用基于 web worker 的线程。
它需要 `Cross-Origin-Opener-Policy: same-origin` 和 `Cross-Origin-Embedder-Policy: require-corp` CORS 策略才能工作。
查看节点.js 和 vercel 的示例,了解适当的头信息。
BLAKE3 和大多数加密算法在多线程模式下运行非常快。其他(例如 SHA256、AES-CBC)不能使用线程并行化一个大型输入,但它们仍然使用 `hash.parallel(input)` 对多个输入进行并行化。
### 流
```
import { sha256 } from '@awasm/noble';
sha256
.create()
.update(new Uint8Array([1, 2, 3]))
.update(new Uint8Array([4, 5, 6]))
.digest();
sha256.chunks([new Uint8Array([1, 2, 3]), new Uint8Array([4, 5, 6])]);
```
为了获得最佳性能:对于小于 1kb 的消息使用块。对于大于等于 1kb 的消息使用流式 API `.update()`。
### 异步
```
import { sha256 } from '@awasm/noble';
import { deepStrictEqual } from 'node:assert';
deepStrictEqual(sha256(new Uint8Array([1, 2, 3])), await sha256.async(new Uint8Array([1, 2, 3])));
deepStrictEqual(
sha256.parallel([new Uint8Array([1, 2, 3])]),
await sha256.parallel.async([new Uint8Array([1, 2, 3])])
);
deepStrictEqual(
sha256.chunks([new Uint8Array([1, 2, 3])]),
await sha256.chunks.async([new Uint8Array([1, 2, 3])])
);
```
### 零分配
```
import { sha256 } from '@awasm/noble';
import { deepStrictEqual } from 'node:assert';
const out = new Uint8Array(sha256.outputLen);
sha256(new Uint8Array([1, 2, 3]), { out });
deepStrictEqual(out, sha256(new Uint8Array([1, 2, 3])));
```
```
import { ctr } from '@awasm/noble';
import { deepStrictEqual } from 'node:assert';
const key = new Uint8Array(32).fill(1);
const nonce = new Uint8Array(16).fill(2);
const msg = new Uint8Array(64).fill(7);
const c = ctr(key, nonce);
const encOut = new Uint8Array(msg.length);
c.encrypt(msg, encOut);
const decOut = new Uint8Array(msg.length);
c.decrypt(encOut, decOut);
deepStrictEqual(decOut, msg);
```
某些加密算法(GCM、GCM-SIV)不支持零分配模式。
## 示例
### 使用 XChaCha20Poly1305 加密
```
import { xchacha20poly1305 } from '@awasm/noble';
const key = new Uint8Array(32).fill(7);
const nonce = new Uint8Array(24).fill(9);
const data = new TextEncoder().encode('hello noble');
const chacha = xchacha20poly1305(key, nonce);
const ciphertext = chacha.encrypt(data);
const data_ = chacha.decrypt(ciphertext);
```
### 使用 AES 加密
```
import { deepStrictEqual } from 'node:assert';
import { gcm, gcmsiv, aessiv, ctr, cfb, cbc, ecb, aeskw, aeskwp } from '@awasm/noble';
const plaintext = new Uint8Array(32).fill(16);
const key = new Uint8Array(32).fill(1);
const nonce12 = new Uint8Array(12).fill(2);
const nonce16 = new Uint8Array(16).fill(3);
for (const cipher of [gcm, gcmsiv, aessiv]) {
const ct = cipher(key, nonce12).encrypt(plaintext);
deepStrictEqual(cipher(key, nonce12).decrypt(ct), plaintext);
}
for (const cipher of [ctr, cbc, cfb]) {
const ct = cipher(key, nonce16).encrypt(plaintext);
deepStrictEqual(cipher(key, nonce16).decrypt(ct), plaintext);
}
const wrapped = aeskw(key.subarray(0, 16)).encrypt(key.subarray(0, 16));
deepStrictEqual(aeskw(key.subarray(0, 16)).decrypt(wrapped), key.subarray(0, 16));
const wrappedP = aeskwp(key.subarray(0, 16)).encrypt(key.subarray(0, 16));
deepStrictEqual(aeskwp(key.subarray(0, 16)).decrypt(wrappedP), key.subarray(0, 16));
deepStrictEqual(ecb(key).decrypt(ecb(key).encrypt(plaintext)), plaintext);
```
### 自动管理的 nonce
```
import { deepStrictEqual } from 'node:assert';
import { xchacha20poly1305 } from '@awasm/noble';
import { managedNonce } from '@awasm/noble/utils.js';
const key = new Uint8Array(32).fill(4);
const chacha = managedNonce(xchacha20poly1305)(key);
const data = new TextEncoder().encode('hello noble');
const ciphertext = chacha.encrypt(data);
deepStrictEqual(chacha.decrypt(ciphertext), data);
```
### 具有进度的异步加密算法
```
import { deepStrictEqual } from 'node:assert';
import { ctr, gcm } from '@awasm/noble';
const msg = Uint8Array.from({ length: 8192 }, (_, i) => i & 0xff);
const key = new Uint8Array(32).fill(8);
const nonce16 = new Uint8Array(16).fill(9);
const nonce12 = new Uint8Array(12).fill(10);
const aad = new Uint8Array(33).fill(11);
const ctrSync = ctr(key, nonce16).encrypt(msg);
const ctrAsync = await ctr(key, nonce16).encrypt.async(msg, undefined, { asyncTick: 0 });
deepStrictEqual(ctrAsync, ctrSync);
deepStrictEqual(await ctr(key, nonce16).decrypt.async(ctrAsync, undefined, { asyncTick: 0 }), msg);
const gcmSync = gcm(key, nonce12, aad).encrypt(msg);
const gcmAsync = await gcm(key, nonce12, aad).encrypt.async(msg, undefined, { asyncTick: 0 });
deepStrictEqual(gcmAsync, gcmSync);
deepStrictEqual(await gcm(key, nonce12, aad).decrypt.async(gcmAsync, undefined, { asyncTick: 0 }), msg);
```
### 流加密算法
```
import { ctr } from '@awasm/noble';
const key = new Uint8Array(32).fill(5);
const nonce = new Uint8Array(16).fill(6);
const msg = new Uint8Array(1024).fill(7);
const enc = ctr(key, nonce).encrypt.create();
const c1 = enc.update(msg.subarray(0, 256));
const c2 = enc.update(msg.subarray(256, 1024));
const tail = enc.finish().data;
const dec = ctr(key, nonce).decrypt.create();
const p1 = dec.update(c1);
const p2 = dec.update(c2);
const end = dec.finish().data;
```
### Scrypt、Argon、PBKDF
```
import { scrypt } from '@awasm/noble';
const scr1 = scrypt('password', 'salt', { N: 2 ** 16, r: 8, p: 1, dkLen: 32 });
const scr2 = await scrypt.async('password', 'salt', { N: 2 ** 16, r: 8, p: 1, dkLen: 32 });
import { argon2d, argon2i, argon2id } from '@awasm/noble';
const arg1 = argon2id('password', 'saltsalt', { t: 2, m: 65536, p: 1, maxmem: 2 ** 32 - 1 });
const arg2 = argon2d('password', 'saltsalt', { t: 2, m: 65536, p: 1, maxmem: 2 ** 32 - 1 });
const arg3 = argon2i('password', 'saltsalt', { t: 2, m: 65536, p: 1, maxmem: 2 ** 32 - 1 });
const arg4 = await argon2i.async('password', 'saltsalt', {
t: 2,
m: 65536,
p: 1,
maxmem: 2 ** 32 - 1,
});
import { sha256 } from '@awasm/noble';
import { pbkdf2 } from '@awasm/noble/kdf.js';
const pbkey1 = pbkdf2(sha256)('password', 'salt', { c: 524288, dkLen: 32 });
const pbkey2 = pbkdf2(sha256).async('password', 'salt', { c: 524288, dkLen: 32 });
```
所有 KDF 都支持 onProgress 回调(即使在同步版本中,也允许在 CLI 脚本中显示进度条)。
此外,我们现在支持覆盖 `nextTick` 函数,该函数用于返回控制权,这意味着可以在需要时将其替换为 `sleep` 或其他实现(https://github.com/paulmillr/noble-hashes/issues/113)
```
import { scrypt } from '@awasm/noble';
const scr3 = await scrypt.async(Uint8Array.from([1, 2, 3]), Uint8Array.from([4, 5, 6]), {
N: 2 ** 17,
r: 8,
p: 1,
dkLen: 32,
asyncTick: 10, // return control after this amount of ms
onProgress(percentage) {
console.log('progress', percentage);
},
nextTick: async () => {},
maxmem: 2 ** 32 + 128 * 8 * 1, // N * r * p * 128 + (128*r*p)
});
```
### MAC
```
import { deepStrictEqual } from 'node:assert';
import { cmac } from '@awasm/noble';
import { poly1305 } from '@awasm/noble';
import { ghash } from '@awasm/noble';
const msg = new Uint8Array([1, 2, 3, 4]);
const key32 = new Uint8Array(32).fill(12);
const key16 = new Uint8Array(16).fill(13);
const p = poly1305(msg, key32);
const g = ghash(msg, key16);
const c = cmac(msg, key16); // note order: (message, key)
deepStrictEqual(poly1305.parallel([msg, msg], key32), [p, p]);
```
### WebCrypto 散列 + KDF/MAC
```
import { deepStrictEqual, throws } from 'node:assert';
import { sha256, hmac, hkdf, pbkdf2 } from '@awasm/noble/webcrypto.js';
import { sha256 as sha256wasm } from '@awasm/noble';
const msg = new Uint8Array([1, 2, 3]);
const key = new Uint8Array([7, 8, 9]);
const salt = new Uint8Array([4, 5, 6]);
if (await sha256.isSupported()) {
deepStrictEqual(await sha256.async(msg), sha256wasm(msg));
await hmac(sha256, key, msg);
await hkdf(sha256, key, salt, msg, 32);
await pbkdf2(sha256).async(key, salt, { c: 10, dkLen: 32 });
}
throws(() => pbkdf2(sha256)(key, salt, { c: 10, dkLen: 32 })); // sync is not supported
throws(() => sha256(msg)); // sync is not supported
```
### WebCrypto 加密算法
```
import { cbc, ctr, gcm } from '@awasm/noble/webcrypto.js';
const key = new Uint8Array(32).fill(1);
const iv16 = new Uint8Array(16).fill(2);
const iv12 = new Uint8Array(12).fill(3);
const aad = new Uint8Array(8).fill(4);
const plaintext = new Uint8Array(64).fill(5);
if (await cbc.isSupported()) await cbc(key, iv16).encrypt.async(plaintext);
if (await ctr.isSupported()) await ctr(key, iv16).encrypt.async(plaintext);
if (await gcm.isSupported()) await gcm(key, iv12, aad).encrypt.async(plaintext);
```
## 内部结构
要设置存储库:
```
git submodule update --init --recursive
npm install
npm run build
npm test
```
贡献很简单!
### 构建过程是什么?
1. `node scripts/build-targets.ts` 脚本将 `src/modules` 编译到 `src/targets`。
- 该脚本使用 [awasm-compiler](https://github.com/paulmillr/awasm-compiler)
- 一些行包含在生成的文件中,请查看脚本以获取详细信息
2. TypeScript 将 `src` 目录编译到根目录
### 为什么一个包包含散列和加密算法?
- 应始终只有一个工作池,而不是两个,以获得最佳性能。
使用两个包将创建两个工作池
- 重要组件在两个部分之间重复使用。这将增加
捆绑包大小,尤其是运行时后端的大小
### 与 noble 的区别
异步方法命名为 `hash.async`,而不是 `hashAsync`。
某些功能在 awasm-noble 中不可用。对于以下内容使用 noble 包:
keccakprg、rngAesCtr、rngChacha、kmac、cshake、turboshake、kt128、ff1。
- 原始异或流加密算法(chacha20/salsa20)使用与其他加密算法相同的对象 API:`cipher(key, nonce).encrypt/decrypt`。
- 在 noble-ciphers 中,它们有单独的异或流式 API,而 `ctr` 有 `encrypt/decrypt`,这并不一致
- `@awasm/noble` 保持 ctr/chacha/salsa 的一个形状,以便更容易切换模式
- `ofb` 在 `@awasm/noble` (`@awasm/noble/*/aes.js`) 中可用,而在 noble-ciphers 导出中不可用。
- cmac 也使用 `(msg, key)`(而不是 noble-ciphers 的 `(key, msg)`)以统一与 ghash/polyval/poly1305。
- 加密算法目前不公开类似散列的 `.parallel(...)` API。
- 相反,`wasm_threads` 后端使用内部块批处理/线程,其中模式允许它
- 顺序模式(如 CBC 和类似依赖链路径)不能以相同的方式并行化
- 许多 AEAD 模式仍然从并行化加密路径中获得强大的速度提升,即使身份验证路径是顺序的(GCM 只是其中一个例子;相同的概念适用于 SIV / XSalsa20-Poly1305 / 其他)
- poly1305/ghash/polyval/cmac 是具有类似散列 API 的单独 MAC:
- 直接:`mac(message, key)` 或 `mac(message, { key })`
- 块:`mac.chunks([part1, part2], key)` 或 `mac.chunks([part1, part2], { key })`
- 并行:`mac.parallel([msg1, msg2], key)` 或 `mac.parallel([msg1, msg2], { key })`
- 流:`mac.create(key).update(...).digest()` 或 `mac.create({ key }).update(...).digest()`
- `secretbox` 是 `xsalsa20poly1305` 的别名(用于 libsodium / nacl-style API 命名),具有 `seal/open` 方法。
### Deno 和 Web Workers
虽然 Node 和 Bun 运作正常,但 Deno 需要 `wasm_threads` 中手动停止 web workers,因为它没有 `unref`:
```
import { sha256 } from '@awasm/noble/wasm_threads.js';
sha256(new Uint8Array([1, 2, 3]));
// will pause in Deno until this called:
import { WP } from '@awasm/noble/workers.js';
WP.stop();
```
## 速度
在 Apple M4 上测量的基准测试。
对于多个小于 1mb 的输入,首选 `.chunks()`。对于大于等于 1mb 的输入,首选流式 API `.update()`。
在线基准测试(BLAKE3 校验和计算器)可在 [Vercel 托管的演示网站](https://b3sum.vercel.app) 上找到。
### wasm_threads
```
# hashes, 输入:32x1mb, +threads
sha256 x 6,687 mb/sec
sha512 x 6,272 mb/sec
sha3_256 x 6,976 mb/sec
sha3_512 x 4,224 mb/sec
blake2b x 9,065 mb/sec
blake2s x 9,610 mb/sec
blake3 48x1mb x 11,058 mb/sec
blake3 1x100mb x 6,564 mb/sec
ripemd160 x 6,588 mb/sec
md5 x 9,078 mb/sec
sha1 x 11,413 mb/sec
# ciphers, 输入:1gb +threads
chacha20poly1305 x 2,318 mb/sec
chacha20 x 6,530 mb/sec
aes-gcm-256 x 1,015 mb/sec
aes-gcm-siv-256 x 927 mb/sec
aes-ecb-256 x 2,185 mb/sec
aes-cbc-256 x 268 mb/sec
aes-ctr-256 x 2,105 mb/sec
```
### wasm (无线程)
```
sha256 x 553 mb/sec
sha512 x 834 mb/sec
sha3_256 x 899 mb/sec
sha3_512 x 502 mb/sec
blake2b x 1,342 mb/sec
blake2s x 812 mb/sec
blake3 x 1,940 mb/sec
ripemd160 x 503 mb/sec
md5 x 857 mb/sec
sha1 x 1,294 mb/sec
chacha20poly1305 x 1,196 mb/sec
aes-gcm-256 x 234 mb/sec
aes-gcm-siv-256 x 236 mb/sec
chacha20 x 1,672 mb/sec
aes-ecb-256 x 277 mb/sec
aes-cbc-256 x 262 mb/sec
aes-ctr-256 x 272 mb/sec
# KDF
pbkdf2(sha256, c: 2 ** 18) x 2 ops/sec @ 351ms/op
pbkdf2(sha512, c: 2 ** 18) x 1 ops/sec @ 503ms/op
scrypt(n: 2 ** 19, r: 8, p: 1) x 1 ops/sec @ 597ms/op
argon2id(t: 1, m: 128MB, p: 1) x 14 ops/sec @ 69ms/op
```
## 许可证
MIT 许可证 (MIT)
版权所有 (c) 2026 Paul Miller [(https://paulmillr.com)](https://paulmillr.com)
请参阅 LICENSE 文件。
标签:AES, AI工具, Argon2, BLAKE, ChaCha, Cilium, CMS安全, DNS解析, HKDF, HMAC, JavaScript, LangChain, NPM, PBKDF, RIPEMD, Salsa, Scrypt, SHA, SIMD, WebAssembly, Web Workers, 代码优化, 加密库, 加密算法, 可审计性, 同步异步, 哈希函数, 安全测试, 安全编码, 开源项目, 性能提升, 攻击性安全, 数据可视化, 构建系统, 树摇优化, 编译器, 自动化攻击, 跨平台开发, 跨浏览器, 轻量级, 零化测试