Skip to content
KitploitKITPLOIT
HerramientasBlog
Enviar
HerramientasBlog
Enviar

¡Herramientas de Hacking, PenTest y Ciberseguridad para tu Arsenal de Seguridad!

Kitploit es un directorio de herramientas de hacking, ciberseguridad y pentesting. Descubre las últimas actualizaciones de proyectos para encontrar vulnerabilidades, analizar sistemas, automatizar pruebas y fortalecer tu seguridad.

··Feeds·Contacto·Privacidad·© 2026 Kitploit

Directorio de Herramientas

Categorías

Ver todas las categorías
Loading categories
noble-curves — Implementación JS auditada y minimalista de criptografía de curva elíptica. | Kitploit
Herramientas/GitHubGitHub/paulmillr/noble-curves
Herramientas de Cifrado/DescifradoAnálisis de HashCriptografíaUtilidades y FrameworksAprendizaje y Educación
GitHubpaulmillr/noble-curves

noble-curves

Implementación JS auditada y minimalista de criptografía de curva elíptica.

Ver Repositorio
95810115hace 7 díasRevisado por Kitploit

Más Populares

Ver todos →

Descubre las herramientas más usadas por nuestra comunidad.

Explora todas las herramientas

Explora nuestra colección de herramientas

Ver todas las herramientas →
Compartir
Sitio web

noble-curves

Implementación JS auditada y minimalista de criptografía de curva elíptica.

  • 🔒 Auditada por firmas de seguridad independientes
  • 🪶 Minimalista: 15KB (comprimido con gzip) secp256k1, el código no utilizado se excluye de tus compilaciones
  • 🏎 Rápida: optimizada manualmente para las particularidades de los motores JS
  • 🔍 Fiable: pruebas cruzadas entre bibliotecas / wycheproof garantizan la corrección
  • ➰ Curvas de Weierstrass, Edwards; firmas ECDSA, EdDSA, Schnorr, BLS
  • ✍️ ECDH, hash-to-curve, OPRF, FROST, hash Poseidon, FFT
  • 🔖 No repudio (SUF-CMA, SBS) y compatibilidad con consenso (ZIP215) en ed25519, ed448
  • 🥈 Wrapper con API idéntica sobre WebCrypto nativo

Las curvas tienen proyectos hermanos de 5kb secp256k1 y ed25519. Tienen una superficie de ataque menor, pero menos características.

Esta biblioteca pertenece a la criptografía noble

noble cryptography — conjunto de bibliotecas y herramientas criptográficas contenidas, de alta seguridad y fácilmente auditables.

  • Dependencias nulas o mínimas
  • Código TypeScript / JS altamente legible
  • Lanzamientos firmados con PGP y compilaciones NPM transparentes
  • Todas las bibliotecas: ciphers, curves, hashes, post-quantum, 5kb secp256k1 / ed25519
  • Versión WASM: awasm-noble
  • Consulta la página principal para recursos de lectura, documentación y aplicaciones construidas con noble

Uso

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);

root@kitploit:~
- [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.

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:~
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.

Recuperación de claves públicas a partir de firmas```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:~
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.

Compatibilidad con el consenso vs voto electrónico```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` (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:

  • Incluyen bytes de paridad de y: usa key.slice(1) para eliminarlos
  • No están hasheados: usa hashing o KDF por encima, como sha256(shared) o hkdf(shared)

webcrypto: envoltorio amigable```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:~
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.

hash-to-curve: hashing a puntos de curva```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:~
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):

  • El servidor no puede calcular Output por sí mismo: no conoce Input
  • El cliente no puede calcular Output por sí mismo: no conoce server secretKey
  • Un atacante que intercepte la comunicación no puede restaurar Input/Output/serverSecretKey y no puede vincular Input a algún valor.

Firmas de umbral FROST

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]);

root@kitploit:~
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

fft: Transformada Rápida de Fourier```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 (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));

Funcionamiento interno

Matemáticas de puntos en curvas elípticas```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:~
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.

weierstrass: curva Weierstrass personalizada y 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:~
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.

Especificaciones

  • ECDSA: k determinista de RFC 6979, firmas hedged del borrador cfrg-det-sigs-with-noise
  • EdDSA: RFC 8032, FIPS 186-5; verificación compatible con consenso: ZIP215
  • Firmas Schnorr: BIP 340
  • X25519, X448 ECDH: RFC 7748
  • ristretto255, decaf448: RFC 9496
  • hash-to-curve: RFC 9380
  • OPRFs: RFC 9497
  • FROST: RFC 9591
  • bn254: EIP-196, EIP-197
  • Poseidon: sitio

Seguridad

La biblioteca ha sido auditada:

  • en la versión 2.3.0, en agosto de 2026, por Trail of Bits, en colaboración con OpenAI
    • Se realizó durante la iniciativa "Patch the Planet"
    • Alcance: todo
  • en la versión 1.6.0, en septiembre de 2024, de forma independiente, por Cure53
    • PDFs: sitio web, en el repositorio
    • Alcance: ed25519, ed448, sus complementos, bls12-381, bn254, hash-to-curve, primitivas de bajo nivel bls, tower, edwards, montgomery.
    • La auditoría fue financiada por OpenSats
  • en la versión 1.2.0, en septiembre de 2023, de forma independiente, por Kudelski Security
    • PDFs: en el repositorio
    • Alcance: scure-starknet y sus módulos abstractos relacionados de noble-curves: curve, modular, poseidon, weierstrass
    • La auditoría fue financiada por Starkware
  • en la versión 0.7.3, en febrero de 2023, de forma independiente, por Trail of Bits
    • PDFs: sitio web, en el repositorio

Comenzamos 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.

Tiempo constante

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:

  • Secuencia de operaciones fija: 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.
  • Enmascaramiento de escalar: los escalares secretos se enmascaran adicionalmente como 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.
  • Validación estadística: un arnés de prueba t de Welch estilo dudect (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.

Volcado de memoria

Usa lenguajes de bajo nivel en lugar de JS / WASM si tu objetivo es la seguridad absoluta.

La biblioteca usa mayormente Uint8Arrays y bigints.

  • Los Uint8Arrays tienen .fill(0) que indica rellenar el contenido con ceros pero no hay garantías en JS
  • los bigints son inmutables y no tienen un método para poner a cero su contenido: un usuario necesita esperar hasta el siguiente ciclo de recolección de basura
  • las cadenas hexadecimales también son inmutables: no hay forma de ponerlas a cero
  • await 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.

Seguridad de la cadena de suministro

  • Los commits están firmados con claves PGP para prevenir falsificaciones. Asegúrate de verificar las firmas de los commits
  • Las versiones se publican de forma transparente a través de CI de GitHub sin tokens y Trusted Publishing. Asegúrate de verificar los registros de procedencia para autenticidad.
  • Se practica la publicación poco frecuente para minimizar la necesidad de reauditorías por parte de los usuarios finales.
  • Las dependencias se minimizan y se fijan estrictamente para reducir el riesgo de la cadena de suministro.
    • Usamos la menor cantidad de dependencias posible.
    • Los rangos de versiones están bloqueados, y los cambios se verifican con npm-diff.
  • Las dependencias de desarrollo se excluyen de las instalaciones de los usuarios finales; solo se usan para pasos de desarrollo y compilación.

Para este paquete, hay 1 dependencia; y algunas dependencias de desarrollo:

  • noble-hashes proporciona funcionalidad de hashing criptográfico
  • jsbt se usa para benchmarking / pruebas / herramientas de compilación y está desarrollado por el mismo autor
  • prettier, fast-check y typescript se usan para calidad de código / generación de pruebas / compilación de ts

Aleatoriedad

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.

Computadoras cuánticas

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.

Velocidad```sh

npm run benchmark

root@kitploit:~
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

Actualización

Versiones de node.js compatibles:

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

v1 a v2

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:

  • El paquete ahora es solo ESM. ESM finalmente puede cargarse desde common.js en node v20.19+
  • Ahora se requiere la extensión .js: @noble/curves/ed25519 => @noble/curves/ed25519.js. Esto permite el uso nativo en el navegador, sin transpiladores
  • p256, p384, p521 se movieron a nist; jubjub se movió a misc
  • Las curvas pasta y bn254_weierstrass (NO bn254 basada en pairing) fueron eliminadas

Nuevas características:

  • webcrypto: wrapper amigable al estilo noble sobre WebCrypto integrado
  • oprf: OPRFs RFC 9497 (funciones pseudorandom oblivious) para p256, p384, p521, ristretto255 y decaf448
  • weierstrass, edwards: nuevos métodos isValidSecretKey, isValidPublicKey
  • misc: curvas Brainpool brainpoolP256r1, brainpoolP384r1, brainpoolP512r1
  • Mensajes de error enormemente mejorados y más descriptivos

Cambios disruptivos:

  • La mayoría de los métodos ahora solo aceptan Uint8Array; las entradas de string hex están prohibidas. Esto simplifica el razonamiento, mejora la seguridad y reduce la maleabilidad. Point.fromHex ahora es solo para strings: usa Point.fromBytes para Uint8Array
  • Firma y verificación ECDSA (secp256k1, p256, p384...):
    • Mensajes prehashed: los métodos ahora esperan el mensaje sin hashear en lugar de messageHash. Comportamiento antiguo: {prehash: false}
    • Firmas lowS por defecto. secp256k1 no se ve afectada: ha usado lowS desde el principio. Comportamiento antiguo: {lowS: false}
    • Firmas Uint8Array (formato: 'compact') por defecto
    • verify: el formato der debe especificarse explícitamente en {format: 'der'}. Esto reduce la maleabilidad
    • verify: las instancias de Signature están prohibidas: llama primero a signature.toBytes()
  • Firmas BLS (bls12-381, bn254):
    • getPublicKey, sign, verify, signShortSignature, etc. se movieron a dos nuevos namespaces: longSignatures (pubkeys G1, sigs G2) y shortSignatures (sigs G1, pubkeys G2)
    • verifyBatch ahora espera un array de entradas {message: ..., publicKey: ...}[]

Renombramientos (curves v1.9 resalta los nombres antiguos como obsoletos):

  • Points
    • ExtendedPoint, ProjectivePoint => Point
    • Coordenadas de Point px/ex, py/ey, pz/ez, et => X, Y, Z, T
    • toRawBytes, fromRawBytes => toBytes, fromBytes
    • Point.normalizeZ, Point.msm => métodos separados en el submódulo abstract/curve.js
    • Point.fromPrivateKey(key) => Point.BASE.multiply(Point.Fn.fromBytes(key))
    • Propiedad CURVE con todo tipo de cosas aleatorias => Point.CURVE(), que solo proporciona parámetros de curva
    • RistrettoPoint => ristretto255.Point, DecafPoint => decaf448.Point
  • Firmas 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
  • Métodos hash-to-curve específicos de curva => *curve*_hasher. Ejemplo: secp256k1.hashToCurve => secp256k1_hasher.hashToCurve()
  • Enormes renombramientos y mejoras de tipos

Características eliminadas: Point#multiplyAndAddUnsafe, Point#hasEvenY, Field.MASK

Contribuir y probar

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.

Licencia

The MIT License (MIT)

Copyright (c) 2022 Paul Miller (https://paulmillr.com)

Consulta el archivo LICENSE.

Descargar herramienta
  • Alcance: módulos abstractos curve, hash-to-curve, modular, poseidon, utils, weierstrass y módulos de nivel superior _shortw_utils y secp256k1
  • La auditoría fue financiada por Ryan Shea
  • Curvas personalizadas:
    • La creación de curvas se simplificó enormemente y se dividió en creación de puntos y creación de generadores de firmas: weierstrass() + 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
    • pippenger: se eliminó el argumento Fn innecesario
    • Field#fromBytes() ahora valida que los elementos estén en el rango 0..order-1