Compare commits
260 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b8ddb603c1 | ||
|
|
943edbceba | ||
|
|
0a663391bd | ||
|
|
7be1dfc55d | ||
|
|
37eab5a28a | ||
|
|
2706fe9f79 | ||
|
|
b39b0d1daf | ||
|
|
4007ee975b | ||
|
|
f8af434b9c | ||
|
|
be8033a2d8 | ||
|
|
b3c239981b | ||
|
|
18b0bc6317 | ||
|
|
30f68c9e54 | ||
|
|
ada1ea5a19 | ||
|
|
0a3a13b3dc | ||
|
|
26a4fd4293 | ||
|
|
9db14fc6d0 | ||
|
|
8e6c19de2b | ||
|
|
4ffb68853d | ||
|
|
008958364e | ||
|
|
1c535a3287 | ||
|
|
b8b12671ac | ||
|
|
2f1460a4d7 | ||
|
|
fb02e93ff6 | ||
|
|
c525356916 | ||
|
|
a4abd8a202 | ||
|
|
c19373a0b5 | ||
|
|
85006ed620 | ||
|
|
fae7f6612a | ||
|
|
36894729c0 | ||
|
|
eabab627c7 | ||
|
|
e1640eb74e | ||
|
|
7f851873f9 | ||
|
|
02099b9b4c | ||
|
|
3b14683806 | ||
|
|
47169740c6 | ||
|
|
45c7cb560d | ||
|
|
b36bf44f4b | ||
|
|
30763066ac | ||
|
|
911801ec0f | ||
|
|
8ba25a1c40 | ||
|
|
43a06b669a | ||
|
|
e7720c1609 | ||
|
|
2da6abb336 | ||
|
|
4752ab1f1e | ||
|
|
f58002e6d4 | ||
|
|
d0294bb2a6 | ||
|
|
2b41e387de | ||
|
|
08850c2d6a | ||
|
|
ce7a8fda55 | ||
|
|
728b485cd8 | ||
|
|
eaefe9a272 | ||
|
|
c935b398fe | ||
|
|
ddad219e7a | ||
|
|
1d83bab27d | ||
|
|
4be208e4b2 | ||
|
|
77bee0d54e | ||
|
|
6bcab6c24b | ||
|
|
7befd5f881 | ||
|
|
8f78471703 | ||
|
|
17294f4974 | ||
|
|
3890b79e7e | ||
|
|
2acebc8176 | ||
|
|
1e67754943 | ||
|
|
156a1e909a | ||
|
|
ccea23a712 | ||
|
|
8661eef949 | ||
|
|
4743182bf7 | ||
|
|
5c477a88fa | ||
|
|
df9d461adf | ||
|
|
5c21fa3855 | ||
|
|
6661a7db7b | ||
|
|
cf5f2268fb | ||
|
|
1d5286ffa7 | ||
|
|
e31efd91d8 | ||
|
|
c5e0e070d1 | ||
|
|
0d7756dceb | ||
|
|
b716b4603f | ||
|
|
d7a139822d | ||
|
|
fb6c379a26 | ||
|
|
eeac255c88 | ||
|
|
925fc3f810 | ||
|
|
eb8e7ec964 | ||
|
|
e7ac5e85d3 | ||
|
|
d285fcce06 | ||
|
|
ef667bb404 | ||
|
|
62749382e7 | ||
|
|
f90e871725 | ||
|
|
f049398718 | ||
|
|
ca99179bd8 | ||
|
|
1545230ee5 | ||
|
|
b082d41c29 | ||
|
|
2ce3b825f8 | ||
|
|
8315fe3580 | ||
|
|
9b7889e16f | ||
|
|
e8b9509c16 | ||
|
|
d92c9d14ad | ||
|
|
05794c0283 | ||
|
|
ca5583f713 | ||
|
|
8c48abe16a | ||
|
|
08bb00cc8f | ||
|
|
1ef16033fe | ||
|
|
113b6d7c00 | ||
|
|
5c3dc0be50 | ||
|
|
e7d01f4038 | ||
|
|
9a39625eda | ||
|
|
af8462b09e | ||
|
|
bfd9ae040d | ||
|
|
2bd437df4e | ||
|
|
b0af0a8977 | ||
|
|
aee10c8141 | ||
|
|
ff92bafb6f | ||
|
|
54679ff788 | ||
|
|
ee4571c7a1 | ||
|
|
fe7afdd392 | ||
|
|
dba2f0e732 | ||
|
|
52c5df0264 | ||
|
|
ebea4a4bcd | ||
|
|
33a53006f7 | ||
|
|
549e286ef0 | ||
|
|
3f0c0b59f1 | ||
|
|
62205347e1 | ||
|
|
476e75104f | ||
|
|
413725cfb3 | ||
|
|
cf17f7fe01 | ||
|
|
49fb90ae9a | ||
|
|
309d29a084 | ||
|
|
d3aa051770 | ||
|
|
5609ec7644 | ||
|
|
af8c1eebee | ||
|
|
08ea57ce5c | ||
|
|
ee3d3815b4 | ||
|
|
f471405798 | ||
|
|
e3a4bbffe9 | ||
|
|
c2edc97868 | ||
|
|
bf70ba9776 | ||
|
|
c71920722c | ||
|
|
62e806cfaf | ||
|
|
6a72821185 | ||
|
|
8cee1f559f | ||
|
|
6f10632ac0 | ||
|
|
b281167e8d | ||
|
|
c6b4aadafb | ||
|
|
aade023e48 | ||
|
|
2e04d96ce9 | ||
|
|
79dd7d3426 | ||
|
|
ff5b231e31 | ||
|
|
648fd2cc07 | ||
|
|
f67134ca86 | ||
|
|
6d0678b076 | ||
|
|
53ebde19ea | ||
|
|
a7755332c8 | ||
|
|
5f0007ab24 | ||
|
|
1ee5a5c07f | ||
|
|
708c0e14d5 | ||
|
|
624d7c9910 | ||
|
|
665ef2dd93 | ||
|
|
acc1f26acf | ||
|
|
3c4a25263e | ||
|
|
e887d516ab | ||
|
|
90e87f7ab1 | ||
|
|
5edafbac97 | ||
|
|
554c94509e | ||
|
|
7c11a021c0 | ||
|
|
531b6a3a48 | ||
|
|
fb5cd9df39 | ||
|
|
53a6d636d4 | ||
|
|
42de620010 | ||
|
|
6621053c7d | ||
|
|
9bee88888f | ||
|
|
103ba5f0a7 | ||
|
|
d5de5d2659 | ||
|
|
217cf8c654 | ||
|
|
8e307d8f89 | ||
|
|
8c0018d57f | ||
|
|
ca7f202839 | ||
|
|
816077ac0a | ||
|
|
bc03a07043 | ||
|
|
63653255e1 | ||
|
|
895ee3a1a4 | ||
|
|
16b31b9087 | ||
|
|
213796db4b | ||
|
|
049d3bce54 | ||
|
|
b2a04c2393 | ||
|
|
cb5e9a6e96 | ||
|
|
36af62357f | ||
|
|
88291eba33 | ||
|
|
848a1b0226 | ||
|
|
972e549dde | ||
|
|
d61c7ae4e5 | ||
|
|
d3de7c8863 | ||
|
|
6316643f51 | ||
|
|
7199f113c6 | ||
|
|
71f6948612 | ||
|
|
d3d03ff115 | ||
|
|
e2c3560686 | ||
|
|
4e9c40b3e5 | ||
|
|
09085d2ee1 | ||
|
|
8c4d781479 | ||
|
|
123431de66 | ||
|
|
7503aff45c | ||
|
|
81e6046698 | ||
|
|
30f7d78c82 | ||
|
|
00665b21ab | ||
|
|
5d54bba846 | ||
|
|
851af4f1bc | ||
|
|
6ea40d9dab | ||
|
|
8beb922ded | ||
|
|
fe380da8c9 | ||
|
|
113d906233 | ||
|
|
65c0dc6c59 | ||
|
|
ed3ba3de6e | ||
|
|
d424c661fb | ||
|
|
31d92cce11 | ||
|
|
c15c964f77 | ||
|
|
37ebe6c40f | ||
|
|
18eabfd3be | ||
|
|
19f04a4c1c | ||
|
|
d0c3bee4de | ||
|
|
4244f97d38 | ||
|
|
618508d32c | ||
|
|
3936449e7b | ||
|
|
0ffa38db6b | ||
|
|
c4c580edc0 | ||
|
|
abe8adac7b | ||
|
|
4fd2ae82b6 | ||
|
|
e2411f7dfd | ||
|
|
cb61e4f292 | ||
|
|
bb875791bd | ||
|
|
3df2553ced | ||
|
|
8fabc7ff06 | ||
|
|
f3c21eb347 | ||
|
|
a8b8192714 | ||
|
|
1c6aa07ff7 | ||
|
|
e110237298 | ||
|
|
45393db807 | ||
|
|
acc3a9dc4d | ||
|
|
9295b0dbae | ||
|
|
5784ef23f6 | ||
|
|
ef55efe842 | ||
|
|
1cfd6a76ca | ||
|
|
89f81b2204 | ||
|
|
d77ac16f51 | ||
|
|
fe68da61f6 | ||
|
|
32c0841bed | ||
|
|
49a659b248 | ||
|
|
9d0a2e25dc | ||
|
|
7c461af2b2 | ||
|
|
4a8f447c8d | ||
|
|
4b2d31ce7f | ||
|
|
16115f27a6 | ||
|
|
0e0d0f530d | ||
|
|
fa5105aef2 | ||
|
|
11f1626ecc | ||
|
|
53ff287bf7 | ||
|
|
214c9aa553 | ||
|
|
ec2c3e1248 | ||
|
|
e64a9d654c | ||
|
|
088edd0fbb | ||
|
|
3e90930e9d |
9
.github/workflows/nodejs.yml
vendored
9
.github/workflows/nodejs.yml
vendored
@@ -3,15 +3,18 @@ name: Node CI
|
|||||||
on: [push, pull_request]
|
on: [push, pull_request]
|
||||||
jobs:
|
jobs:
|
||||||
test:
|
test:
|
||||||
name: v18 @ ubuntu-latest
|
name: v${{ matrix.node }} @ ubuntu-latest
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
node: [18, 20]
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
- name: Use Node.js ${{ matrix.node }}
|
- name: Use Node.js ${{ matrix.node }}
|
||||||
uses: actions/setup-node@v3
|
uses: actions/setup-node@v3
|
||||||
with:
|
with:
|
||||||
node-version: 18
|
node-version: ${{ matrix.node }}
|
||||||
- run: npm install
|
- run: npm install
|
||||||
- run: npm run build --if-present
|
- run: npm run build --if-present
|
||||||
- run: npm run lint --if-present
|
|
||||||
- run: npm test
|
- run: npm test
|
||||||
|
- run: npm run lint --if-present
|
||||||
|
|||||||
23
.github/workflows/publish-npm.yml
vendored
Normal file
23
.github/workflows/publish-npm.yml
vendored
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
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@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3
|
||||||
|
- uses: actions/setup-node@64ed1c7eab4cce3362f8c340dee64e5eaeef8f7c # v3
|
||||||
|
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 }}
|
||||||
16
.gitignore
vendored
16
.gitignore
vendored
@@ -1,13 +1,9 @@
|
|||||||
build/
|
node_modules
|
||||||
node_modules/
|
|
||||||
coverage/
|
|
||||||
/*.js
|
/*.js
|
||||||
/*.ts
|
|
||||||
/*.js.map
|
|
||||||
/*.d.ts.map
|
|
||||||
/esm/*.js
|
/esm/*.js
|
||||||
/esm/*.ts
|
*.d.ts
|
||||||
/esm/*.js.map
|
*.d.ts.map
|
||||||
/esm/*.d.ts.map
|
*.js.map
|
||||||
|
/build
|
||||||
|
/abstract
|
||||||
/esm/abstract
|
/esm/abstract
|
||||||
/abstract/
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
{
|
{
|
||||||
"printWidth": 100,
|
"printWidth": 100,
|
||||||
"singleQuote": true
|
"singleQuote": true,
|
||||||
|
"trailingComma": "es5"
|
||||||
}
|
}
|
||||||
|
|||||||
6
.vscode/settings.json
vendored
Normal file
6
.vscode/settings.json
vendored
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"files.exclude": {
|
||||||
|
"*.{js,d.ts,js.map,d.ts.map}": true,
|
||||||
|
"esm/*.{js,d.ts,js.map,d.ts.map}": true
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,7 @@
|
|||||||
# Security Policy
|
# Security Policy
|
||||||
|
|
||||||
|
See [README's Security section](./README.md#security) for detailed description of internal security practices.
|
||||||
|
|
||||||
## Supported Versions
|
## Supported Versions
|
||||||
|
|
||||||
| Version | Supported |
|
| Version | Supported |
|
||||||
|
|||||||
BIN
audit/2023-01-trailofbits-audit-curves.pdf
Normal file
BIN
audit/2023-01-trailofbits-audit-curves.pdf
Normal file
Binary file not shown.
BIN
audit/2023-09-kudelski-audit-starknet.pdf
Normal file
BIN
audit/2023-09-kudelski-audit-starknet.pdf
Normal file
Binary file not shown.
7
audit/README.md
Normal file
7
audit/README.md
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
# 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.
|
||||||
@@ -39,6 +39,21 @@ run(async () => {
|
|||||||
await mark('sign', 50, () => bls.sign('09', priv));
|
await mark('sign', 50, () => bls.sign('09', priv));
|
||||||
await mark('verify', 50, () => bls.verify(sig, '09', pub));
|
await mark('verify', 50, () => bls.verify(sig, '09', pub));
|
||||||
await mark('pairing', 100, () => bls.pairing(p1, p2));
|
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/8', 100, () => bls.aggregatePublicKeys(pubs.slice(0, 8)));
|
||||||
await mark('aggregatePublicKeys/32', 50, () => bls.aggregatePublicKeys(pub32));
|
await mark('aggregatePublicKeys/32', 50, () => bls.aggregatePublicKeys(pub32));
|
||||||
await mark('aggregatePublicKeys/128', 20, () => bls.aggregatePublicKeys(pub128));
|
await mark('aggregatePublicKeys/128', 20, () => bls.aggregatePublicKeys(pub128));
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
import { run, mark, utils } from 'micro-bmark';
|
import { run, mark, utils } from 'micro-bmark';
|
||||||
import { generateData } from './_shared.js';
|
import { generateData } from './_shared.js';
|
||||||
import { P256 } from '../p256.js';
|
import { p256 } from '../p256.js';
|
||||||
import { P384 } from '../p384.js';
|
import { p384 } from '../p384.js';
|
||||||
import { P521 } from '../p521.js';
|
import { p521 } from '../p521.js';
|
||||||
import { ed25519 } from '../ed25519.js';
|
import { ed25519 } from '../ed25519.js';
|
||||||
import { ed448 } from '../ed448.js';
|
import { ed448 } from '../ed448.js';
|
||||||
|
|
||||||
run(async () => {
|
run(async () => {
|
||||||
const RAM = false
|
const RAM = false
|
||||||
for (let kv of Object.entries({ P256, P384, P521, ed25519, ed448 })) {
|
for (let kv of Object.entries({ ed25519, ed448, p256, p384, p521 })) {
|
||||||
const [name, curve] = kv;
|
const [name, curve] = kv;
|
||||||
console.log();
|
console.log();
|
||||||
console.log(`\x1b[36m${name}\x1b[0m`);
|
console.log(`\x1b[36m${name}\x1b[0m`);
|
||||||
|
|||||||
18
benchmark/decaf448.js
Normal file
18
benchmark/decaf448.js
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
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,14 +1,13 @@
|
|||||||
import { run, mark, compare, utils } from 'micro-bmark';
|
import { run, compare } from 'micro-bmark';
|
||||||
import { generateData } from './_shared.js';
|
|
||||||
import { secp256k1 } from '../secp256k1.js';
|
import { secp256k1 } from '../secp256k1.js';
|
||||||
import { P256 } from '../p256.js';
|
import { p256 } from '../p256.js';
|
||||||
import { P384 } from '../p384.js';
|
import { p384 } from '../p384.js';
|
||||||
import { P521 } from '../p521.js';
|
import { p521 } from '../p521.js';
|
||||||
import { x25519 } from '../ed25519.js';
|
import { x25519 } from '../ed25519.js';
|
||||||
import { x448 } from '../ed448.js';
|
import { x448 } from '../ed448.js';
|
||||||
|
|
||||||
run(async () => {
|
run(async () => {
|
||||||
const curves = { x25519, secp256k1, P256, P384, P521, x448 };
|
const curves = { x25519, secp256k1, p256, p384, p521, x448 };
|
||||||
const fns = {};
|
const fns = {};
|
||||||
for (let [k, c] of Object.entries(curves)) {
|
for (let [k, c] of Object.entries(curves)) {
|
||||||
const pubB = c.getPublicKey(c.utils.randomPrivateKey());
|
const pubB = c.getPublicKey(c.utils.randomPrivateKey());
|
||||||
|
|||||||
@@ -5,11 +5,11 @@ import { randomBytes } from '@noble/hashes/utils';
|
|||||||
import { sha256 } from '@noble/hashes/sha256';
|
import { sha256 } from '@noble/hashes/sha256';
|
||||||
// import { generateData } from './_shared.js';
|
// import { generateData } from './_shared.js';
|
||||||
import { hashToCurve as secp256k1 } from '../secp256k1.js';
|
import { hashToCurve as secp256k1 } from '../secp256k1.js';
|
||||||
import { hashToCurve as P256 } from '../p256.js';
|
import { hashToCurve as p256 } from '../p256.js';
|
||||||
import { hashToCurve as P384 } from '../p384.js';
|
import { hashToCurve as p384 } from '../p384.js';
|
||||||
import { hashToCurve as P521 } from '../p521.js';
|
import { hashToCurve as p521 } from '../p521.js';
|
||||||
import { hashToCurve as ed25519 } from '../ed25519.js';
|
import { hashToCurve as ed25519, hash_to_ristretto255 } from '../ed25519.js';
|
||||||
import { hashToCurve as ed448 } from '../ed448.js';
|
import { hashToCurve as ed448, hash_to_decaf448 } from '../ed448.js';
|
||||||
import { utf8ToBytes } from '../abstract/utils.js';
|
import { utf8ToBytes } from '../abstract/utils.js';
|
||||||
|
|
||||||
const N = 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141n;
|
const N = 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141n;
|
||||||
@@ -20,10 +20,13 @@ run(async () => {
|
|||||||
// - m, the extension degree of F, m >= 1
|
// - 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)
|
// - L = ceil((ceil(log2(p)) + k) / 8), where k is the security of suite (e.g. 128)
|
||||||
await mark('hash_to_field', 1000000, () =>
|
await mark('hash_to_field', 1000000, () =>
|
||||||
hash_to_field(rand, 1, { DST: 'secp256k1', hash: sha256, p: N, m: 1, k: 128 })
|
hash_to_field(rand, 1, { DST: 'secp256k1', hash: sha256, expand: 'xmd', p: N, m: 1, k: 128 })
|
||||||
);
|
);
|
||||||
const msg = utf8ToBytes('message');
|
const msg = utf8ToBytes('message');
|
||||||
for (let [title, fn] of Object.entries({ secp256k1, P256, P384, P521, ed25519, ed448 })) {
|
for (let [title, fn] of Object.entries({ secp256k1, p256, p384, p521, ed25519, ed448 })) {
|
||||||
await mark(`hashToCurve ${title}`, 1000, () => fn(msg));
|
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_' }));
|
||||||
});
|
});
|
||||||
|
|||||||
13
benchmark/modular.js
Normal file
13
benchmark/modular.js
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
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))
|
||||||
|
});
|
||||||
@@ -16,7 +16,6 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@noble/hashes": "^1.1.5",
|
"@noble/hashes": "^1.1.5",
|
||||||
"@starkware-industries/starkware-crypto-utils": "^0.0.2",
|
|
||||||
"elliptic": "^6.5.4"
|
"elliptic": "^6.5.4"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
18
benchmark/ristretto255.js
Normal file
18
benchmark/ristretto255.js
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
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,56 +0,0 @@
|
|||||||
import { run, mark, compare, utils } from 'micro-bmark';
|
|
||||||
import * as starkwareCrypto from '@starkware-industries/starkware-crypto-utils';
|
|
||||||
import * as stark from '../stark.js';
|
|
||||||
|
|
||||||
run(async () => {
|
|
||||||
const RAM = false;
|
|
||||||
if (RAM) utils.logMem();
|
|
||||||
console.log(`\x1b[36mstark\x1b[0m`);
|
|
||||||
await mark('init', 1, () => stark.utils.precompute(8));
|
|
||||||
const d = (() => {
|
|
||||||
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 };
|
|
||||||
})();
|
|
||||||
await compare('pedersen', 500, {
|
|
||||||
old: () => {
|
|
||||||
return starkwareCrypto.default.pedersen([
|
|
||||||
'3d937c035c878245caf64531a5756109c53068da139362728feb561405371cb',
|
|
||||||
'208a0a10250e382e1e4bbe2880906c2791bf6275695e02fbbc6aeff9cd8b31a',
|
|
||||||
]);
|
|
||||||
},
|
|
||||||
noble: () => {
|
|
||||||
return stark.pedersen(
|
|
||||||
'3d937c035c878245caf64531a5756109c53068da139362728feb561405371cb',
|
|
||||||
'208a0a10250e382e1e4bbe2880906c2791bf6275695e02fbbc6aeff9cd8b31a'
|
|
||||||
);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
await mark('poseidon', 10000, () => stark.poseidonHash(
|
|
||||||
0x3d937c035c878245caf64531a5756109c53068da139362728feb561405371cbn,
|
|
||||||
0x208a0a10250e382e1e4bbe2880906c2791bf6275695e02fbbc6aeff9cd8b31an
|
|
||||||
));
|
|
||||||
await compare('verify', 500, {
|
|
||||||
old: () => {
|
|
||||||
return starkwareCrypto.default.verify(
|
|
||||||
d.publicKeyStark,
|
|
||||||
d.msgHash,
|
|
||||||
starkwareCrypto.default.sign(d.keyPair, d.msgHash)
|
|
||||||
);
|
|
||||||
},
|
|
||||||
noble: () => {
|
|
||||||
return stark.verify(stark.sign(d.msg, d.priv), d.msg, d.pub);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
if (RAM) utils.logMem();
|
|
||||||
});
|
|
||||||
9
benchmark/utils.js
Normal file
9
benchmark/utils.js
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
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));
|
||||||
|
});
|
||||||
7
build/README.md
Normal file
7
build/README.md
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
# build
|
||||||
|
|
||||||
|
The directory is used to build a single file `noble-curves.js` which contains everything.
|
||||||
|
|
||||||
|
The output 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.
|
||||||
20
build/input.js
Normal file
20
build/input.js
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
import { bytesToHex, concatBytes, hexToBytes } 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 };
|
||||||
18
build/package.json
Normal file
18
build/package.json
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
{
|
||||||
|
"name": "build",
|
||||||
|
"private": true,
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "Used to build a single file",
|
||||||
|
"main": "input.js",
|
||||||
|
"keywords": [],
|
||||||
|
"type": "module",
|
||||||
|
"author": "",
|
||||||
|
"license": "MIT",
|
||||||
|
"devDependencies": {
|
||||||
|
"@noble/curves": "..",
|
||||||
|
"esbuild": "0.18.11"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"build": "npx esbuild --bundle input.js --outfile=noble-curves.js --global-name=nobleCurves"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,7 +1,4 @@
|
|||||||
{
|
{
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"browser": {
|
"sideEffects": false
|
||||||
"crypto": false,
|
|
||||||
"./crypto": "./esm/cryptoBrowser.js"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
117
package-lock.json
generated
117
package-lock.json
generated
@@ -1,106 +1,37 @@
|
|||||||
{
|
{
|
||||||
"name": "@noble/curves",
|
"name": "@noble/curves",
|
||||||
"version": "0.7.2",
|
"version": "1.3.0",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "@noble/curves",
|
"name": "@noble/curves",
|
||||||
"version": "0.7.2",
|
"version": "1.3.0",
|
||||||
"funding": [
|
|
||||||
{
|
|
||||||
"type": "individual",
|
|
||||||
"url": "https://paulmillr.com/funding/"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@noble/hashes": "1.2.0"
|
"@noble/hashes": "1.3.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@scure/bip32": "~1.1.5",
|
|
||||||
"@scure/bip39": "~1.1.1",
|
|
||||||
"@types/node": "18.11.3",
|
|
||||||
"fast-check": "3.0.0",
|
"fast-check": "3.0.0",
|
||||||
"micro-bmark": "0.3.1",
|
"micro-bmark": "0.3.1",
|
||||||
"micro-should": "0.4.0",
|
"micro-should": "0.4.0",
|
||||||
"prettier": "2.8.3",
|
"prettier": "3.1.1",
|
||||||
"typescript": "4.7.3"
|
"typescript": "5.3.2"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://paulmillr.com/funding/"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@noble/hashes": {
|
"node_modules/@noble/hashes": {
|
||||||
"version": "1.2.0",
|
"version": "1.3.3",
|
||||||
"resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.3.tgz",
|
||||||
"integrity": "sha512-FZfhjEDbT5GRswV3C6uvLPHMiVD6lQBmpoX5+eSiPaMTXte/IKqI5dykDxzZB/WBeK/CDuQRBWarPdi3FNY2zQ==",
|
"integrity": "sha512-V7/fPHgl+jsVPXqqeOzT8egNj2iBIVt+ECeMMG8TdcnTikP3oaBtUVqpT/gYCR68aEBJSF+XbYUxStjbFMqIIA==",
|
||||||
"funding": [
|
"engines": {
|
||||||
{
|
"node": ">= 16"
|
||||||
"type": "individual",
|
},
|
||||||
|
"funding": {
|
||||||
"url": "https://paulmillr.com/funding/"
|
"url": "https://paulmillr.com/funding/"
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
|
||||||
"node_modules/@noble/secp256k1": {
|
|
||||||
"version": "1.7.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/@noble/secp256k1/-/secp256k1-1.7.1.tgz",
|
|
||||||
"integrity": "sha512-hOUk6AyBFmqVrv7k5WAw/LpszxVbj9gGN4JRkIX52fdFAj1UA61KXmZDvqVEm+pOyec3+fIeZB02LYa/pWOArw==",
|
|
||||||
"dev": true,
|
|
||||||
"funding": [
|
|
||||||
{
|
|
||||||
"type": "individual",
|
|
||||||
"url": "https://paulmillr.com/funding/"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"node_modules/@scure/base": {
|
|
||||||
"version": "1.1.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/@scure/base/-/base-1.1.1.tgz",
|
|
||||||
"integrity": "sha512-ZxOhsSyxYwLJj3pLZCefNitxsj093tb2vq90mp2txoYeBqbcjDjqFhyM8eUjq/uFm6zJ+mUuqxlS2FkuSY1MTA==",
|
|
||||||
"dev": true,
|
|
||||||
"funding": [
|
|
||||||
{
|
|
||||||
"type": "individual",
|
|
||||||
"url": "https://paulmillr.com/funding/"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"node_modules/@scure/bip32": {
|
|
||||||
"version": "1.1.5",
|
|
||||||
"resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.1.5.tgz",
|
|
||||||
"integrity": "sha512-XyNh1rB0SkEqd3tXcXMi+Xe1fvg+kUIcoRIEujP1Jgv7DqW2r9lg3Ah0NkFaCs9sTkQAQA8kw7xiRXzENi9Rtw==",
|
|
||||||
"dev": true,
|
|
||||||
"funding": [
|
|
||||||
{
|
|
||||||
"type": "individual",
|
|
||||||
"url": "https://paulmillr.com/funding/"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"dependencies": {
|
|
||||||
"@noble/hashes": "~1.2.0",
|
|
||||||
"@noble/secp256k1": "~1.7.0",
|
|
||||||
"@scure/base": "~1.1.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@scure/bip39": {
|
|
||||||
"version": "1.1.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.1.1.tgz",
|
|
||||||
"integrity": "sha512-t+wDck2rVkh65Hmv280fYdVdY25J9YeEUIgn2LG1WM6gxFkGzcksoDiUkWVpVp3Oex9xGC68JU2dSbUfwZ2jPg==",
|
|
||||||
"dev": true,
|
|
||||||
"funding": [
|
|
||||||
{
|
|
||||||
"type": "individual",
|
|
||||||
"url": "https://paulmillr.com/funding/"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"dependencies": {
|
|
||||||
"@noble/hashes": "~1.2.0",
|
|
||||||
"@scure/base": "~1.1.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@types/node": {
|
|
||||||
"version": "18.11.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.3.tgz",
|
|
||||||
"integrity": "sha512-fNjDQzzOsZeKZu5NATgXUPsaFaTxeRgFXoosrHivTl8RGeV733OLawXsGfEk9a8/tySyZUyiZ6E8LcjPFZ2y1A==",
|
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"node_modules/fast-check": {
|
"node_modules/fast-check": {
|
||||||
"version": "3.0.0",
|
"version": "3.0.0",
|
||||||
@@ -131,15 +62,15 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/prettier": {
|
"node_modules/prettier": {
|
||||||
"version": "2.8.3",
|
"version": "3.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.3.tgz",
|
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.1.1.tgz",
|
||||||
"integrity": "sha512-tJ/oJ4amDihPoufT5sM0Z1SKEuKay8LfVAMlbbhnnkvt6BUserZylqo2PN+p9KeljLr0OHa2rXHU1T8reeoTrw==",
|
"integrity": "sha512-22UbSzg8luF4UuZtzgiUOfcGM8s4tjBv6dJRT7j275NXsy2jb4aJa4NNveul5x4eqlF1wuhuR2RElK71RvmVaw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"bin": {
|
"bin": {
|
||||||
"prettier": "bin-prettier.js"
|
"prettier": "bin/prettier.cjs"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=10.13.0"
|
"node": ">=14"
|
||||||
},
|
},
|
||||||
"funding": {
|
"funding": {
|
||||||
"url": "https://github.com/prettier/prettier?sponsor=1"
|
"url": "https://github.com/prettier/prettier?sponsor=1"
|
||||||
@@ -162,16 +93,16 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/typescript": {
|
"node_modules/typescript": {
|
||||||
"version": "4.7.3",
|
"version": "5.3.2",
|
||||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.3.tgz",
|
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.2.tgz",
|
||||||
"integrity": "sha512-WOkT3XYvrpXx4vMMqlD+8R8R37fZkjyLGlxavMc4iB8lrl8L0DeTcHbYgw/v0N/z9wAFsgBhcsF0ruoySS22mA==",
|
"integrity": "sha512-6l+RyNy7oAHDfxC4FzSJcz9vnjTKxrLpDG5M2Vu4SHRVNg6xzqZp6LYSR9zjqQTu8DU/f5xwxUdADOkbrIX2gQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"bin": {
|
"bin": {
|
||||||
"tsc": "bin/tsc",
|
"tsc": "bin/tsc",
|
||||||
"tsserver": "bin/tsserver"
|
"tsserver": "bin/tsserver"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=4.2.0"
|
"node": ">=14.17"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
45
package.json
45
package.json
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "@noble/curves",
|
"name": "@noble/curves",
|
||||||
"version": "0.7.3",
|
"version": "1.3.0",
|
||||||
"description": "Minimal, auditable JS implementation of elliptic curve cryptography",
|
"description": "Audited & minimal JS implementation of elliptic curve cryptography",
|
||||||
"files": [
|
"files": [
|
||||||
"abstract",
|
"abstract",
|
||||||
"esm",
|
"esm",
|
||||||
@@ -12,9 +12,10 @@
|
|||||||
"*.d.ts.map"
|
"*.d.ts.map"
|
||||||
],
|
],
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"bench": "cd benchmark; node secp256k1.js; node curves.js; node ecdh.js; node stark.js; node bls.js",
|
"bench": "cd benchmark; node secp256k1.js; node curves.js; node ecdh.js; node hash-to-curve.js; node modular.js; node bls.js; node ristretto255.js; node decaf448.js",
|
||||||
"build": "tsc && tsc -p tsconfig.esm.json",
|
"build": "tsc && tsc -p tsconfig.esm.json",
|
||||||
"build:release": "rollup -c rollup.config.js",
|
"build:release": "cd build; npm install && npm run build",
|
||||||
|
"build:clean": "rm *.{js,d.ts,d.ts.map,js.map} esm/*.{js,d.ts,d.ts.map,js.map} 2> /dev/null",
|
||||||
"lint": "prettier --check 'src/**/*.{js,ts}' 'test/*.js'",
|
"lint": "prettier --check 'src/**/*.{js,ts}' 'test/*.js'",
|
||||||
"format": "prettier --write 'src/**/*.{js,ts}' 'test/*.js'",
|
"format": "prettier --write 'src/**/*.{js,ts}' 'test/*.js'",
|
||||||
"test": "node test/index.test.js"
|
"test": "node test/index.test.js"
|
||||||
@@ -23,22 +24,20 @@
|
|||||||
"homepage": "https://paulmillr.com/noble/",
|
"homepage": "https://paulmillr.com/noble/",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/paulmillr/noble-curves.git"
|
"url": "git+https://github.com/paulmillr/noble-curves.git"
|
||||||
},
|
},
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@noble/hashes": "1.2.0"
|
"@noble/hashes": "1.3.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@scure/bip32": "~1.1.5",
|
|
||||||
"@scure/bip39": "~1.1.1",
|
|
||||||
"@types/node": "18.11.3",
|
|
||||||
"fast-check": "3.0.0",
|
"fast-check": "3.0.0",
|
||||||
"micro-bmark": "0.3.1",
|
"micro-bmark": "0.3.1",
|
||||||
"micro-should": "0.4.0",
|
"micro-should": "0.4.0",
|
||||||
"prettier": "2.8.3",
|
"prettier": "3.1.1",
|
||||||
"typescript": "4.7.3"
|
"typescript": "5.3.2"
|
||||||
},
|
},
|
||||||
|
"sideEffects": false,
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"exports": {
|
"exports": {
|
||||||
".": {
|
".": {
|
||||||
@@ -101,10 +100,10 @@
|
|||||||
"import": "./esm/bls12-381.js",
|
"import": "./esm/bls12-381.js",
|
||||||
"default": "./bls12-381.js"
|
"default": "./bls12-381.js"
|
||||||
},
|
},
|
||||||
"./bn": {
|
"./bn254": {
|
||||||
"types": "./bn.d.ts",
|
"types": "./bn254.d.ts",
|
||||||
"import": "./esm/bn.js",
|
"import": "./esm/bn254.js",
|
||||||
"default": "./bn.js"
|
"default": "./bn254.js"
|
||||||
},
|
},
|
||||||
"./ed25519": {
|
"./ed25519": {
|
||||||
"types": "./ed25519.d.ts",
|
"types": "./ed25519.d.ts",
|
||||||
@@ -150,11 +149,6 @@
|
|||||||
"types": "./secp256k1.d.ts",
|
"types": "./secp256k1.d.ts",
|
||||||
"import": "./esm/secp256k1.js",
|
"import": "./esm/secp256k1.js",
|
||||||
"default": "./secp256k1.js"
|
"default": "./secp256k1.js"
|
||||||
},
|
|
||||||
"./stark": {
|
|
||||||
"types": "./stark.d.ts",
|
|
||||||
"import": "./esm/stark.js",
|
|
||||||
"default": "./stark.js"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"keywords": [
|
"keywords": [
|
||||||
@@ -171,20 +165,17 @@
|
|||||||
"secp256k1",
|
"secp256k1",
|
||||||
"ed25519",
|
"ed25519",
|
||||||
"ed448",
|
"ed448",
|
||||||
|
"x25519",
|
||||||
|
"ed25519",
|
||||||
"bls12-381",
|
"bls12-381",
|
||||||
"bn254",
|
"bn254",
|
||||||
"pasta",
|
"pasta",
|
||||||
"bls",
|
"bls",
|
||||||
"nist",
|
"noble",
|
||||||
"ecc",
|
"ecc",
|
||||||
"ecdsa",
|
"ecdsa",
|
||||||
"eddsa",
|
"eddsa",
|
||||||
"schnorr"
|
"schnorr"
|
||||||
],
|
],
|
||||||
"funding": [
|
"funding": "https://paulmillr.com/funding/"
|
||||||
{
|
|
||||||
"type": "individual",
|
|
||||||
"url": "https://paulmillr.com/funding/"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
@@ -12,9 +12,13 @@
|
|||||||
* Some projects may prefer to swap this relation, it is not supported for now.
|
* Some projects may prefer to swap this relation, it is not supported for now.
|
||||||
*/
|
*/
|
||||||
import { AffinePoint } from './curve.js';
|
import { AffinePoint } from './curve.js';
|
||||||
import { Field, hashToPrivateScalar } from './modular.js';
|
import { IField, getMinHashLength, mapHashToField } from './modular.js';
|
||||||
import { Hex, PrivKey, CHash, bitLen, bitGet, ensureBytes } from './utils.js';
|
import { Hex, PrivKey, CHash, bitLen, bitGet, ensureBytes } from './utils.js';
|
||||||
import * as htf from './hash-to-curve.js';
|
// prettier-ignore
|
||||||
|
import {
|
||||||
|
MapToCurve, Opts as HTFOpts, H2CPointConstructor, htfBasicOpts,
|
||||||
|
createHasher
|
||||||
|
} from './hash-to-curve.js';
|
||||||
import {
|
import {
|
||||||
CurvePointsType,
|
CurvePointsType,
|
||||||
ProjPointType as ProjPointType,
|
ProjPointType as ProjPointType,
|
||||||
@@ -24,64 +28,85 @@ import {
|
|||||||
|
|
||||||
type Fp = bigint; // Can be different field?
|
type Fp = bigint; // Can be different field?
|
||||||
|
|
||||||
|
// prettier-ignore
|
||||||
|
const _2n = BigInt(2), _3n = BigInt(3);
|
||||||
|
|
||||||
|
export type ShortSignatureCoder<Fp> = {
|
||||||
|
fromHex(hex: Hex): ProjPointType<Fp>;
|
||||||
|
toRawBytes(point: ProjPointType<Fp>): Uint8Array;
|
||||||
|
toHex(point: ProjPointType<Fp>): string;
|
||||||
|
};
|
||||||
|
|
||||||
export type SignatureCoder<Fp2> = {
|
export type SignatureCoder<Fp2> = {
|
||||||
decode(hex: Hex): ProjPointType<Fp2>;
|
fromHex(hex: Hex): ProjPointType<Fp2>;
|
||||||
encode(point: ProjPointType<Fp2>): Uint8Array;
|
toRawBytes(point: ProjPointType<Fp2>): Uint8Array;
|
||||||
|
toHex(point: ProjPointType<Fp2>): string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type CurveType<Fp, Fp2, Fp6, Fp12> = {
|
export type CurveType<Fp, Fp2, Fp6, Fp12> = {
|
||||||
r: bigint;
|
|
||||||
G1: Omit<CurvePointsType<Fp>, 'n'> & {
|
G1: Omit<CurvePointsType<Fp>, 'n'> & {
|
||||||
mapToCurve: htf.MapToCurve<Fp>;
|
ShortSignature: SignatureCoder<Fp>;
|
||||||
htfDefaults: htf.Opts;
|
mapToCurve: MapToCurve<Fp>;
|
||||||
|
htfDefaults: HTFOpts;
|
||||||
};
|
};
|
||||||
G2: Omit<CurvePointsType<Fp2>, 'n'> & {
|
G2: Omit<CurvePointsType<Fp2>, 'n'> & {
|
||||||
Signature: SignatureCoder<Fp2>;
|
Signature: SignatureCoder<Fp2>;
|
||||||
mapToCurve: htf.MapToCurve<Fp2>;
|
mapToCurve: MapToCurve<Fp2>;
|
||||||
htfDefaults: htf.Opts;
|
htfDefaults: HTFOpts;
|
||||||
};
|
};
|
||||||
x: bigint;
|
fields: {
|
||||||
Fp: Field<Fp>;
|
Fp: IField<Fp>;
|
||||||
Fr: Field<bigint>;
|
Fr: IField<bigint>;
|
||||||
Fp2: Field<Fp2> & {
|
Fp2: IField<Fp2> & {
|
||||||
reim: (num: Fp2) => { re: bigint; im: bigint };
|
reim: (num: Fp2) => { re: bigint; im: bigint };
|
||||||
multiplyByB: (num: Fp2) => Fp2;
|
multiplyByB: (num: Fp2) => Fp2;
|
||||||
frobeniusMap(num: Fp2, power: number): Fp2;
|
frobeniusMap(num: Fp2, power: number): Fp2;
|
||||||
};
|
};
|
||||||
Fp6: Field<Fp6>;
|
Fp6: IField<Fp6>;
|
||||||
Fp12: Field<Fp12> & {
|
Fp12: IField<Fp12> & {
|
||||||
frobeniusMap(num: Fp12, power: number): Fp12;
|
frobeniusMap(num: Fp12, power: number): Fp12;
|
||||||
multiplyBy014(num: Fp12, o0: Fp2, o1: Fp2, o4: Fp2): Fp12;
|
multiplyBy014(num: Fp12, o0: Fp2, o1: Fp2, o4: Fp2): Fp12;
|
||||||
conjugate(num: Fp12): Fp12;
|
conjugate(num: Fp12): Fp12;
|
||||||
finalExponentiate(num: Fp12): Fp12;
|
finalExponentiate(num: Fp12): Fp12;
|
||||||
};
|
};
|
||||||
htfDefaults: htf.Opts;
|
};
|
||||||
|
params: {
|
||||||
|
x: bigint;
|
||||||
|
r: bigint;
|
||||||
|
};
|
||||||
|
htfDefaults: HTFOpts;
|
||||||
hash: CHash; // Because we need outputLen for DRBG
|
hash: CHash; // Because we need outputLen for DRBG
|
||||||
randomBytes: (bytesLength?: number) => Uint8Array;
|
randomBytes: (bytesLength?: number) => Uint8Array;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type CurveFn<Fp, Fp2, Fp6, Fp12> = {
|
export type CurveFn<Fp, Fp2, Fp6, Fp12> = {
|
||||||
CURVE: CurveType<Fp, Fp2, Fp6, Fp12>;
|
|
||||||
Fr: Field<bigint>;
|
|
||||||
Fp: Field<Fp>;
|
|
||||||
Fp2: Field<Fp2>;
|
|
||||||
Fp6: Field<Fp6>;
|
|
||||||
Fp12: Field<Fp12>;
|
|
||||||
G1: CurvePointsRes<Fp> & ReturnType<typeof htf.createHasher<Fp>>;
|
|
||||||
G2: CurvePointsRes<Fp2> & ReturnType<typeof htf.createHasher<Fp2>>;
|
|
||||||
Signature: SignatureCoder<Fp2>;
|
|
||||||
millerLoop: (ell: [Fp2, Fp2, Fp2][], g1: [Fp, Fp]) => Fp12;
|
|
||||||
calcPairingPrecomputes: (p: AffinePoint<Fp2>) => [Fp2, Fp2, Fp2][];
|
|
||||||
pairing: (P: ProjPointType<Fp>, Q: ProjPointType<Fp2>, withFinalExponent?: boolean) => Fp12;
|
|
||||||
getPublicKey: (privateKey: PrivKey) => Uint8Array;
|
getPublicKey: (privateKey: PrivKey) => Uint8Array;
|
||||||
|
getPublicKeyForShortSignatures: (privateKey: PrivKey) => Uint8Array;
|
||||||
sign: {
|
sign: {
|
||||||
(message: Hex, privateKey: PrivKey): Uint8Array;
|
(message: Hex, privateKey: PrivKey): Uint8Array;
|
||||||
(message: ProjPointType<Fp2>, privateKey: PrivKey): ProjPointType<Fp2>;
|
(message: ProjPointType<Fp2>, privateKey: PrivKey): ProjPointType<Fp2>;
|
||||||
};
|
};
|
||||||
|
signShortSignature: {
|
||||||
|
(message: Hex, privateKey: PrivKey): Uint8Array;
|
||||||
|
(message: ProjPointType<Fp>, privateKey: PrivKey): ProjPointType<Fp>;
|
||||||
|
};
|
||||||
verify: (
|
verify: (
|
||||||
signature: Hex | ProjPointType<Fp2>,
|
signature: Hex | ProjPointType<Fp2>,
|
||||||
message: Hex | ProjPointType<Fp2>,
|
message: Hex | ProjPointType<Fp2>,
|
||||||
publicKey: Hex | ProjPointType<Fp>
|
publicKey: Hex | ProjPointType<Fp>,
|
||||||
|
htfOpts?: htfBasicOpts
|
||||||
|
) => boolean;
|
||||||
|
verifyShortSignature: (
|
||||||
|
signature: Hex | ProjPointType<Fp>,
|
||||||
|
message: Hex | ProjPointType<Fp>,
|
||||||
|
publicKey: Hex | ProjPointType<Fp2>,
|
||||||
|
htfOpts?: htfBasicOpts
|
||||||
|
) => boolean;
|
||||||
|
verifyBatch: (
|
||||||
|
signature: Hex | ProjPointType<Fp2>,
|
||||||
|
messages: (Hex | ProjPointType<Fp2>)[],
|
||||||
|
publicKeys: (Hex | ProjPointType<Fp>)[],
|
||||||
|
htfOpts?: htfBasicOpts
|
||||||
) => boolean;
|
) => boolean;
|
||||||
aggregatePublicKeys: {
|
aggregatePublicKeys: {
|
||||||
(publicKeys: Hex[]): Uint8Array;
|
(publicKeys: Hex[]): Uint8Array;
|
||||||
@@ -91,23 +116,41 @@ export type CurveFn<Fp, Fp2, Fp6, Fp12> = {
|
|||||||
(signatures: Hex[]): Uint8Array;
|
(signatures: Hex[]): Uint8Array;
|
||||||
(signatures: ProjPointType<Fp2>[]): ProjPointType<Fp2>;
|
(signatures: ProjPointType<Fp2>[]): ProjPointType<Fp2>;
|
||||||
};
|
};
|
||||||
verifyBatch: (
|
aggregateShortSignatures: {
|
||||||
signature: Hex | ProjPointType<Fp2>,
|
(signatures: Hex[]): Uint8Array;
|
||||||
messages: (Hex | ProjPointType<Fp2>)[],
|
(signatures: ProjPointType<Fp>[]): ProjPointType<Fp>;
|
||||||
publicKeys: (Hex | ProjPointType<Fp>)[]
|
};
|
||||||
) => boolean;
|
millerLoop: (ell: [Fp2, Fp2, Fp2][], g1: [Fp, Fp]) => Fp12;
|
||||||
|
pairing: (P: ProjPointType<Fp>, Q: ProjPointType<Fp2>, withFinalExponent?: boolean) => Fp12;
|
||||||
|
G1: CurvePointsRes<Fp> & ReturnType<typeof createHasher<Fp>>;
|
||||||
|
G2: CurvePointsRes<Fp2> & ReturnType<typeof createHasher<Fp2>>;
|
||||||
|
Signature: SignatureCoder<Fp2>;
|
||||||
|
ShortSignature: ShortSignatureCoder<Fp>;
|
||||||
|
params: {
|
||||||
|
x: bigint;
|
||||||
|
r: bigint;
|
||||||
|
G1b: bigint;
|
||||||
|
G2b: Fp2;
|
||||||
|
};
|
||||||
|
fields: {
|
||||||
|
Fp: IField<Fp>;
|
||||||
|
Fp2: IField<Fp2>;
|
||||||
|
Fp6: IField<Fp6>;
|
||||||
|
Fp12: IField<Fp12>;
|
||||||
|
Fr: IField<bigint>;
|
||||||
|
};
|
||||||
utils: {
|
utils: {
|
||||||
randomPrivateKey: () => Uint8Array;
|
randomPrivateKey: () => Uint8Array;
|
||||||
|
calcPairingPrecomputes: (p: AffinePoint<Fp2>) => [Fp2, Fp2, Fp2][];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export function bls<Fp2, Fp6, Fp12>(
|
export function bls<Fp2, Fp6, Fp12>(
|
||||||
CURVE: CurveType<Fp, Fp2, Fp6, Fp12>
|
CURVE: CurveType<Fp, Fp2, Fp6, Fp12>
|
||||||
): CurveFn<Fp, Fp2, Fp6, Fp12> {
|
): CurveFn<Fp, Fp2, Fp6, Fp12> {
|
||||||
// Fields looks pretty specific for curve, so for now we need to pass them with opts
|
// Fields are specific for curve, so for now we'll need to pass them with opts
|
||||||
const { Fp, Fr, Fp2, Fp6, Fp12 } = CURVE;
|
const { Fp, Fr, Fp2, Fp6, Fp12 } = CURVE.fields;
|
||||||
const BLS_X_LEN = bitLen(CURVE.x);
|
const BLS_X_LEN = bitLen(CURVE.params.x);
|
||||||
const groupLen = 32; // TODO: calculate; hardcoded for now
|
|
||||||
|
|
||||||
// Pre-compute coefficients for sparse multiplication
|
// Pre-compute coefficients for sparse multiplication
|
||||||
// Point addition and point double calculations is reused for coefficients
|
// Point addition and point double calculations is reused for coefficients
|
||||||
@@ -122,18 +165,18 @@ export function bls<Fp2, Fp6, Fp12>(
|
|||||||
// Double
|
// Double
|
||||||
let t0 = Fp2.sqr(Ry); // Ry²
|
let t0 = Fp2.sqr(Ry); // Ry²
|
||||||
let t1 = Fp2.sqr(Rz); // Rz²
|
let t1 = Fp2.sqr(Rz); // Rz²
|
||||||
let t2 = Fp2.multiplyByB(Fp2.mul(t1, 3n)); // 3 * T1 * B
|
let t2 = Fp2.multiplyByB(Fp2.mul(t1, _3n)); // 3 * T1 * B
|
||||||
let t3 = Fp2.mul(t2, 3n); // 3 * T2
|
let t3 = Fp2.mul(t2, _3n); // 3 * T2
|
||||||
let t4 = Fp2.sub(Fp2.sub(Fp2.sqr(Fp2.add(Ry, Rz)), t1), t0); // (Ry + Rz)² - T1 - T0
|
let t4 = Fp2.sub(Fp2.sub(Fp2.sqr(Fp2.add(Ry, Rz)), t1), t0); // (Ry + Rz)² - T1 - T0
|
||||||
ell_coeff.push([
|
ell_coeff.push([
|
||||||
Fp2.sub(t2, t0), // T2 - T0
|
Fp2.sub(t2, t0), // T2 - T0
|
||||||
Fp2.mul(Fp2.sqr(Rx), 3n), // 3 * Rx²
|
Fp2.mul(Fp2.sqr(Rx), _3n), // 3 * Rx²
|
||||||
Fp2.neg(t4), // -T4
|
Fp2.neg(t4), // -T4
|
||||||
]);
|
]);
|
||||||
Rx = Fp2.div(Fp2.mul(Fp2.mul(Fp2.sub(t0, t3), Rx), Ry), 2n); // ((T0 - T3) * Rx * Ry) / 2
|
Rx = Fp2.div(Fp2.mul(Fp2.mul(Fp2.sub(t0, t3), Rx), Ry), _2n); // ((T0 - T3) * Rx * Ry) / 2
|
||||||
Ry = Fp2.sub(Fp2.sqr(Fp2.div(Fp2.add(t0, t3), 2n)), Fp2.mul(Fp2.sqr(t2), 3n)); // ((T0 + T3) / 2)² - 3 * T2²
|
Ry = Fp2.sub(Fp2.sqr(Fp2.div(Fp2.add(t0, t3), _2n)), Fp2.mul(Fp2.sqr(t2), _3n)); // ((T0 + T3) / 2)² - 3 * T2²
|
||||||
Rz = Fp2.mul(t0, t4); // T0 * T4
|
Rz = Fp2.mul(t0, t4); // T0 * T4
|
||||||
if (bitGet(CURVE.x, i)) {
|
if (bitGet(CURVE.params.x, i)) {
|
||||||
// Addition
|
// Addition
|
||||||
let t0 = Fp2.sub(Ry, Fp2.mul(Qy, Rz)); // Ry - Qy * Rz
|
let t0 = Fp2.sub(Ry, Fp2.mul(Qy, Rz)); // Ry - Qy * Rz
|
||||||
let t1 = Fp2.sub(Rx, Fp2.mul(Qx, Rz)); // Rx - Qx * Rz
|
let t1 = Fp2.sub(Rx, Fp2.mul(Qx, Rz)); // Rx - Qx * Rz
|
||||||
@@ -145,7 +188,7 @@ export function bls<Fp2, Fp6, Fp12>(
|
|||||||
let t2 = Fp2.sqr(t1); // T1²
|
let t2 = Fp2.sqr(t1); // T1²
|
||||||
let t3 = Fp2.mul(t2, t1); // T2 * T1
|
let t3 = Fp2.mul(t2, t1); // T2 * T1
|
||||||
let t4 = Fp2.mul(t2, Rx); // T2 * Rx
|
let t4 = Fp2.mul(t2, Rx); // T2 * Rx
|
||||||
let t5 = Fp2.add(Fp2.sub(t3, Fp2.mul(t4, 2n)), Fp2.mul(Fp2.sqr(t0), Rz)); // T3 - 2 * T4 + T0² * Rz
|
let t5 = Fp2.add(Fp2.sub(t3, Fp2.mul(t4, _2n)), Fp2.mul(Fp2.sqr(t0), Rz)); // T3 - 2 * T4 + T0² * Rz
|
||||||
Rx = Fp2.mul(t1, t5); // T1 * T5
|
Rx = Fp2.mul(t1, t5); // T1 * T5
|
||||||
Ry = Fp2.sub(Fp2.mul(Fp2.sub(t4, t5), t0), Fp2.mul(t3, Ry)); // (T4 - T5) * T0 - T3 * Ry
|
Ry = Fp2.sub(Fp2.mul(Fp2.sub(t4, t5), t0), Fp2.mul(t3, Ry)); // (T4 - T5) * T0 - T3 * Ry
|
||||||
Rz = Fp2.mul(Rz, t3); // Rz * T3
|
Rz = Fp2.mul(Rz, t3); // Rz * T3
|
||||||
@@ -155,7 +198,7 @@ export function bls<Fp2, Fp6, Fp12>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
function millerLoop(ell: [Fp2, Fp2, Fp2][], g1: [Fp, Fp]): Fp12 {
|
function millerLoop(ell: [Fp2, Fp2, Fp2][], g1: [Fp, Fp]): Fp12 {
|
||||||
const { x } = CURVE;
|
const { x } = CURVE.params;
|
||||||
const Px = g1[0];
|
const Px = g1[0];
|
||||||
const Py = g1[1];
|
const Py = g1[1];
|
||||||
let f12 = Fp12.ONE;
|
let f12 = Fp12.ONE;
|
||||||
@@ -174,15 +217,17 @@ export function bls<Fp2, Fp6, Fp12>(
|
|||||||
|
|
||||||
const utils = {
|
const utils = {
|
||||||
randomPrivateKey: (): Uint8Array => {
|
randomPrivateKey: (): Uint8Array => {
|
||||||
return Fr.toBytes(hashToPrivateScalar(CURVE.randomBytes(groupLen + 8), CURVE.r));
|
const length = getMinHashLength(Fr.ORDER);
|
||||||
|
return mapHashToField(CURVE.randomBytes(length), Fr.ORDER);
|
||||||
},
|
},
|
||||||
|
calcPairingPrecomputes,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Point on G1 curve: (x, y)
|
// Point on G1 curve: (x, y)
|
||||||
const G1_ = weierstrassPoints({ n: Fr.ORDER, ...CURVE.G1 });
|
const G1_ = weierstrassPoints({ n: Fr.ORDER, ...CURVE.G1 });
|
||||||
const G1 = Object.assign(
|
const G1 = Object.assign(
|
||||||
G1_,
|
G1_,
|
||||||
htf.createHasher(G1_.ProjectivePoint, CURVE.G1.mapToCurve, {
|
createHasher(G1_.ProjectivePoint, CURVE.G1.mapToCurve, {
|
||||||
...CURVE.htfDefaults,
|
...CURVE.htfDefaults,
|
||||||
...CURVE.G1.htfDefaults,
|
...CURVE.G1.htfDefaults,
|
||||||
})
|
})
|
||||||
@@ -208,12 +253,13 @@ export function bls<Fp2, Fp6, Fp12>(
|
|||||||
const G2_ = weierstrassPoints({ n: Fr.ORDER, ...CURVE.G2 });
|
const G2_ = weierstrassPoints({ n: Fr.ORDER, ...CURVE.G2 });
|
||||||
const G2 = Object.assign(
|
const G2 = Object.assign(
|
||||||
G2_,
|
G2_,
|
||||||
htf.createHasher(G2_.ProjectivePoint as htf.H2CPointConstructor<Fp2>, CURVE.G2.mapToCurve, {
|
createHasher(G2_.ProjectivePoint as H2CPointConstructor<Fp2>, CURVE.G2.mapToCurve, {
|
||||||
...CURVE.htfDefaults,
|
...CURVE.htfDefaults,
|
||||||
...CURVE.G2.htfDefaults,
|
...CURVE.G2.htfDefaults,
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const { ShortSignature } = CURVE.G1;
|
||||||
const { Signature } = CURVE.G2;
|
const { Signature } = CURVE.G2;
|
||||||
|
|
||||||
// Calculates bilinear pairing
|
// Calculates bilinear pairing
|
||||||
@@ -235,31 +281,60 @@ export function bls<Fp2, Fp6, Fp12>(
|
|||||||
function normP1(point: G1Hex): G1 {
|
function normP1(point: G1Hex): G1 {
|
||||||
return point instanceof G1.ProjectivePoint ? (point as G1) : G1.ProjectivePoint.fromHex(point);
|
return point instanceof G1.ProjectivePoint ? (point as G1) : G1.ProjectivePoint.fromHex(point);
|
||||||
}
|
}
|
||||||
function normP2(point: G2Hex): G2 {
|
function normP1Hash(point: G1Hex, htfOpts?: htfBasicOpts): G1 {
|
||||||
return point instanceof G2.ProjectivePoint ? point : Signature.decode(point);
|
return point instanceof G1.ProjectivePoint
|
||||||
|
? point
|
||||||
|
: (G1.hashToCurve(ensureBytes('point', point), htfOpts) as G1);
|
||||||
}
|
}
|
||||||
function normP2Hash(point: G2Hex, htfOpts?: htf.htfBasicOpts): G2 {
|
function normP2(point: G2Hex): G2 {
|
||||||
|
return point instanceof G2.ProjectivePoint ? point : Signature.fromHex(point);
|
||||||
|
}
|
||||||
|
function normP2Hash(point: G2Hex, htfOpts?: htfBasicOpts): G2 {
|
||||||
return point instanceof G2.ProjectivePoint
|
return point instanceof G2.ProjectivePoint
|
||||||
? point
|
? point
|
||||||
: (G2.hashToCurve(ensureBytes('point', point), htfOpts) as G2);
|
: (G2.hashToCurve(ensureBytes('point', point), htfOpts) as G2);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Multiplies generator by private key.
|
// Multiplies generator (G1) by private key.
|
||||||
// P = pk x G
|
// P = pk x G
|
||||||
function getPublicKey(privateKey: PrivKey): Uint8Array {
|
function getPublicKey(privateKey: PrivKey): Uint8Array {
|
||||||
return G1.ProjectivePoint.fromPrivateKey(privateKey).toRawBytes(true);
|
return G1.ProjectivePoint.fromPrivateKey(privateKey).toRawBytes(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Multiplies generator (G2) by private key.
|
||||||
|
// P = pk x G
|
||||||
|
function getPublicKeyForShortSignatures(privateKey: PrivKey): Uint8Array {
|
||||||
|
return G2.ProjectivePoint.fromPrivateKey(privateKey).toRawBytes(true);
|
||||||
|
}
|
||||||
|
|
||||||
// Executes `hashToCurve` on the message and then multiplies the result by private key.
|
// Executes `hashToCurve` on the message and then multiplies the result by private key.
|
||||||
// S = pk x H(m)
|
// S = pk x H(m)
|
||||||
function sign(message: Hex, privateKey: PrivKey, htfOpts?: htf.htfBasicOpts): Uint8Array;
|
function sign(message: Hex, privateKey: PrivKey, htfOpts?: htfBasicOpts): Uint8Array;
|
||||||
function sign(message: G2, privateKey: PrivKey, htfOpts?: htf.htfBasicOpts): G2;
|
function sign(message: G2, privateKey: PrivKey, htfOpts?: htfBasicOpts): G2;
|
||||||
function sign(message: G2Hex, privateKey: PrivKey, htfOpts?: htf.htfBasicOpts): Uint8Array | G2 {
|
function sign(message: G2Hex, privateKey: PrivKey, htfOpts?: htfBasicOpts): Uint8Array | G2 {
|
||||||
const msgPoint = normP2Hash(message, htfOpts);
|
const msgPoint = normP2Hash(message, htfOpts);
|
||||||
msgPoint.assertValidity();
|
msgPoint.assertValidity();
|
||||||
const sigPoint = msgPoint.multiply(G1.normPrivateKeyToScalar(privateKey));
|
const sigPoint = msgPoint.multiply(G1.normPrivateKeyToScalar(privateKey));
|
||||||
if (message instanceof G2.ProjectivePoint) return sigPoint;
|
if (message instanceof G2.ProjectivePoint) return sigPoint;
|
||||||
return Signature.encode(sigPoint);
|
return Signature.toRawBytes(sigPoint);
|
||||||
|
}
|
||||||
|
|
||||||
|
function signShortSignature(
|
||||||
|
message: Hex,
|
||||||
|
privateKey: PrivKey,
|
||||||
|
htfOpts?: htfBasicOpts
|
||||||
|
): Uint8Array;
|
||||||
|
function signShortSignature(message: G1, privateKey: PrivKey, htfOpts?: htfBasicOpts): G1;
|
||||||
|
function signShortSignature(
|
||||||
|
message: G1Hex,
|
||||||
|
privateKey: PrivKey,
|
||||||
|
htfOpts?: htfBasicOpts
|
||||||
|
): Uint8Array | G1 {
|
||||||
|
const msgPoint = normP1Hash(message, htfOpts);
|
||||||
|
msgPoint.assertValidity();
|
||||||
|
const sigPoint = msgPoint.multiply(G1.normPrivateKeyToScalar(privateKey));
|
||||||
|
if (message instanceof G1.ProjectivePoint) return sigPoint;
|
||||||
|
return ShortSignature.toRawBytes(sigPoint);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Checks if pairing of public key & hash is equal to pairing of generator & signature.
|
// Checks if pairing of public key & hash is equal to pairing of generator & signature.
|
||||||
@@ -268,7 +343,7 @@ export function bls<Fp2, Fp6, Fp12>(
|
|||||||
signature: G2Hex,
|
signature: G2Hex,
|
||||||
message: G2Hex,
|
message: G2Hex,
|
||||||
publicKey: G1Hex,
|
publicKey: G1Hex,
|
||||||
htfOpts?: htf.htfBasicOpts
|
htfOpts?: htfBasicOpts
|
||||||
): boolean {
|
): boolean {
|
||||||
const P = normP1(publicKey);
|
const P = normP1(publicKey);
|
||||||
const Hm = normP2Hash(message, htfOpts);
|
const Hm = normP2Hash(message, htfOpts);
|
||||||
@@ -282,6 +357,26 @@ export function bls<Fp2, Fp6, Fp12>(
|
|||||||
return Fp12.eql(exp, Fp12.ONE);
|
return Fp12.eql(exp, Fp12.ONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Checks if pairing of public key & hash is equal to pairing of generator & signature.
|
||||||
|
// e(S, G) == e(H(m), P)
|
||||||
|
function verifyShortSignature(
|
||||||
|
signature: G1Hex,
|
||||||
|
message: G1Hex,
|
||||||
|
publicKey: G2Hex,
|
||||||
|
htfOpts?: htfBasicOpts
|
||||||
|
): boolean {
|
||||||
|
const P = normP2(publicKey);
|
||||||
|
const Hm = normP1Hash(message, htfOpts);
|
||||||
|
const G = G2.ProjectivePoint.BASE;
|
||||||
|
const S = normP1(signature);
|
||||||
|
// Instead of doing 2 exponentiations, we use property of billinear maps
|
||||||
|
// and do one exp after multiplying 2 points.
|
||||||
|
const eHmP = pairing(Hm, P, false);
|
||||||
|
const eSG = pairing(S, G.negate(), false);
|
||||||
|
const exp = Fp12.finalExponentiate(Fp12.mul(eSG, eHmP));
|
||||||
|
return Fp12.eql(exp, Fp12.ONE);
|
||||||
|
}
|
||||||
|
|
||||||
// Adds a bunch of public key points together.
|
// Adds a bunch of public key points together.
|
||||||
// pk1 + pk2 + pk3 = pkA
|
// pk1 + pk2 + pk3 = pkA
|
||||||
function aggregatePublicKeys(publicKeys: Hex[]): Uint8Array;
|
function aggregatePublicKeys(publicKeys: Hex[]): Uint8Array;
|
||||||
@@ -309,7 +404,21 @@ export function bls<Fp2, Fp6, Fp12>(
|
|||||||
aggAffine.assertValidity();
|
aggAffine.assertValidity();
|
||||||
return aggAffine;
|
return aggAffine;
|
||||||
}
|
}
|
||||||
return Signature.encode(aggAffine);
|
return Signature.toRawBytes(aggAffine);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Adds a bunch of signature points together.
|
||||||
|
function aggregateShortSignatures(signatures: Hex[]): Uint8Array;
|
||||||
|
function aggregateShortSignatures(signatures: G1[]): G1;
|
||||||
|
function aggregateShortSignatures(signatures: G1Hex[]): Uint8Array | G1 {
|
||||||
|
if (!signatures.length) throw new Error('Expected non-empty array');
|
||||||
|
const agg = signatures.map(normP1).reduce((sum, s) => sum.add(s), G1.ProjectivePoint.ZERO);
|
||||||
|
const aggAffine = agg; //.toAffine();
|
||||||
|
if (signatures[0] instanceof G1.ProjectivePoint) {
|
||||||
|
aggAffine.assertValidity();
|
||||||
|
return aggAffine;
|
||||||
|
}
|
||||||
|
return ShortSignature.toRawBytes(aggAffine);
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://ethresear.ch/t/fast-verification-of-multiple-bls-signatures/5407
|
// https://ethresear.ch/t/fast-verification-of-multiple-bls-signatures/5407
|
||||||
@@ -318,7 +427,7 @@ export function bls<Fp2, Fp6, Fp12>(
|
|||||||
signature: G2Hex,
|
signature: G2Hex,
|
||||||
messages: G2Hex[],
|
messages: G2Hex[],
|
||||||
publicKeys: G1Hex[],
|
publicKeys: G1Hex[],
|
||||||
htfOpts?: htf.htfBasicOpts
|
htfOpts?: htfBasicOpts
|
||||||
): boolean {
|
): boolean {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
// console.log('verifyBatch', bytesToHex(signature as any), messages, publicKeys.map(bytesToHex));
|
// console.log('verifyBatch', bytesToHex(signature as any), messages, publicKeys.map(bytesToHex));
|
||||||
@@ -353,24 +462,35 @@ export function bls<Fp2, Fp6, Fp12>(
|
|||||||
G1.ProjectivePoint.BASE._setWindowSize(4);
|
G1.ProjectivePoint.BASE._setWindowSize(4);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
CURVE,
|
getPublicKey,
|
||||||
|
getPublicKeyForShortSignatures,
|
||||||
|
sign,
|
||||||
|
signShortSignature,
|
||||||
|
verify,
|
||||||
|
verifyBatch,
|
||||||
|
verifyShortSignature,
|
||||||
|
aggregatePublicKeys,
|
||||||
|
aggregateSignatures,
|
||||||
|
aggregateShortSignatures,
|
||||||
|
millerLoop,
|
||||||
|
pairing,
|
||||||
|
G1,
|
||||||
|
G2,
|
||||||
|
Signature,
|
||||||
|
ShortSignature,
|
||||||
|
fields: {
|
||||||
Fr,
|
Fr,
|
||||||
Fp,
|
Fp,
|
||||||
Fp2,
|
Fp2,
|
||||||
Fp6,
|
Fp6,
|
||||||
Fp12,
|
Fp12,
|
||||||
G1,
|
},
|
||||||
G2,
|
params: {
|
||||||
Signature,
|
x: CURVE.params.x,
|
||||||
millerLoop,
|
r: CURVE.params.r,
|
||||||
calcPairingPrecomputes,
|
G1b: CURVE.G1.b,
|
||||||
pairing,
|
G2b: CURVE.G2.b,
|
||||||
getPublicKey,
|
},
|
||||||
sign,
|
|
||||||
verify,
|
|
||||||
aggregatePublicKeys,
|
|
||||||
aggregateSignatures,
|
|
||||||
verifyBatch,
|
|
||||||
utils,
|
utils,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
||||||
// Abelian group utilities
|
// Abelian group utilities
|
||||||
import { Field, validateField, nLength } from './modular.js';
|
import { IField, validateField, nLength } from './modular.js';
|
||||||
import { validateObject } from './utils.js';
|
import { validateObject } from './utils.js';
|
||||||
const _0n = BigInt(0);
|
const _0n = BigInt(0);
|
||||||
const _1n = BigInt(1);
|
const _1n = BigInt(1);
|
||||||
@@ -168,7 +168,7 @@ export function wNAF<T extends Group<T>>(c: GroupConstructor<T>, bits: number) {
|
|||||||
// Generic BasicCurve interface: works even for polynomial fields (BLS): P, n, h would be ok.
|
// Generic BasicCurve interface: works even for polynomial fields (BLS): P, n, h would be ok.
|
||||||
// Though generator can be different (Fp2 / Fp6 for BLS).
|
// Though generator can be different (Fp2 / Fp6 for BLS).
|
||||||
export type BasicCurve<T> = {
|
export type BasicCurve<T> = {
|
||||||
Fp: Field<T>; // Field over which we'll do calculations (Fp)
|
Fp: IField<T>; // Field over which we'll do calculations (Fp)
|
||||||
n: bigint; // Curve order, total count of valid points in the field
|
n: bigint; // Curve order, total count of valid points in the field
|
||||||
nBitLength?: number; // bit length of curve order
|
nBitLength?: number; // bit length of curve order
|
||||||
nByteLength?: number; // byte length of curve order
|
nByteLength?: number; // byte length of curve order
|
||||||
@@ -195,5 +195,9 @@ export function validateBasic<FP, T>(curve: BasicCurve<FP> & T) {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
// Set defaults
|
// Set defaults
|
||||||
return Object.freeze({ ...nLength(curve.n, curve.nBitLength), ...curve } as const);
|
return Object.freeze({
|
||||||
|
...nLength(curve.n, curve.nBitLength),
|
||||||
|
...curve,
|
||||||
|
...{ p: curve.Fp.ORDER },
|
||||||
|
} as const);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,11 +5,9 @@ import * as ut from './utils.js';
|
|||||||
import { ensureBytes, FHash, Hex } from './utils.js';
|
import { ensureBytes, FHash, Hex } from './utils.js';
|
||||||
import { Group, GroupConstructor, wNAF, BasicCurve, validateBasic, AffinePoint } from './curve.js';
|
import { Group, GroupConstructor, wNAF, BasicCurve, validateBasic, AffinePoint } from './curve.js';
|
||||||
|
|
||||||
// Be friendly to bad ECMAScript parsers by not using bigint literals like 123n
|
// Be friendly to bad ECMAScript parsers by not using bigint literals
|
||||||
const _0n = BigInt(0);
|
// prettier-ignore
|
||||||
const _1n = BigInt(1);
|
const _0n = BigInt(0), _1n = BigInt(1), _2n = BigInt(2), _8n = BigInt(8);
|
||||||
const _2n = BigInt(2);
|
|
||||||
const _8n = BigInt(8);
|
|
||||||
|
|
||||||
// Edwards curves must declare params a & d.
|
// Edwards curves must declare params a & d.
|
||||||
export type CurveType = BasicCurve<bigint> & {
|
export type CurveType = BasicCurve<bigint> & {
|
||||||
@@ -20,10 +18,13 @@ export type CurveType = BasicCurve<bigint> & {
|
|||||||
adjustScalarBytes?: (bytes: Uint8Array) => Uint8Array; // clears bits to get valid field elemtn
|
adjustScalarBytes?: (bytes: Uint8Array) => Uint8Array; // clears bits to get valid field elemtn
|
||||||
domain?: (data: Uint8Array, ctx: Uint8Array, phflag: boolean) => Uint8Array; // Used for hashing
|
domain?: (data: Uint8Array, ctx: Uint8Array, phflag: boolean) => Uint8Array; // Used for hashing
|
||||||
uvRatio?: (u: bigint, v: bigint) => { isValid: boolean; value: bigint }; // Ratio √(u/v)
|
uvRatio?: (u: bigint, v: bigint) => { isValid: boolean; value: bigint }; // Ratio √(u/v)
|
||||||
preHash?: FHash; // RFC 8032 pre-hashing of messages to sign() / verify()
|
prehash?: FHash; // RFC 8032 pre-hashing of messages to sign() / verify()
|
||||||
mapToCurve?: (scalar: bigint[]) => AffinePoint<bigint>; // for hash-to-curve standard
|
mapToCurve?: (scalar: bigint[]) => AffinePoint<bigint>; // for hash-to-curve standard
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// verification rule is either zip215 or rfc8032 / nist186-5. Consult fromHex:
|
||||||
|
const VERIFY_DEFAULT = { zip215: true };
|
||||||
|
|
||||||
function validateOpts(curve: CurveType) {
|
function validateOpts(curve: CurveType) {
|
||||||
const opts = validateBasic(curve);
|
const opts = validateBasic(curve);
|
||||||
ut.validateObject(
|
ut.validateObject(
|
||||||
@@ -51,6 +52,8 @@ export interface ExtPointType extends Group<ExtPointType> {
|
|||||||
readonly ey: bigint;
|
readonly ey: bigint;
|
||||||
readonly ez: bigint;
|
readonly ez: bigint;
|
||||||
readonly et: bigint;
|
readonly et: bigint;
|
||||||
|
get x(): bigint;
|
||||||
|
get y(): bigint;
|
||||||
assertValidity(): void;
|
assertValidity(): void;
|
||||||
multiply(scalar: bigint): ExtPointType;
|
multiply(scalar: bigint): ExtPointType;
|
||||||
multiplyUnsafe(scalar: bigint): ExtPointType;
|
multiplyUnsafe(scalar: bigint): ExtPointType;
|
||||||
@@ -58,6 +61,8 @@ export interface ExtPointType extends Group<ExtPointType> {
|
|||||||
isTorsionFree(): boolean;
|
isTorsionFree(): boolean;
|
||||||
clearCofactor(): ExtPointType;
|
clearCofactor(): ExtPointType;
|
||||||
toAffine(iz?: bigint): AffinePoint<bigint>;
|
toAffine(iz?: bigint): AffinePoint<bigint>;
|
||||||
|
toRawBytes(isCompressed?: boolean): Uint8Array;
|
||||||
|
toHex(isCompressed?: boolean): string;
|
||||||
}
|
}
|
||||||
// Static methods of Extended Point with coordinates in X, Y, Z, T
|
// Static methods of Extended Point with coordinates in X, Y, Z, T
|
||||||
export interface ExtPointConstructor extends GroupConstructor<ExtPointType> {
|
export interface ExtPointConstructor extends GroupConstructor<ExtPointType> {
|
||||||
@@ -70,8 +75,13 @@ export interface ExtPointConstructor extends GroupConstructor<ExtPointType> {
|
|||||||
export type CurveFn = {
|
export type CurveFn = {
|
||||||
CURVE: ReturnType<typeof validateOpts>;
|
CURVE: ReturnType<typeof validateOpts>;
|
||||||
getPublicKey: (privateKey: Hex) => Uint8Array;
|
getPublicKey: (privateKey: Hex) => Uint8Array;
|
||||||
sign: (message: Hex, privateKey: Hex) => Uint8Array;
|
sign: (message: Hex, privateKey: Hex, options?: { context?: Hex }) => Uint8Array;
|
||||||
verify: (sig: Hex, message: Hex, publicKey: Hex) => boolean;
|
verify: (
|
||||||
|
sig: Hex,
|
||||||
|
message: Hex,
|
||||||
|
publicKey: Hex,
|
||||||
|
options?: { context?: Hex; zip215: boolean }
|
||||||
|
) => boolean;
|
||||||
ExtendedPoint: ExtPointConstructor;
|
ExtendedPoint: ExtPointConstructor;
|
||||||
utils: {
|
utils: {
|
||||||
randomPrivateKey: () => Uint8Array;
|
randomPrivateKey: () => Uint8Array;
|
||||||
@@ -88,8 +98,16 @@ export type CurveFn = {
|
|||||||
// It is not generic twisted curve for now, but ed25519/ed448 generic implementation
|
// It is not generic twisted curve for now, but ed25519/ed448 generic implementation
|
||||||
export function twistedEdwards(curveDef: CurveType): CurveFn {
|
export function twistedEdwards(curveDef: CurveType): CurveFn {
|
||||||
const CURVE = validateOpts(curveDef) as ReturnType<typeof validateOpts>;
|
const CURVE = validateOpts(curveDef) as ReturnType<typeof validateOpts>;
|
||||||
const { Fp, n: CURVE_ORDER, preHash, hash: cHash, randomBytes, nByteLength, h: cofactor } = CURVE;
|
const {
|
||||||
const MASK = _2n ** BigInt(nByteLength * 8);
|
Fp,
|
||||||
|
n: CURVE_ORDER,
|
||||||
|
prehash: prehash,
|
||||||
|
hash: cHash,
|
||||||
|
randomBytes,
|
||||||
|
nByteLength,
|
||||||
|
h: cofactor,
|
||||||
|
} = CURVE;
|
||||||
|
const MASK = _2n << (BigInt(nByteLength * 8) - _1n);
|
||||||
const modP = Fp.create; // Function overrides
|
const modP = Fp.create; // Function overrides
|
||||||
|
|
||||||
// sqrt(u/v)
|
// sqrt(u/v)
|
||||||
@@ -109,7 +127,7 @@ export function twistedEdwards(curveDef: CurveType): CurveFn {
|
|||||||
if (ctx.length || phflag) throw new Error('Contexts/pre-hash are not supported');
|
if (ctx.length || phflag) throw new Error('Contexts/pre-hash are not supported');
|
||||||
return data;
|
return data;
|
||||||
}); // NOOP
|
}); // NOOP
|
||||||
const inBig = (n: bigint) => typeof n === 'bigint' && 0n < n; // n in [1..]
|
const inBig = (n: bigint) => typeof n === 'bigint' && _0n < n; // n in [1..]
|
||||||
const inRange = (n: bigint, max: bigint) => inBig(n) && inBig(max) && n < max; // n in [1..max-1]
|
const inRange = (n: bigint, max: bigint) => inBig(n) && inBig(max) && n < max; // n in [1..max-1]
|
||||||
const in0MaskRange = (n: bigint) => n === _0n || inRange(n, MASK); // n in [0..MASK-1]
|
const in0MaskRange = (n: bigint) => n === _0n || inRange(n, MASK); // n in [0..MASK-1]
|
||||||
function assertInRange(n: bigint, max: bigint) {
|
function assertInRange(n: bigint, max: bigint) {
|
||||||
@@ -297,8 +315,9 @@ export function twistedEdwards(curveDef: CurveType): CurveFn {
|
|||||||
// Non-constant-time multiplication. Uses double-and-add algorithm.
|
// Non-constant-time multiplication. Uses double-and-add algorithm.
|
||||||
// It's faster, but should only be used when you don't care about
|
// It's faster, but should only be used when you don't care about
|
||||||
// an exposed private key e.g. sig verification.
|
// an exposed private key e.g. sig verification.
|
||||||
|
// Does NOT allow scalars higher than CURVE.n.
|
||||||
multiplyUnsafe(scalar: bigint): Point {
|
multiplyUnsafe(scalar: bigint): Point {
|
||||||
let n = assertGE0(scalar);
|
let n = assertGE0(scalar); // 0 <= scalar < CURVE.n
|
||||||
if (n === _0n) return I;
|
if (n === _0n) return I;
|
||||||
if (this.equals(I) || n === _1n) return this;
|
if (this.equals(I) || n === _1n) return this;
|
||||||
if (this.equals(G)) return this.wNAF(n).p;
|
if (this.equals(G)) return this.wNAF(n).p;
|
||||||
@@ -341,7 +360,7 @@ export function twistedEdwards(curveDef: CurveType): CurveFn {
|
|||||||
|
|
||||||
// Converts hash string or Uint8Array to Point.
|
// Converts hash string or Uint8Array to Point.
|
||||||
// Uses algo from RFC8032 5.1.3.
|
// Uses algo from RFC8032 5.1.3.
|
||||||
static fromHex(hex: Hex, strict = true): Point {
|
static fromHex(hex: Hex, zip215 = false): Point {
|
||||||
const { d, a } = CURVE;
|
const { d, a } = CURVE;
|
||||||
const len = Fp.BYTES;
|
const len = Fp.BYTES;
|
||||||
hex = ensureBytes('pointHex', hex, len); // copy hex to a new array
|
hex = ensureBytes('pointHex', hex, len); // copy hex to a new array
|
||||||
@@ -353,8 +372,8 @@ export function twistedEdwards(curveDef: CurveType): CurveFn {
|
|||||||
// y=0 is allowed
|
// y=0 is allowed
|
||||||
} else {
|
} else {
|
||||||
// RFC8032 prohibits >= p, but ZIP215 doesn't
|
// RFC8032 prohibits >= p, but ZIP215 doesn't
|
||||||
if (strict) assertInRange(y, Fp.ORDER); // strict=true [1..P-1] (2^255-19-1 for ed25519)
|
if (zip215) assertInRange(y, MASK); // zip215=true [1..P-1] (2^255-19-1 for ed25519)
|
||||||
else assertInRange(y, MASK); // strict=false [1..MASK-1] (2^256-1 for ed25519)
|
else assertInRange(y, Fp.ORDER); // zip215=false [1..MASK-1] (2^256-1 for ed25519)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ed25519: x² = (y²-1)/(dy²+1) mod p. Ed448: x² = (y²-1)/(dy²-1) mod p. Generic case:
|
// Ed25519: x² = (y²-1)/(dy²+1) mod p. Ed448: x² = (y²-1)/(dy²-1) mod p. Generic case:
|
||||||
@@ -365,7 +384,10 @@ export function twistedEdwards(curveDef: CurveType): CurveFn {
|
|||||||
let { isValid, value: x } = uvRatio(u, v); // √(u/v)
|
let { isValid, value: x } = uvRatio(u, v); // √(u/v)
|
||||||
if (!isValid) throw new Error('Point.fromHex: invalid y coordinate');
|
if (!isValid) throw new Error('Point.fromHex: invalid y coordinate');
|
||||||
const isXOdd = (x & _1n) === _1n; // There are 2 square roots. Use x_0 bit to select proper
|
const isXOdd = (x & _1n) === _1n; // There are 2 square roots. Use x_0 bit to select proper
|
||||||
const isLastByteOdd = (lastByte & 0x80) !== 0; // if x=0 and x_0 = 1, fail
|
const isLastByteOdd = (lastByte & 0x80) !== 0; // x_0, last bit
|
||||||
|
if (!zip215 && x === _0n && isLastByteOdd)
|
||||||
|
// if x=0 and x_0 = 1, fail
|
||||||
|
throw new Error('Point.fromHex: x=0 and x_0=1');
|
||||||
if (isLastByteOdd !== isXOdd) x = modP(-x); // if x_0 != x mod 2, set x = p-x
|
if (isLastByteOdd !== isXOdd) x = modP(-x); // if x_0 != x mod 2, set x = p-x
|
||||||
return Point.fromAffine({ x, y });
|
return Point.fromAffine({ x, y });
|
||||||
}
|
}
|
||||||
@@ -416,32 +438,44 @@ export function twistedEdwards(curveDef: CurveType): CurveFn {
|
|||||||
// int('LE', SHA512(dom2(F, C) || msgs)) mod N
|
// int('LE', SHA512(dom2(F, C) || msgs)) mod N
|
||||||
function hashDomainToScalar(context: Hex = new Uint8Array(), ...msgs: Uint8Array[]) {
|
function hashDomainToScalar(context: Hex = new Uint8Array(), ...msgs: Uint8Array[]) {
|
||||||
const msg = ut.concatBytes(...msgs);
|
const msg = ut.concatBytes(...msgs);
|
||||||
return modN_LE(cHash(domain(msg, ensureBytes('context', context), !!preHash)));
|
return modN_LE(cHash(domain(msg, ensureBytes('context', context), !!prehash)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Signs message with privateKey. RFC8032 5.1.6 */
|
/** Signs message with privateKey. RFC8032 5.1.6 */
|
||||||
function sign(msg: Hex, privKey: Hex, context?: Hex): Uint8Array {
|
function sign(msg: Hex, privKey: Hex, options: { context?: Hex } = {}): Uint8Array {
|
||||||
msg = ensureBytes('message', msg);
|
msg = ensureBytes('message', msg);
|
||||||
if (preHash) msg = preHash(msg); // for ed25519ph etc.
|
if (prehash) msg = prehash(msg); // for ed25519ph etc.
|
||||||
const { prefix, scalar, pointBytes } = getExtendedPublicKey(privKey);
|
const { prefix, scalar, pointBytes } = getExtendedPublicKey(privKey);
|
||||||
const r = hashDomainToScalar(context, prefix, msg); // r = dom2(F, C) || prefix || PH(M)
|
const r = hashDomainToScalar(options.context, prefix, msg); // r = dom2(F, C) || prefix || PH(M)
|
||||||
const R = G.multiply(r).toRawBytes(); // R = rG
|
const R = G.multiply(r).toRawBytes(); // R = rG
|
||||||
const k = hashDomainToScalar(context, R, pointBytes, msg); // R || A || PH(M)
|
const k = hashDomainToScalar(options.context, R, pointBytes, msg); // R || A || PH(M)
|
||||||
const s = modN(r + k * scalar); // S = (r + k * s) mod L
|
const s = modN(r + k * scalar); // S = (r + k * s) mod L
|
||||||
assertGE0(s); // 0 <= s < l
|
assertGE0(s); // 0 <= s < l
|
||||||
const res = ut.concatBytes(R, ut.numberToBytesLE(s, Fp.BYTES));
|
const res = ut.concatBytes(R, ut.numberToBytesLE(s, Fp.BYTES));
|
||||||
return ensureBytes('result', res, nByteLength * 2); // 64-byte signature
|
return ensureBytes('result', res, nByteLength * 2); // 64-byte signature
|
||||||
}
|
}
|
||||||
|
|
||||||
function verify(sig: Hex, msg: Hex, publicKey: Hex, context?: Hex): boolean {
|
const verifyOpts: { context?: Hex; zip215?: boolean } = VERIFY_DEFAULT;
|
||||||
|
function verify(sig: Hex, msg: Hex, publicKey: Hex, options = verifyOpts): boolean {
|
||||||
|
const { context, zip215 } = options;
|
||||||
const len = Fp.BYTES; // Verifies EdDSA signature against message and public key. RFC8032 5.1.7.
|
const len = Fp.BYTES; // Verifies EdDSA signature against message and public key. RFC8032 5.1.7.
|
||||||
sig = ensureBytes('signature', sig, 2 * len); // An extended group equation is checked.
|
sig = ensureBytes('signature', sig, 2 * len); // An extended group equation is checked.
|
||||||
msg = ensureBytes('message', msg); // ZIP215 compliant, which means not fully RFC8032 compliant.
|
msg = ensureBytes('message', msg);
|
||||||
if (preHash) msg = preHash(msg); // for ed25519ph, etc
|
if (prehash) msg = prehash(msg); // for ed25519ph, etc
|
||||||
const A = Point.fromHex(publicKey, false); // Check for s bounds, hex validity
|
|
||||||
const R = Point.fromHex(sig.slice(0, len), false); // 0 <= R < 2^256: ZIP215 R can be >= P
|
const s = ut.bytesToNumberLE(sig.slice(len, 2 * len));
|
||||||
const s = ut.bytesToNumberLE(sig.slice(len, 2 * len)); // 0 <= s < l
|
// zip215: true is good for consensus-critical apps and allows points < 2^256
|
||||||
const SB = G.multiplyUnsafe(s);
|
// zip215: false follows RFC8032 / NIST186-5 and restricts points to CURVE.p
|
||||||
|
let A, R, SB;
|
||||||
|
try {
|
||||||
|
A = Point.fromHex(publicKey, zip215);
|
||||||
|
R = Point.fromHex(sig.slice(0, len), zip215);
|
||||||
|
SB = G.multiplyUnsafe(s); // 0 <= s < l is done inside
|
||||||
|
} catch (error) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!zip215 && A.isSmallOrder()) return false;
|
||||||
|
|
||||||
const k = hashDomainToScalar(context, R.toRawBytes(), A.toRawBytes(), msg);
|
const k = hashDomainToScalar(context, R.toRawBytes(), A.toRawBytes(), msg);
|
||||||
const RkA = R.add(A.multiplyUnsafe(k));
|
const RkA = R.add(A.multiplyUnsafe(k));
|
||||||
// [8][S]B = [8]R + [8][k]A'
|
// [8][S]B = [8]R + [8][k]A'
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
||||||
import type { Group, GroupConstructor, AffinePoint } from './curve.js';
|
import type { Group, GroupConstructor, AffinePoint } from './curve.js';
|
||||||
import { mod, Field } from './modular.js';
|
import { mod, IField } from './modular.js';
|
||||||
import { bytesToNumberBE, CHash, concatBytes, utf8ToBytes, validateObject } from './utils.js';
|
import type { CHash } from './utils.js';
|
||||||
|
import { bytesToNumberBE, isBytes, concatBytes, utf8ToBytes, validateObject } from './utils.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* * `DST` is a domain separation tag, defined in section 2.2.5
|
* * `DST` is a domain separation tag, defined in section 2.2.5
|
||||||
@@ -11,17 +12,18 @@ import { bytesToNumberBE, CHash, concatBytes, utf8ToBytes, validateObject } from
|
|||||||
* * `expand` is `xmd` (SHA2, SHA3, BLAKE) or `xof` (SHAKE, BLAKE-XOF)
|
* * `expand` is `xmd` (SHA2, SHA3, BLAKE) or `xof` (SHAKE, BLAKE-XOF)
|
||||||
* * `hash` conforming to `utils.CHash` interface, with `outputLen` / `blockLen` props
|
* * `hash` conforming to `utils.CHash` interface, with `outputLen` / `blockLen` props
|
||||||
*/
|
*/
|
||||||
|
type UnicodeOrBytes = string | Uint8Array;
|
||||||
export type Opts = {
|
export type Opts = {
|
||||||
DST: string | Uint8Array;
|
DST: UnicodeOrBytes;
|
||||||
p: bigint;
|
p: bigint;
|
||||||
m: number;
|
m: number;
|
||||||
k: number;
|
k: number;
|
||||||
expand?: 'xmd' | 'xof';
|
expand: 'xmd' | 'xof';
|
||||||
hash: CHash;
|
hash: CHash;
|
||||||
};
|
};
|
||||||
|
|
||||||
function validateDST(dst: string | Uint8Array): Uint8Array {
|
function validateDST(dst: UnicodeOrBytes): Uint8Array {
|
||||||
if (dst instanceof Uint8Array) return dst;
|
if (isBytes(dst)) return dst;
|
||||||
if (typeof dst === 'string') return utf8ToBytes(dst);
|
if (typeof dst === 'string') return utf8ToBytes(dst);
|
||||||
throw new Error('DST must be Uint8Array or string');
|
throw new Error('DST must be Uint8Array or string');
|
||||||
}
|
}
|
||||||
@@ -50,25 +52,25 @@ function strxor(a: Uint8Array, b: Uint8Array): Uint8Array {
|
|||||||
return arr;
|
return arr;
|
||||||
}
|
}
|
||||||
|
|
||||||
function isBytes(item: unknown): void {
|
function abytes(item: unknown): void {
|
||||||
if (!(item instanceof Uint8Array)) throw new Error('Uint8Array expected');
|
if (!isBytes(item)) throw new Error('Uint8Array expected');
|
||||||
}
|
}
|
||||||
function isNum(item: unknown): void {
|
function isNum(item: unknown): void {
|
||||||
if (!Number.isSafeInteger(item)) throw new Error('number expected');
|
if (!Number.isSafeInteger(item)) throw new Error('number expected');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Produces a uniformly random byte string using a cryptographic hash function H that outputs b bits
|
// Produces a uniformly random byte string using a cryptographic hash function H that outputs b bits
|
||||||
// https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-11#section-5.4.1
|
// https://www.rfc-editor.org/rfc/rfc9380#section-5.3.1
|
||||||
export function expand_message_xmd(
|
export function expand_message_xmd(
|
||||||
msg: Uint8Array,
|
msg: Uint8Array,
|
||||||
DST: Uint8Array,
|
DST: Uint8Array,
|
||||||
lenInBytes: number,
|
lenInBytes: number,
|
||||||
H: CHash
|
H: CHash
|
||||||
): Uint8Array {
|
): Uint8Array {
|
||||||
isBytes(msg);
|
abytes(msg);
|
||||||
isBytes(DST);
|
abytes(DST);
|
||||||
isNum(lenInBytes);
|
isNum(lenInBytes);
|
||||||
// https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-16#section-5.3.3
|
// https://www.rfc-editor.org/rfc/rfc9380#section-5.3.3
|
||||||
if (DST.length > 255) DST = H(concatBytes(utf8ToBytes('H2C-OVERSIZE-DST-'), DST));
|
if (DST.length > 255) DST = H(concatBytes(utf8ToBytes('H2C-OVERSIZE-DST-'), DST));
|
||||||
const { outputLen: b_in_bytes, blockLen: r_in_bytes } = H;
|
const { outputLen: b_in_bytes, blockLen: r_in_bytes } = H;
|
||||||
const ell = Math.ceil(lenInBytes / b_in_bytes);
|
const ell = Math.ceil(lenInBytes / b_in_bytes);
|
||||||
@@ -87,6 +89,11 @@ export function expand_message_xmd(
|
|||||||
return pseudo_random_bytes.slice(0, lenInBytes);
|
return pseudo_random_bytes.slice(0, lenInBytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Produces a uniformly random byte string using an extendable-output function (XOF) H.
|
||||||
|
// 1. The collision resistance of H MUST be at least k bits.
|
||||||
|
// 2. H MUST be an XOF that has been proved indifferentiable from
|
||||||
|
// a random oracle under a reasonable cryptographic assumption.
|
||||||
|
// https://www.rfc-editor.org/rfc/rfc9380#section-5.3.2
|
||||||
export function expand_message_xof(
|
export function expand_message_xof(
|
||||||
msg: Uint8Array,
|
msg: Uint8Array,
|
||||||
DST: Uint8Array,
|
DST: Uint8Array,
|
||||||
@@ -94,10 +101,10 @@ export function expand_message_xof(
|
|||||||
k: number,
|
k: number,
|
||||||
H: CHash
|
H: CHash
|
||||||
): Uint8Array {
|
): Uint8Array {
|
||||||
isBytes(msg);
|
abytes(msg);
|
||||||
isBytes(DST);
|
abytes(DST);
|
||||||
isNum(lenInBytes);
|
isNum(lenInBytes);
|
||||||
// https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-16#section-5.3.3
|
// https://www.rfc-editor.org/rfc/rfc9380#section-5.3.3
|
||||||
// DST = H('H2C-OVERSIZE-DST-' || a_very_long_DST, Math.ceil((lenInBytes * k) / 8));
|
// DST = H('H2C-OVERSIZE-DST-' || a_very_long_DST, Math.ceil((lenInBytes * k) / 8));
|
||||||
if (DST.length > 255) {
|
if (DST.length > 255) {
|
||||||
const dkLen = Math.ceil((2 * k) / 8);
|
const dkLen = Math.ceil((2 * k) / 8);
|
||||||
@@ -118,15 +125,22 @@ export function expand_message_xof(
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Hashes arbitrary-length byte strings to a list of one or more elements of a finite field F
|
* Hashes arbitrary-length byte strings to a list of one or more elements of a finite field F
|
||||||
* https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-11#section-5.3
|
* https://www.rfc-editor.org/rfc/rfc9380#section-5.2
|
||||||
* @param msg a byte string containing the message to hash
|
* @param msg a byte string containing the message to hash
|
||||||
* @param count the number of elements of F to output
|
* @param count the number of elements of F to output
|
||||||
* @param options `{DST: string, p: bigint, m: number, k: number, expand: 'xmd' | 'xof', hash: H}`, see above
|
* @param options `{DST: string, p: bigint, m: number, k: number, expand: 'xmd' | 'xof', hash: H}`, see above
|
||||||
* @returns [u_0, ..., u_(count - 1)], a list of field elements.
|
* @returns [u_0, ..., u_(count - 1)], a list of field elements.
|
||||||
*/
|
*/
|
||||||
export function hash_to_field(msg: Uint8Array, count: number, options: Opts): bigint[][] {
|
export function hash_to_field(msg: Uint8Array, count: number, options: Opts): bigint[][] {
|
||||||
|
validateObject(options, {
|
||||||
|
DST: 'stringOrUint8Array',
|
||||||
|
p: 'bigint',
|
||||||
|
m: 'isSafeInteger',
|
||||||
|
k: 'isSafeInteger',
|
||||||
|
hash: 'hash',
|
||||||
|
});
|
||||||
const { p, k, m, hash, expand, DST: _DST } = options;
|
const { p, k, m, hash, expand, DST: _DST } = options;
|
||||||
isBytes(msg);
|
abytes(msg);
|
||||||
isNum(count);
|
isNum(count);
|
||||||
const DST = validateDST(_DST);
|
const DST = validateDST(_DST);
|
||||||
const log2p = p.toString(2).length;
|
const log2p = p.toString(2).length;
|
||||||
@@ -137,10 +151,11 @@ export function hash_to_field(msg: Uint8Array, count: number, options: Opts): bi
|
|||||||
prb = expand_message_xmd(msg, DST, len_in_bytes, hash);
|
prb = expand_message_xmd(msg, DST, len_in_bytes, hash);
|
||||||
} else if (expand === 'xof') {
|
} else if (expand === 'xof') {
|
||||||
prb = expand_message_xof(msg, DST, len_in_bytes, k, hash);
|
prb = expand_message_xof(msg, DST, len_in_bytes, k, hash);
|
||||||
} else if (expand === undefined) {
|
} else if (expand === '_internal_pass') {
|
||||||
|
// for internal tests only
|
||||||
prb = msg;
|
prb = msg;
|
||||||
} else {
|
} else {
|
||||||
throw new Error('expand must be "xmd", "xof" or undefined');
|
throw new Error('expand must be "xmd" or "xof"');
|
||||||
}
|
}
|
||||||
const u = new Array(count);
|
const u = new Array(count);
|
||||||
for (let i = 0; i < count; i++) {
|
for (let i = 0; i < count; i++) {
|
||||||
@@ -155,7 +170,7 @@ export function hash_to_field(msg: Uint8Array, count: number, options: Opts): bi
|
|||||||
return u;
|
return u;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isogenyMap<T, F extends Field<T>>(field: F, map: [T[], T[], T[], T[]]) {
|
export function isogenyMap<T, F extends IField<T>>(field: F, map: [T[], T[], T[], T[]]) {
|
||||||
// Make same order as in spec
|
// Make same order as in spec
|
||||||
const COEFF = map.map((i) => Array.from(i).reverse());
|
const COEFF = map.map((i) => Array.from(i).reverse());
|
||||||
return (x: T, y: T) => {
|
return (x: T, y: T) => {
|
||||||
@@ -183,24 +198,17 @@ export type MapToCurve<T> = (scalar: bigint[]) => AffinePoint<T>;
|
|||||||
|
|
||||||
// Separated from initialization opts, so users won't accidentally change per-curve parameters
|
// Separated from initialization opts, so users won't accidentally change per-curve parameters
|
||||||
// (changing DST is ok!)
|
// (changing DST is ok!)
|
||||||
export type htfBasicOpts = { DST: string };
|
export type htfBasicOpts = { DST: UnicodeOrBytes };
|
||||||
|
|
||||||
export function createHasher<T>(
|
export function createHasher<T>(
|
||||||
Point: H2CPointConstructor<T>,
|
Point: H2CPointConstructor<T>,
|
||||||
mapToCurve: MapToCurve<T>,
|
mapToCurve: MapToCurve<T>,
|
||||||
def: Opts & { encodeDST?: string }
|
def: Opts & { encodeDST?: UnicodeOrBytes }
|
||||||
) {
|
) {
|
||||||
validateObject(def, {
|
|
||||||
DST: 'string',
|
|
||||||
p: 'bigint',
|
|
||||||
m: 'isSafeInteger',
|
|
||||||
k: 'isSafeInteger',
|
|
||||||
hash: 'hash',
|
|
||||||
});
|
|
||||||
if (typeof mapToCurve !== 'function') throw new Error('mapToCurve() must be defined');
|
if (typeof mapToCurve !== 'function') throw new Error('mapToCurve() must be defined');
|
||||||
return {
|
return {
|
||||||
// Encodes byte string to elliptic curve
|
// Encodes byte string to elliptic curve.
|
||||||
// https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-11#section-3
|
// hash_to_curve from https://www.rfc-editor.org/rfc/rfc9380#section-3
|
||||||
hashToCurve(msg: Uint8Array, options?: htfBasicOpts) {
|
hashToCurve(msg: Uint8Array, options?: htfBasicOpts) {
|
||||||
const u = hash_to_field(msg, 2, { ...def, DST: def.DST, ...options } as Opts);
|
const u = hash_to_field(msg, 2, { ...def, DST: def.DST, ...options } as Opts);
|
||||||
const u0 = Point.fromAffine(mapToCurve(u[0]));
|
const u0 = Point.fromAffine(mapToCurve(u[0]));
|
||||||
@@ -210,7 +218,8 @@ export function createHasher<T>(
|
|||||||
return P;
|
return P;
|
||||||
},
|
},
|
||||||
|
|
||||||
// https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-16#section-3
|
// Encodes byte string to elliptic curve.
|
||||||
|
// encode_to_curve from https://www.rfc-editor.org/rfc/rfc9380#section-3
|
||||||
encodeToCurve(msg: Uint8Array, options?: htfBasicOpts) {
|
encodeToCurve(msg: Uint8Array, options?: htfBasicOpts) {
|
||||||
const u = hash_to_field(msg, 1, { ...def, DST: def.encodeDST, ...options } as Opts);
|
const u = hash_to_field(msg, 1, { ...def, DST: def.encodeDST, ...options } as Opts);
|
||||||
const P = Point.fromAffine(mapToCurve(u[0])).clearCofactor();
|
const P = Point.fromAffine(mapToCurve(u[0])).clearCofactor();
|
||||||
|
|||||||
@@ -22,10 +22,10 @@ export function mod(a: bigint, b: bigint): bigint {
|
|||||||
return result >= _0n ? result : b + result;
|
return result >= _0n ? result : b + result;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Efficiently exponentiate num to power and do modular division.
|
* Efficiently raise num to power and do modular division.
|
||||||
* Unsafe in some contexts: uses ladder, so can expose bigint bits.
|
* Unsafe in some contexts: uses ladder, so can expose bigint bits.
|
||||||
* @example
|
* @example
|
||||||
* powMod(2n, 6n, 11n) // 64n % 11n == 9n
|
* pow(2n, 6n, 11n) // 64n % 11n == 9n
|
||||||
*/
|
*/
|
||||||
// TODO: use field version && remove
|
// TODO: use field version && remove
|
||||||
export function pow(num: bigint, power: bigint, modulo: bigint): bigint {
|
export function pow(num: bigint, power: bigint, modulo: bigint): bigint {
|
||||||
@@ -55,7 +55,8 @@ export function invert(number: bigint, modulo: bigint): bigint {
|
|||||||
if (number === _0n || modulo <= _0n) {
|
if (number === _0n || modulo <= _0n) {
|
||||||
throw new Error(`invert: expected positive integers, got n=${number} mod=${modulo}`);
|
throw new Error(`invert: expected positive integers, got n=${number} mod=${modulo}`);
|
||||||
}
|
}
|
||||||
// Eucledian GCD https://brilliant.org/wiki/extended-euclidean-algorithm/
|
// Euclidean GCD https://brilliant.org/wiki/extended-euclidean-algorithm/
|
||||||
|
// Fermat's little theorem "CT-like" version inv(n) = n^(m-2) mod m is 30x slower.
|
||||||
let a = mod(number, modulo);
|
let a = mod(number, modulo);
|
||||||
let b = modulo;
|
let b = modulo;
|
||||||
// prettier-ignore
|
// prettier-ignore
|
||||||
@@ -74,9 +75,14 @@ export function invert(number: bigint, modulo: bigint): bigint {
|
|||||||
return mod(x, modulo);
|
return mod(x, modulo);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tonelli-Shanks algorithm
|
/**
|
||||||
// Paper 1: https://eprint.iacr.org/2012/685.pdf (page 12)
|
* Tonelli-Shanks square root search algorithm.
|
||||||
// Paper 2: Square Roots from 1; 24, 51, 10 to Dan Shanks
|
* 1. https://eprint.iacr.org/2012/685.pdf (page 12)
|
||||||
|
* 2. Square Roots from 1; 24, 51, 10 to Dan Shanks
|
||||||
|
* Will start an infinite loop if field order P is not prime.
|
||||||
|
* @param P field order
|
||||||
|
* @returns function that takes field Fp (created from P) and number n
|
||||||
|
*/
|
||||||
export function tonelliShanks(P: bigint) {
|
export function tonelliShanks(P: bigint) {
|
||||||
// Legendre constant: used to calculate Legendre symbol (a | p),
|
// Legendre constant: used to calculate Legendre symbol (a | p),
|
||||||
// which denotes the value of a^((p-1)/2) (mod p).
|
// which denotes the value of a^((p-1)/2) (mod p).
|
||||||
@@ -96,7 +102,7 @@ export function tonelliShanks(P: bigint) {
|
|||||||
// Fast-path
|
// Fast-path
|
||||||
if (S === 1) {
|
if (S === 1) {
|
||||||
const p1div4 = (P + _1n) / _4n;
|
const p1div4 = (P + _1n) / _4n;
|
||||||
return function tonelliFast<T>(Fp: Field<T>, n: T) {
|
return function tonelliFast<T>(Fp: IField<T>, n: T) {
|
||||||
const root = Fp.pow(n, p1div4);
|
const root = Fp.pow(n, p1div4);
|
||||||
if (!Fp.eql(Fp.sqr(root), n)) throw new Error('Cannot find square root');
|
if (!Fp.eql(Fp.sqr(root), n)) throw new Error('Cannot find square root');
|
||||||
return root;
|
return root;
|
||||||
@@ -105,7 +111,7 @@ export function tonelliShanks(P: bigint) {
|
|||||||
|
|
||||||
// Slow-path
|
// Slow-path
|
||||||
const Q1div2 = (Q + _1n) / _2n;
|
const Q1div2 = (Q + _1n) / _2n;
|
||||||
return function tonelliSlow<T>(Fp: Field<T>, n: T): T {
|
return function tonelliSlow<T>(Fp: IField<T>, n: T): T {
|
||||||
// Step 0: Check that n is indeed a square: (n | p) should not be ≡ -1
|
// Step 0: Check that n is indeed a square: (n | p) should not be ≡ -1
|
||||||
if (Fp.pow(n, legendreC) === Fp.neg(Fp.ONE)) throw new Error('Cannot find square root');
|
if (Fp.pow(n, legendreC) === Fp.neg(Fp.ONE)) throw new Error('Cannot find square root');
|
||||||
let r = S;
|
let r = S;
|
||||||
@@ -145,7 +151,7 @@ export function FpSqrt(P: bigint) {
|
|||||||
// 0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaabn;
|
// 0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaabn;
|
||||||
// const NUM = 72057594037927816n;
|
// const NUM = 72057594037927816n;
|
||||||
const p1div4 = (P + _1n) / _4n;
|
const p1div4 = (P + _1n) / _4n;
|
||||||
return function sqrt3mod4<T>(Fp: Field<T>, n: T) {
|
return function sqrt3mod4<T>(Fp: IField<T>, n: T) {
|
||||||
const root = Fp.pow(n, p1div4);
|
const root = Fp.pow(n, p1div4);
|
||||||
// Throw if root**2 != n
|
// Throw if root**2 != n
|
||||||
if (!Fp.eql(Fp.sqr(root), n)) throw new Error('Cannot find square root');
|
if (!Fp.eql(Fp.sqr(root), n)) throw new Error('Cannot find square root');
|
||||||
@@ -156,7 +162,7 @@ export function FpSqrt(P: bigint) {
|
|||||||
// Atkin algorithm for q ≡ 5 (mod 8), https://eprint.iacr.org/2012/685.pdf (page 10)
|
// Atkin algorithm for q ≡ 5 (mod 8), https://eprint.iacr.org/2012/685.pdf (page 10)
|
||||||
if (P % _8n === _5n) {
|
if (P % _8n === _5n) {
|
||||||
const c1 = (P - _5n) / _8n;
|
const c1 = (P - _5n) / _8n;
|
||||||
return function sqrt5mod8<T>(Fp: Field<T>, n: T) {
|
return function sqrt5mod8<T>(Fp: IField<T>, n: T) {
|
||||||
const n2 = Fp.mul(n, _2n);
|
const n2 = Fp.mul(n, _2n);
|
||||||
const v = Fp.pow(n2, c1);
|
const v = Fp.pow(n2, c1);
|
||||||
const nv = Fp.mul(n, v);
|
const nv = Fp.mul(n, v);
|
||||||
@@ -197,12 +203,8 @@ export function FpSqrt(P: bigint) {
|
|||||||
// Little-endian check for first LE bit (last BE bit);
|
// Little-endian check for first LE bit (last BE bit);
|
||||||
export const isNegativeLE = (num: bigint, modulo: bigint) => (mod(num, modulo) & _1n) === _1n;
|
export const isNegativeLE = (num: bigint, modulo: bigint) => (mod(num, modulo) & _1n) === _1n;
|
||||||
|
|
||||||
// Currently completly inconsistent naming:
|
// Field is not always over prime: for example, Fp2 has ORDER(q)=p^m
|
||||||
// - readable: add, mul, sqr, sqrt, inv, div, pow, eq, sub
|
export interface IField<T> {
|
||||||
// - unreadable mess: addition, multiply, square, squareRoot, inversion, divide, power, equals, subtract
|
|
||||||
|
|
||||||
// Field is not always over prime, Fp2 for example has ORDER(q)=p^m
|
|
||||||
export interface Field<T> {
|
|
||||||
ORDER: bigint;
|
ORDER: bigint;
|
||||||
BYTES: number;
|
BYTES: number;
|
||||||
BITS: number;
|
BITS: number;
|
||||||
@@ -231,7 +233,8 @@ export interface Field<T> {
|
|||||||
sqrN(num: T): T;
|
sqrN(num: T): T;
|
||||||
|
|
||||||
// Optional
|
// Optional
|
||||||
// Should be same as sgn0 function in https://datatracker.ietf.org/doc/draft-irtf-cfrg-hash-to-curve/
|
// Should be same as sgn0 function in
|
||||||
|
// [RFC9380](https://www.rfc-editor.org/rfc/rfc9380#section-4.1).
|
||||||
// NOTE: sgn0 is 'negative in LE', which is same as odd. And negative in LE is kinda strange definition anyway.
|
// NOTE: sgn0 is 'negative in LE', which is same as odd. And negative in LE is kinda strange definition anyway.
|
||||||
isOdd?(num: T): boolean; // Odd instead of even since we have it for Fp2
|
isOdd?(num: T): boolean; // Odd instead of even since we have it for Fp2
|
||||||
// legendre?(num: T): T;
|
// legendre?(num: T): T;
|
||||||
@@ -248,7 +251,7 @@ const FIELD_FIELDS = [
|
|||||||
'eql', 'add', 'sub', 'mul', 'pow', 'div',
|
'eql', 'add', 'sub', 'mul', 'pow', 'div',
|
||||||
'addN', 'subN', 'mulN', 'sqrN'
|
'addN', 'subN', 'mulN', 'sqrN'
|
||||||
] as const;
|
] as const;
|
||||||
export function validateField<T>(field: Field<T>) {
|
export function validateField<T>(field: IField<T>) {
|
||||||
const initial = {
|
const initial = {
|
||||||
ORDER: 'bigint',
|
ORDER: 'bigint',
|
||||||
MASK: 'bigint',
|
MASK: 'bigint',
|
||||||
@@ -263,7 +266,12 @@ export function validateField<T>(field: Field<T>) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Generic field functions
|
// Generic field functions
|
||||||
export function FpPow<T>(f: Field<T>, num: T, power: bigint): T {
|
|
||||||
|
/**
|
||||||
|
* Same as `pow` but for Fp: non-constant-time.
|
||||||
|
* Unsafe in some contexts: uses ladder, so can expose bigint bits.
|
||||||
|
*/
|
||||||
|
export function FpPow<T>(f: IField<T>, num: T, power: bigint): T {
|
||||||
// Should have same speed as pow for bigints
|
// Should have same speed as pow for bigints
|
||||||
// TODO: benchmark!
|
// TODO: benchmark!
|
||||||
if (power < _0n) throw new Error('Expected power > 0');
|
if (power < _0n) throw new Error('Expected power > 0');
|
||||||
@@ -274,12 +282,16 @@ export function FpPow<T>(f: Field<T>, num: T, power: bigint): T {
|
|||||||
while (power > _0n) {
|
while (power > _0n) {
|
||||||
if (power & _1n) p = f.mul(p, d);
|
if (power & _1n) p = f.mul(p, d);
|
||||||
d = f.sqr(d);
|
d = f.sqr(d);
|
||||||
power >>= 1n;
|
power >>= _1n;
|
||||||
}
|
}
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function FpInvertBatch<T>(f: Field<T>, nums: T[]): T[] {
|
/**
|
||||||
|
* Efficiently invert an array of Field elements.
|
||||||
|
* `inv(0)` will return `undefined` here: make sure to throw an error.
|
||||||
|
*/
|
||||||
|
export function FpInvertBatch<T>(f: IField<T>, nums: T[]): T[] {
|
||||||
const tmp = new Array(nums.length);
|
const tmp = new Array(nums.length);
|
||||||
// Walk from first to last, multiply them by each other MOD p
|
// Walk from first to last, multiply them by each other MOD p
|
||||||
const lastMultiplied = nums.reduce((acc, num, i) => {
|
const lastMultiplied = nums.reduce((acc, num, i) => {
|
||||||
@@ -298,12 +310,12 @@ export function FpInvertBatch<T>(f: Field<T>, nums: T[]): T[] {
|
|||||||
return tmp;
|
return tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function FpDiv<T>(f: Field<T>, lhs: T, rhs: T | bigint): T {
|
export function FpDiv<T>(f: IField<T>, lhs: T, rhs: T | bigint): T {
|
||||||
return f.mul(lhs, typeof rhs === 'bigint' ? invert(rhs, f.ORDER) : f.inv(rhs));
|
return f.mul(lhs, typeof rhs === 'bigint' ? invert(rhs, f.ORDER) : f.inv(rhs));
|
||||||
}
|
}
|
||||||
|
|
||||||
// This function returns True whenever the value x is a square in the field F.
|
// This function returns True whenever the value x is a square in the field F.
|
||||||
export function FpIsSquare<T>(f: Field<T>) {
|
export function FpIsSquare<T>(f: IField<T>) {
|
||||||
const legendreConst = (f.ORDER - _1n) / _2n; // Integer arithmetic
|
const legendreConst = (f.ORDER - _1n) / _2n; // Integer arithmetic
|
||||||
return (x: T): boolean => {
|
return (x: T): boolean => {
|
||||||
const p = f.pow(x, legendreConst);
|
const p = f.pow(x, legendreConst);
|
||||||
@@ -319,18 +331,26 @@ export function nLength(n: bigint, nBitLength?: number) {
|
|||||||
return { nBitLength: _nBitLength, nByteLength };
|
return { nBitLength: _nBitLength, nByteLength };
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: very fragile, always bench. Major performance points:
|
type FpField = IField<bigint> & Required<Pick<IField<bigint>, 'isOdd'>>;
|
||||||
// - NonNormalized ops
|
/**
|
||||||
// - Object.freeze
|
* Initializes a finite field over prime. **Non-primes are not supported.**
|
||||||
// - same shape of object (don't add/remove keys)
|
* Do not init in loop: slow. Very fragile: always run a benchmark on a change.
|
||||||
type FpField = Field<bigint> & Required<Pick<Field<bigint>, 'isOdd'>>;
|
* Major performance optimizations:
|
||||||
export function Fp(
|
* * a) denormalized operations like mulN instead of mul
|
||||||
|
* * b) same object shape: never add or remove keys
|
||||||
|
* * c) Object.freeze
|
||||||
|
* @param ORDER prime positive bigint
|
||||||
|
* @param bitLen how many bits the field consumes
|
||||||
|
* @param isLE (def: false) if encoding / decoding should be in little-endian
|
||||||
|
* @param redef optional faster redefinitions of sqrt and other methods
|
||||||
|
*/
|
||||||
|
export function Field(
|
||||||
ORDER: bigint,
|
ORDER: bigint,
|
||||||
bitLen?: number,
|
bitLen?: number,
|
||||||
isLE = false,
|
isLE = false,
|
||||||
redef: Partial<Field<bigint>> = {}
|
redef: Partial<IField<bigint>> = {}
|
||||||
): Readonly<FpField> {
|
): Readonly<FpField> {
|
||||||
if (ORDER <= _0n) throw new Error(`Expected Fp ORDER > 0, got ${ORDER}`);
|
if (ORDER <= _0n) throw new Error(`Expected Field ORDER > 0, got ${ORDER}`);
|
||||||
const { nBitLength: BITS, nByteLength: BYTES } = nLength(ORDER, bitLen);
|
const { nBitLength: BITS, nByteLength: BYTES } = nLength(ORDER, bitLen);
|
||||||
if (BYTES > 2048) throw new Error('Field lengths over 2048 bytes are not supported');
|
if (BYTES > 2048) throw new Error('Field lengths over 2048 bytes are not supported');
|
||||||
const sqrtP = FpSqrt(ORDER);
|
const sqrtP = FpSqrt(ORDER);
|
||||||
@@ -381,26 +401,23 @@ export function Fp(
|
|||||||
return Object.freeze(f);
|
return Object.freeze(f);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function FpSqrtOdd<T>(Fp: Field<T>, elm: T) {
|
export function FpSqrtOdd<T>(Fp: IField<T>, elm: T) {
|
||||||
if (!Fp.isOdd) throw new Error(`Field doesn't have isOdd`);
|
if (!Fp.isOdd) throw new Error(`Field doesn't have isOdd`);
|
||||||
const root = Fp.sqrt(elm);
|
const root = Fp.sqrt(elm);
|
||||||
return Fp.isOdd(root) ? root : Fp.neg(root);
|
return Fp.isOdd(root) ? root : Fp.neg(root);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function FpSqrtEven<T>(Fp: Field<T>, elm: T) {
|
export function FpSqrtEven<T>(Fp: IField<T>, elm: T) {
|
||||||
if (!Fp.isOdd) throw new Error(`Field doesn't have isOdd`);
|
if (!Fp.isOdd) throw new Error(`Field doesn't have isOdd`);
|
||||||
const root = Fp.sqrt(elm);
|
const root = Fp.sqrt(elm);
|
||||||
return Fp.isOdd(root) ? Fp.neg(root) : root;
|
return Fp.isOdd(root) ? Fp.neg(root) : root;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* FIPS 186 B.4.1-compliant "constant-time" private key generation utility.
|
* "Constant-time" private key generation utility.
|
||||||
* Can take (n+8) or more bytes of uniform input e.g. from CSPRNG or KDF
|
* Same as mapKeyToField, but accepts less bytes (40 instead of 48 for 32-byte field).
|
||||||
* and convert them into private scalar, with the modulo bias being neglible.
|
* Which makes it slightly more biased, less secure.
|
||||||
* Needs at least 40 bytes of input for 32-byte private key.
|
* @deprecated use mapKeyToField instead
|
||||||
* https://research.kudelskisecurity.com/2020/07/28/the-definitive-guide-to-modulo-bias-and-how-to-avoid-it/
|
|
||||||
* @param hash hash output from SHA3 or a similar function
|
|
||||||
* @returns valid private scalar
|
|
||||||
*/
|
*/
|
||||||
export function hashToPrivateScalar(
|
export function hashToPrivateScalar(
|
||||||
hash: string | Uint8Array,
|
hash: string | Uint8Array,
|
||||||
@@ -415,3 +432,53 @@ export function hashToPrivateScalar(
|
|||||||
const num = isLE ? bytesToNumberLE(hash) : bytesToNumberBE(hash);
|
const num = isLE ? bytesToNumberLE(hash) : bytesToNumberBE(hash);
|
||||||
return mod(num, groupOrder - _1n) + _1n;
|
return mod(num, groupOrder - _1n) + _1n;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns total number of bytes consumed by the field element.
|
||||||
|
* For example, 32 bytes for usual 256-bit weierstrass curve.
|
||||||
|
* @param fieldOrder number of field elements, usually CURVE.n
|
||||||
|
* @returns byte length of field
|
||||||
|
*/
|
||||||
|
export function getFieldBytesLength(fieldOrder: bigint): number {
|
||||||
|
if (typeof fieldOrder !== 'bigint') throw new Error('field order must be bigint');
|
||||||
|
const bitLength = fieldOrder.toString(2).length;
|
||||||
|
return Math.ceil(bitLength / 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns minimal amount of bytes that can be safely reduced
|
||||||
|
* by field order.
|
||||||
|
* Should be 2^-128 for 128-bit curve such as P256.
|
||||||
|
* @param fieldOrder number of field elements, usually CURVE.n
|
||||||
|
* @returns byte length of target hash
|
||||||
|
*/
|
||||||
|
export function getMinHashLength(fieldOrder: bigint): number {
|
||||||
|
const length = getFieldBytesLength(fieldOrder);
|
||||||
|
return length + Math.ceil(length / 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* "Constant-time" private key generation utility.
|
||||||
|
* Can take (n + n/2) or more bytes of uniform input e.g. from CSPRNG or KDF
|
||||||
|
* and convert them into private scalar, with the modulo bias being negligible.
|
||||||
|
* Needs at least 48 bytes of input for 32-byte private key.
|
||||||
|
* https://research.kudelskisecurity.com/2020/07/28/the-definitive-guide-to-modulo-bias-and-how-to-avoid-it/
|
||||||
|
* FIPS 186-5, A.2 https://csrc.nist.gov/publications/detail/fips/186/5/final
|
||||||
|
* RFC 9380, https://www.rfc-editor.org/rfc/rfc9380#section-5
|
||||||
|
* @param hash hash output from SHA3 or a similar function
|
||||||
|
* @param groupOrder size of subgroup - (e.g. secp256k1.CURVE.n)
|
||||||
|
* @param isLE interpret hash bytes as LE num
|
||||||
|
* @returns valid private scalar
|
||||||
|
*/
|
||||||
|
export function mapHashToField(key: Uint8Array, fieldOrder: bigint, isLE = false): Uint8Array {
|
||||||
|
const len = key.length;
|
||||||
|
const fieldLen = getFieldBytesLength(fieldOrder);
|
||||||
|
const minLen = getMinHashLength(fieldOrder);
|
||||||
|
// No small numbers: need to understand bias story. No huge numbers: easier to detect JS timings.
|
||||||
|
if (len < 16 || len < minLen || len > 1024)
|
||||||
|
throw new Error(`expected ${minLen}-1024 bytes of input, got ${len}`);
|
||||||
|
const num = isLE ? bytesToNumberBE(key) : bytesToNumberLE(key);
|
||||||
|
// `mod(x, 11)` can sometimes produce 0. `mod(x, 10) + 1` is the same, but no 0
|
||||||
|
const reduced = mod(num, fieldOrder - _1n) + _1n;
|
||||||
|
return isLE ? numberToBytesLE(reduced, fieldLen) : numberToBytesBE(reduced, fieldLen);
|
||||||
|
}
|
||||||
|
|||||||
@@ -150,17 +150,15 @@ export function montgomery(curveDef: CurveType): CurveFn {
|
|||||||
function decodeUCoordinate(uEnc: Hex): bigint {
|
function decodeUCoordinate(uEnc: Hex): bigint {
|
||||||
// Section 5: When receiving such an array, implementations of X25519
|
// Section 5: When receiving such an array, implementations of X25519
|
||||||
// MUST mask the most significant bit in the final byte.
|
// MUST mask the most significant bit in the final byte.
|
||||||
// This is very ugly way, but it works because fieldLen-1 is outside of bounds for X448, so this becomes NOOP
|
|
||||||
// fieldLen - scalaryBytes = 1 for X448 and = 0 for X25519
|
|
||||||
const u = ensureBytes('u coordinate', uEnc, montgomeryBytes);
|
const u = ensureBytes('u coordinate', uEnc, montgomeryBytes);
|
||||||
// u[fieldLen-1] crashes QuickJS (TypeError: out-of-bound numeric index)
|
if (fieldLen === 32) u[31] &= 127; // 0b0111_1111
|
||||||
if (fieldLen === montgomeryBytes) u[fieldLen - 1] &= 127; // 0b0111_1111
|
|
||||||
return bytesToNumberLE(u);
|
return bytesToNumberLE(u);
|
||||||
}
|
}
|
||||||
function decodeScalar(n: Hex): bigint {
|
function decodeScalar(n: Hex): bigint {
|
||||||
const bytes = ensureBytes('scalar', n);
|
const bytes = ensureBytes('scalar', n);
|
||||||
if (bytes.length !== montgomeryBytes && bytes.length !== fieldLen)
|
const len = bytes.length;
|
||||||
throw new Error(`Expected ${montgomeryBytes} or ${fieldLen} bytes, got ${bytes.length}`);
|
if (len !== montgomeryBytes && len !== fieldLen)
|
||||||
|
throw new Error(`Expected ${montgomeryBytes} or ${fieldLen} bytes, got ${len}`);
|
||||||
return bytesToNumberLE(adjustScalarBytes(bytes));
|
return bytesToNumberLE(adjustScalarBytes(bytes));
|
||||||
}
|
}
|
||||||
function scalarMult(scalar: Hex, u: Hex): Uint8Array {
|
function scalarMult(scalar: Hex, u: Hex): Uint8Array {
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
||||||
// Poseidon Hash: https://eprint.iacr.org/2019/458.pdf, https://www.poseidon-hash.info
|
// Poseidon Hash: https://eprint.iacr.org/2019/458.pdf, https://www.poseidon-hash.info
|
||||||
import { Field, FpPow, validateField } from './modular.js';
|
import { IField, FpPow, validateField } from './modular.js';
|
||||||
// We don't provide any constants, since different implementations use different constants.
|
// We don't provide any constants, since different implementations use different constants.
|
||||||
// For reference constants see './test/poseidon.test.js'.
|
// For reference constants see './test/poseidon.test.js'.
|
||||||
export type PoseidonOpts = {
|
export type PoseidonOpts = {
|
||||||
Fp: Field<bigint>;
|
Fp: IField<bigint>;
|
||||||
t: number;
|
t: number;
|
||||||
roundsFull: number;
|
roundsFull: number;
|
||||||
roundsPartial: number;
|
roundsPartial: number;
|
||||||
@@ -15,34 +15,36 @@ export type PoseidonOpts = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export function validateOpts(opts: PoseidonOpts) {
|
export function validateOpts(opts: PoseidonOpts) {
|
||||||
const { Fp } = opts;
|
const { Fp, mds, reversePartialPowIdx: rev, roundConstants: rc } = opts;
|
||||||
|
const { roundsFull, roundsPartial, sboxPower, t } = opts;
|
||||||
|
|
||||||
validateField(Fp);
|
validateField(Fp);
|
||||||
for (const i of ['t', 'roundsFull', 'roundsPartial'] as const) {
|
for (const i of ['t', 'roundsFull', 'roundsPartial'] as const) {
|
||||||
if (typeof opts[i] !== 'number' || !Number.isSafeInteger(opts[i]))
|
if (typeof opts[i] !== 'number' || !Number.isSafeInteger(opts[i]))
|
||||||
throw new Error(`Poseidon: invalid param ${i}=${opts[i]} (${typeof opts[i]})`);
|
throw new Error(`Poseidon: invalid param ${i}=${opts[i]} (${typeof opts[i]})`);
|
||||||
}
|
}
|
||||||
if (opts.reversePartialPowIdx !== undefined && typeof opts.reversePartialPowIdx !== 'boolean')
|
|
||||||
throw new Error(`Poseidon: invalid param reversePartialPowIdx=${opts.reversePartialPowIdx}`);
|
|
||||||
// Default is 5, but by some reasons stark uses 3
|
|
||||||
let sboxPower = opts.sboxPower;
|
|
||||||
if (sboxPower === undefined) sboxPower = 5;
|
|
||||||
if (typeof sboxPower !== 'number' || !Number.isSafeInteger(sboxPower))
|
|
||||||
throw new Error(`Poseidon wrong sboxPower=${sboxPower}`);
|
|
||||||
|
|
||||||
const _sboxPower = BigInt(sboxPower);
|
// MDS is TxT matrix
|
||||||
let sboxFn = (n: bigint) => FpPow(Fp, n, _sboxPower);
|
if (!Array.isArray(mds) || mds.length !== t) throw new Error('Poseidon: wrong MDS matrix');
|
||||||
// Unwrapped sbox power for common cases (195->142μs)
|
const _mds = mds.map((mdsRow) => {
|
||||||
if (sboxPower === 3) sboxFn = (n: bigint) => Fp.mul(Fp.sqrN(n), n);
|
if (!Array.isArray(mdsRow) || mdsRow.length !== t)
|
||||||
else if (sboxPower === 5) sboxFn = (n: bigint) => Fp.mul(Fp.sqrN(Fp.sqrN(n)), n);
|
throw new Error(`Poseidon MDS matrix row: ${mdsRow}`);
|
||||||
|
return mdsRow.map((i) => {
|
||||||
|
if (typeof i !== 'bigint') throw new Error(`Poseidon MDS matrix value=${i}`);
|
||||||
|
return Fp.create(i);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
if (opts.roundsFull % 2 !== 0)
|
if (rev !== undefined && typeof rev !== 'boolean')
|
||||||
throw new Error(`Poseidon roundsFull is not even: ${opts.roundsFull}`);
|
throw new Error(`Poseidon: invalid param reversePartialPowIdx=${rev}`);
|
||||||
const rounds = opts.roundsFull + opts.roundsPartial;
|
|
||||||
|
|
||||||
if (!Array.isArray(opts.roundConstants) || opts.roundConstants.length !== rounds)
|
if (roundsFull % 2 !== 0) throw new Error(`Poseidon roundsFull is not even: ${roundsFull}`);
|
||||||
|
const rounds = roundsFull + roundsPartial;
|
||||||
|
|
||||||
|
if (!Array.isArray(rc) || rc.length !== rounds)
|
||||||
throw new Error('Poseidon: wrong round constants');
|
throw new Error('Poseidon: wrong round constants');
|
||||||
const roundConstants = opts.roundConstants.map((rc) => {
|
const roundConstants = rc.map((rc) => {
|
||||||
if (!Array.isArray(rc) || rc.length !== opts.t)
|
if (!Array.isArray(rc) || rc.length !== t)
|
||||||
throw new Error(`Poseidon wrong round constants: ${rc}`);
|
throw new Error(`Poseidon wrong round constants: ${rc}`);
|
||||||
return rc.map((i) => {
|
return rc.map((i) => {
|
||||||
if (typeof i !== 'bigint' || !Fp.isValid(i))
|
if (typeof i !== 'bigint' || !Fp.isValid(i))
|
||||||
@@ -50,18 +52,16 @@ export function validateOpts(opts: PoseidonOpts) {
|
|||||||
return Fp.create(i);
|
return Fp.create(i);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
// MDS is TxT matrix
|
|
||||||
if (!Array.isArray(opts.mds) || opts.mds.length !== opts.t)
|
if (!sboxPower || ![3, 5, 7].includes(sboxPower))
|
||||||
throw new Error('Poseidon: wrong MDS matrix');
|
throw new Error(`Poseidon wrong sboxPower=${sboxPower}`);
|
||||||
const mds = opts.mds.map((mdsRow) => {
|
const _sboxPower = BigInt(sboxPower);
|
||||||
if (!Array.isArray(mdsRow) || mdsRow.length !== opts.t)
|
let sboxFn = (n: bigint) => FpPow(Fp, n, _sboxPower);
|
||||||
throw new Error(`Poseidon MDS matrix row: ${mdsRow}`);
|
// Unwrapped sbox power for common cases (195->142μs)
|
||||||
return mdsRow.map((i) => {
|
if (sboxPower === 3) sboxFn = (n: bigint) => Fp.mul(Fp.sqrN(n), n);
|
||||||
if (typeof i !== 'bigint') throw new Error(`Poseidon MDS matrix value=${i}`);
|
else if (sboxPower === 5) sboxFn = (n: bigint) => Fp.mul(Fp.sqrN(Fp.sqrN(n)), n);
|
||||||
return Fp.create(i);
|
|
||||||
});
|
return Object.freeze({ ...opts, rounds, sboxFn, roundConstants, mds: _mds });
|
||||||
});
|
|
||||||
return Object.freeze({ ...opts, rounds, sboxFn, roundConstants, mds });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function splitConstants(rc: bigint[], t: number) {
|
export function splitConstants(rc: bigint[], t: number) {
|
||||||
@@ -80,18 +80,17 @@ export function splitConstants(rc: bigint[], t: number) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function poseidon(opts: PoseidonOpts) {
|
export function poseidon(opts: PoseidonOpts) {
|
||||||
const { t, Fp, rounds, sboxFn, reversePartialPowIdx } = validateOpts(opts);
|
const _opts = validateOpts(opts);
|
||||||
const halfRoundsFull = Math.floor(opts.roundsFull / 2);
|
const { Fp, mds, roundConstants, rounds, roundsPartial, sboxFn, t } = _opts;
|
||||||
const partialIdx = reversePartialPowIdx ? t - 1 : 0;
|
const halfRoundsFull = _opts.roundsFull / 2;
|
||||||
|
const partialIdx = _opts.reversePartialPowIdx ? t - 1 : 0;
|
||||||
const poseidonRound = (values: bigint[], isFull: boolean, idx: number) => {
|
const poseidonRound = (values: bigint[], isFull: boolean, idx: number) => {
|
||||||
values = values.map((i, j) => Fp.add(i, opts.roundConstants[idx][j]));
|
values = values.map((i, j) => Fp.add(i, roundConstants[idx][j]));
|
||||||
|
|
||||||
if (isFull) values = values.map((i) => sboxFn(i));
|
if (isFull) values = values.map((i) => sboxFn(i));
|
||||||
else values[partialIdx] = sboxFn(values[partialIdx]);
|
else values[partialIdx] = sboxFn(values[partialIdx]);
|
||||||
// Matrix multiplication
|
// Matrix multiplication
|
||||||
values = opts.mds.map((i) =>
|
values = mds.map((i) => i.reduce((acc, i, j) => Fp.add(acc, Fp.mulN(i, values[j])), Fp.ZERO));
|
||||||
i.reduce((acc, i, j) => Fp.add(acc, Fp.mulN(i, values[j])), Fp.ZERO)
|
|
||||||
);
|
|
||||||
return values;
|
return values;
|
||||||
};
|
};
|
||||||
const poseidonHash = function poseidonHash(values: bigint[]) {
|
const poseidonHash = function poseidonHash(values: bigint[]) {
|
||||||
@@ -105,7 +104,7 @@ export function poseidon(opts: PoseidonOpts) {
|
|||||||
// Apply r_f/2 full rounds.
|
// Apply r_f/2 full rounds.
|
||||||
for (let i = 0; i < halfRoundsFull; i++) values = poseidonRound(values, true, round++);
|
for (let i = 0; i < halfRoundsFull; i++) values = poseidonRound(values, true, round++);
|
||||||
// Apply r_p partial rounds.
|
// Apply r_p partial rounds.
|
||||||
for (let i = 0; i < opts.roundsPartial; i++) values = poseidonRound(values, false, round++);
|
for (let i = 0; i < roundsPartial; i++) values = poseidonRound(values, false, round++);
|
||||||
// Apply r_f/2 full rounds.
|
// Apply r_f/2 full rounds.
|
||||||
for (let i = 0; i < halfRoundsFull; i++) values = poseidonRound(values, true, round++);
|
for (let i = 0; i < halfRoundsFull; i++) values = poseidonRound(values, true, round++);
|
||||||
|
|
||||||
@@ -114,6 +113,6 @@ export function poseidon(opts: PoseidonOpts) {
|
|||||||
return values;
|
return values;
|
||||||
};
|
};
|
||||||
// For verification in tests
|
// For verification in tests
|
||||||
poseidonHash.roundConstants = opts.roundConstants;
|
poseidonHash.roundConstants = roundConstants;
|
||||||
return poseidonHash;
|
return poseidonHash;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
||||||
|
// 100 lines of code in the file are duplicated from noble-hashes (utils).
|
||||||
|
// This is OK: `abstract` directory does not use noble-hashes.
|
||||||
|
// User may opt-in into using different hashing library. This way, noble-hashes
|
||||||
|
// won't be included into their bundle.
|
||||||
const _0n = BigInt(0);
|
const _0n = BigInt(0);
|
||||||
const _1n = BigInt(1);
|
const _1n = BigInt(1);
|
||||||
const _2n = BigInt(2);
|
const _2n = BigInt(2);
|
||||||
const u8a = (a: any): a is Uint8Array => a instanceof Uint8Array;
|
export type Hex = Uint8Array | string; // hex strings are accepted for simplicity
|
||||||
|
export type PrivKey = Hex | bigint; // bigints are accepted to ease learning curve
|
||||||
// We accept hex strings besides Uint8Array for simplicity
|
|
||||||
export type Hex = Uint8Array | string;
|
|
||||||
// Very few implementations accept numbers, we do it to ease learning curve
|
|
||||||
export type PrivKey = Hex | bigint;
|
|
||||||
export type CHash = {
|
export type CHash = {
|
||||||
(message: Uint8Array | string): Uint8Array;
|
(message: Uint8Array | string): Uint8Array;
|
||||||
blockLen: number;
|
blockLen: number;
|
||||||
@@ -16,9 +16,22 @@ export type CHash = {
|
|||||||
};
|
};
|
||||||
export type FHash = (message: Uint8Array | string) => Uint8Array;
|
export type FHash = (message: Uint8Array | string) => Uint8Array;
|
||||||
|
|
||||||
const hexes = Array.from({ length: 256 }, (v, i) => i.toString(16).padStart(2, '0'));
|
export function isBytes(a: unknown): a is Uint8Array {
|
||||||
|
return (
|
||||||
|
a instanceof Uint8Array ||
|
||||||
|
(a != null && typeof a === 'object' && a.constructor.name === 'Uint8Array')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Array where index 0xf0 (240) is mapped to string 'f0'
|
||||||
|
const hexes = /* @__PURE__ */ Array.from({ length: 256 }, (_, i) =>
|
||||||
|
i.toString(16).padStart(2, '0')
|
||||||
|
);
|
||||||
|
/**
|
||||||
|
* @example bytesToHex(Uint8Array.from([0xca, 0xfe, 0x01, 0x23])) // 'cafe0123'
|
||||||
|
*/
|
||||||
export function bytesToHex(bytes: Uint8Array): string {
|
export function bytesToHex(bytes: Uint8Array): string {
|
||||||
if (!u8a(bytes)) throw new Error('Uint8Array expected');
|
if (!isBytes(bytes)) throw new Error('Uint8Array expected');
|
||||||
// pre-caching improves the speed 6x
|
// pre-caching improves the speed 6x
|
||||||
let hex = '';
|
let hex = '';
|
||||||
for (let i = 0; i < bytes.length; i++) {
|
for (let i = 0; i < bytes.length; i++) {
|
||||||
@@ -38,36 +51,65 @@ export function hexToNumber(hex: string): bigint {
|
|||||||
return BigInt(hex === '' ? '0' : `0x${hex}`);
|
return BigInt(hex === '' ? '0' : `0x${hex}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Caching slows it down 2-3x
|
// We use optimized technique to convert hex string to byte array
|
||||||
|
const asciis = { _0: 48, _9: 57, _A: 65, _F: 70, _a: 97, _f: 102 } as const;
|
||||||
|
function asciiToBase16(char: number): number | undefined {
|
||||||
|
if (char >= asciis._0 && char <= asciis._9) return char - asciis._0;
|
||||||
|
if (char >= asciis._A && char <= asciis._F) return char - (asciis._A - 10);
|
||||||
|
if (char >= asciis._a && char <= asciis._f) return char - (asciis._a - 10);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @example hexToBytes('cafe0123') // Uint8Array.from([0xca, 0xfe, 0x01, 0x23])
|
||||||
|
*/
|
||||||
export function hexToBytes(hex: string): Uint8Array {
|
export function hexToBytes(hex: string): Uint8Array {
|
||||||
if (typeof hex !== 'string') throw new Error('hex string expected, got ' + typeof hex);
|
if (typeof hex !== 'string') throw new Error('hex string expected, got ' + typeof hex);
|
||||||
if (hex.length % 2) throw new Error('hex string is invalid: unpadded ' + hex.length);
|
const hl = hex.length;
|
||||||
const array = new Uint8Array(hex.length / 2);
|
const al = hl / 2;
|
||||||
for (let i = 0; i < array.length; i++) {
|
if (hl % 2) throw new Error('padded hex string expected, got unpadded hex of length ' + hl);
|
||||||
const j = i * 2;
|
const array = new Uint8Array(al);
|
||||||
const hexByte = hex.slice(j, j + 2);
|
for (let ai = 0, hi = 0; ai < al; ai++, hi += 2) {
|
||||||
const byte = Number.parseInt(hexByte, 16);
|
const n1 = asciiToBase16(hex.charCodeAt(hi));
|
||||||
if (Number.isNaN(byte) || byte < 0) throw new Error('invalid byte sequence');
|
const n2 = asciiToBase16(hex.charCodeAt(hi + 1));
|
||||||
array[i] = byte;
|
if (n1 === undefined || n2 === undefined) {
|
||||||
|
const char = hex[hi] + hex[hi + 1];
|
||||||
|
throw new Error('hex string expected, got non-hex character "' + char + '" at index ' + hi);
|
||||||
|
}
|
||||||
|
array[ai] = n1 * 16 + n2;
|
||||||
}
|
}
|
||||||
return array;
|
return array;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Big Endian
|
// BE: Big Endian, LE: Little Endian
|
||||||
export function bytesToNumberBE(bytes: Uint8Array): bigint {
|
export function bytesToNumberBE(bytes: Uint8Array): bigint {
|
||||||
return hexToNumber(bytesToHex(bytes));
|
return hexToNumber(bytesToHex(bytes));
|
||||||
}
|
}
|
||||||
export function bytesToNumberLE(bytes: Uint8Array): bigint {
|
export function bytesToNumberLE(bytes: Uint8Array): bigint {
|
||||||
if (!u8a(bytes)) throw new Error('Uint8Array expected');
|
if (!isBytes(bytes)) throw new Error('Uint8Array expected');
|
||||||
return hexToNumber(bytesToHex(Uint8Array.from(bytes).reverse()));
|
return hexToNumber(bytesToHex(Uint8Array.from(bytes).reverse()));
|
||||||
}
|
}
|
||||||
|
|
||||||
export const numberToBytesBE = (n: bigint, len: number) =>
|
export function numberToBytesBE(n: number | bigint, len: number): Uint8Array {
|
||||||
hexToBytes(n.toString(16).padStart(len * 2, '0'));
|
return hexToBytes(n.toString(16).padStart(len * 2, '0'));
|
||||||
export const numberToBytesLE = (n: bigint, len: number) => numberToBytesBE(n, len).reverse();
|
}
|
||||||
// Returns variable number bytes (minimal bigint encoding?)
|
export function numberToBytesLE(n: number | bigint, len: number): Uint8Array {
|
||||||
export const numberToVarBytesBE = (n: bigint) => hexToBytes(numberToHexUnpadded(n));
|
return numberToBytesBE(n, len).reverse();
|
||||||
|
}
|
||||||
|
// Unpadded, rarely used
|
||||||
|
export function numberToVarBytesBE(n: number | bigint): Uint8Array {
|
||||||
|
return hexToBytes(numberToHexUnpadded(n));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Takes hex string or Uint8Array, converts to Uint8Array.
|
||||||
|
* Validates output length.
|
||||||
|
* Will throw error for other types.
|
||||||
|
* @param title descriptive title for an error e.g. 'private key'
|
||||||
|
* @param hex hex string or Uint8Array
|
||||||
|
* @param expectedLength optional, will compare to result array's length
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
export function ensureBytes(title: string, hex: Hex, expectedLength?: number): Uint8Array {
|
export function ensureBytes(title: string, hex: Hex, expectedLength?: number): Uint8Array {
|
||||||
let res: Uint8Array;
|
let res: Uint8Array;
|
||||||
if (typeof hex === 'string') {
|
if (typeof hex === 'string') {
|
||||||
@@ -76,7 +118,7 @@ export function ensureBytes(title: string, hex: Hex, expectedLength?: number): U
|
|||||||
} catch (e) {
|
} catch (e) {
|
||||||
throw new Error(`${title} must be valid hex string, got "${hex}". Cause: ${e}`);
|
throw new Error(`${title} must be valid hex string, got "${hex}". Cause: ${e}`);
|
||||||
}
|
}
|
||||||
} else if (u8a(hex)) {
|
} else if (isBytes(hex)) {
|
||||||
// Uint8Array.from() instead of hash.slice() because node.js Buffer
|
// Uint8Array.from() instead of hash.slice() because node.js Buffer
|
||||||
// is instance of Uint8Array, and its slice() creates **mutable** copy
|
// is instance of Uint8Array, and its slice() creates **mutable** copy
|
||||||
res = Uint8Array.from(hex);
|
res = Uint8Array.from(hex);
|
||||||
@@ -89,51 +131,77 @@ export function ensureBytes(title: string, hex: Hex, expectedLength?: number): U
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copies several Uint8Arrays into one.
|
/**
|
||||||
export function concatBytes(...arrs: Uint8Array[]): Uint8Array {
|
* Copies several Uint8Arrays into one.
|
||||||
const r = new Uint8Array(arrs.reduce((sum, a) => sum + a.length, 0));
|
*/
|
||||||
let pad = 0; // walk through each item, ensure they have proper type
|
export function concatBytes(...arrays: Uint8Array[]): Uint8Array {
|
||||||
arrs.forEach((a) => {
|
let sum = 0;
|
||||||
if (!u8a(a)) throw new Error('Uint8Array expected');
|
for (let i = 0; i < arrays.length; i++) {
|
||||||
r.set(a, pad);
|
const a = arrays[i];
|
||||||
|
if (!isBytes(a)) throw new Error('Uint8Array expected');
|
||||||
|
sum += a.length;
|
||||||
|
}
|
||||||
|
const res = new Uint8Array(sum);
|
||||||
|
for (let i = 0, pad = 0; i < arrays.length; i++) {
|
||||||
|
const a = arrays[i];
|
||||||
|
res.set(a, pad);
|
||||||
pad += a.length;
|
pad += a.length;
|
||||||
});
|
}
|
||||||
return r;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function equalBytes(b1: Uint8Array, b2: Uint8Array) {
|
// Compares 2 u8a-s in kinda constant time
|
||||||
// We don't care about timing attacks here
|
export function equalBytes(a: Uint8Array, b: Uint8Array) {
|
||||||
if (b1.length !== b2.length) return false;
|
if (a.length !== b.length) return false;
|
||||||
for (let i = 0; i < b1.length; i++) if (b1[i] !== b2[i]) return false;
|
let diff = 0;
|
||||||
return true;
|
for (let i = 0; i < a.length; i++) diff |= a[i] ^ b[i];
|
||||||
|
return diff === 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Global symbols in both browsers and Node.js since v11
|
// Global symbols in both browsers and Node.js since v11
|
||||||
// See https://github.com/microsoft/TypeScript/issues/31535
|
// See https://github.com/microsoft/TypeScript/issues/31535
|
||||||
declare const TextEncoder: any;
|
declare const TextEncoder: any;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @example utf8ToBytes('abc') // new Uint8Array([97, 98, 99])
|
||||||
|
*/
|
||||||
export function utf8ToBytes(str: string): Uint8Array {
|
export function utf8ToBytes(str: string): Uint8Array {
|
||||||
if (typeof str !== 'string') {
|
if (typeof str !== 'string') throw new Error(`utf8ToBytes expected string, got ${typeof str}`);
|
||||||
throw new Error(`utf8ToBytes expected string, got ${typeof str}`);
|
return new Uint8Array(new TextEncoder().encode(str)); // https://bugzil.la/1681809
|
||||||
}
|
|
||||||
return new TextEncoder().encode(str);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bit operations
|
// Bit operations
|
||||||
|
|
||||||
// Amount of bits inside bigint (Same as n.toString(2).length)
|
/**
|
||||||
|
* Calculates amount of bits in a bigint.
|
||||||
|
* Same as `n.toString(2).length`
|
||||||
|
*/
|
||||||
export function bitLen(n: bigint) {
|
export function bitLen(n: bigint) {
|
||||||
let len;
|
let len;
|
||||||
for (len = 0; n > 0n; n >>= _1n, len += 1);
|
for (len = 0; n > _0n; n >>= _1n, len += 1);
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
// Gets single bit at position. NOTE: first bit position is 0 (same as arrays)
|
|
||||||
// Same as !!+Array.from(n.toString(2)).reverse()[pos]
|
/**
|
||||||
export const bitGet = (n: bigint, pos: number) => (n >> BigInt(pos)) & 1n;
|
* Gets single bit at position.
|
||||||
// Sets single bit at position
|
* NOTE: first bit position is 0 (same as arrays)
|
||||||
export const bitSet = (n: bigint, pos: number, value: boolean) =>
|
* Same as `!!+Array.from(n.toString(2)).reverse()[pos]`
|
||||||
n | ((value ? _1n : _0n) << BigInt(pos));
|
*/
|
||||||
// Return mask for N bits (Same as BigInt(`0b${Array(i).fill('1').join('')}`))
|
export function bitGet(n: bigint, pos: number) {
|
||||||
// Not using ** operator with bigints for old engines.
|
return (n >> BigInt(pos)) & _1n;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets single bit at position.
|
||||||
|
*/
|
||||||
|
export const bitSet = (n: bigint, pos: number, value: boolean) => {
|
||||||
|
return n | ((value ? _1n : _0n) << BigInt(pos));
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculate mask for N bits. Not using ** operator with bigints because of old engines.
|
||||||
|
* Same as BigInt(`0b${Array(i).fill('1').join('')}`)
|
||||||
|
*/
|
||||||
export const bitMask = (n: number) => (_2n << BigInt(n - 1)) - _1n;
|
export const bitMask = (n: number) => (_2n << BigInt(n - 1)) - _1n;
|
||||||
|
|
||||||
// DRBG
|
// DRBG
|
||||||
@@ -205,6 +273,7 @@ const validatorFns = {
|
|||||||
function: (val: any) => typeof val === 'function',
|
function: (val: any) => typeof val === 'function',
|
||||||
boolean: (val: any) => typeof val === 'boolean',
|
boolean: (val: any) => typeof val === 'boolean',
|
||||||
string: (val: any) => typeof val === 'string',
|
string: (val: any) => typeof val === 'string',
|
||||||
|
stringOrUint8Array: (val: any) => typeof val === 'string' || isBytes(val),
|
||||||
isSafeInteger: (val: any) => Number.isSafeInteger(val),
|
isSafeInteger: (val: any) => Number.isSafeInteger(val),
|
||||||
array: (val: any) => Array.isArray(val),
|
array: (val: any) => Array.isArray(val),
|
||||||
field: (val: any, object: any) => (object as any).Fp.isValid(val),
|
field: (val: any, object: any) => (object as any).Fp.isValid(val),
|
||||||
|
|||||||
@@ -58,6 +58,8 @@ export interface ProjPointType<T> extends Group<ProjPointType<T>> {
|
|||||||
readonly px: T;
|
readonly px: T;
|
||||||
readonly py: T;
|
readonly py: T;
|
||||||
readonly pz: T;
|
readonly pz: T;
|
||||||
|
get x(): T;
|
||||||
|
get y(): T;
|
||||||
multiply(scalar: bigint): ProjPointType<T>;
|
multiply(scalar: bigint): ProjPointType<T>;
|
||||||
toAffine(iz?: T): AffinePoint<T>;
|
toAffine(iz?: T): AffinePoint<T>;
|
||||||
isTorsionFree(): boolean;
|
isTorsionFree(): boolean;
|
||||||
@@ -82,8 +84,8 @@ export interface ProjConstructor<T> extends GroupConstructor<ProjPointType<T>> {
|
|||||||
|
|
||||||
export type CurvePointsType<T> = BasicWCurve<T> & {
|
export type CurvePointsType<T> = BasicWCurve<T> & {
|
||||||
// Bytes
|
// Bytes
|
||||||
fromBytes: (bytes: Uint8Array) => AffinePoint<T>;
|
fromBytes?: (bytes: Uint8Array) => AffinePoint<T>;
|
||||||
toBytes: (c: ProjConstructor<T>, point: ProjPointType<T>, compressed: boolean) => Uint8Array;
|
toBytes?: (c: ProjConstructor<T>, point: ProjPointType<T>, isCompressed: boolean) => Uint8Array;
|
||||||
};
|
};
|
||||||
|
|
||||||
function validatePointOpts<T>(curve: CurvePointsType<T>) {
|
function validatePointOpts<T>(curve: CurvePointsType<T>) {
|
||||||
@@ -93,8 +95,6 @@ function validatePointOpts<T>(curve: CurvePointsType<T>) {
|
|||||||
{
|
{
|
||||||
a: 'field',
|
a: 'field',
|
||||||
b: 'field',
|
b: 'field',
|
||||||
fromBytes: 'function',
|
|
||||||
toBytes: 'function',
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
allowedPrivateKeyLengths: 'array',
|
allowedPrivateKeyLengths: 'array',
|
||||||
@@ -102,6 +102,8 @@ function validatePointOpts<T>(curve: CurvePointsType<T>) {
|
|||||||
isTorsionFree: 'function',
|
isTorsionFree: 'function',
|
||||||
clearCofactor: 'function',
|
clearCofactor: 'function',
|
||||||
allowInfinityPoint: 'boolean',
|
allowInfinityPoint: 'boolean',
|
||||||
|
fromBytes: 'function',
|
||||||
|
toBytes: 'function',
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
const { endo, Fp, a } = opts;
|
const { endo, Fp, a } = opts;
|
||||||
@@ -121,6 +123,7 @@ function validatePointOpts<T>(curve: CurvePointsType<T>) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export type CurvePointsRes<T> = {
|
export type CurvePointsRes<T> = {
|
||||||
|
CURVE: ReturnType<typeof validatePointOpts<T>>;
|
||||||
ProjectivePoint: ProjConstructor<T>;
|
ProjectivePoint: ProjConstructor<T>;
|
||||||
normPrivateKeyToScalar: (key: PrivKey) => bigint;
|
normPrivateKeyToScalar: (key: PrivKey) => bigint;
|
||||||
weierstrassEquation: (x: T) => T;
|
weierstrassEquation: (x: T) => T;
|
||||||
@@ -129,7 +132,7 @@ export type CurvePointsRes<T> = {
|
|||||||
|
|
||||||
// ASN.1 DER encoding utilities
|
// ASN.1 DER encoding utilities
|
||||||
const { bytesToNumberBE: b2n, hexToBytes: h2b } = ut;
|
const { bytesToNumberBE: b2n, hexToBytes: h2b } = ut;
|
||||||
const DER = {
|
export const DER = {
|
||||||
// asn.1 DER encoding utils
|
// asn.1 DER encoding utils
|
||||||
Err: class DERErr extends Error {
|
Err: class DERErr extends Error {
|
||||||
constructor(m = '') {
|
constructor(m = '') {
|
||||||
@@ -142,16 +145,20 @@ const DER = {
|
|||||||
const len = data[1];
|
const len = data[1];
|
||||||
const res = data.subarray(2, len + 2);
|
const res = data.subarray(2, len + 2);
|
||||||
if (!len || res.length !== len) throw new E('Invalid signature integer: wrong length');
|
if (!len || res.length !== len) throw new E('Invalid signature integer: wrong length');
|
||||||
if (res[0] === 0x00 && res[1] <= 0x7f)
|
// https://crypto.stackexchange.com/a/57734 Leftmost bit of first byte is 'negative' flag,
|
||||||
throw new E('Invalid signature integer: trailing length');
|
// since we always use positive integers here. It must always be empty:
|
||||||
// ^ Weird condition: not about length, but about first bytes of number.
|
// - add zero byte if exists
|
||||||
|
// - if next byte doesn't have a flag, leading zero is not allowed (minimal encoding)
|
||||||
|
if (res[0] & 0b10000000) throw new E('Invalid signature integer: negative');
|
||||||
|
if (res[0] === 0x00 && !(res[1] & 0b10000000))
|
||||||
|
throw new E('Invalid signature integer: unnecessary leading zero');
|
||||||
return { d: b2n(res), l: data.subarray(len + 2) }; // d is data, l is left
|
return { d: b2n(res), l: data.subarray(len + 2) }; // d is data, l is left
|
||||||
},
|
},
|
||||||
toSig(hex: string | Uint8Array): { r: bigint; s: bigint } {
|
toSig(hex: string | Uint8Array): { r: bigint; s: bigint } {
|
||||||
// parse DER signature
|
// parse DER signature
|
||||||
const { Err: E } = DER;
|
const { Err: E } = DER;
|
||||||
const data = typeof hex === 'string' ? h2b(hex) : hex;
|
const data = typeof hex === 'string' ? h2b(hex) : hex;
|
||||||
if (!(data instanceof Uint8Array)) throw new Error('ui8a expected');
|
if (!ut.isBytes(data)) throw new Error('ui8a expected');
|
||||||
let l = data.length;
|
let l = data.length;
|
||||||
if (l < 2 || data[0] != 0x30) throw new E('Invalid signature tag');
|
if (l < 2 || data[0] != 0x30) throw new E('Invalid signature tag');
|
||||||
if (data[1] !== l - 2) throw new E('Invalid signature: incorrect length');
|
if (data[1] !== l - 2) throw new E('Invalid signature: incorrect length');
|
||||||
@@ -161,7 +168,8 @@ const DER = {
|
|||||||
return { r, s };
|
return { r, s };
|
||||||
},
|
},
|
||||||
hexFromSig(sig: { r: bigint; s: bigint }): string {
|
hexFromSig(sig: { r: bigint; s: bigint }): string {
|
||||||
const slice = (s: string): string => (Number.parseInt(s[0], 16) >= 8 ? '00' + s : s); // slice DER
|
// Add leading zero if first byte has negative bit enabled. More details in '_parseInt'
|
||||||
|
const slice = (s: string): string => (Number.parseInt(s[0], 16) & 0b1000 ? '00' + s : s);
|
||||||
const h = (num: number | bigint) => {
|
const h = (num: number | bigint) => {
|
||||||
const hex = num.toString(16);
|
const hex = num.toString(16);
|
||||||
return hex.length & 1 ? `0${hex}` : hex;
|
return hex.length & 1 ? `0${hex}` : hex;
|
||||||
@@ -176,14 +184,31 @@ const DER = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
// Be friendly to bad ECMAScript parsers by not using bigint literals like 123n
|
// Be friendly to bad ECMAScript parsers by not using bigint literals
|
||||||
const _0n = BigInt(0);
|
// prettier-ignore
|
||||||
const _1n = BigInt(1);
|
const _0n = BigInt(0), _1n = BigInt(1), _2n = BigInt(2), _3n = BigInt(3), _4n = BigInt(4);
|
||||||
|
|
||||||
export function weierstrassPoints<T>(opts: CurvePointsType<T>) {
|
export function weierstrassPoints<T>(opts: CurvePointsType<T>): CurvePointsRes<T> {
|
||||||
const CURVE = validatePointOpts(opts);
|
const CURVE = validatePointOpts(opts);
|
||||||
const { Fp } = CURVE; // All curves has same field / group length as for now, but they can differ
|
const { Fp } = CURVE; // All curves has same field / group length as for now, but they can differ
|
||||||
|
|
||||||
|
const toBytes =
|
||||||
|
CURVE.toBytes ||
|
||||||
|
((_c: ProjConstructor<T>, point: ProjPointType<T>, _isCompressed: boolean) => {
|
||||||
|
const a = point.toAffine();
|
||||||
|
return ut.concatBytes(Uint8Array.from([0x04]), Fp.toBytes(a.x), Fp.toBytes(a.y));
|
||||||
|
});
|
||||||
|
const fromBytes =
|
||||||
|
CURVE.fromBytes ||
|
||||||
|
((bytes: Uint8Array) => {
|
||||||
|
// const head = bytes[0];
|
||||||
|
const tail = bytes.subarray(1);
|
||||||
|
// if (head !== 0x04) throw new Error('Only non-compressed encoding is supported');
|
||||||
|
const x = Fp.fromBytes(tail.subarray(0, Fp.BYTES));
|
||||||
|
const y = Fp.fromBytes(tail.subarray(Fp.BYTES, 2 * Fp.BYTES));
|
||||||
|
return { x, y };
|
||||||
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* y² = x³ + ax + b: Short weierstrass curve formula
|
* y² = x³ + ax + b: Short weierstrass curve formula
|
||||||
* @returns y²
|
* @returns y²
|
||||||
@@ -194,6 +219,12 @@ export function weierstrassPoints<T>(opts: CurvePointsType<T>) {
|
|||||||
const x3 = Fp.mul(x2, x); // x2 * x
|
const x3 = Fp.mul(x2, x); // x2 * x
|
||||||
return Fp.add(Fp.add(x3, Fp.mul(x, a)), b); // x3 + a * x + b
|
return Fp.add(Fp.add(x3, Fp.mul(x, a)), b); // x3 + a * x + b
|
||||||
}
|
}
|
||||||
|
// Validate whether the passed curve params are valid.
|
||||||
|
// We check if curve equation works for generator point.
|
||||||
|
// `assertValidity()` won't work: `isTorsionFree()` is not available at this point in bls12-381.
|
||||||
|
// ProjectivePoint class has not been initialized yet.
|
||||||
|
if (!Fp.eql(Fp.sqr(CURVE.Gy), weierstrassEquation(CURVE.Gx)))
|
||||||
|
throw new Error('bad generator point: equation left != right');
|
||||||
|
|
||||||
// Valid group elements reside in range 1..n-1
|
// Valid group elements reside in range 1..n-1
|
||||||
function isWithinCurveOrder(num: bigint): boolean {
|
function isWithinCurveOrder(num: bigint): boolean {
|
||||||
@@ -207,7 +238,7 @@ export function weierstrassPoints<T>(opts: CurvePointsType<T>) {
|
|||||||
function normPrivateKeyToScalar(key: PrivKey): bigint {
|
function normPrivateKeyToScalar(key: PrivKey): bigint {
|
||||||
const { allowedPrivateKeyLengths: lengths, nByteLength, wrapPrivateKey, n } = CURVE;
|
const { allowedPrivateKeyLengths: lengths, nByteLength, wrapPrivateKey, n } = CURVE;
|
||||||
if (lengths && typeof key !== 'bigint') {
|
if (lengths && typeof key !== 'bigint') {
|
||||||
if (key instanceof Uint8Array) key = ut.bytesToHex(key);
|
if (ut.isBytes(key)) key = ut.bytesToHex(key);
|
||||||
// Normalize to hex string, pad. E.g. P521 would norm 130-132 char hex to 132-char bytes
|
// Normalize to hex string, pad. E.g. P521 would norm 130-132 char hex to 132-char bytes
|
||||||
if (typeof key !== 'string' || !lengths.includes(key.length)) throw new Error('Invalid key');
|
if (typeof key !== 'string' || !lengths.includes(key.length)) throw new Error('Invalid key');
|
||||||
key = key.padStart(nByteLength * 2, '0');
|
key = key.padStart(nByteLength * 2, '0');
|
||||||
@@ -239,7 +270,11 @@ export function weierstrassPoints<T>(opts: CurvePointsType<T>) {
|
|||||||
static readonly BASE = new Point(CURVE.Gx, CURVE.Gy, Fp.ONE);
|
static readonly BASE = new Point(CURVE.Gx, CURVE.Gy, Fp.ONE);
|
||||||
static readonly ZERO = new Point(Fp.ZERO, Fp.ONE, Fp.ZERO);
|
static readonly ZERO = new Point(Fp.ZERO, Fp.ONE, Fp.ZERO);
|
||||||
|
|
||||||
constructor(readonly px: T, readonly py: T, readonly pz: T) {
|
constructor(
|
||||||
|
readonly px: T,
|
||||||
|
readonly py: T,
|
||||||
|
readonly pz: T
|
||||||
|
) {
|
||||||
if (px == null || !Fp.isValid(px)) throw new Error('x required');
|
if (px == null || !Fp.isValid(px)) throw new Error('x required');
|
||||||
if (py == null || !Fp.isValid(py)) throw new Error('y required');
|
if (py == null || !Fp.isValid(py)) throw new Error('y required');
|
||||||
if (pz == null || !Fp.isValid(pz)) throw new Error('z required');
|
if (pz == null || !Fp.isValid(pz)) throw new Error('z required');
|
||||||
@@ -280,7 +315,7 @@ export function weierstrassPoints<T>(opts: CurvePointsType<T>) {
|
|||||||
* @param hex short/long ECDSA hex
|
* @param hex short/long ECDSA hex
|
||||||
*/
|
*/
|
||||||
static fromHex(hex: Hex): Point {
|
static fromHex(hex: Hex): Point {
|
||||||
const P = Point.fromAffine(CURVE.fromBytes(ensureBytes('pointHex', hex)));
|
const P = Point.fromAffine(fromBytes(ensureBytes('pointHex', hex)));
|
||||||
P.assertValidity();
|
P.assertValidity();
|
||||||
return P;
|
return P;
|
||||||
}
|
}
|
||||||
@@ -303,9 +338,11 @@ export function weierstrassPoints<T>(opts: CurvePointsType<T>) {
|
|||||||
|
|
||||||
// A point on curve is valid if it conforms to equation.
|
// A point on curve is valid if it conforms to equation.
|
||||||
assertValidity(): void {
|
assertValidity(): void {
|
||||||
// Zero is valid point too!
|
|
||||||
if (this.is0()) {
|
if (this.is0()) {
|
||||||
if (CURVE.allowInfinityPoint) return;
|
// (0, 1, 0) aka ZERO is invalid in most contexts.
|
||||||
|
// In BLS, ZERO can be serialized, so we allow it.
|
||||||
|
// (0, 0, 0) is wrong representation of ZERO and is always invalid.
|
||||||
|
if (CURVE.allowInfinityPoint && !Fp.is0(this.py)) return;
|
||||||
throw new Error('bad point: ZERO');
|
throw new Error('bad point: ZERO');
|
||||||
}
|
}
|
||||||
// Some 3rd-party test vectors require different wording between here & `fromCompressedHex`
|
// Some 3rd-party test vectors require different wording between here & `fromCompressedHex`
|
||||||
@@ -348,7 +385,7 @@ export function weierstrassPoints<T>(opts: CurvePointsType<T>) {
|
|||||||
// Cost: 8M + 3S + 3*a + 2*b3 + 15add.
|
// Cost: 8M + 3S + 3*a + 2*b3 + 15add.
|
||||||
double() {
|
double() {
|
||||||
const { a, b } = CURVE;
|
const { a, b } = CURVE;
|
||||||
const b3 = Fp.mul(b, 3n);
|
const b3 = Fp.mul(b, _3n);
|
||||||
const { px: X1, py: Y1, pz: Z1 } = this;
|
const { px: X1, py: Y1, pz: Z1 } = this;
|
||||||
let X3 = Fp.ZERO, Y3 = Fp.ZERO, Z3 = Fp.ZERO; // prettier-ignore
|
let X3 = Fp.ZERO, Y3 = Fp.ZERO, Z3 = Fp.ZERO; // prettier-ignore
|
||||||
let t0 = Fp.mul(X1, X1); // step 1
|
let t0 = Fp.mul(X1, X1); // step 1
|
||||||
@@ -395,7 +432,7 @@ export function weierstrassPoints<T>(opts: CurvePointsType<T>) {
|
|||||||
const { px: X2, py: Y2, pz: Z2 } = other;
|
const { px: X2, py: Y2, pz: Z2 } = other;
|
||||||
let X3 = Fp.ZERO, Y3 = Fp.ZERO, Z3 = Fp.ZERO; // prettier-ignore
|
let X3 = Fp.ZERO, Y3 = Fp.ZERO, Z3 = Fp.ZERO; // prettier-ignore
|
||||||
const a = CURVE.a;
|
const a = CURVE.a;
|
||||||
const b3 = Fp.mul(CURVE.b, 3n);
|
const b3 = Fp.mul(CURVE.b, _3n);
|
||||||
let t0 = Fp.mul(X1, X2); // step 1
|
let t0 = Fp.mul(X1, X2); // step 1
|
||||||
let t1 = Fp.mul(Y1, Y2);
|
let t1 = Fp.mul(Y1, Y2);
|
||||||
let t2 = Fp.mul(Z1, Z2);
|
let t2 = Fp.mul(Z1, Z2);
|
||||||
@@ -563,7 +600,7 @@ export function weierstrassPoints<T>(opts: CurvePointsType<T>) {
|
|||||||
|
|
||||||
toRawBytes(isCompressed = true): Uint8Array {
|
toRawBytes(isCompressed = true): Uint8Array {
|
||||||
this.assertValidity();
|
this.assertValidity();
|
||||||
return CURVE.toBytes(Point, this, isCompressed);
|
return toBytes(Point, this, isCompressed);
|
||||||
}
|
}
|
||||||
|
|
||||||
toHex(isCompressed = true): string {
|
toHex(isCompressed = true): string {
|
||||||
@@ -572,8 +609,9 @@ export function weierstrassPoints<T>(opts: CurvePointsType<T>) {
|
|||||||
}
|
}
|
||||||
const _bits = CURVE.nBitLength;
|
const _bits = CURVE.nBitLength;
|
||||||
const wnaf = wNAF(Point, CURVE.endo ? Math.ceil(_bits / 2) : _bits);
|
const wnaf = wNAF(Point, CURVE.endo ? Math.ceil(_bits / 2) : _bits);
|
||||||
|
// Validate if generator point is on curve
|
||||||
return {
|
return {
|
||||||
|
CURVE,
|
||||||
ProjectivePoint: Point as ProjConstructor<T>,
|
ProjectivePoint: Point as ProjConstructor<T>,
|
||||||
normPrivateKeyToScalar,
|
normPrivateKeyToScalar,
|
||||||
weierstrassEquation,
|
weierstrassEquation,
|
||||||
@@ -587,7 +625,7 @@ export interface SignatureType {
|
|||||||
readonly s: bigint;
|
readonly s: bigint;
|
||||||
readonly recovery?: number;
|
readonly recovery?: number;
|
||||||
assertValidity(): void;
|
assertValidity(): void;
|
||||||
addRecoveryBit(recovery: number): SignatureType;
|
addRecoveryBit(recovery: number): RecoveredSignatureType;
|
||||||
hasHighS(): boolean;
|
hasHighS(): boolean;
|
||||||
normalizeS(): SignatureType;
|
normalizeS(): SignatureType;
|
||||||
recoverPublicKey(msgHash: Hex): ProjPointType<bigint>;
|
recoverPublicKey(msgHash: Hex): ProjPointType<bigint>;
|
||||||
@@ -597,6 +635,9 @@ export interface SignatureType {
|
|||||||
toDERRawBytes(isCompressed?: boolean): Uint8Array;
|
toDERRawBytes(isCompressed?: boolean): Uint8Array;
|
||||||
toDERHex(isCompressed?: boolean): string;
|
toDERHex(isCompressed?: boolean): string;
|
||||||
}
|
}
|
||||||
|
export type RecoveredSignatureType = SignatureType & {
|
||||||
|
readonly recovery: number;
|
||||||
|
};
|
||||||
// Static methods
|
// Static methods
|
||||||
export type SignatureConstructor = {
|
export type SignatureConstructor = {
|
||||||
new (r: bigint, s: bigint): SignatureType;
|
new (r: bigint, s: bigint): SignatureType;
|
||||||
@@ -638,7 +679,7 @@ export type CurveFn = {
|
|||||||
CURVE: ReturnType<typeof validateOpts>;
|
CURVE: ReturnType<typeof validateOpts>;
|
||||||
getPublicKey: (privateKey: PrivKey, isCompressed?: boolean) => Uint8Array;
|
getPublicKey: (privateKey: PrivKey, isCompressed?: boolean) => Uint8Array;
|
||||||
getSharedSecret: (privateA: PrivKey, publicB: Hex, isCompressed?: boolean) => Uint8Array;
|
getSharedSecret: (privateA: PrivKey, publicB: Hex, isCompressed?: boolean) => Uint8Array;
|
||||||
sign: (msgHash: Hex, privKey: PrivKey, opts?: SignOpts) => SignatureType;
|
sign: (msgHash: Hex, privKey: PrivKey, opts?: SignOpts) => RecoveredSignatureType;
|
||||||
verify: (signature: Hex | SignatureLike, msgHash: Hex, publicKey: Hex, opts?: VerOpts) => boolean;
|
verify: (signature: Hex | SignatureLike, msgHash: Hex, publicKey: Hex, opts?: VerOpts) => boolean;
|
||||||
ProjectivePoint: ProjConstructor<bigint>;
|
ProjectivePoint: ProjConstructor<bigint>;
|
||||||
Signature: SignatureConstructor;
|
Signature: SignatureConstructor;
|
||||||
@@ -652,8 +693,7 @@ export type CurveFn = {
|
|||||||
|
|
||||||
export function weierstrass(curveDef: CurveType): CurveFn {
|
export function weierstrass(curveDef: CurveType): CurveFn {
|
||||||
const CURVE = validateOpts(curveDef) as ReturnType<typeof validateOpts>;
|
const CURVE = validateOpts(curveDef) as ReturnType<typeof validateOpts>;
|
||||||
const CURVE_ORDER = CURVE.n;
|
const { Fp, n: CURVE_ORDER } = CURVE;
|
||||||
const Fp = CURVE.Fp;
|
|
||||||
const compressedLen = Fp.BYTES + 1; // e.g. 33 for 32
|
const compressedLen = Fp.BYTES + 1; // e.g. 33 for 32
|
||||||
const uncompressedLen = 2 * Fp.BYTES + 1; // e.g. 65 for 32
|
const uncompressedLen = 2 * Fp.BYTES + 1; // e.g. 65 for 32
|
||||||
|
|
||||||
@@ -674,7 +714,7 @@ export function weierstrass(curveDef: CurveType): CurveFn {
|
|||||||
isWithinCurveOrder,
|
isWithinCurveOrder,
|
||||||
} = weierstrassPoints({
|
} = weierstrassPoints({
|
||||||
...CURVE,
|
...CURVE,
|
||||||
toBytes(c, point, isCompressed: boolean): Uint8Array {
|
toBytes(_c, point, isCompressed: boolean): Uint8Array {
|
||||||
const a = point.toAffine();
|
const a = point.toAffine();
|
||||||
const x = Fp.toBytes(a.x);
|
const x = Fp.toBytes(a.x);
|
||||||
const cat = ut.concatBytes;
|
const cat = ut.concatBytes;
|
||||||
@@ -693,7 +733,13 @@ export function weierstrass(curveDef: CurveType): CurveFn {
|
|||||||
const x = ut.bytesToNumberBE(tail);
|
const x = ut.bytesToNumberBE(tail);
|
||||||
if (!isValidFieldElement(x)) throw new Error('Point is not on curve');
|
if (!isValidFieldElement(x)) throw new Error('Point is not on curve');
|
||||||
const y2 = weierstrassEquation(x); // y² = x³ + ax + b
|
const y2 = weierstrassEquation(x); // y² = x³ + ax + b
|
||||||
let y = Fp.sqrt(y2); // y = y² ^ (p+1)/4
|
let y: bigint;
|
||||||
|
try {
|
||||||
|
y = Fp.sqrt(y2); // y = y² ^ (p+1)/4
|
||||||
|
} catch (sqrtError) {
|
||||||
|
const suffix = sqrtError instanceof Error ? ': ' + sqrtError.message : '';
|
||||||
|
throw new Error('Point is not on curve' + suffix);
|
||||||
|
}
|
||||||
const isYOdd = (y & _1n) === _1n;
|
const isYOdd = (y & _1n) === _1n;
|
||||||
// ECDSA
|
// ECDSA
|
||||||
const isHeadOdd = (head & 1) === 1;
|
const isHeadOdd = (head & 1) === 1;
|
||||||
@@ -728,7 +774,11 @@ export function weierstrass(curveDef: CurveType): CurveFn {
|
|||||||
* ECDSA signature with its (r, s) properties. Supports DER & compact representations.
|
* ECDSA signature with its (r, s) properties. Supports DER & compact representations.
|
||||||
*/
|
*/
|
||||||
class Signature implements SignatureType {
|
class Signature implements SignatureType {
|
||||||
constructor(readonly r: bigint, readonly s: bigint, readonly recovery?: number) {
|
constructor(
|
||||||
|
readonly r: bigint,
|
||||||
|
readonly s: bigint,
|
||||||
|
readonly recovery?: number
|
||||||
|
) {
|
||||||
this.assertValidity();
|
this.assertValidity();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -752,8 +802,8 @@ export function weierstrass(curveDef: CurveType): CurveFn {
|
|||||||
if (!isWithinCurveOrder(this.s)) throw new Error('s must be 0 < s < CURVE.n');
|
if (!isWithinCurveOrder(this.s)) throw new Error('s must be 0 < s < CURVE.n');
|
||||||
}
|
}
|
||||||
|
|
||||||
addRecoveryBit(recovery: number) {
|
addRecoveryBit(recovery: number): RecoveredSignature {
|
||||||
return new Signature(this.r, this.s, recovery);
|
return new Signature(this.r, this.s, recovery) as RecoveredSignature;
|
||||||
}
|
}
|
||||||
|
|
||||||
recoverPublicKey(msgHash: Hex): typeof Point.BASE {
|
recoverPublicKey(msgHash: Hex): typeof Point.BASE {
|
||||||
@@ -798,6 +848,7 @@ export function weierstrass(curveDef: CurveType): CurveFn {
|
|||||||
return numToNByteStr(this.r) + numToNByteStr(this.s);
|
return numToNByteStr(this.r) + numToNByteStr(this.s);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
type RecoveredSignature = Signature & { recovery: number };
|
||||||
|
|
||||||
const utils = {
|
const utils = {
|
||||||
isValidPrivateKey(privateKey: PrivKey) {
|
isValidPrivateKey(privateKey: PrivKey) {
|
||||||
@@ -811,13 +862,12 @@ export function weierstrass(curveDef: CurveType): CurveFn {
|
|||||||
normPrivateKeyToScalar: normPrivateKeyToScalar,
|
normPrivateKeyToScalar: normPrivateKeyToScalar,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Produces cryptographically secure private key from random of size (nBitLength+64)
|
* Produces cryptographically secure private key from random of size
|
||||||
* as per FIPS 186 B.4.1 with modulo bias being neglible.
|
* (groupLen + ceil(groupLen / 2)) with modulo bias being negligible.
|
||||||
*/
|
*/
|
||||||
randomPrivateKey: (): Uint8Array => {
|
randomPrivateKey: (): Uint8Array => {
|
||||||
const rand = CURVE.randomBytes(Fp.BYTES + 8);
|
const length = mod.getMinHashLength(CURVE.n);
|
||||||
const num = mod.hashToPrivateScalar(rand, CURVE_ORDER);
|
return mod.mapHashToField(CURVE.randomBytes(length), CURVE.n);
|
||||||
return ut.numberToBytesBE(num, CURVE.nByteLength);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -849,7 +899,7 @@ export function weierstrass(curveDef: CurveType): CurveFn {
|
|||||||
* Quick and dirty check for item being public key. Does not validate hex, or being on-curve.
|
* Quick and dirty check for item being public key. Does not validate hex, or being on-curve.
|
||||||
*/
|
*/
|
||||||
function isProbPub(item: PrivKey | PubKey): boolean {
|
function isProbPub(item: PrivKey | PubKey): boolean {
|
||||||
const arr = item instanceof Uint8Array;
|
const arr = ut.isBytes(item);
|
||||||
const str = typeof item === 'string';
|
const str = typeof item === 'string';
|
||||||
const len = (arr || str) && (item as Hex).length;
|
const len = (arr || str) && (item as Hex).length;
|
||||||
if (arr) return len === compressedLen || len === uncompressedLen;
|
if (arr) return len === compressedLen || len === uncompressedLen;
|
||||||
@@ -930,12 +980,12 @@ export function weierstrass(curveDef: CurveType): CurveFn {
|
|||||||
if (ent != null) {
|
if (ent != null) {
|
||||||
// K = HMAC_K(V || 0x00 || int2octets(x) || bits2octets(h1) || k')
|
// K = HMAC_K(V || 0x00 || int2octets(x) || bits2octets(h1) || k')
|
||||||
const e = ent === true ? randomBytes(Fp.BYTES) : ent; // generate random bytes OR pass as-is
|
const e = ent === true ? randomBytes(Fp.BYTES) : ent; // generate random bytes OR pass as-is
|
||||||
seedArgs.push(ensureBytes('extraEntropy', e, Fp.BYTES)); // check for being of size BYTES
|
seedArgs.push(ensureBytes('extraEntropy', e)); // check for being bytes
|
||||||
}
|
}
|
||||||
const seed = ut.concatBytes(...seedArgs); // Step D of RFC6979 3.2
|
const seed = ut.concatBytes(...seedArgs); // Step D of RFC6979 3.2
|
||||||
const m = h1int; // NOTE: no need to call bits2int second time here, it is inside truncateHash!
|
const m = h1int; // NOTE: no need to call bits2int second time here, it is inside truncateHash!
|
||||||
// Converts signature params into point w r/s, checks result for validity.
|
// Converts signature params into point w r/s, checks result for validity.
|
||||||
function k2sig(kBytes: Uint8Array): Signature | undefined {
|
function k2sig(kBytes: Uint8Array): RecoveredSignature | undefined {
|
||||||
// RFC 6979 Section 3.2, step 3: k = bits2int(T)
|
// RFC 6979 Section 3.2, step 3: k = bits2int(T)
|
||||||
const k = bits2int(kBytes); // Cannot use fields methods, since it is group element
|
const k = bits2int(kBytes); // Cannot use fields methods, since it is group element
|
||||||
if (!isWithinCurveOrder(k)) return; // Important: all mod() calls here must be done over N
|
if (!isWithinCurveOrder(k)) return; // Important: all mod() calls here must be done over N
|
||||||
@@ -943,16 +993,10 @@ export function weierstrass(curveDef: CurveType): CurveFn {
|
|||||||
const q = Point.BASE.multiply(k).toAffine(); // q = Gk
|
const q = Point.BASE.multiply(k).toAffine(); // q = Gk
|
||||||
const r = modN(q.x); // r = q.x mod n
|
const r = modN(q.x); // r = q.x mod n
|
||||||
if (r === _0n) return;
|
if (r === _0n) return;
|
||||||
// X blinding according to https://tches.iacr.org/index.php/TCHES/article/view/7337/6509
|
// Can use scalar blinding b^-1(bm + bdr) where b ∈ [1,q−1] according to
|
||||||
// b * m + b * r * d ∈ [0,q−1] exposed via side-channel, but d (private scalar) is not.
|
// https://tches.iacr.org/index.php/TCHES/article/view/7337/6509. We've decided against it:
|
||||||
// NOTE: there is still probable some leak in multiplication, since it is not constant-time
|
// a) dependency on CSPRNG b) 15% slowdown c) doesn't really help since bigints are not CT
|
||||||
const b = ut.bytesToNumberBE(utils.randomPrivateKey()); // random scalar, b ∈ [1,q−1]
|
const s = modN(ik * modN(m + r * d)); // Not using blinding here
|
||||||
const bi = invN(b); // b^-1
|
|
||||||
const bdr = modN(b * d * r); // b * d * r
|
|
||||||
const bm = modN(b * m); // b * m
|
|
||||||
const mrx = modN(bi * modN(bdr + bm)); // b^-1(bm + bdr) -> m + rd
|
|
||||||
|
|
||||||
const s = modN(ik * mrx); // s = k^-1(m + rd) mod n
|
|
||||||
if (s === _0n) return;
|
if (s === _0n) return;
|
||||||
let recovery = (q.x === r ? 0 : 2) | Number(q.y & _1n); // recovery bit (2 or 3, when q.x > n)
|
let recovery = (q.x === r ? 0 : 2) | Number(q.y & _1n); // recovery bit (2 or 3, when q.x > n)
|
||||||
let normS = s;
|
let normS = s;
|
||||||
@@ -960,7 +1004,7 @@ export function weierstrass(curveDef: CurveType): CurveFn {
|
|||||||
normS = normalizeS(s); // if lowS was passed, ensure s is always
|
normS = normalizeS(s); // if lowS was passed, ensure s is always
|
||||||
recovery ^= 1; // // in the bottom half of N
|
recovery ^= 1; // // in the bottom half of N
|
||||||
}
|
}
|
||||||
return new Signature(r, normS, recovery); // use normS, not s
|
return new Signature(r, normS, recovery) as RecoveredSignature; // use normS, not s
|
||||||
}
|
}
|
||||||
return { seed, k2sig };
|
return { seed, k2sig };
|
||||||
}
|
}
|
||||||
@@ -968,18 +1012,22 @@ export function weierstrass(curveDef: CurveType): CurveFn {
|
|||||||
const defaultVerOpts: VerOpts = { lowS: CURVE.lowS, prehash: false };
|
const defaultVerOpts: VerOpts = { lowS: CURVE.lowS, prehash: false };
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Signs message hash (not message: you need to hash it by yourself).
|
* Signs message hash with a private key.
|
||||||
* ```
|
* ```
|
||||||
* sign(m, d, k) where
|
* sign(m, d, k) where
|
||||||
* (x, y) = G × k
|
* (x, y) = G × k
|
||||||
* r = x mod n
|
* r = x mod n
|
||||||
* s = (m + dr)/k mod n
|
* s = (m + dr)/k mod n
|
||||||
* ```
|
* ```
|
||||||
* @param opts `lowS, extraEntropy, prehash`
|
* @param msgHash NOT message. msg needs to be hashed to `msgHash`, or use `prehash`.
|
||||||
|
* @param privKey private key
|
||||||
|
* @param opts lowS for non-malleable sigs. extraEntropy for mixing randomness into k. prehash will hash first arg.
|
||||||
|
* @returns signature with recovery param
|
||||||
*/
|
*/
|
||||||
function sign(msgHash: Hex, privKey: PrivKey, opts = defaultSigOpts): Signature {
|
function sign(msgHash: Hex, privKey: PrivKey, opts = defaultSigOpts): RecoveredSignature {
|
||||||
const { seed, k2sig } = prepSig(msgHash, privKey, opts); // Steps A, D of RFC6979 3.2.
|
const { seed, k2sig } = prepSig(msgHash, privKey, opts); // Steps A, D of RFC6979 3.2.
|
||||||
const drbg = ut.createHmacDrbg<Signature>(CURVE.hash.outputLen, CURVE.nByteLength, CURVE.hmac);
|
const C = CURVE;
|
||||||
|
const drbg = ut.createHmacDrbg<RecoveredSignature>(C.hash.outputLen, C.nByteLength, C.hmac);
|
||||||
return drbg(seed, k2sig); // Steps B, C, D, E, F, G
|
return drbg(seed, k2sig); // Steps B, C, D, E, F, G
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1015,7 +1063,7 @@ export function weierstrass(curveDef: CurveType): CurveFn {
|
|||||||
let _sig: Signature | undefined = undefined;
|
let _sig: Signature | undefined = undefined;
|
||||||
let P: ProjPointType<bigint>;
|
let P: ProjPointType<bigint>;
|
||||||
try {
|
try {
|
||||||
if (typeof sg === 'string' || sg instanceof Uint8Array) {
|
if (typeof sg === 'string' || ut.isBytes(sg)) {
|
||||||
// Signature can be represented in 2 ways: compact (2*nByteLength) & DER (variable-length).
|
// Signature can be represented in 2 ways: compact (2*nByteLength) & DER (variable-length).
|
||||||
// Since DER can also be 2*nByteLength bytes, we check for it first.
|
// Since DER can also be 2*nByteLength bytes, we check for it first.
|
||||||
try {
|
try {
|
||||||
@@ -1060,23 +1108,31 @@ export function weierstrass(curveDef: CurveType): CurveFn {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Implementation of the Shallue and van de Woestijne method for any Weierstrass curve
|
/**
|
||||||
|
* Implementation of the Shallue and van de Woestijne method for any weierstrass curve.
|
||||||
// TODO: check if there is a way to merge this with uvRatio in Edwards && move to modular?
|
* TODO: check if there is a way to merge this with uvRatio in Edwards; move to modular.
|
||||||
// b = True and y = sqrt(u / v) if (u / v) is square in F, and
|
* b = True and y = sqrt(u / v) if (u / v) is square in F, and
|
||||||
// b = False and y = sqrt(Z * (u / v)) otherwise.
|
* b = False and y = sqrt(Z * (u / v)) otherwise.
|
||||||
export function SWUFpSqrtRatio<T>(Fp: mod.Field<T>, Z: T) {
|
* @param Fp
|
||||||
|
* @param Z
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export function SWUFpSqrtRatio<T>(Fp: mod.IField<T>, Z: T) {
|
||||||
// Generic implementation
|
// Generic implementation
|
||||||
const q = Fp.ORDER;
|
const q = Fp.ORDER;
|
||||||
let l = 0n;
|
let l = _0n;
|
||||||
for (let o = q - 1n; o % 2n === 0n; o /= 2n) l += 1n;
|
for (let o = q - _1n; o % _2n === _0n; o /= _2n) l += _1n;
|
||||||
const c1 = l; // 1. c1, the largest integer such that 2^c1 divides q - 1.
|
const c1 = l; // 1. c1, the largest integer such that 2^c1 divides q - 1.
|
||||||
const c2 = (q - 1n) / 2n ** c1; // 2. c2 = (q - 1) / (2^c1) # Integer arithmetic
|
// We need 2n ** c1 and 2n ** (c1-1). We can't use **; but we can use <<.
|
||||||
const c3 = (c2 - 1n) / 2n; // 3. c3 = (c2 - 1) / 2 # Integer arithmetic
|
// 2n ** c1 == 2n << (c1-1)
|
||||||
const c4 = 2n ** c1 - 1n; // 4. c4 = 2^c1 - 1 # Integer arithmetic
|
const _2n_pow_c1_1 = _2n << (c1 - _1n - _1n);
|
||||||
const c5 = 2n ** (c1 - 1n); // 5. c5 = 2^(c1 - 1) # Integer arithmetic
|
const _2n_pow_c1 = _2n_pow_c1_1 * _2n;
|
||||||
|
const c2 = (q - _1n) / _2n_pow_c1; // 2. c2 = (q - 1) / (2^c1) # Integer arithmetic
|
||||||
|
const c3 = (c2 - _1n) / _2n; // 3. c3 = (c2 - 1) / 2 # Integer arithmetic
|
||||||
|
const c4 = _2n_pow_c1 - _1n; // 4. c4 = 2^c1 - 1 # Integer arithmetic
|
||||||
|
const c5 = _2n_pow_c1_1; // 5. c5 = 2^(c1 - 1) # Integer arithmetic
|
||||||
const c6 = Fp.pow(Z, c2); // 6. c6 = Z^c2
|
const c6 = Fp.pow(Z, c2); // 6. c6 = Z^c2
|
||||||
const c7 = Fp.pow(Z, (c2 + 1n) / 2n); // 7. c7 = Z^((c2 + 1) / 2)
|
const c7 = Fp.pow(Z, (c2 + _1n) / _2n); // 7. c7 = Z^((c2 + 1) / 2)
|
||||||
let sqrtRatio = (u: T, v: T): { isValid: boolean; value: T } => {
|
let sqrtRatio = (u: T, v: T): { isValid: boolean; value: T } => {
|
||||||
let tv1 = c6; // 1. tv1 = c6
|
let tv1 = c6; // 1. tv1 = c6
|
||||||
let tv2 = Fp.pow(v, c4); // 2. tv2 = v^c4
|
let tv2 = Fp.pow(v, c4); // 2. tv2 = v^c4
|
||||||
@@ -1095,8 +1151,9 @@ export function SWUFpSqrtRatio<T>(Fp: mod.Field<T>, Z: T) {
|
|||||||
tv3 = Fp.cmov(tv2, tv3, isQR); // 15. tv3 = CMOV(tv2, tv3, isQR)
|
tv3 = Fp.cmov(tv2, tv3, isQR); // 15. tv3 = CMOV(tv2, tv3, isQR)
|
||||||
tv4 = Fp.cmov(tv5, tv4, isQR); // 16. tv4 = CMOV(tv5, tv4, isQR)
|
tv4 = Fp.cmov(tv5, tv4, isQR); // 16. tv4 = CMOV(tv5, tv4, isQR)
|
||||||
// 17. for i in (c1, c1 - 1, ..., 2):
|
// 17. for i in (c1, c1 - 1, ..., 2):
|
||||||
for (let i = c1; i > 1; i--) {
|
for (let i = c1; i > _1n; i--) {
|
||||||
let tv5 = 2n ** (i - 2n); // 18. tv5 = i - 2; 19. tv5 = 2^tv5
|
let tv5 = i - _2n; // 18. tv5 = i - 2
|
||||||
|
tv5 = _2n << (tv5 - _1n); // 19. tv5 = 2^tv5
|
||||||
let tvv5 = Fp.pow(tv4, tv5); // 20. tv5 = tv4^tv5
|
let tvv5 = Fp.pow(tv4, tv5); // 20. tv5 = tv4^tv5
|
||||||
const e1 = Fp.eql(tvv5, Fp.ONE); // 21. e1 = tv5 == 1
|
const e1 = Fp.eql(tvv5, Fp.ONE); // 21. e1 = tv5 == 1
|
||||||
tv2 = Fp.mul(tv3, tv1); // 22. tv2 = tv3 * tv1
|
tv2 = Fp.mul(tv3, tv1); // 22. tv2 = tv3 * tv1
|
||||||
@@ -1107,9 +1164,9 @@ export function SWUFpSqrtRatio<T>(Fp: mod.Field<T>, Z: T) {
|
|||||||
}
|
}
|
||||||
return { isValid: isQR, value: tv3 };
|
return { isValid: isQR, value: tv3 };
|
||||||
};
|
};
|
||||||
if (Fp.ORDER % 4n === 3n) {
|
if (Fp.ORDER % _4n === _3n) {
|
||||||
// sqrt_ratio_3mod4(u, v)
|
// sqrt_ratio_3mod4(u, v)
|
||||||
const c1 = (Fp.ORDER - 3n) / 4n; // 1. c1 = (q - 3) / 4 # Integer arithmetic
|
const c1 = (Fp.ORDER - _3n) / _4n; // 1. c1 = (q - 3) / 4 # Integer arithmetic
|
||||||
const c2 = Fp.sqrt(Fp.neg(Z)); // 2. c2 = sqrt(-Z)
|
const c2 = Fp.sqrt(Fp.neg(Z)); // 2. c2 = sqrt(-Z)
|
||||||
sqrtRatio = (u: T, v: T) => {
|
sqrtRatio = (u: T, v: T) => {
|
||||||
let tv1 = Fp.sqr(v); // 1. tv1 = v^2
|
let tv1 = Fp.sqr(v); // 1. tv1 = v^2
|
||||||
@@ -1125,12 +1182,15 @@ export function SWUFpSqrtRatio<T>(Fp: mod.Field<T>, Z: T) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
// No curves uses that
|
// No curves uses that
|
||||||
// if (Fp.ORDER % 8n === 5n) // sqrt_ratio_5mod8
|
// if (Fp.ORDER % _8n === _5n) // sqrt_ratio_5mod8
|
||||||
return sqrtRatio;
|
return sqrtRatio;
|
||||||
}
|
}
|
||||||
// From draft-irtf-cfrg-hash-to-curve-16
|
/**
|
||||||
|
* Simplified Shallue-van de Woestijne-Ulas Method
|
||||||
|
* https://www.rfc-editor.org/rfc/rfc9380#section-6.6.2
|
||||||
|
*/
|
||||||
export function mapToCurveSimpleSWU<T>(
|
export function mapToCurveSimpleSWU<T>(
|
||||||
Fp: mod.Field<T>,
|
Fp: mod.IField<T>,
|
||||||
opts: {
|
opts: {
|
||||||
A: T;
|
A: T;
|
||||||
B: T;
|
B: T;
|
||||||
|
|||||||
594
src/bls12-381.ts
594
src/bls12-381.ts
@@ -1,15 +1,9 @@
|
|||||||
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
||||||
|
|
||||||
// bls12-381 pairing-friendly Barreto-Lynn-Scott elliptic curve construction allows to:
|
// bls12-381 is pairing-friendly Barreto-Lynn-Scott elliptic curve construction allowing to:
|
||||||
// - Construct zk-SNARKs at the 128-bit security
|
// - Construct zk-SNARKs at the 120-bit security
|
||||||
// - Use threshold signatures, which allows a user to sign lots of messages with one signature and
|
// - Efficiently verify N aggregate signatures with 1 pairing and N ec additions:
|
||||||
// verify them swiftly in a batch, using Boneh-Lynn-Shacham signature scheme.
|
// the Boneh-Lynn-Shacham signature scheme is orders of magnitude more efficient than Schnorr
|
||||||
//
|
|
||||||
// The library uses G1 for public keys and G2 for signatures. Support for G1 signatures is planned.
|
|
||||||
// Compatible with Algorand, Chia, Dfinity, Ethereum, FIL, Zcash. Matches specs
|
|
||||||
// [pairing-curves-10](https://tools.ietf.org/html/draft-irtf-cfrg-pairing-friendly-curves-10),
|
|
||||||
// [bls-sigs-04](https://tools.ietf.org/html/draft-irtf-cfrg-bls-signature-04),
|
|
||||||
// [hash-to-curve-12](https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-12).
|
|
||||||
//
|
//
|
||||||
// ### Summary
|
// ### Summary
|
||||||
// 1. BLS Relies on Bilinear Pairing (expensive)
|
// 1. BLS Relies on Bilinear Pairing (expensive)
|
||||||
@@ -25,26 +19,17 @@
|
|||||||
// - `S = pk x H(m)` - signing
|
// - `S = pk x H(m)` - signing
|
||||||
// - `e(P, H(m)) == e(G, S)` - verification using pairings
|
// - `e(P, H(m)) == e(G, S)` - verification using pairings
|
||||||
// - `e(G, S) = e(G, SUM(n)(Si)) = MUL(n)(e(G, Si))` - signature aggregation
|
// - `e(G, S) = e(G, SUM(n)(Si)) = MUL(n)(e(G, Si))` - signature aggregation
|
||||||
// Filecoin uses little endian byte arrays for private keys -
|
|
||||||
// so ensure to reverse byte order if you'll use it with FIL.
|
|
||||||
//
|
//
|
||||||
// ### Resources
|
// ### Compatibility and notes
|
||||||
// - [BLS12-381 for the rest of us](https://hackmd.io/@benjaminion/bls12-381)
|
// 1. It is compatible with Algorand, Chia, Dfinity, Ethereum, Filecoin, ZEC
|
||||||
// - [Key concepts of pairings](https://medium.com/@alonmuroch_65570/bls-signatures-part-2-key-concepts-of-pairings-27a8a9533d0c)
|
// Filecoin uses little endian byte arrays for private keys - make sure to reverse byte order.
|
||||||
// - Pairing over bls12-381:
|
// 2. Some projects use G2 for public keys and G1 for signatures. It's called "short signature"
|
||||||
// [part 1](https://research.nccgroup.com/2020/07/06/pairing-over-bls12-381-part-1-fields/),
|
// 3. Curve security level is about 120 bits as per Barbulescu-Duquesne 2017
|
||||||
// [part 2](https://research.nccgroup.com/2020/07/13/pairing-over-bls12-381-part-2-curves/),
|
// https://hal.science/hal-01534101/file/main.pdf
|
||||||
// [part 3](https://research.nccgroup.com/2020/08/13/pairing-over-bls12-381-part-3-pairing/)
|
// 4. Compatible with specs:
|
||||||
// - [Estimating the bit security of pairing-friendly curves](https://research.nccgroup.com/2022/02/03/estimating-the-bit-security-of-pairing-friendly-curves/)
|
// [cfrg-pairing-friendly-curves-11](https://tools.ietf.org/html/draft-irtf-cfrg-pairing-friendly-curves-11),
|
||||||
//
|
// [cfrg-bls-signature-05](https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-bls-signature-05),
|
||||||
// ### Differences from @noble/bls12-381 1.4
|
// [RFC 9380](https://www.rfc-editor.org/rfc/rfc9380).
|
||||||
// - PointG1 -> G1.Point
|
|
||||||
// - PointG2 -> G2.Point
|
|
||||||
// - PointG2.fromSignature -> Signature.decode
|
|
||||||
// - PointG2.toSignature -> Signature.encode
|
|
||||||
// - Fixed Fp2 ORDER
|
|
||||||
// - Points now have only two coordinates
|
|
||||||
|
|
||||||
import { sha256 } from '@noble/hashes/sha256';
|
import { sha256 } from '@noble/hashes/sha256';
|
||||||
import { randomBytes } from '@noble/hashes/utils';
|
import { randomBytes } from '@noble/hashes/utils';
|
||||||
import { bls, CurveFn } from './abstract/bls.js';
|
import { bls, CurveFn } from './abstract/bls.js';
|
||||||
@@ -55,10 +40,10 @@ import {
|
|||||||
numberToBytesBE,
|
numberToBytesBE,
|
||||||
bytesToNumberBE,
|
bytesToNumberBE,
|
||||||
bitLen,
|
bitLen,
|
||||||
bitSet,
|
|
||||||
bitGet,
|
bitGet,
|
||||||
Hex,
|
Hex,
|
||||||
bitMask,
|
bitMask,
|
||||||
|
bytesToHex,
|
||||||
} from './abstract/utils.js';
|
} from './abstract/utils.js';
|
||||||
// Types
|
// Types
|
||||||
import {
|
import {
|
||||||
@@ -69,16 +54,22 @@ import {
|
|||||||
} from './abstract/weierstrass.js';
|
} from './abstract/weierstrass.js';
|
||||||
import { isogenyMap } from './abstract/hash-to-curve.js';
|
import { isogenyMap } from './abstract/hash-to-curve.js';
|
||||||
|
|
||||||
|
// Be friendly to bad ECMAScript parsers by not using bigint literals
|
||||||
|
// prettier-ignore
|
||||||
|
const _0n = BigInt(0), _1n = BigInt(1), _2n = BigInt(2), _3n = BigInt(3), _4n = BigInt(4);
|
||||||
|
// prettier-ignore
|
||||||
|
const _8n = BigInt(8), _16n = BigInt(16);
|
||||||
|
|
||||||
// CURVE FIELDS
|
// CURVE FIELDS
|
||||||
// Finite field over p.
|
// Finite field over p.
|
||||||
const Fp =
|
const Fp_raw = BigInt(
|
||||||
mod.Fp(
|
'0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab'
|
||||||
0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaabn
|
|
||||||
);
|
);
|
||||||
|
const Fp = mod.Field(Fp_raw);
|
||||||
type Fp = bigint;
|
type Fp = bigint;
|
||||||
// Finite field over r.
|
// Finite field over r.
|
||||||
// This particular field is not used anywhere in bls12-381, but it is still useful.
|
// This particular field is not used anywhere in bls12-381, but it is still useful.
|
||||||
const Fr = mod.Fp(0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001n);
|
const Fr = mod.Field(BigInt('0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001'));
|
||||||
|
|
||||||
// Fp₂ over complex plane
|
// Fp₂ over complex plane
|
||||||
type BigintTuple = [bigint, bigint];
|
type BigintTuple = [bigint, bigint];
|
||||||
@@ -120,11 +111,9 @@ type Fp2Utils = {
|
|||||||
// G² - 1
|
// G² - 1
|
||||||
// h2q
|
// h2q
|
||||||
// NOTE: ORDER was wrong!
|
// NOTE: ORDER was wrong!
|
||||||
const FP2_ORDER =
|
const FP2_ORDER = Fp_raw * Fp_raw;
|
||||||
0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaabn **
|
|
||||||
2n;
|
|
||||||
|
|
||||||
const Fp2: mod.Field<Fp2> & Fp2Utils = {
|
const Fp2: mod.IField<Fp2> & Fp2Utils = {
|
||||||
ORDER: FP2_ORDER,
|
ORDER: FP2_ORDER,
|
||||||
BITS: bitLen(FP2_ORDER),
|
BITS: bitLen(FP2_ORDER),
|
||||||
BYTES: Math.ceil(bitLen(FP2_ORDER) / 8),
|
BYTES: Math.ceil(bitLen(FP2_ORDER) / 8),
|
||||||
@@ -175,7 +164,7 @@ const Fp2: mod.Field<Fp2> & Fp2Utils = {
|
|||||||
// https://github.com/zkcrypto/bls12_381/blob/080eaa74ec0e394377caa1ba302c8c121df08b07/src/fp2.rs#L250
|
// https://github.com/zkcrypto/bls12_381/blob/080eaa74ec0e394377caa1ba302c8c121df08b07/src/fp2.rs#L250
|
||||||
// https://github.com/supranational/blst/blob/aae0c7d70b799ac269ff5edf29d8191dbd357876/src/exp2.c#L1
|
// https://github.com/supranational/blst/blob/aae0c7d70b799ac269ff5edf29d8191dbd357876/src/exp2.c#L1
|
||||||
// Inspired by https://github.com/dalek-cryptography/curve25519-dalek/blob/17698df9d4c834204f83a3574143abacb4fc81a5/src/field.rs#L99
|
// Inspired by https://github.com/dalek-cryptography/curve25519-dalek/blob/17698df9d4c834204f83a3574143abacb4fc81a5/src/field.rs#L99
|
||||||
const candidateSqrt = Fp2.pow(num, (Fp2.ORDER + 8n) / 16n);
|
const candidateSqrt = Fp2.pow(num, (Fp2.ORDER + _8n) / _16n);
|
||||||
const check = Fp2.div(Fp2.sqr(candidateSqrt), num); // candidateSqrt.square().div(this);
|
const check = Fp2.div(Fp2.sqr(candidateSqrt), num); // candidateSqrt.square().div(this);
|
||||||
const R = FP2_ROOTS_OF_UNITY;
|
const R = FP2_ROOTS_OF_UNITY;
|
||||||
const divisor = [R[0], R[2], R[4], R[6]].find((r) => Fp2.eql(r, check));
|
const divisor = [R[0], R[2], R[4], R[6]].find((r) => Fp2.eql(r, check));
|
||||||
@@ -190,13 +179,13 @@ const Fp2: mod.Field<Fp2> & Fp2Utils = {
|
|||||||
if (im1 > im2 || (im1 === im2 && re1 > re2)) return x1;
|
if (im1 > im2 || (im1 === im2 && re1 > re2)) return x1;
|
||||||
return x2;
|
return x2;
|
||||||
},
|
},
|
||||||
// Same as sgn0_fp2 in draft-irtf-cfrg-hash-to-curve-16
|
// Same as sgn0_m_eq_2 in RFC 9380
|
||||||
isOdd: (x: Fp2) => {
|
isOdd: (x: Fp2) => {
|
||||||
const { re: x0, im: x1 } = Fp2.reim(x);
|
const { re: x0, im: x1 } = Fp2.reim(x);
|
||||||
const sign_0 = x0 % 2n;
|
const sign_0 = x0 % _2n;
|
||||||
const zero_0 = x0 === 0n;
|
const zero_0 = x0 === _0n;
|
||||||
const sign_1 = x1 % 2n;
|
const sign_1 = x1 % _2n;
|
||||||
return BigInt(sign_0 || (zero_0 && sign_1)) == 1n;
|
return BigInt(sign_0 || (zero_0 && sign_1)) == _1n;
|
||||||
},
|
},
|
||||||
// Bytes util
|
// Bytes util
|
||||||
fromBytes(b: Uint8Array): Fp2 {
|
fromBytes(b: Uint8Array): Fp2 {
|
||||||
@@ -216,8 +205,8 @@ const Fp2: mod.Field<Fp2> & Fp2Utils = {
|
|||||||
// multiply by u + 1
|
// multiply by u + 1
|
||||||
mulByNonresidue: ({ c0, c1 }) => ({ c0: Fp.sub(c0, c1), c1: Fp.add(c0, c1) }),
|
mulByNonresidue: ({ c0, c1 }) => ({ c0: Fp.sub(c0, c1), c1: Fp.add(c0, c1) }),
|
||||||
multiplyByB: ({ c0, c1 }) => {
|
multiplyByB: ({ c0, c1 }) => {
|
||||||
let t0 = Fp.mul(c0, 4n); // 4 * c0
|
let t0 = Fp.mul(c0, _4n); // 4 * c0
|
||||||
let t1 = Fp.mul(c1, 4n); // 4 * c1
|
let t1 = Fp.mul(c1, _4n); // 4 * c1
|
||||||
// (T0-T1) + (T0+T1)*i
|
// (T0-T1) + (T0+T1)*i
|
||||||
return { c0: Fp.sub(t0, t1), c1: Fp.add(t0, t1) };
|
return { c0: Fp.sub(t0, t1), c1: Fp.add(t0, t1) };
|
||||||
},
|
},
|
||||||
@@ -234,33 +223,36 @@ const Fp2: mod.Field<Fp2> & Fp2Utils = {
|
|||||||
// Finite extension field over irreducible polynominal.
|
// Finite extension field over irreducible polynominal.
|
||||||
// Fp(u) / (u² - β) where β = -1
|
// Fp(u) / (u² - β) where β = -1
|
||||||
const FP2_FROBENIUS_COEFFICIENTS = [
|
const FP2_FROBENIUS_COEFFICIENTS = [
|
||||||
0x1n,
|
BigInt('0x1'),
|
||||||
0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaaan,
|
BigInt(
|
||||||
|
'0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaaa'
|
||||||
|
),
|
||||||
].map((item) => Fp.create(item));
|
].map((item) => Fp.create(item));
|
||||||
|
|
||||||
// For Fp2 roots of unity.
|
// For Fp2 roots of unity.
|
||||||
const rv1 =
|
const rv1 = BigInt(
|
||||||
0x6af0e0437ff400b6831e36d6bd17ffe48395dabc2d3435e77f76e17009241c5ee67992f72ec05f4c81084fbede3cc09n;
|
'0x6af0e0437ff400b6831e36d6bd17ffe48395dabc2d3435e77f76e17009241c5ee67992f72ec05f4c81084fbede3cc09'
|
||||||
|
);
|
||||||
// const ev1 =
|
// const ev1 =
|
||||||
// 0x699be3b8c6870965e5bf892ad5d2cc7b0e85a117402dfd83b7f4a947e02d978498255a2aaec0ac627b5afbdf1bf1c90n;
|
// BigInt('0x699be3b8c6870965e5bf892ad5d2cc7b0e85a117402dfd83b7f4a947e02d978498255a2aaec0ac627b5afbdf1bf1c90');
|
||||||
// const ev2 =
|
// const ev2 =
|
||||||
// 0x8157cd83046453f5dd0972b6e3949e4288020b5b8a9cc99ca07e27089a2ce2436d965026adad3ef7baba37f2183e9b5n;
|
// BigInt('0x8157cd83046453f5dd0972b6e3949e4288020b5b8a9cc99ca07e27089a2ce2436d965026adad3ef7baba37f2183e9b5');
|
||||||
// const ev3 =
|
// const ev3 =
|
||||||
// 0xab1c2ffdd6c253ca155231eb3e71ba044fd562f6f72bc5bad5ec46a0b7a3b0247cf08ce6c6317f40edbc653a72dee17n;
|
// BigInt('0xab1c2ffdd6c253ca155231eb3e71ba044fd562f6f72bc5bad5ec46a0b7a3b0247cf08ce6c6317f40edbc653a72dee17');
|
||||||
// const ev4 =
|
// const ev4 =
|
||||||
// 0xaa404866706722864480885d68ad0ccac1967c7544b447873cc37e0181271e006df72162a3d3e0287bf597fbf7f8fc1n;
|
// BigInt('0xaa404866706722864480885d68ad0ccac1967c7544b447873cc37e0181271e006df72162a3d3e0287bf597fbf7f8fc1');
|
||||||
|
|
||||||
// Eighth roots of unity, used for computing square roots in Fp2.
|
// Eighth roots of unity, used for computing square roots in Fp2.
|
||||||
// To verify or re-calculate:
|
// To verify or re-calculate:
|
||||||
// Array(8).fill(new Fp2([1n, 1n])).map((fp2, k) => fp2.pow(Fp2.ORDER * BigInt(k) / 8n))
|
// Array(8).fill(new Fp2([1n, 1n])).map((fp2, k) => fp2.pow(Fp2.ORDER * BigInt(k) / 8n))
|
||||||
const FP2_ROOTS_OF_UNITY = [
|
const FP2_ROOTS_OF_UNITY = [
|
||||||
[1n, 0n],
|
[_1n, _0n],
|
||||||
[rv1, -rv1],
|
[rv1, -rv1],
|
||||||
[0n, 1n],
|
[_0n, _1n],
|
||||||
[rv1, rv1],
|
[rv1, rv1],
|
||||||
[-1n, 0n],
|
[-_1n, _0n],
|
||||||
[-rv1, rv1],
|
[-rv1, rv1],
|
||||||
[0n, -1n],
|
[_0n, -_1n],
|
||||||
[-rv1, -rv1],
|
[-rv1, -rv1],
|
||||||
].map((pair) => Fp2.fromBigTuple(pair));
|
].map((pair) => Fp2.fromBigTuple(pair));
|
||||||
// eta values, used for computing sqrt(g(X1(t)))
|
// eta values, used for computing sqrt(g(X1(t)))
|
||||||
@@ -314,8 +306,8 @@ const Fp6Multiply = ({ c0, c1, c2 }: Fp6, rhs: Fp6 | bigint) => {
|
|||||||
};
|
};
|
||||||
const Fp6Square = ({ c0, c1, c2 }: Fp6) => {
|
const Fp6Square = ({ c0, c1, c2 }: Fp6) => {
|
||||||
let t0 = Fp2.sqr(c0); // c0²
|
let t0 = Fp2.sqr(c0); // c0²
|
||||||
let t1 = Fp2.mul(Fp2.mul(c0, c1), 2n); // 2 * c0 * c1
|
let t1 = Fp2.mul(Fp2.mul(c0, c1), _2n); // 2 * c0 * c1
|
||||||
let t3 = Fp2.mul(Fp2.mul(c1, c2), 2n); // 2 * c1 * c2
|
let t3 = Fp2.mul(Fp2.mul(c1, c2), _2n); // 2 * c1 * c2
|
||||||
let t4 = Fp2.sqr(c2); // c2²
|
let t4 = Fp2.sqr(c2); // c2²
|
||||||
return {
|
return {
|
||||||
c0: Fp2.add(Fp2.mulByNonresidue(t3), t0), // T3 * (u + 1) + T0
|
c0: Fp2.add(Fp2.mulByNonresidue(t3), t0), // T3 * (u + 1) + T0
|
||||||
@@ -333,7 +325,7 @@ type Fp6Utils = {
|
|||||||
multiplyByFp2(lhs: Fp6, rhs: Fp2): Fp6;
|
multiplyByFp2(lhs: Fp6, rhs: Fp2): Fp6;
|
||||||
};
|
};
|
||||||
|
|
||||||
const Fp6: mod.Field<Fp6> & Fp6Utils = {
|
const Fp6: mod.IField<Fp6> & Fp6Utils = {
|
||||||
ORDER: Fp2.ORDER, // TODO: unused, but need to verify
|
ORDER: Fp2.ORDER, // TODO: unused, but need to verify
|
||||||
BITS: 3 * Fp2.BITS,
|
BITS: 3 * Fp2.BITS,
|
||||||
BYTES: 3 * Fp2.BYTES,
|
BYTES: 3 * Fp2.BYTES,
|
||||||
@@ -440,46 +432,64 @@ const Fp6: mod.Field<Fp6> & Fp6Utils = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const FP6_FROBENIUS_COEFFICIENTS_1 = [
|
const FP6_FROBENIUS_COEFFICIENTS_1 = [
|
||||||
[0x1n, 0x0n],
|
[BigInt('0x1'), BigInt('0x0')],
|
||||||
[
|
[
|
||||||
0x0n,
|
BigInt('0x0'),
|
||||||
0x1a0111ea397fe699ec02408663d4de85aa0d857d89759ad4897d29650fb85f9b409427eb4f49fffd8bfd00000000aaacn,
|
BigInt(
|
||||||
|
'0x1a0111ea397fe699ec02408663d4de85aa0d857d89759ad4897d29650fb85f9b409427eb4f49fffd8bfd00000000aaac'
|
||||||
|
),
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
0x00000000000000005f19672fdf76ce51ba69c6076a0f77eaddb3a93be6f89688de17d813620a00022e01fffffffefffen,
|
BigInt(
|
||||||
0x0n,
|
'0x00000000000000005f19672fdf76ce51ba69c6076a0f77eaddb3a93be6f89688de17d813620a00022e01fffffffefffe'
|
||||||
|
),
|
||||||
|
BigInt('0x0'),
|
||||||
],
|
],
|
||||||
[0x0n, 0x1n],
|
[BigInt('0x0'), BigInt('0x1')],
|
||||||
[
|
[
|
||||||
0x1a0111ea397fe699ec02408663d4de85aa0d857d89759ad4897d29650fb85f9b409427eb4f49fffd8bfd00000000aaacn,
|
BigInt(
|
||||||
0x0n,
|
'0x1a0111ea397fe699ec02408663d4de85aa0d857d89759ad4897d29650fb85f9b409427eb4f49fffd8bfd00000000aaac'
|
||||||
|
),
|
||||||
|
BigInt('0x0'),
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
0x0n,
|
BigInt('0x0'),
|
||||||
0x00000000000000005f19672fdf76ce51ba69c6076a0f77eaddb3a93be6f89688de17d813620a00022e01fffffffefffen,
|
BigInt(
|
||||||
|
'0x00000000000000005f19672fdf76ce51ba69c6076a0f77eaddb3a93be6f89688de17d813620a00022e01fffffffefffe'
|
||||||
|
),
|
||||||
],
|
],
|
||||||
].map((pair) => Fp2.fromBigTuple(pair));
|
].map((pair) => Fp2.fromBigTuple(pair));
|
||||||
const FP6_FROBENIUS_COEFFICIENTS_2 = [
|
const FP6_FROBENIUS_COEFFICIENTS_2 = [
|
||||||
[0x1n, 0x0n],
|
[BigInt('0x1'), BigInt('0x0')],
|
||||||
[
|
[
|
||||||
0x1a0111ea397fe699ec02408663d4de85aa0d857d89759ad4897d29650fb85f9b409427eb4f49fffd8bfd00000000aaadn,
|
BigInt(
|
||||||
0x0n,
|
'0x1a0111ea397fe699ec02408663d4de85aa0d857d89759ad4897d29650fb85f9b409427eb4f49fffd8bfd00000000aaad'
|
||||||
|
),
|
||||||
|
BigInt('0x0'),
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
0x1a0111ea397fe699ec02408663d4de85aa0d857d89759ad4897d29650fb85f9b409427eb4f49fffd8bfd00000000aaacn,
|
BigInt(
|
||||||
0x0n,
|
'0x1a0111ea397fe699ec02408663d4de85aa0d857d89759ad4897d29650fb85f9b409427eb4f49fffd8bfd00000000aaac'
|
||||||
|
),
|
||||||
|
BigInt('0x0'),
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaaan,
|
BigInt(
|
||||||
0x0n,
|
'0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaaa'
|
||||||
|
),
|
||||||
|
BigInt('0x0'),
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
0x00000000000000005f19672fdf76ce51ba69c6076a0f77eaddb3a93be6f89688de17d813620a00022e01fffffffefffen,
|
BigInt(
|
||||||
0x0n,
|
'0x00000000000000005f19672fdf76ce51ba69c6076a0f77eaddb3a93be6f89688de17d813620a00022e01fffffffefffe'
|
||||||
|
),
|
||||||
|
BigInt('0x0'),
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
0x00000000000000005f19672fdf76ce51ba69c6076a0f77eaddb3a93be6f89688de17d813620a00022e01fffffffeffffn,
|
BigInt(
|
||||||
0x0n,
|
'0x00000000000000005f19672fdf76ce51ba69c6076a0f77eaddb3a93be6f89688de17d813620a00022e01fffffffeffff'
|
||||||
|
),
|
||||||
|
BigInt('0x0'),
|
||||||
],
|
],
|
||||||
].map((pair) => Fp2.fromBigTuple(pair));
|
].map((pair) => Fp2.fromBigTuple(pair));
|
||||||
|
|
||||||
@@ -488,7 +498,7 @@ const FP6_FROBENIUS_COEFFICIENTS_2 = [
|
|||||||
// Fp₆(w) / (w² - γ) where γ = v
|
// Fp₆(w) / (w² - γ) where γ = v
|
||||||
type Fp12 = { c0: Fp6; c1: Fp6 };
|
type Fp12 = { c0: Fp6; c1: Fp6 };
|
||||||
// The BLS parameter x for BLS12-381
|
// The BLS parameter x for BLS12-381
|
||||||
const BLS_X = 0xd201000000010000n;
|
const BLS_X = BigInt('0xd201000000010000');
|
||||||
const BLS_X_LEN = bitLen(BLS_X);
|
const BLS_X_LEN = bitLen(BLS_X);
|
||||||
|
|
||||||
// prettier-ignore
|
// prettier-ignore
|
||||||
@@ -545,7 +555,7 @@ type Fp12Utils = {
|
|||||||
_cyclotomicExp(num: Fp12, n: bigint): Fp12;
|
_cyclotomicExp(num: Fp12, n: bigint): Fp12;
|
||||||
};
|
};
|
||||||
|
|
||||||
const Fp12: mod.Field<Fp12> & Fp12Utils = {
|
const Fp12: mod.IField<Fp12> & Fp12Utils = {
|
||||||
ORDER: Fp2.ORDER, // TODO: unused, but need to verify
|
ORDER: Fp2.ORDER, // TODO: unused, but need to verify
|
||||||
BITS: 2 * Fp2.BITS,
|
BITS: 2 * Fp2.BITS,
|
||||||
BYTES: 2 * Fp2.BYTES,
|
BYTES: 2 * Fp2.BYTES,
|
||||||
@@ -646,14 +656,14 @@ const Fp12: mod.Field<Fp12> & Fp12Utils = {
|
|||||||
let t9 = Fp2.mulByNonresidue(t8); // T8 * (u + 1)
|
let t9 = Fp2.mulByNonresidue(t8); // T8 * (u + 1)
|
||||||
return {
|
return {
|
||||||
c0: Fp6.create({
|
c0: Fp6.create({
|
||||||
c0: Fp2.add(Fp2.mul(Fp2.sub(t3, c0c0), 2n), t3), // 2 * (T3 - c0c0) + T3
|
c0: Fp2.add(Fp2.mul(Fp2.sub(t3, c0c0), _2n), t3), // 2 * (T3 - c0c0) + T3
|
||||||
c1: Fp2.add(Fp2.mul(Fp2.sub(t5, c0c1), 2n), t5), // 2 * (T5 - c0c1) + T5
|
c1: Fp2.add(Fp2.mul(Fp2.sub(t5, c0c1), _2n), t5), // 2 * (T5 - c0c1) + T5
|
||||||
c2: Fp2.add(Fp2.mul(Fp2.sub(t7, c0c2), 2n), t7),
|
c2: Fp2.add(Fp2.mul(Fp2.sub(t7, c0c2), _2n), t7),
|
||||||
}), // 2 * (T7 - c0c2) + T7
|
}), // 2 * (T7 - c0c2) + T7
|
||||||
c1: Fp6.create({
|
c1: Fp6.create({
|
||||||
c0: Fp2.add(Fp2.mul(Fp2.add(t9, c1c0), 2n), t9), // 2 * (T9 + c1c0) + T9
|
c0: Fp2.add(Fp2.mul(Fp2.add(t9, c1c0), _2n), t9), // 2 * (T9 + c1c0) + T9
|
||||||
c1: Fp2.add(Fp2.mul(Fp2.add(t4, c1c1), 2n), t4), // 2 * (T4 + c1c1) + T4
|
c1: Fp2.add(Fp2.mul(Fp2.add(t4, c1c1), _2n), t4), // 2 * (T4 + c1c1) + T4
|
||||||
c2: Fp2.add(Fp2.mul(Fp2.add(t6, c1c2), 2n), t6),
|
c2: Fp2.add(Fp2.mul(Fp2.add(t6, c1c2), _2n), t6),
|
||||||
}),
|
}),
|
||||||
}; // 2 * (T6 + c1c2) + T6
|
}; // 2 * (T6 + c1c2) + T6
|
||||||
},
|
},
|
||||||
@@ -688,58 +698,91 @@ const Fp12: mod.Field<Fp12> & Fp12Utils = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
const FP12_FROBENIUS_COEFFICIENTS = [
|
const FP12_FROBENIUS_COEFFICIENTS = [
|
||||||
[0x1n, 0x0n],
|
[BigInt('0x1'), BigInt('0x0')],
|
||||||
[
|
[
|
||||||
0x1904d3bf02bb0667c231beb4202c0d1f0fd603fd3cbd5f4f7b2443d784bab9c4f67ea53d63e7813d8d0775ed92235fb8n,
|
BigInt(
|
||||||
0x00fc3e2b36c4e03288e9e902231f9fb854a14787b6c7b36fec0c8ec971f63c5f282d5ac14d6c7ec22cf78a126ddc4af3n,
|
'0x1904d3bf02bb0667c231beb4202c0d1f0fd603fd3cbd5f4f7b2443d784bab9c4f67ea53d63e7813d8d0775ed92235fb8'
|
||||||
|
),
|
||||||
|
BigInt(
|
||||||
|
'0x00fc3e2b36c4e03288e9e902231f9fb854a14787b6c7b36fec0c8ec971f63c5f282d5ac14d6c7ec22cf78a126ddc4af3'
|
||||||
|
),
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
0x00000000000000005f19672fdf76ce51ba69c6076a0f77eaddb3a93be6f89688de17d813620a00022e01fffffffeffffn,
|
BigInt(
|
||||||
0x0n,
|
'0x00000000000000005f19672fdf76ce51ba69c6076a0f77eaddb3a93be6f89688de17d813620a00022e01fffffffeffff'
|
||||||
|
),
|
||||||
|
BigInt('0x0'),
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
0x135203e60180a68ee2e9c448d77a2cd91c3dedd930b1cf60ef396489f61eb45e304466cf3e67fa0af1ee7b04121bdea2n,
|
BigInt(
|
||||||
0x06af0e0437ff400b6831e36d6bd17ffe48395dabc2d3435e77f76e17009241c5ee67992f72ec05f4c81084fbede3cc09n,
|
'0x135203e60180a68ee2e9c448d77a2cd91c3dedd930b1cf60ef396489f61eb45e304466cf3e67fa0af1ee7b04121bdea2'
|
||||||
|
),
|
||||||
|
BigInt(
|
||||||
|
'0x06af0e0437ff400b6831e36d6bd17ffe48395dabc2d3435e77f76e17009241c5ee67992f72ec05f4c81084fbede3cc09'
|
||||||
|
),
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
0x00000000000000005f19672fdf76ce51ba69c6076a0f77eaddb3a93be6f89688de17d813620a00022e01fffffffefffen,
|
BigInt(
|
||||||
0x0n,
|
'0x00000000000000005f19672fdf76ce51ba69c6076a0f77eaddb3a93be6f89688de17d813620a00022e01fffffffefffe'
|
||||||
|
),
|
||||||
|
BigInt('0x0'),
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
0x144e4211384586c16bd3ad4afa99cc9170df3560e77982d0db45f3536814f0bd5871c1908bd478cd1ee605167ff82995n,
|
BigInt(
|
||||||
0x05b2cfd9013a5fd8df47fa6b48b1e045f39816240c0b8fee8beadf4d8e9c0566c63a3e6e257f87329b18fae980078116n,
|
'0x144e4211384586c16bd3ad4afa99cc9170df3560e77982d0db45f3536814f0bd5871c1908bd478cd1ee605167ff82995'
|
||||||
|
),
|
||||||
|
BigInt(
|
||||||
|
'0x05b2cfd9013a5fd8df47fa6b48b1e045f39816240c0b8fee8beadf4d8e9c0566c63a3e6e257f87329b18fae980078116'
|
||||||
|
),
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaaan,
|
BigInt(
|
||||||
0x0n,
|
'0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaaa'
|
||||||
|
),
|
||||||
|
BigInt('0x0'),
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
0x00fc3e2b36c4e03288e9e902231f9fb854a14787b6c7b36fec0c8ec971f63c5f282d5ac14d6c7ec22cf78a126ddc4af3n,
|
BigInt(
|
||||||
0x1904d3bf02bb0667c231beb4202c0d1f0fd603fd3cbd5f4f7b2443d784bab9c4f67ea53d63e7813d8d0775ed92235fb8n,
|
'0x00fc3e2b36c4e03288e9e902231f9fb854a14787b6c7b36fec0c8ec971f63c5f282d5ac14d6c7ec22cf78a126ddc4af3'
|
||||||
|
),
|
||||||
|
BigInt(
|
||||||
|
'0x1904d3bf02bb0667c231beb4202c0d1f0fd603fd3cbd5f4f7b2443d784bab9c4f67ea53d63e7813d8d0775ed92235fb8'
|
||||||
|
),
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
0x1a0111ea397fe699ec02408663d4de85aa0d857d89759ad4897d29650fb85f9b409427eb4f49fffd8bfd00000000aaacn,
|
BigInt(
|
||||||
0x0n,
|
'0x1a0111ea397fe699ec02408663d4de85aa0d857d89759ad4897d29650fb85f9b409427eb4f49fffd8bfd00000000aaac'
|
||||||
|
),
|
||||||
|
BigInt('0x0'),
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
0x06af0e0437ff400b6831e36d6bd17ffe48395dabc2d3435e77f76e17009241c5ee67992f72ec05f4c81084fbede3cc09n,
|
BigInt(
|
||||||
0x135203e60180a68ee2e9c448d77a2cd91c3dedd930b1cf60ef396489f61eb45e304466cf3e67fa0af1ee7b04121bdea2n,
|
'0x06af0e0437ff400b6831e36d6bd17ffe48395dabc2d3435e77f76e17009241c5ee67992f72ec05f4c81084fbede3cc09'
|
||||||
|
),
|
||||||
|
BigInt(
|
||||||
|
'0x135203e60180a68ee2e9c448d77a2cd91c3dedd930b1cf60ef396489f61eb45e304466cf3e67fa0af1ee7b04121bdea2'
|
||||||
|
),
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
0x1a0111ea397fe699ec02408663d4de85aa0d857d89759ad4897d29650fb85f9b409427eb4f49fffd8bfd00000000aaadn,
|
BigInt(
|
||||||
0x0n,
|
'0x1a0111ea397fe699ec02408663d4de85aa0d857d89759ad4897d29650fb85f9b409427eb4f49fffd8bfd00000000aaad'
|
||||||
|
),
|
||||||
|
BigInt('0x0'),
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
0x05b2cfd9013a5fd8df47fa6b48b1e045f39816240c0b8fee8beadf4d8e9c0566c63a3e6e257f87329b18fae980078116n,
|
BigInt(
|
||||||
0x144e4211384586c16bd3ad4afa99cc9170df3560e77982d0db45f3536814f0bd5871c1908bd478cd1ee605167ff82995n,
|
'0x05b2cfd9013a5fd8df47fa6b48b1e045f39816240c0b8fee8beadf4d8e9c0566c63a3e6e257f87329b18fae980078116'
|
||||||
|
),
|
||||||
|
BigInt(
|
||||||
|
'0x144e4211384586c16bd3ad4afa99cc9170df3560e77982d0db45f3536814f0bd5871c1908bd478cd1ee605167ff82995'
|
||||||
|
),
|
||||||
],
|
],
|
||||||
].map((n) => Fp2.fromBigTuple(n));
|
].map((n) => Fp2.fromBigTuple(n));
|
||||||
// END OF CURVE FIELDS
|
// END OF CURVE FIELDS
|
||||||
|
|
||||||
// HashToCurve
|
// HashToCurve
|
||||||
|
|
||||||
// 3-isogeny map from E' to E
|
// 3-isogeny map from E' to E https://www.rfc-editor.org/rfc/rfc9380#appendix-E.3
|
||||||
// https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-11#appendix-E.3
|
|
||||||
const isogenyMapG2 = isogenyMap(
|
const isogenyMapG2 = isogenyMap(
|
||||||
Fp2,
|
Fp2,
|
||||||
[
|
[
|
||||||
@@ -887,19 +930,23 @@ const isogenyMapG1 = isogenyMap(
|
|||||||
|
|
||||||
// SWU Map - Fp2 to G2': y² = x³ + 240i * x + 1012 + 1012i
|
// SWU Map - Fp2 to G2': y² = x³ + 240i * x + 1012 + 1012i
|
||||||
const G2_SWU = mapToCurveSimpleSWU(Fp2, {
|
const G2_SWU = mapToCurveSimpleSWU(Fp2, {
|
||||||
A: Fp2.create({ c0: Fp.create(0n), c1: Fp.create(240n) }), // A' = 240 * I
|
A: Fp2.create({ c0: Fp.create(_0n), c1: Fp.create(BigInt(240)) }), // A' = 240 * I
|
||||||
B: Fp2.create({ c0: Fp.create(1012n), c1: Fp.create(1012n) }), // B' = 1012 * (1 + I)
|
B: Fp2.create({ c0: Fp.create(BigInt(1012)), c1: Fp.create(BigInt(1012)) }), // B' = 1012 * (1 + I)
|
||||||
Z: Fp2.create({ c0: Fp.create(-2n), c1: Fp.create(-1n) }), // Z: -(2 + I)
|
Z: Fp2.create({ c0: Fp.create(BigInt(-2)), c1: Fp.create(BigInt(-1)) }), // Z: -(2 + I)
|
||||||
});
|
});
|
||||||
// Optimized SWU Map - Fp to G1
|
// Optimized SWU Map - Fp to G1
|
||||||
const G1_SWU = mapToCurveSimpleSWU(Fp, {
|
const G1_SWU = mapToCurveSimpleSWU(Fp, {
|
||||||
A: Fp.create(
|
A: Fp.create(
|
||||||
0x144698a3b8e9433d693a02c96d4982b0ea985383ee66a8d8e8981aefd881ac98936f8da0e0f97f5cf428082d584c1dn
|
BigInt(
|
||||||
|
'0x144698a3b8e9433d693a02c96d4982b0ea985383ee66a8d8e8981aefd881ac98936f8da0e0f97f5cf428082d584c1d'
|
||||||
|
)
|
||||||
),
|
),
|
||||||
B: Fp.create(
|
B: Fp.create(
|
||||||
0x12e2908d11688030018b12e8753eee3b2016c1f0f24f4070a0b9c14fcef35ef55a23215a316ceaa5d1cc48e98e172be0n
|
BigInt(
|
||||||
|
'0x12e2908d11688030018b12e8753eee3b2016c1f0f24f4070a0b9c14fcef35ef55a23215a316ceaa5d1cc48e98e172be0'
|
||||||
|
)
|
||||||
),
|
),
|
||||||
Z: Fp.create(11n),
|
Z: Fp.create(BigInt(11)),
|
||||||
});
|
});
|
||||||
|
|
||||||
// Endomorphisms (for fast cofactor clearing)
|
// Endomorphisms (for fast cofactor clearing)
|
||||||
@@ -922,8 +969,9 @@ function G2psi(c: ProjConstructor<Fp2>, P: ProjPointType<Fp2>) {
|
|||||||
}
|
}
|
||||||
// Ψ²(P) endomorphism
|
// Ψ²(P) endomorphism
|
||||||
// 1 / F2(2)^((p-1)/3) in GF(p²)
|
// 1 / F2(2)^((p-1)/3) in GF(p²)
|
||||||
const PSI2_C1 =
|
const PSI2_C1 = BigInt(
|
||||||
0x1a0111ea397fe699ec02408663d4de85aa0d857d89759ad4897d29650fb85f9b409427eb4f49fffd8bfd00000000aaacn;
|
'0x1a0111ea397fe699ec02408663d4de85aa0d857d89759ad4897d29650fb85f9b409427eb4f49fffd8bfd00000000aaac'
|
||||||
|
);
|
||||||
|
|
||||||
function psi2(x: Fp2, y: Fp2): [Fp2, Fp2] {
|
function psi2(x: Fp2, y: Fp2): [Fp2, Fp2] {
|
||||||
return [Fp2.mul(x, PSI2_C1), Fp2.neg(y)];
|
return [Fp2.mul(x, PSI2_C1), Fp2.neg(y)];
|
||||||
@@ -938,7 +986,7 @@ function G2psi2(c: ProjConstructor<Fp2>, P: ProjPointType<Fp2>) {
|
|||||||
//
|
//
|
||||||
// Parameter definitions are in section 5.3 of the spec unless otherwise noted.
|
// Parameter definitions are in section 5.3 of the spec unless otherwise noted.
|
||||||
// Parameter values come from section 8.8.2 of the spec.
|
// Parameter values come from section 8.8.2 of the spec.
|
||||||
// https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-11#section-8.8.2
|
// https://www.rfc-editor.org/rfc/rfc9380#section-8.8.2
|
||||||
//
|
//
|
||||||
// Base field F is GF(p^m)
|
// Base field F is GF(p^m)
|
||||||
// p = 0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab
|
// p = 0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab
|
||||||
@@ -970,14 +1018,62 @@ const htfDefaults = Object.freeze({
|
|||||||
|
|
||||||
// Encoding utils
|
// Encoding utils
|
||||||
// Point on G1 curve: (x, y)
|
// Point on G1 curve: (x, y)
|
||||||
const C_BIT_POS = Fp.BITS; // C_bit, compression bit for serialization flag
|
|
||||||
const I_BIT_POS = Fp.BITS + 1; // I_bit, point-at-infinity bit for serialization flag
|
|
||||||
const S_BIT_POS = Fp.BITS + 2; // S_bit, sign bit for serialization flag
|
|
||||||
// Compressed point of infinity
|
// Compressed point of infinity
|
||||||
const COMPRESSED_ZERO = Fp.toBytes(bitSet(bitSet(0n, I_BIT_POS, true), S_BIT_POS, true)); // set compressed & point-at-infinity bits
|
const COMPRESSED_ZERO = setMask(Fp.toBytes(_0n), { infinity: true, compressed: true }); // set compressed & point-at-infinity bits
|
||||||
|
|
||||||
|
function parseMask(bytes: Uint8Array) {
|
||||||
|
// Copy, so we can remove mask data. It will be removed also later, when Fp.create will call modulo.
|
||||||
|
bytes = bytes.slice();
|
||||||
|
const mask = bytes[0] & 0b1110_0000;
|
||||||
|
const compressed = !!((mask >> 7) & 1); // compression bit (0b1000_0000)
|
||||||
|
const infinity = !!((mask >> 6) & 1); // point at infinity bit (0b0100_0000)
|
||||||
|
const sort = !!((mask >> 5) & 1); // sort bit (0b0010_0000)
|
||||||
|
bytes[0] &= 0b0001_1111; // clear mask (zero first 3 bits)
|
||||||
|
return { compressed, infinity, sort, value: bytes };
|
||||||
|
}
|
||||||
|
|
||||||
|
function setMask(
|
||||||
|
bytes: Uint8Array,
|
||||||
|
mask: { compressed?: boolean; infinity?: boolean; sort?: boolean }
|
||||||
|
) {
|
||||||
|
if (bytes[0] & 0b1110_0000) throw new Error('setMask: non-empty mask');
|
||||||
|
if (mask.compressed) bytes[0] |= 0b1000_0000;
|
||||||
|
if (mask.infinity) bytes[0] |= 0b0100_0000;
|
||||||
|
if (mask.sort) bytes[0] |= 0b0010_0000;
|
||||||
|
return bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
function signatureG1ToRawBytes(point: ProjPointType<Fp>) {
|
||||||
|
point.assertValidity();
|
||||||
|
const isZero = point.equals(bls12_381.G1.ProjectivePoint.ZERO);
|
||||||
|
const { x, y } = point.toAffine();
|
||||||
|
if (isZero) return COMPRESSED_ZERO.slice();
|
||||||
|
const P = Fp.ORDER;
|
||||||
|
const sort = Boolean((y * _2n) / P);
|
||||||
|
return setMask(numberToBytesBE(x, Fp.BYTES), { compressed: true, sort });
|
||||||
|
}
|
||||||
|
|
||||||
|
function signatureG2ToRawBytes(point: ProjPointType<Fp2>) {
|
||||||
|
// NOTE: by some reasons it was missed in bls12-381, looks like bug
|
||||||
|
point.assertValidity();
|
||||||
|
const len = Fp.BYTES;
|
||||||
|
if (point.equals(bls12_381.G2.ProjectivePoint.ZERO))
|
||||||
|
return concatB(COMPRESSED_ZERO, numberToBytesBE(_0n, len));
|
||||||
|
const { x, y } = point.toAffine();
|
||||||
|
const { re: x0, im: x1 } = Fp2.reim(x);
|
||||||
|
const { re: y0, im: y1 } = Fp2.reim(y);
|
||||||
|
const tmp = y1 > _0n ? y1 * _2n : y0 * _2n;
|
||||||
|
const sort = Boolean((tmp / Fp.ORDER) & _1n);
|
||||||
|
const z2 = x0;
|
||||||
|
return concatB(
|
||||||
|
setMask(numberToBytesBE(x1, len), { sort, compressed: true }),
|
||||||
|
numberToBytesBE(z2, len)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// To verify curve parameters, see pairing-friendly-curves spec:
|
// To verify curve parameters, see pairing-friendly-curves spec:
|
||||||
// https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-pairing-friendly-curves-09
|
// https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-pairing-friendly-curves-11
|
||||||
// Basic math is done over finite fields over p.
|
// Basic math is done over finite fields over p.
|
||||||
// More complicated math is done over polynominal extension fields.
|
// More complicated math is done over polynominal extension fields.
|
||||||
// To simplify calculations in Fp12, we construct extension tower:
|
// To simplify calculations in Fp12, we construct extension tower:
|
||||||
@@ -988,27 +1084,31 @@ const COMPRESSED_ZERO = Fp.toBytes(bitSet(bitSet(0n, I_BIT_POS, true), S_BIT_POS
|
|||||||
// Here goes constants && point encoding format
|
// Here goes constants && point encoding format
|
||||||
export const bls12_381: CurveFn<Fp, Fp2, Fp6, Fp12> = bls({
|
export const bls12_381: CurveFn<Fp, Fp2, Fp6, Fp12> = bls({
|
||||||
// Fields
|
// Fields
|
||||||
Fr,
|
fields: {
|
||||||
Fp,
|
Fp,
|
||||||
Fp2,
|
Fp2,
|
||||||
Fp6,
|
Fp6,
|
||||||
Fp12,
|
Fp12,
|
||||||
// order; z⁴ − z² + 1
|
Fr,
|
||||||
r: Fr.ORDER, // Same as N in other curves
|
},
|
||||||
// G1 is the order-q subgroup of E1(Fp) : y² = x³ + 4, #E1(Fp) = h1q, where
|
// G1 is the order-q subgroup of E1(Fp) : y² = x³ + 4, #E1(Fp) = h1q, where
|
||||||
// characteristic; z + (z⁴ - z² + 1)(z - 1)²/3
|
// characteristic; z + (z⁴ - z² + 1)(z - 1)²/3
|
||||||
G1: {
|
G1: {
|
||||||
Fp,
|
Fp,
|
||||||
// cofactor; (z - 1)²/3
|
// cofactor; (z - 1)²/3
|
||||||
h: 0x396c8c005555e1568c00aaab0000aaabn,
|
h: BigInt('0x396c8c005555e1568c00aaab0000aaab'),
|
||||||
// generator's coordinates
|
// generator's coordinates
|
||||||
// x = 3685416753713387016781088315183077757961620795782546409894578378688607592378376318836054947676345821548104185464507
|
// x = 3685416753713387016781088315183077757961620795782546409894578378688607592378376318836054947676345821548104185464507
|
||||||
// y = 1339506544944476473020471379941921221584933875938349620426543736416511423956333506472724655353366534992391756441569
|
// y = 1339506544944476473020471379941921221584933875938349620426543736416511423956333506472724655353366534992391756441569
|
||||||
Gx: 0x17f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bbn,
|
Gx: BigInt(
|
||||||
Gy: 0x08b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e1n,
|
'0x17f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb'
|
||||||
|
),
|
||||||
|
Gy: BigInt(
|
||||||
|
'0x08b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e1'
|
||||||
|
),
|
||||||
a: Fp.ZERO,
|
a: Fp.ZERO,
|
||||||
b: 4n,
|
b: _4n,
|
||||||
htfDefaults: { ...htfDefaults, m: 1 },
|
htfDefaults: { ...htfDefaults, m: 1, DST: 'BLS_SIG_BLS12381G1_XMD:SHA-256_SSWU_RO_NUL_' },
|
||||||
wrapPrivateKey: true,
|
wrapPrivateKey: true,
|
||||||
allowInfinityPoint: true,
|
allowInfinityPoint: true,
|
||||||
// Checks is the point resides in prime-order subgroup.
|
// Checks is the point resides in prime-order subgroup.
|
||||||
@@ -1017,18 +1117,19 @@ export const bls12_381: CurveFn<Fp, Fp2, Fp6, Fp12> = bls({
|
|||||||
// https://eprint.iacr.org/2021/1130.pdf
|
// https://eprint.iacr.org/2021/1130.pdf
|
||||||
isTorsionFree: (c, point): boolean => {
|
isTorsionFree: (c, point): boolean => {
|
||||||
// φ endomorphism
|
// φ endomorphism
|
||||||
const cubicRootOfUnityModP =
|
const cubicRootOfUnityModP = BigInt(
|
||||||
0x5f19672fdf76ce51ba69c6076a0f77eaddb3a93be6f89688de17d813620a00022e01fffffffefffen;
|
'0x5f19672fdf76ce51ba69c6076a0f77eaddb3a93be6f89688de17d813620a00022e01fffffffefffe'
|
||||||
|
);
|
||||||
const phi = new c(Fp.mul(point.px, cubicRootOfUnityModP), point.py, point.pz);
|
const phi = new c(Fp.mul(point.px, cubicRootOfUnityModP), point.py, point.pz);
|
||||||
|
|
||||||
// todo: unroll
|
// todo: unroll
|
||||||
const xP = point.multiplyUnsafe(bls12_381.CURVE.x).negate(); // [x]P
|
const xP = point.multiplyUnsafe(bls12_381.params.x).negate(); // [x]P
|
||||||
const u2P = xP.multiplyUnsafe(bls12_381.CURVE.x); // [u2]P
|
const u2P = xP.multiplyUnsafe(bls12_381.params.x); // [u2]P
|
||||||
return u2P.equals(phi);
|
return u2P.equals(phi);
|
||||||
|
|
||||||
// https://eprint.iacr.org/2019/814.pdf
|
// https://eprint.iacr.org/2019/814.pdf
|
||||||
// (z² − 1)/3
|
// (z² − 1)/3
|
||||||
// const c1 = 0x396c8c005555e1560000000055555555n;
|
// const c1 = BigInt('0x396c8c005555e1560000000055555555');
|
||||||
// const P = this;
|
// const P = this;
|
||||||
// const S = P.sigma();
|
// const S = P.sigma();
|
||||||
// const Q = S.double();
|
// const Q = S.double();
|
||||||
@@ -1040,33 +1141,39 @@ export const bls12_381: CurveFn<Fp, Fp2, Fp6, Fp12> = bls({
|
|||||||
},
|
},
|
||||||
// Clear cofactor of G1
|
// Clear cofactor of G1
|
||||||
// https://eprint.iacr.org/2019/403
|
// https://eprint.iacr.org/2019/403
|
||||||
clearCofactor: (c, point) => {
|
clearCofactor: (_c, point) => {
|
||||||
// return this.multiplyUnsafe(CURVE.h);
|
// return this.multiplyUnsafe(CURVE.h);
|
||||||
return point.multiplyUnsafe(bls12_381.CURVE.x).add(point); // x*P + P
|
return point.multiplyUnsafe(bls12_381.params.x).add(point); // x*P + P
|
||||||
},
|
},
|
||||||
mapToCurve: (scalars: bigint[]) => {
|
mapToCurve: (scalars: bigint[]) => {
|
||||||
const { x, y } = G1_SWU(Fp.create(scalars[0]));
|
const { x, y } = G1_SWU(Fp.create(scalars[0]));
|
||||||
return isogenyMapG1(x, y);
|
return isogenyMapG1(x, y);
|
||||||
},
|
},
|
||||||
fromBytes: (bytes: Uint8Array): AffinePoint<Fp> => {
|
fromBytes: (bytes: Uint8Array): AffinePoint<Fp> => {
|
||||||
if (bytes.length === 48) {
|
const { compressed, infinity, sort, value } = parseMask(bytes);
|
||||||
|
if (value.length === 48 && compressed) {
|
||||||
|
// TODO: Fp.bytes
|
||||||
const P = Fp.ORDER;
|
const P = Fp.ORDER;
|
||||||
const compressedValue = bytesToNumberBE(bytes);
|
const compressedValue = bytesToNumberBE(value);
|
||||||
const bflag = bitGet(compressedValue, I_BIT_POS);
|
|
||||||
// Zero
|
// Zero
|
||||||
if (bflag === 1n) return { x: 0n, y: 0n };
|
|
||||||
const x = Fp.create(compressedValue & Fp.MASK);
|
const x = Fp.create(compressedValue & Fp.MASK);
|
||||||
const right = Fp.add(Fp.pow(x, 3n), Fp.create(bls12_381.CURVE.G1.b)); // y² = x³ + b
|
if (infinity) {
|
||||||
|
if (x !== _0n) throw new Error('G1: non-empty compressed point at infinity');
|
||||||
|
return { x: _0n, y: _0n };
|
||||||
|
}
|
||||||
|
const right = Fp.add(Fp.pow(x, _3n), Fp.create(bls12_381.params.G1b)); // y² = x³ + b
|
||||||
let y = Fp.sqrt(right);
|
let y = Fp.sqrt(right);
|
||||||
if (!y) throw new Error('Invalid compressed G1 point');
|
if (!y) throw new Error('Invalid compressed G1 point');
|
||||||
const aflag = bitGet(compressedValue, C_BIT_POS);
|
if ((y * _2n) / P !== BigInt(sort)) y = Fp.neg(y);
|
||||||
if ((y * 2n) / P !== aflag) y = Fp.neg(y);
|
|
||||||
return { x: Fp.create(x), y: Fp.create(y) };
|
return { x: Fp.create(x), y: Fp.create(y) };
|
||||||
} else if (bytes.length === 96) {
|
} else if (value.length === 96 && !compressed) {
|
||||||
// Check if the infinity flag is set
|
// Check if the infinity flag is set
|
||||||
if ((bytes[0] & (1 << 6)) !== 0) return bls12_381.G1.ProjectivePoint.ZERO.toAffine();
|
const x = bytesToNumberBE(value.subarray(0, Fp.BYTES));
|
||||||
const x = bytesToNumberBE(bytes.slice(0, Fp.BYTES));
|
const y = bytesToNumberBE(value.subarray(Fp.BYTES));
|
||||||
const y = bytesToNumberBE(bytes.slice(Fp.BYTES));
|
if (infinity) {
|
||||||
|
if (x !== _0n || y !== _0n) throw new Error('G1: non-empty point at infinity');
|
||||||
|
return bls12_381.G1.ProjectivePoint.ZERO.toAffine();
|
||||||
|
}
|
||||||
return { x: Fp.create(x), y: Fp.create(y) };
|
return { x: Fp.create(x), y: Fp.create(y) };
|
||||||
} else {
|
} else {
|
||||||
throw new Error('Invalid point G1, expected 48/96 bytes');
|
throw new Error('Invalid point G1, expected 48/96 bytes');
|
||||||
@@ -1078,10 +1185,8 @@ export const bls12_381: CurveFn<Fp, Fp2, Fp6, Fp12> = bls({
|
|||||||
if (isCompressed) {
|
if (isCompressed) {
|
||||||
if (isZero) return COMPRESSED_ZERO.slice();
|
if (isZero) return COMPRESSED_ZERO.slice();
|
||||||
const P = Fp.ORDER;
|
const P = Fp.ORDER;
|
||||||
let num;
|
const sort = Boolean((y * _2n) / P);
|
||||||
num = bitSet(x, C_BIT_POS, Boolean((y * 2n) / P)); // set aflag
|
return setMask(numberToBytesBE(x, Fp.BYTES), { compressed: true, sort });
|
||||||
num = bitSet(num, S_BIT_POS, true);
|
|
||||||
return numberToBytesBE(num, Fp.BYTES);
|
|
||||||
} else {
|
} else {
|
||||||
if (isZero) {
|
if (isZero) {
|
||||||
// 2x PUBLIC_KEY_LENGTH
|
// 2x PUBLIC_KEY_LENGTH
|
||||||
@@ -1092,6 +1197,30 @@ export const bls12_381: CurveFn<Fp, Fp2, Fp6, Fp12> = bls({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
ShortSignature: {
|
||||||
|
fromHex(hex: Hex): ProjPointType<Fp> {
|
||||||
|
const { infinity, sort, value } = parseMask(ensureBytes('signatureHex', hex, 48));
|
||||||
|
const P = Fp.ORDER;
|
||||||
|
const compressedValue = bytesToNumberBE(value);
|
||||||
|
// Zero
|
||||||
|
if (infinity) return bls12_381.G1.ProjectivePoint.ZERO;
|
||||||
|
const x = Fp.create(compressedValue & Fp.MASK);
|
||||||
|
const right = Fp.add(Fp.pow(x, _3n), Fp.create(bls12_381.params.G1b)); // y² = x³ + b
|
||||||
|
let y = Fp.sqrt(right);
|
||||||
|
if (!y) throw new Error('Invalid compressed G1 point');
|
||||||
|
const aflag = BigInt(sort);
|
||||||
|
if ((y * _2n) / P !== aflag) y = Fp.neg(y);
|
||||||
|
const point = bls12_381.G1.ProjectivePoint.fromAffine({ x, y });
|
||||||
|
point.assertValidity();
|
||||||
|
return point;
|
||||||
|
},
|
||||||
|
toRawBytes(point: ProjPointType<Fp>) {
|
||||||
|
return signatureG1ToRawBytes(point);
|
||||||
|
},
|
||||||
|
toHex(point: ProjPointType<Fp>) {
|
||||||
|
return bytesToHex(signatureG1ToRawBytes(point));
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
// G2 is the order-q subgroup of E2(Fp²) : y² = x³+4(1+√−1),
|
// G2 is the order-q subgroup of E2(Fp²) : y² = x³+4(1+√−1),
|
||||||
// where Fp2 is Fp[√−1]/(x2+1). #E2(Fp2 ) = h2q, where
|
// where Fp2 is Fp[√−1]/(x2+1). #E2(Fp2 ) = h2q, where
|
||||||
@@ -1100,21 +1229,33 @@ export const bls12_381: CurveFn<Fp, Fp2, Fp6, Fp12> = bls({
|
|||||||
G2: {
|
G2: {
|
||||||
Fp: Fp2,
|
Fp: Fp2,
|
||||||
// cofactor
|
// cofactor
|
||||||
h: 0x5d543a95414e7f1091d50792876a202cd91de4547085abaa68a205b2e5a7ddfa628f1cb4d9e82ef21537e293a6691ae1616ec6e786f0c70cf1c38e31c7238e5n,
|
h: BigInt(
|
||||||
|
'0x5d543a95414e7f1091d50792876a202cd91de4547085abaa68a205b2e5a7ddfa628f1cb4d9e82ef21537e293a6691ae1616ec6e786f0c70cf1c38e31c7238e5'
|
||||||
|
),
|
||||||
Gx: Fp2.fromBigTuple([
|
Gx: Fp2.fromBigTuple([
|
||||||
0x024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb8n,
|
BigInt(
|
||||||
0x13e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7en,
|
'0x024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb8'
|
||||||
|
),
|
||||||
|
BigInt(
|
||||||
|
'0x13e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e'
|
||||||
|
),
|
||||||
]),
|
]),
|
||||||
// y =
|
// y =
|
||||||
// 927553665492332455747201965776037880757740193453592970025027978793976877002675564980949289727957565575433344219582,
|
// 927553665492332455747201965776037880757740193453592970025027978793976877002675564980949289727957565575433344219582,
|
||||||
// 1985150602287291935568054521177171638300868978215655730859378665066344726373823718423869104263333984641494340347905
|
// 1985150602287291935568054521177171638300868978215655730859378665066344726373823718423869104263333984641494340347905
|
||||||
Gy: Fp2.fromBigTuple([
|
Gy: Fp2.fromBigTuple([
|
||||||
0x0ce5d527727d6e118cc9cdc6da2e351aadfd9baa8cbdd3a76d429a695160d12c923ac9cc3baca289e193548608b82801n,
|
BigInt(
|
||||||
0x0606c4a02ea734cc32acd2b02bc28b99cb3e287e85a763af267492ab572e99ab3f370d275cec1da1aaa9075ff05f79ben,
|
'0x0ce5d527727d6e118cc9cdc6da2e351aadfd9baa8cbdd3a76d429a695160d12c923ac9cc3baca289e193548608b82801'
|
||||||
|
),
|
||||||
|
BigInt(
|
||||||
|
'0x0606c4a02ea734cc32acd2b02bc28b99cb3e287e85a763af267492ab572e99ab3f370d275cec1da1aaa9075ff05f79be'
|
||||||
|
),
|
||||||
]),
|
]),
|
||||||
a: Fp2.ZERO,
|
a: Fp2.ZERO,
|
||||||
b: Fp2.fromBigTuple([4n, 4n]),
|
b: Fp2.fromBigTuple([_4n, _4n]),
|
||||||
hEff: 0xbc69f08f2ee75b3584c6a0ea91b352888e2a8e9145ad7689986ff031508ffe1329c2f178731db956d82bf015d1212b02ec0ec69d7477c1ae954cbc06689f6a359894c0adebbf6b4e8020005aaa95551n,
|
hEff: BigInt(
|
||||||
|
'0xbc69f08f2ee75b3584c6a0ea91b352888e2a8e9145ad7689986ff031508ffe1329c2f178731db956d82bf015d1212b02ec0ec69d7477c1ae954cbc06689f6a359894c0adebbf6b4e8020005aaa95551'
|
||||||
|
),
|
||||||
htfDefaults: { ...htfDefaults },
|
htfDefaults: { ...htfDefaults },
|
||||||
wrapPrivateKey: true,
|
wrapPrivateKey: true,
|
||||||
allowInfinityPoint: true,
|
allowInfinityPoint: true,
|
||||||
@@ -1127,7 +1268,7 @@ export const bls12_381: CurveFn<Fp, Fp2, Fp6, Fp12> = bls({
|
|||||||
// It returns false for shitty points.
|
// It returns false for shitty points.
|
||||||
// https://eprint.iacr.org/2021/1130.pdf
|
// https://eprint.iacr.org/2021/1130.pdf
|
||||||
isTorsionFree: (c, P): boolean => {
|
isTorsionFree: (c, P): boolean => {
|
||||||
return P.multiplyUnsafe(bls12_381.CURVE.x).negate().equals(G2psi(c, P)); // ψ(P) == [u](P)
|
return P.multiplyUnsafe(bls12_381.params.x).negate().equals(G2psi(c, P)); // ψ(P) == [u](P)
|
||||||
// Older version: https://eprint.iacr.org/2019/814.pdf
|
// Older version: https://eprint.iacr.org/2019/814.pdf
|
||||||
// Ψ²(P) => Ψ³(P) => [z]Ψ³(P) where z = -x => [z]Ψ³(P) - Ψ²(P) + P == O
|
// Ψ²(P) => Ψ³(P) => [z]Ψ³(P) where z = -x => [z]Ψ³(P) - Ψ²(P) + P == O
|
||||||
// return P.psi2().psi().mulNegX().subtract(psi2).add(P).isZero();
|
// return P.psi2().psi().mulNegX().subtract(psi2).add(P).isZero();
|
||||||
@@ -1137,7 +1278,7 @@ export const bls12_381: CurveFn<Fp, Fp2, Fp6, Fp12> = bls({
|
|||||||
// https://eprint.iacr.org/2017/419.pdf
|
// https://eprint.iacr.org/2017/419.pdf
|
||||||
// prettier-ignore
|
// prettier-ignore
|
||||||
clearCofactor: (c, P) => {
|
clearCofactor: (c, P) => {
|
||||||
const { x } = bls12_381.CURVE;
|
const x = bls12_381.params.x;
|
||||||
let t1 = P.multiplyUnsafe(x).negate(); // [-x]P
|
let t1 = P.multiplyUnsafe(x).negate(); // [-x]P
|
||||||
let t2 = G2psi(c, P); // Ψ(P)
|
let t2 = G2psi(c, P); // Ψ(P)
|
||||||
let t3 = P.double(); // 2P
|
let t3 = P.double(); // 2P
|
||||||
@@ -1151,90 +1292,89 @@ export const bls12_381: CurveFn<Fp, Fp2, Fp6, Fp12> = bls({
|
|||||||
return Q; // [x²-x-1]P + [x-1]Ψ(P) + Ψ²(2P)
|
return Q; // [x²-x-1]P + [x-1]Ψ(P) + Ψ²(2P)
|
||||||
},
|
},
|
||||||
fromBytes: (bytes: Uint8Array): AffinePoint<Fp2> => {
|
fromBytes: (bytes: Uint8Array): AffinePoint<Fp2> => {
|
||||||
const m_byte = bytes[0] & 0xe0;
|
const { compressed, infinity, sort, value } = parseMask(bytes);
|
||||||
if (m_byte === 0x20 || m_byte === 0x60 || m_byte === 0xe0) {
|
if (
|
||||||
throw new Error('Invalid encoding flag: ' + m_byte);
|
(!compressed && !infinity && sort) || // 00100000
|
||||||
|
(!compressed && infinity && sort) || // 01100000
|
||||||
|
(sort && infinity && compressed) // 11100000
|
||||||
|
) {
|
||||||
|
throw new Error('Invalid encoding flag: ' + (bytes[0] & 0b1110_0000));
|
||||||
}
|
}
|
||||||
const bitC = m_byte & 0x80; // compression bit
|
|
||||||
const bitI = m_byte & 0x40; // point at infinity bit
|
|
||||||
const bitS = m_byte & 0x20; // sign bit
|
|
||||||
const L = Fp.BYTES;
|
const L = Fp.BYTES;
|
||||||
const slc = (b: Uint8Array, from: number, to?: number) => bytesToNumberBE(b.slice(from, to));
|
const slc = (b: Uint8Array, from: number, to?: number) => bytesToNumberBE(b.slice(from, to));
|
||||||
if (bytes.length === 96 && bitC) {
|
if (value.length === 96 && compressed) {
|
||||||
const { b } = bls12_381.CURVE.G2;
|
const b = bls12_381.params.G2b;
|
||||||
const P = Fp.ORDER;
|
const P = Fp.ORDER;
|
||||||
|
if (infinity) {
|
||||||
bytes[0] = bytes[0] & 0x1f; // clear flags
|
|
||||||
if (bitI) {
|
|
||||||
// check that all bytes are 0
|
// check that all bytes are 0
|
||||||
if (bytes.reduce((p, c) => (p !== 0 ? c + 1 : c), 0) > 0) {
|
if (value.reduce((p, c) => (p !== 0 ? c + 1 : c), 0) > 0) {
|
||||||
throw new Error('Invalid compressed G2 point');
|
throw new Error('Invalid compressed G2 point');
|
||||||
}
|
}
|
||||||
return { x: Fp2.ZERO, y: Fp2.ZERO };
|
return { x: Fp2.ZERO, y: Fp2.ZERO };
|
||||||
}
|
}
|
||||||
const x_1 = slc(bytes, 0, L);
|
const x_1 = slc(value, 0, L);
|
||||||
const x_0 = slc(bytes, L, 2 * L);
|
const x_0 = slc(value, L, 2 * L);
|
||||||
const x = Fp2.create({ c0: Fp.create(x_0), c1: Fp.create(x_1) });
|
const x = Fp2.create({ c0: Fp.create(x_0), c1: Fp.create(x_1) });
|
||||||
const right = Fp2.add(Fp2.pow(x, 3n), b); // y² = x³ + 4 * (u+1) = x³ + b
|
const right = Fp2.add(Fp2.pow(x, _3n), b); // y² = x³ + 4 * (u+1) = x³ + b
|
||||||
let y = Fp2.sqrt(right);
|
let y = Fp2.sqrt(right);
|
||||||
const Y_bit = y.c1 === 0n ? (y.c0 * 2n) / P : (y.c1 * 2n) / P ? 1n : 0n;
|
const Y_bit = y.c1 === _0n ? (y.c0 * _2n) / P : (y.c1 * _2n) / P ? _1n : _0n;
|
||||||
y = bitS > 0 && Y_bit > 0 ? y : Fp2.neg(y);
|
y = sort && Y_bit > 0 ? y : Fp2.neg(y);
|
||||||
return { x, y };
|
return { x, y };
|
||||||
} else if (bytes.length === 192 && !bitC) {
|
} else if (value.length === 192 && !compressed) {
|
||||||
// Check if the infinity flag is set
|
if (infinity) {
|
||||||
if ((bytes[0] & (1 << 6)) !== 0) {
|
if (value.reduce((p, c) => (p !== 0 ? c + 1 : c), 0) > 0) {
|
||||||
|
throw new Error('Invalid uncompressed G2 point');
|
||||||
|
}
|
||||||
return { x: Fp2.ZERO, y: Fp2.ZERO };
|
return { x: Fp2.ZERO, y: Fp2.ZERO };
|
||||||
}
|
}
|
||||||
const x1 = slc(bytes, 0, L);
|
const x1 = slc(value, 0, L);
|
||||||
const x0 = slc(bytes, L, 2 * L);
|
const x0 = slc(value, L, 2 * L);
|
||||||
const y1 = slc(bytes, 2 * L, 3 * L);
|
const y1 = slc(value, 2 * L, 3 * L);
|
||||||
const y0 = slc(bytes, 3 * L, 4 * L);
|
const y0 = slc(value, 3 * L, 4 * L);
|
||||||
return { x: Fp2.fromBigTuple([x0, x1]), y: Fp2.fromBigTuple([y0, y1]) };
|
return { x: Fp2.fromBigTuple([x0, x1]), y: Fp2.fromBigTuple([y0, y1]) };
|
||||||
} else {
|
} else {
|
||||||
throw new Error('Invalid point G2, expected 96/192 bytes');
|
throw new Error('Invalid point G2, expected 96/192 bytes');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
toBytes: (c, point, isCompressed) => {
|
toBytes: (c, point, isCompressed) => {
|
||||||
|
const { BYTES: len, ORDER: P } = Fp;
|
||||||
const isZero = point.equals(c.ZERO);
|
const isZero = point.equals(c.ZERO);
|
||||||
const { x, y } = point.toAffine();
|
const { x, y } = point.toAffine();
|
||||||
if (isCompressed) {
|
if (isCompressed) {
|
||||||
const P = Fp.ORDER;
|
if (isZero) return concatB(COMPRESSED_ZERO, numberToBytesBE(_0n, len));
|
||||||
if (isZero) return concatB(COMPRESSED_ZERO, numberToBytesBE(0n, Fp.BYTES));
|
const flag = Boolean(y.c1 === _0n ? (y.c0 * _2n) / P : (y.c1 * _2n) / P);
|
||||||
const flag = Boolean(y.c1 === 0n ? (y.c0 * 2n) / P : (y.c1 * 2n) / P);
|
return concatB(
|
||||||
// set compressed & sign bits (looks like different offsets than for G1/Fp?)
|
setMask(numberToBytesBE(x.c1, len), { compressed: true, sort: flag }),
|
||||||
let x_1 = bitSet(x.c1, C_BIT_POS, flag);
|
numberToBytesBE(x.c0, len)
|
||||||
x_1 = bitSet(x_1, S_BIT_POS, true);
|
);
|
||||||
return concatB(numberToBytesBE(x_1, Fp.BYTES), numberToBytesBE(x.c0, Fp.BYTES));
|
|
||||||
} else {
|
} else {
|
||||||
if (isZero) return concatB(new Uint8Array([0x40]), new Uint8Array(4 * Fp.BYTES - 1)); // bytes[0] |= 1 << 6;
|
if (isZero) return concatB(new Uint8Array([0x40]), new Uint8Array(4 * len - 1)); // bytes[0] |= 1 << 6;
|
||||||
const { re: x0, im: x1 } = Fp2.reim(x);
|
const { re: x0, im: x1 } = Fp2.reim(x);
|
||||||
const { re: y0, im: y1 } = Fp2.reim(y);
|
const { re: y0, im: y1 } = Fp2.reim(y);
|
||||||
return concatB(
|
return concatB(
|
||||||
numberToBytesBE(x1, Fp.BYTES),
|
numberToBytesBE(x1, len),
|
||||||
numberToBytesBE(x0, Fp.BYTES),
|
numberToBytesBE(x0, len),
|
||||||
numberToBytesBE(y1, Fp.BYTES),
|
numberToBytesBE(y1, len),
|
||||||
numberToBytesBE(y0, Fp.BYTES)
|
numberToBytesBE(y0, len)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Signature: {
|
Signature: {
|
||||||
// TODO: Optimize, it's very slow because of sqrt.
|
// TODO: Optimize, it's very slow because of sqrt.
|
||||||
decode(hex: Hex): ProjPointType<Fp2> {
|
fromHex(hex: Hex): ProjPointType<Fp2> {
|
||||||
hex = ensureBytes('signatureHex', hex);
|
const { infinity, sort, value } = parseMask(ensureBytes('signatureHex', hex));
|
||||||
const P = Fp.ORDER;
|
const P = Fp.ORDER;
|
||||||
const half = hex.length / 2;
|
const half = hex.length / 2;
|
||||||
if (half !== 48 && half !== 96)
|
if (half !== 48 && half !== 96)
|
||||||
throw new Error('Invalid compressed signature length, must be 96 or 192');
|
throw new Error('Invalid compressed signature length, must be 96 or 192');
|
||||||
const z1 = bytesToNumberBE(hex.slice(0, half));
|
const z1 = bytesToNumberBE(value.slice(0, half));
|
||||||
const z2 = bytesToNumberBE(hex.slice(half));
|
const z2 = bytesToNumberBE(value.slice(half));
|
||||||
// Indicates the infinity point
|
// Indicates the infinity point
|
||||||
const bflag1 = bitGet(z1, I_BIT_POS);
|
if (infinity) return bls12_381.G2.ProjectivePoint.ZERO;
|
||||||
if (bflag1 === 1n) return bls12_381.G2.ProjectivePoint.ZERO;
|
|
||||||
|
|
||||||
const x1 = Fp.create(z1 & Fp.MASK);
|
const x1 = Fp.create(z1 & Fp.MASK);
|
||||||
const x2 = Fp.create(z2);
|
const x2 = Fp.create(z2);
|
||||||
const x = Fp2.create({ c0: x2, c1: x1 });
|
const x = Fp2.create({ c0: x2, c1: x1 });
|
||||||
const y2 = Fp2.add(Fp2.pow(x, 3n), bls12_381.CURVE.G2.b); // y² = x³ + 4
|
const y2 = Fp2.add(Fp2.pow(x, _3n), bls12_381.params.G2b); // y² = x³ + 4
|
||||||
// The slow part
|
// The slow part
|
||||||
let y = Fp2.sqrt(y2);
|
let y = Fp2.sqrt(y2);
|
||||||
if (!y) throw new Error('Failed to find a square root');
|
if (!y) throw new Error('Failed to find a square root');
|
||||||
@@ -1242,32 +1382,26 @@ export const bls12_381: CurveFn<Fp, Fp2, Fp6, Fp12> = bls({
|
|||||||
// Choose the y whose leftmost bit of the imaginary part is equal to the a_flag1
|
// Choose the y whose leftmost bit of the imaginary part is equal to the a_flag1
|
||||||
// If y1 happens to be zero, then use the bit of y0
|
// If y1 happens to be zero, then use the bit of y0
|
||||||
const { re: y0, im: y1 } = Fp2.reim(y);
|
const { re: y0, im: y1 } = Fp2.reim(y);
|
||||||
const aflag1 = bitGet(z1, 381);
|
const aflag1 = BigInt(sort);
|
||||||
const isGreater = y1 > 0n && (y1 * 2n) / P !== aflag1;
|
const isGreater = y1 > _0n && (y1 * _2n) / P !== aflag1;
|
||||||
const isZero = y1 === 0n && (y0 * 2n) / P !== aflag1;
|
const isZero = y1 === _0n && (y0 * _2n) / P !== aflag1;
|
||||||
if (isGreater || isZero) y = Fp2.neg(y);
|
if (isGreater || isZero) y = Fp2.neg(y);
|
||||||
const point = bls12_381.G2.ProjectivePoint.fromAffine({ x, y });
|
const point = bls12_381.G2.ProjectivePoint.fromAffine({ x, y });
|
||||||
point.assertValidity();
|
point.assertValidity();
|
||||||
return point;
|
return point;
|
||||||
},
|
},
|
||||||
encode(point: ProjPointType<Fp2>) {
|
toRawBytes(point: ProjPointType<Fp2>) {
|
||||||
// NOTE: by some reasons it was missed in bls12-381, looks like bug
|
return signatureG2ToRawBytes(point);
|
||||||
point.assertValidity();
|
},
|
||||||
if (point.equals(bls12_381.G2.ProjectivePoint.ZERO))
|
toHex(point: ProjPointType<Fp2>) {
|
||||||
return concatB(COMPRESSED_ZERO, numberToBytesBE(0n, Fp.BYTES));
|
return bytesToHex(signatureG2ToRawBytes(point));
|
||||||
const a = point.toAffine();
|
|
||||||
const { re: x0, im: x1 } = Fp2.reim(a.x);
|
|
||||||
const { re: y0, im: y1 } = Fp2.reim(a.y);
|
|
||||||
const tmp = y1 > 0n ? y1 * 2n : y0 * 2n;
|
|
||||||
const aflag1 = Boolean((tmp / Fp.ORDER) & 1n);
|
|
||||||
const z1 = bitSet(bitSet(x1, 381, aflag1), S_BIT_POS, true);
|
|
||||||
const z2 = x0;
|
|
||||||
return concatB(numberToBytesBE(z1, Fp.BYTES), numberToBytesBE(z2, Fp.BYTES));
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
// The BLS parameter x for BLS12-381
|
params: {
|
||||||
x: BLS_X,
|
x: BLS_X, // The BLS parameter x for BLS12-381
|
||||||
|
r: Fr.ORDER, // order; z⁴ − z² + 1; CURVE.n from other curves
|
||||||
|
},
|
||||||
htfDefaults,
|
htfDefaults,
|
||||||
hash: sha256,
|
hash: sha256,
|
||||||
randomBytes,
|
randomBytes,
|
||||||
|
|||||||
@@ -2,17 +2,18 @@
|
|||||||
import { sha256 } from '@noble/hashes/sha256';
|
import { sha256 } from '@noble/hashes/sha256';
|
||||||
import { weierstrass } from './abstract/weierstrass.js';
|
import { weierstrass } from './abstract/weierstrass.js';
|
||||||
import { getHash } from './_shortw_utils.js';
|
import { getHash } from './_shortw_utils.js';
|
||||||
import { Fp } from './abstract/modular.js';
|
import { Field } from './abstract/modular.js';
|
||||||
/**
|
/**
|
||||||
* bn254 pairing-friendly curve.
|
* bn254 pairing-friendly curve.
|
||||||
* Previously known as alt_bn_128, when it had 128-bit security.
|
* 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.
|
* Barbulescu-Duquesne 2017 shown it's weaker: just about 100 bits,
|
||||||
* https://github.com/zcash/zcash/issues/2502
|
* so the naming has been adjusted to its prime bit count
|
||||||
|
* https://hal.science/hal-01534101/file/main.pdf
|
||||||
*/
|
*/
|
||||||
export const bn254 = weierstrass({
|
export const bn254 = weierstrass({
|
||||||
a: BigInt(0),
|
a: BigInt(0),
|
||||||
b: BigInt(3),
|
b: BigInt(3),
|
||||||
Fp: Fp(BigInt('0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47')),
|
Fp: Field(BigInt('0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47')),
|
||||||
n: BigInt('0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001'),
|
n: BigInt('0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001'),
|
||||||
Gx: BigInt(1),
|
Gx: BigInt(1),
|
||||||
Gy: BigInt(2),
|
Gy: BigInt(2),
|
||||||
160
src/ed25519.ts
160
src/ed25519.ts
@@ -1,18 +1,19 @@
|
|||||||
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
||||||
import { sha512 } from '@noble/hashes/sha512';
|
import { sha512 } from '@noble/hashes/sha512';
|
||||||
import { concatBytes, randomBytes, utf8ToBytes } from '@noble/hashes/utils';
|
import { concatBytes, randomBytes, utf8ToBytes } from '@noble/hashes/utils';
|
||||||
import { twistedEdwards, ExtPointType } from './abstract/edwards.js';
|
import { ExtPointType, twistedEdwards } from './abstract/edwards.js';
|
||||||
import { montgomery } from './abstract/montgomery.js';
|
import { montgomery } from './abstract/montgomery.js';
|
||||||
import { mod, pow2, isNegativeLE, Fp as Field, FpSqrtEven } from './abstract/modular.js';
|
import { Field, FpSqrtEven, isNegativeLE, mod, pow2 } from './abstract/modular.js';
|
||||||
import {
|
import {
|
||||||
equalBytes,
|
|
||||||
bytesToHex,
|
bytesToHex,
|
||||||
bytesToNumberLE,
|
bytesToNumberLE,
|
||||||
numberToBytesLE,
|
|
||||||
Hex,
|
|
||||||
ensureBytes,
|
ensureBytes,
|
||||||
|
equalBytes,
|
||||||
|
Hex,
|
||||||
|
numberToBytesLE,
|
||||||
} from './abstract/utils.js';
|
} from './abstract/utils.js';
|
||||||
import * as htf from './abstract/hash-to-curve.js';
|
import { createHasher, htfBasicOpts, expand_message_xmd } from './abstract/hash-to-curve.js';
|
||||||
|
import { AffinePoint, Group } from './abstract/curve.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ed25519 Twisted Edwards curve with following addons:
|
* ed25519 Twisted Edwards curve with following addons:
|
||||||
@@ -33,6 +34,7 @@ const ED25519_SQRT_M1 = BigInt(
|
|||||||
const _0n = BigInt(0), _1n = BigInt(1), _2n = BigInt(2), _5n = BigInt(5);
|
const _0n = BigInt(0), _1n = BigInt(1), _2n = BigInt(2), _5n = BigInt(5);
|
||||||
// prettier-ignore
|
// prettier-ignore
|
||||||
const _10n = BigInt(10), _20n = BigInt(20), _40n = BigInt(40), _80n = BigInt(80);
|
const _10n = BigInt(10), _20n = BigInt(20), _40n = BigInt(40), _80n = BigInt(80);
|
||||||
|
|
||||||
function ed25519_pow_2_252_3(x: bigint) {
|
function ed25519_pow_2_252_3(x: bigint) {
|
||||||
const P = ED25519_P;
|
const P = ED25519_P;
|
||||||
const x2 = (x * x) % P;
|
const x2 = (x * x) % P;
|
||||||
@@ -50,6 +52,7 @@ function ed25519_pow_2_252_3(x: bigint) {
|
|||||||
// ^ To pow to (p+3)/8, multiply it by x.
|
// ^ To pow to (p+3)/8, multiply it by x.
|
||||||
return { pow_p_5_8, b2 };
|
return { pow_p_5_8, b2 };
|
||||||
}
|
}
|
||||||
|
|
||||||
function adjustScalarBytes(bytes: Uint8Array): Uint8Array {
|
function adjustScalarBytes(bytes: Uint8Array): Uint8Array {
|
||||||
// Section 5: For X25519, in order to decode 32 random bytes as an integer scalar,
|
// Section 5: For X25519, in order to decode 32 random bytes as an integer scalar,
|
||||||
// set the three least significant bits of the first byte
|
// set the three least significant bits of the first byte
|
||||||
@@ -60,6 +63,7 @@ function adjustScalarBytes(bytes: Uint8Array): Uint8Array {
|
|||||||
bytes[31] |= 64; // 0b0100_0000
|
bytes[31] |= 64; // 0b0100_0000
|
||||||
return bytes;
|
return bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
// sqrt(u/v)
|
// sqrt(u/v)
|
||||||
function uvRatio(u: bigint, v: bigint): { isValid: boolean; value: bigint } {
|
function uvRatio(u: bigint, v: bigint): { isValid: boolean; value: bigint } {
|
||||||
const P = ED25519_P;
|
const P = ED25519_P;
|
||||||
@@ -94,15 +98,15 @@ export const ED25519_TORSION_SUBGROUP = [
|
|||||||
|
|
||||||
const Fp = Field(ED25519_P, undefined, true);
|
const Fp = Field(ED25519_P, undefined, true);
|
||||||
|
|
||||||
const ED25519_DEF = {
|
const ed25519Defaults = {
|
||||||
// Param: a
|
// Param: a
|
||||||
a: BigInt(-1),
|
a: BigInt(-1), // Fp.create(-1) is proper; our way still works and is faster
|
||||||
// Equal to -121665/121666 over finite field.
|
// d is equal to -121665/121666 over finite field.
|
||||||
// Negative number is P - number, and division is invert(number, P)
|
// Negative number is P - number, and division is invert(number, P)
|
||||||
d: BigInt('37095705934669439343138083508754565189542113879843219016388785533085940283555'),
|
d: BigInt('37095705934669439343138083508754565189542113879843219016388785533085940283555'),
|
||||||
// Finite field 𝔽p over which we'll do calculations; 2n**255n - 19n
|
// Finite field 𝔽p over which we'll do calculations; 2n**255n - 19n
|
||||||
Fp,
|
Fp,
|
||||||
// Subgroup order: how many points ed25519 has
|
// Subgroup order: how many points curve has
|
||||||
// 2n**252n + 27742317777372353535851937790883648493n;
|
// 2n**252n + 27742317777372353535851937790883648493n;
|
||||||
n: BigInt('7237005577332262213973186563042994240857116359379907606001950938285454250989'),
|
n: BigInt('7237005577332262213973186563042994240857116359379907606001950938285454250989'),
|
||||||
// Cofactor
|
// Cofactor
|
||||||
@@ -119,7 +123,8 @@ const ED25519_DEF = {
|
|||||||
uvRatio,
|
uvRatio,
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
export const ed25519 = twistedEdwards(ED25519_DEF);
|
export const ed25519 = /* @__PURE__ */ twistedEdwards(ed25519Defaults);
|
||||||
|
|
||||||
function ed25519_domain(data: Uint8Array, ctx: Uint8Array, phflag: boolean) {
|
function ed25519_domain(data: Uint8Array, ctx: Uint8Array, phflag: boolean) {
|
||||||
if (ctx.length > 255) throw new Error('Context is too big');
|
if (ctx.length > 255) throw new Error('Context is too big');
|
||||||
return concatBytes(
|
return concatBytes(
|
||||||
@@ -129,14 +134,19 @@ function ed25519_domain(data: Uint8Array, ctx: Uint8Array, phflag: boolean) {
|
|||||||
data
|
data
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
export const ed25519ctx = twistedEdwards({ ...ED25519_DEF, domain: ed25519_domain });
|
|
||||||
export const ed25519ph = twistedEdwards({
|
export const ed25519ctx = /* @__PURE__ */ twistedEdwards({
|
||||||
...ED25519_DEF,
|
...ed25519Defaults,
|
||||||
domain: ed25519_domain,
|
domain: ed25519_domain,
|
||||||
preHash: sha512,
|
});
|
||||||
|
export const ed25519ph = /* @__PURE__ */ twistedEdwards({
|
||||||
|
...ed25519Defaults,
|
||||||
|
domain: ed25519_domain,
|
||||||
|
prehash: sha512,
|
||||||
});
|
});
|
||||||
|
|
||||||
export const x25519 = montgomery({
|
export const x25519 = /* @__PURE__ */ (() =>
|
||||||
|
montgomery({
|
||||||
P: ED25519_P,
|
P: ED25519_P,
|
||||||
a: BigInt(486662),
|
a: BigInt(486662),
|
||||||
montgomeryBits: 255, // n is 253 bits
|
montgomeryBits: 255, // n is 253 bits
|
||||||
@@ -150,7 +160,35 @@ export const x25519 = montgomery({
|
|||||||
},
|
},
|
||||||
adjustScalarBytes,
|
adjustScalarBytes,
|
||||||
randomBytes,
|
randomBytes,
|
||||||
});
|
}))();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts ed25519 public key to x25519 public key. Uses formula:
|
||||||
|
* * `(u, v) = ((1+y)/(1-y), sqrt(-486664)*u/x)`
|
||||||
|
* * `(x, y) = (sqrt(-486664)*u/v, (u-1)/(u+1))`
|
||||||
|
* @example
|
||||||
|
* const someonesPub = ed25519.getPublicKey(ed25519.utils.randomPrivateKey());
|
||||||
|
* const aPriv = x25519.utils.randomPrivateKey();
|
||||||
|
* x25519.getSharedSecret(aPriv, edwardsToMontgomeryPub(someonesPub))
|
||||||
|
*/
|
||||||
|
export function edwardsToMontgomeryPub(edwardsPub: Hex): Uint8Array {
|
||||||
|
const { y } = ed25519.ExtendedPoint.fromHex(edwardsPub);
|
||||||
|
const _1n = BigInt(1);
|
||||||
|
return Fp.toBytes(Fp.create((_1n + y) * Fp.inv(_1n - y)));
|
||||||
|
}
|
||||||
|
export const edwardsToMontgomery = edwardsToMontgomeryPub; // deprecated
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts ed25519 secret key to x25519 secret key.
|
||||||
|
* @example
|
||||||
|
* const someonesPub = x25519.getPublicKey(x25519.utils.randomPrivateKey());
|
||||||
|
* const aPriv = ed25519.utils.randomPrivateKey();
|
||||||
|
* x25519.getSharedSecret(edwardsToMontgomeryPriv(aPriv), someonesPub)
|
||||||
|
*/
|
||||||
|
export function edwardsToMontgomeryPriv(edwardsPriv: Uint8Array): Uint8Array {
|
||||||
|
const hashed = ed25519Defaults.hash(edwardsPriv.subarray(0, 32));
|
||||||
|
return ed25519Defaults.adjustScalarBytes(hashed).subarray(0, 32);
|
||||||
|
}
|
||||||
|
|
||||||
// Hash To Curve Elligator2 Map (NOTE: different from ristretto255 elligator)
|
// Hash To Curve Elligator2 Map (NOTE: different from ristretto255 elligator)
|
||||||
// NOTE: very important part is usage of FpSqrtEven for ELL2_C1_EDWARDS, since
|
// NOTE: very important part is usage of FpSqrtEven for ELL2_C1_EDWARDS, since
|
||||||
@@ -203,12 +241,13 @@ function map_to_curve_elligator2_curve25519(u: bigint) {
|
|||||||
let y = Fp.cmov(y2, y1, e3); // 36. y = CMOV(y2, y1, e3) # If e3, y = y1, else y = y2
|
let y = Fp.cmov(y2, y1, e3); // 36. y = CMOV(y2, y1, e3) # If e3, y = y1, else y = y2
|
||||||
let e4 = Fp.isOdd(y); // 37. e4 = sgn0(y) == 1 # Fix sign of y
|
let e4 = Fp.isOdd(y); // 37. e4 = sgn0(y) == 1 # Fix sign of y
|
||||||
y = Fp.cmov(y, Fp.neg(y), e3 !== e4); // 38. y = CMOV(y, -y, e3 XOR e4)
|
y = Fp.cmov(y, Fp.neg(y), e3 !== e4); // 38. y = CMOV(y, -y, e3 XOR e4)
|
||||||
return { xMn: xn, xMd: xd, yMn: y, yMd: 1n }; // 39. return (xn, xd, y, 1)
|
return { xMn: xn, xMd: xd, yMn: y, yMd: _1n }; // 39. return (xn, xd, y, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
const ELL2_C1_EDWARDS = FpSqrtEven(Fp, Fp.neg(BigInt(486664))); // sgn0(c1) MUST equal 0
|
const ELL2_C1_EDWARDS = FpSqrtEven(Fp, Fp.neg(BigInt(486664))); // sgn0(c1) MUST equal 0
|
||||||
function map_to_curve_elligator2_edwards25519(u: bigint) {
|
function map_to_curve_elligator2_edwards25519(u: bigint) {
|
||||||
const { xMn, xMd, yMn, yMd } = map_to_curve_elligator2_curve25519(u); // 1. (xMn, xMd, yMn, yMd) = map_to_curve_elligator2_curve25519(u)
|
const { xMn, xMd, yMn, yMd } = map_to_curve_elligator2_curve25519(u); // 1. (xMn, xMd, yMn, yMd) =
|
||||||
|
// map_to_curve_elligator2_curve25519(u)
|
||||||
let xn = Fp.mul(xMn, yMd); // 2. xn = xMn * yMd
|
let xn = Fp.mul(xMn, yMd); // 2. xn = xMn * yMd
|
||||||
xn = Fp.mul(xn, ELL2_C1_EDWARDS); // 3. xn = xn * c1
|
xn = Fp.mul(xn, ELL2_C1_EDWARDS); // 3. xn = xn * c1
|
||||||
let xd = Fp.mul(xMd, yMn); // 4. xd = xMd * yMn # xn / xd = c1 * xM / yM
|
let xd = Fp.mul(xMd, yMn); // 4. xd = xMd * yMn # xn / xd = c1 * xM / yM
|
||||||
@@ -224,7 +263,9 @@ function map_to_curve_elligator2_edwards25519(u: bigint) {
|
|||||||
const inv = Fp.invertBatch([xd, yd]); // batch division
|
const inv = Fp.invertBatch([xd, yd]); // batch division
|
||||||
return { x: Fp.mul(xn, inv[0]), y: Fp.mul(yn, inv[1]) }; // 13. return (xn, xd, yn, yd)
|
return { x: Fp.mul(xn, inv[0]), y: Fp.mul(yn, inv[1]) }; // 13. return (xn, xd, yn, yd)
|
||||||
}
|
}
|
||||||
const { hashToCurve, encodeToCurve } = htf.createHasher(
|
|
||||||
|
const htf = /* @__PURE__ */ (() =>
|
||||||
|
createHasher(
|
||||||
ed25519.ExtendedPoint,
|
ed25519.ExtendedPoint,
|
||||||
(scalars: bigint[]) => map_to_curve_elligator2_edwards25519(scalars[0]),
|
(scalars: bigint[]) => map_to_curve_elligator2_edwards25519(scalars[0]),
|
||||||
{
|
{
|
||||||
@@ -236,16 +277,16 @@ const { hashToCurve, encodeToCurve } = htf.createHasher(
|
|||||||
expand: 'xmd',
|
expand: 'xmd',
|
||||||
hash: sha512,
|
hash: sha512,
|
||||||
}
|
}
|
||||||
);
|
))();
|
||||||
export { hashToCurve, encodeToCurve };
|
export const hashToCurve = /* @__PURE__ */ (() => htf.hashToCurve)();
|
||||||
|
export const encodeToCurve = /* @__PURE__ */ (() => htf.encodeToCurve)();
|
||||||
|
|
||||||
function assertRstPoint(other: unknown) {
|
function assertRstPoint(other: unknown) {
|
||||||
if (!(other instanceof RistrettoPoint)) throw new Error('RistrettoPoint expected');
|
if (!(other instanceof RistPoint)) throw new Error('RistrettoPoint expected');
|
||||||
}
|
}
|
||||||
|
|
||||||
// √(-1) aka √(a) aka 2^((p-1)/4)
|
// √(-1) aka √(a) aka 2^((p-1)/4)
|
||||||
const SQRT_M1 = BigInt(
|
const SQRT_M1 = ED25519_SQRT_M1;
|
||||||
'19681161376707505956807079304988542015446066515923890162744021073123829784752'
|
|
||||||
);
|
|
||||||
// √(ad - 1)
|
// √(ad - 1)
|
||||||
const SQRT_AD_MINUS_ONE = BigInt(
|
const SQRT_AD_MINUS_ONE = BigInt(
|
||||||
'25063068953384623474111414158702152701244531502492656460079210482610430750235'
|
'25063068953384623474111414158702152701244531502492656460079210482610430750235'
|
||||||
@@ -302,27 +343,31 @@ function calcElligatorRistrettoMap(r0: bigint): ExtendedPoint {
|
|||||||
* but it should work in its own namespace: do not combine those two.
|
* but it should work in its own namespace: do not combine those two.
|
||||||
* https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-ristretto255-decaf448
|
* https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-ristretto255-decaf448
|
||||||
*/
|
*/
|
||||||
export class RistrettoPoint {
|
class RistPoint implements Group<RistPoint> {
|
||||||
static BASE = new RistrettoPoint(ed25519.ExtendedPoint.BASE);
|
static BASE: RistPoint;
|
||||||
static ZERO = new RistrettoPoint(ed25519.ExtendedPoint.ZERO);
|
static ZERO: RistPoint;
|
||||||
|
|
||||||
// Private property to discourage combining ExtendedPoint + RistrettoPoint
|
// Private property to discourage combining ExtendedPoint + RistrettoPoint
|
||||||
// Always use Ristretto encoding/decoding instead.
|
// Always use Ristretto encoding/decoding instead.
|
||||||
constructor(private readonly ep: ExtendedPoint) {}
|
constructor(private readonly ep: ExtendedPoint) {}
|
||||||
|
|
||||||
|
static fromAffine(ap: AffinePoint<bigint>) {
|
||||||
|
return new RistPoint(ed25519.ExtendedPoint.fromAffine(ap));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Takes uniform output of 64-bit hash function like sha512 and converts it to `RistrettoPoint`.
|
* Takes uniform output of 64-byte hash function like sha512 and converts it to `RistrettoPoint`.
|
||||||
* The hash-to-group operation applies Elligator twice and adds the results.
|
* 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.
|
* **Note:** this is one-way map, there is no conversion from point to hash.
|
||||||
* https://ristretto.group/formulas/elligator.html
|
* https://ristretto.group/formulas/elligator.html
|
||||||
* @param hex 64-bit output of a hash function
|
* @param hex 64-byte output of a hash function
|
||||||
*/
|
*/
|
||||||
static hashToCurve(hex: Hex): RistrettoPoint {
|
static hashToCurve(hex: Hex): RistPoint {
|
||||||
hex = ensureBytes('ristrettoHash', hex, 64);
|
hex = ensureBytes('ristrettoHash', hex, 64);
|
||||||
const r1 = bytes255ToNumberLE(hex.slice(0, 32));
|
const r1 = bytes255ToNumberLE(hex.slice(0, 32));
|
||||||
const R1 = calcElligatorRistrettoMap(r1);
|
const R1 = calcElligatorRistrettoMap(r1);
|
||||||
const r2 = bytes255ToNumberLE(hex.slice(32, 64));
|
const r2 = bytes255ToNumberLE(hex.slice(32, 64));
|
||||||
const R2 = calcElligatorRistrettoMap(r2);
|
const R2 = calcElligatorRistrettoMap(r2);
|
||||||
return new RistrettoPoint(R1.add(R2));
|
return new RistPoint(R1.add(R2));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -330,7 +375,7 @@ export class RistrettoPoint {
|
|||||||
* https://ristretto.group/formulas/decoding.html
|
* https://ristretto.group/formulas/decoding.html
|
||||||
* @param hex Ristretto-encoded 32 bytes. Not every 32-byte string is valid ristretto encoding
|
* @param hex Ristretto-encoded 32 bytes. Not every 32-byte string is valid ristretto encoding
|
||||||
*/
|
*/
|
||||||
static fromHex(hex: Hex): RistrettoPoint {
|
static fromHex(hex: Hex): RistPoint {
|
||||||
hex = ensureBytes('ristrettoHex', hex, 32);
|
hex = ensureBytes('ristrettoHex', hex, 32);
|
||||||
const { a, d } = ed25519.CURVE;
|
const { a, d } = ed25519.CURVE;
|
||||||
const P = ed25519.CURVE.Fp.ORDER;
|
const P = ed25519.CURVE.Fp.ORDER;
|
||||||
@@ -354,7 +399,7 @@ export class RistrettoPoint {
|
|||||||
const y = mod(u1 * Dy); // 11
|
const y = mod(u1 * Dy); // 11
|
||||||
const t = mod(x * y); // 12
|
const t = mod(x * y); // 12
|
||||||
if (!isValid || isNegativeLE(t, P) || y === _0n) throw new Error(emsg);
|
if (!isValid || isNegativeLE(t, P) || y === _0n) throw new Error(emsg);
|
||||||
return new RistrettoPoint(new ed25519.ExtendedPoint(x, y, _1n, t));
|
return new RistPoint(new ed25519.ExtendedPoint(x, y, _1n, t));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -398,10 +443,10 @@ export class RistrettoPoint {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Compare one point to another.
|
// Compare one point to another.
|
||||||
equals(other: RistrettoPoint): boolean {
|
equals(other: RistPoint): boolean {
|
||||||
assertRstPoint(other);
|
assertRstPoint(other);
|
||||||
const { ex: X1, ey: Y1 } = this.ep;
|
const { ex: X1, ey: Y1 } = this.ep;
|
||||||
const { ex: X2, ey: Y2 } = this.ep;
|
const { ex: X2, ey: Y2 } = other.ep;
|
||||||
const mod = ed25519.CURVE.Fp.create;
|
const mod = ed25519.CURVE.Fp.create;
|
||||||
// (x1 * y2 == y1 * x2) | (y1 * y2 == x1 * x2)
|
// (x1 * y2 == y1 * x2) | (y1 * y2 == x1 * x2)
|
||||||
const one = mod(X1 * Y2) === mod(Y1 * X2);
|
const one = mod(X1 * Y2) === mod(Y1 * X2);
|
||||||
@@ -409,21 +454,44 @@ export class RistrettoPoint {
|
|||||||
return one || two;
|
return one || two;
|
||||||
}
|
}
|
||||||
|
|
||||||
add(other: RistrettoPoint): RistrettoPoint {
|
add(other: RistPoint): RistPoint {
|
||||||
assertRstPoint(other);
|
assertRstPoint(other);
|
||||||
return new RistrettoPoint(this.ep.add(other.ep));
|
return new RistPoint(this.ep.add(other.ep));
|
||||||
}
|
}
|
||||||
|
|
||||||
subtract(other: RistrettoPoint): RistrettoPoint {
|
subtract(other: RistPoint): RistPoint {
|
||||||
assertRstPoint(other);
|
assertRstPoint(other);
|
||||||
return new RistrettoPoint(this.ep.subtract(other.ep));
|
return new RistPoint(this.ep.subtract(other.ep));
|
||||||
}
|
}
|
||||||
|
|
||||||
multiply(scalar: bigint): RistrettoPoint {
|
multiply(scalar: bigint): RistPoint {
|
||||||
return new RistrettoPoint(this.ep.multiply(scalar));
|
return new RistPoint(this.ep.multiply(scalar));
|
||||||
}
|
}
|
||||||
|
|
||||||
multiplyUnsafe(scalar: bigint): RistrettoPoint {
|
multiplyUnsafe(scalar: bigint): RistPoint {
|
||||||
return new RistrettoPoint(this.ep.multiplyUnsafe(scalar));
|
return new RistPoint(this.ep.multiplyUnsafe(scalar));
|
||||||
|
}
|
||||||
|
|
||||||
|
double(): RistPoint {
|
||||||
|
return new RistPoint(this.ep.double());
|
||||||
|
}
|
||||||
|
|
||||||
|
negate(): RistPoint {
|
||||||
|
return new RistPoint(this.ep.negate());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
export const RistrettoPoint = /* @__PURE__ */ (() => {
|
||||||
|
if (!RistPoint.BASE) RistPoint.BASE = new RistPoint(ed25519.ExtendedPoint.BASE);
|
||||||
|
if (!RistPoint.ZERO) RistPoint.ZERO = new RistPoint(ed25519.ExtendedPoint.ZERO);
|
||||||
|
return RistPoint;
|
||||||
|
})();
|
||||||
|
|
||||||
|
// Hashing to ristretto255. https://www.rfc-editor.org/rfc/rfc9380#appendix-B
|
||||||
|
export const hashToRistretto255 = (msg: Uint8Array, options: htfBasicOpts) => {
|
||||||
|
const d = options.DST;
|
||||||
|
const DST = typeof d === 'string' ? utf8ToBytes(d) : d;
|
||||||
|
const uniform_bytes = expand_message_xmd(msg, DST, 64, sha512);
|
||||||
|
const P = RistPoint.hashToCurve(uniform_bytes);
|
||||||
|
return P;
|
||||||
|
};
|
||||||
|
export const hash_to_ristretto255 = hashToRistretto255; // legacy
|
||||||
|
|||||||
344
src/ed448.ts
344
src/ed448.ts
@@ -1,14 +1,25 @@
|
|||||||
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
||||||
import { shake256 } from '@noble/hashes/sha3';
|
import { shake256 } from '@noble/hashes/sha3';
|
||||||
import { concatBytes, randomBytes, utf8ToBytes, wrapConstructor } from '@noble/hashes/utils';
|
import { concatBytes, randomBytes, utf8ToBytes, wrapConstructor } from '@noble/hashes/utils';
|
||||||
import { twistedEdwards } from './abstract/edwards.js';
|
import { ExtPointType, twistedEdwards } from './abstract/edwards.js';
|
||||||
import { mod, pow2, Fp as Field } from './abstract/modular.js';
|
import { mod, pow2, Field, isNegativeLE } from './abstract/modular.js';
|
||||||
import { montgomery } from './abstract/montgomery.js';
|
import { montgomery } from './abstract/montgomery.js';
|
||||||
import * as htf from './abstract/hash-to-curve.js';
|
import { createHasher, htfBasicOpts, expand_message_xof } from './abstract/hash-to-curve.js';
|
||||||
|
import {
|
||||||
|
bytesToHex,
|
||||||
|
bytesToNumberLE,
|
||||||
|
ensureBytes,
|
||||||
|
equalBytes,
|
||||||
|
Hex,
|
||||||
|
numberToBytesLE,
|
||||||
|
} from './abstract/utils.js';
|
||||||
|
import { AffinePoint, Group } from './abstract/curve.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Edwards448 (not Ed448-Goldilocks) curve with following addons:
|
* Edwards448 (not Ed448-Goldilocks) curve with following addons:
|
||||||
* * X448 ECDH
|
* - X448 ECDH
|
||||||
|
* - Decaf cofactor elimination
|
||||||
|
* - Elligator hash-to-group / point indistinguishability
|
||||||
* Conforms to RFC 8032 https://www.rfc-editor.org/rfc/rfc8032.html#section-5.2
|
* Conforms to RFC 8032 https://www.rfc-editor.org/rfc/rfc8032.html#section-5.2
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -18,15 +29,16 @@ const ed448P = BigInt(
|
|||||||
'726838724295606890549323807888004534353641360687318060281490199180612328166730772686396383698676545930088884461843637361053498018365439'
|
'726838724295606890549323807888004534353641360687318060281490199180612328166730772686396383698676545930088884461843637361053498018365439'
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// prettier-ignore
|
||||||
|
const _1n = BigInt(1), _2n = BigInt(2), _3n = BigInt(3), _4n = BigInt(4), _11n = BigInt(11);
|
||||||
|
// prettier-ignore
|
||||||
|
const _22n = BigInt(22), _44n = BigInt(44), _88n = BigInt(88), _223n = BigInt(223);
|
||||||
|
|
||||||
// powPminus3div4 calculates z = x^k mod p, where k = (p-3)/4.
|
// powPminus3div4 calculates z = x^k mod p, where k = (p-3)/4.
|
||||||
// Used for efficient square root calculation.
|
// Used for efficient square root calculation.
|
||||||
// ((P-3)/4).toString(2) would produce bits [223x 1, 0, 222x 1]
|
// ((P-3)/4).toString(2) would produce bits [223x 1, 0, 222x 1]
|
||||||
function ed448_pow_Pminus3div4(x: bigint): bigint {
|
function ed448_pow_Pminus3div4(x: bigint): bigint {
|
||||||
const P = ed448P;
|
const P = ed448P;
|
||||||
// prettier-ignore
|
|
||||||
const _1n = BigInt(1), _2n = BigInt(2), _3n = BigInt(3), _11n = BigInt(11);
|
|
||||||
// prettier-ignore
|
|
||||||
const _22n = BigInt(22), _44n = BigInt(44), _88n = BigInt(88), _223n = BigInt(223);
|
|
||||||
const b2 = (x * x * x) % P;
|
const b2 = (x * x * x) % P;
|
||||||
const b3 = (b2 * b2 * x) % P;
|
const b3 = (b2 * b2 * x) % P;
|
||||||
const b6 = (pow2(b3, _3n, P) * b3) % P;
|
const b6 = (pow2(b3, _3n, P) * b3) % P;
|
||||||
@@ -53,6 +65,28 @@ function adjustScalarBytes(bytes: Uint8Array): Uint8Array {
|
|||||||
return bytes;
|
return bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Constant-time ratio of u to v. Allows to combine inversion and square root u/√v.
|
||||||
|
// Uses algo from RFC8032 5.1.3.
|
||||||
|
function uvRatio(u: bigint, v: bigint): { isValid: boolean; value: bigint } {
|
||||||
|
const P = ed448P;
|
||||||
|
// https://www.rfc-editor.org/rfc/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:
|
||||||
|
// x = (u/v)^((p+1)/4) = u³v(u⁵v³)^((p-3)/4) (mod p)
|
||||||
|
const u2v = mod(u * u * v, P); // u²v
|
||||||
|
const u3v = mod(u2v * u, P); // u³v
|
||||||
|
const u5v3 = mod(u3v * u2v * v, P); // u⁵v³
|
||||||
|
const root = ed448_pow_Pminus3div4(u5v3);
|
||||||
|
const x = mod(u3v * root, P);
|
||||||
|
// Verify that root is exists
|
||||||
|
const x2 = mod(x * x, P); // x²
|
||||||
|
// If vx² = 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 };
|
||||||
|
}
|
||||||
|
|
||||||
const Fp = Field(ed448P, 456, true);
|
const Fp = Field(ed448P, 456, true);
|
||||||
|
|
||||||
const ED448_DEF = {
|
const ED448_DEF = {
|
||||||
@@ -69,6 +103,7 @@ const ED448_DEF = {
|
|||||||
n: BigInt(
|
n: BigInt(
|
||||||
'181709681073901722637330951972001133588410340171829515070372549795146003961539585716195755291692375963310293709091662304773755859649779'
|
'181709681073901722637330951972001133588410340171829515070372549795146003961539585716195755291692375963310293709091662304773755859649779'
|
||||||
),
|
),
|
||||||
|
// RFC 7748 has 56-byte keys, RFC 8032 has 57-byte keys
|
||||||
nBitLength: 456,
|
nBitLength: 456,
|
||||||
// Cofactor
|
// Cofactor
|
||||||
h: BigInt(4),
|
h: BigInt(4),
|
||||||
@@ -93,38 +128,19 @@ const ED448_DEF = {
|
|||||||
data
|
data
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
uvRatio,
|
||||||
// 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:
|
|
||||||
// x = (u/v)^((p+1)/4) = u³v(u⁵v³)^((p-3)/4) (mod p)
|
|
||||||
const u2v = mod(u * u * v, P); // u²v
|
|
||||||
const u3v = mod(u2v * u, P); // u³v
|
|
||||||
const u5v3 = mod(u3v * u2v * v, P); // u⁵v³
|
|
||||||
const root = ed448_pow_Pminus3div4(u5v3);
|
|
||||||
const x = mod(u3v * root, P);
|
|
||||||
// Verify that root is exists
|
|
||||||
const x2 = mod(x * x, P); // x²
|
|
||||||
// If vx² = 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;
|
} as const;
|
||||||
|
|
||||||
export const ed448 = twistedEdwards(ED448_DEF);
|
export const ed448 = /* @__PURE__ */ twistedEdwards(ED448_DEF);
|
||||||
// NOTE: there is no ed448ctx, since ed448 supports ctx by default
|
// NOTE: there is no ed448ctx, since ed448 supports ctx by default
|
||||||
export const ed448ph = twistedEdwards({ ...ED448_DEF, preHash: shake256_64 });
|
export const ed448ph = /* @__PURE__ */ twistedEdwards({ ...ED448_DEF, prehash: shake256_64 });
|
||||||
|
|
||||||
export const x448 = montgomery({
|
export const x448 = /* @__PURE__ */ (() =>
|
||||||
|
montgomery({
|
||||||
a: BigInt(156326),
|
a: BigInt(156326),
|
||||||
|
// RFC 7748 has 56-byte keys, RFC 8032 has 57-byte keys
|
||||||
montgomeryBits: 448,
|
montgomeryBits: 448,
|
||||||
nByteLength: 57,
|
nByteLength: 56,
|
||||||
P: ed448P,
|
P: ed448P,
|
||||||
Gu: BigInt(5),
|
Gu: BigInt(5),
|
||||||
powPminus2: (x: bigint): bigint => {
|
powPminus2: (x: bigint): bigint => {
|
||||||
@@ -135,25 +151,29 @@ export const x448 = montgomery({
|
|||||||
},
|
},
|
||||||
adjustScalarBytes,
|
adjustScalarBytes,
|
||||||
randomBytes,
|
randomBytes,
|
||||||
// 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),
|
* Converts edwards448 public key to x448 public key. Uses formula:
|
||||||
// -(u^5 - 2*u^3 - 4*u*v^2 + u)/
|
* * `(u, v) = ((y-1)/(y+1), sqrt(156324)*u/x)`
|
||||||
// (u^5 - 2*u^2*v^2 - 2*u^3 - 2*v^2 + u))
|
* * `(x, y) = (sqrt(156324)*u/v, (1+u)/(1-u))`
|
||||||
// xyToU: (p: PointType) => {
|
* @example
|
||||||
// const P = ed448P;
|
* const aPub = ed448.getPublicKey(utils.randomPrivateKey());
|
||||||
// const { x, y } = p;
|
* x448.getSharedSecret(edwardsToMontgomery(aPub), edwardsToMontgomery(someonesPub))
|
||||||
// if (x === _0n) throw new Error(`Point with x=0 doesn't have mapping`);
|
*/
|
||||||
// const invX = invert(x * x, P); // x^2
|
export function edwardsToMontgomeryPub(edwardsPub: string | Uint8Array): Uint8Array {
|
||||||
// const u = mod(y * y * invX, P); // (y^2/x^2)
|
const { y } = ed448.ExtendedPoint.fromHex(edwardsPub);
|
||||||
// return numberToBytesLE(u, 56);
|
const _1n = BigInt(1);
|
||||||
// },
|
return Fp.toBytes(Fp.create((y - _1n) * Fp.inv(y + _1n)));
|
||||||
});
|
}
|
||||||
|
|
||||||
|
export const edwardsToMontgomery = edwardsToMontgomeryPub; // deprecated
|
||||||
|
// TODO: add edwardsToMontgomeryPriv, similar to ed25519 version
|
||||||
|
|
||||||
// Hash To Curve Elligator2 Map
|
// Hash To Curve Elligator2 Map
|
||||||
const ELL2_C1 = (Fp.ORDER - BigInt(3)) / BigInt(4); // 1. c1 = (q - 3) / 4 # Integer arithmetic
|
const ELL2_C1 = (Fp.ORDER - BigInt(3)) / BigInt(4); // 1. c1 = (q - 3) / 4 # Integer arithmetic
|
||||||
const ELL2_J = BigInt(156326);
|
const ELL2_J = BigInt(156326);
|
||||||
|
|
||||||
function map_to_curve_elligator2_curve448(u: bigint) {
|
function map_to_curve_elligator2_curve448(u: bigint) {
|
||||||
let tv1 = Fp.sqr(u); // 1. tv1 = u^2
|
let tv1 = Fp.sqr(u); // 1. tv1 = u^2
|
||||||
let e1 = Fp.eql(tv1, Fp.ONE); // 2. e1 = tv1 == 1
|
let e1 = Fp.eql(tv1, Fp.ONE); // 2. e1 = tv1 == 1
|
||||||
@@ -183,6 +203,7 @@ function map_to_curve_elligator2_curve448(u: bigint) {
|
|||||||
y = Fp.cmov(y, Fp.neg(y), e2 !== e3); // 26. y = CMOV(y, -y, e2 XOR e3)
|
y = Fp.cmov(y, Fp.neg(y), e2 !== e3); // 26. y = CMOV(y, -y, e2 XOR e3)
|
||||||
return { xn, xd, yn: y, yd: Fp.ONE }; // 27. return (xn, xd, y, 1)
|
return { xn, xd, yn: y, yd: Fp.ONE }; // 27. return (xn, xd, y, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
function map_to_curve_elligator2_edwards448(u: bigint) {
|
function map_to_curve_elligator2_edwards448(u: bigint) {
|
||||||
let { xn, xd, yn, yd } = map_to_curve_elligator2_curve448(u); // 1. (xn, xd, yn, yd) = map_to_curve_elligator2_curve448(u)
|
let { xn, xd, yn, yd } = map_to_curve_elligator2_curve448(u); // 1. (xn, xd, yn, yd) = map_to_curve_elligator2_curve448(u)
|
||||||
let xn2 = Fp.sqr(xn); // 2. xn2 = xn^2
|
let xn2 = Fp.sqr(xn); // 2. xn2 = xn^2
|
||||||
@@ -195,10 +216,10 @@ function map_to_curve_elligator2_edwards448(u: bigint) {
|
|||||||
xEn = Fp.mul(xEn, xd2); // 9. xEn = xEn * xd2
|
xEn = Fp.mul(xEn, xd2); // 9. xEn = xEn * xd2
|
||||||
xEn = Fp.mul(xEn, yd); // 10. xEn = xEn * yd
|
xEn = Fp.mul(xEn, yd); // 10. xEn = xEn * yd
|
||||||
xEn = Fp.mul(xEn, yn); // 11. xEn = xEn * yn
|
xEn = Fp.mul(xEn, yn); // 11. xEn = xEn * yn
|
||||||
xEn = Fp.mul(xEn, 4n); // 12. xEn = xEn * 4
|
xEn = Fp.mul(xEn, _4n); // 12. xEn = xEn * 4
|
||||||
tv2 = Fp.mul(tv2, xn2); // 13. tv2 = tv2 * xn2
|
tv2 = Fp.mul(tv2, xn2); // 13. tv2 = tv2 * xn2
|
||||||
tv2 = Fp.mul(tv2, yd2); // 14. tv2 = tv2 * yd2
|
tv2 = Fp.mul(tv2, yd2); // 14. tv2 = tv2 * yd2
|
||||||
let tv3 = Fp.mul(yn2, 4n); // 15. tv3 = 4 * yn2
|
let tv3 = Fp.mul(yn2, _4n); // 15. tv3 = 4 * yn2
|
||||||
let tv1 = Fp.add(tv3, yd2); // 16. tv1 = tv3 + yd2
|
let tv1 = Fp.add(tv3, yd2); // 16. tv1 = tv3 + yd2
|
||||||
tv1 = Fp.mul(tv1, xd4); // 17. tv1 = tv1 * xd4
|
tv1 = Fp.mul(tv1, xd4); // 17. tv1 = tv1 * xd4
|
||||||
let xEd = Fp.add(tv1, tv2); // 18. xEd = tv1 + tv2
|
let xEd = Fp.add(tv1, tv2); // 18. xEd = tv1 + tv2
|
||||||
@@ -226,7 +247,8 @@ function map_to_curve_elligator2_edwards448(u: bigint) {
|
|||||||
return { x: Fp.mul(xEn, inv[0]), y: Fp.mul(yEn, inv[1]) }; // 38. return (xEn, xEd, yEn, yEd)
|
return { x: Fp.mul(xEn, inv[0]), y: Fp.mul(yEn, inv[1]) }; // 38. return (xEn, xEd, yEn, yEd)
|
||||||
}
|
}
|
||||||
|
|
||||||
const { hashToCurve, encodeToCurve } = htf.createHasher(
|
const htf = /* @__PURE__ */ (() =>
|
||||||
|
createHasher(
|
||||||
ed448.ExtendedPoint,
|
ed448.ExtendedPoint,
|
||||||
(scalars: bigint[]) => map_to_curve_elligator2_edwards448(scalars[0]),
|
(scalars: bigint[]) => map_to_curve_elligator2_edwards448(scalars[0]),
|
||||||
{
|
{
|
||||||
@@ -238,5 +260,221 @@ const { hashToCurve, encodeToCurve } = htf.createHasher(
|
|||||||
expand: 'xof',
|
expand: 'xof',
|
||||||
hash: shake256,
|
hash: shake256,
|
||||||
}
|
}
|
||||||
|
))();
|
||||||
|
export const hashToCurve = /* @__PURE__ */ (() => htf.hashToCurve)();
|
||||||
|
export const encodeToCurve = /* @__PURE__ */ (() => htf.encodeToCurve)();
|
||||||
|
|
||||||
|
function assertDcfPoint(other: unknown) {
|
||||||
|
if (!(other instanceof DcfPoint)) throw new Error('DecafPoint expected');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1-d
|
||||||
|
const ONE_MINUS_D = BigInt('39082');
|
||||||
|
// 1-2d
|
||||||
|
const ONE_MINUS_TWO_D = BigInt('78163');
|
||||||
|
// √(-d)
|
||||||
|
const SQRT_MINUS_D = BigInt(
|
||||||
|
'98944233647732219769177004876929019128417576295529901074099889598043702116001257856802131563896515373927712232092845883226922417596214'
|
||||||
);
|
);
|
||||||
export { hashToCurve, encodeToCurve };
|
// 1 / √(-d)
|
||||||
|
const INVSQRT_MINUS_D = BigInt(
|
||||||
|
'315019913931389607337177038330951043522456072897266928557328499619017160722351061360252776265186336876723201881398623946864393857820716'
|
||||||
|
);
|
||||||
|
// Calculates 1/√(number)
|
||||||
|
const invertSqrt = (number: bigint) => uvRatio(_1n, number);
|
||||||
|
|
||||||
|
const MAX_448B = BigInt(
|
||||||
|
'0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
|
||||||
|
);
|
||||||
|
const bytes448ToNumberLE = (bytes: Uint8Array) =>
|
||||||
|
ed448.CURVE.Fp.create(bytesToNumberLE(bytes) & MAX_448B);
|
||||||
|
|
||||||
|
type ExtendedPoint = ExtPointType;
|
||||||
|
|
||||||
|
// Computes Elligator map for Decaf
|
||||||
|
// https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-ristretto255-decaf448-07#name-element-derivation-2
|
||||||
|
function calcElligatorDecafMap(r0: bigint): ExtendedPoint {
|
||||||
|
const { d } = ed448.CURVE;
|
||||||
|
const P = ed448.CURVE.Fp.ORDER;
|
||||||
|
const mod = ed448.CURVE.Fp.create;
|
||||||
|
|
||||||
|
const r = mod(-(r0 * r0)); // 1
|
||||||
|
const u0 = mod(d * (r - _1n)); // 2
|
||||||
|
const u1 = mod((u0 + _1n) * (u0 - r)); // 3
|
||||||
|
|
||||||
|
const { isValid: was_square, value: v } = uvRatio(ONE_MINUS_TWO_D, mod((r + _1n) * u1)); // 4
|
||||||
|
|
||||||
|
let v_prime = v; // 5
|
||||||
|
if (!was_square) v_prime = mod(r0 * v);
|
||||||
|
|
||||||
|
let sgn = _1n; // 6
|
||||||
|
if (!was_square) sgn = mod(-_1n);
|
||||||
|
|
||||||
|
const s = mod(v_prime * (r + _1n)); // 7
|
||||||
|
let s_abs = s;
|
||||||
|
if (isNegativeLE(s, P)) s_abs = mod(-s);
|
||||||
|
|
||||||
|
const s2 = s * s;
|
||||||
|
const W0 = mod(s_abs * _2n); // 8
|
||||||
|
const W1 = mod(s2 + _1n); // 9
|
||||||
|
const W2 = mod(s2 - _1n); // 10
|
||||||
|
const W3 = mod(v_prime * s * (r - _1n) * ONE_MINUS_TWO_D + sgn); // 11
|
||||||
|
return new ed448.ExtendedPoint(mod(W0 * W3), mod(W2 * W1), mod(W1 * W3), mod(W0 * W2));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Each ed448/ExtendedPoint has 4 different equivalent points. This can be
|
||||||
|
* a source of bugs for protocols like ring signatures. Decaf was created to solve this.
|
||||||
|
* Decaf 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
|
||||||
|
*/
|
||||||
|
class DcfPoint implements Group<DcfPoint> {
|
||||||
|
static BASE: DcfPoint;
|
||||||
|
static ZERO: DcfPoint;
|
||||||
|
// Private property to discourage combining ExtendedPoint + DecafPoint
|
||||||
|
// Always use Decaf encoding/decoding instead.
|
||||||
|
constructor(private readonly ep: ExtendedPoint) {}
|
||||||
|
|
||||||
|
static fromAffine(ap: AffinePoint<bigint>) {
|
||||||
|
return new DcfPoint(ed448.ExtendedPoint.fromAffine(ap));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Takes uniform output of 112-byte hash function like shake256 and converts it to `DecafPoint`.
|
||||||
|
* 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://datatracker.ietf.org/doc/html/draft-irtf-cfrg-ristretto255-decaf448-07#name-element-derivation-2
|
||||||
|
* @param hex 112-byte output of a hash function
|
||||||
|
*/
|
||||||
|
static hashToCurve(hex: Hex): DcfPoint {
|
||||||
|
hex = ensureBytes('decafHash', hex, 112);
|
||||||
|
const r1 = bytes448ToNumberLE(hex.slice(0, 56));
|
||||||
|
const R1 = calcElligatorDecafMap(r1);
|
||||||
|
const r2 = bytes448ToNumberLE(hex.slice(56, 112));
|
||||||
|
const R2 = calcElligatorDecafMap(r2);
|
||||||
|
return new DcfPoint(R1.add(R2));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts decaf-encoded string to decaf point.
|
||||||
|
* https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-ristretto255-decaf448-07#name-decode-2
|
||||||
|
* @param hex Decaf-encoded 56 bytes. Not every 56-byte string is valid decaf encoding
|
||||||
|
*/
|
||||||
|
static fromHex(hex: Hex): DcfPoint {
|
||||||
|
hex = ensureBytes('decafHex', hex, 56);
|
||||||
|
const { d } = ed448.CURVE;
|
||||||
|
const P = ed448.CURVE.Fp.ORDER;
|
||||||
|
const mod = ed448.CURVE.Fp.create;
|
||||||
|
const emsg = 'DecafPoint.fromHex: the hex is not valid encoding of DecafPoint';
|
||||||
|
const s = bytes448ToNumberLE(hex);
|
||||||
|
|
||||||
|
// 1. Check that s_bytes is the canonical encoding of a field element, or else abort.
|
||||||
|
// 2. Check that s is non-negative, or else abort
|
||||||
|
if (!equalBytes(numberToBytesLE(s, 56), hex) || isNegativeLE(s, P)) throw new Error(emsg);
|
||||||
|
|
||||||
|
const s2 = mod(s * s); // 1
|
||||||
|
const u1 = mod(_1n + s2); // 2
|
||||||
|
const u1sq = mod(u1 * u1);
|
||||||
|
const u2 = mod(u1sq - _4n * d * s2); // 3
|
||||||
|
|
||||||
|
const { isValid, value: invsqrt } = invertSqrt(mod(u2 * u1sq)); // 4
|
||||||
|
|
||||||
|
let u3 = mod((s + s) * invsqrt * u1 * SQRT_MINUS_D); // 5
|
||||||
|
if (isNegativeLE(u3, P)) u3 = mod(-u3);
|
||||||
|
|
||||||
|
const x = mod(u3 * invsqrt * u2 * INVSQRT_MINUS_D); // 6
|
||||||
|
const y = mod((_1n - s2) * invsqrt * u1); // 7
|
||||||
|
const t = mod(x * y); // 8
|
||||||
|
|
||||||
|
if (!isValid) throw new Error(emsg);
|
||||||
|
return new DcfPoint(new ed448.ExtendedPoint(x, y, _1n, t));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encodes decaf point to Uint8Array.
|
||||||
|
* https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-ristretto255-decaf448-07#name-encode-2
|
||||||
|
*/
|
||||||
|
toRawBytes(): Uint8Array {
|
||||||
|
let { ex: x, ey: _y, ez: z, et: t } = this.ep;
|
||||||
|
const P = ed448.CURVE.Fp.ORDER;
|
||||||
|
const mod = ed448.CURVE.Fp.create;
|
||||||
|
|
||||||
|
const u1 = mod(mod(x + t) * mod(x - t)); // 1
|
||||||
|
const x2 = mod(x * x);
|
||||||
|
const { value: invsqrt } = invertSqrt(mod(u1 * ONE_MINUS_D * x2)); // 2
|
||||||
|
|
||||||
|
let ratio = mod(invsqrt * u1 * SQRT_MINUS_D); // 3
|
||||||
|
if (isNegativeLE(ratio, P)) ratio = mod(-ratio);
|
||||||
|
|
||||||
|
const u2 = mod(INVSQRT_MINUS_D * ratio * z - t); // 4
|
||||||
|
|
||||||
|
let s = mod(ONE_MINUS_D * invsqrt * x * u2); // 5
|
||||||
|
if (isNegativeLE(s, P)) s = mod(-s);
|
||||||
|
|
||||||
|
return numberToBytesLE(s, 56);
|
||||||
|
}
|
||||||
|
|
||||||
|
toHex(): string {
|
||||||
|
return bytesToHex(this.toRawBytes());
|
||||||
|
}
|
||||||
|
|
||||||
|
toString(): string {
|
||||||
|
return this.toHex();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compare one point to another.
|
||||||
|
// https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-ristretto255-decaf448-07#name-equals-2
|
||||||
|
equals(other: DcfPoint): boolean {
|
||||||
|
assertDcfPoint(other);
|
||||||
|
const { ex: X1, ey: Y1 } = this.ep;
|
||||||
|
const { ex: X2, ey: Y2 } = other.ep;
|
||||||
|
const mod = ed448.CURVE.Fp.create;
|
||||||
|
// (x1 * y2 == y1 * x2)
|
||||||
|
return mod(X1 * Y2) === mod(Y1 * X2);
|
||||||
|
}
|
||||||
|
|
||||||
|
add(other: DcfPoint): DcfPoint {
|
||||||
|
assertDcfPoint(other);
|
||||||
|
return new DcfPoint(this.ep.add(other.ep));
|
||||||
|
}
|
||||||
|
|
||||||
|
subtract(other: DcfPoint): DcfPoint {
|
||||||
|
assertDcfPoint(other);
|
||||||
|
return new DcfPoint(this.ep.subtract(other.ep));
|
||||||
|
}
|
||||||
|
|
||||||
|
multiply(scalar: bigint): DcfPoint {
|
||||||
|
return new DcfPoint(this.ep.multiply(scalar));
|
||||||
|
}
|
||||||
|
|
||||||
|
multiplyUnsafe(scalar: bigint): DcfPoint {
|
||||||
|
return new DcfPoint(this.ep.multiplyUnsafe(scalar));
|
||||||
|
}
|
||||||
|
|
||||||
|
double(): DcfPoint {
|
||||||
|
return new DcfPoint(this.ep.double());
|
||||||
|
}
|
||||||
|
|
||||||
|
negate(): DcfPoint {
|
||||||
|
return new DcfPoint(this.ep.negate());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const DecafPoint = /* @__PURE__ */ (() => {
|
||||||
|
// decaf448 base point is ed448 base x 2
|
||||||
|
// https://github.com/dalek-cryptography/curve25519-dalek/blob/59837c6ecff02b77b9d5ff84dbc239d0cf33ef90/vendor/ristretto.sage#L699
|
||||||
|
if (!DcfPoint.BASE) DcfPoint.BASE = new DcfPoint(ed448.ExtendedPoint.BASE).multiply(_2n);
|
||||||
|
if (!DcfPoint.ZERO) DcfPoint.ZERO = new DcfPoint(ed448.ExtendedPoint.ZERO);
|
||||||
|
return DcfPoint;
|
||||||
|
})();
|
||||||
|
|
||||||
|
// Hashing to decaf448. https://www.rfc-editor.org/rfc/rfc9380#appendix-C
|
||||||
|
export const hashToDecaf448 = (msg: Uint8Array, options: htfBasicOpts) => {
|
||||||
|
const d = options.DST;
|
||||||
|
const DST = typeof d === 'string' ? utf8ToBytes(d) : d;
|
||||||
|
const uniform_bytes = expand_message_xof(msg, DST, 112, 224, shake256);
|
||||||
|
const P = DcfPoint.hashToCurve(uniform_bytes);
|
||||||
|
return P;
|
||||||
|
};
|
||||||
|
export const hash_to_decaf448 = hashToDecaf448; // legacy
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { sha512 } from '@noble/hashes/sha512';
|
|||||||
import { concatBytes, randomBytes, utf8ToBytes } from '@noble/hashes/utils';
|
import { concatBytes, randomBytes, utf8ToBytes } from '@noble/hashes/utils';
|
||||||
import { twistedEdwards } from './abstract/edwards.js';
|
import { twistedEdwards } from './abstract/edwards.js';
|
||||||
import { blake2s } from '@noble/hashes/blake2s';
|
import { blake2s } from '@noble/hashes/blake2s';
|
||||||
import { Fp } from './abstract/modular.js';
|
import { Field } from './abstract/modular.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* jubjub Twisted Edwards curve.
|
* jubjub Twisted Edwards curve.
|
||||||
@@ -11,13 +11,13 @@ import { Fp } from './abstract/modular.js';
|
|||||||
* jubjub does not use EdDSA, so `hash`/sha512 params are passed because interface expects them.
|
* jubjub does not use EdDSA, so `hash`/sha512 params are passed because interface expects them.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export const jubjub = twistedEdwards({
|
export const jubjub = /* @__PURE__ */ twistedEdwards({
|
||||||
// Params: a, d
|
// Params: a, d
|
||||||
a: BigInt('0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000000'),
|
a: BigInt('0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000000'),
|
||||||
d: BigInt('0x2a9318e74bfa2b48f5fd9207e6bd7fd4292d7f6d37579d2601065fd6d6343eb1'),
|
d: BigInt('0x2a9318e74bfa2b48f5fd9207e6bd7fd4292d7f6d37579d2601065fd6d6343eb1'),
|
||||||
// Finite field 𝔽p over which we'll do calculations
|
// Finite field 𝔽p over which we'll do calculations
|
||||||
// Same value as bls12-381 Fr (not Fp)
|
// Same value as bls12-381 Fr (not Fp)
|
||||||
Fp: Fp(BigInt('0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001')),
|
Fp: Field(BigInt('0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001')),
|
||||||
// Subgroup order: how many points curve has
|
// Subgroup order: how many points curve has
|
||||||
n: BigInt('0xe7db4ea6533afa906673b0101343b00a6682093ccc81082d0970e5ed6f72cb7'),
|
n: BigInt('0xe7db4ea6533afa906673b0101343b00a6682093ccc81082d0970e5ed6f72cb7'),
|
||||||
// Cofactor
|
// Cofactor
|
||||||
|
|||||||
49
src/p256.ts
49
src/p256.ts
@@ -1,46 +1,41 @@
|
|||||||
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
||||||
import { createCurve } from './_shortw_utils.js';
|
import { createCurve } from './_shortw_utils.js';
|
||||||
import { sha256 } from '@noble/hashes/sha256';
|
import { sha256 } from '@noble/hashes/sha256';
|
||||||
import { Fp as Field } from './abstract/modular.js';
|
import { Field } from './abstract/modular.js';
|
||||||
import { mapToCurveSimpleSWU } from './abstract/weierstrass.js';
|
import { mapToCurveSimpleSWU } from './abstract/weierstrass.js';
|
||||||
import * as htf from './abstract/hash-to-curve.js';
|
import { createHasher } from './abstract/hash-to-curve.js';
|
||||||
|
|
||||||
// NIST secp256r1 aka P256
|
// NIST secp256r1 aka p256
|
||||||
// https://www.secg.org/sec2-v2.pdf, https://neuromancer.sk/std/nist/P-256
|
// https://www.secg.org/sec2-v2.pdf, https://neuromancer.sk/std/nist/P-256
|
||||||
|
|
||||||
// Field over which we'll do calculations; 2n**224n * (2n**32n-1n) + 2n**192n + 2n**96n-1n
|
|
||||||
const Fp = Field(BigInt('0xffffffff00000001000000000000000000000000ffffffffffffffffffffffff'));
|
const Fp = Field(BigInt('0xffffffff00000001000000000000000000000000ffffffffffffffffffffffff'));
|
||||||
const CURVE_A = Fp.create(BigInt('-3'));
|
const CURVE_A = Fp.create(BigInt('-3'));
|
||||||
const CURVE_B = BigInt('0x5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b');
|
const CURVE_B = BigInt('0x5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b');
|
||||||
|
|
||||||
const mapSWU = mapToCurveSimpleSWU(Fp, {
|
// prettier-ignore
|
||||||
A: CURVE_A,
|
export const p256 = createCurve({
|
||||||
B: CURVE_B,
|
a: CURVE_A, // Equation params: a, b
|
||||||
Z: Fp.create(BigInt('-10')),
|
|
||||||
});
|
|
||||||
|
|
||||||
export const P256 = createCurve(
|
|
||||||
{
|
|
||||||
// Params: a, b
|
|
||||||
a: CURVE_A,
|
|
||||||
b: CURVE_B,
|
b: CURVE_B,
|
||||||
Fp,
|
Fp, // Field: 2n**224n * (2n**32n-1n) + 2n**192n + 2n**96n-1n
|
||||||
// Curve order, total count of valid points in the field
|
// Curve order, total count of valid points in the field
|
||||||
n: BigInt('0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551'),
|
n: BigInt('0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551'),
|
||||||
// Base point (x, y) aka generator point
|
// Base (generator) point (x, y)
|
||||||
Gx: BigInt('0x6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296'),
|
Gx: BigInt('0x6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296'),
|
||||||
Gy: BigInt('0x4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5'),
|
Gy: BigInt('0x4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5'),
|
||||||
h: BigInt(1),
|
h: BigInt(1),
|
||||||
lowS: false,
|
lowS: false,
|
||||||
} as const,
|
} as const, sha256);
|
||||||
sha256
|
export const secp256r1 = p256;
|
||||||
);
|
|
||||||
export const secp256r1 = P256;
|
|
||||||
|
|
||||||
const { hashToCurve, encodeToCurve } = htf.createHasher(
|
const mapSWU = /* @__PURE__ */ (() =>
|
||||||
secp256r1.ProjectivePoint,
|
mapToCurveSimpleSWU(Fp, {
|
||||||
(scalars: bigint[]) => mapSWU(scalars[0]),
|
A: CURVE_A,
|
||||||
{
|
B: CURVE_B,
|
||||||
|
Z: Fp.create(BigInt('-10')),
|
||||||
|
}))();
|
||||||
|
|
||||||
|
const htf = /* @__PURE__ */ (() =>
|
||||||
|
createHasher(secp256r1.ProjectivePoint, (scalars: bigint[]) => mapSWU(scalars[0]), {
|
||||||
DST: 'P256_XMD:SHA-256_SSWU_RO_',
|
DST: 'P256_XMD:SHA-256_SSWU_RO_',
|
||||||
encodeDST: 'P256_XMD:SHA-256_SSWU_NU_',
|
encodeDST: 'P256_XMD:SHA-256_SSWU_NU_',
|
||||||
p: Fp.ORDER,
|
p: Fp.ORDER,
|
||||||
@@ -48,6 +43,6 @@ const { hashToCurve, encodeToCurve } = htf.createHasher(
|
|||||||
k: 128,
|
k: 128,
|
||||||
expand: 'xmd',
|
expand: 'xmd',
|
||||||
hash: sha256,
|
hash: sha256,
|
||||||
}
|
}))();
|
||||||
);
|
export const hashToCurve = /* @__PURE__ */ (() => htf.hashToCurve)();
|
||||||
export { hashToCurve, encodeToCurve };
|
export const encodeToCurve = /* @__PURE__ */ (() => htf.encodeToCurve)();
|
||||||
|
|||||||
49
src/p384.ts
49
src/p384.ts
@@ -1,14 +1,14 @@
|
|||||||
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
||||||
import { createCurve } from './_shortw_utils.js';
|
import { createCurve } from './_shortw_utils.js';
|
||||||
import { sha384 } from '@noble/hashes/sha512';
|
import { sha384 } from '@noble/hashes/sha512';
|
||||||
import { Fp as Field } from './abstract/modular.js';
|
import { Field } from './abstract/modular.js';
|
||||||
import { mapToCurveSimpleSWU } from './abstract/weierstrass.js';
|
import { mapToCurveSimpleSWU } from './abstract/weierstrass.js';
|
||||||
import * as htf from './abstract/hash-to-curve.js';
|
import { createHasher } from './abstract/hash-to-curve.js';
|
||||||
|
|
||||||
// NIST secp384r1 aka P384
|
// NIST secp384r1 aka p384
|
||||||
// https://www.secg.org/sec2-v2.pdf, https://neuromancer.sk/std/nist/P-384
|
// https://www.secg.org/sec2-v2.pdf, https://neuromancer.sk/std/nist/P-384
|
||||||
|
|
||||||
// Field over which we'll do calculations. 2n**384n - 2n**128n - 2n**96n + 2n**32n - 1n
|
// Field over which we'll do calculations.
|
||||||
// prettier-ignore
|
// prettier-ignore
|
||||||
const P = BigInt('0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000ffffffff');
|
const P = BigInt('0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000ffffffff');
|
||||||
const Fp = Field(P);
|
const Fp = Field(P);
|
||||||
@@ -16,35 +16,30 @@ const CURVE_A = Fp.create(BigInt('-3'));
|
|||||||
// prettier-ignore
|
// prettier-ignore
|
||||||
const CURVE_B = BigInt('0xb3312fa7e23ee7e4988e056be3f82d19181d9c6efe8141120314088f5013875ac656398d8a2ed19d2a85c8edd3ec2aef');
|
const CURVE_B = BigInt('0xb3312fa7e23ee7e4988e056be3f82d19181d9c6efe8141120314088f5013875ac656398d8a2ed19d2a85c8edd3ec2aef');
|
||||||
|
|
||||||
const mapSWU = mapToCurveSimpleSWU(Fp, {
|
|
||||||
A: CURVE_A,
|
|
||||||
B: CURVE_B,
|
|
||||||
Z: Fp.create(BigInt('-12')),
|
|
||||||
});
|
|
||||||
|
|
||||||
// prettier-ignore
|
// prettier-ignore
|
||||||
export const P384 = createCurve({
|
export const p384 = createCurve({
|
||||||
// Params: a, b
|
a: CURVE_A, // Equation params: a, b
|
||||||
a: CURVE_A,
|
|
||||||
b: CURVE_B,
|
b: CURVE_B,
|
||||||
// Field over which we'll do calculations. 2n**384n - 2n**128n - 2n**96n + 2n**32n - 1n
|
Fp, // Field: 2n**384n - 2n**128n - 2n**96n + 2n**32n - 1n
|
||||||
Fp,
|
|
||||||
// Curve order, total count of valid points in the field.
|
// Curve order, total count of valid points in the field.
|
||||||
n: BigInt('0xffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf581a0db248b0a77aecec196accc52973'),
|
n: BigInt('0xffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf581a0db248b0a77aecec196accc52973'),
|
||||||
// Base point (x, y) aka generator point
|
// Base (generator) point (x, y)
|
||||||
Gx: BigInt('0xaa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a385502f25dbf55296c3a545e3872760ab7'),
|
Gx: BigInt('0xaa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a385502f25dbf55296c3a545e3872760ab7'),
|
||||||
Gy: BigInt('0x3617de4a96262c6f5d9e98bf9292dc29f8f41dbd289a147ce9da3113b5f0b8c00a60b1ce1d7e819d7a431d7c90ea0e5f'),
|
Gy: BigInt('0x3617de4a96262c6f5d9e98bf9292dc29f8f41dbd289a147ce9da3113b5f0b8c00a60b1ce1d7e819d7a431d7c90ea0e5f'),
|
||||||
h: BigInt(1),
|
h: BigInt(1),
|
||||||
lowS: false,
|
lowS: false,
|
||||||
} as const,
|
} as const, sha384);
|
||||||
sha384
|
export const secp384r1 = p384;
|
||||||
);
|
|
||||||
export const secp384r1 = P384;
|
|
||||||
|
|
||||||
const { hashToCurve, encodeToCurve } = htf.createHasher(
|
const mapSWU = /* @__PURE__ */ (() =>
|
||||||
secp384r1.ProjectivePoint,
|
mapToCurveSimpleSWU(Fp, {
|
||||||
(scalars: bigint[]) => mapSWU(scalars[0]),
|
A: CURVE_A,
|
||||||
{
|
B: CURVE_B,
|
||||||
|
Z: Fp.create(BigInt('-12')),
|
||||||
|
}))();
|
||||||
|
|
||||||
|
const htf = /* @__PURE__ */ (() =>
|
||||||
|
createHasher(secp384r1.ProjectivePoint, (scalars: bigint[]) => mapSWU(scalars[0]), {
|
||||||
DST: 'P384_XMD:SHA-384_SSWU_RO_',
|
DST: 'P384_XMD:SHA-384_SSWU_RO_',
|
||||||
encodeDST: 'P384_XMD:SHA-384_SSWU_NU_',
|
encodeDST: 'P384_XMD:SHA-384_SSWU_NU_',
|
||||||
p: Fp.ORDER,
|
p: Fp.ORDER,
|
||||||
@@ -52,6 +47,6 @@ const { hashToCurve, encodeToCurve } = htf.createHasher(
|
|||||||
k: 192,
|
k: 192,
|
||||||
expand: 'xmd',
|
expand: 'xmd',
|
||||||
hash: sha384,
|
hash: sha384,
|
||||||
}
|
}))();
|
||||||
);
|
export const hashToCurve = /* @__PURE__ */ (() => htf.hashToCurve)();
|
||||||
export { hashToCurve, encodeToCurve };
|
export const encodeToCurve = /* @__PURE__ */ (() => htf.encodeToCurve)();
|
||||||
|
|||||||
75
src/p521.ts
75
src/p521.ts
@@ -1,50 +1,61 @@
|
|||||||
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
||||||
import { createCurve } from './_shortw_utils.js';
|
import { createCurve } from './_shortw_utils.js';
|
||||||
import { sha512 } from '@noble/hashes/sha512';
|
import { sha512 } from '@noble/hashes/sha512';
|
||||||
import { Fp as Field } from './abstract/modular.js';
|
import { Field } from './abstract/modular.js';
|
||||||
import { mapToCurveSimpleSWU } from './abstract/weierstrass.js';
|
import { mapToCurveSimpleSWU } from './abstract/weierstrass.js';
|
||||||
import * as htf from './abstract/hash-to-curve.js';
|
import { createHasher } from './abstract/hash-to-curve.js';
|
||||||
|
|
||||||
// NIST secp521r1 aka P521
|
// NIST secp521r1 aka p521
|
||||||
// Note that it's 521, which differs from 512 of its hash function.
|
// 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
|
// https://www.secg.org/sec2-v2.pdf, https://neuromancer.sk/std/nist/P-521
|
||||||
|
|
||||||
// Field over which we'll do calculations; 2n**521n - 1n
|
// Field over which we'll do calculations.
|
||||||
// prettier-ignore
|
// prettier-ignore
|
||||||
const P = BigInt('0x1ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff');
|
const P = BigInt('0x1ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff');
|
||||||
const Fp = Field(P);
|
const Fp = Field(P);
|
||||||
|
|
||||||
const CURVE_A = Fp.create(BigInt('-3'));
|
const CURVE = {
|
||||||
// prettier-ignore
|
a: Fp.create(BigInt('-3')),
|
||||||
const CURVE_B = BigInt('0x0051953eb9618e1c9a1f929a21a0b68540eea2da725b99b315f3b8b489918ef109e156193951ec7e937b1652c0bd3bb1bf073573df883d2c34f1ef451fd46b503f00');
|
b: BigInt(
|
||||||
|
'0x0051953eb9618e1c9a1f929a21a0b68540eea2da725b99b315f3b8b489918ef109e156193951ec7e937b1652c0bd3bb1bf073573df883d2c34f1ef451fd46b503f00'
|
||||||
const mapSWU = mapToCurveSimpleSWU(Fp, {
|
),
|
||||||
A: CURVE_A,
|
|
||||||
B: CURVE_B,
|
|
||||||
Z: Fp.create(BigInt('-4')),
|
|
||||||
});
|
|
||||||
|
|
||||||
// prettier-ignore
|
|
||||||
export const P521 = createCurve({
|
|
||||||
// Params: a, b
|
|
||||||
a: CURVE_A,
|
|
||||||
b: CURVE_B,
|
|
||||||
Fp,
|
Fp,
|
||||||
// Curve order, total count of valid points in the field
|
n: BigInt(
|
||||||
n: BigInt('0x01fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa51868783bf2f966b7fcc0148f709a5d03bb5c9b8899c47aebb6fb71e91386409'),
|
'0x01fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa51868783bf2f966b7fcc0148f709a5d03bb5c9b8899c47aebb6fb71e91386409'
|
||||||
// Base point (x, y) aka generator point
|
),
|
||||||
Gx: BigInt('0x00c6858e06b70404e9cd9e3ecb662395b4429c648139053fb521f828af606b4d3dbaa14b5e77efe75928fe1dc127a2ffa8de3348b3c1856a429bf97e7e31c2e5bd66'),
|
Gx: BigInt(
|
||||||
Gy: BigInt('0x011839296a789a3bc0045c8a5fb42c7d1bd998f54449579b446817afbd17273e662c97ee72995ef42640c550b9013fad0761353c7086a272c24088be94769fd16650'),
|
'0x00c6858e06b70404e9cd9e3ecb662395b4429c648139053fb521f828af606b4d3dbaa14b5e77efe75928fe1dc127a2ffa8de3348b3c1856a429bf97e7e31c2e5bd66'
|
||||||
|
),
|
||||||
|
Gy: BigInt(
|
||||||
|
'0x011839296a789a3bc0045c8a5fb42c7d1bd998f54449579b446817afbd17273e662c97ee72995ef42640c550b9013fad0761353c7086a272c24088be94769fd16650'
|
||||||
|
),
|
||||||
h: BigInt(1),
|
h: BigInt(1),
|
||||||
|
};
|
||||||
|
|
||||||
|
// prettier-ignore
|
||||||
|
export const p521 = createCurve({
|
||||||
|
a: CURVE.a, // Equation params: a, b
|
||||||
|
b: CURVE.b,
|
||||||
|
Fp, // Field: 2n**521n - 1n
|
||||||
|
// Curve order, total count of valid points in the field
|
||||||
|
n: CURVE.n,
|
||||||
|
Gx: CURVE.Gx, // Base point (x, y) aka generator point
|
||||||
|
Gy: CURVE.Gy,
|
||||||
|
h: CURVE.h,
|
||||||
lowS: false,
|
lowS: false,
|
||||||
allowedPrivateKeyLengths: [130, 131, 132] // P521 keys are variable-length. Normalize to 132b
|
allowedPrivateKeyLengths: [130, 131, 132] // P521 keys are variable-length. Normalize to 132b
|
||||||
} as const, sha512);
|
} as const, sha512);
|
||||||
export const secp521r1 = P521;
|
export const secp521r1 = p521;
|
||||||
|
|
||||||
const { hashToCurve, encodeToCurve } = htf.createHasher(
|
const mapSWU = /* @__PURE__ */ (() =>
|
||||||
secp521r1.ProjectivePoint,
|
mapToCurveSimpleSWU(Fp, {
|
||||||
(scalars: bigint[]) => mapSWU(scalars[0]),
|
A: CURVE.a,
|
||||||
{
|
B: CURVE.b,
|
||||||
|
Z: Fp.create(BigInt('-4')),
|
||||||
|
}))();
|
||||||
|
|
||||||
|
const htf = /* @__PURE__ */ (() =>
|
||||||
|
createHasher(secp521r1.ProjectivePoint, (scalars: bigint[]) => mapSWU(scalars[0]), {
|
||||||
DST: 'P521_XMD:SHA-512_SSWU_RO_',
|
DST: 'P521_XMD:SHA-512_SSWU_RO_',
|
||||||
encodeDST: 'P521_XMD:SHA-512_SSWU_NU_',
|
encodeDST: 'P521_XMD:SHA-512_SSWU_NU_',
|
||||||
p: Fp.ORDER,
|
p: Fp.ORDER,
|
||||||
@@ -52,6 +63,6 @@ const { hashToCurve, encodeToCurve } = htf.createHasher(
|
|||||||
k: 256,
|
k: 256,
|
||||||
expand: 'xmd',
|
expand: 'xmd',
|
||||||
hash: sha512,
|
hash: sha512,
|
||||||
}
|
}))();
|
||||||
);
|
export const hashToCurve = /* @__PURE__ */ (() => htf.hashToCurve)();
|
||||||
export { hashToCurve, encodeToCurve };
|
export const encodeToCurve = /* @__PURE__ */ (() => htf.encodeToCurve)();
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ export const q = BigInt('0x40000000000000000000000000000000224698fc0994a8dd8c46e
|
|||||||
export const pallas = weierstrass({
|
export const pallas = weierstrass({
|
||||||
a: BigInt(0),
|
a: BigInt(0),
|
||||||
b: BigInt(5),
|
b: BigInt(5),
|
||||||
Fp: mod.Fp(p),
|
Fp: mod.Field(p),
|
||||||
n: q,
|
n: q,
|
||||||
Gx: mod.mod(BigInt(-1), p),
|
Gx: mod.mod(BigInt(-1), p),
|
||||||
Gy: BigInt(2),
|
Gy: BigInt(2),
|
||||||
@@ -22,7 +22,7 @@ export const pallas = weierstrass({
|
|||||||
export const vesta = weierstrass({
|
export const vesta = weierstrass({
|
||||||
a: BigInt(0),
|
a: BigInt(0),
|
||||||
b: BigInt(5),
|
b: BigInt(5),
|
||||||
Fp: mod.Fp(q),
|
Fp: mod.Field(q),
|
||||||
n: p,
|
n: p,
|
||||||
Gx: mod.mod(BigInt(-1), q),
|
Gx: mod.mod(BigInt(-1), q),
|
||||||
Gy: BigInt(2),
|
Gy: BigInt(2),
|
||||||
|
|||||||
168
src/secp256k1.ts
168
src/secp256k1.ts
@@ -1,11 +1,11 @@
|
|||||||
/*! 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 { sha256 } from '@noble/hashes/sha256';
|
||||||
import { randomBytes } from '@noble/hashes/utils';
|
import { randomBytes } from '@noble/hashes/utils';
|
||||||
import { Fp as Field, mod, pow2 } from './abstract/modular.js';
|
import { Field, mod, pow2, FpIsSquare } from './abstract/modular.js';
|
||||||
import { ProjPointType as PointType, mapToCurveSimpleSWU } from './abstract/weierstrass.js';
|
import { ProjPointType as PointType, mapToCurveSimpleSWU } from './abstract/weierstrass.js';
|
||||||
import type { Hex, PrivKey } from './abstract/utils.js';
|
import type { Hex, PrivKey } from './abstract/utils.js';
|
||||||
import { bytesToNumberBE, concatBytes, ensureBytes, numberToBytesBE } from './abstract/utils.js';
|
import { bytesToNumberBE, concatBytes, ensureBytes, numberToBytesBE } from './abstract/utils.js';
|
||||||
import * as htf from './abstract/hash-to-curve.js';
|
import { createHasher, isogenyMap } from './abstract/hash-to-curve.js';
|
||||||
import { createCurve } from './_shortw_utils.js';
|
import { createCurve } from './_shortw_utils.js';
|
||||||
|
|
||||||
const secp256k1P = BigInt('0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f');
|
const secp256k1P = BigInt('0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f');
|
||||||
@@ -43,7 +43,6 @@ function sqrtMod(y: bigint): bigint {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const Fp = Field(secp256k1P, undefined, undefined, { sqrt: sqrtMod });
|
const Fp = Field(secp256k1P, undefined, undefined, { sqrt: sqrtMod });
|
||||||
type Fp = bigint;
|
|
||||||
|
|
||||||
export const secp256k1 = createCurve(
|
export const secp256k1 = createCurve(
|
||||||
{
|
{
|
||||||
@@ -115,12 +114,13 @@ const modN = (x: bigint) => mod(x, secp256k1N);
|
|||||||
const Point = secp256k1.ProjectivePoint;
|
const Point = secp256k1.ProjectivePoint;
|
||||||
const GmulAdd = (Q: PointType<bigint>, a: bigint, b: bigint) =>
|
const GmulAdd = (Q: PointType<bigint>, a: bigint, b: bigint) =>
|
||||||
Point.BASE.multiplyAndAddUnsafe(Q, a, b);
|
Point.BASE.multiplyAndAddUnsafe(Q, a, b);
|
||||||
|
|
||||||
// Calculate point, scalar and bytes
|
// Calculate point, scalar and bytes
|
||||||
function schnorrGetExtPubKey(priv: PrivKey) {
|
function schnorrGetExtPubKey(priv: PrivKey) {
|
||||||
const d = secp256k1.utils.normPrivateKeyToScalar(priv); // same method executed in fromPrivateKey
|
let d_ = secp256k1.utils.normPrivateKeyToScalar(priv); // same method executed in fromPrivateKey
|
||||||
const point = Point.fromPrivateKey(d); // P = d'⋅G; 0 < d' < n check is done inside
|
let p = Point.fromPrivateKey(d_); // P = d'⋅G; 0 < d' < n check is done inside
|
||||||
const scalar = point.hasEvenY() ? d : modN(-d); // d = d' if has_even_y(P), otherwise d = n-d'
|
const scalar = p.hasEvenY() ? d_ : modN(-d_);
|
||||||
return { point, scalar, bytes: pointToBytes(point) };
|
return { scalar: scalar, bytes: pointToBytes(p) };
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* lift_x from BIP340. Convert 32-byte x coordinate to elliptic curve point.
|
* lift_x from BIP340. Convert 32-byte x coordinate to elliptic curve point.
|
||||||
@@ -131,7 +131,7 @@ function lift_x(x: bigint): PointType<bigint> {
|
|||||||
const xx = modP(x * x);
|
const xx = modP(x * x);
|
||||||
const c = modP(xx * x + BigInt(7)); // Let c = x³ + 7 mod p.
|
const c = modP(xx * x + BigInt(7)); // Let c = x³ + 7 mod p.
|
||||||
let y = sqrtMod(c); // Let y = c^(p+1)/4 mod p.
|
let y = sqrtMod(c); // Let y = c^(p+1)/4 mod p.
|
||||||
if (y % 2n !== 0n) y = modP(-y); // Return the unique point P such that x(P) = x and
|
if (y % _2n !== _0n) y = modP(-y); // Return the unique point P such that x(P) = x and
|
||||||
const p = new Point(x, y, _1n); // y(P) = y if y mod 2 = 0 or y(P) = p-y otherwise.
|
const p = new Point(x, y, _1n); // y(P) = y if y mod 2 = 0 or y(P) = p-y otherwise.
|
||||||
p.assertValidity();
|
p.assertValidity();
|
||||||
return p;
|
return p;
|
||||||
@@ -166,10 +166,10 @@ function schnorrSign(
|
|||||||
const rand = taggedHash('BIP0340/nonce', t, px, m); // Let rand = hash/nonce(t || bytes(P) || m)
|
const rand = taggedHash('BIP0340/nonce', t, px, m); // Let rand = hash/nonce(t || bytes(P) || m)
|
||||||
const k_ = modN(bytesToNumberBE(rand)); // Let k' = int(rand) mod n
|
const k_ = modN(bytesToNumberBE(rand)); // Let k' = int(rand) mod n
|
||||||
if (k_ === _0n) throw new Error('sign failed: k is zero'); // Fail if k' = 0.
|
if (k_ === _0n) throw new Error('sign failed: k is zero'); // Fail if k' = 0.
|
||||||
const { point: R, bytes: rx, scalar: k } = schnorrGetExtPubKey(k_); // Let R = k'⋅G.
|
const { bytes: rx, scalar: k } = schnorrGetExtPubKey(k_); // Let R = k'⋅G.
|
||||||
const e = challenge(rx, px, m); // Let e = int(hash/challenge(bytes(R) || bytes(P) || m)) mod n.
|
const e = challenge(rx, px, m); // Let e = int(hash/challenge(bytes(R) || bytes(P) || m)) mod n.
|
||||||
const sig = new Uint8Array(64); // Let sig = bytes(R) || bytes((k + ed) mod n).
|
const sig = new Uint8Array(64); // Let sig = bytes(R) || bytes((k + ed) mod n).
|
||||||
sig.set(numTo32b(R.px), 0);
|
sig.set(rx, 0);
|
||||||
sig.set(numTo32b(modN(k + e * d)), 32);
|
sig.set(numTo32b(modN(k + e * d)), 32);
|
||||||
// If Verify(bytes(P), m, sig) (see below) returns failure, abort
|
// If Verify(bytes(P), m, sig) (see below) returns failure, abort
|
||||||
if (!schnorrVerify(sig, m, px)) throw new Error('sign: Invalid signature produced');
|
if (!schnorrVerify(sig, m, px)) throw new Error('sign: Invalid signature produced');
|
||||||
@@ -199,13 +199,12 @@ function schnorrVerify(signature: Hex, message: Hex, publicKey: Hex): boolean {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const schnorr = {
|
export const schnorr = /* @__PURE__ */ (() => ({
|
||||||
getPublicKey: schnorrGetPublicKey,
|
getPublicKey: schnorrGetPublicKey,
|
||||||
sign: schnorrSign,
|
sign: schnorrSign,
|
||||||
verify: schnorrVerify,
|
verify: schnorrVerify,
|
||||||
utils: {
|
utils: {
|
||||||
randomPrivateKey: secp256k1.utils.randomPrivateKey,
|
randomPrivateKey: secp256k1.utils.randomPrivateKey,
|
||||||
getExtendedPublicKey: schnorrGetExtPubKey,
|
|
||||||
lift_x,
|
lift_x,
|
||||||
pointToBytes,
|
pointToBytes,
|
||||||
numberToBytesBE,
|
numberToBytesBE,
|
||||||
@@ -213,9 +212,10 @@ export const schnorr = {
|
|||||||
taggedHash,
|
taggedHash,
|
||||||
mod,
|
mod,
|
||||||
},
|
},
|
||||||
};
|
}))();
|
||||||
|
|
||||||
const isoMap = htf.isogenyMap(
|
const isoMap = /* @__PURE__ */ (() =>
|
||||||
|
isogenyMap(
|
||||||
Fp,
|
Fp,
|
||||||
[
|
[
|
||||||
// xNum
|
// xNum
|
||||||
@@ -245,14 +245,16 @@ const isoMap = htf.isogenyMap(
|
|||||||
'0x6484aa716545ca2cf3a70c3fa8fe337e0a3d21162f0d6299a7bf8192bfd2a76f',
|
'0x6484aa716545ca2cf3a70c3fa8fe337e0a3d21162f0d6299a7bf8192bfd2a76f',
|
||||||
'0x0000000000000000000000000000000000000000000000000000000000000001', // LAST 1
|
'0x0000000000000000000000000000000000000000000000000000000000000001', // LAST 1
|
||||||
],
|
],
|
||||||
].map((i) => i.map((j) => BigInt(j))) as [Fp[], Fp[], Fp[], Fp[]]
|
].map((i) => i.map((j) => BigInt(j))) as [bigint[], bigint[], bigint[], bigint[]]
|
||||||
);
|
))();
|
||||||
const mapSWU = mapToCurveSimpleSWU(Fp, {
|
const mapSWU = /* @__PURE__ */ (() =>
|
||||||
|
mapToCurveSimpleSWU(Fp, {
|
||||||
A: BigInt('0x3f8731abdd661adca08a5558f0f5d272e953d363cb6f0e5d405447c01a444533'),
|
A: BigInt('0x3f8731abdd661adca08a5558f0f5d272e953d363cb6f0e5d405447c01a444533'),
|
||||||
B: BigInt('1771'),
|
B: BigInt('1771'),
|
||||||
Z: Fp.create(BigInt('-11')),
|
Z: Fp.create(BigInt('-11')),
|
||||||
});
|
}))();
|
||||||
export const { hashToCurve, encodeToCurve } = htf.createHasher(
|
const htf = /* @__PURE__ */ (() =>
|
||||||
|
createHasher(
|
||||||
secp256k1.ProjectivePoint,
|
secp256k1.ProjectivePoint,
|
||||||
(scalars: bigint[]) => {
|
(scalars: bigint[]) => {
|
||||||
const { x, y } = mapSWU(Fp.create(scalars[0]));
|
const { x, y } = mapSWU(Fp.create(scalars[0]));
|
||||||
@@ -267,4 +269,132 @@ export const { hashToCurve, encodeToCurve } = htf.createHasher(
|
|||||||
expand: 'xmd',
|
expand: 'xmd',
|
||||||
hash: sha256,
|
hash: sha256,
|
||||||
}
|
}
|
||||||
|
))();
|
||||||
|
export const hashToCurve = /* @__PURE__ */ (() => htf.hashToCurve)();
|
||||||
|
export const encodeToCurve = /* @__PURE__ */ (() => htf.encodeToCurve)();
|
||||||
|
|
||||||
|
// ElligatorSwift: Schnorr-like x-only ECDH with public keys indistinguishable
|
||||||
|
// from uniformly random bytes.
|
||||||
|
// https://github.com/bitcoin/bips/blob/master/bip-0324.mediawiki,
|
||||||
|
// https://github.com/bitcoin/bitcoin/blob/master/src/secp256k1/doc/ellswift.md
|
||||||
|
// SwiftEC: Shallue-van de Woestijne Indifferentiable Function to Elliptic Curves.
|
||||||
|
// https://eprint.iacr.org/2022/759.pdf
|
||||||
|
//
|
||||||
|
// Curve25519 & P-521 are incompatible with SwiftEC. Differences from SwiftEC:
|
||||||
|
// - undefined inputs are remapped
|
||||||
|
// - y-parity is encoded in u/t values
|
||||||
|
const MINUS_3_SQRT = Fp.sqrt(Fp.create(BigInt(-3)));
|
||||||
|
const _3n = BigInt(3);
|
||||||
|
const _4n = BigInt(4);
|
||||||
|
const _7n = BigInt(7);
|
||||||
|
const isSquare = FpIsSquare(Fp);
|
||||||
|
const isValidX = (x: bigint) => isSquare(Fp.add(Fp.mul(Fp.mul(x, x), x), _7n));
|
||||||
|
const trySqrt = (x: bigint): bigint | void => {
|
||||||
|
try {
|
||||||
|
return Fp.sqrt(x);
|
||||||
|
} catch (_e) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const elligatorSwift = /* @__PURE__ */ {
|
||||||
|
// (internal stuff, exported for tests only): decode(u, _inv(x, u)) = x
|
||||||
|
_inv: (x: bigint, u: bigint, ellCase: number): bigint | void => {
|
||||||
|
if (!Number.isSafeInteger(ellCase) || ellCase < 0 || ellCase > 7)
|
||||||
|
throw new Error(`elligatorSwift._inv: wrong case=${ellCase}`);
|
||||||
|
let v: bigint, s: bigint;
|
||||||
|
// Most rejections happens in 3 condition (in comments, ~33% each)
|
||||||
|
const u2 = Fp.mul(u, u); // u**2
|
||||||
|
const u3 = Fp.mul(u2, u); // u**3
|
||||||
|
if ((ellCase & 2) === 0) {
|
||||||
|
if (isValidX(Fp.sub(Fp.neg(x), u))) return; // [1 condition]
|
||||||
|
v = x;
|
||||||
|
s = Fp.div(Fp.neg(Fp.add(u3, _7n)), Fp.add(Fp.add(u2, Fp.mul(u, v)), Fp.mul(v, v))); // = -(u**3 + 7) / (u**2 + u*v + v**2)
|
||||||
|
} else {
|
||||||
|
s = Fp.sub(x, u); // x - u
|
||||||
|
if (Fp.is0(s)) return;
|
||||||
|
const t0 = Fp.add(u3, _7n); // (u**3 + 7)
|
||||||
|
const t1 = Fp.mul(Fp.mul(_3n, s), u2); // 3 * s * u**2
|
||||||
|
// r = (-s * (4 * (u**3 + 7) + 3 * s * u**2)).sqrt()
|
||||||
|
const r = trySqrt(Fp.mul(Fp.neg(s), Fp.add(Fp.mul(_4n, t0), t1)));
|
||||||
|
if (r === undefined) return; // [2 condition]
|
||||||
|
if (ellCase & 1 && Fp.is0(r)) return;
|
||||||
|
v = Fp.div(Fp.add(Fp.neg(u), Fp.div(r, s)), _2n); // v = (-u + r / s) / 2
|
||||||
|
}
|
||||||
|
const w = trySqrt(s);
|
||||||
|
if (w === undefined) return; // [3 condition]
|
||||||
|
const last = ellCase & 5; // ellCase = 0..8, last = 0,1,4,5
|
||||||
|
const t0 = last & 1 ? Fp.add(_1n, MINUS_3_SQRT) : Fp.sub(_1n, MINUS_3_SQRT);
|
||||||
|
const w0 = last === 0 || last === 5 ? Fp.neg(w) : w; // -w | w
|
||||||
|
// w0 * (u * t0 / 2 + v)
|
||||||
|
return Fp.mul(w0, Fp.add(Fp.div(Fp.mul(u, t0), _2n), v));
|
||||||
|
},
|
||||||
|
// Encode public key (point or x coordinate bigint) into 64-byte pseudorandom encoding
|
||||||
|
encode: (x: bigint | PointType<bigint>): Uint8Array => {
|
||||||
|
if (x instanceof secp256k1.ProjectivePoint) x = x.x;
|
||||||
|
if (typeof x !== 'bigint') {
|
||||||
|
throw new Error(
|
||||||
|
'elligatorSwift.encode: wrong public key. Should be Projective point or x coordinate (bigint)'
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
// 200k test cycles per keygen: avg=4 max=48
|
||||||
|
// seems too much, but same as for reference implementation
|
||||||
|
while (true) {
|
||||||
|
// random scalar 1..Fp.ORDER
|
||||||
|
const u = Fp.create(Fp.fromBytes(secp256k1.utils.randomPrivateKey()));
|
||||||
|
const ellCase = randomBytes(1)[0] & 7; // [0..8)
|
||||||
|
const t = elligatorSwift._inv(x, u, ellCase);
|
||||||
|
if (!t) continue;
|
||||||
|
return concatBytes(numberToBytesBE(u, 32), numberToBytesBE(t, 32));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// Decode elligatorSwift point to xonly
|
||||||
|
decode: (data: Hex): Uint8Array => {
|
||||||
|
const _data = ensureBytes('data', data, 64);
|
||||||
|
let u = Fp.create(Fp.fromBytes(_data.subarray(0, 32)));
|
||||||
|
let t = Fp.create(Fp.fromBytes(_data.subarray(32, 64)));
|
||||||
|
if (Fp.is0(u)) u = Fp.create(_1n);
|
||||||
|
if (Fp.is0(t)) t = Fp.create(_1n);
|
||||||
|
const u3 = Fp.mul(Fp.mul(u, u), u); // u**3
|
||||||
|
const u3plus7 = Fp.add(u3, _7n);
|
||||||
|
// u**3 + t**2 + 7 == 0 -> t = 2 * t
|
||||||
|
if (Fp.is0(Fp.add(u3plus7, Fp.mul(t, t)))) t = Fp.add(t, t);
|
||||||
|
// X = (u**3 + 7 - t**2) / (2 * t)
|
||||||
|
const x = Fp.div(Fp.sub(u3plus7, Fp.mul(t, t)), Fp.add(t, t));
|
||||||
|
// Y = (X + t) / (MINUS_3_SQRT * u);
|
||||||
|
const y = Fp.div(Fp.add(x, t), Fp.mul(MINUS_3_SQRT, u));
|
||||||
|
// try different cases
|
||||||
|
let res = Fp.add(u, Fp.mul(Fp.mul(y, y), _4n)); // u + 4 * Y ** 2,
|
||||||
|
if (isValidX(res)) return numberToBytesBE(res, 32);
|
||||||
|
res = Fp.div(Fp.sub(Fp.div(Fp.neg(x), y), u), _2n); // (-X / Y - u) / 2
|
||||||
|
if (isValidX(res)) return numberToBytesBE(res, 32);
|
||||||
|
res = Fp.div(Fp.sub(Fp.div(x, y), u), _2n); // (X / Y - u) / 2
|
||||||
|
if (isValidX(res)) return numberToBytesBE(res, 32);
|
||||||
|
throw new Error('elligatorSwift: cannot decode public key');
|
||||||
|
},
|
||||||
|
// Generate pair (public key, secret key)
|
||||||
|
keygen: () => {
|
||||||
|
const privateKey = secp256k1.utils.randomPrivateKey();
|
||||||
|
const publicKey = elligatorSwift.encode(Point.fromPrivateKey(privateKey));
|
||||||
|
return { privateKey, publicKey };
|
||||||
|
},
|
||||||
|
// Generates shared secret between a pub key and a priv key
|
||||||
|
getSharedSecret: (privateKeyA: Hex, publicKeyB: Hex) => {
|
||||||
|
const pub = elligatorSwift.decode(publicKeyB);
|
||||||
|
const priv = ensureBytes('privKey', privateKeyA, 32);
|
||||||
|
const point = lift_x(Fp.fromBytes(pub));
|
||||||
|
const d = bytesToNumberBE(priv);
|
||||||
|
return numberToBytesBE(point.multiply(d).x, 32);
|
||||||
|
},
|
||||||
|
// BIP324 shared secret
|
||||||
|
getSharedSecretBip324: (
|
||||||
|
privateKeyOurs: Hex,
|
||||||
|
publicKeyTheirs: Hex,
|
||||||
|
publicKeyOurs: Hex,
|
||||||
|
initiating: boolean
|
||||||
|
) => {
|
||||||
|
const ours = ensureBytes('publicKeyOurs', publicKeyOurs);
|
||||||
|
const theirs = ensureBytes('publicKeyTheirs', publicKeyTheirs);
|
||||||
|
const ecdhPoint = elligatorSwift.getSharedSecret(privateKeyOurs, theirs);
|
||||||
|
const pubs = initiating ? [ours, theirs] : [theirs, ours];
|
||||||
|
return taggedHash('bip324_ellswift_xonly_ecdh', ...pubs, ecdhPoint);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|||||||
318
src/stark.ts
318
src/stark.ts
@@ -1,318 +0,0 @@
|
|||||||
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
|
||||||
import { keccak_256 } from '@noble/hashes/sha3';
|
|
||||||
import { sha256 } from '@noble/hashes/sha256';
|
|
||||||
import { utf8ToBytes } from '@noble/hashes/utils';
|
|
||||||
import { Fp, mod, Field, validateField } from './abstract/modular.js';
|
|
||||||
import { poseidon } from './abstract/poseidon.js';
|
|
||||||
import { weierstrass, ProjPointType, SignatureType } from './abstract/weierstrass.js';
|
|
||||||
import {
|
|
||||||
Hex,
|
|
||||||
bitMask,
|
|
||||||
bytesToHex,
|
|
||||||
bytesToNumberBE,
|
|
||||||
concatBytes,
|
|
||||||
ensureBytes as ensureBytesOrig,
|
|
||||||
hexToBytes,
|
|
||||||
hexToNumber,
|
|
||||||
numberToVarBytesBE,
|
|
||||||
} from './abstract/utils.js';
|
|
||||||
import { getHash } from './_shortw_utils.js';
|
|
||||||
|
|
||||||
// Stark-friendly elliptic curve
|
|
||||||
// https://docs.starkware.co/starkex/stark-curve.html
|
|
||||||
|
|
||||||
type ProjectivePoint = ProjPointType<bigint>;
|
|
||||||
const CURVE_ORDER = BigInt(
|
|
||||||
'3618502788666131213697322783095070105526743751716087489154079457884512865583'
|
|
||||||
);
|
|
||||||
const nBitLength = 252;
|
|
||||||
function bits2int(bytes: Uint8Array): bigint {
|
|
||||||
while (bytes[0] === 0) bytes = bytes.subarray(1); // strip leading 0s
|
|
||||||
// Copy-pasted from weierstrass.ts
|
|
||||||
const delta = bytes.length * 8 - nBitLength;
|
|
||||||
const num = bytesToNumberBE(bytes);
|
|
||||||
return delta > 0 ? num >> BigInt(delta) : num;
|
|
||||||
}
|
|
||||||
function hex0xToBytes(hex: string): Uint8Array {
|
|
||||||
if (typeof hex === 'string') {
|
|
||||||
hex = strip0x(hex); // allow 0x prefix
|
|
||||||
if (hex.length & 1) hex = '0' + hex; // allow unpadded hex
|
|
||||||
}
|
|
||||||
return hexToBytes(hex);
|
|
||||||
}
|
|
||||||
const curve = weierstrass({
|
|
||||||
a: BigInt(1), // Params: a, b
|
|
||||||
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)
|
|
||||||
Fp: Fp(BigInt('0x800000000000011000000000000000000000000000000000000000000000001')),
|
|
||||||
n: CURVE_ORDER, // Curve order, total count of valid points in the field.
|
|
||||||
nBitLength, // len(bin(N).replace('0b',''))
|
|
||||||
// Base point (x, y) aka generator point
|
|
||||||
Gx: BigInt('874739451078007766457464989774322083649278607533249481151382481072868806602'),
|
|
||||||
Gy: BigInt('152666792071518830868575557812948353041420400780739481342941381225525861407'),
|
|
||||||
h: BigInt(1), // cofactor
|
|
||||||
lowS: false, // Allow high-s signatures
|
|
||||||
...getHash(sha256),
|
|
||||||
// Custom truncation routines for stark curve
|
|
||||||
bits2int,
|
|
||||||
bits2int_modN: (bytes: Uint8Array): bigint => {
|
|
||||||
// 2102820b232636d200cb21f1d330f20d096cae09d1bf3edb1cc333ddee11318 =>
|
|
||||||
// 2102820b232636d200cb21f1d330f20d096cae09d1bf3edb1cc333ddee113180
|
|
||||||
const hex = bytesToNumberBE(bytes).toString(16); // toHex unpadded
|
|
||||||
if (hex.length === 63) bytes = hex0xToBytes(hex + '0'); // append trailing 0
|
|
||||||
return mod(bits2int(bytes), CURVE_ORDER);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
export const _starkCurve = curve;
|
|
||||||
|
|
||||||
function ensureBytes(hex: Hex): Uint8Array {
|
|
||||||
return ensureBytesOrig('', typeof hex === 'string' ? hex0xToBytes(hex) : hex);
|
|
||||||
}
|
|
||||||
|
|
||||||
function normPrivKey(privKey: Hex): string {
|
|
||||||
return bytesToHex(ensureBytes(privKey)).padStart(64, '0');
|
|
||||||
}
|
|
||||||
export function getPublicKey(privKey: Hex, isCompressed = false): Uint8Array {
|
|
||||||
return curve.getPublicKey(normPrivKey(privKey), isCompressed);
|
|
||||||
}
|
|
||||||
export function getSharedSecret(privKeyA: Hex, pubKeyB: Hex): Uint8Array {
|
|
||||||
return curve.getSharedSecret(normPrivKey(privKeyA), pubKeyB);
|
|
||||||
}
|
|
||||||
export function sign(msgHash: Hex, privKey: Hex, opts?: any): SignatureType {
|
|
||||||
return curve.sign(ensureBytes(msgHash), normPrivKey(privKey), opts);
|
|
||||||
}
|
|
||||||
export function verify(signature: SignatureType | Hex, msgHash: Hex, pubKey: Hex) {
|
|
||||||
const sig = signature instanceof Signature ? signature : ensureBytes(signature);
|
|
||||||
return curve.verify(sig, ensureBytes(msgHash), ensureBytes(pubKey));
|
|
||||||
}
|
|
||||||
|
|
||||||
const { CURVE, ProjectivePoint, Signature, utils } = curve;
|
|
||||||
export { CURVE, ProjectivePoint, Signature, utils };
|
|
||||||
|
|
||||||
function extractX(bytes: Uint8Array): string {
|
|
||||||
const hex = bytesToHex(bytes.subarray(1));
|
|
||||||
const stripped = hex.replace(/^0+/gm, ''); // strip leading 0s
|
|
||||||
return `0x${stripped}`;
|
|
||||||
}
|
|
||||||
function strip0x(hex: string) {
|
|
||||||
return hex.replace(/^0x/i, '');
|
|
||||||
}
|
|
||||||
function numberTo0x16(num: bigint) {
|
|
||||||
// can't use utils.numberToHexUnpadded: adds leading 0 for even byte length
|
|
||||||
return `0x${num.toString(16)}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
// seed generation
|
|
||||||
export function grindKey(seed: Hex) {
|
|
||||||
const _seed = ensureBytes(seed);
|
|
||||||
const sha256mask = 2n ** 256n;
|
|
||||||
const limit = sha256mask - mod(sha256mask, CURVE_ORDER);
|
|
||||||
for (let i = 0; ; i++) {
|
|
||||||
const key = sha256Num(concatBytes(_seed, numberToVarBytesBE(BigInt(i))));
|
|
||||||
if (key < limit) return mod(key, CURVE_ORDER).toString(16); // key should be in [0, limit)
|
|
||||||
if (i === 100000) throw new Error('grindKey is broken: tried 100k vals'); // prevent dos
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getStarkKey(privateKey: Hex): string {
|
|
||||||
return extractX(getPublicKey(privateKey, true));
|
|
||||||
}
|
|
||||||
|
|
||||||
export function ethSigToPrivate(signature: string): string {
|
|
||||||
signature = strip0x(signature);
|
|
||||||
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
|
|
||||||
): string {
|
|
||||||
const layerNum = int31(sha256Num(layer));
|
|
||||||
const applicationNum = int31(sha256Num(application));
|
|
||||||
const eth = hexToNumber(strip0x(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 ProjectivePoint(
|
|
||||||
2089986280348253421170679821480865132823066470938446095505822317253594081284n,
|
|
||||||
1713931329540660377023406109199410414810705867260802078187082345529207694986n,
|
|
||||||
1n
|
|
||||||
),
|
|
||||||
new ProjectivePoint(
|
|
||||||
996781205833008774514500082376783249102396023663454813447423147977397232763n,
|
|
||||||
1668503676786377725805489344771023921079126552019160156920634619255970485781n,
|
|
||||||
1n
|
|
||||||
),
|
|
||||||
new ProjectivePoint(
|
|
||||||
2251563274489750535117886426533222435294046428347329203627021249169616184184n,
|
|
||||||
1798716007562728905295480679789526322175868328062420237419143593021674992973n,
|
|
||||||
1n
|
|
||||||
),
|
|
||||||
new ProjectivePoint(
|
|
||||||
2138414695194151160943305727036575959195309218611738193261179310511854807447n,
|
|
||||||
113410276730064486255102093846540133784865286929052426931474106396135072156n,
|
|
||||||
1n
|
|
||||||
),
|
|
||||||
new ProjectivePoint(
|
|
||||||
2379962749567351885752724891227938183011949129833673362440656643086021394946n,
|
|
||||||
776496453633298175483985398648758586525933812536653089401905292063708816422n,
|
|
||||||
1n
|
|
||||||
),
|
|
||||||
];
|
|
||||||
|
|
||||||
function pedersenPrecompute(p1: ProjectivePoint, p2: ProjectivePoint): ProjectivePoint[] {
|
|
||||||
const out: ProjectivePoint[] = [];
|
|
||||||
let p = p1;
|
|
||||||
for (let i = 0; i < 248; i++) {
|
|
||||||
out.push(p);
|
|
||||||
p = p.double();
|
|
||||||
}
|
|
||||||
// NOTE: we cannot use wNAF here, because last 4 bits will require full 248 bits multiplication
|
|
||||||
// We can add support for this to wNAF, but it will complicate wNAF.
|
|
||||||
p = p2;
|
|
||||||
for (let i = 0; i < 4; i++) {
|
|
||||||
out.push(p);
|
|
||||||
p = p.double();
|
|
||||||
}
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
const PEDERSEN_POINTS1 = pedersenPrecompute(PEDERSEN_POINTS[1], PEDERSEN_POINTS[2]);
|
|
||||||
const PEDERSEN_POINTS2 = pedersenPrecompute(PEDERSEN_POINTS[3], PEDERSEN_POINTS[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 = bytesToNumberBE(ensureBytes(arg));
|
|
||||||
}
|
|
||||||
if (!(0n <= value && value < curve.CURVE.Fp.ORDER))
|
|
||||||
throw new Error(`PedersenArg should be 0 <= value < CURVE.P: ${value}`); // [0..Fp)
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
function pedersenSingle(point: ProjectivePoint, value: PedersenArg, constants: ProjectivePoint[]) {
|
|
||||||
let x = pedersenArg(value);
|
|
||||||
for (let j = 0; j < 252; j++) {
|
|
||||||
const pt = constants[j];
|
|
||||||
if (pt.px === point.px) 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): string {
|
|
||||||
let point: ProjectivePoint = PEDERSEN_POINTS[0];
|
|
||||||
point = pedersenSingle(point, x, PEDERSEN_POINTS1);
|
|
||||||
point = pedersenSingle(point, y, PEDERSEN_POINTS2);
|
|
||||||
return extractX(point.toRawBytes(true));
|
|
||||||
}
|
|
||||||
|
|
||||||
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 numberTo0x16(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 = bitMask(250);
|
|
||||||
export const keccak = (data: Uint8Array): bigint => bytesToNumberBE(keccak_256(data)) & MASK_250;
|
|
||||||
const sha256Num = (data: Uint8Array | string): bigint => bytesToNumberBE(sha256(data));
|
|
||||||
|
|
||||||
// Poseidon hash
|
|
||||||
export const Fp253 = Fp(
|
|
||||||
BigInt('14474011154664525231415395255581126252639794253786371766033694892385558855681')
|
|
||||||
); // 2^253 + 2^199 + 1
|
|
||||||
export const Fp251 = Fp(
|
|
||||||
BigInt('3618502788666131213697322783095070105623107215331596699973092056135872020481')
|
|
||||||
); // 2^251 + 17 * 2^192 + 1
|
|
||||||
|
|
||||||
function poseidonRoundConstant(Fp: Field<bigint>, name: string, idx: number) {
|
|
||||||
const val = Fp.fromBytes(sha256(utf8ToBytes(`${name}${idx}`)));
|
|
||||||
return Fp.create(val);
|
|
||||||
}
|
|
||||||
|
|
||||||
// NOTE: doesn't check eiginvalues and possible can create unsafe matrix. But any filtration here will break compatibility with starknet
|
|
||||||
// Please use only if you really know what you doing.
|
|
||||||
// https://eprint.iacr.org/2019/458.pdf Section 2.3 (Avoiding Insecure Matrices)
|
|
||||||
export function _poseidonMDS(Fp: Field<bigint>, name: string, m: number, attempt = 0) {
|
|
||||||
const x_values: bigint[] = [];
|
|
||||||
const y_values: bigint[] = [];
|
|
||||||
for (let i = 0; i < m; i++) {
|
|
||||||
x_values.push(poseidonRoundConstant(Fp, `${name}x`, attempt * m + i));
|
|
||||||
y_values.push(poseidonRoundConstant(Fp, `${name}y`, attempt * m + i));
|
|
||||||
}
|
|
||||||
if (new Set([...x_values, ...y_values]).size !== 2 * m)
|
|
||||||
throw new Error('X and Y values are not distinct');
|
|
||||||
return x_values.map((x) => y_values.map((y) => Fp.inv(Fp.sub(x, y))));
|
|
||||||
}
|
|
||||||
|
|
||||||
const MDS_SMALL = [
|
|
||||||
[3, 1, 1],
|
|
||||||
[1, -1, 1],
|
|
||||||
[1, 1, -2],
|
|
||||||
].map((i) => i.map(BigInt));
|
|
||||||
|
|
||||||
export type PoseidonOpts = {
|
|
||||||
Fp: Field<bigint>;
|
|
||||||
rate: number;
|
|
||||||
capacity: number;
|
|
||||||
roundsFull: number;
|
|
||||||
roundsPartial: number;
|
|
||||||
};
|
|
||||||
|
|
||||||
export function poseidonBasic(opts: PoseidonOpts, mds: bigint[][]) {
|
|
||||||
validateField(opts.Fp);
|
|
||||||
if (!Number.isSafeInteger(opts.rate) || !Number.isSafeInteger(opts.capacity))
|
|
||||||
throw new Error(`Wrong poseidon opts: ${opts}`);
|
|
||||||
const m = opts.rate + opts.capacity;
|
|
||||||
const rounds = opts.roundsFull + opts.roundsPartial;
|
|
||||||
const roundConstants = [];
|
|
||||||
for (let i = 0; i < rounds; i++) {
|
|
||||||
const row = [];
|
|
||||||
for (let j = 0; j < m; j++) row.push(poseidonRoundConstant(opts.Fp, 'Hades', m * i + j));
|
|
||||||
roundConstants.push(row);
|
|
||||||
}
|
|
||||||
return poseidon({
|
|
||||||
...opts,
|
|
||||||
t: m,
|
|
||||||
sboxPower: 3,
|
|
||||||
reversePartialPowIdx: true, // Why?!
|
|
||||||
mds,
|
|
||||||
roundConstants,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export function poseidonCreate(opts: PoseidonOpts, mdsAttempt = 0) {
|
|
||||||
const m = opts.rate + opts.capacity;
|
|
||||||
if (!Number.isSafeInteger(mdsAttempt)) throw new Error(`Wrong mdsAttempt=${mdsAttempt}`);
|
|
||||||
return poseidonBasic(opts, _poseidonMDS(opts.Fp, 'HadesMDS', m, mdsAttempt));
|
|
||||||
}
|
|
||||||
|
|
||||||
export const poseidonSmall = poseidonBasic(
|
|
||||||
{ Fp: Fp251, rate: 2, capacity: 1, roundsFull: 8, roundsPartial: 83 },
|
|
||||||
MDS_SMALL
|
|
||||||
);
|
|
||||||
|
|
||||||
export function poseidonHash(x: bigint, y: bigint, fn = poseidonSmall) {
|
|
||||||
return fn([x, y, 2n])[0];
|
|
||||||
}
|
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
||||||
import { createCurve } from '../_shortw_utils.js';
|
import { createCurve } from '../esm/_shortw_utils.js';
|
||||||
import { sha224, sha256 } from '@noble/hashes/sha256';
|
import { sha224, sha256 } from '@noble/hashes/sha256';
|
||||||
import { Fp } from '../abstract/modular.js';
|
import { Field as Fp } from '../esm/abstract/modular.js';
|
||||||
|
|
||||||
// NIST secp192r1 aka P192
|
// NIST secp192r1 aka p192
|
||||||
// https://www.secg.org/sec2-v2.pdf, https://neuromancer.sk/std/secg/secp192r1
|
// https://www.secg.org/sec2-v2.pdf, https://neuromancer.sk/std/secg/secp192r1
|
||||||
export const P192 = createCurve(
|
export const p192 = createCurve(
|
||||||
{
|
{
|
||||||
// Params: a, b
|
// Params: a, b
|
||||||
a: BigInt('0xfffffffffffffffffffffffffffffffefffffffffffffffc'),
|
a: BigInt('0xfffffffffffffffffffffffffffffffefffffffffffffffc'),
|
||||||
@@ -22,9 +22,9 @@ export const P192 = createCurve(
|
|||||||
},
|
},
|
||||||
sha256
|
sha256
|
||||||
);
|
);
|
||||||
export const secp192r1 = P192;
|
export const secp192r1 = p192;
|
||||||
|
|
||||||
export const P224 = createCurve(
|
export const p224 = createCurve(
|
||||||
{
|
{
|
||||||
// Params: a, b
|
// Params: a, b
|
||||||
a: BigInt('0xfffffffffffffffffffffffffffffffefffffffffffffffffffffffe'),
|
a: BigInt('0xfffffffffffffffffffffffffffffffefffffffffffffffffffffffe'),
|
||||||
@@ -41,4 +41,4 @@ export const P224 = createCurve(
|
|||||||
},
|
},
|
||||||
sha224
|
sha224
|
||||||
);
|
);
|
||||||
export const secp224r1 = P224;
|
export const secp224r1 = p224;
|
||||||
|
|||||||
103
test/_poseidon.helpers.js
Normal file
103
test/_poseidon.helpers.js
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
||||||
|
import { sha256 } from '@noble/hashes/sha256';
|
||||||
|
import { utf8ToBytes } from '@noble/hashes/utils';
|
||||||
|
import { Field as Fp, validateField } from '../esm/abstract/modular.js';
|
||||||
|
import { poseidon } from '../esm/abstract/poseidon.js';
|
||||||
|
import * as u from '../esm/abstract/utils.js';
|
||||||
|
|
||||||
|
// Poseidon hash https://docs.starkware.co/starkex/stark-curve.html
|
||||||
|
export const Fp253 = Fp(
|
||||||
|
BigInt('14474011154664525231415395255581126252639794253786371766033694892385558855681')
|
||||||
|
); // 2^253 + 2^199 + 1
|
||||||
|
export const Fp251 = Fp(
|
||||||
|
BigInt('3618502788666131213697322783095070105623107215331596699973092056135872020481')
|
||||||
|
); // 2^251 + 17 * 2^192 + 1
|
||||||
|
|
||||||
|
function poseidonRoundConstant(Fp, name, idx) {
|
||||||
|
const val = Fp.fromBytes(sha256(utf8ToBytes(`${name}${idx}`)));
|
||||||
|
return Fp.create(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: doesn't check eiginvalues and possible can create unsafe matrix. But any filtration here will break compatibility with starknet
|
||||||
|
// Please use only if you really know what you doing.
|
||||||
|
// https://eprint.iacr.org/2019/458.pdf Section 2.3 (Avoiding Insecure Matrices)
|
||||||
|
export function _poseidonMDS(Fp, name, m, attempt = 0) {
|
||||||
|
const x_values = [];
|
||||||
|
const y_values = [];
|
||||||
|
for (let i = 0; i < m; i++) {
|
||||||
|
x_values.push(poseidonRoundConstant(Fp, `${name}x`, attempt * m + i));
|
||||||
|
y_values.push(poseidonRoundConstant(Fp, `${name}y`, attempt * m + i));
|
||||||
|
}
|
||||||
|
if (new Set([...x_values, ...y_values]).size !== 2 * m)
|
||||||
|
throw new Error('X and Y values are not distinct');
|
||||||
|
return x_values.map((x) => y_values.map((y) => Fp.inv(Fp.sub(x, y))));
|
||||||
|
}
|
||||||
|
|
||||||
|
const MDS_SMALL = [
|
||||||
|
[3, 1, 1],
|
||||||
|
[1, -1, 1],
|
||||||
|
[1, 1, -2],
|
||||||
|
].map((i) => i.map(BigInt));
|
||||||
|
|
||||||
|
export function poseidonBasic(opts, mds) {
|
||||||
|
validateField(opts.Fp);
|
||||||
|
if (!Number.isSafeInteger(opts.rate) || !Number.isSafeInteger(opts.capacity))
|
||||||
|
throw new Error(`Wrong poseidon opts: ${opts}`);
|
||||||
|
const m = opts.rate + opts.capacity;
|
||||||
|
const rounds = opts.roundsFull + opts.roundsPartial;
|
||||||
|
const roundConstants = [];
|
||||||
|
for (let i = 0; i < rounds; i++) {
|
||||||
|
const row = [];
|
||||||
|
for (let j = 0; j < m; j++) row.push(poseidonRoundConstant(opts.Fp, 'Hades', m * i + j));
|
||||||
|
roundConstants.push(row);
|
||||||
|
}
|
||||||
|
const res = poseidon({
|
||||||
|
...opts,
|
||||||
|
t: m,
|
||||||
|
sboxPower: 3,
|
||||||
|
reversePartialPowIdx: true, // Why?!
|
||||||
|
mds,
|
||||||
|
roundConstants,
|
||||||
|
});
|
||||||
|
res.m = m;
|
||||||
|
res.rate = opts.rate;
|
||||||
|
res.capacity = opts.capacity;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function poseidonCreate(opts, mdsAttempt = 0) {
|
||||||
|
const m = opts.rate + opts.capacity;
|
||||||
|
if (!Number.isSafeInteger(mdsAttempt)) throw new Error(`Wrong mdsAttempt=${mdsAttempt}`);
|
||||||
|
return poseidonBasic(opts, _poseidonMDS(opts.Fp, 'HadesMDS', m, mdsAttempt));
|
||||||
|
}
|
||||||
|
|
||||||
|
export const poseidonSmall = poseidonBasic(
|
||||||
|
{ Fp: Fp251, rate: 2, capacity: 1, roundsFull: 8, roundsPartial: 83 },
|
||||||
|
MDS_SMALL
|
||||||
|
);
|
||||||
|
|
||||||
|
export function poseidonHash(x, y, fn = poseidonSmall) {
|
||||||
|
return fn([x, y, 2n])[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
export function poseidonHashFunc(x, y, fn = poseidonSmall) {
|
||||||
|
return u.numberToVarBytesBE(poseidonHash(u.bytesToNumberBE(x), u.bytesToNumberBE(y), fn));
|
||||||
|
}
|
||||||
|
|
||||||
|
export function poseidonHashSingle(x, fn = poseidonSmall) {
|
||||||
|
return fn([x, 0n, 1n])[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
export function poseidonHashMany(values, fn = poseidonSmall) {
|
||||||
|
const { m, rate } = fn;
|
||||||
|
if (!Array.isArray(values)) throw new Error('bigint array expected in values');
|
||||||
|
const padded = Array.from(values); // copy
|
||||||
|
padded.push(1n);
|
||||||
|
while (padded.length % rate !== 0) padded.push(0n);
|
||||||
|
let state = new Array(m).fill(0n);
|
||||||
|
for (let i = 0; i < padded.length; i += rate) {
|
||||||
|
for (let j = 0; j < rate; j++) state[j] += padded[i + j];
|
||||||
|
state = fn(state);
|
||||||
|
}
|
||||||
|
return state[0];
|
||||||
|
}
|
||||||
@@ -11,11 +11,14 @@ import { secp521r1 } from '../esm/p521.js';
|
|||||||
import { secp256k1 } from '../esm/secp256k1.js';
|
import { secp256k1 } from '../esm/secp256k1.js';
|
||||||
import { ed25519, ed25519ctx, ed25519ph, x25519 } from '../esm/ed25519.js';
|
import { ed25519, ed25519ctx, ed25519ph, x25519 } from '../esm/ed25519.js';
|
||||||
import { ed448, ed448ph } from '../esm/ed448.js';
|
import { ed448, ed448ph } from '../esm/ed448.js';
|
||||||
import { _starkCurve as starkCurve } from '../esm/stark.js';
|
|
||||||
import { pallas, vesta } from '../esm/pasta.js';
|
import { pallas, vesta } from '../esm/pasta.js';
|
||||||
import { bn254 } from '../esm/bn.js';
|
import { bn254 } from '../esm/bn254.js';
|
||||||
import { jubjub } from '../esm/jubjub.js';
|
import { jubjub } from '../esm/jubjub.js';
|
||||||
import { bls12_381 } from '../esm/bls12-381.js';
|
import { bls12_381 } from '../esm/bls12-381.js';
|
||||||
|
import { default as wyche_curves } from './wycheproof/ec_prime_order_curves_test.json' assert { type: 'json' };
|
||||||
|
import { createCurve } from '../esm/_shortw_utils.js';
|
||||||
|
import { Field } from '../esm/abstract/modular.js';
|
||||||
|
import { sha256 } from '@noble/hashes/sha256';
|
||||||
|
|
||||||
// Fields tests
|
// Fields tests
|
||||||
const FIELDS = {
|
const FIELDS = {
|
||||||
@@ -24,7 +27,6 @@ const FIELDS = {
|
|||||||
secp256r1: { Fp: [secp256r1.CURVE.Fp] },
|
secp256r1: { Fp: [secp256r1.CURVE.Fp] },
|
||||||
secp521r1: { Fp: [secp521r1.CURVE.Fp] },
|
secp521r1: { Fp: [secp521r1.CURVE.Fp] },
|
||||||
secp256k1: { Fp: [secp256k1.CURVE.Fp] },
|
secp256k1: { Fp: [secp256k1.CURVE.Fp] },
|
||||||
stark: { Fp: [starkCurve.CURVE.Fp] },
|
|
||||||
jubjub: { Fp: [jubjub.CURVE.Fp] },
|
jubjub: { Fp: [jubjub.CURVE.Fp] },
|
||||||
ed25519: { Fp: [ed25519.CURVE.Fp] },
|
ed25519: { Fp: [ed25519.CURVE.Fp] },
|
||||||
ed448: { Fp: [ed448.CURVE.Fp] },
|
ed448: { Fp: [ed448.CURVE.Fp] },
|
||||||
@@ -32,19 +34,19 @@ const FIELDS = {
|
|||||||
pallas: { Fp: [pallas.CURVE.Fp] },
|
pallas: { Fp: [pallas.CURVE.Fp] },
|
||||||
vesta: { Fp: [vesta.CURVE.Fp] },
|
vesta: { Fp: [vesta.CURVE.Fp] },
|
||||||
bls12: {
|
bls12: {
|
||||||
Fp: [bls12_381.CURVE.Fp],
|
Fp: [bls12_381.fields.Fp],
|
||||||
Fp2: [
|
Fp2: [
|
||||||
bls12_381.CURVE.Fp2,
|
bls12_381.fields.Fp2,
|
||||||
fc.array(fc.bigInt(1n, bls12_381.CURVE.Fp.ORDER - 1n), {
|
fc.array(fc.bigInt(1n, bls12_381.fields.Fp.ORDER - 1n), {
|
||||||
minLength: 2,
|
minLength: 2,
|
||||||
maxLength: 2,
|
maxLength: 2,
|
||||||
}),
|
}),
|
||||||
(Fp2, num) => Fp2.fromBigTuple([num[0], num[1]]),
|
(Fp2, num) => Fp2.fromBigTuple([num[0], num[1]]),
|
||||||
],
|
],
|
||||||
// Fp6: [bls12_381.CURVE.Fp6],
|
// Fp6: [bls12_381.fields.Fp6],
|
||||||
Fp12: [
|
Fp12: [
|
||||||
bls12_381.CURVE.Fp12,
|
bls12_381.fields.Fp12,
|
||||||
fc.array(fc.bigInt(1n, bls12_381.CURVE.Fp.ORDER - 1n), {
|
fc.array(fc.bigInt(1n, bls12_381.fields.Fp.ORDER - 1n), {
|
||||||
minLength: 12,
|
minLength: 12,
|
||||||
maxLength: 12,
|
maxLength: 12,
|
||||||
}),
|
}),
|
||||||
@@ -223,7 +225,7 @@ for (const c in FIELDS) {
|
|||||||
|
|
||||||
const isSquare = mod.FpIsSquare(Fp);
|
const isSquare = mod.FpIsSquare(Fp);
|
||||||
// Not implemented
|
// Not implemented
|
||||||
if (Fp !== bls12_381.CURVE.Fp12) {
|
if (Fp !== bls12_381.fields.Fp12) {
|
||||||
should('multiply/sqrt', () => {
|
should('multiply/sqrt', () => {
|
||||||
fc.assert(
|
fc.assert(
|
||||||
fc.property(FC_BIGINT, (num) => {
|
fc.property(FC_BIGINT, (num) => {
|
||||||
@@ -314,7 +316,6 @@ const CURVES = {
|
|||||||
secp256k1,
|
secp256k1,
|
||||||
ed25519, ed25519ctx, ed25519ph,
|
ed25519, ed25519ctx, ed25519ph,
|
||||||
ed448, ed448ph,
|
ed448, ed448ph,
|
||||||
starkCurve,
|
|
||||||
pallas, vesta,
|
pallas, vesta,
|
||||||
bn254,
|
bn254,
|
||||||
jubjub,
|
jubjub,
|
||||||
@@ -556,6 +557,7 @@ for (const name in CURVES) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
describe(name, () => {
|
describe(name, () => {
|
||||||
|
if (['bn254', 'pallas', 'vesta'].includes(name)) return;
|
||||||
// Generic complex things (getPublicKey/sign/verify/getSharedSecret)
|
// Generic complex things (getPublicKey/sign/verify/getSharedSecret)
|
||||||
should('.getPublicKey() type check', () => {
|
should('.getPublicKey() type check', () => {
|
||||||
throws(() => C.getPublicKey(0), '0');
|
throws(() => C.getPublicKey(0), '0');
|
||||||
@@ -744,6 +746,54 @@ should('bigInt private keys', () => {
|
|||||||
secp256k1.sign('', 123n);
|
secp256k1.sign('', 123n);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('wycheproof curve creation', () => {
|
||||||
|
const VECTORS = wyche_curves.testGroups[0].tests;
|
||||||
|
for (const v of VECTORS) {
|
||||||
|
should(`${v.name}`, () => {
|
||||||
|
const CURVE = createCurve(
|
||||||
|
{
|
||||||
|
Fp: Field(BigInt(`0x${v.p}`)),
|
||||||
|
a: BigInt(`0x${v.a}`),
|
||||||
|
b: BigInt(`0x${v.b}`),
|
||||||
|
n: BigInt(`0x${v.n}`),
|
||||||
|
h: BigInt(v.h),
|
||||||
|
Gx: BigInt(`0x${v.gx}`),
|
||||||
|
Gy: BigInt(`0x${v.gy}`),
|
||||||
|
},
|
||||||
|
sha256
|
||||||
|
);
|
||||||
|
});
|
||||||
|
const CURVE = CURVES[v.name];
|
||||||
|
if (!CURVE) continue;
|
||||||
|
should(`${v.name} parms verify`, () => {
|
||||||
|
deepStrictEqual(CURVE.CURVE.Fp.ORDER, BigInt(`0x${v.p}`));
|
||||||
|
deepStrictEqual(CURVE.CURVE.a, BigInt(`0x${v.a}`));
|
||||||
|
deepStrictEqual(CURVE.CURVE.b, BigInt(`0x${v.b}`));
|
||||||
|
deepStrictEqual(CURVE.CURVE.n, BigInt(`0x${v.n}`));
|
||||||
|
deepStrictEqual(CURVE.CURVE.Gx, BigInt(`0x${v.gx}`));
|
||||||
|
deepStrictEqual(CURVE.CURVE.Gy, BigInt(`0x${v.gy}`));
|
||||||
|
deepStrictEqual(CURVE.CURVE.h, BigInt(v.h));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
should('validate generator point is on curve', () => {
|
||||||
|
throws(() =>
|
||||||
|
createCurve(
|
||||||
|
{
|
||||||
|
Fp: Field(BigInt(`0x00c302f41d932a36cda7a3463093d18db78fce476de1a86297`)),
|
||||||
|
a: BigInt(`0x00c302f41d932a36cda7a3463093d18db78fce476de1a86294`),
|
||||||
|
b: BigInt(`0x13d56ffaec78681e68f9deb43b35bec2fb68542e27897b79`),
|
||||||
|
n: BigInt(`0x00c302f41d932a36cda7a3462f9e9e916b5be8f1029ac4acc1`),
|
||||||
|
h: BigInt(1),
|
||||||
|
Gx: BigInt(`0x3ae9e58c82f63c30282e1fe7bbf43fa72c446af6f4618129`),
|
||||||
|
Gy: BigInt(`0x097e2c5667c2223a902ab5ca449d0084b7e5b3de7ccc01c8`), // last 9 -> 8
|
||||||
|
},
|
||||||
|
sha256
|
||||||
|
)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
// ESM is broken.
|
// ESM is broken.
|
||||||
import url from 'url';
|
import url from 'url';
|
||||||
if (import.meta.url === url.pathToFileURL(process.argv[1]).href) {
|
if (import.meta.url === url.pathToFileURL(process.argv[1]).href) {
|
||||||
|
|||||||
@@ -5,10 +5,16 @@ import { describe, should } from 'micro-should';
|
|||||||
import { wNAF } from '../esm/abstract/curve.js';
|
import { wNAF } from '../esm/abstract/curve.js';
|
||||||
import { bytesToHex, utf8ToBytes } from '../esm/abstract/utils.js';
|
import { bytesToHex, utf8ToBytes } from '../esm/abstract/utils.js';
|
||||||
import { hash_to_field } from '../esm/abstract/hash-to-curve.js';
|
import { hash_to_field } from '../esm/abstract/hash-to-curve.js';
|
||||||
import { bls12_381 as bls } from '../esm/bls12-381.js';
|
import { bls12_381 as bls, bls12_381 } from '../esm/bls12-381.js';
|
||||||
|
|
||||||
|
import * as utils from '../esm/abstract/utils.js';
|
||||||
|
|
||||||
import zkVectors from './bls12-381/zkcrypto/converted.json' assert { type: 'json' };
|
import zkVectors from './bls12-381/zkcrypto/converted.json' assert { type: 'json' };
|
||||||
import pairingVectors from './bls12-381/go_pairing_vectors/pairing.json' assert { type: 'json' };
|
import pairingVectors from './bls12-381/go_pairing_vectors/pairing.json' assert { type: 'json' };
|
||||||
|
const G1_VECTORS = readFileSync('./test/bls12-381/bls12-381-g1-test-vectors.txt', 'utf-8')
|
||||||
|
.trim()
|
||||||
|
.split('\n')
|
||||||
|
.map((l) => l.split(':'));
|
||||||
const G2_VECTORS = readFileSync('./test/bls12-381/bls12-381-g2-test-vectors.txt', 'utf-8')
|
const G2_VECTORS = readFileSync('./test/bls12-381/bls12-381-g2-test-vectors.txt', 'utf-8')
|
||||||
.trim()
|
.trim()
|
||||||
.split('\n')
|
.split('\n')
|
||||||
@@ -24,11 +30,10 @@ const SCALAR_VECTORS = readFileSync('./test/bls12-381/bls12-381-scalar-test-vect
|
|||||||
const NUM_RUNS = Number(process.env.RUNS_COUNT || 10); // reduce to 1 to shorten test time
|
const NUM_RUNS = Number(process.env.RUNS_COUNT || 10); // reduce to 1 to shorten test time
|
||||||
fc.configureGlobal({ numRuns: NUM_RUNS });
|
fc.configureGlobal({ numRuns: NUM_RUNS });
|
||||||
|
|
||||||
const { Fp2 } = bls;
|
|
||||||
const G1Point = bls.G1.ProjectivePoint;
|
const G1Point = bls.G1.ProjectivePoint;
|
||||||
const G2Point = bls.G2.ProjectivePoint;
|
const G2Point = bls.G2.ProjectivePoint;
|
||||||
const G1Aff = (x, y) => G1Point.fromAffine({ x, y });
|
const G1Aff = (x, y) => G1Point.fromAffine({ x, y });
|
||||||
const CURVE_ORDER = bls.CURVE.r;
|
const CURVE_ORDER = bls.params.r;
|
||||||
|
|
||||||
const FC_MSG = fc.hexaString({ minLength: 64, maxLength: 64 });
|
const FC_MSG = fc.hexaString({ minLength: 64, maxLength: 64 });
|
||||||
const FC_MSG_5 = fc.array(FC_MSG, { minLength: 5, maxLength: 5 });
|
const FC_MSG_5 = fc.array(FC_MSG, { minLength: 5, maxLength: 5 });
|
||||||
@@ -38,14 +43,19 @@ const B_192_40 = '40'.padEnd(192, '0');
|
|||||||
const B_384_40 = '40'.padEnd(384, '0'); // [0x40, 0, 0...]
|
const B_384_40 = '40'.padEnd(384, '0'); // [0x40, 0, 0...]
|
||||||
|
|
||||||
const getPubKey = (priv) => bls.getPublicKey(priv);
|
const getPubKey = (priv) => bls.getPublicKey(priv);
|
||||||
|
function replaceZeroPoint(item) {
|
||||||
|
const zeros = '0000000000000000000000000000000000000000000000000000000000000000';
|
||||||
|
const ones = '1000000000000000000000000000000000000000000000000000000000000001';
|
||||||
|
return item === zeros ? ones : item;
|
||||||
|
}
|
||||||
|
|
||||||
function equal(a, b, comment) {
|
function equal(a, b, comment) {
|
||||||
deepStrictEqual(a.equals(b), true, `eq(${comment})`);
|
deepStrictEqual(a.equals(b), true, `eq(${comment})`);
|
||||||
}
|
}
|
||||||
|
const { Fp, Fp2 } = bls.fields;
|
||||||
|
|
||||||
// Fp
|
// Fp
|
||||||
describe('bls12-381 Fp', () => {
|
describe('bls12-381 Fp', () => {
|
||||||
const Fp = bls.Fp;
|
|
||||||
const FC_BIGINT = fc.bigInt(1n, Fp.ORDER - 1n);
|
const FC_BIGINT = fc.bigInt(1n, Fp.ORDER - 1n);
|
||||||
|
|
||||||
should('multiply/sqrt', () => {
|
should('multiply/sqrt', () => {
|
||||||
@@ -60,8 +70,7 @@ describe('bls12-381 Fp', () => {
|
|||||||
|
|
||||||
// Fp2
|
// Fp2
|
||||||
describe('bls12-381 Fp2', () => {
|
describe('bls12-381 Fp2', () => {
|
||||||
const Fp = bls.Fp;
|
const { Fp, Fp2 } = bls.fields;
|
||||||
const Fp2 = bls.Fp2;
|
|
||||||
const FC_BIGINT = fc.bigInt(1n, Fp.ORDER - 1n);
|
const FC_BIGINT = fc.bigInt(1n, Fp.ORDER - 1n);
|
||||||
const FC_BIGINT_2 = fc.array(FC_BIGINT, { minLength: 2, maxLength: 2 });
|
const FC_BIGINT_2 = fc.array(FC_BIGINT, { minLength: 2, maxLength: 2 });
|
||||||
|
|
||||||
@@ -149,7 +158,7 @@ describe('bls12-381 Fp2', () => {
|
|||||||
|
|
||||||
// Point
|
// Point
|
||||||
describe('bls12-381 Point', () => {
|
describe('bls12-381 Point', () => {
|
||||||
const Fp = bls.Fp;
|
const { Fp } = bls.fields;
|
||||||
const FC_BIGINT = fc.bigInt(1n, Fp.ORDER - 1n);
|
const FC_BIGINT = fc.bigInt(1n, Fp.ORDER - 1n);
|
||||||
const PointG1 = G1Point;
|
const PointG1 = G1Point;
|
||||||
const PointG2 = G2Point;
|
const PointG2 = G2Point;
|
||||||
@@ -557,9 +566,12 @@ describe('bls12-381 Point', () => {
|
|||||||
];
|
];
|
||||||
// Use wNAF allow scalars higher than CURVE.r
|
// Use wNAF allow scalars higher than CURVE.r
|
||||||
const w = wNAF(G2Point, 1);
|
const w = wNAF(G2Point, 1);
|
||||||
|
const hEff = BigInt(
|
||||||
|
'0xbc69f08f2ee75b3584c6a0ea91b352888e2a8e9145ad7689986ff031508ffe1329c2f178731db956d82bf015d1212b02ec0ec69d7477c1ae954cbc06689f6a359894c0adebbf6b4e8020005aaa95551'
|
||||||
|
);
|
||||||
for (let p of points) {
|
for (let p of points) {
|
||||||
const ours = p.clearCofactor();
|
const ours = p.clearCofactor();
|
||||||
const shouldBe = w.unsafeLadder(p, bls.CURVE.G2.hEff);
|
const shouldBe = w.unsafeLadder(p, hEff);
|
||||||
deepStrictEqual(ours.equals(shouldBe), true, 'clearLast');
|
deepStrictEqual(ours.equals(shouldBe), true, 'clearLast');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -577,12 +589,12 @@ describe('bls12-381/basic', () => {
|
|||||||
deepStrictEqual(g1.x, G1Point.ZERO.x);
|
deepStrictEqual(g1.x, G1Point.ZERO.x);
|
||||||
deepStrictEqual(g1.y, G1Point.ZERO.y);
|
deepStrictEqual(g1.y, G1Point.ZERO.y);
|
||||||
// Test Non-Zero
|
// Test Non-Zero
|
||||||
const x = bls.Fp.create(
|
const x = Fp.create(
|
||||||
BigInt(
|
BigInt(
|
||||||
'0x17f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb'
|
'0x17f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb'
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
const y = bls.Fp.create(
|
const y = Fp.create(
|
||||||
BigInt(
|
BigInt(
|
||||||
'0x08b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e1'
|
'0x08b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e1'
|
||||||
)
|
)
|
||||||
@@ -603,12 +615,12 @@ describe('bls12-381/basic', () => {
|
|||||||
deepStrictEqual(g1.x, G1Point.ZERO.x);
|
deepStrictEqual(g1.x, G1Point.ZERO.x);
|
||||||
deepStrictEqual(g1.y, G1Point.ZERO.y);
|
deepStrictEqual(g1.y, G1Point.ZERO.y);
|
||||||
// Test Non-Zero
|
// Test Non-Zero
|
||||||
const x = bls.Fp.create(
|
const x = Fp.create(
|
||||||
BigInt(
|
BigInt(
|
||||||
'0x17f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb'
|
'0x17f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb'
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
const y = bls.Fp.create(
|
const y = Fp.create(
|
||||||
BigInt(
|
BigInt(
|
||||||
'0x08b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e1'
|
'0x08b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e1'
|
||||||
)
|
)
|
||||||
@@ -689,12 +701,12 @@ describe('bls12-381/basic', () => {
|
|||||||
// Test Zero
|
// Test Zero
|
||||||
deepStrictEqual(G1Point.ZERO.toHex(false), B_192_40);
|
deepStrictEqual(G1Point.ZERO.toHex(false), B_192_40);
|
||||||
// Test Non-Zero
|
// Test Non-Zero
|
||||||
const x = bls.Fp.create(
|
const x = Fp.create(
|
||||||
BigInt(
|
BigInt(
|
||||||
'0x17f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb'
|
'0x17f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb'
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
const y = bls.Fp.create(
|
const y = Fp.create(
|
||||||
BigInt(
|
BigInt(
|
||||||
'0x08b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e1'
|
'0x08b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e1'
|
||||||
)
|
)
|
||||||
@@ -710,12 +722,12 @@ describe('bls12-381/basic', () => {
|
|||||||
// Test Zero
|
// Test Zero
|
||||||
deepStrictEqual(G1Point.ZERO.toHex(false), B_192_40);
|
deepStrictEqual(G1Point.ZERO.toHex(false), B_192_40);
|
||||||
// Test Non-Zero
|
// Test Non-Zero
|
||||||
const x = bls.Fp.create(
|
const x = Fp.create(
|
||||||
BigInt(
|
BigInt(
|
||||||
'0x17f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb'
|
'0x17f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb'
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
const y = bls.Fp.create(
|
const y = Fp.create(
|
||||||
BigInt(
|
BigInt(
|
||||||
'0x08b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e1'
|
'0x08b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e1'
|
||||||
)
|
)
|
||||||
@@ -801,32 +813,32 @@ describe('bls12-381/basic', () => {
|
|||||||
throws(() => G2Point.fromPrivateKey(0n));
|
throws(() => G2Point.fromPrivateKey(0n));
|
||||||
});
|
});
|
||||||
const VALID_G1 = new G1Point(
|
const VALID_G1 = new G1Point(
|
||||||
bls.Fp.create(
|
Fp.create(
|
||||||
3609742242174788176010452839163620388872641749536604986743596621604118973777515189035770461528205168143692110933639n
|
3609742242174788176010452839163620388872641749536604986743596621604118973777515189035770461528205168143692110933639n
|
||||||
),
|
),
|
||||||
bls.Fp.create(
|
Fp.create(
|
||||||
1619277690257184054444116778047375363103842303863153349133480657158810226683757397206929105479676799650932070320089n
|
1619277690257184054444116778047375363103842303863153349133480657158810226683757397206929105479676799650932070320089n
|
||||||
),
|
),
|
||||||
bls.Fp.create(1n)
|
Fp.create(1n)
|
||||||
);
|
);
|
||||||
const VALID_G1_2 = new G1Point(
|
const VALID_G1_2 = new G1Point(
|
||||||
bls.Fp.create(
|
Fp.create(
|
||||||
1206972466279728255044019580914616126536509750250979180256809997983196363639429409634110400978470384566664128085207n
|
1206972466279728255044019580914616126536509750250979180256809997983196363639429409634110400978470384566664128085207n
|
||||||
),
|
),
|
||||||
bls.Fp.create(
|
Fp.create(
|
||||||
2991142246317096160788653339959532007292638191110818490939476869616372888657136539642598243964263069435065725313423n
|
2991142246317096160788653339959532007292638191110818490939476869616372888657136539642598243964263069435065725313423n
|
||||||
),
|
),
|
||||||
bls.Fp.create(1n)
|
Fp.create(1n)
|
||||||
);
|
);
|
||||||
|
|
||||||
const INVALID_G1 = new G1Point(
|
const INVALID_G1 = new G1Point(
|
||||||
bls.Fp.create(
|
Fp.create(
|
||||||
499001545268060011619089734015590154568173930614466321429631711131511181286230338880376679848890024401335766847607n
|
499001545268060011619089734015590154568173930614466321429631711131511181286230338880376679848890024401335766847607n
|
||||||
),
|
),
|
||||||
bls.Fp.create(
|
Fp.create(
|
||||||
3934582309586258715640230772291917282844636728991757779640464479794033391537662970190753981664259511166946374555673n
|
3934582309586258715640230772291917282844636728991757779640464479794033391537662970190753981664259511166946374555673n
|
||||||
),
|
),
|
||||||
bls.Fp.create(1n)
|
Fp.create(1n)
|
||||||
);
|
);
|
||||||
|
|
||||||
should('aggregate pubkeys', () => {
|
should('aggregate pubkeys', () => {
|
||||||
@@ -846,6 +858,13 @@ describe('bls12-381/basic', () => {
|
|||||||
});
|
});
|
||||||
// should aggregate signatures
|
// should aggregate signatures
|
||||||
|
|
||||||
|
should(`produce correct short signatures (${G1_VECTORS.length} vectors)`, () => {
|
||||||
|
for (let vector of G1_VECTORS) {
|
||||||
|
const [priv, msg, expected] = vector;
|
||||||
|
const sig = bls.signShortSignature(msg, priv);
|
||||||
|
deepStrictEqual(bytesToHex(sig), expected);
|
||||||
|
}
|
||||||
|
});
|
||||||
should(`produce correct signatures (${G2_VECTORS.length} vectors)`, () => {
|
should(`produce correct signatures (${G2_VECTORS.length} vectors)`, () => {
|
||||||
for (let vector of G2_VECTORS) {
|
for (let vector of G2_VECTORS) {
|
||||||
const [priv, msg, expected] = vector;
|
const [priv, msg, expected] = vector;
|
||||||
@@ -855,15 +874,15 @@ describe('bls12-381/basic', () => {
|
|||||||
});
|
});
|
||||||
should(`produce correct scalars (${SCALAR_VECTORS.length} vectors)`, () => {
|
should(`produce correct scalars (${SCALAR_VECTORS.length} vectors)`, () => {
|
||||||
const options = {
|
const options = {
|
||||||
p: bls.CURVE.r,
|
p: bls.params.r,
|
||||||
m: 1,
|
m: 1,
|
||||||
expand: undefined,
|
expand: '_internal_pass',
|
||||||
};
|
};
|
||||||
for (let vector of SCALAR_VECTORS) {
|
for (let vector of SCALAR_VECTORS) {
|
||||||
const [okmAscii, expectedHex] = vector;
|
const [okmAscii, expectedHex] = vector;
|
||||||
const expected = BigInt('0x' + expectedHex);
|
const expected = BigInt('0x' + expectedHex);
|
||||||
const okm = utf8ToBytes(okmAscii);
|
const okm = utf8ToBytes(okmAscii);
|
||||||
const scalars = hash_to_field(okm, 1, Object.assign({}, bls.CURVE.htfDefaults, options));
|
const scalars = hash_to_field(okm, 1, Object.assign({}, bls.G2.CURVE.htfDefaults, options));
|
||||||
deepStrictEqual(scalars[0][0], expected);
|
deepStrictEqual(scalars[0][0], expected);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -871,7 +890,8 @@ describe('bls12-381/basic', () => {
|
|||||||
|
|
||||||
// Pairing
|
// Pairing
|
||||||
describe('pairing', () => {
|
describe('pairing', () => {
|
||||||
const { pairing, Fp12 } = bls;
|
const { pairing } = bls;
|
||||||
|
const { Fp12 } = bls.fields;
|
||||||
const G1 = G1Point.BASE;
|
const G1 = G1Point.BASE;
|
||||||
const G2 = G2Point.BASE;
|
const G2 = G2Point.BASE;
|
||||||
|
|
||||||
@@ -968,7 +988,7 @@ describe('pairing', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
// hashToCurve
|
// hashToCurve
|
||||||
describe('hash-to-curve', () => {
|
describe('hash-to-curve (against Killic)', () => {
|
||||||
// Point G1
|
// Point G1
|
||||||
const VECTORS_G1 = [
|
const VECTORS_G1 = [
|
||||||
{
|
{
|
||||||
@@ -998,16 +1018,17 @@ describe('hash-to-curve', () => {
|
|||||||
'047a85d6898416a0899e26219bca7c4f0fa682717199de196b02b95eaf9fb55456ac3b810e78571a1b7f5692b7c58ab6',
|
'047a85d6898416a0899e26219bca7c4f0fa682717199de196b02b95eaf9fb55456ac3b810e78571a1b7f5692b7c58ab6',
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
describe('hashToCurve G1', () => {
|
||||||
for (let i = 0; i < VECTORS_G1.length; i++) {
|
for (let i = 0; i < VECTORS_G1.length; i++) {
|
||||||
const t = VECTORS_G1[i];
|
const t = VECTORS_G1[i];
|
||||||
should(`hashToCurve/G1 Killic (${i})`, () => {
|
should(`${i}`, () => {
|
||||||
const p = bls.G1.hashToCurve(t.msg, {
|
const p = bls.G1.hashToCurve(t.msg, {
|
||||||
DST: 'BLS12381G1_XMD:SHA-256_SSWU_RO_TESTGEN',
|
DST: 'BLS12381G1_XMD:SHA-256_SSWU_RO_TESTGEN',
|
||||||
});
|
});
|
||||||
deepStrictEqual(p.toHex(false), t.expected);
|
deepStrictEqual(p.toHex(false), t.expected);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
});
|
||||||
const VECTORS_ENCODE_G1 = [
|
const VECTORS_ENCODE_G1 = [
|
||||||
{
|
{
|
||||||
msg: utf8ToBytes(''),
|
msg: utf8ToBytes(''),
|
||||||
@@ -1036,15 +1057,17 @@ describe('hash-to-curve', () => {
|
|||||||
'094bfdfe3e552447433b5a00967498a3f1314b86ce7a7164c8a8f4131f99333b30a574607e301d5f774172c627fd0bca',
|
'094bfdfe3e552447433b5a00967498a3f1314b86ce7a7164c8a8f4131f99333b30a574607e301d5f774172c627fd0bca',
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
describe('encodeToCurve G1', () => {
|
||||||
for (let i = 0; i < VECTORS_ENCODE_G1.length; i++) {
|
for (let i = 0; i < VECTORS_ENCODE_G1.length; i++) {
|
||||||
const t = VECTORS_ENCODE_G1[i];
|
const t = VECTORS_ENCODE_G1[i];
|
||||||
should(`hashToCurve/G1 (Killic, encodeToCurve) (${i})`, () => {
|
should(`(${i})`, () => {
|
||||||
const p = bls.G1.encodeToCurve(t.msg, {
|
const p = bls.G1.encodeToCurve(t.msg, {
|
||||||
DST: 'BLS12381G1_XMD:SHA-256_SSWU_NU_TESTGEN',
|
DST: 'BLS12381G1_XMD:SHA-256_SSWU_NU_TESTGEN',
|
||||||
});
|
});
|
||||||
deepStrictEqual(p.toHex(false), t.expected);
|
deepStrictEqual(p.toHex(false), t.expected);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
});
|
||||||
// Point G2
|
// Point G2
|
||||||
const VECTORS_G2 = [
|
const VECTORS_G2 = [
|
||||||
{
|
{
|
||||||
@@ -1082,16 +1105,17 @@ describe('hash-to-curve', () => {
|
|||||||
'15c1d4f1a685bb63ee67ca1fd96155e3d091e852a684b78d085fd34f6091e5249ddddbdcf2e7ec82ce6c04c63647eeb7',
|
'15c1d4f1a685bb63ee67ca1fd96155e3d091e852a684b78d085fd34f6091e5249ddddbdcf2e7ec82ce6c04c63647eeb7',
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
describe('hashToCurve G2', () => {
|
||||||
for (let i = 0; i < VECTORS_G2.length; i++) {
|
for (let i = 0; i < VECTORS_G2.length; i++) {
|
||||||
const t = VECTORS_G2[i];
|
const t = VECTORS_G2[i];
|
||||||
should(`hashToCurve/G2 Killic (${i})`, () => {
|
should(`${i}`, () => {
|
||||||
const p = bls.G2.hashToCurve(t.msg, {
|
const p = bls.G2.hashToCurve(t.msg, {
|
||||||
DST: 'BLS12381G2_XMD:SHA-256_SSWU_RO_TESTGEN',
|
DST: 'BLS12381G2_XMD:SHA-256_SSWU_RO_TESTGEN',
|
||||||
});
|
});
|
||||||
deepStrictEqual(p.toHex(false), t.expected);
|
deepStrictEqual(p.toHex(false), t.expected);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
});
|
||||||
const VECTORS_ENCODE_G2 = [
|
const VECTORS_ENCODE_G2 = [
|
||||||
{
|
{
|
||||||
msg: utf8ToBytes(''),
|
msg: utf8ToBytes(''),
|
||||||
@@ -1128,9 +1152,10 @@ describe('hash-to-curve', () => {
|
|||||||
'09e5c8242dd7281ad32c03fe4af3f19167770016255fb25ad9b67ec51d62fade31a1af101e8f6172ec2ee8857662be3a',
|
'09e5c8242dd7281ad32c03fe4af3f19167770016255fb25ad9b67ec51d62fade31a1af101e8f6172ec2ee8857662be3a',
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
describe('encodeToCurve G2', () => {
|
||||||
for (let i = 0; i < VECTORS_ENCODE_G2.length; i++) {
|
for (let i = 0; i < VECTORS_ENCODE_G2.length; i++) {
|
||||||
const t = VECTORS_ENCODE_G2[i];
|
const t = VECTORS_ENCODE_G2[i];
|
||||||
should(`hashToCurve/G2 (Killic, encodeToCurve) (${i})`, () => {
|
should(`${i}`, () => {
|
||||||
const p = bls.G2.encodeToCurve(t.msg, {
|
const p = bls.G2.encodeToCurve(t.msg, {
|
||||||
DST: 'BLS12381G2_XMD:SHA-256_SSWU_NU_TESTGEN',
|
DST: 'BLS12381G2_XMD:SHA-256_SSWU_NU_TESTGEN',
|
||||||
});
|
});
|
||||||
@@ -1138,6 +1163,7 @@ describe('hash-to-curve', () => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('verify()', () => {
|
describe('verify()', () => {
|
||||||
should('verify signed message', () => {
|
should('verify signed message', () => {
|
||||||
@@ -1169,6 +1195,35 @@ describe('verify()', () => {
|
|||||||
deepStrictEqual(res, false);
|
deepStrictEqual(res, false);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
should('verify signed message (short signatures)', () => {
|
||||||
|
for (let i = 0; i < NUM_RUNS; i++) {
|
||||||
|
const [priv, msg] = G1_VECTORS[i];
|
||||||
|
const sig = bls.signShortSignature(msg, priv);
|
||||||
|
const pub = bls.getPublicKeyForShortSignatures(priv);
|
||||||
|
const res = bls.verifyShortSignature(sig, msg, pub);
|
||||||
|
deepStrictEqual(res, true, `${priv}-${msg}`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
should('not verify signature with wrong message (short signatures)', () => {
|
||||||
|
for (let i = 0; i < NUM_RUNS; i++) {
|
||||||
|
const [priv, msg] = G1_VECTORS[i];
|
||||||
|
const invMsg = G1_VECTORS[i + 1][1];
|
||||||
|
const sig = bls.signShortSignature(msg, priv);
|
||||||
|
const pub = bls.getPublicKeyForShortSignatures(priv);
|
||||||
|
const res = bls.verifyShortSignature(sig, invMsg, pub);
|
||||||
|
deepStrictEqual(res, false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
should('not verify signature with wrong key', () => {
|
||||||
|
for (let i = 0; i < NUM_RUNS; i++) {
|
||||||
|
const [priv, msg] = G1_VECTORS[i];
|
||||||
|
const sig = bls.signShortSignature(msg, priv);
|
||||||
|
const invPriv = G1_VECTORS[i + 1][1].padStart(64, '0');
|
||||||
|
const invPub = bls.getPublicKeyForShortSignatures(invPriv);
|
||||||
|
const res = bls.verifyShortSignature(sig, msg, invPub);
|
||||||
|
deepStrictEqual(res, false);
|
||||||
|
}
|
||||||
|
});
|
||||||
describe('batch', () => {
|
describe('batch', () => {
|
||||||
should('verify multi-signature', () => {
|
should('verify multi-signature', () => {
|
||||||
fc.assert(
|
fc.assert(
|
||||||
@@ -1226,6 +1281,7 @@ describe('verify()', () => {
|
|||||||
should('verify multi-signature as simple signature', () => {
|
should('verify multi-signature as simple signature', () => {
|
||||||
fc.assert(
|
fc.assert(
|
||||||
fc.property(FC_MSG, FC_BIGINT_5, (message, privateKeys) => {
|
fc.property(FC_MSG, FC_BIGINT_5, (message, privateKeys) => {
|
||||||
|
message = replaceZeroPoint(message);
|
||||||
const publicKey = privateKeys.map(getPubKey);
|
const publicKey = privateKeys.map(getPubKey);
|
||||||
const signatures = privateKeys.map((privateKey) => bls.sign(message, privateKey));
|
const signatures = privateKeys.map((privateKey) => bls.sign(message, privateKey));
|
||||||
const aggregatedSignature = bls.aggregateSignatures(signatures);
|
const aggregatedSignature = bls.aggregateSignatures(signatures);
|
||||||
@@ -1237,6 +1293,7 @@ describe('verify()', () => {
|
|||||||
should('not verify wrong multi-signature as simple signature', () => {
|
should('not verify wrong multi-signature as simple signature', () => {
|
||||||
fc.assert(
|
fc.assert(
|
||||||
fc.property(FC_MSG, FC_MSG, FC_BIGINT_5, (message, wrongMessage, privateKeys) => {
|
fc.property(FC_MSG, FC_MSG, FC_BIGINT_5, (message, wrongMessage, privateKeys) => {
|
||||||
|
message = replaceZeroPoint(message);
|
||||||
const publicKey = privateKeys.map(getPubKey);
|
const publicKey = privateKeys.map(getPubKey);
|
||||||
const signatures = privateKeys.map((privateKey) => bls.sign(message, privateKey));
|
const signatures = privateKeys.map((privateKey) => bls.sign(message, privateKey));
|
||||||
const aggregatedSignature = bls.aggregateSignatures(signatures);
|
const aggregatedSignature = bls.aggregateSignatures(signatures);
|
||||||
@@ -1259,7 +1316,7 @@ describe('bls12-381 deterministic', () => {
|
|||||||
.reverse()
|
.reverse()
|
||||||
.reduce((acc, i) => acc + i);
|
.reduce((acc, i) => acc + i);
|
||||||
|
|
||||||
const Fp12 = bls.Fp12;
|
const { Fp12 } = bls.fields;
|
||||||
|
|
||||||
should('Killic based/Pairing', () => {
|
should('Killic based/Pairing', () => {
|
||||||
const t = bls.pairing(G1Point.BASE, G2Point.BASE);
|
const t = bls.pairing(G1Point.BASE, G2Point.BASE);
|
||||||
@@ -1360,6 +1417,37 @@ describe('bls12-381 deterministic', () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
should(`zkcrypt/G1 & G2 encoding edge cases`, () => {
|
||||||
|
const Fp = bls12_381.fields.Fp;
|
||||||
|
const S_BIT_POS = Fp.BITS; // C_bit, compression bit for serialization flag
|
||||||
|
const I_BIT_POS = Fp.BITS + 1; // I_bit, point-at-infinity bit for serialization flag
|
||||||
|
const C_BIT_POS = Fp.BITS + 2; // S_bit, sort bit for serialization flag
|
||||||
|
const VECTORS = [
|
||||||
|
{ pos: C_BIT_POS, shift: 7 }, // compression_flag_set = Choice::from((bytes[0] >> 7) & 1);
|
||||||
|
{ pos: I_BIT_POS, shift: 6 }, // infinity_flag_set = Choice::from((bytes[0] >> 6) & 1)
|
||||||
|
{ pos: S_BIT_POS, shift: 5 }, // sort_flag_set = Choice::from((bytes[0] >> 5) & 1)
|
||||||
|
];
|
||||||
|
for (const { pos, shift } of VECTORS) {
|
||||||
|
const d = utils.numberToBytesBE(utils.bitSet(0n, pos, Boolean(true)), Fp.BYTES);
|
||||||
|
deepStrictEqual((d[0] >> shift) & 1, 1, `${pos}`);
|
||||||
|
}
|
||||||
|
const baseC = G1Point.BASE.toRawBytes();
|
||||||
|
deepStrictEqual(baseC.length, 48);
|
||||||
|
const baseU = G1Point.BASE.toRawBytes(false);
|
||||||
|
deepStrictEqual(baseU.length, 96);
|
||||||
|
const compressedBit = baseU.slice();
|
||||||
|
compressedBit[0] |= 0b1000_0000; // add compression bit
|
||||||
|
throws(() => G1Point.fromHex(compressedBit), 'compressed bit'); // uncompressed point with compressed length
|
||||||
|
const uncompressedBit = baseC.slice();
|
||||||
|
uncompressedBit[0] &= 0b0111_1111; // remove compression bit
|
||||||
|
throws(() => G1Point.fromHex(uncompressedBit), 'uncompressed bit');
|
||||||
|
const infinityUncompressed = baseU.slice();
|
||||||
|
infinityUncompressed[0] |= 0b0100_0000;
|
||||||
|
throws(() => G1Point.fromHex(compressedBit), 'infinity uncompressed');
|
||||||
|
const infinityCompressed = baseC.slice();
|
||||||
|
infinityCompressed[0] |= 0b0100_0000;
|
||||||
|
throws(() => G1Point.fromHex(compressedBit), 'infinity compressed');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// ESM is broken.
|
// ESM is broken.
|
||||||
|
|||||||
128
test/bls12-381/bls12-381-g1-test-vectors.txt
Normal file
128
test/bls12-381/bls12-381-g1-test-vectors.txt
Normal file
@@ -0,0 +1,128 @@
|
|||||||
|
25d8cef413ba263e8d5732d3fca51fd369db74712655a5fd7b0b3a58d8095be8::800134e27aacc74dc91153a6bd65f96a5f8c8365c722da2f1e12eb048e0aed6987fa4168a51241ce41434fd05fd4bdd9
|
||||||
|
611810ebd8f5a7faad47b2249f9d13be0506131db987b6948f1ca3194fa6b643:68:94250c0cc62ae9041c6f6e5042202b3c327991ce4b2841a4145d270f6c8311bc95673c826ada72a6d69e92a833d649e6
|
||||||
|
419bb1de76e11a476f8d5cc5d85a648ec04f24bf75f6cf1f3fae43e57bf9a491:c8d0:898f660c5b26e8c9461ab3f42eb394465d5a115702c05d2a2bc761a8873ac0f33d21f9ea9cf4c435cd31391f5c8c0a91
|
||||||
|
0d1bd9077705325666408124339dca98c0c842b35a90bc3cea8e0c36f2d35583:c43623:94f60dc44a4dbb2505befe346c0c143190fc877ded5e877418f0f890b8ae357a40e8fcc189139aaa509d2b6500f623a5
|
||||||
|
50ff7bd9b21916e55debbd0757e945386b6159ef481d9d774ee67d9b07d0e4ed:7e846556:8d8d9e84012c9c0958018202fe944b4517b618cb7df0b61b1f1ce40b43c2da6330ee0c30a37ac6c7ba0f16aeaa5b99db
|
||||||
|
29a8af03f8c73c64e14807cdabae877cb0f273169bc5ebf17f3e4ef334690656:ce8e5953d7:b37528df8825b94349cfe90a8c8665915cc49e6c41d78e28f8f1a05c5956ee9af850b82e9be756f024e396fd85d9b1ca
|
||||||
|
732fbcaef0e216eae6420eff93c68e3547267b69ca48c7ae9d79d481a466fab9:ae9eb5f425ee:b0adf372fe871a5f7efd30ba8f4ea563460a14651b903789324b78fe12c06b23569766c2d7eecdfb734de4485fee2436
|
||||||
|
4a8135a8847019dad5c1f1b609b50ee72bf5e6459f9c4206ce43de04c2a7103a:01a6d7836c68ad:914a38d1fa13ffdff56cbadd1bd77a3108aae19f76ff2a99d18784cf5c7620d44543045d757f61bdd4fa66780b25eb46
|
||||||
|
0681339753344b5a346aeec93a9b3b9d1282d620a3cdfc4fb4f0e7a075a99fa0:c335129a7fa17398:a01d6f24c038ebc110d742babcc9dd0a32eb518e1e52fac73a3e0a3395012e708112e86a314649aa1edf90dc51007042
|
||||||
|
67a4cad01442be6649e8f3de5b14d126baee62c7525ac61e0b2fe3387e7681b5:bb8a6f6e15fce1f262:82aa70654ca48c6ef55ce3edc88ee77922e1064c763aa50fb0d4a2e8b206d4e14ed849b4d175b096481a6afac232c588
|
||||||
|
1e36e3af518a276dedb69eb0e9df882721116cdb336f692eb691a6d2c7f2ec15:5fbb696cc48ea826a789:8a8f9a764916f3fd5b6cc882f9869ebd1d6a24a057a6e436509c916a9a1e9308e5f891e8e49f39afa0e9afbd3d209cb5
|
||||||
|
5984b05cfa8100d150b3a9a0a0c1e2be149a09e2ff6218b0648651f82b4e773e:5d1bf1b69e2774fdb03500:91703b32c962a8bda991561258c29cb726fea6300742cfe37ed929f68087638169750a423b5c4b465f5498b64ec660ce
|
||||||
|
4d84a172794eeeda6217cf4d10fa36f1b21103742926d4948845a8a0e417d13f:8ec1a5032dfff9289fffefaa:92142c1955d234c700373b823ab4b4b308897218096a88ea504267b26c9330b939191c72e770aaed0af3281b418af173
|
||||||
|
4de6bd9f522e6edf20d0e54cc17cc22f558f115b58478ae6155291e67c28e096:3a5e5a964d6acedcae7b23189a:838d07c7d28c62b1e5aadf8c621c4f360407b3124ac7f7ae3a40a56b1b848b8104f59b4d74e278639e35f4ffa64a3767
|
||||||
|
64fe9caf26b773198b6700a23c2618d36c7382440339a60236e210fc7f61ade3:8873768b317b84b32fca283a4082:b9fb8bc5cfda68938437c17e9f5cb448ca4bb79be278d8f1eac42b9f9b03039673c3170af211c24d7006d1af522f805e
|
||||||
|
2b5bf5af15c13c167173ac0b4750a27cd36ebb90cb0ee90d6168fc81eea0c30a:0a93cd89817651705b4fd414054a44:a2216d350329553d3adc81d0d79d000c0edf634443dafe7c292e8f7193d09facf7a6361e02e5df957021429ae306d879
|
||||||
|
507bf8c00a3364d9f297b3df5f523fc786806b3fc60123d8b231831af5dabce5:691cec082f50711675043ed04233437d:aabdfee018464bba85027210a8a8322f9de64b452d296f31bc8c507c05289b70e8642fb2b6aaa33759d857ece7735231
|
||||||
|
46b4cd59574a6c1f845d2a57d41c42096db5d53ffc9ec8d4b080c1542e24f30b:9a877c2bef8fd2ef71b2852e35afde4912:88eaa4631bb68b510601e6b099376adfe05c1eed52757611897935974d82bcc2751036723bcbfaf29c7f8c09bfd93b1f
|
||||||
|
3e04f740b39a8792e414144a3cb0c8816350f5c4744cf6569f258fc9df82a7d9:e5781adf4d2c0501969d2669619934145ffe:92989055e334649063b2242af5890a445a3d9f5fedcc127318da402d3c68f0ef658d0dc0074579218e02e31cb5ece4f2
|
||||||
|
5ff00a071e807e2beee582b790e4f37ea23211273008e37ca683b34632546b90:75659a273db98e3b14cd464cdfb217823f0496:9721a974cdd68946477db08a4221db9b9c2ca07c01b1daf7307ffcaa16603ee9f12e0ea5e446af292bde7b21f5eb4d3d
|
||||||
|
59c6a3ac6fef4c048486c141825a539e5b65ecc5f0a4425c4aa1015735928f0b:d26e8b19e6065dbdf5a7a50954fcf52e046e4a79:8be8f6ec5b39a43b6d24967009b0444a4c30ad57f285ad737b632a963aa3e9511f6e6ef27a502071bea00c4b653fe01d
|
||||||
|
053840cde56e2fab07d92aad4ca4126db0c79b582ae5b6074336f10faa1ce27d:18277161538b41f2116b62f1b4f15f763db71bc95a:a0350c66b6c72e8e745ecacd973aca076c110b218e0275b34976e7e23a3c834b260256227dbd8902e8454bb1d620e92c
|
||||||
|
4dae7ee2946935ab3799f54a67f7f3a1ede349786ac2169c0d4b66bee8659c88:ff0bc27c426ba610feb7b8d7262d27314884f9e98438:b6b4f053da80dc91f5311b1ff12c3de305b0dca42a84818d600644a2e9955afd4f68f61415ba5e4f6684e33da0fc8071
|
||||||
|
2b36bee50f49a23bf9a01d51e5b67acd8dcca3efb310708a742d93e1cb7089ef:5d9bb535996b1a0158f988ad523cdaeb934a69b043b84a:ad4ffad27a2d8e375549a7cdbfea761712f5b422fbc6d619a2de7b985f4c401b524905adb067bf40e1f1cda75a99edbf
|
||||||
|
364aa3c72c66b518e1bb9f28febcfa56f29ca5825fc8f1bb60792703124a7638:cbe2e518132f31a040fdde8e4665130d05aa7ff233d12bc6:902dca0a36d551de11ad849888e93d91023493c6a87ebe242ffba54e299747f8a122d015135a70a2473dd83f401d88bc
|
||||||
|
49a257e61ae16bf1f02cd6e81333ec3dc3b509843a56267ed0d40191c44a823b:df0079e080bbe83a8c3255fbdd26bf143c174ddcf80c969e4b:a3b5027454751a60c5a1204e8b25fe88c278ae2f29449e77c91766feb55ad81c978562e60c00084ff8244b1d8c02a2cd
|
||||||
|
4f7443821af744a272e3fae9ac7350d6344d61d47bdecd23587f794cfe29758a:e8be2bbfa55b3767413a37778a1940104c4a941e018daca7e3b8:963af9ffa575e398bbbba35e68e8a99d8ba77c870f98a6dfe5b48a283a61ccb19071121398669418f2ebbfa910782f29
|
||||||
|
22144d627be8fdea6127df0dcc8b17a141a41b44041548bd367840e372c8de90:a4c9b9b49bf2267674fd979e1eecce161cf13b5042d4ad769b45ad:86eeca7b5d03763d96bece0a865e315d260db6b6d728519bad150ef1d086bd78848994ed769da6f8ecf5ef99550588d0
|
||||||
|
25682a90cf7d1672adc57afe312e0695039d130dc2fa052174d1754dd6bf6f2c:939f9bcd0063da5bba708f16520a7ded65857ac4824e79ab1d6acc8d:a9b56b5df672c163219eb68807c39911bfdd00a6d413f6f1ee75da967017b2ef9ab99528345ed9af70bccc30b49b424d
|
||||||
|
6f4dc51d61fc10750a53a448b0177ab4ddd4727bc3690031615ef5f3ee9a37fd:b64ca223bac328283a133a74cf95ae4b14d6d68784115dba9af1a14e55:b7c5f00708da137f5e8e90b13cf9b41305173f1a616a31f69b37b89d2832d0956e1e6da88838969ce67d90f49c5d4f2e
|
||||||
|
5ca692a6163c55c4945758e4640c46ff0ca34fb870cdee9e067a22b0c0bdabed:bcff7f9acc78a02edb0e163769d6bc4e3a97e9bd3677b98a68d82c6d3b90:93d2e2d57cfe2502ac87207653bad819fe1c13cb321dc34ac074aaf647f3b1637d00f99a3ff0cb527465d45f6be31809
|
||||||
|
2b617ae10e1dc16e41fae911b14e9c150196912a4e89e20981ebcf472b4dd5dc:fc4d92a56983fc61b38b9a8b10abf5f2e914100ce449d4ff8e0ad586e7314d:864b93049434dd8c32b29c8c164b9ce286772da4e61be06b009c4fdba74f9915545cfe005602cabf6b9dfe76e084f0b6
|
||||||
|
3d12a889a4c1cb6066919f7b97086faecaa640580c43a9df4b8263160177a94f:3f0660a2f3dbc7e532fb7961b7cd00e4b95f5a44702e6e19a04321bbd4fedc02:93070b7ff8f81c45cefa10209107e37d567ae22aa92a45ba1e7a922eab7c58f5c7ef7a77881c8be9de29fad6a3ba3081
|
||||||
|
012d893034dbeb4cd2f4a7e7afa16e885e7139ffb2770f4d508ce187ebd01e1a:ae6c892504739f742ca90a2d94b84e1092e63288f220a5a75829ea83c49cacd031:a910f08de82e243ae5feeac46648d19f51b10046959bed0a887b7a2e2e4d9c5c0791c6ee9769c81a85efdcbf51c408d0
|
||||||
|
417e34572c751f1f4cddb3fa89f48640d9471e857e2424a701aa8d7283ba72d1:0f942d30f2b1090003d0faa02a8b1f4fc14500e93ef0df241d0996c7e4711ccac3a8:a3c9cf0e9e9cffdf97ef6fd8c57c60fbf5175d01b6943923eee9c12861d059bcef315c40791e8952861fe3c04f65c203
|
||||||
|
2a4bc53e3c5dd8d2c46ce784b52db7a66b1509a80103329364b78c5243e3b52a:f387978fe8bb746d7500f470ebb28bcad43501780fad6a8dc116052f93831a205b4116:abcbc4a6f49ef189dab4205790c23c0053474d9a1b02bce3979017137566d21eb2b5ce05b7f9bce8be73654ef582349d
|
||||||
|
231fd161a30aae15d7069ea9e81e06bd8a43c483468f8095cfb4b255128df5ec:dd1e2f364fcb24ad18349e07d6f74353cbd48def87b6a8a7147f3d0a461882a61a9fc77d:b9328c61b63b045372ec8fec0541cc70eada8d99414934a385680d5d3c98dd1aae317cd030c7372c1150c117a405335b
|
||||||
|
0e6dc865b8ceacd9e9e1edf3e146a00de60c08aab08dde3cb200fefc24e41eb0:b19a008107d7d89d804ad8a6cae7c039e3d003fd40b93adc746fbee76af5bbf299076482c1:8ac945e4ce9bcbd1042df2d4f29574fedcdca79d25d2358de9acf2ef860c0fc0e528d13c311e6119b73024bfbdd1ff36
|
||||||
|
41c6a0777609d976880906dcfeee73104a93f8527a23c78d5d7f7917401183db:47766621f49ec5c8235c30275ae2a92a615435d29f6bae651bdc90082a6738741e76ce43a3d2:ad5e2a36345fe3e3f6781e8936dafbd6ca0b0371ea59ba1ecb7091a6c40ede7547a82fc8a28b13bdb06a948446542e4d
|
||||||
|
6e6f8e2f4652e14aaa4ef111d7fc8be7ac4d8ada4d051caa52465a4345181990:8a266363f67331b303b5c4594e222a343ae7f5512d94a6df766d3212d1ad4ec2ddd88e62d88c51:a9c21fb52afa29e1c4a8f993e0cf6327023a1fe00db739bb915d9ab3e3238205bda9bc8b6be2f9f87cc29ff69bff9233
|
||||||
|
256a2028788ae24683db9af7d8d976782cfa323ceaf5db0e62272c222c83d331:23204fef64b612a246c470551a58b7e3c4b8ae558edd55c118001ba74ce4c11d22831683f597169e:a382ec60cea2596f472b8805b0271a0978a125c680d523a1f2d4291fffb01a3aa5d22bfe62ca439573525065fd6ec885
|
||||||
|
37b73537fcbb0f6b8bff910fcc0116d905f0960a2233a564d4cbe0b4c53f88ab:43ac6d7da7b0a419d6c893e9ccdbf3b891ec5ca9460fd70d9b2fb6dc9bd482c835af88922d74e4ef38:aafcf57e5db3c378a4d37bfa461ed23113bfa95fa9aece77a4569cb836cc86d311800e9425448c5d0d4302fe180810d1
|
||||||
|
700fb2aa7050df22fede481f8fbc24a937812ddd19dc19404351e2b5c72dc21d:381d1c6c2357c8fa5a07865e5dd0f76f5c4d63d115a49c24a7302d4cd66117683e549be5796ecd16fc56:b4409c7e09d8c79dc2f7a083a23cb02e83ba3c8f4af8ccfca70ad4ce90991333e4ff742fc912afb0de93610c1ec83261
|
||||||
|
56dbc180d43e8688bece1a617d284f2d3880e570650a3f260e9a3abae32c2c3c:7f62eaa50b2ea4288c03ecbbb42a8178aa1289bd1dcd9bb1664be0b8cf971b023b5e29cf47dbeb779f0098:a3fdcffe61c67de9a482e4fccf42ddb9344c8aa4fc3733ff711750287ae87329a82e235c5f9954a8cc5015ce7877ab9a
|
||||||
|
30a003ea75cc507f2b0861d68af83522b451976fbf9f71c6be340ab4b96bc0d2:bf5f878d46a8fa3e3a476fd161a86d053cea93675f18c30fbaab758a1f8f5f6818aaa193fc37f3fee0467264:8c223b8239b826c91eae0c24327e016129c3c13e99ef187a2abd9d710c33db5efd6e05aa4547252182050e06921510f0
|
||||||
|
6c27dc9a7c6291647e61015e9d1f6aa46a38c4f32086b36acb476af525399c0b:1881b2ada37e78f7883d64ff35ad98de04b98d277104534d3d8ae6ef37fe5c584887bf8304ebcbea472bfac050:a6c834443faf4f7d068e48a9a927f15ad5c68c22cb245bbd206ea772493393e6d01b55a31a227643629098ff29b20309
|
||||||
|
5cbc4de784ef59caa11a1faf1c5919499ca1dedecc92840e19adc121cb2a7aa9:ee42c4b9217735f1d9e32ece935893008d8c4009abd98dffa7c2f8214f26e31467f5ebd125abe9f7b6a62b5789a8:8159b26a583da405b5c5dd4da330d358465268e6f65b82c87683f2bec8521d7eb2dc5e13665cad7ee7f8bdc3a9713657
|
||||||
|
3a7c8b649c0c3826efd2646d01ba9800690a39a58af824762412403838042cd9:9aac7c53d666ac80d21af3f9422bce65ae0588acb274b6efec9b2ea75e7b12848da9f038449a5f8f8ac453af28fd02:83660e10ea5050381dcc5a8d8354f5322d60ade1758734a700221abf2cf0e2a04cda83b4cc85783476304cb8431907e3
|
||||||
|
3e5c7d16ffee2ab46e45da4aa41975bc6ece396a8d78bf3d072cbcf7c3d0c687:bf7f6717ac2a33428ad090c12cbc27dcd12a94e143c9eb46aeb11a6c65e7b09d90dd0da5b855ba80620b0ddf48a3843c:83efa6580768eec9514cb4d3c0c22e6a584aea44aee4f7dbf72bff8375668c9ee1935ba5eaae2cda072e5159a0166dbe
|
||||||
|
67db8b638d15e0f17848dfafa0105f04dc100c6bbbb8ca44cfbd7308497f648e:a4e30c5dfe87cd43153142a023fd297a9d1dde2c996f0cf3253623d5f04b36c46a7a70d815774c99d836cfce29cc876464:8f792b13eed2694c24a97623679c8be7bf325b74ee14a3b7e4b764e4ad402618bc1213ed21b04ee43af0aa0d7117f1a5
|
||||||
|
0c0a951ad354113eb871b3b9dd9db522d0abdc98f09c6caabe617a22986838a6:ab9226d0a78fc564c1c1a8a961b90cfe029160cd71e5ba95e6adc258f2ed491c36456e639d9dffd53a338cfe3190a8ab7b83:b8c474f01a43a045047ad4d8b6cfb7296ba6660eca20bb1de26fc158bd8c3744abcbb9867781f7f2a04aabff7a498b19
|
||||||
|
64518ed6d49e33c45c7dbb6b53aa3ae8032be58907f952b7d6d2efcc9b2b1f75:e7c2ac2eab22fae320a9c4aec6fc173668aa9df68d7ab00a75a65da0b121db6283bad06b131282d7045c0ce50a2c9c786c5f88:86625b564b51dca8139c4178453c3376c08a42621de931c9e1abef3f7e23d8c23a23ec617ecce51c241e25dff8949325
|
||||||
|
1796013211bb13b2f2df46e8e8f430ac043fadfe36b46904ca77fe404bc54b1e:67690484edea6aa1ab2b3a0ceca61fc08eefd1362cd4839827b4e45604911f4f97607d989388f707ffddddf42cfa0c779bf4633b:8e283416d53afb6a1281986686e7f40ee59c2abdbf633e7fd8416f0d7a40e7232ea49630fab5d752b0eddc0849816d70
|
||||||
|
3c83aed296db0756243f1c33607cae018f02c30eff97384b788817ee98e08281:ee9b7b3741e1594515e755ce40998a535e9f2ed7d382714ba2137329b5d491ae8fd8a56ce7a74058131e98fed9b3282961fd11d7df:a353943c14bf9e8553ff5d1627e121e8c0819e4406f3346b3d2c7d2721b192863d666262ddaabd0bdef1b2606acfa75e
|
||||||
|
6ab5abc9b803639a1ba34750c7baeb2c0ba315c96dcf70fcfdf634fc1e5b2197:b8b107a526fc51ce96996fa008d806f29052ed82512e73178426e1d694066534b1c7337dc522b0a59dd50cc472700b2642b512d30707:a040803c3d4f0d631b6396e5413d2ee8e5f088bf9272bb6a53789c6c9b41b12d50357b140825483fa7e215499b912439
|
||||||
|
5f6d5c23ab6996e98a6ed399472d97ceedf551135ed029cf68cab520f6ab2313:37b88c5975d31b1206b769943df826568dca065ff27c17232f5bd04bfd1ed4d01a5f1b0f70a89f3e5dc5af7fc2917594c8ae0cb3908b4b:a6ac886556754f0f99489c7fe92fb1231461afd7f6076584564ba58bd80f4e387d035dd1976e1a815b790d350b2707de
|
||||||
|
1696edc94cdf62da22c85e36c9a18580408040012de878ab6d10eeff6c51f049:72df71d31b9843d13ccafee2580500fbd486a54ed42ef9db70e074eeaa2a496054ad1782f504f5e2a7e65a42249a589c358dbfb3e307b864:a4d11fa6abad203f8ad0aa6fc98ce40b8e00ee652a0cf3c2bbdb3b3934757db0cdcb9368585633e277af90417c2ce078
|
||||||
|
1b61072c204850b8ed425526568e9d57f5f9973cea8499b9d3f3e65ee411f7d1:752d9ca07b296305ce8addc54eaaa7e03472aed19626860796c00f3230593e6812dc8114c125a78e7f2c93bb66a8abd3be431b868579cbd193:afa0a0c0472878e0b97d7e4938ee560d4e5d7fb909228fa57567e01394011339adade27d99097e5f663b5aa56f4ed01a
|
||||||
|
49f8b73e487ea32e90fbfa5967d382f828cb03dea8b6e91420e3835590964bb8:11753040da26b28d466fdd0f88494801f9e2a03b42a671a740bbf7d43e90c38fb383a9fb9992912c171f65c66096de05cfc896e449e18a16e3b9:81ad82f0ca54744103651a5ed1daa464e89ad3fd8c26c4d6a2743f8a58ca3fd4693dd338e09264829f8285494d564eff
|
||||||
|
3d7a0771e3c698956350570578e3dba2093315388fb1958a32e387bbd33845f5:247362f06c8f20e956031eed27d8f3be62dbe2154dedf195bb1f9539aecb0ae77aae3c71e6fee8acbdbb6ef8d68244ccd9f6b5a32de290a4001ea5:8e806bd7479057360710060b40be772789f6e7bc52e7e781e6c82a3877d485bb017e69078c1c3f9be628a3f09e857e91
|
||||||
|
3245ff9022c5f0af88741b86344a9dc9473c4dbb28b595711cd4138ca1bffca6:b793d1c58943269274404568a01a756b7b576659334121dfc401963d51bd0de1cf011a6ab6c5d3c8f6a42ea0bc5ee5bed2f70a096c0c05e35356c03f:abb639f7c6d7e6aedf5b2aa0696f5ba1f327668cc1c352a0b5f713e043f5204dc951571d7be952f34a126133d05e8fac
|
||||||
|
26d1b6697b3189154389abdff3eb2d909fb12a0e8440694b59b8ec5a73c366fb:37ce9416c6e2b8d4944beb6cb3775d296bf0364ea3f6d6ebebde5c36a077d2ace37c8a629d8d8abc8a89cd0e7c1a182b7ce81d7173c3a376615a9515e8:a6c860a4ebf8b54adbca5507a5b8414cb1541283e817777350f2424848d290abf0c980fce31e7d3c93ebe409f4735b50
|
||||||
|
1e384f2be1cbda26e0ff77699e1cb94b9a4a58a24159f6cf8ad5413547393e07:822f7451153b2281f3f89715f1d2edaa76628deb8913c0c11fd7e6ca6783ffcf19c4f2ceebe002b0fbc63cbe335d6ebe3ee39c5548d60fae6896dbc2eecb:859a858fdf08c16b720d5a25f89f7660fdab3f1e4be76c7f36d8bb95b53add7232e06af5eac2f71ed0e4e85fd69f0edb
|
||||||
|
0f6c6c95d4d24a72caee5861097970c074842ca0183982006d0d5b9fdcb65513:67ae1492457369dc0b494a5142c0e721613848a76870d369ab53bc4e7599398cb49c89e08b703366bfb964301e09c7b99350283e31616ecf4ae999fbff00e7:ad5378c136d51ca64e4fa7f21aa6732222622b80f30c5dd4ecc572e645a9ee2001a72b43284658d32ef10eb4c1018b95
|
||||||
|
11fa08cd0740c0c37a7c0269215f272855e378dd0f8d81f45b99033f74b721f2:bd8b3e41b647eba1d285853d9254d1f121b2371d3e38c67f31a9d8a718c7d7898664dcf216355f41ecaff9f73f77c35f625ddd7a7614ac7fc4d1754778f84f58:8b02f921cc83b296ef4cfc6baf0ac306567846012223a4bcd89c532eb5c39c80e35e577b368a67b8fd8e687325350fe6
|
||||||
|
6f38baf1cee3a83a4a99b403ed5ae143233d5b228c80b9d421f5772c7439b05d:3fb1e8ef6e99240cba6d89e6642e402e18eb3c135e104f18466b95bb90258ac84b3fbf6327fa6cedbced6e942b64d4d636e40b59ed39d92acbdb2933014f6e9b44:8f82cc3207c5880dd276d59ea1b42e194504b8188467587700da208a6459ea00dbdc3dc54ef3105489dd2c71b0f30fef
|
||||||
|
5e653c12f6483d2fbd963ce05862562ac3843884d961298f7ebf65f05e958d1f:547ddc66f31911b05895c2011da903eb00feb4b1d752ccdd4b862a27ad4b0de4832161bf6b3e132dd0b238902deb0ab8e7edad34fcdfd959032ae311b7e01e40f32f:a12db7e5a27a1a581a5e601d08e907e8ff61cee91a27638e177e048a408a67e2224bf16358c24652e0ea768979c506db
|
||||||
|
08073f9d18132bece9c3f23225118fd7feeadcc0266c1861231d01990f3d3018:1c028e2d3b3376712b2203d418b705b6d317a03c9c257f104660f007737ff11b3f430182181567625f4afdb6358ee862aeaca19c67b3b253fed777595bd79f4f6b9d26:b2adb57dd304ca200aa95254c790784635235ec3cc418ba0deaf0efcc6232434705b00e29889f4e259e704ac4f353633
|
||||||
|
691ede2f41856cddd0cb79cc89f5ad5bfa16c62942b660cb01bf5cab13a22d98:a76de84ca3f22c96b2995e2ba8474ee7f8d7f36aba70f46f26375c1f647fa3bdfe05e13c9b18f16b7933b6809d1cbd0fee5f0e1b780cce726a5c414c406f54e090098345:85dcda6d83ef31d423bcfc1d87444a6226ebd57018f4da52ef8d9e7b45c100f9bf36028bc9b0537b4baf240cf11293cc
|
||||||
|
1a518478b36de27cdb26516d1a96939a515729bca7c51c1f1e240974f3aa73f8:ec6d1b89686f1692c0fb79f6ed782bc1265475764946494aef7ebe64572bbf70e34c72214c276cf9c3c1a1b3b22c01e8a1c1c709dbdd97a199dd854cf7ec23bf564a3d6f16:ae4fd56430e237111e2886d09cd7e5f37f959d32ffae5f87ec51fa2f7bd2faa2c0c81fc60e98bc146f236929def7fc5a
|
||||||
|
359a75965e374ebe361c795d1d7fdbfe40c5709227289966c65d93ba68372832:bbbbde79882192bb916805775b36b769e652a80332897ce32f4757bede663953b40be828ec62b717ae7d3872b4baacd37bbdd85f3c501c5e11f0c738b6d16fe7a66cbf18704f:8d498db4b54bd914a9be4cf650a988e063f7d016b7a3bdee3ce330d9ab4c978bcac3c2958afec8e67cb1e244fbcb1e05
|
||||||
|
67dc679b1a67908eed7a36e1b20a557c0c1eabe7eaaae1cf8e4899da020dd8d2:c01d86741a47ca1c78edad008b24246ba9684e5f12d57ff8659b8453c187efedb4a2f697f414a823f72ee805554fecfc48047d465592c6d8425bd9ab7a1135ac370a22478d52df:9520a5b80e5569a2b07b2365ca780dfee80ad21e12a904e9e974f8cf183ae1655f2b95a598f9f80d6b9bc52040f881df
|
||||||
|
13d5386a288b72437a9279c0caf667533ef11f707ced34362eb6a4570be82b2f:55ce5ac51a3b5da8a128f2e00af927584e8b59694972ee0e6f95e012c308a180e339121050c56a8a900b04fbbe9cddc09c4c3a234d30885da9833b2bef66754015e81b5413d98652:903b042c823a494e6d833dc6f7a0050d4750f80e8b68224712425ff086239b87ea5fbcad5a13f69d7ee7dacfe47e619a
|
||||||
|
2b7969fbf66336b8928f48f6afd3a161254ac01eb4cf94451fba62d9d475f6f1:f53eaf6b0f992c803b28d2984ac74d9292763b8ee599cc0cfe8f135f89bca18ddf87db85d0914760a55d52aa4412008217f836c8517f8dd7390ff82d47ee6a62a306791d27295761e2:b37da593bc046212fa4d0ef084cf456ca7d3fd165ec863d2e980472c441f597a0aa858bf368aa4f4e77dd4b8ba071e69
|
||||||
|
65013f0a26a6e628f8c598af20dcfee2b9b5419e393ca6f832cf5d97a6ba34fa:227d5ccd9bbe4b7a586aaefd083b6a674a126ab864f5d90826cf7e67c4dbaacc7994a1879c50ed2752667066dc00006cc3d47ca53bdafcda5d38995c5b66d95b68c142da786339136332:8204f9b1e6227be7c64b5e629e5d75bfa7bfac17b2cde876ed57ace0be3da8c108fed9c189171741f2840302f1756456
|
||||||
|
1b942e9b54bc8eb2ef0a3deaec60e3c37955a44a3543b9bc0980e16675a1f904:d47e4fe5c7f225d00de4dd5284bb29d2ec57fb8a854596de15669a80e3bb8b1d9b5cb0251f1142f0d5a4b58d2b1090d94799be1d38a7ad65009cd6863ec0e5020850e1b09e5c502a12e23c:b03e1643481f7fd0c98ead4b8185100cb20718c7d4b816aa8b8b3e94987d0c1cb4558860d8e73b198a1655d1138fbf53
|
||||||
|
19d8a8169d57cc62ba1e4c4d9d22a45d0b2280945b2462f031907cb8bd83bb4a:e3ba46786a411d27a815d8fbac5f44e5cfd6f4ffe799e978d606235fd0ee14d58b68c8fd06845632c0030d1d919c90efbcc42a69b22afb1cf3e503f9a7d8193c8d3c297d7ff25740e483af34:82595dfb2e1380680208ca15077487d563e4c02381d2f4663498ee5798307de8391b2694089fe62c9efd1d2e5cc0b089
|
||||||
|
1bff7b1d26603e3f6efbeccdf394ed922e7a1c707365496113d3ad6fcc871195:145b190cd7bf22f6c45aab5e7cb87cf37a4098c5ea1b0d8df9837bd776551f4dca8bc6a6a830ceffac56033ca67d6fcf1f31794abc831f9dc83505f0201e52961fb4816ab21974ed05241eda1f:852af6a672913c27a0e240b7246399e4d23089e4ee727d44ac9a0aa3a7b13b100be82abf201edd35e3ce8c4f506ce484
|
||||||
|
371c2a48d2cd9ae2a13b3dfce09d7fbc9a01b61cf328f096fa87dfeb9e3ac883:785412beb888a53f807e537200ae520df044246aeaf2f86e8d65dc3a30056b57056cc44084fc2762069c49634cdb557cda102d5a7ea8a45bec6813738481b3e5996367d80faad7138791d510ad81:9616060a912f463131d3c0e0c9b5f8e9a40f6cf00b9d6253dd105e77604a687fb2ea7b466ee9421833f3331c25fac1ca
|
||||||
|
61d7787ebbe947d746063f1599c9313f8df517be1494a38cbb7f196a31ee7cd3:4b797f6782ee555113b5ea4166e2c3a2cbe3359256034745c66e59149b97cfba790bd091aa6f809721d6341acca9673a47f34bcdc08499080e30bb1e81defca019f62c886677577ab289be4981436d:a337aa2a22010cb98c0736df043acf9a01d0de654448f144ccc6e35dc53b5f6cc78583c5a465b282ae8add2005caed30
|
||||||
|
6a1a038e5c2bfab87ad3cd29b808c8e7a8b12961f7722d62d4ff7fd8936c6eee:2fc8caa666aeb84beb71d7c6918a8456a23c406b1378a6476607e4b27d651c4c9fde2c8682ed6005ca757dce710c4451372efc5886972cfc89f1eb7e19d80648b9869ba74ca305c6f88b464388ae3f72:9876a586403cb4c0f2b56373996ee524a489d4ded44df55b7db74a749ab74795470cc0a66a6e58193730195c5c444e76
|
||||||
|
3f528ca57a9a03e0e1af999cff2a602d43a8a7fc9774a5b35b91d46ba2332590:5c52e68adbf3a47d0352d333bca88b4559579fe3dc2efe7369fce4c10acea51c4166e8ab22d243741d7e2c2ae49a0ba35f729456f8c37b7bd31e858205a968cc0a6e5afaf2b3964b09619e241b3438c6d7:a2b1e39069444e3b1f14aab6015a6e25543ed0baa4a23ab6b187ac300c54d433580ea036af283a3a25d5421a945409ce
|
||||||
|
1cb19f5b2b6d2d76b26eefeb36d2995bccb77a0048e886b47552b209253e04d9:e8804b79ae38a9ad21cfd3e6e538b9bce254dc020dd42ebd62d4f282fe5da900b97aa86d40d5cab39516c74c33b769ab3e0a644a63a97c4cf9b59e55dfb42c1df038b1bb4ebec3d344ded09a5f90f4bafca8:8c37c7eec66b0c88268aeb7326e85d30a2e8e851750a74aa95870a7259d20f6fddab8dff3e0d4955ae79ca8e80fb515b
|
||||||
|
689216f2c9e7a748c94c898640d7f95d57dd0582eb017ce04351c44f10265472:1b9e066095b608967db1d6b93691bcdb4417f6693e6065186fbd8d1ed5267951db49d215328044d35e3555f6e1ac89fee959625b6bcfe510fe63bfd05de60b7e1e9fb5df9e721141c65bcd7a7e3363e1b5b472:8041368450aa99afec459dc86fc883d9b0ddc846e63a826b93bc07cd64e3520cb09ea5efbd049522fd049f0ab55fb61e
|
||||||
|
0b32a4f24c0c259951660e96457c1e1fa18bb7928c4796dd085dec96a99b0e37:01db4eaaf51d3322aea498726538eac137f248085db057f1faa77fdc8091e331e1d497b4b3276a51a5dc420af871a826c55dbffac511afc9319e9658e68de1ea204808c282e93100a29df7b089ae5551ff2bf95d:9634bb34b8bdb100b233df021f1d99afc8c9c9e8e76a7ff7d3fc62d733ff0819df55e71cfda092f54505a98783f786ea
|
||||||
|
04633de27fae1f070ff87e490e10528e9b40857b5109175a64543eb0ec6c82b7:85fde85aa169a8e44917086910fb1a9bee9f1b30b2d29e154998c6d659206307b5b66a1a3b1af3603becf751d37605e5b1c110578b2094062ad1e62ebd3bb75121d3569bca60bcb26fef490288da106258b904509f:80db12ebb3064c79d372d4779d4900e10c4bd141f109ecaca9c25cb3e789fa4cfd727ce372b6845c956f206f6a73901b
|
||||||
|
44dc2ef437107d48be57678f252e523a08bf63dc720da85b8da7486e875740b2:ee998b1edd10ffaf7d3eb7b163842726e33116efc46d77476fe2d3e8bb3b79f44f065e9bab6d1b9a32912744c2b8538ebdb8dc634c58ed19e179a889d7ca53983eda22ca0dfac2e5b6761f5e7a129a950dcfadc27cdb:8c7cc3d5822bc3b6ff0f9be230cf9fe91f5d86caed86bf3ee8679deaaba06b545f1cf87f63fc601a56da381e74b39e3b
|
||||||
|
5fae658e1beb5ce5aca9025861b991ffe5f0210562e0383a89372c3e9bb01683:391cbe0fbe656e0ca05e1f7ba659d7b931c8c32fc1b4a7477128a3d36fcf2e04e70f930fce6c42d667595b6870da22b29c4b667e08d905f9be6b94d01c5cb6d652b44fab93ec2da57edf40234c2998581fbc6bef11f098:ad2d3e2f04aee369179540b8d78d358ab6f49f03e540b242505eb0e9212d48843e3a4de840cf6534e8e492f4af7468e9
|
||||||
|
3c47c2af3e6fde7084b94f7125003b4730274dc73da91c3a6436a36a58b2d371:34e74e595a04107b38cffc124b941d3d549cef01e3552a75487ed3f1f23ea31046fe6db758683e6b9f034c5d4c63b6b7e92beabe3b7d599efb98250b4dcca3aa6515456b6b19ba984314260fd115b0e12380a5e68ffbcaa1:b140516e7bf5edf67a20fb360ab2932e7af32f38f669053d9fd9506453e71870ad598251dac0ab34117e4562fc946766
|
||||||
|
2e8e531b369ccefd7ac3e91b3a5e4dd671db1b2a05863e5b8170ae0dc27840b6:bbb0b60a66dbdc06791effb0aa45b5e4dd40777822a00aa1e52dbd7d0ba9cd30797612fb128c7c7debf3aa24a4967ab032180a527da239f913bc3551050b23b972642156240d2e42265053cf84e5d870fdb7a1c9c6f4c185ae:90d33306d8ccbf0b4c2f439e59d3633118bcda2a2fee59df40f4dbcb15a5b07c3198385a5d635e0eb8abdf005fe68996
|
||||||
|
4f7f6c0df5d8fb728033a4c7927b121353505ed518112592381faaf17bffe927:c870ba3e0fd1477ef1140246404729dbc4b516e32dc033abaff6149b3ecf4b932243bf9257c26777e1c064b7f3c64bcb3a5fa2e3f0fc7d40bb1b20636d90bd00536de78958c64893fe07a2528f806e2811bddfae9958b241c026:a908968636312fda482872680603307f1f5549e592eb611517e27aa9fac9e9f509356105a5e4fa5013d97613a976ffab
|
||||||
|
0feea23e93e2bb1c9714af6e8a125b6fb179dcc24b2456e40548061359e83034:b927770e3c3ecaf04844ede61c8f82c5394a636a9b481245f03cdb0b6fc75b5263e65a3dddbeadb8e5699edf04fb6b5cc2aff7af1a2b4c042669a9e3f03c0b564fa378ea9332581b8851a88ddd08f9959e0b9f66333ed081733d19:b9e40340b6f649a87312eb663694e24ddf4e842da1c38e5ed90185a61429487877463a9ce0c091f6a6803daee43d0480
|
||||||
|
26af207030b1958690b8da361e81044ab71b4ffdfd9a26f853b090d1c3a0da84:84f1728578942b1f41af223ac189c0de40fbf013608711acc97568ca4d5eb3f357ec7f76902a0b59b94d28959a25c832bde18c56ebe2749e684fd7bd1d5cabcc3ff50088271bda5b12f8cc79e53334ae997493fbc0bda2c56e27acdb:8fb67df1fdf9759139547dac10312170a10d0e220cf83e74a321778198f6ba6f93fe2bbd7e64d061392a195e835f97bb
|
||||||
|
420560ba6da9075a590bff683af1b816c6ed855dbfb89e584cb4904a1c3c18fc:87b7039c154b1ea17e34125afc51b31eb1882d5b0a27f800859c8570f7084d35d9edeeb285aa034bd0de63c85b9f22fc39b6faa69f6d420dad742c0a7828c0e5c16f9dbe93db95c8baab1b20826af7f942872e5e78345b9346a1baf203:a748c3e20476dfde9dd8ae0b1da0be834938d1a3843a93acf1e24a4dbcb808780d0812e78707326f23919f573b529883
|
||||||
|
23d5808d404b06f00e2e97215d55c84b735c4d0552577d842e0138431f69aa4e:528f09550299e52818e5a3af380374b63615c820ee972f8af249167d38c76ff28ce387f6c8712c6a21e529a048ddce22e794f221f8da9efe720e793624f66b5fde02c12c3fad14324dc7923ca6f44b7c610d5ce51e456c3027a303c71b9d:afe5949e2d7d89387864394b31745b922b4a50f7c08a1f092155007b700efc0c4c0fb3aded7c764b4a89d4638b55e033
|
||||||
|
2c2d04eeaa29b0383ffcf3607828ac5f39ca1ab6bececaa6fc8d10c1896fae79:564a760045e175bb5bcf5199f0330c9ee8a9178d7b7e2b574b42c4e8f549d63f05729d7559e1dd43431ef6f0e78a05ab1e676d8e9e972aa625feba814c5ac5b6aecbadcfb926c8de16026fb25d66d347813e636c3356208a704520de0a2f0a:9983cc5cbe5a8bcbe56bc1a71b2ca5b4a32923518ac2959aff0949c28af4124658ebb111d8fb390ca2afa50f089a3e75
|
||||||
|
6ea04b1ac55b80bd9e6f19b34eb635f6f40d65603dc312bd976245aa3a7ec2e9:94ed5fd16860d3062a01b1596040a0d60bc09f9b3c214ead3403109ab805a23210fd385ccfd5a65e80488dd13c1993fb2ec65d1093c8d87095c73a74589abd071bf41a645b0f177f3561165ea3426d29cffcd2315855599bd1dca971a026c906:aa7526a6ba48e05d1be7150815fa8ac4f80a59a08f44b2b7d77c8926e17a058fd6436b5c681ce8dad46351155217b87a
|
||||||
|
272d038fdbc32dc27d9113e69838acc52d61e764a00dec66b9174d1296734b8f:d58f636770468f71344828aa13c8b5c7dcddfc3c00d13e6480102ce6d4a2e0ef04f834058475ae8674b5536c2f5bf1a253a0fd54a36247abb73d1bac90464c214e871bcf737b269045ac59fd176294cdd0a3ad01391d1fd9f1d44db5ceb36244cf:a53737c41fd01aea3fed126a1ac8dab7d7439df0338ccb90f20f7173f3b210da7b3c091d90cd672e8f38c7b7864a56b1
|
||||||
|
62a13093e8754c1423e0f7e73218eb645f38cfc64b072bcbf2a0265946574329:113d0efee5cb3e1f678e684ebe613889dedd0a7820e8120926f4979322ef70bcef21cabcbf8a974eda198deaaddeb7ec5d0f9220f1706aca8f1df10340ca8d40025fca3688ccfba6b010b59110fede77cf0c54b6764756551e99d7016a6728b935a0:a6c302484226d30ab4bb5331c138915c34dfc1bb1a634eaa741af2aaf7a389e4945083ea2ae6ff9142f7010b0ff7360e
|
||||||
|
328b4abd2dfe8702172058f7ac506b1974a5911c4a574e3130950044214c6fbb:821030677bab3b8219adea5fd2fda6987be0422a47acadb76a27792719865f21c433b53fec7cfafb044240918492c7e6da4a1743fe84a472411beaf7e3630862e04c5b53213bcdb7dfe1cde18fff29d049c191f8b72bc8d1fda7a5c57cae62f9c96824:821b0ea7d9ba44a7fe751d380cdad155a44c20959c04c7caa3489983bf25ade2822e53031ebf0ccfc5a76b83ae0344a4
|
||||||
|
3b23859211b5eab5590185e6ae39a645b35012906f894108586824df61906152:8a25a986cc1df8d66b18a058e697ca2df03abf385ec0c39eabfe89bd340046c298a5a2752a7f555a5fbe3a5cd51b7eed0d950ed2c9c5e3a093590fbdcf3e41496ab510f238019733cc43f3a19f0773bed46d101ef847dcb91260ac36dcc7bb11c405bd8d:aaf17bb51a15ecf27d7aafe6a223eac092f257d5aac5d76b989ecb555251d7989ec56e46e7cbf6f68d478dd37d74b740
|
||||||
|
40a563397ead8c7bd84fe395aaf3994ee4b0373a8066e5f6ccd8b01a548229fe:38a06d00930a6247ff7c2ab303dc4f88e07d55442597c0b063ba32ab9dcea20748220f88c7354da3a5d21708b7a01491d58280434914ed16cf64f65e83e2bdc000491d719a5aca31f86c3df94559df1ae950a9d64d948a44f468d87909cb1a1db15c8d5e14:953ef1cd533f2986ac1bc2280ebf4e2522521a8f7b8c2689f04c133f1911405b0b6ea46f879ee7153f99f71d888c4b7e
|
||||||
|
02b22feedeacb437a6c10fd8867c831ff07b370aa287b1d57dbafe34de46ee05:dc59ca5873612bf0e0b0039ac451a3fd6913521bde999bafd87beaf2923802ae09630c05cd07e9d3e8c8bb3497f5a5fa6882d2e6c221470728dce51d96959843e799f02e5a64e1b7d7fb8c9b0ead75e7cc748825be932f735e4b639cacd8d32e0de9242e78ce:96bb0c83dfdfab8b9ecc8b360b3ba2642e285531b4e3ba861ee5169f48d9fa8bd4c84aadbe433ae3e3732eeaff15b9fc
|
||||||
|
58604274117a63977ca1d67b67fd59ebc9562d603f8ee39a02e2e83c2b115f42:769e80b21c38e39215d69c1f1c485ffee1023950edb5d375cd30a2c0e00890a952336be867909c9a55daa9ccf48b9ab5d874bac77635331d13effcadfe2dc321135fa8922c212b81820e3f49045f001f746321465b91d6a0ed34632cc1529848e7ef9fbf41f7d1:8726065a9813ad3449498ddfd51ac0d35e103d05b491880d51418b2782061e4f034b3034880e49c7dbe1e168226dd150
|
||||||
|
4d462264104d551ed98c229ee16d4aa4df79bd2fe3151554b0adb12ca48d2753:86863eb1262d36d8e51130f7a9e85229828a35a458cfb810ec97020df5fbfba89568a81bfdcd6014593cc1621da57720c54523720398dd58e006b89747d75e6eeff0d1d7852f79afd83907f7749245e64a5023f14d4ad663a2b41927ae7f77c3572fa2963fe19615:afd58b032b13a3974494f15d2113a7acca322c50ee686c763948b999641e3334f970ec89c6235b65c59edf5f1a63fd84
|
||||||
|
4d7d222d9de5be19af35cb1a31f556efff92b5afd8e92ddeb0d6820f5cf4103d:8d03abe66a28da061a733753df81c97d5abbdf1d324aba4e4276b43065532f48898dbf7dc7b87cc40cb65d6dc3db0a2a7f084240360dd2485ab44406f1ab90a790d851d49a1cf78cf4dd218b26e16eabbc4f0f7da27d0573dd30032e01134ca7e3c9569eee3b29fcc5:a915963bc69bcca6ac41a68d5587d22042cb44dc9bb58f85448818420126a9438cec846a72ac50da1f1a5bfb9fddd5e2
|
||||||
|
6f2091abc6dd00690688ae8e0644b30fc8b8f931a716ba6fed186981673f929e:cea5ee44948390d5d5f3fded51538f5fcb2a6f3a79b88d5df17f0de46280acb25ae5a918f58275991598f414f6f9a00bea7c30555057a6c04393ba1c9ad6ac555d450b96fdc8abd0b0f6d280ecb6594e021f776415bddf392e6f96d1f5ea074ce6ef81fbb26d3cdf8fe9:a4254a9388bcec6d88f08da8f18973bc381a3065d4bd3cd8c16468e073970cd6508eb77217a9fe3643dfa471faf374d8
|
||||||
|
462a706b92aa64cc85b9e376b5d27cd62f970ec3b7edb817e5b7ac6e239a0e0a:73ef7f6ddc19ad065a9000768ceeae6c455a41281fc581ca31ddde892669a7d9cf1428abfe9f32d410103ad8ade80c1c7d44aacdad110ea4011750aa40ddff3f959c13b04228a5d9f4e9b6ca71ed4f4f06b9995a09050620f18751e18dbf22e7b1793990ec8016717e9be2:b6747c6b843526201d6153e545d3d4fc270da6979d8a9ff291e36b41ab43a3c9308215f3ecfb8873a491bae22b5df37b
|
||||||
|
65237177f0ab7dd39df8c2345e6f56db27159988c7751646bee0dd2cb35f43d5:f473dd71b0fb705be4b377aeb7071bef91dcd49ac24ab5e2a593ef6fbe402b70bb2db06178b3fd6ea7c5a8333e09e721cfea23d63057a363050a0e3afbbe6b7f0def485edb1ad7345cd1cfc52fef5e688a4b9bc205307699fc22fa3fb6cad8ef9fa3eec1c013285417ad256a:913c8c823160436437293495f66e6c91022530e4c9505d25b3cd174a34c4981147d9671f13f84cf85ec78b800d3b07e4
|
||||||
|
64a1fe88f385b2d200a3dc9a5e985a13a3c351d8af112cccbdee1bb62c780688:8206710e7302d8167d219794244b11c906eac5c1c4478343bdd4e88367e18a863423a0ac012ccc9358e76be56a973b4336c81e4f31b068a57eb72c7ccb58d0bd9f9782e5eab8e4137d225b875609ef530b26d85b7c552770c66df01396fad7dab75302acb4c27f752b75b0ce49:96df03f30fbe2c5da70980d45ad4024067a82d4796de091159c197ce448d548bc5b3bc954d18e348bad62dd3c2bcab39
|
||||||
|
32dbc3afc15773c332a2605f24ce2ca3df38567b17a3c7566e772b8fa49f0db8:049f4b3cec24969d680486ead26e96798af64b7a12bcf61da12004c72680bd4f17570d235babbd92cf00037b62da694d16ec1ab11ad22861b14d128c83d9e59b182a264b8fd01d3e69ca91aea576b02ed3038f330c148345b621c4c0fba4ded3003d5b1aa1aa13c1659a4803514c:add4db113f3133a78ee27610aece4df4ff99946b4241fe0cd125025623bd7690d08e2969a59878f9feb4f82e9021772b
|
||||||
|
50034db59355c0cc3205033a648315c297c6bd57f33c5335a66b6d0dd3ce54fa:8f15974518b575933f99af74fa1305c13c6ccb5b004e379c3df457e05eed5e03aacff98d3dbfb5f4b0ef54decfa025cf83765db9a4c9d39054b3e146ad0b4fde2e4a5c208b698d2ba3842544e9df5f6bc17aab787127329bbe8b45ff40245d77e88f437637cd9a1b71a9ca0dc00b77:b32b1cba0fe06dd6d780bcc1c631df9721e8d3fbcaef372da23f40bdf5f6354e366728185e41e6d2dc04ad3e01d8b4d0
|
||||||
|
6294ef0407265a0d19bb3ff7530babd8e32f10a34dff0b37135cd28e82984a8b:f822e5229abe4eabbc054bb516ac3586e182beabdcae28d33336fdbdd23cda050e06a33e03e652165c4a5c32734138126b970308bf20086e9074a3bc8a9d5bdd391fdf7205b21716ba441782fd91245be12ef7a68a07e66b22ada6235f1b3c480f78ce4f945f3b7f985d89106831adfb:a58f90af0ee34e2bc2d13ee421aa90d80bb7c2007cce5b65ac0991a0558dc3a1ea46a8c55819bff404ab297c6ae45066
|
||||||
|
527fce2b29171bbdb60fb573e3639342633b1266e3f695ebce316abc86dd371c:2e549082f9eeb2534d30b90664e5091cf3411ba33fe14e1d86c353837cef4ce5178a59c68f6fea06507291770b52c8f8f28c7791961b2809a0ba682ac78a36de351bc0bd0c54a2916723d5ff2be3c73fb754e7bef4c0388f914ddd31b0f27581369d7a69b78dffc0018f2e1cd9bb840891:a94d698e8362efb86b25b7249fa09c5e627b8f976793ecb85d0f9b06e2ff8077ebafcc8ca104ff869e29f403d9cc9dc7
|
||||||
|
5a03fe3b4164b562d93e129103200ce033da05153fb1a1dc35452c00c8133f6d:7be5bfa4f0ae60a0c2f5258de564ea6f6a42ccd2802928a3fd14b513262b040d78825696aa9e3891947625af2a8e5ab0f663892eb6afc4d463034ff5e7480538f7b32f93f1cb326a52af92d26305d8f3555807597cc66973d29421ce1721872753fa882a3665536f7a9e05ca536b11f8cc4d:84b36b5b7ede2b059a87e6f6b8d7daeb253b9c39438ec407b5885d4186d958e9388af554e236475642eb1102f774a956
|
||||||
|
6136e51d3eadb2a46fb631b099565e6e3cc9feff15f33b9c08b49598d4a664f3:c72773b9026f66fa1299f4412a3e0df893a53a1f9c890a1cd653097459691b72387acaaf5574e293f83820117dc074d7396fee2ebbac34fb69a14ad5a528c03ca409438047e02e9c0ea765c200e3b482224af6874e03484ae19595827374b6eb4ca23d399e9e66f2c8a3732a3f2a27a796703e:98b9ad1abf6655723b2d685b84cb29861d19f8244f505a7ae4d2e4cc97eb203fadb87d2eaec040b07c100b5a790f0432
|
||||||
|
5672c6aeba5dfecc8314b1625f509a4e0dcc36846035bab283e547a5f6d1d4f4:92ed1627ec780c62d968d13bcc181dfaf6470fc1704c92cf7a068a85eae494b7630159f5e044f42a9a7c02e2dde16c8ec81eaf650b4ded6e6cb4e92ac5e54ca4e0d69a4ad3c6d93a0e91a5eaafe989c96c07f5785bdc0b73295eecac04cb71f85fa3744da3cefb9689674d994b52f98ae6a4c784:ac129ded0f581e58ae8f7616633712c68194923db58498290a267552b2885715e437f9414a9b9fb99080f968b56d836a
|
||||||
|
46c3fc71ef1b3c5a5297f9e6a8e3298838c014ab9598eb9f9adbfe067edb4e16:cd6290b58efc9e7b269dd477525cf240a050b30aebf8784a9749183a139f2c8f2b620cb1555d0006cfb0e6610f5b2b3505cf3541c37ad881c898e8f49d6b1f2618792b3c122f93148c14abebc3be947443f968af0c6a0a77ed159eff04e18852d8ffa2f35ec73e21640a1408a51526011fd7a33161:b04276d98fd1b27645187512e20927e735df17d9dc5bf003cb45661119875a6353286f3dcae081df36f0fda36e71e367
|
||||||
|
502ee3c386728a0c1b0cd6787ca78b7d6eb8aed2a9fa0ce7cc50b7c91869917c:7f5a1e1ab71a43bf38cd7accfd20af1e99ae55fba55ec043c5f71e4bce2535ca4c8e50f2e85432658670b6b20a8a1d9620b204938fa1aab412b959a364a5272b7364a0204fc3de15490bca3ecb572ab1ae0dba017619cfabbd10138e65399687c9288caac4ad7f2e81e6156dcfe30ee7d1f7770e03c4:94ab75ad8fc599d4a0f077df652a0c9992486dafcacfd5a5d2d8ba3b5ba0db4fd64f322106d9647aff961766aa6ec719
|
||||||
|
0d59c2cbc5a01509788f8d78768f6b4c70e1e56a3d064ee3a5d214b051373de0:1fb41c046728bc666e16ad566131a5c38b8562942c0f8ab175f2a82886e710e55c3af18be343a496f2426144f985c1101a08ecdd9c39081d650c7192af82a203272661c8424aad5dfd70afbff908f8cdf1b6a12cb3078663e836e317b37b47c7f986b1b4e97f7166dfaaef116205e763eb9998d64964e4:ab511a041e0ada5b71f4699a8b52479c181e1ad068ecd2f5d87fb124f2ecae402f7672851f368ec78d1d0e5ee7514cab
|
||||||
|
03b0c798cc56bd541ccf9b674cb12a8580fd6a0829ac9f5d2f2ce198c1fabf59:6310c538bdba8e586904f3283421e272ad4518bdbde268184bcc3c33b6078d9460b1a295e927a2310dd291a9b9e2bb4b49cc52b972ac6ac9f7a2bd8d8d8b2737224660135cfa5ddcc874186c794dc3898be4302cc771cb6483a7463830fdfc611adcf09b9a28d71c3ef6ff45228e40c12d84459974b8c944:b8291ecf685152e7bc7c1f3753a4dd2bd213c0ffe969249ab8927a6676ecfab3b67a73f3f7ed0f6187fa976b3e8aeec0
|
||||||
|
5ae1bb72838eb38c1f4340c6e22686961e3e34b4d2d518d76ab4f881fd479c94:332c3bbd162c8cb774480ef81cede2aa52a0967a869663cab7c8d105e33038562599881f6ef77aa4e3f4225131fc864a27db9c58f5198e6190d5eec728ec4e698b96d1f982edc5d22231b3d76be10a7deeab8f32af36a2cf5d8aed42102ae20679cbb5c8befc8a65f13837710bf86f344590bc74f96e052eae:80e602213b6c748b3e68430ccd1c4fa288aa5c0a411466dd8994ff19ae8be60ad281da36e8a35e2f2b427ac2edc255cc
|
||||||
|
4113f2add0abb7f05cf56a1281457e9e4f7cfb39d093854b3b4e3bbde237ea23:a83d1cd6999e4940b0d71be96e000e46246a6e451c646756d893b3edb330f2f445858ed12d1d35412fc0eee90204aba0d4fa88583bbc37ee389f88fe0c8dd4c34ffaa8d8c6affeb7feb5f3064af0c06ad3f7a51e4b58f8edc95bd22a02ec4bbe2b2c660762e345d00548995ddcfb10299dd192344d45791ea8bb:a37b03f854b9cb12dc7fc109bea2ccc3423418b89d283715fb8c18db78a68d60b19bdd7e6acf869090b97f538a35df66
|
||||||
|
17c979dc43d5da70f57027cffc420c6df4245db222a2c3060c7499b2663f6093:c20c4351abcf4ecda9b5478cff8af859ec743eb0d67f6ce2b347349460a2854475d0a6e8165b5174434ca77c088e641c109ac8b8d5879586c034eadfa6bc3a1e66faa02a3dc0fed87af670cc8626df5c71a8360e1911159632558e7a99d4830ce21bcbf3f551465bd1061888b83db174343692b6d796460791ab8d:8ff5917a45cdda175f9d6f4a4a99308617ceec290794fda33d7585f4a3964febf0274479f77210373f3ca6350ae0639b
|
||||||
|
50adb11ff487000da2714e104241c0039dc6c2eca5e976a6bca8cc80fd2f22d5:3ca6b6f64aab22ea7dcf85eeb05e5eff6102731bb47c94bb737e77b389334742be939b79219fff38452b411052bba588b7872654d0b40f7be1516b8f243047a9aefb40fb70f93e53def38147fe564214605ef2d7508bd7ef44fdfee7882d754e735ba282e044bb953f18f131212d879def4d4d6923d0dcc0d3bb6a14:989e4389faf99c5cbf6798a147fd85cf1331e1e7faa966d6fbed2cd43c673d6a382e0e304f560e5ba816eb1a0b306cf9
|
||||||
|
55bdf02943f5a8130bcb537972f870043f5d7e3561df8717740e1a7a39bf73df:e288bfeeead0c3050ec6834694323af7bd77dcb52fee6cb54167a73181e487583ac75e63c95e71760cd9a1584b711842f602237f72afb268ef039a044d293d4091abc1807cbec9041ece11905b32ace59db1114047f60ae679c53b465afe03a8ba02ee89e85efebbb93226eaf1cd5c6ce1ef913fbf549934dfbda69dff:94c74729eaecf336b25d82a10798adc97e70cb345313413cf6550d622b0b92b9d4dcf606afb1b7e88db6b3ce106aba04
|
||||||
|
49a477ecf8786a9f5a44a9da0a83da977b844198068f1cadce28c599d9ebddbd:9944eeed83dde7b21b72ff1491cad3d7a1ceae3f9c5c880be49024d9ec055c55189de80b521df30fd17d558f7bc6ff6d5c9dcacae3ec1242929fae1fd8bd7fedea51acd344a1fa0120f60b1a4679e5177588fc27d713173f4fd47cccc16feb8b44a2d670d7b04c8c14bf37527230f3daa6d7c3a6e958c78376c5940f1063:8045a0358069c43170b238e7dc98952bf84e1caa0925905922b5822ab28b498297e901614909376fa04ced4c852c39da
|
||||||
|
6bbc2807b27b635285670a68a42d8fafb461fab581e4e2773c199b29088bc554:0c149764b95e6461e820206e5e2b7fa4acf62a3a132db955d5c4ff1cafbfef3b3816aab1bc9bbcf14af47a4e7753f0243842d9b53b3c3c26b9a2e244f2eb06461e2128949e9b437c96cddbddb52d9d6062d4692d05dc624f94fac39401ce51389576f0fd52e670841602645b4ed6a76cc845ec8454538782b3b179e44cd5ec:aaaa82c3fd810924f41b74bdf484460810f5f3274f8102520099f9ca384a5965e50202a36edfa5b0999c7b3c2548ae74
|
||||||
@@ -1,14 +1,18 @@
|
|||||||
import { sha512 } from '@noble/hashes/sha512';
|
import { sha512 } from '@noble/hashes/sha512';
|
||||||
import { hexToBytes, bytesToHex, randomBytes } from '@noble/hashes/utils';
|
import { bytesToHex as hex, hexToBytes } from '@noble/hashes/utils';
|
||||||
import { deepStrictEqual, strictEqual, throws } from 'assert';
|
import { deepStrictEqual, throws } from 'assert';
|
||||||
import { describe, should } from 'micro-should';
|
import { describe, should } from 'micro-should';
|
||||||
import { numberToBytesLE } from '../esm/abstract/utils.js';
|
import { bytesToNumberLE, numberToBytesLE } from '../esm/abstract/utils.js';
|
||||||
import { default as x25519vectors } from './wycheproof/x25519_test.json' assert { type: 'json' };
|
import { default as x25519vectors } from './wycheproof/x25519_test.json' assert { type: 'json' };
|
||||||
import { ed25519ctx, ed25519ph, RistrettoPoint, x25519 } from '../esm/ed25519.js';
|
import {
|
||||||
|
ed25519,
|
||||||
// const ed = ed25519;
|
ed25519ctx,
|
||||||
const hex = bytesToHex;
|
ed25519ph,
|
||||||
// const Point = ed.ExtendedPoint;
|
edwardsToMontgomeryPub,
|
||||||
|
edwardsToMontgomeryPriv,
|
||||||
|
RistrettoPoint,
|
||||||
|
x25519,
|
||||||
|
} from '../esm/ed25519.js';
|
||||||
|
|
||||||
const VECTORS_RFC8032_CTX = [
|
const VECTORS_RFC8032_CTX = [
|
||||||
{
|
{
|
||||||
@@ -62,8 +66,14 @@ describe('RFC8032ctx', () => {
|
|||||||
const v = VECTORS_RFC8032_CTX[i];
|
const v = VECTORS_RFC8032_CTX[i];
|
||||||
should(`${i}`, () => {
|
should(`${i}`, () => {
|
||||||
deepStrictEqual(hex(ed25519ctx.getPublicKey(v.secretKey)), v.publicKey);
|
deepStrictEqual(hex(ed25519ctx.getPublicKey(v.secretKey)), v.publicKey);
|
||||||
deepStrictEqual(hex(ed25519ctx.sign(v.message, v.secretKey, v.context)), v.signature);
|
deepStrictEqual(
|
||||||
deepStrictEqual(ed25519ctx.verify(v.signature, v.message, v.publicKey, v.context), true);
|
hex(ed25519ctx.sign(v.message, v.secretKey, { context: v.context })),
|
||||||
|
v.signature
|
||||||
|
);
|
||||||
|
deepStrictEqual(
|
||||||
|
ed25519ctx.verify(v.signature, v.message, v.publicKey, { context: v.context }),
|
||||||
|
true
|
||||||
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -93,14 +103,7 @@ describe('RFC8032ph', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// x25519
|
// x25519
|
||||||
should('X25519 base point', () => {
|
describe('RFC7748 X25519 ECDH', () => {
|
||||||
const { y } = ed25519ph.ExtendedPoint.BASE;
|
|
||||||
const { Fp } = ed25519ph.CURVE;
|
|
||||||
const u = Fp.create((y + 1n) * Fp.inv(1n - y));
|
|
||||||
deepStrictEqual(numberToBytesLE(u, 32), x25519.GuBytes);
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('RFC7748', () => {
|
|
||||||
const rfc7748Mul = [
|
const rfc7748Mul = [
|
||||||
{
|
{
|
||||||
scalar: 'a546e36bf0527c9d3b16154b82465edd62144c0ac1fc5a18506a2244ba449ac4',
|
scalar: 'a546e36bf0527c9d3b16154b82465edd62144c0ac1fc5a18506a2244ba449ac4',
|
||||||
@@ -127,7 +130,7 @@ describe('RFC7748', () => {
|
|||||||
];
|
];
|
||||||
for (let i = 0; i < rfc7748Iter.length; i++) {
|
for (let i = 0; i < rfc7748Iter.length; i++) {
|
||||||
const { scalar, iters } = rfc7748Iter[i];
|
const { scalar, iters } = rfc7748Iter[i];
|
||||||
should(`scalarMult iteration (${i})`, () => {
|
should(`scalarMult iteration x${iters}`, () => {
|
||||||
let k = x25519.GuBytes;
|
let k = x25519.GuBytes;
|
||||||
for (let i = 0, u = k; i < iters; i++) [k, u] = [x25519.scalarMult(k, u), k];
|
for (let i = 0, u = k; i < iters; i++) [k, u] = [x25519.scalarMult(k, u), k];
|
||||||
deepStrictEqual(hex(k), scalar);
|
deepStrictEqual(hex(k), scalar);
|
||||||
@@ -145,10 +148,66 @@ describe('RFC7748', () => {
|
|||||||
deepStrictEqual(hex(x25519.scalarMult(alicePrivate, bobPublic)), shared);
|
deepStrictEqual(hex(x25519.scalarMult(alicePrivate, bobPublic)), shared);
|
||||||
deepStrictEqual(hex(x25519.scalarMult(bobPrivate, alicePublic)), shared);
|
deepStrictEqual(hex(x25519.scalarMult(bobPrivate, alicePublic)), shared);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
should('X25519/getSharedSecret() should be commutative', () => {
|
||||||
|
for (let i = 0; i < 512; i++) {
|
||||||
|
const asec = x25519.utils.randomPrivateKey();
|
||||||
|
const apub = x25519.getPublicKey(asec);
|
||||||
|
const bsec = x25519.utils.randomPrivateKey();
|
||||||
|
const bpub = x25519.getPublicKey(bsec);
|
||||||
|
try {
|
||||||
|
deepStrictEqual(x25519.getSharedSecret(asec, bpub), x25519.getSharedSecret(bsec, apub));
|
||||||
|
} catch (error) {
|
||||||
|
console.error('not commutative', { asec, apub, bsec, bpub });
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
describe('Wycheproof', () => {
|
|
||||||
|
should('edwardsToMontgomery should produce correct output', () => {
|
||||||
|
const edSecret = hexToBytes('77076d0a7318a57d3c16c17251b26645df4c2f87ebc0992ab177fba51db92c2a');
|
||||||
|
const edPublic = ed25519.getPublicKey(edSecret);
|
||||||
|
const xPrivate = edwardsToMontgomeryPriv(edSecret);
|
||||||
|
deepStrictEqual(
|
||||||
|
hex(xPrivate),
|
||||||
|
'a8cd44eb8e93319c0570bc11005c0e0189d34ff02f6c17773411ad191293c94f'
|
||||||
|
);
|
||||||
|
const xPublic = edwardsToMontgomeryPub(edPublic);
|
||||||
|
deepStrictEqual(
|
||||||
|
hex(xPublic),
|
||||||
|
'ed7749b4d989f6957f3bfde6c56767e988e21c9f8784d91d610011cd553f9b06'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
should('edwardsToMontgomery should produce correct keyPair', () => {
|
||||||
|
const edSecret = ed25519.utils.randomPrivateKey();
|
||||||
|
const edPublic = ed25519.getPublicKey(edSecret);
|
||||||
|
const xSecret = edwardsToMontgomeryPriv(edSecret);
|
||||||
|
const expectedXPublic = x25519.getPublicKey(xSecret);
|
||||||
|
const xPublic = edwardsToMontgomeryPub(edPublic);
|
||||||
|
deepStrictEqual(xPublic, expectedXPublic);
|
||||||
|
});
|
||||||
|
|
||||||
|
should('ECDH through edwardsToMontgomery should be commutative', () => {
|
||||||
|
const edSecret1 = ed25519.utils.randomPrivateKey();
|
||||||
|
const edPublic1 = ed25519.getPublicKey(edSecret1);
|
||||||
|
const edSecret2 = ed25519.utils.randomPrivateKey();
|
||||||
|
const edPublic2 = ed25519.getPublicKey(edSecret2);
|
||||||
|
deepStrictEqual(
|
||||||
|
x25519.getSharedSecret(edwardsToMontgomeryPriv(edSecret1), edwardsToMontgomeryPub(edPublic2)),
|
||||||
|
x25519.getSharedSecret(edwardsToMontgomeryPriv(edSecret2), edwardsToMontgomeryPub(edPublic1))
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
should('base point', () => {
|
||||||
|
const { y } = ed25519ph.ExtendedPoint.BASE;
|
||||||
|
const { Fp } = ed25519ph.CURVE;
|
||||||
|
const u = Fp.create((y + 1n) * Fp.inv(1n - y));
|
||||||
|
deepStrictEqual(numberToBytesLE(u, 32), x25519.GuBytes);
|
||||||
|
});
|
||||||
|
|
||||||
const group = x25519vectors.testGroups[0];
|
const group = x25519vectors.testGroups[0];
|
||||||
should(`X25519`, () => {
|
should('wycheproof', () => {
|
||||||
for (let i = 0; i < group.tests.length; i++) {
|
for (let i = 0; i < group.tests.length; i++) {
|
||||||
const v = group.tests[i];
|
const v = group.tests[i];
|
||||||
const comment = `(${i}, ${v.result}) ${v.comment}`;
|
const comment = `(${i}, ${v.result}) ${v.comment}`;
|
||||||
@@ -281,10 +340,23 @@ describe('ristretto255', () => {
|
|||||||
deepStrictEqual(point.toHex(), encodedHashToPoints[i]);
|
deepStrictEqual(point.toHex(), encodedHashToPoints[i]);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
should('have proper equality testing', () => {
|
||||||
|
const MAX_255B = BigInt('0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff');
|
||||||
|
const bytes255ToNumberLE = (bytes) =>
|
||||||
|
ed25519ctx.CURVE.Fp.create(bytesToNumberLE(bytes) & MAX_255B);
|
||||||
|
|
||||||
|
const priv = new Uint8Array([
|
||||||
|
198, 101, 65, 165, 93, 120, 37, 238, 16, 133, 10, 35, 253, 243, 161, 246, 229, 135, 12, 137,
|
||||||
|
202, 114, 222, 139, 146, 123, 4, 125, 152, 173, 1, 7,
|
||||||
|
]);
|
||||||
|
const pub = RistrettoPoint.BASE.multiply(bytes255ToNumberLE(priv));
|
||||||
|
deepStrictEqual(pub.equals(RistrettoPoint.ZERO), false);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// ESM is broken.
|
// ESM is broken.
|
||||||
import url from 'url';
|
import url from 'url';
|
||||||
|
|
||||||
if (import.meta.url === url.pathToFileURL(process.argv[1]).href) {
|
if (import.meta.url === url.pathToFileURL(process.argv[1]).href) {
|
||||||
should.run();
|
should.run();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1 +1,2 @@
|
|||||||
|
export { numberToBytesLE } from '../esm/abstract/utils.js';
|
||||||
export { ed25519, ED25519_TORSION_SUBGROUP } from '../esm/ed25519.js';
|
export { ed25519, ED25519_TORSION_SUBGROUP } from '../esm/ed25519.js';
|
||||||
|
|||||||
@@ -1,14 +1,19 @@
|
|||||||
import { deepStrictEqual, strictEqual, throws } from 'assert';
|
import { deepStrictEqual, strictEqual, throws } from 'assert';
|
||||||
import { readFileSync } from 'fs';
|
import { readFileSync } from 'fs';
|
||||||
import { hexToBytes, bytesToHex, randomBytes } from '@noble/hashes/utils';
|
import { bytesToHex, concatBytes, hexToBytes, utf8ToBytes, randomBytes } from '@noble/hashes/utils';
|
||||||
import * as fc from 'fast-check';
|
import * as fc from 'fast-check';
|
||||||
import { describe, should } from 'micro-should';
|
import { describe, should } from 'micro-should';
|
||||||
import { ed25519, ED25519_TORSION_SUBGROUP } from './ed25519.helpers.js';
|
import { ed25519 as ed, ED25519_TORSION_SUBGROUP, numberToBytesLE } from './ed25519.helpers.js';
|
||||||
import { default as ed25519vectors } from './wycheproof/eddsa_test.json' assert { type: 'json' };
|
// Old vectors allow to test sign() because they include private key
|
||||||
|
import { default as ed25519vectors_OLD } from './ed25519/ed25519_test_OLD.json' assert { type: 'json' };
|
||||||
|
import { default as ed25519vectors } from './wycheproof/ed25519_test.json' assert { type: 'json' };
|
||||||
import { default as zip215 } from './ed25519/zip215.json' assert { type: 'json' };
|
import { default as zip215 } from './ed25519/zip215.json' assert { type: 'json' };
|
||||||
|
import { default as edgeCases } from './ed25519/edge-cases.json' assert { type: 'json' };
|
||||||
|
|
||||||
|
// Any changes to the file will need to be aware of the fact
|
||||||
|
// the file is shared between noble-curves and noble-ed25519.
|
||||||
|
|
||||||
describe('ed25519', () => {
|
describe('ed25519', () => {
|
||||||
const ed = ed25519;
|
|
||||||
const hex = bytesToHex;
|
const hex = bytesToHex;
|
||||||
const Point = ed.ExtendedPoint;
|
const Point = ed.ExtendedPoint;
|
||||||
|
|
||||||
@@ -17,13 +22,6 @@ describe('ed25519', () => {
|
|||||||
return hexToBytes(hex.padStart(64, '0'));
|
return hexToBytes(hex.padStart(64, '0'));
|
||||||
}
|
}
|
||||||
|
|
||||||
function utf8ToBytes(str) {
|
|
||||||
if (typeof str !== 'string') {
|
|
||||||
throw new Error(`utf8ToBytes expected string, got ${typeof str}`);
|
|
||||||
}
|
|
||||||
return new TextEncoder().encode(str);
|
|
||||||
}
|
|
||||||
|
|
||||||
ed.utils.precompute(8);
|
ed.utils.precompute(8);
|
||||||
|
|
||||||
should('not accept >32byte private keys', () => {
|
should('not accept >32byte private keys', () => {
|
||||||
@@ -305,7 +303,8 @@ describe('ed25519', () => {
|
|||||||
|
|
||||||
// https://zips.z.cash/zip-0215
|
// https://zips.z.cash/zip-0215
|
||||||
// Vectors from https://gist.github.com/hdevalence/93ed42d17ecab8e42138b213812c8cc7
|
// Vectors from https://gist.github.com/hdevalence/93ed42d17ecab8e42138b213812c8cc7
|
||||||
should('ZIP-215 compliance tests/should pass all of them', () => {
|
describe('ZIP215', () => {
|
||||||
|
should('pass all compliance tests', () => {
|
||||||
const str = utf8ToBytes('Zcash');
|
const str = utf8ToBytes('Zcash');
|
||||||
for (let v of zip215) {
|
for (let v of zip215) {
|
||||||
let noble = false;
|
let noble = false;
|
||||||
@@ -317,11 +316,12 @@ describe('ed25519', () => {
|
|||||||
deepStrictEqual(noble, v.valid_zip215, JSON.stringify(v));
|
deepStrictEqual(noble, v.valid_zip215, JSON.stringify(v));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
should('ZIP-215 compliance tests/disallows sig.s >= CURVE.n', () => {
|
should('disallow sig.s >= CURVE.n', () => {
|
||||||
// sig.R = BASE, sig.s = N+1
|
// sig.R = BASE, sig.s = N+1
|
||||||
const sig =
|
const sig =
|
||||||
'5866666666666666666666666666666666666666666666666666666666666666eed3f55c1a631258d69cf7a2def9de1400000000000000000000000000000010';
|
'5866666666666666666666666666666666666666666666666666666666666666eed3f55c1a631258d69cf7a2def9de1400000000000000000000000000000010';
|
||||||
throws(() => ed.verify(sig, 'deadbeef', Point.BASE));
|
deepStrictEqual(ed.verify(sig, 'deadbeef', Point.BASE), false);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// should('X25519/getSharedSecret() should be commutative', () => {
|
// should('X25519/getSharedSecret() should be commutative', () => {
|
||||||
@@ -346,9 +346,9 @@ describe('ed25519', () => {
|
|||||||
// );
|
// );
|
||||||
// });
|
// });
|
||||||
|
|
||||||
should(`Wycheproof/ED25519`, () => {
|
should(`wycheproof/ED25519 (OLD)`, () => {
|
||||||
for (let g = 0; g < ed25519vectors.testGroups.length; g++) {
|
for (let g = 0; g < ed25519vectors_OLD.testGroups.length; g++) {
|
||||||
const group = ed25519vectors.testGroups[g];
|
const group = ed25519vectors_OLD.testGroups[g];
|
||||||
const key = group.key;
|
const key = group.key;
|
||||||
deepStrictEqual(hex(ed.getPublicKey(key.sk)), key.pk, `(${g}, public)`);
|
deepStrictEqual(hex(ed.getPublicKey(key.sk)), key.pk, `(${g}, public)`);
|
||||||
for (let i = 0; i < group.tests.length; i++) {
|
for (let i = 0; i < group.tests.length; i++) {
|
||||||
@@ -370,7 +370,29 @@ describe('ed25519', () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
should('Property test issue #1', () => {
|
should(`wycheproof/ED25519`, () => {
|
||||||
|
for (let g = 0; g < ed25519vectors.testGroups.length; g++) {
|
||||||
|
const group = ed25519vectors.testGroups[g];
|
||||||
|
const key = group.publicKey;
|
||||||
|
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(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('not mutate inputs', () => {
|
||||||
const message = new Uint8Array([12, 12, 12]);
|
const message = new Uint8Array([12, 12, 12]);
|
||||||
const signature = ed.sign(message, to32Bytes(1n));
|
const signature = ed.sign(message, to32Bytes(1n));
|
||||||
const publicKey = ed.getPublicKey(to32Bytes(1n)); // <- was 1n
|
const publicKey = ed.getPublicKey(to32Bytes(1n)); // <- was 1n
|
||||||
@@ -387,16 +409,43 @@ describe('ed25519', () => {
|
|||||||
strictEqual(cleared.isTorsionFree(), true, `cleared must be torsionFree: ${hex}`);
|
strictEqual(cleared.isTorsionFree(), true, `cleared must be torsionFree: ${hex}`);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
should('have strict SUF-CMA and SBS properties', () => {
|
||||||
|
// https://eprint.iacr.org/2020/1244
|
||||||
|
const list = [0, 1, 6, 7, 8, 9, 10, 11].map((i) => edgeCases[i]);
|
||||||
|
for (let v of list) {
|
||||||
|
const result = ed.verify(v.signature, v.message, v.pub_key, { zip215: false });
|
||||||
|
strictEqual(result, false, `zip215: false must not validate: ${v.signature}`);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
should('ed25519 bug', () => {
|
should('not verify when sig.s >= CURVE.n', () => {
|
||||||
|
const privateKey = ed.utils.randomPrivateKey();
|
||||||
|
const message = Uint8Array.from([0xab, 0xbc, 0xcd, 0xde]);
|
||||||
|
const publicKey = ed.getPublicKey(privateKey);
|
||||||
|
const signature = ed.sign(message, privateKey);
|
||||||
|
|
||||||
|
const R = signature.slice(0, 32);
|
||||||
|
let s = signature.slice(32, 64);
|
||||||
|
|
||||||
|
s = bytesToHex(s.slice().reverse());
|
||||||
|
s = BigInt('0x' + s);
|
||||||
|
s = s + ed.CURVE.n;
|
||||||
|
s = numberToBytesLE(s, 32);
|
||||||
|
|
||||||
|
const sig_invalid = concatBytes(R, s);
|
||||||
|
deepStrictEqual(ed.verify(sig_invalid, message, publicKey), false);
|
||||||
|
});
|
||||||
|
|
||||||
|
should('not accept point without z, t', () => {
|
||||||
const t = 81718630521762619991978402609047527194981150691135404693881672112315521837062n;
|
const t = 81718630521762619991978402609047527194981150691135404693881672112315521837062n;
|
||||||
const point = ed25519.ExtendedPoint.fromAffine({ x: t, y: t });
|
const point = Point.fromAffine({ x: t, y: t });
|
||||||
throws(() => point.assertValidity());
|
throws(() => point.assertValidity());
|
||||||
// Otherwise (without assertValidity):
|
// Otherwise (without assertValidity):
|
||||||
// const point2 = point.double();
|
// const point2 = point.double();
|
||||||
// point2.toAffine(); // crash!
|
// point2.toAffine(); // crash!
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|
||||||
// ESM is broken.
|
// ESM is broken.
|
||||||
import url from 'url';
|
import url from 'url';
|
||||||
|
|||||||
1
test/ed25519/edge-cases.json
Normal file
1
test/ed25519/edge-cases.json
Normal file
@@ -0,0 +1 @@
|
|||||||
|
[{"message":"8c93255d71dcab10e8f379c26200f3c7bd5f09d9bc3068d3ef4edeb4853022b6","pub_key":"c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa","signature":"c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a0000000000000000000000000000000000000000000000000000000000000000"},{"message":"9bd9f44f4dcc75bd531b56b2cd280b0bb38fc1cd6d1230e14861d861de092e79","pub_key":"c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa","signature":"f7badec5b8abeaf699583992219b7b223f1df3fbbea919844e3f7c554a43dd43a5bb704786be79fc476f91d3f3f89b03984d8068dcf1bb7dfc6637b45450ac04"},{"message":"aebf3f2601a0c8c5d39cc7d8911642f740b78168218da8471772b35f9d35b9ab","pub_key":"f7badec5b8abeaf699583992219b7b223f1df3fbbea919844e3f7c554a43dd43","signature":"c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa8c4bd45aecaca5b24fb97bc10ac27ac8751a7dfe1baff8b953ec9f5833ca260e"},{"message":"9bd9f44f4dcc75bd531b56b2cd280b0bb38fc1cd6d1230e14861d861de092e79","pub_key":"cdb267ce40c5cd45306fa5d2f29731459387dbf9eb933b7bd5aed9a765b88d4d","signature":"9046a64750444938de19f227bb80485e92b83fdb4b6506c160484c016cc1852f87909e14428a7a1d62e9f22f3d3ad7802db02eb2e688b6c52fcd6648a98bd009"},{"message":"e47d62c63f830dc7a6851a0b1f33ae4bb2f507fb6cffec4011eaccd55b53f56c","pub_key":"cdb267ce40c5cd45306fa5d2f29731459387dbf9eb933b7bd5aed9a765b88d4d","signature":"160a1cb0dc9c0258cd0a7d23e94d8fa878bcb1925f2c64246b2dee1796bed5125ec6bc982a269b723e0668e540911a9a6a58921d6925e434ab10aa7940551a09"},{"message":"e47d62c63f830dc7a6851a0b1f33ae4bb2f507fb6cffec4011eaccd55b53f56c","pub_key":"cdb267ce40c5cd45306fa5d2f29731459387dbf9eb933b7bd5aed9a765b88d4d","signature":"21122a84e0b5fca4052f5b1235c80a537878b38f3142356b2c2384ebad4668b7e40bc836dac0f71076f9abe3a53f9c03c1ceeeddb658d0030494ace586687405"},{"message":"85e241a07d148b41e47d62c63f830dc7a6851a0b1f33ae4bb2f507fb6cffec40","pub_key":"442aad9f089ad9e14647b1ef9099a1ff4798d78589e66f28eca69c11f582a623","signature":"e96f66be976d82e60150baecff9906684aebb1ef181f67a7189ac78ea23b6c0e547f7690a0e2ddcd04d87dbc3490dc19b3b3052f7ff0538cb68afb369ba3a514"},{"message":"85e241a07d148b41e47d62c63f830dc7a6851a0b1f33ae4bb2f507fb6cffec40","pub_key":"442aad9f089ad9e14647b1ef9099a1ff4798d78589e66f28eca69c11f582a623","signature":"8ce5b96c8f26d0ab6c47958c9e68b937104cd36e13c33566acd2fe8d38aa19427e71f98a473474f2f13f06f97c20d58cc3f54b8bd0d272f42b695dd7e89a8c22"},{"message":"9bedc267423725d473888631ebf45988bad3db83851ee85c85e241a07d148b41","pub_key":"f7badec5b8abeaf699583992219b7b223f1df3fbbea919844e3f7c554a43dd43","signature":"ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff03be9678ac102edcd92b0210bb34d7428d12ffc5df5f37e359941266a4e35f0f"},{"message":"9bedc267423725d473888631ebf45988bad3db83851ee85c85e241a07d148b41","pub_key":"f7badec5b8abeaf699583992219b7b223f1df3fbbea919844e3f7c554a43dd43","signature":"ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffca8c5b64cd208982aa38d4936621a4775aa233aa0505711d8fdcfdaa943d4908"},{"message":"e96b7021eb39c1a163b6da4e3093dcd3f21387da4cc4572be588fafae23c155b","pub_key":"ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff","signature":"a9d55260f765261eb9b84e106f665e00b867287a761990d7135963ee0a7d59dca5bb704786be79fc476f91d3f3f89b03984d8068dcf1bb7dfc6637b45450ac04"},{"message":"39a591f5321bbe07fd5a23dc2f39d025d74526615746727ceefd6e82ae65c06f","pub_key":"ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff","signature":"a9d55260f765261eb9b84e106f665e00b867287a761990d7135963ee0a7d59dca5bb704786be79fc476f91d3f3f89b03984d8068dcf1bb7dfc6637b45450ac04"}]
|
||||||
117
test/ed448-addons.test.js
Normal file
117
test/ed448-addons.test.js
Normal file
@@ -0,0 +1,117 @@
|
|||||||
|
import { bytesToHex as hex, hexToBytes } from '@noble/hashes/utils';
|
||||||
|
import { deepStrictEqual, throws } from 'assert';
|
||||||
|
import { describe, should } from 'micro-should';
|
||||||
|
import { bytesToNumberLE } from '../esm/abstract/utils.js';
|
||||||
|
import { ed448, DecafPoint } from '../esm/ed448.js';
|
||||||
|
|
||||||
|
describe('decaf448', () => {
|
||||||
|
should('follow the byte encodings of small multiples', () => {
|
||||||
|
const encodingsOfSmallMultiples = [
|
||||||
|
// This is the identity point
|
||||||
|
'0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000',
|
||||||
|
// This is the basepoint
|
||||||
|
'6666666666666666666666666666666666666666666666666666666633333333333333333333333333333333333333333333333333333333',
|
||||||
|
// These are small multiples of the basepoint
|
||||||
|
'c898eb4f87f97c564c6fd61fc7e49689314a1f818ec85eeb3bd5514ac816d38778f69ef347a89fca817e66defdedce178c7cc709b2116e75',
|
||||||
|
'a0c09bf2ba7208fda0f4bfe3d0f5b29a543012306d43831b5adc6fe7f8596fa308763db15468323b11cf6e4aeb8c18fe44678f44545a69bc',
|
||||||
|
'b46f1836aa287c0a5a5653f0ec5ef9e903f436e21c1570c29ad9e5f596da97eeaf17150ae30bcb3174d04bc2d712c8c7789d7cb4fda138f4',
|
||||||
|
'1c5bbecf4741dfaae79db72dface00eaaac502c2060934b6eaaeca6a20bd3da9e0be8777f7d02033d1b15884232281a41fc7f80eed04af5e',
|
||||||
|
'86ff0182d40f7f9edb7862515821bd67bfd6165a3c44de95d7df79b8779ccf6460e3c68b70c16aaa280f2d7b3f22d745b97a89906cfc476c',
|
||||||
|
'502bcb6842eb06f0e49032bae87c554c031d6d4d2d7694efbf9c468d48220c50f8ca28843364d70cee92d6fe246e61448f9db9808b3b2408',
|
||||||
|
'0c9810f1e2ebd389caa789374d78007974ef4d17227316f40e578b336827da3f6b482a4794eb6a3975b971b5e1388f52e91ea2f1bcb0f912',
|
||||||
|
'20d41d85a18d5657a29640321563bbd04c2ffbd0a37a7ba43a4f7d263ce26faf4e1f74f9f4b590c69229ae571fe37fa639b5b8eb48bd9a55',
|
||||||
|
'e6b4b8f408c7010d0601e7eda0c309a1a42720d6d06b5759fdc4e1efe22d076d6c44d42f508d67be462914d28b8edce32e7094305164af17',
|
||||||
|
'be88bbb86c59c13d8e9d09ab98105f69c2d1dd134dbcd3b0863658f53159db64c0e139d180f3c89b8296d0ae324419c06fa87fc7daaf34c1',
|
||||||
|
'a456f9369769e8f08902124a0314c7a06537a06e32411f4f93415950a17badfa7442b6217434a3a05ef45be5f10bd7b2ef8ea00c431edec5',
|
||||||
|
'186e452c4466aa4383b4c00210d52e7922dbf9771e8b47e229a9b7b73c8d10fd7ef0b6e41530f91f24a3ed9ab71fa38b98b2fe4746d51d68',
|
||||||
|
'4ae7fdcae9453f195a8ead5cbe1a7b9699673b52c40ab27927464887be53237f7f3a21b938d40d0ec9e15b1d5130b13ffed81373a53e2b43',
|
||||||
|
'841981c3bfeec3f60cfeca75d9d8dc17f46cf0106f2422b59aec580a58f342272e3a5e575a055ddb051390c54c24c6ecb1e0aceb075f6056',
|
||||||
|
];
|
||||||
|
let B = DecafPoint.BASE;
|
||||||
|
let P = DecafPoint.ZERO;
|
||||||
|
for (const encoded of encodingsOfSmallMultiples) {
|
||||||
|
deepStrictEqual(P.toHex(), encoded);
|
||||||
|
deepStrictEqual(DecafPoint.fromHex(encoded).toHex(), encoded);
|
||||||
|
P = P.add(B);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
should('not convert bad bytes encoding', () => {
|
||||||
|
const badEncodings = [
|
||||||
|
// These are all bad because they're non-canonical field encodings.
|
||||||
|
'8e24f838059ee9fef1e209126defe53dcd74ef9b6304601c6966099effffffffffffffffffffffffffffffffffffffffffffffffffffffff',
|
||||||
|
'86fcc7212bd4a0b980928666dc28c444a605ef38e09fb569e28d4443ffffffffffffffffffffffffffffffffffffffffffffffffffffffff',
|
||||||
|
'866d54bd4c4ff41a55d4eefdbeca73cbd653c7bd3135b383708ec0bdffffffffffffffffffffffffffffffffffffffffffffffffffffffff',
|
||||||
|
'4a380ccdab9c86364a89e77a464d64f9157538cfdfa686adc0d5ece4ffffffffffffffffffffffffffffffffffffffffffffffffffffffff',
|
||||||
|
'f22d9d4c945dd44d11e0b1d3d3d358d959b4844d83b08c44e659d79fffffffffffffffffffffffffffffffffffffffffffffffffffffffff',
|
||||||
|
'8cdffc681aa99e9c818c8ef4c3808b58e86acdef1ab68c8477af185bffffffffffffffffffffffffffffffffffffffffffffffffffffffff',
|
||||||
|
'0e1c12ac7b5920effbd044e897c57634e2d05b5c27f8fa3df8a086a1ffffffffffffffffffffffffffffffffffffffffffffffffffffffff',
|
||||||
|
// These are all bad because they're negative field elements.
|
||||||
|
'15141bd2121837ef71a0016bd11be757507221c26542244f23806f3fd3496b7d4c36826276f3bf5deea2c60c4fa4cec69946876da497e795',
|
||||||
|
'455d380238434ab740a56267f4f46b7d2eb2dd8ee905e51d7b0ae8a6cb2bae501e67df34ab21fa45946068c9f233939b1d9521a998b7cb93',
|
||||||
|
'810b1d8e8bf3a9c023294bbfd3d905a97531709bdc0f42390feedd7010f77e98686d400c9c86ed250ceecd9de0a18888ffecda0f4ea1c60d',
|
||||||
|
'd3af9cc41be0e5de83c0c6273bedcb9351970110044a9a41c7b9b2267cdb9d7bf4dc9c2fdb8bed32878184604f1d9944305a8df4274ce301',
|
||||||
|
'9312bcab09009e4330ff89c4bc1e9e000d863efc3c863d3b6c507a40fd2cdefde1bf0892b4b5ed9780b91ed1398fb4a7344c605aa5efda74',
|
||||||
|
'53d11bce9e62a29d63ed82ae93761bdd76e38c21e2822d6ebee5eb1c5b8a03eaf9df749e2490eda9d8ac27d1f71150de93668074d18d1c3a',
|
||||||
|
'697c1aed3cd8858515d4be8ac158b229fe184d79cb2b06e49210a6f3a7cd537bcd9bd390d96c4ab6a4406da5d93640726285370cfa95df80',
|
||||||
|
// These are all bad because they give a nonsquare x².
|
||||||
|
'58ad48715c9a102569b68b88362a4b0645781f5a19eb7e59c6a4686fd0f0750ff42e3d7af1ab38c29d69b670f31258919c9fdbf6093d06c0',
|
||||||
|
'8ca37ee2b15693f06e910cf43c4e32f1d5551dda8b1e48cb6ddd55e440dbc7b296b601919a4e4069f59239ca247ff693f7daa42f086122b1',
|
||||||
|
'982c0ec7f43d9f97c0a74b36db0abd9ca6bfb98123a90782787242c8a523cdc76df14a910d54471127e7662a1059201f902940cd39d57af5',
|
||||||
|
'baa9ab82d07ca282b968a911a6c3728d74bf2fe258901925787f03ee4be7e3cb6684fd1bcfe5071a9a974ad249a4aaa8ca81264216c68574',
|
||||||
|
'2ed9ffe2ded67a372b181ac524996402c42970629db03f5e8636cbaf6074b523d154a7a8c4472c4c353ab88cd6fec7da7780834cc5bd5242',
|
||||||
|
'f063769e4241e76d815800e4933a3a144327a30ec40758ad3723a788388399f7b3f5d45b6351eb8eddefda7d5bff4ee920d338a8b89d8b63',
|
||||||
|
'5a0104f1f55d152ceb68bc138182499891d90ee8f09b40038ccc1e07cb621fd462f781d045732a4f0bda73f0b2acf94355424ff0388d4b9c',
|
||||||
|
];
|
||||||
|
for (const badBytes of badEncodings) {
|
||||||
|
const b = hexToBytes(badBytes);
|
||||||
|
throws(() => DecafPoint.fromHex(b), badBytes);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
should('create right points from uniform hash', () => {
|
||||||
|
const hashes = [
|
||||||
|
'cbb8c991fd2f0b7e1913462d6463e4fd2ce4ccdd28274dc2ca1f4165d5ee6cdccea57be3416e166fd06718a31af45a2f8e987e301be59ae6673e963001dbbda80df47014a21a26d6c7eb4ebe0312aa6fffb8d1b26bc62ca40ed51f8057a635a02c2b8c83f48fa6a2d70f58a1185902c0',
|
||||||
|
'b6d8da654b13c3101d6634a231569e6b85961c3f4b460a08ac4a5857069576b64428676584baa45b97701be6d0b0ba18ac28d443403b45699ea0fbd1164f5893d39ad8f29e48e399aec5902508ea95e33bc1e9e4620489d684eb5c26bc1ad1e09aba61fabc2cdfee0b6b6862ffc8e55a',
|
||||||
|
'36a69976c3e5d74e4904776993cbac27d10f25f5626dd45c51d15dcf7b3e6a5446a6649ec912a56895d6baa9dc395ce9e34b868d9fb2c1fc72eb6495702ea4f446c9b7a188a4e0826b1506b0747a6709f37988ff1aeb5e3788d5076ccbb01a4bc6623c92ff147a1e21b29cc3fdd0e0f4',
|
||||||
|
'd5938acbba432ecd5617c555a6a777734494f176259bff9dab844c81aadcf8f7abd1a9001d89c7008c1957272c1786a4293bb0ee7cb37cf3988e2513b14e1b75249a5343643d3c5e5545a0c1a2a4d3c685927c38bc5e5879d68745464e2589e000b31301f1dfb7471a4f1300d6fd0f99',
|
||||||
|
'4dec58199a35f531a5f0a9f71a53376d7b4bdd6bbd2904234a8ea65bbacbce2a542291378157a8f4be7b6a092672a34d85e473b26ccfbd4cdc6739783dc3f4f6ee3537b7aed81df898c7ea0ae89a15b5559596c2a5eeacf8b2b362f3db2940e3798b63203cae77c4683ebaed71533e51',
|
||||||
|
'df2aa1536abb4acab26efa538ce07fd7bca921b13e17bc5ebcba7d1b6b733deda1d04c220f6b5ab35c61b6bcb15808251cab909a01465b8ae3fc770850c66246d5a9eae9e2877e0826e2b8dc1bc08009590bc6778a84e919fbd28e02a0f9c49b48dc689eb5d5d922dc01469968ee81b5',
|
||||||
|
'e9fb440282e07145f1f7f5ecf3c273212cd3d26b836b41b02f108431488e5e84bd15f2418b3d92a3380dd66a374645c2a995976a015632d36a6c2189f202fc766e1c82f50ad9189be190a1f0e8f9b9e69c9c18cc98fdd885608f68bf0fdedd7b894081a63f70016a8abf04953affbefa',
|
||||||
|
];
|
||||||
|
const encodedHashToPoints = [
|
||||||
|
'0c709c9607dbb01c94513358745b7c23953d03b33e39c7234e268d1d6e24f34014ccbc2216b965dd231d5327e591dc3c0e8844ccfd568848',
|
||||||
|
'76ab794e28ff1224c727fa1016bf7f1d329260b7218a39aea2fdb17d8bd9119017b093d641cedf74328c327184dc6f2a64bd90eddccfcdab',
|
||||||
|
'c8d7ac384143500e50890a1c25d643343accce584caf2544f9249b2bf4a6921082be0e7f3669bb5ec24535e6c45621e1f6dec676edd8b664',
|
||||||
|
'62beffc6b8ee11ccd79dbaac8f0252c750eb052b192f41eeecb12f2979713b563caf7d22588eca5e80995241ef963e7ad7cb7962f343a973',
|
||||||
|
'f4ccb31d263731ab88bed634304956d2603174c66da38742053fa37dd902346c3862155d68db63be87439e3d68758ad7268e239d39c4fd3b',
|
||||||
|
'7e79b00e8e0a76a67c0040f62713b8b8c6d6f05e9c6d02592e8a22ea896f5deacc7c7df5ed42beae6fedb9000285b482aa504e279fd49c32',
|
||||||
|
'20b171cb16be977f15e013b9752cf86c54c631c4fc8cbf7c03c4d3ac9b8e8640e7b0e9300b987fe0ab5044669314f6ed1650ae037db853f1',
|
||||||
|
];
|
||||||
|
|
||||||
|
for (let i = 0; i < hashes.length; i++) {
|
||||||
|
const hash = hexToBytes(hashes[i]);
|
||||||
|
const point = DecafPoint.hashToCurve(hash);
|
||||||
|
deepStrictEqual(point.toHex(), encodedHashToPoints[i]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
should('have proper equality testing', () => {
|
||||||
|
const MAX_448B = BigInt(
|
||||||
|
'0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
|
||||||
|
);
|
||||||
|
const bytes448ToNumberLE = (bytes) => ed448.CURVE.Fp.create(bytesToNumberLE(bytes) & MAX_448B);
|
||||||
|
|
||||||
|
const priv = new Uint8Array([
|
||||||
|
23, 211, 149, 179, 209, 108, 78, 37, 229, 45, 122, 220, 85, 38, 192, 182, 96, 40, 168, 63,
|
||||||
|
175, 194, 73, 202, 14, 175, 78, 15, 117, 175, 40, 32, 218, 221, 151, 58, 158, 91, 250, 141,
|
||||||
|
18, 175, 191, 119, 152, 124, 223, 101, 54, 218, 76, 158, 43, 112, 151, 32,
|
||||||
|
]);
|
||||||
|
const pub = DecafPoint.BASE.multiply(bytes448ToNumberLE(priv));
|
||||||
|
deepStrictEqual(pub.equals(DecafPoint.ZERO), false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// ESM is broken.
|
||||||
|
import url from 'url';
|
||||||
|
|
||||||
|
if (import.meta.url === url.pathToFileURL(process.argv[1]).href) {
|
||||||
|
should.run();
|
||||||
|
}
|
||||||
@@ -2,8 +2,10 @@ import { deepStrictEqual, throws } from 'assert';
|
|||||||
import { describe, should } from 'micro-should';
|
import { describe, should } from 'micro-should';
|
||||||
import * as fc from 'fast-check';
|
import * as fc from 'fast-check';
|
||||||
import { ed448, ed448ph, x448 } from '../esm/ed448.js';
|
import { ed448, ed448ph, x448 } from '../esm/ed448.js';
|
||||||
import { hexToBytes, bytesToHex, randomBytes } from '@noble/hashes/utils';
|
import { bytesToHex, concatBytes, hexToBytes, randomBytes } from '@noble/hashes/utils';
|
||||||
import { numberToBytesLE } from '../esm/abstract/utils.js';
|
import { numberToBytesLE } from '../esm/abstract/utils.js';
|
||||||
|
// Old vectors allow to test sign() because they include private key
|
||||||
|
import { default as ed448vectorsOld } from './ed448/ed448_test_OLD.json' assert { type: 'json' };
|
||||||
import { default as ed448vectors } from './wycheproof/ed448_test.json' assert { type: 'json' };
|
import { default as ed448vectors } from './wycheproof/ed448_test.json' assert { type: 'json' };
|
||||||
import { default as x448vectors } from './wycheproof/x448_test.json' assert { type: 'json' };
|
import { default as x448vectors } from './wycheproof/x448_test.json' assert { type: 'json' };
|
||||||
|
|
||||||
@@ -439,9 +441,9 @@ describe('ed448', () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('wycheproof', () => {
|
describe('wycheproof (OLD)', () => {
|
||||||
for (let g = 0; g < ed448vectors.testGroups.length; g++) {
|
for (let g = 0; g < ed448vectorsOld.testGroups.length; g++) {
|
||||||
const group = ed448vectors.testGroups[g];
|
const group = ed448vectorsOld.testGroups[g];
|
||||||
const key = group.key;
|
const key = group.key;
|
||||||
should(`ED448(${g}, public)`, () => {
|
should(`ED448(${g}, public)`, () => {
|
||||||
deepStrictEqual(hex(ed.getPublicKey(key.sk)), key.pk);
|
deepStrictEqual(hex(ed.getPublicKey(key.sk)), key.pk);
|
||||||
@@ -467,92 +469,20 @@ describe('ed448', () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// ECDH
|
|
||||||
const rfc7748Mul = [
|
|
||||||
{
|
|
||||||
scalar:
|
|
||||||
'3d262fddf9ec8e88495266fea19a34d28882acef045104d0d1aae121700a779c984c24f8cdd78fbff44943eba368f54b29259a4f1c600ad3',
|
|
||||||
u: '06fce640fa3487bfda5f6cf2d5263f8aad88334cbd07437f020f08f9814dc031ddbdc38c19c6da2583fa5429db94ada18aa7a7fb4ef8a086',
|
|
||||||
outputU:
|
|
||||||
'ce3e4ff95a60dc6697da1db1d85e6afbdf79b50a2412d7546d5f239fe14fbaadeb445fc66a01b0779d98223961111e21766282f73dd96b6f',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
scalar:
|
|
||||||
'203d494428b8399352665ddca42f9de8fef600908e0d461cb021f8c538345dd77c3e4806e25f46d3315c44e0a5b4371282dd2c8d5be3095f',
|
|
||||||
u: '0fbcc2f993cd56d3305b0b7d9e55d4c1a8fb5dbb52f8e9a1e9b6201b165d015894e56c4d3570bee52fe205e28a78b91cdfbde71ce8d157db',
|
|
||||||
outputU:
|
|
||||||
'884a02576239ff7a2f2f63b2db6a9ff37047ac13568e1e30fe63c4a7ad1b3ee3a5700df34321d62077e63633c575c1c954514e99da7c179d',
|
|
||||||
},
|
|
||||||
];
|
|
||||||
describe('RFC7748', () => {
|
|
||||||
for (let i = 0; i < rfc7748Mul.length; i++) {
|
|
||||||
const v = rfc7748Mul[i];
|
|
||||||
should(`scalarMult (${i})`, () => {
|
|
||||||
deepStrictEqual(hex(x448.scalarMult(v.scalar, v.u)), 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.GuBytes;
|
|
||||||
for (let i = 0, u = k; i < iters; i++) [k, u] = [x448.scalarMult(k, u), 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(alicePrivate, bobPublic)), shared);
|
|
||||||
deepStrictEqual(hex(x448.scalarMult(bobPrivate, alicePublic)), shared);
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('wycheproof', () => {
|
describe('wycheproof', () => {
|
||||||
const group = x448vectors.testGroups[0];
|
for (let g = 0; g < ed448vectors.testGroups.length; g++) {
|
||||||
should(`X448`, () => {
|
const group = ed448vectors.testGroups[g];
|
||||||
|
const key = group.publicKey;
|
||||||
|
should(`ED448`, () => {
|
||||||
for (let i = 0; i < group.tests.length; i++) {
|
for (let i = 0; i < group.tests.length; i++) {
|
||||||
const v = group.tests[i];
|
const v = group.tests[i];
|
||||||
const index = `(${i}, ${v.result}) ${v.comment}`;
|
const index = `${g}/${i} ${v.comment}`;
|
||||||
if (v.result === 'valid' || v.result === 'acceptable') {
|
if (v.result === 'valid' || v.result === 'acceptable') {
|
||||||
try {
|
deepStrictEqual(ed.verify(v.sig, v.msg, key.pk), true, index);
|
||||||
const shared = hex(x448.scalarMult(v.private, v.public));
|
|
||||||
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') {
|
} else if (v.result === 'invalid') {
|
||||||
let failed = false;
|
let failed = false;
|
||||||
try {
|
try {
|
||||||
x448.scalarMult(v.private, v.public);
|
failed = !ed.verify(v.sig, v.msg, key.pk);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
failed = true;
|
failed = true;
|
||||||
}
|
}
|
||||||
@@ -560,8 +490,8 @@ describe('ed448', () => {
|
|||||||
} else throw new Error('unknown test result');
|
} else throw new Error('unknown test result');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// should('X448: should convert base point to montgomery using fromPoint', () => {
|
// should('X448: should convert base point to montgomery using fromPoint', () => {
|
||||||
// deepStrictEqual(
|
// deepStrictEqual(
|
||||||
// hex(ed.montgomeryCurve.UfromPoint(Point.BASE)),
|
// hex(ed.montgomeryCurve.UfromPoint(Point.BASE)),
|
||||||
@@ -584,6 +514,7 @@ describe('ed448', () => {
|
|||||||
// }
|
// }
|
||||||
// });
|
// });
|
||||||
|
|
||||||
|
describe('ed448ctx', () => {
|
||||||
const VECTORS_RFC8032_CTX = [
|
const VECTORS_RFC8032_CTX = [
|
||||||
{
|
{
|
||||||
secretKey:
|
secretKey:
|
||||||
@@ -603,16 +534,20 @@ describe('ed448', () => {
|
|||||||
'3c00',
|
'3c00',
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
for (let i = 0; i < VECTORS_RFC8032_CTX.length; i++) {
|
for (let i = 0; i < VECTORS_RFC8032_CTX.length; i++) {
|
||||||
const v = VECTORS_RFC8032_CTX[i];
|
const v = VECTORS_RFC8032_CTX[i];
|
||||||
should(`RFC8032ctx/${i}`, () => {
|
should(`${i}`, () => {
|
||||||
deepStrictEqual(hex(ed.getPublicKey(v.secretKey)), v.publicKey);
|
deepStrictEqual(hex(ed.getPublicKey(v.secretKey)), v.publicKey);
|
||||||
deepStrictEqual(hex(ed.sign(v.message, v.secretKey, v.context)), v.signature);
|
deepStrictEqual(hex(ed.sign(v.message, v.secretKey, { context: v.context })), v.signature);
|
||||||
deepStrictEqual(ed.verify(v.signature, v.message, v.publicKey, v.context), true);
|
deepStrictEqual(
|
||||||
|
ed.verify(v.signature, v.message, v.publicKey, { context: v.context }),
|
||||||
|
true
|
||||||
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('ed448ph', () => {
|
||||||
const VECTORS_RFC8032_PH = [
|
const VECTORS_RFC8032_PH = [
|
||||||
{
|
{
|
||||||
secretKey:
|
secretKey:
|
||||||
@@ -648,17 +583,147 @@ describe('ed448', () => {
|
|||||||
'2100',
|
'2100',
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
for (let i = 0; i < VECTORS_RFC8032_PH.length; i++) {
|
for (let i = 0; i < VECTORS_RFC8032_PH.length; i++) {
|
||||||
const v = VECTORS_RFC8032_PH[i];
|
const v = VECTORS_RFC8032_PH[i];
|
||||||
should(`RFC8032ph/${i}`, () => {
|
should(`${i}`, () => {
|
||||||
deepStrictEqual(hex(ed448ph.getPublicKey(v.secretKey)), v.publicKey);
|
deepStrictEqual(hex(ed448ph.getPublicKey(v.secretKey)), v.publicKey);
|
||||||
deepStrictEqual(hex(ed448ph.sign(v.message, v.secretKey, v.context)), v.signature);
|
deepStrictEqual(
|
||||||
deepStrictEqual(ed448ph.verify(v.signature, v.message, v.publicKey, v.context), true);
|
hex(ed448ph.sign(v.message, v.secretKey, { context: v.context })),
|
||||||
|
v.signature
|
||||||
|
);
|
||||||
|
deepStrictEqual(
|
||||||
|
ed448ph.verify(v.signature, v.message, v.publicKey, { context: v.context }),
|
||||||
|
true
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
should('not verify when sig.s >= CURVE.n', () => {
|
||||||
|
function get56bSig() {
|
||||||
|
const privateKey = ed448.utils.randomPrivateKey();
|
||||||
|
const message = Uint8Array.from([0xab, 0xbc, 0xcd, 0xde]);
|
||||||
|
const publicKey = ed448.getPublicKey(privateKey);
|
||||||
|
const signature = ed448.sign(message, privateKey);
|
||||||
|
|
||||||
|
const R = signature.slice(0, 56);
|
||||||
|
let s = signature.slice(56, 112);
|
||||||
|
|
||||||
|
s = bytesToHex(s.slice().reverse());
|
||||||
|
s = BigInt('0x' + s);
|
||||||
|
s = s + ed448.CURVE.n;
|
||||||
|
s = numberToBytesLE(s, 56);
|
||||||
|
|
||||||
|
const sig_invalid = concatBytes(R, s);
|
||||||
|
return { sig_invalid, message, publicKey };
|
||||||
|
}
|
||||||
|
let sig;
|
||||||
|
while (true) {
|
||||||
|
try {
|
||||||
|
sig = get56bSig();
|
||||||
|
break;
|
||||||
|
} catch (error) {
|
||||||
|
// non-56b sig was generated, try again
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throws(() => {
|
||||||
|
ed448.verify(sig.sig_invalid, sig.message, sig.publicKey);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('RFC7748 X448 ECDH', () => {
|
||||||
|
// 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(`scalarMult (${i})`, () => {
|
||||||
|
deepStrictEqual(hex(x448.scalarMult(v.scalar, v.u)), v.outputU);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
should('X448 base point', () => {
|
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(`scalarMult iterated ${iters}x`, () => {
|
||||||
|
let k = x448.GuBytes;
|
||||||
|
for (let i = 0, u = k; i < iters; i++) [k, u] = [x448.scalarMult(k, u), k];
|
||||||
|
deepStrictEqual(hex(k), scalar);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
should('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(alicePrivate, bobPublic)), shared);
|
||||||
|
deepStrictEqual(hex(x448.scalarMult(bobPrivate, alicePublic)), shared);
|
||||||
|
});
|
||||||
|
|
||||||
|
should('wycheproof', () => {
|
||||||
|
const group = x448vectors.testGroups[0];
|
||||||
|
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.private, v.public));
|
||||||
|
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.private, v.public);
|
||||||
|
} catch (error) {
|
||||||
|
failed = true;
|
||||||
|
}
|
||||||
|
deepStrictEqual(failed, true, index);
|
||||||
|
} else throw new Error('unknown test result');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
should('have proper base point', () => {
|
||||||
const { x, y } = Point.BASE;
|
const { x, y } = Point.BASE;
|
||||||
const { Fp } = ed448.CURVE;
|
const { Fp } = ed448.CURVE;
|
||||||
// const invX = Fp.invert(x * x); // x²
|
// const invX = Fp.invert(x * x); // x²
|
||||||
@@ -667,6 +732,7 @@ describe('ed448', () => {
|
|||||||
deepStrictEqual(numberToBytesLE(u, 56), x448.GuBytes);
|
deepStrictEqual(numberToBytesLE(u, 56), x448.GuBytes);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|
||||||
// ESM is broken.
|
// ESM is broken.
|
||||||
import url from 'url';
|
import url from 'url';
|
||||||
|
|||||||
908
test/ed448/ed448_test_OLD.json
Normal file
908
test/ed448/ed448_test_OLD.json
Normal file
@@ -0,0 +1,908 @@
|
|||||||
|
{
|
||||||
|
"algorithm" : "EDDSA",
|
||||||
|
"generatorVersion" : "0.8r12",
|
||||||
|
"numberOfTests" : 86,
|
||||||
|
"header" : [
|
||||||
|
"Test vectors of type EddsaVerify are intended for testing",
|
||||||
|
"the verification of Eddsa signatures."
|
||||||
|
],
|
||||||
|
"notes" : {
|
||||||
|
"SignatureMalleability" : "EdDSA signatures are non-malleable, if implemented accordingly. Failing to check the range of S allows to modify signatures. See RFC 8032, Section 5.2.7 and Section 8.4."
|
||||||
|
},
|
||||||
|
"schema" : "eddsa_verify_schema.json",
|
||||||
|
"testGroups" : [
|
||||||
|
{
|
||||||
|
"jwk" : {
|
||||||
|
"crv" : "Ed448",
|
||||||
|
"d" : "iDAeB2UY01N_kwLuD1Ij5LY-HwFgB9PC69_sX3CZfoEZxrrQrnuAP0h5HKjsVJqiobhi96UVkLnV",
|
||||||
|
"kid" : "none",
|
||||||
|
"kty" : "OKP",
|
||||||
|
"x" : "QZYQpTSvEn9YOwSBjNt_D_MAsCXy4BaCvK4z_Wkc7gOVEd8M3caQ7peEJuizjlDOWvfc-6UPcEwA"
|
||||||
|
},
|
||||||
|
"key" : {
|
||||||
|
"curve" : "edwards448",
|
||||||
|
"keySize" : 448,
|
||||||
|
"pk" : "419610a534af127f583b04818cdb7f0ff300b025f2e01682bcae33fd691cee039511df0cddc690ee978426e8b38e50ce5af7dcfba50f704c00",
|
||||||
|
"sk" : "88301e076518d3537f9302ee0f5223e4b63e1f016007d3c2ebdfec5f70997e8119c6bad0ae7b803f48791ca8ec549aa2a1b862f7a51590b9d5",
|
||||||
|
"type" : "EDDSAKeyPair"
|
||||||
|
},
|
||||||
|
"keyDer" : "3043300506032b6571033a00419610a534af127f583b04818cdb7f0ff300b025f2e01682bcae33fd691cee039511df0cddc690ee978426e8b38e50ce5af7dcfba50f704c00",
|
||||||
|
"keyPem" : "-----BEGIN PUBLIC KEY-----\nMEMwBQYDK2VxAzoAQZYQpTSvEn9YOwSBjNt/D/MAsCXy4BaCvK4z/Wkc7gOVEd8M3caQ7peEJuizjlDOWvfc+6UPcEwA\n-----END PUBLIC KEY-----\n",
|
||||||
|
"type" : "EddsaVerify",
|
||||||
|
"tests" : [
|
||||||
|
{
|
||||||
|
"tcId" : 1,
|
||||||
|
"comment" : "",
|
||||||
|
"msg" : "",
|
||||||
|
"sig" : "cf7953007666e12f73af9ec92e3e018da5ee5a8d5b17f5100a354c58f1d5f4bb37ab835c52f72374c72d612689149cf6d36a70db6dc5a6c400b597348e0e31e51e65bb144e63c892a367b4c055c036aa6cd7e728cdd2a098963bda863903e6dd025b5a5d891209f4e28537694804e50b0800",
|
||||||
|
"result" : "valid",
|
||||||
|
"flags" : []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tcId" : 2,
|
||||||
|
"comment" : "",
|
||||||
|
"msg" : "78",
|
||||||
|
"sig" : "c56e94d5c9ca860c244f33db556bf6b3cec38b024b77604a35d6a07211b1316b9a027133c374b86f72665cc45ce01583a2e0f2775c6172da801acef168717cab1196cddfb149359dfef589756257cc2d6b02fc516d8d41b4adaa3f11428f41410ef0dc3c1b008d3d052173d4389508ed0100",
|
||||||
|
"result" : "valid",
|
||||||
|
"flags" : []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tcId" : 3,
|
||||||
|
"comment" : "",
|
||||||
|
"msg" : "54657374",
|
||||||
|
"sig" : "5d053ff5b71f6ec3284525d35d77933178c8e19879886d08eccc6c7d27e9e5b5e02537dbc4d4723506e8d171fc1733857573dd02d18f48f28031d67d699a188a9ca46b4eabe2107aef237ca609cb462e24c91d25d286402b6ef7862b78a386950246ff38d6d2f458136d12e3c97fdd982600",
|
||||||
|
"result" : "valid",
|
||||||
|
"flags" : []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tcId" : 4,
|
||||||
|
"comment" : "",
|
||||||
|
"msg" : "48656c6c6f",
|
||||||
|
"sig" : "442e33780f199dd7bc71d1335f74df7f3a0ec789e21a175c1bffddb6e50091998d969ac8194b3acefb7702f6c222f84f7eeca3b80406f1fe80687915e7925bf52deb47b6b779e26d30eec7c5fef03580f280a089eefd0bacc9fbbb6a4d73a591d1671d192e6bbcfdb79ad3db5673a1263000",
|
||||||
|
"result" : "valid",
|
||||||
|
"flags" : []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tcId" : 5,
|
||||||
|
"comment" : "",
|
||||||
|
"msg" : "313233343030",
|
||||||
|
"sig" : "5db94c53101f521f6c1f43b60ea4d7e06fbd49c2e8afaf4fcc289e645e0880a87b8e55858df4cf2291a7303ffda446b82a117b4dd408cff28060a05236fc9c1682b0e55b60a082c9a57bffe61ef4dda5ce65df539805122b3a09a05976d41ad68ab52df85428152c57da93531e5d16920e00",
|
||||||
|
"result" : "valid",
|
||||||
|
"flags" : []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tcId" : 6,
|
||||||
|
"comment" : "",
|
||||||
|
"msg" : "000000000000000000000000",
|
||||||
|
"sig" : "a8ca64d1ab00eae77fd2854d8422db3ae12fca91c14f274f30a44df98590786ec4cbb96a9564fc1b9b16c22d2bd00aa65f0876323729f5ac809fb0b89a4d3f27afbabb596851d835173d60ea34e0875359f3d6adb13cef1395b7eaa5f9147583ff38b4deb183062874915bf194ae61072300",
|
||||||
|
"result" : "valid",
|
||||||
|
"flags" : []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tcId" : 7,
|
||||||
|
"comment" : "",
|
||||||
|
"msg" : "6161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161",
|
||||||
|
"sig" : "b205d3e24ccef64c1e86f15f48ddfa682453503489475188b04a8f55860b3c8a9c01e6de820bb7d9b15daff8de25a4a870e987157a115ec1802da0d0606da12842ea7eab658b5eea6dd1f3a641a5174425578003cd318b8d6b8dcb4de954b5078d1912c578ad8281515d6df3672b94173f00",
|
||||||
|
"result" : "valid",
|
||||||
|
"flags" : []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tcId" : 8,
|
||||||
|
"comment" : "",
|
||||||
|
"msg" : "202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f60",
|
||||||
|
"sig" : "3492ef66e5fdf1503e9e206c5c2f0d4b7891aad793575527d2251e0df1b97c2feac188bc382ce3c92c4bc36ba2695f32bedadd480eaa932300d0db1f9a9c60844d2ea5aea64933c7be46c4f9d21cb48b39eae23d08496de7ce9501197185cc5d4ff8aa4b018ce7ad321f6a7d778c4a070400",
|
||||||
|
"result" : "valid",
|
||||||
|
"flags" : []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tcId" : 9,
|
||||||
|
"comment" : "",
|
||||||
|
"msg" : "ffffffffffffffffffffffffffffffff",
|
||||||
|
"sig" : "545e1905af1b5886552eaf78e17304c6f83fcfb3444df2d1ea056486db615e3bb29131bb0c1fd295364dc515dae581967148eb23c6c9012e806d3623baff00548c648e3cb3756aaaaf659f2fb7dd2e71c7611448593ca63f2a98913ab7f182e6820eaf1334e2745e0e7bc0dccab98de71600",
|
||||||
|
"result" : "valid",
|
||||||
|
"flags" : []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tcId" : 10,
|
||||||
|
"comment" : "special values for r and s",
|
||||||
|
"msg" : "3f",
|
||||||
|
"sig" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
|
||||||
|
"result" : "invalid",
|
||||||
|
"flags" : []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tcId" : 11,
|
||||||
|
"comment" : "special values for r and s",
|
||||||
|
"msg" : "3f",
|
||||||
|
"sig" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
|
||||||
|
"result" : "invalid",
|
||||||
|
"flags" : []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tcId" : 12,
|
||||||
|
"comment" : "special values for r and s",
|
||||||
|
"msg" : "3f",
|
||||||
|
"sig" : "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f24458ab92c27823558fc58d72c26c219036d6ae49db4ec4e923ca7cffffffffffffffffffffffffffffffffffffffffffffffffffffff3f",
|
||||||
|
"result" : "invalid",
|
||||||
|
"flags" : []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tcId" : 13,
|
||||||
|
"comment" : "special values for r and s",
|
||||||
|
"msg" : "3f",
|
||||||
|
"sig" : "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f34458ab92c27823558fc58d72c26c219036d6ae49db4ec4e923ca7cffffffffffffffffffffffffffffffffffffffffffffffffffffff3f",
|
||||||
|
"result" : "invalid",
|
||||||
|
"flags" : []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tcId" : 14,
|
||||||
|
"comment" : "special values for r and s",
|
||||||
|
"msg" : "3f",
|
||||||
|
"sig" : "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||||
|
"result" : "invalid",
|
||||||
|
"flags" : []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tcId" : 15,
|
||||||
|
"comment" : "special values for r and s",
|
||||||
|
"msg" : "3f",
|
||||||
|
"sig" : "01000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
|
||||||
|
"result" : "invalid",
|
||||||
|
"flags" : []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tcId" : 16,
|
||||||
|
"comment" : "special values for r and s",
|
||||||
|
"msg" : "3f",
|
||||||
|
"sig" : "01000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
|
||||||
|
"result" : "invalid",
|
||||||
|
"flags" : []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tcId" : 17,
|
||||||
|
"comment" : "special values for r and s",
|
||||||
|
"msg" : "3f",
|
||||||
|
"sig" : "0100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f24458ab92c27823558fc58d72c26c219036d6ae49db4ec4e923ca7cffffffffffffffffffffffffffffffffffffffffffffffffffffff3f",
|
||||||
|
"result" : "invalid",
|
||||||
|
"flags" : []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tcId" : 18,
|
||||||
|
"comment" : "special values for r and s",
|
||||||
|
"msg" : "3f",
|
||||||
|
"sig" : "0100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f34458ab92c27823558fc58d72c26c219036d6ae49db4ec4e923ca7cffffffffffffffffffffffffffffffffffffffffffffffffffffff3f",
|
||||||
|
"result" : "invalid",
|
||||||
|
"flags" : []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tcId" : 19,
|
||||||
|
"comment" : "special values for r and s",
|
||||||
|
"msg" : "3f",
|
||||||
|
"sig" : "0100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||||
|
"result" : "invalid",
|
||||||
|
"flags" : []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tcId" : 20,
|
||||||
|
"comment" : "special values for r and s",
|
||||||
|
"msg" : "3f",
|
||||||
|
"sig" : "f34458ab92c27823558fc58d72c26c219036d6ae49db4ec4e923ca7cffffffffffffffffffffffffffffffffffffffffffffffffffffff3f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
|
||||||
|
"result" : "invalid",
|
||||||
|
"flags" : []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tcId" : 21,
|
||||||
|
"comment" : "special values for r and s",
|
||||||
|
"msg" : "3f",
|
||||||
|
"sig" : "f34458ab92c27823558fc58d72c26c219036d6ae49db4ec4e923ca7cffffffffffffffffffffffffffffffffffffffffffffffffffffff3f0100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
|
||||||
|
"result" : "invalid",
|
||||||
|
"flags" : []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tcId" : 22,
|
||||||
|
"comment" : "special values for r and s",
|
||||||
|
"msg" : "3f",
|
||||||
|
"sig" : "f34458ab92c27823558fc58d72c26c219036d6ae49db4ec4e923ca7cffffffffffffffffffffffffffffffffffffffffffffffffffffff3ff24458ab92c27823558fc58d72c26c219036d6ae49db4ec4e923ca7cffffffffffffffffffffffffffffffffffffffffffffffffffffff3f",
|
||||||
|
"result" : "invalid",
|
||||||
|
"flags" : []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tcId" : 23,
|
||||||
|
"comment" : "special values for r and s",
|
||||||
|
"msg" : "3f",
|
||||||
|
"sig" : "f34458ab92c27823558fc58d72c26c219036d6ae49db4ec4e923ca7cffffffffffffffffffffffffffffffffffffffffffffffffffffff3ff34458ab92c27823558fc58d72c26c219036d6ae49db4ec4e923ca7cffffffffffffffffffffffffffffffffffffffffffffffffffffff3f",
|
||||||
|
"result" : "invalid",
|
||||||
|
"flags" : []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tcId" : 24,
|
||||||
|
"comment" : "special values for r and s",
|
||||||
|
"msg" : "3f",
|
||||||
|
"sig" : "f34458ab92c27823558fc58d72c26c219036d6ae49db4ec4e923ca7cffffffffffffffffffffffffffffffffffffffffffffffffffffff3ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||||
|
"result" : "invalid",
|
||||||
|
"flags" : []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tcId" : 25,
|
||||||
|
"comment" : "special values for r and s",
|
||||||
|
"msg" : "3f",
|
||||||
|
"sig" : "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
|
||||||
|
"result" : "invalid",
|
||||||
|
"flags" : []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tcId" : 26,
|
||||||
|
"comment" : "special values for r and s",
|
||||||
|
"msg" : "3f",
|
||||||
|
"sig" : "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffffffffffffffffffffffffffffffffffffffffffffffffff0100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
|
||||||
|
"result" : "invalid",
|
||||||
|
"flags" : []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tcId" : 27,
|
||||||
|
"comment" : "special values for r and s",
|
||||||
|
"msg" : "3f",
|
||||||
|
"sig" : "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffffffffffffffffffffffffffffffffffffffffffffffffffff24458ab92c27823558fc58d72c26c219036d6ae49db4ec4e923ca7cffffffffffffffffffffffffffffffffffffffffffffffffffffff3f",
|
||||||
|
"result" : "invalid",
|
||||||
|
"flags" : []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tcId" : 28,
|
||||||
|
"comment" : "special values for r and s",
|
||||||
|
"msg" : "3f",
|
||||||
|
"sig" : "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffffffffffffffffffffffffffffffffffffffffffffffffffff34458ab92c27823558fc58d72c26c219036d6ae49db4ec4e923ca7cffffffffffffffffffffffffffffffffffffffffffffffffffffff3f",
|
||||||
|
"result" : "invalid",
|
||||||
|
"flags" : []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tcId" : 29,
|
||||||
|
"comment" : "special values for r and s",
|
||||||
|
"msg" : "3f",
|
||||||
|
"sig" : "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||||
|
"result" : "invalid",
|
||||||
|
"flags" : []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tcId" : 30,
|
||||||
|
"comment" : "empty signature",
|
||||||
|
"msg" : "54657374",
|
||||||
|
"sig" : "",
|
||||||
|
"result" : "invalid",
|
||||||
|
"flags" : []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tcId" : 31,
|
||||||
|
"comment" : "s missing",
|
||||||
|
"msg" : "54657374",
|
||||||
|
"sig" : "5d053ff5b71f6ec3284525d35d77933178c8e19879886d08eccc6c7d27e9e5b5e02537dbc4d4723506e8d171fc1733857573dd02d18f48f280",
|
||||||
|
"result" : "invalid",
|
||||||
|
"flags" : []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tcId" : 32,
|
||||||
|
"comment" : "signature too short",
|
||||||
|
"msg" : "54657374",
|
||||||
|
"sig" : "5d053ff5b71f6ec3284525d35d77933178c8e19879886d08eccc6c7d27e9e5b5e02537dbc4d4723506e8d171fc1733857573dd02d18f48f28031d67d699a188a9ca46b4eabe2107aef237ca609cb462e24c91d25d286402b6ef7862b78a386950246ff38d6d2f458136d12e3c97fdd98",
|
||||||
|
"result" : "invalid",
|
||||||
|
"flags" : []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tcId" : 33,
|
||||||
|
"comment" : "signature too long",
|
||||||
|
"msg" : "54657374",
|
||||||
|
"sig" : "5d053ff5b71f6ec3284525d35d77933178c8e19879886d08eccc6c7d27e9e5b5e02537dbc4d4723506e8d171fc1733857573dd02d18f48f28031d67d699a188a9ca46b4eabe2107aef237ca609cb462e24c91d25d286402b6ef7862b78a386950246ff38d6d2f458136d12e3c97fdd9826002020",
|
||||||
|
"result" : "invalid",
|
||||||
|
"flags" : []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tcId" : 34,
|
||||||
|
"comment" : "include pk in signature",
|
||||||
|
"msg" : "54657374",
|
||||||
|
"sig" : "5d053ff5b71f6ec3284525d35d77933178c8e19879886d08eccc6c7d27e9e5b5e02537dbc4d4723506e8d171fc1733857573dd02d18f48f28031d67d699a188a9ca46b4eabe2107aef237ca609cb462e24c91d25d286402b6ef7862b78a386950246ff38d6d2f458136d12e3c97fdd982600419610a534af127f583b04818cdb7f0ff300b025f2e01682bcae33fd691cee039511df0cddc690ee978426e8b38e50ce5af7dcfba50f704c00",
|
||||||
|
"result" : "invalid",
|
||||||
|
"flags" : []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tcId" : 35,
|
||||||
|
"comment" : "prepending 0 byte to signature",
|
||||||
|
"msg" : "54657374",
|
||||||
|
"sig" : "005d053ff5b71f6ec3284525d35d77933178c8e19879886d08eccc6c7d27e9e5b5e02537dbc4d4723506e8d171fc1733857573dd02d18f48f28031d67d699a188a9ca46b4eabe2107aef237ca609cb462e24c91d25d286402b6ef7862b78a386950246ff38d6d2f458136d12e3c97fdd982600",
|
||||||
|
"result" : "invalid",
|
||||||
|
"flags" : []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tcId" : 36,
|
||||||
|
"comment" : "prepending 0 byte to s",
|
||||||
|
"msg" : "54657374",
|
||||||
|
"sig" : "5d053ff5b71f6ec3284525d35d77933178c8e19879886d08eccc6c7d27e9e5b5e02537dbc4d4723506e8d171fc1733857573dd02d18f48f2800031d67d699a188a9ca46b4eabe2107aef237ca609cb462e24c91d25d286402b6ef7862b78a386950246ff38d6d2f458136d12e3c97fdd982600",
|
||||||
|
"result" : "invalid",
|
||||||
|
"flags" : []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tcId" : 37,
|
||||||
|
"comment" : "appending 0 byte to signature",
|
||||||
|
"msg" : "54657374",
|
||||||
|
"sig" : "5d053ff5b71f6ec3284525d35d77933178c8e19879886d08eccc6c7d27e9e5b5e02537dbc4d4723506e8d171fc1733857573dd02d18f48f28031d67d699a188a9ca46b4eabe2107aef237ca609cb462e24c91d25d286402b6ef7862b78a386950246ff38d6d2f458136d12e3c97fdd98260000",
|
||||||
|
"result" : "invalid",
|
||||||
|
"flags" : []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tcId" : 38,
|
||||||
|
"comment" : "removing 0 byte from signature",
|
||||||
|
"msg" : "5465737430",
|
||||||
|
"sig" : "dbd6384516ab6b0eb2d609414564ec217383b66040dfb0676128251ae24c1d7c179c21a9ee307dc13f8fe6550bc40187f093da85617bcf5d009d3ee8b798ad978b6e683bc4e911940ea82ea0b7e95dc24fe0b29e44663211892c2aaa3451379d22c289b94378f11fb700f1689d4a00d73e",
|
||||||
|
"result" : "invalid",
|
||||||
|
"flags" : []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tcId" : 39,
|
||||||
|
"comment" : "removing 0 byte from signature",
|
||||||
|
"msg" : "546573743535",
|
||||||
|
"sig" : "ce2b2fff0bf445a36813cf2a76e0cc5619a4f16ee53f0fe3cd46fc0414db7248b32fbda54bbb37e708d6238076ea12bf850b964b044520bb80fbaf0e1d1ed3bcab261462df5e7f2de73ac9cbae26dfa29015039acf90575961fc9b91b9ca276dae7d5fa805bd202c5579a0f4c66e801400",
|
||||||
|
"result" : "invalid",
|
||||||
|
"flags" : []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tcId" : 40,
|
||||||
|
"comment" : "dropping byte from signature",
|
||||||
|
"msg" : "546573743633",
|
||||||
|
"sig" : "c283ed36d78c275a5d02f7939aed2c4ef68320ae1bf6fc25e834b758046a6d52a480216a942dfe771f3bd307f4ce7d3f446e0824961bd5de80cda42b5cc38e6ec3d53f386978b9877d3c98a28ac8fc66630ffd178933a18de1aee23cab5011c9ff4c9277311b4c6c33acb8e82b8c693c00",
|
||||||
|
"result" : "invalid",
|
||||||
|
"flags" : []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tcId" : 41,
|
||||||
|
"comment" : "removing leading 0 byte from signature",
|
||||||
|
"msg" : "54657374333631",
|
||||||
|
"sig" : "62e629bd2b8f595df401c362c766216d45de89fceecd99c69d323b5c53ad5ac3ea7224963feba2f2895551d94f548248ef8597d2a959f880d59934a5e8f07847834d66ba1a6b09de5dba692172b13f768f0c29e8196144c130d2353445d63cbd0b690794fdad30a48e8bb7cc2504f80700",
|
||||||
|
"result" : "invalid",
|
||||||
|
"flags" : []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tcId" : 42,
|
||||||
|
"comment" : "modified bit 0 in R",
|
||||||
|
"msg" : "313233343030",
|
||||||
|
"sig" : "5cb94c53101f521f6c1f43b60ea4d7e06fbd49c2e8afaf4fcc289e645e0880a87b8e55858df4cf2291a7303ffda446b82a117b4dd408cff280afc33a525116cc12e0d1c3a1fde6de518a6544f360d0fe18d5be7770b057a2bf792db4b7648fa84a6eaecae909e33fa59c5dfe4804ba2623",
|
||||||
|
"result" : "invalid",
|
||||||
|
"flags" : []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tcId" : 43,
|
||||||
|
"comment" : "modified bit 1 in R",
|
||||||
|
"msg" : "313233343030",
|
||||||
|
"sig" : "5fb94c53101f521f6c1f43b60ea4d7e06fbd49c2e8afaf4fcc289e645e0880a87b8e55858df4cf2291a7303ffda446b82a117b4dd408cff280f91386c3e9dd9e7c9af7ca6bbef8b7a44ae3d68eeade449d7dfbb31de8419eb943e2ecbcdd06df5227e82b9ded519a56e70f0a1c0fc17b06",
|
||||||
|
"result" : "invalid",
|
||||||
|
"flags" : []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tcId" : 44,
|
||||||
|
"comment" : "modified bit 2 in R",
|
||||||
|
"msg" : "313233343030",
|
||||||
|
"sig" : "59b94c53101f521f6c1f43b60ea4d7e06fbd49c2e8afaf4fcc289e645e0880a87b8e55858df4cf2291a7303ffda446b82a117b4dd408cff280f1aab07b4ad069dfafc01b4532e1e44cbf7177e1bdda197fc87434046db5b935afd9114ac5e1138eaead23c3b59dba9026d2da4a86fe800b",
|
||||||
|
"result" : "invalid",
|
||||||
|
"flags" : []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tcId" : 45,
|
||||||
|
"comment" : "modified bit 7 in R",
|
||||||
|
"msg" : "313233343030",
|
||||||
|
"sig" : "ddb94c53101f521f6c1f43b60ea4d7e06fbd49c2e8afaf4fcc289e645e0880a87b8e55858df4cf2291a7303ffda446b82a117b4dd408cff2807668402b7b093fc754019324077c1f842a7d2e35adf7b87094115cec459ad5419e162988ef42b1988d9b944d9d5a7ce09c6f342afa500839",
|
||||||
|
"result" : "invalid",
|
||||||
|
"flags" : []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tcId" : 46,
|
||||||
|
"comment" : "modified bit 8 in R",
|
||||||
|
"msg" : "313233343030",
|
||||||
|
"sig" : "5db84c53101f521f6c1f43b60ea4d7e06fbd49c2e8afaf4fcc289e645e0880a87b8e55858df4cf2291a7303ffda446b82a117b4dd408cff280279b70338586b9e13e669191cc0dfc2a937d50a6118758de04a4ca41f4877abdb971afa87fe4b83bc243b8dfd2cb368aa389a4cb11e83e31",
|
||||||
|
"result" : "invalid",
|
||||||
|
"flags" : []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tcId" : 47,
|
||||||
|
"comment" : "modified bit 16 in R",
|
||||||
|
"msg" : "313233343030",
|
||||||
|
"sig" : "5db94d53101f521f6c1f43b60ea4d7e06fbd49c2e8afaf4fcc289e645e0880a87b8e55858df4cf2291a7303ffda446b82a117b4dd408cff280c7b847556b3a6f9447483899ab730a23004c695054dd57b1c3214fa87f632f39c8ff1471f0532b8eee4154930e1ca30d574b8f9e85b0432b",
|
||||||
|
"result" : "invalid",
|
||||||
|
"flags" : []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tcId" : 48,
|
||||||
|
"comment" : "modified bit 31 in R",
|
||||||
|
"msg" : "313233343030",
|
||||||
|
"sig" : "5db94cd3101f521f6c1f43b60ea4d7e06fbd49c2e8afaf4fcc289e645e0880a87b8e55858df4cf2291a7303ffda446b82a117b4dd408cff2800b017917472b130a1cc1c8e995a252617d5ddaf1f3d48930b4876fa0d2cfedec90a8c85c8274892a1ca3b6cfce63ebfebc307210b844ae0c",
|
||||||
|
"result" : "invalid",
|
||||||
|
"flags" : []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tcId" : 49,
|
||||||
|
"comment" : "modified bit 32 in R",
|
||||||
|
"msg" : "313233343030",
|
||||||
|
"sig" : "5db94c53111f521f6c1f43b60ea4d7e06fbd49c2e8afaf4fcc289e645e0880a87b8e55858df4cf2291a7303ffda446b82a117b4dd408cff2805f38f6371860fcc4f2ec515afd35cb05d8941e2448cc469a15b8537e758b16d46b123581613462c2bb20d8a07299ab795d0998e1e4277931",
|
||||||
|
"result" : "invalid",
|
||||||
|
"flags" : []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tcId" : 50,
|
||||||
|
"comment" : "modified bit 63 in R",
|
||||||
|
"msg" : "313233343030",
|
||||||
|
"sig" : "5db94c53101f529f6c1f43b60ea4d7e06fbd49c2e8afaf4fcc289e645e0880a87b8e55858df4cf2291a7303ffda446b82a117b4dd408cff28017111ba6fefd45e2490f1d53a184007fa073470706d7f4a9606fcad2954e74c32116ba7701d225b76e55164e64df3245c1031f0df734bd31",
|
||||||
|
"result" : "invalid",
|
||||||
|
"flags" : []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tcId" : 51,
|
||||||
|
"comment" : "modified bit 64 in R",
|
||||||
|
"msg" : "313233343030",
|
||||||
|
"sig" : "5db94c53101f521f6d1f43b60ea4d7e06fbd49c2e8afaf4fcc289e645e0880a87b8e55858df4cf2291a7303ffda446b82a117b4dd408cff2808d7d0aa1fd81d0e31789921771c654338f96f0b557b615e3da55670271608a0e022e4e8cf393e309f8f6412281b6147e7fce42b089eb1e0c",
|
||||||
|
"result" : "invalid",
|
||||||
|
"flags" : []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tcId" : 52,
|
||||||
|
"comment" : "modified bit 97 in R",
|
||||||
|
"msg" : "313233343030",
|
||||||
|
"sig" : "5db94c53101f521f6c1f43b60ca4d7e06fbd49c2e8afaf4fcc289e645e0880a87b8e55858df4cf2291a7303ffda446b82a117b4dd408cff280b08d3be6ebf4e60bf6d74e105ea2fa9b965c62816bbd22ea3bb0c1acfd12300523ca76f94b6f789488a957fbeb212d713baccf95fd594f3d",
|
||||||
|
"result" : "invalid",
|
||||||
|
"flags" : []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tcId" : 53,
|
||||||
|
"comment" : "modified bit 127 in R",
|
||||||
|
"msg" : "313233343030",
|
||||||
|
"sig" : "5db94c53101f521f6c1f43b60ea4d7606fbd49c2e8afaf4fcc289e645e0880a87b8e55858df4cf2291a7303ffda446b82a117b4dd408cff280a23f54857e9b0f72b2ef90d2768834590464d75933ed08c454faa762b3702a2b631c33c339d05b2e24c20a8214f99af31f93f80f416a1129",
|
||||||
|
"result" : "invalid",
|
||||||
|
"flags" : []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tcId" : 54,
|
||||||
|
"comment" : "modified bit 240 in R",
|
||||||
|
"msg" : "313233343030",
|
||||||
|
"sig" : "5db94c53101f521f6c1f43b60ea4d7e06fbd49c2e8afaf4fcc289e645e0881a87b8e55858df4cf2291a7303ffda446b82a117b4dd408cff280734bdc399273d3403d934ceaae16e87a68c6bff6b77d8037ff41c97922498a58e704c29ab519d41bab70735f71fc26f589361e2b21754300",
|
||||||
|
"result" : "invalid",
|
||||||
|
"flags" : []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tcId" : 55,
|
||||||
|
"comment" : "modified bit 247 in R",
|
||||||
|
"msg" : "313233343030",
|
||||||
|
"sig" : "5db94c53101f521f6c1f43b60ea4d7e06fbd49c2e8afaf4fcc289e645e0800a87b8e55858df4cf2291a7303ffda446b82a117b4dd408cff280ba961cc8d0765c99d57470ee1c0c77f0a562a198fd0175eddb0c033e0fb8525328c5e2c516e2b00f73609c7f769195eb1a02ff54090d781f",
|
||||||
|
"result" : "invalid",
|
||||||
|
"flags" : []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tcId" : 56,
|
||||||
|
"comment" : "modified bit 248 in R",
|
||||||
|
"msg" : "313233343030",
|
||||||
|
"sig" : "5db94c53101f521f6c1f43b60ea4d7e06fbd49c2e8afaf4fcc289e645e0880a97b8e55858df4cf2291a7303ffda446b82a117b4dd408cff280e72685907da9e5a64e4142ed02fc0c6bf95763201db5942aac055fa87e6fdd32e483fd21ed4110d5d7ef619b740fef2ad8a71fe821e42a2a",
|
||||||
|
"result" : "invalid",
|
||||||
|
"flags" : []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tcId" : 57,
|
||||||
|
"comment" : "modified bit 253 in R",
|
||||||
|
"msg" : "313233343030",
|
||||||
|
"sig" : "5db94c53101f521f6c1f43b60ea4d7e06fbd49c2e8afaf4fcc289e645e0880887b8e55858df4cf2291a7303ffda446b82a117b4dd408cff280500646d67c74f13471f0ad034da530f7238fe7897e532af8ec2977643a410b1d054934df567e170276389e66b3f3ccb3c15aed239d04f72b",
|
||||||
|
"result" : "invalid",
|
||||||
|
"flags" : []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tcId" : 58,
|
||||||
|
"comment" : "modified bit 254 in R",
|
||||||
|
"msg" : "313233343030",
|
||||||
|
"sig" : "5db94c53101f521f6c1f43b60ea4d7e06fbd49c2e8afaf4fcc289e645e0880e87b8e55858df4cf2291a7303ffda446b82a117b4dd408cff2807bb153b8e350aa736a91c921217578539600c1299ab76522ef8f6902d79c93f274073ee6beafe6200ecaf59f7cd11bb1c833f24bf30ed52d",
|
||||||
|
"result" : "invalid",
|
||||||
|
"flags" : []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tcId" : 59,
|
||||||
|
"comment" : "modified bit 255 in R",
|
||||||
|
"msg" : "313233343030",
|
||||||
|
"sig" : "5db94c53101f521f6c1f43b60ea4d7e06fbd49c2e8afaf4fcc289e645e0880287b8e55858df4cf2291a7303ffda446b82a117b4dd408cff2804a67b22be599d6433b87ea961c82c457ab50f64ac6b7efb0b2f90988927f83742303c278f8248e02d5679b41ed505aba0fb51110d0def810",
|
||||||
|
"result" : "invalid",
|
||||||
|
"flags" : []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tcId" : 60,
|
||||||
|
"comment" : "modified bit 440 in R",
|
||||||
|
"msg" : "313233343030",
|
||||||
|
"sig" : "5db94c53101f521f6c1f43b60ea4d7e06fbd49c2e8afaf4fcc289e645e0880a87b8e55858df4cf2291a7303ffda446b82a117b4dd408cff3807f452efb0cd97dab5506028b7b876830dee02a9c0cbd140dcde509638d4d546c30856b2151bdf79930df5bbb11f2beb66bcdc25ad75f2116",
|
||||||
|
"result" : "invalid",
|
||||||
|
"flags" : []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tcId" : 61,
|
||||||
|
"comment" : "modified bit 441 in R",
|
||||||
|
"msg" : "313233343030",
|
||||||
|
"sig" : "5db94c53101f521f6c1f43b60ea4d7e06fbd49c2e8afaf4fcc289e645e0880a87b8e55858df4cf2291a7303ffda446b82a117b4dd408cff0808d78231bb3c9a87c5b8d168fe05f8197503a3d73a6d700f436b5a76ab866388baa6930191a077aca7970058932c88b7f9e6ecb13c89dcd1d",
|
||||||
|
"result" : "invalid",
|
||||||
|
"flags" : []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tcId" : 62,
|
||||||
|
"comment" : "modified bit 447 in R",
|
||||||
|
"msg" : "313233343030",
|
||||||
|
"sig" : "5db94c53101f521f6c1f43b60ea4d7e06fbd49c2e8afaf4fcc289e645e0880a87b8e55858df4cf2291a7303ffda446b82a117b4dd408cf72809e5a8406063fb3545f0fb627f841b2e3a85ad5d378018e8b58fe58e14ee5520d57abc9140e9c5a75a8b09ac3334dd0cad69b48771284321d",
|
||||||
|
"result" : "invalid",
|
||||||
|
"flags" : []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tcId" : 63,
|
||||||
|
"comment" : "modified bit 448 in R",
|
||||||
|
"msg" : "313233343030",
|
||||||
|
"sig" : "5db94c53101f521f6c1f43b60ea4d7e06fbd49c2e8afaf4fcc289e645e0880a87b8e55858df4cf2291a7303ffda446b82a117b4dd408cff2811adf92201088e051ee48b57aecf46edfc68e5baeed5ae4910ba5681d370f75ab593811e18293ef0808581c254196bcbf2b4c454136a6711b",
|
||||||
|
"result" : "invalid",
|
||||||
|
"flags" : []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tcId" : 64,
|
||||||
|
"comment" : "modified bit 449 in R",
|
||||||
|
"msg" : "313233343030",
|
||||||
|
"sig" : "5db94c53101f521f6c1f43b60ea4d7e06fbd49c2e8afaf4fcc289e645e0880a87b8e55858df4cf2291a7303ffda446b82a117b4dd408cff2825e06c3999e8308be439c40940b0075d3e4f65147c1608cbe6e9c432e33bed6686f9393ae2568f0ad60febcb4b6179c0d90d034e7c3c46810",
|
||||||
|
"result" : "invalid",
|
||||||
|
"flags" : []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tcId" : 65,
|
||||||
|
"comment" : "modified bit 454 in R",
|
||||||
|
"msg" : "313233343030",
|
||||||
|
"sig" : "5db94c53101f521f6c1f43b60ea4d7e06fbd49c2e8afaf4fcc289e645e0880a87b8e55858df4cf2291a7303ffda446b82a117b4dd408cff2c02456bbd141df048dbf1843be6d5fef402483314c2af547b361a09f3319489eaede43404df9faf634c1298d678b5261c808b0be3726013e39",
|
||||||
|
"result" : "invalid",
|
||||||
|
"flags" : []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tcId" : 66,
|
||||||
|
"comment" : "modified bit 455 in R",
|
||||||
|
"msg" : "313233343030",
|
||||||
|
"sig" : "5db94c53101f521f6c1f43b60ea4d7e06fbd49c2e8afaf4fcc289e645e0880a87b8e55858df4cf2291a7303ffda446b82a117b4dd408cff2007106d2a896a7fec6dee53eea272d9b6e738c340295416b50f39a9463a5635450b9f93c4c06737affd42ae06cee5879c96c0bd58a91345503",
|
||||||
|
"result" : "invalid",
|
||||||
|
"flags" : []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tcId" : 67,
|
||||||
|
"comment" : "R==0",
|
||||||
|
"msg" : "313233343030",
|
||||||
|
"sig" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000027ab98ab862e4e7ec3361a45ac1993e9b47d9ac40db91faed752399cee0413122b47346594fd7d2c8949b43e4cabaf17d8339ea0e307023f",
|
||||||
|
"result" : "invalid",
|
||||||
|
"flags" : []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tcId" : 68,
|
||||||
|
"comment" : "invalid R",
|
||||||
|
"msg" : "313233343030",
|
||||||
|
"sig" : "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd11bae33a0999fd3fd2bed6fa5577685e8fd595e79c006e58fd35f69f91b1d853553fb4006019a07725aa37773883dbe12253812887ac828",
|
||||||
|
"result" : "invalid",
|
||||||
|
"flags" : []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tcId" : 69,
|
||||||
|
"comment" : "all bits flipped in R",
|
||||||
|
"msg" : "313233343030",
|
||||||
|
"sig" : "a246b3acefe0ade093e0bc49f15b281f9042b63d175050b033d7619ba1f77f578471aa7a720b30dd6e58cfc0025bb947d5ee84b22bf7300d7f334e48141af0fade1469f5dedb851c9e725d27bd65012bada05e70cde641aad9ce0bea4983164f73816b6f13095e6b93eb03e850cad0cf0d",
|
||||||
|
"result" : "invalid",
|
||||||
|
"flags" : []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tcId" : 70,
|
||||||
|
"comment" : "checking malleability ",
|
||||||
|
"msg" : "54657374",
|
||||||
|
"sig" : "5d053ff5b71f6ec3284525d35d77933178c8e19879886d08eccc6c7d27e9e5b5e02537dbc4d4723506e8d171fc1733857573dd02d18f48f280241bd6142ddb02c0f9fa133955d3e610b4b27cb814227de8b241ef4e86402b6ef7862b78a386950246ff38d6d2f458136d12e3c97fdd9866",
|
||||||
|
"result" : "invalid",
|
||||||
|
"flags" : [
|
||||||
|
"SignatureMalleability"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tcId" : 71,
|
||||||
|
"comment" : "checking malleability ",
|
||||||
|
"msg" : "54657374",
|
||||||
|
"sig" : "5d053ff5b71f6ec3284525d35d77933178c8e19879886d08eccc6c7d27e9e5b5e02537dbc4d4723506e8d171fc1733857573dd02d18f48f28017602ec0bf9d7be34e8ad9c6c795533244e952675efdcbac9c65b9cb85402b6ef7862b78a386950246ff38d6d2f458136d12e3c97fdd98a6",
|
||||||
|
"result" : "invalid",
|
||||||
|
"flags" : [
|
||||||
|
"SignatureMalleability"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tcId" : 72,
|
||||||
|
"comment" : "checking malleability ",
|
||||||
|
"msg" : "54657374",
|
||||||
|
"sig" : "5d053ff5b71f6ec3284525d35d77933178c8e19879886d08eccc6c7d27e9e5b5e02537dbc4d4723506e8d171fc1733857573dd02d18f48f280fde9de16e5226d2af9a864e2ac1a2d756456ffc4f1b3693570ad4dc584402b6ef7862b78a386950246ff38d6d2f458136d12e3c97fdd9826",
|
||||||
|
"result" : "invalid",
|
||||||
|
"flags" : [
|
||||||
|
"SignatureMalleability"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tcId" : 73,
|
||||||
|
"comment" : "checking malleability ",
|
||||||
|
"msg" : "54657374",
|
||||||
|
"sig" : "5d053ff5b71f6ec3284525d35d77933178c8e19879886d08eccc6c7d27e9e5b5e02537dbc4d4723506e8d171fc1733857573dd02d18f48f280c9fd3fc42f2d50b84de67a197724e0faa43058801821a546173d76b882402b6ef7862b78a386950246ff38d6d2f458136d12e3c97fdd9826",
|
||||||
|
"result" : "invalid",
|
||||||
|
"flags" : [
|
||||||
|
"SignatureMalleability"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tcId" : 74,
|
||||||
|
"comment" : "checking malleability ",
|
||||||
|
"msg" : "54657374",
|
||||||
|
"sig" : "5d053ff5b71f6ec3284525d35d77933178c8e19879886d08eccc6c7d27e9e5b5e02537dbc4d4723506e8d171fc1733857573dd02d18f48f28031d67d699a188a9ca46b4eabe2107aef237ca609cb462e24c91d25d286402b6ef7862b78a386950246ff38d6d2f458136d12e3c97fdd9866",
|
||||||
|
"result" : "invalid",
|
||||||
|
"flags" : [
|
||||||
|
"SignatureMalleability"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tcId" : 75,
|
||||||
|
"comment" : "checking malleability ",
|
||||||
|
"msg" : "54657374",
|
||||||
|
"sig" : "5d053ff5b71f6ec3284525d35d77933178c8e19879886d08eccc6c7d27e9e5b5e02537dbc4d4723506e8d171fc1733857573dd02d18f48f28031d67d699a188a9ca46b4eabe2107aef237ca609cb462e24c91d25d286402b6ef7862b78a386950246ff38d6d2f458136d12e3c97fdd98a6",
|
||||||
|
"result" : "invalid",
|
||||||
|
"flags" : [
|
||||||
|
"SignatureMalleability"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tcId" : 76,
|
||||||
|
"comment" : "checking malleability ",
|
||||||
|
"msg" : "54657374",
|
||||||
|
"sig" : "5d053ff5b71f6ec3284525d35d77933178c8e19879886d08eccc6c7d27e9e5b5e02537dbc4d4723506e8d171fc1733857573dd02d18f48f28031d67d699a188a9ca46b4eabe2107aef237ca609cb462e24c91d25d286402b6ef7862b78a386950246ff38d6d2f458136d12e3c97fdd9826",
|
||||||
|
"result" : "invalid",
|
||||||
|
"flags" : [
|
||||||
|
"SignatureMalleability"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tcId" : 77,
|
||||||
|
"comment" : "checking malleability ",
|
||||||
|
"msg" : "54657374",
|
||||||
|
"sig" : "5d053ff5b71f6ec3284525d35d77933178c8e19879886d08eccc6c7d27e9e5b5e02537dbc4d4723506e8d171fc1733857573dd02d18f48f28030d67d699a188a9ca46b4eabe2107aef237ca609cb462e24c91d25d285402b6ef7862b78a386950246ff38d6d2f458136d12e3c97fdd9826",
|
||||||
|
"result" : "invalid",
|
||||||
|
"flags" : [
|
||||||
|
"SignatureMalleability"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"jwk" : {
|
||||||
|
"crv" : "Ed448",
|
||||||
|
"d" : "bIKlYsuAjRDWMr6JyFE-v2ySnzTd-oyfY8mWDvbjSKNSjIo_zC8ETjmj_FuUSS-PAy51SaIAmPlb",
|
||||||
|
"kid" : "none",
|
||||||
|
"kty" : "OKP",
|
||||||
|
"x" : "X9dEm1m0Yf0s54fsYWrUah2hNCSFpw4fig6nXYDpZ3jt8SR2m0bHBhvWeD3x5Q9s0foavq_oJWGA"
|
||||||
|
},
|
||||||
|
"key" : {
|
||||||
|
"curve" : "edwards448",
|
||||||
|
"keySize" : 448,
|
||||||
|
"pk" : "5fd7449b59b461fd2ce787ec616ad46a1da1342485a70e1f8a0ea75d80e96778edf124769b46c7061bd6783df1e50f6cd1fa1abeafe8256180",
|
||||||
|
"sk" : "6c82a562cb808d10d632be89c8513ebf6c929f34ddfa8c9f63c9960ef6e348a3528c8a3fcc2f044e39a3fc5b94492f8f032e7549a20098f95b",
|
||||||
|
"type" : "EDDSAKeyPair"
|
||||||
|
},
|
||||||
|
"keyDer" : "3043300506032b6571033a005fd7449b59b461fd2ce787ec616ad46a1da1342485a70e1f8a0ea75d80e96778edf124769b46c7061bd6783df1e50f6cd1fa1abeafe8256180",
|
||||||
|
"keyPem" : "-----BEGIN PUBLIC KEY-----\nMEMwBQYDK2VxAzoAX9dEm1m0Yf0s54fsYWrUah2hNCSFpw4fig6nXYDpZ3jt8SR2m0bHBhvWeD3x5Q9s0foavq/oJWGA\n-----END PUBLIC KEY-----\n",
|
||||||
|
"type" : "EddsaVerify",
|
||||||
|
"tests" : [
|
||||||
|
{
|
||||||
|
"tcId" : 78,
|
||||||
|
"comment" : "RFC 8032",
|
||||||
|
"msg" : "",
|
||||||
|
"sig" : "533a37f6bbe457251f023c0d88f976ae2dfb504a843e34d2074fd823d41a591f2b233f034f628281f2fd7a22ddd47d7828c59bd0a21bfd3980ff0d2028d4b18a9df63e006c5d1c2d345b925d8dc00b4104852db99ac5c7cdda8530a113a0f4dbb61149f05a7363268c71d95808ff2e652600",
|
||||||
|
"result" : "valid",
|
||||||
|
"flags" : []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"jwk" : {
|
||||||
|
"crv" : "Ed448",
|
||||||
|
"d" : "xOqwXTVwB8Yy89u0hImSTVUrCP4MNToNSh8ArNosRjr76mfF6NKHfF47w5emWZSe-AIelU4KEidO",
|
||||||
|
"kid" : "none",
|
||||||
|
"kty" : "OKP",
|
||||||
|
"x" : "Q7oo9DDN_0Vq5TFUX37NCsg0pV2TWMA3K_oMbGeYwIZq6gHrAHQoArhDjqTLghacI1FgYntMOpSA"
|
||||||
|
},
|
||||||
|
"key" : {
|
||||||
|
"curve" : "edwards448",
|
||||||
|
"keySize" : 448,
|
||||||
|
"pk" : "43ba28f430cdff456ae531545f7ecd0ac834a55d9358c0372bfa0c6c6798c0866aea01eb00742802b8438ea4cb82169c235160627b4c3a9480",
|
||||||
|
"sk" : "c4eab05d357007c632f3dbb48489924d552b08fe0c353a0d4a1f00acda2c463afbea67c5e8d2877c5e3bc397a659949ef8021e954e0a12274e",
|
||||||
|
"type" : "EDDSAKeyPair"
|
||||||
|
},
|
||||||
|
"keyDer" : "3043300506032b6571033a0043ba28f430cdff456ae531545f7ecd0ac834a55d9358c0372bfa0c6c6798c0866aea01eb00742802b8438ea4cb82169c235160627b4c3a9480",
|
||||||
|
"keyPem" : "-----BEGIN PUBLIC KEY-----\nMEMwBQYDK2VxAzoAQ7oo9DDN/0Vq5TFUX37NCsg0pV2TWMA3K/oMbGeYwIZq6gHrAHQoArhDjqTLghacI1FgYntMOpSA\n-----END PUBLIC KEY-----\n",
|
||||||
|
"type" : "EddsaVerify",
|
||||||
|
"tests" : [
|
||||||
|
{
|
||||||
|
"tcId" : 79,
|
||||||
|
"comment" : "RFC 8032: 1 octet",
|
||||||
|
"msg" : "03",
|
||||||
|
"sig" : "26b8f91727bd62897af15e41eb43c377efb9c610d48f2335cb0bd0087810f4352541b143c4b981b7e18f62de8ccdf633fc1bf037ab7cd779805e0dbcc0aae1cbcee1afb2e027df36bc04dcecbf154336c19f0af7e0a6472905e799f1953d2a0ff3348ab21aa4adafd1d234441cf807c03a00",
|
||||||
|
"result" : "valid",
|
||||||
|
"flags" : []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tcId" : 80,
|
||||||
|
"comment" : "RFC 8032: 1 octet with context",
|
||||||
|
"msg" : "03",
|
||||||
|
"sig" : "d4f8f6131770dd46f40867d6fd5d5055de43541f8c5e35abbcd001b32a89f7d2151f7647f11d8ca2ae279fb842d607217fce6e042f6815ea000c85741de5c8da1144a6a1aba7f96de42505d7a7298524fda538fccbbb754f578c1cad10d54d0d5428407e85dcbc98a49155c13764e66c3c00",
|
||||||
|
"result" : "invalid",
|
||||||
|
"flags" : []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"jwk" : {
|
||||||
|
"crv" : "Ed448",
|
||||||
|
"d" : "zSPST3FCdOdENDI3uTKQ9RH2Ql-Y5kRZ_yA-iYUIP_32BQBVOrwOBc0CGEvbicTM1n4YeVEmfrMo",
|
||||||
|
"kid" : "none",
|
||||||
|
"kty" : "OKP",
|
||||||
|
"x" : "3OqeePNaG_NJmoMbELhskKrAHNhLZ6AQm1WjbpMoseNl_OFh1xznExpUPqTLX36fHYsAaWRHABQA"
|
||||||
|
},
|
||||||
|
"key" : {
|
||||||
|
"curve" : "edwards448",
|
||||||
|
"keySize" : 448,
|
||||||
|
"pk" : "dcea9e78f35a1bf3499a831b10b86c90aac01cd84b67a0109b55a36e9328b1e365fce161d71ce7131a543ea4cb5f7e9f1d8b00696447001400",
|
||||||
|
"sk" : "cd23d24f714274e744343237b93290f511f6425f98e64459ff203e8985083ffdf60500553abc0e05cd02184bdb89c4ccd67e187951267eb328",
|
||||||
|
"type" : "EDDSAKeyPair"
|
||||||
|
},
|
||||||
|
"keyDer" : "3043300506032b6571033a00dcea9e78f35a1bf3499a831b10b86c90aac01cd84b67a0109b55a36e9328b1e365fce161d71ce7131a543ea4cb5f7e9f1d8b00696447001400",
|
||||||
|
"keyPem" : "-----BEGIN PUBLIC KEY-----\nMEMwBQYDK2VxAzoA3OqeePNaG/NJmoMbELhskKrAHNhLZ6AQm1WjbpMoseNl/OFh1xznExpUPqTLX36fHYsAaWRHABQA\n-----END PUBLIC KEY-----\n",
|
||||||
|
"type" : "EddsaVerify",
|
||||||
|
"tests" : [
|
||||||
|
{
|
||||||
|
"tcId" : 81,
|
||||||
|
"comment" : "RFC 8032: 11 bytes",
|
||||||
|
"msg" : "0c3e544074ec63b0265e0c",
|
||||||
|
"sig" : "1f0a8888ce25e8d458a21130879b840a9089d999aaba039eaf3e3afa090a09d389dba82c4ff2ae8ac5cdfb7c55e94d5d961a29fe0109941e00b8dbdeea6d3b051068df7254c0cdc129cbe62db2dc957dbb47b51fd3f213fb8698f064774250a5028961c9bf8ffd973fe5d5c206492b140e00",
|
||||||
|
"result" : "valid",
|
||||||
|
"flags" : []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"jwk" : {
|
||||||
|
"crv" : "Ed448",
|
||||||
|
"d" : "JYzdStoy7Zyf9U5jdWrlgvuPqyrHIfLI5nanJ2hRPZOfY93bVWCRM_Ka34bsmSncy1LBxf0v9-Ib",
|
||||||
|
"kid" : "none",
|
||||||
|
"kty" : "OKP",
|
||||||
|
"x" : "O6FtoMbyzB8wGHdAdW9eeY1rxfwBXXxjzJUQ7j_UStwk2OlotuRub5TRm5RTYXJr114UnvCYF_WA"
|
||||||
|
},
|
||||||
|
"key" : {
|
||||||
|
"curve" : "edwards448",
|
||||||
|
"keySize" : 448,
|
||||||
|
"pk" : "3ba16da0c6f2cc1f30187740756f5e798d6bc5fc015d7c63cc9510ee3fd44adc24d8e968b6e46e6f94d19b945361726bd75e149ef09817f580",
|
||||||
|
"sk" : "258cdd4ada32ed9c9ff54e63756ae582fb8fab2ac721f2c8e676a72768513d939f63dddb55609133f29adf86ec9929dccb52c1c5fd2ff7e21b",
|
||||||
|
"type" : "EDDSAKeyPair"
|
||||||
|
},
|
||||||
|
"keyDer" : "3043300506032b6571033a003ba16da0c6f2cc1f30187740756f5e798d6bc5fc015d7c63cc9510ee3fd44adc24d8e968b6e46e6f94d19b945361726bd75e149ef09817f580",
|
||||||
|
"keyPem" : "-----BEGIN PUBLIC KEY-----\nMEMwBQYDK2VxAzoAO6FtoMbyzB8wGHdAdW9eeY1rxfwBXXxjzJUQ7j/UStwk2OlotuRub5TRm5RTYXJr114UnvCYF/WA\n-----END PUBLIC KEY-----\n",
|
||||||
|
"type" : "EddsaVerify",
|
||||||
|
"tests" : [
|
||||||
|
{
|
||||||
|
"tcId" : 82,
|
||||||
|
"comment" : "RFC 8032: 12 bytes",
|
||||||
|
"msg" : "64a65f3cdedcdd66811e2915",
|
||||||
|
"sig" : "7eeeab7c4e50fb799b418ee5e3197ff6bf15d43a14c34389b59dd1a7b1b85b4ae90438aca634bea45e3a2695f1270f07fdcdf7c62b8efeaf00b45c2c96ba457eb1a8bf075a3db28e5c24f6b923ed4ad747c3c9e03c7079efb87cb110d3a99861e72003cbae6d6b8b827e4e6c143064ff3c00",
|
||||||
|
"result" : "valid",
|
||||||
|
"flags" : []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"jwk" : {
|
||||||
|
"crv" : "Ed448",
|
||||||
|
"d" : "fvToRUQjZ1L7tWuPMaI6EOQoFPX1XKA3zcwRxkyaOylJwbtgcAMUYRcypsL-qY7rwCZqEak5cBAO",
|
||||||
|
"kid" : "none",
|
||||||
|
"kty" : "OKP",
|
||||||
|
"x" : "s9oHmwqkk6V3ICnwRnuuvuWoES2dOiJTI2HaKU97s4FcXcWeF2tNnzgcoJOOE8bAexdL5l36V46A"
|
||||||
|
},
|
||||||
|
"key" : {
|
||||||
|
"curve" : "edwards448",
|
||||||
|
"keySize" : 448,
|
||||||
|
"pk" : "b3da079b0aa493a5772029f0467baebee5a8112d9d3a22532361da294f7bb3815c5dc59e176b4d9f381ca0938e13c6c07b174be65dfa578e80",
|
||||||
|
"sk" : "7ef4e84544236752fbb56b8f31a23a10e42814f5f55ca037cdcc11c64c9a3b2949c1bb60700314611732a6c2fea98eebc0266a11a93970100e",
|
||||||
|
"type" : "EDDSAKeyPair"
|
||||||
|
},
|
||||||
|
"keyDer" : "3043300506032b6571033a00b3da079b0aa493a5772029f0467baebee5a8112d9d3a22532361da294f7bb3815c5dc59e176b4d9f381ca0938e13c6c07b174be65dfa578e80",
|
||||||
|
"keyPem" : "-----BEGIN PUBLIC KEY-----\nMEMwBQYDK2VxAzoAs9oHmwqkk6V3ICnwRnuuvuWoES2dOiJTI2HaKU97s4FcXcWeF2tNnzgcoJOOE8bAexdL5l36V46A\n-----END PUBLIC KEY-----\n",
|
||||||
|
"type" : "EddsaVerify",
|
||||||
|
"tests" : [
|
||||||
|
{
|
||||||
|
"tcId" : 83,
|
||||||
|
"comment" : "RFC 8032: 13 bytes",
|
||||||
|
"msg" : "64a65f3cdedcdd66811e2915e7",
|
||||||
|
"sig" : "6a12066f55331b6c22acd5d5bfc5d71228fbda80ae8dec26bdd306743c5027cb4890810c162c027468675ecf645a83176c0d7323a2ccde2d80efe5a1268e8aca1d6fbc194d3f77c44986eb4ab4177919ad8bec33eb47bbb5fc6e28196fd1caf56b4e7e0ba5519234d047155ac727a1053100",
|
||||||
|
"result" : "valid",
|
||||||
|
"flags" : []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"jwk" : {
|
||||||
|
"crv" : "Ed448",
|
||||||
|
"d" : "1l3zQa0T4AhWdoi67dqOnc3BfcAkl06ltCJ7ZTDjOb_yH5nmjKaWjzzKbf4PufT6tPoTXVVC6j8B",
|
||||||
|
"kid" : "none",
|
||||||
|
"kty" : "OKP",
|
||||||
|
"x" : "35cF9Y7bq4Asf4Njz-VWCrHGEywgqfHdFjSDom-KxTo51oCL9KHfvSYbCZuwOz-1CQbLKL2KCB8A"
|
||||||
|
},
|
||||||
|
"key" : {
|
||||||
|
"curve" : "edwards448",
|
||||||
|
"keySize" : 448,
|
||||||
|
"pk" : "df9705f58edbab802c7f8363cfe5560ab1c6132c20a9f1dd163483a26f8ac53a39d6808bf4a1dfbd261b099bb03b3fb50906cb28bd8a081f00",
|
||||||
|
"sk" : "d65df341ad13e008567688baedda8e9dcdc17dc024974ea5b4227b6530e339bff21f99e68ca6968f3cca6dfe0fb9f4fab4fa135d5542ea3f01",
|
||||||
|
"type" : "EDDSAKeyPair"
|
||||||
|
},
|
||||||
|
"keyDer" : "3043300506032b6571033a00df9705f58edbab802c7f8363cfe5560ab1c6132c20a9f1dd163483a26f8ac53a39d6808bf4a1dfbd261b099bb03b3fb50906cb28bd8a081f00",
|
||||||
|
"keyPem" : "-----BEGIN PUBLIC KEY-----\nMEMwBQYDK2VxAzoA35cF9Y7bq4Asf4Njz+VWCrHGEywgqfHdFjSDom+KxTo51oCL9KHfvSYbCZuwOz+1CQbLKL2KCB8A\n-----END PUBLIC KEY-----\n",
|
||||||
|
"type" : "EddsaVerify",
|
||||||
|
"tests" : [
|
||||||
|
{
|
||||||
|
"tcId" : 84,
|
||||||
|
"comment" : "RFC 8032: 64 bytes",
|
||||||
|
"msg" : "bd0f6a3747cd561bdddf4640a332461a4a30a12a434cd0bf40d766d9c6d458e5512204a30c17d1f50b5079631f64eb3112182da3005835461113718d1a5ef944",
|
||||||
|
"sig" : "554bc2480860b49eab8532d2a533b7d578ef473eeb58c98bb2d0e1ce488a98b18dfde9b9b90775e67f47d4a1c3482058efc9f40d2ca033a0801b63d45b3b722ef552bad3b4ccb667da350192b61c508cf7b6b5adadc2c8d9a446ef003fb05cba5f30e88e36ec2703b349ca229c2670833900",
|
||||||
|
"result" : "valid",
|
||||||
|
"flags" : []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"jwk" : {
|
||||||
|
"crv" : "Ed448",
|
||||||
|
"d" : "LsX-PBcEWr2xNqXmqRPjKrda5otT0vwUm3flBBMtN1abfnZrp0oZvWFiNDohyFkKqc68qQFMY231",
|
||||||
|
"kid" : "none",
|
||||||
|
"kty" : "OKP",
|
||||||
|
"x" : "eXVvAU3P4gefXdnnGL5BceLvJIagjyUYb2v_Q6mTa5v-EkArCK5leYo9geIunsgOdpCGLvPU7ToA"
|
||||||
|
},
|
||||||
|
"key" : {
|
||||||
|
"curve" : "edwards448",
|
||||||
|
"keySize" : 448,
|
||||||
|
"pk" : "79756f014dcfe2079f5dd9e718be4171e2ef2486a08f25186f6bff43a9936b9bfe12402b08ae65798a3d81e22e9ec80e7690862ef3d4ed3a00",
|
||||||
|
"sk" : "2ec5fe3c17045abdb136a5e6a913e32ab75ae68b53d2fc149b77e504132d37569b7e766ba74a19bd6162343a21c8590aa9cebca9014c636df5",
|
||||||
|
"type" : "EDDSAKeyPair"
|
||||||
|
},
|
||||||
|
"keyDer" : "3043300506032b6571033a0079756f014dcfe2079f5dd9e718be4171e2ef2486a08f25186f6bff43a9936b9bfe12402b08ae65798a3d81e22e9ec80e7690862ef3d4ed3a00",
|
||||||
|
"keyPem" : "-----BEGIN PUBLIC KEY-----\nMEMwBQYDK2VxAzoAeXVvAU3P4gefXdnnGL5BceLvJIagjyUYb2v/Q6mTa5v+EkArCK5leYo9geIunsgOdpCGLvPU7ToA\n-----END PUBLIC KEY-----\n",
|
||||||
|
"type" : "EddsaVerify",
|
||||||
|
"tests" : [
|
||||||
|
{
|
||||||
|
"tcId" : 85,
|
||||||
|
"comment" : "RFC 8032: 256 bytes",
|
||||||
|
"msg" : "15777532b0bdd0d1389f636c5f6b9ba734c90af572877e2d272dd078aa1e567cfa80e12928bb542330e8409f3174504107ecd5efac61ae7504dabe2a602ede89e5cca6257a7c77e27a702b3ae39fc769fc54f2395ae6a1178cab4738e543072fc1c177fe71e92e25bf03e4ecb72f47b64d0465aaea4c7fad372536c8ba516a6039c3c2a39f0e4d832be432dfa9a706a6e5c7e19f397964ca4258002f7c0541b590316dbc5622b6b2a6fe7a4abffd96105eca76ea7b98816af0748c10df048ce012d901015a51f189f3888145c03650aa23ce894c3bd889e030d565071c59f409a9981b51878fd6fc110624dcbcde0bf7a69ccce38fabdf86f3bef6044819de11",
|
||||||
|
"sig" : "c650ddbb0601c19ca11439e1640dd931f43c518ea5bea70d3dcde5f4191fe53f00cf966546b72bcc7d58be2b9badef28743954e3a44a23f880e8d4f1cfce2d7a61452d26da05896f0a50da66a239a8a188b6d825b3305ad77b73fbac0836ecc60987fd08527c1a8e80d5823e65cafe2a3d00",
|
||||||
|
"result" : "valid",
|
||||||
|
"flags" : []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"jwk" : {
|
||||||
|
"crv" : "Ed448",
|
||||||
|
"d" : "hy0JN4D103MN98ISZks3uKDyT1aBDaqDgs1Po_d2NOxE3FTxwu2b6ob6-3Yy2L4ZnqFl9a1V3Zzo",
|
||||||
|
"kid" : "none",
|
||||||
|
"kty" : "OKP",
|
||||||
|
"x" : "qBsuinClrJT_28ybrfw_6wgB8lhXi7EUrUTs4ewOeZ2gjv-4HF1oXAxW9k7srvjN8RzDhzeDjPQA"
|
||||||
|
},
|
||||||
|
"key" : {
|
||||||
|
"curve" : "edwards448",
|
||||||
|
"keySize" : 448,
|
||||||
|
"pk" : "a81b2e8a70a5ac94ffdbcc9badfc3feb0801f258578bb114ad44ece1ec0e799da08effb81c5d685c0c56f64eecaef8cdf11cc38737838cf400",
|
||||||
|
"sk" : "872d093780f5d3730df7c212664b37b8a0f24f56810daa8382cd4fa3f77634ec44dc54f1c2ed9bea86fafb7632d8be199ea165f5ad55dd9ce8",
|
||||||
|
"type" : "EDDSAKeyPair"
|
||||||
|
},
|
||||||
|
"keyDer" : "3043300506032b6571033a00a81b2e8a70a5ac94ffdbcc9badfc3feb0801f258578bb114ad44ece1ec0e799da08effb81c5d685c0c56f64eecaef8cdf11cc38737838cf400",
|
||||||
|
"keyPem" : "-----BEGIN PUBLIC KEY-----\nMEMwBQYDK2VxAzoAqBsuinClrJT/28ybrfw/6wgB8lhXi7EUrUTs4ewOeZ2gjv+4HF1oXAxW9k7srvjN8RzDhzeDjPQA\n-----END PUBLIC KEY-----\n",
|
||||||
|
"type" : "EddsaVerify",
|
||||||
|
"tests" : [
|
||||||
|
{
|
||||||
|
"tcId" : 86,
|
||||||
|
"comment" : "RFC 8032: 1023 bytes",
|
||||||
|
"msg" : "6ddf802e1aae4986935f7f981ba3f0351d6273c0a0c22c9c0e8339168e675412a3debfaf435ed651558007db4384b650fcc07e3b586a27a4f7a00ac8a6fec2cd86ae4bf1570c41e6a40c931db27b2faa15a8cedd52cff7362c4e6e23daec0fbc3a79b6806e316efcc7b68119bf46bc76a26067a53f296dafdbdc11c77f7777e972660cf4b6a9b369a6665f02e0cc9b6edfad136b4fabe723d2813db3136cfde9b6d044322fee2947952e031b73ab5c603349b307bdc27bc6cb8b8bbd7bd323219b8033a581b59eadebb09b3c4f3d2277d4f0343624acc817804728b25ab797172b4c5c21a22f9c7839d64300232eb66e53f31c723fa37fe387c7d3e50bdf9813a30e5bb12cf4cd930c40cfb4e1fc622592a49588794494d56d24ea4b40c89fc0596cc9ebb961c8cb10adde976a5d602b1c3f85b9b9a001ed3c6a4d3b1437f52096cd1956d042a597d561a596ecd3d1735a8d570ea0ec27225a2c4aaff26306d1526c1af3ca6d9cf5a2c98f47e1c46db9a33234cfd4d81f2c98538a09ebe76998d0d8fd25997c7d255c6d66ece6fa56f11144950f027795e653008f4bd7ca2dee85d8e90f3dc315130ce2a00375a318c7c3d97be2c8ce5b6db41a6254ff264fa6155baee3b0773c0f497c573f19bb4f4240281f0b1f4f7be857a4e59d416c06b4c50fa09e1810ddc6b1467baeac5a3668d11b6ecaa901440016f389f80acc4db977025e7f5924388c7e340a732e554440e76570f8dd71b7d640b3450d1fd5f0410a18f9a3494f707c717b79b4bf75c98400b096b21653b5d217cf3565c9597456f70703497a078763829bc01bb1cbc8fa04eadc9a6e3f6699587a9e75c94e5bab0036e0b2e711392cff0047d0d6b05bd2a588bc109718954259f1d86678a579a3120f19cfb2963f177aeb70f2d4844826262e51b80271272068ef5b3856fa8535aa2a88b2d41f2a0e2fda7624c2850272ac4a2f561f8f2f7a318bfd5caf9696149e4ac824ad3460538fdc25421beec2cc6818162d06bbed0c40a387192349db67a118bada6cd5ab0140ee273204f628aad1c135f770279a651e24d8c14d75a6059d76b96a6fd857def5e0b354b27ab937a5815d16b5fae407ff18222c6d1ed263be68c95f32d908bd895cd76207ae726487567f9a67dad79abec316f683b17f2d02bf07e0ac8b5bc6162cf94697b3c27cd1fea49b27f23ba2901871962506520c392da8b6ad0d99f7013fbc06c2c17a569500c8a7696481c1cd33e9b14e40b82e79a5f5db82571ba97bae3ad3e0479515bb0e2b0f3bfcd1fd33034efc6245eddd7ee2086ddae2600d8ca73e214e8c2b0bdb2b047c6a464a562ed77b73d2d841c4b34973551257713b753632efba348169abc90a68f42611a40126d7cb21b58695568186f7e569d2ff0f9e745d0487dd2eb997cafc5abf9dd102e62ff66cba87",
|
||||||
|
"sig" : "e301345a41a39a4d72fff8df69c98075a0cc082b802fc9b2b6bc503f926b65bddf7f4c8f1cb49f6396afc8a70abe6d8aef0db478d4c6b2970076c6a0484fe76d76b3a97625d79f1ce240e7c576750d295528286f719b413de9ada3e8eb78ed573603ce30d8bb761785dc30dbc320869e1a00",
|
||||||
|
"result" : "valid",
|
||||||
|
"flags" : []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
107
test/fixtures/rfc6979.json
vendored
107
test/fixtures/rfc6979.json
vendored
@@ -1,107 +0,0 @@
|
|||||||
[
|
|
||||||
{
|
|
||||||
"curve": "P192",
|
|
||||||
"q": "FFFFFFFFFFFFFFFFFFFFFFFF99DEF836146BC9B1B4D22831",
|
|
||||||
"private": "6FAB034934E4C0FC9AE67F5B5659A9D7D1FEFD187EE09FD4",
|
|
||||||
"Ux": "AC2C77F529F91689FEA0EA5EFEC7F210D8EEA0B9E047ED56",
|
|
||||||
"Uy": "3BC723E57670BD4887EBC732C523063D0A7C957BC97C1C43",
|
|
||||||
"cases": [
|
|
||||||
{
|
|
||||||
"k": "32B1B6D7D42A05CB449065727A84804FB1A3E34D8F261496",
|
|
||||||
"message": "sample",
|
|
||||||
"r": "4B0B8CE98A92866A2820E20AA6B75B56382E0F9BFD5ECB55",
|
|
||||||
"s": "CCDB006926EA9565CBADC840829D8C384E06DE1F1E381B85"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"k": "5C4CE89CF56D9E7C77C8585339B006B97B5F0680B4306C6C",
|
|
||||||
"message": "test",
|
|
||||||
"r": "3A718BD8B4926C3B52EE6BBE67EF79B18CB6EB62B1AD97AE",
|
|
||||||
"s": "5662E6848A4A19B1F1AE2F72ACD4B8BBE50F1EAC65D9124F"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"curve": "P224",
|
|
||||||
"q": "FFFFFFFFFFFFFFFFFFFFFFFFFFFF16A2E0B8F03E13DD29455C5C2A3D",
|
|
||||||
"private": "F220266E1105BFE3083E03EC7A3A654651F45E37167E88600BF257C1",
|
|
||||||
"Ux": "00CF08DA5AD719E42707FA431292DEA11244D64FC51610D94B130D6C",
|
|
||||||
"Uy": "EEAB6F3DEBE455E3DBF85416F7030CBD94F34F2D6F232C69F3C1385A",
|
|
||||||
"cases": [
|
|
||||||
{
|
|
||||||
"k": "C1D1F2F10881088301880506805FEB4825FE09ACB6816C36991AA06D",
|
|
||||||
"message": "sample",
|
|
||||||
"r": "1CDFE6662DDE1E4A1EC4CDEDF6A1F5A2FB7FBD9145C12113E6ABFD3E",
|
|
||||||
"s": "A6694FD7718A21053F225D3F46197CA699D45006C06F871808F43EBC"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"k": "DF8B38D40DCA3E077D0AC520BF56B6D565134D9B5F2EAE0D34900524",
|
|
||||||
"message": "test",
|
|
||||||
"r": "C441CE8E261DED634E4CF84910E4C5D1D22C5CF3B732BB204DBEF019",
|
|
||||||
"s": "902F42847A63BDC5F6046ADA114953120F99442D76510150F372A3F4"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"curve": "P256",
|
|
||||||
"q": "FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551",
|
|
||||||
"private": "C9AFA9D845BA75166B5C215767B1D6934E50C3DB36E89B127B8A622B120F6721",
|
|
||||||
"Ux": "60FED4BA255A9D31C961EB74C6356D68C049B8923B61FA6CE669622E60F29FB6",
|
|
||||||
"Uy": "7903FE1008B8BC99A41AE9E95628BC64F2F1B20C2D7E9F5177A3C294D4462299",
|
|
||||||
"cases": [
|
|
||||||
{
|
|
||||||
"k": "A6E3C57DD01ABE90086538398355DD4C3B17AA873382B0F24D6129493D8AAD60",
|
|
||||||
"message": "sample",
|
|
||||||
"r": "EFD48B2AACB6A8FD1140DD9CD45E81D69D2C877B56AAF991C34D0EA84EAF3716",
|
|
||||||
"s": "F7CB1C942D657C41D436C7A1B6E29F65F3E900DBB9AFF4064DC4AB2F843ACDA8"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"k": "D16B6AE827F17175E040871A1C7EC3500192C4C92677336EC2537ACAEE0008E0",
|
|
||||||
"message": "test",
|
|
||||||
"r": "F1ABB023518351CD71D881567B1EA663ED3EFCF6C5132B354F28D3B0B7D38367",
|
|
||||||
"s": "019F4113742A2B14BD25926B49C649155F267E60D3814B4C0CC84250E46F0083"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"curve": "P384",
|
|
||||||
"q": "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7634D81F4372DDF581A0DB248B0A77AECEC196ACCC52973",
|
|
||||||
"private": "6B9D3DAD2E1B8C1C05B19875B6659F4DE23C3B667BF297BA9AA47740787137D896D5724E4C70A825F872C9EA60D2EDF5",
|
|
||||||
"Ux": "EC3A4E415B4E19A4568618029F427FA5DA9A8BC4AE92E02E06AAE5286B300C64DEF8F0EA9055866064A254515480BC13",
|
|
||||||
"Uy": "8015D9B72D7D57244EA8EF9AC0C621896708A59367F9DFB9F54CA84B3F1C9DB1288B231C3AE0D4FE7344FD2533264720",
|
|
||||||
"cases": [
|
|
||||||
{
|
|
||||||
"k": "94ED910D1A099DAD3254E9242AE85ABDE4BA15168EAF0CA87A555FD56D10FBCA2907E3E83BA95368623B8C4686915CF9",
|
|
||||||
"message": "sample",
|
|
||||||
"r": "94EDBB92A5ECB8AAD4736E56C691916B3F88140666CE9FA73D64C4EA95AD133C81A648152E44ACF96E36DD1E80FABE46",
|
|
||||||
"s": "99EF4AEB15F178CEA1FE40DB2603138F130E740A19624526203B6351D0A3A94FA329C145786E679E7B82C71A38628AC8"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"k": "015EE46A5BF88773ED9123A5AB0807962D193719503C527B031B4C2D225092ADA71F4A459BC0DA98ADB95837DB8312EA",
|
|
||||||
"message": "test",
|
|
||||||
"r": "8203B63D3C853E8D77227FB377BCF7B7B772E97892A80F36AB775D509D7A5FEB0542A7F0812998DA8F1DD3CA3CF023DB",
|
|
||||||
"s": "DDD0760448D42D8A43AF45AF836FCE4DE8BE06B485E9B61B827C2F13173923E06A739F040649A667BF3B828246BAA5A5"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"curve": "P521",
|
|
||||||
"q": "1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA51868783BF2F966B7FCC0148F709A5D03BB5C9B8899C47AEBB6FB71E91386409",
|
|
||||||
"private": "0FAD06DAA62BA3B25D2FB40133DA757205DE67F5BB0018FEE8C86E1B68C7E75CAA896EB32F1F47C70855836A6D16FCC1466F6D8FBEC67DB89EC0C08B0E996B83538",
|
|
||||||
"Ux": "1894550D0785932E00EAA23B694F213F8C3121F86DC97A04E5A7167DB4E5BCD371123D46E45DB6B5D5370A7F20FB633155D38FFA16D2BD761DCAC474B9A2F5023A4",
|
|
||||||
"Uy": "0493101C962CD4D2FDDF782285E64584139C2F91B47F87FF82354D6630F746A28A0DB25741B5B34A828008B22ACC23F924FAAFBD4D33F81EA66956DFEAA2BFDFCF5",
|
|
||||||
"cases": [
|
|
||||||
{
|
|
||||||
"k": "1DAE2EA071F8110DC26882D4D5EAE0621A3256FC8847FB9022E2B7D28E6F10198B1574FDD03A9053C08A1854A168AA5A57470EC97DD5CE090124EF52A2F7ECBFFD3",
|
|
||||||
"message": "sample",
|
|
||||||
"r": "0C328FAFCBD79DD77850370C46325D987CB525569FB63C5D3BC53950E6D4C5F174E25A1EE9017B5D450606ADD152B534931D7D4E8455CC91F9B15BF05EC36E377FA",
|
|
||||||
"s": "0617CCE7CF5064806C467F678D3B4080D6F1CC50AF26CA209417308281B68AF282623EAA63E5B5C0723D8B8C37FF0777B1A20F8CCB1DCCC43997F1EE0E44DA4A67A"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"k": "16200813020EC986863BEDFC1B121F605C1215645018AEA1A7B215A564DE9EB1B38A67AA1128B80CE391C4FB71187654AAA3431027BFC7F395766CA988C964DC56D",
|
|
||||||
"message": "test",
|
|
||||||
"r": "13E99020ABF5CEE7525D16B69B229652AB6BDF2AFFCAEF38773B4B7D08725F10CDB93482FDCC54EDCEE91ECA4166B2A7C6265EF0CE2BD7051B7CEF945BABD47EE6D",
|
|
||||||
"s": "1FBD0013C674AA79CB39849527916CE301C66EA7CE8B80682786AD60F98F7E78A19CA69EFF5C57400E3B3A0AD66CE0978214D13BAF4E9AC60752F7B155E2DE4DCE3"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
@@ -23,29 +23,29 @@ import { default as xof_shake128_36 } from './hash-to-curve/expand_message_xof_S
|
|||||||
import { default as xof_shake128_256 } from './hash-to-curve/expand_message_xof_SHAKE128_256.json' assert { type: 'json' };
|
import { default as xof_shake128_256 } from './hash-to-curve/expand_message_xof_SHAKE128_256.json' assert { type: 'json' };
|
||||||
import { default as xof_shake256_36 } from './hash-to-curve/expand_message_xof_SHAKE256_36.json' assert { type: 'json' };
|
import { default as xof_shake256_36 } from './hash-to-curve/expand_message_xof_SHAKE256_36.json' assert { type: 'json' };
|
||||||
// P256
|
// P256
|
||||||
import { default as p256_ro } from './hash-to-curve/P256_XMD:SHA-256_SSWU_RO_.json' assert { type: 'json' };
|
import { default as p256_ro } from './hash-to-curve/P256_XMD_SHA-256_SSWU_RO_.json' assert { type: 'json' };
|
||||||
import { default as p256_nu } from './hash-to-curve/P256_XMD:SHA-256_SSWU_NU_.json' assert { type: 'json' };
|
import { default as p256_nu } from './hash-to-curve/P256_XMD_SHA-256_SSWU_NU_.json' assert { type: 'json' };
|
||||||
// P384
|
// P384
|
||||||
import { default as p384_ro } from './hash-to-curve/P384_XMD:SHA-384_SSWU_RO_.json' assert { type: 'json' };
|
import { default as p384_ro } from './hash-to-curve/P384_XMD_SHA-384_SSWU_RO_.json' assert { type: 'json' };
|
||||||
import { default as p384_nu } from './hash-to-curve/P384_XMD:SHA-384_SSWU_NU_.json' assert { type: 'json' };
|
import { default as p384_nu } from './hash-to-curve/P384_XMD_SHA-384_SSWU_NU_.json' assert { type: 'json' };
|
||||||
// P521
|
// P521
|
||||||
import { default as p521_ro } from './hash-to-curve/P521_XMD:SHA-512_SSWU_RO_.json' assert { type: 'json' };
|
import { default as p521_ro } from './hash-to-curve/P521_XMD_SHA-512_SSWU_RO_.json' assert { type: 'json' };
|
||||||
import { default as p521_nu } from './hash-to-curve/P521_XMD:SHA-512_SSWU_NU_.json' assert { type: 'json' };
|
import { default as p521_nu } from './hash-to-curve/P521_XMD_SHA-512_SSWU_NU_.json' assert { type: 'json' };
|
||||||
// secp256k1
|
// secp256k1
|
||||||
import { default as secp256k1_ro } from './hash-to-curve/secp256k1_XMD:SHA-256_SSWU_RO_.json' assert { type: 'json' };
|
import { default as secp256k1_ro } from './hash-to-curve/secp256k1_XMD_SHA-256_SSWU_RO_.json' assert { type: 'json' };
|
||||||
import { default as secp256k1_nu } from './hash-to-curve/secp256k1_XMD:SHA-256_SSWU_NU_.json' assert { type: 'json' };
|
import { default as secp256k1_nu } from './hash-to-curve/secp256k1_XMD_SHA-256_SSWU_NU_.json' assert { type: 'json' };
|
||||||
// bls-G1
|
// bls-G1
|
||||||
import { default as g1_ro } from './hash-to-curve/BLS12381G1_XMD:SHA-256_SSWU_RO_.json' assert { type: 'json' };
|
import { default as g1_ro } from './hash-to-curve/BLS12381G1_XMD_SHA-256_SSWU_RO_.json' assert { type: 'json' };
|
||||||
import { default as g1_nu } from './hash-to-curve/BLS12381G1_XMD:SHA-256_SSWU_NU_.json' assert { type: 'json' };
|
import { default as g1_nu } from './hash-to-curve/BLS12381G1_XMD_SHA-256_SSWU_NU_.json' assert { type: 'json' };
|
||||||
// bls-G2
|
// bls-G2
|
||||||
import { default as g2_ro } from './hash-to-curve/BLS12381G2_XMD:SHA-256_SSWU_RO_.json' assert { type: 'json' };
|
import { default as g2_ro } from './hash-to-curve/BLS12381G2_XMD_SHA-256_SSWU_RO_.json' assert { type: 'json' };
|
||||||
import { default as g2_nu } from './hash-to-curve/BLS12381G2_XMD:SHA-256_SSWU_NU_.json' assert { type: 'json' };
|
import { default as g2_nu } from './hash-to-curve/BLS12381G2_XMD_SHA-256_SSWU_NU_.json' assert { type: 'json' };
|
||||||
// ed25519
|
// ed25519
|
||||||
import { default as ed25519_ro } from './hash-to-curve/edwards25519_XMD:SHA-512_ELL2_RO_.json' assert { type: 'json' };
|
import { default as ed25519_ro } from './hash-to-curve/edwards25519_XMD_SHA-512_ELL2_RO_.json' assert { type: 'json' };
|
||||||
import { default as ed25519_nu } from './hash-to-curve/edwards25519_XMD:SHA-512_ELL2_NU_.json' assert { type: 'json' };
|
import { default as ed25519_nu } from './hash-to-curve/edwards25519_XMD_SHA-512_ELL2_NU_.json' assert { type: 'json' };
|
||||||
// ed448
|
// ed448
|
||||||
import { default as ed448_ro } from './hash-to-curve/edwards448_XOF:SHAKE256_ELL2_RO_.json' assert { type: 'json' };
|
import { default as ed448_ro } from './hash-to-curve/edwards448_XOF_SHAKE256_ELL2_RO_.json' assert { type: 'json' };
|
||||||
import { default as ed448_nu } from './hash-to-curve/edwards448_XOF:SHAKE256_ELL2_NU_.json' assert { type: 'json' };
|
import { default as ed448_nu } from './hash-to-curve/edwards448_XOF_SHAKE256_ELL2_NU_.json' assert { type: 'json' };
|
||||||
|
|
||||||
function testExpandXMD(hash, vectors) {
|
function testExpandXMD(hash, vectors) {
|
||||||
describe(`${vectors.hash}/${vectors.DST.length}`, () => {
|
describe(`${vectors.hash}/${vectors.DST.length}`, () => {
|
||||||
|
|||||||
@@ -4,12 +4,15 @@ import { should } from 'micro-should';
|
|||||||
import './basic.test.js';
|
import './basic.test.js';
|
||||||
import './nist.test.js';
|
import './nist.test.js';
|
||||||
import './ed448.test.js';
|
import './ed448.test.js';
|
||||||
|
import './ed448-addons.test.js';
|
||||||
import './ed25519.test.js';
|
import './ed25519.test.js';
|
||||||
|
import './ed25519-addons.test.js';
|
||||||
import './secp256k1.test.js';
|
import './secp256k1.test.js';
|
||||||
import './secp256k1-schnorr.test.js';
|
import './secp256k1-schnorr.test.js';
|
||||||
import './stark/index.test.js';
|
import './secp256k1-bip-0324.test.js';
|
||||||
import './jubjub.test.js';
|
import './jubjub.test.js';
|
||||||
import './bls12-381.test.js';
|
|
||||||
import './hash-to-curve.test.js';
|
import './hash-to-curve.test.js';
|
||||||
|
import './poseidon.test.js';
|
||||||
|
import './bls12-381.test.js';
|
||||||
|
|
||||||
should.run();
|
should.run();
|
||||||
|
|||||||
@@ -1,14 +1,16 @@
|
|||||||
import { deepStrictEqual } from 'assert';
|
import { deepStrictEqual, throws } from 'assert';
|
||||||
import { describe, should } from 'micro-should';
|
import { describe, should } from 'micro-should';
|
||||||
import { secp192r1, secp224r1, P192, P224 } from './_more-curves.helpers.js';
|
import { secp192r1, secp224r1, p192, p224 } from './_more-curves.helpers.js';
|
||||||
import { secp256r1, P256 } from '../esm/p256.js';
|
import { DER } from '../esm/abstract/weierstrass.js';
|
||||||
import { secp384r1, P384 } from '../esm/p384.js';
|
import { secp256r1, p256 } from '../esm/p256.js';
|
||||||
import { secp521r1, P521 } from '../esm/p521.js';
|
import { secp384r1, p384 } from '../esm/p384.js';
|
||||||
|
import { secp521r1, p521 } from '../esm/p521.js';
|
||||||
import { secp256k1 } from '../esm/secp256k1.js';
|
import { secp256k1 } from '../esm/secp256k1.js';
|
||||||
import { hexToBytes, bytesToHex } from '../esm/abstract/utils.js';
|
import { hexToBytes, bytesToHex } from '../esm/abstract/utils.js';
|
||||||
import { default as ecdsa } from './wycheproof/ecdsa_test.json' assert { type: 'json' };
|
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 ecdh } from './wycheproof/ecdh_test.json' assert { type: 'json' };
|
||||||
import { default as rfc6979 } from './fixtures/rfc6979.json' assert { type: 'json' };
|
import { default as rfc6979 } from './vectors/rfc6979.json' assert { type: 'json' };
|
||||||
|
import { default as endoVectors } from './vectors/secp256k1/endomorphism.json' assert { type: 'json' };
|
||||||
|
|
||||||
import { default as ecdh_secp224r1_test } from './wycheproof/ecdh_secp224r1_test.json' assert { type: 'json' };
|
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_secp256r1_test } from './wycheproof/ecdh_secp256r1_test.json' assert { type: 'json' };
|
||||||
@@ -22,38 +24,59 @@ import { default as secp224r1_sha3_224_test } from './wycheproof/ecdsa_secp224r1
|
|||||||
import { default as secp224r1_sha3_256_test } from './wycheproof/ecdsa_secp224r1_sha3_256_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_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 secp224r1_sha512_test } from './wycheproof/ecdsa_secp224r1_sha512_test.json' assert { type: 'json' };
|
||||||
|
import { default as secp224r1_shake128_test } from './wycheproof/ecdsa_secp224r1_shake128_test.json' assert { type: 'json' };
|
||||||
|
|
||||||
|
import { default as secp256k1_sha256_bitcoin_test } from './wycheproof/ecdsa_secp256k1_sha256_bitcoin_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_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_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_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 secp256k1_sha512_test } from './wycheproof/ecdsa_secp256k1_sha512_test.json' assert { type: 'json' };
|
||||||
|
import { default as secp256k1_shake128_test } from './wycheproof/ecdsa_secp256k1_shake128_test.json' assert { type: 'json' };
|
||||||
|
import { default as secp256k1_shake256_test } from './wycheproof/ecdsa_secp256k1_shake256_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_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_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_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 secp256r1_sha512_test } from './wycheproof/ecdsa_secp256r1_sha512_test.json' assert { type: 'json' };
|
||||||
|
import { default as secp256r1_shake128_test } from './wycheproof/ecdsa_secp256r1_shake128_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_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_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_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 secp384r1_sha512_test } from './wycheproof/ecdsa_secp384r1_sha512_test.json' assert { type: 'json' };
|
||||||
|
import { default as secp384r1_shake256_test } from './wycheproof/ecdsa_secp384r1_shake256_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_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 { default as secp521r1_sha512_test } from './wycheproof/ecdsa_secp521r1_sha512_test.json' assert { type: 'json' };
|
||||||
|
import { default as secp521r1_shake256_test } from './wycheproof/ecdsa_secp521r1_shake256_test.json' assert { type: 'json' };
|
||||||
|
|
||||||
import { sha3_224, sha3_256, sha3_384, sha3_512 } from '@noble/hashes/sha3';
|
import { sha3_224, sha3_256, sha3_384, sha3_512, shake128, shake256 } from '@noble/hashes/sha3';
|
||||||
import { sha512, sha384 } from '@noble/hashes/sha512';
|
import { sha512, sha384 } from '@noble/hashes/sha512';
|
||||||
import { sha224, sha256 } from '@noble/hashes/sha256';
|
import { sha224, sha256 } from '@noble/hashes/sha256';
|
||||||
|
|
||||||
|
// TODO: maybe add to noble-hashes?
|
||||||
|
const wrapShake = (shake, dkLen) => {
|
||||||
|
const hashC = (msg) => shake(msg, { dkLen });
|
||||||
|
hashC.outputLen = dkLen;
|
||||||
|
hashC.blockLen = shake.blockLen;
|
||||||
|
hashC.create = () => shake.create({ dkLen });
|
||||||
|
return hashC;
|
||||||
|
};
|
||||||
|
const shake128_224 = wrapShake(shake128, 224 / 8);
|
||||||
|
const shake128_256 = wrapShake(shake128, 256 / 8);
|
||||||
|
const shake256_256 = wrapShake(shake256, 256 / 8);
|
||||||
|
const shake256_384 = wrapShake(shake256, 384 / 8);
|
||||||
|
const shake256_512 = wrapShake(shake256, 512 / 8);
|
||||||
|
|
||||||
const hex = bytesToHex;
|
const hex = bytesToHex;
|
||||||
|
|
||||||
// prettier-ignore
|
// prettier-ignore
|
||||||
const NIST = {
|
const NIST = {
|
||||||
secp192r1, P192,
|
secp192r1, P192: p192,
|
||||||
secp224r1, P224,
|
secp224r1, P224: p224,
|
||||||
secp256r1, P256,
|
secp256r1, P256: p256,
|
||||||
secp384r1, P384,
|
secp384r1, P384: p384,
|
||||||
secp521r1, P521,
|
secp521r1, P521: p521,
|
||||||
secp256k1,
|
secp256k1,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -72,79 +95,32 @@ should('fields', () => {
|
|||||||
for (const n in vectors) deepStrictEqual(NIST[n].CURVE.Fp.ORDER, vectors[n]);
|
for (const n in vectors) deepStrictEqual(NIST[n].CURVE.Fp.ORDER, vectors[n]);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('wycheproof ECDH', () => {
|
// We don't support ASN.1 encoding of points. For tests we've implemented quick
|
||||||
for (const group of ecdh.testGroups) {
|
// and dirty parser: take X last bytes of ASN.1 encoded sequence.
|
||||||
// // Tested in secp256k1.test.js
|
// If that doesn't work, we ignore such vector.
|
||||||
// if (group.key.curve === 'secp256k1') continue;
|
function verifyECDHVector(test, curve) {
|
||||||
// We don't have SHA-224
|
if (test.flags.includes('InvalidAsn')) return; // Ignore invalid ASN
|
||||||
const CURVE = NIST[group.curve];
|
|
||||||
if (!CURVE) continue;
|
|
||||||
should(group.curve, () => {
|
|
||||||
for (const test of group.tests) {
|
|
||||||
if (test.result === 'valid' || test.result === 'acceptable') {
|
if (test.result === 'valid' || test.result === 'acceptable') {
|
||||||
|
const fnLen = curve.CURVE.nByteLength; // 32 for P256
|
||||||
|
const fpLen = curve.CURVE.Fp.BYTES; // 32 for P256
|
||||||
|
const encodedHexLen = fpLen * 2 * 2 + 2; // 130 (65 * 2) for P256
|
||||||
|
const pubB = test.public.slice(-encodedHexLen); // slice(-130) for P256
|
||||||
|
let privA = test.private;
|
||||||
|
|
||||||
|
// Some wycheproof vectors are padded with 00:
|
||||||
|
// 00c6cafb74e2a50c83b3d232c4585237f44d4c5433c4b3f50ce978e6aeda3a4f5d
|
||||||
|
// instead of
|
||||||
|
// c6cafb74e2a50c83b3d232c4585237f44d4c5433c4b3f50ce978e6aeda3a4f5d
|
||||||
|
if (privA.length / 2 === fnLen + 1 && privA.startsWith('00')) privA = privA.slice(2);
|
||||||
|
|
||||||
|
if (!curve.utils.isValidPrivateKey(privA)) return; // Ignore invalid private key size
|
||||||
try {
|
try {
|
||||||
const pub = CURVE.ProjectivePoint.fromHex(test.public);
|
curve.ProjectivePoint.fromHex(pubB);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// Our strict validation filter doesn't let weird-length DER vectors
|
if (e.message.startsWith('Point of length')) return; // Ignore
|
||||||
if (e.message.startsWith('Point of length')) continue;
|
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
const shared = CURVE.getSharedSecret(test.private, test.public);
|
const shared = curve.getSharedSecret(privA, pubB).subarray(1);
|
||||||
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');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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(`additional ${name} (${i}/${j})`, () => {
|
|
||||||
for (const test of group.tests) {
|
|
||||||
if (test.result === 'valid' || test.result === 'acceptable') {
|
|
||||||
try {
|
|
||||||
const pub = curve.ProjectivePoint.fromHex(test.public);
|
|
||||||
} catch (e) {
|
|
||||||
// Our strict validation filter doesn't let weird-length DER vectors
|
|
||||||
if (e.message.includes('Point of length')) continue;
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
const shared = curve.getSharedSecret(test.private, test.public);
|
|
||||||
deepStrictEqual(hex(shared), test.shared, 'valid');
|
deepStrictEqual(hex(shared), test.shared, 'valid');
|
||||||
} else if (test.result === 'invalid') {
|
} else if (test.result === 'invalid') {
|
||||||
let failed = false;
|
let failed = false;
|
||||||
@@ -156,6 +132,52 @@ describe('wycheproof ECDH', () => {
|
|||||||
deepStrictEqual(failed, true, 'invalid');
|
deepStrictEqual(failed, true, 'invalid');
|
||||||
} else throw new Error('unknown test result');
|
} else throw new Error('unknown test result');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
describe('wycheproof ECDH', () => {
|
||||||
|
for (const group of ecdh.testGroups) {
|
||||||
|
const curve = NIST[group.curve];
|
||||||
|
if (!curve) continue;
|
||||||
|
should(group.curve, () => {
|
||||||
|
for (const test of group.tests) {
|
||||||
|
verifyECDHVector(test, curve);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 curveTests = tests[i];
|
||||||
|
for (let j = 0; j < curveTests.testGroups.length; j++) {
|
||||||
|
const group = curveTests.testGroups[j];
|
||||||
|
should(`additional ${name} (${group.tests.length})`, () => {
|
||||||
|
for (const test of group.tests) {
|
||||||
|
verifyECDHVector(test, curve);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -163,8 +185,8 @@ describe('wycheproof ECDH', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const WYCHEPROOF_ECDSA = {
|
const WYCHEPROOF_ECDSA = {
|
||||||
P224: {
|
p224: {
|
||||||
curve: P224,
|
curve: p224,
|
||||||
hashes: {
|
hashes: {
|
||||||
sha224: {
|
sha224: {
|
||||||
hash: sha224,
|
hash: sha224,
|
||||||
@@ -190,6 +212,10 @@ const WYCHEPROOF_ECDSA = {
|
|||||||
hash: sha512,
|
hash: sha512,
|
||||||
tests: [secp224r1_sha512_test],
|
tests: [secp224r1_sha512_test],
|
||||||
},
|
},
|
||||||
|
shake128: {
|
||||||
|
hash: shake128_224,
|
||||||
|
tests: [secp224r1_shake128_test],
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
secp256k1: {
|
secp256k1: {
|
||||||
@@ -197,7 +223,7 @@ const WYCHEPROOF_ECDSA = {
|
|||||||
hashes: {
|
hashes: {
|
||||||
sha256: {
|
sha256: {
|
||||||
hash: sha256,
|
hash: sha256,
|
||||||
tests: [secp256k1_sha256_test],
|
tests: [secp256k1_sha256_test, secp256k1_sha256_bitcoin_test],
|
||||||
},
|
},
|
||||||
sha3_256: {
|
sha3_256: {
|
||||||
hash: sha3_256,
|
hash: sha3_256,
|
||||||
@@ -211,10 +237,18 @@ const WYCHEPROOF_ECDSA = {
|
|||||||
hash: sha512,
|
hash: sha512,
|
||||||
tests: [secp256k1_sha512_test],
|
tests: [secp256k1_sha512_test],
|
||||||
},
|
},
|
||||||
|
shake128: {
|
||||||
|
hash: shake128_256,
|
||||||
|
tests: [secp256k1_shake128_test],
|
||||||
|
},
|
||||||
|
shake256: {
|
||||||
|
hash: shake256_256,
|
||||||
|
tests: [secp256k1_shake256_test],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
P256: {
|
},
|
||||||
curve: P256,
|
p256: {
|
||||||
|
curve: p256,
|
||||||
hashes: {
|
hashes: {
|
||||||
sha256: {
|
sha256: {
|
||||||
hash: sha256,
|
hash: sha256,
|
||||||
@@ -232,10 +266,14 @@ const WYCHEPROOF_ECDSA = {
|
|||||||
hash: sha512,
|
hash: sha512,
|
||||||
tests: [secp256r1_sha512_test],
|
tests: [secp256r1_sha512_test],
|
||||||
},
|
},
|
||||||
|
shake128: {
|
||||||
|
hash: shake128_256,
|
||||||
|
tests: [secp256r1_shake128_test],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
P384: {
|
},
|
||||||
curve: P384,
|
p384: {
|
||||||
|
curve: p384,
|
||||||
hashes: {
|
hashes: {
|
||||||
sha384: {
|
sha384: {
|
||||||
hash: sha384,
|
hash: sha384,
|
||||||
@@ -253,10 +291,14 @@ const WYCHEPROOF_ECDSA = {
|
|||||||
hash: sha512,
|
hash: sha512,
|
||||||
tests: [secp384r1_sha512_test],
|
tests: [secp384r1_sha512_test],
|
||||||
},
|
},
|
||||||
|
shake256: {
|
||||||
|
hash: shake256_384,
|
||||||
|
tests: [secp384r1_shake256_test],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
P521: {
|
},
|
||||||
curve: P521,
|
p521: {
|
||||||
|
curve: p521,
|
||||||
hashes: {
|
hashes: {
|
||||||
sha3_512: {
|
sha3_512: {
|
||||||
hash: sha3_512,
|
hash: sha3_512,
|
||||||
@@ -266,19 +308,23 @@ const WYCHEPROOF_ECDSA = {
|
|||||||
hash: sha512,
|
hash: sha512,
|
||||||
tests: [secp521r1_sha512_test],
|
tests: [secp521r1_sha512_test],
|
||||||
},
|
},
|
||||||
|
shake256: {
|
||||||
|
hash: shake256_512,
|
||||||
|
tests: [secp521r1_shake256_test],
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
function runWycheproof(name, CURVE, group, index) {
|
function runWycheproof(name, CURVE, group, index) {
|
||||||
const pubKey = CURVE.ProjectivePoint.fromHex(group.key.uncompressed);
|
const key = group.publicKey;
|
||||||
deepStrictEqual(pubKey.x, BigInt(`0x${group.key.wx}`));
|
const pubKey = CURVE.ProjectivePoint.fromHex(key.uncompressed);
|
||||||
deepStrictEqual(pubKey.y, BigInt(`0x${group.key.wy}`));
|
deepStrictEqual(pubKey.x, BigInt(`0x${key.wx}`));
|
||||||
|
deepStrictEqual(pubKey.y, BigInt(`0x${key.wy}`));
|
||||||
const pubR = pubKey.toRawBytes();
|
const pubR = pubKey.toRawBytes();
|
||||||
for (const test of group.tests) {
|
for (const test of group.tests) {
|
||||||
const m = CURVE.CURVE.hash(hexToBytes(test.msg));
|
const m = CURVE.CURVE.hash(hexToBytes(test.msg));
|
||||||
const { sig } = test;
|
const { sig } = test;
|
||||||
|
|
||||||
if (test.result === 'valid' || test.result === 'acceptable') {
|
if (test.result === 'valid' || test.result === 'acceptable') {
|
||||||
try {
|
try {
|
||||||
CURVE.Signature.fromDER(sig);
|
CURVE.Signature.fromDER(sig);
|
||||||
@@ -310,7 +356,6 @@ describe('wycheproof ECDSA', () => {
|
|||||||
should('generic', () => {
|
should('generic', () => {
|
||||||
for (const group of ecdsa.testGroups) {
|
for (const group of ecdsa.testGroups) {
|
||||||
// Tested in secp256k1.test.js
|
// Tested in secp256k1.test.js
|
||||||
if (group.key.curve === 'secp256k1') continue;
|
|
||||||
let CURVE = NIST[group.key.curve];
|
let CURVE = NIST[group.key.curve];
|
||||||
if (!CURVE) continue;
|
if (!CURVE) continue;
|
||||||
if (group.key.curve === 'secp224r1' && group.sha !== 'SHA-224') {
|
if (group.key.curve === 'secp224r1' && group.sha !== 'SHA-224') {
|
||||||
@@ -323,6 +368,9 @@ describe('wycheproof ECDSA', () => {
|
|||||||
if (['Hash weaker than DL-group'].includes(test.comment)) {
|
if (['Hash weaker than DL-group'].includes(test.comment)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
// These old Wycheproof vectors which still accept missing zero, new one is not.
|
||||||
|
if (test.flags.includes('MissingZero') && test.result === 'acceptable')
|
||||||
|
test.result = 'invalid';
|
||||||
const m = CURVE.CURVE.hash(hexToBytes(test.msg));
|
const m = CURVE.CURVE.hash(hexToBytes(test.msg));
|
||||||
if (test.result === 'valid' || test.result === 'acceptable') {
|
if (test.result === 'valid' || test.result === 'acceptable') {
|
||||||
try {
|
try {
|
||||||
@@ -333,7 +381,12 @@ describe('wycheproof ECDSA', () => {
|
|||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
const verified = CURVE.verify(test.sig, m, pubKey.toHex());
|
const verified = CURVE.verify(test.sig, m, pubKey.toHex());
|
||||||
deepStrictEqual(verified, true, 'valid');
|
if (group.key.curve === 'secp256k1') {
|
||||||
|
// lowS: true for secp256k1
|
||||||
|
deepStrictEqual(verified, !CURVE.Signature.fromDER(test.sig).hasHighS(), `valid`);
|
||||||
|
} else {
|
||||||
|
deepStrictEqual(verified, true, `valid`);
|
||||||
|
}
|
||||||
} else if (test.result === 'invalid') {
|
} else if (test.result === 'invalid') {
|
||||||
let failed = false;
|
let failed = false;
|
||||||
try {
|
try {
|
||||||
@@ -388,6 +441,43 @@ describe('RFC6979', () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
should('properly add leading zero to DER', () => {
|
||||||
|
// Valid DER
|
||||||
|
deepStrictEqual(
|
||||||
|
DER.toSig(
|
||||||
|
'303c021c70049af31f8348673d56cece2b27e587a402f2a48f0b21a7911a480a021c2840bf24f6f66be287066b7cbf38788e1b7770b18fd1aa6a26d7c6dc'
|
||||||
|
),
|
||||||
|
{
|
||||||
|
r: 11796871166002955884468185727465595477481802908758874298363724580874n,
|
||||||
|
s: 4239126896857047637966364941684493209162496401998708914961872570076n,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
// Invalid DER (missing trailing zero)
|
||||||
|
throws(() =>
|
||||||
|
DER.toSig(
|
||||||
|
'303c021c70049af31f8348673d56cece2b27e587a402f2a48f0b21a7911a480a021cd7bf40db0909941d78f9948340c69e14c5417f8c840b7edb35846361'
|
||||||
|
)
|
||||||
|
);
|
||||||
|
// Correctly adds trailing zero
|
||||||
|
deepStrictEqual(
|
||||||
|
DER.hexFromSig({
|
||||||
|
r: 11796871166002955884468185727465595477481802908758874298363724580874n,
|
||||||
|
s: 22720819770293592156700650145335132731295311312425682806720849797985n,
|
||||||
|
}),
|
||||||
|
'303d021c70049af31f8348673d56cece2b27e587a402f2a48f0b21a7911a480a021d00d7bf40db0909941d78f9948340c69e14c5417f8c840b7edb35846361'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
should('have proper GLV endomorphism logic in secp256k1', () => {
|
||||||
|
const Point = secp256k1.ProjectivePoint;
|
||||||
|
for (let item of endoVectors) {
|
||||||
|
const point = Point.fromAffine({ x: BigInt(item.ax), y: BigInt(item.ay) });
|
||||||
|
const c = point.multiplyUnsafe(BigInt(item.scalar)).toAffine();
|
||||||
|
deepStrictEqual(c.x, BigInt(item.cx));
|
||||||
|
deepStrictEqual(c.y, BigInt(item.cy));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// ESM is broken.
|
// ESM is broken.
|
||||||
import url from 'url';
|
import url from 'url';
|
||||||
if (import.meta.url === url.pathToFileURL(process.argv[1]).href) {
|
if (import.meta.url === url.pathToFileURL(process.argv[1]).href) {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { deepStrictEqual, throws } from 'assert';
|
import { deepStrictEqual, throws } from 'assert';
|
||||||
import { should, describe } from 'micro-should';
|
import { should, describe } from 'micro-should';
|
||||||
import * as poseidon from '../esm/abstract/poseidon.js';
|
import * as poseidon from '../esm/abstract/poseidon.js';
|
||||||
import * as stark from '../esm/stark.js';
|
import * as stark from './_poseidon.helpers.js';
|
||||||
import * as mod from '../esm/abstract/modular.js';
|
import * as mod from '../esm/abstract/modular.js';
|
||||||
import { default as pvectors } from './vectors/poseidon.json' assert { type: 'json' };
|
import { default as pvectors } from './vectors/poseidon.json' assert { type: 'json' };
|
||||||
const { st1, st2, st3, st4 } = pvectors;
|
const { st1, st2, st3, st4 } = pvectors;
|
||||||
@@ -132,7 +132,9 @@ describe('Stark', () => {
|
|||||||
// Official vectors: https://extgit.iaik.tugraz.at/krypto/hadeshash/-/blob/master/code/test_vectors.txt
|
// Official vectors: https://extgit.iaik.tugraz.at/krypto/hadeshash/-/blob/master/code/test_vectors.txt
|
||||||
|
|
||||||
should('poseidonperm_x5_255_3', () => {
|
should('poseidonperm_x5_255_3', () => {
|
||||||
const Fp = mod.Fp(BigInt('0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001'));
|
const Fp = mod.Field(
|
||||||
|
BigInt('0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001')
|
||||||
|
);
|
||||||
|
|
||||||
const mds = [
|
const mds = [
|
||||||
[
|
[
|
||||||
@@ -161,6 +163,7 @@ should('poseidonperm_x5_255_3', () => {
|
|||||||
t,
|
t,
|
||||||
roundsFull: 8,
|
roundsFull: 8,
|
||||||
roundsPartial: 57,
|
roundsPartial: 57,
|
||||||
|
sboxPower: 5,
|
||||||
mds,
|
mds,
|
||||||
roundConstants,
|
roundConstants,
|
||||||
});
|
});
|
||||||
@@ -179,7 +182,7 @@ should('poseidonperm_x5_255_3', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
should('poseidonperm_x5_255_5', () => {
|
should('poseidonperm_x5_255_5', () => {
|
||||||
const Fp = mod.Fp(0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001n);
|
const Fp = mod.Field(0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001n);
|
||||||
const t = 5;
|
const t = 5;
|
||||||
|
|
||||||
const mds = [
|
const mds = [
|
||||||
@@ -227,6 +230,7 @@ should('poseidonperm_x5_255_5', () => {
|
|||||||
t,
|
t,
|
||||||
roundsFull: 8,
|
roundsFull: 8,
|
||||||
roundsPartial: 60,
|
roundsPartial: 60,
|
||||||
|
sboxPower: 5,
|
||||||
mds,
|
mds,
|
||||||
roundConstants,
|
roundConstants,
|
||||||
});
|
});
|
||||||
@@ -250,7 +254,7 @@ should('poseidonperm_x5_255_5', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
should('poseidonperm_x5_254_3', () => {
|
should('poseidonperm_x5_254_3', () => {
|
||||||
const Fp = mod.Fp(0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001n);
|
const Fp = mod.Field(0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001n);
|
||||||
const t = 3;
|
const t = 3;
|
||||||
|
|
||||||
const mds = [
|
const mds = [
|
||||||
@@ -278,6 +282,7 @@ should('poseidonperm_x5_254_3', () => {
|
|||||||
t,
|
t,
|
||||||
roundsFull: 8,
|
roundsFull: 8,
|
||||||
roundsPartial: 57,
|
roundsPartial: 57,
|
||||||
|
sboxPower: 5,
|
||||||
mds,
|
mds,
|
||||||
roundConstants,
|
roundConstants,
|
||||||
});
|
});
|
||||||
@@ -297,7 +302,7 @@ should('poseidonperm_x5_254_3', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
should('poseidonperm_x5_254_5', () => {
|
should('poseidonperm_x5_254_5', () => {
|
||||||
const Fp = mod.Fp(0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001n);
|
const Fp = mod.Field(0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001n);
|
||||||
const t = 5;
|
const t = 5;
|
||||||
|
|
||||||
const mds = [
|
const mds = [
|
||||||
@@ -345,6 +350,7 @@ should('poseidonperm_x5_254_5', () => {
|
|||||||
t,
|
t,
|
||||||
roundsFull: 8,
|
roundsFull: 8,
|
||||||
roundsPartial: 60,
|
roundsPartial: 60,
|
||||||
|
sboxPower: 5,
|
||||||
mds,
|
mds,
|
||||||
roundConstants,
|
roundConstants,
|
||||||
});
|
});
|
||||||
|
|||||||
122
test/secp256k1-bip-0324.test.js
Normal file
122
test/secp256k1-bip-0324.test.js
Normal file
@@ -0,0 +1,122 @@
|
|||||||
|
import { deepStrictEqual } from 'assert';
|
||||||
|
import { should, describe } from 'micro-should';
|
||||||
|
import * as fs from 'fs';
|
||||||
|
import {
|
||||||
|
hexToBytes,
|
||||||
|
hexToNumber,
|
||||||
|
concatBytes,
|
||||||
|
bytesToHex as toHex,
|
||||||
|
} from '../esm/abstract/utils.js';
|
||||||
|
// Generic tests for all curves in package
|
||||||
|
import { secp256k1, elligatorSwift } from '../esm/secp256k1.js';
|
||||||
|
// ESM is broken.
|
||||||
|
import { dirname } from 'path';
|
||||||
|
import { fileURLToPath } from 'url';
|
||||||
|
export const __dirname = dirname(fileURLToPath(import.meta.url));
|
||||||
|
|
||||||
|
// https://eprint.iacr.org/2022/759
|
||||||
|
|
||||||
|
const parseCSV = (path) => {
|
||||||
|
const data = fs.readFileSync(`${__dirname}/vectors/secp256k1/${path}`, 'utf8');
|
||||||
|
const lines = data.split('\n').filter((i) => !!i);
|
||||||
|
const rows = lines.map((i) => i.trim().split(','));
|
||||||
|
const lengths = new Set(rows.map((i) => i.length));
|
||||||
|
if (lengths.size !== 1) throw new Error('wrong dimensions');
|
||||||
|
if (rows.length < 2) throw new Error('wrong rows length');
|
||||||
|
const [head, ...rest] = rows;
|
||||||
|
return rest.map((row) => Object.fromEntries(row.map((cell, j) => [head[j], cell])));
|
||||||
|
};
|
||||||
|
|
||||||
|
describe('ElligatorSwift', () => {
|
||||||
|
should('packet_encoding_test_vectors', () => {
|
||||||
|
for (const t of parseCSV('bip-0324/packet_encoding_test_vectors.csv')) {
|
||||||
|
const inPriv = hexToNumber(t['in_priv_ours']);
|
||||||
|
const pubX = secp256k1.ProjectivePoint.BASE.multiply(inPriv)
|
||||||
|
.x.toString(16)
|
||||||
|
.padStart(2 * 32, '0');
|
||||||
|
deepStrictEqual(pubX, t['mid_x_ours']);
|
||||||
|
|
||||||
|
const bytesOurs = hexToBytes(t['in_ellswift_ours']);
|
||||||
|
const decoded = elligatorSwift.decode(bytesOurs);
|
||||||
|
deepStrictEqual(toHex(decoded), t['mid_x_ours']);
|
||||||
|
|
||||||
|
const bytesTheirs = hexToBytes(t['in_ellswift_theirs']);
|
||||||
|
deepStrictEqual(toHex(elligatorSwift.decode(bytesTheirs)), t['mid_x_theirs']);
|
||||||
|
|
||||||
|
const xShared = elligatorSwift.getSharedSecret(t['in_priv_ours'], bytesTheirs);
|
||||||
|
deepStrictEqual(toHex(xShared), t['mid_x_shared']);
|
||||||
|
|
||||||
|
const sharedSecret = elligatorSwift.getSharedSecretBip324(
|
||||||
|
t['in_priv_ours'],
|
||||||
|
t['in_ellswift_theirs'],
|
||||||
|
t['in_ellswift_ours'],
|
||||||
|
t['in_initiating'] === '1'
|
||||||
|
);
|
||||||
|
deepStrictEqual(toHex(sharedSecret), t['mid_shared_secret']);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
should('xswiftec_inv_test_vectors', () => {
|
||||||
|
for (const t of parseCSV('bip-0324/xswiftec_inv_test_vectors.csv')) {
|
||||||
|
const Fp = secp256k1.CURVE.Fp;
|
||||||
|
const u = Fp.create(Fp.fromBytes(hexToBytes(t['u'])));
|
||||||
|
const x = Fp.create(Fp.fromBytes(hexToBytes(t['x'])));
|
||||||
|
for (let c = 0; c < 8; c++) {
|
||||||
|
const name = `case${c}_t`;
|
||||||
|
const ret = elligatorSwift._inv(x, u, c);
|
||||||
|
if (!ret) deepStrictEqual(t[name], '', 'empty case');
|
||||||
|
else {
|
||||||
|
deepStrictEqual(toHex(Fp.toBytes(ret)), t[name], 'real case');
|
||||||
|
deepStrictEqual(
|
||||||
|
elligatorSwift.decode(concatBytes(Fp.toBytes(u), Fp.toBytes(ret))),
|
||||||
|
Fp.toBytes(x)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
should('ellswift_decode_test_vectors', () => {
|
||||||
|
for (const t of parseCSV('bip-0324/ellswift_decode_test_vectors.csv')) {
|
||||||
|
deepStrictEqual(toHex(elligatorSwift.decode(t['ellswift'])), t['x']);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
should('Example', () => {
|
||||||
|
// random, so test more.
|
||||||
|
for (let i = 0; i < 100; i++) {
|
||||||
|
const alice = elligatorSwift.keygen();
|
||||||
|
const bob = elligatorSwift.keygen();
|
||||||
|
// ECDH
|
||||||
|
const sharedAlice = elligatorSwift.getSharedSecret(alice.privateKey, bob.publicKey);
|
||||||
|
const sharedBob = elligatorSwift.getSharedSecret(bob.privateKey, alice.publicKey);
|
||||||
|
deepStrictEqual(sharedAlice, sharedBob);
|
||||||
|
// ECDH BIP324
|
||||||
|
const sharedAlice2 = elligatorSwift.getSharedSecretBip324(
|
||||||
|
alice.privateKey,
|
||||||
|
bob.publicKey,
|
||||||
|
alice.publicKey,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
const sharedBob2 = elligatorSwift.getSharedSecretBip324(
|
||||||
|
bob.privateKey,
|
||||||
|
alice.publicKey,
|
||||||
|
bob.publicKey,
|
||||||
|
false
|
||||||
|
);
|
||||||
|
deepStrictEqual(sharedAlice2, sharedBob2);
|
||||||
|
// pubKey decoding
|
||||||
|
for (const k of [alice, bob]) {
|
||||||
|
deepStrictEqual(
|
||||||
|
toHex(elligatorSwift.decode(k.publicKey)),
|
||||||
|
toHex(secp256k1.getPublicKey(k.privateKey, true).subarray(1))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// ESM is broken.
|
||||||
|
import url from 'url';
|
||||||
|
if (import.meta.url === url.pathToFileURL(process.argv[1]).href) {
|
||||||
|
should.run();
|
||||||
|
}
|
||||||
@@ -3,7 +3,7 @@ import { readFileSync } from 'fs';
|
|||||||
import { should, describe } from 'micro-should';
|
import { should, describe } from 'micro-should';
|
||||||
import { bytesToHex as hex } from '@noble/hashes/utils';
|
import { bytesToHex as hex } from '@noble/hashes/utils';
|
||||||
import { schnorr } from '../esm/secp256k1.js';
|
import { schnorr } from '../esm/secp256k1.js';
|
||||||
const schCsv = readFileSync('./test/vectors/schnorr.csv', 'utf-8');
|
const schCsv = readFileSync('./test/vectors/secp256k1/schnorr.csv', 'utf-8');
|
||||||
|
|
||||||
describe('schnorr.sign()', () => {
|
describe('schnorr.sign()', () => {
|
||||||
// index,secret key,public key,aux_rand,message,signature,verification result,comment
|
// index,secret key,public key,aux_rand,message,signature,verification result,comment
|
||||||
|
|||||||
@@ -9,6 +9,3 @@ export const sigFromDER = (der) => {
|
|||||||
export const sigToDER = (sig) => sig.toDERHex();
|
export const sigToDER = (sig) => sig.toDERHex();
|
||||||
export const selectHash = (secp) => secp.CURVE.hash;
|
export const selectHash = (secp) => secp.CURVE.hash;
|
||||||
export const normVerifySig = (s) => _secp.Signature.fromDER(s);
|
export const normVerifySig = (s) => _secp.Signature.fromDER(s);
|
||||||
// export const bytesToNumberBE = secp256k1.utils.bytesToNumberBE;
|
|
||||||
// export const numberToBytesBE = secp256k1.utils.numberToBytesBE;
|
|
||||||
// export const mod = mod_;
|
|
||||||
|
|||||||
@@ -8,14 +8,17 @@ import {
|
|||||||
secp, sigFromDER, sigToDER, selectHash, normVerifySig, mod, bytesToNumberBE, numberToBytesBE
|
secp, sigFromDER, sigToDER, selectHash, normVerifySig, mod, bytesToNumberBE, numberToBytesBE
|
||||||
} from './secp256k1.helpers.js';
|
} from './secp256k1.helpers.js';
|
||||||
|
|
||||||
import { default as ecdsa } from './vectors/ecdsa.json' assert { type: 'json' };
|
import { default as ecdsa } from './vectors/secp256k1/ecdsa.json' assert { type: 'json' };
|
||||||
import { default as ecdh } from './vectors/ecdh.json' assert { type: 'json' };
|
import { default as ecdh } from './wycheproof/ecdh_secp256k1_test.json' assert { type: 'json' };
|
||||||
import { default as privates } from './vectors/privates.json' assert { type: 'json' };
|
import { default as privates } from './vectors/secp256k1/privates.json' assert { type: 'json' };
|
||||||
import { default as points } from './vectors/points.json' assert { type: 'json' };
|
import { default as points } from './vectors/secp256k1/points.json' assert { type: 'json' };
|
||||||
import { default as wp } from './vectors/wychenproof.json' assert { type: 'json' };
|
import { default as wp } from './wycheproof/ecdsa_secp256k1_sha256_test.json' assert { type: 'json' };
|
||||||
|
|
||||||
|
// Any changes to the file will need to be aware of the fact
|
||||||
|
// the file is shared between noble-curves and noble-secp256k1.
|
||||||
|
|
||||||
const Point = secp.ProjectivePoint;
|
const Point = secp.ProjectivePoint;
|
||||||
const privatesTxt = readFileSync('./test/vectors/privates-2.txt', 'utf-8');
|
const privatesTxt = readFileSync('./test/vectors/secp256k1/privates-2.txt', 'utf-8');
|
||||||
|
|
||||||
const FC_BIGINT = fc.bigInt(1n + 1n, secp.CURVE.n - 1n);
|
const FC_BIGINT = fc.bigInt(1n + 1n, secp.CURVE.n - 1n);
|
||||||
// prettier-ignore
|
// prettier-ignore
|
||||||
@@ -265,6 +268,33 @@ describe('secp256k1', () => {
|
|||||||
deepStrictEqual(sign(ent5), e.extraEntropyMax);
|
deepStrictEqual(sign(ent5), e.extraEntropyMax);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
should('handle one byte {extraData}', () => {
|
||||||
|
const extraEntropy = '01';
|
||||||
|
const privKey = hexToBytes(
|
||||||
|
'0101010101010101010101010101010101010101010101010101010101010101'
|
||||||
|
);
|
||||||
|
const msg = 'd1a9dc8ed4e46a6a3e5e594615ca351d7d7ef44df1e4c94c1802f3592183794b';
|
||||||
|
const res = secp.sign(msg, privKey, { extraEntropy }).toCompactHex();
|
||||||
|
deepStrictEqual(
|
||||||
|
res,
|
||||||
|
'a250ec23a54bfdecf0e924cbf484077c5044410f915cdba86731cb2e4e925aaa5b1e4e3553d88be2c48a9a0d8d849ce2cc5720d25b2f97473e02f2550abe9545'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
should('handle 48 bytes {extraData}', () => {
|
||||||
|
const extraEntropy =
|
||||||
|
'000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000001';
|
||||||
|
const privKey = hexToBytes(
|
||||||
|
'0101010101010101010101010101010101010101010101010101010101010101'
|
||||||
|
);
|
||||||
|
const msg = 'd1a9dc8ed4e46a6a3e5e594615ca351d7d7ef44df1e4c94c1802f3592183794b';
|
||||||
|
const res = secp.sign(msg, privKey, { extraEntropy }).toCompactHex();
|
||||||
|
deepStrictEqual(
|
||||||
|
res,
|
||||||
|
'2bdf40f42ac0e42ee12750d03bb12b75306dae58eb3c961c5a80d78efae93e595295b66e8eb28f1eb046bb129a976340312159ec0c20b97342667572e4a8379a'
|
||||||
|
);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('verify()', () => {
|
describe('verify()', () => {
|
||||||
@@ -500,14 +530,24 @@ describe('secp256k1', () => {
|
|||||||
should('wycheproof vectors', () => {
|
should('wycheproof vectors', () => {
|
||||||
for (let group of wp.testGroups) {
|
for (let group of wp.testGroups) {
|
||||||
// const pubKey = Point.fromHex().toRawBytes();
|
// const pubKey = Point.fromHex().toRawBytes();
|
||||||
const pubKey = group.key.uncompressed;
|
const key = group.publicKey;
|
||||||
|
const pubKey = key.uncompressed;
|
||||||
|
|
||||||
for (let test of group.tests) {
|
for (let test of group.tests) {
|
||||||
const h = selectHash(secp);
|
const h = selectHash(secp);
|
||||||
|
|
||||||
const m = h(hexToBytes(test.msg));
|
const m = h(hexToBytes(test.msg));
|
||||||
if (test.result === 'valid' || test.result === 'acceptable') {
|
if (test.result === 'valid' || test.result === 'acceptable') {
|
||||||
|
let sig;
|
||||||
|
try {
|
||||||
|
sig = sigFromDER(test.sig);
|
||||||
|
} catch (e) {
|
||||||
|
// These old Wycheproof vectors which allows invalid behaviour of DER parser
|
||||||
|
if (e.message === 'Invalid signature integer: negative') continue;
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
const verified = secp.verify(normVerifySig(test.sig), m, pubKey);
|
const verified = secp.verify(normVerifySig(test.sig), m, pubKey);
|
||||||
if (sigFromDER(test.sig).hasHighS()) {
|
if (sig.hasHighS()) {
|
||||||
deepStrictEqual(verified, false);
|
deepStrictEqual(verified, false);
|
||||||
} else {
|
} else {
|
||||||
deepStrictEqual(verified, true);
|
deepStrictEqual(verified, true);
|
||||||
|
|||||||
@@ -1,201 +0,0 @@
|
|||||||
import { deepStrictEqual, throws } from 'assert';
|
|
||||||
import { describe, should } from 'micro-should';
|
|
||||||
import * as starknet from '../../esm/stark.js';
|
|
||||||
import { default as issue2 } from './fixtures/issue2.json' assert { type: 'json' };
|
|
||||||
import * as bip32 from '@scure/bip32';
|
|
||||||
import * as bip39 from '@scure/bip39';
|
|
||||||
|
|
||||||
describe('starknet basic', () => {
|
|
||||||
should('Basic elliptic sanity check', () => {
|
|
||||||
const g1 = starknet.ProjectivePoint.BASE;
|
|
||||||
deepStrictEqual(
|
|
||||||
g1.toAffine().x.toString(16),
|
|
||||||
'1ef15c18599971b7beced415a40f0c7deacfd9b0d1819e03d723d8bc943cfca'
|
|
||||||
);
|
|
||||||
deepStrictEqual(
|
|
||||||
g1.toAffine().y.toString(16),
|
|
||||||
'5668060aa49730b7be4801df46ec62de53ecd11abe43a32873000c36e8dc1f'
|
|
||||||
);
|
|
||||||
const g2 = g1.double();
|
|
||||||
deepStrictEqual(
|
|
||||||
g2.toAffine().x.toString(16),
|
|
||||||
'759ca09377679ecd535a81e83039658bf40959283187c654c5416f439403cf5'
|
|
||||||
);
|
|
||||||
deepStrictEqual(
|
|
||||||
g2.toAffine().y.toString(16),
|
|
||||||
'6f524a3400e7708d5c01a28598ad272e7455aa88778b19f93b562d7a9646c41'
|
|
||||||
);
|
|
||||||
const g3 = g2.add(g1);
|
|
||||||
deepStrictEqual(
|
|
||||||
g3.toAffine().x.toString(16),
|
|
||||||
'411494b501a98abd8262b0da1351e17899a0c4ef23dd2f96fec5ba847310b20'
|
|
||||||
);
|
|
||||||
deepStrictEqual(
|
|
||||||
g3.toAffine().y.toString(16),
|
|
||||||
'7e1b3ebac08924d2c26f409549191fcf94f3bf6f301ed3553e22dfb802f0686'
|
|
||||||
);
|
|
||||||
const g32 = g1.multiply(3n);
|
|
||||||
deepStrictEqual(
|
|
||||||
g32.toAffine().x.toString(16),
|
|
||||||
'411494b501a98abd8262b0da1351e17899a0c4ef23dd2f96fec5ba847310b20'
|
|
||||||
);
|
|
||||||
deepStrictEqual(
|
|
||||||
g32.toAffine().y.toString(16),
|
|
||||||
'7e1b3ebac08924d2c26f409549191fcf94f3bf6f301ed3553e22dfb802f0686'
|
|
||||||
);
|
|
||||||
const minus1 = g1.multiply(starknet.CURVE.n - 1n);
|
|
||||||
deepStrictEqual(
|
|
||||||
minus1.toAffine().x.toString(16),
|
|
||||||
'1ef15c18599971b7beced415a40f0c7deacfd9b0d1819e03d723d8bc943cfca'
|
|
||||||
);
|
|
||||||
deepStrictEqual(
|
|
||||||
minus1.toAffine().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'
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
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.ProjectivePoint.BASE;
|
|
||||||
const half = starknet.CURVE.n / 2n;
|
|
||||||
const last = starknet.CURVE.n;
|
|
||||||
const vectors = [
|
|
||||||
1n,
|
|
||||||
2n,
|
|
||||||
3n,
|
|
||||||
4n,
|
|
||||||
5n,
|
|
||||||
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.toAffine();
|
|
||||||
for (const v of vectors) {
|
|
||||||
const uncompressed = v.toHex();
|
|
||||||
const compressed = v.toHex(true);
|
|
||||||
const exp = fixPoint(v);
|
|
||||||
deepStrictEqual(fixPoint(starknet.ProjectivePoint.fromHex(uncompressed)), exp);
|
|
||||||
deepStrictEqual(fixPoint(starknet.ProjectivePoint.fromHex(compressed)), exp);
|
|
||||||
deepStrictEqual(starknet.ProjectivePoint.fromHex(compressed).toHex(), uncompressed);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
// ESM is broken.
|
|
||||||
import url from 'url';
|
|
||||||
if (import.meta.url === url.pathToFileURL(process.argv[1]).href) {
|
|
||||||
should.run();
|
|
||||||
}
|
|
||||||
@@ -1,57 +0,0 @@
|
|||||||
import * as microStark from '../../../esm/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();
|
|
||||||
@@ -1,19 +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": {
|
|
||||||
"@starkware-industries/starkware-crypto-utils": "^0.0.2",
|
|
||||||
"micro-bmark": "0.2.0",
|
|
||||||
"micro-should": "0.2.0"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,32 +0,0 @@
|
|||||||
{
|
|
||||||
"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"
|
|
||||||
}
|
|
||||||
@@ -1,57 +0,0 @@
|
|||||||
{
|
|
||||||
"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"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
import { describe, should } from 'micro-should';
|
|
||||||
import './basic.test.js';
|
|
||||||
import './stark.test.js';
|
|
||||||
import './property.test.js';
|
|
||||||
import './poseidon.test.js';
|
|
||||||
|
|
||||||
// ESM is broken.
|
|
||||||
import url from 'url';
|
|
||||||
if (import.meta.url === url.pathToFileURL(process.argv[1]).href) {
|
|
||||||
should.run();
|
|
||||||
}
|
|
||||||
@@ -1,114 +0,0 @@
|
|||||||
import { deepStrictEqual, throws } from 'assert';
|
|
||||||
import { describe, should } from 'micro-should';
|
|
||||||
import * as starknet from '../../esm/stark.js';
|
|
||||||
import * as fs from 'fs';
|
|
||||||
|
|
||||||
function parseTest(path) {
|
|
||||||
let data = fs.readFileSync(path, 'ascii');
|
|
||||||
// Remove whitespaces
|
|
||||||
data = data.replace(/[ |\t]/g, '');
|
|
||||||
const pattern =
|
|
||||||
'Rate=(\\d+)\n' +
|
|
||||||
'Capacity=(\\d+)\n' +
|
|
||||||
'FullRounds=(\\d+)\n' +
|
|
||||||
'PartialRounds=(\\d+)\n' +
|
|
||||||
'MDS=\\[(.+)\\]\n' +
|
|
||||||
'RoundKeys=\\(?\n?\\[\n?(.+)\n?\\]\n?\\)?';
|
|
||||||
const r = data.match(new RegExp(pattern, 'ms'));
|
|
||||||
|
|
||||||
function parseArray(s) {
|
|
||||||
// Remove new lines
|
|
||||||
s = s.replace(/\n/gms, '');
|
|
||||||
return s.match(/(\[.+?\])/g).map((i) =>
|
|
||||||
i
|
|
||||||
.replace(/^\[(.+)\]$/, '$1')
|
|
||||||
.split(',')
|
|
||||||
.filter((i) => !!i)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
const res = {
|
|
||||||
rate: +r[1],
|
|
||||||
capacity: +r[2],
|
|
||||||
roundsFull: +r[3],
|
|
||||||
roundsPartial: +r[4],
|
|
||||||
MDS: parseArray(r[5]).map((i) => i.map((j) => BigInt(j))),
|
|
||||||
roundConstants: parseArray(r[6]).map((i) => i.map((j) => BigInt(j))),
|
|
||||||
};
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
function mapPoseidon(parsed) {
|
|
||||||
return starknet.poseidonBasic(
|
|
||||||
{
|
|
||||||
Fp: starknet.Fp251,
|
|
||||||
rate: parsed.rate,
|
|
||||||
capacity: parsed.capacity,
|
|
||||||
roundsFull: parsed.roundsFull,
|
|
||||||
roundsPartial: parsed.roundsPartial,
|
|
||||||
},
|
|
||||||
parsed.MDS
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const parsed = {
|
|
||||||
poseidon3: parseTest('./test/stark/poseidon/poseidon3.txt'),
|
|
||||||
poseidon4: parseTest('./test/stark/poseidon/poseidon4.txt'),
|
|
||||||
poseidon5: parseTest('./test/stark/poseidon/poseidon5.txt'),
|
|
||||||
poseidon9: parseTest('./test/stark/poseidon/poseidon9.txt'),
|
|
||||||
};
|
|
||||||
|
|
||||||
function poseidonTest(name, parsed) {
|
|
||||||
should(`${name}`, () => {
|
|
||||||
const fn = mapPoseidon(parsed);
|
|
||||||
deepStrictEqual(fn.roundConstants, parsed.roundConstants);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
describe('poseidon txt vectors', () => {
|
|
||||||
poseidonTest('poseidon3', parsed.poseidon3);
|
|
||||||
poseidonTest('poseidon4', parsed.poseidon4);
|
|
||||||
poseidonTest('poseidon5', parsed.poseidon5);
|
|
||||||
poseidonTest('poseidon9', parsed.poseidon9);
|
|
||||||
});
|
|
||||||
|
|
||||||
should('Poseidon examples', () => {
|
|
||||||
const p3 = mapPoseidon(parsed.poseidon3);
|
|
||||||
deepStrictEqual(p3([0n, 0n, 0n]), [
|
|
||||||
3446325744004048536138401612021367625846492093718951375866996507163446763827n,
|
|
||||||
1590252087433376791875644726012779423683501236913937337746052470473806035332n,
|
|
||||||
867921192302518434283879514999422690776342565400001269945778456016268852423n,
|
|
||||||
]);
|
|
||||||
const p4 = mapPoseidon(parsed.poseidon4);
|
|
||||||
deepStrictEqual(p4([0n, 0n, 0n, 0n]), [
|
|
||||||
535071095200566880914603862188010633478042591441142518549720701573192347548n,
|
|
||||||
3567335813488551850156302853280844225974867890860330236555401145692518003968n,
|
|
||||||
229995103310401763929738317978722680640995513996113588430855556460153357543n,
|
|
||||||
3513983790849716360905369754287999509206472929684378838050290392634812839312n,
|
|
||||||
]);
|
|
||||||
const p5 = mapPoseidon(parsed.poseidon5);
|
|
||||||
deepStrictEqual(p5([0n, 0n, 0n, 0n, 0n]), [
|
|
||||||
2337689130971531876049206831496963607805116499042700598724344149414565980684n,
|
|
||||||
3230969295497815870174763682436655274044379544854667759151474216427142025631n,
|
|
||||||
3297330512217530111610698859408044542971696143761201570393504997742535648562n,
|
|
||||||
2585480844700786541432072704002477919020588246983274666988914431019064343941n,
|
|
||||||
3595308260654382824623573767385493361624474708214823462901432822513585995028n,
|
|
||||||
]);
|
|
||||||
const p9 = mapPoseidon(parsed.poseidon9);
|
|
||||||
deepStrictEqual(p9([0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n]), [
|
|
||||||
1534116856660032929112709488204491699743182428465681149262739677337223235050n,
|
|
||||||
1710856073207389764546990138116985223517553616229641666885337928044617114700n,
|
|
||||||
3165864635055638516987240200217592641540231237468651257819894959934472989427n,
|
|
||||||
1003007637710164252047715558598366312649052908276423203724288341354608811559n,
|
|
||||||
68117303579957054409211824649914588822081700129416361923518488718489651489n,
|
|
||||||
1123395637839379807713801282868237406546107732595903195840754789810160564711n,
|
|
||||||
478590974834311070537087181212389392308746075734019180430422247431982932503n,
|
|
||||||
835322726024358888065061514739954009068852229059154336727219387089732433787n,
|
|
||||||
3129703030204995742174502162918848446737407262178341733578946634564864233056n,
|
|
||||||
]);
|
|
||||||
});
|
|
||||||
|
|
||||||
// ESM is broken.
|
|
||||||
import url from 'url';
|
|
||||||
if (import.meta.url === url.pathToFileURL(process.argv[1]).href) {
|
|
||||||
should.run();
|
|
||||||
}
|
|
||||||
@@ -1,201 +0,0 @@
|
|||||||
Apache License
|
|
||||||
Version 2.0, January 2004
|
|
||||||
http://www.apache.org/licenses/
|
|
||||||
|
|
||||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
||||||
|
|
||||||
1. Definitions.
|
|
||||||
|
|
||||||
"License" shall mean the terms and conditions for use, reproduction,
|
|
||||||
and distribution as defined by Sections 1 through 9 of this document.
|
|
||||||
|
|
||||||
"Licensor" shall mean the copyright owner or entity authorized by
|
|
||||||
the copyright owner that is granting the License.
|
|
||||||
|
|
||||||
"Legal Entity" shall mean the union of the acting entity and all
|
|
||||||
other entities that control, are controlled by, or are under common
|
|
||||||
control with that entity. For the purposes of this definition,
|
|
||||||
"control" means (i) the power, direct or indirect, to cause the
|
|
||||||
direction or management of such entity, whether by contract or
|
|
||||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
|
||||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
|
||||||
|
|
||||||
"You" (or "Your") shall mean an individual or Legal Entity
|
|
||||||
exercising permissions granted by this License.
|
|
||||||
|
|
||||||
"Source" form shall mean the preferred form for making modifications,
|
|
||||||
including but not limited to software source code, documentation
|
|
||||||
source, and configuration files.
|
|
||||||
|
|
||||||
"Object" form shall mean any form resulting from mechanical
|
|
||||||
transformation or translation of a Source form, including but
|
|
||||||
not limited to compiled object code, generated documentation,
|
|
||||||
and conversions to other media types.
|
|
||||||
|
|
||||||
"Work" shall mean the work of authorship, whether in Source or
|
|
||||||
Object form, made available under the License, as indicated by a
|
|
||||||
copyright notice that is included in or attached to the work
|
|
||||||
(an example is provided in the Appendix below).
|
|
||||||
|
|
||||||
"Derivative Works" shall mean any work, whether in Source or Object
|
|
||||||
form, that is based on (or derived from) the Work and for which the
|
|
||||||
editorial revisions, annotations, elaborations, or other modifications
|
|
||||||
represent, as a whole, an original work of authorship. For the purposes
|
|
||||||
of this License, Derivative Works shall not include works that remain
|
|
||||||
separable from, or merely link (or bind by name) to the interfaces of,
|
|
||||||
the Work and Derivative Works thereof.
|
|
||||||
|
|
||||||
"Contribution" shall mean any work of authorship, including
|
|
||||||
the original version of the Work and any modifications or additions
|
|
||||||
to that Work or Derivative Works thereof, that is intentionally
|
|
||||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
|
||||||
or by an individual or Legal Entity authorized to submit on behalf of
|
|
||||||
the copyright owner. For the purposes of this definition, "submitted"
|
|
||||||
means any form of electronic, verbal, or written communication sent
|
|
||||||
to the Licensor or its representatives, including but not limited to
|
|
||||||
communication on electronic mailing lists, source code control systems,
|
|
||||||
and issue tracking systems that are managed by, or on behalf of, the
|
|
||||||
Licensor for the purpose of discussing and improving the Work, but
|
|
||||||
excluding communication that is conspicuously marked or otherwise
|
|
||||||
designated in writing by the copyright owner as "Not a Contribution."
|
|
||||||
|
|
||||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
|
||||||
on behalf of whom a Contribution has been received by Licensor and
|
|
||||||
subsequently incorporated within the Work.
|
|
||||||
|
|
||||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
|
||||||
this License, each Contributor hereby grants to You a perpetual,
|
|
||||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
||||||
copyright license to reproduce, prepare Derivative Works of,
|
|
||||||
publicly display, publicly perform, sublicense, and distribute the
|
|
||||||
Work and such Derivative Works in Source or Object form.
|
|
||||||
|
|
||||||
3. Grant of Patent License. Subject to the terms and conditions of
|
|
||||||
this License, each Contributor hereby grants to You a perpetual,
|
|
||||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
||||||
(except as stated in this section) patent license to make, have made,
|
|
||||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
|
||||||
where such license applies only to those patent claims licensable
|
|
||||||
by such Contributor that are necessarily infringed by their
|
|
||||||
Contribution(s) alone or by combination of their Contribution(s)
|
|
||||||
with the Work to which such Contribution(s) was submitted. If You
|
|
||||||
institute patent litigation against any entity (including a
|
|
||||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
|
||||||
or a Contribution incorporated within the Work constitutes direct
|
|
||||||
or contributory patent infringement, then any patent licenses
|
|
||||||
granted to You under this License for that Work shall terminate
|
|
||||||
as of the date such litigation is filed.
|
|
||||||
|
|
||||||
4. Redistribution. You may reproduce and distribute copies of the
|
|
||||||
Work or Derivative Works thereof in any medium, with or without
|
|
||||||
modifications, and in Source or Object form, provided that You
|
|
||||||
meet the following conditions:
|
|
||||||
|
|
||||||
(a) You must give any other recipients of the Work or
|
|
||||||
Derivative Works a copy of this License; and
|
|
||||||
|
|
||||||
(b) You must cause any modified files to carry prominent notices
|
|
||||||
stating that You changed the files; and
|
|
||||||
|
|
||||||
(c) You must retain, in the Source form of any Derivative Works
|
|
||||||
that You distribute, all copyright, patent, trademark, and
|
|
||||||
attribution notices from the Source form of the Work,
|
|
||||||
excluding those notices that do not pertain to any part of
|
|
||||||
the Derivative Works; and
|
|
||||||
|
|
||||||
(d) If the Work includes a "NOTICE" text file as part of its
|
|
||||||
distribution, then any Derivative Works that You distribute must
|
|
||||||
include a readable copy of the attribution notices contained
|
|
||||||
within such NOTICE file, excluding those notices that do not
|
|
||||||
pertain to any part of the Derivative Works, in at least one
|
|
||||||
of the following places: within a NOTICE text file distributed
|
|
||||||
as part of the Derivative Works; within the Source form or
|
|
||||||
documentation, if provided along with the Derivative Works; or,
|
|
||||||
within a display generated by the Derivative Works, if and
|
|
||||||
wherever such third-party notices normally appear. The contents
|
|
||||||
of the NOTICE file are for informational purposes only and
|
|
||||||
do not modify the License. You may add Your own attribution
|
|
||||||
notices within Derivative Works that You distribute, alongside
|
|
||||||
or as an addendum to the NOTICE text from the Work, provided
|
|
||||||
that such additional attribution notices cannot be construed
|
|
||||||
as modifying the License.
|
|
||||||
|
|
||||||
You may add Your own copyright statement to Your modifications and
|
|
||||||
may provide additional or different license terms and conditions
|
|
||||||
for use, reproduction, or distribution of Your modifications, or
|
|
||||||
for any such Derivative Works as a whole, provided Your use,
|
|
||||||
reproduction, and distribution of the Work otherwise complies with
|
|
||||||
the conditions stated in this License.
|
|
||||||
|
|
||||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
|
||||||
any Contribution intentionally submitted for inclusion in the Work
|
|
||||||
by You to the Licensor shall be under the terms and conditions of
|
|
||||||
this License, without any additional terms or conditions.
|
|
||||||
Notwithstanding the above, nothing herein shall supersede or modify
|
|
||||||
the terms of any separate license agreement you may have executed
|
|
||||||
with Licensor regarding such Contributions.
|
|
||||||
|
|
||||||
6. Trademarks. This License does not grant permission to use the trade
|
|
||||||
names, trademarks, service marks, or product names of the Licensor,
|
|
||||||
except as required for reasonable and customary use in describing the
|
|
||||||
origin of the Work and reproducing the content of the NOTICE file.
|
|
||||||
|
|
||||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
|
||||||
agreed to in writing, Licensor provides the Work (and each
|
|
||||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
||||||
implied, including, without limitation, any warranties or conditions
|
|
||||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
|
||||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
|
||||||
appropriateness of using or redistributing the Work and assume any
|
|
||||||
risks associated with Your exercise of permissions under this License.
|
|
||||||
|
|
||||||
8. Limitation of Liability. In no event and under no legal theory,
|
|
||||||
whether in tort (including negligence), contract, or otherwise,
|
|
||||||
unless required by applicable law (such as deliberate and grossly
|
|
||||||
negligent acts) or agreed to in writing, shall any Contributor be
|
|
||||||
liable to You for damages, including any direct, indirect, special,
|
|
||||||
incidental, or consequential damages of any character arising as a
|
|
||||||
result of this License or out of the use or inability to use the
|
|
||||||
Work (including but not limited to damages for loss of goodwill,
|
|
||||||
work stoppage, computer failure or malfunction, or any and all
|
|
||||||
other commercial damages or losses), even if such Contributor
|
|
||||||
has been advised of the possibility of such damages.
|
|
||||||
|
|
||||||
9. Accepting Warranty or Additional Liability. While redistributing
|
|
||||||
the Work or Derivative Works thereof, You may choose to offer,
|
|
||||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
|
||||||
or other liability obligations and/or rights consistent with this
|
|
||||||
License. However, in accepting such obligations, You may act only
|
|
||||||
on Your own behalf and on Your sole responsibility, not on behalf
|
|
||||||
of any other Contributor, and only if You agree to indemnify,
|
|
||||||
defend, and hold each Contributor harmless for any liability
|
|
||||||
incurred by, or claims asserted against, such Contributor by reason
|
|
||||||
of your accepting any such warranty or additional liability.
|
|
||||||
|
|
||||||
END OF TERMS AND CONDITIONS
|
|
||||||
|
|
||||||
APPENDIX: How to apply the Apache License to your work.
|
|
||||||
|
|
||||||
To apply the Apache License to your work, attach the following
|
|
||||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
|
||||||
replaced with your own identifying information. (Don't include
|
|
||||||
the brackets!) The text should be enclosed in the appropriate
|
|
||||||
comment syntax for the file format. We also recommend that a
|
|
||||||
file or class name and description of purpose be included on the
|
|
||||||
same "printed page" as the copyright notice for easier
|
|
||||||
identification within third-party archives.
|
|
||||||
|
|
||||||
Copyright [yyyy] [name of copyright owner]
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
# StarkWare's Poseidon Hash
|
|
||||||
|
|
||||||
[Poseidon](https://www.poseidon-hash.info/) is a family of hash functions designed for being very efficient as algebraic circuits.
|
|
||||||
As such, they may be very useful in ZK proving systems such as STARKs and others.
|
|
||||||
|
|
||||||
This repository provides the official parameters of StarkWare's Poseidon hash implementations.
|
|
||||||
|
|
||||||
All the instances are over the prime field:
|
|
||||||
p = 2^251 + 17 * 2^192 + 1 = 3618502788666131213697322783095070105623107215331596699973092056135872020481
|
|
||||||
|
|
||||||
A few examples hash results with the different parameters:
|
|
||||||
|
|
||||||
```
|
|
||||||
Poseidon3([0,0,0]) = [3446325744004048536138401612021367625846492093718951375866996507163446763827,
|
|
||||||
1590252087433376791875644726012779423683501236913937337746052470473806035332,
|
|
||||||
867921192302518434283879514999422690776342565400001269945778456016268852423]
|
|
||||||
Poseidon4([0,0,0,0]) = [535071095200566880914603862188010633478042591441142518549720701573192347548,
|
|
||||||
3567335813488551850156302853280844225974867890860330236555401145692518003968,
|
|
||||||
229995103310401763929738317978722680640995513996113588430855556460153357543,
|
|
||||||
3513983790849716360905369754287999509206472929684378838050290392634812839312]
|
|
||||||
Poseidon5([0,0,0,0,0]) = [2337689130971531876049206831496963607805116499042700598724344149414565980684,
|
|
||||||
3230969295497815870174763682436655274044379544854667759151474216427142025631,
|
|
||||||
3297330512217530111610698859408044542971696143761201570393504997742535648562,
|
|
||||||
2585480844700786541432072704002477919020588246983274666988914431019064343941,
|
|
||||||
3595308260654382824623573767385493361624474708214823462901432822513585995028]
|
|
||||||
Poseidon9([0,0,0,0,0,0,0,0,0]) = [1534116856660032929112709488204491699743182428465681149262739677337223235050,
|
|
||||||
1710856073207389764546990138116985223517553616229641666885337928044617114700,
|
|
||||||
3165864635055638516987240200217592641540231237468651257819894959934472989427,
|
|
||||||
1003007637710164252047715558598366312649052908276423203724288341354608811559,
|
|
||||||
68117303579957054409211824649914588822081700129416361923518488718489651489,
|
|
||||||
1123395637839379807713801282868237406546107732595903195840754789810160564711,
|
|
||||||
478590974834311070537087181212389392308746075734019180430422247431982932503,
|
|
||||||
835322726024358888065061514739954009068852229059154336727219387089732433787,
|
|
||||||
3129703030204995742174502162918848446737407262178341733578946634564864233056]
|
|
||||||
```
|
|
||||||
@@ -1,462 +0,0 @@
|
|||||||
Rate = 2
|
|
||||||
Capacity = 1
|
|
||||||
FullRounds = 8
|
|
||||||
PartialRounds = 83
|
|
||||||
MDS = [[3, 1, 1], [1, -1, 1], [1, 1, -2]]
|
|
||||||
RoundKeys = [
|
|
||||||
[
|
|
||||||
2950795762459345168613727575620414179244544320470208355568817838579231751791,
|
|
||||||
1587446564224215276866294500450702039420286416111469274423465069420553242820,
|
|
||||||
1645965921169490687904413452218868659025437693527479459426157555728339600137,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
2782373324549879794752287702905278018819686065818504085638398966973694145741,
|
|
||||||
3409172630025222641379726933524480516420204828329395644967085131392375707302,
|
|
||||||
2379053116496905638239090788901387719228422033660130943198035907032739387135,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
2570819397480941104144008784293466051718826502582588529995520356691856497111,
|
|
||||||
3546220846133880637977653625763703334841539452343273304410918449202580719746,
|
|
||||||
2720682389492889709700489490056111332164748138023159726590726667539759963454,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
1899653471897224903834726250400246354200311275092866725547887381599836519005,
|
|
||||||
2369443697923857319844855392163763375394720104106200469525915896159690979559,
|
|
||||||
2354174693689535854311272135513626412848402744119855553970180659094265527996,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
2404084503073127963385083467393598147276436640877011103379112521338973185443,
|
|
||||||
950320777137731763811524327595514151340412860090489448295239456547370725376,
|
|
||||||
2121140748740143694053732746913428481442990369183417228688865837805149503386,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
2372065044800422557577242066480215868569521938346032514014152523102053709709,
|
|
||||||
2618497439310693947058545060953893433487994458443568169824149550389484489896,
|
|
||||||
3518297267402065742048564133910509847197496119850246255805075095266319996916,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
340529752683340505065238931581518232901634742162506851191464448040657139775,
|
|
||||||
1954876811294863748406056845662382214841467408616109501720437541211031966538,
|
|
||||||
813813157354633930267029888722341725864333883175521358739311868164460385261,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
71901595776070443337150458310956362034911936706490730914901986556638720031,
|
|
||||||
2789761472166115462625363403490399263810962093264318361008954888847594113421,
|
|
||||||
2628791615374802560074754031104384456692791616314774034906110098358135152410,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
3617032588734559635167557152518265808024917503198278888820567553943986939719,
|
|
||||||
2624012360209966117322788103333497793082705816015202046036057821340914061980,
|
|
||||||
149101987103211771991327927827692640556911620408176100290586418839323044234,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
1039927963829140138166373450440320262590862908847727961488297105916489431045,
|
|
||||||
2213946951050724449162431068646025833746639391992751674082854766704900195669,
|
|
||||||
2792724903541814965769131737117981991997031078369482697195201969174353468597,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
3212031629728871219804596347439383805499808476303618848198208101593976279441,
|
|
||||||
3343514080098703935339621028041191631325798327656683100151836206557453199613,
|
|
||||||
614054702436541219556958850933730254992710988573177298270089989048553060199,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
148148081026449726283933484730968827750202042869875329032965774667206931170,
|
|
||||||
1158283532103191908366672518396366136968613180867652172211392033571980848414,
|
|
||||||
1032400527342371389481069504520755916075559110755235773196747439146396688513,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
806900704622005851310078578853499250941978435851598088619290797134710613736,
|
|
||||||
462498083559902778091095573017508352472262817904991134671058825705968404510,
|
|
||||||
1003580119810278869589347418043095667699674425582646347949349245557449452503,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
619074932220101074089137133998298830285661916867732916607601635248249357793,
|
|
||||||
2635090520059500019661864086615522409798872905401305311748231832709078452746,
|
|
||||||
978252636251682252755279071140187792306115352460774007308726210405257135181,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
1766912167973123409669091967764158892111310474906691336473559256218048677083,
|
|
||||||
1663265127259512472182980890707014969235283233442916350121860684522654120381,
|
|
||||||
3532407621206959585000336211742670185380751515636605428496206887841428074250,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
2507023127157093845256722098502856938353143387711652912931112668310034975446,
|
|
||||||
3321152907858462102434883844787153373036767230808678981306827073335525034593,
|
|
||||||
3039253036806065280643845548147711477270022154459620569428286684179698125661,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
103480338868480851881924519768416587261556021758163719199282794248762465380,
|
|
||||||
2394049781357087698434751577708655768465803975478348134669006211289636928495,
|
|
||||||
2660531560345476340796109810821127229446538730404600368347902087220064379579,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
3603166934034556203649050570865466556260359798872408576857928196141785055563,
|
|
||||||
1553799760191949768532188139643704561532896296986025007089826672890485412324,
|
|
||||||
2744284717053657689091306578463476341218866418732695211367062598446038965164,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
320745764922149897598257794663594419839885234101078803811049904310835548856,
|
|
||||||
979382242100682161589753881721708883681034024104145498709287731138044566302,
|
|
||||||
1860426855810549882740147175136418997351054138609396651615467358416651354991,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
336173081054369235994909356892506146234495707857220254489443629387613956145,
|
|
||||||
1632470326779699229772327605759783482411227247311431865655466227711078175883,
|
|
||||||
921958250077481394074960433988881176409497663777043304881055317463712938502,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
3034358982193370602048539901033542101022185309652879937418114324899281842797,
|
|
||||||
25626282149517463867572353922222474817434101087272320606729439087234878607,
|
|
||||||
3002662261401575565838149305485737102400501329139562227180277188790091853682,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
2939684373453383817196521641512509179310654199629514917426341354023324109367,
|
|
||||||
1076484609897998179434851570277297233169621096172424141759873688902355505136,
|
|
||||||
2575095284833160494841112025725243274091830284746697961080467506739203605049,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
3565075264617591783581665711620369529657840830498005563542124551465195621851,
|
|
||||||
2197016502533303822395077038351174326125210255869204501838837289716363437993,
|
|
||||||
331415322883530754594261416546036195982886300052707474899691116664327869405,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
1935011233711290003793244296594669823169522055520303479680359990463281661839,
|
|
||||||
3495901467168087413996941216661589517270845976538454329511167073314577412322,
|
|
||||||
954195417117133246453562983448451025087661597543338750600301835944144520375,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
1271840477709992894995746871435810599280944810893784031132923384456797925777,
|
|
||||||
2565310762274337662754531859505158700827688964841878141121196528015826671847,
|
|
||||||
3365022288251637014588279139038152521653896670895105540140002607272936852513,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
1660592021628965529963974299647026602622092163312666588591285654477111176051,
|
|
||||||
970104372286014048279296575474974982288801187216974504035759997141059513421,
|
|
||||||
2617024574317953753849168721871770134225690844968986289121504184985993971227,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
999899815343607746071464113462778273556695659506865124478430189024755832262,
|
|
||||||
2228536129413411161615629030408828764980855956560026807518714080003644769896,
|
|
||||||
2701953891198001564547196795777701119629537795442025393867364730330476403227,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
837078355588159388741598313782044128527494922918203556465116291436461597853,
|
|
||||||
2121749601840466143704862369657561429793951309962582099604848281796392359214,
|
|
||||||
771812260179247428733132708063116523892339056677915387749121983038690154755,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
3317336423132806446086732225036532603224267214833263122557471741829060578219,
|
|
||||||
481570067997721834712647566896657604857788523050900222145547508314620762046,
|
|
||||||
242195042559343964206291740270858862066153636168162642380846129622127460192,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
2855462178889999218204481481614105202770810647859867354506557827319138379686,
|
|
||||||
3525521107148375040131784770413887305850308357895464453970651672160034885202,
|
|
||||||
1320839531502392535964065058804908871811967681250362364246430459003920305799,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
2514191518588387125173345107242226637171897291221681115249521904869763202419,
|
|
||||||
2798335750958827619666318316247381695117827718387653874070218127140615157902,
|
|
||||||
2808467767967035643407948058486565877867906577474361783201337540214875566395,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
3551834385992706206273955480294669176699286104229279436819137165202231595747,
|
|
||||||
1219439673853113792340300173186247996249367102884530407862469123523013083971,
|
|
||||||
761519904537984520554247997444508040636526566551719396202550009393012691157,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
3355402549169351700500518865338783382387571349497391475317206324155237401353,
|
|
||||||
199541098009731541347317515995192175813554789571447733944970283654592727138,
|
|
||||||
192100490643078165121235261796864975568292640203635147901612231594408079071,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
1187019357602953326192019968809486933768550466167033084944727938441427050581,
|
|
||||||
189525349641911362389041124808934468936759383310282010671081989585219065700,
|
|
||||||
2831653363992091308880573627558515686245403755586311978724025292003353336665,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
2052859812632218952608271535089179639890275494426396974475479657192657094698,
|
|
||||||
1670756178709659908159049531058853320846231785448204274277900022176591811072,
|
|
||||||
3538757242013734574731807289786598937548399719866320954894004830207085723125,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
710549042741321081781917034337800036872214466705318638023070812391485261299,
|
|
||||||
2345013122330545298606028187653996682275206910242635100920038943391319595180,
|
|
||||||
3528369671971445493932880023233332035122954362711876290904323783426765912206,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
1167120829038120978297497195837406760848728897181138760506162680655977700764,
|
|
||||||
3073243357129146594530765548901087443775563058893907738967898816092270628884,
|
|
||||||
378514724418106317738164464176041649567501099164061863402473942795977719726,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
333391138410406330127594722511180398159664250722328578952158227406762627796,
|
|
||||||
1727570175639917398410201375510924114487348765559913502662122372848626931905,
|
|
||||||
968312190621809249603425066974405725769739606059422769908547372904403793174,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
360659316299446405855194688051178331671817370423873014757323462844775818348,
|
|
||||||
1386580151907705298970465943238806620109618995410132218037375811184684929291,
|
|
||||||
3604888328937389309031638299660239238400230206645344173700074923133890528967,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
2496185632263372962152518155651824899299616724241852816983268163379540137546,
|
|
||||||
486538168871046887467737983064272608432052269868418721234810979756540672990,
|
|
||||||
1558415498960552213241704009433360128041672577274390114589014204605400783336,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
3512058327686147326577190314835092911156317204978509183234511559551181053926,
|
|
||||||
2235429387083113882635494090887463486491842634403047716936833563914243946191,
|
|
||||||
1290896777143878193192832813769470418518651727840187056683408155503813799882,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
1143310336918357319571079551779316654556781203013096026972411429993634080835,
|
|
||||||
3235435208525081966062419599803346573407862428113723170955762956243193422118,
|
|
||||||
1293239921425673430660897025143433077974838969258268884994339615096356996604,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
236252269127612784685426260840574970698541177557674806964960352572864382971,
|
|
||||||
1733907592497266237374827232200506798207318263912423249709509725341212026275,
|
|
||||||
302004309771755665128395814807589350526779835595021835389022325987048089868,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
3018926838139221755384801385583867283206879023218491758435446265703006270945,
|
|
||||||
39701437664873825906031098349904330565195980985885489447836580931425171297,
|
|
||||||
908381723021746969965674308809436059628307487140174335882627549095646509778,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
219062858908229855064136253265968615354041842047384625689776811853821594358,
|
|
||||||
1283129863776453589317845316917890202859466483456216900835390291449830275503,
|
|
||||||
418512623547417594896140369190919231877873410935689672661226540908900544012,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
1792181590047131972851015200157890246436013346535432437041535789841136268632,
|
|
||||||
370546432987510607338044736824316856592558876687225326692366316978098770516,
|
|
||||||
3323437805230586112013581113386626899534419826098235300155664022709435756946,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
910076621742039763058481476739499965761942516177975130656340375573185415877,
|
|
||||||
1762188042455633427137702520675816545396284185254002959309669405982213803405,
|
|
||||||
2186362253913140345102191078329764107619534641234549431429008219905315900520,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
2230647725927681765419218738218528849146504088716182944327179019215826045083,
|
|
||||||
1069243907556644434301190076451112491469636357133398376850435321160857761825,
|
|
||||||
2695241469149243992683268025359863087303400907336026926662328156934068747593,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
1361519681544413849831669554199151294308350560528931040264950307931824877035,
|
|
||||||
1339116632207878730171031743761550901312154740800549632983325427035029084904,
|
|
||||||
790593524918851401449292693473498591068920069246127392274811084156907468875,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
2723400368331924254840192318398326090089058735091724263333980290765736363637,
|
|
||||||
3457180265095920471443772463283225391927927225993685928066766687141729456030,
|
|
||||||
1483675376954327086153452545475557749815683871577400883707749788555424847954,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
2926303836265506736227240325795090239680154099205721426928300056982414025239,
|
|
||||||
543969119775473768170832347411484329362572550684421616624136244239799475526,
|
|
||||||
237401230683847084256617415614300816373730178313253487575312839074042461932,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
844568412840391587862072008674263874021460074878949862892685736454654414423,
|
|
||||||
151922054871708336050647150237534498235916969120198637893731715254687336644,
|
|
||||||
1299332034710622815055321547569101119597030148120309411086203580212105652312,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
487046922649899823989594814663418784068895385009696501386459462815688122993,
|
|
||||||
1104883249092599185744249485896585912845784382683240114120846423960548576851,
|
|
||||||
1458388705536282069567179348797334876446380557083422364875248475157495514484,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
850248109622750774031817200193861444623975329881731864752464222442574976566,
|
|
||||||
2885843173858536690032695698009109793537724845140477446409245651176355435722,
|
|
||||||
3027068551635372249579348422266406787688980506275086097330568993357835463816,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
3231892723647447539926175383213338123506134054432701323145045438168976970994,
|
|
||||||
1719080830641935421242626784132692936776388194122314954558418655725251172826,
|
|
||||||
1172253756541066126131022537343350498482225068791630219494878195815226839450,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
1619232269633026603732619978083169293258272967781186544174521481891163985093,
|
|
||||||
3495680684841853175973173610562400042003100419811771341346135531754869014567,
|
|
||||||
1576161515913099892951745452471618612307857113799539794680346855318958552758,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
2618326122974253423403350731396350223238201817594761152626832144510903048529,
|
|
||||||
2696245132758436974032479782852265185094623165224532063951287925001108567649,
|
|
||||||
930116505665110070247395429730201844026054810856263733273443066419816003444,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
2786389174502246248523918824488629229455088716707062764363111940462137404076,
|
|
||||||
1555260846425735320214671887347115247546042526197895180675436886484523605116,
|
|
||||||
2306241912153325247392671742757902161446877415586158295423293240351799505917,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
411529621724849932999694270803131456243889635467661223241617477462914950626,
|
|
||||||
1542495485262286701469125140275904136434075186064076910329015697714211835205,
|
|
||||||
1853045663799041100600825096887578544265580718909350942241802897995488264551,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
2963055259497271220202739837493041799968576111953080503132045092194513937286,
|
|
||||||
2303806870349915764285872605046527036748108533406243381676768310692344456050,
|
|
||||||
2622104986201990620910286730213140904984256464479840856728424375142929278875,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
2369987021925266811581727383184031736927816625797282287927222602539037105864,
|
|
||||||
285070227712021899602056480426671736057274017903028992288878116056674401781,
|
|
||||||
3034087076179360957800568733595959058628497428787907887933697691951454610691,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
469095854351700119980323115747590868855368701825706298740201488006320881056,
|
|
||||||
360001976264385426746283365024817520563236378289230404095383746911725100012,
|
|
||||||
3438709327109021347267562000879503009590697221730578667498351600602230296178,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
63573904800572228121671659287593650438456772568903228287754075619928214969,
|
|
||||||
3470881855042989871434874691030920672110111605547839662680968354703074556970,
|
|
||||||
724559311507950497340993415408274803001166693839947519425501269424891465492,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
880409284677518997550768549487344416321062350742831373397603704465823658986,
|
|
||||||
6876255662475867703077362872097208259197756317287339941435193538565586230,
|
|
||||||
2701916445133770775447884812906226786217969545216086200932273680400909154638,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
425152119158711585559310064242720816611629181537672850898056934507216982586,
|
|
||||||
1475552998258917706756737045704649573088377604240716286977690565239187213744,
|
|
||||||
2413772448122400684309006716414417978370152271397082147158000439863002593561,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
392160855822256520519339260245328807036619920858503984710539815951012864164,
|
|
||||||
1075036996503791536261050742318169965707018400307026402939804424927087093987,
|
|
||||||
2176439430328703902070742432016450246365760303014562857296722712989275658921,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
1413865976587623331051814207977382826721471106513581745229680113383908569693,
|
|
||||||
4879283427490523253696177116563427032332223531862961281430108575019551814,
|
|
||||||
3392583297537374046875199552977614390492290683707960975137418536812266544902,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
3600854486849487646325182927019642276644093512133907046667282144129939150983,
|
|
||||||
2779924664161372134024229593301361846129279572186444474616319283535189797834,
|
|
||||||
2722699960903170449291146429799738181514821447014433304730310678334403972040,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
819109815049226540285781191874507704729062681836086010078910930707209464699,
|
|
||||||
3046121243742768013822760785918001632929744274211027071381357122228091333823,
|
|
||||||
1339019590803056172509793134119156250729668216522001157582155155947567682278,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
1933279639657506214789316403763326578443023901555983256955812717638093967201,
|
|
||||||
2138221547112520744699126051903811860205771600821672121643894708182292213541,
|
|
||||||
2694713515543641924097704224170357995809887124438248292930846280951601597065,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
2471734202930133750093618989223585244499567111661178960753938272334153710615,
|
|
||||||
504903761112092757611047718215309856203214372330635774577409639907729993533,
|
|
||||||
1943979703748281357156510253941035712048221353507135074336243405478613241290,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
684525210957572142559049112233609445802004614280157992196913315652663518936,
|
|
||||||
1705585400798782397786453706717059483604368413512485532079242223503960814508,
|
|
||||||
192429517716023021556170942988476050278432319516032402725586427701913624665,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
1586493702243128040549584165333371192888583026298039652930372758731750166765,
|
|
||||||
686072673323546915014972146032384917012218151266600268450347114036285993377,
|
|
||||||
3464340397998075738891129996710075228740496767934137465519455338004332839215,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
2805249176617071054530589390406083958753103601524808155663551392362371834663,
|
|
||||||
667746464250968521164727418691487653339733392025160477655836902744186489526,
|
|
||||||
1131527712905109997177270289411406385352032457456054589588342450404257139778,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
1908969485750011212309284349900149072003218505891252313183123635318886241171,
|
|
||||||
1025257076985551890132050019084873267454083056307650830147063480409707787695,
|
|
||||||
2153175291918371429502545470578981828372846236838301412119329786849737957977,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
3410257749736714576487217882785226905621212230027780855361670645857085424384,
|
|
||||||
3442969106887588154491488961893254739289120695377621434680934888062399029952,
|
|
||||||
3029953900235731770255937704976720759948880815387104275525268727341390470237,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
85453456084781138713939104192561924536933417707871501802199311333127894466,
|
|
||||||
2730629666577257820220329078741301754580009106438115341296453318350676425129,
|
|
||||||
178242450661072967256438102630920745430303027840919213764087927763335940415,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
2844589222514708695700541363167856718216388819406388706818431442998498677557,
|
|
||||||
3547876269219141094308889387292091231377253967587961309624916269569559952944,
|
|
||||||
2525005406762984211707203144785482908331876505006839217175334833739957826850,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
3096397013555211396701910432830904669391580557191845136003938801598654871345,
|
|
||||||
574424067119200181933992948252007230348512600107123873197603373898923821490,
|
|
||||||
1714030696055067278349157346067719307863507310709155690164546226450579547098,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
2339895272202694698739231405357972261413383527237194045718815176814132612501,
|
|
||||||
3562501318971895161271663840954705079797767042115717360959659475564651685069,
|
|
||||||
69069358687197963617161747606993436483967992689488259107924379545671193749,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
2614502738369008850475068874731531583863538486212691941619835266611116051561,
|
|
||||||
655247349763023251625727726218660142895322325659927266813592114640858573566,
|
|
||||||
2305235672527595714255517865498269719545193172975330668070873705108690670678,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
926416070297755413261159098243058134401665060349723804040714357642180531931,
|
|
||||||
866523735635840246543516964237513287099659681479228450791071595433217821460,
|
|
||||||
2284334068466681424919271582037156124891004191915573957556691163266198707693,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
1812588309302477291425732810913354633465435706480768615104211305579383928792,
|
|
||||||
2836899808619013605432050476764608707770404125005720004551836441247917488507,
|
|
||||||
2989087789022865112405242078196235025698647423649950459911546051695688370523,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
68056284404189102136488263779598243992465747932368669388126367131855404486,
|
|
||||||
505425339250887519581119854377342241317528319745596963584548343662758204398,
|
|
||||||
2118963546856545068961709089296976921067035227488975882615462246481055679215,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
2253872596319969096156004495313034590996995209785432485705134570745135149681,
|
|
||||||
1625090409149943603241183848936692198923183279116014478406452426158572703264,
|
|
||||||
179139838844452470348634657368199622305888473747024389514258107503778442495,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
1567067018147735642071130442904093290030432522257811793540290101391210410341,
|
|
||||||
2737301854006865242314806979738760349397411136469975337509958305470398783585,
|
|
||||||
3002738216460904473515791428798860225499078134627026021350799206894618186256,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
374029488099466837453096950537275565120689146401077127482884887409712315162,
|
|
||||||
973403256517481077805460710540468856199855789930951602150773500862180885363,
|
|
||||||
2691967457038172130555117632010860984519926022632800605713473799739632878867,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
3515906794910381201365530594248181418811879320679684239326734893975752012109,
|
|
||||||
148057579455448384062325089530558091463206199724854022070244924642222283388,
|
|
||||||
1541588700238272710315890873051237741033408846596322948443180470429851502842,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
147013865879011936545137344076637170977925826031496203944786839068852795297,
|
|
||||||
2630278389304735265620281704608245039972003761509102213752997636382302839857,
|
|
||||||
1359048670759642844930007747955701205155822111403150159614453244477853867621,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
2438984569205812336319229336885480537793786558293523767186829418969842616677,
|
|
||||||
2137792255841525507649318539501906353254503076308308692873313199435029594138,
|
|
||||||
2262318076430740712267739371170174514379142884859595360065535117601097652755,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
2792703718581084537295613508201818489836796608902614779596544185252826291584,
|
|
||||||
2294173715793292812015960640392421991604150133581218254866878921346561546149,
|
|
||||||
2770011224727997178743274791849308200493823127651418989170761007078565678171,
|
|
||||||
],
|
|
||||||
]
|
|
||||||
@@ -1,559 +0,0 @@
|
|||||||
Rate = 3
|
|
||||||
Capacity = 1
|
|
||||||
FullRounds = 8
|
|
||||||
PartialRounds = 84
|
|
||||||
MDS = [[2, 1, 1, 1], [1, 1, 1, 1], [1, 1, 0, 1], [1, 1, 1, -1]]
|
|
||||||
RoundKeys = [
|
|
||||||
[
|
|
||||||
2950795762459345168613727575620414179244544320470208355568817838579231751791,
|
|
||||||
1587446564224215276866294500450702039420286416111469274423465069420553242820,
|
|
||||||
1645965921169490687904413452218868659025437693527479459426157555728339600137,
|
|
||||||
2782373324549879794752287702905278018819686065818504085638398966973694145741,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
3409172630025222641379726933524480516420204828329395644967085131392375707302,
|
|
||||||
2379053116496905638239090788901387719228422033660130943198035907032739387135,
|
|
||||||
2570819397480941104144008784293466051718826502582588529995520356691856497111,
|
|
||||||
3546220846133880637977653625763703334841539452343273304410918449202580719746,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
2720682389492889709700489490056111332164748138023159726590726667539759963454,
|
|
||||||
1899653471897224903834726250400246354200311275092866725547887381599836519005,
|
|
||||||
2369443697923857319844855392163763375394720104106200469525915896159690979559,
|
|
||||||
2354174693689535854311272135513626412848402744119855553970180659094265527996,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
2404084503073127963385083467393598147276436640877011103379112521338973185443,
|
|
||||||
950320777137731763811524327595514151340412860090489448295239456547370725376,
|
|
||||||
2121140748740143694053732746913428481442990369183417228688865837805149503386,
|
|
||||||
2372065044800422557577242066480215868569521938346032514014152523102053709709,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
2618497439310693947058545060953893433487994458443568169824149550389484489896,
|
|
||||||
3518297267402065742048564133910509847197496119850246255805075095266319996916,
|
|
||||||
340529752683340505065238931581518232901634742162506851191464448040657139775,
|
|
||||||
1954876811294863748406056845662382214841467408616109501720437541211031966538,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
813813157354633930267029888722341725864333883175521358739311868164460385261,
|
|
||||||
71901595776070443337150458310956362034911936706490730914901986556638720031,
|
|
||||||
2789761472166115462625363403490399263810962093264318361008954888847594113421,
|
|
||||||
2628791615374802560074754031104384456692791616314774034906110098358135152410,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
3617032588734559635167557152518265808024917503198278888820567553943986939719,
|
|
||||||
2624012360209966117322788103333497793082705816015202046036057821340914061980,
|
|
||||||
149101987103211771991327927827692640556911620408176100290586418839323044234,
|
|
||||||
1039927963829140138166373450440320262590862908847727961488297105916489431045,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
2213946951050724449162431068646025833746639391992751674082854766704900195669,
|
|
||||||
2792724903541814965769131737117981991997031078369482697195201969174353468597,
|
|
||||||
3212031629728871219804596347439383805499808476303618848198208101593976279441,
|
|
||||||
3343514080098703935339621028041191631325798327656683100151836206557453199613,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
614054702436541219556958850933730254992710988573177298270089989048553060199,
|
|
||||||
148148081026449726283933484730968827750202042869875329032965774667206931170,
|
|
||||||
1158283532103191908366672518396366136968613180867652172211392033571980848414,
|
|
||||||
1032400527342371389481069504520755916075559110755235773196747439146396688513,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
806900704622005851310078578853499250941978435851598088619290797134710613736,
|
|
||||||
462498083559902778091095573017508352472262817904991134671058825705968404510,
|
|
||||||
1003580119810278869589347418043095667699674425582646347949349245557449452503,
|
|
||||||
619074932220101074089137133998298830285661916867732916607601635248249357793,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
2635090520059500019661864086615522409798872905401305311748231832709078452746,
|
|
||||||
978252636251682252755279071140187792306115352460774007308726210405257135181,
|
|
||||||
1766912167973123409669091967764158892111310474906691336473559256218048677083,
|
|
||||||
1663265127259512472182980890707014969235283233442916350121860684522654120381,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
3532407621206959585000336211742670185380751515636605428496206887841428074250,
|
|
||||||
2507023127157093845256722098502856938353143387711652912931112668310034975446,
|
|
||||||
3321152907858462102434883844787153373036767230808678981306827073335525034593,
|
|
||||||
3039253036806065280643845548147711477270022154459620569428286684179698125661,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
103480338868480851881924519768416587261556021758163719199282794248762465380,
|
|
||||||
2394049781357087698434751577708655768465803975478348134669006211289636928495,
|
|
||||||
2660531560345476340796109810821127229446538730404600368347902087220064379579,
|
|
||||||
3603166934034556203649050570865466556260359798872408576857928196141785055563,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
1553799760191949768532188139643704561532896296986025007089826672890485412324,
|
|
||||||
2744284717053657689091306578463476341218866418732695211367062598446038965164,
|
|
||||||
320745764922149897598257794663594419839885234101078803811049904310835548856,
|
|
||||||
979382242100682161589753881721708883681034024104145498709287731138044566302,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
1860426855810549882740147175136418997351054138609396651615467358416651354991,
|
|
||||||
336173081054369235994909356892506146234495707857220254489443629387613956145,
|
|
||||||
1632470326779699229772327605759783482411227247311431865655466227711078175883,
|
|
||||||
921958250077481394074960433988881176409497663777043304881055317463712938502,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
3034358982193370602048539901033542101022185309652879937418114324899281842797,
|
|
||||||
25626282149517463867572353922222474817434101087272320606729439087234878607,
|
|
||||||
3002662261401575565838149305485737102400501329139562227180277188790091853682,
|
|
||||||
2939684373453383817196521641512509179310654199629514917426341354023324109367,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
1076484609897998179434851570277297233169621096172424141759873688902355505136,
|
|
||||||
2575095284833160494841112025725243274091830284746697961080467506739203605049,
|
|
||||||
3565075264617591783581665711620369529657840830498005563542124551465195621851,
|
|
||||||
2197016502533303822395077038351174326125210255869204501838837289716363437993,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
331415322883530754594261416546036195982886300052707474899691116664327869405,
|
|
||||||
1935011233711290003793244296594669823169522055520303479680359990463281661839,
|
|
||||||
3495901467168087413996941216661589517270845976538454329511167073314577412322,
|
|
||||||
954195417117133246453562983448451025087661597543338750600301835944144520375,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
1271840477709992894995746871435810599280944810893784031132923384456797925777,
|
|
||||||
2565310762274337662754531859505158700827688964841878141121196528015826671847,
|
|
||||||
3365022288251637014588279139038152521653896670895105540140002607272936852513,
|
|
||||||
1660592021628965529963974299647026602622092163312666588591285654477111176051,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
970104372286014048279296575474974982288801187216974504035759997141059513421,
|
|
||||||
2617024574317953753849168721871770134225690844968986289121504184985993971227,
|
|
||||||
999899815343607746071464113462778273556695659506865124478430189024755832262,
|
|
||||||
2228536129413411161615629030408828764980855956560026807518714080003644769896,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
2701953891198001564547196795777701119629537795442025393867364730330476403227,
|
|
||||||
837078355588159388741598313782044128527494922918203556465116291436461597853,
|
|
||||||
2121749601840466143704862369657561429793951309962582099604848281796392359214,
|
|
||||||
771812260179247428733132708063116523892339056677915387749121983038690154755,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
3317336423132806446086732225036532603224267214833263122557471741829060578219,
|
|
||||||
481570067997721834712647566896657604857788523050900222145547508314620762046,
|
|
||||||
242195042559343964206291740270858862066153636168162642380846129622127460192,
|
|
||||||
2855462178889999218204481481614105202770810647859867354506557827319138379686,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
3525521107148375040131784770413887305850308357895464453970651672160034885202,
|
|
||||||
1320839531502392535964065058804908871811967681250362364246430459003920305799,
|
|
||||||
2514191518588387125173345107242226637171897291221681115249521904869763202419,
|
|
||||||
2798335750958827619666318316247381695117827718387653874070218127140615157902,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
2808467767967035643407948058486565877867906577474361783201337540214875566395,
|
|
||||||
3551834385992706206273955480294669176699286104229279436819137165202231595747,
|
|
||||||
1219439673853113792340300173186247996249367102884530407862469123523013083971,
|
|
||||||
761519904537984520554247997444508040636526566551719396202550009393012691157,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
3355402549169351700500518865338783382387571349497391475317206324155237401353,
|
|
||||||
199541098009731541347317515995192175813554789571447733944970283654592727138,
|
|
||||||
192100490643078165121235261796864975568292640203635147901612231594408079071,
|
|
||||||
1187019357602953326192019968809486933768550466167033084944727938441427050581,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
189525349641911362389041124808934468936759383310282010671081989585219065700,
|
|
||||||
2831653363992091308880573627558515686245403755586311978724025292003353336665,
|
|
||||||
2052859812632218952608271535089179639890275494426396974475479657192657094698,
|
|
||||||
1670756178709659908159049531058853320846231785448204274277900022176591811072,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
3538757242013734574731807289786598937548399719866320954894004830207085723125,
|
|
||||||
710549042741321081781917034337800036872214466705318638023070812391485261299,
|
|
||||||
2345013122330545298606028187653996682275206910242635100920038943391319595180,
|
|
||||||
3528369671971445493932880023233332035122954362711876290904323783426765912206,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
1167120829038120978297497195837406760848728897181138760506162680655977700764,
|
|
||||||
3073243357129146594530765548901087443775563058893907738967898816092270628884,
|
|
||||||
378514724418106317738164464176041649567501099164061863402473942795977719726,
|
|
||||||
333391138410406330127594722511180398159664250722328578952158227406762627796,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
1727570175639917398410201375510924114487348765559913502662122372848626931905,
|
|
||||||
968312190621809249603425066974405725769739606059422769908547372904403793174,
|
|
||||||
360659316299446405855194688051178331671817370423873014757323462844775818348,
|
|
||||||
1386580151907705298970465943238806620109618995410132218037375811184684929291,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
3604888328937389309031638299660239238400230206645344173700074923133890528967,
|
|
||||||
2496185632263372962152518155651824899299616724241852816983268163379540137546,
|
|
||||||
486538168871046887467737983064272608432052269868418721234810979756540672990,
|
|
||||||
1558415498960552213241704009433360128041672577274390114589014204605400783336,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
3512058327686147326577190314835092911156317204978509183234511559551181053926,
|
|
||||||
2235429387083113882635494090887463486491842634403047716936833563914243946191,
|
|
||||||
1290896777143878193192832813769470418518651727840187056683408155503813799882,
|
|
||||||
1143310336918357319571079551779316654556781203013096026972411429993634080835,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
3235435208525081966062419599803346573407862428113723170955762956243193422118,
|
|
||||||
1293239921425673430660897025143433077974838969258268884994339615096356996604,
|
|
||||||
236252269127612784685426260840574970698541177557674806964960352572864382971,
|
|
||||||
1733907592497266237374827232200506798207318263912423249709509725341212026275,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
302004309771755665128395814807589350526779835595021835389022325987048089868,
|
|
||||||
3018926838139221755384801385583867283206879023218491758435446265703006270945,
|
|
||||||
39701437664873825906031098349904330565195980985885489447836580931425171297,
|
|
||||||
908381723021746969965674308809436059628307487140174335882627549095646509778,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
219062858908229855064136253265968615354041842047384625689776811853821594358,
|
|
||||||
1283129863776453589317845316917890202859466483456216900835390291449830275503,
|
|
||||||
418512623547417594896140369190919231877873410935689672661226540908900544012,
|
|
||||||
1792181590047131972851015200157890246436013346535432437041535789841136268632,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
370546432987510607338044736824316856592558876687225326692366316978098770516,
|
|
||||||
3323437805230586112013581113386626899534419826098235300155664022709435756946,
|
|
||||||
910076621742039763058481476739499965761942516177975130656340375573185415877,
|
|
||||||
1762188042455633427137702520675816545396284185254002959309669405982213803405,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
2186362253913140345102191078329764107619534641234549431429008219905315900520,
|
|
||||||
2230647725927681765419218738218528849146504088716182944327179019215826045083,
|
|
||||||
1069243907556644434301190076451112491469636357133398376850435321160857761825,
|
|
||||||
2695241469149243992683268025359863087303400907336026926662328156934068747593,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
1361519681544413849831669554199151294308350560528931040264950307931824877035,
|
|
||||||
1339116632207878730171031743761550901312154740800549632983325427035029084904,
|
|
||||||
790593524918851401449292693473498591068920069246127392274811084156907468875,
|
|
||||||
2723400368331924254840192318398326090089058735091724263333980290765736363637,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
3457180265095920471443772463283225391927927225993685928066766687141729456030,
|
|
||||||
1483675376954327086153452545475557749815683871577400883707749788555424847954,
|
|
||||||
2926303836265506736227240325795090239680154099205721426928300056982414025239,
|
|
||||||
543969119775473768170832347411484329362572550684421616624136244239799475526,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
237401230683847084256617415614300816373730178313253487575312839074042461932,
|
|
||||||
844568412840391587862072008674263874021460074878949862892685736454654414423,
|
|
||||||
151922054871708336050647150237534498235916969120198637893731715254687336644,
|
|
||||||
1299332034710622815055321547569101119597030148120309411086203580212105652312,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
487046922649899823989594814663418784068895385009696501386459462815688122993,
|
|
||||||
1104883249092599185744249485896585912845784382683240114120846423960548576851,
|
|
||||||
1458388705536282069567179348797334876446380557083422364875248475157495514484,
|
|
||||||
850248109622750774031817200193861444623975329881731864752464222442574976566,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
2885843173858536690032695698009109793537724845140477446409245651176355435722,
|
|
||||||
3027068551635372249579348422266406787688980506275086097330568993357835463816,
|
|
||||||
3231892723647447539926175383213338123506134054432701323145045438168976970994,
|
|
||||||
1719080830641935421242626784132692936776388194122314954558418655725251172826,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
1172253756541066126131022537343350498482225068791630219494878195815226839450,
|
|
||||||
1619232269633026603732619978083169293258272967781186544174521481891163985093,
|
|
||||||
3495680684841853175973173610562400042003100419811771341346135531754869014567,
|
|
||||||
1576161515913099892951745452471618612307857113799539794680346855318958552758,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
2618326122974253423403350731396350223238201817594761152626832144510903048529,
|
|
||||||
2696245132758436974032479782852265185094623165224532063951287925001108567649,
|
|
||||||
930116505665110070247395429730201844026054810856263733273443066419816003444,
|
|
||||||
2786389174502246248523918824488629229455088716707062764363111940462137404076,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
1555260846425735320214671887347115247546042526197895180675436886484523605116,
|
|
||||||
2306241912153325247392671742757902161446877415586158295423293240351799505917,
|
|
||||||
411529621724849932999694270803131456243889635467661223241617477462914950626,
|
|
||||||
1542495485262286701469125140275904136434075186064076910329015697714211835205,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
1853045663799041100600825096887578544265580718909350942241802897995488264551,
|
|
||||||
2963055259497271220202739837493041799968576111953080503132045092194513937286,
|
|
||||||
2303806870349915764285872605046527036748108533406243381676768310692344456050,
|
|
||||||
2622104986201990620910286730213140904984256464479840856728424375142929278875,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
2369987021925266811581727383184031736927816625797282287927222602539037105864,
|
|
||||||
285070227712021899602056480426671736057274017903028992288878116056674401781,
|
|
||||||
3034087076179360957800568733595959058628497428787907887933697691951454610691,
|
|
||||||
469095854351700119980323115747590868855368701825706298740201488006320881056,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
360001976264385426746283365024817520563236378289230404095383746911725100012,
|
|
||||||
3438709327109021347267562000879503009590697221730578667498351600602230296178,
|
|
||||||
63573904800572228121671659287593650438456772568903228287754075619928214969,
|
|
||||||
3470881855042989871434874691030920672110111605547839662680968354703074556970,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
724559311507950497340993415408274803001166693839947519425501269424891465492,
|
|
||||||
880409284677518997550768549487344416321062350742831373397603704465823658986,
|
|
||||||
6876255662475867703077362872097208259197756317287339941435193538565586230,
|
|
||||||
2701916445133770775447884812906226786217969545216086200932273680400909154638,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
425152119158711585559310064242720816611629181537672850898056934507216982586,
|
|
||||||
1475552998258917706756737045704649573088377604240716286977690565239187213744,
|
|
||||||
2413772448122400684309006716414417978370152271397082147158000439863002593561,
|
|
||||||
392160855822256520519339260245328807036619920858503984710539815951012864164,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
1075036996503791536261050742318169965707018400307026402939804424927087093987,
|
|
||||||
2176439430328703902070742432016450246365760303014562857296722712989275658921,
|
|
||||||
1413865976587623331051814207977382826721471106513581745229680113383908569693,
|
|
||||||
4879283427490523253696177116563427032332223531862961281430108575019551814,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
3392583297537374046875199552977614390492290683707960975137418536812266544902,
|
|
||||||
3600854486849487646325182927019642276644093512133907046667282144129939150983,
|
|
||||||
2779924664161372134024229593301361846129279572186444474616319283535189797834,
|
|
||||||
2722699960903170449291146429799738181514821447014433304730310678334403972040,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
819109815049226540285781191874507704729062681836086010078910930707209464699,
|
|
||||||
3046121243742768013822760785918001632929744274211027071381357122228091333823,
|
|
||||||
1339019590803056172509793134119156250729668216522001157582155155947567682278,
|
|
||||||
1933279639657506214789316403763326578443023901555983256955812717638093967201,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
2138221547112520744699126051903811860205771600821672121643894708182292213541,
|
|
||||||
2694713515543641924097704224170357995809887124438248292930846280951601597065,
|
|
||||||
2471734202930133750093618989223585244499567111661178960753938272334153710615,
|
|
||||||
504903761112092757611047718215309856203214372330635774577409639907729993533,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
1943979703748281357156510253941035712048221353507135074336243405478613241290,
|
|
||||||
684525210957572142559049112233609445802004614280157992196913315652663518936,
|
|
||||||
1705585400798782397786453706717059483604368413512485532079242223503960814508,
|
|
||||||
192429517716023021556170942988476050278432319516032402725586427701913624665,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
1586493702243128040549584165333371192888583026298039652930372758731750166765,
|
|
||||||
686072673323546915014972146032384917012218151266600268450347114036285993377,
|
|
||||||
3464340397998075738891129996710075228740496767934137465519455338004332839215,
|
|
||||||
2805249176617071054530589390406083958753103601524808155663551392362371834663,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
667746464250968521164727418691487653339733392025160477655836902744186489526,
|
|
||||||
1131527712905109997177270289411406385352032457456054589588342450404257139778,
|
|
||||||
1908969485750011212309284349900149072003218505891252313183123635318886241171,
|
|
||||||
1025257076985551890132050019084873267454083056307650830147063480409707787695,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
2153175291918371429502545470578981828372846236838301412119329786849737957977,
|
|
||||||
3410257749736714576487217882785226905621212230027780855361670645857085424384,
|
|
||||||
3442969106887588154491488961893254739289120695377621434680934888062399029952,
|
|
||||||
3029953900235731770255937704976720759948880815387104275525268727341390470237,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
85453456084781138713939104192561924536933417707871501802199311333127894466,
|
|
||||||
2730629666577257820220329078741301754580009106438115341296453318350676425129,
|
|
||||||
178242450661072967256438102630920745430303027840919213764087927763335940415,
|
|
||||||
2844589222514708695700541363167856718216388819406388706818431442998498677557,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
3547876269219141094308889387292091231377253967587961309624916269569559952944,
|
|
||||||
2525005406762984211707203144785482908331876505006839217175334833739957826850,
|
|
||||||
3096397013555211396701910432830904669391580557191845136003938801598654871345,
|
|
||||||
574424067119200181933992948252007230348512600107123873197603373898923821490,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
1714030696055067278349157346067719307863507310709155690164546226450579547098,
|
|
||||||
2339895272202694698739231405357972261413383527237194045718815176814132612501,
|
|
||||||
3562501318971895161271663840954705079797767042115717360959659475564651685069,
|
|
||||||
69069358687197963617161747606993436483967992689488259107924379545671193749,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
2614502738369008850475068874731531583863538486212691941619835266611116051561,
|
|
||||||
655247349763023251625727726218660142895322325659927266813592114640858573566,
|
|
||||||
2305235672527595714255517865498269719545193172975330668070873705108690670678,
|
|
||||||
926416070297755413261159098243058134401665060349723804040714357642180531931,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
866523735635840246543516964237513287099659681479228450791071595433217821460,
|
|
||||||
2284334068466681424919271582037156124891004191915573957556691163266198707693,
|
|
||||||
1812588309302477291425732810913354633465435706480768615104211305579383928792,
|
|
||||||
2836899808619013605432050476764608707770404125005720004551836441247917488507,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
2989087789022865112405242078196235025698647423649950459911546051695688370523,
|
|
||||||
68056284404189102136488263779598243992465747932368669388126367131855404486,
|
|
||||||
505425339250887519581119854377342241317528319745596963584548343662758204398,
|
|
||||||
2118963546856545068961709089296976921067035227488975882615462246481055679215,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
2253872596319969096156004495313034590996995209785432485705134570745135149681,
|
|
||||||
1625090409149943603241183848936692198923183279116014478406452426158572703264,
|
|
||||||
179139838844452470348634657368199622305888473747024389514258107503778442495,
|
|
||||||
1567067018147735642071130442904093290030432522257811793540290101391210410341,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
2737301854006865242314806979738760349397411136469975337509958305470398783585,
|
|
||||||
3002738216460904473515791428798860225499078134627026021350799206894618186256,
|
|
||||||
374029488099466837453096950537275565120689146401077127482884887409712315162,
|
|
||||||
973403256517481077805460710540468856199855789930951602150773500862180885363,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
2691967457038172130555117632010860984519926022632800605713473799739632878867,
|
|
||||||
3515906794910381201365530594248181418811879320679684239326734893975752012109,
|
|
||||||
148057579455448384062325089530558091463206199724854022070244924642222283388,
|
|
||||||
1541588700238272710315890873051237741033408846596322948443180470429851502842,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
147013865879011936545137344076637170977925826031496203944786839068852795297,
|
|
||||||
2630278389304735265620281704608245039972003761509102213752997636382302839857,
|
|
||||||
1359048670759642844930007747955701205155822111403150159614453244477853867621,
|
|
||||||
2438984569205812336319229336885480537793786558293523767186829418969842616677,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
2137792255841525507649318539501906353254503076308308692873313199435029594138,
|
|
||||||
2262318076430740712267739371170174514379142884859595360065535117601097652755,
|
|
||||||
2792703718581084537295613508201818489836796608902614779596544185252826291584,
|
|
||||||
2294173715793292812015960640392421991604150133581218254866878921346561546149,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
2770011224727997178743274791849308200493823127651418989170761007078565678171,
|
|
||||||
3321642244537785916275181932172303118112488081726311374164578600576901819844,
|
|
||||||
3522708517589950573320671158134804505970724681591943826922697952040487655044,
|
|
||||||
3417974441436557992524691506735790206623600049454586729879955931972546347402,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
175039333145381316571259690443853067809784261609912638686739799135919647022,
|
|
||||||
1930713062131033273316869231148248962041053029742760224583505092759642967464,
|
|
||||||
2971452932574554603554350185069538580257636405419430340233233400633251319042,
|
|
||||||
2774781903758215341037075610938953949868289195845367046186588750871862784919,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
666516874137869653699423537799457099346460194092311952417454613224504932738,
|
|
||||||
1900462225013533249140457703727169176351786259991305560412832202759625668041,
|
|
||||||
2665631186082687279121709429531834469477679375137509769347092380798929714377,
|
|
||||||
837840745988147279235494664091280091563355097569199320366973125128366540061,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
3391544118305848781823721719916289805455110924839794510205940718821197620955,
|
|
||||||
2888553035909938253628892138500390690221493345071933642853222968481016605919,
|
|
||||||
3386241569867597612447901482685846444743718781330869478721963580925825915450,
|
|
||||||
1205126220630896984850042596877918177217334376800874965105642874206963597698,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
3590072615491710252422997155203204584659171612188004116415640739580250394190,
|
|
||||||
692469013329617220154003334549812915100479873898898958632988703738125356983,
|
|
||||||
1623178235190707102808841905143937367808788834203621005714003335195182126335,
|
|
||||||
1972826180775011489122426045504602288576507493792470102803637471568052321297,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
3415141329098504418158191749675997877417539760075593313736376750580696083073,
|
|
||||||
587811537889727046473915684463981273175495137461951211739526104349163747811,
|
|
||||||
2523982964351069134084525951849317400231659428055762640605248929856135518199,
|
|
||||||
2686176526711834950207666047281383173339057216783586039351834948812568447629,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
983144446441739425577690449774542566745526459152966545642451764143532586964,
|
|
||||||
171558252019175695567663688494555626159399786667979998273792882504784080805,
|
|
||||||
332337623010057542760158225837623039780806442976079546879646069338600179518,
|
|
||||||
1264669683963885571544813806669118319675288608634733888843804451222546848295,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
2426165115815723668018318268486497504249785449504758403912155206515511627681,
|
|
||||||
11387399609384288947733630450855186629703576293221897150193655994854764608,
|
|
||||||
2541728569046079092074077754414781968906176513081761690404588216304985421091,
|
|
||||||
47685947554980329431290582269851186106577733250761848107645535357326439312,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
472176388418187405374813530639596064799362505024895746833751173199773896628,
|
|
||||||
2764298116617383397920343358525617195195060562266243809245480210157942112738,
|
|
||||||
486863835068754002670800862273365477867695879270721744227071001883208334054,
|
|
||||||
2973492686137102577527656941792991264994301121122130295965761350095846874635,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
178385615141132702906181473263873416748818415607305319148067639744074654009,
|
|
||||||
533624640096756667052211553746016402543259206286603356120804827761339634127,
|
|
||||||
819406716720171922688026098737835227857400444543748198788964759773510472096,
|
|
||||||
531851793767260921861217458033110066464894334064526987603936107947006031387,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
3269709072483585277009748181134917746036523619604017812342933951952104134829,
|
|
||||||
838191718603413598040249006803464503100808192944407407147899973659013630611,
|
|
||||||
1574561296941310904780257598780779812250055948216417844567262310524022037406,
|
|
||||||
551394354289003977607664358739006072556227894953233419144430578080352094737,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
445076790942318675726839050057337819004979443030540904213920669247413907302,
|
|
||||||
1963946696292687224902912968478695543164747600779913024040878700455222386521,
|
|
||||||
484284614181963381509745298932402076252103342403432879800905151752488144767,
|
|
||||||
2240507606126946994415203252302826782042951346966859379502140796364876543253,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
3237135638753992982179886898758938279897590886053928839613434762582576319619,
|
|
||||||
2334333034701915027889533058426879447140084891006486138782876488162658230991,
|
|
||||||
14411091399844539897439754491034751977136685514851444574462584316609631592,
|
|
||||||
1264480371592407258420308876448697804787923638319277097663041109464608464284,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
671929312763821646360589403212798993954209530574443543917757335777610372144,
|
|
||||||
2513909805455654095962542944994577107405216428214873444765576238504714067396,
|
|
||||||
870121102846043786263357605823753628974859886859187558617096145653709171231,
|
|
||||||
399132620893316356411986266679786708905730068946836982293484206366500277754,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
2855046250836680633532995284655778407402587437073106249445470889390454667586,
|
|
||||||
2063679741125384345396981490971605710211281905716315529671473143278849561151,
|
|
||||||
1433753212258929925682201698758056443128516570551146995210728194816988328337,
|
|
||||||
3334984763425011856632257855270507440816274246647423607159847074739331865077,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
337911293622078184850923533628334646725451591671907148383867096651211846605,
|
|
||||||
559587005295238702015018022040357402231957131094636365177008701077975941644,
|
|
||||||
885963059604819264377490633589388189646118257469490919900554134369512794660,
|
|
||||||
1957748763518471091057032383332840331641373304981058387824598000170709016333,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
3175295982155056798972302481564899381103533409383494814704562889625572018450,
|
|
||||||
498987160612401618114584726510347771865331516606886613019084323862447372555,
|
|
||||||
947374835104260364630171441676101001841507588423166778786886198914150312958,
|
|
||||||
906933977754491302438795274167251538820934378773708095543613756654712689280,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
2170116291766863179909957030577284618726490893598499117272497866180009722894,
|
|
||||||
1801335399574515889082584621772588704763181408217893911806726119813067220453,
|
|
||||||
1942500232535842474530840356353427989892065499159260166135596750084681859966,
|
|
||||||
62936080219825306823124060587235998278756755377419521154040408253893795176,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
3091993939935137795359769774909373279950941171574748645375255810204590357753,
|
|
||||||
1283528386884634267663661033944552098742115012555712906773586466375284501324,
|
|
||||||
1581820717639229420476069802992937438655873471854930764425841549067913106065,
|
|
||||||
2301986095388751633126546121528329200085681648876910655269533407603441046514,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
2850003828037698751961753862613545302539465803982364898225617297398939302949,
|
|
||||||
48024691078494936445046366770271288984930221238071705874025261821606393528,
|
|
||||||
1482336297033144958942154923925185950152551534403871620222916667536030875354,
|
|
||||||
3081177564717719643771186007689458633949181485535169123213511264603782950049,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
3315701127039521853279746297714590495201061397709680410650043502532250578075,
|
|
||||||
3514407611000441301995070394422463400067690470546731164089622325748803106020,
|
|
||||||
368970178199930154322724953487299516224498421233447528815195701420122548537,
|
|
||||||
584353160413525267849669053228533951552602295860601556035386665117717227391,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
752038702160385294706011538400822066722189014251268673051846350397729870418,
|
|
||||||
3594041683498798688197194521326299097635429790757880308152971477196489335154,
|
|
||||||
1367902435756906062215608264424138718742854099315395230911274560900857414183,
|
|
||||||
1828549068951502746189364466794037234789986878381694857475972053743463890779,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
488172495141237210878388657234137733008417573114482400652274985829148564248,
|
|
||||||
962906242461930394022372340919543491337923491322497419797555620396501785566,
|
|
||||||
2275418085010046236619290386129138234541669589549771944697082317642065048898,
|
|
||||||
1966395064658902622886154686288219600816893261614483533899715888994623208964,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
3496095878293416917311185659829821476802828534554531050412634978086916288609,
|
|
||||||
3368478822390537245916137403277928093536087427951052230723275731232142463388,
|
|
||||||
3397410259276620127103231993277518800970669191016277541098821699302368873803,
|
|
||||||
2662600899665871010006649609856695263727220473364611552472965243032255906029,
|
|
||||||
],
|
|
||||||
]
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user