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, 代码优化, 加密库, 加密算法, 可审计性, 同步异步, 哈希函数, 安全测试, 安全编码, 开源项目, 性能提升, 攻击性安全, 数据可视化, 构建系统, 树摇优化, 编译器, 自动化攻击, 跨平台开发, 跨浏览器, 轻量级, 零化测试