paulmillr/noble-hashes
GitHub: paulmillr/noble-hashes
一款经过审计、极简且跨平台的 JavaScript 密码学哈希、MAC 和 KDF 实现库。
Stars: 844 | Forks: 62
# noble-hashes
经过审计且极简的哈希函数、MAC 和 KDF 的 JS 实现。
- 🔒 由独立安全公司[**审计**](#security)
- 🔻 Tree-shakeable:未使用的代码会被排除在你的构建之外
- 🏎 快速:针对 JS 引擎的特性进行了手工优化
- 🔍 可靠:经过链式/滑动窗口/DoS/ACVP 测试和模糊测试
- 🔁 无循环展开:更易于验证,并将源代码大小减少了多达 5 倍
- 🦘 包括 SHA, RIPEMD, BLAKE, HMAC, HKDF, PBKDF, Scrypt, Argon2
- 🥈 可选的、友好的原生 WebCrypto 封装
- 🪶 全部功能 22KB (gzipped),单哈希构建 2.4KB
如果你需要更快的 (WASM) 替代方案,请使用 [awasm-noble](https://github.com/paulmillr/awasm-noble)。
请查看 [升级](#upgrading) 以获取有关从先前版本升级的信息。
请浏览 [GitHub Discussions](https://github.com/paulmillr/noble-hashes/discussions) 以提问和寻求支持。
该库的初始开发由 [Ethereum Foundation](https://ethereum.org/) 资助。
### 该库属于 _noble_ 密码学系列
- 零或极少的依赖
- 高度可读的 TypeScript / JS 代码
- PGP 签名的发布和透明的 NPM 构建
- 所有库:
[ciphers](https://github.com/paulmillr/noble-ciphers),
[curves](https://github.com/paulmillr/noble-curves),
[hashes](https://github.com/paulmillr/noble-hashes),
[post-quantum](https://github.com/paulmillr/noble-post-quantum),
5kb [secp256k1](https://github.com/paulmillr/noble-secp256k1) /
[ed25519](https://github.com/paulmillr/noble-ed25519)
- [查看主页](https://paulmillr.com/noble/)
以获取阅读资源、文档和使用 noble 构建的应用
## 用法
我们支持所有主要平台和运行时。
对于 React Native,你可能需要一个 [getRandomValues 的 polyfill](https://github.com/LinusU/react-native-get-random-values)。
还提供了一个独立文件 [noble-hashes.js](https://github.com/paulmillr/noble-hashes/releases)。
```
// import * from '@noble/hashes'; // Error: use sub-imports, to ensure small app size
import { sha256 as noble_sha256 } from '@noble/hashes/sha2.js';
const hash = noble_sha256(Uint8Array.from([0xca, 0xfe, 0x01, 0x23]));
// Available modules
import { sha256, sha384, sha512, sha224, sha512_224, sha512_256 } from '@noble/hashes/sha2.js';
import {
sha3_256, sha3_512,
keccak_256, keccak_512,
shake128, shake256,
} from '@noble/hashes/sha3.js';
import {
cshake256, turboshake256, kmac256, tuplehash256,
kt128, kt256, keccakprg,
} from '@noble/hashes/sha3-addons.js';
import { blake3 } from '@noble/hashes/blake3.js';
import { blake2b, blake2s } from '@noble/hashes/blake2.js';
import { blake256, blake512 } from '@noble/hashes/blake1.js';
import { sha1, md5, ripemd160 } from '@noble/hashes/legacy.js';
import { hmac } from '@noble/hashes/hmac.js';
import { hkdf } from '@noble/hashes/hkdf.js';
import { pbkdf2, pbkdf2Async } from '@noble/hashes/pbkdf2.js';
import { scrypt, scryptAsync } from '@noble/hashes/scrypt.js';
import { argon2d, argon2i, argon2id } from '@noble/hashes/argon2.js';
import * as webcrypto from '@noble/hashes/webcrypto.js';
// const { sha256, sha384, sha512, hmac, hkdf, pbkdf2 } = webcrypto;
import * as utils from '@noble/hashes/utils.js';
const { bytesToHex, concatBytes, equalBytes, hexToBytes } = utils;
```
- [sha2: sha256, sha384, sha512](#sha2-sha256-sha384-sha512-and-others)
- [sha3: FIPS, SHAKE, Keccak](#sha3-fips-shake-keccak)
- [sha3-addons: cSHAKE, KMAC, KT128, TurboSHAKE](#sha3-addons-cshake-kmac-kt128-turboshake)
- [blake1, blake2, blake3](#blake1-blake2-blake3)
- [legacy: sha1, md5, ripemd160](#legacy-sha1-md5-ripemd160)
- MACs: [hmac](#hmac) | [kmac](#sha3-addons-cshake-kmac-kt128-turboshake) | [blake3 key mode](#blake1-blake2-blake3)
- KDFs: [hkdf](#hkdf) | [pbkdf2](#pbkdf2) | [scrypt](#scrypt) | [argon2](#argon2)
- [webcrypto: 友好的封装](#webcrypto-friendly-wrapper)
- [utils](#utils)
- [安全性](#security) | [速度](#speed) | [贡献与测试](#contributing--testing) | [许可证](#license)
### 实现
哈希函数:
- `sha256()`:接收并返回 `Uint8Array`
- `sha256.create().update(a).update(b).digest()`:支持部分更新
- `blake3.create({ context: 'e', dkLen: 32 })`:可以带有选项
- 支持小端架构;也实验性地支持大端
- 每个块最多可哈希 4GB,块数量不限
#### sha2: sha256, sha384, sha512 及其他
```
import { sha224, sha256, sha384, sha512, sha512_224, sha512_256 } from '@noble/hashes/sha2.js';
const res = sha256(Uint8Array.from([0xbc])); // basic
for (let hash of [sha256, sha384, sha512, sha224, sha512_224, sha512_256]) {
const arr = Uint8Array.from([0x10, 0x20, 0x30]);
const a = hash(arr);
const b = hash.create().update(arr).digest();
}
```
查看 [RFC 4634](https://datatracker.ietf.org/doc/html/rfc4634) 和
[关于截断 SHA512/256 的论文](https://eprint.iacr.org/2010/548.pdf)。
#### sha3: FIPS、SHAKE、Keccak
```
import {
sha3_224, sha3_256, sha3_384, sha3_512,
keccak_224, keccak_256, keccak_384, keccak_512,
shake128, shake256,
} from '@noble/hashes/sha3.js';
for (let hash of [
sha3_224, sha3_256, sha3_384, sha3_512,
keccak_224, keccak_256, keccak_384, keccak_512,
]) {
const arr = Uint8Array.from([0x10, 0x20, 0x30]);
const a = hash(arr);
const b = hash.create().update(arr).digest();
}
const shka = shake128(Uint8Array.from([0x10]), { dkLen: 512 });
const shkb = shake256(Uint8Array.from([0x30]), { dkLen: 512 });
```
查看 [FIPS-202](https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf),
[网站](https://keccak.team/keccak.html)。
查看 [SHA-3 和 Keccak 之间的区别](https://crypto.stackexchange.com/questions/15727/what-are-the-key-differences-between-the-draft-sha-3-standard-and-the-keccak-sub)
#### sha3-addons: cSHAKE、KMAC、K12、TurboSHAKE
```
import {
cshake128, cshake256, kt128, kt256,
keccakprg, kmac128, kmac256,
parallelhash256, tuplehash256,
turboshake128, turboshake256,
} from '@noble/hashes/sha3-addons.js';
const data = Uint8Array.from([0x10, 0x20, 0x30]);
const personalization = new TextEncoder().encode('def');
const ec1 = cshake128(data, { personalization });
const ec2 = cshake256(data, { personalization });
const et1 = turboshake128(data);
const et2 = turboshake256(data, { D: 0x05 });
// tuplehash(['ab', 'c']) !== tuplehash(['a', 'bc']) !== tuplehash([data])
const et3 = tuplehash256([new TextEncoder().encode('ab'), new TextEncoder().encode('c')]);
// Not parallel in JS (similar to blake3 / kt128), added for compat
const ep1 = parallelhash256(data, { blockLen: 8 });
const kk = Uint8Array.from([0xca]);
const ek10 = kmac128(kk, data);
const ek11 = kmac256(kk, data);
const ek12 = kt128(data); // kangarootwelve 128-bit
const ek13 = kt256(data); // kangarootwelve 256-bit
// pseudo-random generator, first argument is capacity. XKCP recommends 254 bits capacity for 128-bit security strength.
// * with a capacity of 254 bits.
const p = keccakprg(254);
p.addEntropy(Uint8Array.from([1, 2, 3]));
const rand1b = p.randomBytes(32);
```
- cSHAKE, KMAC, TupleHash, ParallelHash + XOF 均可用,符合
[NIST SP 800-185](https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-185.pdf)
- 减少轮次的 Keccak KT128 (KangarooTwelve 🦘, K12) 和 TurboSHAKE 均可用,符合
[RFC 9861](https://datatracker.ietf.org/doc/rfc9861/).
- [KeccakPRG](https://keccak.team/files/CSF-0.1.pdf):基于 Keccak 的伪随机生成器
#### blake1、blake2、blake3
```
import { blake224, blake256, blake384, blake512 } from '@noble/hashes/blake1.js';
import { blake2b, blake2s } from '@noble/hashes/blake2.js';
import { blake3 } from '@noble/hashes/blake3.js';
for (let hash of [blake224, blake256, blake384, blake512, blake2b, blake2s, blake3]) {
const arr = Uint8Array.from([0x10, 0x20, 0x30]);
const a = hash(arr);
const b = hash.create().update(arr).digest();
}
// blake2 advanced usage
const ab = Uint8Array.from([0x01]);
const txt = new TextEncoder();
blake2s(ab);
blake2s(ab, { key: new Uint8Array(32) });
blake2s(ab, { personalization: txt.encode('pers1234') });
blake2s(ab, { salt: txt.encode('salt1234') });
blake2b(ab);
blake2b(ab, { key: new Uint8Array(64) });
blake2b(ab, { personalization: txt.encode('pers1234pers1234') });
blake2b(ab, { salt: txt.encode('salt1234salt1234') });
// blake3 advanced usage
blake3(ab);
blake3(ab, { dkLen: 256 });
blake3(ab, { key: new Uint8Array(32) });
blake3(ab, { context: txt.encode('application-name') });
```
- Blake1 是遗留哈希,是 SHA3 提案之一。它很少在任何地方使用。见 [pdf](https://www.aumasson.jp/blake/blake.pdf)。
- Blake2 是流行的快速哈希。blake2b 专注于 64 位平台,而 blake2s 适用于 8 位到 32 位平台。见 [RFC 7693](https://datatracker.ietf.org/doc/html/rfc7693),[网站](https://www.blake2.net)
- Blake3 更快,是减少轮次的 blake2。见 [网站 & 规范](https://blake3.io)
#### legacy: sha1、md5、ripemd160
SHA1 (RFC 3174), MD5 (RFC 1321) 和 RIPEMD160 (RFC 2286) 遗留的、弱哈希函数。
不要在新协议中使用它们。“弱”意味着:
- MD5 可以在 2^18 的努力下产生碰撞,SHA1 为 2^60,RIPEMD160 为 2^80。
- 没有实际的原图攻击(只有理论上的,2^123.4)
- HMAC 似乎还可以:https://datatracker.ietf.org/doc/html/rfc6151
```
import { md5, ripemd160, sha1 } from '@noble/hashes/legacy.js';
for (let hash of [md5, ripemd160, sha1]) {
const arr = Uint8Array.from([0x10, 0x20, 0x30]);
const a = hash(arr);
const b = hash.create().update(arr).digest();
}
```
#### hmac
```
import { hmac } from '@noble/hashes/hmac.js';
import { sha256 } from '@noble/hashes/sha2.js';
const key = new Uint8Array(32).fill(1);
const msg = new Uint8Array(32).fill(2);
const mac1 = hmac(sha256, key, msg);
const mac2 = hmac.create(sha256, key).update(msg).digest();
```
符合 [RFC 2104](https://datatracker.ietf.org/doc/html/rfc2104)。
#### hkdf
```
import { hkdf } from '@noble/hashes/hkdf.js';
import { randomBytes } from '@noble/hashes/utils.js';
import { sha256 } from '@noble/hashes/sha2.js';
const inputKey = randomBytes(32);
const salt = randomBytes(32);
const info = new TextEncoder().encode('application-key');
const hk1 = hkdf(sha256, inputKey, salt, info, 32);
// == same as
import { extract, expand } from '@noble/hashes/hkdf.js';
const prk = extract(sha256, inputKey, salt);
const hk2 = expand(sha256, prk, info, 32);
```
符合 [RFC 5869](https://datatracker.ietf.org/doc/html/rfc5869)。
#### pbkdf2
```
import { pbkdf2, pbkdf2Async } from '@noble/hashes/pbkdf2.js';
import { sha256 } from '@noble/hashes/sha2.js';
const pbkey1 = pbkdf2(sha256, 'password', 'salt', { c: 524288, dkLen: 32 });
const pbkey2 = await pbkdf2Async(sha256, 'password', 'salt', { c: 524288, dkLen: 32 });
const pbkey3 = await pbkdf2Async(sha256, Uint8Array.from([1, 2, 3]), Uint8Array.from([4, 5, 6]), {
c: 524288,
dkLen: 32,
});
```
符合 [RFC 2898](https://datatracker.ietf.org/doc/html/rfc2898)。
#### scrypt
```
import { scrypt, scryptAsync } from '@noble/hashes/scrypt.js';
const scr1 = scrypt('password', 'salt', { N: 2 ** 16, r: 8, p: 1, dkLen: 32 });
const scr2 = await scryptAsync('password', 'salt', { N: 2 ** 16, r: 8, p: 1, dkLen: 32 });
const scr3 = await scryptAsync(Uint8Array.from([1, 2, 3]), Uint8Array.from([4, 5, 6]), {
N: 2 ** 17,
r: 8,
p: 1,
dkLen: 32,
onProgress(percentage) {
console.log('progress', percentage);
},
maxmem: 2 ** 32 + 128 * 8 * 1, // N * r * p * 128 + (128*r*p)
});
```
符合 [RFC 7914](https://datatracker.ietf.org/doc/html/rfc7914),
[网站](https://www.tarsnap.com/scrypt.html)
- `N, r, p` 是工作量因子。通常只调整 N,同时保持 `r: 8, p: 1`。
见[博客文章](https://blog.filippo.io/the-scrypt-parameters/)。
JS 不支持并行化,使得增加 `p` 毫无意义。
- `dkLen` 是输出字节的长度,例如 `32` 或 `64`
- `onProgress` 可以与函数的异步版本一起使用,以向用户报告进度。
- `maxmem` 防止 DoS,限制为 `1GB + 1KB` (`2**30 + 2**10`),但可以使用公式调整:`N * r * p * 128 + (128 * r * p)`
在 Apple M4 上使用不同的 N (2\*\*N) 值派生 Scrypt 密钥所需的时间(手机可能会慢 1x-4x):
| N pow | 时间 | RAM |
| ----- | ---- | ----- |
| 16 | 0.1s | 64MB |
| 17 | 0.2s | 128MB |
| 18 | 0.4s | 256MB |
| 19 | 0.8s | 512MB |
| 20 | 1.5s | 1GB |
| 21 | 3.1s | 2GB |
| 22 | 6.2s | 4GB |
| 23 | 13s | 8GB |
| 24 | 27s | 16GB |
#### argon2
```
import { argon2d, argon2i, argon2id } from '@noble/hashes/argon2.js';
const arg1 = argon2id('password', 'saltsalt', { t: 2, m: 65536, p: 1, maxmem: 2 ** 32 - 1 });
```
Argon2 [RFC 9106](https://datatracker.ietf.org/doc/html/rfc9106) 实现。
#### webcrypto: 友好的封装
```
import { sha256, sha384, sha512, hmac, hkdf, pbkdf2 } from '@noble/hashes/webcrypto.js';
import { randomBytes } from '@noble/hashes/utils.js';
const whash = await sha256(Uint8Array.from([0xca, 0xfe, 0x01, 0x23]));
const key = new Uint8Array(32).fill(1);
const msg = new Uint8Array(32).fill(2);
const wmac = await hmac(sha256, key, msg);
const inputKey = randomBytes(32);
const salt = randomBytes(32);
const info = new TextEncoder().encode('application-key');
const hk1 = await hkdf(sha256, inputKey, salt, info, 32);
const pbkey1 = await pbkdf2(sha256, 'password', 'salt', { c: 524288, dkLen: 32 });
```
有时人们想使用内置的 `crypto.subtle` 而不是纯 JS 实现。
然而,它的 API 很糟糕。
我们使用镜像 noble-hashes 的 API 简化了对内置功能的访问。
开销极小 - 只有 30 多行代码,用于验证输入的正确性。
#### utils
```
import { bytesToHex as toHex, randomBytes } from '@noble/hashes/utils.js';
console.log(toHex(randomBytes(32)));
```
- `bytesToHex` 将 `Uint8Array` 转换为十六进制字符串
- `randomBytes(bytes)` 将生成密码学安全的、长度为 `bytes` 的随机 `Uint8Array`
## 安全性
该库已经过审计:
- 在 2.1.0 版本,2026 年 4 月,由我们自己(自我审计)
- 范围:所有内容
- [审计后的变更](https://github.com/paulmillr/noble-hashes/compare/2.1.0..main)
- 在 1.0.0 版本,2022 年 1 月,独立由 [Cure53](https://cure53.de) 进行
- PDF:[网站](https://cure53.de/pentest-report_hashing-libs.pdf),[仓库内](./audit/2022-01-05-cure53-audit-nbl2.pdf)
- 范围:除 `blake3`, `sha3-addons`, `sha1` 和 `argon2` 之外的所有内容,这些未被审计
- 审计由 [Ethereum Foundation](https://ethereum.org/en/) 在 [Nomic Labs](https://nomiclabs.io) 的帮助下资助
它经过了基于属性的、跨库的和 Wycheproof 向量的测试,
并在[单独的仓库](https://github.com/paulmillr/fuzzing)中进行模糊测试。
如果你发现任何异常:请调查并报告。
### 恒定时间性
我们的目标是算法上的恒定时间。_JIT-compiler_ 和 _Garbage Collector_ 使得在脚本语言中
极难实现针对[计时攻击](https://en.wikipedia.org/wiki/Timing_attack)的抵抗能力。
这意味着_任何其他 JS 库都无法实现恒定时间性_。即使是静态类型的 Rust,一种没有 GC 的语言,
[在某些情况下也更难实现恒定时间](https://www.chosenplaintext.ca/open-source/rust-timing-shield/security)。
如果你的目标是绝对安全,不要使用任何 JS 库——包括绑定到原生代码的库。
请使用底层库和语言。
### 内存转储
该库在哈希函数调用之间共享状态缓冲区。
缓冲区在每次调用后被清零。但是,如果攻击者能够读取应用程序内存,
无论如何你都注定在劫难逃:
- 在某些时候,输入将是一个字符串,而字符串在 JS 中是不可变的:
无法用零覆盖它们。例如:从 `scrypt(password, salt)` 派生密钥,其中 password 和 salt 是字符串
- 来自文件的输入将保留在文件缓冲区中
- 输入/输出将在应用程序中多次重用,这意味着它可能保留在内存中
- `await anything()` 总是将所有内部变量(包括数字)写入
内存。对于异步函数/Promises,无法保证代码块何时执行。
这意味着攻击者有充足的时间从内存中读取数据
- 如果没有复杂的测试套件(将转储进程内存并验证没有
敏感数据残留),就无法保证任何关于清零敏感数据的事情。
对于 JS,这意味着测试所有浏览器(包括移动端),
这很复杂。当然,如果不使用相同的测试套件在实际使用该库的应用程序中进行测试,这将是徒劳的。
### 供应链安全
- **提交** 使用 PGP 密钥签名以防伪造。请务必验证提交签名
- **发布** 通过无令牌的 GitHub CI 和可信发布透明进行。请务必验证 [来源日志](https://docs.npmjs.com/generating-provenance-statements) 的真实性。
- **极少发布** 以最大限度地减少最终用户重新审计的需要。
- **依赖** 被最小化并严格锁定以降低供应链风险。
- 我们使用尽可能少的依赖。
- 版本范围被锁定,并使用 npm-diff 检查更改。
- **开发依赖** 从最终用户安装中排除;它们仅用于开发和构建步骤。
对于此包,有 0 个依赖项;以及一些开发依赖项:
- jsbt 包含用于构建、基准测试和测试安全 JS 应用程序的助手。它由同一作者开发
- prettier, fast-check 和 typescript 用于代码质量/测试生成/ts 编译
### 随机性
我们依赖内置的
[`crypto.getRandomValues`](https://developer.mozilla.org/en-US/docs/Web/API/Crypto/getRandomValues),
这被认为是密码学安全的 PRNG。
浏览器过去曾有弱点——将来可能还会有——但实现用户空间 CSPRNG 更糟糕,因为没有可靠的用户空间高质量熵源。
### 量子计算机
如果建造出密码学相关的量子计算机,将允许利用 Grover 算法在 2^n/2 次操作中破解哈希,而不是 2^n。
这意味着 SHA256 应被替换为 SHA512,SHA3-256 应被替换为 SHA3-512,SHAKE128 应被替换为 SHAKE256 等。
澳大利亚 ASD [在 2030 年之后](https://www.cyber.gov.au/resources-business-and-government/essential-cyber-security/ism/cyber-security-guidelines/guidelines-cryptography) 禁止使用 SHA256 和类似的哈希。
## 升级
支持的 node.js 版本:
- v2: v20.19+ (仅 ESM)
- v1: v14.21+ (M & CJS)
v2.0 更新日志:
- 该包现在仅支持 ESM。ESM 终于可以在 node v20.19+ 上从 common.js 加载
- 所有模块必须使用 `.js` 扩展名
- 旧版:`@noble/hashes/sha3`
- 新版:`@noble/hashes/sha3.js`
- 这简化了在没有转译器的情况下在浏览器中原生工作
- 仅允许 Uint8Array 作为哈希输入,禁止 `string`
- 严格的验证检查提高了安全性
- 要复制先前的行为,请使用 `utils.utf8ToBytes`
- 重命名/删除某些模块以保持一致性。以前,sha384 位于 sha512 中,这很奇怪
- `sha256`, `sha512` => `sha2.js` (与 `sha3.js` 一致)
- `blake2b`, `blake2s` => `blake2.js` (与 `blake3.js`, `blake1.js` 一致)
- `ripemd160`, `sha1`, `md5` => `legacy.js` (所有低安全性哈希都在那里)
- `_assert` => `utils.js`
- `crypto` 内部模块已删除:请改用内置 WebCrypto
- 改进 typescript 类型和选项自动补全
- 将编译目标从 es2020 提升到 es2022
## 贡献与测试
`test/misc` 目录包含循环展开和 md5 的实现。
- `npm install && npm run build && npm test` 将构建代码并运行测试。
- `npm run lint` / `npm run format` 将运行 linter/修复 linter 问题。
- `npm run bench` 将运行基准测试
- `npm run build:release` 将构建单个文件
- 有**额外的** 20 分钟 DoS 测试 `npm run test:dos` 和 2 小时多核测试 `npm run test:slow`。
请参阅[我们的测试方法](./test/README.md)
某些哈希不在此库的范围内:
- [micro-zk-proofs 中的 Pedersen](https://github.com/paulmillr/micro-zk-proofs/blob/1ed5ce1253583b2e540eef7f3477fb52bf5344ff/src/pedersen.ts)
- [noble-curves 中的 Poseidon](https://github.com/paulmillr/noble-curves/blob/3d124dd3ecec8b6634cc0b2ba1c183aded5304f9/src/abstract/poseidon.ts)
- [noble-ciphers 中的 Poly1305 & GHash](https://github.com/paulmillr/noble-ciphers)
请参阅 [paulmillr.com/noble](https://paulmillr.com/noble/) 获取与该库相关的有用资源、文章、文档和演示。
## 速度
```
npm run bench
```
基准测试在 Apple M4 上测量。如果你需要真正卓越的性能,请切换到 [awasm-noble](https://github.com/paulmillr/awasm-noble)。
```
# 32B
sha256 x 2,016,129 ops/sec @ 496ns/op
sha512 x 740,740 ops/sec @ 1μs/op
sha3_256 x 287,686 ops/sec @ 3μs/op
sha3_512 x 288,267 ops/sec @ 3μs/op
k12 x 476,190 ops/sec @ 2μs/op
blake2b x 410,340 ops/sec @ 2μs/op
blake2s x 942,507 ops/sec @ 1μs/op
blake3 x 1,006,036 ops/sec @ 994ns/op
ripemd160 x 1,410,437 ops/sec @ 709ns/op
md5 x 1,663,893 ops/sec @ 601ns/op
sha1 x 1,589,825 ops/sec @ 629ns/op
# 1MB
sha256 x 331 ops/sec @ 3ms/op
sha512 x 128 ops/sec @ 7ms/op
sha3_256 x 39 ops/sec @ 25ms/op
sha3_512 x 21 ops/sec @ 46ms/op
kt128 x 91 ops/sec @ 10ms/op
kt256 x 75 ops/sec @ 13ms/op
turboshake128 x 93 ops/sec @ 10ms/op
blake256 x 57 ops/sec @ 17ms/op
blake2b x 61 ops/sec @ 16ms/op
blake2s x 78 ops/sec @ 12ms/op
blake3 x 95 ops/sec @ 10ms/op
ripemd160 x 177 ops/sec @ 5ms/op
md5 x 250 ops/sec @ 3ms/op
sha1 x 416 ops/sec @ 2ms/op
# MAC
hmac(sha256) x 599,880 ops/sec @ 1μs/op
hmac(sha512) x 197,122 ops/sec @ 5μs/op
kmac256 x 87,981 ops/sec @ 11μs/op
blake3(key) x 796,812 ops/sec @ 1μs/op
# KDF
hkdf(sha256) x 259,942 ops/sec @ 3μs/op
blake3(context) x 424,808 ops/sec @ 2μs/op
pbkdf2(sha256, c: 2 ** 18) x 5 ops/sec @ 197ms/op
pbkdf2(sha512, c: 2 ** 18) x 1 ops/sec @ 630ms/op
scrypt(n: 2 ** 18, r: 8, p: 1) x 2 ops/sec @ 400ms/op
argon2id(t: 1, m: 256MB) 2881ms
```
该库可以通过利用循环展开快 3 倍。未使用它是因为展开 a) 会增加包大小 b) 使库不可读 c) 当前性能对于大多数用例来说“足够快”。
## 许可证
The MIT License (MIT)
Copyright (c) 2022 Paul Miller [(https://paulmillr.com)](https://paulmillr.com)
请参阅 LICENSE 文件。
标签:Argon2, BLAKE, CMS安全, DNS 反向解析, GNU通用公共许可证, HKDF, HMAC, JavaScript, KDF, MAC, MITM代理, Noble, Node.js, PBKDF2, POC验证, RIPEMD, Scrypt, SHA, StruQ, Tree-shaking, TypeScript, WebCrypto, 前端安全, 加密库, 哈希函数, 哈希算法, 安全插件, 密码学, 密钥派生, 手动系统调用, 数据可视化, 本体建模, 消息认证码, 自动化攻击, 零依赖