Compare commits
No commits in common. "main" and "0.2.0" have entirely different histories.
1
.github/funding.yml
vendored
1
.github/funding.yml
vendored
@ -1 +1,2 @@
|
||||
github: paulmillr
|
||||
# custom: https://paulmillr.com/funding/
|
||||
33
.github/workflows/nodejs.yml
vendored
33
.github/workflows/nodejs.yml
vendored
@ -1,23 +1,18 @@
|
||||
name: Run node.js tests
|
||||
on:
|
||||
- push
|
||||
- pull_request
|
||||
name: Node CI
|
||||
|
||||
on: [push, pull_request]
|
||||
jobs:
|
||||
test:
|
||||
name: v${{ matrix.node }} @ ubuntu-latest
|
||||
name: v18 @ ubuntu-latest
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
node:
|
||||
- 18
|
||||
- 20
|
||||
steps:
|
||||
- uses: actions/checkout@1e31de5234b9f8995739874a8ce0492dc87873e2 # v4
|
||||
- name: Use Node.js ${{ matrix.node }}
|
||||
uses: actions/setup-node@8f152de45cc393bb48ce5d89d36b731f54556e65 # v4
|
||||
with:
|
||||
node-version: ${{ matrix.node }}
|
||||
- run: npm install
|
||||
- run: npm run build --if-present
|
||||
- run: npm test
|
||||
- run: npm run lint --if-present
|
||||
- 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
|
||||
|
||||
23
.github/workflows/publish-npm.yml
vendored
23
.github/workflows/publish-npm.yml
vendored
@ -1,23 +0,0 @@
|
||||
name: Publish package to npm
|
||||
on:
|
||||
release:
|
||||
types: [created]
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
id-token: write
|
||||
steps:
|
||||
- uses: actions/checkout@1e31de5234b9f8995739874a8ce0492dc87873e2 # v4
|
||||
- uses: actions/setup-node@8f152de45cc393bb48ce5d89d36b731f54556e65 # v4
|
||||
with:
|
||||
node-version: 20
|
||||
registry-url: 'https://registry.npmjs.org'
|
||||
cache: npm
|
||||
- run: npm install -g npm
|
||||
- run: npm ci
|
||||
- run: npm run build
|
||||
- run: npm publish --provenance --access public
|
||||
env:
|
||||
NODE_AUTH_TOKEN: ${{ secrets.NPM_PUBLISH_TOKEN }}
|
||||
28
.github/workflows/upload-release.yml
vendored
28
.github/workflows/upload-release.yml
vendored
@ -1,28 +0,0 @@
|
||||
name: Upload standalone file to GitHub Releases
|
||||
on:
|
||||
release:
|
||||
types: [created]
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
id-token: write
|
||||
steps:
|
||||
- uses: actions/checkout@1e31de5234b9f8995739874a8ce0492dc87873e2 # v4
|
||||
- uses: actions/setup-node@8f152de45cc393bb48ce5d89d36b731f54556e65 # v4
|
||||
with:
|
||||
node-version: 20
|
||||
registry-url: 'https://registry.npmjs.org'
|
||||
cache: npm
|
||||
- run: npm install -g npm
|
||||
- run: npm ci
|
||||
- run: npm run build
|
||||
- run: |
|
||||
cd build
|
||||
npm ci
|
||||
npm run build:release
|
||||
cd ..
|
||||
- run: gh release upload ${{ github.event.release.tag_name }} build/`npx jsbt outfile`
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
16
.gitignore
vendored
16
.gitignore
vendored
@ -1,9 +1,7 @@
|
||||
node_modules
|
||||
/*.js
|
||||
/esm/*.js
|
||||
*.d.ts
|
||||
*.d.ts.map
|
||||
*.js.map
|
||||
/build
|
||||
/abstract
|
||||
/esm/abstract
|
||||
build/
|
||||
node_modules/
|
||||
coverage/
|
||||
/lib/**/*.js
|
||||
/lib/**/*.ts
|
||||
/lib/**/*.d.ts.map
|
||||
/curve-definitions/lib
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
{
|
||||
"printWidth": 100,
|
||||
"singleQuote": true,
|
||||
"trailingComma": "es5"
|
||||
"singleQuote": true
|
||||
}
|
||||
|
||||
6
.vscode/settings.json
vendored
6
.vscode/settings.json
vendored
@ -1,6 +0,0 @@
|
||||
{
|
||||
"files.exclude": {
|
||||
"*.{js,d.ts,js.map,d.ts.map}": true,
|
||||
"esm/*.{js,d.ts,js.map,d.ts.map}": true
|
||||
}
|
||||
}
|
||||
20
SECURITY.md
20
SECURITY.md
@ -1,20 +0,0 @@
|
||||
# Security Policy
|
||||
|
||||
See [README's Security section](./README.md#security) for detailed description of internal security practices.
|
||||
|
||||
## Supported Versions
|
||||
|
||||
| Version | Supported |
|
||||
| ------- | ------------------ |
|
||||
| >=1.0.0 | :white_check_mark: |
|
||||
| <1.0.0 | :x: |
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
Use maintainer's email specified at https://github.com/paulmillr.
|
||||
|
||||
It's preferred that you use
|
||||
PGP key from [pgp proof](https://paulmillr.com/pgp_proof.txt) (current is [697079DA6878B89B](https://paulmillr.com/pgp_proof.txt)).
|
||||
Ensure the pgp proof page has maintainer's site/github specified.
|
||||
|
||||
You will get an update as soon as the email is read; a "Security vulnerability" phrase in email's title would help.
|
||||
Binary file not shown.
Binary file not shown.
@ -1,7 +0,0 @@
|
||||
# Audit
|
||||
|
||||
All audits of the library are described in [README's Security section](../README.md#security)
|
||||
|
||||
`2023-01-trailofbits-audit-curves.pdf` file in the directory was saved from
|
||||
[github.com/trailofbits/publications](https://github.com/trailofbits/publications).
|
||||
Check out their repo and verify checksums to ensure the PDF in this directory has not been altered.
|
||||
@ -1,7 +0,0 @@
|
||||
export function generateData(curve) {
|
||||
const priv = curve.utils.randomPrivateKey();
|
||||
const pub = curve.getPublicKey(priv);
|
||||
const msg = curve.utils.randomPrivateKey();
|
||||
const sig = curve.sign(msg, priv);
|
||||
return { priv, pub, msg, sig };
|
||||
}
|
||||
@ -1,67 +0,0 @@
|
||||
import { readFileSync } from 'fs';
|
||||
import { mark, run } from 'micro-bmark';
|
||||
import { bls12_381 as bls } from '../bls12-381.js';
|
||||
|
||||
const G2_VECTORS = readFileSync('../test/bls12-381/bls12-381-g2-test-vectors.txt', 'utf-8')
|
||||
.trim()
|
||||
.split('\n')
|
||||
.map((l) => l.split(':'));
|
||||
|
||||
run(async () => {
|
||||
console.log(`\x1b[36mbls12-381\x1b[0m`);
|
||||
let p1, p2, sig;
|
||||
await mark('init', 1, () => {
|
||||
p1 =
|
||||
bls.G1.ProjectivePoint.BASE.multiply(
|
||||
0x28b90deaf189015d3a325908c5e0e4bf00f84f7e639b056ff82d7e70b6eede4cn
|
||||
);
|
||||
p2 =
|
||||
bls.G2.ProjectivePoint.BASE.multiply(
|
||||
0x28b90deaf189015d3a325908c5e0e4bf00f84f7e639b056ff82d7e70b6eede4dn
|
||||
);
|
||||
bls.pairing(p1, p2);
|
||||
});
|
||||
const priv = '28b90deaf189015d3a325908c5e0e4bf00f84f7e639b056ff82d7e70b6eede4c';
|
||||
sig = bls.sign('09', priv);
|
||||
const pubs = G2_VECTORS.map((v) => bls.getPublicKey(v[0]));
|
||||
const sigs = G2_VECTORS.map((v) => v[2]);
|
||||
const pub = bls.getPublicKey(priv);
|
||||
const pub512 = pubs.slice(0, 512); // .map(bls.PointG1.fromHex)
|
||||
const pub32 = pub512.slice(0, 32);
|
||||
const pub128 = pub512.slice(0, 128);
|
||||
const pub2048 = pub512.concat(pub512, pub512, pub512);
|
||||
const sig512 = sigs.slice(0, 512); // .map(bls.PointG2.fromSignature);
|
||||
const sig32 = sig512.slice(0, 32);
|
||||
const sig128 = sig512.slice(0, 128);
|
||||
const sig2048 = sig512.concat(sig512, sig512, sig512);
|
||||
await mark('getPublicKey 1-bit', 1000, () => bls.getPublicKey('2'.padStart(64, '0')));
|
||||
await mark('getPublicKey', 1000, () => bls.getPublicKey(priv));
|
||||
await mark('sign', 50, () => bls.sign('09', priv));
|
||||
await mark('verify', 50, () => bls.verify(sig, '09', pub));
|
||||
await mark('pairing', 100, () => bls.pairing(p1, p2));
|
||||
|
||||
const scalars1 = Array(4096).fill(0).map(i => 2n ** 235n - BigInt(i));
|
||||
const scalars2 = Array(4096).fill(0).map(i => 2n ** 241n + BigInt(i));
|
||||
const points = scalars1.map(s => bls.G1.ProjectivePoint.BASE.multiply(s));
|
||||
await mark('MSM 4096 scalars x points', 1, () => {
|
||||
// naive approach, not using multi-scalar-multiplication
|
||||
let sum = bls.G1.ProjectivePoint.ZERO;
|
||||
for (let i = 0; i < 4096; i++) {
|
||||
const scalar = scalars2[i];
|
||||
const G1 = points[i];
|
||||
const mutliplied = G1.multiplyUnsafe(scalar);
|
||||
sum = sum.add(mutliplied);
|
||||
}
|
||||
});
|
||||
|
||||
await mark('aggregatePublicKeys/8', 100, () => bls.aggregatePublicKeys(pubs.slice(0, 8)));
|
||||
await mark('aggregatePublicKeys/32', 50, () => bls.aggregatePublicKeys(pub32));
|
||||
await mark('aggregatePublicKeys/128', 20, () => bls.aggregatePublicKeys(pub128));
|
||||
await mark('aggregatePublicKeys/512', 10, () => bls.aggregatePublicKeys(pub512));
|
||||
await mark('aggregatePublicKeys/2048', 5, () => bls.aggregatePublicKeys(pub2048));
|
||||
await mark('aggregateSignatures/8', 100, () => bls.aggregateSignatures(sigs.slice(0, 8)));
|
||||
await mark('aggregateSignatures/32', 50, () => bls.aggregateSignatures(sig32));
|
||||
await mark('aggregateSignatures/128', 20, () => bls.aggregateSignatures(sig128));
|
||||
await mark('aggregateSignatures/512', 10, () => bls.aggregateSignatures(sig512));
|
||||
await mark('aggregateSignatures/2048', 5, () => bls.aggregateSignatures(sig2048));
|
||||
});
|
||||
@ -1,23 +0,0 @@
|
||||
import { run, mark, utils } from 'micro-bmark';
|
||||
import { generateData } from './_shared.js';
|
||||
import { p256 } from '../p256.js';
|
||||
import { p384 } from '../p384.js';
|
||||
import { p521 } from '../p521.js';
|
||||
import { ed25519 } from '../ed25519.js';
|
||||
import { ed448 } from '../ed448.js';
|
||||
|
||||
run(async () => {
|
||||
const RAM = false
|
||||
for (let kv of Object.entries({ ed25519, ed448, p256, p384, p521 })) {
|
||||
const [name, curve] = kv;
|
||||
console.log();
|
||||
console.log(`\x1b[36m${name}\x1b[0m`);
|
||||
if (RAM) utils.logMem();
|
||||
await mark('init', 1, () => curve.utils.precompute(8));
|
||||
const d = generateData(curve);
|
||||
await mark('getPublicKey', 5000, () => curve.getPublicKey(d.priv));
|
||||
await mark('sign', 5000, () => curve.sign(d.msg, d.priv));
|
||||
await mark('verify', 500, () => curve.verify(d.sig, d.msg, d.pub));
|
||||
if (RAM) utils.logMem();
|
||||
}
|
||||
});
|
||||
@ -1,18 +0,0 @@
|
||||
import { run, mark, utils } from 'micro-bmark';
|
||||
import { shake256 } from '@noble/hashes/sha3';
|
||||
import * as mod from '../abstract/modular.js';
|
||||
import { ed448, DecafPoint } from '../ed448.js';
|
||||
|
||||
run(async () => {
|
||||
const RAM = false;
|
||||
if (RAM) utils.logMem();
|
||||
console.log(`\x1b[36mdecaf448\x1b[0m`);
|
||||
const priv = mod.hashToPrivateScalar(shake256(ed448.utils.randomPrivateKey(), { dkLen: 112 }), ed448.CURVE.n);
|
||||
const pub = DecafPoint.BASE.multiply(priv);
|
||||
const encoded = pub.toRawBytes();
|
||||
await mark('add', 1000000, () => pub.add(DecafPoint.BASE));
|
||||
await mark('multiply', 1000, () => DecafPoint.BASE.multiply(priv));
|
||||
await mark('encode', 10000, () => DecafPoint.BASE.toRawBytes());
|
||||
await mark('decode', 10000, () => DecafPoint.fromHex(encoded));
|
||||
if (RAM) utils.logMem();
|
||||
});
|
||||
@ -1,18 +0,0 @@
|
||||
import { run, compare } from 'micro-bmark';
|
||||
import { secp256k1 } from '../secp256k1.js';
|
||||
import { p256 } from '../p256.js';
|
||||
import { p384 } from '../p384.js';
|
||||
import { p521 } from '../p521.js';
|
||||
import { x25519 } from '../ed25519.js';
|
||||
import { x448 } from '../ed448.js';
|
||||
|
||||
run(async () => {
|
||||
const curves = { x25519, secp256k1, p256, p384, p521, x448 };
|
||||
const fns = {};
|
||||
for (let [k, c] of Object.entries(curves)) {
|
||||
const pubB = c.getPublicKey(c.utils.randomPrivateKey());
|
||||
const privA = c.utils.randomPrivateKey();
|
||||
fns[k] = () => c.getSharedSecret(privA, pubB);
|
||||
}
|
||||
await compare('ecdh', 1000, fns);
|
||||
});
|
||||
@ -1,32 +0,0 @@
|
||||
import { run, mark, utils } from 'micro-bmark';
|
||||
import { hash_to_field } from '../abstract/hash-to-curve.js';
|
||||
import { hashToPrivateScalar } from '../abstract/modular.js';
|
||||
import { randomBytes } from '@noble/hashes/utils';
|
||||
import { sha256 } from '@noble/hashes/sha256';
|
||||
// import { generateData } from './_shared.js';
|
||||
import { hashToCurve as secp256k1 } from '../secp256k1.js';
|
||||
import { hashToCurve as p256 } from '../p256.js';
|
||||
import { hashToCurve as p384 } from '../p384.js';
|
||||
import { hashToCurve as p521 } from '../p521.js';
|
||||
import { hashToCurve as ed25519, hash_to_ristretto255 } from '../ed25519.js';
|
||||
import { hashToCurve as ed448, hash_to_decaf448 } from '../ed448.js';
|
||||
import { utf8ToBytes } from '../abstract/utils.js';
|
||||
|
||||
const N = 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141n;
|
||||
run(async () => {
|
||||
const rand = randomBytes(40);
|
||||
await mark('hashToPrivateScalar', 1000000, () => hashToPrivateScalar(rand, N));
|
||||
// - p, the characteristic of F
|
||||
// - m, the extension degree of F, m >= 1
|
||||
// - L = ceil((ceil(log2(p)) + k) / 8), where k is the security of suite (e.g. 128)
|
||||
await mark('hash_to_field', 1000000, () =>
|
||||
hash_to_field(rand, 1, { DST: 'secp256k1', hash: sha256, expand: 'xmd', p: N, m: 1, k: 128 })
|
||||
);
|
||||
const msg = utf8ToBytes('message');
|
||||
for (let [title, fn] of Object.entries({ secp256k1, p256, p384, p521, ed25519, ed448 })) {
|
||||
await mark(`hashToCurve ${title}`, 1000, () => fn(msg));
|
||||
}
|
||||
|
||||
await mark('hash_to_ristretto255', 1000, () => hash_to_ristretto255(msg, { DST: 'ristretto255_XMD:SHA-512_R255MAP_RO_' }));
|
||||
await mark('hash_to_decaf448', 1000, () => hash_to_decaf448(msg, { DST: 'decaf448_XOF:SHAKE256_D448MAP_RO_' }));
|
||||
});
|
||||
@ -1,13 +0,0 @@
|
||||
import { run, mark } from 'micro-bmark';
|
||||
import { secp256k1 } from '../secp256k1.js';
|
||||
import { Field as Fp } from '../abstract/modular.js';
|
||||
|
||||
run(async () => {
|
||||
console.log(`\x1b[36mmodular, secp256k1 field\x1b[0m`);
|
||||
const { Fp: secpFp } = secp256k1.CURVE;
|
||||
await mark('invert a', 300000, () => secpFp.inv(2n ** 232n - 5910n));
|
||||
await mark('invert b', 300000, () => secpFp.inv(2n ** 231n - 5910n));
|
||||
await mark('sqrt p = 3 mod 4', 15000, () => secpFp.sqrt(2n ** 231n - 5910n));
|
||||
const FpStark = Fp(BigInt('0x800000000000011000000000000000000000000000000000000000000000001'));
|
||||
await mark('sqrt tonneli-shanks', 500, () => FpStark.sqrt(2n ** 231n - 5909n))
|
||||
});
|
||||
@ -1,21 +0,0 @@
|
||||
{
|
||||
"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": {
|
||||
"micro-bmark": "0.3.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@noble/hashes": "^1.1.5",
|
||||
"elliptic": "^6.5.4"
|
||||
}
|
||||
}
|
||||
@ -1,18 +0,0 @@
|
||||
import { run, mark, utils } from 'micro-bmark';
|
||||
import { sha512 } from '@noble/hashes/sha512';
|
||||
import * as mod from '../abstract/modular.js';
|
||||
import { ed25519, RistrettoPoint } from '../ed25519.js';
|
||||
|
||||
run(async () => {
|
||||
const RAM = false;
|
||||
if (RAM) utils.logMem();
|
||||
console.log(`\x1b[36mristretto255\x1b[0m`);
|
||||
const priv = mod.hashToPrivateScalar(sha512(ed25519.utils.randomPrivateKey()), ed25519.CURVE.n);
|
||||
const pub = RistrettoPoint.BASE.multiply(priv);
|
||||
const encoded = pub.toRawBytes();
|
||||
await mark('add', 1000000, () => pub.add(RistrettoPoint.BASE));
|
||||
await mark('multiply', 10000, () => RistrettoPoint.BASE.multiply(priv));
|
||||
await mark('encode', 10000, () => RistrettoPoint.BASE.toRawBytes());
|
||||
await mark('decode', 10000, () => RistrettoPoint.fromHex(encoded));
|
||||
if (RAM) utils.logMem();
|
||||
});
|
||||
@ -1,22 +0,0 @@
|
||||
import { run, mark, utils } from 'micro-bmark';
|
||||
import { secp256k1, schnorr } from '../secp256k1.js';
|
||||
import { generateData } from './_shared.js';
|
||||
|
||||
run(async () => {
|
||||
const RAM = false;
|
||||
if (RAM) utils.logMem();
|
||||
console.log(`\x1b[36msecp256k1\x1b[0m`);
|
||||
await mark('init', 1, () => secp256k1.utils.precompute(8));
|
||||
const d = generateData(secp256k1);
|
||||
await mark('getPublicKey', 10000, () => secp256k1.getPublicKey(d.priv));
|
||||
await mark('sign', 10000, () => secp256k1.sign(d.msg, d.priv));
|
||||
await mark('verify', 1000, () => secp256k1.verify(d.sig, d.msg, d.pub));
|
||||
const pub2 = secp256k1.getPublicKey(secp256k1.utils.randomPrivateKey());
|
||||
await mark('getSharedSecret', 1000, () => secp256k1.getSharedSecret(d.priv, pub2));
|
||||
await mark('recoverPublicKey', 1000, () => d.sig.recoverPublicKey(d.msg));
|
||||
const s = schnorr.sign(d.msg, d.priv);
|
||||
const spub = schnorr.getPublicKey(d.priv);
|
||||
await mark('schnorr.sign', 1000, () => schnorr.sign(d.msg, d.priv));
|
||||
await mark('schnorr.verify', 1000, () => schnorr.verify(s, d.msg, spub));
|
||||
if (RAM) utils.logMem();
|
||||
});
|
||||
@ -1,9 +0,0 @@
|
||||
import { hexToBytes } from '../abstract/utils.js';
|
||||
import { run, mark } from 'micro-bmark';
|
||||
|
||||
run(async () => {
|
||||
const hex32 = '0123456789abcdef'.repeat(4);
|
||||
const hex256 = hex32.repeat(8);
|
||||
await mark('hexToBytes 32b', 5000000, () => hexToBytes(hex32));
|
||||
await mark('hexToBytes 256b', 500000, () => hexToBytes(hex256));
|
||||
});
|
||||
@ -1,7 +0,0 @@
|
||||
# build
|
||||
|
||||
The directory is used to build a single file which contains everything.
|
||||
|
||||
The single file uses iife wrapper and can be used in browsers as-is.
|
||||
|
||||
Don't use it unless you can't use NPM/ESM, which support tree shaking.
|
||||
@ -1,20 +0,0 @@
|
||||
import { bytesToHex, concatBytes, hexToBytes, utf8ToBytes } from '@noble/curves/abstract/utils';
|
||||
|
||||
export { secp256k1, schnorr as secp256k1_schnorr } from '@noble/curves/secp256k1';
|
||||
export {
|
||||
ed25519,
|
||||
x25519,
|
||||
edwardsToMontgomeryPub as ed25519_edwardsToMontgomeryPub,
|
||||
edwardsToMontgomeryPriv as ed25519_edwardsToMontgomeryPriv,
|
||||
} from '@noble/curves/ed25519';
|
||||
export {
|
||||
ed448,
|
||||
x448,
|
||||
edwardsToMontgomeryPub as ed448_edwardsToMontgomeryPub,
|
||||
} from '@noble/curves/ed448';
|
||||
export { p256 } from '@noble/curves/p256';
|
||||
export { p384 } from '@noble/curves/p384';
|
||||
export { p521 } from '@noble/curves/p521';
|
||||
export { bls12_381 } from '@noble/curves/bls12-381';
|
||||
|
||||
export const utils = { bytesToHex, concatBytes, hexToBytes, utf8ToBytes };
|
||||
445
build/package-lock.json
generated
445
build/package-lock.json
generated
@ -1,445 +0,0 @@
|
||||
{
|
||||
"name": "build",
|
||||
"version": "1.0.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "build",
|
||||
"version": "1.0.0",
|
||||
"devDependencies": {
|
||||
"@noble/curves": "file:..",
|
||||
"esbuild": "0.20.1"
|
||||
}
|
||||
},
|
||||
"..": {
|
||||
"version": "1.4.0",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@noble/hashes": "1.4.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@paulmillr/jsbt": "0.1.0",
|
||||
"fast-check": "3.0.0",
|
||||
"micro-bmark": "0.3.1",
|
||||
"micro-should": "0.4.0",
|
||||
"prettier": "3.1.1",
|
||||
"typescript": "5.3.2"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://paulmillr.com/funding/"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/aix-ppc64": {
|
||||
"version": "0.20.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.20.1.tgz",
|
||||
"integrity": "sha512-m55cpeupQ2DbuRGQMMZDzbv9J9PgVelPjlcmM5kxHnrBdBx6REaEd7LamYV7Dm8N7rCyR/XwU6rVP8ploKtIkA==",
|
||||
"cpu": [
|
||||
"ppc64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"aix"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/android-arm": {
|
||||
"version": "0.20.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.20.1.tgz",
|
||||
"integrity": "sha512-4j0+G27/2ZXGWR5okcJi7pQYhmkVgb4D7UKwxcqrjhvp5TKWx3cUjgB1CGj1mfdmJBQ9VnUGgUhign+FPF2Zgw==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"android"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/android-arm64": {
|
||||
"version": "0.20.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.20.1.tgz",
|
||||
"integrity": "sha512-hCnXNF0HM6AjowP+Zou0ZJMWWa1VkD77BXe959zERgGJBBxB+sV+J9f/rcjeg2c5bsukD/n17RKWXGFCO5dD5A==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"android"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/android-x64": {
|
||||
"version": "0.20.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.20.1.tgz",
|
||||
"integrity": "sha512-MSfZMBoAsnhpS+2yMFYIQUPs8Z19ajwfuaSZx+tSl09xrHZCjbeXXMsUF/0oq7ojxYEpsSo4c0SfjxOYXRbpaA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"android"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/darwin-arm64": {
|
||||
"version": "0.20.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.20.1.tgz",
|
||||
"integrity": "sha512-Ylk6rzgMD8klUklGPzS414UQLa5NPXZD5tf8JmQU8GQrj6BrFA/Ic9tb2zRe1kOZyCbGl+e8VMbDRazCEBqPvA==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/darwin-x64": {
|
||||
"version": "0.20.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.20.1.tgz",
|
||||
"integrity": "sha512-pFIfj7U2w5sMp52wTY1XVOdoxw+GDwy9FsK3OFz4BpMAjvZVs0dT1VXs8aQm22nhwoIWUmIRaE+4xow8xfIDZA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/freebsd-arm64": {
|
||||
"version": "0.20.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.20.1.tgz",
|
||||
"integrity": "sha512-UyW1WZvHDuM4xDz0jWun4qtQFauNdXjXOtIy7SYdf7pbxSWWVlqhnR/T2TpX6LX5NI62spt0a3ldIIEkPM6RHw==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"freebsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/freebsd-x64": {
|
||||
"version": "0.20.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.20.1.tgz",
|
||||
"integrity": "sha512-itPwCw5C+Jh/c624vcDd9kRCCZVpzpQn8dtwoYIt2TJF3S9xJLiRohnnNrKwREvcZYx0n8sCSbvGH349XkcQeg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"freebsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-arm": {
|
||||
"version": "0.20.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.20.1.tgz",
|
||||
"integrity": "sha512-LojC28v3+IhIbfQ+Vu4Ut5n3wKcgTu6POKIHN9Wpt0HnfgUGlBuyDDQR4jWZUZFyYLiz4RBBBmfU6sNfn6RhLw==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-arm64": {
|
||||
"version": "0.20.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.20.1.tgz",
|
||||
"integrity": "sha512-cX8WdlF6Cnvw/DO9/X7XLH2J6CkBnz7Twjpk56cshk9sjYVcuh4sXQBy5bmTwzBjNVZze2yaV1vtcJS04LbN8w==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-ia32": {
|
||||
"version": "0.20.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.20.1.tgz",
|
||||
"integrity": "sha512-4H/sQCy1mnnGkUt/xszaLlYJVTz3W9ep52xEefGtd6yXDQbz/5fZE5dFLUgsPdbUOQANcVUa5iO6g3nyy5BJiw==",
|
||||
"cpu": [
|
||||
"ia32"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-loong64": {
|
||||
"version": "0.20.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.20.1.tgz",
|
||||
"integrity": "sha512-c0jgtB+sRHCciVXlyjDcWb2FUuzlGVRwGXgI+3WqKOIuoo8AmZAddzeOHeYLtD+dmtHw3B4Xo9wAUdjlfW5yYA==",
|
||||
"cpu": [
|
||||
"loong64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-mips64el": {
|
||||
"version": "0.20.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.20.1.tgz",
|
||||
"integrity": "sha512-TgFyCfIxSujyuqdZKDZ3yTwWiGv+KnlOeXXitCQ+trDODJ+ZtGOzLkSWngynP0HZnTsDyBbPy7GWVXWaEl6lhA==",
|
||||
"cpu": [
|
||||
"mips64el"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-ppc64": {
|
||||
"version": "0.20.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.20.1.tgz",
|
||||
"integrity": "sha512-b+yuD1IUeL+Y93PmFZDZFIElwbmFfIKLKlYI8M6tRyzE6u7oEP7onGk0vZRh8wfVGC2dZoy0EqX1V8qok4qHaw==",
|
||||
"cpu": [
|
||||
"ppc64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-riscv64": {
|
||||
"version": "0.20.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.20.1.tgz",
|
||||
"integrity": "sha512-wpDlpE0oRKZwX+GfomcALcouqjjV8MIX8DyTrxfyCfXxoKQSDm45CZr9fanJ4F6ckD4yDEPT98SrjvLwIqUCgg==",
|
||||
"cpu": [
|
||||
"riscv64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-s390x": {
|
||||
"version": "0.20.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.20.1.tgz",
|
||||
"integrity": "sha512-5BepC2Au80EohQ2dBpyTquqGCES7++p7G+7lXe1bAIvMdXm4YYcEfZtQrP4gaoZ96Wv1Ute61CEHFU7h4FMueQ==",
|
||||
"cpu": [
|
||||
"s390x"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-x64": {
|
||||
"version": "0.20.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.20.1.tgz",
|
||||
"integrity": "sha512-5gRPk7pKuaIB+tmH+yKd2aQTRpqlf1E4f/mC+tawIm/CGJemZcHZpp2ic8oD83nKgUPMEd0fNanrnFljiruuyA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/netbsd-x64": {
|
||||
"version": "0.20.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.20.1.tgz",
|
||||
"integrity": "sha512-4fL68JdrLV2nVW2AaWZBv3XEm3Ae3NZn/7qy2KGAt3dexAgSVT+Hc97JKSZnqezgMlv9x6KV0ZkZY7UO5cNLCg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"netbsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/openbsd-x64": {
|
||||
"version": "0.20.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.20.1.tgz",
|
||||
"integrity": "sha512-GhRuXlvRE+twf2ES+8REbeCb/zeikNqwD3+6S5y5/x+DYbAQUNl0HNBs4RQJqrechS4v4MruEr8ZtAin/hK5iw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"openbsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/sunos-x64": {
|
||||
"version": "0.20.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.20.1.tgz",
|
||||
"integrity": "sha512-ZnWEyCM0G1Ex6JtsygvC3KUUrlDXqOihw8RicRuQAzw+c4f1D66YlPNNV3rkjVW90zXVsHwZYWbJh3v+oQFM9Q==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"sunos"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/win32-arm64": {
|
||||
"version": "0.20.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.20.1.tgz",
|
||||
"integrity": "sha512-QZ6gXue0vVQY2Oon9WyLFCdSuYbXSoxaZrPuJ4c20j6ICedfsDilNPYfHLlMH7vGfU5DQR0czHLmJvH4Nzis/A==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/win32-ia32": {
|
||||
"version": "0.20.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.20.1.tgz",
|
||||
"integrity": "sha512-HzcJa1NcSWTAU0MJIxOho8JftNp9YALui3o+Ny7hCh0v5f90nprly1U3Sj1Ldj/CvKKdvvFsCRvDkpsEMp4DNw==",
|
||||
"cpu": [
|
||||
"ia32"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/win32-x64": {
|
||||
"version": "0.20.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.20.1.tgz",
|
||||
"integrity": "sha512-0MBh53o6XtI6ctDnRMeQ+xoCN8kD2qI1rY1KgF/xdWQwoFeKou7puvDfV8/Wv4Ctx2rRpET/gGdz3YlNtNACSA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@noble/curves": {
|
||||
"resolved": "..",
|
||||
"link": true
|
||||
},
|
||||
"node_modules/esbuild": {
|
||||
"version": "0.20.1",
|
||||
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.20.1.tgz",
|
||||
"integrity": "sha512-OJwEgrpWm/PCMsLVWXKqvcjme3bHNpOgN7Tb6cQnR5n0TPbQx1/Xrn7rqM+wn17bYeT6MGB5sn1Bh5YiGi70nA==",
|
||||
"dev": true,
|
||||
"hasInstallScript": true,
|
||||
"bin": {
|
||||
"esbuild": "bin/esbuild"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@esbuild/aix-ppc64": "0.20.1",
|
||||
"@esbuild/android-arm": "0.20.1",
|
||||
"@esbuild/android-arm64": "0.20.1",
|
||||
"@esbuild/android-x64": "0.20.1",
|
||||
"@esbuild/darwin-arm64": "0.20.1",
|
||||
"@esbuild/darwin-x64": "0.20.1",
|
||||
"@esbuild/freebsd-arm64": "0.20.1",
|
||||
"@esbuild/freebsd-x64": "0.20.1",
|
||||
"@esbuild/linux-arm": "0.20.1",
|
||||
"@esbuild/linux-arm64": "0.20.1",
|
||||
"@esbuild/linux-ia32": "0.20.1",
|
||||
"@esbuild/linux-loong64": "0.20.1",
|
||||
"@esbuild/linux-mips64el": "0.20.1",
|
||||
"@esbuild/linux-ppc64": "0.20.1",
|
||||
"@esbuild/linux-riscv64": "0.20.1",
|
||||
"@esbuild/linux-s390x": "0.20.1",
|
||||
"@esbuild/linux-x64": "0.20.1",
|
||||
"@esbuild/netbsd-x64": "0.20.1",
|
||||
"@esbuild/openbsd-x64": "0.20.1",
|
||||
"@esbuild/sunos-x64": "0.20.1",
|
||||
"@esbuild/win32-arm64": "0.20.1",
|
||||
"@esbuild/win32-ia32": "0.20.1",
|
||||
"@esbuild/win32-x64": "0.20.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,14 +0,0 @@
|
||||
{
|
||||
"name": "build",
|
||||
"private": true,
|
||||
"version": "1.0.0",
|
||||
"main": "input.js",
|
||||
"type": "module",
|
||||
"devDependencies": {
|
||||
"@noble/curves": "file:..",
|
||||
"esbuild": "0.20.1"
|
||||
},
|
||||
"scripts": {
|
||||
"build:release": "npx esbuild --bundle input.js --outfile=`npx jsbt outfile` --global-name=`npx jsbt global`"
|
||||
}
|
||||
}
|
||||
21
curve-definitions/LICENSE
Normal 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.
|
||||
28
curve-definitions/README.md
Normal file
28
curve-definitions/README.md
Normal file
@ -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.
|
||||
231
curve-definitions/benchmark/index.js
Normal file
231
curve-definitions/benchmark/index.js
Normal file
@ -0,0 +1,231 @@
|
||||
import * as bench from 'micro-bmark';
|
||||
const { run, mark } = bench; // or bench.mark
|
||||
// Curves
|
||||
import { secp256k1 } from '../lib/secp256k1.js';
|
||||
import { P256 } from '../lib/p256.js';
|
||||
import { P384 } from '../lib/p384.js';
|
||||
import { P521 } from '../lib/p521.js';
|
||||
import { ed25519 } from '../lib/ed25519.js';
|
||||
import { ed448 } from '../lib/ed448.js';
|
||||
|
||||
// Others
|
||||
import { hmac } from '@noble/hashes/hmac';
|
||||
import { sha256 } from '@noble/hashes/sha256';
|
||||
import { sha512 } from '@noble/hashes/sha512';
|
||||
|
||||
import * as old_secp from '@noble/secp256k1';
|
||||
import { concatBytes, hexToBytes } from '@noble/hashes/utils';
|
||||
|
||||
import * as starkwareCrypto from '@starkware-industries/starkware-crypto-utils';
|
||||
import * as stark from '../lib/stark.js';
|
||||
|
||||
old_secp.utils.sha256Sync = (...msgs) =>
|
||||
sha256
|
||||
.create()
|
||||
.update(concatBytes(...msgs))
|
||||
.digest();
|
||||
old_secp.utils.hmacSha256Sync = (key, ...msgs) =>
|
||||
hmac
|
||||
.create(sha256, key)
|
||||
.update(concatBytes(...msgs))
|
||||
.digest();
|
||||
import * as noble_ed25519 from '@noble/ed25519';
|
||||
noble_ed25519.utils.sha512Sync = (...m) => sha512(concatBytes(...m));
|
||||
|
||||
for (let item of [secp256k1, ed25519, ed448, P256, P384, P521, old_secp, noble_ed25519]) {
|
||||
item.utils.precompute(8);
|
||||
}
|
||||
|
||||
const ONLY_NOBLE = process.argv[2] === 'noble';
|
||||
|
||||
function generateData(namespace) {
|
||||
const priv = namespace.utils.randomPrivateKey();
|
||||
const pub = namespace.getPublicKey(priv);
|
||||
const msg = namespace.utils.randomPrivateKey();
|
||||
const sig = namespace.sign(msg, priv);
|
||||
return { priv, pub, msg, sig };
|
||||
}
|
||||
|
||||
export const CURVES = {
|
||||
secp256k1: {
|
||||
data: () => {
|
||||
return generateData(secp256k1);
|
||||
},
|
||||
getPublicKey1: {
|
||||
samples: 10000,
|
||||
secp256k1_old: () => old_secp.getPublicKey(3n),
|
||||
secp256k1: () => secp256k1.getPublicKey(3n),
|
||||
},
|
||||
getPublicKey255: {
|
||||
samples: 10000,
|
||||
secp256k1_old: () => old_secp.getPublicKey(2n**255n-1n),
|
||||
secp256k1: () => secp256k1.getPublicKey(2n**255n-1n),
|
||||
},
|
||||
sign: {
|
||||
samples: 5000,
|
||||
secp256k1_old: ({ msg, priv }) => old_secp.signSync(msg, priv),
|
||||
secp256k1: ({ msg, priv }) => secp256k1.sign(msg, priv),
|
||||
},
|
||||
verify: {
|
||||
samples: 1000,
|
||||
secp256k1_old: ({ sig, msg, pub }) => {
|
||||
return old_secp.verify((new old_secp.Signature(sig.r, sig.s)), msg, pub);
|
||||
},
|
||||
secp256k1: ({ sig, msg, pub }) => secp256k1.verify(sig, msg, pub)
|
||||
},
|
||||
getSharedSecret: {
|
||||
samples: 1000,
|
||||
secp256k1_old: ({ pub, priv }) => old_secp.getSharedSecret(priv, pub),
|
||||
secp256k1: ({ pub, priv }) => secp256k1.getSharedSecret(priv, pub),
|
||||
},
|
||||
recoverPublicKey: {
|
||||
samples: 1000,
|
||||
secp256k1_old: ({ sig, msg }) =>
|
||||
old_secp.recoverPublicKey(msg, (new old_secp.Signature(sig.r, sig.s)), sig.recovery),
|
||||
secp256k1: ({ sig, msg }) => sig.recoverPublicKey(msg)
|
||||
}
|
||||
},
|
||||
ed25519: {
|
||||
data: () => {
|
||||
function to32Bytes(numOrStr) {
|
||||
const hex = typeof numOrStr === 'string' ? numOrStr : numOrStr.toString(16);
|
||||
return hexToBytes(hex.padStart(64, '0'));
|
||||
}
|
||||
const priv = to32Bytes(0x9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60n);
|
||||
const pub = noble_ed25519.sync.getPublicKey(priv);
|
||||
const msg = to32Bytes('deadbeefdeadbeefdeadbeefdeadbeefdeadbeef');
|
||||
const sig = noble_ed25519.sync.sign(msg, priv);
|
||||
return { pub, priv, msg, sig };
|
||||
},
|
||||
getPublicKey: {
|
||||
samples: 10000,
|
||||
old: () => noble_ed25519.sync.getPublicKey(noble_ed25519.utils.randomPrivateKey()),
|
||||
noble: () => ed25519.getPublicKey(ed25519.utils.randomPrivateKey()),
|
||||
},
|
||||
sign: {
|
||||
samples: 5000,
|
||||
old: ({ msg, priv }) => noble_ed25519.sync.sign(msg, priv),
|
||||
noble: ({ msg, priv }) => ed25519.sign(msg, priv),
|
||||
},
|
||||
verify: {
|
||||
samples: 1000,
|
||||
old: ({ sig, msg, pub }) => noble_ed25519.sync.verify(sig, msg, pub),
|
||||
noble: ({ sig, msg, pub }) => ed25519.verify(sig, msg, pub),
|
||||
},
|
||||
},
|
||||
ed448: {
|
||||
data: () => {
|
||||
const priv = ed448.utils.randomPrivateKey();
|
||||
const pub = ed448.getPublicKey(priv);
|
||||
const msg = ed448.utils.randomPrivateKey();
|
||||
const sig = ed448.sign(msg, priv);
|
||||
return { priv, pub, msg, sig };
|
||||
},
|
||||
getPublicKey: {
|
||||
samples: 5000,
|
||||
noble: () => ed448.getPublicKey(ed448.utils.randomPrivateKey()),
|
||||
},
|
||||
sign: {
|
||||
samples: 2500,
|
||||
noble: ({ msg, priv }) => ed448.sign(msg, priv),
|
||||
},
|
||||
verify: {
|
||||
samples: 500,
|
||||
noble: ({ sig, msg, pub }) => ed448.verify(sig, msg, pub)
|
||||
}
|
||||
},
|
||||
nist: {
|
||||
data: () => {
|
||||
return { p256: generateData(P256), p384: generateData(P384), p521: generateData(P521) }
|
||||
},
|
||||
getPublicKey: {
|
||||
samples: 2500,
|
||||
P256: () => P256.getPublicKey(P256.utils.randomPrivateKey()),
|
||||
P384: () => P384.getPublicKey(P384.utils.randomPrivateKey()),
|
||||
P521: () => P521.getPublicKey(P521.utils.randomPrivateKey()),
|
||||
},
|
||||
sign: {
|
||||
samples: 1000,
|
||||
P256: ({ p256: {msg, priv} }) => P256.sign(msg, priv),
|
||||
P384: ({ p384: {msg, priv} }) => P384.sign(msg, priv),
|
||||
P521: ({ p521: {msg, priv} }) => P521.sign(msg, priv),
|
||||
},
|
||||
verify: {
|
||||
samples: 250,
|
||||
P256: ({ p256: {sig, msg, pub} }) => P256.verify(sig, msg, pub),
|
||||
P384: ({ p384: {sig, msg, pub} }) => P384.verify(sig, msg, pub),
|
||||
P521: ({ p521: {sig, msg, pub} }) => P521.verify(sig, msg, pub),
|
||||
}
|
||||
},
|
||||
stark: {
|
||||
data: () => {
|
||||
const priv = '2dccce1da22003777062ee0870e9881b460a8b7eca276870f57c601f182136c';
|
||||
const msg = 'c465dd6b1bbffdb05442eb17f5ca38ad1aa78a6f56bf4415bdee219114a47';
|
||||
const pub = stark.getPublicKey(priv);
|
||||
const sig = stark.sign(msg, priv);
|
||||
|
||||
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'
|
||||
);
|
||||
|
||||
return { priv, sig, msg, pub, publicKeyStark, msgHash, keyPair }
|
||||
},
|
||||
pedersen: {
|
||||
samples: 500,
|
||||
old: () => {
|
||||
return starkwareCrypto.default.pedersen([
|
||||
'3d937c035c878245caf64531a5756109c53068da139362728feb561405371cb',
|
||||
'208a0a10250e382e1e4bbe2880906c2791bf6275695e02fbbc6aeff9cd8b31a',
|
||||
])
|
||||
},
|
||||
noble: () => {
|
||||
return stark.pedersen(
|
||||
'3d937c035c878245caf64531a5756109c53068da139362728feb561405371cb',
|
||||
'208a0a10250e382e1e4bbe2880906c2791bf6275695e02fbbc6aeff9cd8b31a'
|
||||
)
|
||||
}
|
||||
},
|
||||
verify: {
|
||||
samples: 500,
|
||||
old: ({ publicKeyStark, msgHash, keyPair }) => {
|
||||
return starkwareCrypto.default.verify(
|
||||
publicKeyStark,
|
||||
msgHash,
|
||||
starkwareCrypto.default.sign(keyPair, msgHash)
|
||||
);
|
||||
},
|
||||
noble: ({ priv, msg, pub }) => {
|
||||
return stark.verify(stark.sign(msg, priv), msg, pub)
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const main = () =>
|
||||
run(async () => {
|
||||
for (const [name, curve] of Object.entries(CURVES)) {
|
||||
console.log(`==== ${name} ====`);
|
||||
const data = curve.data();
|
||||
for (const [fnName, libs] of Object.entries(curve)) {
|
||||
if (fnName === 'data') continue;
|
||||
const samples = libs.samples;
|
||||
console.log(` - ${fnName} (samples: ${samples})`);
|
||||
for (const [lib, fn] of Object.entries(libs)) {
|
||||
if (lib === 'samples') continue;
|
||||
if (ONLY_NOBLE && lib !== 'noble') continue;
|
||||
await mark(` ${lib}`, samples, () => fn(data));
|
||||
}
|
||||
}
|
||||
}
|
||||
// Log current RAM
|
||||
bench.logMem();
|
||||
});
|
||||
|
||||
// ESM is broken.
|
||||
import url from 'url';
|
||||
if (import.meta.url === url.pathToFileURL(process.argv[1]).href) {
|
||||
main();
|
||||
}
|
||||
22
curve-definitions/benchmark/package.json
Normal file
22
curve-definitions/benchmark/package.json
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"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": {
|
||||
"micro-bmark": "0.2.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@noble/ed25519": "^1.7.1",
|
||||
"@noble/secp256k1": "^1.7.0",
|
||||
"@starkware-industries/starkware-crypto-utils": "^0.0.2"
|
||||
}
|
||||
}
|
||||
59
curve-definitions/package.json
Normal file
59
curve-definitions/package.json
Normal file
@ -0,0 +1,59 @@
|
||||
{
|
||||
"name": "micro-curve-definitions",
|
||||
"version": "0.2.0",
|
||||
"description": "Curve definitions for @noble/curves",
|
||||
"files": [
|
||||
"lib"
|
||||
],
|
||||
"type": "module",
|
||||
"main": "lib/index.js",
|
||||
"module": "lib/index.js",
|
||||
"types": "lib/index.d.ts",
|
||||
"dependencies": {
|
||||
"@noble/curves": "0.2.0",
|
||||
"@noble/hashes": "1.1.5"
|
||||
},
|
||||
"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 src",
|
||||
"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/"
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -1,10 +1,7 @@
|
||||
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
||||
import { hmac } from '@noble/hashes/hmac';
|
||||
import { concatBytes, randomBytes } from '@noble/hashes/utils';
|
||||
import { weierstrass, CurveType } from './abstract/weierstrass.js';
|
||||
import { CHash } from './abstract/utils.js';
|
||||
import { weierstrass, CurveType, CHash } from '@noble/curves/weierstrass';
|
||||
|
||||
// connects noble-curves to noble-hashes
|
||||
export function getHash(hash: CHash) {
|
||||
return {
|
||||
hash,
|
||||
21
curve-definitions/src/bn.ts
Normal file
21
curve-definitions/src/bn.ts
Normal file
@ -0,0 +1,21 @@
|
||||
/*! @noble/curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
||||
import { weierstrass } from '@noble/curves/weierstrass';
|
||||
import { sha256 } from '@noble/hashes/sha256';
|
||||
import { getHash } from './_shortw_utils.js';
|
||||
|
||||
/**
|
||||
* bn254 pairing-friendly curve.
|
||||
* Previously known as alt_bn_128, when it had 128-bit security.
|
||||
* Recent research shown it's weaker, the naming has been adjusted to its prime bit count.
|
||||
* https://github.com/zcash/zcash/issues/2502
|
||||
*/
|
||||
export const bn254 = weierstrass({
|
||||
a: BigInt(0),
|
||||
b: BigInt(3),
|
||||
P: BigInt('0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47'),
|
||||
n: BigInt('0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001'),
|
||||
Gx: BigInt(1),
|
||||
Gy: BigInt(2),
|
||||
h: BigInt(1),
|
||||
...getHash(sha256),
|
||||
});
|
||||
341
curve-definitions/src/ed25519.ts
Normal file
341
curve-definitions/src/ed25519.ts
Normal file
@ -0,0 +1,341 @@
|
||||
/*! @noble/curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
||||
import { sha512 } from '@noble/hashes/sha512';
|
||||
import { concatBytes, randomBytes, utf8ToBytes } from '@noble/hashes/utils';
|
||||
import { twistedEdwards, ExtendedPointType } from '@noble/curves/edwards';
|
||||
import { montgomery } from '@noble/curves/montgomery';
|
||||
import { mod, pow2, isNegativeLE } from '@noble/curves/modular';
|
||||
import {
|
||||
ensureBytes,
|
||||
equalBytes,
|
||||
bytesToHex,
|
||||
bytesToNumberLE,
|
||||
numberToBytesLE,
|
||||
Hex,
|
||||
} from '@noble/curves/utils';
|
||||
|
||||
/**
|
||||
* ed25519 Twisted Edwards curve with following addons:
|
||||
* - X25519 ECDH
|
||||
* - Ristretto cofactor elimination
|
||||
* - Elligator hash-to-group / point indistinguishability
|
||||
*/
|
||||
|
||||
const ED25519_P = BigInt(
|
||||
'57896044618658097711785492504343953926634992332820282019728792003956564819949'
|
||||
);
|
||||
// √(-1) aka √(a) aka 2^((p-1)/4)
|
||||
const ED25519_SQRT_M1 = BigInt(
|
||||
'19681161376707505956807079304988542015446066515923890162744021073123829784752'
|
||||
);
|
||||
|
||||
// prettier-ignore
|
||||
const _0n = BigInt(0), _1n = BigInt(1), _2n = BigInt(2), _5n = BigInt(5);
|
||||
// prettier-ignore
|
||||
const _10n = BigInt(10), _20n = BigInt(20), _40n = BigInt(40), _80n = BigInt(80);
|
||||
function ed25519_pow_2_252_3(x: bigint) {
|
||||
const P = ED25519_P;
|
||||
const x2 = (x * x) % P;
|
||||
const b2 = (x2 * x) % P; // x^3, 11
|
||||
const b4 = (pow2(b2, _2n, P) * b2) % P; // x^15, 1111
|
||||
const b5 = (pow2(b4, _1n, P) * x) % P; // x^31
|
||||
const b10 = (pow2(b5, _5n, P) * b5) % P;
|
||||
const b20 = (pow2(b10, _10n, P) * b10) % P;
|
||||
const b40 = (pow2(b20, _20n, P) * b20) % P;
|
||||
const b80 = (pow2(b40, _40n, P) * b40) % P;
|
||||
const b160 = (pow2(b80, _80n, P) * b80) % P;
|
||||
const b240 = (pow2(b160, _80n, P) * b80) % P;
|
||||
const b250 = (pow2(b240, _10n, P) * b10) % P;
|
||||
const pow_p_5_8 = (pow2(b250, _2n, P) * x) % P;
|
||||
// ^ To pow to (p+3)/8, multiply it by x.
|
||||
return { pow_p_5_8, b2 };
|
||||
}
|
||||
|
||||
/**
|
||||
* For X25519, in order to decode 32 random bytes as an integer scalar,
|
||||
* set the
|
||||
* three least significant bits of the first byte 0b1111_1000,
|
||||
* and the most significant bit of the last to zero 0b0111_1111,
|
||||
* set the second most significant bit of the last byte to 1 0b0100_0000
|
||||
*/
|
||||
function adjustScalarBytes(bytes: Uint8Array): Uint8Array {
|
||||
bytes[0] &= 248;
|
||||
bytes[31] &= 127;
|
||||
bytes[31] |= 64;
|
||||
return bytes;
|
||||
}
|
||||
// sqrt(u/v)
|
||||
function uvRatio(u: bigint, v: bigint): { isValid: boolean; value: bigint } {
|
||||
const P = ED25519_P;
|
||||
const v3 = mod(v * v * v, P); // v³
|
||||
const v7 = mod(v3 * v3 * v, P); // v⁷
|
||||
// (p+3)/8 and (p-5)/8
|
||||
const pow = ed25519_pow_2_252_3(u * v7).pow_p_5_8;
|
||||
let x = mod(u * v3 * pow, P); // (uv³)(uv⁷)^(p-5)/8
|
||||
const vx2 = mod(v * x * x, P); // vx²
|
||||
const root1 = x; // First root candidate
|
||||
const root2 = mod(x * ED25519_SQRT_M1, P); // Second root candidate
|
||||
const useRoot1 = vx2 === u; // If vx² = u (mod p), x is a square root
|
||||
const useRoot2 = vx2 === mod(-u, P); // If vx² = -u, set x <-- x * 2^((p-1)/4)
|
||||
const noRoot = vx2 === mod(-u * ED25519_SQRT_M1, P); // There is no valid root, vx² = -u√(-1)
|
||||
if (useRoot1) x = root1;
|
||||
if (useRoot2 || noRoot) x = root2; // We return root2 anyway, for const-time
|
||||
if (isNegativeLE(x, P)) x = mod(-x, P);
|
||||
return { isValid: useRoot1 || useRoot2, value: x };
|
||||
}
|
||||
|
||||
// Just in case
|
||||
export const ED25519_TORSION_SUBGROUP = [
|
||||
'0100000000000000000000000000000000000000000000000000000000000000',
|
||||
'c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a',
|
||||
'0000000000000000000000000000000000000000000000000000000000000080',
|
||||
'26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc05',
|
||||
'ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f',
|
||||
'26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc85',
|
||||
'0000000000000000000000000000000000000000000000000000000000000000',
|
||||
'c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa',
|
||||
];
|
||||
|
||||
const ED25519_DEF = {
|
||||
// Param: a
|
||||
a: BigInt(-1),
|
||||
// Equal to -121665/121666 over finite field.
|
||||
// Negative number is P - number, and division is invert(number, P)
|
||||
d: BigInt('37095705934669439343138083508754565189542113879843219016388785533085940283555'),
|
||||
// Finite field 𝔽p over which we'll do calculations; 2n ** 255n - 19n
|
||||
P: ED25519_P,
|
||||
// Subgroup order: how many points ed25519 has
|
||||
// 2n ** 252n + 27742317777372353535851937790883648493n;
|
||||
n: BigInt('7237005577332262213973186563042994240857116359379907606001950938285454250989'),
|
||||
// Cofactor
|
||||
h: BigInt(8),
|
||||
// Base point (x, y) aka generator point
|
||||
Gx: BigInt('15112221349535400772501151409588531511454012693041857206046113283949847762202'),
|
||||
Gy: BigInt('46316835694926478169428394003475163141307993866256225615783033603165251855960'),
|
||||
hash: sha512,
|
||||
randomBytes,
|
||||
adjustScalarBytes,
|
||||
// dom2
|
||||
// Ratio of u to v. Allows us to combine inversion and square root. Uses algo from RFC8032 5.1.3.
|
||||
// Constant-time, u/√v
|
||||
uvRatio,
|
||||
} as const;
|
||||
|
||||
export const ed25519 = twistedEdwards(ED25519_DEF);
|
||||
function ed25519_domain(data: Uint8Array, ctx: Uint8Array, phflag: boolean) {
|
||||
if (ctx.length > 255) throw new Error('Context is too big');
|
||||
return concatBytes(
|
||||
utf8ToBytes('SigEd25519 no Ed25519 collisions'),
|
||||
new Uint8Array([phflag ? 1 : 0, ctx.length]),
|
||||
ctx,
|
||||
data
|
||||
);
|
||||
}
|
||||
export const ed25519ctx = twistedEdwards({ ...ED25519_DEF, domain: ed25519_domain });
|
||||
export const ed25519ph = twistedEdwards({
|
||||
...ED25519_DEF,
|
||||
domain: ed25519_domain,
|
||||
preHash: sha512,
|
||||
});
|
||||
|
||||
export const x25519 = montgomery({
|
||||
P: ED25519_P,
|
||||
a24: BigInt('121665'),
|
||||
montgomeryBits: 255, // n is 253 bits
|
||||
nByteLength: 32,
|
||||
Gu: '0900000000000000000000000000000000000000000000000000000000000000',
|
||||
powPminus2: (x: bigint): bigint => {
|
||||
const P = ED25519_P;
|
||||
// x^(p-2) aka x^(2^255-21)
|
||||
const { pow_p_5_8, b2 } = ed25519_pow_2_252_3(x);
|
||||
return mod(pow2(pow_p_5_8, BigInt(3), P) * b2, P);
|
||||
},
|
||||
adjustScalarBytes,
|
||||
});
|
||||
|
||||
function assertRstPoint(other: unknown) {
|
||||
if (!(other instanceof RistrettoPoint)) throw new TypeError('RistrettoPoint expected');
|
||||
}
|
||||
// √(-1) aka √(a) aka 2^((p-1)/4)
|
||||
const SQRT_M1 = BigInt(
|
||||
'19681161376707505956807079304988542015446066515923890162744021073123829784752'
|
||||
);
|
||||
// √(ad - 1)
|
||||
const SQRT_AD_MINUS_ONE = BigInt(
|
||||
'25063068953384623474111414158702152701244531502492656460079210482610430750235'
|
||||
);
|
||||
// 1 / √(a-d)
|
||||
const INVSQRT_A_MINUS_D = BigInt(
|
||||
'54469307008909316920995813868745141605393597292927456921205312896311721017578'
|
||||
);
|
||||
// 1-d²
|
||||
const ONE_MINUS_D_SQ = BigInt(
|
||||
'1159843021668779879193775521855586647937357759715417654439879720876111806838'
|
||||
);
|
||||
// (d-1)²
|
||||
const D_MINUS_ONE_SQ = BigInt(
|
||||
'40440834346308536858101042469323190826248399146238708352240133220865137265952'
|
||||
);
|
||||
// Calculates 1/√(number)
|
||||
const invertSqrt = (number: bigint) => uvRatio(_1n, number);
|
||||
|
||||
const MAX_255B = BigInt('0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff');
|
||||
const bytes255ToNumberLE = (bytes: Uint8Array) =>
|
||||
ed25519.utils.mod(bytesToNumberLE(bytes) & MAX_255B);
|
||||
|
||||
type ExtendedPoint = ExtendedPointType;
|
||||
|
||||
/**
|
||||
* Each ed25519/ExtendedPoint has 8 different equivalent points. This can be
|
||||
* a source of bugs for protocols like ring signatures. Ristretto was created to solve this.
|
||||
* Ristretto point operates in X:Y:Z:T extended coordinates like ExtendedPoint,
|
||||
* but it should work in its own namespace: do not combine those two.
|
||||
* https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-ristretto255-decaf448
|
||||
*/
|
||||
export class RistrettoPoint {
|
||||
static BASE = new RistrettoPoint(ed25519.ExtendedPoint.BASE);
|
||||
static ZERO = new RistrettoPoint(ed25519.ExtendedPoint.ZERO);
|
||||
|
||||
// Private property to discourage combining ExtendedPoint + RistrettoPoint
|
||||
// Always use Ristretto encoding/decoding instead.
|
||||
constructor(private readonly ep: ExtendedPoint) {}
|
||||
|
||||
// Computes Elligator map for Ristretto
|
||||
// https://ristretto.group/formulas/elligator.html
|
||||
private static calcElligatorRistrettoMap(r0: bigint): ExtendedPoint {
|
||||
const { d, P } = ed25519.CURVE;
|
||||
const { mod } = ed25519.utils;
|
||||
const r = mod(SQRT_M1 * r0 * r0); // 1
|
||||
const Ns = mod((r + _1n) * ONE_MINUS_D_SQ); // 2
|
||||
let c = BigInt(-1); // 3
|
||||
const D = mod((c - d * r) * mod(r + d)); // 4
|
||||
let { isValid: Ns_D_is_sq, value: s } = uvRatio(Ns, D); // 5
|
||||
let s_ = mod(s * r0); // 6
|
||||
if (!isNegativeLE(s_, P)) s_ = mod(-s_);
|
||||
if (!Ns_D_is_sq) s = s_; // 7
|
||||
if (!Ns_D_is_sq) c = r; // 8
|
||||
const Nt = mod(c * (r - _1n) * D_MINUS_ONE_SQ - D); // 9
|
||||
const s2 = s * s;
|
||||
const W0 = mod((s + s) * D); // 10
|
||||
const W1 = mod(Nt * SQRT_AD_MINUS_ONE); // 11
|
||||
const W2 = mod(_1n - s2); // 12
|
||||
const W3 = mod(_1n + s2); // 13
|
||||
return new ed25519.ExtendedPoint(mod(W0 * W3), mod(W2 * W1), mod(W1 * W3), mod(W0 * W2));
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes uniform output of 64-bit hash function like sha512 and converts it to `RistrettoPoint`.
|
||||
* The hash-to-group operation applies Elligator twice and adds the results.
|
||||
* **Note:** this is one-way map, there is no conversion from point to hash.
|
||||
* https://ristretto.group/formulas/elligator.html
|
||||
* @param hex 64-bit output of a hash function
|
||||
*/
|
||||
static hashToCurve(hex: Hex): RistrettoPoint {
|
||||
hex = ensureBytes(hex, 64);
|
||||
const r1 = bytes255ToNumberLE(hex.slice(0, 32));
|
||||
const R1 = this.calcElligatorRistrettoMap(r1);
|
||||
const r2 = bytes255ToNumberLE(hex.slice(32, 64));
|
||||
const R2 = this.calcElligatorRistrettoMap(r2);
|
||||
return new RistrettoPoint(R1.add(R2));
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts ristretto-encoded string to ristretto point.
|
||||
* https://ristretto.group/formulas/decoding.html
|
||||
* @param hex Ristretto-encoded 32 bytes. Not every 32-byte string is valid ristretto encoding
|
||||
*/
|
||||
static fromHex(hex: Hex): RistrettoPoint {
|
||||
hex = ensureBytes(hex, 32);
|
||||
const { a, d, P } = ed25519.CURVE;
|
||||
const { mod } = ed25519.utils;
|
||||
const emsg = 'RistrettoPoint.fromHex: the hex is not valid encoding of RistrettoPoint';
|
||||
const s = bytes255ToNumberLE(hex);
|
||||
// 1. Check that s_bytes is the canonical encoding of a field element, or else abort.
|
||||
// 3. Check that s is non-negative, or else abort
|
||||
if (!equalBytes(numberToBytesLE(s, 32), hex) || isNegativeLE(s, P)) throw new Error(emsg);
|
||||
const s2 = mod(s * s);
|
||||
const u1 = mod(_1n + a * s2); // 4 (a is -1)
|
||||
const u2 = mod(_1n - a * s2); // 5
|
||||
const u1_2 = mod(u1 * u1);
|
||||
const u2_2 = mod(u2 * u2);
|
||||
const v = mod(a * d * u1_2 - u2_2); // 6
|
||||
const { isValid, value: I } = invertSqrt(mod(v * u2_2)); // 7
|
||||
const Dx = mod(I * u2); // 8
|
||||
const Dy = mod(I * Dx * v); // 9
|
||||
let x = mod((s + s) * Dx); // 10
|
||||
if (isNegativeLE(x, P)) x = mod(-x); // 10
|
||||
const y = mod(u1 * Dy); // 11
|
||||
const t = mod(x * y); // 12
|
||||
if (!isValid || isNegativeLE(t, P) || y === _0n) throw new Error(emsg);
|
||||
return new RistrettoPoint(new ed25519.ExtendedPoint(x, y, _1n, t));
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes ristretto point to Uint8Array.
|
||||
* https://ristretto.group/formulas/encoding.html
|
||||
*/
|
||||
toRawBytes(): Uint8Array {
|
||||
let { x, y, z, t } = this.ep;
|
||||
const { P } = ed25519.CURVE;
|
||||
const { mod } = ed25519.utils;
|
||||
const u1 = mod(mod(z + y) * mod(z - y)); // 1
|
||||
const u2 = mod(x * y); // 2
|
||||
// Square root always exists
|
||||
const u2sq = mod(u2 * u2);
|
||||
const { value: invsqrt } = invertSqrt(mod(u1 * u2sq)); // 3
|
||||
const D1 = mod(invsqrt * u1); // 4
|
||||
const D2 = mod(invsqrt * u2); // 5
|
||||
const zInv = mod(D1 * D2 * t); // 6
|
||||
let D: bigint; // 7
|
||||
if (isNegativeLE(t * zInv, P)) {
|
||||
let _x = mod(y * SQRT_M1);
|
||||
let _y = mod(x * SQRT_M1);
|
||||
x = _x;
|
||||
y = _y;
|
||||
D = mod(D1 * INVSQRT_A_MINUS_D);
|
||||
} else {
|
||||
D = D2; // 8
|
||||
}
|
||||
if (isNegativeLE(x * zInv, P)) y = mod(-y); // 9
|
||||
let s = mod((z - y) * D); // 10 (check footer's note, no sqrt(-a))
|
||||
if (isNegativeLE(s, P)) s = mod(-s);
|
||||
return numberToBytesLE(s, 32); // 11
|
||||
}
|
||||
|
||||
toHex(): string {
|
||||
return bytesToHex(this.toRawBytes());
|
||||
}
|
||||
|
||||
toString(): string {
|
||||
return this.toHex();
|
||||
}
|
||||
|
||||
// Compare one point to another.
|
||||
equals(other: RistrettoPoint): boolean {
|
||||
assertRstPoint(other);
|
||||
const a = this.ep;
|
||||
const b = other.ep;
|
||||
const { mod } = ed25519.utils;
|
||||
// (x1 * y2 == y1 * x2) | (y1 * y2 == x1 * x2)
|
||||
const one = mod(a.x * b.y) === mod(a.y * b.x);
|
||||
const two = mod(a.y * b.y) === mod(a.x * b.x);
|
||||
return one || two;
|
||||
}
|
||||
|
||||
add(other: RistrettoPoint): RistrettoPoint {
|
||||
assertRstPoint(other);
|
||||
return new RistrettoPoint(this.ep.add(other.ep));
|
||||
}
|
||||
|
||||
subtract(other: RistrettoPoint): RistrettoPoint {
|
||||
assertRstPoint(other);
|
||||
return new RistrettoPoint(this.ep.subtract(other.ep));
|
||||
}
|
||||
|
||||
multiply(scalar: number | bigint): RistrettoPoint {
|
||||
return new RistrettoPoint(this.ep.multiply(scalar));
|
||||
}
|
||||
|
||||
multiplyUnsafe(scalar: number | bigint): RistrettoPoint {
|
||||
return new RistrettoPoint(this.ep.multiplyUnsafe(scalar));
|
||||
}
|
||||
}
|
||||
146
curve-definitions/src/ed448.ts
Normal file
146
curve-definitions/src/ed448.ts
Normal file
@ -0,0 +1,146 @@
|
||||
/*! @noble/curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
||||
import { shake256 } from '@noble/hashes/sha3';
|
||||
import { concatBytes, randomBytes, utf8ToBytes, wrapConstructor } from '@noble/hashes/utils';
|
||||
import { twistedEdwards } from '@noble/curves/edwards';
|
||||
import { mod, pow2 } from '@noble/curves/modular';
|
||||
import { montgomery } from '../../lib/montgomery.js';
|
||||
|
||||
/**
|
||||
* Edwards448 (not Ed448-Goldilocks) curve with following addons:
|
||||
* * X448 ECDH
|
||||
* Conforms to RFC 8032 https://www.rfc-editor.org/rfc/rfc8032.html#section-5.2
|
||||
*/
|
||||
|
||||
const shake256_114 = wrapConstructor(() => shake256.create({ dkLen: 114 }));
|
||||
const shake256_64 = wrapConstructor(() => shake256.create({ dkLen: 64 }));
|
||||
const ed448P = BigInt(
|
||||
'726838724295606890549323807888004534353641360687318060281490199180612328166730772686396383698676545930088884461843637361053498018365439'
|
||||
);
|
||||
|
||||
// powPminus3div4 calculates z = x^k mod p, where k = (p-3)/4.
|
||||
function ed448_pow_Pminus3div4(x: bigint): bigint {
|
||||
const P = ed448P;
|
||||
// prettier-ignore
|
||||
let [_1n, _2n, _3n, _11n, _22n, _44n, _88n, _223n] = [1, 2, 3, 11, 22, 44, 88, 223]
|
||||
.map(n => BigInt(n));
|
||||
// x ** ((P - 3n)/4n) % P
|
||||
// [223 of 1, 0, 222 of 1], almost same as secp!
|
||||
const b2 = (x * x * x) % P;
|
||||
const b3 = (b2 * b2 * x) % P;
|
||||
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 b222 = (pow2(b220, _2n, P) * b2) % P;
|
||||
const b223 = (pow2(b222, _1n, P) * x) % P;
|
||||
return (pow2(b223, _223n, P) * b222) % P;
|
||||
}
|
||||
|
||||
function adjustScalarBytes(bytes: Uint8Array): Uint8Array {
|
||||
// Section 5: Likewise, for X448, set the two least significant bits of the first byte to 0, and the most
|
||||
// significant bit of the last byte to 1.
|
||||
bytes[0] &= 252; // 0b11111100
|
||||
// and the most significant bit of the last byte to 1.
|
||||
bytes[55] |= 128; // 0b10000000
|
||||
// NOTE: is is NOOP for 56 bytes scalars (X25519/X448)
|
||||
bytes[56] = 0; // Byte outside of group (456 buts vs 448 bits)
|
||||
return bytes;
|
||||
}
|
||||
|
||||
const ED448_DEF = {
|
||||
// Param: a
|
||||
a: BigInt(1),
|
||||
// -39081. Negative number is P - number
|
||||
d: BigInt(
|
||||
'726838724295606890549323807888004534353641360687318060281490199180612328166730772686396383698676545930088884461843637361053498018326358'
|
||||
),
|
||||
// Finite field 𝔽p over which we'll do calculations; 2n ** 448n - 2n ** 224n - 1n
|
||||
P: ed448P,
|
||||
// Subgroup order: how many points ed448 has; 2n**446n - 13818066809895115352007386748515426880336692474882178609894547503885n
|
||||
n: BigInt(
|
||||
'181709681073901722637330951972001133588410340171829515070372549795146003961539585716195755291692375963310293709091662304773755859649779'
|
||||
),
|
||||
nBitLength: 456,
|
||||
// Cofactor
|
||||
h: BigInt(4),
|
||||
// Base point (x, y) aka generator point
|
||||
Gx: BigInt(
|
||||
'224580040295924300187604334099896036246789641632564134246125461686950415467406032909029192869357953282578032075146446173674602635247710'
|
||||
),
|
||||
Gy: BigInt(
|
||||
'298819210078481492676017930443930673437544040154080242095928241372331506189835876003536878655418784733982303233503462500531545062832660'
|
||||
),
|
||||
// SHAKE256(dom4(phflag,context)||x, 114)
|
||||
hash: shake256_114,
|
||||
randomBytes,
|
||||
adjustScalarBytes,
|
||||
// dom4
|
||||
domain: (data: Uint8Array, ctx: Uint8Array, phflag: boolean) => {
|
||||
if (ctx.length > 255) throw new Error(`Context is too big: ${ctx.length}`);
|
||||
return concatBytes(
|
||||
utf8ToBytes('SigEd448'),
|
||||
new Uint8Array([phflag ? 1 : 0, ctx.length]),
|
||||
ctx,
|
||||
data
|
||||
);
|
||||
},
|
||||
// Constant-time ratio of u to v. Allows to combine inversion and square root u/√v.
|
||||
// Uses algo from RFC8032 5.1.3.
|
||||
uvRatio: (u: bigint, v: bigint): { isValid: boolean; value: bigint } => {
|
||||
const P = ed448P;
|
||||
// https://datatracker.ietf.org/doc/html/rfc8032#section-5.2.3
|
||||
// To compute the square root of (u/v), the first step is to compute the
|
||||
// candidate root x = (u/v)^((p+1)/4). This can be done using the
|
||||
// following trick, to use a single modular powering for both the
|
||||
// inversion of v and the square root:
|
||||
// (p+1)/4 3 (p-3)/4
|
||||
// x = (u/v) = u v (u^5 v^3) (mod p)
|
||||
const u2v = mod(u * u * v, P);
|
||||
const u3v = mod(u2v * u, P); // u^2v
|
||||
const u5v3 = mod(u3v * u2v * v, P); // u^5v^3
|
||||
const root = ed448_pow_Pminus3div4(u5v3);
|
||||
const x = mod(u3v * root, P);
|
||||
// Verify that root is exists
|
||||
const x2 = mod(x * x, P); // x^2
|
||||
// If v * x^2 = u, the recovered x-coordinate is x. Otherwise, no
|
||||
// square root exists, and the decoding fails.
|
||||
return { isValid: mod(x2 * v, P) === u, value: x };
|
||||
},
|
||||
} as const;
|
||||
|
||||
export const ed448 = twistedEdwards(ED448_DEF);
|
||||
// NOTE: there is no ed448ctx, since ed448 supports ctx by default
|
||||
export const ed448ph = twistedEdwards({ ...ED448_DEF, preHash: shake256_64 });
|
||||
|
||||
export const x448 = montgomery({
|
||||
a24: BigInt(39081),
|
||||
montgomeryBits: 448,
|
||||
nByteLength: 57,
|
||||
P: ed448P,
|
||||
Gu: '0500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000',
|
||||
powPminus2: (x: bigint): bigint => {
|
||||
const P = ed448P;
|
||||
const Pminus3div4 = ed448_pow_Pminus3div4(x);
|
||||
const Pminus3 = pow2(Pminus3div4, BigInt(2), P);
|
||||
return mod(Pminus3 * x, P); // Pminus3 * x = Pminus2
|
||||
},
|
||||
adjustScalarBytes,
|
||||
// The 4-isogeny maps between the Montgomery curve and this Edwards
|
||||
// curve are:
|
||||
// (u, v) = (y^2/x^2, (2 - x^2 - y^2)*y/x^3)
|
||||
// (x, y) = (4*v*(u^2 - 1)/(u^4 - 2*u^2 + 4*v^2 + 1),
|
||||
// -(u^5 - 2*u^3 - 4*u*v^2 + u)/
|
||||
// (u^5 - 2*u^2*v^2 - 2*u^3 - 2*v^2 + u))
|
||||
// xyToU: (p: PointType) => {
|
||||
// const P = ed448P;
|
||||
// const { x, y } = p;
|
||||
// if (x === _0n) throw new Error(`Point with x=0 doesn't have mapping`);
|
||||
// const invX = invert(x * x, P); // x^2
|
||||
// const u = mod(y * y * invX, P); // (y^2/x^2)
|
||||
// return numberToBytesLE(u, 56);
|
||||
// },
|
||||
});
|
||||
@ -1,31 +1,29 @@
|
||||
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
||||
import { sha512 } from '@noble/hashes/sha512';
|
||||
/*! @noble/curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
||||
import { sha256 } from '@noble/hashes/sha256';
|
||||
import { concatBytes, randomBytes, utf8ToBytes } from '@noble/hashes/utils';
|
||||
import { twistedEdwards } from './abstract/edwards.js';
|
||||
import { twistedEdwards } from '@noble/curves/edwards';
|
||||
import { blake2s } from '@noble/hashes/blake2s';
|
||||
import { Field } from './abstract/modular.js';
|
||||
|
||||
/**
|
||||
* jubjub Twisted Edwards curve.
|
||||
* https://neuromancer.sk/std/other/JubJub
|
||||
* jubjub does not use EdDSA, so `hash`/sha512 params are passed because interface expects them.
|
||||
*/
|
||||
|
||||
export const jubjub = /* @__PURE__ */ twistedEdwards({
|
||||
export const jubjub = twistedEdwards({
|
||||
// Params: a, d
|
||||
a: BigInt('0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000000'),
|
||||
d: BigInt('0x2a9318e74bfa2b48f5fd9207e6bd7fd4292d7f6d37579d2601065fd6d6343eb1'),
|
||||
// Finite field 𝔽p over which we'll do calculations
|
||||
// Same value as bls12-381 Fr (not Fp)
|
||||
Fp: Field(BigInt('0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001')),
|
||||
// Subgroup order: how many points curve has
|
||||
P: BigInt('0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001'),
|
||||
// Subgroup order: how many points ed25519 has
|
||||
// 2n ** 252n + 27742317777372353535851937790883648493n;
|
||||
n: BigInt('0xe7db4ea6533afa906673b0101343b00a6682093ccc81082d0970e5ed6f72cb7'),
|
||||
// Cofactor
|
||||
h: BigInt(8),
|
||||
// Base point (x, y) aka generator point
|
||||
Gx: BigInt('0x11dafe5d23e1218086a365b99fbf3d3be72f6afd7d1f72623e6b071492d1122b'),
|
||||
Gy: BigInt('0x1d523cf1ddab1a1793132e78c866c0c33e26ba5cc220fed7cc3f870e59d292aa'),
|
||||
hash: sha512,
|
||||
hash: sha256,
|
||||
randomBytes,
|
||||
} as const);
|
||||
|
||||
@ -39,7 +37,7 @@ export function groupHash(tag: Uint8Array, personalization: Uint8Array) {
|
||||
h.update(GH_FIRST_BLOCK);
|
||||
h.update(tag);
|
||||
// NOTE: returns ExtendedPoint, in case it will be multiplied later
|
||||
let p = jubjub.ExtendedPoint.fromHex(h.digest());
|
||||
let p = jubjub.ExtendedPoint.fromAffine(jubjub.Point.fromHex(h.digest()));
|
||||
// NOTE: cannot replace with isSmallOrder, returns Point*8
|
||||
p = p.multiply(jubjub.CURVE.h);
|
||||
if (p.equals(jubjub.ExtendedPoint.ZERO)) throw new Error('Point has small order');
|
||||
24
curve-definitions/src/p192.ts
Normal file
24
curve-definitions/src/p192.ts
Normal file
@ -0,0 +1,24 @@
|
||||
/*! @noble/curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
||||
import { createCurve } from './_shortw_utils.js';
|
||||
import { sha256 } from '@noble/hashes/sha256';
|
||||
|
||||
// NIST secp192r1 aka P192
|
||||
// https://www.secg.org/sec2-v2.pdf, https://neuromancer.sk/std/secg/secp192r1
|
||||
export const P192 = createCurve(
|
||||
{
|
||||
// Params: a, b
|
||||
a: BigInt('0xfffffffffffffffffffffffffffffffefffffffffffffffc'),
|
||||
b: BigInt('0x64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1'),
|
||||
// Field over which we'll do calculations; 2n ** 192n - 2n ** 64n - 1n
|
||||
P: BigInt('0xfffffffffffffffffffffffffffffffeffffffffffffffff'),
|
||||
// Curve order, total count of valid points in the field.
|
||||
n: BigInt('0xffffffffffffffffffffffff99def836146bc9b1b4d22831'),
|
||||
// Base point (x, y) aka generator point
|
||||
Gx: BigInt('0x188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012'),
|
||||
Gy: BigInt('0x07192b95ffc8da78631011ed6b24cdd573f977a11e794811'),
|
||||
h: BigInt(1),
|
||||
lowS: false,
|
||||
} as const,
|
||||
sha256
|
||||
);
|
||||
export const secp192r1 = P192;
|
||||
24
curve-definitions/src/p224.ts
Normal file
24
curve-definitions/src/p224.ts
Normal file
@ -0,0 +1,24 @@
|
||||
/*! @noble/curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
||||
import { createCurve } from './_shortw_utils.js';
|
||||
import { sha256 } from '@noble/hashes/sha256';
|
||||
|
||||
// NIST secp224r1 aka P224
|
||||
// https://www.secg.org/sec2-v2.pdf, https://neuromancer.sk/std/nist/P-224
|
||||
export const P224 = createCurve(
|
||||
{
|
||||
// Params: a, b
|
||||
a: BigInt('0xfffffffffffffffffffffffffffffffefffffffffffffffffffffffe'),
|
||||
b: BigInt('0xb4050a850c04b3abf54132565044b0b7d7bfd8ba270b39432355ffb4'),
|
||||
// Field over which we'll do calculations; 2n**224n - 2n**96n + 1n
|
||||
P: BigInt('0xffffffffffffffffffffffffffffffff000000000000000000000001'),
|
||||
// Curve order, total count of valid points in the field
|
||||
n: BigInt('0xffffffffffffffffffffffffffff16a2e0b8f03e13dd29455c5c2a3d'),
|
||||
// Base point (x, y) aka generator point
|
||||
Gx: BigInt('0xb70e0cbd6bb4bf7f321390b94a03c1d356c21122343280d6115c1d21'),
|
||||
Gy: BigInt('0xbd376388b5f723fb4c22dfe6cd4375a05a07476444d5819985007e34'),
|
||||
h: BigInt(1),
|
||||
lowS: false,
|
||||
} as const,
|
||||
sha256 // TODO: replace with sha224 when new @noble/hashes released
|
||||
);
|
||||
export const secp224r1 = P224;
|
||||
24
curve-definitions/src/p256.ts
Normal file
24
curve-definitions/src/p256.ts
Normal file
@ -0,0 +1,24 @@
|
||||
/*! @noble/curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
||||
import { createCurve } from './_shortw_utils.js';
|
||||
import { sha256 } from '@noble/hashes/sha256';
|
||||
|
||||
// NIST secp256r1 aka P256
|
||||
// https://www.secg.org/sec2-v2.pdf, https://neuromancer.sk/std/nist/P-256
|
||||
export const P256 = createCurve(
|
||||
{
|
||||
// Params: a, b
|
||||
a: BigInt('0xffffffff00000001000000000000000000000000fffffffffffffffffffffffc'),
|
||||
b: BigInt('0x5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b'),
|
||||
// Field over which we'll do calculations; 2n**224n * (2n**32n-1n) + 2n**192n + 2n**96n-1n
|
||||
P: BigInt('0xffffffff00000001000000000000000000000000ffffffffffffffffffffffff'),
|
||||
// Curve order, total count of valid points in the field
|
||||
n: BigInt('0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551'),
|
||||
// Base point (x, y) aka generator point
|
||||
Gx: BigInt('0x6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296'),
|
||||
Gy: BigInt('0x4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5'),
|
||||
h: BigInt(1),
|
||||
lowS: false,
|
||||
} as const,
|
||||
sha256
|
||||
);
|
||||
export const secp256r1 = P256;
|
||||
22
curve-definitions/src/p384.ts
Normal file
22
curve-definitions/src/p384.ts
Normal file
@ -0,0 +1,22 @@
|
||||
/*! @noble/curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
||||
import { createCurve } from './_shortw_utils.js';
|
||||
import { sha384 } from '@noble/hashes/sha512';
|
||||
|
||||
// NIST secp384r1 aka P384
|
||||
// https://www.secg.org/sec2-v2.pdf, https://neuromancer.sk/std/nist/P-384
|
||||
// prettier-ignore
|
||||
export const P384 = createCurve({
|
||||
// Params: a, b
|
||||
a: BigInt('0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000fffffffc'),
|
||||
b: BigInt('0xb3312fa7e23ee7e4988e056be3f82d19181d9c6efe8141120314088f5013875ac656398d8a2ed19d2a85c8edd3ec2aef'),
|
||||
// Field over which we'll do calculations. 2n**384n - 2n**128n - 2n**96n + 2n**32n - 1n
|
||||
P: BigInt('0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000ffffffff'),
|
||||
// Curve order, total count of valid points in the field.
|
||||
n: BigInt('0xffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf581a0db248b0a77aecec196accc52973'),
|
||||
// Base point (x, y) aka generator point
|
||||
Gx: BigInt('0xaa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a385502f25dbf55296c3a545e3872760ab7'),
|
||||
Gy: BigInt('0x3617de4a96262c6f5d9e98bf9292dc29f8f41dbd289a147ce9da3113b5f0b8c00a60b1ce1d7e819d7a431d7c90ea0e5f'),
|
||||
h: BigInt(1),
|
||||
lowS: false,
|
||||
} as const, sha384);
|
||||
export const secp384r1 = P384;
|
||||
23
curve-definitions/src/p521.ts
Normal file
23
curve-definitions/src/p521.ts
Normal file
@ -0,0 +1,23 @@
|
||||
/*! @noble/curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
||||
import { createCurve } from './_shortw_utils.js';
|
||||
import { sha512 } from '@noble/hashes/sha512';
|
||||
|
||||
// NIST secp521r1 aka P521
|
||||
// Note that it's 521, which differs from 512 of its hash function.
|
||||
// https://www.secg.org/sec2-v2.pdf, https://neuromancer.sk/std/nist/P-521
|
||||
// prettier-ignore
|
||||
export const P521 = createCurve({
|
||||
// Params: a, b
|
||||
a: BigInt('0x01fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc'),
|
||||
b: BigInt('0x0051953eb9618e1c9a1f929a21a0b68540eea2da725b99b315f3b8b489918ef109e156193951ec7e937b1652c0bd3bb1bf073573df883d2c34f1ef451fd46b503f00'),
|
||||
// Field over which we'll do calculations; 2n**521n - 1n
|
||||
P: BigInt('0x1ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'),
|
||||
// Curve order, total count of valid points in the field
|
||||
n: BigInt('0x01fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa51868783bf2f966b7fcc0148f709a5d03bb5c9b8899c47aebb6fb71e91386409'),
|
||||
// Base point (x, y) aka generator point
|
||||
Gx: BigInt('0x00c6858e06b70404e9cd9e3ecb662395b4429c648139053fb521f828af606b4d3dbaa14b5e77efe75928fe1dc127a2ffa8de3348b3c1856a429bf97e7e31c2e5bd66'),
|
||||
Gy: BigInt('0x011839296a789a3bc0045c8a5fb42c7d1bd998f54449579b446817afbd17273e662c97ee72995ef42640c550b9013fad0761353c7086a272c24088be94769fd16650'),
|
||||
h: BigInt(1),
|
||||
lowS: false,
|
||||
} as const, sha512);
|
||||
export const secp521r1 = P521;
|
||||
@ -1,17 +1,17 @@
|
||||
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
||||
/*! @noble/curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
||||
import { sha256 } from '@noble/hashes/sha256';
|
||||
import { weierstrass } from './abstract/weierstrass.js';
|
||||
import { weierstrass } from '@noble/curves/weierstrass';
|
||||
import { getHash } from './_shortw_utils.js';
|
||||
import * as mod from './abstract/modular.js';
|
||||
import * as mod from '@noble/curves/modular';
|
||||
|
||||
export const p = BigInt('0x40000000000000000000000000000000224698fc094cf91b992d30ed00000001');
|
||||
export const q = BigInt('0x40000000000000000000000000000000224698fc0994a8dd8c46eb2100000001');
|
||||
const p = BigInt('0x40000000000000000000000000000000224698fc094cf91b992d30ed00000001');
|
||||
const q = BigInt('0x40000000000000000000000000000000224698fc0994a8dd8c46eb2100000001');
|
||||
|
||||
// https://neuromancer.sk/std/other/Pallas
|
||||
export const pallas = weierstrass({
|
||||
a: BigInt(0),
|
||||
b: BigInt(5),
|
||||
Fp: mod.Field(p),
|
||||
P: p,
|
||||
n: q,
|
||||
Gx: mod.mod(BigInt(-1), p),
|
||||
Gy: BigInt(2),
|
||||
@ -22,7 +22,7 @@ export const pallas = weierstrass({
|
||||
export const vesta = weierstrass({
|
||||
a: BigInt(0),
|
||||
b: BigInt(5),
|
||||
Fp: mod.Field(q),
|
||||
P: q,
|
||||
n: p,
|
||||
Gx: mod.mod(BigInt(-1), q),
|
||||
Gy: BigInt(2),
|
||||
262
curve-definitions/src/secp256k1.ts
Normal file
262
curve-definitions/src/secp256k1.ts
Normal file
@ -0,0 +1,262 @@
|
||||
/*! @noble/curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
||||
import { sha256 } from '@noble/hashes/sha256';
|
||||
import { mod, pow2 } from '@noble/curves/modular';
|
||||
import { createCurve } from './_shortw_utils.js';
|
||||
import { PointType } from '@noble/curves/weierstrass';
|
||||
import {
|
||||
ensureBytes,
|
||||
concatBytes,
|
||||
Hex,
|
||||
hexToBytes,
|
||||
bytesToNumberBE,
|
||||
PrivKey,
|
||||
} from '@noble/curves/utils';
|
||||
import { randomBytes } from '@noble/hashes/utils';
|
||||
|
||||
/**
|
||||
* secp256k1 belongs to Koblitz curves: it has
|
||||
* efficiently computable Frobenius endomorphism.
|
||||
* Endomorphism 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;
|
||||
|
||||
/**
|
||||
* Allows to compute square root √y 2x faster.
|
||||
* To calculate √y, we need to exponentiate it to a very big number:
|
||||
* `y² = x³ + ax + b; y = y² ^ (p+1)/4`
|
||||
* We are unwrapping the loop and multiplying it bit-by-bit.
|
||||
* (P+1n/4n).toString(2) would produce bits [223x 1, 0, 22x 1, 4x 0, 11, 00]
|
||||
*/
|
||||
// prettier-ignore
|
||||
function sqrtMod(y: bigint): bigint {
|
||||
const P = secp256k1P;
|
||||
const _3n = BigInt(3), _6n = BigInt(6), _11n = BigInt(11); const _22n = BigInt(22);
|
||||
const _23n = BigInt(23), _44n = BigInt(44), _88n = BigInt(88);
|
||||
const b2 = (y * y * y) % P; // x^3, 11
|
||||
const b3 = (b2 * b2 * y) % 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);
|
||||
}
|
||||
|
||||
export const secp256k1 = createCurve(
|
||||
{
|
||||
// Params: a, b
|
||||
// Seem to be rigid https://bitcointalk.org/index.php?topic=289795.msg3183975#msg3183975
|
||||
a: BigInt(0),
|
||||
b: BigInt(7),
|
||||
// Field over which we'll do calculations;
|
||||
// 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
|
||||
n: secp256k1N,
|
||||
// Base point (x, y) aka generator point
|
||||
Gx: BigInt('55066263022277343669578718895168534326250603453777594175500187360389116729240'),
|
||||
Gy: BigInt('32670510020758816978083085130507043184471273380659243275938904335757337482424'),
|
||||
h: BigInt(1),
|
||||
// Alllow only low-S signatures by default in sign() and verify()
|
||||
lowS: true,
|
||||
sqrtMod,
|
||||
endo: {
|
||||
// Params taken from https://gist.github.com/paulmillr/eb670806793e84df628a7c434a873066
|
||||
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 };
|
||||
},
|
||||
},
|
||||
},
|
||||
sha256
|
||||
);
|
||||
|
||||
// Schnorr
|
||||
const _0n = BigInt(0);
|
||||
const numTo32b = secp256k1.utils._bigintToBytes;
|
||||
const numTo32bStr = secp256k1.utils._bigintToString;
|
||||
const normalizePrivateKey = secp256k1.utils._normalizePrivateKey;
|
||||
|
||||
// TODO: export?
|
||||
function normalizePublicKey(publicKey: Hex | PointType): PointType {
|
||||
if (publicKey instanceof secp256k1.Point) {
|
||||
publicKey.assertValidity();
|
||||
return publicKey;
|
||||
} else {
|
||||
const bytes = ensureBytes(publicKey);
|
||||
// Schnorr is 32 bytes
|
||||
if (bytes.length === 32) {
|
||||
const x = bytesToNumberBE(bytes);
|
||||
if (!isValidFieldElement(x)) throw new Error('Point is not on curve');
|
||||
const y2 = secp256k1.utils._weierstrassEquation(x); // y² = x³ + ax + b
|
||||
let y = sqrtMod(y2); // y = y² ^ (p+1)/4
|
||||
const isYOdd = (y & _1n) === _1n;
|
||||
// Schnorr
|
||||
if (isYOdd) y = mod(-y, secp256k1.CURVE.P);
|
||||
const point = new secp256k1.Point(x, y);
|
||||
point.assertValidity();
|
||||
return point;
|
||||
}
|
||||
// Do we need that in schnorr at all?
|
||||
return secp256k1.Point.fromHex(publicKey);
|
||||
}
|
||||
}
|
||||
|
||||
const isWithinCurveOrder = secp256k1.utils._isWithinCurveOrder;
|
||||
const isValidFieldElement = secp256k1.utils._isValidFieldElement;
|
||||
|
||||
const TAGS = {
|
||||
challenge: 'BIP0340/challenge',
|
||||
aux: 'BIP0340/aux',
|
||||
nonce: 'BIP0340/nonce',
|
||||
} as const;
|
||||
|
||||
/** An object mapping tags to their tagged hash prefix of [SHA256(tag) | SHA256(tag)] */
|
||||
const TAGGED_HASH_PREFIXES: { [tag: string]: Uint8Array } = {};
|
||||
export function taggedHash(tag: string, ...messages: Uint8Array[]): Uint8Array {
|
||||
let tagP = TAGGED_HASH_PREFIXES[tag];
|
||||
if (tagP === undefined) {
|
||||
const tagH = sha256(Uint8Array.from(tag, (c) => c.charCodeAt(0)));
|
||||
tagP = concatBytes(tagH, tagH);
|
||||
TAGGED_HASH_PREFIXES[tag] = tagP;
|
||||
}
|
||||
return sha256(concatBytes(tagP, ...messages));
|
||||
}
|
||||
|
||||
const toRawX = (point: PointType) => point.toRawBytes(true).slice(1);
|
||||
|
||||
// Schnorr signatures are superior to ECDSA from above.
|
||||
// Below is Schnorr-specific code as per BIP0340.
|
||||
function schnorrChallengeFinalize(ch: Uint8Array): bigint {
|
||||
return mod(bytesToNumberBE(ch), secp256k1.CURVE.n);
|
||||
}
|
||||
// Do we need this at all for Schnorr?
|
||||
class SchnorrSignature {
|
||||
constructor(readonly r: bigint, readonly s: bigint) {
|
||||
this.assertValidity();
|
||||
}
|
||||
static fromHex(hex: Hex) {
|
||||
const bytes = ensureBytes(hex);
|
||||
if (bytes.length !== 64)
|
||||
throw new TypeError(`SchnorrSignature.fromHex: expected 64 bytes, not ${bytes.length}`);
|
||||
const r = bytesToNumberBE(bytes.subarray(0, 32));
|
||||
const s = bytesToNumberBE(bytes.subarray(32, 64));
|
||||
return new SchnorrSignature(r, s);
|
||||
}
|
||||
assertValidity() {
|
||||
const { r, s } = this;
|
||||
if (!isValidFieldElement(r) || !isWithinCurveOrder(s)) throw new Error('Invalid signature');
|
||||
}
|
||||
toHex(): string {
|
||||
return numTo32bStr(this.r) + numTo32bStr(this.s);
|
||||
}
|
||||
toRawBytes(): Uint8Array {
|
||||
return hexToBytes(this.toHex());
|
||||
}
|
||||
}
|
||||
|
||||
function schnorrGetScalar(priv: bigint) {
|
||||
const point = secp256k1.Point.fromPrivateKey(priv);
|
||||
const scalar = point.hasEvenY() ? priv : secp256k1.CURVE.n - priv;
|
||||
return { point, scalar, x: toRawX(point) };
|
||||
}
|
||||
/**
|
||||
* Synchronously creates Schnorr signature. Improved security: verifies itself before
|
||||
* producing an output.
|
||||
* @param msg message (not message hash)
|
||||
* @param privateKey private key
|
||||
* @param auxRand random bytes that would be added to k. Bad RNG won't break it.
|
||||
*/
|
||||
function schnorrSign(
|
||||
message: Hex,
|
||||
privateKey: PrivKey,
|
||||
auxRand: Hex = randomBytes(32)
|
||||
): Uint8Array {
|
||||
if (message == null) throw new TypeError(`sign: Expected valid message, not "${message}"`);
|
||||
const m = ensureBytes(message);
|
||||
// checks for isWithinCurveOrder
|
||||
const { x: px, scalar: d } = schnorrGetScalar(normalizePrivateKey(privateKey));
|
||||
const rand = ensureBytes(auxRand);
|
||||
if (rand.length !== 32) throw new TypeError('sign: Expected 32 bytes of aux randomness');
|
||||
const tag = taggedHash;
|
||||
const t0h = tag(TAGS.aux, rand);
|
||||
const t = numTo32b(d ^ bytesToNumberBE(t0h));
|
||||
const k0h = tag(TAGS.nonce, t, px, m);
|
||||
const k0 = mod(bytesToNumberBE(k0h), secp256k1.CURVE.n);
|
||||
if (k0 === _0n) throw new Error('sign: Creation of signature failed. k is zero');
|
||||
const { point: R, x: rx, scalar: k } = schnorrGetScalar(k0);
|
||||
const e = schnorrChallengeFinalize(tag(TAGS.challenge, rx, px, m));
|
||||
const sig = new SchnorrSignature(R.x, mod(k + e * d, secp256k1.CURVE.n)).toRawBytes();
|
||||
if (!schnorrVerify(sig, m, px)) throw new Error('sign: Invalid signature produced');
|
||||
return sig;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies Schnorr signature synchronously.
|
||||
*/
|
||||
function schnorrVerify(signature: Hex, message: Hex, publicKey: Hex): boolean {
|
||||
try {
|
||||
const raw = signature instanceof SchnorrSignature;
|
||||
const sig: SchnorrSignature = raw ? signature : SchnorrSignature.fromHex(signature);
|
||||
if (raw) sig.assertValidity(); // just in case
|
||||
|
||||
const { r, s } = sig;
|
||||
const m = ensureBytes(message);
|
||||
const P = normalizePublicKey(publicKey);
|
||||
const e = schnorrChallengeFinalize(taggedHash(TAGS.challenge, numTo32b(r), toRawX(P), m));
|
||||
// Finalize
|
||||
// R = s⋅G - e⋅P
|
||||
// -eP == (n-e)P
|
||||
const R = secp256k1.Point.BASE.multiplyAndAddUnsafe(
|
||||
P,
|
||||
normalizePrivateKey(s),
|
||||
mod(-e, secp256k1.CURVE.n)
|
||||
);
|
||||
if (!R || !R.hasEvenY() || R.x !== r) return false;
|
||||
return true;
|
||||
} catch (error) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export const schnorr = {
|
||||
Signature: SchnorrSignature,
|
||||
// Schnorr's pubkey is just `x` of Point (BIP340)
|
||||
getPublicKey: (privateKey: PrivKey): Uint8Array =>
|
||||
toRawX(secp256k1.Point.fromPrivateKey(privateKey)),
|
||||
sign: schnorrSign,
|
||||
verify: schnorrVerify,
|
||||
};
|
||||
269
curve-definitions/src/stark.ts
Normal file
269
curve-definitions/src/stark.ts
Normal file
@ -0,0 +1,269 @@
|
||||
/*! @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/weierstrass';
|
||||
import * as cutils from '@noble/curves/utils';
|
||||
|
||||
// Stark-friendly elliptic curve
|
||||
// https://docs.starkware.co/starkex/stark-curve.html
|
||||
|
||||
function getHash(hash: CHash) {
|
||||
return {
|
||||
hash,
|
||||
hmac: (key: Uint8Array, ...msgs: Uint8Array[]) => hmac(hash, key, concatBytes(...msgs)),
|
||||
randomBytes,
|
||||
};
|
||||
}
|
||||
|
||||
const CURVE_N = BigInt(
|
||||
'3618502788666131213697322783095070105526743751716087489154079457884512865583'
|
||||
);
|
||||
const nBitLength = 252;
|
||||
export const starkCurve = weierstrass({
|
||||
// Params: a, b
|
||||
a: BigInt(1),
|
||||
b: BigInt('3141592653589793238462643383279502884197169399375105820974944592307816406665'),
|
||||
// Field over which we'll do calculations; 2n**251n + 17n * 2n**192n + 1n
|
||||
// There is no efficient sqrt for field (P%4==1)
|
||||
P: BigInt('0x800000000000011000000000000000000000000000000000000000000000001'),
|
||||
// Curve order, total count of valid points in the field.
|
||||
n: CURVE_N,
|
||||
nBitLength: nBitLength, // len(bin(N).replace('0b',''))
|
||||
// Base point (x, y) aka generator point
|
||||
Gx: BigInt('874739451078007766457464989774322083649278607533249481151382481072868806602'),
|
||||
Gy: BigInt('152666792071518830868575557812948353041420400780739481342941381225525861407'),
|
||||
h: BigInt(1),
|
||||
// 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;
|
||||
317
curve-definitions/test/basic.test.js
Normal file
317
curve-definitions/test/basic.test.js
Normal file
@ -0,0 +1,317 @@
|
||||
import { deepStrictEqual, throws } from 'assert';
|
||||
import { should } from 'micro-should';
|
||||
import * as fc from 'fast-check';
|
||||
import * as mod from '@noble/curves/modular';
|
||||
import { randomBytes } from '@noble/hashes/utils';
|
||||
// Generic tests for all curves in package
|
||||
import { secp192r1 } from '../lib/p192.js';
|
||||
import { secp224r1 } from '../lib/p224.js';
|
||||
import { secp256r1 } from '../lib/p256.js';
|
||||
import { secp384r1 } from '../lib/p384.js';
|
||||
import { secp521r1 } from '../lib/p521.js';
|
||||
import { secp256k1 } from '../lib/secp256k1.js';
|
||||
import { ed25519, ed25519ctx, ed25519ph } from '../lib/ed25519.js';
|
||||
import { ed448, ed448ph } from '../lib/ed448.js';
|
||||
import { starkCurve } from '../lib/stark.js';
|
||||
import { pallas, vesta } from '../lib/pasta.js';
|
||||
import { bn254 } from '../lib/bn.js';
|
||||
import { jubjub } from '../lib/jubjub.js';
|
||||
|
||||
// prettier-ignore
|
||||
const CURVES = {
|
||||
secp192r1, secp224r1, secp256r1, secp384r1, secp521r1,
|
||||
secp256k1,
|
||||
ed25519, ed25519ctx, ed25519ph,
|
||||
ed448, ed448ph,
|
||||
starkCurve,
|
||||
pallas, vesta,
|
||||
bn254,
|
||||
jubjub,
|
||||
};
|
||||
|
||||
const NUM_RUNS = 5;
|
||||
const getXY = (p) => ({ x: p.x, y: p.y });
|
||||
|
||||
function equal(a, b, comment) {
|
||||
deepStrictEqual(a.equals(b), true, `eq(${comment})`);
|
||||
if (a.toAffine && b.toAffine) {
|
||||
deepStrictEqual(getXY(a.toAffine()), getXY(b.toAffine()), `eqToAffine(${comment})`);
|
||||
} else if (!a.toAffine && !b.toAffine) {
|
||||
// Already affine
|
||||
deepStrictEqual(getXY(a), getXY(b), `eqAffine(${comment})`);
|
||||
} else throw new Error('Different point types');
|
||||
}
|
||||
|
||||
for (const name in CURVES) {
|
||||
const C = CURVES[name];
|
||||
const CURVE_ORDER = C.CURVE.n;
|
||||
const FC_BIGINT = fc.bigInt(1n + 1n, CURVE_ORDER - 1n);
|
||||
|
||||
// Check that curve doesn't accept points from other curves
|
||||
const O = name === 'secp256k1' ? secp256r1 : secp256k1;
|
||||
const POINTS = {};
|
||||
const OTHER_POINTS = {};
|
||||
for (const name of ['Point', 'JacobianPoint', 'ExtendedPoint', 'ProjectivePoint']) {
|
||||
POINTS[name] = C[name];
|
||||
OTHER_POINTS[name] = O[name];
|
||||
}
|
||||
|
||||
for (const pointName in POINTS) {
|
||||
const p = POINTS[pointName];
|
||||
const o = OTHER_POINTS[pointName];
|
||||
if (!p) continue;
|
||||
|
||||
const G = [p.ZERO, p.BASE];
|
||||
for (let i = 2; i < 10; i++) G.push(G[1].multiply(i));
|
||||
// Here we check basic group laws, to verify that points works as group
|
||||
should(`${name}/${pointName}/Basic group laws (zero)`, () => {
|
||||
equal(G[0].double(), G[0], '(0*G).double() = 0');
|
||||
equal(G[0].add(G[0]), G[0], '0*G + 0*G = 0');
|
||||
equal(G[0].subtract(G[0]), G[0], '0*G - 0*G = 0');
|
||||
equal(G[0].negate(), G[0], '-0 = 0');
|
||||
for (let i = 0; i < G.length; i++) {
|
||||
const p = G[i];
|
||||
equal(p, p.add(G[0]), `${i}*G + 0 = ${i}*G`);
|
||||
equal(G[0].multiply(i + 1), G[0], `${i + 1}*0 = 0`);
|
||||
}
|
||||
});
|
||||
should(`${name}/${pointName}/Basic group laws (one)`, () => {
|
||||
equal(G[1].double(), G[2], '(1*G).double() = 2*G');
|
||||
equal(G[1].subtract(G[1]), G[0], '1*G - 1*G = 0');
|
||||
equal(G[1].add(G[1]), G[2], '1*G + 1*G = 2*G');
|
||||
});
|
||||
should(`${name}/${pointName}/Basic group laws (sanity tests)`, () => {
|
||||
equal(G[2].double(), G[4], `(2*G).double() = 4*G`);
|
||||
equal(G[2].add(G[2]), G[4], `2*G + 2*G = 4*G`);
|
||||
equal(G[7].add(G[3].negate()), G[4], `7*G - 3*G = 4*G`);
|
||||
});
|
||||
should(`${name}/${pointName}/Basic group laws (addition commutativity)`, () => {
|
||||
equal(G[4].add(G[3]), G[3].add(G[4]), `4*G + 3*G = 3*G + 4*G`);
|
||||
equal(G[4].add(G[3]), G[3].add(G[2]).add(G[2]), `4*G + 3*G = 3*G + 2*G + 2*G`);
|
||||
});
|
||||
should(`${name}/${pointName}/Basic group laws (double)`, () => {
|
||||
equal(G[3].double(), G[6], '(3*G).double() = 6*G');
|
||||
});
|
||||
should(`${name}/${pointName}/Basic group laws (multiply)`, () => {
|
||||
equal(G[2].multiply(3), G[6], '(2*G).multiply(3) = 6*G');
|
||||
});
|
||||
should(`${name}/${pointName}/Basic group laws (same point addition)`, () => {
|
||||
equal(G[3].add(G[3]), G[6], `3*G + 3*G = 6*G`);
|
||||
});
|
||||
should(`${name}/${pointName}/Basic group laws (same point (negative) addition)`, () => {
|
||||
equal(G[3].add(G[3].negate()), G[0], '3*G + (- 3*G) = 0*G');
|
||||
equal(G[3].subtract(G[3]), G[0], '3*G - 3*G = 0*G');
|
||||
});
|
||||
should(`${name}/${pointName}/Basic group laws (curve order)`, () => {
|
||||
equal(G[1].multiply(CURVE_ORDER - 1n).add(G[1]), G[0], '(N-1)*G + G = 0');
|
||||
equal(G[1].multiply(CURVE_ORDER - 1n).add(G[2]), G[1], '(N-1)*G + 2*G = 1*G');
|
||||
equal(G[1].multiply(CURVE_ORDER - 2n).add(G[2]), G[0], '(N-2)*G + 2*G = 0');
|
||||
const half = CURVE_ORDER / 2n;
|
||||
const carry = CURVE_ORDER % 2n === 1n ? G[1] : G[0];
|
||||
equal(G[1].multiply(half).double().add(carry), G[0], '((N/2) * G).double() = 0');
|
||||
});
|
||||
should(`${name}/${pointName}/Basic group laws (inversion)`, () => {
|
||||
const a = 1234n;
|
||||
const b = 5678n;
|
||||
const c = a * b;
|
||||
equal(G[1].multiply(a).multiply(b), G[1].multiply(c), 'a*b*G = c*G');
|
||||
const inv = mod.invert(b, CURVE_ORDER);
|
||||
equal(G[1].multiply(c).multiply(inv), G[1].multiply(a), 'c*G * (1/b)*G = a*G');
|
||||
});
|
||||
should(`${name}/${pointName}/Basic group laws (multiply, rand)`, () =>
|
||||
fc.assert(
|
||||
fc.property(FC_BIGINT, FC_BIGINT, (a, b) => {
|
||||
const c = mod.mod(a + b, CURVE_ORDER);
|
||||
if (c === CURVE_ORDER || c < 1n) return;
|
||||
const pA = G[1].multiply(a);
|
||||
const pB = G[1].multiply(b);
|
||||
const pC = G[1].multiply(c);
|
||||
equal(pA.add(pB), pB.add(pA), `pA + pB = pB + pA`);
|
||||
equal(pA.add(pB), pC, `pA + pB = pC`);
|
||||
}),
|
||||
{ numRuns: NUM_RUNS }
|
||||
)
|
||||
);
|
||||
should(`${name}/${pointName}/Basic group laws (multiply2, rand)`, () =>
|
||||
fc.assert(
|
||||
fc.property(FC_BIGINT, FC_BIGINT, (a, b) => {
|
||||
const c = mod.mod(a * b, CURVE_ORDER);
|
||||
const pA = G[1].multiply(a);
|
||||
const pB = G[1].multiply(b);
|
||||
equal(pA.multiply(b), pB.multiply(a), `b*pA = a*pB`);
|
||||
equal(pA.multiply(b), G[1].multiply(c), `b*pA = c*G`);
|
||||
}),
|
||||
{ numRuns: NUM_RUNS }
|
||||
)
|
||||
);
|
||||
|
||||
for (const op of ['add', 'subtract']) {
|
||||
should(`${name}/${pointName}/${op} type check`, () => {
|
||||
throws(() => G[1][op](0), '0');
|
||||
throws(() => G[1][op](0n), '0n');
|
||||
G[1][op](G[2]);
|
||||
throws(() => G[1][op](CURVE_ORDER), 'CURVE_ORDER');
|
||||
throws(() => G[1][op](123.456), '123.456');
|
||||
throws(() => G[1][op](true), 'true');
|
||||
throws(() => G[1][op]('1'), "'1'");
|
||||
throws(() => G[1][op]({ x: 1n, y: 1n, z: 1n, t: 1n }), '{ x: 1n, y: 1n, z: 1n, t: 1n }');
|
||||
throws(() => G[1][op](new Uint8Array([])), 'ui8a([])');
|
||||
throws(() => G[1][op](new Uint8Array([0])), 'ui8a([0])');
|
||||
throws(() => G[1][op](new Uint8Array([1])), 'ui8a([1])');
|
||||
throws(() => G[1][op](new Uint8Array(4096).fill(1)), 'ui8a(4096*[1])');
|
||||
if (G[1].toAffine) throws(() => G[1][op](C.Point.BASE), `Point ${op} ${pointName}`);
|
||||
throws(() => G[1][op](o.BASE), `${op}/other curve point`);
|
||||
});
|
||||
}
|
||||
|
||||
should(`${name}/${pointName}/equals type check`, () => {
|
||||
throws(() => G[1].equals(0), '0');
|
||||
throws(() => G[1].equals(0n), '0n');
|
||||
deepStrictEqual(G[1].equals(G[2]), false, '1*G != 2*G');
|
||||
deepStrictEqual(G[1].equals(G[1]), true, '1*G == 1*G');
|
||||
deepStrictEqual(G[2].equals(G[2]), true, '2*G == 2*G');
|
||||
throws(() => G[1].equals(CURVE_ORDER), 'CURVE_ORDER');
|
||||
throws(() => G[1].equals(123.456), '123.456');
|
||||
throws(() => G[1].equals(true), 'true');
|
||||
throws(() => G[1].equals('1'), "'1'");
|
||||
throws(() => G[1].equals({ x: 1n, y: 1n, z: 1n, t: 1n }), '{ x: 1n, y: 1n, z: 1n, t: 1n }');
|
||||
throws(() => G[1].equals(new Uint8Array([])), 'ui8a([])');
|
||||
throws(() => G[1].equals(new Uint8Array([0])), 'ui8a([0])');
|
||||
throws(() => G[1].equals(new Uint8Array([1])), 'ui8a([1])');
|
||||
throws(() => G[1].equals(new Uint8Array(4096).fill(1)), 'ui8a(4096*[1])');
|
||||
if (G[1].toAffine) throws(() => G[1].equals(C.Point.BASE), `Point.equals(${pointName})`);
|
||||
throws(() => G[1].equals(o.BASE), 'other curve point');
|
||||
});
|
||||
|
||||
for (const op of ['multiply', 'multiplyUnsafe']) {
|
||||
if (!p.BASE[op]) continue;
|
||||
should(`${name}/${pointName}/${op} type check`, () => {
|
||||
if (op !== 'multiplyUnsafe') {
|
||||
throws(() => G[1][op](0), '0');
|
||||
throws(() => G[1][op](0n), '0n');
|
||||
}
|
||||
G[1][op](1n);
|
||||
G[1][op](CURVE_ORDER - 1n);
|
||||
throws(() => G[1][op](G[2]), 'G[2]');
|
||||
throws(() => G[1][op](CURVE_ORDER), 'CURVE_ORDER');
|
||||
throws(() => G[1][op](CURVE_ORDER + 1n), 'CURVE_ORDER+1');
|
||||
throws(() => G[1][op](123.456), '123.456');
|
||||
throws(() => G[1][op](true), 'true');
|
||||
throws(() => G[1][op]('1'), '1');
|
||||
throws(() => G[1][op](new Uint8Array([])), 'ui8a([])');
|
||||
throws(() => G[1][op](new Uint8Array([0])), 'ui8a([0])');
|
||||
throws(() => G[1][op](new Uint8Array([1])), 'ui8a([1])');
|
||||
throws(() => G[1][op](new Uint8Array(4096).fill(1)), 'ui8a(4096*[1])');
|
||||
throws(() => G[1][op](o.BASE), 'other curve point');
|
||||
});
|
||||
}
|
||||
// Complex point (Extended/Jacobian/Projective?)
|
||||
if (p.BASE.toAffine) {
|
||||
should(`${name}/${pointName}/toAffine()`, () => {
|
||||
equal(p.ZERO.toAffine(), C.Point.ZERO, `0 = 0`);
|
||||
equal(p.BASE.toAffine(), C.Point.BASE, `1 = 1`);
|
||||
});
|
||||
}
|
||||
if (p.fromAffine) {
|
||||
should(`${name}/${pointName}/fromAffine()`, () => {
|
||||
equal(p.ZERO, p.fromAffine(C.Point.ZERO), `0 = 0`);
|
||||
equal(p.BASE, p.fromAffine(C.Point.BASE), `1 = 1`);
|
||||
});
|
||||
}
|
||||
// toHex/fromHex (if available)
|
||||
if (p.fromHex && p.BASE.toHex) {
|
||||
should(`${name}/${pointName}/fromHex(toHex()) roundtrip`, () => {
|
||||
fc.assert(
|
||||
fc.property(FC_BIGINT, (x) => {
|
||||
const hex = p.BASE.multiply(x).toHex();
|
||||
deepStrictEqual(p.fromHex(hex).toHex(), hex);
|
||||
})
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
// Generic complex things (getPublicKey/sign/verify/getSharedSecret)
|
||||
should(`${name}/getPublicKey type check`, () => {
|
||||
throws(() => C.getPublicKey(0), '0');
|
||||
throws(() => C.getPublicKey(0n), '0n');
|
||||
throws(() => C.getPublicKey(false), 'false');
|
||||
throws(() => C.getPublicKey(123.456), '123.456');
|
||||
throws(() => C.getPublicKey(true), 'true');
|
||||
throws(() => C.getPublicKey(''), "''");
|
||||
// NOTE: passes because of disabled hex padding checks for starknet, maybe enable?
|
||||
//throws(() => C.getPublicKey('1'), "'1'");
|
||||
throws(() => C.getPublicKey('key'), "'key'");
|
||||
throws(() => C.getPublicKey(new Uint8Array([])));
|
||||
throws(() => C.getPublicKey(new Uint8Array([0])));
|
||||
throws(() => C.getPublicKey(new Uint8Array([1])));
|
||||
throws(() => C.getPublicKey(new Uint8Array(4096).fill(1)));
|
||||
});
|
||||
should(`${name}.verify()/should verify random signatures`, () =>
|
||||
fc.assert(
|
||||
fc.property(fc.hexaString({ minLength: 64, maxLength: 64 }), (msg) => {
|
||||
const priv = C.utils.randomPrivateKey();
|
||||
const pub = C.getPublicKey(priv);
|
||||
const sig = C.sign(msg, priv);
|
||||
deepStrictEqual(C.verify(sig, msg, pub), true);
|
||||
}),
|
||||
{ numRuns: NUM_RUNS }
|
||||
)
|
||||
);
|
||||
should(`${name}.sign()/edge cases`, () => {
|
||||
throws(() => C.sign());
|
||||
throws(() => C.sign(''));
|
||||
});
|
||||
|
||||
should(`${name}.verify()/should not verify signature with wrong hash`, () => {
|
||||
const MSG = '01'.repeat(32);
|
||||
const PRIV_KEY = 0x2n;
|
||||
const WRONG_MSG = '11'.repeat(32);
|
||||
const signature = C.sign(MSG, PRIV_KEY);
|
||||
const publicKey = C.getPublicKey(PRIV_KEY);
|
||||
deepStrictEqual(C.verify(signature, WRONG_MSG, publicKey), false);
|
||||
});
|
||||
// NOTE: fails for ed, because of empty message. Since we convert it to scalar,
|
||||
// need to check what other implementations do. Empty message != new Uint8Array([0]), but what scalar should be in that case?
|
||||
// should(`${name}/should not verify signature with wrong message`, () => {
|
||||
// fc.assert(
|
||||
// fc.property(
|
||||
// fc.array(fc.integer({ min: 0x00, max: 0xff })),
|
||||
// fc.array(fc.integer({ min: 0x00, max: 0xff })),
|
||||
// (bytes, wrongBytes) => {
|
||||
// const privKey = C.utils.randomPrivateKey();
|
||||
// const message = new Uint8Array(bytes);
|
||||
// const wrongMessage = new Uint8Array(wrongBytes);
|
||||
// const publicKey = C.getPublicKey(privKey);
|
||||
// const signature = C.sign(message, privKey);
|
||||
// deepStrictEqual(
|
||||
// C.verify(signature, wrongMessage, publicKey),
|
||||
// bytes.toString() === wrongBytes.toString()
|
||||
// );
|
||||
// }
|
||||
// ),
|
||||
// { numRuns: NUM_RUNS }
|
||||
// );
|
||||
// });
|
||||
|
||||
if (C.getSharedSecret) {
|
||||
should(`${name}/getSharedSecret() should be commutative`, () => {
|
||||
for (let i = 0; i < NUM_RUNS; i++) {
|
||||
const asec = C.utils.randomPrivateKey();
|
||||
const apub = C.getPublicKey(asec);
|
||||
const bsec = C.utils.randomPrivateKey();
|
||||
const bpub = C.getPublicKey(bsec);
|
||||
try {
|
||||
deepStrictEqual(C.getSharedSecret(asec, bpub), C.getSharedSecret(bsec, apub));
|
||||
} catch (error) {
|
||||
console.error('not commutative', { asec, apub, bsec, bpub });
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
// ESM is broken.
|
||||
import url from 'url';
|
||||
if (import.meta.url === url.pathToFileURL(process.argv[1]).href) {
|
||||
should.run();
|
||||
}
|
||||
657
curve-definitions/test/ed25519.test.js
Normal file
657
curve-definitions/test/ed25519.test.js
Normal file
@ -0,0 +1,657 @@
|
||||
import { deepStrictEqual, throws } from 'assert';
|
||||
import { should } from 'micro-should';
|
||||
import * as fc from 'fast-check';
|
||||
import { ed25519, ed25519ctx, ed25519ph, x25519, RistrettoPoint } from '../lib/ed25519.js';
|
||||
import { readFileSync } from 'fs';
|
||||
import { default as zip215 } from './ed25519/zip215.json' assert { type: 'json' };
|
||||
import { hexToBytes, bytesToHex, randomBytes } from '@noble/hashes/utils';
|
||||
import { numberToBytesLE } from '@noble/curves/utils';
|
||||
import { sha512 } from '@noble/hashes/sha512';
|
||||
import { default as ed25519vectors } from './wycheproof/eddsa_test.json' assert { type: 'json' };
|
||||
import { default as x25519vectors } from './wycheproof/x25519_test.json' assert { type: 'json' };
|
||||
|
||||
const ed = ed25519;
|
||||
const hex = bytesToHex;
|
||||
|
||||
function to32Bytes(numOrStr) {
|
||||
let hex = typeof numOrStr === 'string' ? numOrStr : numOrStr.toString(16);
|
||||
return hexToBytes(hex.padStart(64, '0'));
|
||||
}
|
||||
|
||||
function utf8ToBytes(str) {
|
||||
if (typeof str !== 'string') {
|
||||
throw new TypeError(`utf8ToBytes expected string, got ${typeof str}`);
|
||||
}
|
||||
return new TextEncoder().encode(str);
|
||||
}
|
||||
|
||||
ed.utils.precompute(8);
|
||||
|
||||
should('ed25519/should not accept >32byte private keys', () => {
|
||||
const invalidPriv =
|
||||
100000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000090000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800073278156000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000n;
|
||||
throws(() => ed.getPublicKey(invalidPriv));
|
||||
});
|
||||
should('ed25519/should verify recent signature', () => {
|
||||
fc.assert(
|
||||
fc.property(
|
||||
fc.hexaString({ minLength: 2, maxLength: 32 }),
|
||||
fc.bigInt(2n, ed.CURVE.n),
|
||||
(message, privateKey) => {
|
||||
const publicKey = ed.getPublicKey(to32Bytes(privateKey));
|
||||
const signature = ed.sign(to32Bytes(message), to32Bytes(privateKey));
|
||||
deepStrictEqual(publicKey.length, 32);
|
||||
deepStrictEqual(signature.length, 64);
|
||||
deepStrictEqual(ed.verify(signature, to32Bytes(message), publicKey), true);
|
||||
}
|
||||
),
|
||||
{ numRuns: 5 }
|
||||
);
|
||||
});
|
||||
should('ed25519/should not verify signature with wrong message', () => {
|
||||
fc.assert(
|
||||
fc.property(
|
||||
fc.array(fc.integer({ min: 0x00, max: 0xff })),
|
||||
fc.array(fc.integer({ min: 0x00, max: 0xff })),
|
||||
fc.bigInt(1n, ed.CURVE.n),
|
||||
(bytes, wrongBytes, privateKey) => {
|
||||
const privKey = to32Bytes(privateKey);
|
||||
const message = new Uint8Array(bytes);
|
||||
const wrongMessage = new Uint8Array(wrongBytes);
|
||||
const publicKey = ed.getPublicKey(privKey);
|
||||
const signature = ed.sign(message, privKey);
|
||||
deepStrictEqual(
|
||||
ed.verify(signature, wrongMessage, publicKey),
|
||||
bytes.toString() === wrongBytes.toString()
|
||||
);
|
||||
}
|
||||
),
|
||||
{ numRuns: 5 }
|
||||
);
|
||||
});
|
||||
const privKey = to32Bytes('a665a45920422f9d417e4867ef');
|
||||
const msg = hexToBytes('874f9960c5d2b7a9b5fad383e1ba44719ebb743a');
|
||||
const wrongMsg = hexToBytes('589d8c7f1da0a24bc07b7381ad48b1cfc211af1c');
|
||||
should('ed25519/basic methods/should sign and verify', () => {
|
||||
const publicKey = ed.getPublicKey(privKey);
|
||||
const signature = ed.sign(msg, privKey);
|
||||
deepStrictEqual(ed.verify(signature, msg, publicKey), true);
|
||||
});
|
||||
should('ed25519/basic methods/should not verify signature with wrong public key', () => {
|
||||
const publicKey = ed.getPublicKey(12);
|
||||
const signature = ed.sign(msg, privKey);
|
||||
deepStrictEqual(ed.verify(signature, msg, publicKey), false);
|
||||
});
|
||||
should('ed25519/basic methods/should not verify signature with wrong hash', () => {
|
||||
const publicKey = ed.getPublicKey(privKey);
|
||||
const signature = ed.sign(msg, privKey);
|
||||
deepStrictEqual(ed.verify(signature, wrongMsg, publicKey), false);
|
||||
});
|
||||
|
||||
should('ed25519/sync methods/should sign and verify', () => {
|
||||
const publicKey = ed.getPublicKey(privKey);
|
||||
const signature = ed.sign(msg, privKey);
|
||||
deepStrictEqual(ed.verify(signature, msg, publicKey), true);
|
||||
});
|
||||
should('ed25519/sync methods/should not verify signature with wrong public key', () => {
|
||||
const publicKey = ed.getPublicKey(12);
|
||||
const signature = ed.sign(msg, privKey);
|
||||
deepStrictEqual(ed.verify(signature, msg, publicKey), false);
|
||||
});
|
||||
should('ed25519/sync methods/should not verify signature with wrong hash', () => {
|
||||
const publicKey = ed.getPublicKey(privKey);
|
||||
const signature = ed.sign(msg, privKey);
|
||||
deepStrictEqual(ed.verify(signature, wrongMsg, publicKey), false);
|
||||
});
|
||||
|
||||
// https://xmr.llcoins.net/addresstests.html
|
||||
should(
|
||||
'ed25519/BASE_POINT.multiply()/should create right publicKey without SHA-512 hashing TEST 1',
|
||||
() => {
|
||||
const publicKey =
|
||||
ed.Point.BASE.multiply(0x90af56259a4b6bfbc4337980d5d75fbe3c074630368ff3804d33028e5dbfa77n);
|
||||
deepStrictEqual(
|
||||
publicKey.toHex(),
|
||||
'0f3b913371411b27e646b537e888f685bf929ea7aab93c950ed84433f064480d'
|
||||
);
|
||||
}
|
||||
);
|
||||
should(
|
||||
'ed25519/BASE_POINT.multiply()/should create right publicKey without SHA-512 hashing TEST 2',
|
||||
() => {
|
||||
const publicKey =
|
||||
ed.Point.BASE.multiply(0x364e8711a60780382a5d57b061c126f039940f28a9e91fe039d4d3094d8b88n);
|
||||
deepStrictEqual(
|
||||
publicKey.toHex(),
|
||||
'ad545340b58610f0cd62f17d55af1ab11ecde9c084d5476865ddb4dbda015349'
|
||||
);
|
||||
}
|
||||
);
|
||||
should(
|
||||
'ed25519/BASE_POINT.multiply()/should create right publicKey without SHA-512 hashing TEST 3',
|
||||
() => {
|
||||
const publicKey =
|
||||
ed.Point.BASE.multiply(0xb9bf90ff3abec042752cac3a07a62f0c16cfb9d32a3fc2305d676ec2d86e941n);
|
||||
deepStrictEqual(
|
||||
publicKey.toHex(),
|
||||
'e097c4415fe85724d522b2e449e8fd78dd40d20097bdc9ae36fe8ec6fe12cb8c'
|
||||
);
|
||||
}
|
||||
);
|
||||
should(
|
||||
'ed25519/BASE_POINT.multiply()/should create right publicKey without SHA-512 hashing TEST 4',
|
||||
() => {
|
||||
const publicKey =
|
||||
ed.Point.BASE.multiply(0x69d896f02d79524c9878e080308180e2859d07f9f54454e0800e8db0847a46en);
|
||||
deepStrictEqual(
|
||||
publicKey.toHex(),
|
||||
'f12cb7c43b59971395926f278ce7c2eaded9444fbce62ca717564cb508a0db1d'
|
||||
);
|
||||
}
|
||||
);
|
||||
should('ed25519/BASE_POINT.multiply()/should throw Point#multiply on TEST 5', () => {
|
||||
for (const num of [0n, 0, -1n, -1, 1.1]) {
|
||||
throws(() => ed.Point.BASE.multiply(num));
|
||||
}
|
||||
});
|
||||
|
||||
// https://ed25519.cr.yp.to/python/sign.py
|
||||
// https://ed25519.cr.yp.to/python/sign.input
|
||||
const data = readFileSync('./test/ed25519/vectors.txt', 'utf-8');
|
||||
const vectors = data
|
||||
.trim()
|
||||
.split('\n')
|
||||
.map((line) => line.split(':'));
|
||||
should('ed25519 official vectors/should match 1024 official vectors', () => {
|
||||
for (let i = 0; i < vectors.length; i++) {
|
||||
const vector = vectors[i];
|
||||
// Extract.
|
||||
const priv = vector[0].slice(0, 64);
|
||||
const expectedPub = vector[1];
|
||||
const msg = vector[2];
|
||||
const expectedSignature = vector[3].slice(0, 128);
|
||||
|
||||
// Calculate
|
||||
const pub = ed.getPublicKey(to32Bytes(priv));
|
||||
deepStrictEqual(hex(pub), expectedPub);
|
||||
deepStrictEqual(pub, ed.Point.fromHex(pub).toRawBytes());
|
||||
|
||||
const signature = hex(ed.sign(msg, priv));
|
||||
// console.log('vector', i);
|
||||
// expect(pub).toBe(expectedPub);
|
||||
deepStrictEqual(signature, expectedSignature);
|
||||
}
|
||||
});
|
||||
|
||||
// https://tools.ietf.org/html/rfc8032#section-7
|
||||
should('rfc8032 vectors/should create right signature for 0x9d and empty string', () => {
|
||||
const privateKey = '9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60';
|
||||
const publicKey = ed.getPublicKey(privateKey);
|
||||
const message = '';
|
||||
const signature = ed.sign(message, privateKey);
|
||||
deepStrictEqual(
|
||||
hex(publicKey),
|
||||
'd75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a'
|
||||
);
|
||||
deepStrictEqual(
|
||||
hex(signature),
|
||||
'e5564300c360ac729086e2cc806e828a84877f1eb8e5d974d873e065224901555fb8821590a33bacc61e39701cf9b46bd25bf5f0595bbe24655141438e7a100b'
|
||||
);
|
||||
});
|
||||
should('rfc8032 vectors/should create right signature for 0x4c and 72', () => {
|
||||
const privateKey = '4ccd089b28ff96da9db6c346ec114e0f5b8a319f35aba624da8cf6ed4fb8a6fb';
|
||||
const publicKey = ed.getPublicKey(privateKey);
|
||||
const message = '72';
|
||||
const signature = ed.sign(message, privateKey);
|
||||
deepStrictEqual(
|
||||
hex(publicKey),
|
||||
'3d4017c3e843895a92b70aa74d1b7ebc9c982ccf2ec4968cc0cd55f12af4660c'
|
||||
);
|
||||
deepStrictEqual(
|
||||
hex(signature),
|
||||
'92a009a9f0d4cab8720e820b5f642540a2b27b5416503f8fb3762223ebdb69da085ac1e43e15996e458f3613d0f11d8c387b2eaeb4302aeeb00d291612bb0c00'
|
||||
);
|
||||
});
|
||||
should('rfc8032 vectors/should create right signature for 0x00 and 5a', () => {
|
||||
const privateKey = '002fdd1f7641793ab064bb7aa848f762e7ec6e332ffc26eeacda141ae33b1783';
|
||||
const publicKey = ed.getPublicKey(privateKey);
|
||||
const message =
|
||||
'5ac1dfc324f43e6cb79a87ab0470fa857b51fb944982e19074ca44b1e40082c1d07b92efa7ea55ad42b7c027e0b9e33756d95a2c1796a7c2066811dc41858377d4b835c1688d638884cd2ad8970b74c1a54aadd27064163928a77988b24403aa85af82ceab6b728e554761af7175aeb99215b7421e4474c04d213e01ff03e3529b11077cdf28964b8c49c5649e3a46fa0a09dcd59dcad58b9b922a83210acd5e65065531400234f5e40cddcf9804968e3e9ac6f5c44af65001e158067fc3a660502d13fa8874fa93332138d9606bc41b4cee7edc39d753dae12a873941bb357f7e92a4498847d6605456cb8c0b425a47d7d3ca37e54e903a41e6450a35ebe5237c6f0c1bbbc1fd71fb7cd893d189850295c199b7d88af26bc8548975fda1099ffefee42a52f3428ddff35e0173d3339562507ac5d2c45bbd2c19cfe89b';
|
||||
const signature = ed.sign(message, privateKey);
|
||||
deepStrictEqual(
|
||||
hex(publicKey),
|
||||
'77d1d8ebacd13f4e2f8a40e28c4a63bc9ce3bfb69716334bcb28a33eb134086c'
|
||||
);
|
||||
deepStrictEqual(
|
||||
hex(signature),
|
||||
'0df3aa0d0999ad3dc580378f52d152700d5b3b057f56a66f92112e441e1cb9123c66f18712c87efe22d2573777296241216904d7cdd7d5ea433928bd2872fa0c'
|
||||
);
|
||||
});
|
||||
should('rfc8032 vectors/should create right signature for 0xf5 and long msg', () => {
|
||||
const privateKey = 'f5e5767cf153319517630f226876b86c8160cc583bc013744c6bf255f5cc0ee5';
|
||||
const publicKey = ed.getPublicKey(privateKey);
|
||||
const message =
|
||||
'08b8b2b733424243760fe426a4b54908632110a66c2f6591eabd3345e3e4eb98fa6e264bf09efe12ee50f8f54e9f77b1e355f6c50544e23fb1433ddf73be84d879de7c0046dc4996d9e773f4bc9efe5738829adb26c81b37c93a1b270b20329d658675fc6ea534e0810a4432826bf58c941efb65d57a338bbd2e26640f89ffbc1a858efcb8550ee3a5e1998bd177e93a7363c344fe6b199ee5d02e82d522c4feba15452f80288a821a579116ec6dad2b3b310da903401aa62100ab5d1a36553e06203b33890cc9b832f79ef80560ccb9a39ce767967ed628c6ad573cb116dbefefd75499da96bd68a8a97b928a8bbc103b6621fcde2beca1231d206be6cd9ec7aff6f6c94fcd7204ed3455c68c83f4a41da4af2b74ef5c53f1d8ac70bdcb7ed185ce81bd84359d44254d95629e9855a94a7c1958d1f8ada5d0532ed8a5aa3fb2d17ba70eb6248e594e1a2297acbbb39d502f1a8c6eb6f1ce22b3de1a1f40cc24554119a831a9aad6079cad88425de6bde1a9187ebb6092cf67bf2b13fd65f27088d78b7e883c8759d2c4f5c65adb7553878ad575f9fad878e80a0c9ba63bcbcc2732e69485bbc9c90bfbd62481d9089beccf80cfe2df16a2cf65bd92dd597b0707e0917af48bbb75fed413d238f5555a7a569d80c3414a8d0859dc65a46128bab27af87a71314f318c782b23ebfe808b82b0ce26401d2e22f04d83d1255dc51addd3b75a2b1ae0784504df543af8969be3ea7082ff7fc9888c144da2af58429ec96031dbcad3dad9af0dcbaaaf268cb8fcffead94f3c7ca495e056a9b47acdb751fb73e666c6c655ade8297297d07ad1ba5e43f1bca32301651339e22904cc8c42f58c30c04aafdb038dda0847dd988dcda6f3bfd15c4b4c4525004aa06eeff8ca61783aacec57fb3d1f92b0fe2fd1a85f6724517b65e614ad6808d6f6ee34dff7310fdc82aebfd904b01e1dc54b2927094b2db68d6f903b68401adebf5a7e08d78ff4ef5d63653a65040cf9bfd4aca7984a74d37145986780fc0b16ac451649de6188a7dbdf191f64b5fc5e2ab47b57f7f7276cd419c17a3ca8e1b939ae49e488acba6b965610b5480109c8b17b80e1b7b750dfc7598d5d5011fd2dcc5600a32ef5b52a1ecc820e308aa342721aac0943bf6686b64b2579376504ccc493d97e6aed3fb0f9cd71a43dd497f01f17c0e2cb3797aa2a2f256656168e6c496afc5fb93246f6b1116398a346f1a641f3b041e989f7914f90cc2c7fff357876e506b50d334ba77c225bc307ba537152f3f1610e4eafe595f6d9d90d11faa933a15ef1369546868a7f3a45a96768d40fd9d03412c091c6315cf4fde7cb68606937380db2eaaa707b4c4185c32eddcdd306705e4dc1ffc872eeee475a64dfac86aba41c0618983f8741c5ef68d3a101e8a3b8cac60c905c15fc910840b94c00a0b9d0';
|
||||
const signature = ed.sign(message, privateKey);
|
||||
deepStrictEqual(
|
||||
hex(publicKey),
|
||||
'278117fc144c72340f67d0f2316e8386ceffbf2b2428c9c51fef7c597f1d426e'
|
||||
);
|
||||
deepStrictEqual(
|
||||
hex(signature),
|
||||
'0aab4c900501b3e24d7cdf4663326a3a87df5e4843b2cbdb67cbf6e460fec350aa5371b1508f9f4528ecea23c436d94b5e8fcd4f681e30a6ac00a9704a188a03'
|
||||
);
|
||||
});
|
||||
|
||||
// const PRIVATE_KEY = 0xa665a45920422f9d417e4867efn;
|
||||
// const MESSAGE = ripemd160(new Uint8Array([97, 98, 99, 100, 101, 102, 103]));
|
||||
// prettier-ignore
|
||||
// const MESSAGE = new Uint8Array([
|
||||
// 135, 79, 153, 96, 197, 210, 183, 169, 181, 250, 211, 131, 225, 186, 68, 113, 158, 187, 116, 58,
|
||||
// ]);
|
||||
// const WRONG_MESSAGE = ripemd160(new Uint8Array([98, 99, 100, 101, 102, 103]));
|
||||
// prettier-ignore
|
||||
// const WRONG_MESSAGE = new Uint8Array([
|
||||
// 88, 157, 140, 127, 29, 160, 162, 75, 192, 123, 115, 129, 173, 72, 177, 207, 194, 17, 175, 28,
|
||||
// ]);
|
||||
// // it("should verify just signed message", async () => {
|
||||
// // await fc.assert(fc.asyncProperty(
|
||||
// // fc.hexa(),
|
||||
// // fc.bigInt(2n, ristretto25519.PRIME_ORDER),
|
||||
// // async (message, privateKey) => {
|
||||
// // const publicKey = await ristretto25519.getPublicKey(privateKey);
|
||||
// // const signature = await ristretto25519.sign(message, privateKey);
|
||||
// // expect(publicKey.length).toBe(32);
|
||||
// // expect(signature.length).toBe(64);
|
||||
// // expect(await ristretto25519.verify(signature, message, publicKey)).toBe(true);
|
||||
// // }),
|
||||
// // { numRuns: 1 }
|
||||
// // );
|
||||
// // });
|
||||
// // it("should not verify sign with wrong message", async () => {
|
||||
// // await fc.assert(fc.asyncProperty(
|
||||
// // fc.array(fc.integer(0x00, 0xff)),
|
||||
// // fc.array(fc.integer(0x00, 0xff)),
|
||||
// // fc.bigInt(2n, ristretto25519.PRIME_ORDER),
|
||||
// // async (bytes, wrongBytes, privateKey) => {
|
||||
// // const message = new Uint8Array(bytes);
|
||||
// // const wrongMessage = new Uint8Array(wrongBytes);
|
||||
// // const publicKey = await ristretto25519.getPublicKey(privateKey);
|
||||
// // const signature = await ristretto25519.sign(message, privateKey);
|
||||
// // expect(await ristretto25519.verify(signature, wrongMessage, publicKey)).toBe(
|
||||
// // bytes.toString() === wrongBytes.toString()
|
||||
// // );
|
||||
// // }),
|
||||
// // { numRuns: 1 }
|
||||
// // );
|
||||
// // });
|
||||
// // it("should sign and verify", async () => {
|
||||
// // const publicKey = await ristretto25519.getPublicKey(PRIVATE_KEY);
|
||||
// // const signature = await ristretto25519.sign(MESSAGE, PRIVATE_KEY);
|
||||
// // expect(await ristretto25519.verify(signature, MESSAGE, publicKey)).toBe(true);
|
||||
// // });
|
||||
// // it("should not verify signature with wrong public key", async () => {
|
||||
// // const publicKey = await ristretto25519.getPublicKey(12);
|
||||
// // const signature = await ristretto25519.sign(MESSAGE, PRIVATE_KEY);
|
||||
// // expect(await ristretto25519.verify(signature, MESSAGE, publicKey)).toBe(false);
|
||||
// // });
|
||||
// // it("should not verify signature with wrong hash", async () => {
|
||||
// // const publicKey = await ristretto25519.getPublicKey(PRIVATE_KEY);
|
||||
// // const signature = await ristretto25519.sign(MESSAGE, PRIVATE_KEY);
|
||||
// // expect(await ristretto25519.verify(signature, WRONG_MESSAGE, publicKey)).toBe(false);
|
||||
// // });
|
||||
should('ristretto255/should follow the byte encodings of small multiples', () => {
|
||||
const encodingsOfSmallMultiples = [
|
||||
// This is the identity point
|
||||
'0000000000000000000000000000000000000000000000000000000000000000',
|
||||
// This is the basepoint
|
||||
'e2f2ae0a6abc4e71a884a961c500515f58e30b6aa582dd8db6a65945e08d2d76',
|
||||
// These are small multiples of the basepoint
|
||||
'6a493210f7499cd17fecb510ae0cea23a110e8d5b901f8acadd3095c73a3b919',
|
||||
'94741f5d5d52755ece4f23f044ee27d5d1ea1e2bd196b462166b16152a9d0259',
|
||||
'da80862773358b466ffadfe0b3293ab3d9fd53c5ea6c955358f568322daf6a57',
|
||||
'e882b131016b52c1d3337080187cf768423efccbb517bb495ab812c4160ff44e',
|
||||
'f64746d3c92b13050ed8d80236a7f0007c3b3f962f5ba793d19a601ebb1df403',
|
||||
'44f53520926ec81fbd5a387845beb7df85a96a24ece18738bdcfa6a7822a176d',
|
||||
'903293d8f2287ebe10e2374dc1a53e0bc887e592699f02d077d5263cdd55601c',
|
||||
'02622ace8f7303a31cafc63f8fc48fdc16e1c8c8d234b2f0d6685282a9076031',
|
||||
'20706fd788b2720a1ed2a5dad4952b01f413bcf0e7564de8cdc816689e2db95f',
|
||||
'bce83f8ba5dd2fa572864c24ba1810f9522bc6004afe95877ac73241cafdab42',
|
||||
'e4549ee16b9aa03099ca208c67adafcafa4c3f3e4e5303de6026e3ca8ff84460',
|
||||
'aa52e000df2e16f55fb1032fc33bc42742dad6bd5a8fc0be0167436c5948501f',
|
||||
'46376b80f409b29dc2b5f6f0c52591990896e5716f41477cd30085ab7f10301e',
|
||||
'e0c418f7c8d9c4cdd7395b93ea124f3ad99021bb681dfc3302a9d99a2e53e64e',
|
||||
];
|
||||
let B = RistrettoPoint.BASE;
|
||||
let P = RistrettoPoint.ZERO;
|
||||
for (const encoded of encodingsOfSmallMultiples) {
|
||||
deepStrictEqual(P.toHex(), encoded);
|
||||
deepStrictEqual(RistrettoPoint.fromHex(encoded).toHex(), encoded);
|
||||
P = P.add(B);
|
||||
}
|
||||
});
|
||||
should('ristretto255/should not convert bad bytes encoding', () => {
|
||||
const badEncodings = [
|
||||
// These are all bad because they're non-canonical field encodings.
|
||||
'00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff',
|
||||
'ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f',
|
||||
'f3ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f',
|
||||
'edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f',
|
||||
// These are all bad because they're negative field elements.
|
||||
'0100000000000000000000000000000000000000000000000000000000000000',
|
||||
'01ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f',
|
||||
'ed57ffd8c914fb201471d1c3d245ce3c746fcbe63a3679d51b6a516ebebe0e20',
|
||||
'c34c4e1826e5d403b78e246e88aa051c36ccf0aafebffe137d148a2bf9104562',
|
||||
'c940e5a4404157cfb1628b108db051a8d439e1a421394ec4ebccb9ec92a8ac78',
|
||||
'47cfc5497c53dc8e61c91d17fd626ffb1c49e2bca94eed052281b510b1117a24',
|
||||
'f1c6165d33367351b0da8f6e4511010c68174a03b6581212c71c0e1d026c3c72',
|
||||
'87260f7a2f12495118360f02c26a470f450dadf34a413d21042b43b9d93e1309',
|
||||
// These are all bad because they give a nonsquare x^2.
|
||||
'26948d35ca62e643e26a83177332e6b6afeb9d08e4268b650f1f5bbd8d81d371',
|
||||
'4eac077a713c57b4f4397629a4145982c661f48044dd3f96427d40b147d9742f',
|
||||
'de6a7b00deadc788eb6b6c8d20c0ae96c2f2019078fa604fee5b87d6e989ad7b',
|
||||
'bcab477be20861e01e4a0e295284146a510150d9817763caf1a6f4b422d67042',
|
||||
'2a292df7e32cababbd9de088d1d1abec9fc0440f637ed2fba145094dc14bea08',
|
||||
'f4a9e534fc0d216c44b218fa0c42d99635a0127ee2e53c712f70609649fdff22',
|
||||
'8268436f8c4126196cf64b3c7ddbda90746a378625f9813dd9b8457077256731',
|
||||
'2810e5cbc2cc4d4eece54f61c6f69758e289aa7ab440b3cbeaa21995c2f4232b',
|
||||
// These are all bad because they give a negative xy value.
|
||||
'3eb858e78f5a7254d8c9731174a94f76755fd3941c0ac93735c07ba14579630e',
|
||||
'a45fdc55c76448c049a1ab33f17023edfb2be3581e9c7aade8a6125215e04220',
|
||||
'd483fe813c6ba647ebbfd3ec41adca1c6130c2beeee9d9bf065c8d151c5f396e',
|
||||
'8a2e1d30050198c65a54483123960ccc38aef6848e1ec8f5f780e8523769ba32',
|
||||
'32888462f8b486c68ad7dd9610be5192bbeaf3b443951ac1a8118419d9fa097b',
|
||||
'227142501b9d4355ccba290404bde41575b037693cef1f438c47f8fbf35d1165',
|
||||
'5c37cc491da847cfeb9281d407efc41e15144c876e0170b499a96a22ed31e01e',
|
||||
'445425117cb8c90edcbc7c1cc0e74f747f2c1efa5630a967c64f287792a48a4b',
|
||||
// This is s = -1, which causes y = 0.
|
||||
'ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f',
|
||||
];
|
||||
for (const badBytes of badEncodings) {
|
||||
const b = hexToBytes(badBytes);
|
||||
throws(() => RistrettoPoint.fromHex(b), badBytes);
|
||||
}
|
||||
});
|
||||
should('ristretto255/should create right points from uniform hash', async () => {
|
||||
const labels = [
|
||||
'Ristretto is traditionally a short shot of espresso coffee',
|
||||
'made with the normal amount of ground coffee but extracted with',
|
||||
'about half the amount of water in the same amount of time',
|
||||
'by using a finer grind.',
|
||||
'This produces a concentrated shot of coffee per volume.',
|
||||
'Just pulling a normal shot short will produce a weaker shot',
|
||||
'and is not a Ristretto as some believe.',
|
||||
];
|
||||
const encodedHashToPoints = [
|
||||
'3066f82a1a747d45120d1740f14358531a8f04bbffe6a819f86dfe50f44a0a46',
|
||||
'f26e5b6f7d362d2d2a94c5d0e7602cb4773c95a2e5c31a64f133189fa76ed61b',
|
||||
'006ccd2a9e6867e6a2c5cea83d3302cc9de128dd2a9a57dd8ee7b9d7ffe02826',
|
||||
'f8f0c87cf237953c5890aec3998169005dae3eca1fbb04548c635953c817f92a',
|
||||
'ae81e7dedf20a497e10c304a765c1767a42d6e06029758d2d7e8ef7cc4c41179',
|
||||
'e2705652ff9f5e44d3e841bf1c251cf7dddb77d140870d1ab2ed64f1a9ce8628',
|
||||
'80bd07262511cdde4863f8a7434cef696750681cb9510eea557088f76d9e5065',
|
||||
];
|
||||
|
||||
for (let i = 0; i < labels.length; i++) {
|
||||
const hash = sha512(utf8ToBytes(labels[i]));
|
||||
const point = RistrettoPoint.hashToCurve(hash);
|
||||
deepStrictEqual(point.toHex(), encodedHashToPoints[i]);
|
||||
}
|
||||
});
|
||||
|
||||
should('input immutability: sign/verify are immutable', () => {
|
||||
const privateKey = ed.utils.randomPrivateKey();
|
||||
const publicKey = ed.getPublicKey(privateKey);
|
||||
|
||||
for (let i = 0; i < 100; i++) {
|
||||
let payload = randomBytes(100);
|
||||
let signature = ed.sign(payload, privateKey);
|
||||
if (!ed.verify(signature, payload, publicKey)) {
|
||||
throw new Error('Signature verification failed');
|
||||
}
|
||||
const signatureCopy = Buffer.alloc(signature.byteLength);
|
||||
signatureCopy.set(signature, 0); // <-- breaks
|
||||
payload = payload.slice();
|
||||
signature = signature.slice();
|
||||
|
||||
if (!ed.verify(signatureCopy, payload, publicKey))
|
||||
throw new Error('Copied signature verification failed');
|
||||
}
|
||||
});
|
||||
|
||||
// https://zips.z.cash/zip-0215
|
||||
// Vectors from https://gist.github.com/hdevalence/93ed42d17ecab8e42138b213812c8cc7
|
||||
should('ZIP-215 compliance tests/should pass all of them', () => {
|
||||
const str = utf8ToBytes('Zcash');
|
||||
for (let v of zip215) {
|
||||
let noble = false;
|
||||
try {
|
||||
noble = ed.verify(v.sig_bytes, str, v.vk_bytes);
|
||||
} catch (e) {
|
||||
noble = false;
|
||||
}
|
||||
deepStrictEqual(noble, v.valid_zip215);
|
||||
}
|
||||
});
|
||||
should('ZIP-215 compliance tests/disallows sig.s >= CURVE.n', () => {
|
||||
const sig = new ed.Signature(ed.Point.BASE, 1n);
|
||||
sig.s = ed.CURVE.n + 1n;
|
||||
throws(() => ed.verify(sig, 'deadbeef', ed.Point.BASE));
|
||||
});
|
||||
|
||||
const rfc7748Mul = [
|
||||
{
|
||||
scalar: 'a546e36bf0527c9d3b16154b82465edd62144c0ac1fc5a18506a2244ba449ac4',
|
||||
u: 'e6db6867583030db3594c1a424b15f7c726624ec26b3353b10a903a6d0ab1c4c',
|
||||
outputU: 'c3da55379de9c6908e94ea4df28d084f32eccf03491c71f754b4075577a28552',
|
||||
},
|
||||
{
|
||||
scalar: '4b66e9d4d1b4673c5ad22691957d6af5c11b6421e0ea01d42ca4169e7918ba0d',
|
||||
u: 'e5210f12786811d3f4b7959d0538ae2c31dbe7106fc03c3efc4cd549c715a493',
|
||||
outputU: '95cbde9476e8907d7aade45cb4b873f88b595a68799fa152e6f8f7647aac7957',
|
||||
},
|
||||
];
|
||||
for (let i = 0; i < rfc7748Mul.length; i++) {
|
||||
const v = rfc7748Mul[i];
|
||||
should(`RFC7748: scalarMult (${i})`, () => {
|
||||
deepStrictEqual(hex(x25519.scalarMult(v.u, v.scalar)), v.outputU);
|
||||
});
|
||||
}
|
||||
|
||||
const rfc7748Iter = [
|
||||
{ scalar: '422c8e7a6227d7bca1350b3e2bb7279f7897b87bb6854b783c60e80311ae3079', iters: 1 },
|
||||
{ scalar: '684cf59ba83309552800ef566f2f4d3c1c3887c49360e3875f2eb94d99532c51', iters: 1000 },
|
||||
// { scalar: '7c3911e0ab2586fd864497297e575e6f3bc601c0883c30df5f4dd2d24f665424', iters: 1000000 },
|
||||
];
|
||||
for (let i = 0; i < rfc7748Iter.length; i++) {
|
||||
const { scalar, iters } = rfc7748Iter[i];
|
||||
should(`RFC7748: scalarMult iteration (${i})`, () => {
|
||||
let k = x25519.Gu;
|
||||
for (let i = 0, u = k; i < iters; i++) [k, u] = [x25519.scalarMult(u, k), k];
|
||||
deepStrictEqual(hex(k), scalar);
|
||||
});
|
||||
}
|
||||
|
||||
should('RFC7748 getSharedKey', () => {
|
||||
const alicePrivate = '77076d0a7318a57d3c16c17251b26645df4c2f87ebc0992ab177fba51db92c2a';
|
||||
const alicePublic = '8520f0098930a754748b7ddcb43ef75a0dbf3a0d26381af4eba4a98eaa9b4e6a';
|
||||
const bobPrivate = '5dab087e624a8a4b79e17f8b83800ee66f3bb1292618b6fd1c2f8b27ff88e0eb';
|
||||
const bobPublic = 'de9edb7d7b7dc1b4d35b61c2ece435373f8343c85b78674dadfc7e146f882b4f';
|
||||
const shared = '4a5d9d5ba4ce2de1728e3bf480350f25e07e21c947d19e3376f09b3c1e161742';
|
||||
deepStrictEqual(alicePublic, hex(x25519.getPublicKey(alicePrivate)));
|
||||
deepStrictEqual(bobPublic, hex(x25519.getPublicKey(bobPrivate)));
|
||||
deepStrictEqual(hex(x25519.scalarMult(bobPublic, alicePrivate)), shared);
|
||||
deepStrictEqual(hex(x25519.scalarMult(alicePublic, bobPrivate)), shared);
|
||||
});
|
||||
|
||||
// should('X25519/getSharedSecret() should be commutative', () => {
|
||||
// for (let i = 0; i < 512; i++) {
|
||||
// const asec = ed.utils.randomPrivateKey();
|
||||
// const apub = ed.getPublicKey(asec);
|
||||
// const bsec = ed.utils.randomPrivateKey();
|
||||
// const bpub = ed.getPublicKey(bsec);
|
||||
// try {
|
||||
// deepStrictEqual(ed.getSharedSecret(asec, bpub), ed.getSharedSecret(bsec, apub));
|
||||
// } catch (error) {
|
||||
// console.error('not commutative', { asec, apub, bsec, bpub });
|
||||
// throw error;
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
|
||||
// should('X25519: should convert base point to montgomery using fromPoint', () => {
|
||||
// deepStrictEqual(
|
||||
// hex(ed.montgomeryCurve.UfromPoint(ed.Point.BASE)),
|
||||
// ed.montgomeryCurve.BASE_POINT_U
|
||||
// );
|
||||
// });
|
||||
|
||||
{
|
||||
const group = x25519vectors.testGroups[0];
|
||||
should(`Wycheproof/X25519`, () => {
|
||||
for (let i = 0; i < group.tests.length; i++) {
|
||||
const v = group.tests[i];
|
||||
const comment = `(${i}, ${v.result}) ${v.comment}`;
|
||||
if (v.result === 'valid' || v.result === 'acceptable') {
|
||||
try {
|
||||
const shared = hex(x25519.scalarMult(v.public, v.private));
|
||||
deepStrictEqual(shared, v.shared, comment);
|
||||
} catch (e) {
|
||||
// We are more strict
|
||||
if (e.message.includes('Expected valid scalar')) return;
|
||||
if (e.message.includes('Invalid private or public key received')) return;
|
||||
throw e;
|
||||
}
|
||||
} else if (v.result === 'invalid') {
|
||||
let failed = false;
|
||||
try {
|
||||
x25519.scalarMult(v.public, v.private);
|
||||
} catch (error) {
|
||||
failed = true;
|
||||
}
|
||||
deepStrictEqual(failed, true, comment);
|
||||
} else throw new Error('unknown test result');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
should(`Wycheproof/ED25519`, () => {
|
||||
for (let g = 0; g < ed25519vectors.testGroups.length; g++) {
|
||||
const group = ed25519vectors.testGroups[g];
|
||||
const key = group.key;
|
||||
deepStrictEqual(hex(ed.getPublicKey(key.sk)), key.pk, `(${g}, public)`);
|
||||
for (let i = 0; i < group.tests.length; i++) {
|
||||
const v = group.tests[i];
|
||||
const comment = `(${g}/${i}, ${v.result}): ${v.comment}`;
|
||||
if (v.result === 'valid' || v.result === 'acceptable') {
|
||||
deepStrictEqual(hex(ed.sign(v.msg, key.sk)), v.sig, comment);
|
||||
deepStrictEqual(ed.verify(v.sig, v.msg, key.pk), true, comment);
|
||||
} else if (v.result === 'invalid') {
|
||||
let failed = false;
|
||||
try {
|
||||
failed = !ed.verify(v.sig, v.msg, key.pk);
|
||||
} catch (error) {
|
||||
failed = true;
|
||||
}
|
||||
deepStrictEqual(failed, true, comment);
|
||||
} else throw new Error('unknown test result');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
should('Property test issue #1', () => {
|
||||
const message = new Uint8Array([12, 12, 12]);
|
||||
const signature = ed.sign(message, to32Bytes(1n));
|
||||
const publicKey = ed.getPublicKey(to32Bytes(1n)); // <- was 1n
|
||||
deepStrictEqual(ed.verify(signature, message, publicKey), true);
|
||||
});
|
||||
|
||||
const VECTORS_RFC8032_CTX = [
|
||||
{
|
||||
secretKey: '0305334e381af78f141cb666f6199f57bc3495335a256a95bd2a55bf546663f6',
|
||||
publicKey: 'dfc9425e4f968f7f0c29f0259cf5f9aed6851c2bb4ad8bfb860cfee0ab248292',
|
||||
message: 'f726936d19c800494e3fdaff20b276a8',
|
||||
context: '666f6f',
|
||||
signature:
|
||||
'55a4cc2f70a54e04288c5f4cd1e45a7b' +
|
||||
'b520b36292911876cada7323198dd87a' +
|
||||
'8b36950b95130022907a7fb7c4e9b2d5' +
|
||||
'f6cca685a587b4b21f4b888e4e7edb0d',
|
||||
},
|
||||
{
|
||||
secretKey: '0305334e381af78f141cb666f6199f57bc3495335a256a95bd2a55bf546663f6',
|
||||
publicKey: 'dfc9425e4f968f7f0c29f0259cf5f9aed6851c2bb4ad8bfb860cfee0ab248292',
|
||||
message: 'f726936d19c800494e3fdaff20b276a8',
|
||||
context: '626172',
|
||||
signature:
|
||||
'fc60d5872fc46b3aa69f8b5b4351d580' +
|
||||
'8f92bcc044606db097abab6dbcb1aee3' +
|
||||
'216c48e8b3b66431b5b186d1d28f8ee1' +
|
||||
'5a5ca2df6668346291c2043d4eb3e90d',
|
||||
},
|
||||
{
|
||||
secretKey: '0305334e381af78f141cb666f6199f57bc3495335a256a95bd2a55bf546663f6',
|
||||
publicKey: 'dfc9425e4f968f7f0c29f0259cf5f9aed6851c2bb4ad8bfb860cfee0ab248292',
|
||||
message: '508e9e6882b979fea900f62adceaca35',
|
||||
context: '666f6f',
|
||||
signature:
|
||||
'8b70c1cc8310e1de20ac53ce28ae6e72' +
|
||||
'07f33c3295e03bb5c0732a1d20dc6490' +
|
||||
'8922a8b052cf99b7c4fe107a5abb5b2c' +
|
||||
'4085ae75890d02df26269d8945f84b0b',
|
||||
},
|
||||
{
|
||||
secretKey: 'ab9c2853ce297ddab85c993b3ae14bcad39b2c682beabc27d6d4eb20711d6560',
|
||||
publicKey: '0f1d1274943b91415889152e893d80e93275a1fc0b65fd71b4b0dda10ad7d772',
|
||||
message: 'f726936d19c800494e3fdaff20b276a8',
|
||||
context: '666f6f',
|
||||
signature:
|
||||
'21655b5f1aa965996b3f97b3c849eafb' +
|
||||
'a922a0a62992f73b3d1b73106a84ad85' +
|
||||
'e9b86a7b6005ea868337ff2d20a7f5fb' +
|
||||
'd4cd10b0be49a68da2b2e0dc0ad8960f',
|
||||
},
|
||||
];
|
||||
|
||||
for (let i = 0; i < VECTORS_RFC8032_CTX.length; i++) {
|
||||
const v = VECTORS_RFC8032_CTX[i];
|
||||
should(`RFC8032ctx/${i}`, () => {
|
||||
deepStrictEqual(hex(ed25519ctx.getPublicKey(v.secretKey)), v.publicKey);
|
||||
deepStrictEqual(hex(ed25519ctx.sign(v.message, v.secretKey, v.context)), v.signature);
|
||||
deepStrictEqual(ed25519ctx.verify(v.signature, v.message, v.publicKey, v.context), true);
|
||||
});
|
||||
}
|
||||
|
||||
const VECTORS_RFC8032_PH = [
|
||||
{
|
||||
secretKey: '833fe62409237b9d62ec77587520911e9a759cec1d19755b7da901b96dca3d42',
|
||||
publicKey: 'ec172b93ad5e563bf4932c70e1245034c35467ef2efd4d64ebf819683467e2bf',
|
||||
message: '616263',
|
||||
signature:
|
||||
'98a70222f0b8121aa9d30f813d683f80' +
|
||||
'9e462b469c7ff87639499bb94e6dae41' +
|
||||
'31f85042463c2a355a2003d062adf5aa' +
|
||||
'a10b8c61e636062aaad11c2a26083406',
|
||||
},
|
||||
];
|
||||
|
||||
for (let i = 0; i < VECTORS_RFC8032_PH.length; i++) {
|
||||
const v = VECTORS_RFC8032_PH[i];
|
||||
should(`RFC8032ph/${i}`, () => {
|
||||
deepStrictEqual(hex(ed25519ph.getPublicKey(v.secretKey)), v.publicKey);
|
||||
deepStrictEqual(hex(ed25519ph.sign(v.message, v.secretKey)), v.signature);
|
||||
deepStrictEqual(ed25519ph.verify(v.signature, v.message, v.publicKey), true);
|
||||
});
|
||||
}
|
||||
|
||||
should('X25519 base point', () => {
|
||||
const { y } = ed25519.Point.BASE;
|
||||
const u = ed25519.utils.mod((y + 1n) * ed25519.utils.invert(1n - y, ed25519.CURVE.P));
|
||||
deepStrictEqual(hex(numberToBytesLE(u, 32)), x25519.Gu);
|
||||
});
|
||||
|
||||
// ESM is broken.
|
||||
import url from 'url';
|
||||
if (import.meta.url === url.pathToFileURL(process.argv[1]).href) {
|
||||
should.run();
|
||||
}
|
||||
664
curve-definitions/test/ed448.test.js
Normal file
664
curve-definitions/test/ed448.test.js
Normal file
@ -0,0 +1,664 @@
|
||||
import { deepStrictEqual, throws } from 'assert';
|
||||
import { should } from 'micro-should';
|
||||
import * as fc from 'fast-check';
|
||||
import { ed448, ed448ph, x448 } from '../lib/ed448.js';
|
||||
import { hexToBytes, bytesToHex, randomBytes } from '@noble/hashes/utils';
|
||||
import { numberToBytesLE } from '@noble/curves/utils';
|
||||
import { default as ed448vectors } from './wycheproof/ed448_test.json' assert { type: 'json' };
|
||||
import { default as x448vectors } from './wycheproof/x448_test.json' assert { type: 'json' };
|
||||
|
||||
const ed = ed448;
|
||||
const hex = bytesToHex;
|
||||
ed.utils.precompute(4);
|
||||
|
||||
should(`Basic`, () => {
|
||||
const G1 = ed.Point.BASE;
|
||||
deepStrictEqual(
|
||||
G1.x,
|
||||
224580040295924300187604334099896036246789641632564134246125461686950415467406032909029192869357953282578032075146446173674602635247710n
|
||||
);
|
||||
deepStrictEqual(
|
||||
G1.y,
|
||||
298819210078481492676017930443930673437544040154080242095928241372331506189835876003536878655418784733982303233503462500531545062832660n
|
||||
);
|
||||
const G2 = ed.Point.BASE.multiply(2n);
|
||||
deepStrictEqual(
|
||||
G2.x,
|
||||
484559149530404593699549205258669689569094240458212040187660132787056912146709081364401144455726350866276831544947397859048262938744149n
|
||||
);
|
||||
deepStrictEqual(
|
||||
G2.y,
|
||||
494088759867433727674302672526735089350544552303727723746126484473087719117037293890093462157703888342865036477787453078312060500281069n
|
||||
);
|
||||
const G3 = ed.Point.BASE.multiply(3n);
|
||||
deepStrictEqual(
|
||||
G3.x,
|
||||
23839778817283171003887799738662344287085130522697782688245073320169861206004018274567429238677677920280078599146891901463786155880335n
|
||||
);
|
||||
deepStrictEqual(
|
||||
G3.y,
|
||||
636046652612779686502873775776967954190574036985351036782021535703553242737829645273154208057988851307101009474686328623630835377952508n
|
||||
);
|
||||
});
|
||||
|
||||
should('Basic/decompress', () => {
|
||||
const G1 = ed.Point.BASE;
|
||||
const G2 = ed.Point.BASE.multiply(2n);
|
||||
const G3 = ed.Point.BASE.multiply(3n);
|
||||
const points = [G1, G2, G3];
|
||||
const getXY = (p) => ({ x: p.x, y: p.y });
|
||||
for (const p of points) deepStrictEqual(getXY(ed.Point.fromHex(p.toHex())), getXY(p));
|
||||
});
|
||||
|
||||
const VECTORS_RFC8032 = [
|
||||
{
|
||||
secretKey:
|
||||
'6c82a562cb808d10d632be89c8513ebf' +
|
||||
'6c929f34ddfa8c9f63c9960ef6e348a3' +
|
||||
'528c8a3fcc2f044e39a3fc5b94492f8f' +
|
||||
'032e7549a20098f95b',
|
||||
publicKey:
|
||||
'5fd7449b59b461fd2ce787ec616ad46a' +
|
||||
'1da1342485a70e1f8a0ea75d80e96778' +
|
||||
'edf124769b46c7061bd6783df1e50f6c' +
|
||||
'd1fa1abeafe8256180',
|
||||
message: '',
|
||||
signature:
|
||||
'533a37f6bbe457251f023c0d88f976ae' +
|
||||
'2dfb504a843e34d2074fd823d41a591f' +
|
||||
'2b233f034f628281f2fd7a22ddd47d78' +
|
||||
'28c59bd0a21bfd3980ff0d2028d4b18a' +
|
||||
'9df63e006c5d1c2d345b925d8dc00b41' +
|
||||
'04852db99ac5c7cdda8530a113a0f4db' +
|
||||
'b61149f05a7363268c71d95808ff2e65' +
|
||||
'2600',
|
||||
},
|
||||
{
|
||||
secretKey:
|
||||
'c4eab05d357007c632f3dbb48489924d' +
|
||||
'552b08fe0c353a0d4a1f00acda2c463a' +
|
||||
'fbea67c5e8d2877c5e3bc397a659949e' +
|
||||
'f8021e954e0a12274e',
|
||||
publicKey:
|
||||
'43ba28f430cdff456ae531545f7ecd0a' +
|
||||
'c834a55d9358c0372bfa0c6c6798c086' +
|
||||
'6aea01eb00742802b8438ea4cb82169c' +
|
||||
'235160627b4c3a9480',
|
||||
|
||||
message: '03',
|
||||
signature:
|
||||
'26b8f91727bd62897af15e41eb43c377' +
|
||||
'efb9c610d48f2335cb0bd0087810f435' +
|
||||
'2541b143c4b981b7e18f62de8ccdf633' +
|
||||
'fc1bf037ab7cd779805e0dbcc0aae1cb' +
|
||||
'cee1afb2e027df36bc04dcecbf154336' +
|
||||
'c19f0af7e0a6472905e799f1953d2a0f' +
|
||||
'f3348ab21aa4adafd1d234441cf807c0' +
|
||||
'3a00',
|
||||
},
|
||||
{
|
||||
secretKey:
|
||||
'cd23d24f714274e744343237b93290f5' +
|
||||
'11f6425f98e64459ff203e8985083ffd' +
|
||||
'f60500553abc0e05cd02184bdb89c4cc' +
|
||||
'd67e187951267eb328',
|
||||
publicKey:
|
||||
'dcea9e78f35a1bf3499a831b10b86c90' +
|
||||
'aac01cd84b67a0109b55a36e9328b1e3' +
|
||||
'65fce161d71ce7131a543ea4cb5f7e9f' +
|
||||
'1d8b00696447001400',
|
||||
message: '0c3e544074ec63b0265e0c',
|
||||
signature:
|
||||
'1f0a8888ce25e8d458a21130879b840a' +
|
||||
'9089d999aaba039eaf3e3afa090a09d3' +
|
||||
'89dba82c4ff2ae8ac5cdfb7c55e94d5d' +
|
||||
'961a29fe0109941e00b8dbdeea6d3b05' +
|
||||
'1068df7254c0cdc129cbe62db2dc957d' +
|
||||
'bb47b51fd3f213fb8698f064774250a5' +
|
||||
'028961c9bf8ffd973fe5d5c206492b14' +
|
||||
'0e00',
|
||||
},
|
||||
{
|
||||
secretKey:
|
||||
'258cdd4ada32ed9c9ff54e63756ae582' +
|
||||
'fb8fab2ac721f2c8e676a72768513d93' +
|
||||
'9f63dddb55609133f29adf86ec9929dc' +
|
||||
'cb52c1c5fd2ff7e21b',
|
||||
publicKey:
|
||||
'3ba16da0c6f2cc1f30187740756f5e79' +
|
||||
'8d6bc5fc015d7c63cc9510ee3fd44adc' +
|
||||
'24d8e968b6e46e6f94d19b945361726b' +
|
||||
'd75e149ef09817f580',
|
||||
message: '64a65f3cdedcdd66811e2915',
|
||||
signature:
|
||||
'7eeeab7c4e50fb799b418ee5e3197ff6' +
|
||||
'bf15d43a14c34389b59dd1a7b1b85b4a' +
|
||||
'e90438aca634bea45e3a2695f1270f07' +
|
||||
'fdcdf7c62b8efeaf00b45c2c96ba457e' +
|
||||
'b1a8bf075a3db28e5c24f6b923ed4ad7' +
|
||||
'47c3c9e03c7079efb87cb110d3a99861' +
|
||||
'e72003cbae6d6b8b827e4e6c143064ff' +
|
||||
'3c00',
|
||||
},
|
||||
{
|
||||
secretKey:
|
||||
'7ef4e84544236752fbb56b8f31a23a10' +
|
||||
'e42814f5f55ca037cdcc11c64c9a3b29' +
|
||||
'49c1bb60700314611732a6c2fea98eeb' +
|
||||
'c0266a11a93970100e',
|
||||
publicKey:
|
||||
'b3da079b0aa493a5772029f0467baebe' +
|
||||
'e5a8112d9d3a22532361da294f7bb381' +
|
||||
'5c5dc59e176b4d9f381ca0938e13c6c0' +
|
||||
'7b174be65dfa578e80',
|
||||
message: '64a65f3cdedcdd66811e2915e7',
|
||||
signature:
|
||||
'6a12066f55331b6c22acd5d5bfc5d712' +
|
||||
'28fbda80ae8dec26bdd306743c5027cb' +
|
||||
'4890810c162c027468675ecf645a8317' +
|
||||
'6c0d7323a2ccde2d80efe5a1268e8aca' +
|
||||
'1d6fbc194d3f77c44986eb4ab4177919' +
|
||||
'ad8bec33eb47bbb5fc6e28196fd1caf5' +
|
||||
'6b4e7e0ba5519234d047155ac727a105' +
|
||||
'3100',
|
||||
},
|
||||
{
|
||||
secretKey:
|
||||
'd65df341ad13e008567688baedda8e9d' +
|
||||
'cdc17dc024974ea5b4227b6530e339bf' +
|
||||
'f21f99e68ca6968f3cca6dfe0fb9f4fa' +
|
||||
'b4fa135d5542ea3f01',
|
||||
publicKey:
|
||||
'df9705f58edbab802c7f8363cfe5560a' +
|
||||
'b1c6132c20a9f1dd163483a26f8ac53a' +
|
||||
'39d6808bf4a1dfbd261b099bb03b3fb5' +
|
||||
'0906cb28bd8a081f00',
|
||||
message:
|
||||
'bd0f6a3747cd561bdddf4640a332461a' +
|
||||
'4a30a12a434cd0bf40d766d9c6d458e5' +
|
||||
'512204a30c17d1f50b5079631f64eb31' +
|
||||
'12182da3005835461113718d1a5ef944',
|
||||
signature:
|
||||
'554bc2480860b49eab8532d2a533b7d5' +
|
||||
'78ef473eeb58c98bb2d0e1ce488a98b1' +
|
||||
'8dfde9b9b90775e67f47d4a1c3482058' +
|
||||
'efc9f40d2ca033a0801b63d45b3b722e' +
|
||||
'f552bad3b4ccb667da350192b61c508c' +
|
||||
'f7b6b5adadc2c8d9a446ef003fb05cba' +
|
||||
'5f30e88e36ec2703b349ca229c267083' +
|
||||
'3900',
|
||||
},
|
||||
{
|
||||
secretKey:
|
||||
'2ec5fe3c17045abdb136a5e6a913e32a' +
|
||||
'b75ae68b53d2fc149b77e504132d3756' +
|
||||
'9b7e766ba74a19bd6162343a21c8590a' +
|
||||
'a9cebca9014c636df5',
|
||||
publicKey:
|
||||
'79756f014dcfe2079f5dd9e718be4171' +
|
||||
'e2ef2486a08f25186f6bff43a9936b9b' +
|
||||
'fe12402b08ae65798a3d81e22e9ec80e' +
|
||||
'7690862ef3d4ed3a00',
|
||||
message:
|
||||
'15777532b0bdd0d1389f636c5f6b9ba7' +
|
||||
'34c90af572877e2d272dd078aa1e567c' +
|
||||
'fa80e12928bb542330e8409f31745041' +
|
||||
'07ecd5efac61ae7504dabe2a602ede89' +
|
||||
'e5cca6257a7c77e27a702b3ae39fc769' +
|
||||
'fc54f2395ae6a1178cab4738e543072f' +
|
||||
'c1c177fe71e92e25bf03e4ecb72f47b6' +
|
||||
'4d0465aaea4c7fad372536c8ba516a60' +
|
||||
'39c3c2a39f0e4d832be432dfa9a706a6' +
|
||||
'e5c7e19f397964ca4258002f7c0541b5' +
|
||||
'90316dbc5622b6b2a6fe7a4abffd9610' +
|
||||
'5eca76ea7b98816af0748c10df048ce0' +
|
||||
'12d901015a51f189f3888145c03650aa' +
|
||||
'23ce894c3bd889e030d565071c59f409' +
|
||||
'a9981b51878fd6fc110624dcbcde0bf7' +
|
||||
'a69ccce38fabdf86f3bef6044819de11',
|
||||
signature:
|
||||
'c650ddbb0601c19ca11439e1640dd931' +
|
||||
'f43c518ea5bea70d3dcde5f4191fe53f' +
|
||||
'00cf966546b72bcc7d58be2b9badef28' +
|
||||
'743954e3a44a23f880e8d4f1cfce2d7a' +
|
||||
'61452d26da05896f0a50da66a239a8a1' +
|
||||
'88b6d825b3305ad77b73fbac0836ecc6' +
|
||||
'0987fd08527c1a8e80d5823e65cafe2a' +
|
||||
'3d00',
|
||||
},
|
||||
{
|
||||
secretKey:
|
||||
'872d093780f5d3730df7c212664b37b8' +
|
||||
'a0f24f56810daa8382cd4fa3f77634ec' +
|
||||
'44dc54f1c2ed9bea86fafb7632d8be19' +
|
||||
'9ea165f5ad55dd9ce8',
|
||||
publicKey:
|
||||
'a81b2e8a70a5ac94ffdbcc9badfc3feb' +
|
||||
'0801f258578bb114ad44ece1ec0e799d' +
|
||||
'a08effb81c5d685c0c56f64eecaef8cd' +
|
||||
'f11cc38737838cf400',
|
||||
message:
|
||||
'6ddf802e1aae4986935f7f981ba3f035' +
|
||||
'1d6273c0a0c22c9c0e8339168e675412' +
|
||||
'a3debfaf435ed651558007db4384b650' +
|
||||
'fcc07e3b586a27a4f7a00ac8a6fec2cd' +
|
||||
'86ae4bf1570c41e6a40c931db27b2faa' +
|
||||
'15a8cedd52cff7362c4e6e23daec0fbc' +
|
||||
'3a79b6806e316efcc7b68119bf46bc76' +
|
||||
'a26067a53f296dafdbdc11c77f7777e9' +
|
||||
'72660cf4b6a9b369a6665f02e0cc9b6e' +
|
||||
'dfad136b4fabe723d2813db3136cfde9' +
|
||||
'b6d044322fee2947952e031b73ab5c60' +
|
||||
'3349b307bdc27bc6cb8b8bbd7bd32321' +
|
||||
'9b8033a581b59eadebb09b3c4f3d2277' +
|
||||
'd4f0343624acc817804728b25ab79717' +
|
||||
'2b4c5c21a22f9c7839d64300232eb66e' +
|
||||
'53f31c723fa37fe387c7d3e50bdf9813' +
|
||||
'a30e5bb12cf4cd930c40cfb4e1fc6225' +
|
||||
'92a49588794494d56d24ea4b40c89fc0' +
|
||||
'596cc9ebb961c8cb10adde976a5d602b' +
|
||||
'1c3f85b9b9a001ed3c6a4d3b1437f520' +
|
||||
'96cd1956d042a597d561a596ecd3d173' +
|
||||
'5a8d570ea0ec27225a2c4aaff26306d1' +
|
||||
'526c1af3ca6d9cf5a2c98f47e1c46db9' +
|
||||
'a33234cfd4d81f2c98538a09ebe76998' +
|
||||
'd0d8fd25997c7d255c6d66ece6fa56f1' +
|
||||
'1144950f027795e653008f4bd7ca2dee' +
|
||||
'85d8e90f3dc315130ce2a00375a318c7' +
|
||||
'c3d97be2c8ce5b6db41a6254ff264fa6' +
|
||||
'155baee3b0773c0f497c573f19bb4f42' +
|
||||
'40281f0b1f4f7be857a4e59d416c06b4' +
|
||||
'c50fa09e1810ddc6b1467baeac5a3668' +
|
||||
'd11b6ecaa901440016f389f80acc4db9' +
|
||||
'77025e7f5924388c7e340a732e554440' +
|
||||
'e76570f8dd71b7d640b3450d1fd5f041' +
|
||||
'0a18f9a3494f707c717b79b4bf75c984' +
|
||||
'00b096b21653b5d217cf3565c9597456' +
|
||||
'f70703497a078763829bc01bb1cbc8fa' +
|
||||
'04eadc9a6e3f6699587a9e75c94e5bab' +
|
||||
'0036e0b2e711392cff0047d0d6b05bd2' +
|
||||
'a588bc109718954259f1d86678a579a3' +
|
||||
'120f19cfb2963f177aeb70f2d4844826' +
|
||||
'262e51b80271272068ef5b3856fa8535' +
|
||||
'aa2a88b2d41f2a0e2fda7624c2850272' +
|
||||
'ac4a2f561f8f2f7a318bfd5caf969614' +
|
||||
'9e4ac824ad3460538fdc25421beec2cc' +
|
||||
'6818162d06bbed0c40a387192349db67' +
|
||||
'a118bada6cd5ab0140ee273204f628aa' +
|
||||
'd1c135f770279a651e24d8c14d75a605' +
|
||||
'9d76b96a6fd857def5e0b354b27ab937' +
|
||||
'a5815d16b5fae407ff18222c6d1ed263' +
|
||||
'be68c95f32d908bd895cd76207ae7264' +
|
||||
'87567f9a67dad79abec316f683b17f2d' +
|
||||
'02bf07e0ac8b5bc6162cf94697b3c27c' +
|
||||
'd1fea49b27f23ba2901871962506520c' +
|
||||
'392da8b6ad0d99f7013fbc06c2c17a56' +
|
||||
'9500c8a7696481c1cd33e9b14e40b82e' +
|
||||
'79a5f5db82571ba97bae3ad3e0479515' +
|
||||
'bb0e2b0f3bfcd1fd33034efc6245eddd' +
|
||||
'7ee2086ddae2600d8ca73e214e8c2b0b' +
|
||||
'db2b047c6a464a562ed77b73d2d841c4' +
|
||||
'b34973551257713b753632efba348169' +
|
||||
'abc90a68f42611a40126d7cb21b58695' +
|
||||
'568186f7e569d2ff0f9e745d0487dd2e' +
|
||||
'b997cafc5abf9dd102e62ff66cba87',
|
||||
signature:
|
||||
'e301345a41a39a4d72fff8df69c98075' +
|
||||
'a0cc082b802fc9b2b6bc503f926b65bd' +
|
||||
'df7f4c8f1cb49f6396afc8a70abe6d8a' +
|
||||
'ef0db478d4c6b2970076c6a0484fe76d' +
|
||||
'76b3a97625d79f1ce240e7c576750d29' +
|
||||
'5528286f719b413de9ada3e8eb78ed57' +
|
||||
'3603ce30d8bb761785dc30dbc320869e' +
|
||||
'1a00',
|
||||
},
|
||||
];
|
||||
|
||||
for (let i = 0; i < VECTORS_RFC8032.length; i++) {
|
||||
const v = VECTORS_RFC8032[i];
|
||||
should(`RFC8032/${i}`, () => {
|
||||
deepStrictEqual(hex(ed.getPublicKey(v.secretKey)), v.publicKey);
|
||||
deepStrictEqual(hex(ed.sign(v.message, v.secretKey)), v.signature);
|
||||
deepStrictEqual(ed.verify(v.signature, v.message, v.publicKey), true);
|
||||
});
|
||||
}
|
||||
|
||||
should('ed448/should not accept >57byte private keys', async () => {
|
||||
const invalidPriv =
|
||||
100000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000090000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800073278156000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000n;
|
||||
throws(() => ed.getPublicKey(invalidPriv));
|
||||
});
|
||||
|
||||
function to57Bytes(numOrStr) {
|
||||
let hex = typeof numOrStr === 'string' ? numOrStr : numOrStr.toString(16);
|
||||
return hexToBytes(hex.padStart(114, '0'));
|
||||
}
|
||||
|
||||
should('ed448/should verify recent signature', () => {
|
||||
fc.assert(
|
||||
fc.property(
|
||||
fc.hexaString({ minLength: 2, maxLength: 57 }),
|
||||
fc.bigInt(2n, ed.CURVE.n),
|
||||
(message, privateKey) => {
|
||||
const publicKey = ed.getPublicKey(to57Bytes(privateKey));
|
||||
const signature = ed.sign(to57Bytes(message), to57Bytes(privateKey));
|
||||
deepStrictEqual(publicKey.length, 57);
|
||||
deepStrictEqual(signature.length, 114);
|
||||
deepStrictEqual(ed.verify(signature, to57Bytes(message), publicKey), true);
|
||||
}
|
||||
),
|
||||
{ numRuns: 5 }
|
||||
);
|
||||
});
|
||||
should('ed448/should not verify signature with wrong message', () => {
|
||||
fc.assert(
|
||||
fc.property(
|
||||
fc.array(fc.integer({ min: 0x00, max: 0xff })),
|
||||
fc.array(fc.integer({ min: 0x00, max: 0xff })),
|
||||
fc.bigInt(1n, ed.CURVE.n),
|
||||
(bytes, wrongBytes, privateKey) => {
|
||||
const message = new Uint8Array(bytes);
|
||||
const wrongMessage = new Uint8Array(wrongBytes);
|
||||
const priv = to57Bytes(privateKey);
|
||||
const publicKey = ed.getPublicKey(priv);
|
||||
const signature = ed.sign(message, priv);
|
||||
deepStrictEqual(
|
||||
ed.verify(signature, wrongMessage, publicKey),
|
||||
bytes.toString() === wrongBytes.toString()
|
||||
);
|
||||
}
|
||||
),
|
||||
{ numRuns: 5 }
|
||||
);
|
||||
});
|
||||
const privKey = to57Bytes('a665a45920422f9d417e4867ef');
|
||||
const msg = hexToBytes('874f9960c5d2b7a9b5fad383e1ba44719ebb743a');
|
||||
const wrongMsg = hexToBytes('589d8c7f1da0a24bc07b7381ad48b1cfc211af1c');
|
||||
should('ed25519/basic methods/should sign and verify', () => {
|
||||
const publicKey = ed.getPublicKey(privKey);
|
||||
const signature = ed.sign(msg, privKey);
|
||||
deepStrictEqual(ed.verify(signature, msg, publicKey), true);
|
||||
});
|
||||
should('ed25519/basic methods/should not verify signature with wrong public key', () => {
|
||||
const publicKey = ed.getPublicKey(12);
|
||||
const signature = ed.sign(msg, privKey);
|
||||
deepStrictEqual(ed.verify(signature, msg, publicKey), false);
|
||||
});
|
||||
should('ed25519/basic methods/should not verify signature with wrong hash', () => {
|
||||
const publicKey = ed.getPublicKey(privKey);
|
||||
const signature = ed.sign(msg, privKey);
|
||||
deepStrictEqual(ed.verify(signature, wrongMsg, publicKey), false);
|
||||
});
|
||||
|
||||
should('ed25519/sync methods/should sign and verify', () => {
|
||||
const publicKey = ed.getPublicKey(privKey);
|
||||
const signature = ed.sign(msg, privKey);
|
||||
deepStrictEqual(ed.verify(signature, msg, publicKey), true);
|
||||
});
|
||||
should('ed25519/sync methods/should not verify signature with wrong public key', async () => {
|
||||
const publicKey = ed.getPublicKey(12);
|
||||
const signature = ed.sign(msg, privKey);
|
||||
deepStrictEqual(ed.verify(signature, msg, publicKey), false);
|
||||
});
|
||||
should('ed25519/sync methods/should not verify signature with wrong hash', async () => {
|
||||
const publicKey = ed.getPublicKey(privKey);
|
||||
const signature = ed.sign(msg, privKey);
|
||||
deepStrictEqual(ed.verify(signature, wrongMsg, publicKey), false);
|
||||
});
|
||||
|
||||
should('ed25519/BASE_POINT.multiply()/should throw Point#multiply on TEST 5', () => {
|
||||
for (const num of [0n, 0, -1n, -1, 1.1]) {
|
||||
throws(() => ed.Point.BASE.multiply(num));
|
||||
}
|
||||
});
|
||||
|
||||
should('input immutability: sign/verify are immutable', () => {
|
||||
const privateKey = ed.utils.randomPrivateKey();
|
||||
const publicKey = ed.getPublicKey(privateKey);
|
||||
|
||||
for (let i = 0; i < 100; i++) {
|
||||
let payload = randomBytes(100);
|
||||
let signature = ed.sign(payload, privateKey);
|
||||
if (!ed.verify(signature, payload, publicKey)) {
|
||||
throw new Error('Signature verification failed');
|
||||
}
|
||||
const signatureCopy = Buffer.alloc(signature.byteLength);
|
||||
signatureCopy.set(signature, 0); // <-- breaks
|
||||
payload = payload.slice();
|
||||
signature = signature.slice();
|
||||
|
||||
if (!ed.verify(signatureCopy, payload, publicKey))
|
||||
throw new Error('Copied signature verification failed');
|
||||
}
|
||||
});
|
||||
|
||||
{
|
||||
for (let g = 0; g < ed448vectors.testGroups.length; g++) {
|
||||
const group = ed448vectors.testGroups[g];
|
||||
const key = group.key;
|
||||
should(`Wycheproof/ED448(${g}, public)`, () => {
|
||||
deepStrictEqual(hex(ed.getPublicKey(key.sk)), key.pk);
|
||||
});
|
||||
should(`Wycheproof/ED448`, () => {
|
||||
for (let i = 0; i < group.tests.length; i++) {
|
||||
const v = group.tests[i];
|
||||
const index = `${g}/${i} ${v.comment}`;
|
||||
if (v.result === 'valid' || v.result === 'acceptable') {
|
||||
deepStrictEqual(hex(ed.sign(v.msg, key.sk)), v.sig, index);
|
||||
deepStrictEqual(ed.verify(v.sig, v.msg, key.pk), true, index);
|
||||
} else if (v.result === 'invalid') {
|
||||
let failed = false;
|
||||
try {
|
||||
failed = !ed.verify(v.sig, v.msg, key.pk);
|
||||
} catch (error) {
|
||||
failed = true;
|
||||
}
|
||||
deepStrictEqual(failed, true, index);
|
||||
} else throw new Error('unknown test result');
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// ECDH
|
||||
const rfc7748Mul = [
|
||||
{
|
||||
scalar:
|
||||
'3d262fddf9ec8e88495266fea19a34d28882acef045104d0d1aae121700a779c984c24f8cdd78fbff44943eba368f54b29259a4f1c600ad3',
|
||||
u: '06fce640fa3487bfda5f6cf2d5263f8aad88334cbd07437f020f08f9814dc031ddbdc38c19c6da2583fa5429db94ada18aa7a7fb4ef8a086',
|
||||
outputU:
|
||||
'ce3e4ff95a60dc6697da1db1d85e6afbdf79b50a2412d7546d5f239fe14fbaadeb445fc66a01b0779d98223961111e21766282f73dd96b6f',
|
||||
},
|
||||
{
|
||||
scalar:
|
||||
'203d494428b8399352665ddca42f9de8fef600908e0d461cb021f8c538345dd77c3e4806e25f46d3315c44e0a5b4371282dd2c8d5be3095f',
|
||||
u: '0fbcc2f993cd56d3305b0b7d9e55d4c1a8fb5dbb52f8e9a1e9b6201b165d015894e56c4d3570bee52fe205e28a78b91cdfbde71ce8d157db',
|
||||
outputU:
|
||||
'884a02576239ff7a2f2f63b2db6a9ff37047ac13568e1e30fe63c4a7ad1b3ee3a5700df34321d62077e63633c575c1c954514e99da7c179d',
|
||||
},
|
||||
];
|
||||
for (let i = 0; i < rfc7748Mul.length; i++) {
|
||||
const v = rfc7748Mul[i];
|
||||
should(`RFC7748: scalarMult (${i})`, () => {
|
||||
deepStrictEqual(hex(x448.scalarMult(v.u, v.scalar)), v.outputU);
|
||||
});
|
||||
}
|
||||
|
||||
const rfc7748Iter = [
|
||||
{
|
||||
scalar:
|
||||
'3f482c8a9f19b01e6c46ee9711d9dc14fd4bf67af30765c2ae2b846a4d23a8cd0db897086239492caf350b51f833868b9bc2b3bca9cf4113',
|
||||
iters: 1,
|
||||
},
|
||||
{
|
||||
scalar:
|
||||
'aa3b4749d55b9daf1e5b00288826c467274ce3ebbdd5c17b975e09d4af6c67cf10d087202db88286e2b79fceea3ec353ef54faa26e219f38',
|
||||
iters: 1000,
|
||||
},
|
||||
// { scalar: '077f453681caca3693198420bbe515cae0002472519b3e67661a7e89cab94695c8f4bcd66e61b9b9c946da8d524de3d69bd9d9d66b997e37', iters: 1000000 },
|
||||
];
|
||||
for (let i = 0; i < rfc7748Iter.length; i++) {
|
||||
const { scalar, iters } = rfc7748Iter[i];
|
||||
should(`RFC7748: scalarMult iteration (${i})`, () => {
|
||||
let k = x448.Gu;
|
||||
for (let i = 0, u = k; i < iters; i++) [k, u] = [x448.scalarMult(u, k), k];
|
||||
deepStrictEqual(hex(k), scalar);
|
||||
});
|
||||
}
|
||||
|
||||
should('RFC7748 getSharedKey', () => {
|
||||
const alicePrivate =
|
||||
'9a8f4925d1519f5775cf46b04b5800d4ee9ee8bae8bc5565d498c28dd9c9baf574a9419744897391006382a6f127ab1d9ac2d8c0a598726b';
|
||||
const alicePublic =
|
||||
'9b08f7cc31b7e3e67d22d5aea121074a273bd2b83de09c63faa73d2c22c5d9bbc836647241d953d40c5b12da88120d53177f80e532c41fa0';
|
||||
const bobPrivate =
|
||||
'1c306a7ac2a0e2e0990b294470cba339e6453772b075811d8fad0d1d6927c120bb5ee8972b0d3e21374c9c921b09d1b0366f10b65173992d';
|
||||
const bobPublic =
|
||||
'3eb7a829b0cd20f5bcfc0b599b6feccf6da4627107bdb0d4f345b43027d8b972fc3e34fb4232a13ca706dcb57aec3dae07bdc1c67bf33609';
|
||||
const shared =
|
||||
'07fff4181ac6cc95ec1c16a94a0f74d12da232ce40a77552281d282bb60c0b56fd2464c335543936521c24403085d59a449a5037514a879d';
|
||||
deepStrictEqual(alicePublic, hex(x448.getPublicKey(alicePrivate)));
|
||||
deepStrictEqual(bobPublic, hex(x448.getPublicKey(bobPrivate)));
|
||||
deepStrictEqual(hex(x448.scalarMult(bobPublic, alicePrivate)), shared);
|
||||
deepStrictEqual(hex(x448.scalarMult(alicePublic, bobPrivate)), shared);
|
||||
});
|
||||
|
||||
{
|
||||
const group = x448vectors.testGroups[0];
|
||||
should(`Wycheproof/X448`, () => {
|
||||
for (let i = 0; i < group.tests.length; i++) {
|
||||
const v = group.tests[i];
|
||||
const index = `(${i}, ${v.result}) ${v.comment}`;
|
||||
if (v.result === 'valid' || v.result === 'acceptable') {
|
||||
try {
|
||||
const shared = hex(x448.scalarMult(v.public, v.private));
|
||||
deepStrictEqual(shared, v.shared, index);
|
||||
} catch (e) {
|
||||
// We are more strict
|
||||
if (e.message.includes('Expected valid scalar')) return;
|
||||
if (e.message.includes('Invalid private or public key received')) return;
|
||||
if (e.message.includes('Expected 56 bytes')) return;
|
||||
throw e;
|
||||
}
|
||||
} else if (v.result === 'invalid') {
|
||||
let failed = false;
|
||||
try {
|
||||
x448.scalarMult(v.public, v.private);
|
||||
} catch (error) {
|
||||
failed = true;
|
||||
}
|
||||
deepStrictEqual(failed, true, index);
|
||||
} else throw new Error('unknown test result');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// should('X448: should convert base point to montgomery using fromPoint', () => {
|
||||
// deepStrictEqual(
|
||||
// hex(ed.montgomeryCurve.UfromPoint(ed.Point.BASE)),
|
||||
// ed.montgomeryCurve.BASE_POINT_U
|
||||
// );
|
||||
// });
|
||||
|
||||
// should('X448/getSharedSecret() should be commutative', async () => {
|
||||
// for (let i = 0; i < 512; i++) {
|
||||
// const asec = ed.utils.randomPrivateKey();
|
||||
// const apub = ed.getPublicKey(asec);
|
||||
// const bsec = ed.utils.randomPrivateKey();
|
||||
// const bpub = ed.getPublicKey(bsec);
|
||||
// try {
|
||||
// deepStrictEqual(ed.getSharedSecret(asec, bpub), ed.getSharedSecret(bsec, apub));
|
||||
// } catch (error) {
|
||||
// console.error('not commutative', { asec, apub, bsec, bpub });
|
||||
// throw error;
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
|
||||
const VECTORS_RFC8032_CTX = [
|
||||
{
|
||||
secretKey:
|
||||
'c4eab05d357007c632f3dbb48489924d552b08fe0c353a0d4a1f00acda2c463afbea67c5e8d2877c5e3bc397a659949ef8021e954e0a12274e',
|
||||
publicKey:
|
||||
'43ba28f430cdff456ae531545f7ecd0ac834a55d9358c0372bfa0c6c6798c0866aea01eb00742802b8438ea4cb82169c235160627b4c3a9480',
|
||||
message: '03',
|
||||
context: '666f6f',
|
||||
signature:
|
||||
'd4f8f6131770dd46f40867d6fd5d5055' +
|
||||
'de43541f8c5e35abbcd001b32a89f7d2' +
|
||||
'151f7647f11d8ca2ae279fb842d60721' +
|
||||
'7fce6e042f6815ea000c85741de5c8da' +
|
||||
'1144a6a1aba7f96de42505d7a7298524' +
|
||||
'fda538fccbbb754f578c1cad10d54d0d' +
|
||||
'5428407e85dcbc98a49155c13764e66c' +
|
||||
'3c00',
|
||||
},
|
||||
];
|
||||
|
||||
for (let i = 0; i < VECTORS_RFC8032_CTX.length; i++) {
|
||||
const v = VECTORS_RFC8032_CTX[i];
|
||||
should(`RFC8032ctx/${i}`, () => {
|
||||
deepStrictEqual(hex(ed.getPublicKey(v.secretKey)), v.publicKey);
|
||||
deepStrictEqual(hex(ed.sign(v.message, v.secretKey, v.context)), v.signature);
|
||||
deepStrictEqual(ed.verify(v.signature, v.message, v.publicKey, v.context), true);
|
||||
});
|
||||
}
|
||||
|
||||
const VECTORS_RFC8032_PH = [
|
||||
{
|
||||
secretKey:
|
||||
'833fe62409237b9d62ec77587520911e9a759cec1d19755b7da901b96dca3d42ef7822e0d5104127dc05d6dbefde69e3ab2cec7c867c6e2c49',
|
||||
publicKey:
|
||||
'259b71c19f83ef77a7abd26524cbdb3161b590a48f7d17de3ee0ba9c52beb743c09428a131d6b1b57303d90d8132c276d5ed3d5d01c0f53880',
|
||||
message: '616263',
|
||||
signature:
|
||||
'822f6901f7480f3d5f562c592994d969' +
|
||||
'3602875614483256505600bbc281ae38' +
|
||||
'1f54d6bce2ea911574932f52a4e6cadd' +
|
||||
'78769375ec3ffd1b801a0d9b3f4030cd' +
|
||||
'433964b6457ea39476511214f97469b5' +
|
||||
'7dd32dbc560a9a94d00bff07620464a3' +
|
||||
'ad203df7dc7ce360c3cd3696d9d9fab9' +
|
||||
'0f00',
|
||||
},
|
||||
{
|
||||
secretKey:
|
||||
'833fe62409237b9d62ec77587520911e9a759cec1d19755b7da901b96dca3d42ef7822e0d5104127dc05d6dbefde69e3ab2cec7c867c6e2c49',
|
||||
publicKey:
|
||||
'259b71c19f83ef77a7abd26524cbdb3161b590a48f7d17de3ee0ba9c52beb743c09428a131d6b1b57303d90d8132c276d5ed3d5d01c0f53880',
|
||||
message: '616263',
|
||||
context: '666f6f',
|
||||
signature:
|
||||
'c32299d46ec8ff02b54540982814dce9' +
|
||||
'a05812f81962b649d528095916a2aa48' +
|
||||
'1065b1580423ef927ecf0af5888f90da' +
|
||||
'0f6a9a85ad5dc3f280d91224ba9911a3' +
|
||||
'653d00e484e2ce232521481c8658df30' +
|
||||
'4bb7745a73514cdb9bf3e15784ab7128' +
|
||||
'4f8d0704a608c54a6b62d97beb511d13' +
|
||||
'2100',
|
||||
},
|
||||
];
|
||||
|
||||
for (let i = 0; i < VECTORS_RFC8032_PH.length; i++) {
|
||||
const v = VECTORS_RFC8032_PH[i];
|
||||
should(`RFC8032ph/${i}`, () => {
|
||||
deepStrictEqual(hex(ed448ph.getPublicKey(v.secretKey)), v.publicKey);
|
||||
deepStrictEqual(hex(ed448ph.sign(v.message, v.secretKey, v.context)), v.signature);
|
||||
deepStrictEqual(ed448ph.verify(v.signature, v.message, v.publicKey, v.context), true);
|
||||
});
|
||||
}
|
||||
|
||||
should('X448 base point', () => {
|
||||
const { x, y } = ed448.Point.BASE;
|
||||
const { P } = ed448.CURVE;
|
||||
const invX = ed448.utils.invert(x * x, P); // x^2
|
||||
const u = ed448.utils.mod(y * y * invX, P); // (y^2/x^2)
|
||||
deepStrictEqual(hex(numberToBytesLE(u, 56)), x448.Gu);
|
||||
});
|
||||
|
||||
// ESM is broken.
|
||||
import url from 'url';
|
||||
if (import.meta.url === url.pathToFileURL(process.argv[1]).href) {
|
||||
should.run();
|
||||
}
|
||||
@ -28,16 +28,16 @@
|
||||
"Uy": "EEAB6F3DEBE455E3DBF85416F7030CBD94F34F2D6F232C69F3C1385A",
|
||||
"cases": [
|
||||
{
|
||||
"k": "C1D1F2F10881088301880506805FEB4825FE09ACB6816C36991AA06D",
|
||||
"k": "AD3029E0278F80643DE33917CE6908C70A8FF50A411F06E41DEDFCDC",
|
||||
"message": "sample",
|
||||
"r": "1CDFE6662DDE1E4A1EC4CDEDF6A1F5A2FB7FBD9145C12113E6ABFD3E",
|
||||
"s": "A6694FD7718A21053F225D3F46197CA699D45006C06F871808F43EBC"
|
||||
"r": "61AA3DA010E8E8406C656BC477A7A7189895E7E840CDFE8FF42307BA",
|
||||
"s": "BC814050DAB5D23770879494F9E0A680DC1AF7161991BDE692B10101"
|
||||
},
|
||||
{
|
||||
"k": "DF8B38D40DCA3E077D0AC520BF56B6D565134D9B5F2EAE0D34900524",
|
||||
"k": "FF86F57924DA248D6E44E8154EB69F0AE2AEBAEE9931D0B5A969F904",
|
||||
"message": "test",
|
||||
"r": "C441CE8E261DED634E4CF84910E4C5D1D22C5CF3B732BB204DBEF019",
|
||||
"s": "902F42847A63BDC5F6046ADA114953120F99442D76510150F372A3F4"
|
||||
"r": "AD04DDE87B84747A243A631EA47A1BA6D1FAA059149AD2440DE6FBA6",
|
||||
"s": "178D49B1AE90E3D8B629BE3DB5683915F4E8C99FDF6E666CF37ADCFD"
|
||||
}
|
||||
]
|
||||
},
|
||||
@ -4,14 +4,9 @@ import { should } from 'micro-should';
|
||||
import './basic.test.js';
|
||||
import './nist.test.js';
|
||||
import './ed448.test.js';
|
||||
import './ed448-addons.test.js';
|
||||
import './ed25519.test.js';
|
||||
import './ed25519-addons.test.js';
|
||||
import './secp256k1.test.js';
|
||||
import './secp256k1-schnorr.test.js';
|
||||
import './stark/stark.test.js';
|
||||
import './jubjub.test.js';
|
||||
import './hash-to-curve.test.js';
|
||||
import './poseidon.test.js';
|
||||
import './bls12-381.test.js';
|
||||
|
||||
should.run();
|
||||
74
curve-definitions/test/jubjub.test.js
Normal file
74
curve-definitions/test/jubjub.test.js
Normal file
@ -0,0 +1,74 @@
|
||||
import { jubjub, findGroupHash } from '../lib/jubjub.js';
|
||||
import { should } from 'micro-should';
|
||||
import { deepStrictEqual, throws } from 'assert';
|
||||
import { hexToBytes, bytesToHex } from '@noble/hashes/utils';
|
||||
|
||||
const G_SPEND = new jubjub.ExtendedPoint(
|
||||
0x055f1f24f0f0512287e51c3c5a0a6903fc0baf8711de9eafd7c0e66f69d8d2dbn,
|
||||
0x566178b2505fdd52132a5007d80a04652842e78ffb376897588f406278214ed7n,
|
||||
0x0141fafa1f11088a3b2007c14d652375888f3b37838ba6bdffae096741ceddfen,
|
||||
0x12eada93c0b7d595f5f04f5ebfb4b7d033ef2884136475cab5e41ce17db5be9cn
|
||||
);
|
||||
const G_PROOF = new jubjub.ExtendedPoint(
|
||||
0x0174d54ce9fad258a2f8a86a1deabf15c7a2b51106b0fbcd9d29020f78936f71n,
|
||||
0x16871d6d877dcd222e4ec3bccb3f37cb1865a2d37dd3a5dcbc032a69b62b4445n,
|
||||
0x57a3cd31e496d82bd4aa78bd5ecd751cfb76d54a5d3f4560866379f9fc11c9b3n,
|
||||
0x42cc53f6b519d1f4f52c47ff1256463a616c2c2f49ffe77765481eca04c72081n
|
||||
);
|
||||
|
||||
const getXY = (p) => ({ x: p.x, y: p.y });
|
||||
|
||||
should('toHex/fromHex', () => {
|
||||
// More than field
|
||||
throws(() =>
|
||||
jubjub.Point.fromHex(
|
||||
new Uint8Array([
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
])
|
||||
)
|
||||
);
|
||||
// Multiplicative generator (sqrt == null), not on curve.
|
||||
throws(() =>
|
||||
jubjub.Point.fromHex(
|
||||
new Uint8Array([
|
||||
7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0,
|
||||
])
|
||||
)
|
||||
);
|
||||
const tmp = jubjub.Point.fromHex(
|
||||
new Uint8Array([
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0,
|
||||
])
|
||||
);
|
||||
deepStrictEqual(tmp.x, 0x8d51ccce760304d0ec030002760300000001000000000000n);
|
||||
deepStrictEqual(tmp.y, 0n);
|
||||
|
||||
const S = G_SPEND.toAffine().toRawBytes();
|
||||
const S2 = G_SPEND.double().toAffine().toRawBytes();
|
||||
const P = G_PROOF.toAffine().toRawBytes();
|
||||
const P2 = G_PROOF.double().toAffine().toRawBytes();
|
||||
const S_exp = jubjub.Point.fromHex(S);
|
||||
const S2_exp = jubjub.Point.fromHex(S2);
|
||||
const P_exp = jubjub.Point.fromHex(P);
|
||||
const P2_exp = jubjub.Point.fromHex(P2);
|
||||
deepStrictEqual(getXY(G_SPEND.toAffine()), getXY(S_exp));
|
||||
deepStrictEqual(getXY(G_SPEND.double().toAffine()), getXY(S2_exp));
|
||||
deepStrictEqual(getXY(G_PROOF.toAffine()), getXY(P_exp));
|
||||
deepStrictEqual(getXY(G_PROOF.double().toAffine()), getXY(P2_exp));
|
||||
});
|
||||
|
||||
should('Find generators', () => {
|
||||
const spend = findGroupHash(new Uint8Array(), new Uint8Array([90, 99, 97, 115, 104, 95, 71, 95]));
|
||||
const proof = findGroupHash(new Uint8Array(), new Uint8Array([90, 99, 97, 115, 104, 95, 72, 95]));
|
||||
deepStrictEqual(getXY(spend.toAffine()), getXY(G_SPEND.toAffine()));
|
||||
deepStrictEqual(getXY(proof.toAffine()), getXY(G_PROOF.toAffine()));
|
||||
});
|
||||
|
||||
// ESM is broken.
|
||||
import url from 'url';
|
||||
if (import.meta.url === url.pathToFileURL(process.argv[1]).href) {
|
||||
should.run();
|
||||
}
|
||||
387
curve-definitions/test/nist.test.js
Normal file
387
curve-definitions/test/nist.test.js
Normal file
@ -0,0 +1,387 @@
|
||||
import { deepStrictEqual, throws } from 'assert';
|
||||
import { should } from 'micro-should';
|
||||
import { secp192r1, P192 } from '../lib/p192.js';
|
||||
import { secp224r1, P224 } from '../lib/p224.js';
|
||||
import { secp256r1, P256 } from '../lib/p256.js';
|
||||
import { secp384r1, P384 } from '../lib/p384.js';
|
||||
import { secp521r1, P521 } from '../lib/p521.js';
|
||||
import { secp256k1 } from '../lib/secp256k1.js';
|
||||
import { hexToBytes, bytesToHex } from '@noble/curves/utils';
|
||||
import { default as ecdsa } from './wycheproof/ecdsa_test.json' assert { type: 'json' };
|
||||
import { default as ecdh } from './wycheproof/ecdh_test.json' assert { type: 'json' };
|
||||
import { default as rfc6979 } from './fixtures/rfc6979.json' assert { type: 'json' };
|
||||
|
||||
const hex = bytesToHex;
|
||||
|
||||
// prettier-ignore
|
||||
const NIST = {
|
||||
secp192r1, P192,
|
||||
secp224r1, P224,
|
||||
secp256r1, P256,
|
||||
secp384r1, P384,
|
||||
secp521r1, P521,
|
||||
secp256k1,
|
||||
};
|
||||
|
||||
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');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
import { default as ecdh_secp224r1_test } from './wycheproof/ecdh_secp224r1_test.json' assert { type: 'json' };
|
||||
import { default as ecdh_secp256r1_test } from './wycheproof/ecdh_secp256r1_test.json' assert { type: 'json' };
|
||||
import { default as ecdh_secp256k1_test } from './wycheproof/ecdh_secp256k1_test.json' assert { type: 'json' };
|
||||
import { default as ecdh_secp384r1_test } from './wycheproof/ecdh_secp384r1_test.json' assert { type: 'json' };
|
||||
import { default as ecdh_secp521r1_test } from './wycheproof/ecdh_secp521r1_test.json' assert { type: 'json' };
|
||||
|
||||
// More per curve tests
|
||||
const WYCHEPROOF_ECDH = {
|
||||
P224: {
|
||||
curve: P224,
|
||||
tests: [ecdh_secp224r1_test],
|
||||
},
|
||||
P256: {
|
||||
curve: P256,
|
||||
tests: [ecdh_secp256r1_test],
|
||||
},
|
||||
secp256k1: {
|
||||
curve: secp256k1,
|
||||
tests: [ecdh_secp256k1_test],
|
||||
},
|
||||
P384: {
|
||||
curve: P384,
|
||||
tests: [ecdh_secp384r1_test],
|
||||
},
|
||||
P521: {
|
||||
curve: P521,
|
||||
tests: [ecdh_secp521r1_test],
|
||||
},
|
||||
};
|
||||
|
||||
for (const name in WYCHEPROOF_ECDH) {
|
||||
const { curve, tests } = WYCHEPROOF_ECDH[name];
|
||||
for (let i = 0; i < tests.length; i++) {
|
||||
const test = tests[i];
|
||||
for (let j = 0; j < test.testGroups.length; j++) {
|
||||
const group = test.testGroups[j];
|
||||
should(`Wycheproof/ECDH ${name} (${i}/${j})`, () => {
|
||||
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(hex(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');
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Tests with custom hashes
|
||||
import { default as secp224r1_sha224_test } from './wycheproof/ecdsa_secp224r1_sha224_test.json' assert { type: 'json' };
|
||||
import { default as secp224r1_sha256_test } from './wycheproof/ecdsa_secp224r1_sha256_test.json' assert { type: 'json' };
|
||||
import { default as secp224r1_sha3_224_test } from './wycheproof/ecdsa_secp224r1_sha3_224_test.json' assert { type: 'json' };
|
||||
import { default as secp224r1_sha3_256_test } from './wycheproof/ecdsa_secp224r1_sha3_256_test.json' assert { type: 'json' };
|
||||
import { default as secp224r1_sha3_512_test } from './wycheproof/ecdsa_secp224r1_sha3_512_test.json' assert { type: 'json' };
|
||||
import { default as secp224r1_sha512_test } from './wycheproof/ecdsa_secp224r1_sha512_test.json' assert { type: 'json' };
|
||||
|
||||
import { default as secp256k1_sha256_test } from './wycheproof/ecdsa_secp256k1_sha256_test.json' assert { type: 'json' };
|
||||
import { default as secp256k1_sha3_256_test } from './wycheproof/ecdsa_secp256k1_sha3_256_test.json' assert { type: 'json' };
|
||||
import { default as secp256k1_sha3_512_test } from './wycheproof/ecdsa_secp256k1_sha3_512_test.json' assert { type: 'json' };
|
||||
import { default as secp256k1_sha512_test } from './wycheproof/ecdsa_secp256k1_sha512_test.json' assert { type: 'json' };
|
||||
|
||||
import { default as secp256r1_sha256_test } from './wycheproof/ecdsa_secp256r1_sha256_test.json' assert { type: 'json' };
|
||||
import { default as secp256r1_sha3_256_test } from './wycheproof/ecdsa_secp256r1_sha3_256_test.json' assert { type: 'json' };
|
||||
import { default as secp256r1_sha3_512_test } from './wycheproof/ecdsa_secp256r1_sha3_512_test.json' assert { type: 'json' };
|
||||
import { default as secp256r1_sha512_test } from './wycheproof/ecdsa_secp256r1_sha512_test.json' assert { type: 'json' };
|
||||
|
||||
import { default as secp384r1_sha384_test } from './wycheproof/ecdsa_secp384r1_sha384_test.json' assert { type: 'json' };
|
||||
import { default as secp384r1_sha3_384_test } from './wycheproof/ecdsa_secp384r1_sha3_384_test.json' assert { type: 'json' };
|
||||
import { default as secp384r1_sha3_512_test } from './wycheproof/ecdsa_secp384r1_sha3_512_test.json' assert { type: 'json' };
|
||||
import { default as secp384r1_sha512_test } from './wycheproof/ecdsa_secp384r1_sha512_test.json' assert { type: 'json' };
|
||||
|
||||
import { default as secp521r1_sha3_512_test } from './wycheproof/ecdsa_secp521r1_sha3_512_test.json' assert { type: 'json' };
|
||||
import { default as secp521r1_sha512_test } from './wycheproof/ecdsa_secp521r1_sha512_test.json' assert { type: 'json' };
|
||||
|
||||
import { sha3_224, sha3_256, sha3_384, sha3_512 } from '@noble/hashes/sha3';
|
||||
import { sha512, sha384 } from '@noble/hashes/sha512';
|
||||
import { sha256 } from '@noble/hashes/sha256';
|
||||
|
||||
const WYCHEPROOF_ECDSA = {
|
||||
P224: {
|
||||
curve: P224,
|
||||
hashes: {
|
||||
// sha224 not released yet
|
||||
// sha224: {
|
||||
// hash: sha224,
|
||||
// tests: [secp224r1_sha224_test],
|
||||
// },
|
||||
sha256: {
|
||||
hash: sha256,
|
||||
tests: [secp224r1_sha256_test],
|
||||
},
|
||||
sha3_224: {
|
||||
hash: sha3_224,
|
||||
tests: [secp224r1_sha3_224_test],
|
||||
},
|
||||
sha3_256: {
|
||||
hash: sha3_256,
|
||||
tests: [secp224r1_sha3_256_test],
|
||||
},
|
||||
sha3_512: {
|
||||
hash: sha3_512,
|
||||
tests: [secp224r1_sha3_512_test],
|
||||
},
|
||||
sha512: {
|
||||
hash: sha512,
|
||||
tests: [secp224r1_sha512_test],
|
||||
},
|
||||
},
|
||||
},
|
||||
secp256k1: {
|
||||
curve: secp256k1,
|
||||
hashes: {
|
||||
// TODO: debug why fails, can be bug
|
||||
sha256: {
|
||||
hash: sha256,
|
||||
tests: [secp256k1_sha256_test],
|
||||
},
|
||||
sha3_256: {
|
||||
hash: sha3_256,
|
||||
tests: [secp256k1_sha3_256_test],
|
||||
},
|
||||
sha3_512: {
|
||||
hash: sha3_512,
|
||||
tests: [secp256k1_sha3_512_test],
|
||||
},
|
||||
sha512: {
|
||||
hash: sha512,
|
||||
tests: [secp256k1_sha512_test],
|
||||
},
|
||||
},
|
||||
},
|
||||
P256: {
|
||||
curve: P256,
|
||||
hashes: {
|
||||
sha256: {
|
||||
hash: sha256,
|
||||
tests: [secp256r1_sha256_test],
|
||||
},
|
||||
sha3_256: {
|
||||
hash: sha3_256,
|
||||
tests: [secp256r1_sha3_256_test],
|
||||
},
|
||||
sha3_512: {
|
||||
hash: sha3_512,
|
||||
tests: [secp256r1_sha3_512_test],
|
||||
},
|
||||
sha512: {
|
||||
hash: sha512,
|
||||
tests: [secp256r1_sha512_test],
|
||||
},
|
||||
},
|
||||
},
|
||||
P384: {
|
||||
curve: P384,
|
||||
hashes: {
|
||||
sha384: {
|
||||
hash: sha384,
|
||||
tests: [secp384r1_sha384_test],
|
||||
},
|
||||
sha3_384: {
|
||||
hash: sha3_384,
|
||||
tests: [secp384r1_sha3_384_test],
|
||||
},
|
||||
sha3_512: {
|
||||
hash: sha3_512,
|
||||
tests: [secp384r1_sha3_512_test],
|
||||
},
|
||||
sha512: {
|
||||
hash: sha512,
|
||||
tests: [secp384r1_sha512_test],
|
||||
},
|
||||
},
|
||||
},
|
||||
P521: {
|
||||
curve: P521,
|
||||
hashes: {
|
||||
sha3_512: {
|
||||
hash: sha3_512,
|
||||
tests: [secp521r1_sha3_512_test],
|
||||
},
|
||||
sha512: {
|
||||
hash: sha512,
|
||||
tests: [secp521r1_sha512_test],
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
function runWycheproof(name, CURVE, group, index) {
|
||||
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) {
|
||||
const m = CURVE.CURVE.hash(hexToBytes(test.msg));
|
||||
|
||||
if (test.result === 'valid' || test.result === 'acceptable') {
|
||||
try {
|
||||
CURVE.Signature.fromDER(test.sig);
|
||||
} catch (e) {
|
||||
// Some tests 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);
|
||||
if (name === 'secp256k1') {
|
||||
// lowS: true for secp256k1
|
||||
deepStrictEqual(verified, !CURVE.Signature.fromDER(test.sig).hasHighS(), `${index}: valid`);
|
||||
} else {
|
||||
deepStrictEqual(verified, true, `${index}: valid`);
|
||||
}
|
||||
|
||||
} else if (test.result === 'invalid') {
|
||||
let failed = false;
|
||||
try {
|
||||
failed = !CURVE.verify(test.sig, m, pubKey);
|
||||
} catch (error) {
|
||||
failed = true;
|
||||
}
|
||||
deepStrictEqual(failed, true, `${index}: invalid`);
|
||||
} else throw new Error('unknown test result');
|
||||
}
|
||||
}
|
||||
|
||||
for (const name in WYCHEPROOF_ECDSA) {
|
||||
const { curve, hashes } = WYCHEPROOF_ECDSA[name];
|
||||
for (const hName in hashes) {
|
||||
const { hash, tests } = hashes[hName];
|
||||
const CURVE = curve.create(hash);
|
||||
should(`Wycheproof/WYCHEPROOF_ECDSA ${name}/${hName}`, () => {
|
||||
for (let i = 0; i < tests.length; i++) {
|
||||
const groups = tests[i].testGroups;
|
||||
for (let j = 0; j < groups.length; j++) {
|
||||
const group = groups[j];
|
||||
runWycheproof(name, CURVE, group, `${i}/${j}`);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const hexToBigint = (hex) => 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);
|
||||
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();
|
||||
}
|
||||
534
curve-definitions/test/secp256k1.test.js
Normal file
534
curve-definitions/test/secp256k1.test.js
Normal file
@ -0,0 +1,534 @@
|
||||
import * as fc from 'fast-check';
|
||||
import { secp256k1, schnorr } from '../lib/secp256k1.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 } from 'assert';
|
||||
import { hexToBytes, bytesToHex } from '@noble/hashes/utils';
|
||||
|
||||
const hex = bytesToHex;
|
||||
const secp = 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', () => {
|
||||
for (const vector of ecdsa.valid) {
|
||||
let usig = 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', () => {
|
||||
for (const vector of ecdsa.invalid.sign) {
|
||||
throws(() => secp.sign(vector.m, vector.d));
|
||||
}
|
||||
});
|
||||
|
||||
should('secp256k1.sign()/edge cases', () => {
|
||||
throws(() => secp.sign());
|
||||
throws(() => secp.sign(''));
|
||||
});
|
||||
|
||||
should('secp256k1.sign()/should create correct DER encoding against libsecp256k1', () => {
|
||||
const CASES = [
|
||||
[
|
||||
'd1a9dc8ed4e46a6a3e5e594615ca351d7d7ef44df1e4c94c1802f3592183794b',
|
||||
'304402203de2559fccb00c148574997f660e4d6f40605acc71267ee38101abf15ff467af02200950abdf40628fd13f547792ba2fc544681a485f2fdafb5c3b909a4df7350e6b',
|
||||
],
|
||||
[
|
||||
'5f97983254982546d3976d905c6165033976ee449d300d0e382099fa74deaf82',
|
||||
'3045022100c046d9ff0bd2845b9aa9dff9f997ecebb31e52349f80fe5a5a869747d31dcb88022011f72be2a6d48fe716b825e4117747b397783df26914a58139c3f4c5cbb0e66c',
|
||||
],
|
||||
[
|
||||
'0d7017a96b97cd9be21cf28aada639827b2814a654a478c81945857196187808',
|
||||
'3045022100d18990bba7832bb283e3ecf8700b67beb39acc73f4200ed1c331247c46edccc602202e5c8bbfe47ae159512c583b30a3fa86575cddc62527a03de7756517ae4c6c73',
|
||||
],
|
||||
];
|
||||
const privKey = hexToBytes('0101010101010101010101010101010101010101010101010101010101010101');
|
||||
for (const [msg, exp] of CASES) {
|
||||
const res = 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', () => {
|
||||
const ent1 = '0000000000000000000000000000000000000000000000000000000000000000';
|
||||
const ent2 = '0000000000000000000000000000000000000000000000000000000000000001';
|
||||
const ent3 = '6e723d3fd94ed5d2b6bdd4f123364b0f3ca52af829988a63f8afe91d29db1c33';
|
||||
const ent4 = 'fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141';
|
||||
const ent5 = 'ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff';
|
||||
|
||||
for (const e of ecdsa.extraEntropy) {
|
||||
const sign = (extraEntropy) => {
|
||||
const s = secp.sign(e.m, e.d, { extraEntropy }).toCompactHex();
|
||||
return s;
|
||||
};
|
||||
deepStrictEqual(sign(), e.signature);
|
||||
deepStrictEqual(sign(ent1), e.extraEntropy0);
|
||||
deepStrictEqual(sign(ent2), e.extraEntropy1);
|
||||
deepStrictEqual(sign(ent3), e.extraEntropyRand);
|
||||
deepStrictEqual(sign(ent4), e.extraEntropyN);
|
||||
deepStrictEqual(sign(ent5), e.extraEntropyMax);
|
||||
}
|
||||
});
|
||||
|
||||
should('secp256k1.verify()/should verify signature', () => {
|
||||
const MSG = '01'.repeat(32);
|
||||
const PRIV_KEY = 0x2n;
|
||||
const signature = 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', () => {
|
||||
const MSG = '01'.repeat(32);
|
||||
const PRIV_KEY = 0x2n;
|
||||
const WRONG_PRIV_KEY = 0x22n;
|
||||
const signature = 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', () => {
|
||||
const MSG = '01'.repeat(32);
|
||||
const PRIV_KEY = 0x2n;
|
||||
const WRONG_MSG = '11'.repeat(32);
|
||||
const signature = 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', () =>
|
||||
fc.assert(
|
||||
fc.property(FC_BIGINT, fc.hexaString({ minLength: 64, maxLength: 64 }), (privKey, msg) => {
|
||||
const pub = secp.getPublicKey(privKey);
|
||||
const sig = 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);
|
||||
signature.r = r;
|
||||
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', () => {
|
||||
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...', () => {
|
||||
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);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// index,secret key,public key,aux_rand,message,signature,verification result,comment
|
||||
const vectors = schCsv
|
||||
.split('\n')
|
||||
.map((line) => line.split(','))
|
||||
.slice(1, -1);
|
||||
for (let vec of vectors) {
|
||||
const [index, sec, pub, rnd, msg, expSig, passes, comment] = vec;
|
||||
should(`sign with Schnorr scheme vector ${index}`, () => {
|
||||
if (sec) {
|
||||
deepStrictEqual(hex(schnorr.getPublicKey(sec)), pub.toLowerCase());
|
||||
const sig = schnorr.sign(msg, sec, rnd);
|
||||
deepStrictEqual(hex(sig), expSig.toLowerCase());
|
||||
deepStrictEqual(schnorr.verify(sig, msg, pub), true);
|
||||
} else {
|
||||
const passed = schnorr.verify(expSig, msg, pub);
|
||||
deepStrictEqual(passed, passes === 'TRUE');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
should('secp256k1.recoverPublicKey()/should recover public key from recovery bit', () => {
|
||||
const message = '00000000000000000000000000000000000000000000000000000000deadbeef';
|
||||
const privateKey = 123456789n;
|
||||
const publicKey = secp.Point.fromHex(secp.getPublicKey(privateKey)).toHex(false);
|
||||
const sig = 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', () => {
|
||||
const privKey = secp.utils.randomPrivateKey();
|
||||
const pub = secp.getPublicKey(privKey);
|
||||
const zeros = '0000000000000000000000000000000000000000000000000000000000000000';
|
||||
const sig = secp.sign(zeros, privKey, { recovered: true });
|
||||
const recoveredKey = sig.recoverPublicKey(zeros);
|
||||
deepStrictEqual(recoveredKey.toRawBytes(), pub);
|
||||
});
|
||||
should('secp256k1.recoverPublicKey()/should handle RFC 6979 vectors', () => {
|
||||
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();
|
||||
200
curve-definitions/test/stark/basic.test.js
Normal file
200
curve-definitions/test/stark/basic.test.js
Normal file
@ -0,0 +1,200 @@
|
||||
import { deepStrictEqual, throws } from 'assert';
|
||||
import { should } from 'micro-should';
|
||||
import * as starknet from '../../lib/stark.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();
|
||||
}
|
||||
57
curve-definitions/test/stark/benchmark/index.js
Normal file
57
curve-definitions/test/stark/benchmark/index.js
Normal file
@ -0,0 +1,57 @@
|
||||
import * as microStark from '../../../lib/stark.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();
|
||||
19
curve-definitions/test/stark/benchmark/package.json
Normal file
19
curve-definitions/test/stark/benchmark/package.json
Normal file
@ -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"
|
||||
}
|
||||
}
|
||||
1306
curve-definitions/test/stark/fixtures/issue2.json
Normal file
1306
curve-definitions/test/stark/fixtures/issue2.json
Normal file
File diff suppressed because it is too large
Load Diff
32
curve-definitions/test/stark/fixtures/keys_precomputed.json
Normal file
32
curve-definitions/test/stark/fixtures/keys_precomputed.json
Normal file
@ -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"
|
||||
}
|
||||
]
|
||||
}
|
||||
5
curve-definitions/test/stark/index.test.js
Normal file
5
curve-definitions/test/stark/index.test.js
Normal file
@ -0,0 +1,5 @@
|
||||
|
||||
import './basic.test.js';
|
||||
import './stark.test.js';
|
||||
import './property.test.js';
|
||||
|
||||
51
curve-definitions/test/stark/property.test.js
Normal file
51
curve-definitions/test/stark/property.test.js
Normal file
@ -0,0 +1,51 @@
|
||||
import { deepStrictEqual, throws } from 'assert';
|
||||
import { should } from 'micro-should';
|
||||
import * as starknet from '../../lib/stark.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();
|
||||
}
|
||||
286
curve-definitions/test/stark/stark.test.js
Normal file
286
curve-definitions/test/stark/stark.test.js
Normal file
@ -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/stark.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();
|
||||
}
|
||||
4545
curve-definitions/test/vectors/ecdh.json
Normal file
4545
curve-definitions/test/vectors/ecdh.json
Normal file
File diff suppressed because it is too large
Load Diff
4474
curve-definitions/test/vectors/wychenproof.json
Normal file
4474
curve-definitions/test/vectors/wychenproof.json
Normal file
File diff suppressed because it is too large
Load Diff
@ -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"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
3581
curve-definitions/test/wycheproof/ecdh_secp224r1_test.json
Normal file
3581
curve-definitions/test/wycheproof/ecdh_secp224r1_test.json
Normal file
File diff suppressed because it is too large
Load Diff
4545
curve-definitions/test/wycheproof/ecdh_secp256k1_test.json
Normal file
4545
curve-definitions/test/wycheproof/ecdh_secp256k1_test.json
Normal file
File diff suppressed because it is too large
Load Diff
1994
curve-definitions/test/wycheproof/ecdh_secp256r1_ecpoint_test.json
Normal file
1994
curve-definitions/test/wycheproof/ecdh_secp256r1_ecpoint_test.json
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
1672
curve-definitions/test/wycheproof/ecdh_secp384r1_ecpoint_test.json
Normal file
1672
curve-definitions/test/wycheproof/ecdh_secp384r1_ecpoint_test.json
Normal file
File diff suppressed because it is too large
Load Diff
4366
curve-definitions/test/wycheproof/ecdh_secp384r1_test.json
Normal file
4366
curve-definitions/test/wycheproof/ecdh_secp384r1_test.json
Normal file
File diff suppressed because it is too large
Load Diff
2196
curve-definitions/test/wycheproof/ecdh_secp521r1_ecpoint_test.json
Normal file
2196
curve-definitions/test/wycheproof/ecdh_secp521r1_ecpoint_test.json
Normal file
File diff suppressed because it is too large
Load Diff
4868
curve-definitions/test/wycheproof/ecdh_secp521r1_test.json
Normal file
4868
curve-definitions/test/wycheproof/ecdh_secp521r1_test.json
Normal file
File diff suppressed because it is too large
Load Diff
4218
curve-definitions/test/wycheproof/ecdsa_secp224r1_sha224_test.json
Normal file
4218
curve-definitions/test/wycheproof/ecdsa_secp224r1_sha224_test.json
Normal file
File diff suppressed because it is too large
Load Diff
4447
curve-definitions/test/wycheproof/ecdsa_secp224r1_sha256_test.json
Normal file
4447
curve-definitions/test/wycheproof/ecdsa_secp224r1_sha256_test.json
Normal file
File diff suppressed because it is too large
Load Diff
4444
curve-definitions/test/wycheproof/ecdsa_secp224r1_sha3_224_test.json
Normal file
4444
curve-definitions/test/wycheproof/ecdsa_secp224r1_sha3_224_test.json
Normal file
File diff suppressed because it is too large
Load Diff
4516
curve-definitions/test/wycheproof/ecdsa_secp224r1_sha3_256_test.json
Normal file
4516
curve-definitions/test/wycheproof/ecdsa_secp224r1_sha3_256_test.json
Normal file
File diff suppressed because it is too large
Load Diff
5036
curve-definitions/test/wycheproof/ecdsa_secp224r1_sha3_512_test.json
Normal file
5036
curve-definitions/test/wycheproof/ecdsa_secp224r1_sha3_512_test.json
Normal file
File diff suppressed because it is too large
Load Diff
5002
curve-definitions/test/wycheproof/ecdsa_secp224r1_sha512_test.json
Normal file
5002
curve-definitions/test/wycheproof/ecdsa_secp224r1_sha512_test.json
Normal file
File diff suppressed because it is too large
Load Diff
4474
curve-definitions/test/wycheproof/ecdsa_secp256k1_sha256_test.json
Normal file
4474
curve-definitions/test/wycheproof/ecdsa_secp256k1_sha256_test.json
Normal file
File diff suppressed because it is too large
Load Diff
4538
curve-definitions/test/wycheproof/ecdsa_secp256k1_sha3_256_test.json
Normal file
4538
curve-definitions/test/wycheproof/ecdsa_secp256k1_sha3_256_test.json
Normal file
File diff suppressed because it is too large
Load Diff
5066
curve-definitions/test/wycheproof/ecdsa_secp256k1_sha3_512_test.json
Normal file
5066
curve-definitions/test/wycheproof/ecdsa_secp256k1_sha3_512_test.json
Normal file
File diff suppressed because it is too large
Load Diff
5034
curve-definitions/test/wycheproof/ecdsa_secp256k1_sha512_test.json
Normal file
5034
curve-definitions/test/wycheproof/ecdsa_secp256k1_sha512_test.json
Normal file
File diff suppressed because it is too large
Load Diff
4578
curve-definitions/test/wycheproof/ecdsa_secp256r1_sha256_test.json
Normal file
4578
curve-definitions/test/wycheproof/ecdsa_secp256r1_sha256_test.json
Normal file
File diff suppressed because it is too large
Load Diff
4642
curve-definitions/test/wycheproof/ecdsa_secp256r1_sha3_256_test.json
Normal file
4642
curve-definitions/test/wycheproof/ecdsa_secp256r1_sha3_256_test.json
Normal file
File diff suppressed because it is too large
Load Diff
5172
curve-definitions/test/wycheproof/ecdsa_secp256r1_sha3_512_test.json
Normal file
5172
curve-definitions/test/wycheproof/ecdsa_secp256r1_sha3_512_test.json
Normal file
File diff suppressed because it is too large
Load Diff
5138
curve-definitions/test/wycheproof/ecdsa_secp256r1_sha512_test.json
Normal file
5138
curve-definitions/test/wycheproof/ecdsa_secp256r1_sha512_test.json
Normal file
File diff suppressed because it is too large
Load Diff
4634
curve-definitions/test/wycheproof/ecdsa_secp384r1_sha384_test.json
Normal file
4634
curve-definitions/test/wycheproof/ecdsa_secp384r1_sha384_test.json
Normal file
File diff suppressed because it is too large
Load Diff
4711
curve-definitions/test/wycheproof/ecdsa_secp384r1_sha3_384_test.json
Normal file
4711
curve-definitions/test/wycheproof/ecdsa_secp384r1_sha3_384_test.json
Normal file
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user