
Auditierte & minimale JS-Implementierung der Elliptische-Kurven-Kryptographie.
Geprüfte & minimale JS-Implementierung der Kryptographie elliptischer Kurven.
Kurven haben 5kb-Schwesterprojekte secp256k1 & ed25519. Sie haben eine kleinere Angriffsfläche, aber weniger Funktionen.
noble cryptography — hochsichere, leicht prüfbare Sammlung überschaubarer Kryptographie-Bibliotheken und -Werkzeuge.
npm install @noble/curves
deno add jsr:@noble/curves
Wir unterstützen alle wichtigen Plattformen und Runtimes. Für React Native benötigst du möglicherweise einen Polyfill für getRandomValues. Eine eigenständige Datei noble-curves.js ist ebenfalls verfügbar.```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);
- [ECDSA-, EdDSA-, Schnorr-Signaturen](#ecdsa-eddsa-schnorr-signatures)
- [ECDH: Diffie-Hellman-Shared-Secrets](#ecdh-diffie-hellman-shared-secrets)
- [webcrypto: benutzerfreundlicher Wrapper](#webcrypto-friendly-wrapper)
- [BLS-Signaturen, bls12-381, bn254 aka alt\_bn128](#bls-signatures-bls12-381-bn254-aka-alt_bn128)
- [hash-to-curve: Hashing auf Kurvenpunkte](#hash-to-curve-hashing-to-curve-points)
- [OPRFs](#oprfs) | [FROST-Schwellenwert-Signaturen](#frost-threshold-signatures)
- [poseidon: Poseidon-Hash](#poseidon-poseidon-hash) | [fft: Schnelle Fourier-Transformation](#fft-fast-fourier-transform) | [utils](#utils-byte-shuffling-conversion)
- Interna: [Punktarithmetik](#elliptic-curve-point-math) | [modular](#modular-modular-arithmetics--finite-fields) | [benutzerdefinierte Kurven](#weierstrass-custom-weierstrass-curve--ecdsa)
- [Spezifikationen](#specs)
- [Sicherheit](#security) | [Geschwindigkeit](#speed) | [Upgrade](#upgrading) | [Mitwirken & Testen](#contributing--testing) | [Lizenz](#license)
### ECDSA-, EdDSA-, Schnorr-Signaturen
#### 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);
Nachrichten werden immer zuerst gehasht: siehe prehashed signing. ECDSA verwendet deterministisches k, EdDSA folgt RFC 8032, Schnorr (nur secp256k1) folgt BIP 340: siehe Specs.
MuSig2-Signaturschema und BIP324 ElligatorSwift-Mapping für secp256k1 sind in einem separaten Paket verfügbar.
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);
Sieh dir [RFC 9496](https://www.rfc-editor.org/rfc/rfc9496) an für weitere Informationen zu ristretto255 & decaf448.
Sieh dir die separate Dokumentation für [Point](#elliptic-curve-point-math), [hasher](#hash-to-curve-hashing-to-curve-points) und [oprf](#oprfs) an.
#### Vorab gehashtes Signieren```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 });
Standardmäßig (prehash: true) wenden sign() und verify() zuerst den eingebauten Hash der Kurve auf die Nachricht an:
sha256 für secp256k1, sha512 für p521. prehash: false ermöglicht die Verwendung eines benutzerdefinierten Hashs
(z. B. secp256k1 + keccak_256). In noble-curves v1 war prehash: false der Standard.
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');
Public-Key-Wiederherstellung wird nur mit ECDSA unterstützt. Es ist eine einfache mathematische Operation:
es gibt keine Garantie, dass die Signierung tatsächlich durchgeführt wurde. Ein gefälschtes (r, s, h) wird in
einen zufälligen öffentlichen Schlüssel wiederhergestellt, aber es ist nicht machbar, m zu finden, das zu diesem spezifischen gefälschten h führen würde.
#### Hedged ECDSA mit Rauschen```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 });
Standardmäßig sind ECDSA-Signaturen deterministisch (RFC 6979). Rein deterministische Signaturen sind
anfällig für Fehlerangriffe, weshalb neuere Verfahren wie BIP340 Schnorr Zufälligkeit
in die Signaturerzeugung einbeziehen – auch bekannt als Hedging. extraEntropy aktiviert den Hedged-Modus. Für weitere Informationen siehe
Deterministic signatures are not your friends.
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 });
* `zip215: true` (Standard) verwendet die permissiveren, [konsensfreundlichen](https://hdevalence.ca/blog/2020-10-04-its-25519am) Verifikationsregeln, die in [ZIP215](https://zips.z.cash/zip-0215) definiert sind.
* `zip215: false` erzwingt strikte RFC 8032 / FIPS 186-5-Verifikation und fügt SBS-basierte
Nichtabstreitbarkeit hinzu, was für Vertragsunterzeichnung, E-Voting und Blockchains nützlich ist.
Beide Modi verfügen über SUF-CMA (starke Unfälschbarkeit unter Angriffen mit gewählten Nachrichten);
die meisten anderen Bibliotheken haben weder SUF-CMA noch SBS.
Weitere Informationen finden Sie unter [Taming the many EdDSAs](https://eprint.iacr.org/2020/1244).
### ECDH: Diffie-Hellman shared secrets```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);
Wir bieten ECDH über alle Weierstraß-Kurven und über 2 Montgomery-Kurven X25519 (Curve25519) & X448 (Curve448), konform zu RFC 7748.
Bei Weierstraß-Kurven enthalten die geteilten Geheimnisse:
key.slice(1), um sie zu entfernensha256(shared) oder hkdf(shared)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');
Ein dünner Wrapper über das eingebaute WebCrypto, der die noble-API spiegelt. Methoden sind immer async;
die Laufzeitunterstützung variiert - prüfe mit `await curve.isSupported()`.
Sieh dir [micro-key-producer](https://github.com/paulmillr/micro-key-producer) für
reine JS-Schlüsselkonvertierungs-Utils an.
### BLS-Signaturen, bls12-381, bn254 aka 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
Zur Beispielverwendung sieh dir die Implementierung der BLS-EVM-Precompiles an.
Die BN254-API entspricht bls12-381. Die Kurve hieß früher alt_bn128. Die Implementierung ist kompatibel mit EIP-196 und EIP-197: sieh dir die Implementierung der bn254-EVM-Precompiles an. bn254-Punkte implementieren toBytes nicht, weil es keinen Serialisierungsstandard gibt: Implementierungen weichen bei Endianness, Flags und der Reihenfolge des Imaginärteils von G2 voneinander ab. Initialisiere Punkte stattdessen aus bigints.
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';
Das Modul ermöglicht das Hashen beliebiger Strings auf Punkte elliptischer Kurven. Implementiert [RFC 9380](https://www.rfc-editor.org/rfc/rfc9380).
`_hasher`-Namespaces sind für Tree-Shaking von den Kurven getrennt:
Nutzer, die kein Hash-to-Curve benötigen, haben es nicht in ihren Builds.
### 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';
Wir stellen OPRFs (oblivious pseudorandom functions) bereit, die RFC 9497 entsprechen.
OPRF ermöglicht die interaktive Erzeugung eines Output = PRF(Input, serverSecretKey):
FROST implementiert RFC 9591 Schwellenwert-Schnorr-Signierung.
Aus Anwendungssicht ähnelt es Multisig: Jede min von max Teilnehmern
kann gemeinsam eine Schnorr-Signatur unter einem geteilten öffentlichen Schlüssel erzeugen.
Unterstützte Ciphersuites sind p256_FROST, ed25519_FROST, ed448_FROST, ristretto255_FROST,
secp256k1_FROST und schnorr_FROST (Taproot-kompatibles secp256k1).
Die Signierung erfolgt in zwei Runden: Ausgewählte Unterzeichner committen zuerst und erzeugen dann Signaturanteile.```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]);
Die Schlüsselerzeugung kann mit einem vertrauenswürdigen Dealer (oben) oder mit DKG (distributed key generation) erfolgen.
DKG hat drei Runden: Teilnehmer verpflichten sich zur Schlüsselerzeugung, tauschen private Anteile aus,
und leiten dann die endgültigen Teilnehmerschlüssel ab - siehe `DKG.round1` / `round2` / `round3` Verwendung in
[den Tests](https://github.com/paulmillr/noble-curves/blob/main/test/rfc9591-frost.test.ts).
Die Bibliothek implementiert die kryptografischen Schritte, nicht das umgebende Anwendungsprotokoll:
Aufrufer benötigen weiterhin authentifizierte Kommunikation, Koordination, Wiederholungsversuche, Sitzungsverwaltung und Richtlinien.
### poseidon: Poseidon hash
Implementiert [Poseidon](https://www.poseidon-hash.info) ZK-freundlichen Hash:
Permutation und Sponge.
Es gibt viele Poseidon-Varianten mit unterschiedlichen Konstanten.
Wir stellen sie nicht bereit: Sie sollten sie manuell konstruieren.
Schauen Sie sich das [scure-starknet](https://github.com/paulmillr/scure-starknet) Paket für ein passendes Beispiel an.```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
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);
NTT / FFT (Fast Fourier Transform) über endlichen Körpern.
### utils: Byte-Shuffling, Konvertierung```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));
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 });
Jede Kurve stellt ihre Point-Klasse bereit: secp256k1, schnorr, p256, p384, p521, ed25519, ed448,
ristretto255, decaf448, bls12_381.G1 / G2, bn254.G1, jubjub, babyjubjub.
Weierstrass-Punkte verwenden projektive (homogene) Koordinaten `new Point(X, Y, Z)`,
Edwards-Punkte verwenden erweiterte Koordinaten `new Point(X, Y, Z, T)`; beide mit x=X/Z, y=Y/Z.
#### modular: Modulare Arithmetik & endliche Körper```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
Alle Arithmetik wird mit JS-Bigints über endlichen Körpern durchgeführt,
die aus dem modular-Submodul definiert werden.
Körperoperationen sind nicht konstantzeitig: siehe Sicherheit.
Die Tatsache ist größtenteils irrelevant, aber die wichtige Methode, die man im Hinterkopf behalten sollte, ist pow,
die Exponentenbits preisgeben kann, wenn sie naiv verwendet wird.
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);
Die Formel der kurzen Weierstraß-Kurve lautet `y² = x³ + ax + b`. `weierstrass`
erwartet die Argumente `a`, `b`, die Körpercharakteristik `p`, die Kurvenordnung `n`,
den Kofaktor `h` und die Koordinaten `Gx`, `Gy` des Generatorpunkts und gibt eine Point-Klasse zurück.
`ecdsa` kombiniert eine Point-Klasse mit einer Hash-Funktion zu einem Signaturschema.
#### edwards: Benutzerdefinierte Edwards-Kurve```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);
Die Formel der Twisted-Edwards-Kurve lautet ax² + y² = 1 + dx²y².
Sie müssen a, d, die Körpercharakteristik p, die Kurvenordnung n (manchmal auch als L bezeichnet),
den Kofaktor h und die Koordinaten Gx, Gy des Generatorpunkts angeben.
Die Bibliothek wurde auditiert:
curve, modular, poseidon, weierstrassWir haben im April 2026 mit regelmäßigen KI-gestützten Selbst-Audits begonnen.
Es wird gegen eigenschaftsbasierte, bibliotheksübergreifende und Wycheproof-Vektoren getestet und wird in der GitHub-CI gefuzzt.
Wenn Sie etwas Ungewöhnliches bemerken: untersuchen und melden Sie es.
Wir streben algorithmische konstante Zeit an. JIT-Compiler und Garbage Collector machen „konstante Zeit" in einer Skriptsprache extrem schwer zu erreichen, um Timing-Angriffe abzuwehren. Das bedeutet, dass keine andere JS-Bibliothek Konstantzeitigkeit bieten kann. Selbst statisch typisiertes Rust, eine Sprache ohne GC, macht es schwieriger, konstante Zeit zu erreichen für einige Fälle. Wenn Ihr Ziel absolute Sicherheit ist, verwenden Sie keine JS-Bibliothek — einschließlich Bindings an native Bibliotheken. Verwenden Sie Low-Level-Bibliotheken und -Sprachen.
Innerhalb dieser Grenzen bietet die Multiplikation mit geheimen Skalaren spezifische, messbare Eigenschaften:
multiply() verwendet vorzeichenbehaftete Fixed-Window-Tabellen mit
datenunabhängigen Tabellenscans — die Anzahl und Reihenfolge der Punktoperationen
ist unabhängig vom Skalarwert.s + r·n mit einem zufälligen
128-Bit-r vor der Multiplikation maskiert. Dies gilt für alle Multiplikationen auf Kofaktor-1-Kurven
(p256, p384, p521, secp256k1) und für Basispunkt-Multiplikationen überall.benchmark/ct.ts)
vergleicht das Timing über gegnerische Skalarklassen (sparse vs. dense, niedrige vs. hohe Bits,
nahe der Ordnung, Bitmuster). Die Basispunkt-Multiplikation zeigt auf keiner Kurve unterscheidbares Timing,
und die Multiplikation mit zufälligen Punkten zeigt keines auf den Weierstrass-Kurven
(max |t| ≤ 2.8 bei 1000 Stichproben; Schwellenwert 4.5).Bekannte Einschränkung: Auf kofaktorierten Edwards-Kurven (ed25519, ed448) wird die Multiplikation eines Nicht-Basis-Punkts mit einem geheimen Skalar nicht geblindet. Derselbe Harness erkennt dies zuverlässig. EdDSA-Signierung ist davon nicht betroffen (sie multipliziert nur den geblindeten Basispunkt), und X25519/X448 verwenden eine separate Montgomery-Ladder-Implementierung (ebenfalls nicht betroffen). Es ist relevant für Protokolle, die beliebige Edwards/Ristretto-Punkte mit langlebigen geheimen Skalaren multiplizieren; bevorzugen Sie dort Skalare, die konstruktionsbedingt vollbreit sind. Beachten Sie, dass die Erkennbarkeit in einem isolierten Harness nicht bedeutet, dass sie praktisch ausnutzbar ist: Wir haben die Skalarextraktion in einer realistischen Cross-Tenant-/In-Browser-Umgebung versucht und konnten Edwards-Skalare selbst mit 100.000 Timing-Stichproben nicht wiederherstellen.
Verwenden Sie Low-Level-Sprachen anstelle von JS / WASM, wenn Ihr Ziel absolute Sicherheit ist.
Die Bibliothek verwendet hauptsächlich Uint8Arrays und bigints.
.fill(0), was anweist, den Inhalt mit Nullen zu füllen,
aber es gibt keine Garantien in JSawait fn() schreibt alle internen Variablen in den Speicher. Bei
asynchronen Funktionen gibt es keine Garantien, wann der Codeabschnitt
ausgeführt wird. Das bedeutet, dass ein Angreifer
reichlich Zeit haben kann, Daten aus dem Speicher zu lesen.Das bedeutet, dass einige Geheimnisse länger im Speicher bleiben könnten als erwartet. Wenn ein Angreifer jedoch den Anwendungsspeicher lesen kann, ist es ohnehin aussichtslos: Es gibt keine Möglichkeit, irgendetwas über das Nullen sensibler Daten zu garantieren, ohne eine komplexe Testsuite, die den Prozessspeicher dumpt und verifiziert, dass keine sensiblen Daten zurückbleiben. Für JS bedeutet das, alle Browser (einschließlich mobiler) zu testen. Und natürlich wäre es nutzlos, ohne dieselbe Testsuite in der tatsächlichen Anwendung zu verwenden, die die Bibliothek nutzt.
Für dieses Paket gibt es 1 Abhängigkeit; und einige Dev-Abhängigkeiten:
Wir verlassen uns auf das eingebaute
crypto.getRandomValues,
das als kryptografisch sicherer PRNG gilt.
Browser hatten in der Vergangenheit Schwächen — und könnten sie wieder haben — aber einen Userspace-CSPRNG zu implementieren ist noch schlimmer, da es keine zuverlässige Userspace-Quelle für hochwertige Entropie gibt.
Ein kryptografisch relevanter Quantencomputer, falls gebaut, wird es ermöglichen, Elliptische-Kurven-Kryptografie (sowohl ECDSA / EdDSA als auch ECDH) mithilfe des Shor-Algorithmus zu brechen.
Erwägen Sie den Wechsel zu neueren / hybriden Algorithmen wie SPHINCS+. Sie sind verfügbar in noble-post-quantum.
NIST verbietet klassische Kryptografie (RSA, DSA, ECDSA, ECDH) nach 2035. Das australische ASD verbietet sie nach 2030.
npm run benchmark
noble-curves benötigt über 10 ms, um mehr als 20 MB an Basispunkt-Vorberechnungen zu generieren.
Dies geschieht **einmalig** pro Kurve.
Die Generierung wird verzögert, bis eine beliebige Methode (pubkey, sign, verify) aufgerufen wird.
Der Benutzer kann die Vorberechnungsgenerierung erzwingen, indem er manuell `Point.BASE.precompute(windowSize, false)` aufruft.
Sieh dir den Quellcode an.
Benchmark-Ergebnisse auf 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
Unterstützte node.js-Versionen:
v2 vereinfacht die Interna massiv, verbessert die Sicherheit, reduziert die Bundle-Größe und ebnet den Weg für die Zukunft. Wir haben versucht, v2 so weit wie möglich abwärtskompatibel zu halten.
Upgrade-Pfad: Zuerst auf curves v1.9.x aktualisieren. Die Deprecation-Warnungen beheben, dann auf v2 umsteigen.
Module:
.js-Erweiterung ist jetzt erforderlich: @noble/curves/ed25519 => @noble/curves/ed25519.js.
Dies ermöglicht die native Nutzung im Browser, ohne Transpilerp256, p384, p521 wurden nach nist verschoben; jubjub wurde nach misc verschobenpasta und bn254_weierstrass (NICHT das pairing-basierte bn254) wurden entferntNeue Funktionen:
isValidSecretKey, isValidPublicKeyBreaking Changes:
Point.fromHex akzeptiert jetzt nur noch Strings: Verwenden Sie Point.fromBytes für Uint8Array{prehash: false}{lowS: false}{format: 'der'}.
Dies reduziert die Malleabilitätsignature.toBytes() auflongSignatures (G1-Pubkeys, G2-Sigs) und shortSignatures (G1-Sigs, G2-Pubkeys){message: ..., publicKey: ...}[]Umbenennungen (curves v1.9 markiert alte Namen als veraltet):
abstract/curve.jsPoint.BASE.multiply(Point.Fn.fromBytes(key))CURVE-Eigenschaft mit allerlei zufälligem Zeug => Point.CURVE(),
die nur Kurvenparameter bereitstellt*curve*_hasher.
Beispiel: secp256k1.hashToCurve => secp256k1_hasher.hashToCurve()Entfernte Funktionen: Point#multiplyAndAddUnsafe, Point#hasEvenY, Field.MASK
npm install && npm run build && npm test baut den Code und führt Tests aus.
Es gibt zusätzliche Test-Suites: langsame Large-Scalar-/Large-Curve-Tests npm run test:slow,
und das Constant-Timeness-Harness npm run benchmark:ct.
Siehe paulmillr.com/noble für nützliche Ressourcen, Artikel, Dokumentation und Demos zur Bibliothek.
The MIT License (MIT)
Copyright (c) 2022 Paul Miller (https://paulmillr.com)
Siehe LICENSE-Datei.
curve, hash-to-curve, modular, poseidon, utils, weierstrass und
Top-Level-Module _shortw_utils und secp256k1weierstrass() + ecdsa() / edwards() + eddsa().
weierstrass / edwards erwarten vereinfachte Kurvenparameter (Fp wurde zu p);
ecdsa / eddsa erwarten die Point-Klasse und einen Hash