
Проверенная и минималистичная реализация эллиптической криптографии на JS.
Проверенная аудитом и минималистичная реализация эллиптической криптографии на JS.
У кривых есть 5кб родственные проекты secp256k1 и ed25519. У них меньше поверхность атаки, но и меньше возможностей.
noble криптография — высокобезопасный, легко проверяемый аудитом набор изолированных криптографических библиотек и инструментов.
npm install @noble/curves
deno add jsr:@noble/curves
Мы поддерживаем все основные платформы и среды выполнения. Для React Native может потребоваться полифилл для getRandomValues. Также доступен автономный файл 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);
- [ECDSA, EdDSA, Schnorr signatures](#ecdsa-eddsa-schnorr-signatures)
- [ECDH: Diffie-Hellman shared secrets](#ecdh-diffie-hellman-shared-secrets)
- [webcrypto: friendly wrapper](#webcrypto-friendly-wrapper)
- [BLS signatures, bls12-381, bn254 aka alt\_bn128](#bls-signatures-bls12-381-bn254-aka-alt_bn128)
- [hash-to-curve: hashing to curve points](#hash-to-curve-hashing-to-curve-points)
- [OPRFs](#oprfs) | [FROST threshold signatures](#frost-threshold-signatures)
- [poseidon: Poseidon hash](#poseidon-poseidon-hash) | [fft: Fast Fourier Transform](#fft-fast-fourier-transform) | [utils](#utils-byte-shuffling-conversion)
- Internals: [Point math](#elliptic-curve-point-math) | [modular](#modular-modular-arithmetics--finite-fields) | [custom curves](#weierstrass-custom-weierstrass-curve--ecdsa)
- [Specs](#specs)
- [Security](#security) | [Speed](#speed) | [Upgrading](#upgrading) | [Contributing & testing](#contributing--testing) | [License](#license)
### ECDSA, EdDSA, Schnorr signatures
#### 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 и отображение BIP324 ElligatorSwift для secp256k1 доступны в отдельном пакете.
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);
Ознакомьтесь с [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() сначала применяют встроенную хеш-функцию кривой к сообщению:
sha256 для secp256k1, sha512 для p521. prehash: false позволяет использовать пользовательскую хеш-функцию
(например, secp256k1 + keccak_256). В noble-curves v1 значением по умолчанию было prehash: false.
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');
Восстановление открытого ключа поддерживается только с ECDSA. Это простая математическая операция:
нет никаких гарантий, что подпись действительно была создана. Поддельная (r, s, h) восстанавливается в
случайный открытый ключ, но найти m, которое привело бы к этому конкретному поддельному h, невозможно.
#### Hedged 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 включает режим с хеджированием. Для получения дополнительной информации ознакомьтесь со статьёй
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` (по умолчанию) использует более мягкие, [дружественные к консенсусу](https://hdevalence.ca/blog/2020-10-04-its-25519am) правила верификации, определённые в [ZIP215](https://zips.z.cash/zip-0215).
* `zip215: false` применяет строгую верификацию RFC 8032 / FIPS 186-5 и добавляет основанное на SBS
неотрекаемость, что полезно для подписания контрактов, электронного голосования и блокчейнов.
Оба режима обладают SUF-CMA (strong unforgeability under chosen message attacks);
большинство других библиотек не имеют ни SUF-CMA, ни SBS.
См. [Taming the many EdDSAs](https://eprint.iacr.org/2020/1244) для получения дополнительной информации.
### ECDH: общие секреты Диффи-Хеллмана```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);
Мы предоставляем ECDH для всех кривых Вейерштрасса и для 2 кривых Монтгомери X25519 (Curve25519) и X448 (Curve448), соответствующих RFC 7748.
В кривых Вейерштрасса общие секреты:
key.slice(1), чтобы их отброситьsha256(shared) или 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');
Тонкая обёртка над встроенным WebCrypto, повторяющая API noble. Методы всегда асинхронны;
поддержка во время выполнения различается — проверяйте с помощью `await curve.isSupported()`.
Ознакомьтесь с [micro-key-producer](https://github.com/paulmillr/micro-key-producer) для
чистых JS-утилит преобразования ключей.
### Подписи BLS, 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
Пример использования см. в реализации предкомпилированных контрактов BLS EVM.
API BN254 повторяет bls12-381. Ранее эта кривая называлась alt_bn128. Реализация совместима с EIP-196 и EIP-197: см. реализацию предкомпилированных контрактов bn254 EVM. Точки bn254 не реализуют toBytes, поскольку не существует стандарта сериализации: реализации расходятся в порядке байтов, флагах и порядке мнимой части G2. Инициализируйте точки из bigint.
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';
Модуль позволяет хешировать произвольные строки в точки эллиптической кривой. Реализует [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';
Мы предоставляем OPRF (oblivious pseudorandom functions), соответствующие RFC 9497.
OPRF позволяет интерактивно создавать Output = PRF(Input, serverSecretKey):
FROST реализует пороговую подпись Schnorr согласно RFC 9591.
С точки зрения приложения это похоже на multisig: любые min из max участников
могут совместно создать одну подпись 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]);
Генерация ключей может быть выполнена с помощью доверенного дилера (см. выше) или с помощью DKG (распределённая генерация ключей).
DKG состоит из трёх раундов: участники фиксируют обязательства по генерации ключей, обмениваются приватными долями,
затем выводят итоговые ключи участников — см. использование `DKG.round1` / `round2` / `round3` в
[тестах](https://github.com/paulmillr/noble-curves/blob/main/test/rfc9591-frost.test.ts).
Библиотека реализует криптографические шаги, а не окружающий протокол приложения:
вызывающей стороне по-прежнему необходимы аутентифицированная связь, координация, повторные попытки, управление сессиями и политика.
### 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
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 (быстрое преобразование Фурье) над конечными полями.
### 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));
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 });
Каждая кривая предоставляет свой класс Point: secp256k1, schnorr, p256, p384, p521, ed25519, ed448,
ristretto255, decaf448, bls12_381.G1 / G2, bn254.G1, jubjub, babyjubjub.
Точки Вейерштрасса используют проективные (однородные) координаты `new Point(X, Y, Z)`,
точки Эдвардса используют расширенные координаты `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 bigint над конечными полями,
которые определяются из подмодуля modular.
Операции над полем не являются константными по времени: см. безопасность.
Этот факт в основном несущественен, но важный метод, который следует иметь в виду, — pow,
который может раскрывать биты экспоненты при наивном использовании.
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);
Формула короткой кривой Вейерштрасса: `y² = x³ + ax + b`. `weierstrass`
принимает аргументы `a`, `b`, характеристику поля `p`, порядок кривой `n`,
кофактор `h` и координаты `Gx`, `Gy` порождающей точки, и возвращает класс Point.
`ecdsa` объединяет класс Point с хеш-функцией в схему подписи.
#### 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);
Формула скрученной кривой Эдвардса: ax² + y² = 1 + dx²y².
Необходимо указать a, d, характеристику поля p, порядок кривой n (иногда обозначается как L),
кофактор h и координаты Gx, Gy порождающей точки.
Библиотека прошла аудит:
curve, modular, poseidon, weierstrassВ апреле 2026 мы начали регулярные самоаудиты с использованием ИИ.
Библиотека тестируется на основе свойств, кросс-библиотечных и векторов Wycheproof, а также проходит фаззинг в GitHub CI.
Если вы заметите что-то необычное: исследуйте и сообщите.
Мы стремимся к алгоритмическому константному времени. JIT-компилятор и сборщик мусора делают "константное время" чрезвычайно труднодостижимым для защиты от атак по времени в скриптовом языке. Это означает, что любая другая JS-библиотека не может обладать константным временем выполнения. Даже статически типизированный Rust, язык без сборщика мусора, затрудняет достижение константного времени в некоторых случаях. Если ваша цель — абсолютная безопасность, не используйте никакие JS-библиотеки — включая привязки к нативным. Используйте низкоуровневые библиотеки и языки.
В этих пределах умножение на секретный скаляр обеспечивает конкретные, измеримые свойства:
multiply() использует таблицы со знаковым фиксированным окном и
сканирование таблиц, не зависящее от данных — количество и порядок операций над точками
не зависят от значения скаляра.s + r·n со случайным
128-битным r перед умножением. Это применяется ко всем умножениям на кривых с кофактором 1
(p256, p384, p521, secp256k1) и к умножениям на базовую точку везде.benchmark/ct.ts)
сравнивает время выполнения для различных классов скаляров (разреженные против плотных, младшие против старших битов,
близкие к порядку, битовые шаблоны). Умножение на базовую точку не показывает различимого времени ни на одной
кривой, а умножение на случайную точку не показывает его на кривых Вейерштрасса
(макс. |t| ≤ 2.8 при 1000 выборках; порог 4.5).Известное ограничение: на кривых Эдвардса с кофактором (ed25519, ed448) умножение небазовой точки на секретный скаляр не ослепляется. Тот же стенд надёжно это обнаруживает. Подписание EdDSA не затронуто (оно умножает только ослеплённую базовую точку), а X25519/X448 используют отдельную реализацию лестницы Монтгомери (также не затронуто). Это важно для протоколов, которые умножают произвольные точки Эдвардса/Ristretto на долгоживущие секретные скаляры; предпочитайте скаляры, полноразмерные по построению. Отметим, что обнаружимость в изолированном стенде не означает практической эксплуатируемости: мы пытались извлечь скаляр в реалистичной кросс-тенантной / браузерной среде и не смогли восстановить скаляры Эдвардса даже при 100 000 выборках времени.
Используйте низкоуровневые языки вместо JS / WASM, если ваша цель — абсолютная безопасность.
Библиотека в основном использует Uint8Array и bigint.
.fill(0), который предписывает заполнить содержимое нулями,
но в JS нет никаких гарантийawait fn() запишет все внутренние переменные в память. С
асинхронными функциями нет гарантий, когда блок кода
будет выполнен. Это означает, что у злоумышленника может быть
достаточно времени, чтобы прочитать данные из памяти.Это означает, что некоторые секреты могут оставаться в памяти дольше, чем предполагалось. Однако если злоумышленник может читать память приложения, всё уже обречено: нет способа гарантировать что-либо относительно затирания конфиденциальных данных без сложного набора тестов, который сбросит память процесса и проверит, что не осталось конфиденциальных данных. Для JS это означает тестирование всех браузеров (включая мобильные). И, конечно, это будет бесполезно без использования того же набора тестов в реальном приложении, которое использует библиотеку.
Для этого пакета существует 1 зависимость; и несколько dev-зависимостей:
Мы полагаемся на встроенный
crypto.getRandomValues,
который считается криптографически стойким PRNG.
У браузеров в прошлом были слабости — и могут появиться снова — но реализация CSPRNG в пользовательском пространстве ещё хуже, поскольку нет надёжного источника высококачественной энтропии в пользовательском пространстве.
Криптографически значимый квантовый компьютер, если будет построен, позволит взломать криптографию на эллиптических кривых (как ECDSA / EdDSA, так и ECDH) с помощью алгоритма Шора.
Рассмотрите переход на более новые / гибридные алгоритмы, такие как SPHINCS+. Они доступны в noble-post-quantum.
NIST запрещает классическую криптографию (RSA, DSA, ECDSA, ECDH) после 2035 года. Австралийское ASD запрещает её после 2030 года.
npm run benchmark
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 значительно упрощает внутреннее устройство, повышает безопасность, уменьшает размер бандла и прокладывает путь в будущее. Мы постарались сделать v2 настолько обратно совместимой, насколько это возможно.
Путь обновления: сначала обновитесь до curves v1.9.x. Исправьте предупреждения об устаревании, затем переходите на v2.
Модули:
.js: @noble/curves/ed25519 => @noble/curves/ed25519.js.
Это обеспечивает нативное использование в браузере, без транспайлеровp256, p384, p521 были перемещены в nist; jubjub был перемещён в miscpasta и bn254_weierstrass (НЕ bn254 на основе спариваний) были удаленыНовые возможности:
isValidSecretKey, isValidPublicKeyКритические изменения:
Point.fromHex теперь принимает только строки: используйте Point.fromBytes для Uint8Array{prehash: false}{lowS: false}{format: 'der'}.
Это снижает пластичностьsignature.toBytes()longSignatures (публичные ключи G1, подписи G2) и shortSignatures (подписи G1, публичные ключи G2){message: ..., publicKey: ...}[]Переименования (в curves v1.9 старые имена помечены как устаревшие):
abstract/curve.jsPoint.BASE.multiply(Point.Fn.fromBytes(key))CURVE со всякой всячиной => Point.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 для полезных ресурсов, статей, документации и демо, связанных с библиотекой.
The MIT License (MIT)
Copyright (c) 2022 Paul Miller (https://paulmillr.com)
См. файл LICENSE.
curvehash-to-curvemodularposeidonutilsweierstrass_shortw_utilssecp256k1weierstrass() + ecdsa() / edwards() + eddsa().
weierstrass / edwards ожидают упрощённые параметры кривой (Fp стал p);
ecdsa / eddsa ожидают класс Point и хеш