2022-12-03 13:08:49 +03:00
# noble-curves
2023-02-12 13:30:55 +03:00
Audited & minimal JS implementation of elliptic curve cryptography.
2022-12-03 13:08:49 +03:00
2023-02-12 13:30:55 +03:00
- **noble** family, zero dependencies
2022-12-24 16:04:06 +03:00
- Short Weierstrass, Edwards, Montgomery curves
2022-12-28 09:32:27 +03:00
- ECDSA, EdDSA, Schnorr, BLS signature schemes, ECDH key agreement
2023-02-12 13:30:55 +03:00
- #️ ⃣ [hash to curve ](https://datatracker.ietf.org/doc/draft-irtf-cfrg-hash-to-curve/ )
for encoding or hashing an arbitrary string to an elliptic curve point
- 🧜♂️ [Poseidon ](https://www.poseidon-hash.info ) ZK-friendly hash
2023-01-26 08:31:16 +03:00
- 🏎 [Ultra-fast ](#speed ), hand-optimized for caveats of JS engines
2022-12-24 16:04:06 +03:00
- 🔍 Unique tests ensure correctness. Wycheproof vectors included
2022-12-31 12:00:29 +03:00
- 🔻 Tree-shaking-friendly: there is no entry point, which ensures small size of your app
2022-12-03 13:08:49 +03:00
2023-01-29 07:10:58 +03:00
Package consists of two parts:
2022-12-09 23:17:29 +03:00
2023-02-12 23:37:27 +03:00
1. [Abstract ](#abstract-api ), zero-dependency EC algorithms
2. [Implementations ](#implementations ), utilizing one dependency `@noble/hashes` , providing ready-to-use:
2022-12-28 10:04:55 +03:00
- NIST curves secp192r1/P192, secp224r1/P224, secp256r1/P256, secp384r1/P384, secp521r1/P521
- SECG curve secp256k1
2023-02-12 23:37:27 +03:00
- ed25519/curve25519/x25519/ristretto255, edwards448/curve448/x448 RFC7748 / RFC8032 / ZIP215 stuff
2023-02-12 13:30:55 +03:00
- pairing-friendly curves bls12-381, bn254
2022-12-03 13:08:49 +03:00
2023-02-12 23:37:27 +03:00
Check out [Upgrading ](#upgrading ) if you've previously used single-feature noble packages
([secp256k1](https://github.com/paulmillr/noble-secp256k1), [ed25519 ](https://github.com/paulmillr/noble-ed25519 )).
See [Examples ](#examples ) for real-world software that uses curves.
2022-12-03 13:08:49 +03:00
### This library belongs to _noble_ crypto
> **noble-crypto** — high-security, easily auditable set of contained cryptographic libraries and tools.
2023-02-12 13:30:55 +03:00
- No dependencies, protection against supply chain attacks
2022-12-03 13:08:49 +03:00
- 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 ](https://paulmillr.com/noble/ ) & all libraries:
2023-02-06 22:50:23 +03:00
[curves ](https://github.com/paulmillr/noble-curves )
([secp256k1](https://github.com/paulmillr/noble-secp256k1),
[ed25519 ](https://github.com/paulmillr/noble-ed25519 )),
2022-12-24 16:04:06 +03:00
[hashes ](https://github.com/paulmillr/noble-hashes )
2022-12-03 13:08:49 +03:00
## Usage
2023-02-12 13:30:55 +03:00
Use NPM for browser / node.js:
2022-12-03 13:08:49 +03:00
2022-12-17 01:12:26 +03:00
> npm install @noble/curves
2022-12-03 13:08:49 +03:00
2023-02-12 23:37:27 +03:00
For [Deno ](https://deno.land ), use it with npm specifier. In browser, you could also include the single file from
2023-02-12 13:30:55 +03:00
[GitHub's releases page ](https://github.com/paulmillr/noble-curves/releases ).
2023-02-12 23:37:27 +03:00
The library is tree-shaking-friendly and does not expose root entry point as `import * from '@noble/curves'` .
Instead, you need to import specific primitives. This is done to ensure small size of your apps.
### Implementations
Each curve can be used in the following way:
```ts
import { secp256k1 } from '@noble/curves/secp256k1'; // ECMAScript Modules (ESM) and Common.js
// import { secp256k1 } from 'npm:@noble/curves@1.2.0/secp256k1'; // Deno
const priv = secp256k1.utils.randomPrivateKey();
const pub = secp256k1.getPublicKey(priv); // keys & other inputs can be Uint8Array-s or hex strings
const msg = new Uint8Array(32).fill(1);
const sig = secp256k1.sign(msg, priv);
secp256k1.verify(sig, msg, pub) === true;
```
All curves:
2022-12-28 09:52:04 +03:00
2023-02-12 13:30:55 +03:00
```typescript
2023-02-12 23:37:27 +03:00
import { secp256k1, schnorr } from '@noble/curves/secp256k1';
2022-12-28 09:52:04 +03:00
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';
```
2023-02-12 23:37:27 +03:00
Weierstrass curves feature recovering public keys from signatures and ECDH key agreement:
2023-02-06 22:50:23 +03:00
```ts
2023-02-12 23:37:27 +03:00
// extraEntropy https://moderncrypto.org/mail-archive/curves/2017/000925.html
const sigImprovedSecurity = secp256k1.sign(msg, priv, { extraEntropy: true });
sig.recoverPublicKey(msg) === pub; // public key recovery
2023-02-06 22:50:23 +03:00
const someonesPub = secp256k1.getPublicKey(secp256k1.utils.randomPrivateKey());
2023-02-12 23:37:27 +03:00
const shared = secp256k1.getSharedSecret(priv, someonesPub); // ECDH (elliptic curve diffie-hellman)
```
secp256k1 has schnorr signature implementation which follows
[BIP340 ](https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki ):
```ts
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 module has ed25519ctx / ed25519ph variants,
x25519 ECDH and [ristretto255 ](https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-ristretto255-decaf448 ):
```ts
import { ed25519 } from '@noble/curves/ed25519';
import { ed25519ctx, ed25519ph, x25519, RistrettoPoint } from '@noble/curves/ed25519';
x25519.getSharedSecret()
const pub = ed25519.curve25519.scalarMultBase(privateKey);
const shared = ed25519.curve25519.scalarMult(privateKeyA, publicKeyB);
```
BLS12-381 pairing-friendly Barreto-Lynn-Scott elliptic curve construction allows to
construct [zk-SNARKs ](https://z.cash/technology/zksnarks/ ) at the 128-bit security
and use aggregated, batch-verifiable
[threshold signatures ](https://medium.com/snigirev.stepan/bls-signatures-better-than-schnorr-5a7fe30ea716 ),
using Boneh-Lynn-Shacham signature scheme.
```ts
import { bls12_381 as bls } from '@noble/curves/bls12-381';
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)
2023-02-06 22:50:23 +03:00
```
2023-02-12 23:37:27 +03:00
## Abstract API
Abstract API allows to define custom curves. All arithmetics is done with JS bigints over finite fields,
which is defined from `modular` sub-module. For scalar multiplication, we use w-ary non-adjacent form (wNAF) method.
2022-12-28 10:04:55 +03:00
2023-02-12 23:37:27 +03:00
Precomputes are enabled for weierstrass and edwards BASE points of a curve. You could precompute
any other point (e.g. for ECDH) using `utils.precompute()` method.
2022-12-28 10:04:55 +03:00
2023-02-12 23:37:27 +03:00
There are following zero-dependency algorithms:
- [abstract/weierstrass: Short Weierstrass curve ](#abstractweierstrass-short-weierstrass-curve )
2022-12-31 12:29:25 +03:00
- [abstract/edwards: Twisted Edwards curve ](#abstractedwards-twisted-edwards-curve )
- [abstract/montgomery: Montgomery curve ](#abstractmontgomery-montgomery-curve )
- [abstract/hash-to-curve: Hashing strings to curve points ](#abstracthash-to-curve-hashing-strings-to-curve-points )
2023-01-26 08:31:16 +03:00
- [abstract/poseidon: Poseidon hash ](#abstractposeidon-poseidon-hash )
2022-12-31 12:29:25 +03:00
- [abstract/modular ](#abstractmodular )
- [abstract/utils ](#abstractutils )
2022-12-28 10:04:55 +03:00
2023-02-12 23:37:27 +03:00
### abstract/weierstrass: Short Weierstrass curve
2022-12-28 09:52:04 +03:00
```ts
import { weierstrass } from '@noble/curves/abstract/weierstrass';
```
2023-02-12 23:37:27 +03:00
Short Weierstrass curve's formula is `y² = x³ + ax + b` . `weierstrass` expects arguments `a` , `b` , field `Fp` , curve order `n` , cofactor `h`
and coordinates `Gx` , `Gy` of generator point.
**`k` generation** is done deterministically, following [RFC6979 ](https://www.rfc-editor.org/rfc/rfc6979 ).
For this you will need `hmac` & `hash` , which in our implementations is provided by noble-hashes.
If you're using different hashing library, make sure to wrap it in the following interface:
```ts
export type CHash = {
(message: Uint8Array): Uint8Array;
blockLen: number;
outputLen: number;
create(): any;
};
```
**Weierstrass points:**
1. Exported as `ProjectivePoint`
2. Represented in projective (homogeneous) coordinates: (x, y, z) ∋ (x=x/z, y=y/z)
3. Use complete exception-free formulas for addition and doubling
4. Can be decoded/encoded from/to Uint8Array / hex strings using `ProjectivePoint.fromHex` and `ProjectivePoint#toRawBytes()`
5. Have `assertValidity()` which checks for being on-curve
6. Have `toAffine()` and `x` / `y` getters which convert to 2d xy affine coordinates
2022-12-28 10:04:55 +03:00
```ts
2023-02-12 23:37:27 +03:00
// T is usually bigint, but can be something else like complex numbers in BLS curves
export interface ProjPointType< T > extends Group< ProjPointType < T > > {
readonly px: T;
readonly py: T;
readonly pz: T;
multiply(scalar: bigint): ProjPointType< T > ;
multiplyUnsafe(scalar: bigint): ProjPointType< T > ;
multiplyAndAddUnsafe(Q: ProjPointType< T > , a: bigint, b: bigint): ProjPointType< T > | undefined;
toAffine(iz?: T): AffinePoint< T > ;
isTorsionFree(): boolean;
clearCofactor(): ProjPointType< T > ;
assertValidity(): void;
hasEvenY(): boolean;
toRawBytes(isCompressed?: boolean): Uint8Array;
toHex(isCompressed?: boolean): string;
}
// Static methods for 3d XYZ points
export interface ProjConstructor< T > extends GroupConstructor< ProjPointType < T > > {
new (x: T, y: T, z: T): ProjPointType< T > ;
fromAffine(p: AffinePoint< T > ): ProjPointType< T > ;
fromHex(hex: Hex): ProjPointType< T > ;
fromPrivateKey(privateKey: PrivKey): ProjPointType< T > ;
}
```
**ECDSA signatures** are represented by `Signature` instances and can be described by the interface:
```ts
export interface SignatureType {
readonly r: bigint;
readonly s: bigint;
readonly recovery?: number;
assertValidity(): void;
addRecoveryBit(recovery: number): SignatureType;
hasHighS(): boolean;
normalizeS(): SignatureType;
recoverPublicKey(msgHash: Hex): ProjPointType< bigint > ;
toCompactRawBytes(): Uint8Array;
toCompactHex(): string;
// DER-encoded
toDERRawBytes(isCompressed?: boolean): Uint8Array;
toDERHex(isCompressed?: boolean): string;
}
```
Example implementing [secq256k1 ](https://personaelabs.org/posts/spartan-ecdsa ) (NOT secp256k1)
[cycle ](https://zcash.github.io/halo2/background/curves.html#cycles-of-curves ) of secp256k1 with Fp/N flipped.
```typescript
import { weierstrass } from '@noble/curves/abstract/weierstrass';
import { Field } from '@noble/curves/abstract/modular'; // finite field, mod arithmetics done over it
2023-02-12 13:30:55 +03:00
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
2023-02-12 23:37:27 +03:00
const secq256k1 = weierstrass({ // secq256k1: cycle of secp256k1 with Fp/N flipped.
2022-12-28 10:04:55 +03:00
a: 0n,
b: 7n,
2023-02-06 22:50:23 +03:00
Fp: Field(2n ** 256n - 432420386565659656852420866394968145599n),
n: 2n ** 256n - 2n ** 32n - 2n ** 9n - 2n ** 8n - 2n ** 7n - 2n ** 6n - 2n ** 4n - 1n,
2022-12-28 10:04:55 +03:00
Gx: 55066263022277343669578718895168534326250603453777594175500187360389116729240n,
Gy: 32670510020758816978083085130507043184471273380659243275938904335757337482424n,
hash: sha256,
hmac: (key: Uint8Array, ...msgs: Uint8Array[]) => hmac(sha256, key, concatBytes(...msgs)),
randomBytes,
});
2023-02-12 23:37:27 +03:00
// All curves expose same generic interface.
const priv = secq256k1.utils.randomPrivateKey();
secq256k1.getPublicKey(priv); // Convert private key to public.
const sig = secq256k1.sign(msg, priv); // Sign msg with private key.
secq256k1.verify(sig, msg, priv); // Verify if sig is correct.
const point = secq256k1.Point.BASE; // Elliptic curve Point class and BASE point static var.
point.add(point).equals(point.double()); // add(), equals(), double() methods
point.subtract(point).equals(secq256k1.Point.ZERO); // subtract() method, ZERO static var
point.negate(); // Flips point over x/y coordinate.
point.multiply(31415n); // Multiplication of Point by scalar.
point.assertValidity();
point.toAffine(); point.x; point.y; // Converts to 2d affine xy coordinates
secq256k1.CURVE.n;
secq256k1.CURVE.Fp.mod();
secq256k1.CURVE.hash();
2022-12-28 10:04:55 +03:00
```
2023-02-12 23:37:27 +03:00
`weierstrass()` returns `CurveFn` :
```ts
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; prehash?: boolean }
) => boolean;
ProjectivePoint: ProjectivePointConstructor;
Signature: SignatureConstructor;
utils: {
isValidPrivateKey(privateKey: PrivKey): boolean;
randomPrivateKey: () => Uint8Array;
2022-12-28 10:04:55 +03:00
};
2023-02-12 23:37:27 +03:00
};
```
2022-12-17 03:23:16 +03:00
2022-12-28 09:52:04 +03:00
### abstract/edwards: Twisted Edwards curve
2022-12-17 01:12:26 +03:00
2023-02-12 23:37:27 +03:00
Twisted Edwards curve's formula is `ax² + y² = 1 + dx²y²` . You must specify `a` , `d` , field `Fp` , order `n` , cofactor `h`
and coordinates `Gx` , `Gy` of generator point.
2022-12-16 00:42:30 +03:00
2023-02-12 23:37:27 +03:00
For EdDSA signatures, `hash` param required. `adjustScalarBytes` which instructs how to change private scalars could be specified.
2022-12-17 01:12:26 +03:00
2023-02-12 13:30:55 +03:00
```ts
2022-12-28 09:52:04 +03:00
import { twistedEdwards } from '@noble/curves/abstract/edwards';
import { div } from '@noble/curves/abstract/modular';
2022-12-16 00:42:30 +03:00
import { sha512 } from '@noble/hashes/sha512';
const ed25519 = twistedEdwards({
a: -1n,
2022-12-28 09:52:04 +03:00
d: div(-121665n, 121666n, 2n ** 255n - 19n), // -121665n/121666n
2022-12-16 01:11:40 +03:00
P: 2n ** 255n - 19n,
n: 2n ** 252n + 27742317777372353535851937790883648493n,
2022-12-16 00:42:30 +03:00
h: 8n,
Gx: 15112221349535400772501151409588531511454012693041857206046113283949847762202n,
Gy: 46316835694926478169428394003475163141307993866256225615783033603165251855960n,
hash: sha512,
randomBytes,
2022-12-28 10:04:55 +03:00
adjustScalarBytes(bytes) {
2023-02-12 23:37:27 +03:00
// optional; but mandatory in ed25519
2022-12-16 00:42:30 +03:00
bytes[0] & = 248;
bytes[31] & = 127;
bytes[31] |= 64;
return bytes;
},
} as const);
2022-12-03 13:08:49 +03:00
```
2022-12-17 03:23:16 +03:00
`twistedEdwards()` returns `CurveFn` of following type:
```ts
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;
ExtendedPoint: ExtendedPointConstructor;
Signature: SignatureConstructor;
utils: {
randomPrivateKey: () => Uint8Array;
getExtendedPublicKey: (key: PrivKey) => {
head: Uint8Array;
prefix: Uint8Array;
scalar: bigint;
point: PointType;
pointBytes: Uint8Array;
};
};
};
```
2022-12-28 09:52:04 +03:00
### abstract/montgomery: Montgomery curve
2022-12-17 01:12:26 +03:00
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.
```typescript
2022-12-28 09:52:04 +03:00
import { montgomery } from '@noble/curves/abstract/montgomery';
2022-12-17 01:12:26 +03:00
const x25519 = montgomery({
P: 2n ** 255n - 19n,
a24: 121665n, // TODO: change to a
montgomeryBits: 255,
nByteLength: 32,
Gu: '0900000000000000000000000000000000000000000000000000000000000000',
// Optional params
2022-12-28 10:04:55 +03:00
powPminus2: (x: bigint): bigint => {
return mod.pow(x, P - 2, P);
},
2022-12-17 01:12:26 +03:00
adjustScalarBytes(bytes) {
bytes[0] & = 248;
bytes[31] & = 127;
bytes[31] |= 64;
return bytes;
},
});
```
2022-12-31 12:00:29 +03:00
### abstract/hash-to-curve: Hashing strings to curve points
The module allows to hash arbitrary strings to elliptic curve points.
2023-02-12 23:37:27 +03:00
`expand_message_xmd` [(spec) ](https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-11#section-5.4.1 ) produces a uniformly random byte string using a cryptographic hash function H that outputs b bits..
2022-12-31 12:00:29 +03:00
2023-02-12 23:37:27 +03:00
```ts
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;
```
2022-12-31 12:00:29 +03:00
2023-02-12 23:37:27 +03:00
`hash_to_field(msg, count, options)` [(spec) ](https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-11#section-5.3 )
2023-01-30 07:55:36 +03:00
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.
2023-02-12 23:37:27 +03:00
```ts
function hash_to_field(msg: Uint8Array, count: number, options: htfOpts): bigint[][];
type htfOpts = {
DST: string; // a domain separation tag defined in section 2.2.5
// 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: number; // the target security level for the suite in bits defined in section 5.1
expand?: 'xmd' | 'xof'; // option to use a message that has already been processed by expand_message_xmd
// 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;
};
```
2022-12-31 12:00:29 +03:00
2023-01-26 08:31:16 +03:00
### abstract/poseidon: Poseidon hash
Implements [Poseidon ](https://www.poseidon-hash.info ) ZK-friendly hash.
2023-02-12 23:37:27 +03:00
There are many poseidon variants with different constants.
We don't provide them: you should construct them manually.
The only variant provided resides in `stark` module: inspect it for proper usage.
2023-01-26 08:31:16 +03:00
```ts
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);
```
2023-02-12 13:30:55 +03:00
### abstract/bls
2023-02-12 23:37:27 +03:00
The module abstracts BLS (Barreto-Lynn-Scott) primitives. In theory you should be able to write BLS12-377, BLS24,
and others with it.
2023-02-12 13:30:55 +03:00
2022-12-28 09:52:04 +03:00
### abstract/modular
2022-12-17 01:12:26 +03:00
Modular arithmetics utilities.
```typescript
2023-02-12 13:30:55 +03:00
import { Field, mod, invert, div, invertBatch, sqrt } from '@noble/curves/abstract/modular';
const fp = Field(2n ** 255n - 19n); // Finite field over 2^255-19
2022-12-31 12:00:29 +03:00
fp.mul(591n, 932n);
fp.pow(481n, 11024858120n);
// Generic non-FP utils are also available
2022-12-27 05:16:45 +03:00
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
2022-12-17 01:12:26 +03:00
```
2022-12-28 09:52:04 +03:00
### abstract/utils
2022-12-17 01:12:26 +03:00
```typescript
2022-12-28 09:52:04 +03:00
import * as utils from '@noble/curves/abstract/utils';
2022-12-17 01:12:26 +03:00
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]));
```
## Security
The library had no prior security audit.
[Timing attack ](https://en.wikipedia.org/wiki/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 ](https://www.chosenplaintext.ca/open-source/rust-timing-shield/security ) 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
2022-12-14 21:34:30 +03:00
Benchmark results on Apple M2 with node v18.10:
```
2023-01-27 05:48:53 +03:00
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
2022-12-27 05:16:45 +03:00
pedersen
2023-01-27 05:48:53 +03:00
├─old x 84 ops/sec @ 11ms/op
└─noble x 802 ops/sec @ 1ms/op
poseidon x 7,466 ops/sec @ 133μs/op
2022-12-27 05:16:45 +03:00
verify
2023-01-27 05:48:53 +03:00
├─old x 300 ops/sec @ 3ms/op
└─noble x 474 ops/sec @ 2ms/op
2022-12-14 21:34:30 +03:00
```
2023-02-12 23:37:27 +03:00
## Examples
Elliptic curve calculator: [paulmillr.com/ecc ](https://paulmillr.com/ecc ).
- secp256k1
- [btc-signer ](https://github.com/paulmillr/micro-btc-signer ), [eth-signer ](https://github.com/paulmillr/micro-eth-signer )
- ed25519
- [sol-signer ](https://github.com/paulmillr/micro-sol-signer ) for Solana
- BLS12-381
- Threshold sigs demo [genthresh.com ](https://genthresh.com )
- BBS signatures [github.com/Wind4Greg/BBS-Draft-Checks ](https://github.com/Wind4Greg/BBS-Draft-Checks ) following [draft-irtf-cfrg-bbs-signatures-latest ](https://identity.foundation/bbs-signature/draft-irtf-cfrg-bbs-signatures.html )
2023-01-26 05:07:45 +03:00
## Upgrading
2023-01-29 07:10:58 +03:00
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 in `utils` . 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()`
2023-01-30 07:55:36 +03:00
- `der` , `recovered` options were removed
- `canonical` was renamed to `lowS`
- Return type is now `{ r: bigint, s: bigint, recovery: number }` instance of `Signature`
2023-01-29 07:10:58 +03:00
- `verify()`
2023-01-30 07:55:36 +03:00
- `strict` was renamed to `lowS`
2023-01-29 07:10:58 +03:00
- `recoverPublicKey()` : moved to sig instance `Signature#recoverPublicKey(msgHash)`
- `Point` was removed: use `ProjectivePoint` in xyz coordinates
- `utils` : Many methods were removed, others were moved to `schnorr` namespace
Upgrading from @noble/ed25519 1.7:
- Methods are now synchronous. Setting `secp.utils.hmacSha256` is no longer required
- ed25519ph, ed25519ctx
- `Point` was removed: use `ExtendedPoint` in xyzt coordinates
- `Signature` was removed
- `getSharedSecret` was removed: use separate x25519 sub-module
2023-01-30 07:55:36 +03:00
- `bigint` is no longer allowed in `getPublicKey` , `sign` , `verify` . Reason: ed25519 is LE, can lead to bugs
2023-01-26 05:07:45 +03:00
2022-12-17 01:12:26 +03:00
## Contributing & testing
1. Clone the repository
2. `npm install` to install build dependencies like TypeScript
3. `npm run build` to compile TypeScript code
4. `npm run test` will execute all main tests
2022-12-03 13:08:49 +03:00
## License
2022-12-17 01:12:26 +03:00
The MIT License (MIT)
Copyright (c) 2022 Paul Miller [(https://paulmillr.com) ](https://paulmillr.com )
See LICENSE file.