Compare commits
18 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0ffa38db6b | ||
|
|
c4c580edc0 | ||
|
|
abe8adac7b | ||
|
|
4fd2ae82b6 | ||
|
|
e2411f7dfd | ||
|
|
cb61e4f292 | ||
|
|
bb875791bd | ||
|
|
3df2553ced | ||
|
|
8fabc7ff06 | ||
|
|
f3c21eb347 | ||
|
|
a8b8192714 | ||
|
|
1c6aa07ff7 | ||
|
|
e110237298 | ||
|
|
45393db807 | ||
|
|
acc3a9dc4d | ||
|
|
9295b0dbae | ||
|
|
5784ef23f6 | ||
|
|
ef55efe842 |
6
.vscode/settings.json
vendored
Normal file
6
.vscode/settings.json
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"files.exclude": {
|
||||
"*.{js,d.ts,js.map,d.ts.map}": true,
|
||||
"esm/*.{js,d.ts,js.map,d.ts.map}": true
|
||||
}
|
||||
}
|
||||
410
README.md
410
README.md
@@ -1,28 +1,21 @@
|
||||
# noble-curves
|
||||
|
||||
[Audited](#security) & minimal JS implementation of elliptic curve cryptography.
|
||||
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
|
||||
- 🔒 [**Audited**](#security) by an independent security firm
|
||||
- #️⃣ [hash to curve](#abstracthash-to-curve-hashing-strings-to-curve-points)
|
||||
for encoding or hashing an arbitrary string to an elliptic curve point
|
||||
- 🧜♂️ [Poseidon](https://www.poseidon-hash.info) ZK-friendly hash
|
||||
- 🏎 [Ultra-fast](#speed), hand-optimized for caveats of JS engines
|
||||
- 🔍 Unique tests ensure correctness with Wycheproof vectors and [cryptofuzz](https://github.com/guidovranken/cryptofuzz) differential fuzzing
|
||||
- 🔻 Tree-shaking-friendly: there is no entry point, which ensures small size of your app
|
||||
- 🔍 Unique tests ensure correctness with Wycheproof vectors and
|
||||
[cryptofuzz](https://github.com/guidovranken/cryptofuzz) differential fuzzing
|
||||
- 🔻 Tree-shaking-friendly: use only what's necessary, other code won't be included
|
||||
|
||||
Package consists of two parts:
|
||||
|
||||
1. [Abstract](#abstract-api), zero-dependency EC algorithms
|
||||
2. [Implementations](#implementations), utilizing one dependency `@noble/hashes`, providing ready-to-use:
|
||||
- NIST curves secp256r1/P256, secp384r1/P384, secp521r1/P521
|
||||
- SECG curve secp256k1
|
||||
- ed25519/curve25519/x25519/ristretto255, edwards448/curve448/x448 [RFC7748](https://www.rfc-editor.org/rfc/rfc7748) / [RFC8032](https://www.rfc-editor.org/rfc/rfc8032) / [ZIP215](https://zips.z.cash/zip-0215) stuff
|
||||
- pairing-friendly curves bls12-381, bn254
|
||||
|
||||
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)).
|
||||
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 [Resources](#resources) for articles and real-world software that uses curves.
|
||||
|
||||
### This library belongs to _noble_ crypto
|
||||
@@ -30,33 +23,50 @@ See [Resources](#resources) for articles and real-world software that uses curve
|
||||
> **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
|
||||
- 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:
|
||||
[curves](https://github.com/paulmillr/noble-curves)
|
||||
([secp256k1](https://github.com/paulmillr/noble-secp256k1),
|
||||
(4kb versions [secp256k1](https://github.com/paulmillr/noble-secp256k1),
|
||||
[ed25519](https://github.com/paulmillr/noble-ed25519)),
|
||||
[hashes](https://github.com/paulmillr/noble-hashes)
|
||||
|
||||
## Usage
|
||||
|
||||
Use NPM for browser / node.js:
|
||||
Browser, deno and node.js are supported:
|
||||
|
||||
> npm install @noble/curves
|
||||
|
||||
For [Deno](https://deno.land), use it with [npm specifier](https://deno.land/manual@v1.28.0/node/npm_specifiers). In browser, you could also include the single file from
|
||||
For [Deno](https://deno.land), use it with
|
||||
[npm specifier](https://deno.land/manual@v1.28.0/node/npm_specifiers).
|
||||
In browser, you could also include the single file from
|
||||
[GitHub's releases page](https://github.com/paulmillr/noble-curves/releases).
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
Package consists of two parts:
|
||||
|
||||
1. [Implementations](#implementations), utilizing one dependency `@noble/hashes`,
|
||||
providing ready-to-use:
|
||||
- NIST curves secp256r1/P256, secp384r1/P384, secp521r1/P521
|
||||
- SECG curve secp256k1
|
||||
- ed25519/curve25519/x25519/ristretto255, edwards448/curve448/x448
|
||||
implementing
|
||||
[RFC7748](https://www.rfc-editor.org/rfc/rfc7748) /
|
||||
[RFC8032](https://www.rfc-editor.org/rfc/rfc8032) /
|
||||
[ZIP215](https://zips.z.cash/zip-0215) standards
|
||||
- pairing-friendly curves bls12-381, bn254
|
||||
2. [Abstract](#abstract-api), zero-dependency EC algorithms
|
||||
|
||||
### 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 '@noble/curves/secp256k1'; // 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);
|
||||
@@ -64,8 +74,9 @@ const msg = new Uint8Array(32).fill(1);
|
||||
const sig = secp256k1.sign(msg, priv);
|
||||
secp256k1.verify(sig, msg, pub) === true;
|
||||
|
||||
// hex strings are also supported besides Uint8Arrays:
|
||||
const privHex = '46c930bc7bb4db7f55da20798697421b98c4175a52c630294d75a84b9c126236';
|
||||
const pub2 = secp256k1.getPublicKey(privHex); // keys & other inputs can be Uint8Array-s or hex strings
|
||||
const pub2 = secp256k1.getPublicKey(privHex);
|
||||
```
|
||||
|
||||
All curves:
|
||||
@@ -90,7 +101,7 @@ Weierstrass curves feature recovering public keys from signatures and ECDH key a
|
||||
const sigImprovedSecurity = secp256k1.sign(msg, priv, { extraEntropy: true });
|
||||
sig.recoverPublicKey(msg) === pub; // public key recovery
|
||||
const someonesPub = secp256k1.getPublicKey(secp256k1.utils.randomPrivateKey());
|
||||
const shared = secp256k1.getSharedSecret(priv, someonesPub); // ECDH (elliptic curve diffie-hellman)
|
||||
const shared = secp256k1.getSharedSecret(priv, someonesPub); // ECDH
|
||||
```
|
||||
|
||||
secp256k1 has schnorr signature implementation which follows
|
||||
@@ -103,7 +114,6 @@ 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,
|
||||
@@ -134,18 +144,27 @@ RistrettoPoint.hashToCurve('Ristretto is traditionally a short shot of espresso
|
||||
// also has add(), equals(), multiply(), toRawBytes() methods
|
||||
```
|
||||
|
||||
ed448 module is basically the same:
|
||||
ed448 is similar:
|
||||
|
||||
```ts
|
||||
import { ed448, ed448ph, ed448ctx, x448 } from '@noble/curves/ed448';
|
||||
import { hashToCurve, encodeToCurve } from '@noble/curves/ed448';
|
||||
ed448.getPublicKey(ed448.utils.randomPrivateKey());
|
||||
```
|
||||
|
||||
Every curve has params:
|
||||
|
||||
```ts
|
||||
import { secp256k1 } from '@noble/curves/secp256k1'; // ESM and Common.js
|
||||
console.log(secp256k1.CURVE.p, secp256k1.CURVE.n, secp256k1.CURVE.a, secp256k1.CURVE.b);
|
||||
```
|
||||
|
||||
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.
|
||||
using Boneh-Lynn-Shacham signature scheme. Compatible with ETH and others,
|
||||
just make sure to provide correct DST (domain separation tag argument).
|
||||
|
||||
```ts
|
||||
import { bls12_381 as bls } from '@noble/curves/bls12-381';
|
||||
@@ -182,10 +201,13 @@ console.log({ publicKeys, signatures3, aggSignature3, isValid3 });
|
||||
|
||||
## 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 [precomputed tables with w-ary non-adjacent form (wNAF)](https://paulmillr.com/posts/noble-secp256k1-fast-ecc/).
|
||||
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: check out examples.
|
||||
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
|
||||
[precomputed tables with w-ary non-adjacent form (wNAF)](https://paulmillr.com/posts/noble-secp256k1-fast-ecc/).
|
||||
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: check out examples.
|
||||
|
||||
There are following zero-dependency algorithms:
|
||||
|
||||
@@ -201,14 +223,36 @@ There are following zero-dependency algorithms:
|
||||
|
||||
```ts
|
||||
import { weierstrass } from '@noble/curves/abstract/weierstrass';
|
||||
import { Field } from '@noble/curves/abstract/modular'; // finite field for mod arithmetics
|
||||
import { sha256 } from '@noble/hashes/sha256'; // 3rd-party sha256() of type utils.CHash
|
||||
import { hmac } from '@noble/hashes/hmac'; // 3rd-party hmac() that will accept sha256()
|
||||
import { concatBytes, randomBytes } from '@noble/hashes/utils'; // 3rd-party utilities
|
||||
const secq256k1 = weierstrass({
|
||||
// secq256k1: cycle of secp256k1 with Fp/N flipped.
|
||||
// https://personaelabs.org/posts/spartan-ecdsa
|
||||
// https://zcash.github.io/halo2/background/curves.html#cycles-of-curves
|
||||
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,
|
||||
});
|
||||
|
||||
// weierstrassPoints can also be used if you don't need ECDSA, hash, hmac, randomBytes
|
||||
```
|
||||
|
||||
Short Weierstrass curve's formula is `y² = x³ + ax + b`. `weierstrass` expects arguments `a`, `b`, field `Fp`, curve order `n`, cofactor `h`
|
||||
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:
|
||||
**`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
|
||||
type CHash = {
|
||||
@@ -224,11 +268,36 @@ type CHash = {
|
||||
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()`
|
||||
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
|
||||
|
||||
```ts
|
||||
// `weierstrassPoints()` returns `CURVE` and `ProjectivePoint`
|
||||
// `weierstrass()` returns `CurveFn`
|
||||
type SignOpts = { lowS?: boolean; prehash?: boolean; extraEntropy: boolean | Uint8Array };
|
||||
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: {
|
||||
normPrivateKeyToScalar: (key: PrivKey) => bigint;
|
||||
isValidPrivateKey(key: PrivKey): boolean;
|
||||
randomPrivateKey: () => Uint8Array;
|
||||
precompute: (windowSize?: number, point?: ProjPointType<bigint>) => ProjPointType<bigint>;
|
||||
};
|
||||
};
|
||||
|
||||
// T is usually bigint, but can be something else like complex numbers in BLS curves
|
||||
interface ProjPointType<T> extends Group<ProjPointType<T>> {
|
||||
readonly px: T;
|
||||
@@ -254,7 +323,8 @@ interface ProjConstructor<T> extends GroupConstructor<ProjPointType<T>> {
|
||||
}
|
||||
```
|
||||
|
||||
**ECDSA signatures** are represented by `Signature` instances and can be described by the interface:
|
||||
**ECDSA signatures** are represented by `Signature` instances and can be
|
||||
described by the interface:
|
||||
|
||||
```ts
|
||||
interface SignatureType {
|
||||
@@ -279,28 +349,9 @@ type SignatureConstructor = {
|
||||
};
|
||||
```
|
||||
|
||||
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.
|
||||
More examples:
|
||||
|
||||
```typescript
|
||||
import { weierstrass } from '@noble/curves/abstract/weierstrass';
|
||||
import { Field } from '@noble/curves/abstract/modular'; // finite field, mod arithmetics done over it
|
||||
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
|
||||
const secq256k1 = weierstrass({
|
||||
// secq256k1: cycle of secp256k1 with Fp/N flipped.
|
||||
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,
|
||||
});
|
||||
|
||||
// All curves expose same generic interface.
|
||||
const priv = secq256k1.utils.randomPrivateKey();
|
||||
secq256k1.getPublicKey(priv); // Convert private key to public.
|
||||
@@ -318,6 +369,7 @@ point.assertValidity(); // Checks for being on-curve
|
||||
point.toAffine(); // Converts to 2d affine xy coordinates
|
||||
|
||||
secq256k1.CURVE.n;
|
||||
secq256k1.CURVE.p;
|
||||
secq256k1.CURVE.Fp.mod();
|
||||
secq256k1.CURVE.hash();
|
||||
|
||||
@@ -326,33 +378,34 @@ const fast = secq256k1.utils.precompute(8, Point.fromHex(someonesPubKey));
|
||||
fast.multiply(privKey); // much faster ECDH now
|
||||
```
|
||||
|
||||
`weierstrass()` returns `CurveFn`:
|
||||
### abstract/edwards: Twisted Edwards curve
|
||||
|
||||
```ts
|
||||
type SignOpts = { lowS?: boolean; prehash?: boolean; extraEntropy: boolean | Uint8Array };
|
||||
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: {
|
||||
normPrivateKeyToScalar: (key: PrivKey) => bigint;
|
||||
isValidPrivateKey(key: PrivKey): boolean;
|
||||
randomPrivateKey: () => Uint8Array;
|
||||
precompute: (windowSize?: number, point?: ProjPointType<bigint>) => ProjPointType<bigint>;
|
||||
};
|
||||
};
|
||||
```
|
||||
import { twistedEdwards } from '@noble/curves/abstract/edwards';
|
||||
import { Field } from '@noble/curves/abstract/modular';
|
||||
import { sha512 } from '@noble/hashes/sha512';
|
||||
import { randomBytes } from '@noble/hashes/utils';
|
||||
|
||||
### abstract/edwards: Twisted Edwards curve
|
||||
const Fp = Field(2n ** 255n - 19n);
|
||||
const ed25519 = twistedEdwards({
|
||||
a: -1n,
|
||||
d: Fp.div(-121665n, 121666n), // -121665n/121666n mod p
|
||||
Fp: Fp,
|
||||
n: 2n ** 252n + 27742317777372353535851937790883648493n,
|
||||
h: 8n,
|
||||
Gx: 15112221349535400772501151409588531511454012693041857206046113283949847762202n,
|
||||
Gy: 46316835694926478169428394003475163141307993866256225615783033603165251855960n,
|
||||
hash: sha512,
|
||||
randomBytes,
|
||||
adjustScalarBytes(bytes) {
|
||||
// optional; but mandatory in ed25519
|
||||
bytes[0] &= 248;
|
||||
bytes[31] &= 127;
|
||||
bytes[31] |= 64;
|
||||
return bytes;
|
||||
},
|
||||
} as const);
|
||||
```
|
||||
|
||||
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.
|
||||
@@ -370,6 +423,25 @@ For EdDSA signatures, `hash` param required. `adjustScalarBytes` which instructs
|
||||
7. Have `isTorsionFree()`, `clearCofactor()` and `isSmallOrder()` utilities to handle torsions
|
||||
|
||||
```ts
|
||||
// `twistedEdwards()` returns `CurveFn` of following type:
|
||||
type CurveFn = {
|
||||
CURVE: ReturnType<typeof validateOpts>;
|
||||
getPublicKey: (privateKey: Hex) => Uint8Array;
|
||||
sign: (message: Hex, privateKey: Hex, context?: Hex) => Uint8Array;
|
||||
verify: (sig: SigType, message: Hex, publicKey: Hex, context?: Hex) => boolean;
|
||||
ExtendedPoint: ExtPointConstructor;
|
||||
utils: {
|
||||
randomPrivateKey: () => Uint8Array;
|
||||
getExtendedPublicKey: (key: PrivKey) => {
|
||||
head: Uint8Array;
|
||||
prefix: Uint8Array;
|
||||
scalar: bigint;
|
||||
point: PointType;
|
||||
pointBytes: Uint8Array;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
interface ExtPointType extends Group<ExtPointType> {
|
||||
readonly ex: bigint;
|
||||
readonly ey: bigint;
|
||||
@@ -392,69 +464,16 @@ interface ExtPointConstructor extends GroupConstructor<ExtPointType> {
|
||||
}
|
||||
```
|
||||
|
||||
Example implementing edwards25519:
|
||||
|
||||
```ts
|
||||
import { twistedEdwards } from '@noble/curves/abstract/edwards';
|
||||
import { Field, div } from '@noble/curves/abstract/modular';
|
||||
import { sha512 } from '@noble/hashes/sha512';
|
||||
|
||||
const Fp = Field(2n ** 255n - 19n);
|
||||
const ed25519 = twistedEdwards({
|
||||
a: -1n,
|
||||
d: Fp.div(-121665n, 121666n), // -121665n/121666n mod p
|
||||
Fp,
|
||||
n: 2n ** 252n + 27742317777372353535851937790883648493n,
|
||||
h: 8n,
|
||||
Gx: 15112221349535400772501151409588531511454012693041857206046113283949847762202n,
|
||||
Gy: 46316835694926478169428394003475163141307993866256225615783033603165251855960n,
|
||||
hash: sha512,
|
||||
randomBytes,
|
||||
adjustScalarBytes(bytes) {
|
||||
// optional; but mandatory in ed25519
|
||||
bytes[0] &= 248;
|
||||
bytes[31] &= 127;
|
||||
bytes[31] |= 64;
|
||||
return bytes;
|
||||
},
|
||||
} as const);
|
||||
```
|
||||
|
||||
`twistedEdwards()` returns `CurveFn` of following type:
|
||||
|
||||
```ts
|
||||
type CurveFn = {
|
||||
CURVE: ReturnType<typeof validateOpts>;
|
||||
getPublicKey: (privateKey: Hex) => Uint8Array;
|
||||
sign: (message: Hex, privateKey: Hex, context?: Hex) => Uint8Array;
|
||||
verify: (sig: SigType, message: Hex, publicKey: Hex, context?: Hex) => boolean;
|
||||
ExtendedPoint: ExtPointConstructor;
|
||||
utils: {
|
||||
randomPrivateKey: () => Uint8Array;
|
||||
getExtendedPublicKey: (key: PrivKey) => {
|
||||
head: Uint8Array;
|
||||
prefix: Uint8Array;
|
||||
scalar: bigint;
|
||||
point: PointType;
|
||||
pointBytes: Uint8Array;
|
||||
};
|
||||
};
|
||||
};
|
||||
```
|
||||
|
||||
### abstract/montgomery: Montgomery curve
|
||||
|
||||
The module contains methods for x-only ECDH on Curve25519 / Curve448 from RFC7748. Proper Elliptic Curve Points are not implemented yet.
|
||||
|
||||
You must specify curve params `Fp`, `a`, `Gu` coordinate of u, `montgomeryBits` and `nByteLength`.
|
||||
|
||||
```typescript
|
||||
import { montgomery } from '@noble/curves/abstract/montgomery';
|
||||
import { Field } from '@noble/curves/abstract/modular';
|
||||
|
||||
const x25519 = montgomery({
|
||||
Fp: Field(2n ** 255n - 19n),
|
||||
a: 486662n,
|
||||
Gu: 9n,
|
||||
Fp: Field(2n ** 255n - 19n),
|
||||
montgomeryBits: 255,
|
||||
nByteLength: 32,
|
||||
// Optional param
|
||||
@@ -467,6 +486,11 @@ const x25519 = montgomery({
|
||||
});
|
||||
```
|
||||
|
||||
The module contains methods for x-only ECDH on Curve25519 / Curve448 from RFC7748.
|
||||
Proper Elliptic Curve Points are not implemented yet.
|
||||
|
||||
You must specify curve params `Fp`, `a`, `Gu` coordinate of u, `montgomeryBits` and `nByteLength`.
|
||||
|
||||
### abstract/hash-to-curve: Hashing strings to curve points
|
||||
|
||||
The module allows to hash arbitrary strings to elliptic curve points. Implements [hash-to-curve v16](https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-16).
|
||||
@@ -507,19 +531,37 @@ function expand_message_xof(
|
||||
): Uint8Array;
|
||||
```
|
||||
|
||||
`hash_to_field(msg, count, options)` [(spec)](https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-11#section-5.3)
|
||||
`hash_to_field(msg, count, options)`
|
||||
[(spec)](https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-11#section-5.3)
|
||||
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}`.
|
||||
- `p` is field prime, m=field extension (1 for prime fields)
|
||||
- `k` is security target in bits (e.g. 128).
|
||||
- `expand` should be `xmd` for SHA2, SHA3, BLAKE; `xof` for SHAKE, BLAKE-XOF
|
||||
- `hash` conforming to `utils.CHash` interface, with `outputLen` / `blockLen` props
|
||||
- Returns `[u_0, ..., u_(count - 1)]`, a list of field elements.
|
||||
|
||||
```ts
|
||||
/**
|
||||
* * `DST` is a domain separation tag, defined in section 2.2.5
|
||||
* * `p` characteristic of F, where F is a finite field of characteristic p and order q = p^m
|
||||
* * `m` is extension degree (1 for prime fields)
|
||||
* * `k` is the target security target in bits (e.g. 128), from section 5.1
|
||||
* * `expand` is `xmd` (SHA2, SHA3, BLAKE) or `xof` (SHAKE, BLAKE-XOF)
|
||||
* * `hash` conforming to `utils.CHash` interface, with `outputLen` / `blockLen` props
|
||||
*/
|
||||
type UnicodeOrBytes = string | Uint8Array;
|
||||
type Opts = {
|
||||
DST: UnicodeOrBytes;
|
||||
p: bigint;
|
||||
m: number;
|
||||
k: number;
|
||||
expand?: 'xmd' | 'xof';
|
||||
hash: CHash;
|
||||
};
|
||||
|
||||
/**
|
||||
* Hashes arbitrary-length byte strings to a list of one or more elements of a finite field F
|
||||
* https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-11#section-5.3
|
||||
* @param msg a byte string containing the message to hash
|
||||
* @param count the number of elements of F to output
|
||||
* @param options `{DST: string, p: bigint, m: number, k: number, expand: 'xmd' | 'xof', hash: H}`, see above
|
||||
* @returns [u_0, ..., u_(count - 1)], a list of field elements.
|
||||
*/
|
||||
function hash_to_field(msg: Uint8Array, count: number, options: Opts): bigint[][];
|
||||
```
|
||||
|
||||
@@ -704,6 +746,13 @@ hashToCurve
|
||||
└─ed448 x 1,045 ops/sec @ 956μs/op
|
||||
```
|
||||
|
||||
## 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
|
||||
|
||||
## Resources
|
||||
|
||||
Article about some of library's features: [Learning fast elliptic-curve cryptography](https://paulmillr.com/posts/noble-secp256k1-fast-ecc/)
|
||||
@@ -719,45 +768,52 @@ Projects using the library:
|
||||
- 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)
|
||||
- Others
|
||||
- All curves demo: Elliptic curve calculator [paulmillr.com/ecc](https://paulmillr.com/ecc)
|
||||
- All curves demo: Elliptic curve calculator [paulmillr.com/noble](https://paulmillr.com/noble)
|
||||
- [micro-starknet](https://github.com/paulmillr/micro-starknet) for stark-friendly elliptic curve.
|
||||
|
||||
## Upgrading
|
||||
|
||||
If you're coming from single-feature noble packages, the following changes need to be kept in mind:
|
||||
Previously, the library was split into single-feature packages
|
||||
noble-secp256k1 and noble-ed25519. curves can be thought as a continuation of their
|
||||
original work. The libraries now changed their direction towards providing
|
||||
minimal 4kb implementations of cryptography and are not as feature-complete.
|
||||
|
||||
- 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`
|
||||
Upgrading from [@noble/secp256k1](https://github.com/paulmillr/noble-secp256k1) 1.7:
|
||||
|
||||
Upgrading from @noble/secp256k1 1.7:
|
||||
- `getPublicKey`
|
||||
- now produce 33-byte compressed signatures by default
|
||||
- to use old behavior, which produced 65-byte uncompressed keys, set
|
||||
argument `isCompressed` to `false`: `getPublicKey(priv, false)`
|
||||
- `sign`
|
||||
- is now sync; use `signAsync` for async version
|
||||
- now returns `Signature` instance with `{ r, s, recovery }` properties
|
||||
- `canonical` option was renamed to `lowS`
|
||||
- `recovered` option has been removed because recovery bit is always returned now
|
||||
- `der` option has been removed. There are 2 options:
|
||||
1. Use compact encoding: `fromCompact`, `toCompactRawBytes`, `toCompactHex`.
|
||||
Compact encoding is simply a concatenation of 32-byte r and 32-byte s.
|
||||
2. If you must use DER encoding, switch to noble-curves (see above).
|
||||
- `verify`
|
||||
- `strict` option was renamed to `lowS`
|
||||
- `getSharedSecret`
|
||||
- now produce 33-byte compressed signatures by default
|
||||
- to use old behavior, which produced 65-byte uncompressed keys, set
|
||||
argument `isCompressed` to `false`: `getSharedSecret(a, b, false)`
|
||||
- `recoverPublicKey(msg, sig, rec)` was changed to `sig.recoverPublicKey(msg)`
|
||||
- `number` type for private keys have been removed: use `bigint` instead
|
||||
- `Point` (2d xy) has been changed to `ProjectivePoint` (3d xyz)
|
||||
- `utils` were split into `utils` (same api as in noble-curves) and
|
||||
`etc` (`hmacSha256Sync` and others)
|
||||
|
||||
- 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 removed
|
||||
- `canonical` was renamed to `lowS`
|
||||
- Return type is now `{ r: bigint, s: bigint, recovery: number }` instance of `Signature`
|
||||
- `verify()`
|
||||
- `strict` was renamed to `lowS`
|
||||
- `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](https://github.com/paulmillr/noble-ed25519) 1.7:
|
||||
|
||||
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
|
||||
- Methods are now sync by default
|
||||
- `bigint` is no longer allowed in `getPublicKey`, `sign`, `verify`. Reason: ed25519 is LE, can lead to bugs
|
||||
|
||||
## 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
|
||||
- `Point` (2d xy) has been changed to `ExtendedPoint` (xyzt)
|
||||
- `Signature` was removed: just use raw bytes or hex now
|
||||
- `utils` were split into `utils` (same api as in noble-curves) and
|
||||
`etc` (`sha512Sync` and others)
|
||||
- `getSharedSecret` was moved to `x25519` module
|
||||
|
||||
## License
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { run, mark } from 'micro-bmark';
|
||||
import { secp256k1 } from '../secp256k1.js';
|
||||
import { Fp } from '../abstract/modular.js';
|
||||
import { Field as Fp } from '../abstract/modular.js';
|
||||
|
||||
run(async () => {
|
||||
console.log(`\x1b[36mmodular, secp256k1 field\x1b[0m`);
|
||||
|
||||
77
package-lock.json
generated
77
package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "@noble/curves",
|
||||
"version": "0.8.0",
|
||||
"version": "0.8.3",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@noble/curves",
|
||||
"version": "0.8.0",
|
||||
"version": "0.8.3",
|
||||
"funding": [
|
||||
{
|
||||
"type": "individual",
|
||||
@@ -15,35 +15,38 @@
|
||||
],
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@noble/hashes": "1.2.0"
|
||||
"@noble/hashes": "1.3.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@scure/bip32": "~1.1.5",
|
||||
"@scure/bip39": "~1.1.1",
|
||||
"@types/node": "18.11.3",
|
||||
"@scure/bip32": "~1.2.0",
|
||||
"@scure/bip39": "~1.2.0",
|
||||
"@types/node": "18.11.18",
|
||||
"fast-check": "3.0.0",
|
||||
"micro-bmark": "0.3.1",
|
||||
"micro-should": "0.4.0",
|
||||
"prettier": "2.8.3",
|
||||
"typescript": "4.7.3"
|
||||
"prettier": "2.8.4",
|
||||
"typescript": "5.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@noble/hashes": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.2.0.tgz",
|
||||
"integrity": "sha512-FZfhjEDbT5GRswV3C6uvLPHMiVD6lQBmpoX5+eSiPaMTXte/IKqI5dykDxzZB/WBeK/CDuQRBWarPdi3FNY2zQ==",
|
||||
"node_modules/@noble/curves": {
|
||||
"version": "0.8.3",
|
||||
"resolved": "https://registry.npmjs.org/@noble/curves/-/curves-0.8.3.tgz",
|
||||
"integrity": "sha512-OqaOf4RWDaCRuBKJLDURrgVxjLmneGsiCXGuzYB5y95YithZMA6w4uk34DHSm0rKMrrYiaeZj48/81EvaAScLQ==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "individual",
|
||||
"url": "https://paulmillr.com/funding/"
|
||||
}
|
||||
]
|
||||
],
|
||||
"dependencies": {
|
||||
"@noble/hashes": "1.3.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@noble/secp256k1": {
|
||||
"version": "1.7.1",
|
||||
"resolved": "https://registry.npmjs.org/@noble/secp256k1/-/secp256k1-1.7.1.tgz",
|
||||
"integrity": "sha512-hOUk6AyBFmqVrv7k5WAw/LpszxVbj9gGN4JRkIX52fdFAj1UA61KXmZDvqVEm+pOyec3+fIeZB02LYa/pWOArw==",
|
||||
"dev": true,
|
||||
"node_modules/@noble/hashes": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.0.tgz",
|
||||
"integrity": "sha512-ilHEACi9DwqJB0pw7kv+Apvh50jiiSyR/cQ3y4W7lOR5mhvn/50FLUfsnfJz0BDZtl/RR16kXvptiv6q1msYZg==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "individual",
|
||||
@@ -64,9 +67,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@scure/bip32": {
|
||||
"version": "1.1.5",
|
||||
"resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.1.5.tgz",
|
||||
"integrity": "sha512-XyNh1rB0SkEqd3tXcXMi+Xe1fvg+kUIcoRIEujP1Jgv7DqW2r9lg3Ah0NkFaCs9sTkQAQA8kw7xiRXzENi9Rtw==",
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.2.0.tgz",
|
||||
"integrity": "sha512-O+vT/hBVk+ag2i6j2CDemwd1E1MtGt+7O1KzrPNsaNvSsiEK55MyPIxJIMI2PS8Ijj464B2VbQlpRoQXxw1uHg==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
@@ -75,15 +78,15 @@
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"@noble/hashes": "~1.2.0",
|
||||
"@noble/secp256k1": "~1.7.0",
|
||||
"@noble/curves": "~0.8.3",
|
||||
"@noble/hashes": "~1.3.0",
|
||||
"@scure/base": "~1.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@scure/bip39": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.1.1.tgz",
|
||||
"integrity": "sha512-t+wDck2rVkh65Hmv280fYdVdY25J9YeEUIgn2LG1WM6gxFkGzcksoDiUkWVpVp3Oex9xGC68JU2dSbUfwZ2jPg==",
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.2.0.tgz",
|
||||
"integrity": "sha512-SX/uKq52cuxm4YFXWFaVByaSHJh2w3BnokVSeUJVCv6K7WulT9u2BuNRBhuFl8vAuYnzx9bEu9WgpcNYTrYieg==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
@@ -92,14 +95,14 @@
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"@noble/hashes": "~1.2.0",
|
||||
"@noble/hashes": "~1.3.0",
|
||||
"@scure/base": "~1.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "18.11.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.3.tgz",
|
||||
"integrity": "sha512-fNjDQzzOsZeKZu5NATgXUPsaFaTxeRgFXoosrHivTl8RGeV733OLawXsGfEk9a8/tySyZUyiZ6E8LcjPFZ2y1A==",
|
||||
"version": "18.11.18",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.18.tgz",
|
||||
"integrity": "sha512-DHQpWGjyQKSHj3ebjFI/wRKcqQcdR+MoFBygntYOZytCqNfkd2ZC4ARDJ2DQqhjH5p85Nnd3jhUJIXrszFX/JA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/fast-check": {
|
||||
@@ -131,9 +134,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/prettier": {
|
||||
"version": "2.8.3",
|
||||
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.3.tgz",
|
||||
"integrity": "sha512-tJ/oJ4amDihPoufT5sM0Z1SKEuKay8LfVAMlbbhnnkvt6BUserZylqo2PN+p9KeljLr0OHa2rXHU1T8reeoTrw==",
|
||||
"version": "2.8.4",
|
||||
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.4.tgz",
|
||||
"integrity": "sha512-vIS4Rlc2FNh0BySk3Wkd6xmwxB0FpOndW5fisM5H8hsZSxU2VWVB5CWIkIjWvrHjIhxk2g3bfMKM87zNTrZddw==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"prettier": "bin-prettier.js"
|
||||
@@ -162,16 +165,16 @@
|
||||
]
|
||||
},
|
||||
"node_modules/typescript": {
|
||||
"version": "4.7.3",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.3.tgz",
|
||||
"integrity": "sha512-WOkT3XYvrpXx4vMMqlD+8R8R37fZkjyLGlxavMc4iB8lrl8L0DeTcHbYgw/v0N/z9wAFsgBhcsF0ruoySS22mA==",
|
||||
"version": "5.0.2",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.0.2.tgz",
|
||||
"integrity": "sha512-wVORMBGO/FAs/++blGNeAVdbNKtIh1rbBL2EyQ1+J9lClJ93KiiKe8PmFIVdXhHcyv44SL9oglmfeSsndo0jRw==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"tsc": "bin/tsc",
|
||||
"tsserver": "bin/tsserver"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4.2.0"
|
||||
"node": ">=12.20"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
18
package.json
18
package.json
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@noble/curves",
|
||||
"version": "0.8.1",
|
||||
"description": "Minimal, auditable JS implementation of elliptic curve cryptography",
|
||||
"version": "0.9.0",
|
||||
"description": "Audited & minimal JS implementation of elliptic curve cryptography",
|
||||
"files": [
|
||||
"abstract",
|
||||
"esm",
|
||||
@@ -28,17 +28,17 @@
|
||||
},
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@noble/hashes": "1.2.0"
|
||||
"@noble/hashes": "1.3.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@scure/bip32": "~1.1.5",
|
||||
"@scure/bip39": "~1.1.1",
|
||||
"@types/node": "18.11.3",
|
||||
"@scure/bip32": "~1.2.0",
|
||||
"@scure/bip39": "~1.2.0",
|
||||
"@types/node": "18.11.18",
|
||||
"fast-check": "3.0.0",
|
||||
"micro-bmark": "0.3.1",
|
||||
"micro-should": "0.4.0",
|
||||
"prettier": "2.8.3",
|
||||
"typescript": "4.7.3"
|
||||
"prettier": "2.8.4",
|
||||
"typescript": "5.0.2"
|
||||
},
|
||||
"main": "index.js",
|
||||
"exports": {
|
||||
@@ -171,7 +171,7 @@
|
||||
"bn254",
|
||||
"pasta",
|
||||
"bls",
|
||||
"nist",
|
||||
"noble",
|
||||
"ecc",
|
||||
"ecdsa",
|
||||
"eddsa",
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
* Some projects may prefer to swap this relation, it is not supported for now.
|
||||
*/
|
||||
import { AffinePoint } from './curve.js';
|
||||
import { Field, hashToPrivateScalar } from './modular.js';
|
||||
import { IField, hashToPrivateScalar } from './modular.js';
|
||||
import { Hex, PrivKey, CHash, bitLen, bitGet, ensureBytes } from './utils.js';
|
||||
import * as htf from './hash-to-curve.js';
|
||||
import {
|
||||
@@ -41,15 +41,15 @@ export type CurveType<Fp, Fp2, Fp6, Fp12> = {
|
||||
htfDefaults: htf.Opts;
|
||||
};
|
||||
x: bigint;
|
||||
Fp: Field<Fp>;
|
||||
Fr: Field<bigint>;
|
||||
Fp2: Field<Fp2> & {
|
||||
Fp: IField<Fp>;
|
||||
Fr: IField<bigint>;
|
||||
Fp2: IField<Fp2> & {
|
||||
reim: (num: Fp2) => { re: bigint; im: bigint };
|
||||
multiplyByB: (num: Fp2) => Fp2;
|
||||
frobeniusMap(num: Fp2, power: number): Fp2;
|
||||
};
|
||||
Fp6: Field<Fp6>;
|
||||
Fp12: Field<Fp12> & {
|
||||
Fp6: IField<Fp6>;
|
||||
Fp12: IField<Fp12> & {
|
||||
frobeniusMap(num: Fp12, power: number): Fp12;
|
||||
multiplyBy014(num: Fp12, o0: Fp2, o1: Fp2, o4: Fp2): Fp12;
|
||||
conjugate(num: Fp12): Fp12;
|
||||
@@ -62,11 +62,11 @@ export type CurveType<Fp, Fp2, Fp6, Fp12> = {
|
||||
|
||||
export type CurveFn<Fp, Fp2, Fp6, Fp12> = {
|
||||
CURVE: CurveType<Fp, Fp2, Fp6, Fp12>;
|
||||
Fr: Field<bigint>;
|
||||
Fp: Field<Fp>;
|
||||
Fp2: Field<Fp2>;
|
||||
Fp6: Field<Fp6>;
|
||||
Fp12: Field<Fp12>;
|
||||
Fr: IField<bigint>;
|
||||
Fp: IField<Fp>;
|
||||
Fp2: IField<Fp2>;
|
||||
Fp6: IField<Fp6>;
|
||||
Fp12: IField<Fp12>;
|
||||
G1: CurvePointsRes<Fp> & ReturnType<typeof htf.createHasher<Fp>>;
|
||||
G2: CurvePointsRes<Fp2> & ReturnType<typeof htf.createHasher<Fp2>>;
|
||||
Signature: SignatureCoder<Fp2>;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
||||
// Abelian group utilities
|
||||
import { Field, validateField, nLength } from './modular.js';
|
||||
import { IField, validateField, nLength } from './modular.js';
|
||||
import { validateObject } from './utils.js';
|
||||
const _0n = BigInt(0);
|
||||
const _1n = BigInt(1);
|
||||
@@ -168,7 +168,7 @@ export function wNAF<T extends Group<T>>(c: GroupConstructor<T>, bits: number) {
|
||||
// Generic BasicCurve interface: works even for polynomial fields (BLS): P, n, h would be ok.
|
||||
// Though generator can be different (Fp2 / Fp6 for BLS).
|
||||
export type BasicCurve<T> = {
|
||||
Fp: Field<T>; // Field over which we'll do calculations (Fp)
|
||||
Fp: IField<T>; // Field over which we'll do calculations (Fp)
|
||||
n: bigint; // Curve order, total count of valid points in the field
|
||||
nBitLength?: number; // bit length of curve order
|
||||
nByteLength?: number; // byte length of curve order
|
||||
@@ -195,5 +195,9 @@ export function validateBasic<FP, T>(curve: BasicCurve<FP> & T) {
|
||||
}
|
||||
);
|
||||
// Set defaults
|
||||
return Object.freeze({ ...nLength(curve.n, curve.nBitLength), ...curve } as const);
|
||||
return Object.freeze({
|
||||
...nLength(curve.n, curve.nBitLength),
|
||||
...curve,
|
||||
...{ p: curve.Fp.ORDER },
|
||||
} as const);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
||||
import type { Group, GroupConstructor, AffinePoint } from './curve.js';
|
||||
import { mod, Field } from './modular.js';
|
||||
import { mod, IField } from './modular.js';
|
||||
import { bytesToNumberBE, CHash, concatBytes, utf8ToBytes, validateObject } from './utils.js';
|
||||
|
||||
/**
|
||||
@@ -163,7 +163,7 @@ export function hash_to_field(msg: Uint8Array, count: number, options: Opts): bi
|
||||
return u;
|
||||
}
|
||||
|
||||
export function isogenyMap<T, F extends Field<T>>(field: F, map: [T[], T[], T[], T[]]) {
|
||||
export function isogenyMap<T, F extends IField<T>>(field: F, map: [T[], T[], T[], T[]]) {
|
||||
// Make same order as in spec
|
||||
const COEFF = map.map((i) => Array.from(i).reverse());
|
||||
return (x: T, y: T) => {
|
||||
|
||||
@@ -97,7 +97,7 @@ export function tonelliShanks(P: bigint) {
|
||||
// Fast-path
|
||||
if (S === 1) {
|
||||
const p1div4 = (P + _1n) / _4n;
|
||||
return function tonelliFast<T>(Fp: Field<T>, n: T) {
|
||||
return function tonelliFast<T>(Fp: IField<T>, n: T) {
|
||||
const root = Fp.pow(n, p1div4);
|
||||
if (!Fp.eql(Fp.sqr(root), n)) throw new Error('Cannot find square root');
|
||||
return root;
|
||||
@@ -106,7 +106,7 @@ export function tonelliShanks(P: bigint) {
|
||||
|
||||
// Slow-path
|
||||
const Q1div2 = (Q + _1n) / _2n;
|
||||
return function tonelliSlow<T>(Fp: Field<T>, n: T): T {
|
||||
return function tonelliSlow<T>(Fp: IField<T>, n: T): T {
|
||||
// Step 0: Check that n is indeed a square: (n | p) should not be ≡ -1
|
||||
if (Fp.pow(n, legendreC) === Fp.neg(Fp.ONE)) throw new Error('Cannot find square root');
|
||||
let r = S;
|
||||
@@ -146,7 +146,7 @@ export function FpSqrt(P: bigint) {
|
||||
// 0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaabn;
|
||||
// const NUM = 72057594037927816n;
|
||||
const p1div4 = (P + _1n) / _4n;
|
||||
return function sqrt3mod4<T>(Fp: Field<T>, n: T) {
|
||||
return function sqrt3mod4<T>(Fp: IField<T>, n: T) {
|
||||
const root = Fp.pow(n, p1div4);
|
||||
// Throw if root**2 != n
|
||||
if (!Fp.eql(Fp.sqr(root), n)) throw new Error('Cannot find square root');
|
||||
@@ -157,7 +157,7 @@ export function FpSqrt(P: bigint) {
|
||||
// Atkin algorithm for q ≡ 5 (mod 8), https://eprint.iacr.org/2012/685.pdf (page 10)
|
||||
if (P % _8n === _5n) {
|
||||
const c1 = (P - _5n) / _8n;
|
||||
return function sqrt5mod8<T>(Fp: Field<T>, n: T) {
|
||||
return function sqrt5mod8<T>(Fp: IField<T>, n: T) {
|
||||
const n2 = Fp.mul(n, _2n);
|
||||
const v = Fp.pow(n2, c1);
|
||||
const nv = Fp.mul(n, v);
|
||||
@@ -203,7 +203,7 @@ export const isNegativeLE = (num: bigint, modulo: bigint) => (mod(num, modulo) &
|
||||
// - unreadable mess: addition, multiply, square, squareRoot, inversion, divide, power, equals, subtract
|
||||
|
||||
// Field is not always over prime, Fp2 for example has ORDER(q)=p^m
|
||||
export interface Field<T> {
|
||||
export interface IField<T> {
|
||||
ORDER: bigint;
|
||||
BYTES: number;
|
||||
BITS: number;
|
||||
@@ -249,7 +249,7 @@ const FIELD_FIELDS = [
|
||||
'eql', 'add', 'sub', 'mul', 'pow', 'div',
|
||||
'addN', 'subN', 'mulN', 'sqrN'
|
||||
] as const;
|
||||
export function validateField<T>(field: Field<T>) {
|
||||
export function validateField<T>(field: IField<T>) {
|
||||
const initial = {
|
||||
ORDER: 'bigint',
|
||||
MASK: 'bigint',
|
||||
@@ -264,7 +264,7 @@ export function validateField<T>(field: Field<T>) {
|
||||
}
|
||||
|
||||
// Generic field functions
|
||||
export function FpPow<T>(f: Field<T>, num: T, power: bigint): T {
|
||||
export function FpPow<T>(f: IField<T>, num: T, power: bigint): T {
|
||||
// Should have same speed as pow for bigints
|
||||
// TODO: benchmark!
|
||||
if (power < _0n) throw new Error('Expected power > 0');
|
||||
@@ -280,7 +280,8 @@ export function FpPow<T>(f: Field<T>, num: T, power: bigint): T {
|
||||
return p;
|
||||
}
|
||||
|
||||
export function FpInvertBatch<T>(f: Field<T>, nums: T[]): T[] {
|
||||
// 0 is non-invertible: non-batched version will throw on 0
|
||||
export function FpInvertBatch<T>(f: IField<T>, nums: T[]): T[] {
|
||||
const tmp = new Array(nums.length);
|
||||
// Walk from first to last, multiply them by each other MOD p
|
||||
const lastMultiplied = nums.reduce((acc, num, i) => {
|
||||
@@ -299,12 +300,12 @@ export function FpInvertBatch<T>(f: Field<T>, nums: T[]): T[] {
|
||||
return tmp;
|
||||
}
|
||||
|
||||
export function FpDiv<T>(f: Field<T>, lhs: T, rhs: T | bigint): T {
|
||||
export function FpDiv<T>(f: IField<T>, lhs: T, rhs: T | bigint): T {
|
||||
return f.mul(lhs, typeof rhs === 'bigint' ? invert(rhs, f.ORDER) : f.inv(rhs));
|
||||
}
|
||||
|
||||
// This function returns True whenever the value x is a square in the field F.
|
||||
export function FpIsSquare<T>(f: Field<T>) {
|
||||
export function FpIsSquare<T>(f: IField<T>) {
|
||||
const legendreConst = (f.ORDER - _1n) / _2n; // Integer arithmetic
|
||||
return (x: T): boolean => {
|
||||
const p = f.pow(x, legendreConst);
|
||||
@@ -320,16 +321,24 @@ export function nLength(n: bigint, nBitLength?: number) {
|
||||
return { nBitLength: _nBitLength, nByteLength };
|
||||
}
|
||||
|
||||
// NOTE: very fragile, always bench. Major performance points:
|
||||
// - NonNormalized ops
|
||||
// - Object.freeze
|
||||
// - same shape of object (don't add/remove keys)
|
||||
type FpField = Field<bigint> & Required<Pick<Field<bigint>, 'isOdd'>>;
|
||||
export function Fp(
|
||||
type FpField = IField<bigint> & Required<Pick<IField<bigint>, 'isOdd'>>;
|
||||
/**
|
||||
* Initializes a galois field over prime. Non-primes are not supported for now.
|
||||
* Do not init in loop: slow. Very fragile: always run a benchmark on change.
|
||||
* Major performance gains:
|
||||
* a) non-normalized operations like mulN instead of mul
|
||||
* b) `Object.freeze`
|
||||
* c) Same object shape: never add or remove keys
|
||||
* @param ORDER prime positive bigint
|
||||
* @param bitLen how many bits the field consumes
|
||||
* @param isLE (def: false) if encoding / decoding should be in little-endian
|
||||
* @param redef optional faster redefinitions of sqrt and other methods
|
||||
*/
|
||||
export function Field(
|
||||
ORDER: bigint,
|
||||
bitLen?: number,
|
||||
isLE = false,
|
||||
redef: Partial<Field<bigint>> = {}
|
||||
redef: Partial<IField<bigint>> = {}
|
||||
): Readonly<FpField> {
|
||||
if (ORDER <= _0n) throw new Error(`Expected Fp ORDER > 0, got ${ORDER}`);
|
||||
const { nBitLength: BITS, nByteLength: BYTES } = nLength(ORDER, bitLen);
|
||||
@@ -382,13 +391,13 @@ export function Fp(
|
||||
return Object.freeze(f);
|
||||
}
|
||||
|
||||
export function FpSqrtOdd<T>(Fp: Field<T>, elm: T) {
|
||||
export function FpSqrtOdd<T>(Fp: IField<T>, elm: T) {
|
||||
if (!Fp.isOdd) throw new Error(`Field doesn't have isOdd`);
|
||||
const root = Fp.sqrt(elm);
|
||||
return Fp.isOdd(root) ? root : Fp.neg(root);
|
||||
}
|
||||
|
||||
export function FpSqrtEven<T>(Fp: Field<T>, elm: T) {
|
||||
export function FpSqrtEven<T>(Fp: IField<T>, elm: T) {
|
||||
if (!Fp.isOdd) throw new Error(`Field doesn't have isOdd`);
|
||||
const root = Fp.sqrt(elm);
|
||||
return Fp.isOdd(root) ? Fp.neg(root) : root;
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
||||
// Poseidon Hash: https://eprint.iacr.org/2019/458.pdf, https://www.poseidon-hash.info
|
||||
import { Field, FpPow, validateField } from './modular.js';
|
||||
import { IField, FpPow, validateField } from './modular.js';
|
||||
// We don't provide any constants, since different implementations use different constants.
|
||||
// For reference constants see './test/poseidon.test.js'.
|
||||
export type PoseidonOpts = {
|
||||
Fp: Field<bigint>;
|
||||
Fp: IField<bigint>;
|
||||
t: number;
|
||||
roundsFull: number;
|
||||
roundsPartial: number;
|
||||
|
||||
@@ -82,8 +82,8 @@ export interface ProjConstructor<T> extends GroupConstructor<ProjPointType<T>> {
|
||||
|
||||
export type CurvePointsType<T> = BasicWCurve<T> & {
|
||||
// Bytes
|
||||
fromBytes: (bytes: Uint8Array) => AffinePoint<T>;
|
||||
toBytes: (c: ProjConstructor<T>, point: ProjPointType<T>, compressed: boolean) => Uint8Array;
|
||||
fromBytes?: (bytes: Uint8Array) => AffinePoint<T>;
|
||||
toBytes?: (c: ProjConstructor<T>, point: ProjPointType<T>, isCompressed: boolean) => Uint8Array;
|
||||
};
|
||||
|
||||
function validatePointOpts<T>(curve: CurvePointsType<T>) {
|
||||
@@ -93,8 +93,6 @@ function validatePointOpts<T>(curve: CurvePointsType<T>) {
|
||||
{
|
||||
a: 'field',
|
||||
b: 'field',
|
||||
fromBytes: 'function',
|
||||
toBytes: 'function',
|
||||
},
|
||||
{
|
||||
allowedPrivateKeyLengths: 'array',
|
||||
@@ -102,6 +100,8 @@ function validatePointOpts<T>(curve: CurvePointsType<T>) {
|
||||
isTorsionFree: 'function',
|
||||
clearCofactor: 'function',
|
||||
allowInfinityPoint: 'boolean',
|
||||
fromBytes: 'function',
|
||||
toBytes: 'function',
|
||||
}
|
||||
);
|
||||
const { endo, Fp, a } = opts;
|
||||
@@ -184,6 +184,23 @@ export function weierstrassPoints<T>(opts: CurvePointsType<T>) {
|
||||
const CURVE = validatePointOpts(opts);
|
||||
const { Fp } = CURVE; // All curves has same field / group length as for now, but they can differ
|
||||
|
||||
const toBytes =
|
||||
CURVE.toBytes ||
|
||||
((c: ProjConstructor<T>, point: ProjPointType<T>, isCompressed: boolean) => {
|
||||
const a = point.toAffine();
|
||||
return ut.concatBytes(Uint8Array.from([0x04]), Fp.toBytes(a.x), Fp.toBytes(a.y));
|
||||
});
|
||||
const fromBytes =
|
||||
CURVE.fromBytes ||
|
||||
((bytes: Uint8Array) => {
|
||||
// const head = bytes[0];
|
||||
const tail = bytes.subarray(1);
|
||||
// if (head !== 0x04) throw new Error('Only non-compressed encoding is supported');
|
||||
const x = Fp.fromBytes(tail.subarray(0, Fp.BYTES));
|
||||
const y = Fp.fromBytes(tail.subarray(Fp.BYTES, 2 * Fp.BYTES));
|
||||
return { x, y };
|
||||
});
|
||||
|
||||
/**
|
||||
* y² = x³ + ax + b: Short weierstrass curve formula
|
||||
* @returns y²
|
||||
@@ -280,7 +297,7 @@ export function weierstrassPoints<T>(opts: CurvePointsType<T>) {
|
||||
* @param hex short/long ECDSA hex
|
||||
*/
|
||||
static fromHex(hex: Hex): Point {
|
||||
const P = Point.fromAffine(CURVE.fromBytes(ensureBytes('pointHex', hex)));
|
||||
const P = Point.fromAffine(fromBytes(ensureBytes('pointHex', hex)));
|
||||
P.assertValidity();
|
||||
return P;
|
||||
}
|
||||
@@ -563,7 +580,7 @@ export function weierstrassPoints<T>(opts: CurvePointsType<T>) {
|
||||
|
||||
toRawBytes(isCompressed = true): Uint8Array {
|
||||
this.assertValidity();
|
||||
return CURVE.toBytes(Point, this, isCompressed);
|
||||
return toBytes(Point, this, isCompressed);
|
||||
}
|
||||
|
||||
toHex(isCompressed = true): string {
|
||||
@@ -574,6 +591,7 @@ export function weierstrassPoints<T>(opts: CurvePointsType<T>) {
|
||||
const wnaf = wNAF(Point, CURVE.endo ? Math.ceil(_bits / 2) : _bits);
|
||||
|
||||
return {
|
||||
CURVE,
|
||||
ProjectivePoint: Point as ProjConstructor<T>,
|
||||
normPrivateKeyToScalar,
|
||||
weierstrassEquation,
|
||||
@@ -652,8 +670,7 @@ export type CurveFn = {
|
||||
|
||||
export function weierstrass(curveDef: CurveType): CurveFn {
|
||||
const CURVE = validateOpts(curveDef) as ReturnType<typeof validateOpts>;
|
||||
const CURVE_ORDER = CURVE.n;
|
||||
const Fp = CURVE.Fp;
|
||||
const { Fp, n: CURVE_ORDER } = CURVE;
|
||||
const compressedLen = Fp.BYTES + 1; // e.g. 33 for 32
|
||||
const uncompressedLen = 2 * Fp.BYTES + 1; // e.g. 65 for 32
|
||||
|
||||
@@ -1055,11 +1072,10 @@ export function weierstrass(curveDef: CurveType): CurveFn {
|
||||
}
|
||||
|
||||
// Implementation of the Shallue and van de Woestijne method for any Weierstrass curve
|
||||
|
||||
// TODO: check if there is a way to merge this with uvRatio in Edwards && move to modular?
|
||||
// b = True and y = sqrt(u / v) if (u / v) is square in F, and
|
||||
// b = False and y = sqrt(Z * (u / v)) otherwise.
|
||||
export function SWUFpSqrtRatio<T>(Fp: mod.Field<T>, Z: T) {
|
||||
export function SWUFpSqrtRatio<T>(Fp: mod.IField<T>, Z: T) {
|
||||
// Generic implementation
|
||||
const q = Fp.ORDER;
|
||||
let l = 0n;
|
||||
@@ -1124,7 +1140,7 @@ export function SWUFpSqrtRatio<T>(Fp: mod.Field<T>, Z: T) {
|
||||
}
|
||||
// From draft-irtf-cfrg-hash-to-curve-16
|
||||
export function mapToCurveSimpleSWU<T>(
|
||||
Fp: mod.Field<T>,
|
||||
Fp: mod.IField<T>,
|
||||
opts: {
|
||||
A: T;
|
||||
B: T;
|
||||
|
||||
@@ -72,13 +72,13 @@ import { isogenyMap } from './abstract/hash-to-curve.js';
|
||||
// CURVE FIELDS
|
||||
// Finite field over p.
|
||||
const Fp =
|
||||
mod.Fp(
|
||||
mod.Field(
|
||||
0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaabn
|
||||
);
|
||||
type Fp = bigint;
|
||||
// Finite field over r.
|
||||
// This particular field is not used anywhere in bls12-381, but it is still useful.
|
||||
const Fr = mod.Fp(0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001n);
|
||||
const Fr = mod.Field(0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001n);
|
||||
|
||||
// Fp₂ over complex plane
|
||||
type BigintTuple = [bigint, bigint];
|
||||
@@ -124,7 +124,7 @@ const FP2_ORDER =
|
||||
0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaabn **
|
||||
2n;
|
||||
|
||||
const Fp2: mod.Field<Fp2> & Fp2Utils = {
|
||||
const Fp2: mod.IField<Fp2> & Fp2Utils = {
|
||||
ORDER: FP2_ORDER,
|
||||
BITS: bitLen(FP2_ORDER),
|
||||
BYTES: Math.ceil(bitLen(FP2_ORDER) / 8),
|
||||
@@ -333,7 +333,7 @@ type Fp6Utils = {
|
||||
multiplyByFp2(lhs: Fp6, rhs: Fp2): Fp6;
|
||||
};
|
||||
|
||||
const Fp6: mod.Field<Fp6> & Fp6Utils = {
|
||||
const Fp6: mod.IField<Fp6> & Fp6Utils = {
|
||||
ORDER: Fp2.ORDER, // TODO: unused, but need to verify
|
||||
BITS: 3 * Fp2.BITS,
|
||||
BYTES: 3 * Fp2.BYTES,
|
||||
@@ -545,7 +545,7 @@ type Fp12Utils = {
|
||||
_cyclotomicExp(num: Fp12, n: bigint): Fp12;
|
||||
};
|
||||
|
||||
const Fp12: mod.Field<Fp12> & Fp12Utils = {
|
||||
const Fp12: mod.IField<Fp12> & Fp12Utils = {
|
||||
ORDER: Fp2.ORDER, // TODO: unused, but need to verify
|
||||
BITS: 2 * Fp2.BITS,
|
||||
BYTES: 2 * Fp2.BYTES,
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
import { sha256 } from '@noble/hashes/sha256';
|
||||
import { weierstrass } from './abstract/weierstrass.js';
|
||||
import { getHash } from './_shortw_utils.js';
|
||||
import { Fp } from './abstract/modular.js';
|
||||
import { Field } from './abstract/modular.js';
|
||||
/**
|
||||
* bn254 pairing-friendly curve.
|
||||
* Previously known as alt_bn_128, when it had 128-bit security.
|
||||
@@ -12,7 +12,7 @@ import { Fp } from './abstract/modular.js';
|
||||
export const bn254 = weierstrass({
|
||||
a: BigInt(0),
|
||||
b: BigInt(3),
|
||||
Fp: Fp(BigInt('0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47')),
|
||||
Fp: Field(BigInt('0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47')),
|
||||
n: BigInt('0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001'),
|
||||
Gx: BigInt(1),
|
||||
Gy: BigInt(2),
|
||||
|
||||
@@ -3,7 +3,7 @@ import { sha512 } from '@noble/hashes/sha512';
|
||||
import { concatBytes, randomBytes, utf8ToBytes } from '@noble/hashes/utils';
|
||||
import { twistedEdwards, ExtPointType } from './abstract/edwards.js';
|
||||
import { montgomery } from './abstract/montgomery.js';
|
||||
import { mod, pow2, isNegativeLE, Fp as Field, FpSqrtEven } from './abstract/modular.js';
|
||||
import { mod, pow2, isNegativeLE, Field, FpSqrtEven } from './abstract/modular.js';
|
||||
import {
|
||||
equalBytes,
|
||||
bytesToHex,
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
import { shake256 } from '@noble/hashes/sha3';
|
||||
import { concatBytes, randomBytes, utf8ToBytes, wrapConstructor } from '@noble/hashes/utils';
|
||||
import { twistedEdwards } from './abstract/edwards.js';
|
||||
import { mod, pow2, Fp as Field } from './abstract/modular.js';
|
||||
import { mod, pow2, Field } from './abstract/modular.js';
|
||||
import { montgomery } from './abstract/montgomery.js';
|
||||
import * as htf from './abstract/hash-to-curve.js';
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ import { sha512 } from '@noble/hashes/sha512';
|
||||
import { concatBytes, randomBytes, utf8ToBytes } from '@noble/hashes/utils';
|
||||
import { twistedEdwards } from './abstract/edwards.js';
|
||||
import { blake2s } from '@noble/hashes/blake2s';
|
||||
import { Fp } from './abstract/modular.js';
|
||||
import { Field } from './abstract/modular.js';
|
||||
|
||||
/**
|
||||
* jubjub Twisted Edwards curve.
|
||||
@@ -17,7 +17,7 @@ export const jubjub = twistedEdwards({
|
||||
d: BigInt('0x2a9318e74bfa2b48f5fd9207e6bd7fd4292d7f6d37579d2601065fd6d6343eb1'),
|
||||
// Finite field 𝔽p over which we'll do calculations
|
||||
// Same value as bls12-381 Fr (not Fp)
|
||||
Fp: Fp(BigInt('0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001')),
|
||||
Fp: Field(BigInt('0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001')),
|
||||
// Subgroup order: how many points curve has
|
||||
n: BigInt('0xe7db4ea6533afa906673b0101343b00a6682093ccc81082d0970e5ed6f72cb7'),
|
||||
// Cofactor
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
||||
import { createCurve } from './_shortw_utils.js';
|
||||
import { sha256 } from '@noble/hashes/sha256';
|
||||
import { Fp as Field } from './abstract/modular.js';
|
||||
import { Field } from './abstract/modular.js';
|
||||
import { mapToCurveSimpleSWU } from './abstract/weierstrass.js';
|
||||
import * as htf from './abstract/hash-to-curve.js';
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
||||
import { createCurve } from './_shortw_utils.js';
|
||||
import { sha384 } from '@noble/hashes/sha512';
|
||||
import { Fp as Field } from './abstract/modular.js';
|
||||
import { Field } from './abstract/modular.js';
|
||||
import { mapToCurveSimpleSWU } from './abstract/weierstrass.js';
|
||||
import * as htf from './abstract/hash-to-curve.js';
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
||||
import { createCurve } from './_shortw_utils.js';
|
||||
import { sha512 } from '@noble/hashes/sha512';
|
||||
import { Fp as Field } from './abstract/modular.js';
|
||||
import { Field } from './abstract/modular.js';
|
||||
import { mapToCurveSimpleSWU } from './abstract/weierstrass.js';
|
||||
import * as htf from './abstract/hash-to-curve.js';
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ export const q = BigInt('0x40000000000000000000000000000000224698fc0994a8dd8c46e
|
||||
export const pallas = weierstrass({
|
||||
a: BigInt(0),
|
||||
b: BigInt(5),
|
||||
Fp: mod.Fp(p),
|
||||
Fp: mod.Field(p),
|
||||
n: q,
|
||||
Gx: mod.mod(BigInt(-1), p),
|
||||
Gy: BigInt(2),
|
||||
@@ -22,7 +22,7 @@ export const pallas = weierstrass({
|
||||
export const vesta = weierstrass({
|
||||
a: BigInt(0),
|
||||
b: BigInt(5),
|
||||
Fp: mod.Fp(q),
|
||||
Fp: mod.Field(q),
|
||||
n: p,
|
||||
Gx: mod.mod(BigInt(-1), q),
|
||||
Gy: BigInt(2),
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
||||
import { sha256 } from '@noble/hashes/sha256';
|
||||
import { randomBytes } from '@noble/hashes/utils';
|
||||
import { Fp as Field, mod, pow2 } from './abstract/modular.js';
|
||||
import { Field, mod, pow2 } from './abstract/modular.js';
|
||||
import { ProjPointType as PointType, mapToCurveSimpleSWU } from './abstract/weierstrass.js';
|
||||
import type { Hex, PrivKey } from './abstract/utils.js';
|
||||
import { bytesToNumberBE, concatBytes, ensureBytes, numberToBytesBE } from './abstract/utils.js';
|
||||
@@ -43,7 +43,6 @@ function sqrtMod(y: bigint): bigint {
|
||||
}
|
||||
|
||||
const Fp = Field(secp256k1P, undefined, undefined, { sqrt: sqrtMod });
|
||||
type Fp = bigint;
|
||||
|
||||
export const secp256k1 = createCurve(
|
||||
{
|
||||
@@ -245,7 +244,7 @@ const isoMap = htf.isogenyMap(
|
||||
'0x6484aa716545ca2cf3a70c3fa8fe337e0a3d21162f0d6299a7bf8192bfd2a76f',
|
||||
'0x0000000000000000000000000000000000000000000000000000000000000001', // LAST 1
|
||||
],
|
||||
].map((i) => i.map((j) => BigInt(j))) as [Fp[], Fp[], Fp[], Fp[]]
|
||||
].map((i) => i.map((j) => BigInt(j))) as [bigint[], bigint[], bigint[], bigint[]]
|
||||
);
|
||||
const mapSWU = mapToCurveSimpleSWU(Fp, {
|
||||
A: BigInt('0x3f8731abdd661adca08a5558f0f5d272e953d363cb6f0e5d405447c01a444533'),
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
||||
import { createCurve } from '../esm/_shortw_utils.js';
|
||||
import { sha224, sha256 } from '@noble/hashes/sha256';
|
||||
import { Fp } from '../esm/abstract/modular.js';
|
||||
import { Field as Fp } from '../esm/abstract/modular.js';
|
||||
|
||||
// NIST secp192r1 aka P192
|
||||
// https://www.secg.org/sec2-v2.pdf, https://neuromancer.sk/std/secg/secp192r1
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
||||
import { sha256 } from '@noble/hashes/sha256';
|
||||
import { utf8ToBytes } from '@noble/hashes/utils';
|
||||
import { Fp, validateField } from '../esm/abstract/modular.js';
|
||||
import { Field as Fp, validateField } from '../esm/abstract/modular.js';
|
||||
import { poseidon } from '../esm/abstract/poseidon.js';
|
||||
import * as u from '../esm/abstract/utils.js';
|
||||
|
||||
|
||||
@@ -553,6 +553,7 @@ for (const name in CURVES) {
|
||||
});
|
||||
}
|
||||
describe(name, () => {
|
||||
if (['bn254', 'pallas', 'vesta'].includes(name)) return;
|
||||
// Generic complex things (getPublicKey/sign/verify/getSharedSecret)
|
||||
should('.getPublicKey() type check', () => {
|
||||
throws(() => C.getPublicKey(0), '0');
|
||||
|
||||
@@ -8,7 +8,8 @@ import './ed25519.test.js';
|
||||
import './secp256k1.test.js';
|
||||
import './secp256k1-schnorr.test.js';
|
||||
import './jubjub.test.js';
|
||||
import './bls12-381.test.js';
|
||||
import './hash-to-curve.test.js';
|
||||
import './poseidon.test.js';
|
||||
import './bls12-381.test.js';
|
||||
|
||||
should.run();
|
||||
|
||||
@@ -132,7 +132,9 @@ describe('Stark', () => {
|
||||
// Official vectors: https://extgit.iaik.tugraz.at/krypto/hadeshash/-/blob/master/code/test_vectors.txt
|
||||
|
||||
should('poseidonperm_x5_255_3', () => {
|
||||
const Fp = mod.Fp(BigInt('0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001'));
|
||||
const Fp = mod.Field(
|
||||
BigInt('0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001')
|
||||
);
|
||||
|
||||
const mds = [
|
||||
[
|
||||
@@ -179,7 +181,7 @@ should('poseidonperm_x5_255_3', () => {
|
||||
});
|
||||
|
||||
should('poseidonperm_x5_255_5', () => {
|
||||
const Fp = mod.Fp(0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001n);
|
||||
const Fp = mod.Field(0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001n);
|
||||
const t = 5;
|
||||
|
||||
const mds = [
|
||||
@@ -250,7 +252,7 @@ should('poseidonperm_x5_255_5', () => {
|
||||
});
|
||||
|
||||
should('poseidonperm_x5_254_3', () => {
|
||||
const Fp = mod.Fp(0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001n);
|
||||
const Fp = mod.Field(0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001n);
|
||||
const t = 3;
|
||||
|
||||
const mds = [
|
||||
@@ -297,7 +299,7 @@ should('poseidonperm_x5_254_3', () => {
|
||||
});
|
||||
|
||||
should('poseidonperm_x5_254_5', () => {
|
||||
const Fp = mod.Fp(0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001n);
|
||||
const Fp = mod.Field(0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001n);
|
||||
const t = 5;
|
||||
|
||||
const mds = [
|
||||
|
||||
@@ -7,8 +7,8 @@
|
||||
"outDir": ".",
|
||||
"target": "es2020",
|
||||
"lib": ["es2020"], // Set explicitly to remove DOM
|
||||
"module": "es6",
|
||||
"moduleResolution": "node16",
|
||||
"module": "commonjs",
|
||||
"moduleResolution": "node",
|
||||
"noUnusedLocals": true,
|
||||
"baseUrl": ".",
|
||||
},
|
||||
@@ -17,4 +17,4 @@
|
||||
"node_modules",
|
||||
"*.d.ts"
|
||||
],
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user