Compare commits
100 Commits
Author | SHA1 | Date | |
---|---|---|---|
a8ea9d757f | |||
|
efeca9f478 | ||
|
8ad2f9a185 | ||
|
be576b4c17 | ||
|
819514576c | ||
|
a0e398489f | ||
|
85d194cb93 | ||
|
1830124ca1 | ||
|
72cc640bb1 | ||
|
32bda7926d | ||
|
38a4ca1e6b | ||
|
07f7e53e31 | ||
|
537db4a968 | ||
|
a70501cec4 | ||
|
89aaf264c1 | ||
|
e93caf9567 | ||
|
0ce103bd6b | ||
|
6a85252dc3 | ||
|
a8503d6819 | ||
|
8397b26b45 | ||
|
8c39a6ac5a | ||
|
a1a7dc9cbf | ||
|
ba58a282bd | ||
|
c4c479047e | ||
|
2bf2e312a0 | ||
|
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 | ||
|
b082d41c29 |
.github
.gitignore.prettierrc.jsonREADME.mdSECURITY.mdaudit
benchmark
build
package-lock.jsonpackage.jsonsrc
test
basic.test.jsbls12-381.test.js
tsconfig.esm.jsontsconfig.jsonbls12-381
hash-to-curve.test.jshash-to-curve
BLS12381G1_XMD_SHA-256_SSWU_NU_.jsonBLS12381G1_XMD_SHA-256_SSWU_RO_.jsonBLS12381G2_XMD_SHA-256_SSWU_NU_.jsonBLS12381G2_XMD_SHA-256_SSWU_RO_.jsonP256_XMD_SHA-256_SSWU_NU_.jsonP256_XMD_SHA-256_SSWU_RO_.jsonP384_XMD_SHA-384_SSWU_NU_.jsonP384_XMD_SHA-384_SSWU_RO_.jsonP521_XMD_SHA-512_SSWU_NU_.jsonP521_XMD_SHA-512_SSWU_RO_.jsoncurve25519_XMD_SHA-512_ELL2_NU_.jsoncurve25519_XMD_SHA-512_ELL2_RO_.jsoncurve448_XOF_SHAKE256_ELL2_NU_.jsoncurve448_XOF_SHAKE256_ELL2_RO_.jsonedwards25519_XMD_SHA-512_ELL2_NU_.jsonedwards25519_XMD_SHA-512_ELL2_RO_.jsonedwards448_XOF_SHAKE256_ELL2_NU_.jsonedwards448_XOF_SHAKE256_ELL2_RO_.jsonsecp256k1_XMD_SHA-256_SSWU_NU_.jsonsecp256k1_XMD_SHA-256_SSWU_RO_.json
nist.test.js
1
.github/funding.yml
vendored
1
.github/funding.yml
vendored
@ -1,2 +1 @@
|
||||
github: paulmillr
|
||||
# custom: https://paulmillr.com/funding/
|
15
.github/workflows/nodejs.yml
vendored
15
.github/workflows/nodejs.yml
vendored
@ -1,17 +1,20 @@
|
||||
name: Node CI
|
||||
|
||||
on: [push, pull_request]
|
||||
name: Run node.js tests
|
||||
on:
|
||||
- push
|
||||
- pull_request
|
||||
jobs:
|
||||
test:
|
||||
name: v${{ matrix.node }} @ ubuntu-latest
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
node: [18, 20]
|
||||
node:
|
||||
- 18
|
||||
- 20
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@1e31de5234b9f8995739874a8ce0492dc87873e2 # v4
|
||||
- name: Use Node.js ${{ matrix.node }}
|
||||
uses: actions/setup-node@v3
|
||||
uses: actions/setup-node@8f152de45cc393bb48ce5d89d36b731f54556e65 # v4
|
||||
with:
|
||||
node-version: ${{ matrix.node }}
|
||||
- run: npm install
|
||||
|
6
.github/workflows/publish-npm.yml
vendored
6
.github/workflows/publish-npm.yml
vendored
@ -1,4 +1,4 @@
|
||||
name: Publish Package to npm
|
||||
name: Publish package to npm
|
||||
on:
|
||||
release:
|
||||
types: [created]
|
||||
@ -9,8 +9,8 @@ jobs:
|
||||
contents: read
|
||||
id-token: write
|
||||
steps:
|
||||
- uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3
|
||||
- uses: actions/setup-node@64ed1c7eab4cce3362f8c340dee64e5eaeef8f7c # v3
|
||||
- uses: actions/checkout@1e31de5234b9f8995739874a8ce0492dc87873e2 # v4
|
||||
- uses: actions/setup-node@8f152de45cc393bb48ce5d89d36b731f54556e65 # v4
|
||||
with:
|
||||
node-version: 20
|
||||
registry-url: 'https://registry.npmjs.org'
|
||||
|
28
.github/workflows/upload-release.yml
vendored
Normal file
28
.github/workflows/upload-release.yml
vendored
Normal file
@ -0,0 +1,28 @@
|
||||
name: Upload standalone file to GitHub Releases
|
||||
on:
|
||||
release:
|
||||
types: [created]
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
id-token: write
|
||||
steps:
|
||||
- uses: actions/checkout@1e31de5234b9f8995739874a8ce0492dc87873e2 # v4
|
||||
- uses: actions/setup-node@8f152de45cc393bb48ce5d89d36b731f54556e65 # v4
|
||||
with:
|
||||
node-version: 20
|
||||
registry-url: 'https://registry.npmjs.org'
|
||||
cache: npm
|
||||
- run: npm install -g npm
|
||||
- run: npm ci
|
||||
- run: npm run build
|
||||
- run: |
|
||||
cd build
|
||||
npm ci
|
||||
npm run build:release
|
||||
cd ..
|
||||
- run: gh release upload ${{ github.event.release.tag_name }} build/`npx jsbt outfile`
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
16
.gitignore
vendored
16
.gitignore
vendored
@ -1,13 +1,9 @@
|
||||
build/
|
||||
node_modules/
|
||||
coverage/
|
||||
node_modules
|
||||
/*.js
|
||||
/*.ts
|
||||
/*.js.map
|
||||
/*.d.ts.map
|
||||
/esm/*.js
|
||||
/esm/*.ts
|
||||
/esm/*.js.map
|
||||
/esm/*.d.ts.map
|
||||
*.d.ts
|
||||
*.d.ts.map
|
||||
*.js.map
|
||||
/build
|
||||
/abstract
|
||||
/esm/abstract
|
||||
/abstract/
|
||||
|
@ -1,4 +1,5 @@
|
||||
{
|
||||
"printWidth": 100,
|
||||
"singleQuote": true
|
||||
"singleQuote": true,
|
||||
"trailingComma": "es5"
|
||||
}
|
||||
|
319
README.md
319
README.md
@ -2,30 +2,36 @@
|
||||
|
||||
Audited & minimal JS implementation of elliptic curve cryptography.
|
||||
|
||||
- 🔒 [**Audited**](#security) by an independent security firm
|
||||
- 🔒 [**Audited**](#security) by independent security firms
|
||||
- 🔻 Tree-shaking-friendly: use only what's necessary, other code won't be included
|
||||
- 🏎 Ultra-fast, hand-optimized for caveats of JS engines
|
||||
- 🔍 Unique tests ensure correctness: property-based, cross-library and Wycheproof vectors, fuzzing
|
||||
- ➰ Short Weierstrass, Edwards, Montgomery curves
|
||||
- ✍️ ECDSA, EdDSA, Schnorr, BLS signature schemes, ECDH key agreement
|
||||
- 🔖 SUF-CMA and SBS (non-repudiation) for ed25519, ed448 and others
|
||||
- #️⃣ hash-to-curve for encoding or hashing an arbitrary string to an elliptic curve point
|
||||
- ✍️ ECDSA, EdDSA, Schnorr, BLS signature schemes, ECDH key agreement, hashing to curves
|
||||
- 🔖 SUF-CMA, SBS (non-repudiation), ZIP215 (consensus friendliness) features for ed25519
|
||||
- 🧜♂️ Poseidon ZK-friendly hash
|
||||
- 🪶 178KB for everything, 25KB for single-curve build
|
||||
|
||||
### This library belongs to _noble_ crypto
|
||||
For discussions, questions and support, visit
|
||||
[GitHub Discussions](https://github.com/paulmillr/noble-curves/discussions)
|
||||
section of the repository.
|
||||
|
||||
> **noble-crypto** — high-security, easily auditable set of contained cryptographic libraries and tools.
|
||||
### This library belongs to _noble_ cryptography
|
||||
|
||||
- No dependencies, protection against supply chain attacks
|
||||
- Auditable TypeScript / JS code
|
||||
- Supported on all major platforms
|
||||
- Releases are signed with PGP keys and built transparently with NPM provenance
|
||||
- Check out [homepage](https://paulmillr.com/noble/) & all libraries:
|
||||
> **noble cryptography** — high-security, easily auditable set of contained cryptographic libraries and tools.
|
||||
|
||||
- Zero or minimal dependencies
|
||||
- Highly readable TypeScript / JS code
|
||||
- PGP-signed releases and transparent NPM builds
|
||||
- All libraries:
|
||||
[ciphers](https://github.com/paulmillr/noble-ciphers),
|
||||
[curves](https://github.com/paulmillr/noble-curves),
|
||||
[hashes](https://github.com/paulmillr/noble-hashes),
|
||||
[post-quantum](https://github.com/paulmillr/noble-post-quantum),
|
||||
4kb [secp256k1](https://github.com/paulmillr/noble-secp256k1) /
|
||||
[ed25519](https://github.com/paulmillr/noble-ed25519)
|
||||
- [Check out homepage](https://paulmillr.com/noble/)
|
||||
for reading resources, documentation and apps built with noble
|
||||
|
||||
## Usage
|
||||
|
||||
@ -33,13 +39,19 @@ Audited & minimal JS implementation of elliptic curve cryptography.
|
||||
|
||||
We support all major platforms and runtimes.
|
||||
For [Deno](https://deno.land), ensure to use [npm specifier](https://deno.land/manual@v1.28.0/node/npm_specifiers).
|
||||
For React Native, you may need a [polyfill for crypto.getRandomValues](https://github.com/LinusU/react-native-get-random-values).
|
||||
If you don't like NPM, a standalone [noble-curves.js](https://github.com/paulmillr/noble-curves/releases) is also available.
|
||||
For React Native, you may need a [polyfill for getRandomValues](https://github.com/LinusU/react-native-get-random-values).
|
||||
A standalone file [noble-curves.js](https://github.com/paulmillr/noble-curves/releases) is also available.
|
||||
|
||||
```js
|
||||
// import * from '@noble/curves'; // Error: use sub-imports, to ensure small app size
|
||||
import { secp256k1 } from '@noble/curves/secp256k1'; // ESM and Common.js
|
||||
// import { secp256k1 } from 'npm:@noble/curves@1.4.0/secp256k1'; // Deno
|
||||
```
|
||||
|
||||
- [Implementations](#implementations)
|
||||
- [ECDSA signature scheme](#ecdsa-signature-scheme)
|
||||
- [ECDSA public key recovery & extra entropy](#ecdsa-public-key-recovery--extra-entropy)
|
||||
- [ECDH (Elliptic Curve Diffie-Hellman)](#ecdh-elliptic-curve-diffie-hellman)
|
||||
- [ECDH: Elliptic Curve Diffie-Hellman](#ecdh-elliptic-curve-diffie-hellman)
|
||||
- [Schnorr signatures over secp256k1, BIP340](#schnorr-signatures-over-secp256k1-bip340)
|
||||
- [ed25519, X25519, ristretto255](#ed25519-x25519-ristretto255)
|
||||
- [ed448, X448, decaf448](#ed448-x448-decaf448)
|
||||
@ -47,37 +59,32 @@ If you don't like NPM, a standalone [noble-curves.js](https://github.com/paulmil
|
||||
- [All available imports](#all-available-imports)
|
||||
- [Accessing a curve's variables](#accessing-a-curves-variables)
|
||||
- [Abstract API](#abstract-api)
|
||||
- [abstract/weierstrass: Short Weierstrass curve](#abstractweierstrass-short-weierstrass-curve)
|
||||
- [abstract/edwards: Twisted Edwards curve](#abstractedwards-twisted-edwards-curve)
|
||||
- [abstract/montgomery: Montgomery curve](#abstractmontgomery-montgomery-curve)
|
||||
- [abstract/bls: Barreto-Lynn-Scott curves](#abstractbls-barreto-lynn-scott-curves)
|
||||
- [abstract/hash-to-curve: Hashing strings to curve points](#abstracthash-to-curve-hashing-strings-to-curve-points)
|
||||
- [abstract/poseidon: Poseidon hash](#abstractposeidon-poseidon-hash)
|
||||
- [abstract/modular: Modular arithmetics utilities](#abstractmodular-modular-arithmetics-utilities)
|
||||
- [weierstrass: Short Weierstrass curve](#weierstrass-short-weierstrass-curve)
|
||||
- [edwards: Twisted Edwards curve](#edwards-twisted-edwards-curve)
|
||||
- [montgomery: Montgomery curve](#montgomery-montgomery-curve)
|
||||
- [bls: Barreto-Lynn-Scott curves](#bls-barreto-lynn-scott-curves)
|
||||
- [hash-to-curve: Hashing strings to curve points](#hash-to-curve-hashing-strings-to-curve-points)
|
||||
- [poseidon: Poseidon hash](#poseidon-poseidon-hash)
|
||||
- [modular: Modular arithmetics utilities](#modular-modular-arithmetics-utilities)
|
||||
- [Creating private keys from hashes](#creating-private-keys-from-hashes)
|
||||
- [abstract/utils: Useful utilities](#abstractutils-useful-utilities)
|
||||
- [utils: Useful utilities](#utils-useful-utilities)
|
||||
- [Security](#security)
|
||||
- [Speed](#speed)
|
||||
- [Contributing & testing](#contributing--testing)
|
||||
- [Upgrading](#upgrading)
|
||||
- [Contributing & testing](#contributing--testing)
|
||||
- [Resources](#resources)
|
||||
- [Demos](#demos)
|
||||
- [Projects using curves](#projects-using-curves)
|
||||
- [License](#license)
|
||||
|
||||
### Implementations
|
||||
|
||||
Implementations are utilizing [noble-hashes](https://github.com/paulmillr/noble-hashes).
|
||||
[Abstract API](#abstract-api) doesn't depend on them: you can use a different hashing library.
|
||||
Implementations use [noble-hashes](https://github.com/paulmillr/noble-hashes).
|
||||
If you want to use a different hashing library, [abstract API](#abstract-api) doesn't depend on them.
|
||||
|
||||
#### ECDSA signature scheme
|
||||
|
||||
Generic example that works for all curves, shown for secp256k1:
|
||||
|
||||
```ts
|
||||
// import * from '@noble/curves'; // Error: use sub-imports, to ensure small app size
|
||||
import { secp256k1 } from '@noble/curves/secp256k1'; // ESM and Common.js
|
||||
// import { secp256k1 } from 'npm:@noble/curves@1.2.0/secp256k1'; // Deno
|
||||
import { secp256k1 } from '@noble/curves/secp256k1';
|
||||
const priv = secp256k1.utils.randomPrivateKey();
|
||||
const pub = secp256k1.getPublicKey(priv);
|
||||
const msg = new Uint8Array(32).fill(1); // message hash (not message) in ecdsa
|
||||
@ -89,16 +96,20 @@ const privHex = '46c930bc7bb4db7f55da20798697421b98c4175a52c630294d75a84b9c12623
|
||||
const pub2 = secp256k1.getPublicKey(privHex);
|
||||
```
|
||||
|
||||
We support P256 (secp256r1), P384 (secp384r1), P521 (secp521r1).
|
||||
|
||||
#### ECDSA public key recovery & extra entropy
|
||||
|
||||
```ts
|
||||
// let sig = secp256k1.Signature.fromCompact(sigHex); // or .fromDER(sigDERHex)
|
||||
// sig = sig.addRecoveryBit(bit); // bit is not serialized into compact / der format
|
||||
sig.recoverPublicKey(msg).toRawBytes(); // === pub; // public key recovery
|
||||
|
||||
// extraEntropy https://moderncrypto.org/mail-archive/curves/2017/000925.html
|
||||
const sigImprovedSecurity = secp256k1.sign(msg, priv, { extraEntropy: true });
|
||||
```
|
||||
|
||||
#### ECDH (Elliptic Curve Diffie-Hellman)
|
||||
#### ECDH: Elliptic Curve Diffie-Hellman
|
||||
|
||||
```ts
|
||||
// 1. The output includes parity byte. Strip it using shared.slice(1)
|
||||
@ -235,7 +246,7 @@ Same RFC7748 / RFC8032 / IRTF draft are followed.
|
||||
|
||||
#### bls12-381
|
||||
|
||||
See [abstract/bls](#abstractbls-barreto-lynn-scott-curves).
|
||||
See [abstract/bls](#bls-barreto-lynn-scott-curves).
|
||||
|
||||
#### All available imports
|
||||
|
||||
@ -274,7 +285,7 @@ Precomputes are enabled for weierstrass and edwards BASE points of a curve. You
|
||||
could precompute any other point (e.g. for ECDH) using `utils.precompute()`
|
||||
method: check out examples.
|
||||
|
||||
### abstract/weierstrass: Short Weierstrass curve
|
||||
### weierstrass: Short Weierstrass curve
|
||||
|
||||
```ts
|
||||
import { weierstrass } from '@noble/curves/abstract/weierstrass';
|
||||
@ -316,6 +327,10 @@ type CHash = {
|
||||
outputLen: number;
|
||||
create(): any;
|
||||
};
|
||||
|
||||
// example
|
||||
function sha256(message: Uint8Array) { return _internal_lowlvl(message) }
|
||||
sha256.outputLen = 32; // 32 bytes of output for sha2-256
|
||||
```
|
||||
|
||||
**Message hash** is expected instead of message itself:
|
||||
@ -441,7 +456,7 @@ const fast = secq256k1.utils.precompute(8, Point.fromHex(someonesPubKey));
|
||||
fast.multiply(privKey); // much faster ECDH now
|
||||
```
|
||||
|
||||
### abstract/edwards: Twisted Edwards curve
|
||||
### edwards: Twisted Edwards curve
|
||||
|
||||
```ts
|
||||
import { twistedEdwards } from '@noble/curves/abstract/edwards';
|
||||
@ -531,7 +546,7 @@ interface ExtPointConstructor extends GroupConstructor<ExtPointType> {
|
||||
}
|
||||
```
|
||||
|
||||
### abstract/montgomery: Montgomery curve
|
||||
### montgomery: Montgomery curve
|
||||
|
||||
```typescript
|
||||
import { montgomery } from '@noble/curves/abstract/montgomery';
|
||||
@ -540,7 +555,7 @@ import { Field } from '@noble/curves/abstract/modular';
|
||||
const x25519 = montgomery({
|
||||
a: 486662n,
|
||||
Gu: 9n,
|
||||
Fp: Field(2n ** 255n - 19n),
|
||||
P: 2n ** 255n - 19n,
|
||||
montgomeryBits: 255,
|
||||
nByteLength: 32,
|
||||
// Optional param
|
||||
@ -558,7 +573,7 @@ Proper Elliptic Curve Points are not implemented yet.
|
||||
|
||||
You must specify curve params `Fp`, `a`, `Gu` coordinate of u, `montgomeryBits` and `nByteLength`.
|
||||
|
||||
### abstract/bls: Barreto-Lynn-Scott curves
|
||||
### bls: Barreto-Lynn-Scott curves
|
||||
|
||||
The module abstracts BLS (Barreto-Lynn-Scott) pairing-friendly elliptic curve construction.
|
||||
They allow to construct [zk-SNARKs](https://z.cash/technology/zksnarks/) and
|
||||
@ -567,6 +582,8 @@ use aggregated, batch-verifiable
|
||||
using Boneh-Lynn-Shacham signature scheme.
|
||||
|
||||
The module doesn't expose `CURVE` property: use `G1.CURVE`, `G2.CURVE` instead.
|
||||
Only BLS12-381 is implemented currently.
|
||||
Defining BLS12-377 and BLS24 should be straightforward.
|
||||
|
||||
Main methods and properties are:
|
||||
|
||||
@ -579,8 +596,13 @@ Main methods and properties are:
|
||||
- `Signature` property with `fromHex`, `toHex` methods
|
||||
- `fields` containing `Fp`, `Fp2`, `Fp6`, `Fp12`, `Fr`
|
||||
|
||||
Right now we only implement BLS12-381 (compatible with ETH and others),
|
||||
but in theory defining BLS12-377, BLS24 should be straightforward. An example:
|
||||
The default BLS uses short public keys (with public keys in G1 and signatures in G2).
|
||||
Short signatures (public keys in G2 and signatures in G1) is also supported, using:
|
||||
|
||||
- `getPublicKeyForShortSignatures(privateKey)`
|
||||
- `signShortSignature(message, privateKey)`
|
||||
- `verifyShortSignature(signature, message, publicKey)`
|
||||
- `aggregateShortSignatures(signatures)`
|
||||
|
||||
```ts
|
||||
import { bls12_381 as bls } from '@noble/curves/bls12-381';
|
||||
@ -591,6 +613,12 @@ const signature = bls.sign(message, privateKey);
|
||||
const isValid = bls.verify(signature, message, publicKey);
|
||||
console.log({ publicKey, signature, isValid });
|
||||
|
||||
// Use custom DST, e.g. for Ethereum consensus layer
|
||||
const htfEthereum = {DST: 'BLS_SIG_BLS12381G2_XMD:SHA-256_SSWU_RO_POP_'};
|
||||
const signatureEth = bls.sign(message, privateKey, htfEthereum);
|
||||
const isValidEth = bls.verify(signature, message, publicKey, htfEthereum);
|
||||
console.log({ signatureEth, isValidEth });
|
||||
|
||||
// Sign 1 msg with 3 keys
|
||||
const privateKeys = [
|
||||
'18f020b98eb798752a50ed0563b079c125b0db5dd0b1060d1c1b47d4a193e1e4',
|
||||
@ -612,68 +640,19 @@ const isValid3 = bls.verifyBatch(aggSignature3, messages, publicKeys);
|
||||
console.log({ publicKeys, signatures3, aggSignature3, isValid3 });
|
||||
|
||||
// Pairings, with and without final exponentiation
|
||||
// bls.pairing(PointG1, PointG2);
|
||||
// bls.pairing(PointG1, PointG2, false);
|
||||
// bls.fields.Fp12.finalExponentiate(bls.fields.Fp12.mul(eGS, ePHm));
|
||||
bls.pairing(PointG1, PointG2);
|
||||
bls.pairing(PointG1, PointG2, false);
|
||||
bls.fields.Fp12.finalExponentiate(bls.fields.Fp12.mul(PointG1, PointG2));
|
||||
|
||||
// Others
|
||||
// bls.G1.ProjectivePoint.BASE, bls.G2.ProjectivePoint.BASE
|
||||
// bls.fields.Fp, bls.fields.Fp2, bls.fields.Fp12, bls.fields.Fr
|
||||
bls.G1.ProjectivePoint.BASE, bls.G2.ProjectivePoint.BASE
|
||||
bls.fields.Fp, bls.fields.Fp2, bls.fields.Fp12, bls.fields.Fr
|
||||
bls.params.x, bls.params.r, bls.params.G1b, bls.params.G2b
|
||||
|
||||
// hash-to-curve examples can be seen below
|
||||
```
|
||||
|
||||
Full types:
|
||||
|
||||
```ts
|
||||
getPublicKey: (privateKey: PrivKey) => Uint8Array;
|
||||
sign: {
|
||||
(message: Hex, privateKey: PrivKey): Uint8Array;
|
||||
(message: ProjPointType<Fp2>, privateKey: PrivKey): ProjPointType<Fp2>;
|
||||
};
|
||||
verify: (
|
||||
signature: Hex | ProjPointType<Fp2>,
|
||||
message: Hex | ProjPointType<Fp2>,
|
||||
publicKey: Hex | ProjPointType<Fp>
|
||||
) => boolean;
|
||||
verifyBatch: (
|
||||
signature: Hex | ProjPointType<Fp2>,
|
||||
messages: (Hex | ProjPointType<Fp2>)[],
|
||||
publicKeys: (Hex | ProjPointType<Fp>)[]
|
||||
) => boolean;
|
||||
aggregatePublicKeys: {
|
||||
(publicKeys: Hex[]): Uint8Array;
|
||||
(publicKeys: ProjPointType<Fp>[]): ProjPointType<Fp>;
|
||||
};
|
||||
aggregateSignatures: {
|
||||
(signatures: Hex[]): Uint8Array;
|
||||
(signatures: ProjPointType<Fp2>[]): ProjPointType<Fp2>;
|
||||
};
|
||||
millerLoop: (ell: [Fp2, Fp2, Fp2][], g1: [Fp, Fp]) => Fp12;
|
||||
pairing: (P: ProjPointType<Fp>, Q: ProjPointType<Fp2>, withFinalExponent?: boolean) => Fp12;
|
||||
G1: CurvePointsRes<Fp> & ReturnType<typeof htf.createHasher<Fp>>;
|
||||
G2: CurvePointsRes<Fp2> & ReturnType<typeof htf.createHasher<Fp2>>;
|
||||
Signature: SignatureCoder<Fp2>;
|
||||
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: {
|
||||
randomPrivateKey: () => Uint8Array;
|
||||
calcPairingPrecomputes: (p: AffinePoint<Fp2>) => [Fp2, Fp2, Fp2][];
|
||||
};
|
||||
```
|
||||
|
||||
### abstract/hash-to-curve: Hashing strings to curve points
|
||||
### hash-to-curve: Hashing strings to curve points
|
||||
|
||||
The module allows to hash arbitrary strings to elliptic curve points. Implements [RFC 9380](https://www.rfc-editor.org/rfc/rfc9380).
|
||||
|
||||
@ -731,7 +710,7 @@ type Opts = {
|
||||
};
|
||||
```
|
||||
|
||||
### abstract/poseidon: Poseidon hash
|
||||
### poseidon: Poseidon hash
|
||||
|
||||
Implements [Poseidon](https://www.poseidon-hash.info) ZK-friendly hash.
|
||||
|
||||
@ -755,7 +734,7 @@ type PoseidonOpts = {
|
||||
const instance = poseidon(opts: PoseidonOpts);
|
||||
```
|
||||
|
||||
### abstract/modular: Modular arithmetics utilities
|
||||
### modular: Modular arithmetics utilities
|
||||
|
||||
```ts
|
||||
import * as mod from '@noble/curves/abstract/modular';
|
||||
@ -792,19 +771,20 @@ and [RFC 9380](https://www.rfc-editor.org/rfc/rfc9380#section-5.2).
|
||||
This means, for 32-byte key, we would need 48-byte hash to get 2^-128 bias, which matches curve security level.
|
||||
|
||||
`hashToPrivateScalar()` that hashes to **private key** was created for this purpose.
|
||||
Use [abstract/hash-to-curve](#abstracthash-to-curve-hashing-strings-to-curve-points)
|
||||
Use [abstract/hash-to-curve](#hash-to-curve-hashing-strings-to-curve-points)
|
||||
if you need to hash to **public key**.
|
||||
|
||||
```ts
|
||||
import { p256 } from '@noble/curves/p256';
|
||||
import { sha256 } from '@noble/hashes/sha256';
|
||||
import { hkdf } from '@noble/hashes/hkdf';
|
||||
import * as mod from '@noble/curves/abstract/modular';
|
||||
const someKey = new Uint8Array(32).fill(2); // Needs to actually be random, not .fill(2)
|
||||
const derived = hkdf(sha256, someKey, undefined, 'application', 48); // 48 bytes for 32-byte priv
|
||||
const validPrivateKey = mod.hashToPrivateScalar(derived, p256.CURVE.n);
|
||||
```
|
||||
|
||||
### abstract/utils: Useful utilities
|
||||
### utils: Useful utilities
|
||||
|
||||
```ts
|
||||
import * as utils from '@noble/curves/abstract/utils';
|
||||
@ -826,43 +806,61 @@ utils.equalBytes(Uint8Array.from([0xde]), Uint8Array.from([0xde]));
|
||||
|
||||
## Security
|
||||
|
||||
1. The library has been independently audited:
|
||||
The library has been independently audited:
|
||||
|
||||
- in Feb 2023 by [Trail of Bits](https://www.trailofbits.com):
|
||||
[PDF](https://github.com/trailofbits/publications/blob/master/reviews/2023-01-ryanshea-noblecurveslibrary-securityreview.pdf).
|
||||
The audit has been funded by [Ryan Shea](https://www.shea.io).
|
||||
Audit scope was abstract modules `curve`, `hash-to-curve`, `modular`, `poseidon`, `utils`, `weierstrass`,
|
||||
and top-level modules `_shortw_utils` and `secp256k1`.
|
||||
See [changes since v0.7.3 audit](https://github.com/paulmillr/noble-curves/compare/0.7.3..main).
|
||||
- at version 1.2.0, in Sep 2023, by [Kudelski Security](https://kudelskisecurity.com)
|
||||
- PDFs: [offline](./audit/2023-09-kudelski-audit-starknet.pdf)
|
||||
- [Changes since audit](https://github.com/paulmillr/noble-curves/compare/1.2.0..main)
|
||||
- Scope: [scure-starknet](https://github.com/paulmillr/scure-starknet) and its related
|
||||
abstract modules of noble-curves: `curve`, `modular`, `poseidon`, `weierstrass`
|
||||
- The audit has been funded by [Starkware](https://starkware.co)
|
||||
- at version 0.7.3, in Feb 2023, by [Trail of Bits](https://www.trailofbits.com)
|
||||
- PDFs: [online](https://github.com/trailofbits/publications/blob/master/reviews/2023-01-ryanshea-noblecurveslibrary-securityreview.pdf),
|
||||
[offline](./audit/2023-01-trailofbits-audit-curves.pdf)
|
||||
- [Changes since audit](https://github.com/paulmillr/noble-curves/compare/0.7.3..main)
|
||||
- Scope: abstract modules `curve`, `hash-to-curve`, `modular`, `poseidon`, `utils`, `weierstrass` and
|
||||
top-level modules `_shortw_utils` and `secp256k1`
|
||||
- The audit has been funded by [Ryan Shea](https://www.shea.io)
|
||||
|
||||
It is tested against property-based, cross-library and Wycheproof vectors,
|
||||
and has fuzzing by [Guido Vranken's cryptofuzz](https://github.com/guidovranken/cryptofuzz).
|
||||
|
||||
If you see anything unusual: investigate and report.
|
||||
|
||||
### Constant-timeness
|
||||
|
||||
2. The library has been fuzzed by [Guido Vranken's cryptofuzz](https://github.com/guidovranken/cryptofuzz).
|
||||
You can run the fuzzer by yourself to check it.
|
||||
3. [Timing attack](https://en.wikipedia.org/wiki/Timing_attack) considerations:
|
||||
_JIT-compiler_ and _Garbage Collector_ make "constant time" extremely hard to
|
||||
achieve in a scripting language. Which means _any other JS library can't have
|
||||
achieve [timing attack](https://en.wikipedia.org/wiki/Timing_attack) resistance
|
||||
in a scripting language. Which means _any other JS library can't have
|
||||
constant-timeness_. Even statically typed Rust, a language without GC,
|
||||
[makes it harder to achieve constant-time](https://www.chosenplaintext.ca/open-source/rust-timing-shield/security)
|
||||
for some cases. If your goal is absolute security, don't use any JS lib — including bindings to native ones.
|
||||
Use low-level libraries & languages. Nonetheless we're targetting algorithmic constant time.
|
||||
|
||||
We consider infrastructure attacks like rogue NPM modules very important;
|
||||
that's why it's crucial to minimize the amount of 3rd-party dependencies & native bindings.
|
||||
If your app uses 500 dependencies, any dep could get hacked and you'll be
|
||||
downloading malware with every `npm install`. Our goal is to minimize this attack vector.
|
||||
As for devDependencies used by the library:
|
||||
### Supply chain security
|
||||
|
||||
- `@scure` base, bip32, bip39 (used in tests), micro-bmark (benchmark), micro-should (testing)
|
||||
are developed by us and follow the same practices such as: minimal library size, auditability,
|
||||
signed releases
|
||||
- prettier (linter), fast-check (property-based testing), typescript versions
|
||||
are locked and rarely updated. Every update is checked with `npm-diff`.
|
||||
The packages are big, which makes it hard to audit their source code thoroughly and fully.
|
||||
- They are only used if you clone the git repo and want to add some feature to it. End-users won't use them.
|
||||
* **Commits** are signed with PGP keys, to prevent forgery. Make sure to verify commit signatures.
|
||||
* **Releases** are transparent and built on GitHub CI. Make sure to verify [provenance](https://docs.npmjs.com/generating-provenance-statements) logs
|
||||
* **Rare releasing** is followed to ensure less re-audit need for end-users
|
||||
* **Dependencies** are minimized and locked-down:
|
||||
- If your app has 500 dependencies, any dep could get hacked and you'll be downloading
|
||||
malware with every install. We make sure to use as few dependencies as possible
|
||||
- We prevent automatic dependency updates by locking-down version ranges. Every update is checked with `npm-diff`
|
||||
- One dependency [noble-hashes](https://github.com/paulmillr/noble-hashes) is used, by the same author, to provide hashing functionality
|
||||
* **Dev Dependencies** are only used if you want to contribute to the repo. They are disabled for end-users:
|
||||
- scure-base, scure-bip32, scure-bip39, micro-bmark and micro-should are developed by the same author and follow identical security practices
|
||||
- prettier (linter), fast-check (property-based testing) and typescript are used for code quality, vector generation and ts compilation. The packages are big, which makes it hard to audit their source code thoroughly and fully
|
||||
|
||||
As for key generation, we're deferring to built-in
|
||||
### Randomness
|
||||
|
||||
We're deferring to built-in
|
||||
[crypto.getRandomValues](https://developer.mozilla.org/en-US/docs/Web/API/Crypto/getRandomValues)
|
||||
which is considered cryptographically secure (CSPRNG).
|
||||
|
||||
In the past, browsers had bugs that made it weak: it may happen again.
|
||||
Implementing a userspace CSPRNG to get resilient to the weakness
|
||||
is even worse: there is no reliable userspace source of quality entropy.
|
||||
|
||||
## Speed
|
||||
|
||||
Benchmark results on Apple M2 with node v20:
|
||||
@ -944,13 +942,6 @@ ed25519 x 3,088 ops/sec @ 323μs/op
|
||||
ed448 x 1,247 ops/sec @ 801μs/op
|
||||
```
|
||||
|
||||
## Contributing & testing
|
||||
|
||||
1. Clone the repository
|
||||
2. `npm install` to install build dependencies like TypeScript
|
||||
3. `npm run build` to compile TypeScript code
|
||||
4. `npm run test` will execute all main tests
|
||||
|
||||
## Upgrading
|
||||
|
||||
Previously, the library was split into single-feature packages
|
||||
@ -971,7 +962,7 @@ Upgrading from noble-secp256k1 1.7:
|
||||
- to use old behavior, which produced 65-byte uncompressed keys, set
|
||||
argument `isCompressed` to `false`: `getPublicKey(priv, false)`
|
||||
- `sign`
|
||||
- is now sync; use `signAsync` for async version
|
||||
- is now sync
|
||||
- now returns `Signature` instance with `{ r, s, recovery }` properties
|
||||
- `canonical` option was renamed to `lowS`
|
||||
- `recovered` option has been removed because recovery bit is always returned now
|
||||
@ -980,6 +971,7 @@ Upgrading from noble-secp256k1 1.7:
|
||||
Compact encoding is simply a concatenation of 32-byte r and 32-byte s.
|
||||
2. If you must use DER encoding, switch to noble-curves (see above).
|
||||
- `verify`
|
||||
- is now sync
|
||||
- `strict` option was renamed to `lowS`
|
||||
- `getSharedSecret`
|
||||
- now produce 33-byte compressed signatures by default
|
||||
@ -1009,61 +1001,18 @@ Upgrading from [@noble/bls12-381](https://github.com/paulmillr/noble-bls12-381):
|
||||
- PointG2.fromSignature -> Signature.decode, PointG2.toSignature -> Signature.encode
|
||||
- Fp2 ORDER was corrected
|
||||
|
||||
## Contributing & testing
|
||||
|
||||
1. Clone the repository
|
||||
2. `npm install` to install build dependencies like TypeScript
|
||||
3. `npm run build` to compile TypeScript code
|
||||
4. `npm run test` will execute all main tests
|
||||
|
||||
## Resources
|
||||
|
||||
- [Learning fast elliptic-curve cryptography](https://paulmillr.com/posts/noble-secp256k1-fast-ecc/)
|
||||
- EdDSA
|
||||
- [A Deep dive into Ed25519 Signatures](https://cendyne.dev/posts/2022-03-06-ed25519-signatures.html)
|
||||
- [Ed25519 Deep Dive Addendum](https://cendyne.dev/posts/2022-09-11-ed25519-deep-dive-addendum.html)
|
||||
- [It’s 255:19AM. Do you know what your validation criteria are?](https://hdevalence.ca/blog/2020-10-04-its-25519am)
|
||||
- [Taming the many EdDSAs](https://csrc.nist.gov/csrc/media/Presentations/2023/crclub-2023-03-08/images-media/20230308-crypto-club-slides--taming-the-many-EdDSAs.pdf)
|
||||
that describes concepts of Strong UnForgeability under Chosen Message Attacks and Strongly Binding Signatures
|
||||
- [Cofactor Explained: Clearing Elliptic Curves’ dirty little secret](https://loup-vaillant.fr/tutorials/cofactor)
|
||||
- [Surrounded by Elligators](https://loup-vaillant.fr/articles/implementing-elligator)
|
||||
- Pairings and BLS
|
||||
- [BLS signatures for busy people](https://gist.github.com/paulmillr/18b802ad219b1aee34d773d08ec26ca2)
|
||||
- [BLS12-381 for the rest of us](https://hackmd.io/@benjaminion/bls12-381)
|
||||
- [Key concepts of pairings](https://medium.com/@alonmuroch_65570/bls-signatures-part-2-key-concepts-of-pairings-27a8a9533d0c)
|
||||
- Pairing over bls12-381:
|
||||
[fields](https://research.nccgroup.com/2020/07/06/pairing-over-bls12-381-part-1-fields/),
|
||||
[curves](https://research.nccgroup.com/2020/07/13/pairing-over-bls12-381-part-2-curves/),
|
||||
[pairings](https://research.nccgroup.com/2020/08/13/pairing-over-bls12-381-part-3-pairing/)
|
||||
- [Estimating the bit security of pairing-friendly curves](https://research.nccgroup.com/2022/02/03/estimating-the-bit-security-of-pairing-friendly-curves/)
|
||||
|
||||
### Demos
|
||||
|
||||
- [Elliptic Curve Calculator](https://paulmillr.com/noble): add / multiply points, sign messages
|
||||
- [BLS threshold signatures](https://genthresh.com)
|
||||
|
||||
### Projects using curves
|
||||
|
||||
- HDkey libraries: [scure-bip32](https://github.com/paulmillr/scure-bip32), [bip32](https://github.com/bitcoinjs/bip32)
|
||||
- Social networks: [nostr](https://github.com/nbd-wtf/nostr-tools), [bluesky](https://github.com/bluesky-social/atproto)
|
||||
- Ethereum libraries:
|
||||
- [ethereum-cryptography](https://github.com/ethereum/js-ethereum-cryptography)
|
||||
- [micro-eth-signer](https://github.com/paulmillr/micro-eth-signer),
|
||||
[ethers](https://github.com/ethers-io/ethers.js) (old noble),
|
||||
[viem.sh](https://viem.sh),
|
||||
[@ethereumjs](https://github.com/ethereumjs/ethereumjs-monorepo)
|
||||
- [metamask's eth-sig-util](https://github.com/MetaMask/eth-sig-util)
|
||||
- [gridplus lattice sdk](https://github.com/GridPlus/lattice-eth2-utils)
|
||||
- Bitcoin libraries:
|
||||
- [scure-btc-signer](https://github.com/paulmillr/scure-btc-signer)
|
||||
- [tapscript](https://github.com/cmdruid/tapscript)
|
||||
- Solana libraries: [micro-sol-signer](https://github.com/paulmillr/micro-sol-signer), [solana-web3.js](https://github.com/solana-labs/solana-web3.js)
|
||||
- Other web3 stuff:
|
||||
- [scure-starknet](https://github.com/paulmillr/scure-starknet)
|
||||
- [aztec](https://github.com/AztecProtocol/aztec-packages)
|
||||
- [polkadot.js](https://github.com/polkadot-js/common), [drand-client](https://github.com/drand/drand-client), [moneroj](https://github.com/beritani/moneroj), [tronlib](https://github.com/CoinSpace/tronlib)
|
||||
- [protonmail](https://github.com/ProtonMail/WebClients) (old noble for now)
|
||||
- [did-jwt](https://github.com/decentralized-identity/did-jwt), [hpke-js](https://github.com/dajiaji/hpke-js),
|
||||
[js-libp2p-noise](https://github.com/ChainSafe/js-libp2p-noise)
|
||||
- [ed25519-keygen](https://github.com/paulmillr/ed25519-keygen) SSH, PGP, TOR key generation
|
||||
- [secp256k1 compatibility layer](https://github.com/ethereum/js-ethereum-cryptography/blob/2.0.0/src/secp256k1-compat.ts)
|
||||
for users who want to switch from secp256k1-node or tiny-secp256k1. Allows to see which methods map to corresponding noble code.
|
||||
- [BLS BBS signatures](https://github.com/Wind4Greg/BBS-Draft-Checks) following [draft-irtf-cfrg-bbs-signatures-latest](https://identity.foundation/bbs-signature/draft-irtf-cfrg-bbs-signatures.html)
|
||||
- [KZG trusted setup ceremony](https://github.com/dsrvlabs/czg-keremony)
|
||||
- See [full list of projects on GitHub](https://github.com/paulmillr/noble-curves/network/dependents).
|
||||
Check out [paulmillr.com/noble](https://paulmillr.com/noble/)
|
||||
for useful resources, articles, documentation and demos
|
||||
related to the library.
|
||||
|
||||
## License
|
||||
|
||||
|
@ -1,5 +1,7 @@
|
||||
# Security Policy
|
||||
|
||||
See [README's Security section](./README.md#security) for detailed description of internal security practices.
|
||||
|
||||
## Supported Versions
|
||||
|
||||
| Version | Supported |
|
||||
|
BIN
audit/2023-09-kudelski-audit-starknet.pdf
Normal file
BIN
audit/2023-09-kudelski-audit-starknet.pdf
Normal file
Binary file not shown.
@ -1,11 +1,7 @@
|
||||
# Audit
|
||||
|
||||
The library has been audited during Jan-Feb 2023 by an independent security firm [Trail of Bits](https://www.trailofbits.com):
|
||||
[PDF](https://github.com/trailofbits/publications/blob/master/reviews/2023-01-ryanshea-noblecurveslibrary-securityreview.pdf).
|
||||
The audit has been funded by Ryan Shea. Audit scope was abstract modules `curve`, `hash-to-curve`, `modular`, `poseidon`, `utils`, `weierstrass`, and top-level modules `_shortw_utils` and `secp256k1`. See [changes since audit](https://github.com/paulmillr/noble-curves/compare/0.7.3..main).
|
||||
All audits of the library are described in [README's Security section](../README.md#security)
|
||||
|
||||
File in the directory was saved from
|
||||
`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.
|
||||
|
||||
See information about fuzzing in root [README](../README.md).
|
||||
|
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));
|
||||
});
|
@ -1,7 +1,7 @@
|
||||
# build
|
||||
|
||||
The directory is used to build a single file `noble-curves.js` which contains everything.
|
||||
The directory is used to build a single file which contains everything.
|
||||
|
||||
The output file uses iife wrapper and can be used in browsers as-is.
|
||||
The single file uses iife wrapper and can be used in browsers as-is.
|
||||
|
||||
Don't use it unless you can't use NPM/ESM, which support tree shaking.
|
||||
|
@ -1,11 +1,20 @@
|
||||
import { bytesToHex, concatBytes, hexToBytes } from '@noble/curves/abstract/utils';
|
||||
import { bytesToHex, concatBytes, hexToBytes, utf8ToBytes } from '@noble/curves/abstract/utils';
|
||||
|
||||
export { secp256k1 } from '@noble/curves/secp256k1';
|
||||
export { ed25519, x25519 } from '@noble/curves/ed25519';
|
||||
export { ed448, x448 } from '@noble/curves/ed448';
|
||||
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 };
|
||||
export const utils = { bytesToHex, concatBytes, hexToBytes, utf8ToBytes };
|
||||
|
445
build/package-lock.json
generated
Normal file
445
build/package-lock.json
generated
Normal file
@ -0,0 +1,445 @@
|
||||
{
|
||||
"name": "build",
|
||||
"version": "1.0.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "build",
|
||||
"version": "1.0.0",
|
||||
"devDependencies": {
|
||||
"@noble/curves": "file:..",
|
||||
"esbuild": "0.20.1"
|
||||
}
|
||||
},
|
||||
"..": {
|
||||
"version": "1.4.0",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@noble/hashes": "1.4.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@paulmillr/jsbt": "0.1.0",
|
||||
"fast-check": "3.0.0",
|
||||
"micro-bmark": "0.3.1",
|
||||
"micro-should": "0.4.0",
|
||||
"prettier": "3.1.1",
|
||||
"typescript": "5.3.2"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://paulmillr.com/funding/"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/aix-ppc64": {
|
||||
"version": "0.20.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.20.1.tgz",
|
||||
"integrity": "sha512-m55cpeupQ2DbuRGQMMZDzbv9J9PgVelPjlcmM5kxHnrBdBx6REaEd7LamYV7Dm8N7rCyR/XwU6rVP8ploKtIkA==",
|
||||
"cpu": [
|
||||
"ppc64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"aix"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/android-arm": {
|
||||
"version": "0.20.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.20.1.tgz",
|
||||
"integrity": "sha512-4j0+G27/2ZXGWR5okcJi7pQYhmkVgb4D7UKwxcqrjhvp5TKWx3cUjgB1CGj1mfdmJBQ9VnUGgUhign+FPF2Zgw==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"android"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/android-arm64": {
|
||||
"version": "0.20.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.20.1.tgz",
|
||||
"integrity": "sha512-hCnXNF0HM6AjowP+Zou0ZJMWWa1VkD77BXe959zERgGJBBxB+sV+J9f/rcjeg2c5bsukD/n17RKWXGFCO5dD5A==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"android"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/android-x64": {
|
||||
"version": "0.20.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.20.1.tgz",
|
||||
"integrity": "sha512-MSfZMBoAsnhpS+2yMFYIQUPs8Z19ajwfuaSZx+tSl09xrHZCjbeXXMsUF/0oq7ojxYEpsSo4c0SfjxOYXRbpaA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"android"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/darwin-arm64": {
|
||||
"version": "0.20.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.20.1.tgz",
|
||||
"integrity": "sha512-Ylk6rzgMD8klUklGPzS414UQLa5NPXZD5tf8JmQU8GQrj6BrFA/Ic9tb2zRe1kOZyCbGl+e8VMbDRazCEBqPvA==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/darwin-x64": {
|
||||
"version": "0.20.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.20.1.tgz",
|
||||
"integrity": "sha512-pFIfj7U2w5sMp52wTY1XVOdoxw+GDwy9FsK3OFz4BpMAjvZVs0dT1VXs8aQm22nhwoIWUmIRaE+4xow8xfIDZA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/freebsd-arm64": {
|
||||
"version": "0.20.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.20.1.tgz",
|
||||
"integrity": "sha512-UyW1WZvHDuM4xDz0jWun4qtQFauNdXjXOtIy7SYdf7pbxSWWVlqhnR/T2TpX6LX5NI62spt0a3ldIIEkPM6RHw==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"freebsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/freebsd-x64": {
|
||||
"version": "0.20.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.20.1.tgz",
|
||||
"integrity": "sha512-itPwCw5C+Jh/c624vcDd9kRCCZVpzpQn8dtwoYIt2TJF3S9xJLiRohnnNrKwREvcZYx0n8sCSbvGH349XkcQeg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"freebsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-arm": {
|
||||
"version": "0.20.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.20.1.tgz",
|
||||
"integrity": "sha512-LojC28v3+IhIbfQ+Vu4Ut5n3wKcgTu6POKIHN9Wpt0HnfgUGlBuyDDQR4jWZUZFyYLiz4RBBBmfU6sNfn6RhLw==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-arm64": {
|
||||
"version": "0.20.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.20.1.tgz",
|
||||
"integrity": "sha512-cX8WdlF6Cnvw/DO9/X7XLH2J6CkBnz7Twjpk56cshk9sjYVcuh4sXQBy5bmTwzBjNVZze2yaV1vtcJS04LbN8w==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-ia32": {
|
||||
"version": "0.20.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.20.1.tgz",
|
||||
"integrity": "sha512-4H/sQCy1mnnGkUt/xszaLlYJVTz3W9ep52xEefGtd6yXDQbz/5fZE5dFLUgsPdbUOQANcVUa5iO6g3nyy5BJiw==",
|
||||
"cpu": [
|
||||
"ia32"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-loong64": {
|
||||
"version": "0.20.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.20.1.tgz",
|
||||
"integrity": "sha512-c0jgtB+sRHCciVXlyjDcWb2FUuzlGVRwGXgI+3WqKOIuoo8AmZAddzeOHeYLtD+dmtHw3B4Xo9wAUdjlfW5yYA==",
|
||||
"cpu": [
|
||||
"loong64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-mips64el": {
|
||||
"version": "0.20.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.20.1.tgz",
|
||||
"integrity": "sha512-TgFyCfIxSujyuqdZKDZ3yTwWiGv+KnlOeXXitCQ+trDODJ+ZtGOzLkSWngynP0HZnTsDyBbPy7GWVXWaEl6lhA==",
|
||||
"cpu": [
|
||||
"mips64el"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-ppc64": {
|
||||
"version": "0.20.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.20.1.tgz",
|
||||
"integrity": "sha512-b+yuD1IUeL+Y93PmFZDZFIElwbmFfIKLKlYI8M6tRyzE6u7oEP7onGk0vZRh8wfVGC2dZoy0EqX1V8qok4qHaw==",
|
||||
"cpu": [
|
||||
"ppc64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-riscv64": {
|
||||
"version": "0.20.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.20.1.tgz",
|
||||
"integrity": "sha512-wpDlpE0oRKZwX+GfomcALcouqjjV8MIX8DyTrxfyCfXxoKQSDm45CZr9fanJ4F6ckD4yDEPT98SrjvLwIqUCgg==",
|
||||
"cpu": [
|
||||
"riscv64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-s390x": {
|
||||
"version": "0.20.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.20.1.tgz",
|
||||
"integrity": "sha512-5BepC2Au80EohQ2dBpyTquqGCES7++p7G+7lXe1bAIvMdXm4YYcEfZtQrP4gaoZ96Wv1Ute61CEHFU7h4FMueQ==",
|
||||
"cpu": [
|
||||
"s390x"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-x64": {
|
||||
"version": "0.20.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.20.1.tgz",
|
||||
"integrity": "sha512-5gRPk7pKuaIB+tmH+yKd2aQTRpqlf1E4f/mC+tawIm/CGJemZcHZpp2ic8oD83nKgUPMEd0fNanrnFljiruuyA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/netbsd-x64": {
|
||||
"version": "0.20.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.20.1.tgz",
|
||||
"integrity": "sha512-4fL68JdrLV2nVW2AaWZBv3XEm3Ae3NZn/7qy2KGAt3dexAgSVT+Hc97JKSZnqezgMlv9x6KV0ZkZY7UO5cNLCg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"netbsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/openbsd-x64": {
|
||||
"version": "0.20.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.20.1.tgz",
|
||||
"integrity": "sha512-GhRuXlvRE+twf2ES+8REbeCb/zeikNqwD3+6S5y5/x+DYbAQUNl0HNBs4RQJqrechS4v4MruEr8ZtAin/hK5iw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"openbsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/sunos-x64": {
|
||||
"version": "0.20.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.20.1.tgz",
|
||||
"integrity": "sha512-ZnWEyCM0G1Ex6JtsygvC3KUUrlDXqOihw8RicRuQAzw+c4f1D66YlPNNV3rkjVW90zXVsHwZYWbJh3v+oQFM9Q==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"sunos"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/win32-arm64": {
|
||||
"version": "0.20.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.20.1.tgz",
|
||||
"integrity": "sha512-QZ6gXue0vVQY2Oon9WyLFCdSuYbXSoxaZrPuJ4c20j6ICedfsDilNPYfHLlMH7vGfU5DQR0czHLmJvH4Nzis/A==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/win32-ia32": {
|
||||
"version": "0.20.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.20.1.tgz",
|
||||
"integrity": "sha512-HzcJa1NcSWTAU0MJIxOho8JftNp9YALui3o+Ny7hCh0v5f90nprly1U3Sj1Ldj/CvKKdvvFsCRvDkpsEMp4DNw==",
|
||||
"cpu": [
|
||||
"ia32"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/win32-x64": {
|
||||
"version": "0.20.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.20.1.tgz",
|
||||
"integrity": "sha512-0MBh53o6XtI6ctDnRMeQ+xoCN8kD2qI1rY1KgF/xdWQwoFeKou7puvDfV8/Wv4Ctx2rRpET/gGdz3YlNtNACSA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@noble/curves": {
|
||||
"resolved": "..",
|
||||
"link": true
|
||||
},
|
||||
"node_modules/esbuild": {
|
||||
"version": "0.20.1",
|
||||
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.20.1.tgz",
|
||||
"integrity": "sha512-OJwEgrpWm/PCMsLVWXKqvcjme3bHNpOgN7Tb6cQnR5n0TPbQx1/Xrn7rqM+wn17bYeT6MGB5sn1Bh5YiGi70nA==",
|
||||
"dev": true,
|
||||
"hasInstallScript": true,
|
||||
"bin": {
|
||||
"esbuild": "bin/esbuild"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@esbuild/aix-ppc64": "0.20.1",
|
||||
"@esbuild/android-arm": "0.20.1",
|
||||
"@esbuild/android-arm64": "0.20.1",
|
||||
"@esbuild/android-x64": "0.20.1",
|
||||
"@esbuild/darwin-arm64": "0.20.1",
|
||||
"@esbuild/darwin-x64": "0.20.1",
|
||||
"@esbuild/freebsd-arm64": "0.20.1",
|
||||
"@esbuild/freebsd-x64": "0.20.1",
|
||||
"@esbuild/linux-arm": "0.20.1",
|
||||
"@esbuild/linux-arm64": "0.20.1",
|
||||
"@esbuild/linux-ia32": "0.20.1",
|
||||
"@esbuild/linux-loong64": "0.20.1",
|
||||
"@esbuild/linux-mips64el": "0.20.1",
|
||||
"@esbuild/linux-ppc64": "0.20.1",
|
||||
"@esbuild/linux-riscv64": "0.20.1",
|
||||
"@esbuild/linux-s390x": "0.20.1",
|
||||
"@esbuild/linux-x64": "0.20.1",
|
||||
"@esbuild/netbsd-x64": "0.20.1",
|
||||
"@esbuild/openbsd-x64": "0.20.1",
|
||||
"@esbuild/sunos-x64": "0.20.1",
|
||||
"@esbuild/win32-arm64": "0.20.1",
|
||||
"@esbuild/win32-ia32": "0.20.1",
|
||||
"@esbuild/win32-x64": "0.20.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -2,17 +2,13 @@
|
||||
"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"
|
||||
"@noble/curves": "file:..",
|
||||
"esbuild": "0.20.1"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "npx esbuild --bundle input.js --outfile=noble-curves.js --global-name=nobleCurves"
|
||||
"build:release": "npx esbuild --bundle input.js --outfile=`npx jsbt outfile` --global-name=`npx jsbt global`"
|
||||
}
|
||||
}
|
||||
|
48
package-lock.json
generated
48
package-lock.json
generated
@ -1,31 +1,32 @@
|
||||
{
|
||||
"name": "@noble/curves",
|
||||
"version": "1.2.0",
|
||||
"name": "@tornado/noble-curves",
|
||||
"version": "1.4.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@noble/curves",
|
||||
"version": "1.2.0",
|
||||
"name": "@tornado/noble-curves",
|
||||
"version": "1.4.0",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@noble/hashes": "1.3.2"
|
||||
"@noble/hashes": "1.4.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@paulmillr/jsbt": "0.1.0",
|
||||
"fast-check": "3.0.0",
|
||||
"micro-bmark": "0.3.1",
|
||||
"micro-should": "0.4.0",
|
||||
"prettier": "2.8.4",
|
||||
"typescript": "5.0.2"
|
||||
"prettier": "3.1.1",
|
||||
"typescript": "5.3.2"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://paulmillr.com/funding/"
|
||||
}
|
||||
},
|
||||
"node_modules/@noble/hashes": {
|
||||
"version": "1.3.2",
|
||||
"resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.2.tgz",
|
||||
"integrity": "sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ==",
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.4.0.tgz",
|
||||
"integrity": "sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==",
|
||||
"engines": {
|
||||
"node": ">= 16"
|
||||
},
|
||||
@ -33,6 +34,15 @@
|
||||
"url": "https://paulmillr.com/funding/"
|
||||
}
|
||||
},
|
||||
"node_modules/@paulmillr/jsbt": {
|
||||
"version": "0.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@paulmillr/jsbt/-/jsbt-0.1.0.tgz",
|
||||
"integrity": "sha512-TdowoHD36hkZARv6LW4jenkVTdK2vP0sy4ZM8E9MxaqAAIRdwmn3RlB+zWkEHi4hKTgLqMGkURfNkFtt0STX2Q==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"jsbt": "jsbt.js"
|
||||
}
|
||||
},
|
||||
"node_modules/fast-check": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/fast-check/-/fast-check-3.0.0.tgz",
|
||||
@ -62,15 +72,15 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/prettier": {
|
||||
"version": "2.8.4",
|
||||
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.4.tgz",
|
||||
"integrity": "sha512-vIS4Rlc2FNh0BySk3Wkd6xmwxB0FpOndW5fisM5H8hsZSxU2VWVB5CWIkIjWvrHjIhxk2g3bfMKM87zNTrZddw==",
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.1.1.tgz",
|
||||
"integrity": "sha512-22UbSzg8luF4UuZtzgiUOfcGM8s4tjBv6dJRT7j275NXsy2jb4aJa4NNveul5x4eqlF1wuhuR2RElK71RvmVaw==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"prettier": "bin-prettier.js"
|
||||
"prettier": "bin/prettier.cjs"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.13.0"
|
||||
"node": ">=14"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/prettier/prettier?sponsor=1"
|
||||
@ -93,16 +103,16 @@
|
||||
]
|
||||
},
|
||||
"node_modules/typescript": {
|
||||
"version": "5.0.2",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.0.2.tgz",
|
||||
"integrity": "sha512-wVORMBGO/FAs/++blGNeAVdbNKtIh1rbBL2EyQ1+J9lClJ93KiiKe8PmFIVdXhHcyv44SL9oglmfeSsndo0jRw==",
|
||||
"version": "5.3.2",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.2.tgz",
|
||||
"integrity": "sha512-6l+RyNy7oAHDfxC4FzSJcz9vnjTKxrLpDG5M2Vu4SHRVNg6xzqZp6LYSR9zjqQTu8DU/f5xwxUdADOkbrIX2gQ==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"tsc": "bin/tsc",
|
||||
"tsserver": "bin/tsserver"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12.20"
|
||||
"node": ">=14.17"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
15
package.json
15
package.json
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@noble/curves",
|
||||
"version": "1.2.0",
|
||||
"name": "@tornado/noble-curves",
|
||||
"version": "1.4.0",
|
||||
"description": "Audited & minimal JS implementation of elliptic curve cryptography",
|
||||
"files": [
|
||||
"abstract",
|
||||
@ -14,7 +14,7 @@
|
||||
"scripts": {
|
||||
"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:release": "rollup -c rollup.config.js",
|
||||
"build:release": "cd build && npm i && 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'",
|
||||
"format": "prettier --write 'src/**/*.{js,ts}' 'test/*.js'",
|
||||
@ -24,18 +24,19 @@
|
||||
"homepage": "https://paulmillr.com/noble/",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/paulmillr/noble-curves.git"
|
||||
"url": "https://git.tornado.ws/tornado-packages/noble-curvest"
|
||||
},
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@noble/hashes": "1.3.2"
|
||||
"@noble/hashes": "1.4.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@paulmillr/jsbt": "0.1.0",
|
||||
"fast-check": "3.0.0",
|
||||
"micro-bmark": "0.3.1",
|
||||
"micro-should": "0.4.0",
|
||||
"prettier": "2.8.4",
|
||||
"typescript": "5.0.2"
|
||||
"prettier": "3.1.1",
|
||||
"typescript": "5.3.2"
|
||||
},
|
||||
"sideEffects": false,
|
||||
"main": "index.js",
|
||||
|
@ -14,7 +14,11 @@
|
||||
import { AffinePoint } from './curve.js';
|
||||
import { IField, getMinHashLength, mapHashToField } from './modular.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 {
|
||||
CurvePointsType,
|
||||
ProjPointType as ProjPointType,
|
||||
@ -27,6 +31,12 @@ 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> = {
|
||||
fromHex(hex: Hex): ProjPointType<Fp2>;
|
||||
toRawBytes(point: ProjPointType<Fp2>): Uint8Array;
|
||||
@ -35,13 +45,14 @@ export type SignatureCoder<Fp2> = {
|
||||
|
||||
export type CurveType<Fp, Fp2, Fp6, Fp12> = {
|
||||
G1: Omit<CurvePointsType<Fp>, 'n'> & {
|
||||
mapToCurve: htf.MapToCurve<Fp>;
|
||||
htfDefaults: htf.Opts;
|
||||
ShortSignature: SignatureCoder<Fp>;
|
||||
mapToCurve: MapToCurve<Fp>;
|
||||
htfDefaults: HTFOpts;
|
||||
};
|
||||
G2: Omit<CurvePointsType<Fp2>, 'n'> & {
|
||||
Signature: SignatureCoder<Fp2>;
|
||||
mapToCurve: htf.MapToCurve<Fp2>;
|
||||
htfDefaults: htf.Opts;
|
||||
mapToCurve: MapToCurve<Fp2>;
|
||||
htfDefaults: HTFOpts;
|
||||
};
|
||||
fields: {
|
||||
Fp: IField<Fp>;
|
||||
@ -63,26 +74,39 @@ export type CurveType<Fp, Fp2, Fp6, Fp12> = {
|
||||
x: bigint;
|
||||
r: bigint;
|
||||
};
|
||||
htfDefaults: htf.Opts;
|
||||
htfDefaults: HTFOpts;
|
||||
hash: CHash; // Because we need outputLen for DRBG
|
||||
randomBytes: (bytesLength?: number) => Uint8Array;
|
||||
};
|
||||
|
||||
export type CurveFn<Fp, Fp2, Fp6, Fp12> = {
|
||||
getPublicKey: (privateKey: PrivKey) => Uint8Array;
|
||||
getPublicKeyForShortSignatures: (privateKey: PrivKey) => Uint8Array;
|
||||
sign: {
|
||||
(message: Hex, privateKey: PrivKey): Uint8Array;
|
||||
(message: ProjPointType<Fp2>, privateKey: PrivKey): ProjPointType<Fp2>;
|
||||
(message: Hex, privateKey: PrivKey, htfOpts?: htfBasicOpts): Uint8Array;
|
||||
(message: ProjPointType<Fp2>, privateKey: PrivKey, htfOpts?: htfBasicOpts): ProjPointType<Fp2>;
|
||||
};
|
||||
signShortSignature: {
|
||||
(message: Hex, privateKey: PrivKey, htfOpts?: htfBasicOpts): Uint8Array;
|
||||
(message: ProjPointType<Fp>, privateKey: PrivKey, htfOpts?: htfBasicOpts): ProjPointType<Fp>;
|
||||
};
|
||||
verify: (
|
||||
signature: 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>)[]
|
||||
publicKeys: (Hex | ProjPointType<Fp>)[],
|
||||
htfOpts?: htfBasicOpts
|
||||
) => boolean;
|
||||
aggregatePublicKeys: {
|
||||
(publicKeys: Hex[]): Uint8Array;
|
||||
@ -92,11 +116,16 @@ export type CurveFn<Fp, Fp2, Fp6, Fp12> = {
|
||||
(signatures: Hex[]): Uint8Array;
|
||||
(signatures: ProjPointType<Fp2>[]): ProjPointType<Fp2>;
|
||||
};
|
||||
aggregateShortSignatures: {
|
||||
(signatures: Hex[]): Uint8Array;
|
||||
(signatures: ProjPointType<Fp>[]): ProjPointType<Fp>;
|
||||
};
|
||||
millerLoop: (ell: [Fp2, Fp2, Fp2][], g1: [Fp, Fp]) => Fp12;
|
||||
pairing: (P: ProjPointType<Fp>, Q: ProjPointType<Fp2>, withFinalExponent?: boolean) => Fp12;
|
||||
G1: CurvePointsRes<Fp> & ReturnType<typeof htf.createHasher<Fp>>;
|
||||
G2: CurvePointsRes<Fp2> & ReturnType<typeof htf.createHasher<Fp2>>;
|
||||
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;
|
||||
@ -198,7 +227,7 @@ export function bls<Fp2, Fp6, Fp12>(
|
||||
const G1_ = weierstrassPoints({ n: Fr.ORDER, ...CURVE.G1 });
|
||||
const G1 = Object.assign(
|
||||
G1_,
|
||||
htf.createHasher(G1_.ProjectivePoint, CURVE.G1.mapToCurve, {
|
||||
createHasher(G1_.ProjectivePoint, CURVE.G1.mapToCurve, {
|
||||
...CURVE.htfDefaults,
|
||||
...CURVE.G1.htfDefaults,
|
||||
})
|
||||
@ -224,12 +253,13 @@ export function bls<Fp2, Fp6, Fp12>(
|
||||
const G2_ = weierstrassPoints({ n: Fr.ORDER, ...CURVE.G2 });
|
||||
const G2 = Object.assign(
|
||||
G2_,
|
||||
htf.createHasher(G2_.ProjectivePoint as htf.H2CPointConstructor<Fp2>, CURVE.G2.mapToCurve, {
|
||||
createHasher(G2_.ProjectivePoint as H2CPointConstructor<Fp2>, CURVE.G2.mapToCurve, {
|
||||
...CURVE.htfDefaults,
|
||||
...CURVE.G2.htfDefaults,
|
||||
})
|
||||
);
|
||||
|
||||
const { ShortSignature } = CURVE.G1;
|
||||
const { Signature } = CURVE.G2;
|
||||
|
||||
// Calculates bilinear pairing
|
||||
@ -251,26 +281,37 @@ export function bls<Fp2, Fp6, Fp12>(
|
||||
function normP1(point: G1Hex): G1 {
|
||||
return point instanceof G1.ProjectivePoint ? (point as G1) : G1.ProjectivePoint.fromHex(point);
|
||||
}
|
||||
function normP1Hash(point: G1Hex, htfOpts?: htfBasicOpts): G1 {
|
||||
return point instanceof G1.ProjectivePoint
|
||||
? point
|
||||
: (G1.hashToCurve(ensureBytes('point', point), htfOpts) as G1);
|
||||
}
|
||||
function normP2(point: G2Hex): G2 {
|
||||
return point instanceof G2.ProjectivePoint ? point : Signature.fromHex(point);
|
||||
}
|
||||
function normP2Hash(point: G2Hex, htfOpts?: htf.htfBasicOpts): G2 {
|
||||
function normP2Hash(point: G2Hex, htfOpts?: htfBasicOpts): G2 {
|
||||
return point instanceof G2.ProjectivePoint
|
||||
? point
|
||||
: (G2.hashToCurve(ensureBytes('point', point), htfOpts) as G2);
|
||||
}
|
||||
|
||||
// Multiplies generator by private key.
|
||||
// Multiplies generator (G1) by private key.
|
||||
// P = pk x G
|
||||
function getPublicKey(privateKey: PrivKey): Uint8Array {
|
||||
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.
|
||||
// S = pk x H(m)
|
||||
function sign(message: Hex, privateKey: PrivKey, htfOpts?: htf.htfBasicOpts): Uint8Array;
|
||||
function sign(message: G2, privateKey: PrivKey, htfOpts?: htf.htfBasicOpts): G2;
|
||||
function sign(message: G2Hex, privateKey: PrivKey, htfOpts?: htf.htfBasicOpts): Uint8Array | G2 {
|
||||
function sign(message: Hex, privateKey: PrivKey, htfOpts?: htfBasicOpts): Uint8Array;
|
||||
function sign(message: G2, privateKey: PrivKey, htfOpts?: htfBasicOpts): G2;
|
||||
function sign(message: G2Hex, privateKey: PrivKey, htfOpts?: htfBasicOpts): Uint8Array | G2 {
|
||||
const msgPoint = normP2Hash(message, htfOpts);
|
||||
msgPoint.assertValidity();
|
||||
const sigPoint = msgPoint.multiply(G1.normPrivateKeyToScalar(privateKey));
|
||||
@ -278,13 +319,31 @@ export function bls<Fp2, Fp6, Fp12>(
|
||||
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.
|
||||
// e(P, H(m)) == e(G, S)
|
||||
function verify(
|
||||
signature: G2Hex,
|
||||
message: G2Hex,
|
||||
publicKey: G1Hex,
|
||||
htfOpts?: htf.htfBasicOpts
|
||||
htfOpts?: htfBasicOpts
|
||||
): boolean {
|
||||
const P = normP1(publicKey);
|
||||
const Hm = normP2Hash(message, htfOpts);
|
||||
@ -298,6 +357,26 @@ export function bls<Fp2, Fp6, Fp12>(
|
||||
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.
|
||||
// pk1 + pk2 + pk3 = pkA
|
||||
function aggregatePublicKeys(publicKeys: Hex[]): Uint8Array;
|
||||
@ -328,13 +407,27 @@ export function bls<Fp2, Fp6, Fp12>(
|
||||
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
|
||||
// e(G, S) = e(G, SUM(n)(Si)) = MUL(n)(e(G, Si))
|
||||
function verifyBatch(
|
||||
signature: G2Hex,
|
||||
messages: G2Hex[],
|
||||
publicKeys: G1Hex[],
|
||||
htfOpts?: htf.htfBasicOpts
|
||||
htfOpts?: htfBasicOpts
|
||||
): boolean {
|
||||
// @ts-ignore
|
||||
// console.log('verifyBatch', bytesToHex(signature as any), messages, publicKeys.map(bytesToHex));
|
||||
@ -370,16 +463,21 @@ export function bls<Fp2, Fp6, Fp12>(
|
||||
|
||||
return {
|
||||
getPublicKey,
|
||||
getPublicKeyForShortSignatures,
|
||||
sign,
|
||||
signShortSignature,
|
||||
verify,
|
||||
verifyBatch,
|
||||
verifyShortSignature,
|
||||
aggregatePublicKeys,
|
||||
aggregateSignatures,
|
||||
aggregateShortSignatures,
|
||||
millerLoop,
|
||||
pairing,
|
||||
G1,
|
||||
G2,
|
||||
Signature,
|
||||
ShortSignature,
|
||||
fields: {
|
||||
Fr,
|
||||
Fp,
|
||||
|
@ -1,7 +1,8 @@
|
||||
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
||||
import type { Group, GroupConstructor, AffinePoint } from './curve.js';
|
||||
import { mod, IField } from './modular.js';
|
||||
import { bytesToNumberBE, CHash, concatBytes, utf8ToBytes, validateObject } from './utils.js';
|
||||
import type { CHash } from './utils.js';
|
||||
import { bytesToNumberBE, abytes, concatBytes, utf8ToBytes, validateObject } from './utils.js';
|
||||
|
||||
/**
|
||||
* * `DST` is a domain separation tag, defined in section 2.2.5
|
||||
@ -21,12 +22,6 @@ export type Opts = {
|
||||
hash: CHash;
|
||||
};
|
||||
|
||||
function validateDST(dst: UnicodeOrBytes): Uint8Array {
|
||||
if (dst instanceof Uint8Array) return dst;
|
||||
if (typeof dst === 'string') return utf8ToBytes(dst);
|
||||
throw new Error('DST must be Uint8Array or string');
|
||||
}
|
||||
|
||||
// Octet Stream to Integer. "spec" implementation of os2ip is 2.5x slower vs bytesToNumberBE.
|
||||
const os2ip = bytesToNumberBE;
|
||||
|
||||
@ -51,10 +46,7 @@ function strxor(a: Uint8Array, b: Uint8Array): Uint8Array {
|
||||
return arr;
|
||||
}
|
||||
|
||||
function isBytes(item: unknown): void {
|
||||
if (!(item instanceof Uint8Array)) throw new Error('Uint8Array expected');
|
||||
}
|
||||
function isNum(item: unknown): void {
|
||||
function anum(item: unknown): void {
|
||||
if (!Number.isSafeInteger(item)) throw new Error('number expected');
|
||||
}
|
||||
|
||||
@ -66,9 +58,9 @@ export function expand_message_xmd(
|
||||
lenInBytes: number,
|
||||
H: CHash
|
||||
): Uint8Array {
|
||||
isBytes(msg);
|
||||
isBytes(DST);
|
||||
isNum(lenInBytes);
|
||||
abytes(msg);
|
||||
abytes(DST);
|
||||
anum(lenInBytes);
|
||||
// https://www.rfc-editor.org/rfc/rfc9380#section-5.3.3
|
||||
if (DST.length > 255) DST = H(concatBytes(utf8ToBytes('H2C-OVERSIZE-DST-'), DST));
|
||||
const { outputLen: b_in_bytes, blockLen: r_in_bytes } = H;
|
||||
@ -100,9 +92,9 @@ export function expand_message_xof(
|
||||
k: number,
|
||||
H: CHash
|
||||
): Uint8Array {
|
||||
isBytes(msg);
|
||||
isBytes(DST);
|
||||
isNum(lenInBytes);
|
||||
abytes(msg);
|
||||
abytes(DST);
|
||||
anum(lenInBytes);
|
||||
// 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));
|
||||
if (DST.length > 255) {
|
||||
@ -139,9 +131,9 @@ export function hash_to_field(msg: Uint8Array, count: number, options: Opts): bi
|
||||
hash: 'hash',
|
||||
});
|
||||
const { p, k, m, hash, expand, DST: _DST } = options;
|
||||
isBytes(msg);
|
||||
isNum(count);
|
||||
const DST = validateDST(_DST);
|
||||
abytes(msg);
|
||||
anum(count);
|
||||
const DST = typeof _DST === 'string' ? utf8ToBytes(_DST) : _DST;
|
||||
const log2p = p.toString(2).length;
|
||||
const L = Math.ceil((log2p + k) / 8); // section 5.1 of ietf draft link above
|
||||
const len_in_bytes = count * m * L;
|
||||
|
@ -150,17 +150,15 @@ export function montgomery(curveDef: CurveType): CurveFn {
|
||||
function decodeUCoordinate(uEnc: Hex): bigint {
|
||||
// Section 5: When receiving such an array, implementations of X25519
|
||||
// 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);
|
||||
// u[fieldLen-1] crashes QuickJS (TypeError: out-of-bound numeric index)
|
||||
if (fieldLen === montgomeryBytes) u[fieldLen - 1] &= 127; // 0b0111_1111
|
||||
if (fieldLen === 32) u[31] &= 127; // 0b0111_1111
|
||||
return bytesToNumberLE(u);
|
||||
}
|
||||
function decodeScalar(n: Hex): bigint {
|
||||
const bytes = ensureBytes('scalar', n);
|
||||
if (bytes.length !== montgomeryBytes && bytes.length !== fieldLen)
|
||||
throw new Error(`Expected ${montgomeryBytes} or ${fieldLen} bytes, got ${bytes.length}`);
|
||||
const len = bytes.length;
|
||||
if (len !== montgomeryBytes && len !== fieldLen)
|
||||
throw new Error(`Expected ${montgomeryBytes} or ${fieldLen} bytes, got ${len}`);
|
||||
return bytesToNumberLE(adjustScalarBytes(bytes));
|
||||
}
|
||||
function scalarMult(scalar: Hex, u: Hex): Uint8Array {
|
||||
|
@ -6,7 +6,6 @@
|
||||
const _0n = BigInt(0);
|
||||
const _1n = BigInt(1);
|
||||
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
|
||||
export type CHash = {
|
||||
@ -17,6 +16,18 @@ export type CHash = {
|
||||
};
|
||||
export type FHash = (message: Uint8Array | string) => Uint8Array;
|
||||
|
||||
export function isBytes(a: unknown): a is Uint8Array {
|
||||
return (
|
||||
a instanceof Uint8Array ||
|
||||
(a != null && typeof a === 'object' && a.constructor.name === 'Uint8Array')
|
||||
);
|
||||
}
|
||||
|
||||
export function abytes(item: unknown): void {
|
||||
if (!isBytes(item)) throw new Error('Uint8Array expected');
|
||||
}
|
||||
|
||||
// Array where index 0xf0 (240) is mapped to string 'f0'
|
||||
const hexes = /* @__PURE__ */ Array.from({ length: 256 }, (_, i) =>
|
||||
i.toString(16).padStart(2, '0')
|
||||
);
|
||||
@ -24,7 +35,7 @@ const hexes = /* @__PURE__ */ Array.from({ length: 256 }, (_, i) =>
|
||||
* @example bytesToHex(Uint8Array.from([0xca, 0xfe, 0x01, 0x23])) // 'cafe0123'
|
||||
*/
|
||||
export function bytesToHex(bytes: Uint8Array): string {
|
||||
if (!u8a(bytes)) throw new Error('Uint8Array expected');
|
||||
abytes(bytes);
|
||||
// pre-caching improves the speed 6x
|
||||
let hex = '';
|
||||
for (let i = 0; i < bytes.length; i++) {
|
||||
@ -44,20 +55,32 @@ export function hexToNumber(hex: string): bigint {
|
||||
return BigInt(hex === '' ? '0' : `0x${hex}`);
|
||||
}
|
||||
|
||||
// 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 {
|
||||
if (typeof hex !== 'string') throw new Error('hex string expected, got ' + typeof hex);
|
||||
const len = hex.length;
|
||||
if (len % 2) throw new Error('padded hex string expected, got unpadded hex of length ' + len);
|
||||
const array = new Uint8Array(len / 2);
|
||||
for (let i = 0; i < array.length; i++) {
|
||||
const j = i * 2;
|
||||
const hexByte = hex.slice(j, j + 2);
|
||||
const byte = Number.parseInt(hexByte, 16);
|
||||
if (Number.isNaN(byte) || byte < 0) throw new Error('Invalid byte sequence');
|
||||
array[i] = byte;
|
||||
const hl = hex.length;
|
||||
const al = hl / 2;
|
||||
if (hl % 2) throw new Error('padded hex string expected, got unpadded hex of length ' + hl);
|
||||
const array = new Uint8Array(al);
|
||||
for (let ai = 0, hi = 0; ai < al; ai++, hi += 2) {
|
||||
const n1 = asciiToBase16(hex.charCodeAt(hi));
|
||||
const n2 = asciiToBase16(hex.charCodeAt(hi + 1));
|
||||
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;
|
||||
}
|
||||
@ -67,7 +90,7 @@ export function bytesToNumberBE(bytes: Uint8Array): bigint {
|
||||
return hexToNumber(bytesToHex(bytes));
|
||||
}
|
||||
export function bytesToNumberLE(bytes: Uint8Array): bigint {
|
||||
if (!u8a(bytes)) throw new Error('Uint8Array expected');
|
||||
abytes(bytes);
|
||||
return hexToNumber(bytesToHex(Uint8Array.from(bytes).reverse()));
|
||||
}
|
||||
|
||||
@ -99,7 +122,7 @@ export function ensureBytes(title: string, hex: Hex, expectedLength?: number): U
|
||||
} catch (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
|
||||
// is instance of Uint8Array, and its slice() creates **mutable** copy
|
||||
res = Uint8Array.from(hex);
|
||||
@ -116,21 +139,27 @@ export function ensureBytes(title: string, hex: Hex, expectedLength?: number): U
|
||||
* Copies several Uint8Arrays into one.
|
||||
*/
|
||||
export function concatBytes(...arrays: Uint8Array[]): Uint8Array {
|
||||
const r = new Uint8Array(arrays.reduce((sum, a) => sum + a.length, 0));
|
||||
let pad = 0; // walk through each item, ensure they have proper type
|
||||
arrays.forEach((a) => {
|
||||
if (!u8a(a)) throw new Error('Uint8Array expected');
|
||||
r.set(a, pad);
|
||||
let sum = 0;
|
||||
for (let i = 0; i < arrays.length; i++) {
|
||||
const a = arrays[i];
|
||||
abytes(a);
|
||||
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;
|
||||
});
|
||||
return r;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
export function equalBytes(b1: Uint8Array, b2: Uint8Array) {
|
||||
// We don't care about timing attacks here
|
||||
if (b1.length !== b2.length) return false;
|
||||
for (let i = 0; i < b1.length; i++) if (b1[i] !== b2[i]) return false;
|
||||
return true;
|
||||
// Compares 2 u8a-s in kinda constant time
|
||||
export function equalBytes(a: Uint8Array, b: Uint8Array) {
|
||||
if (a.length !== b.length) return false;
|
||||
let diff = 0;
|
||||
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
|
||||
@ -169,9 +198,9 @@ export function bitGet(n: bigint, pos: number) {
|
||||
/**
|
||||
* Sets single bit at position.
|
||||
*/
|
||||
export const bitSet = (n: bigint, pos: number, value: boolean) => {
|
||||
export function 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.
|
||||
@ -248,7 +277,7 @@ const validatorFns = {
|
||||
function: (val: any) => typeof val === 'function',
|
||||
boolean: (val: any) => typeof val === 'boolean',
|
||||
string: (val: any) => typeof val === 'string',
|
||||
stringOrUint8Array: (val: any) => typeof val === 'string' || val instanceof Uint8Array,
|
||||
stringOrUint8Array: (val: any) => typeof val === 'string' || isBytes(val),
|
||||
isSafeInteger: (val: any) => Number.isSafeInteger(val),
|
||||
array: (val: any) => Array.isArray(val),
|
||||
field: (val: any, object: any) => (object as any).Fp.isValid(val),
|
||||
|
@ -27,7 +27,7 @@ export type BasicWCurve<T> = BasicCurve<T> & {
|
||||
clearCofactor?: (c: ProjConstructor<T>, point: ProjPointType<T>) => ProjPointType<T>;
|
||||
};
|
||||
|
||||
type Entropy = Hex | true;
|
||||
type Entropy = Hex | boolean;
|
||||
export type SignOpts = { lowS?: boolean; extraEntropy?: Entropy; prehash?: boolean };
|
||||
export type VerOpts = { lowS?: boolean; prehash?: boolean };
|
||||
|
||||
@ -123,6 +123,7 @@ function validatePointOpts<T>(curve: CurvePointsType<T>) {
|
||||
}
|
||||
|
||||
export type CurvePointsRes<T> = {
|
||||
CURVE: ReturnType<typeof validatePointOpts<T>>;
|
||||
ProjectivePoint: ProjConstructor<T>;
|
||||
normPrivateKeyToScalar: (key: PrivKey) => bigint;
|
||||
weierstrassEquation: (x: T) => T;
|
||||
@ -157,7 +158,7 @@ export const DER = {
|
||||
// parse DER signature
|
||||
const { Err: E } = DER;
|
||||
const data = typeof hex === 'string' ? h2b(hex) : hex;
|
||||
if (!(data instanceof Uint8Array)) throw new Error('ui8a expected');
|
||||
ut.abytes(data);
|
||||
let l = data.length;
|
||||
if (l < 2 || data[0] != 0x30) throw new E('Invalid signature tag');
|
||||
if (data[1] !== l - 2) throw new E('Invalid signature: incorrect length');
|
||||
@ -187,7 +188,7 @@ export const DER = {
|
||||
// prettier-ignore
|
||||
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 { Fp } = CURVE; // All curves has same field / group length as for now, but they can differ
|
||||
|
||||
@ -237,7 +238,7 @@ export function weierstrassPoints<T>(opts: CurvePointsType<T>) {
|
||||
function normPrivateKeyToScalar(key: PrivKey): bigint {
|
||||
const { allowedPrivateKeyLengths: lengths, nByteLength, wrapPrivateKey, n } = CURVE;
|
||||
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
|
||||
if (typeof key !== 'string' || !lengths.includes(key.length)) throw new Error('Invalid key');
|
||||
key = key.padStart(nByteLength * 2, '0');
|
||||
@ -269,7 +270,11 @@ export function weierstrassPoints<T>(opts: CurvePointsType<T>) {
|
||||
static readonly BASE = new Point(CURVE.Gx, CURVE.Gy, Fp.ONE);
|
||||
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 (py == null || !Fp.isValid(py)) throw new Error('y required');
|
||||
if (pz == null || !Fp.isValid(pz)) throw new Error('z required');
|
||||
@ -728,7 +733,13 @@ export function weierstrass(curveDef: CurveType): CurveFn {
|
||||
const x = ut.bytesToNumberBE(tail);
|
||||
if (!isValidFieldElement(x)) throw new Error('Point is not on curve');
|
||||
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;
|
||||
// ECDSA
|
||||
const isHeadOdd = (head & 1) === 1;
|
||||
@ -763,7 +774,11 @@ export function weierstrass(curveDef: CurveType): CurveFn {
|
||||
* ECDSA signature with its (r, s) properties. Supports DER & compact representations.
|
||||
*/
|
||||
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();
|
||||
}
|
||||
|
||||
@ -884,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.
|
||||
*/
|
||||
function isProbPub(item: PrivKey | PubKey): boolean {
|
||||
const arr = item instanceof Uint8Array;
|
||||
const arr = ut.isBytes(item);
|
||||
const str = typeof item === 'string';
|
||||
const len = (arr || str) && (item as Hex).length;
|
||||
if (arr) return len === compressedLen || len === uncompressedLen;
|
||||
@ -962,7 +977,7 @@ export function weierstrass(curveDef: CurveType): CurveFn {
|
||||
const d = normPrivateKeyToScalar(privateKey); // validate private key, convert to bigint
|
||||
const seedArgs = [int2octets(d), int2octets(h1int)];
|
||||
// extraEntropy. RFC6979 3.6: additional k' (optional).
|
||||
if (ent != null) {
|
||||
if (ent != null && ent !== false) {
|
||||
// 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
|
||||
seedArgs.push(ensureBytes('extraEntropy', e)); // check for being bytes
|
||||
@ -1048,7 +1063,7 @@ export function weierstrass(curveDef: CurveType): CurveFn {
|
||||
let _sig: Signature | undefined = undefined;
|
||||
let P: ProjPointType<bigint>;
|
||||
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).
|
||||
// Since DER can also be 2*nByteLength bytes, we check for it first.
|
||||
try {
|
||||
|
198
src/bls12-381.ts
198
src/bls12-381.ts
@ -1,15 +1,9 @@
|
||||
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
||||
|
||||
// bls12-381 pairing-friendly Barreto-Lynn-Scott elliptic curve construction allows to:
|
||||
// - Construct zk-SNARKs at the 128-bit security
|
||||
// - Use threshold signatures, which allows a user to sign lots of messages with one signature and
|
||||
// verify them swiftly in a batch, using Boneh-Lynn-Shacham signature scheme.
|
||||
//
|
||||
// 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-11](https://tools.ietf.org/html/draft-irtf-cfrg-pairing-friendly-curves-11),
|
||||
// [bls-sigs-04](https:/cfrg-hash-to/tools.ietf.org/html/draft-irtf-cfrg-bls-signature-04),
|
||||
// [hash-to-curve-12](https://tools.ietf.org/html/draft-irtf--curve-12).
|
||||
// bls12-381 is pairing-friendly Barreto-Lynn-Scott elliptic curve construction allowing to:
|
||||
// - Construct zk-SNARKs at the 120-bit security
|
||||
// - Efficiently verify N aggregate signatures with 1 pairing and N ec additions:
|
||||
// the Boneh-Lynn-Shacham signature scheme is orders of magnitude more efficient than Schnorr
|
||||
//
|
||||
// ### Summary
|
||||
// 1. BLS Relies on Bilinear Pairing (expensive)
|
||||
@ -25,8 +19,17 @@
|
||||
// - `S = pk x H(m)` - signing
|
||||
// - `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
|
||||
// Filecoin uses little endian byte arrays for private keys -
|
||||
// so ensure to reverse byte order if you'll use it with FIL.
|
||||
//
|
||||
// ### Compatibility and notes
|
||||
// 1. It is compatible with Algorand, Chia, Dfinity, Ethereum, Filecoin, ZEC
|
||||
// Filecoin uses little endian byte arrays for private keys - make sure to reverse byte order.
|
||||
// 2. Some projects use G2 for public keys and G1 for signatures. It's called "short signature"
|
||||
// 3. Curve security level is about 120 bits as per Barbulescu-Duquesne 2017
|
||||
// https://hal.science/hal-01534101/file/main.pdf
|
||||
// 4. Compatible with specs:
|
||||
// [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),
|
||||
// [RFC 9380](https://www.rfc-editor.org/rfc/rfc9380).
|
||||
import { sha256 } from '@noble/hashes/sha256';
|
||||
import { randomBytes } from '@noble/hashes/utils';
|
||||
import { bls, CurveFn } from './abstract/bls.js';
|
||||
@ -37,7 +40,6 @@ import {
|
||||
numberToBytesBE,
|
||||
bytesToNumberBE,
|
||||
bitLen,
|
||||
bitSet,
|
||||
bitGet,
|
||||
Hex,
|
||||
bitMask,
|
||||
@ -1016,11 +1018,41 @@ const htfDefaults = Object.freeze({
|
||||
|
||||
// Encoding utils
|
||||
// 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
|
||||
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
|
||||
@ -1032,10 +1064,12 @@ function signatureG2ToRawBytes(point: ProjPointType<Fp2>) {
|
||||
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 aflag1 = Boolean((tmp / Fp.ORDER) & _1n);
|
||||
const z1 = bitSet(bitSet(x1, 381, aflag1), S_BIT_POS, true);
|
||||
const sort = Boolean((tmp / Fp.ORDER) & _1n);
|
||||
const z2 = x0;
|
||||
return concatB(numberToBytesBE(z1, len), numberToBytesBE(z2, len));
|
||||
return concatB(
|
||||
setMask(numberToBytesBE(x1, len), { sort, compressed: true }),
|
||||
numberToBytesBE(z2, len)
|
||||
);
|
||||
}
|
||||
|
||||
// To verify curve parameters, see pairing-friendly-curves spec:
|
||||
@ -1074,7 +1108,7 @@ export const bls12_381: CurveFn<Fp, Fp2, Fp6, Fp12> = bls({
|
||||
),
|
||||
a: Fp.ZERO,
|
||||
b: _4n,
|
||||
htfDefaults: { ...htfDefaults, m: 1 },
|
||||
htfDefaults: { ...htfDefaults, m: 1, DST: 'BLS_SIG_BLS12381G1_XMD:SHA-256_SSWU_RO_NUL_' },
|
||||
wrapPrivateKey: true,
|
||||
allowInfinityPoint: true,
|
||||
// Checks is the point resides in prime-order subgroup.
|
||||
@ -1116,26 +1150,30 @@ export const bls12_381: CurveFn<Fp, Fp2, Fp6, Fp12> = bls({
|
||||
return isogenyMapG1(x, y);
|
||||
},
|
||||
fromBytes: (bytes: Uint8Array): AffinePoint<Fp> => {
|
||||
bytes = bytes.slice();
|
||||
if (bytes.length === 48) {
|
||||
const { compressed, infinity, sort, value } = parseMask(bytes);
|
||||
if (value.length === 48 && compressed) {
|
||||
// TODO: Fp.bytes
|
||||
const P = Fp.ORDER;
|
||||
const compressedValue = bytesToNumberBE(bytes);
|
||||
const bflag = bitGet(compressedValue, I_BIT_POS);
|
||||
const compressedValue = bytesToNumberBE(value);
|
||||
// Zero
|
||||
if (bflag === _1n) return { x: _0n, y: _0n };
|
||||
const x = Fp.create(compressedValue & Fp.MASK);
|
||||
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);
|
||||
if (!y) throw new Error('Invalid compressed G1 point');
|
||||
const aflag = bitGet(compressedValue, C_BIT_POS);
|
||||
if ((y * _2n) / P !== aflag) y = Fp.neg(y);
|
||||
if ((y * _2n) / P !== BigInt(sort)) y = Fp.neg(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
|
||||
if ((bytes[0] & (1 << 6)) !== 0) return bls12_381.G1.ProjectivePoint.ZERO.toAffine();
|
||||
const x = bytesToNumberBE(bytes.subarray(0, Fp.BYTES));
|
||||
const y = bytesToNumberBE(bytes.subarray(Fp.BYTES));
|
||||
const x = bytesToNumberBE(value.subarray(0, Fp.BYTES));
|
||||
const y = bytesToNumberBE(value.subarray(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) };
|
||||
} else {
|
||||
throw new Error('Invalid point G1, expected 48/96 bytes');
|
||||
@ -1147,10 +1185,8 @@ export const bls12_381: CurveFn<Fp, Fp2, Fp6, Fp12> = bls({
|
||||
if (isCompressed) {
|
||||
if (isZero) return COMPRESSED_ZERO.slice();
|
||||
const P = Fp.ORDER;
|
||||
let num;
|
||||
num = bitSet(x, C_BIT_POS, Boolean((y * _2n) / P)); // set aflag
|
||||
num = bitSet(num, S_BIT_POS, true);
|
||||
return numberToBytesBE(num, Fp.BYTES);
|
||||
const sort = Boolean((y * _2n) / P);
|
||||
return setMask(numberToBytesBE(x, Fp.BYTES), { compressed: true, sort });
|
||||
} else {
|
||||
if (isZero) {
|
||||
// 2x PUBLIC_KEY_LENGTH
|
||||
@ -1161,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),
|
||||
// where Fp2 is Fp[√−1]/(x2+1). #E2(Fp2 ) = h2q, where
|
||||
@ -1232,45 +1292,45 @@ export const bls12_381: CurveFn<Fp, Fp2, Fp6, Fp12> = bls({
|
||||
return Q; // [x²-x-1]P + [x-1]Ψ(P) + Ψ²(2P)
|
||||
},
|
||||
fromBytes: (bytes: Uint8Array): AffinePoint<Fp2> => {
|
||||
bytes = bytes.slice();
|
||||
const m_byte = bytes[0] & 0xe0;
|
||||
if (m_byte === 0x20 || m_byte === 0x60 || m_byte === 0xe0) {
|
||||
throw new Error('Invalid encoding flag: ' + m_byte);
|
||||
const { compressed, infinity, sort, value } = parseMask(bytes);
|
||||
if (
|
||||
(!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 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.params.G2b;
|
||||
const P = Fp.ORDER;
|
||||
|
||||
bytes[0] = bytes[0] & 0x1f; // clear flags
|
||||
if (bitI) {
|
||||
if (infinity) {
|
||||
// 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');
|
||||
}
|
||||
return { x: Fp2.ZERO, y: Fp2.ZERO };
|
||||
}
|
||||
const x_1 = slc(bytes, 0, L);
|
||||
const x_0 = slc(bytes, L, 2 * L);
|
||||
const x_1 = slc(value, 0, L);
|
||||
const x_0 = slc(value, L, 2 * L);
|
||||
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
|
||||
let y = Fp2.sqrt(right);
|
||||
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 };
|
||||
} else if (bytes.length === 192 && !bitC) {
|
||||
// Check if the infinity flag is set
|
||||
if ((bytes[0] & (1 << 6)) !== 0) {
|
||||
} else if (value.length === 192 && !compressed) {
|
||||
if (infinity) {
|
||||
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 };
|
||||
}
|
||||
const x1 = slc(bytes, 0, L);
|
||||
const x0 = slc(bytes, L, 2 * L);
|
||||
const y1 = slc(bytes, 2 * L, 3 * L);
|
||||
const y0 = slc(bytes, 3 * L, 4 * L);
|
||||
const x1 = slc(value, 0, L);
|
||||
const x0 = slc(value, L, 2 * L);
|
||||
const y1 = slc(value, 2 * L, 3 * L);
|
||||
const y0 = slc(value, 3 * L, 4 * L);
|
||||
return { x: Fp2.fromBigTuple([x0, x1]), y: Fp2.fromBigTuple([y0, y1]) };
|
||||
} else {
|
||||
throw new Error('Invalid point G2, expected 96/192 bytes');
|
||||
@ -1283,10 +1343,10 @@ export const bls12_381: CurveFn<Fp, Fp2, Fp6, Fp12> = bls({
|
||||
if (isCompressed) {
|
||||
if (isZero) return concatB(COMPRESSED_ZERO, numberToBytesBE(_0n, len));
|
||||
const flag = Boolean(y.c1 === _0n ? (y.c0 * _2n) / P : (y.c1 * _2n) / P);
|
||||
// set compressed & sign bits (looks like different offsets than for G1/Fp?)
|
||||
let x_1 = bitSet(x.c1, C_BIT_POS, flag);
|
||||
x_1 = bitSet(x_1, S_BIT_POS, true);
|
||||
return concatB(numberToBytesBE(x_1, len), numberToBytesBE(x.c0, len));
|
||||
return concatB(
|
||||
setMask(numberToBytesBE(x.c1, len), { compressed: true, sort: flag }),
|
||||
numberToBytesBE(x.c0, len)
|
||||
);
|
||||
} else {
|
||||
if (isZero) return concatB(new Uint8Array([0x40]), new Uint8Array(4 * len - 1)); // bytes[0] |= 1 << 6;
|
||||
const { re: x0, im: x1 } = Fp2.reim(x);
|
||||
@ -1302,17 +1362,15 @@ export const bls12_381: CurveFn<Fp, Fp2, Fp6, Fp12> = bls({
|
||||
Signature: {
|
||||
// TODO: Optimize, it's very slow because of sqrt.
|
||||
fromHex(hex: Hex): ProjPointType<Fp2> {
|
||||
hex = ensureBytes('signatureHex', hex);
|
||||
const { infinity, sort, value } = parseMask(ensureBytes('signatureHex', hex));
|
||||
const P = Fp.ORDER;
|
||||
const half = hex.length / 2;
|
||||
const half = value.length / 2;
|
||||
if (half !== 48 && half !== 96)
|
||||
throw new Error('Invalid compressed signature length, must be 96 or 192');
|
||||
const z1 = bytesToNumberBE(hex.slice(0, half));
|
||||
const z2 = bytesToNumberBE(hex.slice(half));
|
||||
const z1 = bytesToNumberBE(value.slice(0, half));
|
||||
const z2 = bytesToNumberBE(value.slice(half));
|
||||
// Indicates the infinity point
|
||||
const bflag1 = bitGet(z1, I_BIT_POS);
|
||||
if (bflag1 === _1n) return bls12_381.G2.ProjectivePoint.ZERO;
|
||||
|
||||
if (infinity) return bls12_381.G2.ProjectivePoint.ZERO;
|
||||
const x1 = Fp.create(z1 & Fp.MASK);
|
||||
const x2 = Fp.create(z2);
|
||||
const x = Fp2.create({ c0: x2, c1: x1 });
|
||||
@ -1324,7 +1382,7 @@ 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
|
||||
// If y1 happens to be zero, then use the bit of y0
|
||||
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 isZero = y1 === _0n && (y0 * _2n) / P !== aflag1;
|
||||
if (isGreater || isZero) y = Fp2.neg(y);
|
||||
|
@ -6,8 +6,9 @@ import { Field } from './abstract/modular.js';
|
||||
/**
|
||||
* bn254 pairing-friendly curve.
|
||||
* Previously known as alt_bn_128, when it had 128-bit security.
|
||||
* Recent research shown it's weaker, the naming has been adjusted to its prime bit count.
|
||||
* https://github.com/zcash/zcash/issues/2502
|
||||
* Barbulescu-Duquesne 2017 shown it's weaker: just about 100 bits,
|
||||
* so the naming has been adjusted to its prime bit count
|
||||
* https://hal.science/hal-01534101/file/main.pdf
|
||||
*/
|
||||
export const bn254 = weierstrass({
|
||||
a: BigInt(0),
|
||||
|
@ -13,7 +13,7 @@ import {
|
||||
numberToBytesLE,
|
||||
} from './abstract/utils.js';
|
||||
import { createHasher, htfBasicOpts, expand_message_xmd } from './abstract/hash-to-curve.js';
|
||||
import { AffinePoint } from './abstract/curve.js';
|
||||
import { AffinePoint, Group } from './abstract/curve.js';
|
||||
|
||||
/**
|
||||
* ed25519 Twisted Edwards curve with following addons:
|
||||
@ -343,7 +343,7 @@ function calcElligatorRistrettoMap(r0: bigint): 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 RistPoint {
|
||||
class RistPoint implements Group<RistPoint> {
|
||||
static BASE: RistPoint;
|
||||
static ZERO: RistPoint;
|
||||
// Private property to discourage combining ExtendedPoint + RistrettoPoint
|
||||
@ -471,6 +471,14 @@ class RistPoint {
|
||||
multiplyUnsafe(scalar: bigint): RistPoint {
|
||||
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);
|
||||
|
21
src/ed448.ts
21
src/ed448.ts
@ -13,7 +13,7 @@ import {
|
||||
Hex,
|
||||
numberToBytesLE,
|
||||
} from './abstract/utils.js';
|
||||
import { AffinePoint } from './abstract/curve.js';
|
||||
import { AffinePoint, Group } from './abstract/curve.js';
|
||||
|
||||
/**
|
||||
* Edwards448 (not Ed448-Goldilocks) curve with following addons:
|
||||
@ -103,6 +103,7 @@ const ED448_DEF = {
|
||||
n: BigInt(
|
||||
'181709681073901722637330951972001133588410340171829515070372549795146003961539585716195755291692375963310293709091662304773755859649779'
|
||||
),
|
||||
// RFC 7748 has 56-byte keys, RFC 8032 has 57-byte keys
|
||||
nBitLength: 456,
|
||||
// Cofactor
|
||||
h: BigInt(4),
|
||||
@ -137,8 +138,9 @@ export const ed448ph = /* @__PURE__ */ twistedEdwards({ ...ED448_DEF, prehash: s
|
||||
export const x448 = /* @__PURE__ */ (() =>
|
||||
montgomery({
|
||||
a: BigInt(156326),
|
||||
// RFC 7748 has 56-byte keys, RFC 8032 has 57-byte keys
|
||||
montgomeryBits: 448,
|
||||
nByteLength: 57,
|
||||
nByteLength: 56,
|
||||
P: ed448P,
|
||||
Gu: BigInt(5),
|
||||
powPminus2: (x: bigint): bigint => {
|
||||
@ -164,11 +166,14 @@ export function edwardsToMontgomeryPub(edwardsPub: string | Uint8Array): Uint8Ar
|
||||
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
|
||||
const ELL2_C1 = (Fp.ORDER - BigInt(3)) / BigInt(4); // 1. c1 = (q - 3) / 4 # Integer arithmetic
|
||||
const ELL2_J = BigInt(156326);
|
||||
|
||||
function map_to_curve_elligator2_curve448(u: bigint) {
|
||||
let tv1 = Fp.sqr(u); // 1. tv1 = u^2
|
||||
let e1 = Fp.eql(tv1, Fp.ONE); // 2. e1 = tv1 == 1
|
||||
@ -198,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)
|
||||
return { xn, xd, yn: y, yd: Fp.ONE }; // 27. return (xn, xd, y, 1)
|
||||
}
|
||||
|
||||
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 xn2 = Fp.sqr(xn); // 2. xn2 = xn^2
|
||||
@ -323,7 +329,7 @@ function calcElligatorDecafMap(r0: bigint): 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 {
|
||||
class DcfPoint implements Group<DcfPoint> {
|
||||
static BASE: DcfPoint;
|
||||
static ZERO: DcfPoint;
|
||||
// Private property to discourage combining ExtendedPoint + DecafPoint
|
||||
@ -445,7 +451,16 @@ class DcfPoint {
|
||||
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
|
||||
|
3
src/package.json
Normal file
3
src/package.json
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"type": "module"
|
||||
}
|
@ -2,7 +2,7 @@ import { deepStrictEqual, throws } from 'assert';
|
||||
import { should, describe } from 'micro-should';
|
||||
import * as fc from 'fast-check';
|
||||
import * as mod from '../esm/abstract/modular.js';
|
||||
import { bytesToHex as toHex } from '../esm/abstract/utils.js';
|
||||
import { bytesToHex, isBytes, bytesToHex as toHex } from '../esm/abstract/utils.js';
|
||||
// Generic tests for all curves in package
|
||||
import { secp192r1, secp224r1 } from './_more-curves.helpers.js';
|
||||
import { secp256r1 } from '../esm/p256.js';
|
||||
@ -595,6 +595,18 @@ for (const name in CURVES) {
|
||||
{ numRuns: NUM_RUNS }
|
||||
)
|
||||
);
|
||||
should('.verify() should verify random signatures in hex', () =>
|
||||
fc.assert(
|
||||
fc.property(fc.hexaString({ minLength: 64, maxLength: 64 }), (msg) => {
|
||||
const priv = toHex(C.utils.randomPrivateKey());
|
||||
const pub = toHex(C.getPublicKey(priv));
|
||||
const sig = C.sign(msg, priv);
|
||||
let sighex = isBytes(sig) ? toHex(sig) : sig.toCompactHex();
|
||||
deepStrictEqual(C.verify(sighex, msg, pub), true, `priv=${priv},pub=${pub},msg=${msg}`);
|
||||
}),
|
||||
{ numRuns: NUM_RUNS }
|
||||
)
|
||||
);
|
||||
should('.verify() should verify empty signatures', () => {
|
||||
const msg = new Uint8Array([]);
|
||||
const priv = C.utils.randomPrivateKey();
|
||||
|
@ -5,10 +5,16 @@ import { describe, should } from 'micro-should';
|
||||
import { wNAF } from '../esm/abstract/curve.js';
|
||||
import { bytesToHex, utf8ToBytes } from '../esm/abstract/utils.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 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')
|
||||
.trim()
|
||||
.split('\n')
|
||||
@ -852,6 +858,13 @@ describe('bls12-381/basic', () => {
|
||||
});
|
||||
// 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)`, () => {
|
||||
for (let vector of G2_VECTORS) {
|
||||
const [priv, msg, expected] = vector;
|
||||
@ -1160,6 +1173,8 @@ describe('verify()', () => {
|
||||
const pub = bls.getPublicKey(priv);
|
||||
const res = bls.verify(sig, msg, pub);
|
||||
deepStrictEqual(res, true, `${priv}-${msg}`);
|
||||
const resHex = bls.verify(bytesToHex(sig), msg, pub);
|
||||
deepStrictEqual(resHex, true, `${priv}-${msg}-hex`);
|
||||
}
|
||||
});
|
||||
should('not verify signature with wrong message', () => {
|
||||
@ -1180,6 +1195,43 @@ describe('verify()', () => {
|
||||
const invPub = bls.getPublicKey(invPriv);
|
||||
const res = bls.verify(sig, msg, invPub);
|
||||
deepStrictEqual(res, false);
|
||||
const resHex = bls.verify(bytesToHex(sig), msg, invPub);
|
||||
deepStrictEqual(resHex, 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}`);
|
||||
const resHex = bls.verifyShortSignature(bytesToHex(sig), msg, pub);
|
||||
deepStrictEqual(resHex, 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);
|
||||
const resHex = bls.verifyShortSignature(bytesToHex(sig), invMsg, pub);
|
||||
deepStrictEqual(resHex, 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);
|
||||
const resHex = bls.verifyShortSignature(bytesToHex(sig), msg, invPub);
|
||||
deepStrictEqual(resHex, false);
|
||||
}
|
||||
});
|
||||
describe('batch', () => {
|
||||
@ -1192,6 +1244,10 @@ describe('verify()', () => {
|
||||
const signatures = messages.map((message, i) => bls.sign(message, privateKeys[i]));
|
||||
const aggregatedSignature = bls.aggregateSignatures(signatures);
|
||||
deepStrictEqual(bls.verifyBatch(aggregatedSignature, messages, publicKey), true);
|
||||
deepStrictEqual(
|
||||
bls.verifyBatch(bytesToHex(aggregatedSignature), messages, publicKey),
|
||||
true
|
||||
);
|
||||
})
|
||||
);
|
||||
});
|
||||
@ -1210,6 +1266,10 @@ describe('verify()', () => {
|
||||
bls.verifyBatch(aggregatedSignature, wrongMessages, publicKey),
|
||||
messages.every((m, i) => m === wrongMessages[i])
|
||||
);
|
||||
deepStrictEqual(
|
||||
bls.verifyBatch(bytesToHex(aggregatedSignature), wrongMessages, publicKey),
|
||||
messages.every((m, i) => m === wrongMessages[i])
|
||||
);
|
||||
})
|
||||
);
|
||||
});
|
||||
@ -1232,6 +1292,10 @@ describe('verify()', () => {
|
||||
bls.verifyBatch(aggregatedSignature, messages, wrongPublicKeys),
|
||||
wrongPrivateKeys.every((p, i) => p === privateKeys[i])
|
||||
);
|
||||
deepStrictEqual(
|
||||
bls.verifyBatch(bytesToHex(aggregatedSignature), messages, wrongPublicKeys),
|
||||
wrongPrivateKeys.every((p, i) => p === privateKeys[i])
|
||||
);
|
||||
}
|
||||
)
|
||||
);
|
||||
@ -1245,6 +1309,10 @@ describe('verify()', () => {
|
||||
const aggregatedSignature = bls.aggregateSignatures(signatures);
|
||||
const aggregatedPublicKey = bls.aggregatePublicKeys(publicKey);
|
||||
deepStrictEqual(bls.verify(aggregatedSignature, message, aggregatedPublicKey), true);
|
||||
deepStrictEqual(
|
||||
bls.verify(bytesToHex(aggregatedSignature), message, aggregatedPublicKey),
|
||||
true
|
||||
);
|
||||
})
|
||||
);
|
||||
});
|
||||
@ -1260,6 +1328,10 @@ describe('verify()', () => {
|
||||
bls.verify(aggregatedSignature, wrongMessage, aggregatedPublicKey),
|
||||
message === wrongMessage
|
||||
);
|
||||
deepStrictEqual(
|
||||
bls.verify(bytesToHex(aggregatedSignature), wrongMessage, aggregatedPublicKey),
|
||||
message === wrongMessage
|
||||
);
|
||||
})
|
||||
);
|
||||
});
|
||||
@ -1375,6 +1447,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.
|
||||
|
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
|
@ -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_shake256_36 } from './hash-to-curve/expand_message_xof_SHAKE256_36.json' assert { type: 'json' };
|
||||
// P256
|
||||
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_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' };
|
||||
// P384
|
||||
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_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' };
|
||||
// P521
|
||||
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_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' };
|
||||
// secp256k1
|
||||
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_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' };
|
||||
// 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_nu } from './hash-to-curve/BLS12381G1_XMD:SHA-256_SSWU_NU_.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' };
|
||||
// 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_nu } from './hash-to-curve/BLS12381G2_XMD:SHA-256_SSWU_NU_.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' };
|
||||
// ed25519
|
||||
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_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' };
|
||||
// ed448
|
||||
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_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' };
|
||||
|
||||
function testExpandXMD(hash, vectors) {
|
||||
describe(`${vectors.hash}/${vectors.DST.length}`, () => {
|
||||
|
@ -95,32 +95,52 @@ should('fields', () => {
|
||||
for (const n in vectors) deepStrictEqual(NIST[n].CURVE.Fp.ORDER, vectors[n]);
|
||||
});
|
||||
|
||||
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) {
|
||||
// We don't support ASN.1 encoding of points. For tests we've implemented quick
|
||||
// and dirty parser: take X last bytes of ASN.1 encoded sequence.
|
||||
// If that doesn't work, we ignore such vector.
|
||||
function verifyECDHVector(test, curve) {
|
||||
if (test.flags.includes('InvalidAsn')) return; // Ignore invalid ASN
|
||||
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 {
|
||||
const pub = CURVE.ProjectivePoint.fromHex(test.public);
|
||||
curve.ProjectivePoint.fromHex(pubB);
|
||||
} catch (e) {
|
||||
// Our strict validation filter doesn't let weird-length DER vectors
|
||||
if (e.message.startsWith('Point of length')) continue;
|
||||
if (e.message.startsWith('Point of length')) return; // Ignore
|
||||
throw e;
|
||||
}
|
||||
const shared = CURVE.getSharedSecret(test.private, test.public);
|
||||
deepStrictEqual(shared, test.shared, 'valid');
|
||||
const shared = curve.getSharedSecret(privA, pubB).subarray(1);
|
||||
deepStrictEqual(hex(shared), test.shared, 'valid');
|
||||
} else if (test.result === 'invalid') {
|
||||
let failed = false;
|
||||
try {
|
||||
CURVE.getSharedSecret(test.private, test.public);
|
||||
curve.getSharedSecret(test.private, test.public);
|
||||
} catch (error) {
|
||||
failed = true;
|
||||
}
|
||||
deepStrictEqual(failed, true, 'invalid');
|
||||
} 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);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@ -151,30 +171,12 @@ describe('wycheproof ECDH', () => {
|
||||
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})`, () => {
|
||||
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) {
|
||||
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');
|
||||
} 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');
|
||||
verifyECDHVector(test, curve);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -1,24 +1,9 @@
|
||||
{
|
||||
"extends": "@paulmillr/jsbt/tsconfigs/esm.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "esm",
|
||||
"target": "es2020",
|
||||
"module": "es6",
|
||||
"moduleResolution": "node16",
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"@noble/hashes/crypto": ["src/crypto"]
|
||||
"target": "ES2015"
|
||||
},
|
||||
"sourceMap": true,
|
||||
"strict": true,
|
||||
"allowSyntheticDefaultImports": false,
|
||||
"allowUnreachableCode": false,
|
||||
"esModuleInterop": false,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"noImplicitReturns": true,
|
||||
"noUncheckedIndexedAccess": false,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
},
|
||||
"include": ["src"],
|
||||
"include": ["index.ts", "src"],
|
||||
"exclude": ["node_modules", "lib"]
|
||||
}
|
||||
|
@ -1,24 +1,9 @@
|
||||
{
|
||||
"extends": "@paulmillr/jsbt/tsconfigs/cjs.json",
|
||||
"compilerOptions": {
|
||||
"outDir": ".",
|
||||
"target": "es2020",
|
||||
"lib": ["es2020"], // Set explicitly to remove DOM
|
||||
"module": "commonjs",
|
||||
"moduleResolution": "node",
|
||||
"baseUrl": ".",
|
||||
"sourceMap": true,
|
||||
"declaration": true,
|
||||
"declarationMap": true,
|
||||
"strict": true,
|
||||
"allowSyntheticDefaultImports": false,
|
||||
"allowUnreachableCode": false,
|
||||
"esModuleInterop": false,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"noImplicitReturns": true,
|
||||
"noUncheckedIndexedAccess": false,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true
|
||||
"target": "ES2015"
|
||||
},
|
||||
"include": ["src"],
|
||||
"exclude": ["node_modules", "*.d.ts"]
|
||||
"include": ["index.ts", "src"],
|
||||
"exclude": ["node_modules", "lib"]
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user