Skip to content
KitploitKITPLOIT
工具博客
提交
工具博客
提交

黑客、渗透测试和网络安全工具,武装您的安全武器库!

Kitploit 是一个黑客、网络安全和渗透测试工具的目录。发现最新的项目更新,查找漏洞、分析系统、自动化测试并加强你的安全。

··订阅源·联系·隐私·© 2026 Kitploit

工具目录

分类

查看所有分类
Loading categories
noble-curves — 经过审计且极简的椭圆曲线密码学 JS 实现。 | Kitploit
工具/GitHubGitHub/paulmillr/noble-curves
加密/解密工具哈希分析密码学实用工具与框架学习与教育
GitHubpaulmillr/noble-curves

noble-curves

经过审计且极简的椭圆曲线密码学 JS 实现。

查看仓库
95810187天前Kitploit 审核通过

最受欢迎

查看全部 →

发现我们社区最常用的工具。

探索所有工具

浏览我们的工具集合

查看所有工具 →
分享
网站

noble-curves

经过审计且极简的椭圆曲线密码学 JS 实现。

  • 🔒 由独立安全公司审计
  • 🪶 极简:secp256k1 仅 15KB(gzip 压缩后),未使用的代码会从你的构建中排除
  • 🏎 快速:针对 JS 引擎的特性手工优化
  • 🔍 可靠:跨库 / wycheproof 测试确保正确性
  • ➰ Weierstrass、Edwards 曲线;ECDSA、EdDSA、Schnorr、BLS 签名
  • ✍️ ECDH、hash-to-curve、OPRF、FROST、Poseidon 哈希、FFT
  • 🔖 ed25519、ed448 中的不可否认性(SUF-CMA、SBS)与共识友好性(ZIP215)
  • 🥈 基于原生 WebCrypto 的相同 API 封装

曲线有 5kb 的姊妹项目 secp256k1 和 ed25519。 它们攻击面更小,但功能也更少。

本库属于 noble 密码学

noble cryptography — 高安全性、易于审计的独立密码学库与工具集。

  • 零依赖或极少依赖
  • 高度可读的 TypeScript / JS 代码
  • PGP 签名的发布版本与透明的 NPM 构建
  • 所有库: ciphers、 curves、 hashes、 post-quantum、 5kb secp256k1 / ed25519
  • WASM 版本:awasm-noble
  • 查看主页 获取阅读资源、文档以及使用 noble 构建的应用

用法

npm install @noble/curves

deno add jsr:@noble/curves

我们支持所有主流平台和运行时。 对于 React Native,你可能需要 getRandomValues 的 polyfill。 也提供独立文件 noble-curves.js。```js // import * from '@noble/curves'; // Error: use sub-imports, to ensure small app size import { secp256k1 } from '@noble/curves/secp256k1.js'; const { secretKey, publicKey } = secp256k1.keygen(); const msg = new TextEncoder().encode('hello noble'); const sig = secp256k1.sign(msg, secretKey); const isValid = secp256k1.verify(sig, msg, publicKey);

root@kitploit:~
- [ECDSA、EdDSA、Schnorr 签名](#ecdsa-eddsa-schnorr-signatures)
- [ECDH:Diffie-Hellman 共享密钥](#ecdh-diffie-hellman-shared-secrets)
- [webcrypto:友好封装](#webcrypto-friendly-wrapper)
- [BLS 签名、bls12-381、bn254 又名 alt\_bn128](#bls-signatures-bls12-381-bn254-aka-alt_bn128)
- [hash-to-curve:哈希到曲线点](#hash-to-curve-hashing-to-curve-points)
- [OPRF](#oprfs) | [FROST 门限签名](#frost-threshold-signatures)
- [poseidon:Poseidon 哈希](#poseidon-poseidon-hash) | [fft:快速傅里叶变换](#fft-fast-fourier-transform) | [utils](#utils-byte-shuffling-conversion)
- 内部实现:[点运算](#elliptic-curve-point-math) | [模运算](#modular-modular-arithmetics--finite-fields) | [自定义曲线](#weierstrass-custom-weierstrass-curve--ecdsa)
- [规范](#specs)
- [安全性](#security) | [速度](#speed) | [升级](#upgrading) | [贡献与测试](#contributing--testing) | [许可证](#license)

### ECDSA、EdDSA、Schnorr 签名

#### secp256k1、p256、p384、p521、ed25519、ed448、brainpool```js
import { secp256k1, schnorr } from '@noble/curves/secp256k1.js';
import { p256, p384, p521 } from '@noble/curves/nist.js';
import { ed25519 } from '@noble/curves/ed25519.js';
import { ed448 } from '@noble/curves/ed448.js';
import { brainpoolP256r1, brainpoolP384r1, brainpoolP512r1 } from '@noble/curves/misc.js';
for (const curve of [
  secp256k1, schnorr,
  p256, p384, p521,
  ed25519, ed448,
  brainpoolP256r1, brainpoolP384r1, brainpoolP512r1
]) {
  const { secretKey, publicKey } = curve.keygen();
  const msg = new TextEncoder().encode('hello noble');
  const sig = curve.sign(msg, secretKey);
  const isValid = curve.verify(sig, msg, publicKey);
  console.log(curve, secretKey, publicKey, sig, isValid);
}

// Specific private key
import { hexToBytes } from '@noble/curves/utils.js';
const secret2 = hexToBytes('46c930bc7bb4db7f55da20798697421b98c4175a52c630294d75a84b9c126236');
const pub2 = secp256k1.getPublicKey(secret2);

消息始终先进行哈希:参见预哈希签名。 ECDSA 使用确定性 k,EdDSA 遵循 RFC 8032,Schnorr(仅限 secp256k1)遵循 BIP 340:参见规范。

MuSig2 签名方案以及用于 secp256k1 的 BIP324 ElligatorSwift 映射 可在单独的包中获取。

ristretto255, decaf448```ts

import { ristretto255, ristretto255_hasher, ristretto255_oprf } from '@noble/curves/ed25519.js'; import { decaf448, decaf448_hasher, decaf448_oprf } from '@noble/curves/ed448.js';

console.log(ristretto255.Point, decaf448.Point);

root@kitploit:~
查看 [RFC 9496](https://www.rfc-editor.org/rfc/rfc9496) 以获取有关 ristretto255 和 decaf448 的更多信息。
查看关于 [Point](#elliptic-curve-point-math)、[hasher](#hash-to-curve-hashing-to-curve-points) 和 [oprf](#oprfs) 的单独文档。

#### 预哈希签名```js
import { secp256k1 } from '@noble/curves/secp256k1.js';
import { keccak_256 } from '@noble/hashes/sha3.js';
const { secretKey } = secp256k1.keygen();
const msg = new TextEncoder().encode('hello noble');
// prehash: true (default) - hash using secp256k1.hash (sha256)
const sig = secp256k1.sign(msg, secretKey);
// prehash: false - hash using custom hash
const sigKeccak = secp256k1.sign(keccak_256(msg), secretKey, { prehash: false });

默认情况下(prehash: true),sign() 和 verify() 会先对消息应用曲线内置的哈希: secp256k1 使用 sha256,p521 使用 sha512。prehash: false 允许使用自定义哈希 (例如 secp256k1 + keccak_256)。在 noble-curves v1 中,prehash: false 是默认值。

从签名中恢复公钥```js

import { secp256k1 } from '@noble/curves/secp256k1.js'; const { secretKey, publicKey } = secp256k1.keygen(); const msg = new TextEncoder().encode('hello noble'); const sigRec = secp256k1.sign(msg, secretKey, { format: 'recovered' }); const publicKey_ = secp256k1.recoverPublicKey(sigRec, msg); // == publicKey

// recovered sig is compact sig with an extra byte const sigNoRec = secp256k1.sign(msg, secretKey, { format: 'compact' }); // sigNoRec == sigRec.slice(1)

// Signature instance const sigInstance = secp256k1.Signature.fromBytes(sigRec, 'recovered');

root@kitploit:~
公钥恢复仅支持 ECDSA。这是一个简单的数学运算:
无法保证签名确实已完成。伪造的 (r, s, h) 会恢复出一个
随机公钥,但要找到能导致这个特定伪造 h 的 m 是不可行的。

#### 带噪声的对冲 ECDSA```js
import { secp256k1 } from '@noble/curves/secp256k1.js';
const { secretKey } = secp256k1.keygen();
const msg = new TextEncoder().encode('hello noble');
// extraEntropy: false - default, hedging disabled
const sigNoisy = secp256k1.sign(msg, secretKey);
// extraEntropy: true - fetch 32 random bytes from CSPRNG
const sigNoisyA = secp256k1.sign(msg, secretKey, { extraEntropy: true });
// extraEntropy: bytes - specific extra entropy
const ent = Uint8Array.from([0xca, 0xfe, 0x01, 0x23]);
const sigNoisy2 = secp256k1.sign(msg, secretKey, { extraEntropy: ent });

默认情况下,ECDSA 签名是确定性的(RFC 6979)。纯确定性签名容易受到故障攻击,因此较新的方案(如 BIP340 schnorr)在签名生成中引入了随机性——也称为对冲。extraEntropy 启用对冲模式。更多信息,请查看确定性签名不是你的朋友。

共识友好性与电子投票```js

import { ed25519 } from '@noble/curves/ed25519.js'; const { secretKey, publicKey } = ed25519.keygen(); const msg = new TextEncoder().encode('hello noble'); const sig = ed25519.sign(msg, secretKey); // zip215: true const isValid = ed25519.verify(sig, msg, publicKey); // SBS / e-voting / RFC8032 / FIPS 186-5 const isValidRfc = ed25519.verify(sig, msg, publicKey, { zip215: false });

root@kitploit:~
* `zip215: true`(默认)使用 [ZIP215](https://zips.z.cash/zip-0215) 中定义的更宽松、[共识友好](https://hdevalence.ca/blog/2020-10-04-its-25519am)的验证规则。
* `zip215: false` 强制执行严格的 RFC 8032 / FIPS 186-5 验证,并添加基于 SBS 的
  不可否认性,这对于合同签署、电子投票和区块链非常有用。

两种模式都具有 SUF-CMA(选择消息攻击下的强不可伪造性);
大多数其他库既没有 SUF-CMA 也没有 SBS。
更多信息请参见 [Taming the many EdDSAs](https://eprint.iacr.org/2020/1244)。

### ECDH:Diffie-Hellman 共享密钥```js
import { x25519 } from '@noble/curves/ed25519.js';
const alice = x25519.keygen();
const bob = x25519.keygen();
const sharedKey = x25519.getSharedSecret(alice.secretKey, bob.publicKey);
// Same API: secp256k1, p256, p384, p521, x448

// converting ed25519 keys to x25519
import { ed25519 } from '@noble/curves/ed25519.js';
const alice2 = ed25519.keygen();
const bob2 = ed25519.keygen();
const aliceSecX = ed25519.utils.toMontgomerySecret(alice2.secretKey);
const bobPubX = ed25519.utils.toMontgomery(bob2.publicKey);
const sharedKey2 = x25519.getSharedSecret(aliceSecX, bobPubX);

我们为所有 Weierstrass 曲线以及 2 条 Montgomery 曲线 X25519(Curve25519)和 X448(Curve448)提供 ECDH,符合 RFC 7748。

在 Weierstrass 曲线中,共享密钥:

  • 包含 y 奇偶校验字节:使用 key.slice(1) 将其剥离
  • 不进行哈希:在其上使用哈希或 KDF,例如 sha256(shared) 或 hkdf(shared)

webcrypto:友好的封装```js

import { ed25519, x25519 } from '@noble/curves/webcrypto.js';

// signatures: p256, p384, p521, ed25519, ed448 const keys = await ed25519.keygen(); const msg = new TextEncoder().encode('hello noble'); const sig = await ed25519.sign(msg, keys.secretKey); const isValid = await ed25519.verify(sig, msg, keys.publicKey);

// ECDH: p256, p384, p521, x25519, x448 const alice = await x25519.keygen(); const bob = await x25519.keygen(); const shared = await x25519.getSharedSecret(alice.secretKey, bob.publicKey);

// key conversion between noble (raw) and webcrypto (pkcs8 / spki) formats import { p256 as p256n } from '@noble/curves/nist.js'; import { p256 } from '@noble/curves/webcrypto.js'; const nobleKeys = p256n.keygen(); const secretKeyPkcs8 = await p256.utils.convertSecretKey(nobleKeys.secretKey, 'raw', 'pkcs8'); const publicKeySpki = await p256.utils.convertPublicKey(nobleKeys.publicKey, 'raw', 'spki');

root@kitploit:~
一个对内置 WebCrypto 的轻量封装,镜像 noble API。方法始终为异步;
运行时支持情况各异——使用 `await curve.isSupported()` 进行检查。
查看 [micro-key-producer](https://github.com/paulmillr/micro-key-producer) 获取
纯 JS 密钥转换工具。

### BLS 签名、bls12-381、bn254 又名 alt_bn128```ts
import { bls12_381 } from '@noble/curves/bls12-381.js';

// G1 pubkeys, G2 sigs
const blsl = bls12_381.longSignatures;
const { secretKey, publicKey } = blsl.keygen();
const msg = new TextEncoder().encode('hello noble');
const msgp = blsl.hash(msg); // hash to point, default DST
const msgpd = blsl.hash(msg, 'BLS_SIG_BLS12381G2_XMD:SHA-256_SSWU_RO_POP_'); // custom DST (Ethereum)
const signature = blsl.sign(msgp, secretKey);
const isValid = blsl.verify(signature, msgp, publicKey);

// G1 sigs, G2 pubkeys: identical API
const blss = bls12_381.shortSignatures;

// Aggregation
const aggregatedKey = blsl.aggregatePublicKeys([
  blsl.getPublicKey(bls12_381.utils.randomSecretKey()),
  blsl.getPublicKey(bls12_381.utils.randomSecretKey()),
]);
// const aggregatedSig = blsl.aggregateSignatures(sigs)

// Pairings: bls12_381.pairing(PointG1, PointG2)
// Fields: bls12_381.fields.Fp, Fp2, Fp12, Fr

例如用法,请查看 BLS EVM 预编译的实现。

BN254 API 与 bls12-381 类似。该曲线之前被称为 alt_bn128。 该实现兼容 EIP-196 和 EIP-197: 请查看 bn254 EVM 预编译的实现。 bn254 点不实现 toBytes,因为没有序列化标准: 不同实现在字节序、标志和 G2 虚部顺序上存在分歧。 请改为从 bigint 初始化点。

hash-to-curve:哈希到曲线点```ts

import { secp256k1_hasher } from '@noble/curves/secp256k1.js';

const msg = Uint8Array.from([0xca, 0xfe, 0x01, 0x23]); const point = secp256k1_hasher.hashToCurve(msg); const pointDst = secp256k1_hasher.hashToCurve(msg, { DST: 'hello noble' }); const pointNu = secp256k1_hasher.encodeToCurve(msg); const scalar = secp256k1_hasher.hashToScalar(msg);

// Same API: p256_hasher, p384_hasher, p521_hasher (nist.js), // ed25519_hasher, ristretto255_hasher (ed25519.js), ed448_hasher, decaf448_hasher (ed448.js), // bls12_381.G1, bls12_381.G2. // ristretto255 & decaf448 also provide deriveToCurve.

// abstract methods import { expand_message_xmd, expand_message_xof, hash_to_field } from '@noble/curves/abstract/hash-to-curve.js';

root@kitploit:~
该模块允许将任意字符串哈希到椭圆曲线点。实现了 [RFC 9380](https://www.rfc-editor.org/rfc/rfc9380)。
`_hasher` 命名空间与曲线分离,以便进行 tree-shaking:
不需要 hash-to-curve 的用户不会在构建中包含它。

### OPRFs```js
import { p256_oprf, p384_oprf, p521_oprf } from '@noble/curves/nist.js';
import { ristretto255_oprf } from '@noble/curves/ed25519.js';
import { decaf448_oprf } from '@noble/curves/ed448.js';

我们提供符合 RFC 9497 的 OPRF(不经意伪随机函数)。

OPRF 允许交互式地创建 Output = PRF(Input, serverSecretKey):

  • 服务器无法自行计算 Output:它不知道 Input
  • 客户端无法自行计算 Output:它不知道 server secretKey
  • 截获通信的攻击者无法恢复 Input/Output/serverSecretKey,也无法将 Input 关联到某个值。

FROST 门限签名

FROST 实现了 RFC 9591 门限 Schnorr 签名。 从应用角度看,它类似于多重签名:max 个参与者中的任意 min 个可以共同在共享公钥下生成一个 Schnorr 签名。 支持的密码套件有 p256_FROST、ed25519_FROST、ed448_FROST、ristretto255_FROST、secp256k1_FROST 和 schnorr_FROST(兼容 Taproot 的 secp256k1)。 签名分为两轮:选定的签名者先提交承诺,然后生成签名份额。```js import { p256_FROST } from '@noble/curves/nist.js';

const signers = { min: 2, max: 3 }; const alice = p256_FROST.Identifier.derive('[email protected]'); const bob = p256_FROST.Identifier.derive('[email protected]'); const carol = p256_FROST.Identifier.derive('[email protected]'); // trusted dealer const deal = p256_FROST.trustedDealer(signers, [alice, bob, carol]); for (const id of [alice, bob, carol]) p256_FROST.validateSecret(deal.secretShares[id], deal.public);

const msg = new TextEncoder().encode('hello threshold'); // round 1: selected signers commit const aliceRound1 = p256_FROST.commit(deal.secretShares[alice]); const bobRound1 = p256_FROST.commit(deal.secretShares[bob]); const commitmentList = [aliceRound1.commitments, bobRound1.commitments]; // round 2: signers produce signature shares const sigShares = { [alice]: https://raw.githubusercontent.com/paulmillr/noble-curves/main/p256_FROST.signShare( deal.secretShares[alice], deal.public, aliceRound1.nonces, commitmentList, msg ), [bob]: https://raw.githubusercontent.com/paulmillr/noble-curves/main/p256_FROST.signShare( deal.secretShares[bob], deal.public, bobRound1.nonces, commitmentList, msg ), }; const sig = p256_FROST.aggregate(deal.public, commitmentList, msg, sigShares); const isValid = p256_FROST.verify(sig, msg, deal.public.commitments[0]);

root@kitploit:~
密钥生成可以通过可信经销商(如上所述)或使用 DKG(分布式密钥生成)来完成。
DKG 有三个轮次:参与者对密钥生成进行承诺,交换私有份额,
然后推导出最终的参与者密钥——参见
[测试](https://github.com/paulmillr/noble-curves/blob/main/test/rfc9591-frost.test.ts) 中 `DKG.round1` / `round2` / `round3` 的用法。
该库实现的是密码学步骤,而非外围的应用协议:
调用方仍然需要经过身份验证的通信、协调、重试、会话处理以及策略。

### poseidon:Poseidon 哈希

实现了 [Poseidon](https://www.poseidon-hash.info) 这一对 ZK 友好的哈希:
置换和海绵结构。

存在许多具有不同常量的 poseidon 变体。
我们不提供它们:你应该手动构造它们。
请查看 [scure-starknet](https://github.com/paulmillr/scure-starknet) 包以获取一个合适的示例。```ts
import { bn254 } from '@noble/curves/bn254.js';
import { grainGenConstants, poseidon, poseidonSponge } from '@noble/curves/abstract/poseidon.js';

const rate = 2;
const capacity = 1;
const Fp = bn254.fields.Fr;
const { mds, roundConstants } = grainGenConstants({
  Fp,
  t: rate + capacity,
  roundsFull: 8,
  roundsPartial: 31,
});
const opts = {
  Fp,
  rate,
  capacity,
  sboxPower: 17,
  mds,
  roundConstants,
  roundsFull: 8,
  roundsPartial: 31,
};
const permutation = poseidon({ ...opts, t: rate + capacity });
const sponge = poseidonSponge(opts); // use carefully, not specced

fft:快速傅里叶变换```ts

import * as fft from '@noble/curves/abstract/fft.js'; import { bls12_381 } from '@noble/curves/bls12-381.js'; const Fr = bls12_381.fields.Fr; const roots = fft.rootsOfUnity(Fr, 7n); const fftFr = fft.FFT(roots, Fr);

root@kitploit:~
有限域上的 NTT / FFT(快速傅里叶变换)。

### utils:字节混洗、转换```ts
import { bytesToHex, concatBytes, equalBytes, hexToBytes } from '@noble/curves/utils.js';

bytesToHex(Uint8Array.from([0xca, 0xfe, 0x01, 0x23]));
hexToBytes('cafe0123');
concatBytes(Uint8Array.from([0xca, 0xfe]), Uint8Array.from([0x01, 0x23]));
equalBytes(Uint8Array.of(0xca), Uint8Array.of(0xca));

内部机制

椭圆曲线点运算```js

import { secp256k1 } from '@noble/curves/secp256k1.js'; const { Point } = secp256k1; const { BASE, ZERO, Fp, Fn } = Point; const p = BASE.multiply(2n);

// Math const p1 = p.add(p); const p2 = p.double(); const p3 = p.subtract(p); const p4 = p.negate(); const p5 = p.multiply(451n);

// MSM (multi-scalar multiplication) import { pippenger } from '@noble/curves/abstract/curve.js'; const pa = [BASE, BASE.multiply(2n), BASE.multiply(4n), BASE.multiply(8n)]; const p6 = pippenger(Point, pa, [3n, 5n, 7n, 11n]); // == BASE.multiply(129n)

// Cofactor const pcl = p.clearCofactor(); const isTorsionFree = p.isTorsionFree();

// Conversions const bytes = p.toBytes(); const p_ = Point.fromBytes(bytes); const { x, y } = p.toAffine(); const p__ = Point.fromAffine({ x, y });

root@kitploit:~
每条曲线都暴露其 Point 类:secp256k1、schnorr、p256、p384、p521、ed25519、ed448、
ristretto255、decaf448、bls12_381.G1 / G2、bn254.G1、jubjub、babyjubjub。
Weierstrass 点使用射影(齐次)坐标 `new Point(X, Y, Z)`,
edwards 点使用扩展坐标 `new Point(X, Y, Z, T)`;两者均满足 x=X/Z, y=Y/Z。

#### modular:模运算与有限域```js
import { mod, invert, Field } from '@noble/curves/abstract/modular.js';

// Finite Field utils
const fp = Field(2n ** 255n - 19n); // Finite field over 2^255-19
fp.mul(591n, 932n); // multiplication
fp.pow(481n, 11024858120n); // exponentiation
fp.div(5n, 17n); // division: 5/17 mod 2^255-19 == 5 * invert(17)
fp.inv(5n); // modular inverse
fp.sqrt(4n); // square root

// Non-Field generic utils are also available
mod(21n, 10n); // 21 mod 10 == 1n; fixed version of 21 % 10
invert(17n, 10n); // invert(17) mod 10; modular multiplicative inverse

所有算术运算均基于有限域上的 JS bigints 进行, 该有限域由 modular 子模块定义。

域运算并非恒定时间:参见安全性。 这一事实大多无关紧要,但需要牢记的重要方法是 pow, 在朴素使用时,它可能会泄露指数位。

weierstrass:自定义 Weierstrass 曲线与 ECDSA```js

import { weierstrass, ecdsa } from '@noble/curves/abstract/weierstrass.js'; import { sha256 } from '@noble/hashes/sha2.js'; // NIST secp192r1 aka p192. https://www.secg.org/sec2-v2.pdf const p192_CURVE = { p: 0xfffffffffffffffffffffffffffffffeffffffffffffffffn, n: 0xffffffffffffffffffffffff99def836146bc9b1b4d22831n, h: 1n, a: 0xfffffffffffffffffffffffffffffffefffffffffffffffcn, b: 0x64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1n, Gx: 0x188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012n, Gy: 0x07192b95ffc8da78631011ed6b24cdd573f977a11e794811n, }; const p192_Point = weierstrass(p192_CURVE); const p192 = ecdsa(p192_Point, sha256);

const keys = p192.keygen(); const msg = new TextEncoder().encode('custom curve'); const sig = p192.sign(msg, keys.secretKey); const isValid = p192.verify(sig, msg, keys.publicKey);

root@kitploit:~
Short Weierstrass 曲线的公式为 `y² = x³ + ax + b`。`weierstrass`
期望参数 `a`、`b`、域特征 `p`、曲线阶 `n`、
余因子 `h` 以及生成点的坐标 `Gx`、`Gy`,并返回一个 Point 类。
`ecdsa` 将 Point 类与哈希函数结合成一个签名方案。

#### edwards:自定义 Edwards 曲线```js
import { edwards } from '@noble/curves/abstract/edwards.js';
const ed25519_CURVE = {
  p: 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffedn,
  n: 0x1000000000000000000000000000000014def9dea2f79cd65812631a5cf5d3edn,
  h: 8n,
  a: 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffecn,
  d: 0x52036cee2b6ffe738cc740797779e89800700a4d4141d8ab75eb4dca135978a3n,
  Gx: 0x216936d3cd6e53fec0a4e231fdd6dc5c692cc7609525a7b2c9562d608f25d51an,
  Gy: 0x6666666666666666666666666666666666666666666666666666666666666658n,
};
const ed25519_Point = edwards(ed25519_CURVE);

Twisted Edwards 曲线的公式为 ax² + y² = 1 + dx²y²。 你必须指定 a、d、域特征 p、曲线阶 n(有时称为 L)、 余因子 h 以及生成元点的坐标 Gx、Gy。

规格

  • ECDSA:确定性 k 来自 RFC 6979, 对冲签名来自 cfrg-det-sigs-with-noise 草案
  • EdDSA:RFC 8032、 FIPS 186-5; 共识友好验证:ZIP215
  • Schnorr 签名:BIP 340
  • X25519、X448 ECDH:RFC 7748
  • ristretto255、decaf448:RFC 9496
  • hash-to-curve:RFC 9380
  • OPRF:RFC 9497
  • FROST:RFC 9591
  • bn254:EIP-196、EIP-197
  • Poseidon:网站

安全性

该库已经过审计:

  • 在 2.3.0 版本,2026 年 8 月,由 Trail of Bits 与 OpenAI 合作进行
    • 该审计是在 "Patch the Planet" 倡议期间完成的
    • 范围:全部内容
  • 在 1.6.0 版本,2024 年 9 月,由 Cure53 独立进行
    • PDF:网站、仓库内
    • 范围:ed25519、ed448 及其附加组件、bls12-381、bn254、 hash-to-curve、底层原语 bls、tower、edwards、montgomery。
    • 该审计由 OpenSats 资助
  • 在 1.2.0 版本,2023 年 9 月,由 Kudelski Security 独立进行
    • PDF:仓库内
    • 范围:scure-starknet 及其相关的 noble-curves 抽象模块:curve、modular、poseidon、weierstrass
    • 该审计由 Starkware 资助
  • 在 0.7.3 版本,2023 年 2 月,由 Trail of Bits 独立进行
    • PDF:网站、 仓库内
    • 范围:抽象模块 curve、hash-to-curve、、、、 以及 顶层模块 和

我们已于 2026 年 4 月开始定期进行 AI 辅助的自审计。

它已针对基于属性的、跨库的和 Wycheproof 向量进行了测试, 并正在 GitHub CI 中进行模糊测试。

如果你发现任何异常:请调查并报告。

常量时间性

我们的目标是算法层面的常量时间。JIT 编译器 和 垃圾回收器 使得在脚本语言中 极难实现时序攻击抗性。 这意味着 任何其他 JS 库都无法具备常量时间性。即使是静态类型、没有 GC 的 Rust, 在某些情况下也更难实现常量时间。 如果你的目标是绝对安全,请不要使用任何 JS 库——包括对原生库的绑定。 请使用底层库和语言。

在这些限制内,秘密标量乘法提供了具体、可测量的特性:

  • 固定操作序列: multiply() 使用带符号固定窗口表, 并进行数据无关的表扫描——点操作的数量和顺序 与标量值无关。
  • 标量盲化: 秘密标量在乘法前还会额外用随机 128 位 r 掩码为 s + r·n。这适用于余因子为 1 的曲线 (p256、p384、p521、secp256k1)上的所有乘法,以及所有地方的基点乘法。
  • 统计验证: 一个 dudect 风格的 Welch t 检验工具(benchmark/ct.ts) 比较对抗性标量类别(稀疏 vs 密集、低位 vs 高位、 接近阶、位模式)之间的时序。基点乘法在任何曲线上 都没有显示出可区分的时序,随机点乘法在 Weierstrass 曲线上 也没有显示出可区分的时序(1000 个样本时最大 |t| ≤ 2.8;阈值为 4.5)。

已知限制:在带余因子的 Edwards 曲线(ed25519、ed448)上,将非基点 点与秘密标量相乘时没有进行盲化。同一工具可以可靠地检测到这一点。EdDSA 签名 不受影响(它只乘以经过盲化的基点),而 X25519/X448 使用单独的 Montgomery 阶梯实现(同样不受影响)。这对于那些将任意 Edwards/Ristretto 点与长期存活的秘密标量相乘的协议很重要;在那里应优先使用 按构造即为全宽的标量。请注意,在孤立工具中的可检测性并不 意味着实际可利用性:我们在现实的 跨租户 / 浏览器内环境中尝试提取标量,即使使用 100,000 个时序样本, 也无法恢复 Edwards 标量。

内存转储

如果你的目标是绝对安全,请使用底层语言而不是 JS / WASM。

该库主要使用 Uint8Array 和 bigint。

  • Uint8Array 有 .fill(0),它会指示将内容填充为零, 但在 JS 中没有保证
  • bigint 是不可变的,并且没有方法将其内容清零: 用户需要等到下一个垃圾回收周期
  • 十六进制字符串也是不可变的:无法将它们清零
  • await fn() 会将所有内部变量写入内存。对于 异步函数,无法保证代码块何时 被执行。这意味着攻击者可以有 充足的时间从内存中读取数据。

这意味着某些秘密可能会比预期更久地留在内存中。 然而,如果攻击者能够读取应用程序内存,那无论如何都完了: 如果不使用复杂的测试套件来转储进程内存并验证 没有敏感数据残留,就无法保证任何关于清零敏感数据的事情。 对于 JS 来说,这意味着要测试所有浏览器(包括移动端)。 当然,如果不在实际使用该库的应用程序中使用相同的 测试套件,那也将毫无用处。

供应链安全

  • 提交使用 PGP 密钥签名以防止伪造。请务必验证提交签名
  • 发布通过无令牌 GitHub CI 和 Trusted Publishing 透明地进行。请务必验证来源日志的真实性。
  • 低频发布被采用,以尽量减少最终用户重新审计的需要。
  • 依赖被最小化并严格固定,以降低供应链风险。
    • 我们尽可能少地使用依赖。
    • 版本范围被锁定,变更通过 npm-diff 检查。
  • 开发依赖不包含在最终用户安装中;它们仅用于开发和构建步骤。

对于此包,有 1 个依赖;以及少量开发依赖:

  • noble-hashes 提供加密哈希功能
  • jsbt 用于基准测试 / 测试 / 构建工具,由同一作者开发
  • prettier、fast-check 和 typescript 用于代码质量 / 测试生成 / TS 编译

随机性

我们依赖内置的 crypto.getRandomValues, 它被认为是加密安全的 PRNG。

浏览器过去曾有过弱点——将来可能还会——但实现用户空间 CSPRNG 更糟,因为不存在可靠的用户空间高质量熵源。

量子计算机

与密码学相关的量子计算机如果被建造出来,将能够 使用 Shor 算法破解椭圆曲线密码学(ECDSA / EdDSA 和 ECDH)。

考虑切换到更新 / 混合算法,例如 SPHINCS+。它们可在 noble-post-quantum 中获得。

NIST 禁止经典密码学(RSA、DSA、ECDSA、ECDH)在 2035 年之后。澳大利亚 ASD 禁止其在 2030 年之后。

速度```sh

npm run benchmark

root@kitploit:~
noble-curves 需要花费 10 毫秒以上来生成 20MB 以上的基点预计算数据。
此操作对每条曲线**仅执行一次**。

生成过程会延迟到任何方法(pubkey、sign、verify)被调用时才进行。
用户可以通过手动调用 `Point.BASE.precompute(windowSize, false)` 来强制生成预计算数据。
请查看源代码。

在 Apple M4 上的基准测试结果:```
# algorithm=getPublicKey
ed25519                    7,299 ops/sec · 137 μs/op
secp256k1                  4,872 ops/sec · 205 μs/op · -1.5x
p256                       4,724 ops/sec · 212 μs/op · -1.5x
bls12_381 (long, G2 sig)   3,466 ops/sec · 288 μs/op · -2.1x
ed448                      3,224 ops/sec · 310 μs/op · -2.3x
p384                       2,185 ops/sec · 458 μs/op · -3.3x
p521                       1,221 ops/sec · 819 μs/op · -6x
bls12_381 (short, G1 sig)  1,070 ops/sec · 934 μs/op · -6.8x

# algorithm=sign
secp256k1                  4,217 ops/sec · 237 μs/op
p256                       4,116 ops/sec · 243 μs/op · ≈
ed25519                    3,536 ops/sec · 283 μs/op · -1.2x
p384                       1,992 ops/sec · 502 μs/op · -2.1x
ed448                      1,577 ops/sec · 634 μs/op · -2.7x
p521                       1,131 ops/sec · 884 μs/op · -3.7x
bls12_381 (short, G1 sig)  417 ops/sec · 2.39 ms/op · -10x
bls12_381 (long, G2 sig)   112 ops/sec · 8.88 ms/op · -37x

# algorithm=verify
ed25519                    1,504 ops/sec · 665 μs/op
secp256k1                  1,352 ops/sec · 739 μs/op · -1.1x
p256                       917 ops/sec · 1.09 ms/op · -1.6x
ed448                      546 ops/sec · 1.83 ms/op · -2.8x
p384                       381 ops/sec · 2.62 ms/op · -3.9x
p521                       187 ops/sec · 5.34 ms/op · -8x
bls12_381 (short, G1 sig)  100 ops/sec · 9.98 ms/op · -15x
bls12_381 (long, G2 sig)   77 ops/sec · 12.9 ms/op · -19x

# algorithm=getSharedSecret
ed25519                    1,695 ops/sec · 590 μs/op
secp256k1                  763 ops/sec · 1.31 ms/op · -2.2x
p256                       737 ops/sec · 1.36 ms/op · -2.3x
ed448                      599 ops/sec · 1.67 ms/op · -2.8x
p384                       326 ops/sec · 3.06 ms/op · -5.2x
p521                       176 ops/sec · 5.68 ms/op · -9.6x

升级

支持的 node.js 版本:

  • v2 (2025-08):v20.19+(仅 ESM)
  • v1 (2023-04):v14.21+(ESM 与 CJS)

v1 到 v2

v2 大幅简化了内部实现,提升了安全性,减小了打包体积,并为未来铺平了道路。 我们尽可能保持 v2 向后兼容。

升级路径: 先升级到 curves v1.9.x。修复弃用警告,然后切换到 v2。

模块:

  • 该包现在仅支持 ESM。在 node v20.19+ 上,ESM 终于可以从 common.js 中加载
  • 现在需要 .js 扩展名:@noble/curves/ed25519 => @noble/curves/ed25519.js。 这使得无需转译器即可在浏览器中原生使用
  • p256、p384、p521 已移至 nist;jubjub 已移至 misc
  • pasta 和 bn254_weierstrass(非基于配对的 bn254)曲线已被移除

新特性:

  • webcrypto:对内置 WebCrypto 的友好 noble 风格封装
  • oprf:RFC 9497 OPRF(不经意伪随机函数) 支持 p256、p384、p521、ristretto255 和 decaf448
  • weierstrass、edwards:新增 isValidSecretKey、isValidPublicKey 方法
  • misc:Brainpool 曲线 brainpoolP256r1、brainpoolP384r1、brainpoolP512r1
  • 大幅改进、更具描述性的错误消息

破坏性变更:

  • 大多数方法现在只接受 Uint8Array;禁止使用字符串十六进制输入。 这简化了推理,提升了安全性并减少了可延展性。 Point.fromHex 现在仅接受字符串:对于 Uint8Array 请使用 Point.fromBytes
  • ECDSA(secp256k1、p256、p384...)签名与验证:
    • 预哈希消息:方法现在期望未哈希的消息 而非 messageHash。旧行为:{prehash: false}
    • 默认使用 lowS 签名。secp256k1 不受影响:它从一开始就使用 lowS。旧行为:{lowS: false}
    • 默认使用 Uint8Array 签名(格式:'compact')
    • verify:必须显式指定 der 格式,即 {format: 'der'}。 这减少了可延展性
    • verify:禁止使用 Signature 实例:请先调用 signature.toBytes()
  • BLS 签名(bls12-381、bn254):
    • getPublicKey、sign、verify、signShortSignature 等已移至两个新命名空间: longSignatures(G1 公钥,G2 签名)和 shortSignatures(G1 签名,G2 公钥)
    • verifyBatch 现在期望输入数组 {message: ..., publicKey: ...}[]
  • 自定义曲线:
    • 曲线创建已大幅简化,并拆分为点创建与 签名生成器创建:weierstrass() + ecdsa() / edwards() + eddsa()。 weierstrass / edwards 期望简化的曲线参数(Fp 变为 p); ecdsa / eddsa 期望 Point 类和哈希

重命名(curves v1.9 将旧名称标记为已弃用):

  • 点
    • ExtendedPoint、ProjectivePoint => Point
    • 点坐标 px/ex、py/ey、pz/ez、et => X、Y、Z、T
    • toRawBytes、fromRawBytes => toBytes、fromBytes
    • Point.normalizeZ、Point.msm => abstract/curve.js 子模块中的独立方法
    • Point.fromPrivateKey(key) => Point.BASE.multiply(Point.Fn.fromBytes(key))
    • 包含各种随机内容的 CURVE 属性 => Point.CURVE(), 仅提供曲线参数
    • RistrettoPoint => ristretto255.Point,DecafPoint => decaf448.Point
  • ECDSA 签名
    • toCompactRawBytes、toDERRawBytes => toBytes('compact')、toBytes('der')
    • toCompactHex、toDERHex => toHex('compact')、toHex('der')
    • fromCompact、fromDER => fromBytes(bytes, format)、fromHex(hex, format)
  • utils
    • randomPrivateKey => randomSecretKey
    • normPrivateKeyToScalar => Point.Fn.fromBytes
    • utils.precompute、Point#_setWindowSize => Point#precompute
    • edwardsToMontgomery、edwardsToMontgomeryPriv => utils.toMontgomery、utils.toMontgomerySecret
  • 曲线特定的 hash-to-curve 方法 => *curve*_hasher。 例如:secp256k1.hashToCurve => secp256k1_hasher.hashToCurve()
  • 大量类型重命名与改进

已移除的特性:Point#multiplyAndAddUnsafe、Point#hasEvenY、Field.MASK

贡献与测试

npm install && npm run build && npm test 将构建代码并运行测试。

还有额外的测试套件:慢速大标量 / 大曲线测试 npm run test:slow, 以及常量时间测试框架 npm run benchmark:ct。

有关该库的有用资源、文章、文档和演示,请参见 paulmillr.com/noble。

许可证

MIT 许可证(MIT)

版权所有 (c) 2022 Paul Miller (https://paulmillr.com)

参见 LICENSE 文件。

下载工具
modular
poseidon
utils
weierstrass
_shortw_utils
secp256k1
  • 该审计由 Ryan Shea 资助
  • pippenger:移除了不必要的 Fn 参数
  • Field#fromBytes() 现在验证元素是否在 0..order-1 范围内