Initial commit

This commit is contained in:
Paul Miller 2022-12-03 10:08:49 +00:00
commit a20a357225
No known key found for this signature in database
GPG Key ID: 697079DA6878B89B
56 changed files with 293009 additions and 0 deletions

2
.github/funding.yml vendored Normal file

@ -0,0 +1,2 @@
github: paulmillr
# custom: https://paulmillr.com/funding/

18
.github/workflows/nodejs.yml vendored Normal file

@ -0,0 +1,18 @@
name: Node CI
on: [push, pull_request]
jobs:
test:
name: v18 @ ubuntu-latest
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Use Node.js ${{ matrix.node }}
uses: actions/setup-node@v3
with:
node-version: 18
- run: npm install
- run: npm run build --if-present
- run: cd curve-definitions; npm install; npm run build --if-present
- run: npm test
- run: npm run lint --if-present

7
.gitignore vendored Normal file

@ -0,0 +1,7 @@
build/
node_modules/
coverage/
/lib/**/*.js
/lib/**/*.ts
/lib/**/*.d.ts.map
/curve-definitions/lib

4
.prettierrc.json Normal file

@ -0,0 +1,4 @@
{
"printWidth": 100,
"singleQuote": true
}

21
LICENSE Normal file

@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2022 Paul Miller (https://paulmillr.com)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the “Software”), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

71
README.md Normal file

@ -0,0 +1,71 @@
# noble-curves
Minimal, zero-dependency JS implementation of elliptic curve cryptography.
Implements Short Weierstrass curves with ECDSA signature scheme.
To keep the package minimal, no curve definitions are provided out-of-box.
Main reason for that is the fact hashing library is usually required for full functionality. Use separate package that defines popular curves: `micro-curve-definitions` for P192, P224, P256, P384, P521, secp256k1, stark curve, bn254, pasta (pallas/vesta) - it depends on `@noble/hashes`.
Future plans:
- Edwards, Twisted Edwards & Montgomery curves
- hash-to-curve standard
- pairings
### This library belongs to _noble_ crypto
> **noble-crypto** — high-security, easily auditable set of contained cryptographic libraries and tools.
- No dependencies, small files
- 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:
[secp256k1](https://github.com/paulmillr/noble-secp256k1),
[ed25519](https://github.com/paulmillr/noble-ed25519),
[bls12-381](https://github.com/paulmillr/noble-bls12-381),
[hashes](https://github.com/paulmillr/noble-hashes),
[curves](https://github.com/paulmillr/noble-curves)
## Usage
Use NPM in node.js / browser, or include single file from
[GitHub's releases page](https://github.com/paulmillr/noble-curves/releases):
## Usage
```sh
npm install @noble/curves
```
```ts
// Short Weierstrass curve
import shortw from '@noble/curves/shortw';
import { sha256 } from '@noble/hashes/sha256';
import { hmac } from '@noble/hashes/hmac';
import { concatBytes, randomBytes } from '@noble/hashes/utils';
export const secp256k1 = shortw({
a: 0n,
b: 7n,
// Field over which we'll do calculations
P: 2n ** 256n - 2n ** 32n - 2n ** 9n - 2n ** 8n - 2n ** 7n - 2n ** 6n - 2n ** 4n - 1n,
// Curve order, total count of valid points in the field
n: 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141n,
// Base point (x, y) aka generator point
Gx: 55066263022277343669578718895168534326250603453777594175500187360389116729240n,
Gy: 32670510020758816978083085130507043184471273380659243275938904335757337482424n,
hash: sha256,
hmac: (k: Uint8Array, ...msgs: Uint8Array[]) => hmac(sha256, key, concatBytes(...msgs)),
randomBytes: randomBytes
});
// secp256k1.getPublicKey(priv)
// secp256k1.sign(msg, priv)
// secp256k1.verify(sig, msg, pub)
```
## License
MIT (c) Paul Miller [(https://paulmillr.com)](https://paulmillr.com), see LICENSE file.

21
curve-definitions/LICENSE Normal file

@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2022 Paul Miller (https://paulmillr.com)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the “Software”), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

@ -0,0 +1,28 @@
# micro-curve-definitions
Elliptic curves implementations. `@noble/curves` is zero-dependency library for internal arithmetics.
`micro-curve-definitions` is the actual implementations. Current functionality:
- NIST curves: P192, P224, P256, P384, P521 (ECDSA)
- secp256k1 (ECDSA, without Schnorr)
- stark curve
- bn254
Pairings are not implemented.
## Usage
```sh
npm install micro-curve-definitions
```
```ts
import * as nist from 'micro-curve-definitions';
// P192, P224, P256, P384, P521, bn254
```
## License
MIT (c) Paul Miller [(https://paulmillr.com)](https://paulmillr.com), see LICENSE file.

@ -0,0 +1,62 @@
{
"name": "micro-curve-definitions",
"version": "0.1.0",
"description": "Curve definitions for @noble/curves",
"files": [
"index.js",
"index.d.ts",
"index.d.ts.map",
"index.ts"
],
"type": "module",
"main": "index.js",
"module": "index.js",
"types": "index.d.ts",
"dependencies": {
"@noble/curves": "file:../",
"@noble/hashes": "1.1.4"
},
"devDependencies": {
"@scure/base": "~1.1.0",
"@scure/bip32": "^1.1.1",
"@scure/bip39": "^1.1.0",
"@types/node": "^18.11.3",
"fast-check": "3.0.0",
"micro-should": "0.2.0",
"prettier": "2.6.2",
"typescript": "4.7.3"
},
"author": "Paul Miller (https://paulmillr.com)",
"license": "MIT",
"homepage": "https://github.com/paulmillr/noble-curves",
"repository": {
"type": "git",
"url": "git+https://github.com/paulmillr/noble-curves.git"
},
"scripts": {
"build": "tsc",
"lint": "prettier --check index.ts",
"test": "node test/index.test.js"
},
"keywords": [
"secp192r1",
"secp224r1",
"secp256r1",
"secp384r1",
"secp521r1",
"NIST P192",
"NIST P224",
"NIST P256",
"NIST P384",
"NIST P521",
"NIST curves",
"EC",
"elliptic curves"
],
"funding": [
{
"type": "individual",
"url": "https://paulmillr.com/funding/"
}
]
}

@ -0,0 +1,25 @@
/*! @noble/curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
import { weierstrass, CHash } from '@noble/curves/shortw';
import { concatBytes, randomBytes } from '@noble/hashes/utils';
import { hmac } from '@noble/hashes/hmac';
import { sha256 } from '@noble/hashes/sha256';
function getHash(hash: CHash) {
return {
hash,
hmac: (key: Uint8Array, ...msgs: Uint8Array[]) => hmac(hash, key, concatBytes(...msgs)),
randomBytes,
};
}
// Was known as alt_bn128 when it had 128-bit security. Now that it's much lower, the naming
// has been changed to its prime bit count.
export const bn254 = weierstrass({
a: 0n,
b: 3n,
P: 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47n,
n: 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001n,
Gx: 1n,
Gy: 2n,
...getHash(sha256),
});

@ -0,0 +1,190 @@
/*! @noble/curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
import { hmac } from '@noble/hashes/hmac';
import { sha256 } from '@noble/hashes/sha256';
import { sha384, sha512 } from '@noble/hashes/sha512';
import { concatBytes, randomBytes } from '@noble/hashes/utils';
import { weierstrass, CHash } from '@noble/curves/shortw';
import { mod, pow2 } from '@noble/curves/modular';
function getHash(hash: CHash) {
return {
hash,
hmac: (key: Uint8Array, ...msgs: Uint8Array[]) => hmac(hash, key, concatBytes(...msgs)),
randomBytes,
};
}
// https://www.secg.org/sec2-v2.pdf
// https://neuromancer.sk/std/secg/secp192r1
export const P192 = weierstrass({
// Params: a, b
a: BigInt('0xfffffffffffffffffffffffffffffffefffffffffffffffc'),
b: BigInt('0x64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1'),
// Field over which we'll do calculations. Verify with: 2n ** 192n - 2n ** 64n - 1n
P: BigInt('0xfffffffffffffffffffffffffffffffeffffffffffffffff'),
// Curve order, total count of valid points in the field. Verify with:
n: BigInt('0xffffffffffffffffffffffff99def836146bc9b1b4d22831'),
// Base point (x, y) aka generator point
Gx: BigInt('0x188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012'),
Gy: BigInt('0x07192b95ffc8da78631011ed6b24cdd573f977a11e794811'),
lowS: false,
// Default options
...getHash(sha256),
} as const);
export const secp192r1 = P192;
// https://neuromancer.sk/std/nist/P-224
export const P224 = weierstrass({
// Params: a, b
a: BigInt('0xfffffffffffffffffffffffffffffffefffffffffffffffffffffffe'),
b: BigInt('0xb4050a850c04b3abf54132565044b0b7d7bfd8ba270b39432355ffb4'),
// Field over which we'll do calculations. Verify with:
P: 2n ** 224n - 2n ** 96n + 1n,
// Curve order, total count of valid points in the field. Verify with:
n: BigInt('0xffffffffffffffffffffffffffff16a2e0b8f03e13dd29455c5c2a3d'),
// Base point (x, y) aka generator point
Gx: BigInt('0xb70e0cbd6bb4bf7f321390b94a03c1d356c21122343280d6115c1d21'),
Gy: BigInt('0xbd376388b5f723fb4c22dfe6cd4375a05a07476444d5819985007e34'),
lowS: false,
// Default options
...getHash(sha256),
} as const);
export const secp224r1 = P224;
// https://neuromancer.sk/std/nist/P-256
export const P256 = weierstrass({
// Params: a, b
a: BigInt('0xffffffff00000001000000000000000000000000fffffffffffffffffffffffc'),
b: BigInt('0x5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b'),
// Field over which we'll do calculations. Verify with:
// 2n ** 224n * (2n ** 32n - 1n) + 2n ** 192n + 2n ** 96n - 1n,
P: BigInt('0xffffffff00000001000000000000000000000000ffffffffffffffffffffffff'),
// Curve order, total count of valid points in the field. Verify with:
n: BigInt('0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551'),
// Base point (x, y) aka generator point
Gx: BigInt('0x6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296'),
Gy: BigInt('0x4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5'),
lowS: false,
// Default options
...getHash(sha256),
} as const);
export const secp256r1 = P256;
// https://neuromancer.sk/std/nist/P-384
// prettier-ignore
export const P384 = weierstrass({
// Params: a, b
a: BigInt('0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000fffffffc'),
b: BigInt('0xb3312fa7e23ee7e4988e056be3f82d19181d9c6efe8141120314088f5013875ac656398d8a2ed19d2a85c8edd3ec2aef'),
// Field over which we'll do calculations. Verify with:
// 2n ** 384n - 2n ** 128n - 2n ** 96n + 2n ** 32n - 1n
P: BigInt('0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000ffffffff'),
// Curve order, total count of valid points in the field. Verify with:
n: BigInt('0xffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf581a0db248b0a77aecec196accc52973'),
// Base point (x, y) aka generator point
Gx: BigInt('0xaa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a385502f25dbf55296c3a545e3872760ab7'),
Gy: BigInt('0x3617de4a96262c6f5d9e98bf9292dc29f8f41dbd289a147ce9da3113b5f0b8c00a60b1ce1d7e819d7a431d7c90ea0e5f'),
lowS: false,
// Default options
...getHash(sha384),
} as const);
export const secp384r1 = P384;
// https://neuromancer.sk/std/nist/P-521
// prettier-ignore
export const P521 = weierstrass({
// Params: a, b
a: BigInt('0x01fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc'),
b: BigInt('0x0051953eb9618e1c9a1f929a21a0b68540eea2da725b99b315f3b8b489918ef109e156193951ec7e937b1652c0bd3bb1bf073573df883d2c34f1ef451fd46b503f00'),
// Field over which we'll do calculations. Verify with:
// 2n ** 521n - 1n,
P: BigInt('0x1ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'),
// Curve order, total count of valid points in the field. Verify with:
n: BigInt('0x01fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa51868783bf2f966b7fcc0148f709a5d03bb5c9b8899c47aebb6fb71e91386409'),
// Base point (x, y) aka generator point
Gx: BigInt('0x00c6858e06b70404e9cd9e3ecb662395b4429c648139053fb521f828af606b4d3dbaa14b5e77efe75928fe1dc127a2ffa8de3348b3c1856a429bf97e7e31c2e5bd66'),
Gy: BigInt('0x011839296a789a3bc0045c8a5fb42c7d1bd998f54449579b446817afbd17273e662c97ee72995ef42640c550b9013fad0761353c7086a272c24088be94769fd16650'),
lowS: false,
// Default options
...getHash(sha512),
} as const);
export const secp521r1 = P521;
/**
* secp256k1 definition with efficient square root and endomorphism.
* Endomorphism works only for Koblitz curves with a == 0.
* It improves efficiency:
* Uses 2x less RAM, speeds up precomputation by 2x and ECDH / sign key recovery by 20%.
* Should always be used for Jacobian's double-and-add multiplication.
* For affines cached multiplication, it trades off 1/2 init time & 1/3 ram for 20% perf hit.
* https://gist.github.com/paulmillr/eb670806793e84df628a7c434a873066
*/
const secp256k1P = BigInt('0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f');
const secp256k1N = BigInt('0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141');
const _1n = BigInt(1);
const _2n = BigInt(2);
const divNearest = (a: bigint, b: bigint) => (a + b / _2n) / b;
export const secp256k1 = weierstrass({
a: 0n,
b: 7n,
// Field over which we'll do calculations. Verify with:
// 2n ** 256n - 2n ** 32n - 2n ** 9n - 2n ** 8n - 2n ** 7n - 2n ** 6n - 2n ** 4n - 1n
P: secp256k1P,
// Curve order, total count of valid points in the field. Verify with:
n: secp256k1N,
// Base point (x, y) aka generator point
Gx: BigInt('55066263022277343669578718895168534326250603453777594175500187360389116729240'),
Gy: BigInt('32670510020758816978083085130507043184471273380659243275938904335757337482424'),
...getHash(sha256),
// noble-secp256k1 compat
lowS: true,
// Used to calculate y - the square root of y².
// Exponentiates it to very big number (P+1)/4.
// We are unwrapping the loop because it's 2x faster.
// (P+1n/4n).toString(2) would produce bits [223x 1, 0, 22x 1, 4x 0, 11, 00]
// We are multiplying it bit-by-bit
sqrtMod: (x: bigint): bigint => {
const P = secp256k1P;
const _3n = BigInt(3);
const _6n = BigInt(6);
const _11n = BigInt(11);
const _22n = BigInt(22);
const _23n = BigInt(23);
const _44n = BigInt(44);
const _88n = BigInt(88);
const b2 = (x * x * x) % P; // x^3, 11
const b3 = (b2 * b2 * x) % P; // x^7
const b6 = (pow2(b3, _3n, P) * b3) % P;
const b9 = (pow2(b6, _3n, P) * b3) % P;
const b11 = (pow2(b9, _2n, P) * b2) % P;
const b22 = (pow2(b11, _11n, P) * b11) % P;
const b44 = (pow2(b22, _22n, P) * b22) % P;
const b88 = (pow2(b44, _44n, P) * b44) % P;
const b176 = (pow2(b88, _88n, P) * b88) % P;
const b220 = (pow2(b176, _44n, P) * b44) % P;
const b223 = (pow2(b220, _3n, P) * b3) % P;
const t1 = (pow2(b223, _23n, P) * b22) % P;
const t2 = (pow2(t1, _6n, P) * b2) % P;
return pow2(t2, _2n, P);
},
endo: {
beta: BigInt('0x7ae96a2b657c07106e64479eac3434e99cf0497512f58995c1396c28719501ee'),
splitScalar: (k: bigint) => {
const n = secp256k1N;
const a1 = BigInt('0x3086d221a7d46bcde86c90e49284eb15');
const b1 = -_1n * BigInt('0xe4437ed6010e88286f547fa90abfe4c3');
const a2 = BigInt('0x114ca50f7a8e2f3f657c1108d9d44cfd8');
const b2 = a1;
const POW_2_128 = BigInt('0x100000000000000000000000000000000');
const c1 = divNearest(b2 * k, n);
const c2 = divNearest(-b1 * k, n);
let k1 = mod(k - c1 * a1 - c2 * a2, n);
let k2 = mod(-c1 * b1 - c2 * b2, n);
const k1neg = k1 > POW_2_128;
const k2neg = k2 > POW_2_128;
if (k1neg) k1 = n - k1;
if (k2neg) k2 = n - k2;
if (k1 > POW_2_128 || k2 > POW_2_128) {
throw new Error('splitScalar: Endomorphism failed, k=' + k);
}
return { k1neg, k1, k2neg, k2 };
},
},
});

@ -0,0 +1,35 @@
/*! @noble/curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
import { hmac } from '@noble/hashes/hmac';
import { sha256 } from '@noble/hashes/sha256';
import { concatBytes, randomBytes } from '@noble/hashes/utils';
import { weierstrass, CHash } from '@noble/curves/shortw';
function getHash(hash: CHash) {
return {
hash,
hmac: (key: Uint8Array, ...msgs: Uint8Array[]) => hmac(hash, key, concatBytes(...msgs)),
randomBytes,
};
}
const p = BigInt('0x40000000000000000000000000000000224698fc094cf91b992d30ed00000001');
const q = BigInt('0x40000000000000000000000000000000224698fc0994a8dd8c46eb2100000001');
export const pallas = weierstrass({
a: BigInt(0),
b: BigInt(5),
P: p,
n: q,
Gx: BigInt(-1),
Gy: BigInt(2),
...getHash(sha256),
});
export const vesta = weierstrass({
a: BigInt(0),
b: BigInt(5),
P: q,
n: p,
Gx: BigInt(-1),
Gy: BigInt(2),
...getHash(sha256),
});

@ -0,0 +1,264 @@
/*! @noble/curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
import { keccak_256 } from '@noble/hashes/sha3';
import { sha256 } from '@noble/hashes/sha256';
import { hmac } from '@noble/hashes/hmac';
import { concatBytes, randomBytes } from '@noble/hashes/utils';
import { weierstrass, CHash, JacobianPointType } from '@noble/curves/shortw';
import * as cutils from '@noble/curves/utils';
function getHash(hash: CHash) {
return {
hash,
hmac: (key: Uint8Array, ...msgs: Uint8Array[]) => hmac(hash, key, concatBytes(...msgs)),
randomBytes,
};
}
const CURVE_N = 3618502788666131213697322783095070105526743751716087489154079457884512865583n;
const nBitLength = 252;
// https://docs.starkware.co/starkex/stark-curve.html
export const starkCurve = weierstrass({
// Params: a, b
a: 1n,
b: 3141592653589793238462643383279502884197169399375105820974944592307816406665n,
// Field over which we'll do calculations. Verify with:
// NOTE: there is no efficient sqrt for field (P%4==1)
P: 2n ** 251n + 17n * 2n ** 192n + 1n,
// Curve order, total count of valid points in the field. Verify with:
n: CURVE_N,
nBitLength: nBitLength, // len(bin(N).replace('0b',''))
// Base point (x, y) aka generator point
Gx: 874739451078007766457464989774322083649278607533249481151382481072868806602n,
Gy: 152666792071518830868575557812948353041420400780739481342941381225525861407n,
// Default options
lowS: false,
...getHash(sha256),
truncateHash: (hash: Uint8Array, truncateOnly = false): bigint => {
// TODO: cleanup, ugly code
// Fix truncation
if (!truncateOnly) {
let hashS = bytesToNumber0x(hash).toString(16);
if (hashS.length === 63) {
hashS += '0';
hash = hexToBytes0x(hashS);
}
}
// Truncate zero bytes on left (compat with elliptic)
while (hash[0] === 0) hash = hash.subarray(1);
const byteLength = hash.length;
const delta = byteLength * 8 - nBitLength; // size of curve.n (252 bits)
let h = hash.length ? bytesToNumber0x(hash) : 0n;
if (delta > 0) h = h >> BigInt(delta);
if (!truncateOnly && h >= CURVE_N) h -= CURVE_N;
return h;
},
});
// Custom Starknet type conversion functions that can handle 0x and unpadded hex
function hexToBytes0x(hex: string): Uint8Array {
if (typeof hex !== 'string') {
throw new TypeError('hexToBytes: expected string, got ' + typeof hex);
}
hex = strip0x(hex);
if (hex.length & 1) hex = '0' + hex; // padding
if (hex.length % 2) throw new Error('hexToBytes: received invalid unpadded hex ' + hex.length);
const array = new Uint8Array(hex.length / 2);
for (let i = 0; i < array.length; i++) {
const j = i * 2;
const hexByte = hex.slice(j, j + 2);
const byte = Number.parseInt(hexByte, 16);
if (Number.isNaN(byte) || byte < 0) throw new Error('Invalid byte sequence');
array[i] = byte;
}
return array;
}
function hexToNumber0x(hex: string): bigint {
if (typeof hex !== 'string') {
throw new TypeError('hexToNumber: expected string, got ' + typeof hex);
}
// Big Endian
// TODO: strip vs no strip?
return BigInt(`0x${strip0x(hex)}`);
}
function bytesToNumber0x(bytes: Uint8Array): bigint {
return hexToNumber0x(cutils.bytesToHex(bytes));
}
function ensureBytes0x(hex: Hex): Uint8Array {
// Uint8Array.from() instead of hash.slice() because node.js Buffer
// is instance of Uint8Array, and its slice() creates **mutable** copy
return hex instanceof Uint8Array ? Uint8Array.from(hex) : hexToBytes0x(hex);
}
function sign0x(msgHash: Hex, privKey: Hex, opts: any) {
return starkCurve.sign(ensureBytes0x(msgHash), ensureBytes0x(privKey), opts);
}
function verify0x(signature: Hex, msgHash: Hex, pubKey: Hex) {
const sig = signature instanceof Signature ? signature : ensureBytes0x(signature);
return starkCurve.verify(sig, ensureBytes0x(msgHash), ensureBytes0x(pubKey));
}
const { CURVE, Point, JacobianPoint, Signature, getPublicKey, getSharedSecret } = starkCurve;
export const utils = starkCurve.utils;
export {
CURVE,
Point,
Signature,
JacobianPoint,
getPublicKey,
getSharedSecret,
sign0x as sign,
verify0x as verify,
};
const stripLeadingZeros = (s: string) => s.replace(/^0+/gm, '');
export const bytesToHexEth = (uint8a: Uint8Array): string =>
`0x${stripLeadingZeros(cutils.bytesToHex(uint8a))}`;
export const strip0x = (hex: string) => hex.replace(/^0x/i, '');
export const numberToHexEth = (num: bigint | number) => `0x${num.toString(16)}`;
// We accept hex strings besides Uint8Array for simplicity
type Hex = Uint8Array | string;
// 1. seed generation
function hashKeyWithIndex(key: Uint8Array, index: number) {
let indexHex = cutils.numberToHexUnpadded(index);
if (indexHex.length & 1) indexHex = '0' + indexHex;
return bytesToNumber0x(sha256(cutils.concatBytes(key, hexToBytes0x(indexHex))));
}
export function grindKey(seed: Hex) {
const _seed = ensureBytes0x(seed);
const sha256mask = 2n ** 256n;
const limit = sha256mask - starkCurve.utils.mod(sha256mask, starkCurve.CURVE.n);
for (let i = 0; ; i++) {
const key = hashKeyWithIndex(_seed, i);
// key should be in [0, limit)
if (key < limit) return starkCurve.utils.mod(key, starkCurve.CURVE.n).toString(16);
}
}
export function getStarkKey(privateKey: Hex) {
const priv = typeof privateKey === 'string' ? strip0x(privateKey) : privateKey;
return bytesToHexEth(Point.fromPrivateKey(priv).toRawBytes(true).slice(1));
}
export function ethSigToPrivate(signature: string) {
signature = strip0x(signature.replace(/^0x/, ''));
if (signature.length !== 130) throw new Error('Wrong ethereum signature');
return grindKey(signature.substring(0, 64));
}
const MASK_31 = 2n ** 31n - 1n;
const int31 = (n: bigint) => Number(n & MASK_31);
export function getAccountPath(
layer: string,
application: string,
ethereumAddress: string,
index: number
) {
const layerNum = int31(bytesToNumber0x(sha256(layer)));
const applicationNum = int31(bytesToNumber0x(sha256(application)));
const eth = hexToNumber0x(ethereumAddress);
return `m/2645'/${layerNum}'/${applicationNum}'/${int31(eth)}'/${int31(eth >> 31n)}'/${index}`;
}
// https://docs.starkware.co/starkex/pedersen-hash-function.html
const PEDERSEN_POINTS = [
new Point(
2089986280348253421170679821480865132823066470938446095505822317253594081284n,
1713931329540660377023406109199410414810705867260802078187082345529207694986n
),
new Point(
996781205833008774514500082376783249102396023663454813447423147977397232763n,
1668503676786377725805489344771023921079126552019160156920634619255970485781n
),
new Point(
2251563274489750535117886426533222435294046428347329203627021249169616184184n,
1798716007562728905295480679789526322175868328062420237419143593021674992973n
),
new Point(
2138414695194151160943305727036575959195309218611738193261179310511854807447n,
113410276730064486255102093846540133784865286929052426931474106396135072156n
),
new Point(
2379962749567351885752724891227938183011949129833673362440656643086021394946n,
776496453633298175483985398648758586525933812536653089401905292063708816422n
),
];
// for (const p of PEDERSEN_POINTS) p._setWindowSize(8);
const PEDERSEN_POINTS_JACOBIAN = PEDERSEN_POINTS.map(JacobianPoint.fromAffine);
function pedersenPrecompute(p1: JacobianPointType, p2: JacobianPointType): JacobianPointType[] {
const out: JacobianPointType[] = [];
let p = p1;
for (let i = 0; i < 248; i++) {
out.push(p);
p = p.double();
}
p = p2;
for (let i = 0; i < 4; i++) {
out.push(p);
p = p.double();
}
return out;
}
const PEDERSEN_POINTS1 = pedersenPrecompute(
PEDERSEN_POINTS_JACOBIAN[1],
PEDERSEN_POINTS_JACOBIAN[2]
);
const PEDERSEN_POINTS2 = pedersenPrecompute(
PEDERSEN_POINTS_JACOBIAN[3],
PEDERSEN_POINTS_JACOBIAN[4]
);
type PedersenArg = Hex | bigint | number;
function pedersenArg(arg: PedersenArg): bigint {
let value: bigint;
if (typeof arg === 'bigint') value = arg;
else if (typeof arg === 'number') {
if (!Number.isSafeInteger(arg)) throw new Error(`Invalid pedersenArg: ${arg}`);
value = BigInt(arg);
} else value = bytesToNumber0x(ensureBytes0x(arg));
// [0..Fp)
if (!(0n <= value && value < starkCurve.CURVE.P))
throw new Error(`PedersenArg should be 0 <= value < CURVE.P: ${value}`);
return value;
}
function pedersenSingle(
point: JacobianPointType,
value: PedersenArg,
constants: JacobianPointType[]
) {
let x = pedersenArg(value);
for (let j = 0; j < 252; j++) {
const pt = constants[j];
if (pt.x === point.x) throw new Error('Same point');
if ((x & 1n) !== 0n) point = point.add(pt);
x >>= 1n;
}
return point;
}
// shift_point + x_low * P_0 + x_high * P1 + y_low * P2 + y_high * P3
export function pedersen(x: PedersenArg, y: PedersenArg) {
let point: JacobianPointType = PEDERSEN_POINTS_JACOBIAN[0];
point = pedersenSingle(point, x, PEDERSEN_POINTS1);
point = pedersenSingle(point, y, PEDERSEN_POINTS2);
return bytesToHexEth(point.toAffine().toRawBytes(true).slice(1));
}
export function hashChain(data: PedersenArg[], fn = pedersen) {
if (!Array.isArray(data) || data.length < 1)
throw new Error('data should be array of at least 1 element');
if (data.length === 1) return numberToHexEth(pedersenArg(data[0]));
return Array.from(data)
.reverse()
.reduce((acc, i) => fn(i, acc));
}
// Same as hashChain, but computes hash even for single element and order is not revesed
export const computeHashOnElements = (data: PedersenArg[], fn = pedersen) =>
[0, ...data, data.length].reduce((x, y) => fn(x, y));
const MASK_250 = 2n ** 250n - 1n;
export const keccak = (data: Uint8Array) => bytesToNumber0x(keccak_256(data)) & MASK_250;

@ -0,0 +1,97 @@
import { deepStrictEqual, throws } from 'assert';
import { should } from 'micro-should';
import * as nist from '../lib/nist.js';
import { hexToBytes } from '@noble/curves/utils';
import { default as ecdsa } from './fixtures/ecdsa_test.json' assert { type: 'json' };
import { default as ecdh } from './fixtures/ecdh_test.json' assert { type: 'json' };
// import { hexToBytes } from '@noble/curves';
should('Curve Fields', () => {
const vectors = {
secp192r1: 0xfffffffffffffffffffffffffffffffeffffffffffffffffn,
secp224r1: 0xffffffffffffffffffffffffffffffff000000000000000000000001n,
secp256r1: 0xffffffff00000001000000000000000000000000ffffffffffffffffffffffffn,
secp256k1: 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2fn,
secp384r1:
0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000ffffffffn,
secp521r1:
0x01ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffn,
};
for (const n in vectors) deepStrictEqual(nist[n].CURVE.P, vectors[n]);
});
should('wychenproof ECDSA vectors', () => {
for (const group of ecdsa.testGroups) {
// Tested in secp256k1.test.js
if (group.key.curve === 'secp256k1') continue;
// We don't have SHA-224
if (group.key.curve === 'secp224r1' && group.sha === 'SHA-224') continue;
const CURVE = nist[group.key.curve];
if (!CURVE) continue;
const pubKey = CURVE.Point.fromHex(group.key.uncompressed);
deepStrictEqual(pubKey.x, BigInt(`0x${group.key.wx}`));
deepStrictEqual(pubKey.y, BigInt(`0x${group.key.wy}`));
for (const test of group.tests) {
if (['Hash weaker than DL-group'].includes(test.comment)) {
continue;
}
const m = CURVE.CURVE.hash(hexToBytes(test.msg));
if (test.result === 'valid' || test.result === 'acceptable') {
try {
CURVE.Signature.fromDER(test.sig);
} catch (e) {
// Some test has invalid signature which we don't accept
if (e.message.includes('Invalid signature: incorrect length')) continue;
throw e;
}
const verified = CURVE.verify(test.sig, m, pubKey);
deepStrictEqual(verified, true, 'valid');
} else if (test.result === 'invalid') {
let failed = false;
try {
failed = !CURVE.verify(test.sig, m, pubKey);
} catch (error) {
failed = true;
}
deepStrictEqual(failed, true, 'invalid');
} else throw new Error('unknown test result');
}
}
});
should('wychenproof ECDH vectors', () => {
for (const group of ecdh.testGroups) {
// // Tested in secp256k1.test.js
// if (group.key.curve === 'secp256k1') continue;
// We don't have SHA-224
const CURVE = nist[group.curve];
if (!CURVE) continue;
for (const test of group.tests) {
if (test.result === 'valid' || test.result === 'acceptable') {
try {
const pub = CURVE.Point.fromHex(test.public);
} catch (e) {
if (e.message.includes('Point.fromHex: received invalid point.')) continue;
throw e;
}
const shared = CURVE.getSharedSecret(test.private, test.public);
deepStrictEqual(shared, test.shared, 'valid');
} else if (test.result === 'invalid') {
let failed = false;
try {
CURVE.getSharedSecret(test.private, test.public);
} catch (error) {
failed = true;
}
deepStrictEqual(failed, true, 'invalid');
} else throw new Error('unknown test result');
}
}
});
// ESM is broken.
import url from 'url';
if (import.meta.url === url.pathToFileURL(process.argv[1]).href) {
should.run();
}

@ -0,0 +1,898 @@
{
"algorithm" : "ECDH",
"generatorVersion" : "0.8r12",
"numberOfTests" : 96,
"header" : [
"Test vectors of type EcdhWebTest are intended for",
"testing an ECDH implementations where the public key",
"is just an ASN encoded point."
],
"notes" : {
"AddSubChain" : "The private key has a special value. Implementations using addition subtraction chains for the point multiplication may get the point at infinity as an intermediate result. See CVE_2017_10176",
"CompressedPoint" : "The point in the public key is compressed. Not every library supports points in compressed format."
},
"schema" : "ecdh_ecpoint_test_schema.json",
"testGroups" : [
{
"curve" : "secp224r1",
"encoding" : "ecpoint",
"type" : "EcdhEcpointTest",
"tests" : [
{
"tcId" : 1,
"comment" : "normal case",
"public" : "047d8ac211e1228eb094e285a957d9912e93deee433ed777440ae9fc719b01d050dfbe653e72f39491be87fb1a2742daa6e0a2aada98bb1aca",
"private" : "565577a49415ca761a0322ad54e4ad0ae7625174baf372c2816f5328",
"shared" : "b8ecdb552d39228ee332bafe4886dbff272f7109edf933bc7542bd4f",
"result" : "valid",
"flags" : []
},
{
"tcId" : 2,
"comment" : "compressed public key",
"public" : "027d8ac211e1228eb094e285a957d9912e93deee433ed777440ae9fc71",
"private" : "565577a49415ca761a0322ad54e4ad0ae7625174baf372c2816f5328",
"shared" : "b8ecdb552d39228ee332bafe4886dbff272f7109edf933bc7542bd4f",
"result" : "acceptable",
"flags" : [
"CompressedPoint"
]
},
{
"tcId" : 3,
"comment" : "edge case for shared secret",
"public" : "04e73a6ca72f3a2fae6e0a01a0ed03bfa3058b04576942eaf063095e62ca16fd31fa0f38eeb592cbeea1147751fdd2a5b6cc0ead404467a5b6",
"private" : "00a2b6442a37f9201b56758034d2009be64b0ab7c02d7e398cac9665d6",
"shared" : "00000000000000000000000000000000000000000000000000000003",
"result" : "valid",
"flags" : []
},
{
"tcId" : 4,
"comment" : "edge case for shared secret",
"public" : "045763fa2ae16367ad23d471cc9a52466f0d81d864e5640cefe384114594d9fecfbed4f254505ac8b41d2532055a07f0241c4818b552cbb636",
"private" : "00a2b6442a37f9201b56758034d2009be64b0ab7c02d7e398cac9665d6",
"shared" : "00000000000000000000000100000000000000000000000000000001",
"result" : "valid",
"flags" : []
},
{
"tcId" : 5,
"comment" : "edge case for shared secret",
"public" : "04142c1fd80fa2121a59aa898144084ec033f7a56a34eee0b499e29ae51c6d8c1bbb1ef2a76d565899fe44ffc1207d530d7f598fb77f4bb76b",
"private" : "00a2b6442a37f9201b56758034d2009be64b0ab7c02d7e398cac9665d6",
"shared" : "00000000000000ffffffffffffff0000000000000100000000000000",
"result" : "valid",
"flags" : []
},
{
"tcId" : 6,
"comment" : "edge case for shared secret",
"public" : "04ed6f793e10c80d12d871cf8988399c4898a9bf9ffd8f27399f63de25f0051cdf4eec7f368f922cfcd948893ceca0c92e540cc4367a99a66a",
"private" : "00a2b6442a37f9201b56758034d2009be64b0ab7c02d7e398cac9665d6",
"shared" : "00000000ffffffffffffffff00000000000000010000000000000000",
"result" : "valid",
"flags" : []
},
{
"tcId" : 7,
"comment" : "edge case for shared secret",
"public" : "0408fcfc1a63c82860be12e4137433dfc40be9acdd245f9a8c4e56be61a385fc09f808383383f4b1d0d5365b6e5dcfacdc19bc7bcfed221274",
"private" : "00a2b6442a37f9201b56758034d2009be64b0ab7c02d7e398cac9665d6",
"shared" : "0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff",
"result" : "valid",
"flags" : []
},
{
"tcId" : 8,
"comment" : "edge case for shared secret",
"public" : "04d883ed77f1861e8712800d31df67888fe39f150c79a27aa88caeda6b180f3f623e2ff3ab5370cf8179165b085af3dd4502850c0104caed9a",
"private" : "00a2b6442a37f9201b56758034d2009be64b0ab7c02d7e398cac9665d6",
"shared" : "0003fffffff00000003fffffff00000003fffffff000000040000000",
"result" : "valid",
"flags" : []
},
{
"tcId" : 9,
"comment" : "edge case for shared secret",
"public" : "042b8b279b85ee3f3d2c0abeb36fdfc5aad6157d652d26489381a32cd73224bd757ef794acc92b0b3b9e7990618bb343a9a09bdb9d3616eff6",
"private" : "00a2b6442a37f9201b56758034d2009be64b0ab7c02d7e398cac9665d6",
"shared" : "01fffffffc00000007fffffff00000001fffffffc000000080000001",
"result" : "valid",
"flags" : []
},
{
"tcId" : 10,
"comment" : "edge case for shared secret",
"public" : "048bd5f03391eeeae1744e8fc53d314efffafa4d3fa4f1b95c3388a9cd7c86358b273119c537133eb55e79c6ac510b10980b379b919ccf2e2f",
"private" : "00a2b6442a37f9201b56758034d2009be64b0ab7c02d7e398cac9665d6",
"shared" : "0a15c112ff784b1445e889f955be7e3ffdf451a2c0e76ab5cb32cf41",
"result" : "valid",
"flags" : []
},
{
"tcId" : 11,
"comment" : "edge case for shared secret",
"public" : "04ce9631b6a16227778625c8e5421ae083cdd913abefde01dbe69f6c2b95386aff2b483b2c47151cfaabfd000614c683ce2e1778221ae42c1b",
"private" : "00a2b6442a37f9201b56758034d2009be64b0ab7c02d7e398cac9665d6",
"shared" : "62989eaaa26a16f07330c3c51e0a4631fd016bfcede26552816aee39",
"result" : "valid",
"flags" : []
},
{
"tcId" : 12,
"comment" : "edge case for shared secret",
"public" : "041f441c98eda956a6a7fdbfd8d21910860ab59d16c3e52f8e7fad6ca5df61a55fc508fc0499c55492f1e87bb2faa0cb4170b79f3a85ec2f3d",
"private" : "00a2b6442a37f9201b56758034d2009be64b0ab7c02d7e398cac9665d6",
"shared" : "661ac958c0febbc718ccf39cefc6b66c4231fbb9a76f35228a3bf5c3",
"result" : "valid",
"flags" : []
},
{
"tcId" : 13,
"comment" : "edge case for shared secret",
"public" : "04be74583cb9d3a05ae54923624e478a329a697d842dfae33141c844d7d9ba4fc96e0fe716ac0542e87368662fc2f0cb9b0ae57936ddec7190",
"private" : "00a2b6442a37f9201b56758034d2009be64b0ab7c02d7e398cac9665d6",
"shared" : "6d7e41821abe1094d430237923d2a50de31768ab51b12dce8a09e34c",
"result" : "valid",
"flags" : []
},
{
"tcId" : 14,
"comment" : "edge case for shared secret",
"public" : "04a281ad992b363597ac93ff0de8ab1f7e51a6672dcbb58f9d739ba430ce0192874038daefc3130eec65811c7255da70fea65c1003f6892faa",
"private" : "00a2b6442a37f9201b56758034d2009be64b0ab7c02d7e398cac9665d6",
"shared" : "7fffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"result" : "valid",
"flags" : []
},
{
"tcId" : 15,
"comment" : "edge case for shared secret",
"public" : "04be3e22133f51203f631b81dde8c020cdea5daa1f99cfc05c88fad2dc0f243798d6e72d1de9e3cdca4144e0a6c0f2a584d07589006972c197",
"private" : "00a2b6442a37f9201b56758034d2009be64b0ab7c02d7e398cac9665d6",
"shared" : "fffc0007fff0001fffc0007fff0001fffc0007fff0001fffc0008001",
"result" : "valid",
"flags" : []
},
{
"tcId" : 16,
"comment" : "edge case for shared secret",
"public" : "04af14547c20afbd91bfe64ea03d45a76a71241f23520ef897ff91eff1b54ca6ca8c25fd73852ec6654617434eff7f0225684d4dea7a4f8a97",
"private" : "00a2b6442a37f9201b56758034d2009be64b0ab7c02d7e398cac9665d6",
"shared" : "ffff0000003ffffff0000003ffffff0000003ffffff0000003ffffff",
"result" : "valid",
"flags" : []
},
{
"tcId" : 17,
"comment" : "edge case for shared secret",
"public" : "04b1e484925018729926acda56ff3e2f6c1e7e8f162b178d8e8afb45564fceaa6da5d998fe26b6b26a055169063a5ab6908852ca8b54e2de6c",
"private" : "00a2b6442a37f9201b56758034d2009be64b0ab7c02d7e398cac9665d6",
"shared" : "fffff0000007fffffe000000ffffffc000001ffffff8000003ffffff",
"result" : "valid",
"flags" : []
},
{
"tcId" : 18,
"comment" : "edge case for shared secret",
"public" : "04937eb09fb145c8829cb7df20a4cbeed396791373de277871d6c5f9cc3b5b4fd56464a71fc4a2a6af3bd251952bffa829489e68a8d06f96b6",
"private" : "00a2b6442a37f9201b56758034d2009be64b0ab7c02d7e398cac9665d6",
"shared" : "ffffffff00000000ffffffff00000000ffffffff00000000ffffffff",
"result" : "valid",
"flags" : []
},
{
"tcId" : 19,
"comment" : "edge cases for ephemeral key",
"public" : "04000000000000000000000000000000000000000000000000000000037cac269c67bd55ea14efff4eadefe5e74978514af14c88fab46ec046",
"private" : "2bc15cf3981f4e15bbad387b506df647989e5478160be862f8c26969",
"shared" : "3fa0b9ff70b884f9f57bb84f7a9532d93f6ba803f89dd8ff008177d7",
"result" : "valid",
"flags" : []
},
{
"tcId" : 20,
"comment" : "edge cases for ephemeral key",
"public" : "04000000000000000000000001000000000000000000000000000000012ea2f4917bdfdb008306cc10a18e2557633ba861001829dcbfb96fba",
"private" : "2bc15cf3981f4e15bbad387b506df647989e5478160be862f8c26969",
"shared" : "be1ded8cb7ff8a585181f96d681e31b332fe27dcae922dca2310300d",
"result" : "valid",
"flags" : []
},
{
"tcId" : 21,
"comment" : "edge cases for ephemeral key",
"public" : "0400000000000000ffffffffffffff000000000000010000000000000073ca5f8f104997a2399e0c7f25e72a75ec29fc4542533d3fea89a33a",
"private" : "2bc15cf3981f4e15bbad387b506df647989e5478160be862f8c26969",
"shared" : "a2e86a260e13515918a0cafdd87855f231b5624c560f976159e06a75",
"result" : "valid",
"flags" : []
},
{
"tcId" : 22,
"comment" : "edge cases for ephemeral key",
"public" : "0400000000ffffffffffffffff000000000000000100000000000000006fe6805f59b19b0dd389452a1d4a420bfeb6c369cf6fed5b12e6e654",
"private" : "2bc15cf3981f4e15bbad387b506df647989e5478160be862f8c26969",
"shared" : "31ef7c8d10404a0046994f313a70574b027e87f9028eca242c1b5bf5",
"result" : "valid",
"flags" : []
},
{
"tcId" : 23,
"comment" : "edge cases for ephemeral key",
"public" : "040000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff77c5cfa4e2c384938d48bd8dd98f54c86b279f1df8c0a1f6692439c9",
"private" : "2bc15cf3981f4e15bbad387b506df647989e5478160be862f8c26969",
"shared" : "d1976a8ef5f54f24f5a269ad504fdca849fc9c28587ba294ef267396",
"result" : "valid",
"flags" : []
},
{
"tcId" : 24,
"comment" : "edge cases for ephemeral key",
"public" : "040003fffffff00000003fffffff00000003fffffff00000004000000001f0828136016bb97445461bc59f2175d8d23557d6b9381f26136e3d",
"private" : "2bc15cf3981f4e15bbad387b506df647989e5478160be862f8c26969",
"shared" : "ce7890d108ddb2e5474e6417fcf7a9f2b3bd018816062f4835260dc8",
"result" : "valid",
"flags" : []
},
{
"tcId" : 25,
"comment" : "edge cases for ephemeral key",
"public" : "0401fffffffc00000007fffffff00000001fffffffc0000000800000012d8acca6f199d4a94b933ba1aa713a7debde8ac57b928f596ae66a66",
"private" : "2bc15cf3981f4e15bbad387b506df647989e5478160be862f8c26969",
"shared" : "30b6ff6e8051dae51e4fe34b2d9a0b1879153e007eb0b5bdf1791a9c",
"result" : "valid",
"flags" : []
},
{
"tcId" : 26,
"comment" : "edge cases for ephemeral key",
"public" : "040a15c112ff784b1445e889f955be7e3ffdf451a2c0e76ab5cb32cf413d4df973c563c6decdd435e4f864557e4c273096d9941ca4260a266e",
"private" : "2bc15cf3981f4e15bbad387b506df647989e5478160be862f8c26969",
"shared" : "77ec668a00f72d85aa527624abb16c039fe490d17dd6c455a1ed7fd8",
"result" : "valid",
"flags" : []
},
{
"tcId" : 27,
"comment" : "edge cases for ephemeral key",
"public" : "0462989eaaa26a16f07330c3c51e0a4631fd016bfcede26552816aee39389ee9436d616cab90032931aa7fbbfcfc13309f61e2423cc8dab93c",
"private" : "2bc15cf3981f4e15bbad387b506df647989e5478160be862f8c26969",
"shared" : "a3f432f6aba9a92f49a5ea64ffe7059a9d9b487a0b5223ddc988208b",
"result" : "valid",
"flags" : []
},
{
"tcId" : 28,
"comment" : "edge cases for ephemeral key",
"public" : "04661ac958c0febbc718ccf39cefc6b66c4231fbb9a76f35228a3bf5c3103b8040e3cb41966fc64a68cacb0c14053f87d27e8ed7bf2d7fe51b",
"private" : "2bc15cf3981f4e15bbad387b506df647989e5478160be862f8c26969",
"shared" : "1530fd9caf03737af34a4ba716b558cbecbc35d18402535a0a142313",
"result" : "valid",
"flags" : []
},
{
"tcId" : 29,
"comment" : "edge cases for ephemeral key",
"public" : "046d7e41821abe1094d430237923d2a50de31768ab51b12dce8a09e34c276cf273d75d367820dd556182def0957af0a314f48fed227c298dc0",
"private" : "2bc15cf3981f4e15bbad387b506df647989e5478160be862f8c26969",
"shared" : "cfc39ccacb94ad0e0552b2e47112f60fbbe7ae0dc32230b9273dd210",
"result" : "valid",
"flags" : []
},
{
"tcId" : 30,
"comment" : "edge cases for ephemeral key",
"public" : "047fffffffffffffffffffffffffffffffffffffffffffffffffffffff7d8dbca36c56bcaae92e3475f799294f30768038e816a7d5f7f07d77",
"private" : "2bc15cf3981f4e15bbad387b506df647989e5478160be862f8c26969",
"shared" : "73bd63bd384a0faafb75cfed3e95d3892cbacf0db10f282c3b644771",
"result" : "valid",
"flags" : []
},
{
"tcId" : 31,
"comment" : "edge cases for ephemeral key",
"public" : "04fffc0007fff0001fffc0007fff0001fffc0007fff0001fffc000800174f1ff5ea7fbc72b92f61e06556c26bab84c0b082dd6400ca1c1eb6d",
"private" : "2bc15cf3981f4e15bbad387b506df647989e5478160be862f8c26969",
"shared" : "85b079c62e1f5b0fd6841dfa16026e15b641f65e13a14042567166bb",
"result" : "valid",
"flags" : []
},
{
"tcId" : 32,
"comment" : "edge cases for ephemeral key",
"public" : "04ffff0000003ffffff0000003ffffff0000003ffffff0000003ffffff0126fdd5fccd0b5aa7fd5bb5b1308584b30556248cec80208a2fe962",
"private" : "2bc15cf3981f4e15bbad387b506df647989e5478160be862f8c26969",
"shared" : "8a834ff40e3fc9f9d412a481e18537ea799536c5520c6c7baaf12166",
"result" : "valid",
"flags" : []
},
{
"tcId" : 33,
"comment" : "edge cases for ephemeral key",
"public" : "04fffff0000007fffffe000000ffffffc000001ffffff8000003ffffff20cfa23077acc9fbcb71339c65880cd0b966b8a9497e65abed17f0b5",
"private" : "2bc15cf3981f4e15bbad387b506df647989e5478160be862f8c26969",
"shared" : "a0887269766e6efcbc81d2b38f2d4638663f12377468a23421044188",
"result" : "valid",
"flags" : []
},
{
"tcId" : 34,
"comment" : "edge cases for ephemeral key",
"public" : "04ffffffff00000000ffffffff00000000ffffffff00000000ffffffff1c05ac2d4f10b69877c3243d51f887277b7bf735c326ab2f0d70da8c",
"private" : "2bc15cf3981f4e15bbad387b506df647989e5478160be862f8c26969",
"shared" : "c65d1911bc076a74588d8793ce7a0dcabf5793460cd2ebb02754a1be",
"result" : "valid",
"flags" : []
},
{
"tcId" : 35,
"comment" : "point with coordinate y = 1",
"public" : "043b5889352ddf7468bf8c0729212aa1b2a3fcb1a844b8be91abb753d500000000000000000000000000000000000000000000000000000001",
"private" : "00938f3dbe37135cdbdb9993a187a0e9b9f0def035fbc52ad59fc50421",
"shared" : "e973c413cc7dd34d4e3637522b2e033c20815412b67574a1f2f6bdd7",
"result" : "valid",
"flags" : []
},
{
"tcId" : 36,
"comment" : "point with coordinate y = 1",
"public" : "04bf09e268942555c73ce9e00d272c9b12bf0c3fc13a639acc791167f6b05df0023c9bd41d0b0c461854582d0601182213f2219d44ea44914a",
"private" : "00938f3dbe37135cdbdb9993a187a0e9b9f0def035fbc52ad59fc50421",
"shared" : "ec856e807808a9c5332e886759e03f01be02437cfe0214613e4e7dc7",
"result" : "valid",
"flags" : []
},
{
"tcId" : 37,
"comment" : "point with coordinate y = 1",
"public" : "047b664cff2eef0a4f7dce24780113432f66feb25cb0931d033d63910f548ee514f6fdf1cb6f5709581c197d76a5eb218afaed19f205f4ab80",
"private" : "00938f3dbe37135cdbdb9993a187a0e9b9f0def035fbc52ad59fc50421",
"shared" : "91d424e122c9c01720bbed6b53ec1b37a86996fa4fcf74bfd30f723d",
"result" : "valid",
"flags" : []
},
{
"tcId" : 38,
"comment" : "point with coordinate y = 1 in left to right addition chain",
"public" : "045a2b3ec1053390550b587557712bcc0bf85654d23099420154877ec4138322ca02e5fceae870227a43ae8982b67276f6d8f1dd7e12692474",
"private" : "00938f3dbe37135cdbdb9993a187a0e9b9f0def035fbc52ad59fc50421",
"shared" : "012879a1ff456acb8726455836bc4f504c1bd799a4d96f514b3730c6",
"result" : "valid",
"flags" : []
},
{
"tcId" : 39,
"comment" : "point with coordinate y = 1 in left to right addition chain",
"public" : "04fc229bb1df3e11351e7e4224f68f40c0d0e194023c6e0840cd45ee5ca242112fbab5736e821dad26493e4006e2c6125342e7d9bc25272856",
"private" : "00938f3dbe37135cdbdb9993a187a0e9b9f0def035fbc52ad59fc50421",
"shared" : "fd6e5edb54d7dd554f8747ec87b8031258fc0bf1d2404b64db4540d4",
"result" : "valid",
"flags" : []
},
{
"tcId" : 40,
"comment" : "point with coordinate y = 1 in left to right addition chain",
"public" : "0469a65f62d4159235801a246f2d13e45c8983a3362da480e7a51d42a65b7047abfc2a179d943bb196fede7ac3ad8a4fcacd4c4caa717b6b26",
"private" : "00938f3dbe37135cdbdb9993a187a0e9b9f0def035fbc52ad59fc50421",
"shared" : "164e95bfa2a9c3a1f959feb88720bb7a37f988a08124639d8adf86df",
"result" : "valid",
"flags" : []
},
{
"tcId" : 41,
"comment" : "point with coordinate y = 1 in left to right addition chain",
"public" : "04dc68eb945528af0051cbf23e3eea43b2bc4c728976231e7031e63a2744ba65a4e1e34e8ec50cf7e8df4458582b16413ab83f568508c59037",
"private" : "00938f3dbe37135cdbdb9993a187a0e9b9f0def035fbc52ad59fc50421",
"shared" : "b0ffd55fa112aa48eddc960db4a1200d406e144aac9e109ad9892b2d",
"result" : "valid",
"flags" : []
},
{
"tcId" : 42,
"comment" : "point with coordinate y = 1 in left to right addition chain",
"public" : "0481c89369d7be252920e08e2d6c6841b887efb4fc747db31dd1030b1919bf8ccb629b58fea6234e39812083fb0833a0c937e348eda22ea0c0",
"private" : "00938f3dbe37135cdbdb9993a187a0e9b9f0def035fbc52ad59fc50421",
"shared" : "d6ab4567eff21277284be082d9e09eb08bb80685f4929dc3dca4b333",
"result" : "valid",
"flags" : []
},
{
"tcId" : 43,
"comment" : "point with coordinate y = 1 in left to right addition chain",
"public" : "0451d830f792795409f1ee972d3b94289f59206fe09e12166920739a73d2f1831b26677901bfaf8323f82b81e1012d9d3f1c9296c59c97970f",
"private" : "00938f3dbe37135cdbdb9993a187a0e9b9f0def035fbc52ad59fc50421",
"shared" : "b43de12912b40cbdd56e30fdfe9a2c24fb72687168c9cfe6b7476966",
"result" : "valid",
"flags" : []
},
{
"tcId" : 44,
"comment" : "point with coordinate y = 1 in left to right addition chain",
"public" : "04ab63ce55145842149f99023f37a0a89b9fc4ae6a878fdae8caf31d17ffd0d55830eed46f8255f94b6dcf98a22f1ff26dabf773d556788881",
"private" : "00938f3dbe37135cdbdb9993a187a0e9b9f0def035fbc52ad59fc50421",
"shared" : "588ee0af3bc60118a715325c6d56c850f73067dcb37b7596d0cfda5f",
"result" : "valid",
"flags" : []
},
{
"tcId" : 45,
"comment" : "point with coordinate y = 1 in left to right addition chain",
"public" : "041d64535d54bfcccb38165acbfac01ae33db20e802c5687343cb21b7eb59d86f1892a974741925624477eef21f4e72fa04ee6ce35dfffe5f2",
"private" : "00938f3dbe37135cdbdb9993a187a0e9b9f0def035fbc52ad59fc50421",
"shared" : "7219ef73ac9e47ac2e03dead23fa8382ae898e2415017cdeb4739f0f",
"result" : "valid",
"flags" : []
},
{
"tcId" : 46,
"comment" : "point with coordinate y = 1 in left to right addition chain",
"public" : "04d9d78436a3f9c1fa20e8c2318e61e62b94623e23a0ab746c5ac0cbc38262bd66c17515d3048944dae43b2bd6dd9d7c7a0f7042de2d1001c6",
"private" : "00938f3dbe37135cdbdb9993a187a0e9b9f0def035fbc52ad59fc50421",
"shared" : "267b069aac5d768a720acc62c92f20b786fc48c7da42f1f5677424ee",
"result" : "valid",
"flags" : []
},
{
"tcId" : 47,
"comment" : "point with coordinate y = 1 in left to right addition chain",
"public" : "0465eb3750c6401339caa69ebe6dec86dfc4d79bf657d68bbdd082c5a03eb81e85931352ff338ccbc3a1d332e2d8bc84342d516da06bef220f",
"private" : "00938f3dbe37135cdbdb9993a187a0e9b9f0def035fbc52ad59fc50421",
"shared" : "bbdd4ac5890b9c0412e4ef3135f666e5b3ddb658ec837691e8129be8",
"result" : "valid",
"flags" : []
},
{
"tcId" : 48,
"comment" : "point with coordinate y = 1 in left to right addition chain",
"public" : "04e92d3be1614555ae17a90647979fbb37468c55a1fff9e15f376d49994e470f515b7b3fe50cb55def16142df594c3e46d9d1354730778f9e8",
"private" : "00938f3dbe37135cdbdb9993a187a0e9b9f0def035fbc52ad59fc50421",
"shared" : "f793ff0d14bd7690840c733162b589cd3413d8c41f4488b427da496f",
"result" : "valid",
"flags" : []
},
{
"tcId" : 49,
"comment" : "point with coordinate y = 1 in left to right addition chain",
"public" : "043c92710c9a7f6f98bbec9d2a4fa617cc70e96bc96ecd4597e329143f4750a027c6972459c091ab02c0e2a3082fccec429a38d3596e7aff2b",
"private" : "00938f3dbe37135cdbdb9993a187a0e9b9f0def035fbc52ad59fc50421",
"shared" : "56c703d4716239c954109b9b841db75b04a790f1f72aa966aece3494",
"result" : "valid",
"flags" : []
},
{
"tcId" : 50,
"comment" : "point with coordinate y = 1 in left to right addition chain",
"public" : "04568dfbfa42efc94ce207322e637b4c94f37a5668ad230e987a91d048dcadd244fc059cffab5fa8820a969353620e708e85bd5eec8a0c68ec",
"private" : "00938f3dbe37135cdbdb9993a187a0e9b9f0def035fbc52ad59fc50421",
"shared" : "7823fe7eb642d50984fb32f911ef289419d85330c3398423d0eda05f",
"result" : "valid",
"flags" : []
},
{
"tcId" : 51,
"comment" : "point with coordinate y = 1 in left to right addition chain",
"public" : "04ec10837e495b644904dba58d8dd82133c905a285ae7c2a06d5ccaf6bf0fbf00d13e21a399dc95ae5524a1a37044193e94e3300259b70e058",
"private" : "00938f3dbe37135cdbdb9993a187a0e9b9f0def035fbc52ad59fc50421",
"shared" : "f7014d38f460836a51075cce9667b56b8851ba19011c8b0274b74a4b",
"result" : "valid",
"flags" : []
},
{
"tcId" : 52,
"comment" : "point with coordinate y = 1 in left to right addition chain",
"public" : "04bee2f9352f42ceeb3bf3109e90e6578d0bd4888458df7d179d746977e50e53503dee83eca1824a290566588fa3591645b1a2d56861bda760",
"private" : "00938f3dbe37135cdbdb9993a187a0e9b9f0def035fbc52ad59fc50421",
"shared" : "777f99f2bdaa72a1185388465ddda1d059872ad043c7cb85b94e28bb",
"result" : "valid",
"flags" : []
},
{
"tcId" : 53,
"comment" : "point with coordinate y = 1 in left to right addition chain",
"public" : "04546facbcaa8b551c51715a9add5edc3c8a66dcc47a6223f605614cf7af6d92f5bdebea738658a42c6231e53c08237ccf52f79399579b2dcc",
"private" : "00938f3dbe37135cdbdb9993a187a0e9b9f0def035fbc52ad59fc50421",
"shared" : "a1db178b716e51e0fa46c1d74a2603005326bca7e81170d4b33a3d2a",
"result" : "valid",
"flags" : []
},
{
"tcId" : 54,
"comment" : "point with coordinate y = 1 in left to right addition chain",
"public" : "0423b1811fee891adb33c8bfee289964e92a9d3358daf975d0efb73e229a3332668b7d6da290a2edc941e8bd6f2e33745fc606756eddc013bb",
"private" : "00938f3dbe37135cdbdb9993a187a0e9b9f0def035fbc52ad59fc50421",
"shared" : "f455c8273416199505019861266ddb9bcde7bee3c3f15a98ee54607b",
"result" : "valid",
"flags" : []
},
{
"tcId" : 55,
"comment" : "point with coordinate y = 1 in precomputation or right to left addition chain",
"public" : "0458f53d67332415fe5b4b81999f8332fb6dcdb965d96dbcbab0fac375f29efef7ab4d94bb2d25d25205eae29fe8d9a85b811114a50f6c6859",
"private" : "00c1781d86cac2c0af3fb50d54c554a67bd75d25ca796f0486e3fa84f9",
"shared" : "d3af1857aca1689514fcfee8d8c40b8637d40452ae35c404f9e67494",
"result" : "valid",
"flags" : []
},
{
"tcId" : 56,
"comment" : "point with coordinate y = 1 in precomputation or right to left addition chain",
"public" : "04f2d6e58fcd3ed3f656a9bc687fe4c789ba9614d0359967bc0468eabfa1658a14ef0633f2485e29141e2c4a13bd328ec9bf6af4c7a774131b",
"private" : "00c1781d86cac2c0af3fb50d54c554a67bd75d25ca796f0486e3fa84f9",
"shared" : "933c385d5fadb57de53e4a5d385118fce830430703c3f585a5d4d0b5",
"result" : "valid",
"flags" : []
},
{
"tcId" : 57,
"comment" : "point with coordinate y = 1 in precomputation or right to left addition chain",
"public" : "0402ca5d1b7638b7b88ad02176bd10ff1cfe8812a62f9769a6d62e0c6c787b3e3b2a063940911bf987fc38deebf542400b8bbd9dfeb7d90a8a",
"private" : "00c1781d86cac2c0af3fb50d54c554a67bd75d25ca796f0486e3fa84f9",
"shared" : "75aea79d99e5c7edaab0284443b548843371d1d9b55f2d73a1a9092f",
"result" : "valid",
"flags" : []
},
{
"tcId" : 58,
"comment" : "point with coordinate y = 1 in precomputation or right to left addition chain",
"public" : "04a394d8bf9b479ec3c7ac3fc6a631d01d57d338b9fb5a0ed6e5130e050cfc600cfb08e67727ac5a33345ec1d48d4a9a18516c2203acbd2667",
"private" : "00c1781d86cac2c0af3fb50d54c554a67bd75d25ca796f0486e3fa84f9",
"shared" : "8c1d0850691cda7523ffccf1cba44b4d472193e6a3bb0727e490a8b5",
"result" : "valid",
"flags" : []
},
{
"tcId" : 59,
"comment" : "point with coordinate y = 1 in precomputation or right to left addition chain",
"public" : "04642e26421e96fa88f956d098ac26f02f1d6faa80e460e701a3789a66c38dd95c6b33de8768c85cbe6879d0d77e29fe5a18b26a35cb60c0b6",
"private" : "00c1781d86cac2c0af3fb50d54c554a67bd75d25ca796f0486e3fa84f9",
"shared" : "50b9ed4d99e2f24e0096eaeded0b552cf8deff5ca8f976964ae47e92",
"result" : "valid",
"flags" : []
},
{
"tcId" : 60,
"comment" : "point with coordinate y = 1 in precomputation or right to left addition chain",
"public" : "04f974d1cbbf4171d4773c3e84eab80bc3c6c2858dadcfbd11d64316905df36fbe345f28a3ef663125649474c6fc1ebe175c3865c4469e192b",
"private" : "00c1781d86cac2c0af3fb50d54c554a67bd75d25ca796f0486e3fa84f9",
"shared" : "5616ee3e63dfb424d329c2b9b50cf378bb77a8bd7e314a241b5942c7",
"result" : "valid",
"flags" : []
},
{
"tcId" : 61,
"comment" : "point with coordinate y = 1 in right to left addition chain",
"public" : "0455561db3cc8fb08a71654ee9573a1a36a44f0913ca8ad7582cfafbfc62b31e5e78be98ad8c8ceab4bb82e8efc0acb29f1a8d031ed044046c",
"private" : "00c1781d86cac2c0af3fb50d54c554a67bd75d25ca796f0486e3fa84f9",
"shared" : "b1da14507b5c05159e15f77d085c017acd89f158011357a97802855d",
"result" : "valid",
"flags" : []
},
{
"tcId" : 62,
"comment" : "point with coordinate y = 1 in right to left addition chain",
"public" : "04a363bcb9bddd5de84a2f4433c039f7be3fce6057b0d3b4a3459e54a2ba32302871e7ba5c3dd7ec9b76946cdc702c15a8d9ec0f4a04e7afb6",
"private" : "00c1781d86cac2c0af3fb50d54c554a67bd75d25ca796f0486e3fa84f9",
"shared" : "2f1bd4a5a497481c4a21222320ff61f32674a95d540cc3f4f3ca5849",
"result" : "valid",
"flags" : []
},
{
"tcId" : 63,
"comment" : "point with coordinate y = 1 in right to left addition chain",
"public" : "043a656d0e25bce27282f256b121fbfcde0a180ccd7aa601a5929fc74002f89e45b4dcb873c56da5d1a28fbca33a126177b217a098e0952e62",
"private" : "00c1781d86cac2c0af3fb50d54c554a67bd75d25ca796f0486e3fa84f9",
"shared" : "8c807d65ba7b9fd3061dffef26c025a89524a26b942edd3a984fe51d",
"result" : "valid",
"flags" : []
},
{
"tcId" : 64,
"comment" : "point with coordinate y = 1 in right to left addition chain",
"public" : "04bf5f49ba0086eec289b068b783438ef24b6f28130bb1ed969ef8b041f11b0de95f15edcd835f01bab1f5faaa1749c2ca4f16a7d99d916ff4",
"private" : "00c1781d86cac2c0af3fb50d54c554a67bd75d25ca796f0486e3fa84f9",
"shared" : "8fda76f4d124e6727f855e5f4921cc05c48e2a8ed0fee7c75d6a8047",
"result" : "valid",
"flags" : []
},
{
"tcId" : 65,
"comment" : "point with coordinate y = 1 in right to left addition chain",
"public" : "04a57232560d9d604655181f775859b0723d4e01a4c867844eb9d81dabb5d19507bbe9cda3346bad7c184daa432e7f794a5b9b8b8d4e55be3a",
"private" : "00c1781d86cac2c0af3fb50d54c554a67bd75d25ca796f0486e3fa84f9",
"shared" : "daf35bb7bf3a056bb62bb01ba00f581c107f64de85842b3a49bc2a4a",
"result" : "valid",
"flags" : []
},
{
"tcId" : 66,
"comment" : "edge case private key",
"public" : "04478e73465bb1183583f4064e67e8b4343af4a05d29dfc04eb60ac2302e5b9a3a1b32e4208d4c284ff26822e09c3a9a4683443e4a35175504",
"private" : "03",
"shared" : "e71f2157bfe37697ea5193d4732dcc6e5412fa9d38387eacd391c1c6",
"result" : "valid",
"flags" : []
},
{
"tcId" : 67,
"comment" : "edge case private key",
"public" : "04478e73465bb1183583f4064e67e8b4343af4a05d29dfc04eb60ac2302e5b9a3a1b32e4208d4c284ff26822e09c3a9a4683443e4a35175504",
"private" : "00ffffffffffffffffffffffffffffffffffffffffffffffff",
"shared" : "fa2664717c7fa0161ec2c669b2c0986cdc20456a6e5406302bb53c77",
"result" : "valid",
"flags" : []
},
{
"tcId" : 68,
"comment" : "edge case private key",
"public" : "04478e73465bb1183583f4064e67e8b4343af4a05d29dfc04eb60ac2302e5b9a3a1b32e4208d4c284ff26822e09c3a9a4683443e4a35175504",
"private" : "01000000000000000000000000000000000000000000000000000000",
"shared" : "af6e5ad34497bae0745f53ad78ce8b285d79f400d5c6e6a071f8e6bd",
"result" : "valid",
"flags" : []
},
{
"tcId" : 69,
"comment" : "edge case private key",
"public" : "04478e73465bb1183583f4064e67e8b4343af4a05d29dfc04eb60ac2302e5b9a3a1b32e4208d4c284ff26822e09c3a9a4683443e4a35175504",
"private" : "7fffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"shared" : "12fd302ff8c13c55a9c111f8bb6b0a13ecf88299c0ae3032ce2bcaff",
"result" : "valid",
"flags" : []
},
{
"tcId" : 70,
"comment" : "edge case private key",
"public" : "04478e73465bb1183583f4064e67e8b4343af4a05d29dfc04eb60ac2302e5b9a3a1b32e4208d4c284ff26822e09c3a9a4683443e4a35175504",
"private" : "0080000000000000000000000000000000000000000000000000000000",
"shared" : "73f1a395b842f1a6752ae417e2c3dc90cafc4476d1d861b7e68ad030",
"result" : "valid",
"flags" : []
},
{
"tcId" : 71,
"comment" : "edge case private key",
"public" : "04478e73465bb1183583f4064e67e8b4343af4a05d29dfc04eb60ac2302e5b9a3a1b32e4208d4c284ff26822e09c3a9a4683443e4a35175504",
"private" : "00ffffffffffffffffffffffffffff16a2e0b8f03d13dd29455c5c2a3d",
"shared" : "b329c20ddb7c78ee4e622bb23a984c0d273ba34b6269f3d9e8f89f8e",
"result" : "valid",
"flags" : []
},
{
"tcId" : 72,
"comment" : "edge case private key",
"public" : "04478e73465bb1183583f4064e67e8b4343af4a05d29dfc04eb60ac2302e5b9a3a1b32e4208d4c284ff26822e09c3a9a4683443e4a35175504",
"private" : "00ffffffffffffffffffffffffffff16a2e0b8f03e13cd29455c5c2a3d",
"shared" : "6f48345209b290ffc5abbe754a201479e5d667a209468080d06197b4",
"result" : "valid",
"flags" : []
},
{
"tcId" : 73,
"comment" : "edge case private key",
"public" : "04478e73465bb1183583f4064e67e8b4343af4a05d29dfc04eb60ac2302e5b9a3a1b32e4208d4c284ff26822e09c3a9a4683443e4a35175504",
"private" : "00ffffffffffffffffffffffffffff16a2e0b8f03e13d529455c5c2a3d",
"shared" : "9f6e30c1c9dad42a153aacd4b49a8e5c721d085cd07b5d5aec244fc1",
"result" : "valid",
"flags" : []
},
{
"tcId" : 74,
"comment" : "edge case private key",
"public" : "04478e73465bb1183583f4064e67e8b4343af4a05d29dfc04eb60ac2302e5b9a3a1b32e4208d4c284ff26822e09c3a9a4683443e4a35175504",
"private" : "00ffffffffffffffffffffffffffff16a2e0b8f03e13dd29445c5c2a3d",
"shared" : "8cadfb19a80949e61bd5b829ad0e76d18a5bb2eeb9ed7fe2b901cecd",
"result" : "valid",
"flags" : []
},
{
"tcId" : 75,
"comment" : "edge case private key",
"public" : "04478e73465bb1183583f4064e67e8b4343af4a05d29dfc04eb60ac2302e5b9a3a1b32e4208d4c284ff26822e09c3a9a4683443e4a35175504",
"private" : "00ffffffffffffffffffffffffffff16a2e0b8f03e13dd29455c5c29b7",
"shared" : "475fd96e0eb8cb8f100a5d7fe043a7a6851d1d611da2643a3c6ae708",
"result" : "valid",
"flags" : [
"AddSubChain"
]
},
{
"tcId" : 76,
"comment" : "edge case private key",
"public" : "04478e73465bb1183583f4064e67e8b4343af4a05d29dfc04eb60ac2302e5b9a3a1b32e4208d4c284ff26822e09c3a9a4683443e4a35175504",
"private" : "00ffffffffffffffffffffffffffff16a2e0b8f03e13dd29455c5c2a37",
"shared" : "41ef931d669d1f57d8bb95a01a92321da74be8c6cbc3bbe0b2e73ebd",
"result" : "valid",
"flags" : [
"AddSubChain"
]
},
{
"tcId" : 77,
"comment" : "edge case private key",
"public" : "04478e73465bb1183583f4064e67e8b4343af4a05d29dfc04eb60ac2302e5b9a3a1b32e4208d4c284ff26822e09c3a9a4683443e4a35175504",
"private" : "00ffffffffffffffffffffffffffff16a2e0b8f03e13dd29455c5c2a3a",
"shared" : "e71f2157bfe37697ea5193d4732dcc6e5412fa9d38387eacd391c1c6",
"result" : "valid",
"flags" : []
},
{
"tcId" : 78,
"comment" : "edge case private key",
"public" : "04478e73465bb1183583f4064e67e8b4343af4a05d29dfc04eb60ac2302e5b9a3a1b32e4208d4c284ff26822e09c3a9a4683443e4a35175504",
"private" : "00ffffffffffffffffffffffffffff16a2e0b8f03e13dd29455c5c2a3b",
"shared" : "11ff15126411299cbd49e2b7542e69e91ef132e2551a16ecfebb23a3",
"result" : "valid",
"flags" : [
"AddSubChain"
]
},
{
"tcId" : 79,
"comment" : "point is not on curve",
"public" : "040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"private" : "00c6cafb74e2a5b5ed4b991cbbfbc28c18f6df208b6d05e7a2e6668014",
"shared" : "",
"result" : "invalid",
"flags" : []
},
{
"tcId" : 80,
"comment" : "point is not on curve",
"public" : "040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001",
"private" : "00c6cafb74e2a5b5ed4b991cbbfbc28c18f6df208b6d05e7a2e6668014",
"shared" : "",
"result" : "invalid",
"flags" : []
},
{
"tcId" : 81,
"comment" : "point is not on curve",
"public" : "0400000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffff000000000000000000000000",
"private" : "00c6cafb74e2a5b5ed4b991cbbfbc28c18f6df208b6d05e7a2e6668014",
"shared" : "",
"result" : "invalid",
"flags" : []
},
{
"tcId" : 82,
"comment" : "point is not on curve",
"public" : "0400000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffff000000000000000000000001",
"private" : "00c6cafb74e2a5b5ed4b991cbbfbc28c18f6df208b6d05e7a2e6668014",
"shared" : "",
"result" : "invalid",
"flags" : []
},
{
"tcId" : 83,
"comment" : "point is not on curve",
"public" : "040000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000",
"private" : "00c6cafb74e2a5b5ed4b991cbbfbc28c18f6df208b6d05e7a2e6668014",
"shared" : "",
"result" : "invalid",
"flags" : []
},
{
"tcId" : 84,
"comment" : "point is not on curve",
"public" : "040000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000001",
"private" : "00c6cafb74e2a5b5ed4b991cbbfbc28c18f6df208b6d05e7a2e6668014",
"shared" : "",
"result" : "invalid",
"flags" : []
},
{
"tcId" : 85,
"comment" : "point is not on curve",
"public" : "0400000000000000000000000000000000000000000000000000000001ffffffffffffffffffffffffffffffff000000000000000000000000",
"private" : "00c6cafb74e2a5b5ed4b991cbbfbc28c18f6df208b6d05e7a2e6668014",
"shared" : "",
"result" : "invalid",
"flags" : []
},
{
"tcId" : 86,
"comment" : "point is not on curve",
"public" : "0400000000000000000000000000000000000000000000000000000001ffffffffffffffffffffffffffffffff000000000000000000000001",
"private" : "00c6cafb74e2a5b5ed4b991cbbfbc28c18f6df208b6d05e7a2e6668014",
"shared" : "",
"result" : "invalid",
"flags" : []
},
{
"tcId" : 87,
"comment" : "point is not on curve",
"public" : "04ffffffffffffffffffffffffffffffff00000000000000000000000000000000000000000000000000000000000000000000000000000000",
"private" : "00c6cafb74e2a5b5ed4b991cbbfbc28c18f6df208b6d05e7a2e6668014",
"shared" : "",
"result" : "invalid",
"flags" : []
},
{
"tcId" : 88,
"comment" : "point is not on curve",
"public" : "04ffffffffffffffffffffffffffffffff00000000000000000000000000000000000000000000000000000000000000000000000000000001",
"private" : "00c6cafb74e2a5b5ed4b991cbbfbc28c18f6df208b6d05e7a2e6668014",
"shared" : "",
"result" : "invalid",
"flags" : []
},
{
"tcId" : 89,
"comment" : "point is not on curve",
"public" : "04ffffffffffffffffffffffffffffffff000000000000000000000000ffffffffffffffffffffffffffffffff000000000000000000000000",
"private" : "00c6cafb74e2a5b5ed4b991cbbfbc28c18f6df208b6d05e7a2e6668014",
"shared" : "",
"result" : "invalid",
"flags" : []
},
{
"tcId" : 90,
"comment" : "point is not on curve",
"public" : "04ffffffffffffffffffffffffffffffff000000000000000000000000ffffffffffffffffffffffffffffffff000000000000000000000001",
"private" : "00c6cafb74e2a5b5ed4b991cbbfbc28c18f6df208b6d05e7a2e6668014",
"shared" : "",
"result" : "invalid",
"flags" : []
},
{
"tcId" : 91,
"comment" : "point is not on curve",
"public" : "04ffffffffffffffffffffffffffffffff00000000000000000000000100000000000000000000000000000000000000000000000000000000",
"private" : "00c6cafb74e2a5b5ed4b991cbbfbc28c18f6df208b6d05e7a2e6668014",
"shared" : "",
"result" : "invalid",
"flags" : []
},
{
"tcId" : 92,
"comment" : "point is not on curve",
"public" : "04ffffffffffffffffffffffffffffffff00000000000000000000000100000000000000000000000000000000000000000000000000000001",
"private" : "00c6cafb74e2a5b5ed4b991cbbfbc28c18f6df208b6d05e7a2e6668014",
"shared" : "",
"result" : "invalid",
"flags" : []
},
{
"tcId" : 93,
"comment" : "point is not on curve",
"public" : "04ffffffffffffffffffffffffffffffff000000000000000000000001ffffffffffffffffffffffffffffffff000000000000000000000000",
"private" : "00c6cafb74e2a5b5ed4b991cbbfbc28c18f6df208b6d05e7a2e6668014",
"shared" : "",
"result" : "invalid",
"flags" : []
},
{
"tcId" : 94,
"comment" : "point is not on curve",
"public" : "04ffffffffffffffffffffffffffffffff000000000000000000000001ffffffffffffffffffffffffffffffff000000000000000000000001",
"private" : "00c6cafb74e2a5b5ed4b991cbbfbc28c18f6df208b6d05e7a2e6668014",
"shared" : "",
"result" : "invalid",
"flags" : []
},
{
"tcId" : 95,
"comment" : "",
"public" : "",
"private" : "00c6cafb74e2a5b5ed4b991cbbfbc28c18f6df208b6d05e7a2e6668014",
"shared" : "",
"result" : "invalid",
"flags" : []
},
{
"tcId" : 96,
"comment" : "invalid public key",
"public" : "020ca753db5ddeca474241f8d2dafc0844343fd0e37eded2f0192d51b2",
"private" : "00fc28a0ca0f8e36b0d4f71421845135a22aef543b9fddf8c775b2d18f",
"shared" : "",
"result" : "invalid",
"flags" : [
"CompressedPoint"
]
}
]
}
]
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -0,0 +1,107 @@
[
{
"curve": "P192",
"q": "FFFFFFFFFFFFFFFFFFFFFFFF99DEF836146BC9B1B4D22831",
"private": "6FAB034934E4C0FC9AE67F5B5659A9D7D1FEFD187EE09FD4",
"Ux": "AC2C77F529F91689FEA0EA5EFEC7F210D8EEA0B9E047ED56",
"Uy": "3BC723E57670BD4887EBC732C523063D0A7C957BC97C1C43",
"cases": [
{
"k": "32B1B6D7D42A05CB449065727A84804FB1A3E34D8F261496",
"message": "sample",
"r": "4B0B8CE98A92866A2820E20AA6B75B56382E0F9BFD5ECB55",
"s": "CCDB006926EA9565CBADC840829D8C384E06DE1F1E381B85"
},
{
"k": "5C4CE89CF56D9E7C77C8585339B006B97B5F0680B4306C6C",
"message": "test",
"r": "3A718BD8B4926C3B52EE6BBE67EF79B18CB6EB62B1AD97AE",
"s": "5662E6848A4A19B1F1AE2F72ACD4B8BBE50F1EAC65D9124F"
}
]
},
{
"curve": "P224",
"q": "FFFFFFFFFFFFFFFFFFFFFFFFFFFF16A2E0B8F03E13DD29455C5C2A3D",
"private": "F220266E1105BFE3083E03EC7A3A654651F45E37167E88600BF257C1",
"Ux": "00CF08DA5AD719E42707FA431292DEA11244D64FC51610D94B130D6C",
"Uy": "EEAB6F3DEBE455E3DBF85416F7030CBD94F34F2D6F232C69F3C1385A",
"cases": [
{
"k": "AD3029E0278F80643DE33917CE6908C70A8FF50A411F06E41DEDFCDC",
"message": "sample",
"r": "61AA3DA010E8E8406C656BC477A7A7189895E7E840CDFE8FF42307BA",
"s": "BC814050DAB5D23770879494F9E0A680DC1AF7161991BDE692B10101"
},
{
"k": "FF86F57924DA248D6E44E8154EB69F0AE2AEBAEE9931D0B5A969F904",
"message": "test",
"r": "AD04DDE87B84747A243A631EA47A1BA6D1FAA059149AD2440DE6FBA6",
"s": "178D49B1AE90E3D8B629BE3DB5683915F4E8C99FDF6E666CF37ADCFD"
}
]
},
{
"curve": "P256",
"q": "FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551",
"private": "C9AFA9D845BA75166B5C215767B1D6934E50C3DB36E89B127B8A622B120F6721",
"Ux": "60FED4BA255A9D31C961EB74C6356D68C049B8923B61FA6CE669622E60F29FB6",
"Uy": "7903FE1008B8BC99A41AE9E95628BC64F2F1B20C2D7E9F5177A3C294D4462299",
"cases": [
{
"k": "A6E3C57DD01ABE90086538398355DD4C3B17AA873382B0F24D6129493D8AAD60",
"message": "sample",
"r": "EFD48B2AACB6A8FD1140DD9CD45E81D69D2C877B56AAF991C34D0EA84EAF3716",
"s": "F7CB1C942D657C41D436C7A1B6E29F65F3E900DBB9AFF4064DC4AB2F843ACDA8"
},
{
"k": "D16B6AE827F17175E040871A1C7EC3500192C4C92677336EC2537ACAEE0008E0",
"message": "test",
"r": "F1ABB023518351CD71D881567B1EA663ED3EFCF6C5132B354F28D3B0B7D38367",
"s": "019F4113742A2B14BD25926B49C649155F267E60D3814B4C0CC84250E46F0083"
}
]
},
{
"curve": "P384",
"q": "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7634D81F4372DDF581A0DB248B0A77AECEC196ACCC52973",
"private": "6B9D3DAD2E1B8C1C05B19875B6659F4DE23C3B667BF297BA9AA47740787137D896D5724E4C70A825F872C9EA60D2EDF5",
"Ux": "EC3A4E415B4E19A4568618029F427FA5DA9A8BC4AE92E02E06AAE5286B300C64DEF8F0EA9055866064A254515480BC13",
"Uy": "8015D9B72D7D57244EA8EF9AC0C621896708A59367F9DFB9F54CA84B3F1C9DB1288B231C3AE0D4FE7344FD2533264720",
"cases": [
{
"k": "94ED910D1A099DAD3254E9242AE85ABDE4BA15168EAF0CA87A555FD56D10FBCA2907E3E83BA95368623B8C4686915CF9",
"message": "sample",
"r": "94EDBB92A5ECB8AAD4736E56C691916B3F88140666CE9FA73D64C4EA95AD133C81A648152E44ACF96E36DD1E80FABE46",
"s": "99EF4AEB15F178CEA1FE40DB2603138F130E740A19624526203B6351D0A3A94FA329C145786E679E7B82C71A38628AC8"
},
{
"k": "015EE46A5BF88773ED9123A5AB0807962D193719503C527B031B4C2D225092ADA71F4A459BC0DA98ADB95837DB8312EA",
"message": "test",
"r": "8203B63D3C853E8D77227FB377BCF7B7B772E97892A80F36AB775D509D7A5FEB0542A7F0812998DA8F1DD3CA3CF023DB",
"s": "DDD0760448D42D8A43AF45AF836FCE4DE8BE06B485E9B61B827C2F13173923E06A739F040649A667BF3B828246BAA5A5"
}
]
},
{
"curve": "P521",
"q": "1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA51868783BF2F966B7FCC0148F709A5D03BB5C9B8899C47AEBB6FB71E91386409",
"private": "0FAD06DAA62BA3B25D2FB40133DA757205DE67F5BB0018FEE8C86E1B68C7E75CAA896EB32F1F47C70855836A6D16FCC1466F6D8FBEC67DB89EC0C08B0E996B83538",
"Ux": "1894550D0785932E00EAA23B694F213F8C3121F86DC97A04E5A7167DB4E5BCD371123D46E45DB6B5D5370A7F20FB633155D38FFA16D2BD761DCAC474B9A2F5023A4",
"Uy": "0493101C962CD4D2FDDF782285E64584139C2F91B47F87FF82354D6630F746A28A0DB25741B5B34A828008B22ACC23F924FAAFBD4D33F81EA66956DFEAA2BFDFCF5",
"cases": [
{
"k": "1DAE2EA071F8110DC26882D4D5EAE0621A3256FC8847FB9022E2B7D28E6F10198B1574FDD03A9053C08A1854A168AA5A57470EC97DD5CE090124EF52A2F7ECBFFD3",
"message": "sample",
"r": "0C328FAFCBD79DD77850370C46325D987CB525569FB63C5D3BC53950E6D4C5F174E25A1EE9017B5D450606ADD152B534931D7D4E8455CC91F9B15BF05EC36E377FA",
"s": "0617CCE7CF5064806C467F678D3B4080D6F1CC50AF26CA209417308281B68AF282623EAA63E5B5C0723D8B8C37FF0777B1A20F8CCB1DCCC43997F1EE0E44DA4A67A"
},
{
"k": "16200813020EC986863BEDFC1B121F605C1215645018AEA1A7B215A564DE9EB1B38A67AA1128B80CE391C4FB71187654AAA3431027BFC7F395766CA988C964DC56D",
"message": "test",
"r": "13E99020ABF5CEE7525D16B69B229652AB6BDF2AFFCAEF38773B4B7D08725F10CDB93482FDCC54EDCEE91ECA4166B2A7C6265EF0CE2BD7051B7CEF945BABD47EE6D",
"s": "1FBD0013C674AA79CB39849527916CE301C66EA7CE8B80682786AD60F98F7E78A19CA69EFF5C57400E3B3A0AD66CE0978214D13BAF4E9AC60752F7B155E2DE4DCE3"
}
]
}
]

@ -0,0 +1,8 @@
import { should } from 'micro-should';
import './basic.test.js';
import './rfc6979.test.js';
import './secp256k1.test.js';
import './starknet/starknet.test.js';
should.run();

@ -0,0 +1,33 @@
import { deepStrictEqual } from 'assert';
import { should } from 'micro-should';
import * as nist from '../lib/nist.js';
import { default as rfc6979 } from './fixtures/rfc6979.json' assert { type: 'json' };
function hexToBigint(hex) {
return BigInt('0x' + hex)
}
should('RFC6979', () => {
for (const v of rfc6979) {
const curve = nist[v.curve];
deepStrictEqual(curve.CURVE.n, hexToBigint(v.q));
const pubKey = curve.getPublicKey(v.private);
const pubPoint = curve.Point.fromHex(pubKey);
deepStrictEqual(pubPoint.x, hexToBigint(v.Ux));
deepStrictEqual(pubPoint.y, hexToBigint(v.Uy));
for (const c of v.cases) {
const h = curve.CURVE.hash(c.message);
const sigObj = curve.sign(h, v.private);
// const sigObj = curve.Signature.fromDER(sig);
deepStrictEqual(sigObj.r, hexToBigint(c.r), 'R');
deepStrictEqual(sigObj.s, hexToBigint(c.s), 'S');
deepStrictEqual(curve.verify(sigObj.toDERRawBytes(), h, pubKey), true, 'verify(1)');
deepStrictEqual(curve.verify(sigObj, h, pubKey), true, 'verify(2)');
}
}
});
// ESM is broken.
import url from 'url';
if (import.meta.url === url.pathToFileURL(process.argv[1]).href) {
should.run();
}

@ -0,0 +1,559 @@
import * as fc from 'fast-check';
import * as nist from '../lib/nist.js';
import { readFileSync } from 'fs';
import { default as ecdsa } from './vectors/ecdsa.json' assert { type: 'json' };
import { default as ecdh } from './vectors/ecdh.json' assert { type: 'json' };
import { default as privates } from './vectors/privates.json' assert { type: 'json' };
import { default as points } from './vectors/points.json' assert { type: 'json' };
import { default as wp } from './vectors/wychenproof.json' assert { type: 'json' };
import { should } from 'micro-should';
import { deepStrictEqual, throws, rejects } from 'assert';
import { hexToBytes, bytesToHex } from '@noble/hashes/utils';
const hex = bytesToHex;
const secp = nist.secp256k1;
const privatesTxt = readFileSync('./test/vectors/privates-2.txt', 'utf-8');
const schCsv = readFileSync('./test/vectors/schnorr.csv', 'utf-8');
const FC_BIGINT = fc.bigInt(1n + 1n, secp.CURVE.n - 1n);
// prettier-ignore
const INVALID_ITEMS = ['deadbeef', Math.pow(2, 53), [1], 'xyzxyzxyxyzxyzxyxyzxyzxyxyzxyzxyxyzxyzxyxyzxyzxyxyzxyzxyxyzxyzxy', secp.CURVE.n + 2n];
const toBEHex = (n) => n.toString(16).padStart(64, '0');
function hexToNumber(hex) {
if (typeof hex !== 'string') {
throw new TypeError('hexToNumber: expected string, got ' + typeof hex);
}
// Big Endian
return BigInt(`0x${hex}`);
}
should('secp256k1.getPublicKey()', () => {
const data = privatesTxt
.split('\n')
.filter((line) => line)
.map((line) => line.split(':'));
for (let [priv, x, y] of data) {
const point = secp.Point.fromPrivateKey(BigInt(priv));
deepStrictEqual(toBEHex(point.x), x);
deepStrictEqual(toBEHex(point.y), y);
const point2 = secp.Point.fromHex(secp.getPublicKey(toBEHex(BigInt(priv))));
deepStrictEqual(toBEHex(point2.x), x);
deepStrictEqual(toBEHex(point2.y), y);
const point3 = secp.Point.fromHex(secp.getPublicKey(hexToBytes(toBEHex(BigInt(priv)))));
deepStrictEqual(toBEHex(point3.x), x);
deepStrictEqual(toBEHex(point3.y), y);
}
});
should('secp256k1.getPublicKey() rejects invalid keys', () => {
// for (const item of INVALID_ITEMS) {
// throws(() => secp.getPublicKey(item));
// }
});
should('secp256k1.precompute', () => {
secp.utils.precompute(4);
const data = privatesTxt
.split('\n')
.filter((line) => line)
.map((line) => line.split(':'));
for (let [priv, x, y] of data) {
const point = secp.Point.fromPrivateKey(BigInt(priv));
deepStrictEqual(toBEHex(point.x), x);
deepStrictEqual(toBEHex(point.y), y);
const point2 = secp.Point.fromHex(secp.getPublicKey(toBEHex(BigInt(priv))));
deepStrictEqual(toBEHex(point2.x), x);
deepStrictEqual(toBEHex(point2.y), y);
const point3 = secp.Point.fromHex(secp.getPublicKey(hexToBytes(toBEHex(BigInt(priv)))));
deepStrictEqual(toBEHex(point3.x), x);
deepStrictEqual(toBEHex(point3.y), y);
}
});
should('secp256k1.Point.isValidPoint()', () => {
for (const vector of points.valid.isPoint) {
const { P, expected } = vector;
if (expected) {
secp.Point.fromHex(P);
} else {
throws(() => secp.Point.fromHex(P));
}
}
});
should('secp256k1.Point.fromPrivateKey()', () => {
for (const vector of points.valid.pointFromScalar) {
const { d, expected } = vector;
let p = secp.Point.fromPrivateKey(d);
deepStrictEqual(p.toHex(true), expected);
}
});
should('secp256k1.Point#toHex(compressed)', () => {
for (const vector of points.valid.pointCompress) {
const { P, compress, expected } = vector;
let p = secp.Point.fromHex(P);
deepStrictEqual(p.toHex(compress), expected);
}
});
should('secp256k1.Point#toHex() roundtrip (failed case)', () => {
const point1 =
secp.Point.fromPrivateKey(
88572218780422190464634044548753414301110513745532121983949500266768436236425n
);
// const hex = point1.toHex(true);
// deepStrictEqual(secp.Point.fromHex(hex).toHex(true), hex);
});
should('secp256k1.Point#toHex() roundtrip', () => {
fc.assert(
fc.property(FC_BIGINT, (x) => {
const point1 = secp.Point.fromPrivateKey(x);
const hex = point1.toHex(true);
deepStrictEqual(secp.Point.fromHex(hex).toHex(true), hex);
})
);
});
should('secp256k1.Point#add(other)', () => {
for (const vector of points.valid.pointAdd) {
const { P, Q, expected } = vector;
let p = secp.Point.fromHex(P);
let q = secp.Point.fromHex(Q);
if (expected) {
deepStrictEqual(p.add(q).toHex(true), expected);
} else {
if (!p.equals(q.negate())) {
throws(() => p.add(q).toHex(true));
}
}
}
});
should('secp256k1.Point#multiply(privateKey)', () => {
for (const vector of points.valid.pointMultiply) {
const { P, d, expected } = vector;
const p = secp.Point.fromHex(P);
if (expected) {
deepStrictEqual(p.multiply(hexToNumber(d)).toHex(true), expected);
} else {
throws(() => {
p.multiply(hexToNumber(d)).toHex(true);
});
}
}
for (const vector of points.invalid.pointMultiply) {
const { P, d } = vector;
if (hexToNumber(d) < secp.CURVE.n) {
throws(() => {
const p = secp.Point.fromHex(P);
p.multiply(hexToNumber(d)).toHex(true);
});
}
}
for (const num of [0n, 0, -1n, -1, 1.1]) {
throws(() => secp.Point.BASE.multiply(num));
}
});
// multiply() should equal multiplyUnsafe()
// should('JacobianPoint#multiplyUnsafe', () => {
// const p0 = new secp.JacobianPoint(
// 55066263022277343669578718895168534326250603453777594175500187360389116729240n,
// 32670510020758816978083085130507043184471273380659243275938904335757337482424n,
// 1n
// );
// const z = 106011723082030650010038151861333186846790370053628296836951575624442507889495n;
// console.log(p0.multiply(z));
// console.log(secp.JacobianPoint.normalizeZ([p0.multiplyUnsafe(z)])[0])
// });
should('secp256k1.Signature.fromCompactHex() roundtrip', () => {
fc.assert(
fc.property(FC_BIGINT, FC_BIGINT, (r, s) => {
const sig = new secp.Signature(r, s);
deepStrictEqual(secp.Signature.fromCompact(sig.toCompactHex()), sig);
})
);
});
should('secp256k1.Signature.fromDERHex() roundtrip', () => {
fc.assert(
fc.property(FC_BIGINT, FC_BIGINT, (r, s) => {
const sig = new secp.Signature(r, s);
deepStrictEqual(secp.Signature.fromDER(sig.toDERHex()), sig);
})
);
});
should('secp256k1.sign()/should create deterministic signatures with RFC 6979', async () => {
for (const vector of ecdsa.valid) {
let usig = await secp.sign(vector.m, vector.d);
let sig = (usig.toCompactHex());
const vsig = vector.signature;
deepStrictEqual(sig.slice(0, 64), vsig.slice(0, 64));
deepStrictEqual(sig.slice(64, 128), vsig.slice(64, 128));
}
});
should(
'secp256k1.sign()/should not create invalid deterministic signatures with RFC 6979',
async () => {
for (const vector of ecdsa.invalid.sign) {
throws(() => {
return secp.sign(vector.m, vector.d);
});
}
}
);
should('secp256k1.sign()/edge cases', () => {
// @ts-ignore
rejects(async () => await secp.sign());
// @ts-ignore
rejects(async () => await secp.sign(''));
});
should('secp256k1.sign()/should create correct DER encoding against libsecp256k1', async () => {
const CASES = [
[
'd1a9dc8ed4e46a6a3e5e594615ca351d7d7ef44df1e4c94c1802f3592183794b',
'304402203de2559fccb00c148574997f660e4d6f40605acc71267ee38101abf15ff467af02200950abdf40628fd13f547792ba2fc544681a485f2fdafb5c3b909a4df7350e6b',
],
[
'5f97983254982546d3976d905c6165033976ee449d300d0e382099fa74deaf82',
'3045022100c046d9ff0bd2845b9aa9dff9f997ecebb31e52349f80fe5a5a869747d31dcb88022011f72be2a6d48fe716b825e4117747b397783df26914a58139c3f4c5cbb0e66c',
],
[
'0d7017a96b97cd9be21cf28aada639827b2814a654a478c81945857196187808',
'3045022100d18990bba7832bb283e3ecf8700b67beb39acc73f4200ed1c331247c46edccc602202e5c8bbfe47ae159512c583b30a3fa86575cddc62527a03de7756517ae4c6c73',
],
];
const privKey = hexToBytes('0101010101010101010101010101010101010101010101010101010101010101');
for (let [msg, exp] of CASES) {
const res = await secp.sign(msg, privKey, { extraEntropy: undefined });
deepStrictEqual((res.toDERHex()), exp);
const rs = secp.Signature.fromDER(res.toDERHex()).toCompactHex();
deepStrictEqual(secp.Signature.fromCompact(rs).toDERHex(), exp);
}
});
should('secp256k1.sign()/sign ecdsa extraData', async () => {
const ent1 = '0000000000000000000000000000000000000000000000000000000000000000';
const ent2 = '0000000000000000000000000000000000000000000000000000000000000001';
const ent3 = '6e723d3fd94ed5d2b6bdd4f123364b0f3ca52af829988a63f8afe91d29db1c33';
const ent4 = 'fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141';
const ent5 = 'ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff';
for (const e of ecdsa.extraEntropy) {
const sign = async (extraEntropy) => {
const s = secp.sign(e.m, e.d, {extraEntropy }).toCompactHex();
return s;
};
deepStrictEqual(await sign(), e.signature);
deepStrictEqual(await sign(ent1), e.extraEntropy0);
deepStrictEqual(await sign(ent2), e.extraEntropy1);
deepStrictEqual(await sign(ent3), e.extraEntropyRand);
deepStrictEqual(await sign(ent4), e.extraEntropyN);
deepStrictEqual(await sign(ent5), e.extraEntropyMax);
}
});
should('secp256k1.verify()/should verify signature', async () => {
const MSG = '01'.repeat(32);
const PRIV_KEY = 0x2n;
const signature = await secp.sign(MSG, PRIV_KEY);
const publicKey = secp.getPublicKey(PRIV_KEY);
deepStrictEqual(publicKey.length, 65);
deepStrictEqual(secp.verify(signature, MSG, publicKey), true);
});
should('secp256k1.verify()/should not verify signature with wrong public key', async () => {
const MSG = '01'.repeat(32);
const PRIV_KEY = 0x2n;
const WRONG_PRIV_KEY = 0x22n;
const signature = await secp.sign(MSG, PRIV_KEY);
const publicKey = secp.Point.fromPrivateKey(WRONG_PRIV_KEY).toHex();
deepStrictEqual(publicKey.length, 130);
deepStrictEqual(secp.verify(signature, MSG, publicKey), false);
});
should('secp256k1.verify()/should not verify signature with wrong hash', async () => {
const MSG = '01'.repeat(32);
const PRIV_KEY = 0x2n;
const WRONG_MSG = '11'.repeat(32);
const signature = await secp.sign(MSG, PRIV_KEY);
const publicKey = secp.getPublicKey(PRIV_KEY);
deepStrictEqual(publicKey.length, 65);
deepStrictEqual(secp.verify(signature, WRONG_MSG, publicKey), false);
});
should('secp256k1.verify()/should verify random signatures', async () =>
fc.assert(
fc.asyncProperty(
FC_BIGINT,
fc.hexaString({ minLength: 64, maxLength: 64 }),
async (privKey, msg) => {
const pub = secp.getPublicKey(privKey);
const sig = await secp.sign(msg, privKey);
deepStrictEqual(secp.verify(sig, msg, pub), true);
}
)
)
);
should('secp256k1.verify()/should not verify signature with invalid r/s', () => {
const msg = new Uint8Array([
0xbb, 0x5a, 0x52, 0xf4, 0x2f, 0x9c, 0x92, 0x61, 0xed, 0x43, 0x61, 0xf5, 0x94, 0x22, 0xa1, 0xe3,
0x00, 0x36, 0xe7, 0xc3, 0x2b, 0x27, 0x0c, 0x88, 0x07, 0xa4, 0x19, 0xfe, 0xca, 0x60, 0x50, 0x23,
]);
const x = 100260381870027870612475458630405506840396644859280795015145920502443964769584n;
const y = 41096923727651821103518389640356553930186852801619204169823347832429067794568n;
const r = 1n;
const s = 115792089237316195423570985008687907852837564279074904382605163141518162728904n;
const pub = new secp.Point(x, y);
const signature = new secp.Signature(2n, 2n);
// @ts-ignore
signature.r = r;
// @ts-ignore
signature.s = s;
const verified = secp.verify(signature, msg, pub);
// Verifies, but it shouldn't, because signature S > curve order
deepStrictEqual(verified, false);
});
should('secp256k1.verify()/should not verify msg = curve order', async () => {
const msg = 'fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141';
const x = 55066263022277343669578718895168534326250603453777594175500187360389116729240n;
const y = 32670510020758816978083085130507043184471273380659243275938904335757337482424n;
const r = 104546003225722045112039007203142344920046999340768276760147352389092131869133n;
const s = 96900796730960181123786672629079577025401317267213807243199432755332205217369n;
const pub = new secp.Point(x, y);
const sig = new secp.Signature(r, s);
deepStrictEqual(secp.verify(sig, msg, pub), false);
});
should('secp256k1.verify()/should verify non-strict msg bb5a...', async () => {
const msg = 'bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023';
const x = 3252872872578928810725465493269682203671229454553002637820453004368632726370n;
const y = 17482644437196207387910659778872952193236850502325156318830589868678978890912n;
const r = 432420386565659656852420866390673177323n;
const s = 115792089237316195423570985008687907852837564279074904382605163141518161494334n;
const pub = new secp.Point(x, y);
const sig = new secp.Signature(r, s);
deepStrictEqual(secp.verify(sig, msg, pub, { strict: false }), true);
});
should(
'secp256k1.verify()/should not verify invalid deterministic signatures with RFC 6979',
() => {
for (const vector of ecdsa.invalid.verify) {
const res = secp.verify(vector.signature, vector.m, vector.Q);
deepStrictEqual(res, false);
}
}
);
// describe('schnorr', () => {
// // index,secret key,public key,aux_rand,message,signature,verification result,comment
// const vectors = schCsv
// .split('\n')
// .map((line: string) => line.split(','))
// .slice(1, -1);
// for (let vec of vectors) {
// const [index, sec, pub, rnd, msg, expSig, passes, comment] = vec;
// it(`should sign with Schnorr scheme vector ${index}`, async () => {
// if (sec) {
// expect(hex(secp.schnorr.getPublicKey(sec))).toBe(pub.toLowerCase());
// const sig = await secp.schnorr.sign(msg, sec, rnd);
// const sigS = secp.schnorr.signSync(msg, sec, rnd);
// expect(hex(sig)).toBe(expSig.toLowerCase());
// expect(hex(sigS)).toBe(expSig.toLowerCase());
// expect(await secp.schnorr.verify(sigS, msg, pub)).toBe(true);
// expect(secp.schnorr.verifySync(sig, msg, pub)).toBe(true);
// } else {
// const passed = await secp.schnorr.verify(expSig, msg, pub);
// const passedS = secp.schnorr.verifySync(expSig, msg, pub);
// if (passes === 'TRUE') {
// expect(passed).toBeTruthy();
// expect(passedS).toBeTruthy();
// } else {
// expect(passed).toBeFalsy();
// expect(passedS).toBeFalsy();
// }
// }
// });
// }
// });
should('secp256k1.recoverPublicKey()/should recover public key from recovery bit', async () => {
const message = '00000000000000000000000000000000000000000000000000000000deadbeef';
const privateKey = 123456789n;
const publicKey = secp.Point.fromHex(secp.getPublicKey(privateKey)).toHex(false);
const sig = await secp.sign(message, privateKey);
const recoveredPubkey = sig.recoverPublicKey(message);
// const recoveredPubkey = secp.recoverPublicKey(message, signature, recovery);
deepStrictEqual(recoveredPubkey !== null, true);
deepStrictEqual((recoveredPubkey).toHex(), publicKey);
deepStrictEqual(secp.verify(sig, message, publicKey), true);
});
should('secp256k1.recoverPublicKey()/should not recover zero points', () => {
const msgHash = '6b8d2c81b11b2d699528dde488dbdf2f94293d0d33c32e347f255fa4a6c1f0a9';
const sig =
'79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f817986b8d2c81b11b2d699528dde488dbdf2f94293d0d33c32e347f255fa4a6c1f0a9';
const recovery = 0;
throws(() => secp.recoverPublicKey(msgHash, sig, recovery));
});
should('secp256k1.recoverPublicKey()/should handle all-zeros msghash', async () => {
const privKey = secp.utils.randomPrivateKey();
const pub = secp.getPublicKey(privKey);
const zeros = '0000000000000000000000000000000000000000000000000000000000000000';
const sig = await secp.sign(zeros, privKey, { recovered: true });
const recoveredKey = sig.recoverPublicKey(zeros);
deepStrictEqual(recoveredKey.toRawBytes(), pub);
});
should('secp256k1.recoverPublicKey()/should handle RFC 6979 vectors', async () => {
for (const vector of ecdsa.valid) {
if (secp.utils.mod(hexToNumber(vector.m), secp.CURVE.n) === 0n) continue;
let usig = secp.sign(vector.m, vector.d);
let sig = (usig).toDERHex();
const vpub = secp.getPublicKey(vector.d);
const recovered = usig.recoverPublicKey(vector.m);
deepStrictEqual((recovered).toHex(), hex(vpub));
}
});
// TODO: Real implementation.
function derToPub(der) {
return der.slice(46);
}
should('secp256k1.getSharedSecret()/should produce correct results', () => {
// TODO: Once der is there, run all tests.
for (const vector of ecdh.testGroups[0].tests.slice(0, 230)) {
if (vector.result === 'invalid' || vector.private.length !== 64) {
// We support eth-like hexes
if (vector.private.length < 64) continue;
throws(() => {
secp.getSharedSecret(vector.private, derToPub(vector.public), true);
});
} else if (vector.result === 'valid') {
const res = secp.getSharedSecret(vector.private, derToPub(vector.public), true);
deepStrictEqual(hex(res.slice(1)), `${vector.shared}`);
}
}
});
should('secp256k1.getSharedSecret()/priv/pub order matters', () => {
for (const vector of ecdh.testGroups[0].tests.slice(0, 100)) {
if (vector.result === 'valid') {
let priv = vector.private;
priv = priv.length === 66 ? priv.slice(2) : priv;
throws(() => secp.getSharedSecret(derToPub(vector.public), priv, true));
}
}
});
should('secp256k1.getSharedSecret()/rejects invalid keys', () => {
throws(() => secp.getSharedSecret('01', '02'));
});
should('secp256k1.utils.isValidPrivateKey()', () => {
for (const vector of privates.valid.isPrivate) {
const { d, expected } = vector;
deepStrictEqual(secp.utils.isValidPrivateKey(d), expected);
}
});
const normal = secp.utils._normalizePrivateKey;
const tweakUtils = {
privateAdd: (privateKey, tweak) => {
const p = normal(privateKey);
const t = normal(tweak);
return secp.utils._bigintToBytes(secp.utils.mod(p + t, secp.CURVE.n));
},
privateNegate: (privateKey) => {
const p = normal(privateKey);
return secp.utils._bigintToBytes(secp.CURVE.n - p);
},
pointAddScalar: (p, tweak, isCompressed) => {
const P = secp.Point.fromHex(p);
const t = normal(tweak);
const Q = secp.Point.BASE.multiplyAndAddUnsafe(P, t, 1n);
if (!Q) throw new Error('Tweaked point at infinity');
return Q.toRawBytes(isCompressed);
},
pointMultiply: (p, tweak, isCompressed) => {
const P = secp.Point.fromHex(p);
const h = typeof tweak === 'string' ? tweak : bytesToHex(tweak);
const t = BigInt(`0x${h}`);
return P.multiply(t).toRawBytes(isCompressed);
},
};
should('secp256k1.privateAdd()', () => {
for (const vector of privates.valid.add) {
const { a, b, expected } = vector;
deepStrictEqual(bytesToHex(tweakUtils.privateAdd(a, b)), expected);
}
});
should('secp256k1.privateNegate()', () => {
for (const vector of privates.valid.negate) {
const { a, expected } = vector;
deepStrictEqual(bytesToHex(tweakUtils.privateNegate(a)), expected);
}
});
should('secp256k1.pointAddScalar()', () => {
for (const vector of points.valid.pointAddScalar) {
const { description, P, d, expected } = vector;
const compressed = !!expected && expected.length === 66; // compressed === 33 bytes
deepStrictEqual(bytesToHex(tweakUtils.pointAddScalar(P, d, compressed)), expected);
}
});
should('secp256k1.pointAddScalar() invalid', () => {
for (const vector of points.invalid.pointAddScalar) {
const { P, d, exception } = vector;
throws(() => tweakUtils.pointAddScalar(P, d));
}
});
should('secp256k1.pointMultiply()', () => {
for (const vector of points.valid.pointMultiply) {
const { P, d, expected } = vector;
deepStrictEqual(bytesToHex(tweakUtils.pointMultiply(P, d, true)), expected);
}
});
should('secp256k1.pointMultiply() invalid', () => {
for (const vector of points.invalid.pointMultiply) {
const { P, d, exception } = vector;
throws(() => tweakUtils.pointMultiply(P, d));
}
});
should('secp256k1.wychenproof vectors', () => {
for (let group of wp.testGroups) {
const pubKey = secp.Point.fromHex(group.key.uncompressed);
for (let test of group.tests) {
const m = secp.CURVE.hash(hexToBytes(test.msg));
if (test.result === 'valid' || test.result === 'acceptable') {
const verified = secp.verify(test.sig, m, pubKey);
if (secp.Signature.fromDER(test.sig).hasHighS()) {
deepStrictEqual(verified, false);
} else {
deepStrictEqual(verified, true);
}
} else if (test.result === 'invalid') {
let failed = false;
try {
const verified = secp.verify(test.sig, m, pubKey);
if (!verified) failed = true;
} catch (error) {
failed = true;
}
deepStrictEqual(failed, true);
} else {
deepStrictEqual(false, true);
}
}
}
});
should.run();

@ -0,0 +1,200 @@
import { deepStrictEqual, throws } from 'assert';
import { should } from 'micro-should';
import * as starknet from '../../lib/starknet.js';
import { default as issue2 } from './fixtures/issue2.json' assert { type: 'json' };
should('Basic elliptic sanity check', () => {
const g1 = starknet.Point.BASE;
deepStrictEqual(
g1.x.toString(16),
'1ef15c18599971b7beced415a40f0c7deacfd9b0d1819e03d723d8bc943cfca'
);
deepStrictEqual(
g1.y.toString(16),
'5668060aa49730b7be4801df46ec62de53ecd11abe43a32873000c36e8dc1f'
);
const g2 = g1.double();
deepStrictEqual(
g2.x.toString(16),
'759ca09377679ecd535a81e83039658bf40959283187c654c5416f439403cf5'
);
deepStrictEqual(
g2.y.toString(16),
'6f524a3400e7708d5c01a28598ad272e7455aa88778b19f93b562d7a9646c41'
);
const g3 = g2.add(g1);
deepStrictEqual(
g3.x.toString(16),
'411494b501a98abd8262b0da1351e17899a0c4ef23dd2f96fec5ba847310b20'
);
deepStrictEqual(
g3.y.toString(16),
'7e1b3ebac08924d2c26f409549191fcf94f3bf6f301ed3553e22dfb802f0686'
);
const g32 = g1.multiply(3);
deepStrictEqual(
g32.x.toString(16),
'411494b501a98abd8262b0da1351e17899a0c4ef23dd2f96fec5ba847310b20'
);
deepStrictEqual(
g32.y.toString(16),
'7e1b3ebac08924d2c26f409549191fcf94f3bf6f301ed3553e22dfb802f0686'
);
const minus1 = g1.multiply(starknet.CURVE.n - 1n);
deepStrictEqual(
minus1.x.toString(16),
'1ef15c18599971b7beced415a40f0c7deacfd9b0d1819e03d723d8bc943cfca'
);
deepStrictEqual(
minus1.y.toString(16),
'7a997f9f55b68e04841b7fe20b9139d21ac132ee541bc5cd78cfff3c91723e2'
);
});
should('Pedersen', () => {
deepStrictEqual(
starknet.pedersen(2, 3),
'0x5774fa77b3d843ae9167abd61cf80365a9b2b02218fc2f628494b5bdc9b33b8'
);
deepStrictEqual(
starknet.pedersen(1, 2),
'0x5bb9440e27889a364bcb678b1f679ecd1347acdedcbf36e83494f857cc58026'
);
deepStrictEqual(
starknet.pedersen(3, 4),
'0x262697b88544f733e5c6907c3e1763131e9f14c51ee7951258abbfb29415fbf'
);
});
should('Hash chain', () => {
deepStrictEqual(
starknet.hashChain([1, 2, 3]),
'0x5d9d62d4040b977c3f8d2389d494e4e89a96a8b45c44b1368f1cc6ec5418915'
);
});
should('Pedersen hash edgecases', () => {
// >>> pedersen_hash(0,0)
const zero = '0x49ee3eba8c1600700ee1b87eb599f16716b0b1022947733551fde4050ca6804';
deepStrictEqual(starknet.pedersen(0, 0), zero);
deepStrictEqual(starknet.pedersen(0n, 0n), zero);
deepStrictEqual(starknet.pedersen('0', '0'), zero);
deepStrictEqual(starknet.pedersen('0x0', '0x0'), zero);
// >>> pedersen_hash(3618502788666131213697322783095070105623107215331596699973092056135872020475,3618502788666131213697322783095070105623107215331596699973092056135872020475)
// 3226051580231087455100099637526672350308978851161639703631919449959447036451
const big = 3618502788666131213697322783095070105623107215331596699973092056135872020475n;
const bigExp = '0x721e167a36655994e88efa865e2ed8a0488d36db4d988fec043cda755728223';
deepStrictEqual(starknet.pedersen(big, big), bigExp);
// >= FIELD
const big2 = 36185027886661312136973227830950701056231072153315966999730920561358720204751n;
throws(() => starknet.pedersen(big2, big2), 'big2');
// FIELD -1
const big3 = 3618502788666131213697322783095070105623107215331596699973092056135872020480n;
const big3exp = '0x7258fccaf3371fad51b117471d9d888a1786c5694c3e6099160477b593a576e';
deepStrictEqual(starknet.pedersen(big3, big3), big3exp, 'big3');
// FIELD
const big4 = 3618502788666131213697322783095070105623107215331596699973092056135872020481n;
throws(() => starknet.pedersen(big4, big4), 'big4');
throws(() => starknet.pedersen(-1, -1), 'neg');
throws(() => starknet.pedersen(false, false), 'false');
throws(() => starknet.pedersen(true, true), 'true');
throws(() => starknet.pedersen(10.1, 10.1), 'float');
});
should('hashChain edgecases', () => {
deepStrictEqual(starknet.hashChain([32312321312321312312312321n]), '0x1aba6672c014b4838cc201');
deepStrictEqual(
starknet.hashChain([1n, 2n]),
'0x5bb9440e27889a364bcb678b1f679ecd1347acdedcbf36e83494f857cc58026'
);
deepStrictEqual(
starknet.hashChain([1, 2]),
'0x5bb9440e27889a364bcb678b1f679ecd1347acdedcbf36e83494f857cc58026'
);
throws(() => starknet.hashChain([]));
throws(() => starknet.hashChain('123'));
deepStrictEqual(
starknet.hashChain([1, 2]),
'0x5bb9440e27889a364bcb678b1f679ecd1347acdedcbf36e83494f857cc58026'
);
});
should('Pedersen hash, issue #2', () => {
// Verified with starnet.js
deepStrictEqual(
starknet.computeHashOnElements(issue2),
'0x22064462ea33a6ce5272a295e0f551c5da3834f80d8444e7a4df68190b1bc42'
);
deepStrictEqual(
starknet.computeHashOnElements([]),
'0x49ee3eba8c1600700ee1b87eb599f16716b0b1022947733551fde4050ca6804'
);
deepStrictEqual(
starknet.computeHashOnElements([1]),
'0x78d74f61aeaa8286418fd34b3a12a610445eba11d00ecc82ecac2542d55f7a4'
);
});
import * as bip32 from '@scure/bip32';
import * as bip39 from '@scure/bip39';
should('Seed derivation (example)', () => {
const layer = 'starkex';
const application = 'starkdeployement';
const mnemonic =
'range mountain blast problem vibrant void vivid doctor cluster enough melody ' +
'salt layer language laptop boat major space monkey unit glimpse pause change vibrant';
const ethAddress = '0xa4864d977b944315389d1765ffa7e66F74ee8cd7';
const hdKey = bip32.HDKey.fromMasterSeed(bip39.mnemonicToSeedSync(mnemonic)).derive(
starknet.getAccountPath(layer, application, ethAddress, 0)
);
deepStrictEqual(
starknet.grindKey(hdKey.privateKey),
'6cf0a8bf113352eb863157a45c5e5567abb34f8d32cddafd2c22aa803f4892c'
);
});
should('Compressed keys', () => {
const G = starknet.Point.BASE;
const half = starknet.CURVE.n / 2n;
const last = starknet.CURVE.n;
const vectors = [
1,
2,
3,
4,
5,
half - 5n,
half - 4n,
half - 3n,
half - 2n,
half - 1n,
half,
half + 1n,
half + 2n,
half + 3n,
half + 4n,
half + 5n,
last - 5n,
last - 4n,
last - 3n,
last - 2n,
last - 1n,
].map((i) => G.multiply(i));
const fixPoint = (pt) => ({ ...pt, _WINDOW_SIZE: undefined });
for (const v of vectors) {
const uncompressed = v.toHex();
const compressed = v.toHex(true);
const exp = fixPoint(v);
deepStrictEqual(fixPoint(starknet.Point.fromHex(uncompressed)), exp);
deepStrictEqual(fixPoint(starknet.Point.fromHex(compressed)), exp);
deepStrictEqual(starknet.Point.fromHex(compressed).toHex(), uncompressed);
}
});
// ESM is broken.
import url from 'url';
if (import.meta.url === url.pathToFileURL(process.argv[1]).href) {
should.run();
}

@ -0,0 +1,57 @@
import * as microStark from '../../../lib/starknet.js';
import * as starkwareCrypto from '@starkware-industries/starkware-crypto-utils';
import * as bench from 'micro-bmark';
const { run, mark } = bench; // or bench.mark
const privateKey = '2dccce1da22003777062ee0870e9881b460a8b7eca276870f57c601f182136c';
const msgHash = 'c465dd6b1bbffdb05442eb17f5ca38ad1aa78a6f56bf4415bdee219114a47';
const keyPair = starkwareCrypto.default.ec.keyFromPrivate(privateKey, 'hex');
const publicKeyStark = starkwareCrypto.default.ec.keyFromPublic(
keyPair.getPublic(true, 'hex'),
'hex'
);
const publicKeyMicro = microStark.getPublicKey(privateKey);
const FNS = {
pedersenHash: {
samples: 250,
starkware: () =>
starkwareCrypto.default.pedersen([
'3d937c035c878245caf64531a5756109c53068da139362728feb561405371cb',
'208a0a10250e382e1e4bbe2880906c2791bf6275695e02fbbc6aeff9cd8b31a',
]),
'micro-starknet': () =>
microStark.pedersen(
'3d937c035c878245caf64531a5756109c53068da139362728feb561405371cb',
'208a0a10250e382e1e4bbe2880906c2791bf6275695e02fbbc6aeff9cd8b31a'
),
},
signVerify: {
samples: 500,
starkware: () =>
starkwareCrypto.default.verify(
publicKeyStark,
msgHash,
starkwareCrypto.default.sign(keyPair, msgHash)
),
'micro-starknet': () =>
microStark.verify(microStark.sign(msgHash, privateKey), msgHash, publicKeyMicro),
},
};
const main = () =>
run(async () => {
for (let [k, libs] of Object.entries(FNS)) {
console.log(`==== ${k} ====`);
for (const [lib, fn] of Object.entries(libs)) {
if (lib === 'samples') continue;
let title = `${k} (${lib})`;
await mark(title, libs.samples, () => fn());
}
console.log();
}
// Log current RAM
bench.logMem();
});
main();

@ -0,0 +1,19 @@
{
"name": "benchmark",
"private": true,
"version": "0.1.0",
"description": "benchmarks",
"main": "index.js",
"type": "module",
"scripts": {
"bench": "node index.js"
},
"keywords": [],
"author": "",
"license": "MIT",
"devDependencies": {
"@starkware-industries/starkware-crypto-utils": "^0.0.2",
"micro-bmark": "0.2.0",
"micro-should": "0.2.0"
}
}

File diff suppressed because it is too large Load Diff

@ -0,0 +1,32 @@
{
"0x1": "0x1ef15c18599971b7beced415a40f0c7deacfd9b0d1819e03d723d8bc943cfca",
"0x2": "0x759ca09377679ecd535a81e83039658bf40959283187c654c5416f439403cf5",
"0x3": "0x411494b501a98abd8262b0da1351e17899a0c4ef23dd2f96fec5ba847310b20",
"0x4": "0xa7da05a4d664859ccd6e567b935cdfbfe3018c7771cb980892ef38878ae9bc",
"0x5": "0x788435d61046d3eec54d77d25bd194525f4fa26ebe6575536bc6f656656b74c",
"0x6": "0x1efc3d7c9649900fcbd03f578a8248d095bc4b6a13b3c25f9886ef971ff96fa",
"0x7": "0x743829e0a179f8afe223fc8112dfc8d024ab6b235fd42283c4f5970259ce7b7",
"0x8": "0x6eeee2b0c71d681692559735e08a2c3ba04e7347c0c18d4d49b83bb89771591",
"0x9": "0x216b4f076ff47e03a05032d1c6ee17933d8de8b2b4c43eb5ad5a7e1b25d3849",
"0x800000000000000000000000000000000000000000000000000000000000000": "0x5c79074e7f7b834c12c81a9bb0d46691a5e7517767a849d9d98cb84e2176ed2",
"0x800000000000000000000000000000000000000000000000000000000000001": "0x1c4f24e3bd16db0e2457bc005a9d61965105a535554c6b338871e34cb8e2d3a",
"0x800000000000000000000000000000000000000000000000000000000000002": "0xdfbb89b39288a9ddacf3942b4481b04d4fa2f8ed3c424757981cc6357f27ac",
"0x800000000000000000000000000000000000000000000000000000000000003": "0x41bef28265fd750b102f4f2d1e0231de7f4a33900a214f191a63d4fec4e72f4",
"0x800000000000000000000000000000000000000000000000000000000000004": "0x24de66eb164797d4b414e81ded0cfa1a592ef0a9363ebbcb440d4d03cb18af1",
"0x800000000000000000000000000000000000000000000000000000000000005": "0x5efb18c3bc9b69003746acc85fb6ee0cfbdc6adfb982f089cc63e1e5495daad",
"0x800000000000000000000000000000000000000000000000000000000000006": "0x10dc71f00918a8ebfe4085c834d41dd22b251b9f81eef8b9a4fab77e7e1afe9",
"0x800000000000000000000000000000000000000000000000000000000000007": "0x4267ebfd379b1c8caae73febc5920b0c95bd6f9f3536f47c5ddad1259c332ff",
"0x800000000000000000000000000000000000000000000000000000000000008": "0x6da515118c8e01fd5b2e96b814ee95bad7d60be4d2ba6b47e0d283f579d9671",
"0x800000000000000000000000000000000000000000000000000000000000009": "0x7a5b4797f4e56ed1473876bc2693fbe3f2fef7e050717cbae924ff23d426052",
"0x2e9c99d8382fa004dcbbee720aef8a97002de0e991f6a8344e6dc636a71b59e": "0x1ff6803ae740e7e596504ac5c6afbea472e53679361e214f12be0155b13e25d",
"0x8620458785138df8722214e073a91b8f55076ea78197cf41007692dd27fd90": "0x5967da40b90d7ca1e36dc4024381d7d4b403c6ac1a0ab358b0743984934a805",
"0x1b920e7dfb49ba5ada673882af5342e7448d3e9335e0ac37feb6280cd7289ce": "0x78c7ab46333968fbde3201cf512c1eeb5529360259072c459a158dee4449b57",
"0x704170dbfd5dc63caef69d2ce6dfc2b2dbb2af6e75851242bbe79fb6e62a118": "0x534bd8d6ebe4bb2f6992e2d7c19ef3146247e10c2849f357e44eddd283b2af6",
"0x4b58bf4228f39550eca59b5c96a0cb606036cc9495eef9a546f24f01b1b7829": "0x1097a8c5a46d94596f1c8e70ca66941f2bb11e3c8d4fd58fdc4589f09965be8",
"0x2e93226c90fb7a2381a24e940a94b98433e3553dcbf745d3f54d62963c75604": "0x369f0e8c8e984f244290267393a004dba435a4df091767ad5063fece7b1884c",
"0x4615f94598cd756ad1a551d7e57fd725916adfd0054eb773ceb482eef87d0b2": "0x1ee5b8d612102a2408cde59ce52a6498d2e38fe8789bb26d400dea310684ec9",
"0x6ade54b7debd7ca1d4e8e932f9545f8fa4024d73be1efcc86df86367fc333f8": "0x37de3bf52412b2fb9b0030d232ca9dd921cd8f71fd67975cdc62546826e121",
"0x618e7467dd24c2a3449c4df640439c12cdd0f8ea779afcee6e252b2cf494354": "0x71c2b578c432f2d305d3808bb645ecc46dd670cb43d4f4a076f75ccbff74fbc",
"0x7eae185e1f41ec76d214d763f0592f194933622a9dd5f3d52d0209f71619c1a": "0x2b0160052e70176e5b0ff2a6eff90896ae07b732fc27219e36e077735abd57e",
"0x178047D3869489C055D7EA54C014FFB834A069C9595186ABE04EA4D1223A03F": "0x1895a6a77ae14e7987b9cb51329a5adfb17bd8e7c638f92d6892d76e51cebcf"
}

@ -0,0 +1,57 @@
{
"private_key": "0x3c1e9550e66958296d11b60f8e8e7a7ad990d07fa65d5f7652c4a6c87d4e3cc",
"messages": [
{
"hash": "0x1",
"r": "3162358736122783857144396205516927012128897537504463716197279730251407200037",
"s": "1447067116407676619871126378936374427636662490882969509559888874644844560850"
},
{
"hash": "0x11",
"r": "2282960348362869237018441985726545922711140064809058182483721438101695251648",
"s": "2905868291002627709651322791912000820756370440695830310841564989426104902684"
},
{
"hash": "0x223",
"r": "2851492577225522862152785068304516872062840835882746625971400995051610132955",
"s": "2227464623243182122770469099770977514100002325017609907274766387592987135410"
},
{
"hash": "0x9999",
"r": "3551214266795401081823453828727326248401688527835302880992409448142527576296",
"s": "2580950807716503852408066180369610390914312729170066679103651110985466032285"
},
{
"hash": "0x387e76d1667c4454bfb835144120583af836f8e32a516765497d23eabe16b3f",
"r": "3518448914047769356425227827389998721396724764083236823647519654917215164512",
"s": "3042321032945513635364267149196358883053166552342928199041742035443537684462"
},
{
"hash": "0x3a7e76d1697c4455bfb835144120283af236f8e32a516765497d23eabe16b2",
"r": "2261926635950780594216378185339927576862772034098248230433352748057295357217",
"s": "2708700003762962638306717009307430364534544393269844487939098184375356178572"
},
{
"hash": "0xfa5f0cd1ebff93c9e6474379a213ba111f9e42f2f1cb361b0327e0737203",
"r": "3016953906936760149710218073693613509330129567629289734816320774638425763370",
"s": "306146275372136078470081798635201810092238376869367156373203048583896337506"
},
{
"hash": "0x4c1e9550e66958296d11b60f8e8e7f7ae99dd0cfa6bd5fa652c1a6c87d4e2cc",
"r": "3562728603055564208884290243634917206833465920158600288670177317979301056463",
"s": "1958799632261808501999574190111106370256896588537275453140683641951899459876"
},
{
"hash": "0x6362b40c218fb4c8a8bd42ca482145e8513b78e00faa0de76a98ba14fc37ae8",
"r": "3485557127492692423490706790022678621438670833185864153640824729109010175518",
"s": "897592218067946175671768586886915961592526001156186496738437723857225288280"
}
]
}

@ -0,0 +1,5 @@
import './basic.test.js';
import './starknet.test.js';
import './property.test.js';

@ -0,0 +1,51 @@
import { deepStrictEqual, throws } from 'assert';
import { should } from 'micro-should';
import * as starknet from '../../lib/starknet.js';
import * as fc from 'fast-check';
const FC_BIGINT = fc.bigInt(1n + 1n, starknet.CURVE.n - 1n);
should('Point#toHex() roundtrip', () => {
fc.assert(
fc.property(FC_BIGINT, (x) => {
const point1 = starknet.Point.fromPrivateKey(x);
const hex = point1.toHex(true);
deepStrictEqual(starknet.Point.fromHex(hex).toHex(true), hex);
})
);
});
should('Signature.fromCompactHex() roundtrip', () => {
fc.assert(
fc.property(FC_BIGINT, FC_BIGINT, (r, s) => {
const sig = new starknet.Signature(r, s);
deepStrictEqual(starknet.Signature.fromCompact(sig.toCompactHex()), sig);
})
);
});
should('Signature.fromDERHex() roundtrip', () => {
fc.assert(
fc.property(FC_BIGINT, FC_BIGINT, (r, s) => {
const sig = new starknet.Signature(r, s);
deepStrictEqual(starknet.Signature.fromDER(sig.toDERHex()), sig);
})
);
});
should('verify()/should verify random signatures', () =>
fc.assert(
fc.asyncProperty(FC_BIGINT, fc.hexaString({ minLength: 64, maxLength: 64 }), (privNum, msg) => {
const privKey = privNum.toString(16).padStart(64, '0');
const pub = starknet.getPublicKey(privKey);
const sig = starknet.sign(msg, privKey);
deepStrictEqual(starknet.verify(sig, msg, pub), true);
})
)
);
// ESM is broken.
import url from 'url';
if (import.meta.url === url.pathToFileURL(process.argv[1]).href) {
should.run();
}

@ -0,0 +1,286 @@
import { deepStrictEqual, throws } from 'assert';
import { should } from 'micro-should';
import { hex, utf8 } from '@scure/base';
import * as bip32 from '@scure/bip32';
import * as bip39 from '@scure/bip39';
import * as starknet from '../../lib/starknet.js';
import { default as sigVec } from './fixtures/rfc6979_signature_test_vector.json' assert { type: 'json' };
import { default as precomputedKeys } from './fixtures/keys_precomputed.json' assert { type: 'json' };
should('Starknet keccak', () => {
const value = starknet.keccak(utf8.decode('hello'));
deepStrictEqual(value, 0x8aff950685c2ed4bc3174f3472287b56d9517b9c948127319a09a7a36deac8n);
deepStrictEqual(value < 2n ** 250n, true);
});
should('RFC6979', () => {
for (const msg of sigVec.messages) {
const { r, s } = starknet.sign(msg.hash, sigVec.private_key);
// const { r, s } = starknet.Signature.fromDER(sig);
deepStrictEqual(r.toString(10), msg.r);
deepStrictEqual(s.toString(10), msg.s);
}
});
should('Signatures', () => {
const vectors = [
{
// Message hash of length 61.
msg: 'c465dd6b1bbffdb05442eb17f5ca38ad1aa78a6f56bf4415bdee219114a47',
r: '5f496f6f210b5810b2711c74c15c05244dad43d18ecbbdbe6ed55584bc3b0a2',
s: '4e8657b153787f741a67c0666bad6426c3741b478c8eaa3155196fc571416f3',
},
{
// Message hash of length 61, with leading zeros.
msg: '00c465dd6b1bbffdb05442eb17f5ca38ad1aa78a6f56bf4415bdee219114a47',
r: '5f496f6f210b5810b2711c74c15c05244dad43d18ecbbdbe6ed55584bc3b0a2',
s: '4e8657b153787f741a67c0666bad6426c3741b478c8eaa3155196fc571416f3',
},
{
// Message hash of length 62.
msg: 'c465dd6b1bbffdb05442eb17f5ca38ad1aa78a6f56bf4415bdee219114a47a',
r: '233b88c4578f0807b4a7480c8076eca5cfefa29980dd8e2af3c46a253490e9c',
s: '28b055e825bc507349edfb944740a35c6f22d377443c34742c04e0d82278cf1',
},
{
// Message hash of length 63.
msg: '7465dd6b1bbffdb05442eb17f5ca38ad1aa78a6f56bf4415bdee219114a47a1',
r: 'b6bee8010f96a723f6de06b5fa06e820418712439c93850dd4e9bde43ddf',
s: '1a3d2bc954ed77e22986f507d68d18115fa543d1901f5b4620db98e2f6efd80',
},
];
const privateKey = '2dccce1da22003777062ee0870e9881b460a8b7eca276870f57c601f182136c';
const publicKey = starknet.getPublicKey(privateKey);
for (const v of vectors) {
const sig = starknet.sign(v.msg, privateKey);
const { r, s } = sig;
// const { r, s } = starknet.Signature.fromDER(sig);
deepStrictEqual(r.toString(16), v.r, 'r equality');
deepStrictEqual(s.toString(16), v.s, 's equality');
deepStrictEqual(starknet.verify(sig, v.msg, publicKey), true, 'verify');
}
});
should('Invalid signatures', () => {
/*
it('should not verify invalid signature inputs lengths', () => {
const ecOrder = starkwareCrypto.ec.n;
const {maxEcdsaVal} = starkwareCrypto;
const maxMsgHash = maxEcdsaVal.sub(oneBn);
const maxR = maxEcdsaVal.sub(oneBn);
const maxS = ecOrder.sub(oneBn).sub(oneBn);
const maxStarkKey = maxEcdsaVal.sub(oneBn);
// Test invalid message length.
expect(() =>
starkwareCrypto.verify(maxStarkKey, maxMsgHash.add(oneBn).toString(16), {
r: maxR,
s: maxS
})
).to.throw('Message not signable, invalid msgHash length.');
// Test invalid r length.
expect(() =>
starkwareCrypto.verify(maxStarkKey, maxMsgHash.toString(16), {
r: maxR.add(oneBn),
s: maxS
})
).to.throw('Message not signable, invalid r length.');
// Test invalid w length.
expect(() =>
starkwareCrypto.verify(maxStarkKey, maxMsgHash.toString(16), {
r: maxR,
s: maxS.add(oneBn)
})
).to.throw('Message not signable, invalid w length.');
// Test invalid s length.
expect(() =>
starkwareCrypto.verify(maxStarkKey, maxMsgHash.toString(16), {
r: maxR,
s: maxS.add(oneBn).add(oneBn)
})
).to.throw('Message not signable, invalid s length.');
});
it('should not verify invalid signatures', () => {
const privKey = generateRandomStarkPrivateKey();
const keyPair = starkwareCrypto.ec.keyFromPrivate(privKey, 'hex');
const keyPairPub = starkwareCrypto.ec.keyFromPublic(
keyPair.getPublic(),
'BN'
);
const msgHash = new BN(randomHexString(61));
const msgSignature = starkwareCrypto.sign(keyPair, msgHash);
// Test invalid public key.
const invalidKeyPairPub = starkwareCrypto.ec.keyFromPublic(
{x: keyPairPub.pub.getX().add(oneBn), y: keyPairPub.pub.getY()},
'BN'
);
expect(
starkwareCrypto.verify(
invalidKeyPairPub,
msgHash.toString(16),
msgSignature
)
).to.be.false;
// Test invalid message.
expect(
starkwareCrypto.verify(
keyPair,
msgHash.add(oneBn).toString(16),
msgSignature
)
).to.be.false;
expect(
starkwareCrypto.verify(
keyPairPub,
msgHash.add(oneBn).toString(16),
msgSignature
)
).to.be.false;
// Test invalid r.
msgSignature.r.iadd(oneBn);
expect(starkwareCrypto.verify(keyPair, msgHash.toString(16), msgSignature))
.to.be.false;
expect(
starkwareCrypto.verify(keyPairPub, msgHash.toString(16), msgSignature)
).to.be.false;
// Test invalid s.
msgSignature.r.isub(oneBn);
msgSignature.s.iadd(oneBn);
expect(starkwareCrypto.verify(keyPair, msgHash.toString(16), msgSignature))
.to.be.false;
expect(
starkwareCrypto.verify(keyPairPub, msgHash.toString(16), msgSignature)
).to.be.false;
});
});
*/
});
should('Pedersen', () => {
deepStrictEqual(
starknet.pedersen(
'0x3d937c035c878245caf64531a5756109c53068da139362728feb561405371cb',
'0x208a0a10250e382e1e4bbe2880906c2791bf6275695e02fbbc6aeff9cd8b31a'
),
'0x30e480bed5fe53fa909cc0f8c4d99b8f9f2c016be4c41e13a4848797979c662'
);
deepStrictEqual(
starknet.pedersen(
'0x58f580910a6ca59b28927c08fe6c43e2e303ca384badc365795fc645d479d45',
'0x78734f65a067be9bdb39de18434d71e79f7b6466a4b66bbd979ab9e7515fe0b'
),
'0x68cc0b76cddd1dd4ed2301ada9b7c872b23875d5ff837b3a87993e0d9996b87'
);
});
should('Hash chain', () => {
deepStrictEqual(starknet.hashChain([1, 2, 3]), starknet.pedersen(1, starknet.pedersen(2, 3)));
});
should('Key grinding', () => {
deepStrictEqual(
starknet.grindKey('86F3E7293141F20A8BAFF320E8EE4ACCB9D4A4BF2B4D295E8CEE784DB46E0519'),
'5c8c8683596c732541a59e03007b2d30dbbbb873556fe65b5fb63c16688f941'
);
// Loops more than once (verified manually)
deepStrictEqual(
starknet.grindKey('94F3E7293141F20A8BAFF320E8EE4ACCB9D4A4BF2B4D295E8CEE784DB46E0595'),
'33880b9aba464c1c01c9f8f5b4fc1134698f9b0a8d18505cab6cdd34d93dc02'
);
});
should('Private to stark key', () => {
deepStrictEqual(
starknet.getStarkKey('0x178047D3869489C055D7EA54C014FFB834A069C9595186ABE04EA4D1223A03F'),
'0x1895a6a77ae14e7987b9cb51329a5adfb17bd8e7c638f92d6892d76e51cebcf'
);
for (const [privKey, expectedPubKey] of Object.entries(precomputedKeys)) {
deepStrictEqual(starknet.getStarkKey(privKey), expectedPubKey);
}
});
should('Private stark key from eth signature', () => {
const ethSignature =
'0x21fbf0696d5e0aa2ef41a2b4ffb623bcaf070461d61cf7251c74161f82fec3a43' +
'70854bc0a34b3ab487c1bc021cd318c734c51ae29374f2beb0e6f2dd49b4bf41c';
deepStrictEqual(
starknet.ethSigToPrivate(ethSignature),
'766f11e90cd7c7b43085b56da35c781f8c067ac0d578eabdceebc4886435bda'
);
});
should('Key derivation', () => {
const layer = 'starkex';
const application = 'starkdeployement';
const mnemonic =
'range mountain blast problem vibrant void vivid doctor cluster enough melody ' +
'salt layer language laptop boat major space monkey unit glimpse pause change vibrant';
const ethAddress = '0xa4864d977b944315389d1765ffa7e66F74ee8cd7';
const VECTORS = [
{
index: 0,
path: "m/2645'/579218131'/891216374'/1961790679'/2135936222'/0",
privateKey: '6cf0a8bf113352eb863157a45c5e5567abb34f8d32cddafd2c22aa803f4892c',
},
{
index: 7,
path: "m/2645'/579218131'/891216374'/1961790679'/2135936222'/7",
privateKey: '341751bdc42841da35ab74d13a1372c1f0250617e8a2ef96034d9f46e6847af',
},
{
index: 598,
path: "m/2645'/579218131'/891216374'/1961790679'/2135936222'/598",
privateKey: '41a4d591a868353d28b7947eb132aa4d00c4a022743689ffd20a3628d6ca28c',
},
];
const hd = bip32.HDKey.fromMasterSeed(bip39.mnemonicToSeedSync(mnemonic));
for (const { index, path, privateKey } of VECTORS) {
const realPath = starknet.getAccountPath(layer, application, ethAddress, index);
deepStrictEqual(realPath, path);
deepStrictEqual(starknet.grindKey(hd.derive(realPath).privateKey), privateKey);
}
});
// Verified against starknet.js
should('Starknet.js cross-tests', () => {
const privateKey = '0x019800ea6a9a73f94aee6a3d2edf018fc770443e90c7ba121e8303ec6b349279';
// NOTE: there is no compressed keys here, getPubKey returns stark-key (which is schnorr-like X coordinate)
// But it is not used in signing/verifying
deepStrictEqual(
starknet.getStarkKey(privateKey),
'0x33f45f07e1bd1a51b45fc24ec8c8c9908db9e42191be9e169bfcac0c0d99745'
);
const msgHash = '0x6d1706bd3d1ba7c517be2a2a335996f63d4738e2f182144d078a1dd9997062e';
const sig = starknet.sign(msgHash, privateKey);
const { r, s } = (sig);
deepStrictEqual(
r.toString(),
'1427981024487605678086498726488552139932400435436186597196374630267616399345'
);
deepStrictEqual(
s.toString(),
'1853664302719670721837677288395394946745467311923401353018029119631574115563'
);
const hashMsg2 = starknet.pedersen(
'0x33f45f07e1bd1a51b45fc24ec8c8c9908db9e42191be9e169bfcac0c0d99745',
'1'
);
deepStrictEqual(hashMsg2, '0x2b0d4d43acce8ff68416f667f92ec7eab2b96f1d2224abd4d9d4d1e7fa4bb00');
const pubKey =
'04033f45f07e1bd1a51b45fc24ec8c8c9908db9e42191be9e169bfcac0c0d997450319d0f53f6ca077c4fa5207819144a2a4165daef6ee47a7c1d06c0dcaa3e456';
const sig2 = new starknet.Signature(
558858382392827003930138586379728730695763862039474863361948210004201119180n,
2440689354481625417078677634625227600823892606910345662891037256374285369343n
);
deepStrictEqual(starknet.verify(sig2.toDERHex(), hashMsg2, pubKey), true);
});
// ESM is broken.
import url from 'url';
if (import.meta.url === url.pathToFileURL(process.argv[1]).href) {
should.run();
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -0,0 +1,45 @@
1:79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798:483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8
2:c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5:1ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a
3:f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9:388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e672
4:e493dbf1c10d80f3581e4904930b1404cc6c13900ee0758474fa94abe8c4cd13:51ed993ea0d455b75642e2098ea51448d967ae33bfbdfe40cfe97bdc47739922
5:2f8bde4d1a07209355b4a7250a5c5128e88b84bddc619ab7cba8d569b240efe4:d8ac222636e5e3d6d4dba9dda6c9c426f788271bab0d6840dca87d3aa6ac62d6
6:fff97bd5755eeea420453a14355235d382f6472f8568a18b2f057a1460297556:ae12777aacfbb620f3be96017f45c560de80f0f6518fe4a03c870c36b075f297
7:5cbdf0646e5db4eaa398f365f2ea7a0e3d419b7e0330e39ce92bddedcac4f9bc:6aebca40ba255960a3178d6d861a54dba813d0b813fde7b5a5082628087264da
8:2f01e5e15cca351daff3843fb70f3c2f0a1bdd05e5af888a67784ef3e10a2a01:5c4da8a741539949293d082a132d13b4c2e213d6ba5b7617b5da2cb76cbde904
9:acd484e2f0c7f65309ad178a9f559abde09796974c57e714c35f110dfc27ccbe:cc338921b0a7d9fd64380971763b61e9add888a4375f8e0f05cc262ac64f9c37
10:a0434d9e47f3c86235477c7b1ae6ae5d3442d49b1943c2b752a68e2a47e247c7:893aba425419bc27a3b6c7e693a24c696f794c2ed877a1593cbee53b037368d7
11:774ae7f858a9411e5ef4246b70c65aac5649980be5c17891bbec17895da008cb:d984a032eb6b5e190243dd56d7b7b365372db1e2dff9d6a8301d74c9c953c61b
12:d01115d548e7561b15c38f004d734633687cf4419620095bc5b0f47070afe85a:a9f34ffdc815e0d7a8b64537e17bd81579238c5dd9a86d526b051b13f4062327
13:f28773c2d975288bc7d1d205c3748651b075fbc6610e58cddeeddf8f19405aa8:0ab0902e8d880a89758212eb65cdaf473a1a06da521fa91f29b5cb52db03ed81
14:499fdf9e895e719cfd64e67f07d38e3226aa7b63678949e6e49b241a60e823e4:cac2f6c4b54e855190f044e4a7b3d464464279c27a3f95bcc65f40d403a13f5b
15:d7924d4f7d43ea965a465ae3095ff41131e5946f3c85f79e44adbcf8e27e080e:581e2872a86c72a683842ec228cc6defea40af2bd896d3a5c504dc9ff6a26b58
16:e60fce93b59e9ec53011aabc21c23e97b2a31369b87a5ae9c44ee89e2a6dec0a:f7e3507399e595929db99f34f57937101296891e44d23f0be1f32cce69616821
17:defdea4cdb677750a420fee807eacf21eb9898ae79b9768766e4faa04a2d4a34:4211ab0694635168e997b0ead2a93daeced1f4a04a95c0f6cfb199f69e56eb77
18:5601570cb47f238d2b0286db4a990fa0f3ba28d1a319f5e7cf55c2a2444da7cc:c136c1dc0cbeb930e9e298043589351d81d8e0bc736ae2a1f5192e5e8b061d58
19:2b4ea0a797a443d293ef5cff444f4979f06acfebd7e86d277475656138385b6c:85e89bc037945d93b343083b5a1c86131a01f60c50269763b570c854e5c09b7a
20:4ce119c96e2fa357200b559b2f7dd5a5f02d5290aff74b03f3e471b273211c97:12ba26dcb10ec1625da61fa10a844c676162948271d96967450288ee9233dc3a
112233445566778899:a90cc3d3f3e146daadfc74ca1372207cb4b725ae708cef713a98edd73d99ef29:5a79d6b289610c68bc3b47f3d72f9788a26a06868b4d8e433e1e2ad76fb7dc76
112233445566778899112233445566778899:e5a2636bcfd412ebf36ec45b19bfb68a1bc5f8632e678132b885f7df99c5e9b3:736c1ce161ae27b405cafd2a7520370153c2c861ac51d6c1d5985d9606b45f39
28948022309329048855892746252171976963209391069768726095651290785379540373584:a6b594b38fb3e77c6edf78161fade2041f4e09fd8497db776e546c41567feb3c:71444009192228730cd8237a490feba2afe3d27d7cc1136bc97e439d13330d55
57896044618658097711785492504343953926418782139537452191302581570759080747168:00000000000000000000003b78ce563f89a0ed9414f5aa28ad0d96d6795f9c63:3f3979bf72ae8202983dc989aec7f2ff2ed91bdd69ce02fc0700ca100e59ddf3
86844066927987146567678238756515930889628173209306178286953872356138621120752:e24ce4beee294aa6350faa67512b99d388693ae4e7f53d19882a6ea169fc1ce1:8b71e83545fc2b5872589f99d948c03108d36797c4de363ebd3ff6a9e1a95b10
115792089237316195423570985008687907852837564279074904382605163141518161494317:4ce119c96e2fa357200b559b2f7dd5a5f02d5290aff74b03f3e471b273211c97:ed45d9234ef13e9da259e05ef57bb3989e9d6b7d8e269698bafd77106dcc1ff5
115792089237316195423570985008687907852837564279074904382605163141518161494318:2b4ea0a797a443d293ef5cff444f4979f06acfebd7e86d277475656138385b6c:7a17643fc86ba26c4cbcf7c4a5e379ece5fe09f3afd9689c4a8f37aa1a3f60b5
115792089237316195423570985008687907852837564279074904382605163141518161494319:5601570cb47f238d2b0286db4a990fa0f3ba28d1a319f5e7cf55c2a2444da7cc:3ec93e23f34146cf161d67fbca76cae27e271f438c951d5e0ae6d1a074f9ded7
115792089237316195423570985008687907852837564279074904382605163141518161494320:defdea4cdb677750a420fee807eacf21eb9898ae79b9768766e4faa04a2d4a34:bdee54f96b9cae9716684f152d56c251312e0b5fb56a3f09304e660861a910b8
115792089237316195423570985008687907852837564279074904382605163141518161494321:e60fce93b59e9ec53011aabc21c23e97b2a31369b87a5ae9c44ee89e2a6dec0a:081caf8c661a6a6d624660cb0a86c8efed6976e1bb2dc0f41e0cd330969e940e
115792089237316195423570985008687907852837564279074904382605163141518161494322:d7924d4f7d43ea965a465ae3095ff41131e5946f3c85f79e44adbcf8e27e080e:a7e1d78d57938d597c7bd13dd733921015bf50d427692c5a3afb235f095d90d7
115792089237316195423570985008687907852837564279074904382605163141518161494323:499fdf9e895e719cfd64e67f07d38e3226aa7b63678949e6e49b241a60e823e4:353d093b4ab17aae6f0fbb1b584c2b9bb9bd863d85c06a4339a0bf2afc5ebcd4
115792089237316195423570985008687907852837564279074904382605163141518161494324:f28773c2d975288bc7d1d205c3748651b075fbc6610e58cddeeddf8f19405aa8:f54f6fd17277f5768a7ded149a3250b8c5e5f925ade056e0d64a34ac24fc0eae
115792089237316195423570985008687907852837564279074904382605163141518161494325:d01115d548e7561b15c38f004d734633687cf4419620095bc5b0f47070afe85a:560cb00237ea1f285749bac81e8427ea86dc73a2265792ad94fae4eb0bf9d908
115792089237316195423570985008687907852837564279074904382605163141518161494326:774ae7f858a9411e5ef4246b70c65aac5649980be5c17891bbec17895da008cb:267b5fcd1494a1e6fdbc22a928484c9ac8d24e1d20062957cfe28b3536ac3614
115792089237316195423570985008687907852837564279074904382605163141518161494327:a0434d9e47f3c86235477c7b1ae6ae5d3442d49b1943c2b752a68e2a47e247c7:76c545bdabe643d85c4938196c5db3969086b3d127885ea6c3411ac3fc8c9358
115792089237316195423570985008687907852837564279074904382605163141518161494328:acd484e2f0c7f65309ad178a9f559abde09796974c57e714c35f110dfc27ccbe:33cc76de4f5826029bc7f68e89c49e165227775bc8a071f0fa33d9d439b05ff8
115792089237316195423570985008687907852837564279074904382605163141518161494329:2f01e5e15cca351daff3843fb70f3c2f0a1bdd05e5af888a67784ef3e10a2a01:a3b25758beac66b6d6c2f7d5ecd2ec4b3d1dec2945a489e84a25d3479342132b
115792089237316195423570985008687907852837564279074904382605163141518161494330:5cbdf0646e5db4eaa398f365f2ea7a0e3d419b7e0330e39ce92bddedcac4f9bc:951435bf45daa69f5ce8729279e5ab2457ec2f47ec02184a5af7d9d6f78d9755
115792089237316195423570985008687907852837564279074904382605163141518161494331:fff97bd5755eeea420453a14355235d382f6472f8568a18b2f057a1460297556:51ed8885530449df0c4169fe80ba3a9f217f0f09ae701b5fc378f3c84f8a0998
115792089237316195423570985008687907852837564279074904382605163141518161494332:2f8bde4d1a07209355b4a7250a5c5128e88b84bddc619ab7cba8d569b240efe4:2753ddd9c91a1c292b24562259363bd90877d8e454f297bf235782c459539959
115792089237316195423570985008687907852837564279074904382605163141518161494333:e493dbf1c10d80f3581e4904930b1404cc6c13900ee0758474fa94abe8c4cd13:ae1266c15f2baa48a9bd1df6715aebb7269851cc404201bf30168422b88c630d
115792089237316195423570985008687907852837564279074904382605163141518161494334:f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9:c77084f09cd217ebf01cc819d5c80ca99aff5666cb3ddce4934602897b4715bd
115792089237316195423570985008687907852837564279074904382605163141518161494335:c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5:e51e970159c23cc65c3a7be6b99315110809cd9acd992f1edc9bce55af301705
115792089237316195423570985008687907852837564279074904382605163141518161494336:79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798:b7c52588d95c3b9aa25b0403f1eef75702e84bb7597aabe663b82f6f04ef2777

File diff suppressed because it is too large Load Diff

@ -0,0 +1,72 @@
[
{
"message": "test data",
"d": "fee0a1f7afebf9d2a5a80c0c98a31c709681cce195cbcd06342b517970c0be1e",
"k0": "fcce1de7a9bcd6b2d3defade6afa1913fb9229e3b7ddf4749b55c4848b2a196e",
"k1": "727fbcb59eb48b1d7d46f95a04991fc512eb9dbf9105628e3aec87428df28fd8",
"k15": "398f0e2c9f79728f7b3d84d447ac3a86d8b2083c8f234a0ffa9c4043d68bd258"
},
{
"message": "Everything should be made as simple as possible, but not simpler.",
"d": "0000000000000000000000000000000000000000000000000000000000000001",
"k0": "ec633bd56a5774a0940cb97e27a9e4e51dc94af737596a0c5cbb3d30332d92a5",
"k1": "df55b6d1b5c48184622b0ead41a0e02bfa5ac3ebdb4c34701454e80aabf36f56",
"k15": "def007a9a3c2f7c769c75da9d47f2af84075af95cadd1407393dc1e26086ef87"
},
{
"message": "Satoshi Nakamoto",
"d": "0000000000000000000000000000000000000000000000000000000000000002",
"k0": "d3edc1b8224e953f6ee05c8bbf7ae228f461030e47caf97cde91430b4607405e",
"k1": "f86d8e43c09a6a83953f0ab6d0af59fb7446b4660119902e9967067596b58374",
"k15": "241d1f57d6cfd2f73b1ada7907b199951f95ef5ad362b13aed84009656e0254a"
},
{
"message": "Diffie Hellman",
"d": "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f",
"k0": "c378a41cb17dce12340788dd3503635f54f894c306d52f6e9bc4b8f18d27afcc",
"k1": "90756c96fef41152ac9abe08819c4e95f16da2af472880192c69a2b7bac29114",
"k15": "7b3f53300ab0ccd0f698f4d67db87c44cf3e9e513d9df61137256652b2e94e7c"
},
{
"message": "Japan",
"d": "8080808080808080808080808080808080808080808080808080808080808080",
"k0": "f471e61b51d2d8db78f3dae19d973616f57cdc54caaa81c269394b8c34edcf59",
"k1": "6819d85b9730acc876fdf59e162bf309e9f63dd35550edf20869d23c2f3e6d17",
"k15": "d8e8bae3ee330a198d1f5e00ad7c5f9ed7c24c357c0a004322abca5d9cd17847"
},
{
"message": "Bitcoin",
"d": "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140",
"k0": "36c848ffb2cbecc5422c33a994955b807665317c1ce2a0f59c689321aaa631cc",
"k1": "4ed8de1ec952a4f5b3bd79d1ff96446bcd45cabb00fc6ca127183e14671bcb85",
"k15": "56b6f47babc1662c011d3b1f93aa51a6e9b5f6512e9f2e16821a238d450a31f8"
},
{
"message": "i2FLPP8WEus5WPjpoHwheXOMSobUJVaZM1JPMQZq",
"d": "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140",
"k0": "6e9b434fcc6bbb081a0463c094356b47d62d7efae7da9c518ed7bac23f4e2ed6",
"k1": "ae5323ae338d6117ce8520a43b92eacd2ea1312ae514d53d8e34010154c593bb",
"k15": "3eaa1b61d1b8ab2f1ca71219c399f2b8b3defa624719f1e96fe3957628c2c4ea"
},
{
"message": "lEE55EJNP7aLrMtjkeJKKux4Yg0E8E1SAJnWTCEh",
"d": "3881e5286abc580bb6139fe8e83d7c8271c6fe5e5c2d640c1f0ed0e1ee37edc9",
"k0": "5b606665a16da29cc1c5411d744ab554640479dd8abd3c04ff23bd6b302e7034",
"k1": "f8b25263152c042807c992eacd2ac2cc5790d1e9957c394f77ea368e3d9923bd",
"k15": "ea624578f7e7964ac1d84adb5b5087dd14f0ee78b49072aa19051cc15dab6f33"
},
{
"message": "2SaVPvhxkAPrayIVKcsoQO5DKA8Uv5X/esZFlf+y",
"d": "7259dff07922de7f9c4c5720d68c9745e230b32508c497dd24cb95ef18856631",
"k0": "3ab6c19ab5d3aea6aa0c6da37516b1d6e28e3985019b3adb388714e8f536686b",
"k1": "19af21b05004b0ce9cdca82458a371a9d2cf0dc35a813108c557b551c08eb52e",
"k15": "117a32665fca1b7137a91c4739ac5719fec0cf2e146f40f8e7c21b45a07ebc6a"
},
{
"message": "00A0OwO2THi7j5Z/jp0FmN6nn7N/DQd6eBnCS+/b",
"d": "0d6ea45d62b334777d6995052965c795a4f8506044b4fd7dc59c15656a28f7aa",
"k0": "79487de0c8799158294d94c0eb92ee4b567e4dc7ca18addc86e49d31ce1d2db6",
"k1": "9561d2401164a48a8f600882753b3105ebdd35e2358f4f808c4f549c91490009",
"k15": "b0d273634129ff4dbdf0df317d4062a1dbc58818f88878ffdb4ec511c77976c0"
}
]

@ -0,0 +1,16 @@
index,secret key,public key,aux_rand,message,signature,verification result,comment
0,0000000000000000000000000000000000000000000000000000000000000003,F9308A019258C31049344F85F89D5229B531C845836F99B08601F113BCE036F9,0000000000000000000000000000000000000000000000000000000000000000,0000000000000000000000000000000000000000000000000000000000000000,E907831F80848D1069A5371B402410364BDF1C5F8307B0084C55F1CE2DCA821525F66A4A85EA8B71E482A74F382D2CE5EBEEE8FDB2172F477DF4900D310536C0,TRUE,
1,B7E151628AED2A6ABF7158809CF4F3C762E7160F38B4DA56A784D9045190CFEF,DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659,0000000000000000000000000000000000000000000000000000000000000001,243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89,6896BD60EEAE296DB48A229FF71DFE071BDE413E6D43F917DC8DCF8C78DE33418906D11AC976ABCCB20B091292BFF4EA897EFCB639EA871CFA95F6DE339E4B0A,TRUE,
2,C90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B14E5C9,DD308AFEC5777E13121FA72B9CC1B7CC0139715309B086C960E18FD969774EB8,C87AA53824B4D7AE2EB035A2B5BBBCCC080E76CDC6D1692C4B0B62D798E6D906,7E2D58D8B3BCDF1ABADEC7829054F90DDA9805AAB56C77333024B9D0A508B75C,5831AAEED7B44BB74E5EAB94BA9D4294C49BCF2A60728D8B4C200F50DD313C1BAB745879A5AD954A72C45A91C3A51D3C7ADEA98D82F8481E0E1E03674A6F3FB7,TRUE,
3,0B432B2677937381AEF05BB02A66ECD012773062CF3FA2549E44F58ED2401710,25D1DFF95105F5253C4022F628A996AD3A0D95FBF21D468A1B33F8C160D8F517,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF,7EB0509757E246F19449885651611CB965ECC1A187DD51B64FDA1EDC9637D5EC97582B9CB13DB3933705B32BA982AF5AF25FD78881EBB32771FC5922EFC66EA3,TRUE,test fails if msg is reduced modulo p or n
4,,D69C3509BB99E412E68B0FE8544E72837DFA30746D8BE2AA65975F29D22DC7B9,,4DF3C3F68FCC83B27E9D42C90431A72499F17875C81A599B566C9889B9696703,00000000000000000000003B78CE563F89A0ED9414F5AA28AD0D96D6795F9C6376AFB1548AF603B3EB45C9F8207DEE1060CB71C04E80F593060B07D28308D7F4,TRUE,
5,,EEFDEA4CDB677750A420FEE807EACF21EB9898AE79B9768766E4FAA04A2D4A34,,243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89,6CFF5C3BA86C69EA4B7376F31A9BCB4F74C1976089B2D9963DA2E5543E17776969E89B4C5564D00349106B8497785DD7D1D713A8AE82B32FA79D5F7FC407D39B,FALSE,public key not on the curve
6,,DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659,,243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89,FFF97BD5755EEEA420453A14355235D382F6472F8568A18B2F057A14602975563CC27944640AC607CD107AE10923D9EF7A73C643E166BE5EBEAFA34B1AC553E2,FALSE,has_even_y(R) is false
7,,DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659,,243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89,1FA62E331EDBC21C394792D2AB1100A7B432B013DF3F6FF4F99FCB33E0E1515F28890B3EDB6E7189B630448B515CE4F8622A954CFE545735AAEA5134FCCDB2BD,FALSE,negated message
8,,DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659,,243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89,6CFF5C3BA86C69EA4B7376F31A9BCB4F74C1976089B2D9963DA2E5543E177769961764B3AA9B2FFCB6EF947B6887A226E8D7C93E00C5ED0C1834FF0D0C2E6DA6,FALSE,negated s value
9,,DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659,,243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89,0000000000000000000000000000000000000000000000000000000000000000123DDA8328AF9C23A94C1FEECFD123BA4FB73476F0D594DCB65C6425BD186051,FALSE,sG - eP is infinite. Test fails in single verification if has_even_y(inf) is defined as true and x(inf) as 0
10,,DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659,,243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89,00000000000000000000000000000000000000000000000000000000000000017615FBAF5AE28864013C099742DEADB4DBA87F11AC6754F93780D5A1837CF197,FALSE,sG - eP is infinite. Test fails in single verification if has_even_y(inf) is defined as true and x(inf) as 1
11,,DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659,,243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89,4A298DACAE57395A15D0795DDBFD1DCB564DA82B0F269BC70A74F8220429BA1D69E89B4C5564D00349106B8497785DD7D1D713A8AE82B32FA79D5F7FC407D39B,FALSE,sig[0:32] is not an X coordinate on the curve
12,,DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659,,243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F69E89B4C5564D00349106B8497785DD7D1D713A8AE82B32FA79D5F7FC407D39B,FALSE,sig[0:32] is equal to field size
13,,DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659,,243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89,6CFF5C3BA86C69EA4B7376F31A9BCB4F74C1976089B2D9963DA2E5543E177769FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141,FALSE,sig[32:64] is equal to curve order
14,,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC30,,243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89,6CFF5C3BA86C69EA4B7376F31A9BCB4F74C1976089B2D9963DA2E5543E17776969E89B4C5564D00349106B8497785DD7D1D713A8AE82B32FA79D5F7FC407D39B,FALSE,public key is not a valid X coordinate because it exceeds the field size
1 index secret key public key aux_rand message signature verification result comment
2 0 0000000000000000000000000000000000000000000000000000000000000003 F9308A019258C31049344F85F89D5229B531C845836F99B08601F113BCE036F9 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 E907831F80848D1069A5371B402410364BDF1C5F8307B0084C55F1CE2DCA821525F66A4A85EA8B71E482A74F382D2CE5EBEEE8FDB2172F477DF4900D310536C0 TRUE
3 1 B7E151628AED2A6ABF7158809CF4F3C762E7160F38B4DA56A784D9045190CFEF DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659 0000000000000000000000000000000000000000000000000000000000000001 243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89 6896BD60EEAE296DB48A229FF71DFE071BDE413E6D43F917DC8DCF8C78DE33418906D11AC976ABCCB20B091292BFF4EA897EFCB639EA871CFA95F6DE339E4B0A TRUE
4 2 C90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B14E5C9 DD308AFEC5777E13121FA72B9CC1B7CC0139715309B086C960E18FD969774EB8 C87AA53824B4D7AE2EB035A2B5BBBCCC080E76CDC6D1692C4B0B62D798E6D906 7E2D58D8B3BCDF1ABADEC7829054F90DDA9805AAB56C77333024B9D0A508B75C 5831AAEED7B44BB74E5EAB94BA9D4294C49BCF2A60728D8B4C200F50DD313C1BAB745879A5AD954A72C45A91C3A51D3C7ADEA98D82F8481E0E1E03674A6F3FB7 TRUE
5 3 0B432B2677937381AEF05BB02A66ECD012773062CF3FA2549E44F58ED2401710 25D1DFF95105F5253C4022F628A996AD3A0D95FBF21D468A1B33F8C160D8F517 FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF 7EB0509757E246F19449885651611CB965ECC1A187DD51B64FDA1EDC9637D5EC97582B9CB13DB3933705B32BA982AF5AF25FD78881EBB32771FC5922EFC66EA3 TRUE test fails if msg is reduced modulo p or n
6 4 D69C3509BB99E412E68B0FE8544E72837DFA30746D8BE2AA65975F29D22DC7B9 4DF3C3F68FCC83B27E9D42C90431A72499F17875C81A599B566C9889B9696703 00000000000000000000003B78CE563F89A0ED9414F5AA28AD0D96D6795F9C6376AFB1548AF603B3EB45C9F8207DEE1060CB71C04E80F593060B07D28308D7F4 TRUE
7 5 EEFDEA4CDB677750A420FEE807EACF21EB9898AE79B9768766E4FAA04A2D4A34 243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89 6CFF5C3BA86C69EA4B7376F31A9BCB4F74C1976089B2D9963DA2E5543E17776969E89B4C5564D00349106B8497785DD7D1D713A8AE82B32FA79D5F7FC407D39B FALSE public key not on the curve
8 6 DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659 243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89 FFF97BD5755EEEA420453A14355235D382F6472F8568A18B2F057A14602975563CC27944640AC607CD107AE10923D9EF7A73C643E166BE5EBEAFA34B1AC553E2 FALSE has_even_y(R) is false
9 7 DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659 243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89 1FA62E331EDBC21C394792D2AB1100A7B432B013DF3F6FF4F99FCB33E0E1515F28890B3EDB6E7189B630448B515CE4F8622A954CFE545735AAEA5134FCCDB2BD FALSE negated message
10 8 DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659 243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89 6CFF5C3BA86C69EA4B7376F31A9BCB4F74C1976089B2D9963DA2E5543E177769961764B3AA9B2FFCB6EF947B6887A226E8D7C93E00C5ED0C1834FF0D0C2E6DA6 FALSE negated s value
11 9 DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659 243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89 0000000000000000000000000000000000000000000000000000000000000000123DDA8328AF9C23A94C1FEECFD123BA4FB73476F0D594DCB65C6425BD186051 FALSE sG - eP is infinite. Test fails in single verification if has_even_y(inf) is defined as true and x(inf) as 0
12 10 DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659 243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89 00000000000000000000000000000000000000000000000000000000000000017615FBAF5AE28864013C099742DEADB4DBA87F11AC6754F93780D5A1837CF197 FALSE sG - eP is infinite. Test fails in single verification if has_even_y(inf) is defined as true and x(inf) as 1
13 11 DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659 243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89 4A298DACAE57395A15D0795DDBFD1DCB564DA82B0F269BC70A74F8220429BA1D69E89B4C5564D00349106B8497785DD7D1D713A8AE82B32FA79D5F7FC407D39B FALSE sig[0:32] is not an X coordinate on the curve
14 12 DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659 243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89 FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F69E89B4C5564D00349106B8497785DD7D1D713A8AE82B32FA79D5F7FC407D39B FALSE sig[0:32] is equal to field size
15 13 DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659 243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89 6CFF5C3BA86C69EA4B7376F31A9BCB4F74C1976089B2D9963DA2E5543E177769FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 FALSE sig[32:64] is equal to curve order
16 14 FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC30 243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89 6CFF5C3BA86C69EA4B7376F31A9BCB4F74C1976089B2D9963DA2E5543E17776969E89B4C5564D00349106B8497785DD7D1D713A8AE82B32FA79D5F7FC407D39B FALSE public key is not a valid X coordinate because it exceeds the field size

File diff suppressed because it is too large Load Diff

@ -0,0 +1,25 @@
{
"compilerOptions": {
"strict": true,
"declaration": true,
"declarationMap": true,
"target": "es2020",
"lib": [
"es2020",
"dom"
],
"module": "es6",
"moduleResolution": "node16",
"outDir": "lib",
"noImplicitAny": true,
"preserveConstEnums": true,
"baseUrl": ".",
},
"include": [
"src",
],
"exclude": [
"node_modules",
"lib"
]
}

1
index.js Normal file

@ -0,0 +1 @@
throw new Error('Incorrect usage. Import submodules instead');

7
lib/esm/package.json Normal file

@ -0,0 +1,7 @@
{
"type": "module",
"browser": {
"crypto": false,
"./crypto": "./esm/cryptoBrowser.js"
}
}

75
package.json Normal file

@ -0,0 +1,75 @@
{
"name": "@noble/curves",
"version": "0.1.0",
"description": "Minimal, zero-dependency JS implementation of elliptic curve cryptography",
"files": [
"index.js",
"lib",
"lib/esm"
],
"scripts": {
"bench": "node test/benchmark/index.js",
"build": "tsc && tsc -p tsconfig.esm.json",
"build:release": "rollup -c rollup.config.js",
"lint": "prettier --check 'src/**/*.{js,ts}' 'curve-definitions/src/**/*.{js,ts}'",
"format": "prettier --write 'src/**/*.{js,ts}' 'curve-definitions/src/**/*.{js,ts}'",
"test": "cd curve-definitions; node test/index.test.js"
},
"author": "Paul Miller (https://paulmillr.com)",
"homepage": "https://paulmillr.com/noble/",
"repository": {
"type": "git",
"url": "https://github.com/paulmillr/noble-curves.git"
},
"license": "MIT",
"devDependencies": {
"@rollup/plugin-node-resolve": "13.3.0",
"micro-bmark": "0.2.0",
"micro-should": "0.2.0",
"prettier": "2.6.2",
"rollup": "2.75.5",
"typescript": "4.7.3"
},
"main": "index.js",
"exports": {
"./modular": {
"types": "./lib/modular.d.ts",
"import": "./lib/esm/modular.js",
"default": "./lib/modular.js"
},
"./shortw": {
"types": "./lib/shortw.d.ts",
"import": "./lib/esm/shortw.js",
"default": "./lib/shortw.js"
},
"./utils": {
"types": "./lib/utils.d.ts",
"import": "./lib/esm/utils.js",
"default": "./lib/utils.js"
}
},
"keywords": [
"elliptic",
"curve",
"cryptography",
"hyperelliptic",
"p256",
"p384",
"p521",
"nist",
"weierstrass",
"edwards",
"montgomery",
"hashes",
"ecc",
"ecdsa",
"eddsa",
"schnorr"
],
"funding": [
{
"type": "individual",
"url": "https://paulmillr.com/funding/"
}
]
}

146
src/modular.ts Normal file

@ -0,0 +1,146 @@
/*! @noble/curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
const _0n = BigInt(0);
const _1n = BigInt(1);
const _2n = BigInt(2);
const _3n = BigInt(3);
const _4n = BigInt(4);
const _5n = BigInt(5);
const _8n = BigInt(8);
// Calculates a modulo b
export function mod(a: bigint, b: bigint): bigint {
const result = a % b;
return result >= _0n ? result : b + result;
}
/**
* Efficiently exponentiate num to power and do modular division.
* @example
* powMod(2n, 6n, 11n) // 64n % 11n == 9n
*/
export function pow(num: bigint, power: bigint, modulo: bigint): bigint {
if (modulo <= _0n || power < _0n) throw new Error('Expected power/modulo > 0');
if (modulo === _1n) return _0n;
let res = _1n;
while (power > _0n) {
if (power & _1n) res = (res * num) % modulo;
num = (num * num) % modulo;
power >>= _1n;
}
return res;
}
// Does x ^ (2 ^ power) mod p. pow2(30, 4) == 30 ^ (2 ^ 4)
export function pow2(x: bigint, power: bigint, modulo: bigint): bigint {
let res = x;
while (power-- > _0n) {
res *= res;
res %= modulo;
}
return res;
}
// Inverses number over modulo
export function invert(number: bigint, modulo: bigint): bigint {
if (number === _0n || modulo <= _0n) {
throw new Error(`invert: expected positive integers, got n=${number} mod=${modulo}`);
}
// Eucledian GCD https://brilliant.org/wiki/extended-euclidean-algorithm/
let a = mod(number, modulo);
let b = modulo;
// prettier-ignore
let x = _0n, y = _1n, u = _1n, v = _0n;
while (a !== _0n) {
const q = b / a;
const r = b % a;
const m = x - u * q;
const n = y - v * q;
// prettier-ignore
b = a, a = r, x = u, y = v, u = m, v = n;
}
const gcd = b;
if (gcd !== _1n) throw new Error('invert: does not exist');
return mod(x, modulo);
}
/**
* Takes a list of numbers, efficiently inverts all of them.
* @param nums list of bigints
* @param p modulo
* @returns list of inverted bigints
* @example
* invertBatch([1n, 2n, 4n], 21n);
* // => [1n, 11n, 16n]
*/
export function invertBatch(nums: bigint[], modulo: bigint): bigint[] {
const scratch = new Array(nums.length);
// Walk from first to last, multiply them by each other MOD p
const lastMultiplied = nums.reduce((acc, num, i) => {
if (num === _0n) return acc;
scratch[i] = acc;
return mod(acc * num, modulo);
}, _1n);
// Invert last element
const inverted = invert(lastMultiplied, modulo);
// Walk from last to first, multiply them by inverted each other MOD p
nums.reduceRight((acc, num, i) => {
if (num === _0n) return acc;
scratch[i] = mod(acc * scratch[i], modulo);
return mod(acc * num, modulo);
}, inverted);
return scratch;
}
// Calculates Legendre symbol: num^((P-1)/2)
export function legendre(num: bigint, fieldPrime: bigint): bigint {
return pow(num, (fieldPrime - _1n) / _2n, fieldPrime);
}
/**
* Calculates square root of a number in a finite field.
* Used to calculate y - the square root of y².
*/
export function sqrt(number: bigint, modulo: bigint): bigint {
const n = number;
const P = modulo;
const p1div4 = (P + _1n) / _4n;
// P = 3 (mod 4)
// sqrt n = n^((P+1)/4)
if (P % _4n === _3n) return pow(n, p1div4, P);
// P = 5 (mod 8)
if (P % _8n === _5n) {
const n2 = mod(n * _2n, P);
const v = pow(n2, (P - _5n) / _8n, P);
const nv = mod(n * v, P);
const i = mod(_2n * nv * v, P);
const r = mod(nv * (i - _1n), P);
return r;
}
// Other cases: Tonelli-Shanks algorithm
if (legendre(n, P) !== _1n) throw new Error('Cannot find square root');
let q: bigint, s: number, z: bigint;
for (q = P - _1n, s = 0; q % _2n === _0n; q /= _2n, s++);
if (s === 1) return pow(n, p1div4, P);
for (z = _2n; z < P && legendre(z, P) !== P - _1n; z++);
let c = pow(z, q, P);
let r = pow(n, (q + _1n) / _2n, P);
let t = pow(n, q, P);
let t2 = _0n;
while (mod(t - _1n, P) !== _0n) {
t2 = mod(t * t, P);
let i;
for (i = 1; i < s; i++) {
if (mod(t2 - _1n, P) === _0n) break;
t2 = mod(t2 * t2, P);
}
let b = pow(c, BigInt(1 << (s - i - 1)), P);
r = mod(r * b, P);
c = mod(b * b, P);
t = mod(t * c, P);
s = i;
}
return r;
}

1262
src/shortw.ts Normal file

File diff suppressed because it is too large Load Diff

69
src/utils.ts Normal file

@ -0,0 +1,69 @@
/*! @noble/curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
// Convert between types
// ---------------------
const hexes = Array.from({ length: 256 }, (v, i) => i.toString(16).padStart(2, '0'));
export function bytesToHex(uint8a: Uint8Array): string {
if (!(uint8a instanceof Uint8Array)) throw new Error('Expected Uint8Array');
// pre-caching improves the speed 6x
let hex = '';
for (let i = 0; i < uint8a.length; i++) {
hex += hexes[uint8a[i]];
}
return hex;
}
export function numberToHexUnpadded(num: number | bigint): string {
const hex = num.toString(16);
return hex.length & 1 ? `0${hex}` : hex;
}
export function hexToNumber(hex: string): bigint {
if (typeof hex !== 'string') {
throw new TypeError('hexToNumber: expected string, got ' + typeof hex);
}
// Big Endian
return BigInt(`0x${hex}`);
}
// Caching slows it down 2-3x
export function hexToBytes(hex: string): Uint8Array {
if (typeof hex !== 'string') {
throw new TypeError('hexToBytes: expected string, got ' + typeof hex);
}
if (hex.length % 2) throw new Error('hexToBytes: received invalid unpadded hex ' + hex.length);
const array = new Uint8Array(hex.length / 2);
for (let i = 0; i < array.length; i++) {
const j = i * 2;
const hexByte = hex.slice(j, j + 2);
const byte = Number.parseInt(hexByte, 16);
if (Number.isNaN(byte) || byte < 0) throw new Error('Invalid byte sequence');
array[i] = byte;
}
return array;
}
// Big Endian
export function bytesToNumber(bytes: Uint8Array): bigint {
return hexToNumber(bytesToHex(bytes));
}
export function ensureBytes(hex: string | Uint8Array): Uint8Array {
// Uint8Array.from() instead of hash.slice() because node.js Buffer
// is instance of Uint8Array, and its slice() creates **mutable** copy
return hex instanceof Uint8Array ? Uint8Array.from(hex) : hexToBytes(hex);
}
// Copies several Uint8Arrays into one.
export function concatBytes(...arrays: Uint8Array[]): Uint8Array {
if (!arrays.every((b) => b instanceof Uint8Array)) throw new Error('Uint8Array list expected');
if (arrays.length === 1) return arrays[0];
const length = arrays.reduce((a, arr) => a + arr.length, 0);
const result = new Uint8Array(length);
for (let i = 0, pad = 0; i < arrays.length; i++) {
const arr = arrays[i];
result.set(arr, pad);
pad += arr.length;
}
return result;
}

19
tsconfig.esm.json Normal file

@ -0,0 +1,19 @@
{
"compilerOptions": {
"strict": true,
"outDir": "lib/esm",
"target": "es2020",
"module": "es6",
"moduleResolution": "node16",
"noUnusedLocals": true,
"baseUrl": ".",
"paths": {
"@noble/hashes/crypto": [ "src/crypto" ]
},
},
"include": ["src"],
"exclude": [
"node_modules",
"lib",
],
}

18
tsconfig.json Normal file

@ -0,0 +1,18 @@
{
"compilerOptions": {
"strict": true,
"declaration": true,
"outDir": "lib",
"target": "es2020",
"lib": ["es2020"], // Set explicitly to remove DOM
"module": "commonjs",
"moduleResolution": "node",
"noUnusedLocals": true,
"baseUrl": ".",
},
"include": ["src"],
"exclude": [
"node_modules",
"*.d.ts"
],
}