Compare commits
11 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4df1e8de02 | ||
|
|
dd7b48ac71 | ||
|
|
254bb712b4 | ||
|
|
31f780027a | ||
|
|
80edb3323a | ||
|
|
d30b1855ee | ||
|
|
f1d8650842 | ||
|
|
54c7cf8b33 | ||
|
|
56892cc164 | ||
|
|
7d746a7408 | ||
|
|
989af14b10 |
261
README.md
261
README.md
@@ -39,11 +39,9 @@ Future plans:
|
|||||||
Use NPM in node.js / browser, or include single file from
|
Use NPM in node.js / browser, or include single file from
|
||||||
[GitHub's releases page](https://github.com/paulmillr/noble-curves/releases):
|
[GitHub's releases page](https://github.com/paulmillr/noble-curves/releases):
|
||||||
|
|
||||||
## Usage
|
> npm install @noble/curves
|
||||||
|
|
||||||
```sh
|
The library does not have an entry point. It allows you to select specific primitives and drop everything else. If you only want to use secp256k1, just use the library with rollup or other bundlers. This is done to make your bundles tiny.
|
||||||
npm install @noble/curves
|
|
||||||
```
|
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
import { weierstrass } from '@noble/curves/weierstrass'; // Short Weierstrass curve
|
import { weierstrass } from '@noble/curves/weierstrass'; // Short Weierstrass curve
|
||||||
@@ -60,21 +58,74 @@ const secp256k1 = weierstrass({
|
|||||||
Gy: 32670510020758816978083085130507043184471273380659243275938904335757337482424n,
|
Gy: 32670510020758816978083085130507043184471273380659243275938904335757337482424n,
|
||||||
hash: sha256,
|
hash: sha256,
|
||||||
hmac: (k: Uint8Array, ...msgs: Uint8Array[]) => hmac(sha256, key, concatBytes(...msgs)),
|
hmac: (k: Uint8Array, ...msgs: Uint8Array[]) => hmac(sha256, key, concatBytes(...msgs)),
|
||||||
randomBytes
|
|
||||||
});
|
});
|
||||||
|
|
||||||
secp256k1.getPublicKey(secp256k1.utils.randomPrivateKey());
|
const key = secp256k1.utils.randomPrivateKey();
|
||||||
secp256k1.sign(randomBytes(32), secp256k1.utils.randomPrivateKey());
|
const pub = secp256k1.getPublicKey(key);
|
||||||
// secp256k1.verify(sig, msg, pub)
|
const msg = randomBytes(32);
|
||||||
|
const sig = secp256k1.sign(msg, key);
|
||||||
|
secp256k1.verify(sig, msg, pub); // true
|
||||||
|
sig.recoverPublicKey(msg); // == pub
|
||||||
|
const someonesPubkey = secp256k1.getPublicKey(secp256k1.utils.randomPrivateKey());
|
||||||
|
const shared = secp256k1.getSharedSecret(key, someonesPubkey);
|
||||||
|
```
|
||||||
|
|
||||||
|
## API
|
||||||
|
|
||||||
|
- [Overview](#overview)
|
||||||
|
- [edwards: Twisted Edwards curve](#edwards-twisted-edwards-curve)
|
||||||
|
- [montgomery: Montgomery curve](#montgomery-montgomery-curve)
|
||||||
|
- [weierstrass: Short Weierstrass curve](#weierstrass-short-weierstrass-curve)
|
||||||
|
- [modular](#modular)
|
||||||
|
- [utils](#utils)
|
||||||
|
|
||||||
|
### Overview
|
||||||
|
|
||||||
|
* All arithmetics is done with JS bigints in finite fields
|
||||||
|
* Curve variables, order (number of points on curve), field prime (over which the modular division would be done)
|
||||||
|
are required
|
||||||
|
* Many features require hashing, which is not provided. `@noble/hashes` can be used for this purpose.
|
||||||
|
Any other library must conform to the CHash interface:
|
||||||
|
```ts
|
||||||
|
export type CHash = {
|
||||||
|
(message: Uint8Array): Uint8Array;
|
||||||
|
blockLen: number; outputLen: number; create(): any;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
* w-ary non-adjacent form (wNAF) method with constant-time adjustments is used for point multiplication.
|
||||||
|
It is possible to enable precomputes for edwards & weierstrass curves.
|
||||||
|
Precomputes are calculated once (takes ~20-40ms), after that most `G` multiplications
|
||||||
|
- for example, `getPublicKey()`, `sign()` and similar methods - would be much faster.
|
||||||
|
Use `curve.utils.precompute()`
|
||||||
|
* Special params that tune performance can be optionally provided.
|
||||||
|
For example, square root calculation, which is commonly used in point decompression routines
|
||||||
|
* Curves export `Point`, which conforms to `Group` interface, which has following methods:
|
||||||
|
- `double()`, `negate()`
|
||||||
|
- `add()`, `subtract()`, `equals()`
|
||||||
|
- `multiply()`
|
||||||
|
Every group also has `BASE` (generator) and `ZERO` (infinity) static properties.
|
||||||
|
* Curves export `CURVE` object
|
||||||
|
* Curves export `utils`:
|
||||||
|
* `randomPrivateKey()` specific for the curve, avoiding modulo bias
|
||||||
|
* `mod()` & `invert()` methods: function from `modular` with default `P` set to CURVE
|
||||||
|
|
||||||
|
### edwards: Twisted Edwards curve
|
||||||
|
|
||||||
|
Twisted Edwards curve's formula is: ax² + y² = 1 + dx²y².
|
||||||
|
|
||||||
|
* You must specify curve params `a`, `d`, field `P`, order `n`, cofactor `h`, and coordinates `Gx`, `Gy` of generator point.
|
||||||
|
* For EdDSA signatures, params `hash` is also required. `adjustScalarBytes` which instructs how to change private scalars could be specified.
|
||||||
|
|
||||||
|
```typescript
|
||||||
import { twistedEdwards } from '@noble/curves/edwards'; // Twisted Edwards curve
|
import { twistedEdwards } from '@noble/curves/edwards'; // Twisted Edwards curve
|
||||||
import { sha512 } from '@noble/hashes/sha512';
|
import { sha512 } from '@noble/hashes/sha512';
|
||||||
|
import { div } from '@noble/curves/modular';
|
||||||
|
|
||||||
const ed25519 = twistedEdwards({
|
const ed25519 = twistedEdwards({
|
||||||
a: -1n,
|
a: -1n,
|
||||||
d: 37095705934669439343138083508754565189542113879843219016388785533085940283555n,
|
d: div(-121665n, 121666n, 2n ** 255n - 19n), // -121665n/121666n
|
||||||
P: 57896044618658097711785492504343953926634992332820282019728792003956564819949n,
|
P: 2n ** 255n - 19n,
|
||||||
n: 7237005577332262213973186563042994240857116359379907606001950938285454250989n,
|
n: 2n ** 252n + 27742317777372353535851937790883648493n,
|
||||||
h: 8n,
|
h: 8n,
|
||||||
Gx: 15112221349535400772501151409588531511454012693041857206046113283949847762202n,
|
Gx: 15112221349535400772501151409588531511454012693041857206046113283949847762202n,
|
||||||
Gy: 46316835694926478169428394003475163141307993866256225615783033603165251855960n,
|
Gy: 46316835694926478169428394003475163141307993866256225615783033603165251855960n,
|
||||||
@@ -90,7 +141,180 @@ const ed25519 = twistedEdwards({
|
|||||||
ed25519.getPublicKey(ed25519.utils.randomPrivateKey());
|
ed25519.getPublicKey(ed25519.utils.randomPrivateKey());
|
||||||
```
|
```
|
||||||
|
|
||||||
## Performance
|
`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;
|
||||||
|
Point: PointConstructor;
|
||||||
|
ExtendedPoint: ExtendedPointConstructor;
|
||||||
|
Signature: SignatureConstructor;
|
||||||
|
utils: {
|
||||||
|
mod: (a: bigint, b?: bigint) => bigint;
|
||||||
|
invert: (number: bigint, modulo?: bigint) => bigint;
|
||||||
|
randomPrivateKey: () => Uint8Array;
|
||||||
|
getExtendedPublicKey: (key: PrivKey) => {
|
||||||
|
head: Uint8Array;
|
||||||
|
prefix: Uint8Array;
|
||||||
|
scalar: bigint;
|
||||||
|
point: PointType;
|
||||||
|
pointBytes: Uint8Array;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
### montgomery: Montgomery curve
|
||||||
|
|
||||||
|
For now the module only contains methods for x-only ECDH on Curve25519 / Curve448 from RFC7748.
|
||||||
|
|
||||||
|
Proper Elliptic Curve Points are not implemented yet.
|
||||||
|
|
||||||
|
You must specify curve field, `a24` special variable, `montgomeryBits`, `nByteLength`, and coordinate `u` of generator point.
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
const x25519 = montgomery({
|
||||||
|
P: 2n ** 255n - 19n,
|
||||||
|
a24: 121665n, // TODO: change to a
|
||||||
|
montgomeryBits: 255,
|
||||||
|
nByteLength: 32,
|
||||||
|
Gu: '0900000000000000000000000000000000000000000000000000000000000000',
|
||||||
|
|
||||||
|
// Optional params
|
||||||
|
powPminus2: (x: bigint): bigint => { return mod.pow(x, P-2, P); },
|
||||||
|
adjustScalarBytes(bytes) {
|
||||||
|
bytes[0] &= 248;
|
||||||
|
bytes[31] &= 127;
|
||||||
|
bytes[31] |= 64;
|
||||||
|
return bytes;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
### weierstrass: Short Weierstrass curve
|
||||||
|
|
||||||
|
Short Weierstrass curve's formula is: y² = x³ + ax + b. Uses deterministic ECDSA from RFC6979. You can also specify `extraEntropy` in `sign()`.
|
||||||
|
|
||||||
|
* You must specify curve params: `a`, `b`; field `P`; curve order `n`; coordinates `Gx`, `Gy` of generator point
|
||||||
|
* For ECDSA, you must specify `hash`, `hmac`. It is also possible to recover keys from signatures
|
||||||
|
* For ECDH, use `getSharedSecret(privKeyA, pubKeyB)`
|
||||||
|
* Optional params are `lowS` (default value), `sqrtMod` (square root chain) and `endo` (endomorphism)
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import { weierstrass } from '@noble/curves/weierstrass'; // Short Weierstrass curve
|
||||||
|
import { sha256 } from '@noble/hashes/sha256';
|
||||||
|
import { hmac } from '@noble/hashes/hmac';
|
||||||
|
import { concatBytes, randomBytes } from '@noble/hashes/utils';
|
||||||
|
|
||||||
|
const secp256k1 = weierstrass({
|
||||||
|
// Required params
|
||||||
|
a: 0n,
|
||||||
|
b: 7n,
|
||||||
|
P: 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2fn,
|
||||||
|
n: 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141n,
|
||||||
|
Gx: 55066263022277343669578718895168534326250603453777594175500187360389116729240n,
|
||||||
|
Gy: 32670510020758816978083085130507043184471273380659243275938904335757337482424n,
|
||||||
|
hash: sha256,
|
||||||
|
hmac: (k: Uint8Array, ...msgs: Uint8Array[]) => hmac(sha256, key, concatBytes(...msgs)),
|
||||||
|
randomBytes,
|
||||||
|
|
||||||
|
// Optional params
|
||||||
|
// Cofactor
|
||||||
|
h: BigInt(1),
|
||||||
|
// Allow only low-S signatures by default in sign() and verify()
|
||||||
|
lowS: true,
|
||||||
|
// More efficient curve-specific implementation of square root
|
||||||
|
sqrtMod(y: bigint) { return sqrt(y); },
|
||||||
|
// Endomorphism options
|
||||||
|
endo: {
|
||||||
|
// Beta param
|
||||||
|
beta: BigInt('0x7ae96a2b657c07106e64479eac3434e99cf0497512f58995c1396c28719501ee'),
|
||||||
|
// Split scalar k into k1, k2
|
||||||
|
splitScalar: (k: bigint) => {
|
||||||
|
return { k1neg: true, k1: 512n, k2neg: false, k2: 448n };
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// Usage
|
||||||
|
const key = secp256k1.utils.randomPrivateKey();
|
||||||
|
const pub = secp256k1.getPublicKey(key);
|
||||||
|
const msg = randomBytes(32);
|
||||||
|
const sig = secp256k1.sign(msg, key);
|
||||||
|
secp256k1.verify(sig, msg, pub); // true
|
||||||
|
sig.recoverPublicKey(msg); // == pub
|
||||||
|
const someonesPubkey = secp256k1.getPublicKey(secp256k1.utils.randomPrivateKey());
|
||||||
|
const shared = secp256k1.getSharedSecret(key, someonesPubkey);
|
||||||
|
```
|
||||||
|
|
||||||
|
`weierstrass()` returns `CurveFn`:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
export type CurveFn = {
|
||||||
|
CURVE: ReturnType<typeof validateOpts>;
|
||||||
|
getPublicKey: (privateKey: PrivKey, isCompressed?: boolean) => Uint8Array;
|
||||||
|
getSharedSecret: (privateA: PrivKey, publicB: PubKey, isCompressed?: boolean) => Uint8Array;
|
||||||
|
sign: (msgHash: Hex, privKey: PrivKey, opts?: SignOpts) => SignatureType;
|
||||||
|
verify: (
|
||||||
|
signature: Hex | SignatureType, msgHash: Hex, publicKey: PubKey, opts?: {lowS?: boolean;}
|
||||||
|
) => boolean;
|
||||||
|
Point: PointConstructor;
|
||||||
|
JacobianPoint: JacobianPointConstructor;
|
||||||
|
Signature: SignatureConstructor;
|
||||||
|
utils: {
|
||||||
|
mod: (a: bigint, b?: bigint) => bigint;
|
||||||
|
invert: (number: bigint, modulo?: bigint) => bigint;
|
||||||
|
isValidPrivateKey(privateKey: PrivKey): boolean;
|
||||||
|
hashToPrivateKey: (hash: Hex) => Uint8Array;
|
||||||
|
randomPrivateKey: () => Uint8Array;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
### modular
|
||||||
|
|
||||||
|
Modular arithmetics utilities.
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import * as mod from '@noble/curves/modular';
|
||||||
|
mod.mod(21n, 10n); // 21 mod 10 == 1n; fixed version of 21 % 10
|
||||||
|
mod.invert(17n, 10n); // invert(17) mod 10; modular multiplicative inverse
|
||||||
|
mod.div(5n, 17n, 10n); // 5/17 mod 10 == 5 * invert(17) mod 10; division
|
||||||
|
mod.invertBatch([1n, 2n, 4n], 21n); // => [1n, 11n, 16n] in one inversion
|
||||||
|
mod.sqrt(21n, 73n); // sqrt(21) mod 73; square root
|
||||||
|
```
|
||||||
|
|
||||||
|
### utils
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import * as utils from '@noble/curves/utils';
|
||||||
|
|
||||||
|
utils.bytesToHex(Uint8Array.from([0xde, 0xad, 0xbe, 0xef]));
|
||||||
|
utils.hexToBytes('deadbeef');
|
||||||
|
utils.hexToNumber();
|
||||||
|
utils.bytesToNumberBE(Uint8Array.from([0xde, 0xad, 0xbe, 0xef]));
|
||||||
|
utils.bytesToNumberLE(Uint8Array.from([0xde, 0xad, 0xbe, 0xef]));
|
||||||
|
utils.numberToBytesBE(123n);
|
||||||
|
utils.numberToBytesLE(123n);
|
||||||
|
utils.numberToHexUnpadded(123n);
|
||||||
|
utils.concatBytes(Uint8Array.from([0xde, 0xad]), Uint8Array.from([0xbe, 0xef]));
|
||||||
|
utils.nLength(255n);
|
||||||
|
utils.hashToPrivateScalar(sha512_of_something, secp256r1.n);
|
||||||
|
utils.equalBytes(Uint8Array.from([0xde]), Uint8Array.from([0xde]));
|
||||||
|
```
|
||||||
|
|
||||||
|
## 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
|
||||||
|
|
||||||
Benchmark results on Apple M2 with node v18.10:
|
Benchmark results on Apple M2 with node v18.10:
|
||||||
|
|
||||||
@@ -150,6 +374,17 @@ Benchmark results on Apple M2 with node v18.10:
|
|||||||
noble x 698 ops/sec @ 1ms/op
|
noble x 698 ops/sec @ 1ms/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
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
MIT (c) Paul Miller [(https://paulmillr.com)](https://paulmillr.com), see LICENSE file.
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2022 Paul Miller [(https://paulmillr.com)](https://paulmillr.com)
|
||||||
|
|
||||||
|
See LICENSE file.
|
||||||
|
|||||||
7
curve-definitions/lib/esm/package.json
Normal file
7
curve-definitions/lib/esm/package.json
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"type": "module",
|
||||||
|
"browser": {
|
||||||
|
"crypto": false,
|
||||||
|
"./crypto": "./esm/cryptoBrowser.js"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,16 +1,15 @@
|
|||||||
{
|
{
|
||||||
"name": "micro-curve-definitions",
|
"name": "micro-curve-definitions",
|
||||||
"version": "0.2.0",
|
"version": "0.2.1",
|
||||||
"description": "Curve definitions for @noble/curves",
|
"description": "Curve definitions for @noble/curves",
|
||||||
"files": [
|
"files": [
|
||||||
"lib"
|
"lib"
|
||||||
],
|
],
|
||||||
"type": "module",
|
|
||||||
"main": "lib/index.js",
|
"main": "lib/index.js",
|
||||||
"module": "lib/index.js",
|
"module": "lib/index.js",
|
||||||
"types": "lib/index.d.ts",
|
"types": "lib/index.d.ts",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@noble/curves": "0.2.0",
|
"@noble/curves": "0.2.1",
|
||||||
"@noble/hashes": "1.1.5"
|
"@noble/hashes": "1.1.5"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
@@ -31,7 +30,7 @@
|
|||||||
"url": "git+https://github.com/paulmillr/noble-curves.git"
|
"url": "git+https://github.com/paulmillr/noble-curves.git"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "tsc",
|
"build": "tsc && tsc -p tsconfig.esm.json",
|
||||||
"lint": "prettier --check src",
|
"lint": "prettier --check src",
|
||||||
"test": "node test/index.test.js"
|
"test": "node test/index.test.js"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import * as cutils from '@noble/curves/utils';
|
|||||||
|
|
||||||
// Stark-friendly elliptic curve
|
// Stark-friendly elliptic curve
|
||||||
// https://docs.starkware.co/starkex/stark-curve.html
|
// https://docs.starkware.co/starkex/stark-curve.html
|
||||||
|
// TODO: clarify exports; it is exporting both starkCurve and sign() now, can be confusing
|
||||||
|
|
||||||
function getHash(hash: CHash) {
|
function getHash(hash: CHash) {
|
||||||
return {
|
return {
|
||||||
|
|||||||
7
curve-definitions/test/package.json
Normal file
7
curve-definitions/test/package.json
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"type": "module",
|
||||||
|
"browser": {
|
||||||
|
"crypto": false,
|
||||||
|
"./crypto": "./esm/cryptoBrowser.js"
|
||||||
|
}
|
||||||
|
}
|
||||||
25
curve-definitions/tsconfig.esm.json
Normal file
25
curve-definitions/tsconfig.esm.json
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"strict": true,
|
||||||
|
"declaration": true,
|
||||||
|
"declarationMap": true,
|
||||||
|
"target": "es2020",
|
||||||
|
"lib": [
|
||||||
|
"es2020",
|
||||||
|
"dom"
|
||||||
|
],
|
||||||
|
"module": "es6",
|
||||||
|
"moduleResolution": "node16",
|
||||||
|
"outDir": "lib/esm",
|
||||||
|
"noImplicitAny": true,
|
||||||
|
"preserveConstEnums": true,
|
||||||
|
"baseUrl": ".",
|
||||||
|
},
|
||||||
|
"include": [
|
||||||
|
"src",
|
||||||
|
],
|
||||||
|
"exclude": [
|
||||||
|
"node_modules",
|
||||||
|
"lib"
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -8,7 +8,7 @@
|
|||||||
"es2020",
|
"es2020",
|
||||||
"dom"
|
"dom"
|
||||||
],
|
],
|
||||||
"module": "es6",
|
"module": "commonjs",
|
||||||
"moduleResolution": "node16",
|
"moduleResolution": "node16",
|
||||||
"outDir": "lib",
|
"outDir": "lib",
|
||||||
"noImplicitAny": true,
|
"noImplicitAny": true,
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@noble/curves",
|
"name": "@noble/curves",
|
||||||
"version": "0.2.0",
|
"version": "0.2.1",
|
||||||
"description": "Minimal, zero-dependency JS implementation of elliptic curve cryptography",
|
"description": "Minimal, zero-dependency JS implementation of elliptic curve cryptography",
|
||||||
"files": [
|
"files": [
|
||||||
"index.js",
|
"index.js",
|
||||||
|
|||||||
@@ -64,6 +64,16 @@ export function invert(number: bigint, modulo: bigint): bigint {
|
|||||||
return mod(x, modulo);
|
return mod(x, modulo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Division over finite field.
|
||||||
|
* `a/b mod p == a * invert(b) mod p`
|
||||||
|
*/
|
||||||
|
export function div(numerator: bigint, denominator: bigint, modulo: bigint): bigint {
|
||||||
|
const num = mod(numerator, modulo);
|
||||||
|
const iden = invert(denominator, modulo);
|
||||||
|
return mod(num * iden, modulo);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Takes a list of numbers, efficiently inverts all of them.
|
* Takes a list of numbers, efficiently inverts all of them.
|
||||||
* @param nums list of bigints
|
* @param nums list of bigints
|
||||||
|
|||||||
@@ -752,7 +752,8 @@ export function weierstrass(curveDef: CurveType): CurveFn {
|
|||||||
|
|
||||||
// A point on curve is valid if it conforms to equation.
|
// A point on curve is valid if it conforms to equation.
|
||||||
assertValidity(): void {
|
assertValidity(): void {
|
||||||
const msg = 'Point is not on curve';
|
// Some 3rd-party test vectors require different wording between here & `fromCompressedHex`
|
||||||
|
const msg = 'Point is not on elliptic curve';
|
||||||
const { x, y } = this;
|
const { x, y } = this;
|
||||||
if (!isValidFieldElement(x) || !isValidFieldElement(y)) throw new Error(msg);
|
if (!isValidFieldElement(x) || !isValidFieldElement(y)) throw new Error(msg);
|
||||||
const left = modP(y * y);
|
const left = modP(y * y);
|
||||||
|
|||||||
Reference in New Issue
Block a user