
Implementación JS auditada y minimalista de criptografía de curva elíptica.
Implementación JS auditada y minimalista de criptografía de curva elíptica.
Las curvas tienen proyectos hermanos de 5kb secp256k1 y ed25519. Tienen una superficie de ataque menor, pero menos características.
noble cryptography — conjunto de bibliotecas y herramientas criptográficas contenidas, de alta seguridad y fácilmente auditables.
npm install @noble/curves
deno add jsr:@noble/curves
Soportamos todas las plataformas y entornos de ejecución principales. Para React Native, es posible que necesites un polyfill para getRandomValues. También está disponible un archivo independiente 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);
- [Firmas ECDSA, EdDSA, Schnorr](#ecdsa-eddsa-schnorr-signatures)
- [ECDH: secretos compartidos Diffie-Hellman](#ecdh-diffie-hellman-shared-secrets)
- [webcrypto: envoltorio amigable](#webcrypto-friendly-wrapper)
- [Firmas BLS, bls12-381, bn254 aka alt\_bn128](#bls-signatures-bls12-381-bn254-aka-alt_bn128)
- [hash-to-curve: hashing a puntos de curva](#hash-to-curve-hashing-to-curve-points)
- [OPRFs](#oprfs) | [Firmas de umbral FROST](#frost-threshold-signatures)
- [poseidon: hash Poseidon](#poseidon-poseidon-hash) | [fft: Transformada Rápida de Fourier](#fft-fast-fourier-transform) | [utils](#utils-byte-shuffling-conversion)
- Internos: [Aritmética de puntos](#elliptic-curve-point-math) | [modular](#modular-modular-arithmetics--finite-fields) | [curvas personalizadas](#weierstrass-custom-weierstrass-curve--ecdsa)
- [Especificaciones](#specs)
- [Seguridad](#security) | [Velocidad](#speed) | [Actualización](#upgrading) | [Contribución y pruebas](#contributing--testing) | [Licencia](#license)
### Firmas 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);
Los mensajes siempre se hashean primero: véase firma prehasheada. ECDSA utiliza k determinista, EdDSA sigue RFC 8032, Schnorr (solo secp256k1) sigue BIP 340: véase Especificaciones.
El esquema de firma MuSig2 y el mapeo ElligatorSwift de BIP324 para secp256k1 están disponibles en un paquete separado.
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);
Consulta el [RFC 9496](https://www.rfc-editor.org/rfc/rfc9496) para obtener más información sobre ristretto255 y decaf448.
Consulta la documentación separada para [Point](#elliptic-curve-point-math), [hasher](#hash-to-curve-hashing-to-curve-points) y [oprf](#oprfs).
#### Firma prehashed```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 });
Por defecto (prehash: true), sign() y verify() aplican primero el hash integrado de la curva al mensaje:
sha256 para secp256k1, sha512 para p521. prehash: false permite usar un hash personalizado
(p. ej. secp256k1 + keccak_256). En noble-curves v1, prehash: false era el valor predeterminado.
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');
La recuperación de clave pública solo es compatible con ECDSA. Es una operación matemática simple:
no hay garantías de que la firma se haya realizado realmente. Una (r, s, h) falsificada se recupera en
una clave pública aleatoria, pero no es factible encontrar m que conduzca a esta h falsificada específica.
#### ECDSA con cobertura y ruido```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 });
Por defecto, las firmas ECDSA son deterministas (RFC 6979). Las firmas puramente deterministas son
vulnerables a ataques de fallo, por lo que esquemas más recientes, como BIP340 schnorr, incorporan aleatoriedad
en la generación de firmas - también conocido como hedging. extraEntropy habilita el modo hedged. Para más información, consulta
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` (predeterminado) utiliza las reglas de verificación más permisivas y [compatibles con el consenso](https://hdevalence.ca/blog/2020-10-04-its-25519am) definidas en [ZIP215](https://zips.z.cash/zip-0215).
* `zip215: false` aplica la verificación estricta de RFC 8032 / FIPS 186-5 y añade
no repudio basado en SBS, lo cual es útil para la firma de contratos, el voto electrónico y las blockchains.
Ambos modos tienen SUF-CMA (fuerte infalsificabilidad bajo ataques de mensaje elegido);
la mayoría de las otras bibliotecas no tienen ni SUF-CMA ni SBS.
Consulte [Taming the many EdDSAs](https://eprint.iacr.org/2020/1244) para más información.
### ECDH: secretos compartidos 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);
Proporcionamos ECDH sobre todas las curvas Weierstrass, y sobre 2 curvas Montgomery X25519 (Curve25519) y X448 (Curve448), conforme a RFC 7748.
En las curvas Weierstrass, los secretos compartidos:
key.slice(1) para eliminarlossha256(shared) o 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');
Un envoltorio ligero sobre WebCrypto integrado, que refleja la API de noble. Los métodos son siempre asíncronos;
el soporte en tiempo de ejecución varía - compruébalo con `await curve.isSupported()`.
Consulta [micro-key-producer](https://github.com/paulmillr/micro-key-producer) para
utilidades de conversión de claves en JS puro.
### Firmas 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
Para ver un ejemplo de uso, consulta la implementación de los precompilados BLS EVM.
La API de BN254 refleja la de bls12-381. La curva se llamaba anteriormente alt_bn128. La implementación es compatible con EIP-196 y EIP-197: consulta la implementación de los precompilados bn254 EVM. Los puntos bn254 no implementan toBytes, porque no existe un estándar de serialización: las implementaciones difieren en el endianness, los flags y el orden de la parte imaginaria de G2. Inicializa los puntos desde bigints en su lugar.
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';
El módulo permite hashear cadenas arbitrarias a puntos de curva elíptica. Implementa [RFC 9380](https://www.rfc-editor.org/rfc/rfc9380).
Los espacios de nombres de `_hasher` están separados de las curvas para tree-shaking:
los usuarios que no necesitan hash-to-curve no lo tendrán en sus 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';
Proporcionamos OPRFs (funciones pseudorandom oblivious), conformes a RFC 9497.
OPRF permite crear interactivamente una Output = PRF(Input, serverSecretKey):
FROST implementa la firma Schnorr de umbral RFC 9591.
Es similar a multisig desde el punto de vista de la aplicación: cualquier min de max participantes
pueden producir conjuntamente una firma Schnorr bajo una clave pública compartida.
Los ciphersuites soportados son p256_FROST, ed25519_FROST, ed448_FROST, ristretto255_FROST,
secp256k1_FROST, y schnorr_FROST (secp256k1 compatible con Taproot).
La firma tiene dos rondas: los firmantes seleccionados se comprometen primero, luego producen las partes de la firma.```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]);
La generación de claves se puede realizar con un distribuidor de confianza (arriba) o con DKG (generación distribuida de claves).
DKG tiene tres rondas: los participantes se comprometen a la generación de claves, intercambian participaciones privadas,
y luego derivan las claves finales de los participantes - consulta el uso de `DKG.round1` / `round2` / `round3` en
[las pruebas](https://github.com/paulmillr/noble-curves/blob/main/test/rfc9591-frost.test.ts).
La biblioteca implementa los pasos criptográficos, no el protocolo de aplicación circundante:
los llamadores aún necesitan comunicación autenticada, coordinación, reintentos, manejo de sesiones y políticas.
### poseidon: hash Poseidon
Implementa el hash compatible con ZK [Poseidon](https://www.poseidon-hash.info):
permutación y esponja.
Existen muchas variantes de poseidon con diferentes constantes.
No las proporcionamos: debes construirlas manualmente.
Consulta el paquete [scure-starknet](https://github.com/paulmillr/scure-starknet) para ver un ejemplo adecuado.```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 (Transformada Rápida de Fourier) sobre cuerpos finitos.
### utils: reordenamiento de bytes, conversión```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 });
Cada curva expone su clase Point: secp256k1, schnorr, p256, p384, p521, ed25519, ed448,
ristretto255, decaf448, bls12_381.G1 / G2, bn254.G1, jubjub, babyjubjub.
Los puntos de Weierstrass usan coordenadas proyectivas (homogéneas) `new Point(X, Y, Z)`,
los puntos de Edwards usan coordenadas extendidas `new Point(X, Y, Z, T)`; ambos con x=X/Z, y=Y/Z.
#### modular: Aritmética modular y cuerpos finitos```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
Toda la aritmética se realiza con bigints de JS sobre campos finitos,
lo cual se define desde el submódulo modular.
Las operaciones de campo no son de tiempo constante: véase security.
El hecho es en su mayoría irrelevante, pero el método importante a tener en cuenta es pow,
que puede filtrar bits del exponente cuando se usa de forma ingenua.
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);
La fórmula de la curva de Weierstrass corta es `y² = x³ + ax + b`. `weierstrass`
espera los argumentos `a`, `b`, la característica del cuerpo `p`, el orden de la curva `n`,
el cofactor `h` y las coordenadas `Gx`, `Gy` del punto generador, y devuelve una clase Point.
`ecdsa` combina una clase Point con una función hash en un esquema de firma.
#### edwards: Curva de Edwards personalizada```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);
La fórmula de la curva de Twisted Edwards es ax² + y² = 1 + dx²y².
Debes especificar a, d, la característica del campo p, el orden de la curva n (a veces llamado L),
el cofactor h y las coordenadas Gx, Gy del punto generador.
La biblioteca ha sido auditada:
curve, modular, poseidon, weierstrassComenzamos autoevaluaciones periódicas asistidas por IA en abril de 2026.
Se prueba contra vectores basados en propiedades, de bibliotecas cruzadas y de Wycheproof, y se somete a fuzzing en la CI de GitHub.
Si ves algo inusual: investiga y reporta.
Nuestro objetivo es el tiempo constante algorítmico. El compilador JIT y el recolector de basura hacen que la resistencia a ataques de temporización en "tiempo constante" sea extremadamente difícil de lograr en un lenguaje de scripting. Lo que significa que cualquier otra biblioteca JS no puede tener tiempo constante. Incluso Rust, un lenguaje con tipado estático y sin GC, hace más difícil lograr tiempo constante en algunos casos. Si tu objetivo es la seguridad absoluta, no uses ninguna biblioteca JS — incluyendo enlaces a bibliotecas nativas. Usa bibliotecas y lenguajes de bajo nivel.
Dentro de esos límites, la multiplicación por escalar secreto proporciona propiedades específicas y medibles:
multiply() usa tablas de ventana fija con signo y
escaneos de tabla con independencia de datos — el número y orden de las operaciones de punto
es independiente del valor del escalar.s + r·n con un r aleatorio
de 128 bits antes de la multiplicación. Esto aplica a todas las multiplicaciones en curvas de cofactor 1
(p256, p384, p521, secp256k1), y a las multiplicaciones por el punto base en todas partes.benchmark/ct.ts)
compara los tiempos entre clases de escalares adversarias (dispersos vs densos, bits bajos vs altos,
cercanos al orden, patrones de bits). La multiplicación por el punto base no muestra tiempos distinguibles en ninguna
curva, y la multiplicación por punto aleatorio no muestra ninguno en las curvas de Weierstrass
(máx |t| ≤ 2.8 con 1000 muestras; umbral 4.5).Limitación conocida: en curvas de Edwards con cofactor (ed25519, ed448), multiplicar un punto no base por un escalar secreto no está enmascarado. El mismo arnés detecta esto de forma fiable. La firma EdDSA no se ve afectada (solo multiplica el punto base enmascarado), y X25519/X448 usan una implementación separada de escalera de Montgomery (también no afectada). Importa para protocolos que multiplican puntos arbitrarios de Edwards/Ristretto por escalares secretos de larga duración; prefiere escalares que sean de ancho completo por construcción en esos casos. Ten en cuenta que la detectabilidad en un arnés aislado no implica explotabilidad práctica: intentamos la extracción de escalares en un entorno realista multi-inquilino / en el navegador y no pudimos recuperar escalares de Edwards incluso con 100,000 muestras de temporización.
Usa lenguajes de bajo nivel en lugar de JS / WASM si tu objetivo es la seguridad absoluta.
La biblioteca usa mayormente Uint8Arrays y bigints.
.fill(0) que indica rellenar el contenido con ceros
pero no hay garantías en JSawait fn() escribirá todas las variables internas en memoria. Con
funciones asíncronas no hay garantías de cuándo se ejecutaría el fragmento
de código. Lo que significa que un atacante puede tener
mucho tiempo para leer datos de la memoria.Esto significa que algunos secretos podrían permanecer en memoria más tiempo de lo previsto. Sin embargo, si un atacante puede leer la memoria de la aplicación, está condenada de todos modos: no hay forma de garantizar nada sobre poner a cero datos sensibles sin una compleja suite de pruebas que volcará la memoria del proceso y verificará que no queda ningún dato sensible. Para JS esto significa probar todos los navegadores (incluidos los móviles). Y, por supuesto, será inútil sin usar la misma suite de pruebas en la aplicación real que consume la biblioteca.
Para este paquete, hay 1 dependencia; y algunas dependencias de desarrollo:
Confiamos en la función integrada
crypto.getRandomValues,
que se considera un PRNG criptográficamente seguro.
Los navegadores han tenido debilidades en el pasado — y podrían volver a tenerlas — pero implementar un CSPRNG en espacio de usuario es aún peor, ya que no hay una fuente fiable en espacio de usuario de entropía de alta calidad.
Una computadora cuántica criptográficamente relevante, si se construye, permitirá romper la criptografía de curva elíptica (tanto ECDSA / EdDSA como ECDH) usando el algoritmo de Shor.
Considera cambiar a algoritmos más nuevos / híbridos, como SPHINCS+. Están disponibles en noble-post-quantum.
NIST prohíbe la criptografía clásica (RSA, DSA, ECDSA, ECDH) después de 2035. El ASD australiano la prohíbe después de 2030.
npm run benchmark
noble-curves tarda más de 10 ms en generar más de 20 MB de precomputaciones de puntos base.
Esto se hace **una sola vez** por curva.
La generación se aplaza hasta que se llama a cualquier método (pubkey, sign, verify).
El usuario puede forzar la generación de precomputaciones llamando manualmente a `Point.BASE.precompute(windowSize, false)`.
Consulta el código fuente.
Resultados de benchmark en 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
Versiones de node.js compatibles:
v2 simplifica enormemente los internos, mejora la seguridad, reduce el tamaño del bundle y allana el camino hacia el futuro. Intentamos mantener v2 lo más compatible hacia atrás posible.
Ruta de actualización: actualiza primero a curves v1.9.x. Corrige las advertencias de obsolescencia, luego cambia a v2.
Módulos:
.js: @noble/curves/ed25519 => @noble/curves/ed25519.js.
Esto permite el uso nativo en el navegador, sin transpiladoresp256, p384, p521 se movieron a nist; jubjub se movió a miscpasta y bn254_weierstrass (NO bn254 basada en pairing) fueron eliminadasNuevas características:
isValidSecretKey, isValidPublicKeyCambios disruptivos:
Point.fromHex ahora es solo para strings: usa Point.fromBytes para Uint8Array{prehash: false}{lowS: false}{format: 'der'}.
Esto reduce la maleabilidadsignature.toBytes()longSignatures (pubkeys G1, sigs G2) y shortSignatures (sigs G1, pubkeys G2){message: ..., publicKey: ...}[]Renombramientos (curves v1.9 resalta los nombres antiguos como obsoletos):
abstract/curve.jsPoint.BASE.multiply(Point.Fn.fromBytes(key))CURVE con todo tipo de cosas aleatorias => Point.CURVE(),
que solo proporciona parámetros de curva*curve*_hasher.
Ejemplo: secp256k1.hashToCurve => secp256k1_hasher.hashToCurve()Características eliminadas: Point#multiplyAndAddUnsafe, Point#hasEvenY, Field.MASK
npm install && npm run build && npm test compilará el código y ejecutará las pruebas.
Hay suites adicionales: pruebas lentas de escalares grandes / curvas grandes npm run test:slow,
y el arnés de constancia temporal npm run benchmark:ct.
Consulta paulmillr.com/noble para recursos útiles, artículos, documentación y demos relacionados con la librería.
The MIT License (MIT)
Copyright (c) 2022 Paul Miller (https://paulmillr.com)
Consulta el archivo LICENSE.
curve, hash-to-curve, modular, poseidon, utils, weierstrass y
módulos de nivel superior _shortw_utils y secp256k1weierstrass() + ecdsa() / edwards() + eddsa().
weierstrass / edwards esperan parámetros de curva simplificados (Fp se convirtió en p);
ecdsa / eddsa esperan la clase Point y el hash