.github | ||
benchmark | ||
lib/esm | ||
src | ||
test | ||
.gitignore | ||
.prettierrc.json | ||
LICENSE | ||
package-lock.json | ||
package.json | ||
README.md | ||
SECURITY.md | ||
tsconfig.esm.json | ||
tsconfig.json |
noble-curves
Audited & minimal JS implementation of elliptic curve cryptography.
- noble family, zero dependencies
- Short Weierstrass, Edwards, Montgomery curves
- ECDSA, EdDSA, Schnorr, BLS signature schemes, ECDH key agreement
- #️⃣ hash to curve for encoding or hashing an arbitrary string to an elliptic curve point
- 🧜♂️ Poseidon ZK-friendly hash
- 🏎 Ultra-fast, hand-optimized for caveats of JS engines
- 🔍 Unique tests ensure correctness. Wycheproof vectors included
- 🔻 Tree-shaking-friendly: there is no entry point, which ensures small size of your app
Package consists of two parts:
abstract/
directory specifies zero-dependency EC algorithms- root directory utilizes one dependency
@noble/hashes
and provides ready-to-use:- NIST curves secp192r1/P192, secp224r1/P224, secp256r1/P256, secp384r1/P384, secp521r1/P521
- SECG curve secp256k1
- ed25519/curve25519/x25519/ristretto, edwards448/curve448/x448 RFC7748 / RFC8032 / ZIP215 stuff
- pairing-friendly curves bls12-381, bn254
Curves incorporate work from previous noble packages (secp256k1, ed25519), which were developed from 2019 to 2022. Check out Upgrading section if you've used them before.
This library belongs to noble crypto
noble-crypto — high-security, easily auditable set of contained cryptographic libraries and tools.
- No dependencies, protection against supply chain attacks
- Easily auditable TypeScript/JS code
- Supported in all major browsers and stable node.js versions
- All releases are signed with PGP keys
- Check out homepage & all libraries: curves (secp256k1, ed25519), hashes
Usage
Use NPM for browser / node.js:
npm install @noble/curves
For Deno, use it with npm specifier: import { secp256k1 } from 'npm:@noble/curves@1.2.0/secp256k1';
.
In browser, you could also include the single file from
GitHub's releases page.
The library does not have an entry point. It allows you to select specific primitives and drop everything else. If you only want to use secp256k1, just use the library with rollup or other bundlers. This is done to make your bundles tiny. All curves:
import { secp256k1 } from '@noble/curves/secp256k1';
import { ed25519, ed25519ph, ed25519ctx, x25519, RistrettoPoint } from '@noble/curves/ed25519';
import { ed448, ed448ph, ed448ctx, x448 } from '@noble/curves/ed448';
import { p256 } from '@noble/curves/p256';
import { p384 } from '@noble/curves/p384';
import { p521 } from '@noble/curves/p521';
import { pallas, vesta } from '@noble/curves/pasta';
import * as stark from '@noble/curves/stark';
import { bls12_381 } from '@noble/curves/bls12-381';
import { bn254 } from '@noble/curves/bn';
import { jubjub } from '@noble/curves/jubjub';
Every curve can be used in the following way:
import { secp256k1 } from '@noble/curves/secp256k1'; // Common.js and ECMAScript Modules (ESM)
const key = secp256k1.utils.randomPrivateKey();
const pub = secp256k1.getPublicKey(key);
const msg = new Uint8Array(32).fill(1);
const sig = secp256k1.sign(msg, key);
// weierstrass curves should use extraEntropy: https://moderncrypto.org/mail-archive/curves/2017/000925.html
const sigImprovedSecurity = secp256k1.sign(msg, key, { extraEntropy: true });
secp256k1.verify(sig, msg, pub) === true;
// secp, p*, pasta curves allow pub recovery
sig.recoverPublicKey(msg) === pub;
const someonesPub = secp256k1.getPublicKey(secp256k1.utils.randomPrivateKey());
const shared = secp256k1.getSharedSecret(key, someonesPub);
See additional examples for guides.
API
- Overview
- abstract/edwards: Twisted Edwards curve
- abstract/montgomery: Montgomery curve
- abstract/weierstrass: Short Weierstrass curve
- abstract/hash-to-curve: Hashing strings to curve points
- abstract/poseidon: Poseidon hash
- abstract/modular
- abstract/utils
Overview
There are following zero-dependency abstract algorithms:
import { bls } from '@noble/curves/abstract/bls';
import { twistedEdwards } from '@noble/curves/abstract/edwards';
import { montgomery } from '@noble/curves/abstract/montgomery';
import { weierstrass } from '@noble/curves/abstract/weierstrass';
import * as curve from '@noble/curves/abstract/curve';
import * as mod from '@noble/curves/abstract/modular';
import * as utils from '@noble/curves/abstract/utils';
They allow to define a new curve in a few lines of code:
import { Field } from '@noble/curves/abstract/modular'; // finite field, modulo arithmetics done over it
import { weierstrass } from '@noble/curves/abstract/weierstrass'; // short weierstrass curve
import { sha256 } from '@noble/hashes/sha256'; // 3rd-party sha256() of type utils.CHash, with blockLen/outputLen
import { hmac } from '@noble/hashes/hmac'; // 3rd-party hmac() that will accept sha256()
import { concatBytes, randomBytes } from '@noble/hashes/utils'; // 3rd-party utilities
// secq (NOT secp) 256k1: cycle of secp256k1 with Fp/N flipped.
// https://zcash.github.io/halo2/background/curves.html#cycles-of-curves
// https://personaelabs.org/posts/spartan-ecdsa
const secq256k1 = weierstrass({
a: 0n,
b: 7n,
Fp: Field(2n ** 256n - 432420386565659656852420866394968145599n),
n: 2n ** 256n - 2n ** 32n - 2n ** 9n - 2n ** 8n - 2n ** 7n - 2n ** 6n - 2n ** 4n - 1n,
Gx: 55066263022277343669578718895168534326250603453777594175500187360389116729240n,
Gy: 32670510020758816978083085130507043184471273380659243275938904335757337482424n,
hash: sha256,
hmac: (key: Uint8Array, ...msgs: Uint8Array[]) => hmac(sha256, key, concatBytes(...msgs)),
randomBytes,
});
- To initialize new curve, you must specify its variables, order (number of points on curve), field prime (over which the modular division would be done)
- All curves expose same generic interface:
getPublicKey()
,sign()
,verify()
functionsPoint
conforming toGroup
interface with add/multiply/double/negate/add/equals methodsCURVE
object with curve variables likeGx
,Gy
,Fp
(field),n
(order)utils
object withrandomPrivateKey()
,mod()
,invert()
methods (mod CURVE.P
)
- All arithmetics is done with JS bigints over finite fields, which is defined from
modular
sub-module - Many features require hashing, which is not provided.
@noble/hashes
can be used for this purpose. Any other library must conform to the CHash interface:export type CHash = { (message: Uint8Array): Uint8Array; blockLen: number; outputLen: number; create(): any; };
- w-ary non-adjacent form (wNAF) method with constant-time adjustments is used for point multiplication.
It is possible to enable precomputes for edwards & weierstrass curves.
Precomputes are calculated once (takes ~20-40ms), after that most
G
base point multiplications: for example,getPublicKey()
,sign()
and similar methods - would be much faster. Usecurve.utils.precompute()
to adjust precomputation window size - You could use optional special params to tune performance:
Field({sqrt})
square root calculation, used for point decompressionendo
endomorphism options for Koblitz curves
abstract/edwards: Twisted Edwards curve
Twisted Edwards curve's formula is: ax² + y² = 1 + dx²y².
- You must specify curve params
a
,d
, fieldFp
, ordern
, cofactorh
and coordinatesGx
,Gy
of generator point - For EdDSA signatures, params
hash
is also required.adjustScalarBytes
which instructs how to change private scalars could be specified
import { twistedEdwards } from '@noble/curves/abstract/edwards';
import { div } from '@noble/curves/abstract/modular';
import { sha512 } from '@noble/hashes/sha512';
const ed25519 = twistedEdwards({
a: -1n,
d: div(-121665n, 121666n, 2n ** 255n - 19n), // -121665n/121666n
P: 2n ** 255n - 19n,
n: 2n ** 252n + 27742317777372353535851937790883648493n,
h: 8n,
Gx: 15112221349535400772501151409588531511454012693041857206046113283949847762202n,
Gy: 46316835694926478169428394003475163141307993866256225615783033603165251855960n,
hash: sha512,
randomBytes,
adjustScalarBytes(bytes) {
// optional in general, mandatory in ed25519
bytes[0] &= 248;
bytes[31] &= 127;
bytes[31] |= 64;
return bytes;
},
} as const);
const key = ed25519.utils.randomPrivateKey();
const pub = ed25519.getPublicKey(key);
const msg = new TextEncoder().encode('hello world'); // strings not accepted, must be Uint8Array
const sig = ed25519.sign(msg, key);
ed25519.verify(sig, msg, pub) === true;
twistedEdwards()
returns CurveFn
of following type:
export type CurveFn = {
CURVE: ReturnType<typeof validateOpts>;
getPublicKey: (privateKey: PrivKey, isCompressed?: boolean) => Uint8Array;
sign: (message: Hex, privateKey: Hex) => Uint8Array;
verify: (sig: SigType, message: Hex, publicKey: PubKey) => boolean;
Point: PointConstructor;
ExtendedPoint: ExtendedPointConstructor;
Signature: SignatureConstructor;
utils: {
randomPrivateKey: () => Uint8Array;
getExtendedPublicKey: (key: PrivKey) => {
head: Uint8Array;
prefix: Uint8Array;
scalar: bigint;
point: PointType;
pointBytes: Uint8Array;
};
};
};
abstract/montgomery: Montgomery curve
For now the module only contains methods for x-only ECDH on Curve25519 / Curve448 from RFC7748.
Proper Elliptic Curve Points are not implemented yet.
You must specify curve field, a24
special variable, montgomeryBits
, nByteLength
, and coordinate u
of generator point.
import { montgomery } from '@noble/curves/abstract/montgomery';
const x25519 = montgomery({
P: 2n ** 255n - 19n,
a24: 121665n, // TODO: change to a
montgomeryBits: 255,
nByteLength: 32,
Gu: '0900000000000000000000000000000000000000000000000000000000000000',
// Optional params
powPminus2: (x: bigint): bigint => {
return mod.pow(x, P - 2, P);
},
adjustScalarBytes(bytes) {
bytes[0] &= 248;
bytes[31] &= 127;
bytes[31] |= 64;
return bytes;
},
});
abstract/weierstrass: Short Weierstrass curve
Short Weierstrass curve's formula is: y² = x³ + ax + b. Uses deterministic ECDSA from RFC6979. You can also specify extraEntropy
in sign()
.
- You must specify curve params:
a
,b
, fieldFp
, ordern
, cofactorh
and coordinatesGx
,Gy
of generator point - For ECDSA, you must specify
hash
,hmac
. It is also possible to recover keys from signatures - For ECDH, use
getSharedSecret(privKeyA, pubKeyB)
- Optional params are
lowS
(default value) andendo
(endomorphism)
import { Field } from '@noble/curves/abstract/modular';
import { weierstrass } from '@noble/curves/abstract/weierstrass'; // Short Weierstrass curve
import { sha256 } from '@noble/hashes/sha256';
import { hmac } from '@noble/hashes/hmac';
import { concatBytes, randomBytes } from '@noble/hashes/utils';
const secp256k1 = weierstrass({
a: 0n,
b: 7n,
Fp: Field(2n ** 256n - 2n ** 32n - 2n ** 9n - 2n ** 8n - 2n ** 7n - 2n ** 6n - 2n ** 4n - 1n),
n: 2n ** 256n - 432420386565659656852420866394968145599n,
Gx: 55066263022277343669578718895168534326250603453777594175500187360389116729240n,
Gy: 32670510020758816978083085130507043184471273380659243275938904335757337482424n,
hash: sha256,
hmac: (k: Uint8Array, ...msgs: Uint8Array[]) => hmac(sha256, key, concatBytes(...msgs)),
randomBytes,
h: 1n, // cofactor
});
// Optional weierstrass params:
// lowS: true, // Allow only low-S signatures by default in sign() and verify()
// endo: {
// // Endomorphism options for Koblitz curve
// // Beta param
// beta: 0x7ae96a2b657c07106e64479eac3434e99cf0497512f58995c1396c28719501een,
// // Split scalar k into k1, k2
// splitScalar: (k: bigint) => {
// // return { k1neg: true, k1: 512n, k2neg: false, k2: 448n };
// },
// },
// Usage
const key = secp256k1.utils.randomPrivateKey();
const pub = secp256k1.getPublicKey(key);
const msg = randomBytes(32);
const sig = secp256k1.sign(msg, key);
secp256k1.verify(sig, msg, pub); // true
sig.recoverPublicKey(msg); // == pub
const someonesPubkey = secp256k1.getPublicKey(secp256k1.utils.randomPrivateKey());
const shared = secp256k1.getSharedSecret(key, someonesPubkey);
weierstrass()
returns CurveFn
:
export type CurveFn = {
CURVE: ReturnType<typeof validateOpts>;
getPublicKey: (privateKey: PrivKey, isCompressed?: boolean) => Uint8Array;
getSharedSecret: (privateA: PrivKey, publicB: Hex, isCompressed?: boolean) => Uint8Array;
sign: (msgHash: Hex, privKey: PrivKey, opts?: SignOpts) => SignatureType;
verify: (
signature: Hex | SignatureType,
msgHash: Hex,
publicKey: Hex,
opts?: { lowS?: boolean }
) => boolean;
Point: PointConstructor;
ProjectivePoint: ProjectivePointConstructor;
Signature: SignatureConstructor;
utils: {
isValidPrivateKey(privateKey: PrivKey): boolean;
hashToPrivateKey: (hash: Hex) => Uint8Array;
randomPrivateKey: () => Uint8Array;
};
};
abstract/hash-to-curve: Hashing strings to curve points
The module allows to hash arbitrary strings to elliptic curve points.
-
expand_message_xmd
(spec) produces a uniformly random byte string using a cryptographic hash function H that outputs b bits..function expand_message_xmd( msg: Uint8Array, DST: Uint8Array, lenInBytes: number, H: CHash ): Uint8Array; function expand_message_xof( msg: Uint8Array, DST: Uint8Array, lenInBytes: number, k: number, H: CHash ): Uint8Array;
-
hash_to_field(msg, count, options)
(spec) hashes arbitrary-length byte strings to a list of one or more elements of a finite field F. _msg
a byte string containing the message to hash _count
the number of elements of F to output _options
{DST: string, p: bigint, m: number, k: number, expand: 'xmd' | 'xof', hash: H}
_ Returns[u_0, ..., u_(count - 1)]
, a list of field elements.```ts function hash_to_field(msg: Uint8Array, count: number, options: htfOpts): bigint[][]; type htfOpts = { // DST: a domain separation tag // defined in section 2.2.5 DST: string; // p: the characteristic of F // where F is a finite field of characteristic p and order q = p^m p: bigint; // m: the extension degree of F, m >= 1 // where F is a finite field of characteristic p and order q = p^m m: number; // k: the target security level for the suite in bits // defined in section 5.1 k: number; // option to use a message that has already been processed by // expand_message_xmd expand?: 'xmd' | 'xof'; // Hash functions for: expand_message_xmd is appropriate for use with a // wide range of hash functions, including SHA-2, SHA-3, BLAKE2, and others. // BBS+ uses blake2: https://github.com/hyperledger/aries-framework-go/issues/2247 // TODO: verify that hash is shake if expand==='xof' via types hash: CHash; }; ```
abstract/poseidon: Poseidon hash
Implements Poseidon ZK-friendly hash.
There are many poseidon instances with different constants. We don't provide them, but we provide ability to specify them manually. For actual usage, check out stark curve source code.
import { poseidon } from '@noble/curves/abstract/poseidon';
type PoseidonOpts = {
Fp: Field<bigint>;
t: number;
roundsFull: number;
roundsPartial: number;
sboxPower?: number;
reversePartialPowIdx?: boolean; // Hack for stark
mds: bigint[][];
roundConstants: bigint[][];
};
const instance = poseidon(opts: PoseidonOpts);
abstract/bls
The pairing-friendly Barreto-Lynn-Scott elliptic curve construction allows to:
- Construct zk-SNARKs at the 128-bit security
- Use threshold signatures, which allows a user to sign lots of messages with one signature and verify them swiftly in a batch, using Boneh-Lynn-Shacham signature scheme.
Compatible with Algorand, Chia, Dfinity, Ethereum, FIL, Zcash. Matches specs pairing-curves-10, bls-sigs-04, hash-to-curve-12. To learn more about internals, navigate to utilities section.
Resources that help to understand bls12-381:
- BLS12-381 for the rest of us
- Key concepts of pairings
- Pairing over bls12-381: part 1, part 2, part 3
- Estimating the bit security of pairing-friendly curves
- Check out the online demo and threshold sigs demo
- See BBS signatures implementation based on the library, following draft-irtf-cfrg-bbs-signatures-latest
The library uses G1 for public keys and G2 for signatures. Adding support for G1 signatures is planned.
- BLS Relies on Bilinear Pairing (expensive)
- Private Keys: 32 bytes
- Public Keys: 48 bytes: 381 bit affine x coordinate, encoded into 48 big-endian bytes.
- Signatures: 96 bytes: two 381 bit integers (affine x coordinate), encoded into two 48 big-endian byte arrays.
- The signature is a point on the G2 subgroup, which is defined over a finite field with elements twice as big as the G1 curve (G2 is over Fp2 rather than Fp. Fp2 is analogous to the complex numbers).
- The 12 stands for the Embedding degree.
Formulas:
P = pk x G
- public keysS = pk x H(m)
- signinge(P, H(m)) == e(G, S)
- verification using pairingse(G, S) = e(G, SUM(n)(Si)) = MUL(n)(e(G, Si))
- signature aggregation
The BLS parameters for the library are:
PK_IN
G1
HASH_OR_ENCODE
true
DST
BLS_SIG_BLS12381G2_XMD:SHA-256_SSWU_RO_NUL_
- usebls.utils.getDSTLabel()
&bls.utils.setDSTLabel("...")
to read/change the Domain Separation Tag labelRAND_BITS
64
Filecoin uses little endian byte arrays for private keys - so ensure to reverse byte order if you'll use it with FIL.
abstract/modular
Modular arithmetics utilities.
import { Field, mod, invert, div, invertBatch, sqrt } from '@noble/curves/abstract/modular';
const fp = Field(2n ** 255n - 19n); // Finite field over 2^255-19
fp.mul(591n, 932n);
fp.pow(481n, 11024858120n);
// Generic non-FP 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
div(5n, 17n, 10n); // 5/17 mod 10 == 5 * invert(17) mod 10; division
invertBatch([1n, 2n, 4n], 21n); // => [1n, 11n, 16n] in one inversion
sqrt(21n, 73n); // √21 mod 73; square root
abstract/utils
import * as utils from '@noble/curves/abstract/utils';
utils.bytesToHex(Uint8Array.from([0xde, 0xad, 0xbe, 0xef]));
utils.hexToBytes('deadbeef');
utils.hexToNumber();
utils.bytesToNumberBE(Uint8Array.from([0xde, 0xad, 0xbe, 0xef]));
utils.bytesToNumberLE(Uint8Array.from([0xde, 0xad, 0xbe, 0xef]));
utils.numberToBytesBE(123n);
utils.numberToBytesLE(123n);
utils.numberToHexUnpadded(123n);
utils.concatBytes(Uint8Array.from([0xde, 0xad]), Uint8Array.from([0xbe, 0xef]));
utils.nLength(255n);
utils.hashToPrivateScalar(sha512_of_something, secp256r1.n);
utils.equalBytes(Uint8Array.from([0xde]), Uint8Array.from([0xde]));
Additional examples
secp256k1 schnorr:
import { schnorr } from '@noble/curves/secp256k1';
const priv = schnorr.utils.randomPrivateKey();
const pub = schnorr.getPublicKey(priv);
const msg = new TextEncoder().encode('hello');
const sig = schnorr.sign(msg, priv);
const isValid = schnorr.verify(sig, msg, pub);
console.log(isValid);
ed25519, x25519, ristretto255:
import { ed25519, ed25519ctx, ed25519ph, x25519, RistrettoPoint } from '@noble/curves/ed25519';
bls12_381
import { bls12_381 as bls } from '@noble/curves/bls12-381';
// keys, messages & other inputs can be Uint8Arrays or hex strings
const privateKey = '67d53f170b908cabb9eb326c3c337762d59289a8fec79f7bc9254b584b73265c';
const message = '64726e3da8';
const publicKey = bls.getPublicKey(privateKey);
const signature = bls.sign(message, privateKey);
const isValid = bls.verify(signature, message, publicKey);
console.log({ publicKey, signature, isValid });
// Sign 1 msg with 3 keys
const privateKeys = [
'18f020b98eb798752a50ed0563b079c125b0db5dd0b1060d1c1b47d4a193e1e4',
'ed69a8c50cf8c9836be3b67c7eeff416612d45ba39a5c099d48fa668bf558c9c',
'16ae669f3be7a2121e17d0c68c05a8f3d6bef21ec0f2315f1d7aec12484e4cf5'
];
const messages = ['d2', '0d98', '05caf3'];
const publicKeys = privateKeys.map(bls.getPublicKey);
const signatures2 = privateKeys.map(p => bls.sign(message, p))
const aggPubKey2 = bls.aggregatePublicKeys(publicKeys);
const aggSignature2 = bls.aggregateSignatures(signatures2);
const isValid2 = bls.verify(aggSignature2, message, aggPubKey2);
console.log({ signatures2, aggSignature2, isValid2 });
// Sign 3 msgs with 3 keys
const signatures3 = privateKeys.map((p, i) => bls.sign(messages[i], p));
const aggSignature3 = bls.aggregateSignatures(signatures3);
const isValid3 = bls.verifyBatch(aggSignature3, messages, publicKeys);
console.log({ publicKeys, signatures3, aggSignature3, isValid3 });
// Pairing API
// bls.pairing(PointG1, PointG2)
Security
The library had no prior security audit.
Timing attack considerations: JIT-compiler and Garbage Collector make "constant time" extremely hard to achieve in a scripting language. Which means any other JS library can't have constant-timeness. Even statically typed Rust, a language without GC, makes it harder to achieve constant-time for some cases. If your goal is absolute security, don't use any JS lib — including bindings to native ones. Use low-level libraries & languages. Nonetheless we're targetting algorithmic constant time.
We consider infrastructure attacks like rogue NPM modules very important; that's why it's crucial to minimize the amount of 3rd-party dependencies & native bindings. If your app uses 500 dependencies, any dep could get hacked and you'll be downloading malware with every npm install
. Our goal is to minimize this attack vector.
Speed
Benchmark results on Apple M2 with node v18.10:
secp256k1
init x 57 ops/sec @ 17ms/op
getPublicKey x 4,946 ops/sec @ 202μs/op
sign x 3,914 ops/sec @ 255μs/op
verify x 682 ops/sec @ 1ms/op
getSharedSecret x 427 ops/sec @ 2ms/op
recoverPublicKey x 683 ops/sec @ 1ms/op
schnorr.sign x 539 ops/sec @ 1ms/op
schnorr.verify x 716 ops/sec @ 1ms/op
P256
init x 30 ops/sec @ 32ms/op
getPublicKey x 5,008 ops/sec @ 199μs/op
sign x 3,970 ops/sec @ 251μs/op
verify x 515 ops/sec @ 1ms/op
P384
init x 14 ops/sec @ 66ms/op
getPublicKey x 2,434 ops/sec @ 410μs/op
sign x 1,942 ops/sec @ 514μs/op
verify x 206 ops/sec @ 4ms/op
P521
init x 7 ops/sec @ 126ms/op
getPublicKey x 1,282 ops/sec @ 779μs/op
sign x 1,077 ops/sec @ 928μs/op
verify x 110 ops/sec @ 9ms/op
ed25519
init x 37 ops/sec @ 26ms/op
getPublicKey x 8,147 ops/sec @ 122μs/op
sign x 3,979 ops/sec @ 251μs/op
verify x 848 ops/sec @ 1ms/op
ed448
init x 17 ops/sec @ 58ms/op
getPublicKey x 3,083 ops/sec @ 324μs/op
sign x 1,473 ops/sec @ 678μs/op
verify x 323 ops/sec @ 3ms/op
bls12-381
init x 30 ops/sec @ 33ms/op
getPublicKey x 788 ops/sec @ 1ms/op
sign x 45 ops/sec @ 21ms/op
verify x 32 ops/sec @ 30ms/op
pairing x 88 ops/sec @ 11ms/op
stark
init x 31 ops/sec @ 31ms/op
pedersen
├─old x 84 ops/sec @ 11ms/op
└─noble x 802 ops/sec @ 1ms/op
poseidon x 7,466 ops/sec @ 133μs/op
verify
├─old x 300 ops/sec @ 3ms/op
└─noble x 474 ops/sec @ 2ms/op
Upgrading
If you're coming from single-curve noble packages, the following changes need to be kept in mind:
- 2d affine (x, y) points have been removed to reduce complexity and improve speed
- Removed
number
support as a type for private keys.bigint
is still supported mod
,invert
are no longer present inutils
. Use@noble/curves/abstract/modular.js
now.
Upgrading from @noble/secp256k1 1.7:
- Compressed (33-byte) public keys are now returned by default, instead of uncompressed
- Methods are now synchronous. Setting
secp.utils.hmacSha256
is no longer required sign()
der
,recovered
options were removedcanonical
was renamed tolowS
- Return type is now
{ r: bigint, s: bigint, recovery: number }
instance ofSignature
verify()
strict
was renamed tolowS
recoverPublicKey()
: moved to sig instanceSignature#recoverPublicKey(msgHash)
Point
was removed: useProjectivePoint
in xyz coordinatesutils
: Many methods were removed, others were moved toschnorr
namespace
Upgrading from @noble/ed25519 1.7:
- Methods are now synchronous. Setting
secp.utils.hmacSha256
is no longer required - ed25519ph, ed25519ctx
Point
was removed: useExtendedPoint
in xyzt coordinatesSignature
was removedgetSharedSecret
was removed: use separate x25519 sub-modulebigint
is no longer allowed ingetPublicKey
,sign
,verify
. Reason: ed25519 is LE, can lead to bugs
Contributing & testing
- Clone the repository
npm install
to install build dependencies like TypeScriptnpm run build
to compile TypeScript codenpm run test
will execute all main tests
License
The MIT License (MIT)
Copyright (c) 2022 Paul Miller (https://paulmillr.com)
See LICENSE file.