Compare commits
121 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e2a7594eae | ||
|
|
823149ecd9 | ||
|
|
e57aec63d8 | ||
|
|
837aca98c9 | ||
|
|
dbb16b0e5e | ||
|
|
e14af67254 | ||
|
|
4780850748 | ||
|
|
3374a70f47 | ||
|
|
131f88b504 | ||
|
|
4333e9a686 | ||
|
|
a60d15ff05 | ||
|
|
ceffbc69da | ||
|
|
c75129e629 | ||
|
|
f39fb80c52 | ||
|
|
fcd422d246 | ||
|
|
ed9bf89038 | ||
|
|
7262b4219f | ||
|
|
02b0b25147 | ||
|
|
79100c2d47 | ||
|
|
4ef2cad685 | ||
|
|
69b3ab5a57 | ||
|
|
9465e60d30 | ||
|
|
0fb78b7097 | ||
|
|
be0b2a32a5 | ||
|
|
3d77422731 | ||
|
|
c46914f1bc | ||
|
|
f250f355e8 | ||
|
|
c095d74673 | ||
|
|
ac52fea952 | ||
|
|
f2ee24bee4 | ||
|
|
cffea91061 | ||
|
|
5fc38fc0e7 | ||
|
|
849dc38f3c | ||
|
|
0422e6ef38 | ||
|
|
21d2438a33 | ||
|
|
cea4696599 | ||
|
|
f14b8d2be5 | ||
|
|
2ed27da8eb | ||
|
|
17e5be5f1b | ||
|
|
a49f0d266e | ||
|
|
bfbcf733e6 | ||
|
|
7fda6de619 | ||
|
|
2b908ad602 | ||
|
|
ceb3f67faa | ||
|
|
a2c87f9c2f | ||
|
|
e1fd346279 | ||
|
|
11e78aadbf | ||
|
|
055147f1be | ||
|
|
6f99f6042e | ||
|
|
1e47bf2372 | ||
|
|
40530eae0c | ||
|
|
b9482bb17d | ||
|
|
74475dca68 | ||
|
|
f4cf21b9c8 | ||
|
|
5312d92b2c | ||
|
|
d1770c0ac7 | ||
|
|
2d37edf7d1 | ||
|
|
36998fede8 | ||
|
|
83960d445d | ||
|
|
23cc2aa5d1 | ||
|
|
e45d7c2d25 | ||
|
|
bfe929aac3 | ||
|
|
069452dbe7 | ||
|
|
2e81f31d2e | ||
|
|
9f7df0f13b | ||
|
|
5600629bca | ||
|
|
2bd5e9ac16 | ||
|
|
6890c26091 | ||
|
|
a15e3a93a9 | ||
|
|
910c508da9 | ||
|
|
12da04a2bb | ||
|
|
cc2c84f040 | ||
|
|
5d42549acc | ||
|
|
65d7256b9e | ||
|
|
d77a98a7aa | ||
|
|
1bfab42620 | ||
|
|
f1ab259941 | ||
|
|
242ee620c5 | ||
|
|
d837831d22 | ||
|
|
cae888d942 | ||
|
|
1ab77b95dd | ||
|
|
8b5819b12d | ||
|
|
4b5560ab4b | ||
|
|
ba121ff24c | ||
|
|
0277c01efd | ||
|
|
6ffe656871 | ||
|
|
135e69bd7b | ||
|
|
7a34c16c2b | ||
|
|
458cddcc7f | ||
|
|
ccfb8695d5 | ||
|
|
f165222425 | ||
|
|
785d74edb9 | ||
|
|
768b268baf | ||
|
|
4df1e8de02 | ||
|
|
dd7b48ac71 | ||
|
|
254bb712b4 | ||
|
|
31f780027a | ||
|
|
80edb3323a | ||
|
|
d30b1855ee | ||
|
|
f1d8650842 | ||
|
|
54c7cf8b33 | ||
|
|
56892cc164 | ||
|
|
7d746a7408 | ||
|
|
989af14b10 | ||
|
|
0592b16a49 | ||
|
|
fbf85ce732 | ||
|
|
cafe51a6e3 | ||
|
|
43b18ea13b | ||
|
|
fd75293334 | ||
|
|
20c6d11917 | ||
|
|
bbe46843fb | ||
|
|
9e5ad8dc85 | ||
|
|
5b305abe85 | ||
|
|
6b0d9611a5 | ||
|
|
b92866d9b8 | ||
|
|
c8fc24fd8f | ||
|
|
4c6ca2326a | ||
|
|
c660712fee | ||
|
|
5983975ada | ||
|
|
1ed861dbad | ||
|
|
211c887a57 |
3
.github/workflows/nodejs.yml
vendored
3
.github/workflows/nodejs.yml
vendored
@@ -13,6 +13,5 @@ jobs:
|
||||
node-version: 18
|
||||
- run: npm install
|
||||
- run: npm run build --if-present
|
||||
- run: cd curve-definitions; npm install; npm run build --if-present
|
||||
- run: npm test
|
||||
- run: npm run lint --if-present
|
||||
- run: npm test
|
||||
|
||||
546
README.md
546
README.md
@@ -1,71 +1,557 @@
|
||||
# noble-curves
|
||||
|
||||
Minimal, zero-dependency JS implementation of elliptic curve cryptography.
|
||||
Minimal, auditable JS implementation of elliptic curve cryptography.
|
||||
|
||||
Implements Short Weierstrass curves with ECDSA signature scheme.
|
||||
- Short Weierstrass, Edwards, Montgomery curves
|
||||
- ECDSA, EdDSA, Schnorr, BLS signature schemes, ECDH key agreement
|
||||
- [hash to curve](https://datatracker.ietf.org/doc/draft-irtf-cfrg-hash-to-curve/)
|
||||
for encoding or hashing an arbitrary string to a point on an elliptic curve
|
||||
- [Poseidon](https://www.poseidon-hash.info) ZK-friendly hash
|
||||
- 🏎 [Ultra-fast](#speed), hand-optimized for caveats of JS engines
|
||||
- 🔍 Unique tests ensure correctness. Wycheproof vectors included
|
||||
- 🔻 Tree-shaking-friendly: there is no entry point, which ensures small size of your app
|
||||
|
||||
To keep the package minimal, no curve definitions are provided out-of-box.
|
||||
Main reason for that is the fact hashing library is usually required for full functionality. Use separate package that defines popular curves: `micro-curve-definitions` for P192, P224, P256, P384, P521, secp256k1, stark curve, bn254, pasta (pallas/vesta) - it depends on `@noble/hashes`.
|
||||
Package consists of two parts:
|
||||
|
||||
Future plans:
|
||||
1. `abstract/` directory specifies zero-dependency EC algorithms
|
||||
2. root directory utilizes one dependency `@noble/hashes` and provides ready-to-use:
|
||||
- NIST curves secp192r1/P192, secp224r1/P224, secp256r1/P256, secp384r1/P384, secp521r1/P521
|
||||
- SECG curve secp256k1
|
||||
- pairing-friendly curves bls12-381, bn254
|
||||
- ed25519/curve25519/x25519/ristretto, edwards448/curve448/x448 RFC7748 / RFC8032 / ZIP215 stuff
|
||||
|
||||
- Edwards, Twisted Edwards & Montgomery curves
|
||||
- hash-to-curve standard
|
||||
- pairings
|
||||
Curves incorporate work from previous noble packages
|
||||
([secp256k1](https://github.com/paulmillr/noble-secp256k1),
|
||||
[ed25519](https://github.com/paulmillr/noble-ed25519),
|
||||
[bls12-381](https://github.com/paulmillr/noble-bls12-381)),
|
||||
which had security audits and were developed from 2019 to 2022.
|
||||
Check out [Upgrading](#upgrading) section if you've used them before.
|
||||
|
||||
### This library belongs to _noble_ crypto
|
||||
|
||||
> **noble-crypto** — high-security, easily auditable set of contained cryptographic libraries and tools.
|
||||
|
||||
- No dependencies, small files
|
||||
- Minimal dependencies, small files
|
||||
- Easily auditable TypeScript/JS code
|
||||
- Supported in all major browsers and stable node.js versions
|
||||
- All releases are signed with PGP keys
|
||||
- Check out [homepage](https://paulmillr.com/noble/) & all libraries:
|
||||
[secp256k1](https://github.com/paulmillr/noble-secp256k1),
|
||||
[curves](https://github.com/paulmillr/noble-curves) ([secp256k1](https://github.com/paulmillr/noble-secp256k1),
|
||||
[ed25519](https://github.com/paulmillr/noble-ed25519),
|
||||
[bls12-381](https://github.com/paulmillr/noble-bls12-381),
|
||||
[hashes](https://github.com/paulmillr/noble-hashes),
|
||||
[curves](https://github.com/paulmillr/noble-curves)
|
||||
[bls12-381](https://github.com/paulmillr/noble-bls12-381)),
|
||||
[hashes](https://github.com/paulmillr/noble-hashes)
|
||||
|
||||
## Usage
|
||||
|
||||
Use NPM in node.js / browser, or include single file from
|
||||
[GitHub's releases page](https://github.com/paulmillr/noble-curves/releases):
|
||||
|
||||
## Usage
|
||||
> npm install @noble/curves
|
||||
|
||||
```sh
|
||||
npm install @noble/curves
|
||||
```
|
||||
The library does not have an entry point. It allows you to select specific primitives and drop everything else. If you only want to use secp256k1, just use the library with rollup or other bundlers. This is done to make your bundles tiny.
|
||||
|
||||
```ts
|
||||
// Short Weierstrass curve
|
||||
import shortw from '@noble/curves/shortw';
|
||||
// Common.js and ECMAScript Modules (ESM)
|
||||
import { secp256k1 } from '@noble/curves/secp256k1';
|
||||
|
||||
const key = secp256k1.utils.randomPrivateKey();
|
||||
const pub = secp256k1.getPublicKey(key);
|
||||
const msg = new Uint8Array(32).fill(1);
|
||||
const sig = secp256k1.sign(msg, key);
|
||||
secp256k1.verify(sig, msg, pub) === true;
|
||||
sig.recoverPublicKey(msg) === pub;
|
||||
const someonesPub = secp256k1.getPublicKey(secp256k1.utils.randomPrivateKey());
|
||||
const shared = secp256k1.getSharedSecret(key, someonesPub);
|
||||
```
|
||||
|
||||
All curves:
|
||||
|
||||
```ts
|
||||
import { secp256k1 } from '@noble/curves/secp256k1';
|
||||
import { ed25519, ed25519ph, ed25519ctx, x25519, RistrettoPoint } from '@noble/curves/ed25519';
|
||||
import { ed448, ed448ph, ed448ctx, x448 } from '@noble/curves/ed448';
|
||||
import { p256 } from '@noble/curves/p256';
|
||||
import { p384 } from '@noble/curves/p384';
|
||||
import { p521 } from '@noble/curves/p521';
|
||||
import { pallas, vesta } from '@noble/curves/pasta';
|
||||
import * as stark from '@noble/curves/stark';
|
||||
import { bls12_381 } from '@noble/curves/bls12-381';
|
||||
import { bn254 } from '@noble/curves/bn';
|
||||
import { jubjub } from '@noble/curves/jubjub';
|
||||
```
|
||||
|
||||
To define a custom curve, check out API below.
|
||||
|
||||
## API
|
||||
|
||||
- [Overview](#overview)
|
||||
- [abstract/edwards: Twisted Edwards curve](#abstractedwards-twisted-edwards-curve)
|
||||
- [abstract/montgomery: Montgomery curve](#abstractmontgomery-montgomery-curve)
|
||||
- [abstract/weierstrass: Short Weierstrass curve](#abstractweierstrass-short-weierstrass-curve)
|
||||
- [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](#abstractmodular)
|
||||
- [abstract/utils](#abstractutils)
|
||||
|
||||
### Overview
|
||||
|
||||
There are following zero-dependency abstract algorithms:
|
||||
|
||||
```ts
|
||||
import { bls } from '@noble/curves/abstract/bls';
|
||||
import { twistedEdwards } from '@noble/curves/abstract/edwards';
|
||||
import { montgomery } from '@noble/curves/abstract/montgomery';
|
||||
import { weierstrass } from '@noble/curves/abstract/weierstrass';
|
||||
import * as mod from '@noble/curves/abstract/modular';
|
||||
import * as utils from '@noble/curves/abstract/utils';
|
||||
```
|
||||
|
||||
They allow to define a new curve in a few lines of code:
|
||||
|
||||
```ts
|
||||
import { Fp } from '@noble/curves/abstract/modular';
|
||||
import { weierstrass } from '@noble/curves/abstract/weierstrass';
|
||||
import { hmac } from '@noble/hashes/hmac';
|
||||
import { sha256 } from '@noble/hashes/sha256';
|
||||
import { concatBytes, randomBytes } from '@noble/hashes/utils';
|
||||
|
||||
const secp256k1 = weierstrass({
|
||||
a: 0n,
|
||||
b: 7n,
|
||||
Fp: Fp(2n ** 256n - 2n ** 32n - 2n ** 9n - 2n ** 8n - 2n ** 7n - 2n ** 6n - 2n ** 4n - 1n),
|
||||
n: 2n ** 256n - 432420386565659656852420866394968145599n,
|
||||
Gx: 55066263022277343669578718895168534326250603453777594175500187360389116729240n,
|
||||
Gy: 32670510020758816978083085130507043184471273380659243275938904335757337482424n,
|
||||
hash: sha256,
|
||||
hmac: (key: Uint8Array, ...msgs: Uint8Array[]) => hmac(sha256, key, concatBytes(...msgs)),
|
||||
randomBytes,
|
||||
});
|
||||
```
|
||||
|
||||
- To initialize new curve, you must specify its variables, order (number of points on curve), field prime (over which the modular division would be done)
|
||||
- All curves expose same generic interface:
|
||||
- `getPublicKey()`, `sign()`, `verify()` functions
|
||||
- `Point` conforming to `Group` interface with add/multiply/double/negate/add/equals methods
|
||||
- `CURVE` object with curve variables like `Gx`, `Gy`, `Fp` (field), `n` (order)
|
||||
- `utils` object with `randomPrivateKey()`, `mod()`, `invert()` methods (`mod CURVE.P`)
|
||||
- All arithmetics is done with JS bigints over finite fields, which is defined from `modular` sub-module
|
||||
- Many features require hashing, which is not provided. `@noble/hashes` can be used for this purpose.
|
||||
Any other library must conform to the CHash interface:
|
||||
```ts
|
||||
export type CHash = {
|
||||
(message: Uint8Array): Uint8Array;
|
||||
blockLen: number;
|
||||
outputLen: number;
|
||||
create(): any;
|
||||
};
|
||||
```
|
||||
- w-ary non-adjacent form (wNAF) method with constant-time adjustments is used for point multiplication.
|
||||
It is possible to enable precomputes for edwards & weierstrass curves.
|
||||
Precomputes are calculated once (takes ~20-40ms), after that most `G` base point multiplications:
|
||||
for example, `getPublicKey()`, `sign()` and similar methods - would be much faster.
|
||||
Use `curve.utils.precompute()` to adjust precomputation window size
|
||||
- You could use optional special params to tune performance:
|
||||
- `Fp({sqrt})` square root calculation, used for point decompression
|
||||
- `endo` endomorphism options for Koblitz curves
|
||||
|
||||
### abstract/edwards: Twisted Edwards curve
|
||||
|
||||
Twisted Edwards curve's formula is: ax² + y² = 1 + dx²y².
|
||||
|
||||
- You must specify curve params `a`, `d`, field `Fp`, order `n`, cofactor `h` and coordinates `Gx`, `Gy` of generator point
|
||||
- For EdDSA signatures, params `hash` is also required. `adjustScalarBytes` which instructs how to change private scalars could be specified
|
||||
|
||||
```typescript
|
||||
import { twistedEdwards } from '@noble/curves/abstract/edwards';
|
||||
import { div } from '@noble/curves/abstract/modular';
|
||||
import { sha512 } from '@noble/hashes/sha512';
|
||||
|
||||
const ed25519 = twistedEdwards({
|
||||
a: -1n,
|
||||
d: div(-121665n, 121666n, 2n ** 255n - 19n), // -121665n/121666n
|
||||
P: 2n ** 255n - 19n,
|
||||
n: 2n ** 252n + 27742317777372353535851937790883648493n,
|
||||
h: 8n,
|
||||
Gx: 15112221349535400772501151409588531511454012693041857206046113283949847762202n,
|
||||
Gy: 46316835694926478169428394003475163141307993866256225615783033603165251855960n,
|
||||
hash: sha512,
|
||||
randomBytes,
|
||||
adjustScalarBytes(bytes) {
|
||||
// optional in general, mandatory in ed25519
|
||||
bytes[0] &= 248;
|
||||
bytes[31] &= 127;
|
||||
bytes[31] |= 64;
|
||||
return bytes;
|
||||
},
|
||||
} as const);
|
||||
const key = ed25519.utils.randomPrivateKey();
|
||||
const pub = ed25519.getPublicKey(key);
|
||||
const msg = new TextEncoder().encode('hello world'); // strings not accepted, must be Uint8Array
|
||||
const sig = ed25519.sign(msg, key);
|
||||
ed25519.verify(sig, msg, pub) === true;
|
||||
```
|
||||
|
||||
`twistedEdwards()` returns `CurveFn` of following type:
|
||||
|
||||
```ts
|
||||
export type CurveFn = {
|
||||
CURVE: ReturnType<typeof validateOpts>;
|
||||
getPublicKey: (privateKey: PrivKey, isCompressed?: boolean) => Uint8Array;
|
||||
sign: (message: Hex, privateKey: Hex) => Uint8Array;
|
||||
verify: (sig: SigType, message: Hex, publicKey: PubKey) => boolean;
|
||||
Point: PointConstructor;
|
||||
ExtendedPoint: ExtendedPointConstructor;
|
||||
Signature: SignatureConstructor;
|
||||
utils: {
|
||||
randomPrivateKey: () => Uint8Array;
|
||||
getExtendedPublicKey: (key: PrivKey) => {
|
||||
head: Uint8Array;
|
||||
prefix: Uint8Array;
|
||||
scalar: bigint;
|
||||
point: PointType;
|
||||
pointBytes: Uint8Array;
|
||||
};
|
||||
};
|
||||
};
|
||||
```
|
||||
|
||||
### abstract/montgomery: Montgomery curve
|
||||
|
||||
For now the module only contains methods for x-only ECDH on Curve25519 / Curve448 from RFC7748.
|
||||
|
||||
Proper Elliptic Curve Points are not implemented yet.
|
||||
|
||||
You must specify curve field, `a24` special variable, `montgomeryBits`, `nByteLength`, and coordinate `u` of generator point.
|
||||
|
||||
```typescript
|
||||
import { montgomery } from '@noble/curves/abstract/montgomery';
|
||||
|
||||
const x25519 = montgomery({
|
||||
P: 2n ** 255n - 19n,
|
||||
a24: 121665n, // TODO: change to a
|
||||
montgomeryBits: 255,
|
||||
nByteLength: 32,
|
||||
Gu: '0900000000000000000000000000000000000000000000000000000000000000',
|
||||
|
||||
// Optional params
|
||||
powPminus2: (x: bigint): bigint => {
|
||||
return mod.pow(x, P - 2, P);
|
||||
},
|
||||
adjustScalarBytes(bytes) {
|
||||
bytes[0] &= 248;
|
||||
bytes[31] &= 127;
|
||||
bytes[31] |= 64;
|
||||
return bytes;
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
### abstract/weierstrass: Short Weierstrass curve
|
||||
|
||||
Short Weierstrass curve's formula is: y² = x³ + ax + b. Uses deterministic ECDSA from RFC6979. You can also specify `extraEntropy` in `sign()`.
|
||||
|
||||
- You must specify curve params: `a`, `b`, field `Fp`, order `n`, cofactor `h` and coordinates `Gx`, `Gy` of generator point
|
||||
- For ECDSA, you must specify `hash`, `hmac`. It is also possible to recover keys from signatures
|
||||
- For ECDH, use `getSharedSecret(privKeyA, pubKeyB)`
|
||||
- Optional params are `lowS` (default value) and `endo` (endomorphism)
|
||||
|
||||
```typescript
|
||||
import { Fp } from '@noble/curves/abstract/modular';
|
||||
import { weierstrass } from '@noble/curves/abstract/weierstrass'; // Short Weierstrass curve
|
||||
import { sha256 } from '@noble/hashes/sha256';
|
||||
import { hmac } from '@noble/hashes/hmac';
|
||||
import { concatBytes, randomBytes } from '@noble/hashes/utils';
|
||||
|
||||
export const secp256k1 = shortw({
|
||||
const secp256k1 = weierstrass({
|
||||
a: 0n,
|
||||
b: 7n,
|
||||
// Field over which we'll do calculations
|
||||
P: 2n ** 256n - 2n ** 32n - 2n ** 9n - 2n ** 8n - 2n ** 7n - 2n ** 6n - 2n ** 4n - 1n,
|
||||
// Curve order, total count of valid points in the field
|
||||
n: 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141n,
|
||||
// Base point (x, y) aka generator point
|
||||
Fp: Fp(2n ** 256n - 2n ** 32n - 2n ** 9n - 2n ** 8n - 2n ** 7n - 2n ** 6n - 2n ** 4n - 1n),
|
||||
n: 2n ** 256n - 432420386565659656852420866394968145599n,
|
||||
Gx: 55066263022277343669578718895168534326250603453777594175500187360389116729240n,
|
||||
Gy: 32670510020758816978083085130507043184471273380659243275938904335757337482424n,
|
||||
hash: sha256,
|
||||
hmac: (k: Uint8Array, ...msgs: Uint8Array[]) => hmac(sha256, key, concatBytes(...msgs)),
|
||||
randomBytes: randomBytes
|
||||
randomBytes,
|
||||
|
||||
// Optional params
|
||||
h: 1n, // Cofactor
|
||||
lowS: true, // Allow only low-S signatures by default in sign() and verify()
|
||||
endo: {
|
||||
// Endomorphism options for Koblitz curve
|
||||
// Beta param
|
||||
beta: 0x7ae96a2b657c07106e64479eac3434e99cf0497512f58995c1396c28719501een,
|
||||
// Split scalar k into k1, k2
|
||||
splitScalar: (k: bigint) => {
|
||||
// return { k1neg: true, k1: 512n, k2neg: false, k2: 448n };
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
// secp256k1.getPublicKey(priv)
|
||||
// secp256k1.sign(msg, priv)
|
||||
// secp256k1.verify(sig, msg, pub)
|
||||
// Usage
|
||||
const key = secp256k1.utils.randomPrivateKey();
|
||||
const pub = secp256k1.getPublicKey(key);
|
||||
const msg = randomBytes(32);
|
||||
const sig = secp256k1.sign(msg, key);
|
||||
secp256k1.verify(sig, msg, pub); // true
|
||||
sig.recoverPublicKey(msg); // == pub
|
||||
const someonesPubkey = secp256k1.getPublicKey(secp256k1.utils.randomPrivateKey());
|
||||
const shared = secp256k1.getSharedSecret(key, someonesPubkey);
|
||||
```
|
||||
|
||||
`weierstrass()` returns `CurveFn`:
|
||||
|
||||
```ts
|
||||
export type CurveFn = {
|
||||
CURVE: ReturnType<typeof validateOpts>;
|
||||
getPublicKey: (privateKey: PrivKey, isCompressed?: boolean) => Uint8Array;
|
||||
getSharedSecret: (privateA: PrivKey, publicB: Hex, isCompressed?: boolean) => Uint8Array;
|
||||
sign: (msgHash: Hex, privKey: PrivKey, opts?: SignOpts) => SignatureType;
|
||||
verify: (
|
||||
signature: Hex | SignatureType,
|
||||
msgHash: Hex,
|
||||
publicKey: Hex,
|
||||
opts?: { lowS?: boolean }
|
||||
) => boolean;
|
||||
Point: PointConstructor;
|
||||
ProjectivePoint: ProjectivePointConstructor;
|
||||
Signature: SignatureConstructor;
|
||||
utils: {
|
||||
isValidPrivateKey(privateKey: PrivKey): boolean;
|
||||
hashToPrivateKey: (hash: Hex) => Uint8Array;
|
||||
randomPrivateKey: () => Uint8Array;
|
||||
};
|
||||
};
|
||||
```
|
||||
|
||||
### abstract/hash-to-curve: Hashing strings to curve points
|
||||
|
||||
The module allows to hash arbitrary strings to elliptic curve points.
|
||||
|
||||
- `expand_message_xmd` [(spec)](https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-11#section-5.4.1) produces a uniformly random byte string using a cryptographic hash function H that outputs b bits..
|
||||
|
||||
```ts
|
||||
function expand_message_xmd(
|
||||
msg: Uint8Array,
|
||||
DST: Uint8Array,
|
||||
lenInBytes: number,
|
||||
H: CHash
|
||||
): Uint8Array;
|
||||
function expand_message_xof(
|
||||
msg: Uint8Array,
|
||||
DST: Uint8Array,
|
||||
lenInBytes: number,
|
||||
k: number,
|
||||
H: CHash
|
||||
): Uint8Array;
|
||||
```
|
||||
|
||||
- `hash_to_field(msg, count, options)` [(spec)](https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-11#section-5.3)
|
||||
hashes arbitrary-length byte strings to a list of one or more elements of a finite field F.
|
||||
_ `msg` a byte string containing the message to hash
|
||||
_ `count` the number of elements of F to output
|
||||
_ `options` `{DST: string, p: bigint, m: number, k: number, expand: 'xmd' | 'xof', hash: H}`
|
||||
_ Returns `[u_0, ..., u_(count - 1)]`, a list of field elements.
|
||||
|
||||
```ts
|
||||
function hash_to_field(msg: Uint8Array, count: number, options: htfOpts): bigint[][];
|
||||
type htfOpts = {
|
||||
// DST: a domain separation tag
|
||||
// defined in section 2.2.5
|
||||
DST: string;
|
||||
// p: the characteristic of F
|
||||
// where F is a finite field of characteristic p and order q = p^m
|
||||
p: bigint;
|
||||
// m: the extension degree of F, m >= 1
|
||||
// where F is a finite field of characteristic p and order q = p^m
|
||||
m: number;
|
||||
// k: the target security level for the suite in bits
|
||||
// defined in section 5.1
|
||||
k: number;
|
||||
// option to use a message that has already been processed by
|
||||
// expand_message_xmd
|
||||
expand?: 'xmd' | 'xof';
|
||||
// Hash functions for: expand_message_xmd is appropriate for use with a
|
||||
// wide range of hash functions, including SHA-2, SHA-3, BLAKE2, and others.
|
||||
// BBS+ uses blake2: https://github.com/hyperledger/aries-framework-go/issues/2247
|
||||
// TODO: verify that hash is shake if expand==='xof' via types
|
||||
hash: CHash;
|
||||
};
|
||||
```
|
||||
|
||||
### abstract/poseidon: Poseidon hash
|
||||
|
||||
Implements [Poseidon](https://www.poseidon-hash.info) ZK-friendly hash.
|
||||
|
||||
There are many poseidon instances with different constants. We don't provide them,
|
||||
but we provide ability to specify them manually. For actual usage, check out
|
||||
stark curve source code.
|
||||
|
||||
```ts
|
||||
import { poseidon } from '@noble/curves/abstract/poseidon';
|
||||
|
||||
type PoseidonOpts = {
|
||||
Fp: Field<bigint>;
|
||||
t: number;
|
||||
roundsFull: number;
|
||||
roundsPartial: number;
|
||||
sboxPower?: number;
|
||||
reversePartialPowIdx?: boolean; // Hack for stark
|
||||
mds: bigint[][];
|
||||
roundConstants: bigint[][];
|
||||
};
|
||||
const instance = poseidon(opts: PoseidonOpts);
|
||||
```
|
||||
|
||||
### abstract/modular
|
||||
|
||||
Modular arithmetics utilities.
|
||||
|
||||
```typescript
|
||||
import { Fp, mod, invert, div, invertBatch, sqrt } from '@noble/curves/abstract/modular';
|
||||
const fp = Fp(2n ** 255n - 19n); // Finite field over 2^255-19
|
||||
fp.mul(591n, 932n);
|
||||
fp.pow(481n, 11024858120n);
|
||||
|
||||
// Generic non-FP utils are also available
|
||||
mod(21n, 10n); // 21 mod 10 == 1n; fixed version of 21 % 10
|
||||
invert(17n, 10n); // invert(17) mod 10; modular multiplicative inverse
|
||||
div(5n, 17n, 10n); // 5/17 mod 10 == 5 * invert(17) mod 10; division
|
||||
invertBatch([1n, 2n, 4n], 21n); // => [1n, 11n, 16n] in one inversion
|
||||
sqrt(21n, 73n); // √21 mod 73; square root
|
||||
```
|
||||
|
||||
### abstract/utils
|
||||
|
||||
```typescript
|
||||
import * as utils from '@noble/curves/abstract/utils';
|
||||
|
||||
utils.bytesToHex(Uint8Array.from([0xde, 0xad, 0xbe, 0xef]));
|
||||
utils.hexToBytes('deadbeef');
|
||||
utils.hexToNumber();
|
||||
utils.bytesToNumberBE(Uint8Array.from([0xde, 0xad, 0xbe, 0xef]));
|
||||
utils.bytesToNumberLE(Uint8Array.from([0xde, 0xad, 0xbe, 0xef]));
|
||||
utils.numberToBytesBE(123n);
|
||||
utils.numberToBytesLE(123n);
|
||||
utils.numberToHexUnpadded(123n);
|
||||
utils.concatBytes(Uint8Array.from([0xde, 0xad]), Uint8Array.from([0xbe, 0xef]));
|
||||
utils.nLength(255n);
|
||||
utils.hashToPrivateScalar(sha512_of_something, secp256r1.n);
|
||||
utils.equalBytes(Uint8Array.from([0xde]), Uint8Array.from([0xde]));
|
||||
```
|
||||
|
||||
## Security
|
||||
|
||||
The library had no prior security audit.
|
||||
|
||||
[Timing attack](https://en.wikipedia.org/wiki/Timing_attack) considerations: _JIT-compiler_ and _Garbage Collector_ make "constant time" extremely hard to achieve in a scripting language. Which means _any other JS library can't have constant-timeness_. Even statically typed Rust, a language without GC, [makes it harder to achieve constant-time](https://www.chosenplaintext.ca/open-source/rust-timing-shield/security) for some cases. If your goal is absolute security, don't use any JS lib — including bindings to native ones. Use low-level libraries & languages. Nonetheless we're targetting algorithmic constant time.
|
||||
|
||||
We consider infrastructure attacks like rogue NPM modules very important; that's why it's crucial to minimize the amount of 3rd-party dependencies & native bindings. If your app uses 500 dependencies, any dep could get hacked and you'll be downloading malware with every `npm install`. Our goal is to minimize this attack vector.
|
||||
|
||||
## Speed
|
||||
|
||||
Benchmark results on Apple M2 with node v18.10:
|
||||
|
||||
```
|
||||
secp256k1
|
||||
init x 57 ops/sec @ 17ms/op
|
||||
getPublicKey x 4,946 ops/sec @ 202μs/op
|
||||
sign x 3,914 ops/sec @ 255μs/op
|
||||
verify x 682 ops/sec @ 1ms/op
|
||||
getSharedSecret x 427 ops/sec @ 2ms/op
|
||||
recoverPublicKey x 683 ops/sec @ 1ms/op
|
||||
schnorr.sign x 539 ops/sec @ 1ms/op
|
||||
schnorr.verify x 716 ops/sec @ 1ms/op
|
||||
|
||||
P256
|
||||
init x 30 ops/sec @ 32ms/op
|
||||
getPublicKey x 5,008 ops/sec @ 199μs/op
|
||||
sign x 3,970 ops/sec @ 251μs/op
|
||||
verify x 515 ops/sec @ 1ms/op
|
||||
|
||||
P384
|
||||
init x 14 ops/sec @ 66ms/op
|
||||
getPublicKey x 2,434 ops/sec @ 410μs/op
|
||||
sign x 1,942 ops/sec @ 514μs/op
|
||||
verify x 206 ops/sec @ 4ms/op
|
||||
|
||||
P521
|
||||
init x 7 ops/sec @ 126ms/op
|
||||
getPublicKey x 1,282 ops/sec @ 779μs/op
|
||||
sign x 1,077 ops/sec @ 928μs/op
|
||||
verify x 110 ops/sec @ 9ms/op
|
||||
|
||||
ed25519
|
||||
init x 37 ops/sec @ 26ms/op
|
||||
getPublicKey x 8,147 ops/sec @ 122μs/op
|
||||
sign x 3,979 ops/sec @ 251μs/op
|
||||
verify x 848 ops/sec @ 1ms/op
|
||||
|
||||
ed448
|
||||
init x 17 ops/sec @ 58ms/op
|
||||
getPublicKey x 3,083 ops/sec @ 324μs/op
|
||||
sign x 1,473 ops/sec @ 678μs/op
|
||||
verify x 323 ops/sec @ 3ms/op
|
||||
|
||||
bls12-381
|
||||
init x 30 ops/sec @ 33ms/op
|
||||
getPublicKey x 788 ops/sec @ 1ms/op
|
||||
sign x 45 ops/sec @ 21ms/op
|
||||
verify x 32 ops/sec @ 30ms/op
|
||||
pairing x 88 ops/sec @ 11ms/op
|
||||
|
||||
stark
|
||||
init x 31 ops/sec @ 31ms/op
|
||||
pedersen
|
||||
├─old x 84 ops/sec @ 11ms/op
|
||||
└─noble x 802 ops/sec @ 1ms/op
|
||||
poseidon x 7,466 ops/sec @ 133μs/op
|
||||
verify
|
||||
├─old x 300 ops/sec @ 3ms/op
|
||||
└─noble x 474 ops/sec @ 2ms/op
|
||||
```
|
||||
|
||||
## Upgrading
|
||||
|
||||
If you're coming from single-curve noble packages, the following changes need to be kept in mind:
|
||||
|
||||
- 2d affine (x, y) points have been removed to reduce complexity and improve speed
|
||||
- Removed `number` support as a type for private keys. `bigint` is still supported
|
||||
- `mod`, `invert` are no longer present in `utils`. Use `@noble/curves/abstract/modular.js` now.
|
||||
|
||||
Upgrading from @noble/secp256k1 1.7:
|
||||
|
||||
- Compressed (33-byte) public keys are now returned by default, instead of uncompressed
|
||||
- Methods are now synchronous. Setting `secp.utils.hmacSha256` is no longer required
|
||||
- `sign()`
|
||||
- `der`, `recovered` options were removed
|
||||
- `canonical` was renamed to `lowS`
|
||||
- Return type is now `{ r: bigint, s: bigint, recovery: number }` instance of `Signature`
|
||||
- `verify()`
|
||||
- `strict` was renamed to `lowS`
|
||||
- `recoverPublicKey()`: moved to sig instance `Signature#recoverPublicKey(msgHash)`
|
||||
- `Point` was removed: use `ProjectivePoint` in xyz coordinates
|
||||
- `utils`: Many methods were removed, others were moved to `schnorr` namespace
|
||||
|
||||
Upgrading from @noble/ed25519 1.7:
|
||||
|
||||
- Methods are now synchronous. Setting `secp.utils.hmacSha256` is no longer required
|
||||
- ed25519ph, ed25519ctx
|
||||
- `Point` was removed: use `ExtendedPoint` in xyzt coordinates
|
||||
- `Signature` was removed
|
||||
- `getSharedSecret` was removed: use separate x25519 sub-module
|
||||
- `bigint` is no longer allowed in `getPublicKey`, `sign`, `verify`. Reason: ed25519 is LE, can lead to bugs
|
||||
|
||||
## Contributing & testing
|
||||
|
||||
1. Clone the repository
|
||||
2. `npm install` to install build dependencies like TypeScript
|
||||
3. `npm run build` to compile TypeScript code
|
||||
4. `npm run test` will execute all main tests
|
||||
|
||||
## License
|
||||
|
||||
MIT (c) Paul Miller [(https://paulmillr.com)](https://paulmillr.com), see LICENSE file.
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2022 Paul Miller [(https://paulmillr.com)](https://paulmillr.com)
|
||||
|
||||
See LICENSE file.
|
||||
|
||||
18
SECURITY.md
Normal file
18
SECURITY.md
Normal file
@@ -0,0 +1,18 @@
|
||||
# Security Policy
|
||||
|
||||
## Supported Versions
|
||||
|
||||
| Version | Supported |
|
||||
| ------- | ------------------ |
|
||||
| >=0.5.0 | :white_check_mark: |
|
||||
| <0.5.0 | :x: |
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
Use maintainer's email specified at https://github.com/paulmillr.
|
||||
|
||||
It's preferred that you use
|
||||
PGP key from [pgp proof](https://paulmillr.com/pgp_proof.txt) (current is [697079DA6878B89B](https://paulmillr.com/pgp_proof.txt)).
|
||||
Ensure the pgp proof page has maintainer's site/github specified.
|
||||
|
||||
You will get an update as soon as the email is read; a "Security vulnerability" phrase in email's title would help.
|
||||
7
benchmark/_shared.js
Normal file
7
benchmark/_shared.js
Normal file
@@ -0,0 +1,7 @@
|
||||
export function generateData(curve) {
|
||||
const priv = curve.utils.randomPrivateKey();
|
||||
const pub = curve.getPublicKey(priv);
|
||||
const msg = curve.utils.randomPrivateKey();
|
||||
const sig = curve.sign(msg, priv);
|
||||
return { priv, pub, msg, sig };
|
||||
}
|
||||
52
benchmark/bls.js
Normal file
52
benchmark/bls.js
Normal file
@@ -0,0 +1,52 @@
|
||||
import { readFileSync } from 'fs';
|
||||
import { mark, run } from 'micro-bmark';
|
||||
import { bls12_381 as bls } from '../lib/bls12-381.js';
|
||||
|
||||
const G2_VECTORS = readFileSync('../test/bls12-381/bls12-381-g2-test-vectors.txt', 'utf-8')
|
||||
.trim()
|
||||
.split('\n')
|
||||
.map((l) => l.split(':'));
|
||||
|
||||
run(async () => {
|
||||
console.log(`\x1b[36mbls12-381\x1b[0m`);
|
||||
let p1, p2, sig;
|
||||
await mark('init', 1, () => {
|
||||
p1 =
|
||||
bls.G1.ProjectivePoint.BASE.multiply(
|
||||
0x28b90deaf189015d3a325908c5e0e4bf00f84f7e639b056ff82d7e70b6eede4cn
|
||||
);
|
||||
p2 =
|
||||
bls.G2.ProjectivePoint.BASE.multiply(
|
||||
0x28b90deaf189015d3a325908c5e0e4bf00f84f7e639b056ff82d7e70b6eede4dn
|
||||
);
|
||||
bls.pairing(p1, p2);
|
||||
});
|
||||
const priv = '28b90deaf189015d3a325908c5e0e4bf00f84f7e639b056ff82d7e70b6eede4c';
|
||||
sig = bls.sign('09', priv);
|
||||
const pubs = G2_VECTORS.map((v) => bls.getPublicKey(v[0]));
|
||||
const sigs = G2_VECTORS.map((v) => v[2]);
|
||||
const pub = bls.getPublicKey(priv);
|
||||
const pub512 = pubs.slice(0, 512); // .map(bls.PointG1.fromHex)
|
||||
const pub32 = pub512.slice(0, 32);
|
||||
const pub128 = pub512.slice(0, 128);
|
||||
const pub2048 = pub512.concat(pub512, pub512, pub512);
|
||||
const sig512 = sigs.slice(0, 512); // .map(bls.PointG2.fromSignature);
|
||||
const sig32 = sig512.slice(0, 32);
|
||||
const sig128 = sig512.slice(0, 128);
|
||||
const sig2048 = sig512.concat(sig512, sig512, sig512);
|
||||
await mark('getPublicKey 1-bit', 1000, () => bls.getPublicKey('2'.padStart(64, '0')));
|
||||
await mark('getPublicKey', 1000, () => bls.getPublicKey(priv));
|
||||
await mark('sign', 50, () => bls.sign('09', priv));
|
||||
await mark('verify', 50, () => bls.verify(sig, '09', pub));
|
||||
await mark('pairing', 100, () => bls.pairing(p1, p2));
|
||||
await mark('aggregatePublicKeys/8', 100, () => bls.aggregatePublicKeys(pubs.slice(0, 8)));
|
||||
await mark('aggregatePublicKeys/32', 50, () => bls.aggregatePublicKeys(pub32));
|
||||
await mark('aggregatePublicKeys/128', 20, () => bls.aggregatePublicKeys(pub128));
|
||||
await mark('aggregatePublicKeys/512', 10, () => bls.aggregatePublicKeys(pub512));
|
||||
await mark('aggregatePublicKeys/2048', 5, () => bls.aggregatePublicKeys(pub2048));
|
||||
await mark('aggregateSignatures/8', 100, () => bls.aggregateSignatures(sigs.slice(0, 8)));
|
||||
await mark('aggregateSignatures/32', 50, () => bls.aggregateSignatures(sig32));
|
||||
await mark('aggregateSignatures/128', 20, () => bls.aggregateSignatures(sig128));
|
||||
await mark('aggregateSignatures/512', 10, () => bls.aggregateSignatures(sig512));
|
||||
await mark('aggregateSignatures/2048', 5, () => bls.aggregateSignatures(sig2048));
|
||||
});
|
||||
23
benchmark/curves.js
Normal file
23
benchmark/curves.js
Normal file
@@ -0,0 +1,23 @@
|
||||
import { run, mark, utils } from 'micro-bmark';
|
||||
import { generateData } from './_shared.js';
|
||||
import { P256 } from '../lib/p256.js';
|
||||
import { P384 } from '../lib/p384.js';
|
||||
import { P521 } from '../lib/p521.js';
|
||||
import { ed25519 } from '../lib/ed25519.js';
|
||||
import { ed448 } from '../lib/ed448.js';
|
||||
|
||||
run(async () => {
|
||||
const RAM = false
|
||||
for (let kv of Object.entries({ P256, P384, P521, ed25519, ed448 })) {
|
||||
const [name, curve] = kv;
|
||||
console.log();
|
||||
console.log(`\x1b[36m${name}\x1b[0m`);
|
||||
if (RAM) utils.logMem();
|
||||
await mark('init', 1, () => curve.utils.precompute(8));
|
||||
const d = generateData(curve);
|
||||
await mark('getPublicKey', 5000, () => curve.getPublicKey(d.priv));
|
||||
await mark('sign', 5000, () => curve.sign(d.msg, d.priv));
|
||||
await mark('verify', 500, () => curve.verify(d.sig, d.msg, d.pub));
|
||||
if (RAM) utils.logMem();
|
||||
}
|
||||
});
|
||||
22
benchmark/package.json
Normal file
22
benchmark/package.json
Normal file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"name": "benchmark",
|
||||
"private": true,
|
||||
"version": "0.1.0",
|
||||
"description": "benchmarks",
|
||||
"main": "index.js",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"bench": "node index.js"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"micro-bmark": "0.3.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@noble/hashes": "^1.1.5",
|
||||
"@starkware-industries/starkware-crypto-utils": "^0.0.2",
|
||||
"elliptic": "^6.5.4"
|
||||
}
|
||||
}
|
||||
22
benchmark/secp256k1.js
Normal file
22
benchmark/secp256k1.js
Normal file
@@ -0,0 +1,22 @@
|
||||
import { run, mark, utils } from 'micro-bmark';
|
||||
import { secp256k1, schnorr } from '../lib/secp256k1.js';
|
||||
import { generateData } from './_shared.js';
|
||||
|
||||
run(async () => {
|
||||
const RAM = false;
|
||||
if (RAM) utils.logMem();
|
||||
console.log(`\x1b[36msecp256k1\x1b[0m`);
|
||||
await mark('init', 1, () => secp256k1.utils.precompute(8));
|
||||
const d = generateData(secp256k1);
|
||||
await mark('getPublicKey', 10000, () => secp256k1.getPublicKey(d.priv));
|
||||
await mark('sign', 10000, () => secp256k1.sign(d.msg, d.priv));
|
||||
await mark('verify', 1000, () => secp256k1.verify(d.sig, d.msg, d.pub));
|
||||
const pub2 = secp256k1.getPublicKey(secp256k1.utils.randomPrivateKey());
|
||||
await mark('getSharedSecret', 1000, () => secp256k1.getSharedSecret(d.priv, pub2));
|
||||
await mark('recoverPublicKey', 1000, () => d.sig.recoverPublicKey(d.msg));
|
||||
const s = schnorr.sign(d.msg, d.priv);
|
||||
const spub = schnorr.getPublicKey(d.priv);
|
||||
await mark('schnorr.sign', 1000, () => schnorr.sign(d.msg, d.priv));
|
||||
await mark('schnorr.verify', 1000, () => schnorr.verify(s, d.msg, spub));
|
||||
if (RAM) utils.logMem();
|
||||
});
|
||||
56
benchmark/stark.js
Normal file
56
benchmark/stark.js
Normal file
@@ -0,0 +1,56 @@
|
||||
import { run, mark, compare, utils } from 'micro-bmark';
|
||||
import * as starkwareCrypto from '@starkware-industries/starkware-crypto-utils';
|
||||
import * as stark from '../lib/stark.js';
|
||||
|
||||
run(async () => {
|
||||
const RAM = false;
|
||||
if (RAM) utils.logMem();
|
||||
console.log(`\x1b[36mstark\x1b[0m`);
|
||||
await mark('init', 1, () => stark.utils.precompute(8));
|
||||
const d = (() => {
|
||||
const priv = '2dccce1da22003777062ee0870e9881b460a8b7eca276870f57c601f182136c';
|
||||
const msg = 'c465dd6b1bbffdb05442eb17f5ca38ad1aa78a6f56bf4415bdee219114a47';
|
||||
const pub = stark.getPublicKey(priv);
|
||||
const sig = stark.sign(msg, priv);
|
||||
|
||||
const privateKey = '2dccce1da22003777062ee0870e9881b460a8b7eca276870f57c601f182136c';
|
||||
const msgHash = 'c465dd6b1bbffdb05442eb17f5ca38ad1aa78a6f56bf4415bdee219114a47';
|
||||
const keyPair = starkwareCrypto.default.ec.keyFromPrivate(privateKey, 'hex');
|
||||
const publicKeyStark = starkwareCrypto.default.ec.keyFromPublic(
|
||||
keyPair.getPublic(true, 'hex'),
|
||||
'hex'
|
||||
);
|
||||
return { priv, sig, msg, pub, publicKeyStark, msgHash, keyPair };
|
||||
})();
|
||||
await compare('pedersen', 500, {
|
||||
old: () => {
|
||||
return starkwareCrypto.default.pedersen([
|
||||
'3d937c035c878245caf64531a5756109c53068da139362728feb561405371cb',
|
||||
'208a0a10250e382e1e4bbe2880906c2791bf6275695e02fbbc6aeff9cd8b31a',
|
||||
]);
|
||||
},
|
||||
noble: () => {
|
||||
return stark.pedersen(
|
||||
'3d937c035c878245caf64531a5756109c53068da139362728feb561405371cb',
|
||||
'208a0a10250e382e1e4bbe2880906c2791bf6275695e02fbbc6aeff9cd8b31a'
|
||||
);
|
||||
},
|
||||
});
|
||||
await mark('poseidon', 10000, () => stark.poseidonHash(
|
||||
0x3d937c035c878245caf64531a5756109c53068da139362728feb561405371cbn,
|
||||
0x208a0a10250e382e1e4bbe2880906c2791bf6275695e02fbbc6aeff9cd8b31an
|
||||
));
|
||||
await compare('verify', 500, {
|
||||
old: () => {
|
||||
return starkwareCrypto.default.verify(
|
||||
d.publicKeyStark,
|
||||
d.msgHash,
|
||||
starkwareCrypto.default.sign(d.keyPair, d.msgHash)
|
||||
);
|
||||
},
|
||||
noble: () => {
|
||||
return stark.verify(stark.sign(d.msg, d.priv), d.msg, d.pub);
|
||||
},
|
||||
});
|
||||
if (RAM) utils.logMem();
|
||||
});
|
||||
@@ -1,21 +0,0 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2022 Paul Miller (https://paulmillr.com)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the “Software”), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
@@ -1,28 +0,0 @@
|
||||
# micro-curve-definitions
|
||||
|
||||
Elliptic curves implementations. `@noble/curves` is zero-dependency library for internal arithmetics.
|
||||
|
||||
`micro-curve-definitions` is the actual implementations. Current functionality:
|
||||
|
||||
- NIST curves: P192, P224, P256, P384, P521 (ECDSA)
|
||||
- secp256k1 (ECDSA, without Schnorr)
|
||||
- stark curve
|
||||
- bn254
|
||||
|
||||
Pairings are not implemented.
|
||||
|
||||
## Usage
|
||||
|
||||
```sh
|
||||
npm install micro-curve-definitions
|
||||
```
|
||||
|
||||
```ts
|
||||
import * as nist from 'micro-curve-definitions';
|
||||
|
||||
// P192, P224, P256, P384, P521, bn254
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
MIT (c) Paul Miller [(https://paulmillr.com)](https://paulmillr.com), see LICENSE file.
|
||||
@@ -1,62 +0,0 @@
|
||||
{
|
||||
"name": "micro-curve-definitions",
|
||||
"version": "0.1.0",
|
||||
"description": "Curve definitions for @noble/curves",
|
||||
"files": [
|
||||
"index.js",
|
||||
"index.d.ts",
|
||||
"index.d.ts.map",
|
||||
"index.ts"
|
||||
],
|
||||
"type": "module",
|
||||
"main": "index.js",
|
||||
"module": "index.js",
|
||||
"types": "index.d.ts",
|
||||
"dependencies": {
|
||||
"@noble/curves": "~0.1.0",
|
||||
"@noble/hashes": "1.1.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@scure/base": "~1.1.0",
|
||||
"@scure/bip32": "^1.1.1",
|
||||
"@scure/bip39": "^1.1.0",
|
||||
"@types/node": "^18.11.3",
|
||||
"fast-check": "3.0.0",
|
||||
"micro-should": "0.2.0",
|
||||
"prettier": "2.6.2",
|
||||
"typescript": "4.7.3"
|
||||
},
|
||||
"author": "Paul Miller (https://paulmillr.com)",
|
||||
"license": "MIT",
|
||||
"homepage": "https://github.com/paulmillr/noble-curves",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/paulmillr/noble-curves.git"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "tsc",
|
||||
"lint": "prettier --check index.ts",
|
||||
"test": "node test/index.test.js"
|
||||
},
|
||||
"keywords": [
|
||||
"secp192r1",
|
||||
"secp224r1",
|
||||
"secp256r1",
|
||||
"secp384r1",
|
||||
"secp521r1",
|
||||
"NIST P192",
|
||||
"NIST P224",
|
||||
"NIST P256",
|
||||
"NIST P384",
|
||||
"NIST P521",
|
||||
"NIST curves",
|
||||
"EC",
|
||||
"elliptic curves"
|
||||
],
|
||||
"funding": [
|
||||
{
|
||||
"type": "individual",
|
||||
"url": "https://paulmillr.com/funding/"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
/*! @noble/curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
||||
import { weierstrass, CHash } from '@noble/curves/shortw';
|
||||
import { concatBytes, randomBytes } from '@noble/hashes/utils';
|
||||
import { hmac } from '@noble/hashes/hmac';
|
||||
import { sha256 } from '@noble/hashes/sha256';
|
||||
|
||||
function getHash(hash: CHash) {
|
||||
return {
|
||||
hash,
|
||||
hmac: (key: Uint8Array, ...msgs: Uint8Array[]) => hmac(hash, key, concatBytes(...msgs)),
|
||||
randomBytes,
|
||||
};
|
||||
}
|
||||
|
||||
// Was known as alt_bn128 when it had 128-bit security. Now that it's much lower, the naming
|
||||
// has been changed to its prime bit count.
|
||||
export const bn254 = weierstrass({
|
||||
a: 0n,
|
||||
b: 3n,
|
||||
P: 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47n,
|
||||
n: 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001n,
|
||||
Gx: 1n,
|
||||
Gy: 2n,
|
||||
...getHash(sha256),
|
||||
});
|
||||
@@ -1,190 +0,0 @@
|
||||
/*! @noble/curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
||||
import { hmac } from '@noble/hashes/hmac';
|
||||
import { sha256 } from '@noble/hashes/sha256';
|
||||
import { sha384, sha512 } from '@noble/hashes/sha512';
|
||||
import { concatBytes, randomBytes } from '@noble/hashes/utils';
|
||||
import { weierstrass, CHash } from '@noble/curves/shortw';
|
||||
import { mod, pow2 } from '@noble/curves/modular';
|
||||
|
||||
function getHash(hash: CHash) {
|
||||
return {
|
||||
hash,
|
||||
hmac: (key: Uint8Array, ...msgs: Uint8Array[]) => hmac(hash, key, concatBytes(...msgs)),
|
||||
randomBytes,
|
||||
};
|
||||
}
|
||||
|
||||
// https://www.secg.org/sec2-v2.pdf
|
||||
// https://neuromancer.sk/std/secg/secp192r1
|
||||
export const P192 = weierstrass({
|
||||
// Params: a, b
|
||||
a: BigInt('0xfffffffffffffffffffffffffffffffefffffffffffffffc'),
|
||||
b: BigInt('0x64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1'),
|
||||
// Field over which we'll do calculations. Verify with: 2n ** 192n - 2n ** 64n - 1n
|
||||
P: BigInt('0xfffffffffffffffffffffffffffffffeffffffffffffffff'),
|
||||
// Curve order, total count of valid points in the field. Verify with:
|
||||
n: BigInt('0xffffffffffffffffffffffff99def836146bc9b1b4d22831'),
|
||||
// Base point (x, y) aka generator point
|
||||
Gx: BigInt('0x188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012'),
|
||||
Gy: BigInt('0x07192b95ffc8da78631011ed6b24cdd573f977a11e794811'),
|
||||
lowS: false,
|
||||
// Default options
|
||||
...getHash(sha256),
|
||||
} as const);
|
||||
export const secp192r1 = P192;
|
||||
// https://neuromancer.sk/std/nist/P-224
|
||||
export const P224 = weierstrass({
|
||||
// Params: a, b
|
||||
a: BigInt('0xfffffffffffffffffffffffffffffffefffffffffffffffffffffffe'),
|
||||
b: BigInt('0xb4050a850c04b3abf54132565044b0b7d7bfd8ba270b39432355ffb4'),
|
||||
// Field over which we'll do calculations. Verify with:
|
||||
P: 2n ** 224n - 2n ** 96n + 1n,
|
||||
// Curve order, total count of valid points in the field. Verify with:
|
||||
n: BigInt('0xffffffffffffffffffffffffffff16a2e0b8f03e13dd29455c5c2a3d'),
|
||||
// Base point (x, y) aka generator point
|
||||
Gx: BigInt('0xb70e0cbd6bb4bf7f321390b94a03c1d356c21122343280d6115c1d21'),
|
||||
Gy: BigInt('0xbd376388b5f723fb4c22dfe6cd4375a05a07476444d5819985007e34'),
|
||||
lowS: false,
|
||||
// Default options
|
||||
...getHash(sha256),
|
||||
} as const);
|
||||
export const secp224r1 = P224;
|
||||
// https://neuromancer.sk/std/nist/P-256
|
||||
export const P256 = weierstrass({
|
||||
// Params: a, b
|
||||
a: BigInt('0xffffffff00000001000000000000000000000000fffffffffffffffffffffffc'),
|
||||
b: BigInt('0x5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b'),
|
||||
// Field over which we'll do calculations. Verify with:
|
||||
// 2n ** 224n * (2n ** 32n - 1n) + 2n ** 192n + 2n ** 96n - 1n,
|
||||
P: BigInt('0xffffffff00000001000000000000000000000000ffffffffffffffffffffffff'),
|
||||
// Curve order, total count of valid points in the field. Verify with:
|
||||
n: BigInt('0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551'),
|
||||
// Base point (x, y) aka generator point
|
||||
Gx: BigInt('0x6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296'),
|
||||
Gy: BigInt('0x4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5'),
|
||||
lowS: false,
|
||||
// Default options
|
||||
...getHash(sha256),
|
||||
} as const);
|
||||
export const secp256r1 = P256;
|
||||
// https://neuromancer.sk/std/nist/P-384
|
||||
// prettier-ignore
|
||||
export const P384 = weierstrass({
|
||||
// Params: a, b
|
||||
a: BigInt('0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000fffffffc'),
|
||||
b: BigInt('0xb3312fa7e23ee7e4988e056be3f82d19181d9c6efe8141120314088f5013875ac656398d8a2ed19d2a85c8edd3ec2aef'),
|
||||
// Field over which we'll do calculations. Verify with:
|
||||
// 2n ** 384n - 2n ** 128n - 2n ** 96n + 2n ** 32n - 1n
|
||||
P: BigInt('0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000ffffffff'),
|
||||
// Curve order, total count of valid points in the field. Verify with:
|
||||
n: BigInt('0xffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf581a0db248b0a77aecec196accc52973'),
|
||||
// Base point (x, y) aka generator point
|
||||
Gx: BigInt('0xaa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a385502f25dbf55296c3a545e3872760ab7'),
|
||||
Gy: BigInt('0x3617de4a96262c6f5d9e98bf9292dc29f8f41dbd289a147ce9da3113b5f0b8c00a60b1ce1d7e819d7a431d7c90ea0e5f'),
|
||||
lowS: false,
|
||||
// Default options
|
||||
...getHash(sha384),
|
||||
} as const);
|
||||
export const secp384r1 = P384;
|
||||
// https://neuromancer.sk/std/nist/P-521
|
||||
// prettier-ignore
|
||||
export const P521 = weierstrass({
|
||||
// Params: a, b
|
||||
a: BigInt('0x01fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc'),
|
||||
b: BigInt('0x0051953eb9618e1c9a1f929a21a0b68540eea2da725b99b315f3b8b489918ef109e156193951ec7e937b1652c0bd3bb1bf073573df883d2c34f1ef451fd46b503f00'),
|
||||
// Field over which we'll do calculations. Verify with:
|
||||
// 2n ** 521n - 1n,
|
||||
P: BigInt('0x1ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'),
|
||||
// Curve order, total count of valid points in the field. Verify with:
|
||||
n: BigInt('0x01fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa51868783bf2f966b7fcc0148f709a5d03bb5c9b8899c47aebb6fb71e91386409'),
|
||||
// Base point (x, y) aka generator point
|
||||
Gx: BigInt('0x00c6858e06b70404e9cd9e3ecb662395b4429c648139053fb521f828af606b4d3dbaa14b5e77efe75928fe1dc127a2ffa8de3348b3c1856a429bf97e7e31c2e5bd66'),
|
||||
Gy: BigInt('0x011839296a789a3bc0045c8a5fb42c7d1bd998f54449579b446817afbd17273e662c97ee72995ef42640c550b9013fad0761353c7086a272c24088be94769fd16650'),
|
||||
lowS: false,
|
||||
// Default options
|
||||
...getHash(sha512),
|
||||
} as const);
|
||||
export const secp521r1 = P521;
|
||||
|
||||
/**
|
||||
* secp256k1 definition with efficient square root and endomorphism.
|
||||
* Endomorphism works only for Koblitz curves with a == 0.
|
||||
* It improves efficiency:
|
||||
* Uses 2x less RAM, speeds up precomputation by 2x and ECDH / sign key recovery by 20%.
|
||||
* Should always be used for Jacobian's double-and-add multiplication.
|
||||
* For affines cached multiplication, it trades off 1/2 init time & 1/3 ram for 20% perf hit.
|
||||
* https://gist.github.com/paulmillr/eb670806793e84df628a7c434a873066
|
||||
*/
|
||||
const secp256k1P = BigInt('0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f');
|
||||
const secp256k1N = BigInt('0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141');
|
||||
const _1n = BigInt(1);
|
||||
const _2n = BigInt(2);
|
||||
const divNearest = (a: bigint, b: bigint) => (a + b / _2n) / b;
|
||||
export const secp256k1 = weierstrass({
|
||||
a: 0n,
|
||||
b: 7n,
|
||||
// Field over which we'll do calculations. Verify with:
|
||||
// 2n ** 256n - 2n ** 32n - 2n ** 9n - 2n ** 8n - 2n ** 7n - 2n ** 6n - 2n ** 4n - 1n
|
||||
P: secp256k1P,
|
||||
// Curve order, total count of valid points in the field. Verify with:
|
||||
n: secp256k1N,
|
||||
// Base point (x, y) aka generator point
|
||||
Gx: BigInt('55066263022277343669578718895168534326250603453777594175500187360389116729240'),
|
||||
Gy: BigInt('32670510020758816978083085130507043184471273380659243275938904335757337482424'),
|
||||
...getHash(sha256),
|
||||
// noble-secp256k1 compat
|
||||
lowS: true,
|
||||
// Used to calculate y - the square root of y².
|
||||
// Exponentiates it to very big number (P+1)/4.
|
||||
// We are unwrapping the loop because it's 2x faster.
|
||||
// (P+1n/4n).toString(2) would produce bits [223x 1, 0, 22x 1, 4x 0, 11, 00]
|
||||
// We are multiplying it bit-by-bit
|
||||
sqrtMod: (x: bigint): bigint => {
|
||||
const P = secp256k1P;
|
||||
const _3n = BigInt(3);
|
||||
const _6n = BigInt(6);
|
||||
const _11n = BigInt(11);
|
||||
const _22n = BigInt(22);
|
||||
const _23n = BigInt(23);
|
||||
const _44n = BigInt(44);
|
||||
const _88n = BigInt(88);
|
||||
const b2 = (x * x * x) % P; // x^3, 11
|
||||
const b3 = (b2 * b2 * x) % P; // x^7
|
||||
const b6 = (pow2(b3, _3n, P) * b3) % P;
|
||||
const b9 = (pow2(b6, _3n, P) * b3) % P;
|
||||
const b11 = (pow2(b9, _2n, P) * b2) % P;
|
||||
const b22 = (pow2(b11, _11n, P) * b11) % P;
|
||||
const b44 = (pow2(b22, _22n, P) * b22) % P;
|
||||
const b88 = (pow2(b44, _44n, P) * b44) % P;
|
||||
const b176 = (pow2(b88, _88n, P) * b88) % P;
|
||||
const b220 = (pow2(b176, _44n, P) * b44) % P;
|
||||
const b223 = (pow2(b220, _3n, P) * b3) % P;
|
||||
const t1 = (pow2(b223, _23n, P) * b22) % P;
|
||||
const t2 = (pow2(t1, _6n, P) * b2) % P;
|
||||
return pow2(t2, _2n, P);
|
||||
},
|
||||
endo: {
|
||||
beta: BigInt('0x7ae96a2b657c07106e64479eac3434e99cf0497512f58995c1396c28719501ee'),
|
||||
splitScalar: (k: bigint) => {
|
||||
const n = secp256k1N;
|
||||
const a1 = BigInt('0x3086d221a7d46bcde86c90e49284eb15');
|
||||
const b1 = -_1n * BigInt('0xe4437ed6010e88286f547fa90abfe4c3');
|
||||
const a2 = BigInt('0x114ca50f7a8e2f3f657c1108d9d44cfd8');
|
||||
const b2 = a1;
|
||||
const POW_2_128 = BigInt('0x100000000000000000000000000000000');
|
||||
|
||||
const c1 = divNearest(b2 * k, n);
|
||||
const c2 = divNearest(-b1 * k, n);
|
||||
let k1 = mod(k - c1 * a1 - c2 * a2, n);
|
||||
let k2 = mod(-c1 * b1 - c2 * b2, n);
|
||||
const k1neg = k1 > POW_2_128;
|
||||
const k2neg = k2 > POW_2_128;
|
||||
if (k1neg) k1 = n - k1;
|
||||
if (k2neg) k2 = n - k2;
|
||||
if (k1 > POW_2_128 || k2 > POW_2_128) {
|
||||
throw new Error('splitScalar: Endomorphism failed, k=' + k);
|
||||
}
|
||||
return { k1neg, k1, k2neg, k2 };
|
||||
},
|
||||
},
|
||||
});
|
||||
@@ -1,35 +0,0 @@
|
||||
/*! @noble/curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
||||
import { hmac } from '@noble/hashes/hmac';
|
||||
import { sha256 } from '@noble/hashes/sha256';
|
||||
import { concatBytes, randomBytes } from '@noble/hashes/utils';
|
||||
import { weierstrass, CHash } from '@noble/curves/shortw';
|
||||
|
||||
function getHash(hash: CHash) {
|
||||
return {
|
||||
hash,
|
||||
hmac: (key: Uint8Array, ...msgs: Uint8Array[]) => hmac(hash, key, concatBytes(...msgs)),
|
||||
randomBytes,
|
||||
};
|
||||
}
|
||||
const p = BigInt('0x40000000000000000000000000000000224698fc094cf91b992d30ed00000001');
|
||||
const q = BigInt('0x40000000000000000000000000000000224698fc0994a8dd8c46eb2100000001');
|
||||
|
||||
export const pallas = weierstrass({
|
||||
a: BigInt(0),
|
||||
b: BigInt(5),
|
||||
P: p,
|
||||
n: q,
|
||||
Gx: BigInt(-1),
|
||||
Gy: BigInt(2),
|
||||
...getHash(sha256),
|
||||
});
|
||||
|
||||
export const vesta = weierstrass({
|
||||
a: BigInt(0),
|
||||
b: BigInt(5),
|
||||
P: q,
|
||||
n: p,
|
||||
Gx: BigInt(-1),
|
||||
Gy: BigInt(2),
|
||||
...getHash(sha256),
|
||||
});
|
||||
@@ -1,264 +0,0 @@
|
||||
/*! @noble/curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
||||
import { keccak_256 } from '@noble/hashes/sha3';
|
||||
import { sha256 } from '@noble/hashes/sha256';
|
||||
import { hmac } from '@noble/hashes/hmac';
|
||||
import { concatBytes, randomBytes } from '@noble/hashes/utils';
|
||||
import { weierstrass, CHash, JacobianPointType } from '@noble/curves/shortw';
|
||||
import * as cutils from '@noble/curves/utils';
|
||||
|
||||
function getHash(hash: CHash) {
|
||||
return {
|
||||
hash,
|
||||
hmac: (key: Uint8Array, ...msgs: Uint8Array[]) => hmac(hash, key, concatBytes(...msgs)),
|
||||
randomBytes,
|
||||
};
|
||||
}
|
||||
|
||||
const CURVE_N = 3618502788666131213697322783095070105526743751716087489154079457884512865583n;
|
||||
const nBitLength = 252;
|
||||
// https://docs.starkware.co/starkex/stark-curve.html
|
||||
export const starkCurve = weierstrass({
|
||||
// Params: a, b
|
||||
a: 1n,
|
||||
b: 3141592653589793238462643383279502884197169399375105820974944592307816406665n,
|
||||
// Field over which we'll do calculations. Verify with:
|
||||
// NOTE: there is no efficient sqrt for field (P%4==1)
|
||||
P: 2n ** 251n + 17n * 2n ** 192n + 1n,
|
||||
// Curve order, total count of valid points in the field. Verify with:
|
||||
n: CURVE_N,
|
||||
nBitLength: nBitLength, // len(bin(N).replace('0b',''))
|
||||
// Base point (x, y) aka generator point
|
||||
Gx: 874739451078007766457464989774322083649278607533249481151382481072868806602n,
|
||||
Gy: 152666792071518830868575557812948353041420400780739481342941381225525861407n,
|
||||
// Default options
|
||||
lowS: false,
|
||||
...getHash(sha256),
|
||||
truncateHash: (hash: Uint8Array, truncateOnly = false): bigint => {
|
||||
// TODO: cleanup, ugly code
|
||||
// Fix truncation
|
||||
if (!truncateOnly) {
|
||||
let hashS = bytesToNumber0x(hash).toString(16);
|
||||
if (hashS.length === 63) {
|
||||
hashS += '0';
|
||||
hash = hexToBytes0x(hashS);
|
||||
}
|
||||
}
|
||||
// Truncate zero bytes on left (compat with elliptic)
|
||||
while (hash[0] === 0) hash = hash.subarray(1);
|
||||
const byteLength = hash.length;
|
||||
const delta = byteLength * 8 - nBitLength; // size of curve.n (252 bits)
|
||||
let h = hash.length ? bytesToNumber0x(hash) : 0n;
|
||||
if (delta > 0) h = h >> BigInt(delta);
|
||||
if (!truncateOnly && h >= CURVE_N) h -= CURVE_N;
|
||||
return h;
|
||||
},
|
||||
});
|
||||
|
||||
// Custom Starknet type conversion functions that can handle 0x and unpadded hex
|
||||
function hexToBytes0x(hex: string): Uint8Array {
|
||||
if (typeof hex !== 'string') {
|
||||
throw new TypeError('hexToBytes: expected string, got ' + typeof hex);
|
||||
}
|
||||
hex = strip0x(hex);
|
||||
if (hex.length & 1) hex = '0' + hex; // padding
|
||||
if (hex.length % 2) throw new Error('hexToBytes: received invalid unpadded hex ' + hex.length);
|
||||
const array = new Uint8Array(hex.length / 2);
|
||||
for (let i = 0; i < array.length; i++) {
|
||||
const j = i * 2;
|
||||
const hexByte = hex.slice(j, j + 2);
|
||||
const byte = Number.parseInt(hexByte, 16);
|
||||
if (Number.isNaN(byte) || byte < 0) throw new Error('Invalid byte sequence');
|
||||
array[i] = byte;
|
||||
}
|
||||
return array;
|
||||
}
|
||||
function hexToNumber0x(hex: string): bigint {
|
||||
if (typeof hex !== 'string') {
|
||||
throw new TypeError('hexToNumber: expected string, got ' + typeof hex);
|
||||
}
|
||||
// Big Endian
|
||||
// TODO: strip vs no strip?
|
||||
return BigInt(`0x${strip0x(hex)}`);
|
||||
}
|
||||
function bytesToNumber0x(bytes: Uint8Array): bigint {
|
||||
return hexToNumber0x(cutils.bytesToHex(bytes));
|
||||
}
|
||||
function ensureBytes0x(hex: Hex): Uint8Array {
|
||||
// Uint8Array.from() instead of hash.slice() because node.js Buffer
|
||||
// is instance of Uint8Array, and its slice() creates **mutable** copy
|
||||
return hex instanceof Uint8Array ? Uint8Array.from(hex) : hexToBytes0x(hex);
|
||||
}
|
||||
|
||||
function sign0x(msgHash: Hex, privKey: Hex, opts: any) {
|
||||
return starkCurve.sign(ensureBytes0x(msgHash), ensureBytes0x(privKey), opts);
|
||||
}
|
||||
function verify0x(signature: Hex, msgHash: Hex, pubKey: Hex) {
|
||||
const sig = signature instanceof Signature ? signature : ensureBytes0x(signature);
|
||||
return starkCurve.verify(sig, ensureBytes0x(msgHash), ensureBytes0x(pubKey));
|
||||
}
|
||||
|
||||
const { CURVE, Point, JacobianPoint, Signature, getPublicKey, getSharedSecret } = starkCurve;
|
||||
export const utils = starkCurve.utils;
|
||||
export {
|
||||
CURVE,
|
||||
Point,
|
||||
Signature,
|
||||
JacobianPoint,
|
||||
getPublicKey,
|
||||
getSharedSecret,
|
||||
sign0x as sign,
|
||||
verify0x as verify,
|
||||
};
|
||||
|
||||
const stripLeadingZeros = (s: string) => s.replace(/^0+/gm, '');
|
||||
export const bytesToHexEth = (uint8a: Uint8Array): string =>
|
||||
`0x${stripLeadingZeros(cutils.bytesToHex(uint8a))}`;
|
||||
export const strip0x = (hex: string) => hex.replace(/^0x/i, '');
|
||||
export const numberToHexEth = (num: bigint | number) => `0x${num.toString(16)}`;
|
||||
|
||||
// We accept hex strings besides Uint8Array for simplicity
|
||||
type Hex = Uint8Array | string;
|
||||
|
||||
// 1. seed generation
|
||||
function hashKeyWithIndex(key: Uint8Array, index: number) {
|
||||
let indexHex = cutils.numberToHexUnpadded(index);
|
||||
if (indexHex.length & 1) indexHex = '0' + indexHex;
|
||||
return bytesToNumber0x(sha256(cutils.concatBytes(key, hexToBytes0x(indexHex))));
|
||||
}
|
||||
|
||||
export function grindKey(seed: Hex) {
|
||||
const _seed = ensureBytes0x(seed);
|
||||
const sha256mask = 2n ** 256n;
|
||||
const limit = sha256mask - starkCurve.utils.mod(sha256mask, starkCurve.CURVE.n);
|
||||
for (let i = 0; ; i++) {
|
||||
const key = hashKeyWithIndex(_seed, i);
|
||||
// key should be in [0, limit)
|
||||
if (key < limit) return starkCurve.utils.mod(key, starkCurve.CURVE.n).toString(16);
|
||||
}
|
||||
}
|
||||
|
||||
export function getStarkKey(privateKey: Hex) {
|
||||
const priv = typeof privateKey === 'string' ? strip0x(privateKey) : privateKey;
|
||||
return bytesToHexEth(Point.fromPrivateKey(priv).toRawBytes(true).slice(1));
|
||||
}
|
||||
|
||||
export function ethSigToPrivate(signature: string) {
|
||||
signature = strip0x(signature.replace(/^0x/, ''));
|
||||
if (signature.length !== 130) throw new Error('Wrong ethereum signature');
|
||||
return grindKey(signature.substring(0, 64));
|
||||
}
|
||||
|
||||
const MASK_31 = 2n ** 31n - 1n;
|
||||
const int31 = (n: bigint) => Number(n & MASK_31);
|
||||
export function getAccountPath(
|
||||
layer: string,
|
||||
application: string,
|
||||
ethereumAddress: string,
|
||||
index: number
|
||||
) {
|
||||
const layerNum = int31(bytesToNumber0x(sha256(layer)));
|
||||
const applicationNum = int31(bytesToNumber0x(sha256(application)));
|
||||
const eth = hexToNumber0x(ethereumAddress);
|
||||
return `m/2645'/${layerNum}'/${applicationNum}'/${int31(eth)}'/${int31(eth >> 31n)}'/${index}`;
|
||||
}
|
||||
|
||||
// https://docs.starkware.co/starkex/pedersen-hash-function.html
|
||||
const PEDERSEN_POINTS = [
|
||||
new Point(
|
||||
2089986280348253421170679821480865132823066470938446095505822317253594081284n,
|
||||
1713931329540660377023406109199410414810705867260802078187082345529207694986n
|
||||
),
|
||||
new Point(
|
||||
996781205833008774514500082376783249102396023663454813447423147977397232763n,
|
||||
1668503676786377725805489344771023921079126552019160156920634619255970485781n
|
||||
),
|
||||
new Point(
|
||||
2251563274489750535117886426533222435294046428347329203627021249169616184184n,
|
||||
1798716007562728905295480679789526322175868328062420237419143593021674992973n
|
||||
),
|
||||
new Point(
|
||||
2138414695194151160943305727036575959195309218611738193261179310511854807447n,
|
||||
113410276730064486255102093846540133784865286929052426931474106396135072156n
|
||||
),
|
||||
new Point(
|
||||
2379962749567351885752724891227938183011949129833673362440656643086021394946n,
|
||||
776496453633298175483985398648758586525933812536653089401905292063708816422n
|
||||
),
|
||||
];
|
||||
// for (const p of PEDERSEN_POINTS) p._setWindowSize(8);
|
||||
const PEDERSEN_POINTS_JACOBIAN = PEDERSEN_POINTS.map(JacobianPoint.fromAffine);
|
||||
|
||||
function pedersenPrecompute(p1: JacobianPointType, p2: JacobianPointType): JacobianPointType[] {
|
||||
const out: JacobianPointType[] = [];
|
||||
let p = p1;
|
||||
for (let i = 0; i < 248; i++) {
|
||||
out.push(p);
|
||||
p = p.double();
|
||||
}
|
||||
p = p2;
|
||||
for (let i = 0; i < 4; i++) {
|
||||
out.push(p);
|
||||
p = p.double();
|
||||
}
|
||||
return out;
|
||||
}
|
||||
const PEDERSEN_POINTS1 = pedersenPrecompute(
|
||||
PEDERSEN_POINTS_JACOBIAN[1],
|
||||
PEDERSEN_POINTS_JACOBIAN[2]
|
||||
);
|
||||
const PEDERSEN_POINTS2 = pedersenPrecompute(
|
||||
PEDERSEN_POINTS_JACOBIAN[3],
|
||||
PEDERSEN_POINTS_JACOBIAN[4]
|
||||
);
|
||||
|
||||
type PedersenArg = Hex | bigint | number;
|
||||
function pedersenArg(arg: PedersenArg): bigint {
|
||||
let value: bigint;
|
||||
if (typeof arg === 'bigint') value = arg;
|
||||
else if (typeof arg === 'number') {
|
||||
if (!Number.isSafeInteger(arg)) throw new Error(`Invalid pedersenArg: ${arg}`);
|
||||
value = BigInt(arg);
|
||||
} else value = bytesToNumber0x(ensureBytes0x(arg));
|
||||
// [0..Fp)
|
||||
if (!(0n <= value && value < starkCurve.CURVE.P))
|
||||
throw new Error(`PedersenArg should be 0 <= value < CURVE.P: ${value}`);
|
||||
return value;
|
||||
}
|
||||
|
||||
function pedersenSingle(
|
||||
point: JacobianPointType,
|
||||
value: PedersenArg,
|
||||
constants: JacobianPointType[]
|
||||
) {
|
||||
let x = pedersenArg(value);
|
||||
for (let j = 0; j < 252; j++) {
|
||||
const pt = constants[j];
|
||||
if (pt.x === point.x) throw new Error('Same point');
|
||||
if ((x & 1n) !== 0n) point = point.add(pt);
|
||||
x >>= 1n;
|
||||
}
|
||||
return point;
|
||||
}
|
||||
|
||||
// shift_point + x_low * P_0 + x_high * P1 + y_low * P2 + y_high * P3
|
||||
export function pedersen(x: PedersenArg, y: PedersenArg) {
|
||||
let point: JacobianPointType = PEDERSEN_POINTS_JACOBIAN[0];
|
||||
point = pedersenSingle(point, x, PEDERSEN_POINTS1);
|
||||
point = pedersenSingle(point, y, PEDERSEN_POINTS2);
|
||||
return bytesToHexEth(point.toAffine().toRawBytes(true).slice(1));
|
||||
}
|
||||
|
||||
export function hashChain(data: PedersenArg[], fn = pedersen) {
|
||||
if (!Array.isArray(data) || data.length < 1)
|
||||
throw new Error('data should be array of at least 1 element');
|
||||
if (data.length === 1) return numberToHexEth(pedersenArg(data[0]));
|
||||
return Array.from(data)
|
||||
.reverse()
|
||||
.reduce((acc, i) => fn(i, acc));
|
||||
}
|
||||
// Same as hashChain, but computes hash even for single element and order is not revesed
|
||||
export const computeHashOnElements = (data: PedersenArg[], fn = pedersen) =>
|
||||
[0, ...data, data.length].reduce((x, y) => fn(x, y));
|
||||
|
||||
const MASK_250 = 2n ** 250n - 1n;
|
||||
export const keccak = (data: Uint8Array) => bytesToNumber0x(keccak_256(data)) & MASK_250;
|
||||
@@ -1,97 +0,0 @@
|
||||
import { deepStrictEqual, throws } from 'assert';
|
||||
import { should } from 'micro-should';
|
||||
import * as nist from '../lib/nist.js';
|
||||
import { hexToBytes } from '@noble/curves/utils';
|
||||
import { default as ecdsa } from './fixtures/ecdsa_test.json' assert { type: 'json' };
|
||||
import { default as ecdh } from './fixtures/ecdh_test.json' assert { type: 'json' };
|
||||
|
||||
// import { hexToBytes } from '@noble/curves';
|
||||
|
||||
should('Curve Fields', () => {
|
||||
const vectors = {
|
||||
secp192r1: 0xfffffffffffffffffffffffffffffffeffffffffffffffffn,
|
||||
secp224r1: 0xffffffffffffffffffffffffffffffff000000000000000000000001n,
|
||||
secp256r1: 0xffffffff00000001000000000000000000000000ffffffffffffffffffffffffn,
|
||||
secp256k1: 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2fn,
|
||||
secp384r1:
|
||||
0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000ffffffffn,
|
||||
secp521r1:
|
||||
0x01ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffn,
|
||||
};
|
||||
for (const n in vectors) deepStrictEqual(nist[n].CURVE.P, vectors[n]);
|
||||
});
|
||||
|
||||
should('wychenproof ECDSA vectors', () => {
|
||||
for (const group of ecdsa.testGroups) {
|
||||
// Tested in secp256k1.test.js
|
||||
if (group.key.curve === 'secp256k1') continue;
|
||||
// We don't have SHA-224
|
||||
if (group.key.curve === 'secp224r1' && group.sha === 'SHA-224') continue;
|
||||
const CURVE = nist[group.key.curve];
|
||||
if (!CURVE) continue;
|
||||
const pubKey = CURVE.Point.fromHex(group.key.uncompressed);
|
||||
deepStrictEqual(pubKey.x, BigInt(`0x${group.key.wx}`));
|
||||
deepStrictEqual(pubKey.y, BigInt(`0x${group.key.wy}`));
|
||||
for (const test of group.tests) {
|
||||
if (['Hash weaker than DL-group'].includes(test.comment)) {
|
||||
continue;
|
||||
}
|
||||
const m = CURVE.CURVE.hash(hexToBytes(test.msg));
|
||||
if (test.result === 'valid' || test.result === 'acceptable') {
|
||||
try {
|
||||
CURVE.Signature.fromDER(test.sig);
|
||||
} catch (e) {
|
||||
// Some test has invalid signature which we don't accept
|
||||
if (e.message.includes('Invalid signature: incorrect length')) continue;
|
||||
throw e;
|
||||
}
|
||||
const verified = CURVE.verify(test.sig, m, pubKey);
|
||||
deepStrictEqual(verified, true, 'valid');
|
||||
} else if (test.result === 'invalid') {
|
||||
let failed = false;
|
||||
try {
|
||||
failed = !CURVE.verify(test.sig, m, pubKey);
|
||||
} catch (error) {
|
||||
failed = true;
|
||||
}
|
||||
deepStrictEqual(failed, true, 'invalid');
|
||||
} else throw new Error('unknown test result');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
should('wychenproof ECDH vectors', () => {
|
||||
for (const group of ecdh.testGroups) {
|
||||
// // Tested in secp256k1.test.js
|
||||
// if (group.key.curve === 'secp256k1') continue;
|
||||
// We don't have SHA-224
|
||||
const CURVE = nist[group.curve];
|
||||
if (!CURVE) continue;
|
||||
for (const test of group.tests) {
|
||||
if (test.result === 'valid' || test.result === 'acceptable') {
|
||||
try {
|
||||
const pub = CURVE.Point.fromHex(test.public);
|
||||
} catch (e) {
|
||||
if (e.message.includes('Point.fromHex: received invalid point.')) continue;
|
||||
throw e;
|
||||
}
|
||||
const shared = CURVE.getSharedSecret(test.private, test.public);
|
||||
deepStrictEqual(shared, test.shared, 'valid');
|
||||
} else if (test.result === 'invalid') {
|
||||
let failed = false;
|
||||
try {
|
||||
CURVE.getSharedSecret(test.private, test.public);
|
||||
} catch (error) {
|
||||
failed = true;
|
||||
}
|
||||
deepStrictEqual(failed, true, 'invalid');
|
||||
} else throw new Error('unknown test result');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// ESM is broken.
|
||||
import url from 'url';
|
||||
if (import.meta.url === url.pathToFileURL(process.argv[1]).href) {
|
||||
should.run();
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
import { should } from 'micro-should';
|
||||
|
||||
import './basic.test.js';
|
||||
import './rfc6979.test.js';
|
||||
import './secp256k1.test.js';
|
||||
import './starknet/starknet.test.js';
|
||||
|
||||
should.run();
|
||||
@@ -1,33 +0,0 @@
|
||||
import { deepStrictEqual } from 'assert';
|
||||
import { should } from 'micro-should';
|
||||
import * as nist from '../lib/nist.js';
|
||||
import { default as rfc6979 } from './fixtures/rfc6979.json' assert { type: 'json' };
|
||||
function hexToBigint(hex) {
|
||||
return BigInt('0x' + hex)
|
||||
}
|
||||
|
||||
should('RFC6979', () => {
|
||||
for (const v of rfc6979) {
|
||||
const curve = nist[v.curve];
|
||||
deepStrictEqual(curve.CURVE.n, hexToBigint(v.q));
|
||||
const pubKey = curve.getPublicKey(v.private);
|
||||
const pubPoint = curve.Point.fromHex(pubKey);
|
||||
deepStrictEqual(pubPoint.x, hexToBigint(v.Ux));
|
||||
deepStrictEqual(pubPoint.y, hexToBigint(v.Uy));
|
||||
for (const c of v.cases) {
|
||||
const h = curve.CURVE.hash(c.message);
|
||||
const sigObj = curve.sign(h, v.private);
|
||||
// const sigObj = curve.Signature.fromDER(sig);
|
||||
deepStrictEqual(sigObj.r, hexToBigint(c.r), 'R');
|
||||
deepStrictEqual(sigObj.s, hexToBigint(c.s), 'S');
|
||||
deepStrictEqual(curve.verify(sigObj.toDERRawBytes(), h, pubKey), true, 'verify(1)');
|
||||
deepStrictEqual(curve.verify(sigObj, h, pubKey), true, 'verify(2)');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// ESM is broken.
|
||||
import url from 'url';
|
||||
if (import.meta.url === url.pathToFileURL(process.argv[1]).href) {
|
||||
should.run();
|
||||
}
|
||||
@@ -1,559 +0,0 @@
|
||||
import * as fc from 'fast-check';
|
||||
import * as nist from '../lib/nist.js';
|
||||
import { readFileSync } from 'fs';
|
||||
import { default as ecdsa } from './vectors/ecdsa.json' assert { type: 'json' };
|
||||
import { default as ecdh } from './vectors/ecdh.json' assert { type: 'json' };
|
||||
import { default as privates } from './vectors/privates.json' assert { type: 'json' };
|
||||
import { default as points } from './vectors/points.json' assert { type: 'json' };
|
||||
import { default as wp } from './vectors/wychenproof.json' assert { type: 'json' };
|
||||
import { should } from 'micro-should';
|
||||
import { deepStrictEqual, throws, rejects } from 'assert';
|
||||
import { hexToBytes, bytesToHex } from '@noble/hashes/utils';
|
||||
|
||||
const hex = bytesToHex;
|
||||
const secp = nist.secp256k1;
|
||||
const privatesTxt = readFileSync('./test/vectors/privates-2.txt', 'utf-8');
|
||||
const schCsv = readFileSync('./test/vectors/schnorr.csv', 'utf-8');
|
||||
|
||||
const FC_BIGINT = fc.bigInt(1n + 1n, secp.CURVE.n - 1n);
|
||||
// prettier-ignore
|
||||
const INVALID_ITEMS = ['deadbeef', Math.pow(2, 53), [1], 'xyzxyzxyxyzxyzxyxyzxyzxyxyzxyzxyxyzxyzxyxyzxyzxyxyzxyzxyxyzxyzxy', secp.CURVE.n + 2n];
|
||||
|
||||
const toBEHex = (n) => n.toString(16).padStart(64, '0');
|
||||
|
||||
function hexToNumber(hex) {
|
||||
if (typeof hex !== 'string') {
|
||||
throw new TypeError('hexToNumber: expected string, got ' + typeof hex);
|
||||
}
|
||||
// Big Endian
|
||||
return BigInt(`0x${hex}`);
|
||||
}
|
||||
|
||||
should('secp256k1.getPublicKey()', () => {
|
||||
const data = privatesTxt
|
||||
.split('\n')
|
||||
.filter((line) => line)
|
||||
.map((line) => line.split(':'));
|
||||
for (let [priv, x, y] of data) {
|
||||
const point = secp.Point.fromPrivateKey(BigInt(priv));
|
||||
deepStrictEqual(toBEHex(point.x), x);
|
||||
deepStrictEqual(toBEHex(point.y), y);
|
||||
|
||||
const point2 = secp.Point.fromHex(secp.getPublicKey(toBEHex(BigInt(priv))));
|
||||
deepStrictEqual(toBEHex(point2.x), x);
|
||||
deepStrictEqual(toBEHex(point2.y), y);
|
||||
|
||||
const point3 = secp.Point.fromHex(secp.getPublicKey(hexToBytes(toBEHex(BigInt(priv)))));
|
||||
deepStrictEqual(toBEHex(point3.x), x);
|
||||
deepStrictEqual(toBEHex(point3.y), y);
|
||||
}
|
||||
});
|
||||
should('secp256k1.getPublicKey() rejects invalid keys', () => {
|
||||
// for (const item of INVALID_ITEMS) {
|
||||
// throws(() => secp.getPublicKey(item));
|
||||
// }
|
||||
});
|
||||
should('secp256k1.precompute', () => {
|
||||
secp.utils.precompute(4);
|
||||
const data = privatesTxt
|
||||
.split('\n')
|
||||
.filter((line) => line)
|
||||
.map((line) => line.split(':'));
|
||||
for (let [priv, x, y] of data) {
|
||||
const point = secp.Point.fromPrivateKey(BigInt(priv));
|
||||
deepStrictEqual(toBEHex(point.x), x);
|
||||
deepStrictEqual(toBEHex(point.y), y);
|
||||
|
||||
const point2 = secp.Point.fromHex(secp.getPublicKey(toBEHex(BigInt(priv))));
|
||||
deepStrictEqual(toBEHex(point2.x), x);
|
||||
deepStrictEqual(toBEHex(point2.y), y);
|
||||
|
||||
const point3 = secp.Point.fromHex(secp.getPublicKey(hexToBytes(toBEHex(BigInt(priv)))));
|
||||
deepStrictEqual(toBEHex(point3.x), x);
|
||||
deepStrictEqual(toBEHex(point3.y), y);
|
||||
}
|
||||
});
|
||||
|
||||
should('secp256k1.Point.isValidPoint()', () => {
|
||||
for (const vector of points.valid.isPoint) {
|
||||
const { P, expected } = vector;
|
||||
if (expected) {
|
||||
secp.Point.fromHex(P);
|
||||
} else {
|
||||
throws(() => secp.Point.fromHex(P));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
should('secp256k1.Point.fromPrivateKey()', () => {
|
||||
for (const vector of points.valid.pointFromScalar) {
|
||||
const { d, expected } = vector;
|
||||
let p = secp.Point.fromPrivateKey(d);
|
||||
deepStrictEqual(p.toHex(true), expected);
|
||||
}
|
||||
});
|
||||
|
||||
should('secp256k1.Point#toHex(compressed)', () => {
|
||||
for (const vector of points.valid.pointCompress) {
|
||||
const { P, compress, expected } = vector;
|
||||
let p = secp.Point.fromHex(P);
|
||||
deepStrictEqual(p.toHex(compress), expected);
|
||||
}
|
||||
});
|
||||
|
||||
should('secp256k1.Point#toHex() roundtrip (failed case)', () => {
|
||||
const point1 =
|
||||
secp.Point.fromPrivateKey(
|
||||
88572218780422190464634044548753414301110513745532121983949500266768436236425n
|
||||
);
|
||||
// const hex = point1.toHex(true);
|
||||
// deepStrictEqual(secp.Point.fromHex(hex).toHex(true), hex);
|
||||
});
|
||||
|
||||
should('secp256k1.Point#toHex() roundtrip', () => {
|
||||
fc.assert(
|
||||
fc.property(FC_BIGINT, (x) => {
|
||||
const point1 = secp.Point.fromPrivateKey(x);
|
||||
const hex = point1.toHex(true);
|
||||
deepStrictEqual(secp.Point.fromHex(hex).toHex(true), hex);
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
should('secp256k1.Point#add(other)', () => {
|
||||
for (const vector of points.valid.pointAdd) {
|
||||
const { P, Q, expected } = vector;
|
||||
let p = secp.Point.fromHex(P);
|
||||
let q = secp.Point.fromHex(Q);
|
||||
if (expected) {
|
||||
deepStrictEqual(p.add(q).toHex(true), expected);
|
||||
} else {
|
||||
if (!p.equals(q.negate())) {
|
||||
throws(() => p.add(q).toHex(true));
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
should('secp256k1.Point#multiply(privateKey)', () => {
|
||||
for (const vector of points.valid.pointMultiply) {
|
||||
const { P, d, expected } = vector;
|
||||
const p = secp.Point.fromHex(P);
|
||||
if (expected) {
|
||||
deepStrictEqual(p.multiply(hexToNumber(d)).toHex(true), expected);
|
||||
} else {
|
||||
throws(() => {
|
||||
p.multiply(hexToNumber(d)).toHex(true);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
for (const vector of points.invalid.pointMultiply) {
|
||||
const { P, d } = vector;
|
||||
if (hexToNumber(d) < secp.CURVE.n) {
|
||||
throws(() => {
|
||||
const p = secp.Point.fromHex(P);
|
||||
p.multiply(hexToNumber(d)).toHex(true);
|
||||
});
|
||||
}
|
||||
}
|
||||
for (const num of [0n, 0, -1n, -1, 1.1]) {
|
||||
throws(() => secp.Point.BASE.multiply(num));
|
||||
}
|
||||
});
|
||||
|
||||
// multiply() should equal multiplyUnsafe()
|
||||
// should('JacobianPoint#multiplyUnsafe', () => {
|
||||
// const p0 = new secp.JacobianPoint(
|
||||
// 55066263022277343669578718895168534326250603453777594175500187360389116729240n,
|
||||
// 32670510020758816978083085130507043184471273380659243275938904335757337482424n,
|
||||
// 1n
|
||||
// );
|
||||
// const z = 106011723082030650010038151861333186846790370053628296836951575624442507889495n;
|
||||
// console.log(p0.multiply(z));
|
||||
// console.log(secp.JacobianPoint.normalizeZ([p0.multiplyUnsafe(z)])[0])
|
||||
// });
|
||||
|
||||
should('secp256k1.Signature.fromCompactHex() roundtrip', () => {
|
||||
fc.assert(
|
||||
fc.property(FC_BIGINT, FC_BIGINT, (r, s) => {
|
||||
const sig = new secp.Signature(r, s);
|
||||
deepStrictEqual(secp.Signature.fromCompact(sig.toCompactHex()), sig);
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
should('secp256k1.Signature.fromDERHex() roundtrip', () => {
|
||||
fc.assert(
|
||||
fc.property(FC_BIGINT, FC_BIGINT, (r, s) => {
|
||||
const sig = new secp.Signature(r, s);
|
||||
deepStrictEqual(secp.Signature.fromDER(sig.toDERHex()), sig);
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
should('secp256k1.sign()/should create deterministic signatures with RFC 6979', async () => {
|
||||
for (const vector of ecdsa.valid) {
|
||||
let usig = await secp.sign(vector.m, vector.d);
|
||||
let sig = (usig.toCompactHex());
|
||||
const vsig = vector.signature;
|
||||
deepStrictEqual(sig.slice(0, 64), vsig.slice(0, 64));
|
||||
deepStrictEqual(sig.slice(64, 128), vsig.slice(64, 128));
|
||||
}
|
||||
});
|
||||
|
||||
should(
|
||||
'secp256k1.sign()/should not create invalid deterministic signatures with RFC 6979',
|
||||
async () => {
|
||||
for (const vector of ecdsa.invalid.sign) {
|
||||
throws(() => {
|
||||
return secp.sign(vector.m, vector.d);
|
||||
});
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
should('secp256k1.sign()/edge cases', () => {
|
||||
// @ts-ignore
|
||||
rejects(async () => await secp.sign());
|
||||
// @ts-ignore
|
||||
rejects(async () => await secp.sign(''));
|
||||
});
|
||||
|
||||
should('secp256k1.sign()/should create correct DER encoding against libsecp256k1', async () => {
|
||||
const CASES = [
|
||||
[
|
||||
'd1a9dc8ed4e46a6a3e5e594615ca351d7d7ef44df1e4c94c1802f3592183794b',
|
||||
'304402203de2559fccb00c148574997f660e4d6f40605acc71267ee38101abf15ff467af02200950abdf40628fd13f547792ba2fc544681a485f2fdafb5c3b909a4df7350e6b',
|
||||
],
|
||||
[
|
||||
'5f97983254982546d3976d905c6165033976ee449d300d0e382099fa74deaf82',
|
||||
'3045022100c046d9ff0bd2845b9aa9dff9f997ecebb31e52349f80fe5a5a869747d31dcb88022011f72be2a6d48fe716b825e4117747b397783df26914a58139c3f4c5cbb0e66c',
|
||||
],
|
||||
[
|
||||
'0d7017a96b97cd9be21cf28aada639827b2814a654a478c81945857196187808',
|
||||
'3045022100d18990bba7832bb283e3ecf8700b67beb39acc73f4200ed1c331247c46edccc602202e5c8bbfe47ae159512c583b30a3fa86575cddc62527a03de7756517ae4c6c73',
|
||||
],
|
||||
];
|
||||
const privKey = hexToBytes('0101010101010101010101010101010101010101010101010101010101010101');
|
||||
for (let [msg, exp] of CASES) {
|
||||
const res = await secp.sign(msg, privKey, { extraEntropy: undefined });
|
||||
deepStrictEqual((res.toDERHex()), exp);
|
||||
const rs = secp.Signature.fromDER(res.toDERHex()).toCompactHex();
|
||||
deepStrictEqual(secp.Signature.fromCompact(rs).toDERHex(), exp);
|
||||
}
|
||||
});
|
||||
should('secp256k1.sign()/sign ecdsa extraData', async () => {
|
||||
const ent1 = '0000000000000000000000000000000000000000000000000000000000000000';
|
||||
const ent2 = '0000000000000000000000000000000000000000000000000000000000000001';
|
||||
const ent3 = '6e723d3fd94ed5d2b6bdd4f123364b0f3ca52af829988a63f8afe91d29db1c33';
|
||||
const ent4 = 'fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141';
|
||||
const ent5 = 'ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff';
|
||||
|
||||
for (const e of ecdsa.extraEntropy) {
|
||||
const sign = async (extraEntropy) => {
|
||||
const s = secp.sign(e.m, e.d, {extraEntropy }).toCompactHex();
|
||||
return s;
|
||||
};
|
||||
deepStrictEqual(await sign(), e.signature);
|
||||
deepStrictEqual(await sign(ent1), e.extraEntropy0);
|
||||
deepStrictEqual(await sign(ent2), e.extraEntropy1);
|
||||
deepStrictEqual(await sign(ent3), e.extraEntropyRand);
|
||||
deepStrictEqual(await sign(ent4), e.extraEntropyN);
|
||||
deepStrictEqual(await sign(ent5), e.extraEntropyMax);
|
||||
}
|
||||
});
|
||||
|
||||
should('secp256k1.verify()/should verify signature', async () => {
|
||||
const MSG = '01'.repeat(32);
|
||||
const PRIV_KEY = 0x2n;
|
||||
const signature = await secp.sign(MSG, PRIV_KEY);
|
||||
const publicKey = secp.getPublicKey(PRIV_KEY);
|
||||
deepStrictEqual(publicKey.length, 65);
|
||||
deepStrictEqual(secp.verify(signature, MSG, publicKey), true);
|
||||
});
|
||||
should('secp256k1.verify()/should not verify signature with wrong public key', async () => {
|
||||
const MSG = '01'.repeat(32);
|
||||
const PRIV_KEY = 0x2n;
|
||||
const WRONG_PRIV_KEY = 0x22n;
|
||||
const signature = await secp.sign(MSG, PRIV_KEY);
|
||||
const publicKey = secp.Point.fromPrivateKey(WRONG_PRIV_KEY).toHex();
|
||||
deepStrictEqual(publicKey.length, 130);
|
||||
deepStrictEqual(secp.verify(signature, MSG, publicKey), false);
|
||||
});
|
||||
should('secp256k1.verify()/should not verify signature with wrong hash', async () => {
|
||||
const MSG = '01'.repeat(32);
|
||||
const PRIV_KEY = 0x2n;
|
||||
const WRONG_MSG = '11'.repeat(32);
|
||||
const signature = await secp.sign(MSG, PRIV_KEY);
|
||||
const publicKey = secp.getPublicKey(PRIV_KEY);
|
||||
deepStrictEqual(publicKey.length, 65);
|
||||
deepStrictEqual(secp.verify(signature, WRONG_MSG, publicKey), false);
|
||||
});
|
||||
should('secp256k1.verify()/should verify random signatures', async () =>
|
||||
fc.assert(
|
||||
fc.asyncProperty(
|
||||
FC_BIGINT,
|
||||
fc.hexaString({ minLength: 64, maxLength: 64 }),
|
||||
async (privKey, msg) => {
|
||||
const pub = secp.getPublicKey(privKey);
|
||||
const sig = await secp.sign(msg, privKey);
|
||||
deepStrictEqual(secp.verify(sig, msg, pub), true);
|
||||
}
|
||||
)
|
||||
)
|
||||
);
|
||||
should('secp256k1.verify()/should not verify signature with invalid r/s', () => {
|
||||
const msg = new Uint8Array([
|
||||
0xbb, 0x5a, 0x52, 0xf4, 0x2f, 0x9c, 0x92, 0x61, 0xed, 0x43, 0x61, 0xf5, 0x94, 0x22, 0xa1, 0xe3,
|
||||
0x00, 0x36, 0xe7, 0xc3, 0x2b, 0x27, 0x0c, 0x88, 0x07, 0xa4, 0x19, 0xfe, 0xca, 0x60, 0x50, 0x23,
|
||||
]);
|
||||
const x = 100260381870027870612475458630405506840396644859280795015145920502443964769584n;
|
||||
const y = 41096923727651821103518389640356553930186852801619204169823347832429067794568n;
|
||||
const r = 1n;
|
||||
const s = 115792089237316195423570985008687907852837564279074904382605163141518162728904n;
|
||||
|
||||
const pub = new secp.Point(x, y);
|
||||
const signature = new secp.Signature(2n, 2n);
|
||||
// @ts-ignore
|
||||
signature.r = r;
|
||||
// @ts-ignore
|
||||
signature.s = s;
|
||||
|
||||
const verified = secp.verify(signature, msg, pub);
|
||||
// Verifies, but it shouldn't, because signature S > curve order
|
||||
deepStrictEqual(verified, false);
|
||||
});
|
||||
should('secp256k1.verify()/should not verify msg = curve order', async () => {
|
||||
const msg = 'fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141';
|
||||
const x = 55066263022277343669578718895168534326250603453777594175500187360389116729240n;
|
||||
const y = 32670510020758816978083085130507043184471273380659243275938904335757337482424n;
|
||||
const r = 104546003225722045112039007203142344920046999340768276760147352389092131869133n;
|
||||
const s = 96900796730960181123786672629079577025401317267213807243199432755332205217369n;
|
||||
const pub = new secp.Point(x, y);
|
||||
const sig = new secp.Signature(r, s);
|
||||
deepStrictEqual(secp.verify(sig, msg, pub), false);
|
||||
});
|
||||
should('secp256k1.verify()/should verify non-strict msg bb5a...', async () => {
|
||||
const msg = 'bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023';
|
||||
const x = 3252872872578928810725465493269682203671229454553002637820453004368632726370n;
|
||||
const y = 17482644437196207387910659778872952193236850502325156318830589868678978890912n;
|
||||
const r = 432420386565659656852420866390673177323n;
|
||||
const s = 115792089237316195423570985008687907852837564279074904382605163141518161494334n;
|
||||
const pub = new secp.Point(x, y);
|
||||
const sig = new secp.Signature(r, s);
|
||||
deepStrictEqual(secp.verify(sig, msg, pub, { strict: false }), true);
|
||||
});
|
||||
should(
|
||||
'secp256k1.verify()/should not verify invalid deterministic signatures with RFC 6979',
|
||||
() => {
|
||||
for (const vector of ecdsa.invalid.verify) {
|
||||
const res = secp.verify(vector.signature, vector.m, vector.Q);
|
||||
deepStrictEqual(res, false);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// describe('schnorr', () => {
|
||||
// // index,secret key,public key,aux_rand,message,signature,verification result,comment
|
||||
// const vectors = schCsv
|
||||
// .split('\n')
|
||||
// .map((line: string) => line.split(','))
|
||||
// .slice(1, -1);
|
||||
// for (let vec of vectors) {
|
||||
// const [index, sec, pub, rnd, msg, expSig, passes, comment] = vec;
|
||||
// it(`should sign with Schnorr scheme vector ${index}`, async () => {
|
||||
// if (sec) {
|
||||
// expect(hex(secp.schnorr.getPublicKey(sec))).toBe(pub.toLowerCase());
|
||||
// const sig = await secp.schnorr.sign(msg, sec, rnd);
|
||||
// const sigS = secp.schnorr.signSync(msg, sec, rnd);
|
||||
// expect(hex(sig)).toBe(expSig.toLowerCase());
|
||||
// expect(hex(sigS)).toBe(expSig.toLowerCase());
|
||||
// expect(await secp.schnorr.verify(sigS, msg, pub)).toBe(true);
|
||||
// expect(secp.schnorr.verifySync(sig, msg, pub)).toBe(true);
|
||||
// } else {
|
||||
// const passed = await secp.schnorr.verify(expSig, msg, pub);
|
||||
// const passedS = secp.schnorr.verifySync(expSig, msg, pub);
|
||||
// if (passes === 'TRUE') {
|
||||
// expect(passed).toBeTruthy();
|
||||
// expect(passedS).toBeTruthy();
|
||||
// } else {
|
||||
// expect(passed).toBeFalsy();
|
||||
// expect(passedS).toBeFalsy();
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
// });
|
||||
|
||||
should('secp256k1.recoverPublicKey()/should recover public key from recovery bit', async () => {
|
||||
const message = '00000000000000000000000000000000000000000000000000000000deadbeef';
|
||||
const privateKey = 123456789n;
|
||||
const publicKey = secp.Point.fromHex(secp.getPublicKey(privateKey)).toHex(false);
|
||||
const sig = await secp.sign(message, privateKey);
|
||||
const recoveredPubkey = sig.recoverPublicKey(message);
|
||||
// const recoveredPubkey = secp.recoverPublicKey(message, signature, recovery);
|
||||
deepStrictEqual(recoveredPubkey !== null, true);
|
||||
deepStrictEqual((recoveredPubkey).toHex(), publicKey);
|
||||
deepStrictEqual(secp.verify(sig, message, publicKey), true);
|
||||
});
|
||||
should('secp256k1.recoverPublicKey()/should not recover zero points', () => {
|
||||
const msgHash = '6b8d2c81b11b2d699528dde488dbdf2f94293d0d33c32e347f255fa4a6c1f0a9';
|
||||
const sig =
|
||||
'79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f817986b8d2c81b11b2d699528dde488dbdf2f94293d0d33c32e347f255fa4a6c1f0a9';
|
||||
const recovery = 0;
|
||||
throws(() => secp.recoverPublicKey(msgHash, sig, recovery));
|
||||
});
|
||||
should('secp256k1.recoverPublicKey()/should handle all-zeros msghash', async () => {
|
||||
const privKey = secp.utils.randomPrivateKey();
|
||||
const pub = secp.getPublicKey(privKey);
|
||||
const zeros = '0000000000000000000000000000000000000000000000000000000000000000';
|
||||
const sig = await secp.sign(zeros, privKey, { recovered: true });
|
||||
const recoveredKey = sig.recoverPublicKey(zeros);
|
||||
deepStrictEqual(recoveredKey.toRawBytes(), pub);
|
||||
});
|
||||
should('secp256k1.recoverPublicKey()/should handle RFC 6979 vectors', async () => {
|
||||
for (const vector of ecdsa.valid) {
|
||||
if (secp.utils.mod(hexToNumber(vector.m), secp.CURVE.n) === 0n) continue;
|
||||
let usig = secp.sign(vector.m, vector.d);
|
||||
let sig = (usig).toDERHex();
|
||||
const vpub = secp.getPublicKey(vector.d);
|
||||
const recovered = usig.recoverPublicKey(vector.m);
|
||||
deepStrictEqual((recovered).toHex(), hex(vpub));
|
||||
}
|
||||
});
|
||||
|
||||
// TODO: Real implementation.
|
||||
function derToPub(der) {
|
||||
return der.slice(46);
|
||||
}
|
||||
should('secp256k1.getSharedSecret()/should produce correct results', () => {
|
||||
// TODO: Once der is there, run all tests.
|
||||
for (const vector of ecdh.testGroups[0].tests.slice(0, 230)) {
|
||||
if (vector.result === 'invalid' || vector.private.length !== 64) {
|
||||
// We support eth-like hexes
|
||||
if (vector.private.length < 64) continue;
|
||||
throws(() => {
|
||||
secp.getSharedSecret(vector.private, derToPub(vector.public), true);
|
||||
});
|
||||
} else if (vector.result === 'valid') {
|
||||
const res = secp.getSharedSecret(vector.private, derToPub(vector.public), true);
|
||||
deepStrictEqual(hex(res.slice(1)), `${vector.shared}`);
|
||||
}
|
||||
}
|
||||
});
|
||||
should('secp256k1.getSharedSecret()/priv/pub order matters', () => {
|
||||
for (const vector of ecdh.testGroups[0].tests.slice(0, 100)) {
|
||||
if (vector.result === 'valid') {
|
||||
let priv = vector.private;
|
||||
priv = priv.length === 66 ? priv.slice(2) : priv;
|
||||
throws(() => secp.getSharedSecret(derToPub(vector.public), priv, true));
|
||||
}
|
||||
}
|
||||
});
|
||||
should('secp256k1.getSharedSecret()/rejects invalid keys', () => {
|
||||
throws(() => secp.getSharedSecret('01', '02'));
|
||||
});
|
||||
|
||||
should('secp256k1.utils.isValidPrivateKey()', () => {
|
||||
for (const vector of privates.valid.isPrivate) {
|
||||
const { d, expected } = vector;
|
||||
deepStrictEqual(secp.utils.isValidPrivateKey(d), expected);
|
||||
}
|
||||
});
|
||||
const normal = secp.utils._normalizePrivateKey;
|
||||
const tweakUtils = {
|
||||
privateAdd: (privateKey, tweak) => {
|
||||
const p = normal(privateKey);
|
||||
const t = normal(tweak);
|
||||
return secp.utils._bigintToBytes(secp.utils.mod(p + t, secp.CURVE.n));
|
||||
},
|
||||
|
||||
privateNegate: (privateKey) => {
|
||||
const p = normal(privateKey);
|
||||
return secp.utils._bigintToBytes(secp.CURVE.n - p);
|
||||
},
|
||||
|
||||
pointAddScalar: (p, tweak, isCompressed) => {
|
||||
const P = secp.Point.fromHex(p);
|
||||
const t = normal(tweak);
|
||||
const Q = secp.Point.BASE.multiplyAndAddUnsafe(P, t, 1n);
|
||||
if (!Q) throw new Error('Tweaked point at infinity');
|
||||
return Q.toRawBytes(isCompressed);
|
||||
},
|
||||
|
||||
pointMultiply: (p, tweak, isCompressed) => {
|
||||
const P = secp.Point.fromHex(p);
|
||||
const h = typeof tweak === 'string' ? tweak : bytesToHex(tweak);
|
||||
const t = BigInt(`0x${h}`);
|
||||
return P.multiply(t).toRawBytes(isCompressed);
|
||||
},
|
||||
};
|
||||
|
||||
should('secp256k1.privateAdd()', () => {
|
||||
for (const vector of privates.valid.add) {
|
||||
const { a, b, expected } = vector;
|
||||
deepStrictEqual(bytesToHex(tweakUtils.privateAdd(a, b)), expected);
|
||||
}
|
||||
});
|
||||
should('secp256k1.privateNegate()', () => {
|
||||
for (const vector of privates.valid.negate) {
|
||||
const { a, expected } = vector;
|
||||
deepStrictEqual(bytesToHex(tweakUtils.privateNegate(a)), expected);
|
||||
}
|
||||
});
|
||||
should('secp256k1.pointAddScalar()', () => {
|
||||
for (const vector of points.valid.pointAddScalar) {
|
||||
const { description, P, d, expected } = vector;
|
||||
const compressed = !!expected && expected.length === 66; // compressed === 33 bytes
|
||||
deepStrictEqual(bytesToHex(tweakUtils.pointAddScalar(P, d, compressed)), expected);
|
||||
}
|
||||
});
|
||||
should('secp256k1.pointAddScalar() invalid', () => {
|
||||
for (const vector of points.invalid.pointAddScalar) {
|
||||
const { P, d, exception } = vector;
|
||||
throws(() => tweakUtils.pointAddScalar(P, d));
|
||||
}
|
||||
});
|
||||
should('secp256k1.pointMultiply()', () => {
|
||||
for (const vector of points.valid.pointMultiply) {
|
||||
const { P, d, expected } = vector;
|
||||
deepStrictEqual(bytesToHex(tweakUtils.pointMultiply(P, d, true)), expected);
|
||||
}
|
||||
});
|
||||
should('secp256k1.pointMultiply() invalid', () => {
|
||||
for (const vector of points.invalid.pointMultiply) {
|
||||
const { P, d, exception } = vector;
|
||||
throws(() => tweakUtils.pointMultiply(P, d));
|
||||
}
|
||||
});
|
||||
|
||||
should('secp256k1.wychenproof vectors', () => {
|
||||
for (let group of wp.testGroups) {
|
||||
const pubKey = secp.Point.fromHex(group.key.uncompressed);
|
||||
for (let test of group.tests) {
|
||||
const m = secp.CURVE.hash(hexToBytes(test.msg));
|
||||
if (test.result === 'valid' || test.result === 'acceptable') {
|
||||
const verified = secp.verify(test.sig, m, pubKey);
|
||||
if (secp.Signature.fromDER(test.sig).hasHighS()) {
|
||||
deepStrictEqual(verified, false);
|
||||
} else {
|
||||
deepStrictEqual(verified, true);
|
||||
}
|
||||
} else if (test.result === 'invalid') {
|
||||
let failed = false;
|
||||
try {
|
||||
const verified = secp.verify(test.sig, m, pubKey);
|
||||
if (!verified) failed = true;
|
||||
} catch (error) {
|
||||
failed = true;
|
||||
}
|
||||
deepStrictEqual(failed, true);
|
||||
} else {
|
||||
deepStrictEqual(false, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
should.run();
|
||||
@@ -1,200 +0,0 @@
|
||||
import { deepStrictEqual, throws } from 'assert';
|
||||
import { should } from 'micro-should';
|
||||
import * as starknet from '../../lib/starknet.js';
|
||||
import { default as issue2 } from './fixtures/issue2.json' assert { type: 'json' };
|
||||
|
||||
should('Basic elliptic sanity check', () => {
|
||||
const g1 = starknet.Point.BASE;
|
||||
deepStrictEqual(
|
||||
g1.x.toString(16),
|
||||
'1ef15c18599971b7beced415a40f0c7deacfd9b0d1819e03d723d8bc943cfca'
|
||||
);
|
||||
deepStrictEqual(
|
||||
g1.y.toString(16),
|
||||
'5668060aa49730b7be4801df46ec62de53ecd11abe43a32873000c36e8dc1f'
|
||||
);
|
||||
const g2 = g1.double();
|
||||
deepStrictEqual(
|
||||
g2.x.toString(16),
|
||||
'759ca09377679ecd535a81e83039658bf40959283187c654c5416f439403cf5'
|
||||
);
|
||||
deepStrictEqual(
|
||||
g2.y.toString(16),
|
||||
'6f524a3400e7708d5c01a28598ad272e7455aa88778b19f93b562d7a9646c41'
|
||||
);
|
||||
const g3 = g2.add(g1);
|
||||
deepStrictEqual(
|
||||
g3.x.toString(16),
|
||||
'411494b501a98abd8262b0da1351e17899a0c4ef23dd2f96fec5ba847310b20'
|
||||
);
|
||||
deepStrictEqual(
|
||||
g3.y.toString(16),
|
||||
'7e1b3ebac08924d2c26f409549191fcf94f3bf6f301ed3553e22dfb802f0686'
|
||||
);
|
||||
const g32 = g1.multiply(3);
|
||||
deepStrictEqual(
|
||||
g32.x.toString(16),
|
||||
'411494b501a98abd8262b0da1351e17899a0c4ef23dd2f96fec5ba847310b20'
|
||||
);
|
||||
deepStrictEqual(
|
||||
g32.y.toString(16),
|
||||
'7e1b3ebac08924d2c26f409549191fcf94f3bf6f301ed3553e22dfb802f0686'
|
||||
);
|
||||
const minus1 = g1.multiply(starknet.CURVE.n - 1n);
|
||||
deepStrictEqual(
|
||||
minus1.x.toString(16),
|
||||
'1ef15c18599971b7beced415a40f0c7deacfd9b0d1819e03d723d8bc943cfca'
|
||||
);
|
||||
deepStrictEqual(
|
||||
minus1.y.toString(16),
|
||||
'7a997f9f55b68e04841b7fe20b9139d21ac132ee541bc5cd78cfff3c91723e2'
|
||||
);
|
||||
});
|
||||
|
||||
should('Pedersen', () => {
|
||||
deepStrictEqual(
|
||||
starknet.pedersen(2, 3),
|
||||
'0x5774fa77b3d843ae9167abd61cf80365a9b2b02218fc2f628494b5bdc9b33b8'
|
||||
);
|
||||
deepStrictEqual(
|
||||
starknet.pedersen(1, 2),
|
||||
'0x5bb9440e27889a364bcb678b1f679ecd1347acdedcbf36e83494f857cc58026'
|
||||
);
|
||||
deepStrictEqual(
|
||||
starknet.pedersen(3, 4),
|
||||
'0x262697b88544f733e5c6907c3e1763131e9f14c51ee7951258abbfb29415fbf'
|
||||
);
|
||||
});
|
||||
|
||||
should('Hash chain', () => {
|
||||
deepStrictEqual(
|
||||
starknet.hashChain([1, 2, 3]),
|
||||
'0x5d9d62d4040b977c3f8d2389d494e4e89a96a8b45c44b1368f1cc6ec5418915'
|
||||
);
|
||||
});
|
||||
|
||||
should('Pedersen hash edgecases', () => {
|
||||
// >>> pedersen_hash(0,0)
|
||||
const zero = '0x49ee3eba8c1600700ee1b87eb599f16716b0b1022947733551fde4050ca6804';
|
||||
deepStrictEqual(starknet.pedersen(0, 0), zero);
|
||||
deepStrictEqual(starknet.pedersen(0n, 0n), zero);
|
||||
deepStrictEqual(starknet.pedersen('0', '0'), zero);
|
||||
deepStrictEqual(starknet.pedersen('0x0', '0x0'), zero);
|
||||
// >>> pedersen_hash(3618502788666131213697322783095070105623107215331596699973092056135872020475,3618502788666131213697322783095070105623107215331596699973092056135872020475)
|
||||
// 3226051580231087455100099637526672350308978851161639703631919449959447036451
|
||||
const big = 3618502788666131213697322783095070105623107215331596699973092056135872020475n;
|
||||
const bigExp = '0x721e167a36655994e88efa865e2ed8a0488d36db4d988fec043cda755728223';
|
||||
deepStrictEqual(starknet.pedersen(big, big), bigExp);
|
||||
// >= FIELD
|
||||
const big2 = 36185027886661312136973227830950701056231072153315966999730920561358720204751n;
|
||||
throws(() => starknet.pedersen(big2, big2), 'big2');
|
||||
|
||||
// FIELD -1
|
||||
const big3 = 3618502788666131213697322783095070105623107215331596699973092056135872020480n;
|
||||
const big3exp = '0x7258fccaf3371fad51b117471d9d888a1786c5694c3e6099160477b593a576e';
|
||||
deepStrictEqual(starknet.pedersen(big3, big3), big3exp, 'big3');
|
||||
// FIELD
|
||||
const big4 = 3618502788666131213697322783095070105623107215331596699973092056135872020481n;
|
||||
throws(() => starknet.pedersen(big4, big4), 'big4');
|
||||
throws(() => starknet.pedersen(-1, -1), 'neg');
|
||||
throws(() => starknet.pedersen(false, false), 'false');
|
||||
throws(() => starknet.pedersen(true, true), 'true');
|
||||
throws(() => starknet.pedersen(10.1, 10.1), 'float');
|
||||
});
|
||||
|
||||
should('hashChain edgecases', () => {
|
||||
deepStrictEqual(starknet.hashChain([32312321312321312312312321n]), '0x1aba6672c014b4838cc201');
|
||||
deepStrictEqual(
|
||||
starknet.hashChain([1n, 2n]),
|
||||
'0x5bb9440e27889a364bcb678b1f679ecd1347acdedcbf36e83494f857cc58026'
|
||||
);
|
||||
deepStrictEqual(
|
||||
starknet.hashChain([1, 2]),
|
||||
'0x5bb9440e27889a364bcb678b1f679ecd1347acdedcbf36e83494f857cc58026'
|
||||
);
|
||||
throws(() => starknet.hashChain([]));
|
||||
throws(() => starknet.hashChain('123'));
|
||||
deepStrictEqual(
|
||||
starknet.hashChain([1, 2]),
|
||||
'0x5bb9440e27889a364bcb678b1f679ecd1347acdedcbf36e83494f857cc58026'
|
||||
);
|
||||
});
|
||||
|
||||
should('Pedersen hash, issue #2', () => {
|
||||
// Verified with starnet.js
|
||||
deepStrictEqual(
|
||||
starknet.computeHashOnElements(issue2),
|
||||
'0x22064462ea33a6ce5272a295e0f551c5da3834f80d8444e7a4df68190b1bc42'
|
||||
);
|
||||
deepStrictEqual(
|
||||
starknet.computeHashOnElements([]),
|
||||
'0x49ee3eba8c1600700ee1b87eb599f16716b0b1022947733551fde4050ca6804'
|
||||
);
|
||||
deepStrictEqual(
|
||||
starknet.computeHashOnElements([1]),
|
||||
'0x78d74f61aeaa8286418fd34b3a12a610445eba11d00ecc82ecac2542d55f7a4'
|
||||
);
|
||||
});
|
||||
|
||||
import * as bip32 from '@scure/bip32';
|
||||
import * as bip39 from '@scure/bip39';
|
||||
|
||||
should('Seed derivation (example)', () => {
|
||||
const layer = 'starkex';
|
||||
const application = 'starkdeployement';
|
||||
const mnemonic =
|
||||
'range mountain blast problem vibrant void vivid doctor cluster enough melody ' +
|
||||
'salt layer language laptop boat major space monkey unit glimpse pause change vibrant';
|
||||
const ethAddress = '0xa4864d977b944315389d1765ffa7e66F74ee8cd7';
|
||||
const hdKey = bip32.HDKey.fromMasterSeed(bip39.mnemonicToSeedSync(mnemonic)).derive(
|
||||
starknet.getAccountPath(layer, application, ethAddress, 0)
|
||||
);
|
||||
deepStrictEqual(
|
||||
starknet.grindKey(hdKey.privateKey),
|
||||
'6cf0a8bf113352eb863157a45c5e5567abb34f8d32cddafd2c22aa803f4892c'
|
||||
);
|
||||
});
|
||||
|
||||
should('Compressed keys', () => {
|
||||
const G = starknet.Point.BASE;
|
||||
const half = starknet.CURVE.n / 2n;
|
||||
const last = starknet.CURVE.n;
|
||||
const vectors = [
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
5,
|
||||
half - 5n,
|
||||
half - 4n,
|
||||
half - 3n,
|
||||
half - 2n,
|
||||
half - 1n,
|
||||
half,
|
||||
half + 1n,
|
||||
half + 2n,
|
||||
half + 3n,
|
||||
half + 4n,
|
||||
half + 5n,
|
||||
last - 5n,
|
||||
last - 4n,
|
||||
last - 3n,
|
||||
last - 2n,
|
||||
last - 1n,
|
||||
].map((i) => G.multiply(i));
|
||||
const fixPoint = (pt) => ({ ...pt, _WINDOW_SIZE: undefined });
|
||||
for (const v of vectors) {
|
||||
const uncompressed = v.toHex();
|
||||
const compressed = v.toHex(true);
|
||||
const exp = fixPoint(v);
|
||||
deepStrictEqual(fixPoint(starknet.Point.fromHex(uncompressed)), exp);
|
||||
deepStrictEqual(fixPoint(starknet.Point.fromHex(compressed)), exp);
|
||||
deepStrictEqual(starknet.Point.fromHex(compressed).toHex(), uncompressed);
|
||||
}
|
||||
});
|
||||
|
||||
// ESM is broken.
|
||||
import url from 'url';
|
||||
if (import.meta.url === url.pathToFileURL(process.argv[1]).href) {
|
||||
should.run();
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
import { deepStrictEqual, throws } from 'assert';
|
||||
import { should } from 'micro-should';
|
||||
import * as starknet from '../../lib/starknet.js';
|
||||
import * as fc from 'fast-check';
|
||||
|
||||
const FC_BIGINT = fc.bigInt(1n + 1n, starknet.CURVE.n - 1n);
|
||||
|
||||
should('Point#toHex() roundtrip', () => {
|
||||
fc.assert(
|
||||
fc.property(FC_BIGINT, (x) => {
|
||||
const point1 = starknet.Point.fromPrivateKey(x);
|
||||
const hex = point1.toHex(true);
|
||||
deepStrictEqual(starknet.Point.fromHex(hex).toHex(true), hex);
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
should('Signature.fromCompactHex() roundtrip', () => {
|
||||
fc.assert(
|
||||
fc.property(FC_BIGINT, FC_BIGINT, (r, s) => {
|
||||
const sig = new starknet.Signature(r, s);
|
||||
deepStrictEqual(starknet.Signature.fromCompact(sig.toCompactHex()), sig);
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
should('Signature.fromDERHex() roundtrip', () => {
|
||||
fc.assert(
|
||||
fc.property(FC_BIGINT, FC_BIGINT, (r, s) => {
|
||||
const sig = new starknet.Signature(r, s);
|
||||
deepStrictEqual(starknet.Signature.fromDER(sig.toDERHex()), sig);
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
should('verify()/should verify random signatures', () =>
|
||||
fc.assert(
|
||||
fc.asyncProperty(FC_BIGINT, fc.hexaString({ minLength: 64, maxLength: 64 }), (privNum, msg) => {
|
||||
const privKey = privNum.toString(16).padStart(64, '0');
|
||||
const pub = starknet.getPublicKey(privKey);
|
||||
const sig = starknet.sign(msg, privKey);
|
||||
deepStrictEqual(starknet.verify(sig, msg, pub), true);
|
||||
})
|
||||
)
|
||||
);
|
||||
|
||||
// ESM is broken.
|
||||
import url from 'url';
|
||||
if (import.meta.url === url.pathToFileURL(process.argv[1]).href) {
|
||||
should.run();
|
||||
}
|
||||
@@ -1,286 +0,0 @@
|
||||
import { deepStrictEqual, throws } from 'assert';
|
||||
import { should } from 'micro-should';
|
||||
import { hex, utf8 } from '@scure/base';
|
||||
import * as bip32 from '@scure/bip32';
|
||||
import * as bip39 from '@scure/bip39';
|
||||
import * as starknet from '../../lib/starknet.js';
|
||||
import { default as sigVec } from './fixtures/rfc6979_signature_test_vector.json' assert { type: 'json' };
|
||||
import { default as precomputedKeys } from './fixtures/keys_precomputed.json' assert { type: 'json' };
|
||||
|
||||
should('Starknet keccak', () => {
|
||||
const value = starknet.keccak(utf8.decode('hello'));
|
||||
deepStrictEqual(value, 0x8aff950685c2ed4bc3174f3472287b56d9517b9c948127319a09a7a36deac8n);
|
||||
deepStrictEqual(value < 2n ** 250n, true);
|
||||
});
|
||||
|
||||
should('RFC6979', () => {
|
||||
for (const msg of sigVec.messages) {
|
||||
const { r, s } = starknet.sign(msg.hash, sigVec.private_key);
|
||||
// const { r, s } = starknet.Signature.fromDER(sig);
|
||||
deepStrictEqual(r.toString(10), msg.r);
|
||||
deepStrictEqual(s.toString(10), msg.s);
|
||||
}
|
||||
});
|
||||
|
||||
should('Signatures', () => {
|
||||
const vectors = [
|
||||
{
|
||||
// Message hash of length 61.
|
||||
msg: 'c465dd6b1bbffdb05442eb17f5ca38ad1aa78a6f56bf4415bdee219114a47',
|
||||
r: '5f496f6f210b5810b2711c74c15c05244dad43d18ecbbdbe6ed55584bc3b0a2',
|
||||
s: '4e8657b153787f741a67c0666bad6426c3741b478c8eaa3155196fc571416f3',
|
||||
},
|
||||
{
|
||||
// Message hash of length 61, with leading zeros.
|
||||
msg: '00c465dd6b1bbffdb05442eb17f5ca38ad1aa78a6f56bf4415bdee219114a47',
|
||||
r: '5f496f6f210b5810b2711c74c15c05244dad43d18ecbbdbe6ed55584bc3b0a2',
|
||||
s: '4e8657b153787f741a67c0666bad6426c3741b478c8eaa3155196fc571416f3',
|
||||
},
|
||||
{
|
||||
// Message hash of length 62.
|
||||
msg: 'c465dd6b1bbffdb05442eb17f5ca38ad1aa78a6f56bf4415bdee219114a47a',
|
||||
r: '233b88c4578f0807b4a7480c8076eca5cfefa29980dd8e2af3c46a253490e9c',
|
||||
s: '28b055e825bc507349edfb944740a35c6f22d377443c34742c04e0d82278cf1',
|
||||
},
|
||||
{
|
||||
// Message hash of length 63.
|
||||
msg: '7465dd6b1bbffdb05442eb17f5ca38ad1aa78a6f56bf4415bdee219114a47a1',
|
||||
r: 'b6bee8010f96a723f6de06b5fa06e820418712439c93850dd4e9bde43ddf',
|
||||
s: '1a3d2bc954ed77e22986f507d68d18115fa543d1901f5b4620db98e2f6efd80',
|
||||
},
|
||||
];
|
||||
const privateKey = '2dccce1da22003777062ee0870e9881b460a8b7eca276870f57c601f182136c';
|
||||
const publicKey = starknet.getPublicKey(privateKey);
|
||||
for (const v of vectors) {
|
||||
const sig = starknet.sign(v.msg, privateKey);
|
||||
const { r, s } = sig;
|
||||
// const { r, s } = starknet.Signature.fromDER(sig);
|
||||
deepStrictEqual(r.toString(16), v.r, 'r equality');
|
||||
deepStrictEqual(s.toString(16), v.s, 's equality');
|
||||
deepStrictEqual(starknet.verify(sig, v.msg, publicKey), true, 'verify');
|
||||
}
|
||||
});
|
||||
|
||||
should('Invalid signatures', () => {
|
||||
/*
|
||||
|
||||
it('should not verify invalid signature inputs lengths', () => {
|
||||
const ecOrder = starkwareCrypto.ec.n;
|
||||
const {maxEcdsaVal} = starkwareCrypto;
|
||||
const maxMsgHash = maxEcdsaVal.sub(oneBn);
|
||||
const maxR = maxEcdsaVal.sub(oneBn);
|
||||
const maxS = ecOrder.sub(oneBn).sub(oneBn);
|
||||
const maxStarkKey = maxEcdsaVal.sub(oneBn);
|
||||
|
||||
// Test invalid message length.
|
||||
expect(() =>
|
||||
starkwareCrypto.verify(maxStarkKey, maxMsgHash.add(oneBn).toString(16), {
|
||||
r: maxR,
|
||||
s: maxS
|
||||
})
|
||||
).to.throw('Message not signable, invalid msgHash length.');
|
||||
// Test invalid r length.
|
||||
expect(() =>
|
||||
starkwareCrypto.verify(maxStarkKey, maxMsgHash.toString(16), {
|
||||
r: maxR.add(oneBn),
|
||||
s: maxS
|
||||
})
|
||||
).to.throw('Message not signable, invalid r length.');
|
||||
// Test invalid w length.
|
||||
expect(() =>
|
||||
starkwareCrypto.verify(maxStarkKey, maxMsgHash.toString(16), {
|
||||
r: maxR,
|
||||
s: maxS.add(oneBn)
|
||||
})
|
||||
).to.throw('Message not signable, invalid w length.');
|
||||
// Test invalid s length.
|
||||
expect(() =>
|
||||
starkwareCrypto.verify(maxStarkKey, maxMsgHash.toString(16), {
|
||||
r: maxR,
|
||||
s: maxS.add(oneBn).add(oneBn)
|
||||
})
|
||||
).to.throw('Message not signable, invalid s length.');
|
||||
});
|
||||
|
||||
it('should not verify invalid signatures', () => {
|
||||
const privKey = generateRandomStarkPrivateKey();
|
||||
const keyPair = starkwareCrypto.ec.keyFromPrivate(privKey, 'hex');
|
||||
const keyPairPub = starkwareCrypto.ec.keyFromPublic(
|
||||
keyPair.getPublic(),
|
||||
'BN'
|
||||
);
|
||||
const msgHash = new BN(randomHexString(61));
|
||||
const msgSignature = starkwareCrypto.sign(keyPair, msgHash);
|
||||
|
||||
// Test invalid public key.
|
||||
const invalidKeyPairPub = starkwareCrypto.ec.keyFromPublic(
|
||||
{x: keyPairPub.pub.getX().add(oneBn), y: keyPairPub.pub.getY()},
|
||||
'BN'
|
||||
);
|
||||
expect(
|
||||
starkwareCrypto.verify(
|
||||
invalidKeyPairPub,
|
||||
msgHash.toString(16),
|
||||
msgSignature
|
||||
)
|
||||
).to.be.false;
|
||||
// Test invalid message.
|
||||
expect(
|
||||
starkwareCrypto.verify(
|
||||
keyPair,
|
||||
msgHash.add(oneBn).toString(16),
|
||||
msgSignature
|
||||
)
|
||||
).to.be.false;
|
||||
expect(
|
||||
starkwareCrypto.verify(
|
||||
keyPairPub,
|
||||
msgHash.add(oneBn).toString(16),
|
||||
msgSignature
|
||||
)
|
||||
).to.be.false;
|
||||
// Test invalid r.
|
||||
msgSignature.r.iadd(oneBn);
|
||||
expect(starkwareCrypto.verify(keyPair, msgHash.toString(16), msgSignature))
|
||||
.to.be.false;
|
||||
expect(
|
||||
starkwareCrypto.verify(keyPairPub, msgHash.toString(16), msgSignature)
|
||||
).to.be.false;
|
||||
// Test invalid s.
|
||||
msgSignature.r.isub(oneBn);
|
||||
msgSignature.s.iadd(oneBn);
|
||||
expect(starkwareCrypto.verify(keyPair, msgHash.toString(16), msgSignature))
|
||||
.to.be.false;
|
||||
expect(
|
||||
starkwareCrypto.verify(keyPairPub, msgHash.toString(16), msgSignature)
|
||||
).to.be.false;
|
||||
});
|
||||
});
|
||||
*/
|
||||
});
|
||||
|
||||
should('Pedersen', () => {
|
||||
deepStrictEqual(
|
||||
starknet.pedersen(
|
||||
'0x3d937c035c878245caf64531a5756109c53068da139362728feb561405371cb',
|
||||
'0x208a0a10250e382e1e4bbe2880906c2791bf6275695e02fbbc6aeff9cd8b31a'
|
||||
),
|
||||
'0x30e480bed5fe53fa909cc0f8c4d99b8f9f2c016be4c41e13a4848797979c662'
|
||||
);
|
||||
deepStrictEqual(
|
||||
starknet.pedersen(
|
||||
'0x58f580910a6ca59b28927c08fe6c43e2e303ca384badc365795fc645d479d45',
|
||||
'0x78734f65a067be9bdb39de18434d71e79f7b6466a4b66bbd979ab9e7515fe0b'
|
||||
),
|
||||
'0x68cc0b76cddd1dd4ed2301ada9b7c872b23875d5ff837b3a87993e0d9996b87'
|
||||
);
|
||||
});
|
||||
|
||||
should('Hash chain', () => {
|
||||
deepStrictEqual(starknet.hashChain([1, 2, 3]), starknet.pedersen(1, starknet.pedersen(2, 3)));
|
||||
});
|
||||
|
||||
should('Key grinding', () => {
|
||||
deepStrictEqual(
|
||||
starknet.grindKey('86F3E7293141F20A8BAFF320E8EE4ACCB9D4A4BF2B4D295E8CEE784DB46E0519'),
|
||||
'5c8c8683596c732541a59e03007b2d30dbbbb873556fe65b5fb63c16688f941'
|
||||
);
|
||||
// Loops more than once (verified manually)
|
||||
deepStrictEqual(
|
||||
starknet.grindKey('94F3E7293141F20A8BAFF320E8EE4ACCB9D4A4BF2B4D295E8CEE784DB46E0595'),
|
||||
'33880b9aba464c1c01c9f8f5b4fc1134698f9b0a8d18505cab6cdd34d93dc02'
|
||||
);
|
||||
});
|
||||
|
||||
should('Private to stark key', () => {
|
||||
deepStrictEqual(
|
||||
starknet.getStarkKey('0x178047D3869489C055D7EA54C014FFB834A069C9595186ABE04EA4D1223A03F'),
|
||||
'0x1895a6a77ae14e7987b9cb51329a5adfb17bd8e7c638f92d6892d76e51cebcf'
|
||||
);
|
||||
for (const [privKey, expectedPubKey] of Object.entries(precomputedKeys)) {
|
||||
deepStrictEqual(starknet.getStarkKey(privKey), expectedPubKey);
|
||||
}
|
||||
});
|
||||
|
||||
should('Private stark key from eth signature', () => {
|
||||
const ethSignature =
|
||||
'0x21fbf0696d5e0aa2ef41a2b4ffb623bcaf070461d61cf7251c74161f82fec3a43' +
|
||||
'70854bc0a34b3ab487c1bc021cd318c734c51ae29374f2beb0e6f2dd49b4bf41c';
|
||||
deepStrictEqual(
|
||||
starknet.ethSigToPrivate(ethSignature),
|
||||
'766f11e90cd7c7b43085b56da35c781f8c067ac0d578eabdceebc4886435bda'
|
||||
);
|
||||
});
|
||||
|
||||
should('Key derivation', () => {
|
||||
const layer = 'starkex';
|
||||
const application = 'starkdeployement';
|
||||
const mnemonic =
|
||||
'range mountain blast problem vibrant void vivid doctor cluster enough melody ' +
|
||||
'salt layer language laptop boat major space monkey unit glimpse pause change vibrant';
|
||||
const ethAddress = '0xa4864d977b944315389d1765ffa7e66F74ee8cd7';
|
||||
const VECTORS = [
|
||||
{
|
||||
index: 0,
|
||||
path: "m/2645'/579218131'/891216374'/1961790679'/2135936222'/0",
|
||||
privateKey: '6cf0a8bf113352eb863157a45c5e5567abb34f8d32cddafd2c22aa803f4892c',
|
||||
},
|
||||
{
|
||||
index: 7,
|
||||
path: "m/2645'/579218131'/891216374'/1961790679'/2135936222'/7",
|
||||
privateKey: '341751bdc42841da35ab74d13a1372c1f0250617e8a2ef96034d9f46e6847af',
|
||||
},
|
||||
{
|
||||
index: 598,
|
||||
path: "m/2645'/579218131'/891216374'/1961790679'/2135936222'/598",
|
||||
privateKey: '41a4d591a868353d28b7947eb132aa4d00c4a022743689ffd20a3628d6ca28c',
|
||||
},
|
||||
];
|
||||
const hd = bip32.HDKey.fromMasterSeed(bip39.mnemonicToSeedSync(mnemonic));
|
||||
for (const { index, path, privateKey } of VECTORS) {
|
||||
const realPath = starknet.getAccountPath(layer, application, ethAddress, index);
|
||||
deepStrictEqual(realPath, path);
|
||||
deepStrictEqual(starknet.grindKey(hd.derive(realPath).privateKey), privateKey);
|
||||
}
|
||||
});
|
||||
|
||||
// Verified against starknet.js
|
||||
should('Starknet.js cross-tests', () => {
|
||||
const privateKey = '0x019800ea6a9a73f94aee6a3d2edf018fc770443e90c7ba121e8303ec6b349279';
|
||||
// NOTE: there is no compressed keys here, getPubKey returns stark-key (which is schnorr-like X coordinate)
|
||||
// But it is not used in signing/verifying
|
||||
deepStrictEqual(
|
||||
starknet.getStarkKey(privateKey),
|
||||
'0x33f45f07e1bd1a51b45fc24ec8c8c9908db9e42191be9e169bfcac0c0d99745'
|
||||
);
|
||||
const msgHash = '0x6d1706bd3d1ba7c517be2a2a335996f63d4738e2f182144d078a1dd9997062e';
|
||||
const sig = starknet.sign(msgHash, privateKey);
|
||||
const { r, s } = (sig);
|
||||
|
||||
deepStrictEqual(
|
||||
r.toString(),
|
||||
'1427981024487605678086498726488552139932400435436186597196374630267616399345'
|
||||
);
|
||||
deepStrictEqual(
|
||||
s.toString(),
|
||||
'1853664302719670721837677288395394946745467311923401353018029119631574115563'
|
||||
);
|
||||
const hashMsg2 = starknet.pedersen(
|
||||
'0x33f45f07e1bd1a51b45fc24ec8c8c9908db9e42191be9e169bfcac0c0d99745',
|
||||
'1'
|
||||
);
|
||||
deepStrictEqual(hashMsg2, '0x2b0d4d43acce8ff68416f667f92ec7eab2b96f1d2224abd4d9d4d1e7fa4bb00');
|
||||
const pubKey =
|
||||
'04033f45f07e1bd1a51b45fc24ec8c8c9908db9e42191be9e169bfcac0c0d997450319d0f53f6ca077c4fa5207819144a2a4165daef6ee47a7c1d06c0dcaa3e456';
|
||||
const sig2 = new starknet.Signature(
|
||||
558858382392827003930138586379728730695763862039474863361948210004201119180n,
|
||||
2440689354481625417078677634625227600823892606910345662891037256374285369343n
|
||||
);
|
||||
deepStrictEqual(starknet.verify(sig2.toDERHex(), hashMsg2, pubKey), true);
|
||||
});
|
||||
|
||||
// ESM is broken.
|
||||
import url from 'url';
|
||||
if (import.meta.url === url.pathToFileURL(process.argv[1]).href) {
|
||||
should.run();
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"strict": true,
|
||||
"declaration": true,
|
||||
"declarationMap": true,
|
||||
"target": "es2020",
|
||||
"lib": [
|
||||
"es2020",
|
||||
"dom"
|
||||
],
|
||||
"module": "es6",
|
||||
"moduleResolution": "node16",
|
||||
"outDir": "lib",
|
||||
"noImplicitAny": true,
|
||||
"preserveConstEnums": true,
|
||||
"baseUrl": ".",
|
||||
},
|
||||
"include": [
|
||||
"src",
|
||||
],
|
||||
"exclude": [
|
||||
"node_modules",
|
||||
"lib"
|
||||
]
|
||||
}
|
||||
182
package.json
182
package.json
@@ -1,19 +1,17 @@
|
||||
{
|
||||
"name": "@noble/curves",
|
||||
"version": "0.1.0",
|
||||
"description": "Minimal, zero-dependency JS implementation of elliptic curve cryptography",
|
||||
"version": "0.6.2",
|
||||
"description": "Minimal, auditable JS implementation of elliptic curve cryptography",
|
||||
"files": [
|
||||
"index.js",
|
||||
"lib",
|
||||
"lib/esm"
|
||||
"lib"
|
||||
],
|
||||
"scripts": {
|
||||
"bench": "node test/benchmark/index.js",
|
||||
"bench": "cd benchmark; node secp256k1.js; node curves.js; node stark.js; node bls.js",
|
||||
"build": "tsc && tsc -p tsconfig.esm.json",
|
||||
"build:release": "rollup -c rollup.config.js",
|
||||
"lint": "prettier --check 'src/**/*.{js,ts}' 'curve-definitions/src/**/*.{js,ts}'",
|
||||
"format": "prettier --write 'src/**/*.{js,ts}' 'curve-definitions/src/**/*.{js,ts}'",
|
||||
"test": "cd curve-definitions; node test/index.test.js"
|
||||
"lint": "prettier --check 'src/**/*.{js,ts}' 'test/*.js'",
|
||||
"format": "prettier --write 'src/**/*.{js,ts}' 'test/*.js'",
|
||||
"test": "node test/index.test.js"
|
||||
},
|
||||
"author": "Paul Miller (https://paulmillr.com)",
|
||||
"homepage": "https://paulmillr.com/noble/",
|
||||
@@ -22,45 +20,169 @@
|
||||
"url": "https://github.com/paulmillr/noble-curves.git"
|
||||
},
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@noble/hashes": "1.1.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@rollup/plugin-node-resolve": "13.3.0",
|
||||
"micro-bmark": "0.2.0",
|
||||
"micro-should": "0.2.0",
|
||||
"prettier": "2.6.2",
|
||||
"@scure/base": "~1.1.1",
|
||||
"@scure/bip32": "~1.1.1",
|
||||
"@scure/bip39": "~1.1.0",
|
||||
"@types/node": "18.11.3",
|
||||
"fast-check": "3.0.0",
|
||||
"micro-bmark": "0.3.0",
|
||||
"micro-should": "0.4.0",
|
||||
"prettier": "2.8.3",
|
||||
"rollup": "2.75.5",
|
||||
"typescript": "4.7.3"
|
||||
},
|
||||
"main": "index.js",
|
||||
"exports": {
|
||||
"./modular": {
|
||||
"types": "./lib/modular.d.ts",
|
||||
"import": "./lib/esm/modular.js",
|
||||
"default": "./lib/modular.js"
|
||||
".": {
|
||||
"types": "./lib/index.d.ts",
|
||||
"import": "./lib/esm/index.js",
|
||||
"default": "./lib/index.js"
|
||||
},
|
||||
"./shortw": {
|
||||
"types": "./lib/shortw.d.ts",
|
||||
"import": "./lib/esm/shortw.js",
|
||||
"default": "./lib/shortw.js"
|
||||
"./abstract/edwards": {
|
||||
"types": "./lib/abstract/edwards.d.ts",
|
||||
"import": "./lib/esm/abstract/edwards.js",
|
||||
"default": "./lib/abstract/edwards.js"
|
||||
},
|
||||
"./utils": {
|
||||
"types": "./lib/utils.d.ts",
|
||||
"import": "./lib/esm/utils.js",
|
||||
"default": "./lib/utils.js"
|
||||
"./abstract/modular": {
|
||||
"types": "./lib/abstract/modular.d.ts",
|
||||
"import": "./lib/esm/abstract/modular.js",
|
||||
"default": "./lib/abstract/modular.js"
|
||||
},
|
||||
"./abstract/montgomery": {
|
||||
"types": "./lib/abstract/montgomery.d.ts",
|
||||
"import": "./lib/esm/abstract/montgomery.js",
|
||||
"default": "./lib/abstract/montgomery.js"
|
||||
},
|
||||
"./abstract/weierstrass": {
|
||||
"types": "./lib/abstract/weierstrass.d.ts",
|
||||
"import": "./lib/esm/abstract/weierstrass.js",
|
||||
"default": "./lib/abstract/weierstrass.js"
|
||||
},
|
||||
"./abstract/bls": {
|
||||
"types": "./lib/abstract/bls.d.ts",
|
||||
"import": "./lib/esm/abstract/bls.js",
|
||||
"default": "./lib/abstract/bls.js"
|
||||
},
|
||||
"./abstract/hash-to-curve": {
|
||||
"types": "./lib/abstract/hash-to-curve.d.ts",
|
||||
"import": "./lib/esm/abstract/hash-to-curve.js",
|
||||
"default": "./lib/abstract/hash-to-curve.js"
|
||||
},
|
||||
"./abstract/curve": {
|
||||
"types": "./lib/abstract/curve.d.ts",
|
||||
"import": "./lib/esm/abstract/curve.js",
|
||||
"default": "./lib/abstract/curve.js"
|
||||
},
|
||||
"./abstract/utils": {
|
||||
"types": "./lib/abstract/utils.d.ts",
|
||||
"import": "./lib/esm/abstract/utils.js",
|
||||
"default": "./lib/abstract/utils.js"
|
||||
},
|
||||
"./abstract/poseidon": {
|
||||
"types": "./lib/abstract/poseidon.d.ts",
|
||||
"import": "./lib/esm/abstract/poseidon.js",
|
||||
"default": "./lib/abstract/poseidon.js"
|
||||
},
|
||||
"./_shortw_utils": {
|
||||
"types": "./lib/_shortw_utils.d.ts",
|
||||
"import": "./lib/esm/_shortw_utils.js",
|
||||
"default": "./lib/_shortw_utils.js"
|
||||
},
|
||||
"./bls12-381": {
|
||||
"types": "./lib/bls12-381.d.ts",
|
||||
"import": "./lib/esm/bls12-381.js",
|
||||
"default": "./lib/bls12-381.js"
|
||||
},
|
||||
"./bn": {
|
||||
"types": "./lib/bn.d.ts",
|
||||
"import": "./lib/esm/bn.js",
|
||||
"default": "./lib/bn.js"
|
||||
},
|
||||
"./ed25519": {
|
||||
"types": "./lib/ed25519.d.ts",
|
||||
"import": "./lib/esm/ed25519.js",
|
||||
"default": "./lib/ed25519.js"
|
||||
},
|
||||
"./ed448": {
|
||||
"types": "./lib/ed448.d.ts",
|
||||
"import": "./lib/esm/ed448.js",
|
||||
"default": "./lib/ed448.js"
|
||||
},
|
||||
"./index": {
|
||||
"types": "./lib/index.d.ts",
|
||||
"import": "./lib/esm/index.js",
|
||||
"default": "./lib/index.js"
|
||||
},
|
||||
"./jubjub": {
|
||||
"types": "./lib/jubjub.d.ts",
|
||||
"import": "./lib/esm/jubjub.js",
|
||||
"default": "./lib/jubjub.js"
|
||||
},
|
||||
"./p192": {
|
||||
"types": "./lib/p192.d.ts",
|
||||
"import": "./lib/esm/p192.js",
|
||||
"default": "./lib/p192.js"
|
||||
},
|
||||
"./p224": {
|
||||
"types": "./lib/p224.d.ts",
|
||||
"import": "./lib/esm/p224.js",
|
||||
"default": "./lib/p224.js"
|
||||
},
|
||||
"./p256": {
|
||||
"types": "./lib/p256.d.ts",
|
||||
"import": "./lib/esm/p256.js",
|
||||
"default": "./lib/p256.js"
|
||||
},
|
||||
"./p384": {
|
||||
"types": "./lib/p384.d.ts",
|
||||
"import": "./lib/esm/p384.js",
|
||||
"default": "./lib/p384.js"
|
||||
},
|
||||
"./p521": {
|
||||
"types": "./lib/p521.d.ts",
|
||||
"import": "./lib/esm/p521.js",
|
||||
"default": "./lib/p521.js"
|
||||
},
|
||||
"./pasta": {
|
||||
"types": "./lib/pasta.d.ts",
|
||||
"import": "./lib/esm/pasta.js",
|
||||
"default": "./lib/pasta.js"
|
||||
},
|
||||
"./secp256k1": {
|
||||
"types": "./lib/secp256k1.d.ts",
|
||||
"import": "./lib/esm/secp256k1.js",
|
||||
"default": "./lib/secp256k1.js"
|
||||
},
|
||||
"./stark": {
|
||||
"types": "./lib/stark.d.ts",
|
||||
"import": "./lib/esm/stark.js",
|
||||
"default": "./lib/stark.js"
|
||||
}
|
||||
},
|
||||
"keywords": [
|
||||
"elliptic",
|
||||
"curve",
|
||||
"cryptography",
|
||||
"hyperelliptic",
|
||||
"weierstrass",
|
||||
"montgomery",
|
||||
"edwards",
|
||||
"p256",
|
||||
"p384",
|
||||
"p521",
|
||||
"secp256r1",
|
||||
"secp256k1",
|
||||
"ed25519",
|
||||
"ed448",
|
||||
"bls12-381",
|
||||
"bn254",
|
||||
"pasta",
|
||||
"bls",
|
||||
"nist",
|
||||
"weierstrass",
|
||||
"edwards",
|
||||
"montgomery",
|
||||
"hashes",
|
||||
"ecc",
|
||||
"ecdsa",
|
||||
"eddsa",
|
||||
@@ -72,4 +194,4 @@
|
||||
"url": "https://paulmillr.com/funding/"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
19
src/_shortw_utils.ts
Normal file
19
src/_shortw_utils.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
||||
import { hmac } from '@noble/hashes/hmac';
|
||||
import { concatBytes, randomBytes } from '@noble/hashes/utils';
|
||||
import { weierstrass, CurveType } from './abstract/weierstrass.js';
|
||||
import { CHash } from './abstract/utils.js';
|
||||
|
||||
export function getHash(hash: CHash) {
|
||||
return {
|
||||
hash,
|
||||
hmac: (key: Uint8Array, ...msgs: Uint8Array[]) => hmac(hash, key, concatBytes(...msgs)),
|
||||
randomBytes,
|
||||
};
|
||||
}
|
||||
// Same API as @noble/hashes, with ability to create curve with custom hash
|
||||
type CurveDef = Readonly<Omit<CurveType, 'hash' | 'hmac' | 'randomBytes'>>;
|
||||
export function createCurve(curveDef: CurveDef, defHash: CHash) {
|
||||
const create = (hash: CHash) => weierstrass({ ...curveDef, ...getHash(hash) });
|
||||
return Object.freeze({ ...create(defHash), create });
|
||||
}
|
||||
396
src/abstract/bls.ts
Normal file
396
src/abstract/bls.ts
Normal file
@@ -0,0 +1,396 @@
|
||||
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
||||
/**
|
||||
* BLS (Barreto-Lynn-Scott) family of pairing-friendly curves.
|
||||
* Implements BLS (Boneh-Lynn-Shacham) signatures.
|
||||
* Consists of two curves: G1 and G2:
|
||||
* - G1 is a subgroup of (x, y) E(Fq) over y² = x³ + 4.
|
||||
* - G2 is a subgroup of ((x₁, x₂+i), (y₁, y₂+i)) E(Fq²) over y² = x³ + 4(1 + i) where i is √-1
|
||||
* - Gt, created by bilinear (ate) pairing e(G1, G2), consists of p-th roots of unity in
|
||||
* Fq^k where k is embedding degree. Only degree 12 is currently supported, 24 is not.
|
||||
* Pairing is used to aggregate and verify signatures.
|
||||
* We are using Fp for private keys (shorter) and Fp₂ for signatures (longer).
|
||||
* Some projects may prefer to swap this relation, it is not supported for now.
|
||||
*/
|
||||
import { AffinePoint } from './curve.js';
|
||||
import { Field, hashToPrivateScalar } from './modular.js';
|
||||
import { Hex, PrivKey, CHash, bitLen, bitGet, hexToBytes, bytesToHex } from './utils.js';
|
||||
import * as htf from './hash-to-curve.js';
|
||||
import {
|
||||
CurvePointsType,
|
||||
ProjPointType as ProjPointType,
|
||||
CurvePointsRes,
|
||||
weierstrassPoints,
|
||||
} from './weierstrass.js';
|
||||
|
||||
type Fp = bigint; // Can be different field?
|
||||
|
||||
export type SignatureCoder<Fp2> = {
|
||||
decode(hex: Hex): ProjPointType<Fp2>;
|
||||
encode(point: ProjPointType<Fp2>): Uint8Array;
|
||||
};
|
||||
|
||||
export type CurveType<Fp, Fp2, Fp6, Fp12> = {
|
||||
r: bigint;
|
||||
G1: Omit<CurvePointsType<Fp>, 'n'> & {
|
||||
mapToCurve: htf.MapToCurve<Fp>;
|
||||
htfDefaults: htf.Opts;
|
||||
};
|
||||
G2: Omit<CurvePointsType<Fp2>, 'n'> & {
|
||||
Signature: SignatureCoder<Fp2>;
|
||||
mapToCurve: htf.MapToCurve<Fp2>;
|
||||
htfDefaults: htf.Opts;
|
||||
};
|
||||
x: bigint;
|
||||
Fp: Field<Fp>;
|
||||
Fr: Field<bigint>;
|
||||
Fp2: Field<Fp2> & {
|
||||
reim: (num: Fp2) => { re: bigint; im: bigint };
|
||||
multiplyByB: (num: Fp2) => Fp2;
|
||||
frobeniusMap(num: Fp2, power: number): Fp2;
|
||||
};
|
||||
Fp6: Field<Fp6>;
|
||||
Fp12: Field<Fp12> & {
|
||||
frobeniusMap(num: Fp12, power: number): Fp12;
|
||||
multiplyBy014(num: Fp12, o0: Fp2, o1: Fp2, o4: Fp2): Fp12;
|
||||
conjugate(num: Fp12): Fp12;
|
||||
finalExponentiate(num: Fp12): Fp12;
|
||||
};
|
||||
htfDefaults: htf.Opts;
|
||||
hash: CHash; // Because we need outputLen for DRBG
|
||||
randomBytes: (bytesLength?: number) => Uint8Array;
|
||||
};
|
||||
|
||||
export type CurveFn<Fp, Fp2, Fp6, Fp12> = {
|
||||
CURVE: CurveType<Fp, Fp2, Fp6, Fp12>;
|
||||
Fr: Field<bigint>;
|
||||
Fp: Field<Fp>;
|
||||
Fp2: Field<Fp2>;
|
||||
Fp6: Field<Fp6>;
|
||||
Fp12: Field<Fp12>;
|
||||
G1: CurvePointsRes<Fp>;
|
||||
G2: CurvePointsRes<Fp2>;
|
||||
Signature: SignatureCoder<Fp2>;
|
||||
millerLoop: (ell: [Fp2, Fp2, Fp2][], g1: [Fp, Fp]) => Fp12;
|
||||
calcPairingPrecomputes: (p: AffinePoint<Fp2>) => [Fp2, Fp2, Fp2][];
|
||||
// prettier-ignore
|
||||
hashToCurve: {
|
||||
G1: ReturnType<(typeof htf.hashToCurve<Fp>)>,
|
||||
G2: ReturnType<(typeof htf.hashToCurve<Fp2>)>,
|
||||
},
|
||||
pairing: (P: ProjPointType<Fp>, Q: ProjPointType<Fp2>, withFinalExponent?: boolean) => Fp12;
|
||||
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;
|
||||
aggregatePublicKeys: {
|
||||
(publicKeys: Hex[]): Uint8Array;
|
||||
(publicKeys: ProjPointType<Fp>[]): ProjPointType<Fp>;
|
||||
};
|
||||
aggregateSignatures: {
|
||||
(signatures: Hex[]): Uint8Array;
|
||||
(signatures: ProjPointType<Fp2>[]): ProjPointType<Fp2>;
|
||||
};
|
||||
verifyBatch: (
|
||||
signature: Hex | ProjPointType<Fp2>,
|
||||
messages: (Hex | ProjPointType<Fp2>)[],
|
||||
publicKeys: (Hex | ProjPointType<Fp>)[]
|
||||
) => boolean;
|
||||
utils: {
|
||||
stringToBytes: typeof htf.stringToBytes;
|
||||
hashToField: typeof htf.hash_to_field;
|
||||
expandMessageXMD: typeof htf.expand_message_xmd;
|
||||
};
|
||||
};
|
||||
|
||||
export function bls<Fp2, Fp6, Fp12>(
|
||||
CURVE: CurveType<Fp, Fp2, Fp6, Fp12>
|
||||
): CurveFn<Fp, Fp2, Fp6, Fp12> {
|
||||
// Fields looks pretty specific for curve, so for now we need to pass them with options
|
||||
const { Fp, Fr, Fp2, Fp6, Fp12 } = CURVE;
|
||||
const BLS_X_LEN = bitLen(CURVE.x);
|
||||
const groupLen = 32; // TODO: calculate; hardcoded for now
|
||||
|
||||
// Pre-compute coefficients for sparse multiplication
|
||||
// Point addition and point double calculations is reused for coefficients
|
||||
function calcPairingPrecomputes(p: AffinePoint<Fp2>) {
|
||||
const { x, y } = p;
|
||||
// prettier-ignore
|
||||
const Qx = x, Qy = y, Qz = Fp2.ONE;
|
||||
// prettier-ignore
|
||||
let Rx = Qx, Ry = Qy, Rz = Qz;
|
||||
let ell_coeff: [Fp2, Fp2, Fp2][] = [];
|
||||
for (let i = BLS_X_LEN - 2; i >= 0; i--) {
|
||||
// Double
|
||||
let t0 = Fp2.sqr(Ry); // Ry²
|
||||
let t1 = Fp2.sqr(Rz); // Rz²
|
||||
let t2 = Fp2.multiplyByB(Fp2.mul(t1, 3n)); // 3 * T1 * B
|
||||
let t3 = Fp2.mul(t2, 3n); // 3 * T2
|
||||
let t4 = Fp2.sub(Fp2.sub(Fp2.sqr(Fp2.add(Ry, Rz)), t1), t0); // (Ry + Rz)² - T1 - T0
|
||||
ell_coeff.push([
|
||||
Fp2.sub(t2, t0), // T2 - T0
|
||||
Fp2.mul(Fp2.sqr(Rx), 3n), // 3 * Rx²
|
||||
Fp2.neg(t4), // -T4
|
||||
]);
|
||||
Rx = Fp2.div(Fp2.mul(Fp2.mul(Fp2.sub(t0, t3), Rx), Ry), 2n); // ((T0 - T3) * Rx * Ry) / 2
|
||||
Ry = Fp2.sub(Fp2.sqr(Fp2.div(Fp2.add(t0, t3), 2n)), Fp2.mul(Fp2.sqr(t2), 3n)); // ((T0 + T3) / 2)² - 3 * T2²
|
||||
Rz = Fp2.mul(t0, t4); // T0 * T4
|
||||
if (bitGet(CURVE.x, i)) {
|
||||
// Addition
|
||||
let t0 = Fp2.sub(Ry, Fp2.mul(Qy, Rz)); // Ry - Qy * Rz
|
||||
let t1 = Fp2.sub(Rx, Fp2.mul(Qx, Rz)); // Rx - Qx * Rz
|
||||
ell_coeff.push([
|
||||
Fp2.sub(Fp2.mul(t0, Qx), Fp2.mul(t1, Qy)), // T0 * Qx - T1 * Qy
|
||||
Fp2.neg(t0), // -T0
|
||||
t1, // T1
|
||||
]);
|
||||
let t2 = Fp2.sqr(t1); // T1²
|
||||
let t3 = Fp2.mul(t2, t1); // T2 * T1
|
||||
let t4 = Fp2.mul(t2, Rx); // T2 * Rx
|
||||
let t5 = Fp2.add(Fp2.sub(t3, Fp2.mul(t4, 2n)), Fp2.mul(Fp2.sqr(t0), Rz)); // T3 - 2 * T4 + T0² * Rz
|
||||
Rx = Fp2.mul(t1, t5); // T1 * T5
|
||||
Ry = Fp2.sub(Fp2.mul(Fp2.sub(t4, t5), t0), Fp2.mul(t3, Ry)); // (T4 - T5) * T0 - T3 * Ry
|
||||
Rz = Fp2.mul(Rz, t3); // Rz * T3
|
||||
}
|
||||
}
|
||||
return ell_coeff;
|
||||
}
|
||||
|
||||
function millerLoop(ell: [Fp2, Fp2, Fp2][], g1: [Fp, Fp]): Fp12 {
|
||||
const { x } = CURVE;
|
||||
const Px = g1[0];
|
||||
const Py = g1[1];
|
||||
let f12 = Fp12.ONE;
|
||||
for (let j = 0, i = BLS_X_LEN - 2; i >= 0; i--, j++) {
|
||||
const E = ell[j];
|
||||
f12 = Fp12.multiplyBy014(f12, E[0], Fp2.mul(E[1], Px), Fp2.mul(E[2], Py));
|
||||
if (bitGet(x, i)) {
|
||||
j += 1;
|
||||
const F = ell[j];
|
||||
f12 = Fp12.multiplyBy014(f12, F[0], Fp2.mul(F[1], Px), Fp2.mul(F[2], Py));
|
||||
}
|
||||
if (i !== 0) f12 = Fp12.sqr(f12);
|
||||
}
|
||||
return Fp12.conjugate(f12);
|
||||
}
|
||||
|
||||
const utils = {
|
||||
hexToBytes: hexToBytes,
|
||||
bytesToHex: bytesToHex,
|
||||
stringToBytes: htf.stringToBytes,
|
||||
// TODO: do we need to export it here?
|
||||
hashToField: (
|
||||
msg: Uint8Array,
|
||||
count: number,
|
||||
options: Partial<typeof CURVE.htfDefaults> = {}
|
||||
) => htf.hash_to_field(msg, count, { ...CURVE.htfDefaults, ...options }),
|
||||
expandMessageXMD: (msg: Uint8Array, DST: Uint8Array, lenInBytes: number, H = CURVE.hash) =>
|
||||
htf.expand_message_xmd(msg, DST, lenInBytes, H),
|
||||
hashToPrivateKey: (hash: Hex): Uint8Array => Fr.toBytes(hashToPrivateScalar(hash, CURVE.r)),
|
||||
randomBytes: (bytesLength: number = groupLen): Uint8Array => CURVE.randomBytes(bytesLength),
|
||||
randomPrivateKey: (): Uint8Array => utils.hashToPrivateKey(utils.randomBytes(groupLen + 8)),
|
||||
};
|
||||
|
||||
// Point on G1 curve: (x, y)
|
||||
const G1 = weierstrassPoints({
|
||||
n: Fr.ORDER,
|
||||
...CURVE.G1,
|
||||
});
|
||||
const G1HashToCurve = htf.hashToCurve(G1.ProjectivePoint, CURVE.G1.mapToCurve, {
|
||||
...CURVE.htfDefaults,
|
||||
...CURVE.G1.htfDefaults,
|
||||
});
|
||||
|
||||
// Sparse multiplication against precomputed coefficients
|
||||
// TODO: replace with weakmap?
|
||||
type withPairingPrecomputes = { _PPRECOMPUTES: [Fp2, Fp2, Fp2][] | undefined };
|
||||
function pairingPrecomputes(point: G2): [Fp2, Fp2, Fp2][] {
|
||||
const p = point as G2 & withPairingPrecomputes;
|
||||
if (p._PPRECOMPUTES) return p._PPRECOMPUTES;
|
||||
p._PPRECOMPUTES = calcPairingPrecomputes(point.toAffine());
|
||||
return p._PPRECOMPUTES;
|
||||
}
|
||||
|
||||
// TODO: export
|
||||
// function clearPairingPrecomputes(point: G2) {
|
||||
// const p = point as G2 & withPairingPrecomputes;
|
||||
// p._PPRECOMPUTES = undefined;
|
||||
// }
|
||||
|
||||
// Point on G2 curve (complex numbers): (x₁, x₂+i), (y₁, y₂+i)
|
||||
const G2 = weierstrassPoints({
|
||||
n: Fr.ORDER,
|
||||
...CURVE.G2,
|
||||
});
|
||||
const C = G2.ProjectivePoint as htf.H2CPointConstructor<Fp2>; // TODO: fix
|
||||
const G2HashToCurve = htf.hashToCurve(C, CURVE.G2.mapToCurve, {
|
||||
...CURVE.htfDefaults,
|
||||
...CURVE.G2.htfDefaults,
|
||||
});
|
||||
|
||||
const { Signature } = CURVE.G2;
|
||||
|
||||
// Calculates bilinear pairing
|
||||
function pairing(Q: G1, P: G2, withFinalExponent: boolean = true): Fp12 {
|
||||
if (Q.equals(G1.ProjectivePoint.ZERO) || P.equals(G2.ProjectivePoint.ZERO))
|
||||
throw new Error('pairing is not available for ZERO point');
|
||||
Q.assertValidity();
|
||||
P.assertValidity();
|
||||
// Performance: 9ms for millerLoop and ~14ms for exp.
|
||||
const Qa = Q.toAffine();
|
||||
const looped = millerLoop(pairingPrecomputes(P), [Qa.x, Qa.y]);
|
||||
return withFinalExponent ? Fp12.finalExponentiate(looped) : looped;
|
||||
}
|
||||
type G1 = typeof G1.ProjectivePoint.BASE;
|
||||
type G2 = typeof G2.ProjectivePoint.BASE;
|
||||
|
||||
type G1Hex = Hex | G1;
|
||||
type G2Hex = Hex | G2;
|
||||
function normP1(point: G1Hex): G1 {
|
||||
return point instanceof G1.ProjectivePoint ? (point as G1) : G1.ProjectivePoint.fromHex(point);
|
||||
}
|
||||
function normP2(point: G2Hex): G2 {
|
||||
return point instanceof G2.ProjectivePoint ? point : Signature.decode(point);
|
||||
}
|
||||
function normP2Hash(point: G2Hex, htfOpts?: htf.htfBasicOpts): G2 {
|
||||
return point instanceof G2.ProjectivePoint
|
||||
? point
|
||||
: (G2HashToCurve.hashToCurve(point, htfOpts) as G2);
|
||||
}
|
||||
|
||||
// Multiplies generator by private key.
|
||||
// P = pk x G
|
||||
function getPublicKey(privateKey: PrivKey): Uint8Array {
|
||||
return G1.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 {
|
||||
const msgPoint = normP2Hash(message, htfOpts);
|
||||
msgPoint.assertValidity();
|
||||
const sigPoint = msgPoint.multiply(G1.normalizePrivateKey(privateKey));
|
||||
if (message instanceof G2.ProjectivePoint) return sigPoint;
|
||||
return Signature.encode(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
|
||||
): boolean {
|
||||
const P = normP1(publicKey);
|
||||
const Hm = normP2Hash(message, htfOpts);
|
||||
const G = G1.ProjectivePoint.BASE;
|
||||
const S = normP2(signature);
|
||||
// Instead of doing 2 exponentiations, we use property of billinear maps
|
||||
// and do one exp after multiplying 2 points.
|
||||
const ePHm = pairing(P.negate(), Hm, false);
|
||||
const eGS = pairing(G, S, false);
|
||||
const exp = Fp12.finalExponentiate(Fp12.mul(eGS, ePHm));
|
||||
return Fp12.eql(exp, Fp12.ONE);
|
||||
}
|
||||
|
||||
// Adds a bunch of public key points together.
|
||||
// pk1 + pk2 + pk3 = pkA
|
||||
function aggregatePublicKeys(publicKeys: Hex[]): Uint8Array;
|
||||
function aggregatePublicKeys(publicKeys: G1[]): G1;
|
||||
function aggregatePublicKeys(publicKeys: G1Hex[]): Uint8Array | G1 {
|
||||
if (!publicKeys.length) throw new Error('Expected non-empty array');
|
||||
const agg = publicKeys.map(normP1).reduce((sum, p) => sum.add(p), G1.ProjectivePoint.ZERO);
|
||||
const aggAffine = agg; //.toAffine();
|
||||
if (publicKeys[0] instanceof G1.ProjectivePoint) {
|
||||
aggAffine.assertValidity();
|
||||
return aggAffine;
|
||||
}
|
||||
// toRawBytes ensures point validity
|
||||
return aggAffine.toRawBytes(true);
|
||||
}
|
||||
|
||||
// Adds a bunch of signature points together.
|
||||
function aggregateSignatures(signatures: Hex[]): Uint8Array;
|
||||
function aggregateSignatures(signatures: G2[]): G2;
|
||||
function aggregateSignatures(signatures: G2Hex[]): Uint8Array | G2 {
|
||||
if (!signatures.length) throw new Error('Expected non-empty array');
|
||||
const agg = signatures.map(normP2).reduce((sum, s) => sum.add(s), G2.ProjectivePoint.ZERO);
|
||||
const aggAffine = agg; //.toAffine();
|
||||
if (signatures[0] instanceof G2.ProjectivePoint) {
|
||||
aggAffine.assertValidity();
|
||||
return aggAffine;
|
||||
}
|
||||
return Signature.encode(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
|
||||
): boolean {
|
||||
// @ts-ignore
|
||||
// console.log('verifyBatch', bytesToHex(signature as any), messages, publicKeys.map(bytesToHex));
|
||||
|
||||
if (!messages.length) throw new Error('Expected non-empty messages array');
|
||||
if (publicKeys.length !== messages.length)
|
||||
throw new Error('Pubkey count should equal msg count');
|
||||
const sig = normP2(signature);
|
||||
const nMessages = messages.map((i) => normP2Hash(i, htfOpts));
|
||||
const nPublicKeys = publicKeys.map(normP1);
|
||||
try {
|
||||
const paired = [];
|
||||
for (const message of new Set(nMessages)) {
|
||||
const groupPublicKey = nMessages.reduce(
|
||||
(groupPublicKey, subMessage, i) =>
|
||||
subMessage === message ? groupPublicKey.add(nPublicKeys[i]) : groupPublicKey,
|
||||
G1.ProjectivePoint.ZERO
|
||||
);
|
||||
// const msg = message instanceof PointG2 ? message : await PointG2.hashToCurve(message);
|
||||
// Possible to batch pairing for same msg with different groupPublicKey here
|
||||
paired.push(pairing(groupPublicKey, message, false));
|
||||
}
|
||||
paired.push(pairing(G1.ProjectivePoint.BASE.negate(), sig, false));
|
||||
const product = paired.reduce((a, b) => Fp12.mul(a, b), Fp12.ONE);
|
||||
const exp = Fp12.finalExponentiate(product);
|
||||
return Fp12.eql(exp, Fp12.ONE);
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
G1.ProjectivePoint.BASE._setWindowSize(4);
|
||||
|
||||
return {
|
||||
CURVE,
|
||||
Fr,
|
||||
Fp,
|
||||
Fp2,
|
||||
Fp6,
|
||||
Fp12,
|
||||
G1,
|
||||
G2,
|
||||
Signature,
|
||||
millerLoop,
|
||||
calcPairingPrecomputes,
|
||||
hashToCurve: { G1: G1HashToCurve, G2: G2HashToCurve },
|
||||
pairing,
|
||||
getPublicKey,
|
||||
sign,
|
||||
verify,
|
||||
aggregatePublicKeys,
|
||||
aggregateSignatures,
|
||||
verifyBatch,
|
||||
utils,
|
||||
};
|
||||
}
|
||||
186
src/abstract/curve.ts
Normal file
186
src/abstract/curve.ts
Normal file
@@ -0,0 +1,186 @@
|
||||
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
||||
// Abelian group utilities
|
||||
import { Field, validateField, nLength } from './modular.js';
|
||||
import { validateObject } from './utils.js';
|
||||
const _0n = BigInt(0);
|
||||
const _1n = BigInt(1);
|
||||
|
||||
export type AffinePoint<T> = {
|
||||
x: T;
|
||||
y: T;
|
||||
} & { z?: never; t?: never };
|
||||
|
||||
export interface Group<T extends Group<T>> {
|
||||
double(): T;
|
||||
negate(): T;
|
||||
add(other: T): T;
|
||||
subtract(other: T): T;
|
||||
equals(other: T): boolean;
|
||||
multiply(scalar: bigint): T;
|
||||
}
|
||||
|
||||
export type GroupConstructor<T> = {
|
||||
BASE: T;
|
||||
ZERO: T;
|
||||
};
|
||||
export type Mapper<T> = (i: T[]) => T[];
|
||||
|
||||
// Elliptic curve multiplication of Point by scalar. Complicated and fragile. Uses wNAF method.
|
||||
// Windowed method is 10% faster, but takes 2x longer to generate & consumes 2x memory.
|
||||
export function wNAF<T extends Group<T>>(c: GroupConstructor<T>, bits: number) {
|
||||
const constTimeNegate = (condition: boolean, item: T): T => {
|
||||
const neg = item.negate();
|
||||
return condition ? neg : item;
|
||||
};
|
||||
const opts = (W: number) => {
|
||||
const windows = Math.ceil(bits / W) + 1; // +1, because
|
||||
const windowSize = 2 ** (W - 1); // -1 because we skip zero
|
||||
return { windows, windowSize };
|
||||
};
|
||||
return {
|
||||
constTimeNegate,
|
||||
// non-const time multiplication ladder
|
||||
unsafeLadder(elm: T, n: bigint) {
|
||||
let p = c.ZERO;
|
||||
let d: T = elm;
|
||||
while (n > _0n) {
|
||||
if (n & _1n) p = p.add(d);
|
||||
d = d.double();
|
||||
n >>= _1n;
|
||||
}
|
||||
return p;
|
||||
},
|
||||
|
||||
/**
|
||||
* Creates a wNAF precomputation window. Used for caching.
|
||||
* Default window size is set by `utils.precompute()` and is equal to 8.
|
||||
* Which means we are caching 65536 points: 256 points for every bit from 0 to 256.
|
||||
* @returns 65K precomputed points, depending on W
|
||||
*/
|
||||
precomputeWindow(elm: T, W: number): Group<T>[] {
|
||||
const { windows, windowSize } = opts(W);
|
||||
const points: T[] = [];
|
||||
let p: T = elm;
|
||||
let base = p;
|
||||
for (let window = 0; window < windows; window++) {
|
||||
base = p;
|
||||
points.push(base);
|
||||
// =1, because we skip zero
|
||||
for (let i = 1; i < windowSize; i++) {
|
||||
base = base.add(p);
|
||||
points.push(base);
|
||||
}
|
||||
p = base.double();
|
||||
}
|
||||
return points;
|
||||
},
|
||||
|
||||
/**
|
||||
* Implements w-ary non-adjacent form for calculating ec multiplication.
|
||||
* @param W window size
|
||||
* @param affinePoint optional 2d point to save cached precompute windows on it.
|
||||
* @param n bits
|
||||
* @returns real and fake (for const-time) points
|
||||
*/
|
||||
wNAF(W: number, precomputes: T[], n: bigint): { p: T; f: T } {
|
||||
// TODO: maybe check that scalar is less than group order? wNAF will fail otherwise
|
||||
// But need to carefully remove other checks before wNAF. ORDER == bits here
|
||||
const { windows, windowSize } = opts(W);
|
||||
|
||||
let p = c.ZERO;
|
||||
let f = c.BASE;
|
||||
|
||||
const mask = BigInt(2 ** W - 1); // Create mask with W ones: 0b1111 for W=4 etc.
|
||||
const maxNumber = 2 ** W;
|
||||
const shiftBy = BigInt(W);
|
||||
|
||||
for (let window = 0; window < windows; window++) {
|
||||
const offset = window * windowSize;
|
||||
// Extract W bits.
|
||||
let wbits = Number(n & mask);
|
||||
|
||||
// Shift number by W bits.
|
||||
n >>= shiftBy;
|
||||
|
||||
// If the bits are bigger than max size, we'll split those.
|
||||
// +224 => 256 - 32
|
||||
if (wbits > windowSize) {
|
||||
wbits -= maxNumber;
|
||||
n += _1n;
|
||||
}
|
||||
|
||||
// This code was first written with assumption that 'f' and 'p' will never be infinity point:
|
||||
// since each addition is multiplied by 2 ** W, it cannot cancel each other. However,
|
||||
// there is negate now: it is possible that negated element from low value
|
||||
// would be the same as high element, which will create carry into next window.
|
||||
// It's not obvious how this can fail, but still worth investigating later.
|
||||
|
||||
// Check if we're onto Zero point.
|
||||
// Add random point inside current window to f.
|
||||
const offset1 = offset;
|
||||
const offset2 = offset + Math.abs(wbits) - 1; // -1 because we skip zero
|
||||
const cond1 = window % 2 !== 0;
|
||||
const cond2 = wbits < 0;
|
||||
if (wbits === 0) {
|
||||
// The most important part for const-time getPublicKey
|
||||
f = f.add(constTimeNegate(cond1, precomputes[offset1]));
|
||||
} else {
|
||||
p = p.add(constTimeNegate(cond2, precomputes[offset2]));
|
||||
}
|
||||
}
|
||||
// JIT-compiler should not eliminate f here, since it will later be used in normalizeZ()
|
||||
// Even if the variable is still unused, there are some checks which will
|
||||
// throw an exception, so compiler needs to prove they won't happen, which is hard.
|
||||
// At this point there is a way to F be infinity-point even if p is not,
|
||||
// which makes it less const-time: around 1 bigint multiply.
|
||||
return { p, f };
|
||||
},
|
||||
|
||||
wNAFCached(P: T, precomputesMap: Map<T, T[]>, n: bigint, transform: Mapper<T>): { p: T; f: T } {
|
||||
// @ts-ignore
|
||||
const W: number = P._WINDOW_SIZE || 1;
|
||||
// Calculate precomputes on a first run, reuse them after
|
||||
let comp = precomputesMap.get(P);
|
||||
if (!comp) {
|
||||
comp = this.precomputeWindow(P, W) as T[];
|
||||
if (W !== 1) {
|
||||
precomputesMap.set(P, transform(comp));
|
||||
}
|
||||
}
|
||||
return this.wNAF(W, comp, n);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
// Generic BasicCurve interface: works even for polynomial fields (BLS): P, n, h would be ok.
|
||||
// Though generator can be different (Fp2 / Fp6 for BLS).
|
||||
export type BasicCurve<T> = {
|
||||
Fp: Field<T>; // Field over which we'll do calculations (Fp)
|
||||
n: bigint; // Curve order, total count of valid points in the field
|
||||
nBitLength?: number; // bit length of curve order
|
||||
nByteLength?: number; // byte length of curve order
|
||||
h: bigint; // cofactor. we can assign default=1, but users will just ignore it w/o validation
|
||||
hEff?: bigint; // Number to multiply to clear cofactor
|
||||
Gx: T; // base point X coordinate
|
||||
Gy: T; // base point Y coordinate
|
||||
allowInfinityPoint?: boolean; // bls12-381 requires it. ZERO point is valid, but invalid pubkey
|
||||
};
|
||||
|
||||
export function validateBasic<FP, T>(curve: BasicCurve<FP> & T) {
|
||||
validateField(curve.Fp);
|
||||
validateObject(
|
||||
curve,
|
||||
{
|
||||
n: 'bigint',
|
||||
h: 'bigint',
|
||||
Gx: 'field',
|
||||
Gy: 'field',
|
||||
},
|
||||
{
|
||||
nBitLength: 'isSafeInteger',
|
||||
nByteLength: 'isSafeInteger',
|
||||
}
|
||||
);
|
||||
// Set defaults
|
||||
return Object.freeze({ ...nLength(curve.n, curve.nBitLength), ...curve } as const);
|
||||
}
|
||||
486
src/abstract/edwards.ts
Normal file
486
src/abstract/edwards.ts
Normal file
@@ -0,0 +1,486 @@
|
||||
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
||||
// Twisted Edwards curve. The formula is: ax² + y² = 1 + dx²y²
|
||||
import { mod } from './modular.js';
|
||||
import * as ut from './utils.js';
|
||||
import { ensureBytes, FHash, Hex } from './utils.js';
|
||||
import { Group, GroupConstructor, wNAF, BasicCurve, validateBasic, AffinePoint } from './curve.js';
|
||||
|
||||
// Be friendly to bad ECMAScript parsers by not using bigint literals like 123n
|
||||
const _0n = BigInt(0);
|
||||
const _1n = BigInt(1);
|
||||
const _2n = BigInt(2);
|
||||
const _8n = BigInt(8);
|
||||
|
||||
// Edwards curves must declare params a & d.
|
||||
export type CurveType = BasicCurve<bigint> & {
|
||||
a: bigint; // curve param a
|
||||
d: bigint; // curve param d
|
||||
hash: FHash; // Hashing
|
||||
randomBytes: (bytesLength?: number) => Uint8Array; // CSPRNG
|
||||
adjustScalarBytes?: (bytes: Uint8Array) => Uint8Array; // clears bits to get valid field elemtn
|
||||
domain?: (data: Uint8Array, ctx: Uint8Array, phflag: boolean) => Uint8Array; // Used for hashing
|
||||
uvRatio?: (u: bigint, v: bigint) => { isValid: boolean; value: bigint }; // Ratio √(u/v)
|
||||
preHash?: FHash; // RFC 8032 pre-hashing of messages to sign() / verify()
|
||||
mapToCurve?: (scalar: bigint[]) => AffinePoint<bigint>; // for hash-to-curve standard
|
||||
};
|
||||
|
||||
function validateOpts(curve: CurveType) {
|
||||
const opts = validateBasic(curve);
|
||||
ut.validateObject(
|
||||
curve,
|
||||
{
|
||||
hash: 'function',
|
||||
a: 'bigint',
|
||||
d: 'bigint',
|
||||
randomBytes: 'function',
|
||||
},
|
||||
{
|
||||
adjustScalarBytes: 'function',
|
||||
domain: 'function',
|
||||
uvRatio: 'function',
|
||||
mapToCurve: 'function',
|
||||
}
|
||||
);
|
||||
// Set defaults
|
||||
return Object.freeze({ ...opts } as const);
|
||||
}
|
||||
|
||||
// Instance of Extended Point with coordinates in X, Y, Z, T
|
||||
export interface ExtPointType extends Group<ExtPointType> {
|
||||
readonly ex: bigint;
|
||||
readonly ey: bigint;
|
||||
readonly ez: bigint;
|
||||
readonly et: bigint;
|
||||
assertValidity(): void;
|
||||
multiply(scalar: bigint): ExtPointType;
|
||||
multiplyUnsafe(scalar: bigint): ExtPointType;
|
||||
isSmallOrder(): boolean;
|
||||
isTorsionFree(): boolean;
|
||||
clearCofactor(): ExtPointType;
|
||||
toAffine(iz?: bigint): AffinePoint<bigint>;
|
||||
}
|
||||
// Static methods of Extended Point with coordinates in X, Y, Z, T
|
||||
export interface ExtPointConstructor extends GroupConstructor<ExtPointType> {
|
||||
new (x: bigint, y: bigint, z: bigint, t: bigint): ExtPointType;
|
||||
fromAffine(p: AffinePoint<bigint>): ExtPointType;
|
||||
fromHex(hex: Hex): ExtPointType;
|
||||
fromPrivateKey(privateKey: Hex): ExtPointType;
|
||||
}
|
||||
|
||||
export type CurveFn = {
|
||||
CURVE: ReturnType<typeof validateOpts>;
|
||||
getPublicKey: (privateKey: Hex) => Uint8Array;
|
||||
sign: (message: Hex, privateKey: Hex) => Uint8Array;
|
||||
verify: (sig: Hex, message: Hex, publicKey: Hex) => boolean;
|
||||
ExtendedPoint: ExtPointConstructor;
|
||||
utils: {
|
||||
randomPrivateKey: () => Uint8Array;
|
||||
getExtendedPublicKey: (key: Hex) => {
|
||||
head: Uint8Array;
|
||||
prefix: Uint8Array;
|
||||
scalar: bigint;
|
||||
point: ExtPointType;
|
||||
pointBytes: Uint8Array;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
// It is not generic twisted curve for now, but ed25519/ed448 generic implementation
|
||||
export function twistedEdwards(curveDef: CurveType): CurveFn {
|
||||
const CURVE = validateOpts(curveDef) as ReturnType<typeof validateOpts>;
|
||||
const { Fp, n: CURVE_ORDER, preHash, hash: cHash, randomBytes, nByteLength, h: cofactor } = CURVE;
|
||||
const MASK = _2n ** BigInt(nByteLength * 8);
|
||||
const modP = Fp.create; // Function overrides
|
||||
|
||||
// sqrt(u/v)
|
||||
const uvRatio =
|
||||
CURVE.uvRatio ||
|
||||
((u: bigint, v: bigint) => {
|
||||
try {
|
||||
return { isValid: true, value: Fp.sqrt(u * Fp.inv(v)) };
|
||||
} catch (e) {
|
||||
return { isValid: false, value: _0n };
|
||||
}
|
||||
});
|
||||
const adjustScalarBytes = CURVE.adjustScalarBytes || ((bytes: Uint8Array) => bytes); // NOOP
|
||||
const domain =
|
||||
CURVE.domain ||
|
||||
((data: Uint8Array, ctx: Uint8Array, phflag: boolean) => {
|
||||
if (ctx.length || phflag) throw new Error('Contexts/pre-hash are not supported');
|
||||
return data;
|
||||
}); // NOOP
|
||||
const inBig = (n: bigint) => typeof n === 'bigint' && 0n < n; // n in [1..]
|
||||
const inRange = (n: bigint, max: bigint) => inBig(n) && inBig(max) && n < max; // n in [1..max-1]
|
||||
const in0MaskRange = (n: bigint) => n === _0n || inRange(n, MASK); // n in [0..MASK-1]
|
||||
function assertInRange(n: bigint, max: bigint) {
|
||||
// n in [1..max-1]
|
||||
if (inRange(n, max)) return n;
|
||||
throw new Error(`Expected valid scalar < ${max}, got ${typeof n} ${n}`);
|
||||
}
|
||||
function assertGE0(n: bigint) {
|
||||
// n in [0..CURVE_ORDER-1]
|
||||
return n === _0n ? n : assertInRange(n, CURVE_ORDER); // GE = prime subgroup, not full group
|
||||
}
|
||||
const pointPrecomputes = new Map<Point, Point[]>();
|
||||
function isPoint(other: unknown) {
|
||||
if (!(other instanceof Point)) throw new Error('ExtendedPoint expected');
|
||||
}
|
||||
// Extended Point works in extended coordinates: (x, y, z, t) ∋ (x=x/z, y=y/z, t=xy).
|
||||
// https://en.wikipedia.org/wiki/Twisted_Edwards_curve#Extended_coordinates
|
||||
class Point implements ExtPointType {
|
||||
static readonly BASE = new Point(CURVE.Gx, CURVE.Gy, _1n, modP(CURVE.Gx * CURVE.Gy));
|
||||
static readonly ZERO = new Point(_0n, _1n, _1n, _0n); // 0, 1, 1, 0
|
||||
|
||||
constructor(
|
||||
readonly ex: bigint,
|
||||
readonly ey: bigint,
|
||||
readonly ez: bigint,
|
||||
readonly et: bigint
|
||||
) {
|
||||
if (!in0MaskRange(ex)) throw new Error('x required');
|
||||
if (!in0MaskRange(ey)) throw new Error('y required');
|
||||
if (!in0MaskRange(ez)) throw new Error('z required');
|
||||
if (!in0MaskRange(et)) throw new Error('t required');
|
||||
}
|
||||
|
||||
get x(): bigint {
|
||||
return this.toAffine().x;
|
||||
}
|
||||
get y(): bigint {
|
||||
return this.toAffine().y;
|
||||
}
|
||||
|
||||
static fromAffine(p: AffinePoint<bigint>): Point {
|
||||
if (p instanceof Point) throw new Error('extended point not allowed');
|
||||
const { x, y } = p || {};
|
||||
if (!in0MaskRange(x) || !in0MaskRange(y)) throw new Error('invalid affine point');
|
||||
return new Point(x, y, _1n, modP(x * y));
|
||||
}
|
||||
static normalizeZ(points: Point[]): Point[] {
|
||||
const toInv = Fp.invertBatch(points.map((p) => p.ez));
|
||||
return points.map((p, i) => p.toAffine(toInv[i])).map(Point.fromAffine);
|
||||
}
|
||||
|
||||
// We calculate precomputes for elliptic curve point multiplication
|
||||
// using windowed method. This specifies window size and
|
||||
// stores precomputed values. Usually only base point would be precomputed.
|
||||
_WINDOW_SIZE?: number;
|
||||
|
||||
// "Private method", don't use it directly
|
||||
_setWindowSize(windowSize: number) {
|
||||
this._WINDOW_SIZE = windowSize;
|
||||
pointPrecomputes.delete(this);
|
||||
}
|
||||
// Not required for fromHex(), which always creates valid points.
|
||||
// Could be useful for fromAffine().
|
||||
assertValidity(): void {
|
||||
const { a, d } = CURVE;
|
||||
if (this.is0()) throw new Error('bad point: ZERO'); // TODO: optimize, with vars below?
|
||||
// Equation in affine coordinates: ax² + y² = 1 + dx²y²
|
||||
// Equation in projective coordinates (X/Z, Y/Z, Z): (aX² + Y²)Z² = Z⁴ + dX²Y²
|
||||
const { ex: X, ey: Y, ez: Z, et: T } = this;
|
||||
const X2 = modP(X * X); // X²
|
||||
const Y2 = modP(Y * Y); // Y²
|
||||
const Z2 = modP(Z * Z); // Z²
|
||||
const Z4 = modP(Z2 * Z2); // Z⁴
|
||||
const aX2 = modP(X2 * a); // aX²
|
||||
const left = modP(Z2 * modP(aX2 + Y2)); // (aX² + Y²)Z²
|
||||
const right = modP(Z4 + modP(d * modP(X2 * Y2))); // Z⁴ + dX²Y²
|
||||
if (left !== right) throw new Error('bad point: equation left != right (1)');
|
||||
// In Extended coordinates we also have T, which is x*y=T/Z: check X*Y == Z*T
|
||||
const XY = modP(X * Y);
|
||||
const ZT = modP(Z * T);
|
||||
if (XY !== ZT) throw new Error('bad point: equation left != right (2)');
|
||||
}
|
||||
|
||||
// Compare one point to another.
|
||||
equals(other: Point): boolean {
|
||||
isPoint(other);
|
||||
const { ex: X1, ey: Y1, ez: Z1 } = this;
|
||||
const { ex: X2, ey: Y2, ez: Z2 } = other;
|
||||
const X1Z2 = modP(X1 * Z2);
|
||||
const X2Z1 = modP(X2 * Z1);
|
||||
const Y1Z2 = modP(Y1 * Z2);
|
||||
const Y2Z1 = modP(Y2 * Z1);
|
||||
return X1Z2 === X2Z1 && Y1Z2 === Y2Z1;
|
||||
}
|
||||
|
||||
protected is0(): boolean {
|
||||
return this.equals(Point.ZERO);
|
||||
}
|
||||
|
||||
negate(): Point {
|
||||
// Flips point sign to a negative one (-x, y in affine coords)
|
||||
return new Point(modP(-this.ex), this.ey, this.ez, modP(-this.et));
|
||||
}
|
||||
|
||||
// Fast algo for doubling Extended Point.
|
||||
// https://hyperelliptic.org/EFD/g1p/auto-twisted-extended.html#doubling-dbl-2008-hwcd
|
||||
// Cost: 4M + 4S + 1*a + 6add + 1*2.
|
||||
double(): Point {
|
||||
const { a } = CURVE;
|
||||
const { ex: X1, ey: Y1, ez: Z1 } = this;
|
||||
const A = modP(X1 * X1); // A = X12
|
||||
const B = modP(Y1 * Y1); // B = Y12
|
||||
const C = modP(_2n * modP(Z1 * Z1)); // C = 2*Z12
|
||||
const D = modP(a * A); // D = a*A
|
||||
const x1y1 = X1 + Y1;
|
||||
const E = modP(modP(x1y1 * x1y1) - A - B); // E = (X1+Y1)2-A-B
|
||||
const G = D + B; // G = D+B
|
||||
const F = G - C; // F = G-C
|
||||
const H = D - B; // H = D-B
|
||||
const X3 = modP(E * F); // X3 = E*F
|
||||
const Y3 = modP(G * H); // Y3 = G*H
|
||||
const T3 = modP(E * H); // T3 = E*H
|
||||
const Z3 = modP(F * G); // Z3 = F*G
|
||||
return new Point(X3, Y3, Z3, T3);
|
||||
}
|
||||
|
||||
// Fast algo for adding 2 Extended Points.
|
||||
// https://hyperelliptic.org/EFD/g1p/auto-twisted-extended.html#addition-add-2008-hwcd
|
||||
// Cost: 9M + 1*a + 1*d + 7add.
|
||||
add(other: Point) {
|
||||
isPoint(other);
|
||||
const { a, d } = CURVE;
|
||||
const { ex: X1, ey: Y1, ez: Z1, et: T1 } = this;
|
||||
const { ex: X2, ey: Y2, ez: Z2, et: T2 } = other;
|
||||
// Faster algo for adding 2 Extended Points when curve's a=-1.
|
||||
// http://hyperelliptic.org/EFD/g1p/auto-twisted-extended-1.html#addition-add-2008-hwcd-4
|
||||
// Cost: 8M + 8add + 2*2.
|
||||
// Note: It does not check whether the `other` point is valid.
|
||||
if (a === BigInt(-1)) {
|
||||
const A = modP((Y1 - X1) * (Y2 + X2));
|
||||
const B = modP((Y1 + X1) * (Y2 - X2));
|
||||
const F = modP(B - A);
|
||||
if (F === _0n) return this.double(); // Same point. Tests say it doesn't affect timing
|
||||
const C = modP(Z1 * _2n * T2);
|
||||
const D = modP(T1 * _2n * Z2);
|
||||
const E = D + C;
|
||||
const G = B + A;
|
||||
const H = D - C;
|
||||
const X3 = modP(E * F);
|
||||
const Y3 = modP(G * H);
|
||||
const T3 = modP(E * H);
|
||||
const Z3 = modP(F * G);
|
||||
return new Point(X3, Y3, Z3, T3);
|
||||
}
|
||||
const A = modP(X1 * X2); // A = X1*X2
|
||||
const B = modP(Y1 * Y2); // B = Y1*Y2
|
||||
const C = modP(T1 * d * T2); // C = T1*d*T2
|
||||
const D = modP(Z1 * Z2); // D = Z1*Z2
|
||||
const E = modP((X1 + Y1) * (X2 + Y2) - A - B); // E = (X1+Y1)*(X2+Y2)-A-B
|
||||
const F = D - C; // F = D-C
|
||||
const G = D + C; // G = D+C
|
||||
const H = modP(B - a * A); // H = B-a*A
|
||||
const X3 = modP(E * F); // X3 = E*F
|
||||
const Y3 = modP(G * H); // Y3 = G*H
|
||||
const T3 = modP(E * H); // T3 = E*H
|
||||
const Z3 = modP(F * G); // Z3 = F*G
|
||||
|
||||
return new Point(X3, Y3, Z3, T3);
|
||||
}
|
||||
|
||||
subtract(other: Point): Point {
|
||||
return this.add(other.negate());
|
||||
}
|
||||
|
||||
private wNAF(n: bigint): { p: Point; f: Point } {
|
||||
return wnaf.wNAFCached(this, pointPrecomputes, n, Point.normalizeZ);
|
||||
}
|
||||
|
||||
// Constant-time multiplication.
|
||||
multiply(scalar: bigint): Point {
|
||||
const { p, f } = this.wNAF(assertInRange(scalar, CURVE_ORDER));
|
||||
return Point.normalizeZ([p, f])[0];
|
||||
}
|
||||
|
||||
// Non-constant-time multiplication. Uses double-and-add algorithm.
|
||||
// It's faster, but should only be used when you don't care about
|
||||
// an exposed private key e.g. sig verification.
|
||||
multiplyUnsafe(scalar: bigint): Point {
|
||||
let n = assertGE0(scalar);
|
||||
if (n === _0n) return I;
|
||||
if (this.equals(I) || n === _1n) return this;
|
||||
if (this.equals(G)) return this.wNAF(n).p;
|
||||
return wnaf.unsafeLadder(this, n);
|
||||
}
|
||||
|
||||
// Checks if point is of small order.
|
||||
// If you add something to small order point, you will have "dirty"
|
||||
// point with torsion component.
|
||||
// Multiplies point by cofactor and checks if the result is 0.
|
||||
isSmallOrder(): boolean {
|
||||
return this.multiplyUnsafe(cofactor).is0();
|
||||
}
|
||||
|
||||
// Multiplies point by curve order and checks if the result is 0.
|
||||
// Returns `false` is the point is dirty.
|
||||
isTorsionFree(): boolean {
|
||||
return wnaf.unsafeLadder(this, CURVE_ORDER).is0();
|
||||
}
|
||||
|
||||
// Converts Extended point to default (x, y) coordinates.
|
||||
// Can accept precomputed Z^-1 - for example, from invertBatch.
|
||||
toAffine(iz?: bigint): AffinePoint<bigint> {
|
||||
const { ex: x, ey: y, ez: z } = this;
|
||||
const is0 = this.is0();
|
||||
if (iz == null) iz = is0 ? _8n : (Fp.inv(z) as bigint); // 8 was chosen arbitrarily
|
||||
const ax = modP(x * iz);
|
||||
const ay = modP(y * iz);
|
||||
const zz = modP(z * iz);
|
||||
if (is0) return { x: _0n, y: _1n };
|
||||
if (zz !== _1n) throw new Error('invZ was invalid');
|
||||
return { x: ax, y: ay };
|
||||
}
|
||||
|
||||
clearCofactor(): Point {
|
||||
const { h: cofactor } = CURVE;
|
||||
if (cofactor === _1n) return this;
|
||||
return this.multiplyUnsafe(cofactor);
|
||||
}
|
||||
|
||||
// Converts hash string or Uint8Array to Point.
|
||||
// Uses algo from RFC8032 5.1.3.
|
||||
static fromHex(hex: Hex, strict = true): Point {
|
||||
const { d, a } = CURVE;
|
||||
const len = Fp.BYTES;
|
||||
hex = ensureBytes(hex, len); // copy hex to a new array
|
||||
const normed = hex.slice(); // copy again, we'll manipulate it
|
||||
const lastByte = hex[len - 1]; // select last byte
|
||||
normed[len - 1] = lastByte & ~0x80; // clear last bit
|
||||
const y = ut.bytesToNumberLE(normed);
|
||||
if (y === _0n) {
|
||||
// y=0 is allowed
|
||||
} else {
|
||||
// RFC8032 prohibits >= p, but ZIP215 doesn't
|
||||
if (strict) assertInRange(y, Fp.ORDER); // strict=true [1..P-1] (2^255-19-1 for ed25519)
|
||||
else assertInRange(y, MASK); // strict=false [1..MASK-1] (2^256-1 for ed25519)
|
||||
}
|
||||
|
||||
// Ed25519: x² = (y²-1)/(dy²+1) mod p. Ed448: x² = (y²-1)/(dy²-1) mod p. Generic case:
|
||||
// ax²+y²=1+dx²y² => y²-1=dx²y²-ax² => y²-1=x²(dy²-a) => x²=(y²-1)/(dy²-a)
|
||||
const y2 = modP(y * y); // denominator is always non-0 mod p.
|
||||
const u = modP(y2 - _1n); // u = y² - 1
|
||||
const v = modP(d * y2 - a); // v = d y² + 1.
|
||||
let { isValid, value: x } = uvRatio(u, v); // √(u/v)
|
||||
if (!isValid) throw new Error('Point.fromHex: invalid y coordinate');
|
||||
const isXOdd = (x & _1n) === _1n; // There are 2 square roots. Use x_0 bit to select proper
|
||||
const isLastByteOdd = (lastByte & 0x80) !== 0; // if x=0 and x_0 = 1, fail
|
||||
if (isLastByteOdd !== isXOdd) x = modP(-x); // if x_0 != x mod 2, set x = p-x
|
||||
return Point.fromAffine({ x, y });
|
||||
}
|
||||
static fromPrivateKey(privKey: Hex) {
|
||||
return getExtendedPublicKey(privKey).point;
|
||||
}
|
||||
toRawBytes(): Uint8Array {
|
||||
const { x, y } = this.toAffine();
|
||||
const bytes = ut.numberToBytesLE(y, Fp.BYTES); // each y has 2 x values (x, -y)
|
||||
bytes[bytes.length - 1] |= x & _1n ? 0x80 : 0; // when compressing, it's enough to store y
|
||||
return bytes; // and use the last byte to encode sign of x
|
||||
}
|
||||
toHex(): string {
|
||||
return ut.bytesToHex(this.toRawBytes()); // Same as toRawBytes, but returns string.
|
||||
}
|
||||
}
|
||||
const { BASE: G, ZERO: I } = Point;
|
||||
const wnaf = wNAF(Point, nByteLength * 8);
|
||||
|
||||
function modN(a: bigint) {
|
||||
return mod(a, CURVE_ORDER);
|
||||
}
|
||||
// Little-endian SHA512 with modulo n
|
||||
function modN_LE(hash: Uint8Array): bigint {
|
||||
return modN(ut.bytesToNumberLE(hash));
|
||||
}
|
||||
function isHex(item: Hex, err: string) {
|
||||
if (typeof item !== 'string' && !(item instanceof Uint8Array))
|
||||
throw new Error(`${err} must be hex string or Uint8Array`);
|
||||
}
|
||||
|
||||
/** Convenience method that creates public key and other stuff. RFC8032 5.1.5 */
|
||||
function getExtendedPublicKey(key: Hex) {
|
||||
isHex(key, 'private key');
|
||||
const len = nByteLength;
|
||||
// Hash private key with curve's hash function to produce uniformingly random input
|
||||
// Check byte lengths: ensure(64, h(ensure(32, key)))
|
||||
const hashed = ensureBytes(cHash(ensureBytes(key, len)), 2 * len);
|
||||
const head = adjustScalarBytes(hashed.slice(0, len)); // clear first half bits, produce FE
|
||||
const prefix = hashed.slice(len, 2 * len); // second half is called key prefix (5.1.6)
|
||||
const scalar = modN_LE(head); // The actual private scalar
|
||||
const point = G.multiply(scalar); // Point on Edwards curve aka public key
|
||||
const pointBytes = point.toRawBytes(); // Uint8Array representation
|
||||
return { head, prefix, scalar, point, pointBytes };
|
||||
}
|
||||
|
||||
// Calculates EdDSA pub key. RFC8032 5.1.5. Privkey is hashed. Use first half with 3 bits cleared
|
||||
function getPublicKey(privKey: Hex): Uint8Array {
|
||||
return getExtendedPublicKey(privKey).pointBytes;
|
||||
}
|
||||
|
||||
// int('LE', SHA512(dom2(F, C) || msgs)) mod N
|
||||
function hashDomainToScalar(context: Hex = new Uint8Array(), ...msgs: Uint8Array[]) {
|
||||
const msg = ut.concatBytes(...msgs);
|
||||
return modN_LE(cHash(domain(msg, ensureBytes(context), !!preHash)));
|
||||
}
|
||||
|
||||
/** Signs message with privateKey. RFC8032 5.1.6 */
|
||||
function sign(msg: Hex, privKey: Hex, context?: Hex): Uint8Array {
|
||||
isHex(msg, 'message');
|
||||
msg = ensureBytes(msg);
|
||||
if (preHash) msg = preHash(msg); // for ed25519ph etc.
|
||||
const { prefix, scalar, pointBytes } = getExtendedPublicKey(privKey);
|
||||
const r = hashDomainToScalar(context, prefix, msg); // r = dom2(F, C) || prefix || PH(M)
|
||||
const R = G.multiply(r).toRawBytes(); // R = rG
|
||||
const k = hashDomainToScalar(context, R, pointBytes, msg); // R || A || PH(M)
|
||||
const s = modN(r + k * scalar); // S = (r + k * s) mod L
|
||||
assertGE0(s); // 0 <= s < l
|
||||
const res = ut.concatBytes(R, ut.numberToBytesLE(s, Fp.BYTES));
|
||||
return ensureBytes(res, nByteLength * 2); // 64-byte signature
|
||||
}
|
||||
|
||||
function verify(sig: Hex, msg: Hex, publicKey: Hex, context?: Hex): boolean {
|
||||
isHex(sig, 'sig');
|
||||
isHex(msg, 'message');
|
||||
const len = Fp.BYTES; // Verifies EdDSA signature against message and public key. RFC8032 5.1.7.
|
||||
sig = ensureBytes(sig, 2 * len); // An extended group equation is checked.
|
||||
msg = ensureBytes(msg); // ZIP215 compliant, which means not fully RFC8032 compliant.
|
||||
if (preHash) msg = preHash(msg); // for ed25519ph, etc
|
||||
const A = Point.fromHex(publicKey, false); // Check for s bounds, hex validity
|
||||
const R = Point.fromHex(sig.slice(0, len), false); // 0 <= R < 2^256: ZIP215 R can be >= P
|
||||
const s = ut.bytesToNumberLE(sig.slice(len, 2 * len)); // 0 <= s < l
|
||||
const SB = G.multiplyUnsafe(s);
|
||||
const k = hashDomainToScalar(context, R.toRawBytes(), A.toRawBytes(), msg);
|
||||
const RkA = R.add(A.multiplyUnsafe(k));
|
||||
// [8][S]B = [8]R + [8][k]A'
|
||||
return RkA.subtract(SB).clearCofactor().equals(Point.ZERO);
|
||||
}
|
||||
|
||||
G._setWindowSize(8); // Enable precomputes. Slows down first publicKey computation by 20ms.
|
||||
|
||||
const utils = {
|
||||
getExtendedPublicKey,
|
||||
// ed25519 private keys are uniform 32b. No need to check for modulo bias, like in secp256k1.
|
||||
randomPrivateKey: (): Uint8Array => randomBytes(Fp.BYTES),
|
||||
|
||||
/**
|
||||
* We're doing scalar multiplication (used in getPublicKey etc) with precomputed BASE_POINT
|
||||
* values. This slows down first getPublicKey() by milliseconds (see Speed section),
|
||||
* but allows to speed-up subsequent getPublicKey() calls up to 20x.
|
||||
* @param windowSize 2, 4, 8, 16
|
||||
*/
|
||||
precompute(windowSize = 8, point = Point.BASE): typeof Point.BASE {
|
||||
point._setWindowSize(windowSize);
|
||||
point.multiply(BigInt(3));
|
||||
return point;
|
||||
},
|
||||
};
|
||||
|
||||
return {
|
||||
CURVE,
|
||||
getPublicKey,
|
||||
sign,
|
||||
verify,
|
||||
ExtendedPoint: Point,
|
||||
utils,
|
||||
};
|
||||
}
|
||||
236
src/abstract/hash-to-curve.ts
Normal file
236
src/abstract/hash-to-curve.ts
Normal file
@@ -0,0 +1,236 @@
|
||||
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
||||
import type { Group, GroupConstructor, AffinePoint } from './curve.js';
|
||||
import { mod, Field } from './modular.js';
|
||||
import { CHash, Hex, concatBytes, ensureBytes } from './utils.js';
|
||||
|
||||
export type Opts = {
|
||||
// DST: a domain separation tag
|
||||
// defined in section 2.2.5
|
||||
DST: string;
|
||||
encodeDST: string;
|
||||
// p: the characteristic of F
|
||||
// where F is a finite field of characteristic p and order q = p^m
|
||||
p: bigint;
|
||||
// m: the extension degree of F, m >= 1
|
||||
// where F is a finite field of characteristic p and order q = p^m
|
||||
m: number;
|
||||
// k: the target security level for the suite in bits
|
||||
// defined in section 5.1
|
||||
k: number;
|
||||
// option to use a message that has already been processed by
|
||||
// expand_message_xmd
|
||||
expand?: 'xmd' | 'xof';
|
||||
// Hash functions for: expand_message_xmd is appropriate for use with a
|
||||
// wide range of hash functions, including SHA-2, SHA-3, BLAKE2, and others.
|
||||
// BBS+ uses blake2: https://github.com/hyperledger/aries-framework-go/issues/2247
|
||||
// TODO: verify that hash is shake if expand==='xof' via types
|
||||
hash: CHash;
|
||||
};
|
||||
|
||||
export function validateOpts(opts: Opts) {
|
||||
if (typeof opts.DST !== 'string') throw new Error('Invalid htf/DST');
|
||||
if (typeof opts.p !== 'bigint') throw new Error('Invalid htf/p');
|
||||
if (typeof opts.m !== 'number') throw new Error('Invalid htf/m');
|
||||
if (typeof opts.k !== 'number') throw new Error('Invalid htf/k');
|
||||
if (opts.expand !== 'xmd' && opts.expand !== 'xof' && opts.expand !== undefined)
|
||||
throw new Error('Invalid htf/expand');
|
||||
if (typeof opts.hash !== 'function' || !Number.isSafeInteger(opts.hash.outputLen))
|
||||
throw new Error('Invalid htf/hash function');
|
||||
}
|
||||
|
||||
// Global symbols in both browsers and Node.js since v11
|
||||
// See https://github.com/microsoft/TypeScript/issues/31535
|
||||
declare const TextEncoder: any;
|
||||
declare const TextDecoder: any;
|
||||
|
||||
export function stringToBytes(str: string): Uint8Array {
|
||||
if (typeof str !== 'string') {
|
||||
throw new Error(`utf8ToBytes expected string, got ${typeof str}`);
|
||||
}
|
||||
return new TextEncoder().encode(str);
|
||||
}
|
||||
|
||||
// Octet Stream to Integer (bytesToNumberBE)
|
||||
function os2ip(bytes: Uint8Array): bigint {
|
||||
let result = 0n;
|
||||
for (let i = 0; i < bytes.length; i++) {
|
||||
result <<= 8n;
|
||||
result += BigInt(bytes[i]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// Integer to Octet Stream
|
||||
function i2osp(value: number, length: number): Uint8Array {
|
||||
if (value < 0 || value >= 1 << (8 * length)) {
|
||||
throw new Error(`bad I2OSP call: value=${value} length=${length}`);
|
||||
}
|
||||
const res = Array.from({ length }).fill(0) as number[];
|
||||
for (let i = length - 1; i >= 0; i--) {
|
||||
res[i] = value & 0xff;
|
||||
value >>>= 8;
|
||||
}
|
||||
return new Uint8Array(res);
|
||||
}
|
||||
|
||||
function strxor(a: Uint8Array, b: Uint8Array): Uint8Array {
|
||||
const arr = new Uint8Array(a.length);
|
||||
for (let i = 0; i < a.length; i++) {
|
||||
arr[i] = a[i] ^ b[i];
|
||||
}
|
||||
return arr;
|
||||
}
|
||||
|
||||
// Produces a uniformly random byte string using a cryptographic hash function H that outputs b bits
|
||||
// https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-11#section-5.4.1
|
||||
export function expand_message_xmd(
|
||||
msg: Uint8Array,
|
||||
DST: Uint8Array,
|
||||
lenInBytes: number,
|
||||
H: CHash
|
||||
): Uint8Array {
|
||||
// https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-16#section-5.3.3
|
||||
if (DST.length > 255) DST = H(concatBytes(stringToBytes('H2C-OVERSIZE-DST-'), DST));
|
||||
const b_in_bytes = H.outputLen;
|
||||
const r_in_bytes = H.blockLen;
|
||||
const ell = Math.ceil(lenInBytes / b_in_bytes);
|
||||
if (ell > 255) throw new Error('Invalid xmd length');
|
||||
const DST_prime = concatBytes(DST, i2osp(DST.length, 1));
|
||||
const Z_pad = i2osp(0, r_in_bytes);
|
||||
const l_i_b_str = i2osp(lenInBytes, 2);
|
||||
const b = new Array<Uint8Array>(ell);
|
||||
const b_0 = H(concatBytes(Z_pad, msg, l_i_b_str, i2osp(0, 1), DST_prime));
|
||||
b[0] = H(concatBytes(b_0, i2osp(1, 1), DST_prime));
|
||||
for (let i = 1; i <= ell; i++) {
|
||||
const args = [strxor(b_0, b[i - 1]), i2osp(i + 1, 1), DST_prime];
|
||||
b[i] = H(concatBytes(...args));
|
||||
}
|
||||
const pseudo_random_bytes = concatBytes(...b);
|
||||
return pseudo_random_bytes.slice(0, lenInBytes);
|
||||
}
|
||||
|
||||
export function expand_message_xof(
|
||||
msg: Uint8Array,
|
||||
DST: Uint8Array,
|
||||
lenInBytes: number,
|
||||
k: number,
|
||||
H: CHash
|
||||
): Uint8Array {
|
||||
// https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-16#section-5.3.3
|
||||
// DST = H('H2C-OVERSIZE-DST-' || a_very_long_DST, Math.ceil((lenInBytes * k) / 8));
|
||||
if (DST.length > 255) {
|
||||
const dkLen = Math.ceil((2 * k) / 8);
|
||||
DST = H.create({ dkLen }).update(stringToBytes('H2C-OVERSIZE-DST-')).update(DST).digest();
|
||||
}
|
||||
if (lenInBytes > 65535 || DST.length > 255)
|
||||
throw new Error('expand_message_xof: invalid lenInBytes');
|
||||
return (
|
||||
H.create({ dkLen: lenInBytes })
|
||||
.update(msg)
|
||||
.update(i2osp(lenInBytes, 2))
|
||||
// 2. DST_prime = DST || I2OSP(len(DST), 1)
|
||||
.update(DST)
|
||||
.update(i2osp(DST.length, 1))
|
||||
.digest()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Hashes arbitrary-length byte strings to a list of one or more elements of a finite field F
|
||||
* https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-11#section-5.3
|
||||
* @param msg a byte string containing the message to hash
|
||||
* @param count the number of elements of F to output
|
||||
* @param options `{DST: string, p: bigint, m: number, k: number, expand: 'xmd' | 'xof', hash: H}`
|
||||
* @returns [u_0, ..., u_(count - 1)], a list of field elements.
|
||||
*/
|
||||
export function hash_to_field(msg: Uint8Array, count: number, options: Opts): bigint[][] {
|
||||
// if options is provided but incomplete, fill any missing fields with the
|
||||
// value in hftDefaults (ie hash to G2).
|
||||
const log2p = options.p.toString(2).length;
|
||||
const L = Math.ceil((log2p + options.k) / 8); // section 5.1 of ietf draft link above
|
||||
const len_in_bytes = count * options.m * L;
|
||||
const DST = stringToBytes(options.DST);
|
||||
let pseudo_random_bytes = msg;
|
||||
if (options.expand === 'xmd') {
|
||||
pseudo_random_bytes = expand_message_xmd(msg, DST, len_in_bytes, options.hash);
|
||||
} else if (options.expand === 'xof') {
|
||||
pseudo_random_bytes = expand_message_xof(msg, DST, len_in_bytes, options.k, options.hash);
|
||||
}
|
||||
const u = new Array(count);
|
||||
for (let i = 0; i < count; i++) {
|
||||
const e = new Array(options.m);
|
||||
for (let j = 0; j < options.m; j++) {
|
||||
const elm_offset = L * (j + i * options.m);
|
||||
const tv = pseudo_random_bytes.subarray(elm_offset, elm_offset + L);
|
||||
e[j] = mod(os2ip(tv), options.p);
|
||||
}
|
||||
u[i] = e;
|
||||
}
|
||||
return u;
|
||||
}
|
||||
|
||||
export function isogenyMap<T, F extends Field<T>>(field: F, map: [T[], T[], T[], T[]]) {
|
||||
// Make same order as in spec
|
||||
const COEFF = map.map((i) => Array.from(i).reverse());
|
||||
return (x: T, y: T) => {
|
||||
const [xNum, xDen, yNum, yDen] = COEFF.map((val) =>
|
||||
val.reduce((acc, i) => field.add(field.mul(acc, x), i))
|
||||
);
|
||||
x = field.div(xNum, xDen); // xNum / xDen
|
||||
y = field.mul(y, field.div(yNum, yDen)); // y * (yNum / yDev)
|
||||
return { x, y };
|
||||
};
|
||||
}
|
||||
|
||||
export interface H2CPoint<T> extends Group<H2CPoint<T>> {
|
||||
add(rhs: H2CPoint<T>): H2CPoint<T>;
|
||||
toAffine(iz?: bigint): AffinePoint<T>;
|
||||
clearCofactor(): H2CPoint<T>;
|
||||
assertValidity(): void;
|
||||
}
|
||||
|
||||
export interface H2CPointConstructor<T> extends GroupConstructor<H2CPoint<T>> {
|
||||
fromAffine(ap: AffinePoint<T>): H2CPoint<T>;
|
||||
}
|
||||
|
||||
export type MapToCurve<T> = (scalar: bigint[]) => AffinePoint<T>;
|
||||
|
||||
// Separated from initialization opts, so users won't accidentally change per-curve parameters (changing DST is ok!)
|
||||
export type htfBasicOpts = {
|
||||
DST: string;
|
||||
};
|
||||
|
||||
export function hashToCurve<T>(
|
||||
Point: H2CPointConstructor<T>,
|
||||
mapToCurve: MapToCurve<T>,
|
||||
def: Opts
|
||||
) {
|
||||
validateOpts(def);
|
||||
if (typeof mapToCurve !== 'function')
|
||||
throw new Error('hashToCurve: mapToCurve() has not been defined');
|
||||
|
||||
return {
|
||||
// Encodes byte string to elliptic curve
|
||||
// https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-11#section-3
|
||||
hashToCurve(msg: Hex, options?: htfBasicOpts) {
|
||||
if (!mapToCurve) throw new Error('CURVE.mapToCurve() has not been defined');
|
||||
msg = ensureBytes(msg);
|
||||
const u = hash_to_field(msg, 2, { ...def, DST: def.DST, ...options } as Opts);
|
||||
const P = Point.fromAffine(mapToCurve(u[0]))
|
||||
.add(Point.fromAffine(mapToCurve(u[1])))
|
||||
.clearCofactor();
|
||||
P.assertValidity();
|
||||
return P;
|
||||
},
|
||||
|
||||
// https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-16#section-3
|
||||
encodeToCurve(msg: Hex, options?: htfBasicOpts) {
|
||||
if (!mapToCurve) throw new Error('CURVE.mapToCurve() has not been defined');
|
||||
msg = ensureBytes(msg);
|
||||
const u = hash_to_field(msg, 1, { ...def, DST: def.encodeDST, ...options } as Opts);
|
||||
const P = Point.fromAffine(mapToCurve(u[0])).clearCofactor();
|
||||
P.assertValidity();
|
||||
return P;
|
||||
},
|
||||
};
|
||||
}
|
||||
417
src/abstract/modular.ts
Normal file
417
src/abstract/modular.ts
Normal file
@@ -0,0 +1,417 @@
|
||||
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
||||
// Utilities for modular arithmetics and finite fields
|
||||
import {
|
||||
bitMask,
|
||||
numberToBytesBE,
|
||||
numberToBytesLE,
|
||||
bytesToNumberBE,
|
||||
bytesToNumberLE,
|
||||
ensureBytes,
|
||||
validateObject,
|
||||
} from './utils.js';
|
||||
// prettier-ignore
|
||||
const _0n = BigInt(0), _1n = BigInt(1), _2n = BigInt(2), _3n = BigInt(3);
|
||||
// prettier-ignore
|
||||
const _4n = BigInt(4), _5n = BigInt(5), _8n = BigInt(8);
|
||||
// prettier-ignore
|
||||
const _9n = BigInt(9), _16n = BigInt(16);
|
||||
|
||||
// Calculates a modulo b
|
||||
export function mod(a: bigint, b: bigint): bigint {
|
||||
const result = a % b;
|
||||
return result >= _0n ? result : b + result;
|
||||
}
|
||||
/**
|
||||
* Efficiently exponentiate num to power and do modular division.
|
||||
* Unsafe in some contexts: uses ladder, so can expose bigint bits.
|
||||
* @example
|
||||
* powMod(2n, 6n, 11n) // 64n % 11n == 9n
|
||||
*/
|
||||
// TODO: use field version && remove
|
||||
export function pow(num: bigint, power: bigint, modulo: bigint): bigint {
|
||||
if (modulo <= _0n || power < _0n) throw new Error('Expected power/modulo > 0');
|
||||
if (modulo === _1n) return _0n;
|
||||
let res = _1n;
|
||||
while (power > _0n) {
|
||||
if (power & _1n) res = (res * num) % modulo;
|
||||
num = (num * num) % modulo;
|
||||
power >>= _1n;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
// Does x ^ (2 ^ power) mod p. pow2(30, 4) == 30 ^ (2 ^ 4)
|
||||
export function pow2(x: bigint, power: bigint, modulo: bigint): bigint {
|
||||
let res = x;
|
||||
while (power-- > _0n) {
|
||||
res *= res;
|
||||
res %= modulo;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
// Inverses number over modulo
|
||||
export function invert(number: bigint, modulo: bigint): bigint {
|
||||
if (number === _0n || modulo <= _0n) {
|
||||
throw new Error(`invert: expected positive integers, got n=${number} mod=${modulo}`);
|
||||
}
|
||||
// Eucledian GCD https://brilliant.org/wiki/extended-euclidean-algorithm/
|
||||
let a = mod(number, modulo);
|
||||
let b = modulo;
|
||||
// prettier-ignore
|
||||
let x = _0n, y = _1n, u = _1n, v = _0n;
|
||||
while (a !== _0n) {
|
||||
// JIT applies optimization if those two lines follow each other
|
||||
const q = b / a;
|
||||
const r = b % a;
|
||||
const m = x - u * q;
|
||||
const n = y - v * q;
|
||||
// prettier-ignore
|
||||
b = a, a = r, x = u, y = v, u = m, v = n;
|
||||
}
|
||||
const gcd = b;
|
||||
if (gcd !== _1n) throw new Error('invert: does not exist');
|
||||
return mod(x, modulo);
|
||||
}
|
||||
|
||||
// Tonelli-Shanks algorithm
|
||||
// Paper 1: https://eprint.iacr.org/2012/685.pdf (page 12)
|
||||
// Paper 2: Square Roots from 1; 24, 51, 10 to Dan Shanks
|
||||
export function tonelliShanks(P: bigint) {
|
||||
// Legendre constant: used to calculate Legendre symbol (a | p),
|
||||
// which denotes the value of a^((p-1)/2) (mod p).
|
||||
// (a | p) ≡ 1 if a is a square (mod p)
|
||||
// (a | p) ≡ -1 if a is not a square (mod p)
|
||||
// (a | p) ≡ 0 if a ≡ 0 (mod p)
|
||||
const legendreC = (P - _1n) / _2n;
|
||||
|
||||
let Q: bigint, S: number, Z: bigint;
|
||||
// Step 1: By factoring out powers of 2 from p - 1,
|
||||
// find q and s such that p - 1 = q*(2^s) with q odd
|
||||
for (Q = P - _1n, S = 0; Q % _2n === _0n; Q /= _2n, S++);
|
||||
|
||||
// Step 2: Select a non-square z such that (z | p) ≡ -1 and set c ≡ zq
|
||||
for (Z = _2n; Z < P && pow(Z, legendreC, P) !== P - _1n; Z++);
|
||||
|
||||
// Fast-path
|
||||
if (S === 1) {
|
||||
const p1div4 = (P + _1n) / _4n;
|
||||
return function tonelliFast<T>(Fp: Field<T>, n: T) {
|
||||
const root = Fp.pow(n, p1div4);
|
||||
if (!Fp.eql(Fp.sqr(root), n)) throw new Error('Cannot find square root');
|
||||
return root;
|
||||
};
|
||||
}
|
||||
|
||||
// Slow-path
|
||||
const Q1div2 = (Q + _1n) / _2n;
|
||||
return function tonelliSlow<T>(Fp: Field<T>, n: T): T {
|
||||
// Step 0: Check that n is indeed a square: (n | p) should not be ≡ -1
|
||||
if (Fp.pow(n, legendreC) === Fp.neg(Fp.ONE)) throw new Error('Cannot find square root');
|
||||
let r = S;
|
||||
// TODO: will fail at Fp2/etc
|
||||
let g = Fp.pow(Fp.mul(Fp.ONE, Z), Q); // will update both x and b
|
||||
let x = Fp.pow(n, Q1div2); // first guess at the square root
|
||||
let b = Fp.pow(n, Q); // first guess at the fudge factor
|
||||
|
||||
while (!Fp.eql(b, Fp.ONE)) {
|
||||
if (Fp.eql(b, Fp.ZERO)) return Fp.ZERO; // https://en.wikipedia.org/wiki/Tonelli%E2%80%93Shanks_algorithm (4. If t = 0, return r = 0)
|
||||
// Find m such b^(2^m)==1
|
||||
let m = 1;
|
||||
for (let t2 = Fp.sqr(b); m < r; m++) {
|
||||
if (Fp.eql(t2, Fp.ONE)) break;
|
||||
t2 = Fp.sqr(t2); // t2 *= t2
|
||||
}
|
||||
// NOTE: r-m-1 can be bigger than 32, need to convert to bigint before shift, otherwise there will be overflow
|
||||
const ge = Fp.pow(g, _1n << BigInt(r - m - 1)); // ge = 2^(r-m-1)
|
||||
g = Fp.sqr(ge); // g = ge * ge
|
||||
x = Fp.mul(x, ge); // x *= ge
|
||||
b = Fp.mul(b, g); // b *= g
|
||||
r = m;
|
||||
}
|
||||
return x;
|
||||
};
|
||||
}
|
||||
|
||||
export function FpSqrt(P: bigint) {
|
||||
// NOTE: different algorithms can give different roots, it is up to user to decide which one they want.
|
||||
// For example there is FpSqrtOdd/FpSqrtEven to choice root based on oddness (used for hash-to-curve).
|
||||
|
||||
// P ≡ 3 (mod 4)
|
||||
// √n = n^((P+1)/4)
|
||||
if (P % _4n === _3n) {
|
||||
// Not all roots possible!
|
||||
// const ORDER =
|
||||
// 0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaabn;
|
||||
// const NUM = 72057594037927816n;
|
||||
const p1div4 = (P + _1n) / _4n;
|
||||
return function sqrt3mod4<T>(Fp: Field<T>, n: T) {
|
||||
const root = Fp.pow(n, p1div4);
|
||||
// Throw if root**2 != n
|
||||
if (!Fp.eql(Fp.sqr(root), n)) throw new Error('Cannot find square root');
|
||||
return root;
|
||||
};
|
||||
}
|
||||
|
||||
// Atkin algorithm for q ≡ 5 (mod 8), https://eprint.iacr.org/2012/685.pdf (page 10)
|
||||
if (P % _8n === _5n) {
|
||||
const c1 = (P - _5n) / _8n;
|
||||
return function sqrt5mod8<T>(Fp: Field<T>, n: T) {
|
||||
const n2 = Fp.mul(n, _2n);
|
||||
const v = Fp.pow(n2, c1);
|
||||
const nv = Fp.mul(n, v);
|
||||
const i = Fp.mul(Fp.mul(nv, _2n), v);
|
||||
const root = Fp.mul(nv, Fp.sub(i, Fp.ONE));
|
||||
if (!Fp.eql(Fp.sqr(root), n)) throw new Error('Cannot find square root');
|
||||
return root;
|
||||
};
|
||||
}
|
||||
|
||||
// P ≡ 9 (mod 16)
|
||||
if (P % _16n === _9n) {
|
||||
// NOTE: tonelli is too slow for bls-Fp2 calculations even on start
|
||||
// Means we cannot use sqrt for constants at all!
|
||||
//
|
||||
// const c1 = Fp.sqrt(Fp.negate(Fp.ONE)); // 1. c1 = sqrt(-1) in F, i.e., (c1^2) == -1 in F
|
||||
// const c2 = Fp.sqrt(c1); // 2. c2 = sqrt(c1) in F, i.e., (c2^2) == c1 in F
|
||||
// const c3 = Fp.sqrt(Fp.negate(c1)); // 3. c3 = sqrt(-c1) in F, i.e., (c3^2) == -c1 in F
|
||||
// const c4 = (P + _7n) / _16n; // 4. c4 = (q + 7) / 16 # Integer arithmetic
|
||||
// sqrt = (x) => {
|
||||
// let tv1 = Fp.pow(x, c4); // 1. tv1 = x^c4
|
||||
// let tv2 = Fp.mul(c1, tv1); // 2. tv2 = c1 * tv1
|
||||
// const tv3 = Fp.mul(c2, tv1); // 3. tv3 = c2 * tv1
|
||||
// let tv4 = Fp.mul(c3, tv1); // 4. tv4 = c3 * tv1
|
||||
// const e1 = Fp.equals(Fp.square(tv2), x); // 5. e1 = (tv2^2) == x
|
||||
// const e2 = Fp.equals(Fp.square(tv3), x); // 6. e2 = (tv3^2) == x
|
||||
// tv1 = Fp.cmov(tv1, tv2, e1); // 7. tv1 = CMOV(tv1, tv2, e1) # Select tv2 if (tv2^2) == x
|
||||
// tv2 = Fp.cmov(tv4, tv3, e2); // 8. tv2 = CMOV(tv4, tv3, e2) # Select tv3 if (tv3^2) == x
|
||||
// const e3 = Fp.equals(Fp.square(tv2), x); // 9. e3 = (tv2^2) == x
|
||||
// return Fp.cmov(tv1, tv2, e3); // 10. z = CMOV(tv1, tv2, e3) # Select the sqrt from tv1 and tv2
|
||||
// }
|
||||
}
|
||||
|
||||
// Other cases: Tonelli-Shanks algorithm
|
||||
return tonelliShanks(P);
|
||||
}
|
||||
|
||||
// Little-endian check for first LE bit (last BE bit);
|
||||
export const isNegativeLE = (num: bigint, modulo: bigint) => (mod(num, modulo) & _1n) === _1n;
|
||||
|
||||
// Currently completly inconsistent naming:
|
||||
// - readable: add, mul, sqr, sqrt, inv, div, pow, eq, sub
|
||||
// - unreadable mess: addition, multiply, square, squareRoot, inversion, divide, power, equals, subtract
|
||||
|
||||
// Field is not always over prime, Fp2 for example has ORDER(q)=p^m
|
||||
export interface Field<T> {
|
||||
ORDER: bigint;
|
||||
BYTES: number;
|
||||
BITS: number;
|
||||
MASK: bigint;
|
||||
ZERO: T;
|
||||
ONE: T;
|
||||
// 1-arg
|
||||
create: (num: T) => T;
|
||||
isValid: (num: T) => boolean;
|
||||
is0: (num: T) => boolean;
|
||||
neg(num: T): T;
|
||||
inv(num: T): T;
|
||||
sqrt(num: T): T;
|
||||
sqr(num: T): T;
|
||||
// 2-args
|
||||
eql(lhs: T, rhs: T): boolean;
|
||||
add(lhs: T, rhs: T): T;
|
||||
sub(lhs: T, rhs: T): T;
|
||||
mul(lhs: T, rhs: T | bigint): T;
|
||||
pow(lhs: T, power: bigint): T;
|
||||
div(lhs: T, rhs: T | bigint): T;
|
||||
// N for NonNormalized (for now)
|
||||
addN(lhs: T, rhs: T): T;
|
||||
subN(lhs: T, rhs: T): T;
|
||||
mulN(lhs: T, rhs: T | bigint): T;
|
||||
sqrN(num: T): T;
|
||||
|
||||
// Optional
|
||||
// Should be same as sgn0 function in https://datatracker.ietf.org/doc/draft-irtf-cfrg-hash-to-curve/
|
||||
// NOTE: sgn0 is 'negative in LE', which is same as odd. And negative in LE is kinda strange definition anyway.
|
||||
isOdd?(num: T): boolean; // Odd instead of even since we have it for Fp2
|
||||
// legendre?(num: T): T;
|
||||
pow(lhs: T, power: bigint): T;
|
||||
invertBatch: (lst: T[]) => T[];
|
||||
toBytes(num: T): Uint8Array;
|
||||
fromBytes(bytes: Uint8Array): T;
|
||||
// If c is False, CMOV returns a, otherwise it returns b.
|
||||
cmov(a: T, b: T, c: boolean): T;
|
||||
}
|
||||
// prettier-ignore
|
||||
const FIELD_FIELDS = [
|
||||
'create', 'isValid', 'is0', 'neg', 'inv', 'sqrt', 'sqr',
|
||||
'eql', 'add', 'sub', 'mul', 'pow', 'div',
|
||||
'addN', 'subN', 'mulN', 'sqrN'
|
||||
] as const;
|
||||
export function validateField<T>(field: Field<T>) {
|
||||
const initial = {
|
||||
ORDER: 'bigint',
|
||||
MASK: 'bigint',
|
||||
BYTES: 'isSafeInteger',
|
||||
BITS: 'isSafeInteger',
|
||||
} as Record<string, string>;
|
||||
const opts = FIELD_FIELDS.reduce((map, val: string) => {
|
||||
map[val] = 'function';
|
||||
return map;
|
||||
}, initial);
|
||||
return validateObject(field, opts);
|
||||
}
|
||||
|
||||
// Generic field functions
|
||||
export function FpPow<T>(f: Field<T>, num: T, power: bigint): T {
|
||||
// Should have same speed as pow for bigints
|
||||
// TODO: benchmark!
|
||||
if (power < _0n) throw new Error('Expected power > 0');
|
||||
if (power === _0n) return f.ONE;
|
||||
if (power === _1n) return num;
|
||||
let p = f.ONE;
|
||||
let d = num;
|
||||
while (power > _0n) {
|
||||
if (power & _1n) p = f.mul(p, d);
|
||||
d = f.sqr(d);
|
||||
power >>= 1n;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
export function FpInvertBatch<T>(f: Field<T>, nums: T[]): T[] {
|
||||
const tmp = new Array(nums.length);
|
||||
// Walk from first to last, multiply them by each other MOD p
|
||||
const lastMultiplied = nums.reduce((acc, num, i) => {
|
||||
if (f.is0(num)) return acc;
|
||||
tmp[i] = acc;
|
||||
return f.mul(acc, num);
|
||||
}, f.ONE);
|
||||
// Invert last element
|
||||
const inverted = f.inv(lastMultiplied);
|
||||
// Walk from last to first, multiply them by inverted each other MOD p
|
||||
nums.reduceRight((acc, num, i) => {
|
||||
if (f.is0(num)) return acc;
|
||||
tmp[i] = f.mul(acc, tmp[i]);
|
||||
return f.mul(acc, num);
|
||||
}, inverted);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
export function FpDiv<T>(f: Field<T>, lhs: T, rhs: T | bigint): T {
|
||||
return f.mul(lhs, typeof rhs === 'bigint' ? invert(rhs, f.ORDER) : f.inv(rhs));
|
||||
}
|
||||
|
||||
// This function returns True whenever the value x is a square in the field F.
|
||||
export function FpIsSquare<T>(f: Field<T>) {
|
||||
const legendreConst = (f.ORDER - _1n) / _2n; // Integer arithmetic
|
||||
return (x: T): boolean => {
|
||||
const p = f.pow(x, legendreConst);
|
||||
return f.eql(p, f.ZERO) || f.eql(p, f.ONE);
|
||||
};
|
||||
}
|
||||
|
||||
// CURVE.n lengths
|
||||
export function nLength(n: bigint, nBitLength?: number) {
|
||||
// Bit size, byte size of CURVE.n
|
||||
const _nBitLength = nBitLength !== undefined ? nBitLength : n.toString(2).length;
|
||||
const nByteLength = Math.ceil(_nBitLength / 8);
|
||||
return { nBitLength: _nBitLength, nByteLength };
|
||||
}
|
||||
|
||||
// NOTE: very fragile, always bench. Major performance points:
|
||||
// - NonNormalized ops
|
||||
// - Object.freeze
|
||||
// - same shape of object (don't add/remove keys)
|
||||
type FpField = Field<bigint> & Required<Pick<Field<bigint>, 'isOdd'>>;
|
||||
export function Fp(
|
||||
ORDER: bigint,
|
||||
bitLen?: number,
|
||||
isLE = false,
|
||||
redef: Partial<Field<bigint>> = {}
|
||||
): Readonly<FpField> {
|
||||
if (ORDER <= _0n) throw new Error(`Expected Fp ORDER > 0, got ${ORDER}`);
|
||||
const { nBitLength: BITS, nByteLength: BYTES } = nLength(ORDER, bitLen);
|
||||
if (BYTES > 2048) throw new Error('Field lengths over 2048 bytes are not supported');
|
||||
const sqrtP = FpSqrt(ORDER);
|
||||
const f: Readonly<FpField> = Object.freeze({
|
||||
ORDER,
|
||||
BITS,
|
||||
BYTES,
|
||||
MASK: bitMask(BITS),
|
||||
ZERO: _0n,
|
||||
ONE: _1n,
|
||||
create: (num) => mod(num, ORDER),
|
||||
isValid: (num) => {
|
||||
if (typeof num !== 'bigint')
|
||||
throw new Error(`Invalid field element: expected bigint, got ${typeof num}`);
|
||||
return _0n <= num && num < ORDER; // 0 is valid element, but it's not invertible
|
||||
},
|
||||
is0: (num) => num === _0n,
|
||||
isOdd: (num) => (num & _1n) === _1n,
|
||||
neg: (num) => mod(-num, ORDER),
|
||||
eql: (lhs, rhs) => lhs === rhs,
|
||||
|
||||
sqr: (num) => mod(num * num, ORDER),
|
||||
add: (lhs, rhs) => mod(lhs + rhs, ORDER),
|
||||
sub: (lhs, rhs) => mod(lhs - rhs, ORDER),
|
||||
mul: (lhs, rhs) => mod(lhs * rhs, ORDER),
|
||||
pow: (num, power) => FpPow(f, num, power),
|
||||
div: (lhs, rhs) => mod(lhs * invert(rhs, ORDER), ORDER),
|
||||
|
||||
// Same as above, but doesn't normalize
|
||||
sqrN: (num) => num * num,
|
||||
addN: (lhs, rhs) => lhs + rhs,
|
||||
subN: (lhs, rhs) => lhs - rhs,
|
||||
mulN: (lhs, rhs) => lhs * rhs,
|
||||
|
||||
inv: (num) => invert(num, ORDER),
|
||||
sqrt: redef.sqrt || ((n) => sqrtP(f, n)),
|
||||
invertBatch: (lst) => FpInvertBatch(f, lst),
|
||||
// TODO: do we really need constant cmov?
|
||||
// We don't have const-time bigints anyway, so probably will be not very useful
|
||||
cmov: (a, b, c) => (c ? b : a),
|
||||
toBytes: (num) => (isLE ? numberToBytesLE(num, BYTES) : numberToBytesBE(num, BYTES)),
|
||||
fromBytes: (bytes) => {
|
||||
if (bytes.length !== BYTES)
|
||||
throw new Error(`Fp.fromBytes: expected ${BYTES}, got ${bytes.length}`);
|
||||
return isLE ? bytesToNumberLE(bytes) : bytesToNumberBE(bytes);
|
||||
},
|
||||
} as FpField);
|
||||
return Object.freeze(f);
|
||||
}
|
||||
|
||||
export function FpSqrtOdd<T>(Fp: Field<T>, elm: T) {
|
||||
if (!Fp.isOdd) throw new Error(`Field doesn't have isOdd`);
|
||||
const root = Fp.sqrt(elm);
|
||||
return Fp.isOdd(root) ? root : Fp.neg(root);
|
||||
}
|
||||
|
||||
export function FpSqrtEven<T>(Fp: Field<T>, elm: T) {
|
||||
if (!Fp.isOdd) throw new Error(`Field doesn't have isOdd`);
|
||||
const root = Fp.sqrt(elm);
|
||||
return Fp.isOdd(root) ? Fp.neg(root) : root;
|
||||
}
|
||||
|
||||
/**
|
||||
* FIPS 186 B.4.1-compliant "constant-time" private key generation utility.
|
||||
* Can take (n+8) or more bytes of uniform input e.g. from CSPRNG or KDF
|
||||
* and convert them into private scalar, with the modulo bias being neglible.
|
||||
* Needs at least 40 bytes of input for 32-byte private key.
|
||||
* https://research.kudelskisecurity.com/2020/07/28/the-definitive-guide-to-modulo-bias-and-how-to-avoid-it/
|
||||
* @param hash hash output from SHA3 or a similar function
|
||||
* @returns valid private scalar
|
||||
*/
|
||||
export function hashToPrivateScalar(
|
||||
hash: string | Uint8Array,
|
||||
groupOrder: bigint,
|
||||
isLE = false
|
||||
): bigint {
|
||||
hash = ensureBytes(hash);
|
||||
const hashLen = hash.length;
|
||||
const minLen = nLength(groupOrder).nByteLength + 8;
|
||||
if (minLen < 24 || hashLen < minLen || hashLen > 1024)
|
||||
throw new Error(`hashToPrivateScalar: expected ${minLen}-1024 bytes of input, got ${hashLen}`);
|
||||
const num = isLE ? bytesToNumberLE(hash) : bytesToNumberBE(hash);
|
||||
return mod(num, groupOrder - _1n) + _1n;
|
||||
}
|
||||
184
src/abstract/montgomery.ts
Normal file
184
src/abstract/montgomery.ts
Normal file
@@ -0,0 +1,184 @@
|
||||
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
||||
import { mod, pow } from './modular.js';
|
||||
import { bytesToNumberLE, ensureBytes, numberToBytesLE, validateObject } from './utils.js';
|
||||
|
||||
const _0n = BigInt(0);
|
||||
const _1n = BigInt(1);
|
||||
type Hex = string | Uint8Array;
|
||||
|
||||
export type CurveType = {
|
||||
P: bigint; // finite field prime
|
||||
nByteLength: number;
|
||||
adjustScalarBytes?: (bytes: Uint8Array) => Uint8Array;
|
||||
domain?: (data: Uint8Array, ctx: Uint8Array, phflag: boolean) => Uint8Array;
|
||||
a24: bigint; // Related to d, but cannot be derived from it
|
||||
montgomeryBits: number;
|
||||
powPminus2?: (x: bigint) => bigint;
|
||||
xyToU?: (x: bigint, y: bigint) => bigint;
|
||||
Gu: string;
|
||||
};
|
||||
export type CurveFn = {
|
||||
scalarMult: (scalar: Hex, u: Hex) => Uint8Array;
|
||||
scalarMultBase: (scalar: Hex) => Uint8Array;
|
||||
getSharedSecret: (privateKeyA: Hex, publicKeyB: Hex) => Uint8Array;
|
||||
getPublicKey: (privateKey: Hex) => Uint8Array;
|
||||
Gu: string;
|
||||
};
|
||||
|
||||
function validateOpts(curve: CurveType) {
|
||||
validateObject(
|
||||
curve,
|
||||
{
|
||||
a24: 'bigint',
|
||||
},
|
||||
{
|
||||
montgomeryBits: 'isSafeInteger',
|
||||
nByteLength: 'isSafeInteger',
|
||||
adjustScalarBytes: 'function',
|
||||
domain: 'function',
|
||||
powPminus2: 'function',
|
||||
Gu: 'string',
|
||||
}
|
||||
);
|
||||
// Set defaults
|
||||
return Object.freeze({ ...curve } as const);
|
||||
}
|
||||
|
||||
// NOTE: not really montgomery curve, just bunch of very specific methods for X25519/X448 (RFC 7748, https://www.rfc-editor.org/rfc/rfc7748)
|
||||
// Uses only one coordinate instead of two
|
||||
export function montgomery(curveDef: CurveType): CurveFn {
|
||||
const CURVE = validateOpts(curveDef);
|
||||
const { P } = CURVE;
|
||||
const modP = (a: bigint) => mod(a, P);
|
||||
const montgomeryBits = CURVE.montgomeryBits;
|
||||
const montgomeryBytes = Math.ceil(montgomeryBits / 8);
|
||||
const fieldLen = CURVE.nByteLength;
|
||||
const adjustScalarBytes = CURVE.adjustScalarBytes || ((bytes: Uint8Array) => bytes);
|
||||
const powPminus2 = CURVE.powPminus2 || ((x: bigint) => pow(x, P - BigInt(2), P));
|
||||
|
||||
// cswap from RFC7748. But it is not from RFC7748!
|
||||
/*
|
||||
cswap(swap, x_2, x_3):
|
||||
dummy = mask(swap) AND (x_2 XOR x_3)
|
||||
x_2 = x_2 XOR dummy
|
||||
x_3 = x_3 XOR dummy
|
||||
Return (x_2, x_3)
|
||||
Where mask(swap) is the all-1 or all-0 word of the same length as x_2
|
||||
and x_3, computed, e.g., as mask(swap) = 0 - swap.
|
||||
*/
|
||||
function cswap(swap: bigint, x_2: bigint, x_3: bigint): [bigint, bigint] {
|
||||
const dummy = modP(swap * (x_2 - x_3));
|
||||
x_2 = modP(x_2 - dummy);
|
||||
x_3 = modP(x_3 + dummy);
|
||||
return [x_2, x_3];
|
||||
}
|
||||
|
||||
function assertFieldElement(n: bigint): bigint {
|
||||
if (typeof n === 'bigint' && _0n <= n && n < P) return n;
|
||||
throw new Error('Expected valid scalar 0 < scalar < CURVE.P');
|
||||
}
|
||||
|
||||
// x25519 from 4
|
||||
/**
|
||||
*
|
||||
* @param pointU u coordinate (x) on Montgomery Curve 25519
|
||||
* @param scalar by which the point would be multiplied
|
||||
* @returns new Point on Montgomery curve
|
||||
*/
|
||||
function montgomeryLadder(pointU: bigint, scalar: bigint): bigint {
|
||||
const u = assertFieldElement(pointU);
|
||||
// Section 5: Implementations MUST accept non-canonical values and process them as
|
||||
// if they had been reduced modulo the field prime.
|
||||
const k = assertFieldElement(scalar);
|
||||
// The constant a24 is (486662 - 2) / 4 = 121665 for curve25519/X25519
|
||||
const a24 = CURVE.a24;
|
||||
const x_1 = u;
|
||||
let x_2 = _1n;
|
||||
let z_2 = _0n;
|
||||
let x_3 = u;
|
||||
let z_3 = _1n;
|
||||
let swap = _0n;
|
||||
let sw: [bigint, bigint];
|
||||
for (let t = BigInt(montgomeryBits - 1); t >= _0n; t--) {
|
||||
const k_t = (k >> t) & _1n;
|
||||
swap ^= k_t;
|
||||
sw = cswap(swap, x_2, x_3);
|
||||
x_2 = sw[0];
|
||||
x_3 = sw[1];
|
||||
sw = cswap(swap, z_2, z_3);
|
||||
z_2 = sw[0];
|
||||
z_3 = sw[1];
|
||||
swap = k_t;
|
||||
|
||||
const A = x_2 + z_2;
|
||||
const AA = modP(A * A);
|
||||
const B = x_2 - z_2;
|
||||
const BB = modP(B * B);
|
||||
const E = AA - BB;
|
||||
const C = x_3 + z_3;
|
||||
const D = x_3 - z_3;
|
||||
const DA = modP(D * A);
|
||||
const CB = modP(C * B);
|
||||
const dacb = DA + CB;
|
||||
const da_cb = DA - CB;
|
||||
x_3 = modP(dacb * dacb);
|
||||
z_3 = modP(x_1 * modP(da_cb * da_cb));
|
||||
x_2 = modP(AA * BB);
|
||||
z_2 = modP(E * (AA + modP(a24 * E)));
|
||||
}
|
||||
// (x_2, x_3) = cswap(swap, x_2, x_3)
|
||||
sw = cswap(swap, x_2, x_3);
|
||||
x_2 = sw[0];
|
||||
x_3 = sw[1];
|
||||
// (z_2, z_3) = cswap(swap, z_2, z_3)
|
||||
sw = cswap(swap, z_2, z_3);
|
||||
z_2 = sw[0];
|
||||
z_3 = sw[1];
|
||||
// z_2^(p - 2)
|
||||
const z2 = powPminus2(z_2);
|
||||
// Return x_2 * (z_2^(p - 2))
|
||||
return modP(x_2 * z2);
|
||||
}
|
||||
|
||||
function encodeUCoordinate(u: bigint): Uint8Array {
|
||||
return numberToBytesLE(modP(u), montgomeryBytes);
|
||||
}
|
||||
|
||||
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(uEnc, montgomeryBytes);
|
||||
// u[fieldLen-1] crashes QuickJS (TypeError: out-of-bound numeric index)
|
||||
if (fieldLen === montgomeryBytes) u[fieldLen - 1] &= 127; // 0b0111_1111
|
||||
return bytesToNumberLE(u);
|
||||
}
|
||||
function decodeScalar(n: Hex): bigint {
|
||||
const bytes = ensureBytes(n);
|
||||
if (bytes.length !== montgomeryBytes && bytes.length !== fieldLen)
|
||||
throw new Error(`Expected ${montgomeryBytes} or ${fieldLen} bytes, got ${bytes.length}`);
|
||||
return bytesToNumberLE(adjustScalarBytes(bytes));
|
||||
}
|
||||
function scalarMult(scalar: Hex, u: Hex): Uint8Array {
|
||||
const pointU = decodeUCoordinate(u);
|
||||
const _scalar = decodeScalar(scalar);
|
||||
const pu = montgomeryLadder(pointU, _scalar);
|
||||
// The result was not contributory
|
||||
// https://cr.yp.to/ecdh.html#validate
|
||||
if (pu === _0n) throw new Error('Invalid private or public key received');
|
||||
return encodeUCoordinate(pu);
|
||||
}
|
||||
// Computes public key from private. By doing scalar multiplication of base point.
|
||||
function scalarMultBase(scalar: Hex): Uint8Array {
|
||||
return scalarMult(scalar, CURVE.Gu);
|
||||
}
|
||||
|
||||
return {
|
||||
scalarMult,
|
||||
scalarMultBase,
|
||||
getSharedSecret: (privateKey: Hex, publicKey: Hex) => scalarMult(privateKey, publicKey),
|
||||
getPublicKey: (privateKey: Hex): Uint8Array => scalarMultBase(privateKey),
|
||||
Gu: CURVE.Gu,
|
||||
};
|
||||
}
|
||||
119
src/abstract/poseidon.ts
Normal file
119
src/abstract/poseidon.ts
Normal file
@@ -0,0 +1,119 @@
|
||||
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
||||
// Poseidon Hash: https://eprint.iacr.org/2019/458.pdf, https://www.poseidon-hash.info
|
||||
import { Field, FpPow, validateField } from './modular.js';
|
||||
// We don't provide any constants, since different implementations use different constants.
|
||||
// For reference constants see './test/poseidon.test.js'.
|
||||
export type PoseidonOpts = {
|
||||
Fp: Field<bigint>;
|
||||
t: number;
|
||||
roundsFull: number;
|
||||
roundsPartial: number;
|
||||
sboxPower?: number;
|
||||
reversePartialPowIdx?: boolean; // Hack for stark
|
||||
mds: bigint[][];
|
||||
roundConstants: bigint[][];
|
||||
};
|
||||
|
||||
export function validateOpts(opts: PoseidonOpts) {
|
||||
const { Fp } = opts;
|
||||
validateField(Fp);
|
||||
for (const i of ['t', 'roundsFull', 'roundsPartial'] as const) {
|
||||
if (typeof opts[i] !== 'number' || !Number.isSafeInteger(opts[i]))
|
||||
throw new Error(`Poseidon: invalid param ${i}=${opts[i]} (${typeof opts[i]})`);
|
||||
}
|
||||
if (opts.reversePartialPowIdx !== undefined && typeof opts.reversePartialPowIdx !== 'boolean')
|
||||
throw new Error(`Poseidon: invalid param reversePartialPowIdx=${opts.reversePartialPowIdx}`);
|
||||
// Default is 5, but by some reasons stark uses 3
|
||||
let sboxPower = opts.sboxPower;
|
||||
if (sboxPower === undefined) sboxPower = 5;
|
||||
if (typeof sboxPower !== 'number' || !Number.isSafeInteger(sboxPower))
|
||||
throw new Error(`Poseidon wrong sboxPower=${sboxPower}`);
|
||||
|
||||
const _sboxPower = BigInt(sboxPower);
|
||||
let sboxFn = (n: bigint) => FpPow(Fp, n, _sboxPower);
|
||||
// Unwrapped sbox power for common cases (195->142μs)
|
||||
if (sboxPower === 3) sboxFn = (n: bigint) => Fp.mul(Fp.sqrN(n), n);
|
||||
else if (sboxPower === 5) sboxFn = (n: bigint) => Fp.mul(Fp.sqrN(Fp.sqrN(n)), n);
|
||||
|
||||
if (opts.roundsFull % 2 !== 0)
|
||||
throw new Error(`Poseidon roundsFull is not even: ${opts.roundsFull}`);
|
||||
const rounds = opts.roundsFull + opts.roundsPartial;
|
||||
|
||||
if (!Array.isArray(opts.roundConstants) || opts.roundConstants.length !== rounds)
|
||||
throw new Error('Poseidon: wrong round constants');
|
||||
const roundConstants = opts.roundConstants.map((rc) => {
|
||||
if (!Array.isArray(rc) || rc.length !== opts.t)
|
||||
throw new Error(`Poseidon wrong round constants: ${rc}`);
|
||||
return rc.map((i) => {
|
||||
if (typeof i !== 'bigint' || !Fp.isValid(i))
|
||||
throw new Error(`Poseidon wrong round constant=${i}`);
|
||||
return Fp.create(i);
|
||||
});
|
||||
});
|
||||
// MDS is TxT matrix
|
||||
if (!Array.isArray(opts.mds) || opts.mds.length !== opts.t)
|
||||
throw new Error('Poseidon: wrong MDS matrix');
|
||||
const mds = opts.mds.map((mdsRow) => {
|
||||
if (!Array.isArray(mdsRow) || mdsRow.length !== opts.t)
|
||||
throw new Error(`Poseidon MDS matrix row: ${mdsRow}`);
|
||||
return mdsRow.map((i) => {
|
||||
if (typeof i !== 'bigint') throw new Error(`Poseidon MDS matrix value=${i}`);
|
||||
return Fp.create(i);
|
||||
});
|
||||
});
|
||||
return Object.freeze({ ...opts, rounds, sboxFn, roundConstants, mds });
|
||||
}
|
||||
|
||||
export function splitConstants(rc: bigint[], t: number) {
|
||||
if (typeof t !== 'number') throw new Error('poseidonSplitConstants: wrong t');
|
||||
if (!Array.isArray(rc) || rc.length % t) throw new Error('poseidonSplitConstants: wrong rc');
|
||||
const res = [];
|
||||
let tmp = [];
|
||||
for (let i = 0; i < rc.length; i++) {
|
||||
tmp.push(rc[i]);
|
||||
if (tmp.length === t) {
|
||||
res.push(tmp);
|
||||
tmp = [];
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
export function poseidon(opts: PoseidonOpts) {
|
||||
const { t, Fp, rounds, sboxFn, reversePartialPowIdx } = validateOpts(opts);
|
||||
const halfRoundsFull = Math.floor(opts.roundsFull / 2);
|
||||
const partialIdx = reversePartialPowIdx ? t - 1 : 0;
|
||||
const poseidonRound = (values: bigint[], isFull: boolean, idx: number) => {
|
||||
values = values.map((i, j) => Fp.add(i, opts.roundConstants[idx][j]));
|
||||
|
||||
if (isFull) values = values.map((i) => sboxFn(i));
|
||||
else values[partialIdx] = sboxFn(values[partialIdx]);
|
||||
// Matrix multiplication
|
||||
values = opts.mds.map((i) =>
|
||||
i.reduce((acc, i, j) => Fp.add(acc, Fp.mulN(i, values[j])), Fp.ZERO)
|
||||
);
|
||||
return values;
|
||||
};
|
||||
const poseidonHash = function poseidonHash(values: bigint[]) {
|
||||
if (!Array.isArray(values) || values.length !== t)
|
||||
throw new Error(`Poseidon: wrong values (expected array of bigints with length ${t})`);
|
||||
values = values.map((i) => {
|
||||
if (typeof i !== 'bigint') throw new Error(`Poseidon: wrong value=${i} (${typeof i})`);
|
||||
return Fp.create(i);
|
||||
});
|
||||
let round = 0;
|
||||
// Apply r_f/2 full rounds.
|
||||
for (let i = 0; i < halfRoundsFull; i++) values = poseidonRound(values, true, round++);
|
||||
// Apply r_p partial rounds.
|
||||
for (let i = 0; i < opts.roundsPartial; i++) values = poseidonRound(values, false, round++);
|
||||
// Apply r_f/2 full rounds.
|
||||
for (let i = 0; i < halfRoundsFull; i++) values = poseidonRound(values, true, round++);
|
||||
|
||||
if (round !== rounds)
|
||||
throw new Error(`Poseidon: wrong number of rounds: last round=${round}, total=${rounds}`);
|
||||
return values;
|
||||
};
|
||||
// For verification in tests
|
||||
poseidonHash.roundConstants = opts.roundConstants;
|
||||
return poseidonHash;
|
||||
}
|
||||
160
src/abstract/utils.ts
Normal file
160
src/abstract/utils.ts
Normal file
@@ -0,0 +1,160 @@
|
||||
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
||||
const _0n = BigInt(0);
|
||||
const _1n = BigInt(1);
|
||||
const _2n = BigInt(2);
|
||||
const u8a = (a: any): a is Uint8Array => a instanceof Uint8Array;
|
||||
|
||||
// We accept hex strings besides Uint8Array for simplicity
|
||||
export type Hex = Uint8Array | string;
|
||||
// Very few implementations accept numbers, we do it to ease learning curve
|
||||
export type PrivKey = Hex | bigint;
|
||||
export type CHash = {
|
||||
(message: Uint8Array | string): Uint8Array;
|
||||
blockLen: number;
|
||||
outputLen: number;
|
||||
create(opts?: { dkLen?: number }): any; // For shake
|
||||
};
|
||||
export type FHash = (message: Uint8Array | string) => Uint8Array;
|
||||
|
||||
const hexes = Array.from({ length: 256 }, (v, i) => i.toString(16).padStart(2, '0'));
|
||||
export function bytesToHex(bytes: Uint8Array): string {
|
||||
if (!u8a(bytes)) throw new Error('Uint8Array expected');
|
||||
// pre-caching improves the speed 6x
|
||||
let hex = '';
|
||||
for (let i = 0; i < bytes.length; i++) {
|
||||
hex += hexes[bytes[i]];
|
||||
}
|
||||
return hex;
|
||||
}
|
||||
|
||||
export function numberToHexUnpadded(num: number | bigint): string {
|
||||
const hex = num.toString(16);
|
||||
return hex.length & 1 ? `0${hex}` : hex;
|
||||
}
|
||||
|
||||
export function hexToNumber(hex: string): bigint {
|
||||
if (typeof hex !== 'string') throw new Error('string expected, got ' + typeof hex);
|
||||
// Big Endian
|
||||
return BigInt(hex === '' ? '0' : `0x${hex}`);
|
||||
}
|
||||
|
||||
// Caching slows it down 2-3x
|
||||
export function hexToBytes(hex: string): Uint8Array {
|
||||
if (typeof hex !== 'string') throw new Error('string expected, got ' + typeof hex);
|
||||
if (hex.length % 2) throw new Error('hex string is invalid: unpadded ' + hex.length);
|
||||
const array = new Uint8Array(hex.length / 2);
|
||||
for (let i = 0; i < array.length; i++) {
|
||||
const j = i * 2;
|
||||
const hexByte = hex.slice(j, j + 2);
|
||||
const byte = Number.parseInt(hexByte, 16);
|
||||
if (Number.isNaN(byte) || byte < 0) throw new Error('invalid byte sequence');
|
||||
array[i] = byte;
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
// Big Endian
|
||||
export function bytesToNumberBE(bytes: Uint8Array): bigint {
|
||||
return hexToNumber(bytesToHex(bytes));
|
||||
}
|
||||
export function bytesToNumberLE(bytes: Uint8Array): bigint {
|
||||
if (!u8a(bytes)) throw new Error('Uint8Array expected');
|
||||
return hexToNumber(bytesToHex(Uint8Array.from(bytes).reverse()));
|
||||
}
|
||||
|
||||
export const numberToBytesBE = (n: bigint, len: number) =>
|
||||
hexToBytes(n.toString(16).padStart(len * 2, '0'));
|
||||
export const numberToBytesLE = (n: bigint, len: number) => numberToBytesBE(n, len).reverse();
|
||||
// Returns variable number bytes (minimal bigint encoding?)
|
||||
export const numberToVarBytesBE = (n: bigint) => hexToBytes(numberToHexUnpadded(n));
|
||||
|
||||
export function ensureBytes(hex: Hex, expectedLength?: number): Uint8Array {
|
||||
// Uint8Array.from() instead of hash.slice() because node.js Buffer
|
||||
// is instance of Uint8Array, and its slice() creates **mutable** copy
|
||||
const bytes = u8a(hex) ? Uint8Array.from(hex) : hexToBytes(hex);
|
||||
if (typeof expectedLength === 'number' && bytes.length !== expectedLength)
|
||||
throw new Error(`Expected ${expectedLength} bytes`);
|
||||
return bytes;
|
||||
}
|
||||
|
||||
// Copies several Uint8Arrays into one.
|
||||
export function concatBytes(...arrs: Uint8Array[]): Uint8Array {
|
||||
const r = new Uint8Array(arrs.reduce((sum, a) => sum + a.length, 0));
|
||||
let pad = 0; // walk through each item, ensure they have proper type
|
||||
arrs.forEach((a) => {
|
||||
if (!u8a(a)) throw new Error('Uint8Array expected');
|
||||
r.set(a, pad);
|
||||
pad += a.length;
|
||||
});
|
||||
return r;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
// Bit operations
|
||||
|
||||
// Amount of bits inside bigint (Same as n.toString(2).length)
|
||||
export function bitLen(n: bigint) {
|
||||
let len;
|
||||
for (len = 0; n > 0n; n >>= _1n, len += 1);
|
||||
return len;
|
||||
}
|
||||
// Gets single bit at position. NOTE: first bit position is 0 (same as arrays)
|
||||
// Same as !!+Array.from(n.toString(2)).reverse()[pos]
|
||||
export const bitGet = (n: bigint, pos: number) => (n >> BigInt(pos)) & 1n;
|
||||
// Sets single bit at position
|
||||
export const bitSet = (n: bigint, pos: number, value: boolean) =>
|
||||
n | ((value ? _1n : _0n) << BigInt(pos));
|
||||
// Return mask for N bits (Same as BigInt(`0b${Array(i).fill('1').join('')}`))
|
||||
// Not using ** operator with bigints for old engines.
|
||||
export const bitMask = (n: number) => (_2n << BigInt(n - 1)) - _1n;
|
||||
|
||||
const validatorFns = {
|
||||
bigint: (val: any) => typeof val === 'bigint',
|
||||
function: (val: any) => typeof val === 'function',
|
||||
boolean: (val: any) => typeof val === 'boolean',
|
||||
string: (val: any) => typeof val === 'string',
|
||||
isSafeInteger: (val: any) => Number.isSafeInteger(val),
|
||||
array: (val: any) => Array.isArray(val),
|
||||
field: (val: any, object: any) => (object as any).Fp.isValid(val),
|
||||
hash: (val: any) => typeof val === 'function' && Number.isSafeInteger(val.outputLen),
|
||||
} as const;
|
||||
type Validator = keyof typeof validatorFns;
|
||||
type ValMap<T extends Record<string, any>> = { [K in keyof T]?: Validator };
|
||||
// type Record<K extends string | number | symbol, T> = { [P in K]: T; }
|
||||
|
||||
export function validateObject<T extends Record<string, any>>(
|
||||
object: T,
|
||||
validators: ValMap<T>,
|
||||
optValidators: ValMap<T> = {}
|
||||
) {
|
||||
const checkField = (fieldName: keyof T, type: Validator, isOptional: boolean) => {
|
||||
const checkVal = validatorFns[type];
|
||||
if (typeof checkVal !== 'function')
|
||||
throw new Error(`Invalid validator "${type}", expected function`);
|
||||
|
||||
const val = object[fieldName as keyof typeof object];
|
||||
if (isOptional && val === undefined) return;
|
||||
if (!checkVal(val, object)) {
|
||||
throw new Error(
|
||||
`Invalid param ${String(fieldName)}=${val} (${typeof val}), expected ${type}`
|
||||
);
|
||||
}
|
||||
};
|
||||
for (const [fieldName, type] of Object.entries(validators)) checkField(fieldName, type!, false);
|
||||
for (const [fieldName, type] of Object.entries(optValidators)) checkField(fieldName, type!, true);
|
||||
return object;
|
||||
}
|
||||
// validate type tests
|
||||
// const o: { a: number; b: number; c: number } = { a: 1, b: 5, c: 6 };
|
||||
// const z0 = validateObject(o, { a: 'isSafeInteger' }, { c: 'bigint' }); // Ok!
|
||||
// // Should fail type-check
|
||||
// const z1 = validateObject(o, { a: 'tmp' }, { c: 'zz' });
|
||||
// const z2 = validateObject(o, { a: 'isSafeInteger' }, { c: 'zz' });
|
||||
// const z3 = validateObject(o, { test: 'boolean', z: 'bug' });
|
||||
// const z4 = validateObject(o, { a: 'boolean', z: 'bug' });
|
||||
1210
src/abstract/weierstrass.ts
Normal file
1210
src/abstract/weierstrass.ts
Normal file
File diff suppressed because it is too large
Load Diff
1241
src/bls12-381.ts
Normal file
1241
src/bls12-381.ts
Normal file
File diff suppressed because it is too large
Load Diff
21
src/bn.ts
Normal file
21
src/bn.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
||||
import { sha256 } from '@noble/hashes/sha256';
|
||||
import { weierstrass } from './abstract/weierstrass.js';
|
||||
import { getHash } from './_shortw_utils.js';
|
||||
import { Fp } 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
|
||||
*/
|
||||
export const bn254 = weierstrass({
|
||||
a: BigInt(0),
|
||||
b: BigInt(3),
|
||||
Fp: Fp(BigInt('0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47')),
|
||||
n: BigInt('0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001'),
|
||||
Gx: BigInt(1),
|
||||
Gy: BigInt(2),
|
||||
h: BigInt(1),
|
||||
...getHash(sha256),
|
||||
});
|
||||
428
src/ed25519.ts
Normal file
428
src/ed25519.ts
Normal file
@@ -0,0 +1,428 @@
|
||||
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
||||
import { sha512 } from '@noble/hashes/sha512';
|
||||
import { concatBytes, randomBytes, utf8ToBytes } from '@noble/hashes/utils';
|
||||
import { twistedEdwards, ExtPointType } from './abstract/edwards.js';
|
||||
import { montgomery } from './abstract/montgomery.js';
|
||||
import { mod, pow2, isNegativeLE, Fp as Field, FpSqrtEven } from './abstract/modular.js';
|
||||
import {
|
||||
ensureBytes,
|
||||
equalBytes,
|
||||
bytesToHex,
|
||||
bytesToNumberLE,
|
||||
numberToBytesLE,
|
||||
Hex,
|
||||
} from './abstract/utils.js';
|
||||
import * as htf from './abstract/hash-to-curve.js';
|
||||
|
||||
/**
|
||||
* ed25519 Twisted Edwards curve with following addons:
|
||||
* - X25519 ECDH
|
||||
* - Ristretto cofactor elimination
|
||||
* - Elligator hash-to-group / point indistinguishability
|
||||
*/
|
||||
|
||||
const ED25519_P = BigInt(
|
||||
'57896044618658097711785492504343953926634992332820282019728792003956564819949'
|
||||
);
|
||||
// √(-1) aka √(a) aka 2^((p-1)/4)
|
||||
const ED25519_SQRT_M1 = BigInt(
|
||||
'19681161376707505956807079304988542015446066515923890162744021073123829784752'
|
||||
);
|
||||
|
||||
// prettier-ignore
|
||||
const _0n = BigInt(0), _1n = BigInt(1), _2n = BigInt(2), _5n = BigInt(5);
|
||||
// prettier-ignore
|
||||
const _10n = BigInt(10), _20n = BigInt(20), _40n = BigInt(40), _80n = BigInt(80);
|
||||
function ed25519_pow_2_252_3(x: bigint) {
|
||||
const P = ED25519_P;
|
||||
const x2 = (x * x) % P;
|
||||
const b2 = (x2 * x) % P; // x^3, 11
|
||||
const b4 = (pow2(b2, _2n, P) * b2) % P; // x^15, 1111
|
||||
const b5 = (pow2(b4, _1n, P) * x) % P; // x^31
|
||||
const b10 = (pow2(b5, _5n, P) * b5) % P;
|
||||
const b20 = (pow2(b10, _10n, P) * b10) % P;
|
||||
const b40 = (pow2(b20, _20n, P) * b20) % P;
|
||||
const b80 = (pow2(b40, _40n, P) * b40) % P;
|
||||
const b160 = (pow2(b80, _80n, P) * b80) % P;
|
||||
const b240 = (pow2(b160, _80n, P) * b80) % P;
|
||||
const b250 = (pow2(b240, _10n, P) * b10) % P;
|
||||
const pow_p_5_8 = (pow2(b250, _2n, P) * x) % P;
|
||||
// ^ To pow to (p+3)/8, multiply it by x.
|
||||
return { pow_p_5_8, b2 };
|
||||
}
|
||||
function adjustScalarBytes(bytes: Uint8Array): Uint8Array {
|
||||
// Section 5: For X25519, in order to decode 32 random bytes as an integer scalar,
|
||||
// set the three least significant bits of the first byte
|
||||
bytes[0] &= 248; // 0b1111_1000
|
||||
// and the most significant bit of the last to zero,
|
||||
bytes[31] &= 127; // 0b0111_1111
|
||||
// set the second most significant bit of the last byte to 1
|
||||
bytes[31] |= 64; // 0b0100_0000
|
||||
return bytes;
|
||||
}
|
||||
// sqrt(u/v)
|
||||
function uvRatio(u: bigint, v: bigint): { isValid: boolean; value: bigint } {
|
||||
const P = ED25519_P;
|
||||
const v3 = mod(v * v * v, P); // v³
|
||||
const v7 = mod(v3 * v3 * v, P); // v⁷
|
||||
// (p+3)/8 and (p-5)/8
|
||||
const pow = ed25519_pow_2_252_3(u * v7).pow_p_5_8;
|
||||
let x = mod(u * v3 * pow, P); // (uv³)(uv⁷)^(p-5)/8
|
||||
const vx2 = mod(v * x * x, P); // vx²
|
||||
const root1 = x; // First root candidate
|
||||
const root2 = mod(x * ED25519_SQRT_M1, P); // Second root candidate
|
||||
const useRoot1 = vx2 === u; // If vx² = u (mod p), x is a square root
|
||||
const useRoot2 = vx2 === mod(-u, P); // If vx² = -u, set x <-- x * 2^((p-1)/4)
|
||||
const noRoot = vx2 === mod(-u * ED25519_SQRT_M1, P); // There is no valid root, vx² = -u√(-1)
|
||||
if (useRoot1) x = root1;
|
||||
if (useRoot2 || noRoot) x = root2; // We return root2 anyway, for const-time
|
||||
if (isNegativeLE(x, P)) x = mod(-x, P);
|
||||
return { isValid: useRoot1 || useRoot2, value: x };
|
||||
}
|
||||
|
||||
// Just in case
|
||||
export const ED25519_TORSION_SUBGROUP = [
|
||||
'0100000000000000000000000000000000000000000000000000000000000000',
|
||||
'c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a',
|
||||
'0000000000000000000000000000000000000000000000000000000000000080',
|
||||
'26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc05',
|
||||
'ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f',
|
||||
'26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc85',
|
||||
'0000000000000000000000000000000000000000000000000000000000000000',
|
||||
'c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa',
|
||||
];
|
||||
|
||||
const Fp = Field(ED25519_P, undefined, true);
|
||||
|
||||
const ED25519_DEF = {
|
||||
// Param: a
|
||||
a: BigInt(-1),
|
||||
// Equal to -121665/121666 over finite field.
|
||||
// Negative number is P - number, and division is invert(number, P)
|
||||
d: BigInt('37095705934669439343138083508754565189542113879843219016388785533085940283555'),
|
||||
// Finite field 𝔽p over which we'll do calculations; 2n ** 255n - 19n
|
||||
Fp,
|
||||
// Subgroup order: how many points ed25519 has
|
||||
// 2n ** 252n + 27742317777372353535851937790883648493n;
|
||||
n: BigInt('7237005577332262213973186563042994240857116359379907606001950938285454250989'),
|
||||
// Cofactor
|
||||
h: BigInt(8),
|
||||
// Base point (x, y) aka generator point
|
||||
Gx: BigInt('15112221349535400772501151409588531511454012693041857206046113283949847762202'),
|
||||
Gy: BigInt('46316835694926478169428394003475163141307993866256225615783033603165251855960'),
|
||||
hash: sha512,
|
||||
randomBytes,
|
||||
adjustScalarBytes,
|
||||
// dom2
|
||||
// Ratio of u to v. Allows us to combine inversion and square root. Uses algo from RFC8032 5.1.3.
|
||||
// Constant-time, u/√v
|
||||
uvRatio,
|
||||
} as const;
|
||||
|
||||
export const ed25519 = twistedEdwards(ED25519_DEF);
|
||||
function ed25519_domain(data: Uint8Array, ctx: Uint8Array, phflag: boolean) {
|
||||
if (ctx.length > 255) throw new Error('Context is too big');
|
||||
return concatBytes(
|
||||
utf8ToBytes('SigEd25519 no Ed25519 collisions'),
|
||||
new Uint8Array([phflag ? 1 : 0, ctx.length]),
|
||||
ctx,
|
||||
data
|
||||
);
|
||||
}
|
||||
export const ed25519ctx = twistedEdwards({ ...ED25519_DEF, domain: ed25519_domain });
|
||||
export const ed25519ph = twistedEdwards({
|
||||
...ED25519_DEF,
|
||||
domain: ed25519_domain,
|
||||
preHash: sha512,
|
||||
});
|
||||
|
||||
export const x25519 = montgomery({
|
||||
P: ED25519_P,
|
||||
a24: BigInt('121665'),
|
||||
montgomeryBits: 255, // n is 253 bits
|
||||
nByteLength: 32,
|
||||
Gu: '0900000000000000000000000000000000000000000000000000000000000000',
|
||||
powPminus2: (x: bigint): bigint => {
|
||||
const P = ED25519_P;
|
||||
// x^(p-2) aka x^(2^255-21)
|
||||
const { pow_p_5_8, b2 } = ed25519_pow_2_252_3(x);
|
||||
return mod(pow2(pow_p_5_8, BigInt(3), P) * b2, P);
|
||||
},
|
||||
adjustScalarBytes,
|
||||
});
|
||||
|
||||
// Hash To Curve Elligator2 Map (NOTE: different from ristretto255 elligator)
|
||||
// NOTE: very important part is usage of FpSqrtEven for ELL2_C1_EDWARDS, since
|
||||
// SageMath returns different root first and everything falls apart
|
||||
|
||||
const ELL2_C1 = (Fp.ORDER + BigInt(3)) / BigInt(8); // 1. c1 = (q + 3) / 8 # Integer arithmetic
|
||||
|
||||
const ELL2_C2 = Fp.pow(_2n, ELL2_C1); // 2. c2 = 2^c1
|
||||
const ELL2_C3 = Fp.sqrt(Fp.neg(Fp.ONE)); // 3. c3 = sqrt(-1)
|
||||
const ELL2_C4 = (Fp.ORDER - BigInt(5)) / BigInt(8); // 4. c4 = (q - 5) / 8 # Integer arithmetic
|
||||
const ELL2_J = BigInt(486662);
|
||||
|
||||
// prettier-ignore
|
||||
function map_to_curve_elligator2_curve25519(u: bigint) {
|
||||
let tv1 = Fp.sqr(u); // 1. tv1 = u^2
|
||||
tv1 = Fp.mul(tv1, _2n); // 2. tv1 = 2 * tv1
|
||||
let xd = Fp.add(tv1, Fp.ONE); // 3. xd = tv1 + 1 # Nonzero: -1 is square (mod p), tv1 is not
|
||||
let x1n = Fp.neg(ELL2_J); // 4. x1n = -J # x1 = x1n / xd = -J / (1 + 2 * u^2)
|
||||
let tv2 = Fp.sqr(xd); // 5. tv2 = xd^2
|
||||
let gxd = Fp.mul(tv2, xd); // 6. gxd = tv2 * xd # gxd = xd^3
|
||||
let gx1 = Fp.mul(tv1, ELL2_J); // 7. gx1 = J * tv1 # x1n + J * xd
|
||||
gx1 = Fp.mul(gx1, x1n); // 8. gx1 = gx1 * x1n # x1n^2 + J * x1n * xd
|
||||
gx1 = Fp.add(gx1, tv2); // 9. gx1 = gx1 + tv2 # x1n^2 + J * x1n * xd + xd^2
|
||||
gx1 = Fp.mul(gx1, x1n); // 10. gx1 = gx1 * x1n # x1n^3 + J * x1n^2 * xd + x1n * xd^2
|
||||
let tv3 = Fp.sqr(gxd); // 11. tv3 = gxd^2
|
||||
tv2 = Fp.sqr(tv3); // 12. tv2 = tv3^2 # gxd^4
|
||||
tv3 = Fp.mul(tv3, gxd); // 13. tv3 = tv3 * gxd # gxd^3
|
||||
tv3 = Fp.mul(tv3, gx1); // 14. tv3 = tv3 * gx1 # gx1 * gxd^3
|
||||
tv2 = Fp.mul(tv2, tv3); // 15. tv2 = tv2 * tv3 # gx1 * gxd^7
|
||||
let y11 = Fp.pow(tv2, ELL2_C4); // 16. y11 = tv2^c4 # (gx1 * gxd^7)^((p - 5) / 8)
|
||||
y11 = Fp.mul(y11, tv3); // 17. y11 = y11 * tv3 # gx1*gxd^3*(gx1*gxd^7)^((p-5)/8)
|
||||
let y12 = Fp.mul(y11, ELL2_C3); // 18. y12 = y11 * c3
|
||||
tv2 = Fp.sqr(y11); // 19. tv2 = y11^2
|
||||
tv2 = Fp.mul(tv2, gxd); // 20. tv2 = tv2 * gxd
|
||||
let e1 = Fp.eql(tv2, gx1); // 21. e1 = tv2 == gx1
|
||||
let y1 = Fp.cmov(y12, y11, e1); // 22. y1 = CMOV(y12, y11, e1) # If g(x1) is square, this is its sqrt
|
||||
let x2n = Fp.mul(x1n, tv1); // 23. x2n = x1n * tv1 # x2 = x2n / xd = 2 * u^2 * x1n / xd
|
||||
let y21 = Fp.mul(y11, u); // 24. y21 = y11 * u
|
||||
y21 = Fp.mul(y21, ELL2_C2); // 25. y21 = y21 * c2
|
||||
let y22 = Fp.mul(y21, ELL2_C3); // 26. y22 = y21 * c3
|
||||
let gx2 = Fp.mul(gx1, tv1); // 27. gx2 = gx1 * tv1 # g(x2) = gx2 / gxd = 2 * u^2 * g(x1)
|
||||
tv2 = Fp.sqr(y21); // 28. tv2 = y21^2
|
||||
tv2 = Fp.mul(tv2, gxd); // 29. tv2 = tv2 * gxd
|
||||
let e2 = Fp.eql(tv2, gx2); // 30. e2 = tv2 == gx2
|
||||
let y2 = Fp.cmov(y22, y21, e2); // 31. y2 = CMOV(y22, y21, e2) # If g(x2) is square, this is its sqrt
|
||||
tv2 = Fp.sqr(y1); // 32. tv2 = y1^2
|
||||
tv2 = Fp.mul(tv2, gxd); // 33. tv2 = tv2 * gxd
|
||||
let e3 = Fp.eql(tv2, gx1); // 34. e3 = tv2 == gx1
|
||||
let xn = Fp.cmov(x2n, x1n, e3); // 35. xn = CMOV(x2n, x1n, e3) # If e3, x = x1, else x = x2
|
||||
let y = Fp.cmov(y2, y1, e3); // 36. y = CMOV(y2, y1, e3) # If e3, y = y1, else y = y2
|
||||
let e4 = Fp.isOdd(y); // 37. e4 = sgn0(y) == 1 # Fix sign of y
|
||||
y = Fp.cmov(y, Fp.neg(y), e3 !== e4); // 38. y = CMOV(y, -y, e3 XOR e4)
|
||||
return { xMn: xn, xMd: xd, yMn: y, yMd: 1n }; // 39. return (xn, xd, y, 1)
|
||||
}
|
||||
|
||||
const ELL2_C1_EDWARDS = FpSqrtEven(Fp, Fp.neg(BigInt(486664))); // sgn0(c1) MUST equal 0
|
||||
function map_to_curve_elligator2_edwards25519(u: bigint) {
|
||||
const { xMn, xMd, yMn, yMd } = map_to_curve_elligator2_curve25519(u); // 1. (xMn, xMd, yMn, yMd) = map_to_curve_elligator2_curve25519(u)
|
||||
let xn = Fp.mul(xMn, yMd); // 2. xn = xMn * yMd
|
||||
xn = Fp.mul(xn, ELL2_C1_EDWARDS); // 3. xn = xn * c1
|
||||
let xd = Fp.mul(xMd, yMn); // 4. xd = xMd * yMn # xn / xd = c1 * xM / yM
|
||||
let yn = Fp.sub(xMn, xMd); // 5. yn = xMn - xMd
|
||||
let yd = Fp.add(xMn, xMd); // 6. yd = xMn + xMd # (n / d - 1) / (n / d + 1) = (n - d) / (n + d)
|
||||
let tv1 = Fp.mul(xd, yd); // 7. tv1 = xd * yd
|
||||
let e = Fp.eql(tv1, Fp.ZERO); // 8. e = tv1 == 0
|
||||
xn = Fp.cmov(xn, Fp.ZERO, e); // 9. xn = CMOV(xn, 0, e)
|
||||
xd = Fp.cmov(xd, Fp.ONE, e); // 10. xd = CMOV(xd, 1, e)
|
||||
yn = Fp.cmov(yn, Fp.ONE, e); // 11. yn = CMOV(yn, 1, e)
|
||||
yd = Fp.cmov(yd, Fp.ONE, e); // 12. yd = CMOV(yd, 1, e)
|
||||
|
||||
const inv = Fp.invertBatch([xd, yd]); // batch division
|
||||
return { x: Fp.mul(xn, inv[0]), y: Fp.mul(yn, inv[1]) }; // 13. return (xn, xd, yn, yd)
|
||||
}
|
||||
const { hashToCurve, encodeToCurve } = htf.hashToCurve(
|
||||
ed25519.ExtendedPoint,
|
||||
(scalars: bigint[]) => map_to_curve_elligator2_edwards25519(scalars[0]),
|
||||
{
|
||||
DST: 'edwards25519_XMD:SHA-512_ELL2_RO_',
|
||||
encodeDST: 'edwards25519_XMD:SHA-512_ELL2_NU_',
|
||||
p: Fp.ORDER,
|
||||
m: 1,
|
||||
k: 128,
|
||||
expand: 'xmd',
|
||||
hash: sha512,
|
||||
}
|
||||
);
|
||||
export { hashToCurve, encodeToCurve };
|
||||
|
||||
function assertRstPoint(other: unknown) {
|
||||
if (!(other instanceof RistrettoPoint)) throw new Error('RistrettoPoint expected');
|
||||
}
|
||||
// √(-1) aka √(a) aka 2^((p-1)/4)
|
||||
const SQRT_M1 = BigInt(
|
||||
'19681161376707505956807079304988542015446066515923890162744021073123829784752'
|
||||
);
|
||||
// √(ad - 1)
|
||||
const SQRT_AD_MINUS_ONE = BigInt(
|
||||
'25063068953384623474111414158702152701244531502492656460079210482610430750235'
|
||||
);
|
||||
// 1 / √(a-d)
|
||||
const INVSQRT_A_MINUS_D = BigInt(
|
||||
'54469307008909316920995813868745141605393597292927456921205312896311721017578'
|
||||
);
|
||||
// 1-d²
|
||||
const ONE_MINUS_D_SQ = BigInt(
|
||||
'1159843021668779879193775521855586647937357759715417654439879720876111806838'
|
||||
);
|
||||
// (d-1)²
|
||||
const D_MINUS_ONE_SQ = BigInt(
|
||||
'40440834346308536858101042469323190826248399146238708352240133220865137265952'
|
||||
);
|
||||
// Calculates 1/√(number)
|
||||
const invertSqrt = (number: bigint) => uvRatio(_1n, number);
|
||||
|
||||
const MAX_255B = BigInt('0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff');
|
||||
const bytes255ToNumberLE = (bytes: Uint8Array) =>
|
||||
ed25519.CURVE.Fp.create(bytesToNumberLE(bytes) & MAX_255B);
|
||||
|
||||
type ExtendedPoint = ExtPointType;
|
||||
|
||||
// Computes Elligator map for Ristretto
|
||||
// https://ristretto.group/formulas/elligator.html
|
||||
function calcElligatorRistrettoMap(r0: bigint): ExtendedPoint {
|
||||
const { d } = ed25519.CURVE;
|
||||
const P = ed25519.CURVE.Fp.ORDER;
|
||||
const mod = ed25519.CURVE.Fp.create;
|
||||
const r = mod(SQRT_M1 * r0 * r0); // 1
|
||||
const Ns = mod((r + _1n) * ONE_MINUS_D_SQ); // 2
|
||||
let c = BigInt(-1); // 3
|
||||
const D = mod((c - d * r) * mod(r + d)); // 4
|
||||
let { isValid: Ns_D_is_sq, value: s } = uvRatio(Ns, D); // 5
|
||||
let s_ = mod(s * r0); // 6
|
||||
if (!isNegativeLE(s_, P)) s_ = mod(-s_);
|
||||
if (!Ns_D_is_sq) s = s_; // 7
|
||||
if (!Ns_D_is_sq) c = r; // 8
|
||||
const Nt = mod(c * (r - _1n) * D_MINUS_ONE_SQ - D); // 9
|
||||
const s2 = s * s;
|
||||
const W0 = mod((s + s) * D); // 10
|
||||
const W1 = mod(Nt * SQRT_AD_MINUS_ONE); // 11
|
||||
const W2 = mod(_1n - s2); // 12
|
||||
const W3 = mod(_1n + s2); // 13
|
||||
return new ed25519.ExtendedPoint(mod(W0 * W3), mod(W2 * W1), mod(W1 * W3), mod(W0 * W2));
|
||||
}
|
||||
|
||||
/**
|
||||
* Each ed25519/ExtendedPoint has 8 different equivalent points. This can be
|
||||
* a source of bugs for protocols like ring signatures. Ristretto was created to solve this.
|
||||
* Ristretto point operates in X:Y:Z:T extended coordinates like ExtendedPoint,
|
||||
* but it should work in its own namespace: do not combine those two.
|
||||
* https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-ristretto255-decaf448
|
||||
*/
|
||||
export class RistrettoPoint {
|
||||
static BASE = new RistrettoPoint(ed25519.ExtendedPoint.BASE);
|
||||
static ZERO = new RistrettoPoint(ed25519.ExtendedPoint.ZERO);
|
||||
|
||||
// Private property to discourage combining ExtendedPoint + RistrettoPoint
|
||||
// Always use Ristretto encoding/decoding instead.
|
||||
constructor(private readonly ep: ExtendedPoint) {}
|
||||
/**
|
||||
* Takes uniform output of 64-bit hash function like sha512 and converts it to `RistrettoPoint`.
|
||||
* The hash-to-group operation applies Elligator twice and adds the results.
|
||||
* **Note:** this is one-way map, there is no conversion from point to hash.
|
||||
* https://ristretto.group/formulas/elligator.html
|
||||
* @param hex 64-bit output of a hash function
|
||||
*/
|
||||
static hashToCurve(hex: Hex): RistrettoPoint {
|
||||
hex = ensureBytes(hex, 64);
|
||||
const r1 = bytes255ToNumberLE(hex.slice(0, 32));
|
||||
const R1 = calcElligatorRistrettoMap(r1);
|
||||
const r2 = bytes255ToNumberLE(hex.slice(32, 64));
|
||||
const R2 = calcElligatorRistrettoMap(r2);
|
||||
return new RistrettoPoint(R1.add(R2));
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts ristretto-encoded string to ristretto point.
|
||||
* https://ristretto.group/formulas/decoding.html
|
||||
* @param hex Ristretto-encoded 32 bytes. Not every 32-byte string is valid ristretto encoding
|
||||
*/
|
||||
static fromHex(hex: Hex): RistrettoPoint {
|
||||
hex = ensureBytes(hex, 32);
|
||||
const { a, d } = ed25519.CURVE;
|
||||
const P = ed25519.CURVE.Fp.ORDER;
|
||||
const mod = ed25519.CURVE.Fp.create;
|
||||
const emsg = 'RistrettoPoint.fromHex: the hex is not valid encoding of RistrettoPoint';
|
||||
const s = bytes255ToNumberLE(hex);
|
||||
// 1. Check that s_bytes is the canonical encoding of a field element, or else abort.
|
||||
// 3. Check that s is non-negative, or else abort
|
||||
if (!equalBytes(numberToBytesLE(s, 32), hex) || isNegativeLE(s, P)) throw new Error(emsg);
|
||||
const s2 = mod(s * s);
|
||||
const u1 = mod(_1n + a * s2); // 4 (a is -1)
|
||||
const u2 = mod(_1n - a * s2); // 5
|
||||
const u1_2 = mod(u1 * u1);
|
||||
const u2_2 = mod(u2 * u2);
|
||||
const v = mod(a * d * u1_2 - u2_2); // 6
|
||||
const { isValid, value: I } = invertSqrt(mod(v * u2_2)); // 7
|
||||
const Dx = mod(I * u2); // 8
|
||||
const Dy = mod(I * Dx * v); // 9
|
||||
let x = mod((s + s) * Dx); // 10
|
||||
if (isNegativeLE(x, P)) x = mod(-x); // 10
|
||||
const y = mod(u1 * Dy); // 11
|
||||
const t = mod(x * y); // 12
|
||||
if (!isValid || isNegativeLE(t, P) || y === _0n) throw new Error(emsg);
|
||||
return new RistrettoPoint(new ed25519.ExtendedPoint(x, y, _1n, t));
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes ristretto point to Uint8Array.
|
||||
* https://ristretto.group/formulas/encoding.html
|
||||
*/
|
||||
toRawBytes(): Uint8Array {
|
||||
let { ex: x, ey: y, ez: z, et: t } = this.ep;
|
||||
const P = ed25519.CURVE.Fp.ORDER;
|
||||
const mod = ed25519.CURVE.Fp.create;
|
||||
const u1 = mod(mod(z + y) * mod(z - y)); // 1
|
||||
const u2 = mod(x * y); // 2
|
||||
// Square root always exists
|
||||
const u2sq = mod(u2 * u2);
|
||||
const { value: invsqrt } = invertSqrt(mod(u1 * u2sq)); // 3
|
||||
const D1 = mod(invsqrt * u1); // 4
|
||||
const D2 = mod(invsqrt * u2); // 5
|
||||
const zInv = mod(D1 * D2 * t); // 6
|
||||
let D: bigint; // 7
|
||||
if (isNegativeLE(t * zInv, P)) {
|
||||
let _x = mod(y * SQRT_M1);
|
||||
let _y = mod(x * SQRT_M1);
|
||||
x = _x;
|
||||
y = _y;
|
||||
D = mod(D1 * INVSQRT_A_MINUS_D);
|
||||
} else {
|
||||
D = D2; // 8
|
||||
}
|
||||
if (isNegativeLE(x * zInv, P)) y = mod(-y); // 9
|
||||
let s = mod((z - y) * D); // 10 (check footer's note, no sqrt(-a))
|
||||
if (isNegativeLE(s, P)) s = mod(-s);
|
||||
return numberToBytesLE(s, 32); // 11
|
||||
}
|
||||
|
||||
toHex(): string {
|
||||
return bytesToHex(this.toRawBytes());
|
||||
}
|
||||
|
||||
toString(): string {
|
||||
return this.toHex();
|
||||
}
|
||||
|
||||
// Compare one point to another.
|
||||
equals(other: RistrettoPoint): boolean {
|
||||
assertRstPoint(other);
|
||||
const { ex: X1, ey: Y1 } = this.ep;
|
||||
const { ex: X2, ey: Y2 } = this.ep;
|
||||
const mod = ed25519.CURVE.Fp.create;
|
||||
// (x1 * y2 == y1 * x2) | (y1 * y2 == x1 * x2)
|
||||
const one = mod(X1 * Y2) === mod(Y1 * X2);
|
||||
const two = mod(Y1 * Y2) === mod(X1 * X2);
|
||||
return one || two;
|
||||
}
|
||||
|
||||
add(other: RistrettoPoint): RistrettoPoint {
|
||||
assertRstPoint(other);
|
||||
return new RistrettoPoint(this.ep.add(other.ep));
|
||||
}
|
||||
|
||||
subtract(other: RistrettoPoint): RistrettoPoint {
|
||||
assertRstPoint(other);
|
||||
return new RistrettoPoint(this.ep.subtract(other.ep));
|
||||
}
|
||||
|
||||
multiply(scalar: bigint): RistrettoPoint {
|
||||
return new RistrettoPoint(this.ep.multiply(scalar));
|
||||
}
|
||||
|
||||
multiplyUnsafe(scalar: bigint): RistrettoPoint {
|
||||
return new RistrettoPoint(this.ep.multiplyUnsafe(scalar));
|
||||
}
|
||||
}
|
||||
241
src/ed448.ts
Normal file
241
src/ed448.ts
Normal file
@@ -0,0 +1,241 @@
|
||||
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
||||
import { shake256 } from '@noble/hashes/sha3';
|
||||
import { concatBytes, randomBytes, utf8ToBytes, wrapConstructor } from '@noble/hashes/utils';
|
||||
import { twistedEdwards } from './abstract/edwards.js';
|
||||
import { mod, pow2, Fp as Field } from './abstract/modular.js';
|
||||
import { montgomery } from './abstract/montgomery.js';
|
||||
import * as htf from './abstract/hash-to-curve.js';
|
||||
|
||||
/**
|
||||
* Edwards448 (not Ed448-Goldilocks) curve with following addons:
|
||||
* * X448 ECDH
|
||||
* Conforms to RFC 8032 https://www.rfc-editor.org/rfc/rfc8032.html#section-5.2
|
||||
*/
|
||||
|
||||
const shake256_114 = wrapConstructor(() => shake256.create({ dkLen: 114 }));
|
||||
const shake256_64 = wrapConstructor(() => shake256.create({ dkLen: 64 }));
|
||||
const ed448P = BigInt(
|
||||
'726838724295606890549323807888004534353641360687318060281490199180612328166730772686396383698676545930088884461843637361053498018365439'
|
||||
);
|
||||
|
||||
// powPminus3div4 calculates z = x^k mod p, where k = (p-3)/4.
|
||||
// Used for efficient square root calculation.
|
||||
// ((P-3)/4).toString(2) would produce bits [223x 1, 0, 222x 1]
|
||||
function ed448_pow_Pminus3div4(x: bigint): bigint {
|
||||
const P = ed448P;
|
||||
// prettier-ignore
|
||||
const _1n = BigInt(1), _2n = BigInt(2), _3n = BigInt(3), _11n = BigInt(11);
|
||||
// prettier-ignore
|
||||
const _22n = BigInt(22), _44n = BigInt(44), _88n = BigInt(88), _223n = BigInt(223);
|
||||
const b2 = (x * x * x) % P;
|
||||
const b3 = (b2 * b2 * x) % P;
|
||||
const b6 = (pow2(b3, _3n, P) * b3) % P;
|
||||
const b9 = (pow2(b6, _3n, P) * b3) % P;
|
||||
const b11 = (pow2(b9, _2n, P) * b2) % P;
|
||||
const b22 = (pow2(b11, _11n, P) * b11) % P;
|
||||
const b44 = (pow2(b22, _22n, P) * b22) % P;
|
||||
const b88 = (pow2(b44, _44n, P) * b44) % P;
|
||||
const b176 = (pow2(b88, _88n, P) * b88) % P;
|
||||
const b220 = (pow2(b176, _44n, P) * b44) % P;
|
||||
const b222 = (pow2(b220, _2n, P) * b2) % P;
|
||||
const b223 = (pow2(b222, _1n, P) * x) % P;
|
||||
return (pow2(b223, _223n, P) * b222) % P;
|
||||
}
|
||||
|
||||
function adjustScalarBytes(bytes: Uint8Array): Uint8Array {
|
||||
// Section 5: Likewise, for X448, set the two least significant bits of the first byte to 0, and the most
|
||||
// significant bit of the last byte to 1.
|
||||
bytes[0] &= 252; // 0b11111100
|
||||
// and the most significant bit of the last byte to 1.
|
||||
bytes[55] |= 128; // 0b10000000
|
||||
// NOTE: is is NOOP for 56 bytes scalars (X25519/X448)
|
||||
bytes[56] = 0; // Byte outside of group (456 buts vs 448 bits)
|
||||
return bytes;
|
||||
}
|
||||
|
||||
const Fp = Field(ed448P, 456, true);
|
||||
|
||||
const ED448_DEF = {
|
||||
// Param: a
|
||||
a: BigInt(1),
|
||||
// -39081. Negative number is P - number
|
||||
d: BigInt(
|
||||
'726838724295606890549323807888004534353641360687318060281490199180612328166730772686396383698676545930088884461843637361053498018326358'
|
||||
),
|
||||
// Finite field 𝔽p over which we'll do calculations; 2n ** 448n - 2n ** 224n - 1n
|
||||
Fp,
|
||||
// Subgroup order: how many points curve has;
|
||||
// 2n**446n - 13818066809895115352007386748515426880336692474882178609894547503885n
|
||||
n: BigInt(
|
||||
'181709681073901722637330951972001133588410340171829515070372549795146003961539585716195755291692375963310293709091662304773755859649779'
|
||||
),
|
||||
nBitLength: 456,
|
||||
// Cofactor
|
||||
h: BigInt(4),
|
||||
// Base point (x, y) aka generator point
|
||||
Gx: BigInt(
|
||||
'224580040295924300187604334099896036246789641632564134246125461686950415467406032909029192869357953282578032075146446173674602635247710'
|
||||
),
|
||||
Gy: BigInt(
|
||||
'298819210078481492676017930443930673437544040154080242095928241372331506189835876003536878655418784733982303233503462500531545062832660'
|
||||
),
|
||||
// SHAKE256(dom4(phflag,context)||x, 114)
|
||||
hash: shake256_114,
|
||||
randomBytes,
|
||||
adjustScalarBytes,
|
||||
// dom4
|
||||
domain: (data: Uint8Array, ctx: Uint8Array, phflag: boolean) => {
|
||||
if (ctx.length > 255) throw new Error(`Context is too big: ${ctx.length}`);
|
||||
return concatBytes(
|
||||
utf8ToBytes('SigEd448'),
|
||||
new Uint8Array([phflag ? 1 : 0, ctx.length]),
|
||||
ctx,
|
||||
data
|
||||
);
|
||||
},
|
||||
|
||||
// Constant-time ratio of u to v. Allows to combine inversion and square root u/√v.
|
||||
// Uses algo from RFC8032 5.1.3.
|
||||
uvRatio: (u: bigint, v: bigint): { isValid: boolean; value: bigint } => {
|
||||
const P = ed448P;
|
||||
// https://datatracker.ietf.org/doc/html/rfc8032#section-5.2.3
|
||||
// To compute the square root of (u/v), the first step is to compute the
|
||||
// candidate root x = (u/v)^((p+1)/4). This can be done using the
|
||||
// following trick, to use a single modular powering for both the
|
||||
// inversion of v and the square root:
|
||||
// x = (u/v)^((p+1)/4) = u³v(u⁵v³)^((p-3)/4) (mod p)
|
||||
const u2v = mod(u * u * v, P); // u²v
|
||||
const u3v = mod(u2v * u, P); // u³v
|
||||
const u5v3 = mod(u3v * u2v * v, P); // u⁵v³
|
||||
const root = ed448_pow_Pminus3div4(u5v3);
|
||||
const x = mod(u3v * root, P);
|
||||
// Verify that root is exists
|
||||
const x2 = mod(x * x, P); // x²
|
||||
// If vx² = u, the recovered x-coordinate is x. Otherwise, no
|
||||
// square root exists, and the decoding fails.
|
||||
return { isValid: mod(x2 * v, P) === u, value: x };
|
||||
},
|
||||
} as const;
|
||||
|
||||
export const ed448 = twistedEdwards(ED448_DEF);
|
||||
// NOTE: there is no ed448ctx, since ed448 supports ctx by default
|
||||
export const ed448ph = twistedEdwards({ ...ED448_DEF, preHash: shake256_64 });
|
||||
|
||||
export const x448 = montgomery({
|
||||
a24: BigInt(39081),
|
||||
montgomeryBits: 448,
|
||||
nByteLength: 57,
|
||||
P: ed448P,
|
||||
Gu: '0500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000',
|
||||
powPminus2: (x: bigint): bigint => {
|
||||
const P = ed448P;
|
||||
const Pminus3div4 = ed448_pow_Pminus3div4(x);
|
||||
const Pminus3 = pow2(Pminus3div4, BigInt(2), P);
|
||||
return mod(Pminus3 * x, P); // Pminus3 * x = Pminus2
|
||||
},
|
||||
adjustScalarBytes,
|
||||
// The 4-isogeny maps between the Montgomery curve and this Edwards
|
||||
// curve are:
|
||||
// (u, v) = (y^2/x^2, (2 - x^2 - y^2)*y/x^3)
|
||||
// (x, y) = (4*v*(u^2 - 1)/(u^4 - 2*u^2 + 4*v^2 + 1),
|
||||
// -(u^5 - 2*u^3 - 4*u*v^2 + u)/
|
||||
// (u^5 - 2*u^2*v^2 - 2*u^3 - 2*v^2 + u))
|
||||
// xyToU: (p: PointType) => {
|
||||
// const P = ed448P;
|
||||
// const { x, y } = p;
|
||||
// if (x === _0n) throw new Error(`Point with x=0 doesn't have mapping`);
|
||||
// const invX = invert(x * x, P); // x^2
|
||||
// const u = mod(y * y * invX, P); // (y^2/x^2)
|
||||
// return numberToBytesLE(u, 56);
|
||||
// },
|
||||
});
|
||||
|
||||
// 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
|
||||
tv1 = Fp.cmov(tv1, Fp.ZERO, e1); // 3. tv1 = CMOV(tv1, 0, e1) # If Z * u^2 == -1, set tv1 = 0
|
||||
let xd = Fp.sub(Fp.ONE, tv1); // 4. xd = 1 - tv1
|
||||
let x1n = Fp.neg(ELL2_J); // 5. x1n = -J
|
||||
let tv2 = Fp.sqr(xd); // 6. tv2 = xd^2
|
||||
let gxd = Fp.mul(tv2, xd); // 7. gxd = tv2 * xd # gxd = xd^3
|
||||
let gx1 = Fp.mul(tv1, Fp.neg(ELL2_J)); // 8. gx1 = -J * tv1 # x1n + J * xd
|
||||
gx1 = Fp.mul(gx1, x1n); // 9. gx1 = gx1 * x1n # x1n^2 + J * x1n * xd
|
||||
gx1 = Fp.add(gx1, tv2); // 10. gx1 = gx1 + tv2 # x1n^2 + J * x1n * xd + xd^2
|
||||
gx1 = Fp.mul(gx1, x1n); // 11. gx1 = gx1 * x1n # x1n^3 + J * x1n^2 * xd + x1n * xd^2
|
||||
let tv3 = Fp.sqr(gxd); // 12. tv3 = gxd^2
|
||||
tv2 = Fp.mul(gx1, gxd); // 13. tv2 = gx1 * gxd # gx1 * gxd
|
||||
tv3 = Fp.mul(tv3, tv2); // 14. tv3 = tv3 * tv2 # gx1 * gxd^3
|
||||
let y1 = Fp.pow(tv3, ELL2_C1); // 15. y1 = tv3^c1 # (gx1 * gxd^3)^((p - 3) / 4)
|
||||
y1 = Fp.mul(y1, tv2); // 16. y1 = y1 * tv2 # gx1 * gxd * (gx1 * gxd^3)^((p - 3) / 4)
|
||||
let x2n = Fp.mul(x1n, Fp.neg(tv1)); // 17. x2n = -tv1 * x1n # x2 = x2n / xd = -1 * u^2 * x1n / xd
|
||||
let y2 = Fp.mul(y1, u); // 18. y2 = y1 * u
|
||||
y2 = Fp.cmov(y2, Fp.ZERO, e1); // 19. y2 = CMOV(y2, 0, e1)
|
||||
tv2 = Fp.sqr(y1); // 20. tv2 = y1^2
|
||||
tv2 = Fp.mul(tv2, gxd); // 21. tv2 = tv2 * gxd
|
||||
let e2 = Fp.eql(tv2, gx1); // 22. e2 = tv2 == gx1
|
||||
let xn = Fp.cmov(x2n, x1n, e2); // 23. xn = CMOV(x2n, x1n, e2) # If e2, x = x1, else x = x2
|
||||
let y = Fp.cmov(y2, y1, e2); // 24. y = CMOV(y2, y1, e2) # If e2, y = y1, else y = y2
|
||||
let e3 = Fp.isOdd(y); // 25. e3 = sgn0(y) == 1 # Fix sign of y
|
||||
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
|
||||
let xd2 = Fp.sqr(xd); // 3. xd2 = xd^2
|
||||
let xd4 = Fp.sqr(xd2); // 4. xd4 = xd2^2
|
||||
let yn2 = Fp.sqr(yn); // 5. yn2 = yn^2
|
||||
let yd2 = Fp.sqr(yd); // 6. yd2 = yd^2
|
||||
let xEn = Fp.sub(xn2, xd2); // 7. xEn = xn2 - xd2
|
||||
let tv2 = Fp.sub(xEn, xd2); // 8. tv2 = xEn - xd2
|
||||
xEn = Fp.mul(xEn, xd2); // 9. xEn = xEn * xd2
|
||||
xEn = Fp.mul(xEn, yd); // 10. xEn = xEn * yd
|
||||
xEn = Fp.mul(xEn, yn); // 11. xEn = xEn * yn
|
||||
xEn = Fp.mul(xEn, 4n); // 12. xEn = xEn * 4
|
||||
tv2 = Fp.mul(tv2, xn2); // 13. tv2 = tv2 * xn2
|
||||
tv2 = Fp.mul(tv2, yd2); // 14. tv2 = tv2 * yd2
|
||||
let tv3 = Fp.mul(yn2, 4n); // 15. tv3 = 4 * yn2
|
||||
let tv1 = Fp.add(tv3, yd2); // 16. tv1 = tv3 + yd2
|
||||
tv1 = Fp.mul(tv1, xd4); // 17. tv1 = tv1 * xd4
|
||||
let xEd = Fp.add(tv1, tv2); // 18. xEd = tv1 + tv2
|
||||
tv2 = Fp.mul(tv2, xn); // 19. tv2 = tv2 * xn
|
||||
let tv4 = Fp.mul(xn, xd4); // 20. tv4 = xn * xd4
|
||||
let yEn = Fp.sub(tv3, yd2); // 21. yEn = tv3 - yd2
|
||||
yEn = Fp.mul(yEn, tv4); // 22. yEn = yEn * tv4
|
||||
yEn = Fp.sub(yEn, tv2); // 23. yEn = yEn - tv2
|
||||
tv1 = Fp.add(xn2, xd2); // 24. tv1 = xn2 + xd2
|
||||
tv1 = Fp.mul(tv1, xd2); // 25. tv1 = tv1 * xd2
|
||||
tv1 = Fp.mul(tv1, xd); // 26. tv1 = tv1 * xd
|
||||
tv1 = Fp.mul(tv1, yn2); // 27. tv1 = tv1 * yn2
|
||||
tv1 = Fp.mul(tv1, BigInt(-2)); // 28. tv1 = -2 * tv1
|
||||
let yEd = Fp.add(tv2, tv1); // 29. yEd = tv2 + tv1
|
||||
tv4 = Fp.mul(tv4, yd2); // 30. tv4 = tv4 * yd2
|
||||
yEd = Fp.add(yEd, tv4); // 31. yEd = yEd + tv4
|
||||
tv1 = Fp.mul(xEd, yEd); // 32. tv1 = xEd * yEd
|
||||
let e = Fp.eql(tv1, Fp.ZERO); // 33. e = tv1 == 0
|
||||
xEn = Fp.cmov(xEn, Fp.ZERO, e); // 34. xEn = CMOV(xEn, 0, e)
|
||||
xEd = Fp.cmov(xEd, Fp.ONE, e); // 35. xEd = CMOV(xEd, 1, e)
|
||||
yEn = Fp.cmov(yEn, Fp.ONE, e); // 36. yEn = CMOV(yEn, 1, e)
|
||||
yEd = Fp.cmov(yEd, Fp.ONE, e); // 37. yEd = CMOV(yEd, 1, e)
|
||||
|
||||
const inv = Fp.invertBatch([xEd, yEd]); // batch division
|
||||
return { x: Fp.mul(xEn, inv[0]), y: Fp.mul(yEn, inv[1]) }; // 38. return (xEn, xEd, yEn, yEd)
|
||||
}
|
||||
|
||||
const { hashToCurve, encodeToCurve } = htf.hashToCurve(
|
||||
ed448.ExtendedPoint,
|
||||
(scalars: bigint[]) => map_to_curve_elligator2_edwards448(scalars[0]),
|
||||
{
|
||||
DST: 'edwards448_XOF:SHAKE256_ELL2_RO_',
|
||||
encodeDST: 'edwards448_XOF:SHAKE256_ELL2_NU_',
|
||||
p: Fp.ORDER,
|
||||
m: 1,
|
||||
k: 224,
|
||||
expand: 'xof',
|
||||
hash: shake256,
|
||||
}
|
||||
);
|
||||
export { hashToCurve, encodeToCurve };
|
||||
1
src/index.ts
Normal file
1
src/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
throw new Error('Incorrect usage. Import submodules instead');
|
||||
58
src/jubjub.ts
Normal file
58
src/jubjub.ts
Normal file
@@ -0,0 +1,58 @@
|
||||
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
||||
import { sha512 } from '@noble/hashes/sha512';
|
||||
import { concatBytes, randomBytes, utf8ToBytes } from '@noble/hashes/utils';
|
||||
import { twistedEdwards } from './abstract/edwards.js';
|
||||
import { blake2s } from '@noble/hashes/blake2s';
|
||||
import { Fp } from './abstract/modular.js';
|
||||
|
||||
/**
|
||||
* jubjub Twisted Edwards curve.
|
||||
* https://neuromancer.sk/std/other/JubJub
|
||||
* jubjub does not use EdDSA, so `hash`/sha512 params are passed because interface expects them.
|
||||
*/
|
||||
|
||||
export const jubjub = twistedEdwards({
|
||||
// Params: a, d
|
||||
a: BigInt('0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000000'),
|
||||
d: BigInt('0x2a9318e74bfa2b48f5fd9207e6bd7fd4292d7f6d37579d2601065fd6d6343eb1'),
|
||||
// Finite field 𝔽p over which we'll do calculations
|
||||
// Same value as bls12-381 Fr (not Fp)
|
||||
Fp: Fp(BigInt('0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001')),
|
||||
// Subgroup order: how many points curve has
|
||||
n: BigInt('0xe7db4ea6533afa906673b0101343b00a6682093ccc81082d0970e5ed6f72cb7'),
|
||||
// Cofactor
|
||||
h: BigInt(8),
|
||||
// Base point (x, y) aka generator point
|
||||
Gx: BigInt('0x11dafe5d23e1218086a365b99fbf3d3be72f6afd7d1f72623e6b071492d1122b'),
|
||||
Gy: BigInt('0x1d523cf1ddab1a1793132e78c866c0c33e26ba5cc220fed7cc3f870e59d292aa'),
|
||||
hash: sha512,
|
||||
randomBytes,
|
||||
} as const);
|
||||
|
||||
const GH_FIRST_BLOCK = utf8ToBytes(
|
||||
'096b36a5804bfacef1691e173c366a47ff5ba84a44f26ddd7e8d9f79d5b42df0'
|
||||
);
|
||||
|
||||
// Returns point at JubJub curve which is prime order and not zero
|
||||
export function groupHash(tag: Uint8Array, personalization: Uint8Array) {
|
||||
const h = blake2s.create({ personalization, dkLen: 32 });
|
||||
h.update(GH_FIRST_BLOCK);
|
||||
h.update(tag);
|
||||
// NOTE: returns ExtendedPoint, in case it will be multiplied later
|
||||
let p = jubjub.ExtendedPoint.fromHex(h.digest());
|
||||
// NOTE: cannot replace with isSmallOrder, returns Point*8
|
||||
p = p.multiply(jubjub.CURVE.h);
|
||||
if (p.equals(jubjub.ExtendedPoint.ZERO)) throw new Error('Point has small order');
|
||||
return p;
|
||||
}
|
||||
|
||||
export function findGroupHash(m: Uint8Array, personalization: Uint8Array) {
|
||||
const tag = concatBytes(m, new Uint8Array([0]));
|
||||
for (let i = 0; i < 256; i++) {
|
||||
tag[tag.length - 1] = i;
|
||||
try {
|
||||
return groupHash(tag, personalization);
|
||||
} catch (e) {}
|
||||
}
|
||||
throw new Error('findGroupHash tag overflow');
|
||||
}
|
||||
146
src/modular.ts
146
src/modular.ts
@@ -1,146 +0,0 @@
|
||||
/*! @noble/curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
||||
const _0n = BigInt(0);
|
||||
const _1n = BigInt(1);
|
||||
const _2n = BigInt(2);
|
||||
const _3n = BigInt(3);
|
||||
const _4n = BigInt(4);
|
||||
const _5n = BigInt(5);
|
||||
const _8n = BigInt(8);
|
||||
|
||||
// Calculates a modulo b
|
||||
export function mod(a: bigint, b: bigint): bigint {
|
||||
const result = a % b;
|
||||
return result >= _0n ? result : b + result;
|
||||
}
|
||||
/**
|
||||
* Efficiently exponentiate num to power and do modular division.
|
||||
* @example
|
||||
* powMod(2n, 6n, 11n) // 64n % 11n == 9n
|
||||
*/
|
||||
export function pow(num: bigint, power: bigint, modulo: bigint): bigint {
|
||||
if (modulo <= _0n || power < _0n) throw new Error('Expected power/modulo > 0');
|
||||
if (modulo === _1n) return _0n;
|
||||
let res = _1n;
|
||||
while (power > _0n) {
|
||||
if (power & _1n) res = (res * num) % modulo;
|
||||
num = (num * num) % modulo;
|
||||
power >>= _1n;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
// Does x ^ (2 ^ power) mod p. pow2(30, 4) == 30 ^ (2 ^ 4)
|
||||
export function pow2(x: bigint, power: bigint, modulo: bigint): bigint {
|
||||
let res = x;
|
||||
while (power-- > _0n) {
|
||||
res *= res;
|
||||
res %= modulo;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
// Inverses number over modulo
|
||||
export function invert(number: bigint, modulo: bigint): bigint {
|
||||
if (number === _0n || modulo <= _0n) {
|
||||
throw new Error(`invert: expected positive integers, got n=${number} mod=${modulo}`);
|
||||
}
|
||||
// Eucledian GCD https://brilliant.org/wiki/extended-euclidean-algorithm/
|
||||
let a = mod(number, modulo);
|
||||
let b = modulo;
|
||||
// prettier-ignore
|
||||
let x = _0n, y = _1n, u = _1n, v = _0n;
|
||||
while (a !== _0n) {
|
||||
const q = b / a;
|
||||
const r = b % a;
|
||||
const m = x - u * q;
|
||||
const n = y - v * q;
|
||||
// prettier-ignore
|
||||
b = a, a = r, x = u, y = v, u = m, v = n;
|
||||
}
|
||||
const gcd = b;
|
||||
if (gcd !== _1n) throw new Error('invert: does not exist');
|
||||
return mod(x, modulo);
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes a list of numbers, efficiently inverts all of them.
|
||||
* @param nums list of bigints
|
||||
* @param p modulo
|
||||
* @returns list of inverted bigints
|
||||
* @example
|
||||
* invertBatch([1n, 2n, 4n], 21n);
|
||||
* // => [1n, 11n, 16n]
|
||||
*/
|
||||
export function invertBatch(nums: bigint[], modulo: bigint): bigint[] {
|
||||
const scratch = new Array(nums.length);
|
||||
// Walk from first to last, multiply them by each other MOD p
|
||||
const lastMultiplied = nums.reduce((acc, num, i) => {
|
||||
if (num === _0n) return acc;
|
||||
scratch[i] = acc;
|
||||
return mod(acc * num, modulo);
|
||||
}, _1n);
|
||||
// Invert last element
|
||||
const inverted = invert(lastMultiplied, modulo);
|
||||
// Walk from last to first, multiply them by inverted each other MOD p
|
||||
nums.reduceRight((acc, num, i) => {
|
||||
if (num === _0n) return acc;
|
||||
scratch[i] = mod(acc * scratch[i], modulo);
|
||||
return mod(acc * num, modulo);
|
||||
}, inverted);
|
||||
return scratch;
|
||||
}
|
||||
|
||||
// Calculates Legendre symbol: num^((P-1)/2)
|
||||
export function legendre(num: bigint, fieldPrime: bigint): bigint {
|
||||
return pow(num, (fieldPrime - _1n) / _2n, fieldPrime);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates square root of a number in a finite field.
|
||||
* Used to calculate y - the square root of y².
|
||||
*/
|
||||
export function sqrt(number: bigint, modulo: bigint): bigint {
|
||||
const n = number;
|
||||
const P = modulo;
|
||||
const p1div4 = (P + _1n) / _4n;
|
||||
|
||||
// P = 3 (mod 4)
|
||||
// sqrt n = n^((P+1)/4)
|
||||
if (P % _4n === _3n) return pow(n, p1div4, P);
|
||||
// P = 5 (mod 8)
|
||||
if (P % _8n === _5n) {
|
||||
const n2 = mod(n * _2n, P);
|
||||
const v = pow(n2, (P - _5n) / _8n, P);
|
||||
const nv = mod(n * v, P);
|
||||
const i = mod(_2n * nv * v, P);
|
||||
const r = mod(nv * (i - _1n), P);
|
||||
return r;
|
||||
}
|
||||
|
||||
// Other cases: Tonelli-Shanks algorithm
|
||||
if (legendre(n, P) !== _1n) throw new Error('Cannot find square root');
|
||||
let q: bigint, s: number, z: bigint;
|
||||
for (q = P - _1n, s = 0; q % _2n === _0n; q /= _2n, s++);
|
||||
if (s === 1) return pow(n, p1div4, P);
|
||||
for (z = _2n; z < P && legendre(z, P) !== P - _1n; z++);
|
||||
|
||||
let c = pow(z, q, P);
|
||||
let r = pow(n, (q + _1n) / _2n, P);
|
||||
let t = pow(n, q, P);
|
||||
|
||||
let t2 = _0n;
|
||||
while (mod(t - _1n, P) !== _0n) {
|
||||
t2 = mod(t * t, P);
|
||||
let i;
|
||||
for (i = 1; i < s; i++) {
|
||||
if (mod(t2 - _1n, P) === _0n) break;
|
||||
t2 = mod(t2 * t2, P);
|
||||
}
|
||||
let b = pow(c, BigInt(1 << (s - i - 1)), P);
|
||||
r = mod(r * b, P);
|
||||
c = mod(b * b, P);
|
||||
t = mod(t * c, P);
|
||||
s = i;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
25
src/p192.ts
Normal file
25
src/p192.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
||||
import { createCurve } from './_shortw_utils.js';
|
||||
import { sha256 } from '@noble/hashes/sha256';
|
||||
import { Fp } from './abstract/modular.js';
|
||||
|
||||
// NIST secp192r1 aka P192
|
||||
// https://www.secg.org/sec2-v2.pdf, https://neuromancer.sk/std/secg/secp192r1
|
||||
export const P192 = createCurve(
|
||||
{
|
||||
// Params: a, b
|
||||
a: BigInt('0xfffffffffffffffffffffffffffffffefffffffffffffffc'),
|
||||
b: BigInt('0x64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1'),
|
||||
// Field over which we'll do calculations; 2n ** 192n - 2n ** 64n - 1n
|
||||
Fp: Fp(BigInt('0xfffffffffffffffffffffffffffffffeffffffffffffffff')),
|
||||
// Curve order, total count of valid points in the field.
|
||||
n: BigInt('0xffffffffffffffffffffffff99def836146bc9b1b4d22831'),
|
||||
// Base point (x, y) aka generator point
|
||||
Gx: BigInt('0x188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012'),
|
||||
Gy: BigInt('0x07192b95ffc8da78631011ed6b24cdd573f977a11e794811'),
|
||||
h: BigInt(1),
|
||||
lowS: false,
|
||||
} as const,
|
||||
sha256
|
||||
);
|
||||
export const secp192r1 = P192;
|
||||
25
src/p224.ts
Normal file
25
src/p224.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
||||
import { createCurve } from './_shortw_utils.js';
|
||||
import { sha224 } from '@noble/hashes/sha256';
|
||||
import { Fp } from './abstract/modular.js';
|
||||
|
||||
// NIST secp224r1 aka P224
|
||||
// https://www.secg.org/sec2-v2.pdf, https://neuromancer.sk/std/nist/P-224
|
||||
export const P224 = createCurve(
|
||||
{
|
||||
// Params: a, b
|
||||
a: BigInt('0xfffffffffffffffffffffffffffffffefffffffffffffffffffffffe'),
|
||||
b: BigInt('0xb4050a850c04b3abf54132565044b0b7d7bfd8ba270b39432355ffb4'),
|
||||
// Field over which we'll do calculations;
|
||||
Fp: Fp(BigInt('0xffffffffffffffffffffffffffffffff000000000000000000000001')),
|
||||
// Curve order, total count of valid points in the field
|
||||
n: BigInt('0xffffffffffffffffffffffffffff16a2e0b8f03e13dd29455c5c2a3d'),
|
||||
// Base point (x, y) aka generator point
|
||||
Gx: BigInt('0xb70e0cbd6bb4bf7f321390b94a03c1d356c21122343280d6115c1d21'),
|
||||
Gy: BigInt('0xbd376388b5f723fb4c22dfe6cd4375a05a07476444d5819985007e34'),
|
||||
h: BigInt(1),
|
||||
lowS: false,
|
||||
} as const,
|
||||
sha224
|
||||
);
|
||||
export const secp224r1 = P224;
|
||||
53
src/p256.ts
Normal file
53
src/p256.ts
Normal file
@@ -0,0 +1,53 @@
|
||||
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
||||
import { createCurve } from './_shortw_utils.js';
|
||||
import { sha256 } from '@noble/hashes/sha256';
|
||||
import { Fp as Field } from './abstract/modular.js';
|
||||
import { mapToCurveSimpleSWU } from './abstract/weierstrass.js';
|
||||
import * as htf from './abstract/hash-to-curve.js';
|
||||
|
||||
// NIST secp256r1 aka P256
|
||||
// https://www.secg.org/sec2-v2.pdf, https://neuromancer.sk/std/nist/P-256
|
||||
|
||||
// Field over which we'll do calculations; 2n**224n * (2n**32n-1n) + 2n**192n + 2n**96n-1n
|
||||
const Fp = Field(BigInt('0xffffffff00000001000000000000000000000000ffffffffffffffffffffffff'));
|
||||
const CURVE_A = Fp.create(BigInt('-3'));
|
||||
const CURVE_B = BigInt('0x5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b');
|
||||
|
||||
const mapSWU = mapToCurveSimpleSWU(Fp, {
|
||||
A: CURVE_A,
|
||||
B: CURVE_B,
|
||||
Z: Fp.create(BigInt('-10')),
|
||||
});
|
||||
|
||||
export const P256 = createCurve(
|
||||
{
|
||||
// Params: a, b
|
||||
a: CURVE_A,
|
||||
b: CURVE_B,
|
||||
Fp,
|
||||
// Curve order, total count of valid points in the field
|
||||
n: BigInt('0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551'),
|
||||
// Base point (x, y) aka generator point
|
||||
Gx: BigInt('0x6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296'),
|
||||
Gy: BigInt('0x4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5'),
|
||||
h: BigInt(1),
|
||||
lowS: false,
|
||||
} as const,
|
||||
sha256
|
||||
);
|
||||
export const secp256r1 = P256;
|
||||
|
||||
const { hashToCurve, encodeToCurve } = htf.hashToCurve(
|
||||
secp256r1.ProjectivePoint,
|
||||
(scalars: bigint[]) => mapSWU(scalars[0]),
|
||||
{
|
||||
DST: 'P256_XMD:SHA-256_SSWU_RO_',
|
||||
encodeDST: 'P256_XMD:SHA-256_SSWU_NU_',
|
||||
p: Fp.ORDER,
|
||||
m: 1,
|
||||
k: 128,
|
||||
expand: 'xmd',
|
||||
hash: sha256,
|
||||
}
|
||||
);
|
||||
export { hashToCurve, encodeToCurve };
|
||||
57
src/p384.ts
Normal file
57
src/p384.ts
Normal file
@@ -0,0 +1,57 @@
|
||||
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
||||
import { createCurve } from './_shortw_utils.js';
|
||||
import { sha384 } from '@noble/hashes/sha512';
|
||||
import { Fp as Field } from './abstract/modular.js';
|
||||
import { mapToCurveSimpleSWU } from './abstract/weierstrass.js';
|
||||
import * as htf from './abstract/hash-to-curve.js';
|
||||
|
||||
// NIST secp384r1 aka P384
|
||||
// https://www.secg.org/sec2-v2.pdf, https://neuromancer.sk/std/nist/P-384
|
||||
|
||||
// Field over which we'll do calculations. 2n**384n - 2n**128n - 2n**96n + 2n**32n - 1n
|
||||
// prettier-ignore
|
||||
const P = BigInt('0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000ffffffff');
|
||||
const Fp = Field(P);
|
||||
const CURVE_A = Fp.create(BigInt('-3'));
|
||||
// prettier-ignore
|
||||
const CURVE_B = BigInt('0xb3312fa7e23ee7e4988e056be3f82d19181d9c6efe8141120314088f5013875ac656398d8a2ed19d2a85c8edd3ec2aef');
|
||||
|
||||
const mapSWU = mapToCurveSimpleSWU(Fp, {
|
||||
A: CURVE_A,
|
||||
B: CURVE_B,
|
||||
Z: Fp.create(BigInt('-12')),
|
||||
});
|
||||
|
||||
// prettier-ignore
|
||||
export const P384 = createCurve({
|
||||
// Params: a, b
|
||||
a: CURVE_A,
|
||||
b: CURVE_B,
|
||||
// Field over which we'll do calculations. 2n**384n - 2n**128n - 2n**96n + 2n**32n - 1n
|
||||
Fp,
|
||||
// Curve order, total count of valid points in the field.
|
||||
n: BigInt('0xffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf581a0db248b0a77aecec196accc52973'),
|
||||
// Base point (x, y) aka generator point
|
||||
Gx: BigInt('0xaa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a385502f25dbf55296c3a545e3872760ab7'),
|
||||
Gy: BigInt('0x3617de4a96262c6f5d9e98bf9292dc29f8f41dbd289a147ce9da3113b5f0b8c00a60b1ce1d7e819d7a431d7c90ea0e5f'),
|
||||
h: BigInt(1),
|
||||
lowS: false,
|
||||
} as const,
|
||||
sha384
|
||||
);
|
||||
export const secp384r1 = P384;
|
||||
|
||||
const { hashToCurve, encodeToCurve } = htf.hashToCurve(
|
||||
secp384r1.ProjectivePoint,
|
||||
(scalars: bigint[]) => mapSWU(scalars[0]),
|
||||
{
|
||||
DST: 'P384_XMD:SHA-384_SSWU_RO_',
|
||||
encodeDST: 'P384_XMD:SHA-384_SSWU_NU_',
|
||||
p: Fp.ORDER,
|
||||
m: 1,
|
||||
k: 192,
|
||||
expand: 'xmd',
|
||||
hash: sha384,
|
||||
}
|
||||
);
|
||||
export { hashToCurve, encodeToCurve };
|
||||
57
src/p521.ts
Normal file
57
src/p521.ts
Normal file
@@ -0,0 +1,57 @@
|
||||
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
||||
import { createCurve } from './_shortw_utils.js';
|
||||
import { sha512 } from '@noble/hashes/sha512';
|
||||
import { Fp as Field } from './abstract/modular.js';
|
||||
import { mapToCurveSimpleSWU } from './abstract/weierstrass.js';
|
||||
import * as htf from './abstract/hash-to-curve.js';
|
||||
|
||||
// NIST secp521r1 aka P521
|
||||
// Note that it's 521, which differs from 512 of its hash function.
|
||||
// https://www.secg.org/sec2-v2.pdf, https://neuromancer.sk/std/nist/P-521
|
||||
|
||||
// Field over which we'll do calculations; 2n**521n - 1n
|
||||
// prettier-ignore
|
||||
const P = BigInt('0x1ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff');
|
||||
const Fp = Field(P);
|
||||
|
||||
const CURVE_A = Fp.create(BigInt('-3'));
|
||||
// prettier-ignore
|
||||
const CURVE_B = BigInt('0x0051953eb9618e1c9a1f929a21a0b68540eea2da725b99b315f3b8b489918ef109e156193951ec7e937b1652c0bd3bb1bf073573df883d2c34f1ef451fd46b503f00');
|
||||
|
||||
const mapSWU = mapToCurveSimpleSWU(Fp, {
|
||||
A: CURVE_A,
|
||||
B: CURVE_B,
|
||||
Z: Fp.create(BigInt('-4')),
|
||||
});
|
||||
|
||||
// prettier-ignore
|
||||
export const P521 = createCurve({
|
||||
// Params: a, b
|
||||
a: CURVE_A,
|
||||
b: CURVE_B,
|
||||
Fp,
|
||||
// Curve order, total count of valid points in the field
|
||||
n: BigInt('0x01fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa51868783bf2f966b7fcc0148f709a5d03bb5c9b8899c47aebb6fb71e91386409'),
|
||||
// Base point (x, y) aka generator point
|
||||
Gx: BigInt('0x00c6858e06b70404e9cd9e3ecb662395b4429c648139053fb521f828af606b4d3dbaa14b5e77efe75928fe1dc127a2ffa8de3348b3c1856a429bf97e7e31c2e5bd66'),
|
||||
Gy: BigInt('0x011839296a789a3bc0045c8a5fb42c7d1bd998f54449579b446817afbd17273e662c97ee72995ef42640c550b9013fad0761353c7086a272c24088be94769fd16650'),
|
||||
h: BigInt(1),
|
||||
lowS: false,
|
||||
allowedPrivateKeyLengths: [130, 131, 132] // P521 keys are variable-length. Normalize to 132b
|
||||
} as const, sha512);
|
||||
export const secp521r1 = P521;
|
||||
|
||||
const { hashToCurve, encodeToCurve } = htf.hashToCurve(
|
||||
secp521r1.ProjectivePoint,
|
||||
(scalars: bigint[]) => mapSWU(scalars[0]),
|
||||
{
|
||||
DST: 'P521_XMD:SHA-512_SSWU_RO_',
|
||||
encodeDST: 'P521_XMD:SHA-512_SSWU_NU_',
|
||||
p: Fp.ORDER,
|
||||
m: 1,
|
||||
k: 256,
|
||||
expand: 'xmd',
|
||||
hash: sha512,
|
||||
}
|
||||
);
|
||||
export { hashToCurve, encodeToCurve };
|
||||
31
src/pasta.ts
Normal file
31
src/pasta.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
||||
import { sha256 } from '@noble/hashes/sha256';
|
||||
import { weierstrass } from './abstract/weierstrass.js';
|
||||
import { getHash } from './_shortw_utils.js';
|
||||
import * as mod from './abstract/modular.js';
|
||||
|
||||
export const p = BigInt('0x40000000000000000000000000000000224698fc094cf91b992d30ed00000001');
|
||||
export const q = BigInt('0x40000000000000000000000000000000224698fc0994a8dd8c46eb2100000001');
|
||||
|
||||
// https://neuromancer.sk/std/other/Pallas
|
||||
export const pallas = weierstrass({
|
||||
a: BigInt(0),
|
||||
b: BigInt(5),
|
||||
Fp: mod.Fp(p),
|
||||
n: q,
|
||||
Gx: mod.mod(BigInt(-1), p),
|
||||
Gy: BigInt(2),
|
||||
h: BigInt(1),
|
||||
...getHash(sha256),
|
||||
});
|
||||
// https://neuromancer.sk/std/other/Vesta
|
||||
export const vesta = weierstrass({
|
||||
a: BigInt(0),
|
||||
b: BigInt(5),
|
||||
Fp: mod.Fp(q),
|
||||
n: p,
|
||||
Gx: mod.mod(BigInt(-1), q),
|
||||
Gy: BigInt(2),
|
||||
h: BigInt(1),
|
||||
...getHash(sha256),
|
||||
});
|
||||
278
src/secp256k1.ts
Normal file
278
src/secp256k1.ts
Normal file
@@ -0,0 +1,278 @@
|
||||
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
||||
import { sha256 } from '@noble/hashes/sha256';
|
||||
import { Fp as Field, mod, pow2 } from './abstract/modular.js';
|
||||
import { createCurve } from './_shortw_utils.js';
|
||||
import { ProjPointType as PointType, mapToCurveSimpleSWU } from './abstract/weierstrass.js';
|
||||
import {
|
||||
ensureBytes,
|
||||
concatBytes,
|
||||
Hex,
|
||||
bytesToNumberBE as bytesToInt,
|
||||
PrivKey,
|
||||
numberToBytesBE,
|
||||
} from './abstract/utils.js';
|
||||
import { randomBytes } from '@noble/hashes/utils';
|
||||
import * as htf from './abstract/hash-to-curve.js';
|
||||
|
||||
/**
|
||||
* secp256k1 belongs to Koblitz curves: it has efficiently computable endomorphism.
|
||||
* Endomorphism uses 2x less RAM, speeds up precomputation by 2x and ECDH / key recovery by 20%.
|
||||
* Should always be used for Projective's double-and-add multiplication.
|
||||
* For affines cached multiplication, it trades off 1/2 init time & 1/3 ram for 20% perf hit.
|
||||
* https://gist.github.com/paulmillr/eb670806793e84df628a7c434a873066
|
||||
*/
|
||||
|
||||
const secp256k1P = BigInt('0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f');
|
||||
const secp256k1N = BigInt('0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141');
|
||||
const _1n = BigInt(1);
|
||||
const _2n = BigInt(2);
|
||||
const divNearest = (a: bigint, b: bigint) => (a + b / _2n) / b;
|
||||
|
||||
/**
|
||||
* √n = n^((p+1)/4) for fields p = 3 mod 4. We unwrap the loop and multiply bit-by-bit.
|
||||
* (P+1n/4n).toString(2) would produce bits [223x 1, 0, 22x 1, 4x 0, 11, 00]
|
||||
*/
|
||||
function sqrtMod(y: bigint): bigint {
|
||||
const P = secp256k1P;
|
||||
// prettier-ignore
|
||||
const _3n = BigInt(3), _6n = BigInt(6), _11n = BigInt(11), _22n = BigInt(22);
|
||||
// prettier-ignore
|
||||
const _23n = BigInt(23), _44n = BigInt(44), _88n = BigInt(88);
|
||||
const b2 = (y * y * y) % P; // x^3, 11
|
||||
const b3 = (b2 * b2 * y) % P; // x^7
|
||||
const b6 = (pow2(b3, _3n, P) * b3) % P;
|
||||
const b9 = (pow2(b6, _3n, P) * b3) % P;
|
||||
const b11 = (pow2(b9, _2n, P) * b2) % P;
|
||||
const b22 = (pow2(b11, _11n, P) * b11) % P;
|
||||
const b44 = (pow2(b22, _22n, P) * b22) % P;
|
||||
const b88 = (pow2(b44, _44n, P) * b44) % P;
|
||||
const b176 = (pow2(b88, _88n, P) * b88) % P;
|
||||
const b220 = (pow2(b176, _44n, P) * b44) % P;
|
||||
const b223 = (pow2(b220, _3n, P) * b3) % P;
|
||||
const t1 = (pow2(b223, _23n, P) * b22) % P;
|
||||
const t2 = (pow2(t1, _6n, P) * b2) % P;
|
||||
const root = pow2(t2, _2n, P);
|
||||
if (!Fp.eql(Fp.sqr(root), y)) throw new Error('Cannot find square root');
|
||||
return root;
|
||||
}
|
||||
|
||||
const Fp = Field(secp256k1P, undefined, undefined, { sqrt: sqrtMod });
|
||||
type Fp = bigint;
|
||||
|
||||
export const secp256k1 = createCurve(
|
||||
{
|
||||
// Params: a, b
|
||||
// Seem to be rigid https://bitcointalk.org/index.php?topic=289795.msg3183975#msg3183975
|
||||
a: BigInt(0),
|
||||
b: BigInt(7),
|
||||
// Field over which we'll do calculations;
|
||||
// 2n**256n - 2n**32n - 2n**9n - 2n**8n - 2n**7n - 2n**6n - 2n**4n - 1n
|
||||
Fp,
|
||||
// Curve order, total count of valid points in the field
|
||||
n: secp256k1N,
|
||||
// Base point (x, y) aka generator point
|
||||
Gx: BigInt('55066263022277343669578718895168534326250603453777594175500187360389116729240'),
|
||||
Gy: BigInt('32670510020758816978083085130507043184471273380659243275938904335757337482424'),
|
||||
h: BigInt(1),
|
||||
// Alllow only low-S signatures by default in sign() and verify()
|
||||
lowS: true,
|
||||
endo: {
|
||||
// Params taken from https://gist.github.com/paulmillr/eb670806793e84df628a7c434a873066
|
||||
beta: BigInt('0x7ae96a2b657c07106e64479eac3434e99cf0497512f58995c1396c28719501ee'),
|
||||
splitScalar: (k: bigint) => {
|
||||
const n = secp256k1N;
|
||||
const a1 = BigInt('0x3086d221a7d46bcde86c90e49284eb15');
|
||||
const b1 = -_1n * BigInt('0xe4437ed6010e88286f547fa90abfe4c3');
|
||||
const a2 = BigInt('0x114ca50f7a8e2f3f657c1108d9d44cfd8');
|
||||
const b2 = a1;
|
||||
const POW_2_128 = BigInt('0x100000000000000000000000000000000'); // (2n**128n).toString(16)
|
||||
|
||||
const c1 = divNearest(b2 * k, n);
|
||||
const c2 = divNearest(-b1 * k, n);
|
||||
let k1 = mod(k - c1 * a1 - c2 * a2, n);
|
||||
let k2 = mod(-c1 * b1 - c2 * b2, n);
|
||||
const k1neg = k1 > POW_2_128;
|
||||
const k2neg = k2 > POW_2_128;
|
||||
if (k1neg) k1 = n - k1;
|
||||
if (k2neg) k2 = n - k2;
|
||||
if (k1 > POW_2_128 || k2 > POW_2_128) {
|
||||
throw new Error('splitScalar: Endomorphism failed, k=' + k);
|
||||
}
|
||||
return { k1neg, k1, k2neg, k2 };
|
||||
},
|
||||
},
|
||||
},
|
||||
sha256
|
||||
);
|
||||
|
||||
// Schnorr signatures are superior to ECDSA from above.
|
||||
// Below is Schnorr-specific code as per BIP0340.
|
||||
// https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki
|
||||
const _0n = BigInt(0);
|
||||
const fe = (x: bigint) => typeof x === 'bigint' && _0n < x && x < secp256k1P;
|
||||
const ge = (x: bigint) => typeof x === 'bigint' && _0n < x && x < secp256k1N;
|
||||
|
||||
const TAGS = {
|
||||
challenge: 'BIP0340/challenge',
|
||||
aux: 'BIP0340/aux',
|
||||
nonce: 'BIP0340/nonce',
|
||||
} as const;
|
||||
|
||||
/** An object mapping tags to their tagged hash prefix of [SHA256(tag) | SHA256(tag)] */
|
||||
const TAGGED_HASH_PREFIXES: { [tag: string]: Uint8Array } = {};
|
||||
function taggedHash(tag: string, ...messages: Uint8Array[]): Uint8Array {
|
||||
let tagP = TAGGED_HASH_PREFIXES[tag];
|
||||
if (tagP === undefined) {
|
||||
const tagH = sha256(Uint8Array.from(tag, (c) => c.charCodeAt(0)));
|
||||
tagP = concatBytes(tagH, tagH);
|
||||
TAGGED_HASH_PREFIXES[tag] = tagP;
|
||||
}
|
||||
return sha256(concatBytes(tagP, ...messages));
|
||||
}
|
||||
|
||||
const pointToBytes = (point: PointType<bigint>) => point.toRawBytes(true).slice(1);
|
||||
const numTo32b = (n: bigint) => numberToBytesBE(n, 32);
|
||||
const modN = (x: bigint) => mod(x, secp256k1N);
|
||||
const Point = secp256k1.ProjectivePoint;
|
||||
const GmulAdd = (Q: PointType<bigint>, a: bigint, b: bigint) =>
|
||||
Point.BASE.multiplyAndAddUnsafe(Q, a, b);
|
||||
const hex32ToInt = (key: Hex) => bytesToInt(ensureBytes(key, 32));
|
||||
function schnorrGetExtPubKey(priv: PrivKey) {
|
||||
let d = typeof priv === 'bigint' ? priv : hex32ToInt(priv);
|
||||
const point = Point.fromPrivateKey(d); // P = d'⋅G; 0 < d' < n check is done inside
|
||||
const scalar = point.hasEvenY() ? d : modN(-d); // d = d' if has_even_y(P), otherwise d = n-d'
|
||||
return { point, scalar, bytes: pointToBytes(point) };
|
||||
}
|
||||
function lift_x(x: bigint): PointType<bigint> {
|
||||
if (!fe(x)) throw new Error('bad x: need 0 < x < p'); // Fail if x ≥ p.
|
||||
const c = mod(x * x * x + BigInt(7), secp256k1P); // Let c = x³ + 7 mod p.
|
||||
let y = sqrtMod(c); // Let y = c^(p+1)/4 mod p.
|
||||
if (y % 2n !== 0n) y = mod(-y, secp256k1P); // Return the unique point P such that x(P) = x and
|
||||
const p = new Point(x, y, _1n); // y(P) = y if y mod 2 = 0 or y(P) = p-y otherwise.
|
||||
p.assertValidity();
|
||||
return p;
|
||||
}
|
||||
function challenge(...args: Uint8Array[]): bigint {
|
||||
return modN(bytesToInt(taggedHash(TAGS.challenge, ...args)));
|
||||
}
|
||||
|
||||
// Schnorr's pubkey is just `x` of Point (BIP340)
|
||||
function schnorrGetPublicKey(privateKey: Hex): Uint8Array {
|
||||
return schnorrGetExtPubKey(privateKey).bytes; // d'=int(sk). Fail if d'=0 or d'≥n. Ret bytes(d'⋅G)
|
||||
}
|
||||
|
||||
// Creates Schnorr signature as per BIP340. Verifies itself before returning anything.
|
||||
// auxRand is optional and is not the sole source of k generation: bad CSPRNG won't be dangerous
|
||||
function schnorrSign(
|
||||
message: Hex,
|
||||
privateKey: PrivKey,
|
||||
auxRand: Hex = randomBytes(32)
|
||||
): Uint8Array {
|
||||
if (message == null) throw new Error(`sign: Expected valid message, not "${message}"`);
|
||||
const m = ensureBytes(message); // checks for isWithinCurveOrder
|
||||
const { bytes: px, scalar: d } = schnorrGetExtPubKey(privateKey);
|
||||
const a = ensureBytes(auxRand, 32); // Auxiliary random data a: a 32-byte array
|
||||
const t = numTo32b(d ^ bytesToInt(taggedHash(TAGS.aux, a))); // Let t be the byte-wise xor of bytes(d) and hash/aux(a)
|
||||
const rand = taggedHash(TAGS.nonce, t, px, m); // Let rand = hash/nonce(t || bytes(P) || m)
|
||||
const k_ = modN(bytesToInt(rand)); // Let k' = int(rand) mod n
|
||||
if (k_ === _0n) throw new Error('sign failed: k is zero'); // Fail if k' = 0.
|
||||
const { point: R, bytes: rx, scalar: k } = schnorrGetExtPubKey(k_); // Let R = k'⋅G.
|
||||
const e = challenge(rx, px, m); // Let e = int(hash/challenge(bytes(R) || bytes(P) || m)) mod n.
|
||||
const sig = new Uint8Array(64); // Let sig = bytes(R) || bytes((k + ed) mod n).
|
||||
sig.set(numTo32b(R.px), 0);
|
||||
sig.set(numTo32b(modN(k + e * d)), 32);
|
||||
// If Verify(bytes(P), m, sig) (see below) returns failure, abort
|
||||
if (!schnorrVerify(sig, m, px)) throw new Error('sign: Invalid signature produced');
|
||||
return sig;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies Schnorr signature synchronously.
|
||||
*/
|
||||
function schnorrVerify(signature: Hex, message: Hex, publicKey: Hex): boolean {
|
||||
try {
|
||||
const P = lift_x(hex32ToInt(publicKey)); // P = lift_x(int(pk)); fail if that fails
|
||||
const sig = ensureBytes(signature, 64);
|
||||
const r = bytesToInt(sig.subarray(0, 32)); // Let r = int(sig[0:32]); fail if r ≥ p.
|
||||
if (!fe(r)) return false;
|
||||
const s = bytesToInt(sig.subarray(32, 64)); // Let s = int(sig[32:64]); fail if s ≥ n.
|
||||
if (!ge(s)) return false;
|
||||
const m = ensureBytes(message);
|
||||
const e = challenge(numTo32b(r), pointToBytes(P), m); // int(challenge(bytes(r)||bytes(P)||m)) mod n
|
||||
const R = GmulAdd(P, s, modN(-e)); // R = s⋅G - e⋅P
|
||||
if (!R || !R.hasEvenY() || R.toAffine().x !== r) return false; // -eP == (n-e)P
|
||||
return true; // Fail if is_infinite(R) / not has_even_y(R) / x(R) ≠ r.
|
||||
} catch (error) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export const schnorr = {
|
||||
getPublicKey: schnorrGetPublicKey,
|
||||
sign: schnorrSign,
|
||||
verify: schnorrVerify,
|
||||
utils: {
|
||||
getExtendedPublicKey: schnorrGetExtPubKey,
|
||||
lift_x,
|
||||
pointToBytes,
|
||||
numberToBytesBE,
|
||||
bytesToNumberBE: bytesToInt,
|
||||
taggedHash,
|
||||
mod,
|
||||
},
|
||||
};
|
||||
|
||||
const isoMap = htf.isogenyMap(
|
||||
Fp,
|
||||
[
|
||||
// xNum
|
||||
[
|
||||
'0x8e38e38e38e38e38e38e38e38e38e38e38e38e38e38e38e38e38e38daaaaa8c7',
|
||||
'0x7d3d4c80bc321d5b9f315cea7fd44c5d595d2fc0bf63b92dfff1044f17c6581',
|
||||
'0x534c328d23f234e6e2a413deca25caece4506144037c40314ecbd0b53d9dd262',
|
||||
'0x8e38e38e38e38e38e38e38e38e38e38e38e38e38e38e38e38e38e38daaaaa88c',
|
||||
],
|
||||
// xDen
|
||||
[
|
||||
'0xd35771193d94918a9ca34ccbb7b640dd86cd409542f8487d9fe6b745781eb49b',
|
||||
'0xedadc6f64383dc1df7c4b2d51b54225406d36b641f5e41bbc52a56612a8c6d14',
|
||||
'0x0000000000000000000000000000000000000000000000000000000000000001', // LAST 1
|
||||
],
|
||||
// yNum
|
||||
[
|
||||
'0x4bda12f684bda12f684bda12f684bda12f684bda12f684bda12f684b8e38e23c',
|
||||
'0xc75e0c32d5cb7c0fa9d0a54b12a0a6d5647ab046d686da6fdffc90fc201d71a3',
|
||||
'0x29a6194691f91a73715209ef6512e576722830a201be2018a765e85a9ecee931',
|
||||
'0x2f684bda12f684bda12f684bda12f684bda12f684bda12f684bda12f38e38d84',
|
||||
],
|
||||
// yDen
|
||||
[
|
||||
'0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffff93b',
|
||||
'0x7a06534bb8bdb49fd5e9e6632722c2989467c1bfc8e8d978dfb425d2685c2573',
|
||||
'0x6484aa716545ca2cf3a70c3fa8fe337e0a3d21162f0d6299a7bf8192bfd2a76f',
|
||||
'0x0000000000000000000000000000000000000000000000000000000000000001', // LAST 1
|
||||
],
|
||||
].map((i) => i.map((j) => BigInt(j))) as [Fp[], Fp[], Fp[], Fp[]]
|
||||
);
|
||||
const mapSWU = mapToCurveSimpleSWU(Fp, {
|
||||
A: BigInt('0x3f8731abdd661adca08a5558f0f5d272e953d363cb6f0e5d405447c01a444533'),
|
||||
B: BigInt('1771'),
|
||||
Z: Fp.create(BigInt('-11')),
|
||||
});
|
||||
const { hashToCurve, encodeToCurve } = htf.hashToCurve(
|
||||
secp256k1.ProjectivePoint,
|
||||
(scalars: bigint[]) => {
|
||||
const { x, y } = mapSWU(Fp.create(scalars[0]));
|
||||
return isoMap(x, y);
|
||||
},
|
||||
{
|
||||
DST: 'secp256k1_XMD:SHA-256_SSWU_RO_',
|
||||
encodeDST: 'secp256k1_XMD:SHA-256_SSWU_NU_',
|
||||
p: Fp.ORDER,
|
||||
m: 1,
|
||||
k: 128,
|
||||
expand: 'xmd',
|
||||
hash: sha256,
|
||||
}
|
||||
);
|
||||
export { hashToCurve, encodeToCurve };
|
||||
1262
src/shortw.ts
1262
src/shortw.ts
File diff suppressed because it is too large
Load Diff
356
src/stark.ts
Normal file
356
src/stark.ts
Normal file
@@ -0,0 +1,356 @@
|
||||
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
||||
import { keccak_256 } from '@noble/hashes/sha3';
|
||||
import { sha256 } from '@noble/hashes/sha256';
|
||||
import { weierstrass, ProjPointType } from './abstract/weierstrass.js';
|
||||
import * as cutils from './abstract/utils.js';
|
||||
import { Fp, mod, Field, validateField } from './abstract/modular.js';
|
||||
import { getHash } from './_shortw_utils.js';
|
||||
import * as poseidon from './abstract/poseidon.js';
|
||||
import { utf8ToBytes } from '@noble/hashes/utils';
|
||||
|
||||
type ProjectivePoint = ProjPointType<bigint>;
|
||||
// Stark-friendly elliptic curve
|
||||
// https://docs.starkware.co/starkex/stark-curve.html
|
||||
|
||||
const CURVE_N = BigInt(
|
||||
'3618502788666131213697322783095070105526743751716087489154079457884512865583'
|
||||
);
|
||||
const nBitLength = 252;
|
||||
// Copy-pasted from weierstrass.ts
|
||||
function bits2int(bytes: Uint8Array): bigint {
|
||||
const delta = bytes.length * 8 - nBitLength;
|
||||
const num = cutils.bytesToNumberBE(bytes);
|
||||
return delta > 0 ? num >> BigInt(delta) : num;
|
||||
}
|
||||
function bits2int_modN(bytes: Uint8Array): bigint {
|
||||
return mod(bits2int(bytes), CURVE_N);
|
||||
}
|
||||
export const starkCurve = weierstrass({
|
||||
// Params: a, b
|
||||
a: BigInt(1),
|
||||
b: BigInt('3141592653589793238462643383279502884197169399375105820974944592307816406665'),
|
||||
// Field over which we'll do calculations; 2n**251n + 17n * 2n**192n + 1n
|
||||
// There is no efficient sqrt for field (P%4==1)
|
||||
Fp: Fp(BigInt('0x800000000000011000000000000000000000000000000000000000000000001')),
|
||||
// Curve order, total count of valid points in the field.
|
||||
n: CURVE_N,
|
||||
nBitLength: nBitLength, // len(bin(N).replace('0b',''))
|
||||
// Base point (x, y) aka generator point
|
||||
Gx: BigInt('874739451078007766457464989774322083649278607533249481151382481072868806602'),
|
||||
Gy: BigInt('152666792071518830868575557812948353041420400780739481342941381225525861407'),
|
||||
h: BigInt(1),
|
||||
// Default options
|
||||
lowS: false,
|
||||
...getHash(sha256),
|
||||
// Custom truncation routines for stark curve
|
||||
bits2int: (bytes: Uint8Array): bigint => {
|
||||
while (bytes[0] === 0) bytes = bytes.subarray(1);
|
||||
return bits2int(bytes);
|
||||
},
|
||||
bits2int_modN: (bytes: Uint8Array): bigint => {
|
||||
let hashS = cutils.bytesToNumberBE(bytes).toString(16);
|
||||
if (hashS.length === 63) {
|
||||
hashS += '0';
|
||||
bytes = hexToBytes0x(hashS);
|
||||
}
|
||||
// Truncate zero bytes on left (compat with elliptic)
|
||||
while (bytes[0] === 0) bytes = bytes.subarray(1);
|
||||
return bits2int_modN(bytes);
|
||||
},
|
||||
});
|
||||
|
||||
// Custom Starknet type conversion functions that can handle 0x and unpadded hex
|
||||
function hexToBytes0x(hex: string): Uint8Array {
|
||||
if (typeof hex !== 'string') {
|
||||
throw new Error('hexToBytes: expected string, got ' + typeof hex);
|
||||
}
|
||||
hex = strip0x(hex);
|
||||
if (hex.length & 1) hex = '0' + hex; // padding
|
||||
if (hex.length % 2) throw new Error('hexToBytes: received invalid unpadded hex ' + hex.length);
|
||||
const array = new Uint8Array(hex.length / 2);
|
||||
for (let i = 0; i < array.length; i++) {
|
||||
const j = i * 2;
|
||||
const hexByte = hex.slice(j, j + 2);
|
||||
const byte = Number.parseInt(hexByte, 16);
|
||||
if (Number.isNaN(byte) || byte < 0) throw new Error('Invalid byte sequence');
|
||||
array[i] = byte;
|
||||
}
|
||||
return array;
|
||||
}
|
||||
function hexToNumber0x(hex: string): bigint {
|
||||
if (typeof hex !== 'string') {
|
||||
throw new Error('hexToNumber: expected string, got ' + typeof hex);
|
||||
}
|
||||
// Big Endian
|
||||
// TODO: strip vs no strip?
|
||||
return BigInt(`0x${strip0x(hex)}`);
|
||||
}
|
||||
function bytesToNumber0x(bytes: Uint8Array): bigint {
|
||||
return hexToNumber0x(cutils.bytesToHex(bytes));
|
||||
}
|
||||
function ensureBytes0x(hex: Hex): Uint8Array {
|
||||
// Uint8Array.from() instead of hash.slice() because node.js Buffer
|
||||
// is instance of Uint8Array, and its slice() creates **mutable** copy
|
||||
return hex instanceof Uint8Array ? Uint8Array.from(hex) : hexToBytes0x(hex);
|
||||
}
|
||||
|
||||
function normalizePrivateKey(privKey: Hex) {
|
||||
return cutils.bytesToHex(ensureBytes0x(privKey)).padStart(64, '0');
|
||||
}
|
||||
function getPublicKey0x(privKey: Hex, isCompressed = false) {
|
||||
return starkCurve.getPublicKey(normalizePrivateKey(privKey), isCompressed);
|
||||
}
|
||||
function getSharedSecret0x(privKeyA: Hex, pubKeyB: Hex) {
|
||||
return starkCurve.getSharedSecret(normalizePrivateKey(privKeyA), pubKeyB);
|
||||
}
|
||||
|
||||
function sign0x(msgHash: Hex, privKey: Hex, opts?: any) {
|
||||
if (typeof privKey === 'string') privKey = strip0x(privKey).padStart(64, '0');
|
||||
return starkCurve.sign(ensureBytes0x(msgHash), normalizePrivateKey(privKey), opts);
|
||||
}
|
||||
function verify0x(signature: Hex, msgHash: Hex, pubKey: Hex) {
|
||||
const sig = signature instanceof Signature ? signature : ensureBytes0x(signature);
|
||||
return starkCurve.verify(sig, ensureBytes0x(msgHash), ensureBytes0x(pubKey));
|
||||
}
|
||||
|
||||
const { CURVE, ProjectivePoint, Signature } = starkCurve;
|
||||
export const utils = starkCurve.utils;
|
||||
export {
|
||||
CURVE,
|
||||
Signature,
|
||||
ProjectivePoint,
|
||||
getPublicKey0x as getPublicKey,
|
||||
getSharedSecret0x as getSharedSecret,
|
||||
sign0x as sign,
|
||||
verify0x as verify,
|
||||
};
|
||||
|
||||
const stripLeadingZeros = (s: string) => s.replace(/^0+/gm, '');
|
||||
export const bytesToHexEth = (uint8a: Uint8Array): string =>
|
||||
`0x${stripLeadingZeros(cutils.bytesToHex(uint8a))}`;
|
||||
export const strip0x = (hex: string) => hex.replace(/^0x/i, '');
|
||||
export const numberToHexEth = (num: bigint | number) => `0x${num.toString(16)}`;
|
||||
|
||||
// We accept hex strings besides Uint8Array for simplicity
|
||||
type Hex = Uint8Array | string;
|
||||
|
||||
// 1. seed generation
|
||||
function hashKeyWithIndex(key: Uint8Array, index: number) {
|
||||
let indexHex = cutils.numberToHexUnpadded(index);
|
||||
if (indexHex.length & 1) indexHex = '0' + indexHex;
|
||||
return sha256Num(cutils.concatBytes(key, hexToBytes0x(indexHex)));
|
||||
}
|
||||
|
||||
export function grindKey(seed: Hex) {
|
||||
const _seed = ensureBytes0x(seed);
|
||||
const sha256mask = 2n ** 256n;
|
||||
|
||||
const limit = sha256mask - mod(sha256mask, CURVE_N);
|
||||
for (let i = 0; ; i++) {
|
||||
const key = hashKeyWithIndex(_seed, i);
|
||||
// key should be in [0, limit)
|
||||
if (key < limit) return mod(key, CURVE_N).toString(16);
|
||||
}
|
||||
}
|
||||
|
||||
export function getStarkKey(privateKey: Hex) {
|
||||
return bytesToHexEth(getPublicKey0x(privateKey, true).slice(1));
|
||||
}
|
||||
|
||||
export function ethSigToPrivate(signature: string) {
|
||||
signature = strip0x(signature.replace(/^0x/, ''));
|
||||
if (signature.length !== 130) throw new Error('Wrong ethereum signature');
|
||||
return grindKey(signature.substring(0, 64));
|
||||
}
|
||||
|
||||
const MASK_31 = 2n ** 31n - 1n;
|
||||
const int31 = (n: bigint) => Number(n & MASK_31);
|
||||
export function getAccountPath(
|
||||
layer: string,
|
||||
application: string,
|
||||
ethereumAddress: string,
|
||||
index: number
|
||||
) {
|
||||
const layerNum = int31(sha256Num(layer));
|
||||
const applicationNum = int31(sha256Num(application));
|
||||
const eth = hexToNumber0x(ethereumAddress);
|
||||
return `m/2645'/${layerNum}'/${applicationNum}'/${int31(eth)}'/${int31(eth >> 31n)}'/${index}`;
|
||||
}
|
||||
|
||||
// https://docs.starkware.co/starkex/pedersen-hash-function.html
|
||||
const PEDERSEN_POINTS_AFFINE = [
|
||||
new ProjectivePoint(
|
||||
2089986280348253421170679821480865132823066470938446095505822317253594081284n,
|
||||
1713931329540660377023406109199410414810705867260802078187082345529207694986n,
|
||||
1n
|
||||
),
|
||||
new ProjectivePoint(
|
||||
996781205833008774514500082376783249102396023663454813447423147977397232763n,
|
||||
1668503676786377725805489344771023921079126552019160156920634619255970485781n,
|
||||
1n
|
||||
),
|
||||
new ProjectivePoint(
|
||||
2251563274489750535117886426533222435294046428347329203627021249169616184184n,
|
||||
1798716007562728905295480679789526322175868328062420237419143593021674992973n,
|
||||
1n
|
||||
),
|
||||
new ProjectivePoint(
|
||||
2138414695194151160943305727036575959195309218611738193261179310511854807447n,
|
||||
113410276730064486255102093846540133784865286929052426931474106396135072156n,
|
||||
1n
|
||||
),
|
||||
new ProjectivePoint(
|
||||
2379962749567351885752724891227938183011949129833673362440656643086021394946n,
|
||||
776496453633298175483985398648758586525933812536653089401905292063708816422n,
|
||||
1n
|
||||
),
|
||||
];
|
||||
// for (const p of PEDERSEN_POINTS) p._setWindowSize(8);
|
||||
const PEDERSEN_POINTS = PEDERSEN_POINTS_AFFINE;
|
||||
|
||||
function pedersenPrecompute(p1: ProjectivePoint, p2: ProjectivePoint): ProjectivePoint[] {
|
||||
const out: ProjectivePoint[] = [];
|
||||
let p = p1;
|
||||
for (let i = 0; i < 248; i++) {
|
||||
out.push(p);
|
||||
p = p.double();
|
||||
}
|
||||
// NOTE: we cannot use wNAF here, because last 4 bits will require full 248 bits multiplication
|
||||
// We can add support for this to wNAF, but it will complicate wNAF.
|
||||
p = p2;
|
||||
for (let i = 0; i < 4; i++) {
|
||||
out.push(p);
|
||||
p = p.double();
|
||||
}
|
||||
return out;
|
||||
}
|
||||
const PEDERSEN_POINTS1 = pedersenPrecompute(PEDERSEN_POINTS[1], PEDERSEN_POINTS[2]);
|
||||
const PEDERSEN_POINTS2 = pedersenPrecompute(PEDERSEN_POINTS[3], PEDERSEN_POINTS[4]);
|
||||
|
||||
type PedersenArg = Hex | bigint | number;
|
||||
function pedersenArg(arg: PedersenArg): bigint {
|
||||
let value: bigint;
|
||||
if (typeof arg === 'bigint') value = arg;
|
||||
else if (typeof arg === 'number') {
|
||||
if (!Number.isSafeInteger(arg)) throw new Error(`Invalid pedersenArg: ${arg}`);
|
||||
value = BigInt(arg);
|
||||
} else value = bytesToNumber0x(ensureBytes0x(arg));
|
||||
// [0..Fp)
|
||||
if (!(0n <= value && value < starkCurve.CURVE.Fp.ORDER))
|
||||
throw new Error(`PedersenArg should be 0 <= value < CURVE.P: ${value}`);
|
||||
return value;
|
||||
}
|
||||
|
||||
function pedersenSingle(point: ProjectivePoint, value: PedersenArg, constants: ProjectivePoint[]) {
|
||||
let x = pedersenArg(value);
|
||||
for (let j = 0; j < 252; j++) {
|
||||
const pt = constants[j];
|
||||
if (pt.px === point.px) throw new Error('Same point');
|
||||
if ((x & 1n) !== 0n) point = point.add(pt);
|
||||
x >>= 1n;
|
||||
}
|
||||
return point;
|
||||
}
|
||||
|
||||
// shift_point + x_low * P_0 + x_high * P1 + y_low * P2 + y_high * P3
|
||||
export function pedersen(x: PedersenArg, y: PedersenArg) {
|
||||
let point: ProjectivePoint = PEDERSEN_POINTS[0];
|
||||
point = pedersenSingle(point, x, PEDERSEN_POINTS1);
|
||||
point = pedersenSingle(point, y, PEDERSEN_POINTS2);
|
||||
return bytesToHexEth(point.toRawBytes(true).slice(1));
|
||||
}
|
||||
|
||||
export function hashChain(data: PedersenArg[], fn = pedersen) {
|
||||
if (!Array.isArray(data) || data.length < 1)
|
||||
throw new Error('data should be array of at least 1 element');
|
||||
if (data.length === 1) return numberToHexEth(pedersenArg(data[0]));
|
||||
return Array.from(data)
|
||||
.reverse()
|
||||
.reduce((acc, i) => fn(i, acc));
|
||||
}
|
||||
// Same as hashChain, but computes hash even for single element and order is not revesed
|
||||
export const computeHashOnElements = (data: PedersenArg[], fn = pedersen) =>
|
||||
[0, ...data, data.length].reduce((x, y) => fn(x, y));
|
||||
|
||||
const MASK_250 = cutils.bitMask(250);
|
||||
export const keccak = (data: Uint8Array): bigint => bytesToNumber0x(keccak_256(data)) & MASK_250;
|
||||
const sha256Num = (data: Uint8Array | string): bigint => cutils.bytesToNumberBE(sha256(data));
|
||||
|
||||
// Poseidon hash
|
||||
export const Fp253 = Fp(
|
||||
BigInt('14474011154664525231415395255581126252639794253786371766033694892385558855681')
|
||||
); // 2^253 + 2^199 + 1
|
||||
export const Fp251 = Fp(
|
||||
BigInt('3618502788666131213697322783095070105623107215331596699973092056135872020481')
|
||||
); // 2^251 + 17 * 2^192 + 1
|
||||
|
||||
function poseidonRoundConstant(Fp: Field<bigint>, name: string, idx: number) {
|
||||
const val = Fp.fromBytes(sha256(utf8ToBytes(`${name}${idx}`)));
|
||||
return Fp.create(val);
|
||||
}
|
||||
|
||||
// NOTE: doesn't check eiginvalues and possible can create unsafe matrix. But any filtration here will break compatibility with starknet
|
||||
// Please use only if you really know what you doing.
|
||||
// https://eprint.iacr.org/2019/458.pdf Section 2.3 (Avoiding Insecure Matrices)
|
||||
export function _poseidonMDS(Fp: Field<bigint>, name: string, m: number, attempt = 0) {
|
||||
const x_values: bigint[] = [];
|
||||
const y_values: bigint[] = [];
|
||||
for (let i = 0; i < m; i++) {
|
||||
x_values.push(poseidonRoundConstant(Fp, `${name}x`, attempt * m + i));
|
||||
y_values.push(poseidonRoundConstant(Fp, `${name}y`, attempt * m + i));
|
||||
}
|
||||
if (new Set([...x_values, ...y_values]).size !== 2 * m)
|
||||
throw new Error('X and Y values are not distinct');
|
||||
return x_values.map((x) => y_values.map((y) => Fp.inv(Fp.sub(x, y))));
|
||||
}
|
||||
|
||||
const MDS_SMALL = [
|
||||
[3, 1, 1],
|
||||
[1, -1, 1],
|
||||
[1, 1, -2],
|
||||
].map((i) => i.map(BigInt));
|
||||
|
||||
export type PoseidonOpts = {
|
||||
Fp: Field<bigint>;
|
||||
rate: number;
|
||||
capacity: number;
|
||||
roundsFull: number;
|
||||
roundsPartial: number;
|
||||
};
|
||||
|
||||
export function poseidonBasic(opts: PoseidonOpts, mds: bigint[][]) {
|
||||
validateField(opts.Fp);
|
||||
if (!Number.isSafeInteger(opts.rate) || !Number.isSafeInteger(opts.capacity))
|
||||
throw new Error(`Wrong poseidon opts: ${opts}`);
|
||||
const m = opts.rate + opts.capacity;
|
||||
const rounds = opts.roundsFull + opts.roundsPartial;
|
||||
const roundConstants = [];
|
||||
for (let i = 0; i < rounds; i++) {
|
||||
const row = [];
|
||||
for (let j = 0; j < m; j++) row.push(poseidonRoundConstant(opts.Fp, 'Hades', m * i + j));
|
||||
roundConstants.push(row);
|
||||
}
|
||||
return poseidon.poseidon({
|
||||
...opts,
|
||||
t: m,
|
||||
sboxPower: 3,
|
||||
reversePartialPowIdx: true, // Why?!
|
||||
mds,
|
||||
roundConstants,
|
||||
});
|
||||
}
|
||||
|
||||
export function poseidonCreate(opts: PoseidonOpts, mdsAttempt = 0) {
|
||||
const m = opts.rate + opts.capacity;
|
||||
if (!Number.isSafeInteger(mdsAttempt)) throw new Error(`Wrong mdsAttempt=${mdsAttempt}`);
|
||||
return poseidonBasic(opts, _poseidonMDS(opts.Fp, 'HadesMDS', m, mdsAttempt));
|
||||
}
|
||||
|
||||
export const poseidonSmall = poseidonBasic(
|
||||
{ Fp: Fp251, rate: 2, capacity: 1, roundsFull: 8, roundsPartial: 83 },
|
||||
MDS_SMALL
|
||||
);
|
||||
|
||||
export function poseidonHash(x: bigint, y: bigint, fn = poseidonSmall) {
|
||||
return fn([x, y, 2n])[0];
|
||||
}
|
||||
69
src/utils.ts
69
src/utils.ts
@@ -1,69 +0,0 @@
|
||||
/*! @noble/curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
||||
// Convert between types
|
||||
// ---------------------
|
||||
|
||||
const hexes = Array.from({ length: 256 }, (v, i) => i.toString(16).padStart(2, '0'));
|
||||
export function bytesToHex(uint8a: Uint8Array): string {
|
||||
if (!(uint8a instanceof Uint8Array)) throw new Error('Expected Uint8Array');
|
||||
// pre-caching improves the speed 6x
|
||||
let hex = '';
|
||||
for (let i = 0; i < uint8a.length; i++) {
|
||||
hex += hexes[uint8a[i]];
|
||||
}
|
||||
return hex;
|
||||
}
|
||||
|
||||
export function numberToHexUnpadded(num: number | bigint): string {
|
||||
const hex = num.toString(16);
|
||||
return hex.length & 1 ? `0${hex}` : hex;
|
||||
}
|
||||
|
||||
export function hexToNumber(hex: string): bigint {
|
||||
if (typeof hex !== 'string') {
|
||||
throw new TypeError('hexToNumber: expected string, got ' + typeof hex);
|
||||
}
|
||||
// Big Endian
|
||||
return BigInt(`0x${hex}`);
|
||||
}
|
||||
|
||||
// Caching slows it down 2-3x
|
||||
export function hexToBytes(hex: string): Uint8Array {
|
||||
if (typeof hex !== 'string') {
|
||||
throw new TypeError('hexToBytes: expected string, got ' + typeof hex);
|
||||
}
|
||||
if (hex.length % 2) throw new Error('hexToBytes: received invalid unpadded hex ' + hex.length);
|
||||
const array = new Uint8Array(hex.length / 2);
|
||||
for (let i = 0; i < array.length; i++) {
|
||||
const j = i * 2;
|
||||
const hexByte = hex.slice(j, j + 2);
|
||||
const byte = Number.parseInt(hexByte, 16);
|
||||
if (Number.isNaN(byte) || byte < 0) throw new Error('Invalid byte sequence');
|
||||
array[i] = byte;
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
// Big Endian
|
||||
export function bytesToNumber(bytes: Uint8Array): bigint {
|
||||
return hexToNumber(bytesToHex(bytes));
|
||||
}
|
||||
|
||||
export function ensureBytes(hex: string | Uint8Array): Uint8Array {
|
||||
// Uint8Array.from() instead of hash.slice() because node.js Buffer
|
||||
// is instance of Uint8Array, and its slice() creates **mutable** copy
|
||||
return hex instanceof Uint8Array ? Uint8Array.from(hex) : hexToBytes(hex);
|
||||
}
|
||||
|
||||
// Copies several Uint8Arrays into one.
|
||||
export function concatBytes(...arrays: Uint8Array[]): Uint8Array {
|
||||
if (!arrays.every((b) => b instanceof Uint8Array)) throw new Error('Uint8Array list expected');
|
||||
if (arrays.length === 1) return arrays[0];
|
||||
const length = arrays.reduce((a, arr) => a + arr.length, 0);
|
||||
const result = new Uint8Array(length);
|
||||
for (let i = 0, pad = 0; i < arrays.length; i++) {
|
||||
const arr = arrays[i];
|
||||
result.set(arr, pad);
|
||||
pad += arr.length;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
679
test/basic.test.js
Normal file
679
test/basic.test.js
Normal file
@@ -0,0 +1,679 @@
|
||||
import { deepStrictEqual, throws } from 'assert';
|
||||
import { should, describe } from 'micro-should';
|
||||
import * as fc from 'fast-check';
|
||||
import * as mod from '../lib/esm/abstract/modular.js';
|
||||
import { bytesToHex as toHex } from '../lib/esm/abstract/utils.js';
|
||||
// Generic tests for all curves in package
|
||||
import { secp192r1 } from '../lib/esm/p192.js';
|
||||
import { secp224r1 } from '../lib/esm/p224.js';
|
||||
import { secp256r1 } from '../lib/esm/p256.js';
|
||||
import { secp384r1 } from '../lib/esm/p384.js';
|
||||
import { secp521r1 } from '../lib/esm/p521.js';
|
||||
import { secp256k1 } from '../lib/esm/secp256k1.js';
|
||||
import { ed25519, ed25519ctx, ed25519ph, x25519 } from '../lib/esm/ed25519.js';
|
||||
import { ed448, ed448ph } from '../lib/esm/ed448.js';
|
||||
import { starkCurve } from '../lib/esm/stark.js';
|
||||
import { pallas, vesta } from '../lib/esm/pasta.js';
|
||||
import { bn254 } from '../lib/esm/bn.js';
|
||||
import { jubjub } from '../lib/esm/jubjub.js';
|
||||
import { bls12_381 } from '../lib/esm/bls12-381.js';
|
||||
|
||||
// Fields tests
|
||||
const FIELDS = {
|
||||
secp192r1: { Fp: [secp192r1.CURVE.Fp] },
|
||||
secp224r1: { Fp: [secp224r1.CURVE.Fp] },
|
||||
secp256r1: { Fp: [secp256r1.CURVE.Fp] },
|
||||
secp521r1: { Fp: [secp521r1.CURVE.Fp] },
|
||||
secp256k1: { Fp: [secp256k1.CURVE.Fp] },
|
||||
stark: { Fp: [starkCurve.CURVE.Fp] },
|
||||
jubjub: { Fp: [jubjub.CURVE.Fp] },
|
||||
ed25519: { Fp: [ed25519.CURVE.Fp] },
|
||||
ed448: { Fp: [ed448.CURVE.Fp] },
|
||||
bn254: { Fp: [bn254.CURVE.Fp] },
|
||||
pallas: { Fp: [pallas.CURVE.Fp] },
|
||||
vesta: { Fp: [vesta.CURVE.Fp] },
|
||||
bls12: {
|
||||
Fp: [bls12_381.CURVE.Fp],
|
||||
Fp2: [
|
||||
bls12_381.CURVE.Fp2,
|
||||
fc.array(fc.bigInt(1n, bls12_381.CURVE.Fp.ORDER - 1n), {
|
||||
minLength: 2,
|
||||
maxLength: 2,
|
||||
}),
|
||||
(Fp2, num) => Fp2.fromBigTuple([num[0], num[1]]),
|
||||
],
|
||||
// Fp6: [bls12_381.CURVE.Fp6],
|
||||
Fp12: [
|
||||
bls12_381.CURVE.Fp12,
|
||||
fc.array(fc.bigInt(1n, bls12_381.CURVE.Fp.ORDER - 1n), {
|
||||
minLength: 12,
|
||||
maxLength: 12,
|
||||
}),
|
||||
(Fp12, num) => Fp12.fromBigTwelve(num),
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
for (const c in FIELDS) {
|
||||
const curve = FIELDS[c];
|
||||
for (const f in curve) {
|
||||
const Fp = curve[f][0];
|
||||
const name = `${c}/${f}:`;
|
||||
const FC_BIGINT = curve[f][1] ? curve[f][1] : fc.bigInt(1n, Fp.ORDER - 1n);
|
||||
|
||||
const create = curve[f][2] ? curve[f][2].bind(null, Fp) : (num) => Fp.create(num);
|
||||
describe(name, () => {
|
||||
should('equality', () => {
|
||||
fc.assert(
|
||||
fc.property(FC_BIGINT, (num) => {
|
||||
const a = create(num);
|
||||
const b = create(num);
|
||||
deepStrictEqual(Fp.eql(a, b), true);
|
||||
deepStrictEqual(Fp.eql(b, a), true);
|
||||
})
|
||||
);
|
||||
});
|
||||
should('non-equality', () => {
|
||||
fc.assert(
|
||||
fc.property(FC_BIGINT, FC_BIGINT, (num1, num2) => {
|
||||
const a = create(num1);
|
||||
const b = create(num2);
|
||||
deepStrictEqual(Fp.eql(a, b), num1 === num2);
|
||||
deepStrictEqual(Fp.eql(b, a), num1 === num2);
|
||||
})
|
||||
);
|
||||
});
|
||||
should('add/subtract/commutativity', () => {
|
||||
fc.assert(
|
||||
fc.property(FC_BIGINT, FC_BIGINT, (num1, num2) => {
|
||||
const a = create(num1);
|
||||
const b = create(num2);
|
||||
deepStrictEqual(Fp.add(a, b), Fp.add(b, a));
|
||||
})
|
||||
);
|
||||
});
|
||||
should('add/subtract/associativity', () => {
|
||||
fc.assert(
|
||||
fc.property(FC_BIGINT, FC_BIGINT, FC_BIGINT, (num1, num2, num3) => {
|
||||
const a = create(num1);
|
||||
const b = create(num2);
|
||||
const c = create(num3);
|
||||
deepStrictEqual(Fp.add(a, Fp.add(b, c)), Fp.add(Fp.add(a, b), c));
|
||||
})
|
||||
);
|
||||
});
|
||||
should('add/subtract/x+0=x', () => {
|
||||
fc.assert(
|
||||
fc.property(FC_BIGINT, (num) => {
|
||||
const a = create(num);
|
||||
deepStrictEqual(Fp.add(a, Fp.ZERO), a);
|
||||
})
|
||||
);
|
||||
});
|
||||
should('add/subtract/x-0=x', () => {
|
||||
fc.assert(
|
||||
fc.property(FC_BIGINT, (num) => {
|
||||
const a = create(num);
|
||||
deepStrictEqual(Fp.sub(a, Fp.ZERO), a);
|
||||
deepStrictEqual(Fp.sub(a, a), Fp.ZERO);
|
||||
})
|
||||
);
|
||||
});
|
||||
should('add/subtract/negate equality', () => {
|
||||
fc.assert(
|
||||
fc.property(FC_BIGINT, (num1) => {
|
||||
const a = create(num1);
|
||||
const b = create(num1);
|
||||
deepStrictEqual(Fp.sub(Fp.ZERO, a), Fp.neg(a));
|
||||
deepStrictEqual(Fp.sub(a, b), Fp.add(a, Fp.neg(b)));
|
||||
deepStrictEqual(Fp.sub(a, b), Fp.add(a, Fp.mul(b, Fp.create(-1n))));
|
||||
})
|
||||
);
|
||||
});
|
||||
should('add/subtract/negate', () => {
|
||||
fc.assert(
|
||||
fc.property(FC_BIGINT, (num) => {
|
||||
const a = create(num);
|
||||
deepStrictEqual(Fp.neg(a), Fp.sub(Fp.ZERO, a));
|
||||
deepStrictEqual(Fp.neg(a), Fp.mul(a, Fp.create(-1n)));
|
||||
})
|
||||
);
|
||||
});
|
||||
should('negate(0)', () => {
|
||||
deepStrictEqual(Fp.neg(Fp.ZERO), Fp.ZERO);
|
||||
});
|
||||
|
||||
should('multiply/commutativity', () => {
|
||||
fc.assert(
|
||||
fc.property(FC_BIGINT, FC_BIGINT, (num1, num2) => {
|
||||
const a = create(num1);
|
||||
const b = create(num2);
|
||||
deepStrictEqual(Fp.mul(a, b), Fp.mul(b, a));
|
||||
})
|
||||
);
|
||||
});
|
||||
should('multiply/associativity', () => {
|
||||
fc.assert(
|
||||
fc.property(FC_BIGINT, FC_BIGINT, FC_BIGINT, (num1, num2, num3) => {
|
||||
const a = create(num1);
|
||||
const b = create(num2);
|
||||
const c = create(num3);
|
||||
deepStrictEqual(Fp.mul(a, Fp.mul(b, c)), Fp.mul(Fp.mul(a, b), c));
|
||||
})
|
||||
);
|
||||
});
|
||||
should('multiply/distributivity', () => {
|
||||
fc.assert(
|
||||
fc.property(FC_BIGINT, FC_BIGINT, FC_BIGINT, (num1, num2, num3) => {
|
||||
const a = create(num1);
|
||||
const b = create(num2);
|
||||
const c = create(num3);
|
||||
deepStrictEqual(Fp.mul(a, Fp.add(b, c)), Fp.add(Fp.mul(b, a), Fp.mul(c, a)));
|
||||
})
|
||||
);
|
||||
});
|
||||
should('multiply/add equality', () => {
|
||||
fc.assert(
|
||||
fc.property(FC_BIGINT, (num) => {
|
||||
const a = create(num);
|
||||
deepStrictEqual(Fp.mul(a, 0n), Fp.ZERO);
|
||||
deepStrictEqual(Fp.mul(a, Fp.ZERO), Fp.ZERO);
|
||||
deepStrictEqual(Fp.mul(a, 1n), a);
|
||||
deepStrictEqual(Fp.mul(a, Fp.ONE), a);
|
||||
deepStrictEqual(Fp.mul(a, 2n), Fp.add(a, a));
|
||||
deepStrictEqual(Fp.mul(a, 3n), Fp.add(Fp.add(a, a), a));
|
||||
deepStrictEqual(Fp.mul(a, 4n), Fp.add(Fp.add(Fp.add(a, a), a), a));
|
||||
})
|
||||
);
|
||||
});
|
||||
should('multiply/square equality', () => {
|
||||
fc.assert(
|
||||
fc.property(FC_BIGINT, (num) => {
|
||||
const a = create(num);
|
||||
deepStrictEqual(Fp.sqr(a), Fp.mul(a, a));
|
||||
})
|
||||
);
|
||||
});
|
||||
should('multiply/pow equality', () => {
|
||||
fc.assert(
|
||||
fc.property(FC_BIGINT, (num) => {
|
||||
const a = create(num);
|
||||
deepStrictEqual(Fp.pow(a, 0n), Fp.ONE);
|
||||
deepStrictEqual(Fp.pow(a, 1n), a);
|
||||
deepStrictEqual(Fp.pow(a, 2n), Fp.mul(a, a));
|
||||
deepStrictEqual(Fp.pow(a, 3n), Fp.mul(Fp.mul(a, a), a));
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
should('square(0)', () => {
|
||||
deepStrictEqual(Fp.sqr(Fp.ZERO), Fp.ZERO);
|
||||
deepStrictEqual(Fp.mul(Fp.ZERO, Fp.ZERO), Fp.ZERO);
|
||||
});
|
||||
|
||||
should('square(1)', () => {
|
||||
deepStrictEqual(Fp.sqr(Fp.ONE), Fp.ONE);
|
||||
deepStrictEqual(Fp.mul(Fp.ONE, Fp.ONE), Fp.ONE);
|
||||
});
|
||||
|
||||
should('square(-1)', () => {
|
||||
const minus1 = Fp.neg(Fp.ONE);
|
||||
deepStrictEqual(Fp.sqr(minus1), Fp.ONE);
|
||||
deepStrictEqual(Fp.mul(minus1, minus1), Fp.ONE);
|
||||
});
|
||||
|
||||
const isSquare = mod.FpIsSquare(Fp);
|
||||
// Not implemented
|
||||
if (Fp !== bls12_381.CURVE.Fp12) {
|
||||
should('multiply/sqrt', () => {
|
||||
fc.assert(
|
||||
fc.property(FC_BIGINT, (num) => {
|
||||
const a = create(num);
|
||||
let root;
|
||||
try {
|
||||
root = Fp.sqrt(a);
|
||||
} catch (e) {
|
||||
deepStrictEqual(isSquare(a), false);
|
||||
return;
|
||||
}
|
||||
deepStrictEqual(isSquare(a), true);
|
||||
deepStrictEqual(Fp.eql(Fp.sqr(root), a), true, 'sqrt(a)^2 == a');
|
||||
deepStrictEqual(Fp.eql(Fp.sqr(Fp.neg(root)), a), true, '(-sqrt(a))^2 == a');
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
should('sqrt(0)', () => {
|
||||
deepStrictEqual(Fp.sqrt(Fp.ZERO), Fp.ZERO);
|
||||
const sqrt1 = Fp.sqrt(Fp.ONE);
|
||||
deepStrictEqual(
|
||||
Fp.eql(sqrt1, Fp.ONE) || Fp.eql(sqrt1, Fp.neg(Fp.ONE)),
|
||||
true,
|
||||
'sqrt(1) = 1 or -1'
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
should('div/division by one equality', () => {
|
||||
fc.assert(
|
||||
fc.property(FC_BIGINT, (num) => {
|
||||
const a = create(num);
|
||||
if (Fp.eql(a, Fp.ZERO)) return; // No division by zero
|
||||
deepStrictEqual(Fp.div(a, Fp.ONE), a);
|
||||
deepStrictEqual(Fp.div(a, a), Fp.ONE);
|
||||
})
|
||||
);
|
||||
});
|
||||
should('zero division equality', () => {
|
||||
fc.assert(
|
||||
fc.property(FC_BIGINT, (num) => {
|
||||
const a = create(num);
|
||||
deepStrictEqual(Fp.div(Fp.ZERO, a), Fp.ZERO);
|
||||
})
|
||||
);
|
||||
});
|
||||
should('div/division distributivity', () => {
|
||||
fc.assert(
|
||||
fc.property(FC_BIGINT, FC_BIGINT, FC_BIGINT, (num1, num2, num3) => {
|
||||
const a = create(num1);
|
||||
const b = create(num2);
|
||||
const c = create(num3);
|
||||
deepStrictEqual(Fp.div(Fp.add(a, b), c), Fp.add(Fp.div(a, c), Fp.div(b, c)));
|
||||
})
|
||||
);
|
||||
});
|
||||
should('div/division and multiplication equality', () => {
|
||||
fc.assert(
|
||||
fc.property(FC_BIGINT, FC_BIGINT, (num1, num2) => {
|
||||
const a = create(num1);
|
||||
const b = create(num2);
|
||||
deepStrictEqual(Fp.div(a, b), Fp.mul(a, Fp.inv(b)));
|
||||
})
|
||||
);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Group tests
|
||||
// prettier-ignore
|
||||
const CURVES = {
|
||||
secp192r1, secp224r1, secp256r1, secp384r1, secp521r1,
|
||||
secp256k1,
|
||||
ed25519, ed25519ctx, ed25519ph,
|
||||
ed448, ed448ph,
|
||||
starkCurve,
|
||||
pallas, vesta,
|
||||
bn254,
|
||||
jubjub,
|
||||
};
|
||||
|
||||
const NUM_RUNS = 5;
|
||||
|
||||
const getXY = (p) => ({ x: p.x, y: p.y });
|
||||
|
||||
function equal(a, b, comment) {
|
||||
deepStrictEqual(a.equals(b), true, `eq(${comment})`);
|
||||
if (a.toAffine && b.toAffine) {
|
||||
deepStrictEqual(getXY(a.toAffine()), getXY(b.toAffine()), `eqToAffine(${comment})`);
|
||||
} else if (!a.toAffine && !b.toAffine) {
|
||||
// Already affine
|
||||
deepStrictEqual(getXY(a), getXY(b), `eqAffine(${comment})`);
|
||||
} else throw new Error('Different point types');
|
||||
}
|
||||
|
||||
for (const name in CURVES) {
|
||||
const C = CURVES[name];
|
||||
const CURVE_ORDER = C.CURVE.n;
|
||||
const FC_BIGINT = fc.bigInt(1n + 1n, CURVE_ORDER - 1n);
|
||||
|
||||
// Check that curve doesn't accept points from other curves
|
||||
const O = name === 'secp256k1' ? secp256r1 : secp256k1;
|
||||
const POINTS = {};
|
||||
const OTHER_POINTS = {};
|
||||
for (const name of ['Point', 'ProjectivePoint', 'ExtendedPoint', 'ProjectivePoint']) {
|
||||
POINTS[name] = C[name];
|
||||
OTHER_POINTS[name] = O[name];
|
||||
}
|
||||
|
||||
for (const pointName in POINTS) {
|
||||
const p = POINTS[pointName];
|
||||
const o = OTHER_POINTS[pointName];
|
||||
if (!p) continue;
|
||||
|
||||
const G = [p.ZERO, p.BASE];
|
||||
for (let i = 2n; i < 10n; i++) G.push(G[1].multiply(i));
|
||||
const title = `${name}/${pointName}`;
|
||||
describe(title, () => {
|
||||
describe('basic group laws', () => {
|
||||
// Here we check basic group laws, to verify that points works as group
|
||||
should('zero', () => {
|
||||
equal(G[0].double(), G[0], '(0*G).double() = 0');
|
||||
equal(G[0].add(G[0]), G[0], '0*G + 0*G = 0');
|
||||
equal(G[0].subtract(G[0]), G[0], '0*G - 0*G = 0');
|
||||
equal(G[0].negate(), G[0], '-0 = 0');
|
||||
for (let i = 0; i < G.length; i++) {
|
||||
const p = G[i];
|
||||
equal(p, p.add(G[0]), `${i}*G + 0 = ${i}*G`);
|
||||
equal(G[0].multiply(BigInt(i + 1)), G[0], `${i + 1}*0 = 0`);
|
||||
}
|
||||
});
|
||||
should('one', () => {
|
||||
equal(G[1].double(), G[2], '(1*G).double() = 2*G');
|
||||
equal(G[1].subtract(G[1]), G[0], '1*G - 1*G = 0');
|
||||
equal(G[1].add(G[1]), G[2], '1*G + 1*G = 2*G');
|
||||
});
|
||||
should('sanity tests', () => {
|
||||
equal(G[2].double(), G[4], '(2*G).double() = 4*G');
|
||||
equal(G[2].add(G[2]), G[4], '2*G + 2*G = 4*G');
|
||||
equal(G[7].add(G[3].negate()), G[4], '7*G - 3*G = 4*G');
|
||||
});
|
||||
should('add commutativity', () => {
|
||||
equal(G[4].add(G[3]), G[3].add(G[4]), '4*G + 3*G = 3*G + 4*G');
|
||||
equal(G[4].add(G[3]), G[3].add(G[2]).add(G[2]), '4*G + 3*G = 3*G + 2*G + 2*G');
|
||||
});
|
||||
should('double', () => {
|
||||
equal(G[3].double(), G[6], '(3*G).double() = 6*G');
|
||||
});
|
||||
should('multiply', () => {
|
||||
equal(G[2].multiply(3n), G[6], '(2*G).multiply(3) = 6*G');
|
||||
});
|
||||
should('add same-point', () => {
|
||||
equal(G[3].add(G[3]), G[6], '3*G + 3*G = 6*G');
|
||||
});
|
||||
should('add same-point negative', () => {
|
||||
equal(G[3].add(G[3].negate()), G[0], '3*G + (- 3*G) = 0*G');
|
||||
equal(G[3].subtract(G[3]), G[0], '3*G - 3*G = 0*G');
|
||||
});
|
||||
should('mul by curve order', () => {
|
||||
equal(G[1].multiply(CURVE_ORDER - 1n).add(G[1]), G[0], '(N-1)*G + G = 0');
|
||||
equal(G[1].multiply(CURVE_ORDER - 1n).add(G[2]), G[1], '(N-1)*G + 2*G = 1*G');
|
||||
equal(G[1].multiply(CURVE_ORDER - 2n).add(G[2]), G[0], '(N-2)*G + 2*G = 0');
|
||||
const half = CURVE_ORDER / 2n;
|
||||
const carry = CURVE_ORDER % 2n === 1n ? G[1] : G[0];
|
||||
equal(G[1].multiply(half).double().add(carry), G[0], '((N/2) * G).double() = 0');
|
||||
});
|
||||
should('inversion', () => {
|
||||
const a = 1234n;
|
||||
const b = 5678n;
|
||||
const c = a * b;
|
||||
equal(G[1].multiply(a).multiply(b), G[1].multiply(c), 'a*b*G = c*G');
|
||||
const inv = mod.invert(b, CURVE_ORDER);
|
||||
equal(G[1].multiply(c).multiply(inv), G[1].multiply(a), 'c*G * (1/b)*G = a*G');
|
||||
});
|
||||
should('multiply, rand', () =>
|
||||
fc.assert(
|
||||
fc.property(FC_BIGINT, FC_BIGINT, (a, b) => {
|
||||
const c = mod.mod(a + b, CURVE_ORDER);
|
||||
if (c === CURVE_ORDER || c < 1n) return;
|
||||
const pA = G[1].multiply(a);
|
||||
const pB = G[1].multiply(b);
|
||||
const pC = G[1].multiply(c);
|
||||
equal(pA.add(pB), pB.add(pA), 'pA + pB = pB + pA');
|
||||
equal(pA.add(pB), pC, 'pA + pB = pC');
|
||||
}),
|
||||
{ numRuns: NUM_RUNS }
|
||||
)
|
||||
);
|
||||
should('multiply2, rand', () =>
|
||||
fc.assert(
|
||||
fc.property(FC_BIGINT, FC_BIGINT, (a, b) => {
|
||||
const c = mod.mod(a * b, CURVE_ORDER);
|
||||
const pA = G[1].multiply(a);
|
||||
const pB = G[1].multiply(b);
|
||||
equal(pA.multiply(b), pB.multiply(a), 'b*pA = a*pB');
|
||||
equal(pA.multiply(b), G[1].multiply(c), 'b*pA = c*G');
|
||||
}),
|
||||
{ numRuns: NUM_RUNS }
|
||||
)
|
||||
);
|
||||
});
|
||||
|
||||
for (const op of ['add', 'subtract']) {
|
||||
describe(op, () => {
|
||||
should('type check', () => {
|
||||
throws(() => G[1][op](0), '0');
|
||||
throws(() => G[1][op](0n), '0n');
|
||||
G[1][op](G[2]);
|
||||
throws(() => G[1][op](CURVE_ORDER), 'CURVE_ORDER');
|
||||
throws(() => G[1][op](-123n), '-123n');
|
||||
throws(() => G[1][op](123), '123');
|
||||
throws(() => G[1][op](123.456), '123.456');
|
||||
throws(() => G[1][op](true), 'true');
|
||||
throws(() => G[1][op](false), 'false');
|
||||
throws(() => G[1][op](null), 'null');
|
||||
throws(() => G[1][op](undefined), 'undefined');
|
||||
throws(() => G[1][op]('1'), "'1'");
|
||||
throws(() => G[1][op]({ x: 1n, y: 1n }), '{ x: 1n, y: 1n }');
|
||||
throws(() => G[1][op]({ x: 1n, y: 1n, z: 1n }), '{ x: 1n, y: 1n, z: 1n }');
|
||||
throws(
|
||||
() => G[1][op]({ x: 1n, y: 1n, z: 1n, t: 1n }),
|
||||
'{ x: 1n, y: 1n, z: 1n, t: 1n }'
|
||||
);
|
||||
throws(() => G[1][op](new Uint8Array([])), 'ui8a([])');
|
||||
throws(() => G[1][op](new Uint8Array([0])), 'ui8a([0])');
|
||||
throws(() => G[1][op](new Uint8Array([1])), 'ui8a([1])');
|
||||
throws(() => G[1][op](new Uint8Array(4096).fill(1)), 'ui8a(4096*[1])');
|
||||
// if (G[1].toAffine) throws(() => G[1][op](C.Point.BASE), `Point ${op} ${pointName}`);
|
||||
throws(() => G[1][op](o.BASE), `${op}/other curve point`);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
should('equals type check', () => {
|
||||
throws(() => G[1].equals(0), '0');
|
||||
throws(() => G[1].equals(0n), '0n');
|
||||
deepStrictEqual(G[1].equals(G[2]), false, '1*G != 2*G');
|
||||
deepStrictEqual(G[1].equals(G[1]), true, '1*G == 1*G');
|
||||
deepStrictEqual(G[2].equals(G[2]), true, '2*G == 2*G');
|
||||
throws(() => G[1].equals(CURVE_ORDER), 'CURVE_ORDER');
|
||||
throws(() => G[1].equals(123.456), '123.456');
|
||||
throws(() => G[1].equals(true), 'true');
|
||||
throws(() => G[1].equals('1'), "'1'");
|
||||
throws(() => G[1].equals({ x: 1n, y: 1n, z: 1n, t: 1n }), '{ x: 1n, y: 1n, z: 1n, t: 1n }');
|
||||
throws(() => G[1].equals(new Uint8Array([])), 'ui8a([])');
|
||||
throws(() => G[1].equals(new Uint8Array([0])), 'ui8a([0])');
|
||||
throws(() => G[1].equals(new Uint8Array([1])), 'ui8a([1])');
|
||||
throws(() => G[1].equals(new Uint8Array(4096).fill(1)), 'ui8a(4096*[1])');
|
||||
// if (G[1].toAffine) throws(() => G[1].equals(C.Point.BASE), 'Point.equals(${pointName})');
|
||||
throws(() => G[1].equals(o.BASE), 'other curve point');
|
||||
});
|
||||
|
||||
for (const op of ['multiply', 'multiplyUnsafe']) {
|
||||
if (!p.BASE[op]) continue;
|
||||
describe(op, () => {
|
||||
should('type check', () => {
|
||||
if (op !== 'multiplyUnsafe') {
|
||||
throws(() => G[1][op](0), '0');
|
||||
throws(() => G[1][op](0n), '0n');
|
||||
}
|
||||
G[1][op](1n);
|
||||
G[1][op](CURVE_ORDER - 1n);
|
||||
throws(() => G[1][op](G[2]), 'G[2]');
|
||||
throws(() => G[1][op](CURVE_ORDER), 'CURVE_ORDER');
|
||||
throws(() => G[1][op](CURVE_ORDER + 1n), 'CURVE_ORDER+1');
|
||||
throws(() => G[1][op](123.456), '123.456');
|
||||
throws(() => G[1][op](true), 'true');
|
||||
throws(() => G[1][op]('1'), '1');
|
||||
throws(() => G[1][op](new Uint8Array([])), 'ui8a([])');
|
||||
throws(() => G[1][op](new Uint8Array([0])), 'ui8a([0])');
|
||||
throws(() => G[1][op](new Uint8Array([1])), 'ui8a([1])');
|
||||
throws(() => G[1][op](new Uint8Array(4096).fill(1)), 'ui8a(4096*[1])');
|
||||
throws(() => G[1][op](o.BASE), 'other curve point');
|
||||
});
|
||||
});
|
||||
}
|
||||
// Complex point (Extended/Jacobian/Projective?)
|
||||
// if (p.BASE.toAffine && C.Point) {
|
||||
// should('toAffine()', () => {
|
||||
// equal(p.ZERO.toAffine(), C.Point.ZERO, '0 = 0');
|
||||
// equal(p.BASE.toAffine(), C.Point.BASE, '1 = 1');
|
||||
// });
|
||||
// }
|
||||
// if (p.fromAffine && C.Point) {
|
||||
// should('fromAffine()', () => {
|
||||
// equal(p.ZERO, p.fromAffine(C.Point.ZERO), '0 = 0');
|
||||
// equal(p.BASE, p.fromAffine(C.Point.BASE), '1 = 1');
|
||||
// });
|
||||
// }
|
||||
// toHex/fromHex (if available)
|
||||
if (p.fromHex && p.BASE.toHex) {
|
||||
should('fromHex(toHex()) roundtrip', () => {
|
||||
fc.assert(
|
||||
fc.property(FC_BIGINT, (x) => {
|
||||
const hex = p.BASE.multiply(x).toHex();
|
||||
deepStrictEqual(p.fromHex(hex).toHex(), hex);
|
||||
})
|
||||
);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
describe(name, () => {
|
||||
// Generic complex things (getPublicKey/sign/verify/getSharedSecret)
|
||||
should('.getPublicKey() type check', () => {
|
||||
throws(() => C.getPublicKey(0), '0');
|
||||
throws(() => C.getPublicKey(0n), '0n');
|
||||
throws(() => C.getPublicKey(-123n), '-123n');
|
||||
throws(() => C.getPublicKey(123), '123');
|
||||
throws(() => C.getPublicKey(123.456), '123.456');
|
||||
throws(() => C.getPublicKey(true), 'true');
|
||||
throws(() => C.getPublicKey(false), 'false');
|
||||
throws(() => C.getPublicKey(null), 'null');
|
||||
throws(() => C.getPublicKey(undefined), 'undefined');
|
||||
throws(() => C.getPublicKey(''), "''");
|
||||
// NOTE: passes because of disabled hex padding checks for starknet, maybe enable?
|
||||
// throws(() => C.getPublicKey('1'), "'1'");
|
||||
throws(() => C.getPublicKey('key'), "'key'");
|
||||
throws(() => C.getPublicKey({}));
|
||||
throws(() => C.getPublicKey(new Uint8Array([])));
|
||||
throws(() => C.getPublicKey(new Uint8Array([0])));
|
||||
throws(() => C.getPublicKey(new Uint8Array([1])));
|
||||
throws(() => C.getPublicKey(new Uint8Array(4096).fill(1)));
|
||||
throws(() => C.getPublicKey(Array(32).fill(1)));
|
||||
});
|
||||
should('.verify() should verify random signatures', () =>
|
||||
fc.assert(
|
||||
fc.property(fc.hexaString({ minLength: 64, maxLength: 64 }), (msg) => {
|
||||
const priv = C.utils.randomPrivateKey();
|
||||
const pub = C.getPublicKey(priv);
|
||||
const sig = C.sign(msg, priv);
|
||||
deepStrictEqual(
|
||||
C.verify(sig, msg, pub),
|
||||
true,
|
||||
'priv=${toHex(priv)},pub=${toHex(pub)},msg=${msg}'
|
||||
);
|
||||
}),
|
||||
{ numRuns: NUM_RUNS }
|
||||
)
|
||||
);
|
||||
should('.verify() should verify empty signatures', () => {
|
||||
const msg = new Uint8Array([]);
|
||||
const priv = C.utils.randomPrivateKey();
|
||||
const pub = C.getPublicKey(priv);
|
||||
const sig = C.sign(msg, priv);
|
||||
deepStrictEqual(
|
||||
C.verify(sig, msg, pub),
|
||||
true,
|
||||
'priv=${toHex(priv)},pub=${toHex(pub)},msg=${msg}'
|
||||
);
|
||||
});
|
||||
should('.sign() edge cases', () => {
|
||||
throws(() => C.sign());
|
||||
throws(() => C.sign(''));
|
||||
throws(() => C.sign('', ''));
|
||||
throws(() => C.sign(new Uint8Array(), new Uint8Array()));
|
||||
});
|
||||
|
||||
describe('verify()', () => {
|
||||
const msg = '01'.repeat(32);
|
||||
should('true for proper signatures', () => {
|
||||
const priv = C.utils.randomPrivateKey();
|
||||
const sig = C.sign(msg, priv);
|
||||
const pub = C.getPublicKey(priv);
|
||||
deepStrictEqual(C.verify(sig, msg, pub), true);
|
||||
});
|
||||
should('false for wrong messages', () => {
|
||||
const priv = C.utils.randomPrivateKey();
|
||||
const sig = C.sign(msg, priv);
|
||||
const pub = C.getPublicKey(priv);
|
||||
deepStrictEqual(C.verify(sig, '11'.repeat(32), pub), false);
|
||||
});
|
||||
should('false for wrong keys', () => {
|
||||
const priv = C.utils.randomPrivateKey();
|
||||
const sig = C.sign(msg, priv);
|
||||
deepStrictEqual(C.verify(sig, msg, C.getPublicKey(C.utils.randomPrivateKey())), false);
|
||||
});
|
||||
});
|
||||
// NOTE: fails for ed, because of empty message. Since we convert it to scalar,
|
||||
// need to check what other implementations do. Empty message != new Uint8Array([0]), but what scalar should be in that case?
|
||||
// should('should not verify signature with wrong message', () => {
|
||||
// fc.assert(
|
||||
// fc.property(
|
||||
// fc.array(fc.integer({ min: 0x00, max: 0xff })),
|
||||
// fc.array(fc.integer({ min: 0x00, max: 0xff })),
|
||||
// (bytes, wrongBytes) => {
|
||||
// const privKey = C.utils.randomPrivateKey();
|
||||
// const message = new Uint8Array(bytes);
|
||||
// const wrongMessage = new Uint8Array(wrongBytes);
|
||||
// const publicKey = C.getPublicKey(privKey);
|
||||
// const signature = C.sign(message, privKey);
|
||||
// deepStrictEqual(
|
||||
// C.verify(signature, wrongMessage, publicKey),
|
||||
// bytes.toString() === wrongBytes.toString()
|
||||
// );
|
||||
// }
|
||||
// ),
|
||||
// { numRuns: NUM_RUNS }
|
||||
// );
|
||||
// });
|
||||
|
||||
if (C.getSharedSecret) {
|
||||
should('getSharedSecret() should be commutative', () => {
|
||||
for (let i = 0; i < NUM_RUNS; i++) {
|
||||
const asec = C.utils.randomPrivateKey();
|
||||
const apub = C.getPublicKey(asec);
|
||||
const bsec = C.utils.randomPrivateKey();
|
||||
const bpub = C.getPublicKey(bsec);
|
||||
try {
|
||||
deepStrictEqual(C.getSharedSecret(asec, bpub), C.getSharedSecret(bsec, apub));
|
||||
} catch (error) {
|
||||
console.error('not commutative', { asec, apub, bsec, bpub });
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
should('secp224k1 sqrt bug', () => {
|
||||
const { Fp } = secp224r1.CURVE;
|
||||
const sqrtMinus1 = Fp.sqrt(-1n);
|
||||
// Verified against sage
|
||||
deepStrictEqual(
|
||||
sqrtMinus1,
|
||||
23621584063597419797792593680131996961517196803742576047493035507225n
|
||||
);
|
||||
deepStrictEqual(
|
||||
Fp.neg(sqrtMinus1),
|
||||
3338362603553219996874421406887633712040719456283732096017030791656n
|
||||
);
|
||||
deepStrictEqual(Fp.sqr(sqrtMinus1), Fp.create(-1n));
|
||||
});
|
||||
|
||||
should('bigInt private keys', () => {
|
||||
// Doesn't support bigints anymore
|
||||
throws(() => ed25519.sign('', 123n));
|
||||
throws(() => ed25519.getPublicKey(123n));
|
||||
throws(() => x25519.getPublicKey(123n));
|
||||
// Weierstrass still supports
|
||||
secp256k1.getPublicKey(123n);
|
||||
secp256k1.sign('', 123n);
|
||||
});
|
||||
|
||||
// ESM is broken.
|
||||
import url from 'url';
|
||||
if (import.meta.url === url.pathToFileURL(process.argv[1]).href) {
|
||||
should.run();
|
||||
}
|
||||
1372
test/bls12-381.test.js
Normal file
1372
test/bls12-381.test.js
Normal file
File diff suppressed because it is too large
Load Diff
559
test/bls12-381/bls12-381-g2-test-vectors.txt
Normal file
559
test/bls12-381/bls12-381-g2-test-vectors.txt
Normal file
@@ -0,0 +1,559 @@
|
||||
db29a6e1db5d6dcb485f26c174d11dd0ab1ecc54125e31dde2949b03e925ef23::8e49a02dc374bb1702ec4c8aa514c6d72e0884d3611334ae749462eb545a4d0a6086ef0a6b1bbc5db2934d297bf766c60dbe665dfc33d3aa765d071712075b4102a71f518e16376fc58c982d30a6196fdd8319090bcb2728c9bbbd8045fc7863
|
||||
28b90deaf189015d3a325908c5e0e4bf00f84f7e639b056ff82d7e70b6eede4c:09:8647aa9680cd0cdf065b94e818ff2bb948cc97838bcee987b9bc1b76d0a0a6e0d85db4e9d75aaedfc79d4ea2733a21ae0579014de7636dd2943d45b87c82b1c66a289006b0b9767921bb8edd3f6c5c5dec0d54cd65f61513113c50cc977849e5
|
||||
177c50ec35b1da25f68b9f7bad8f1c443a01fa2b20de37be0caec8b62db5c902:d2:8166ef48e7c1de5f8256a670511aad114f956382eed36f3bb45a7a1bf473e982f0e399924b4dc92795d043d9475402aa0d065e10f05a2026a0961882b6c2e6c6ae429edd17c7a43586a814121044e41c5c1d3397452b2fc61fdc523cc943ef68
|
||||
e99d0f7a4f8a9e3f74a6bd9677b3fd5be32f7cea4e5b898ed3dea735fa647632:0d98:a70b42352845ca47713a20a243ec2aeb63bab7c4126d9cbd390b6f59372de383b93698c66f7e75452cbc569147b1f9f70be3b03539a4d110c65082f7918942b962543494469a5271208cdec9c234689bcae9c88c7cdc3ef9eefdf11a522794c6
|
||||
2c864f383cd664839ce6d7d049f8083870b628d7bb8a4539cc84a35bbd723736:4a35:88c76ed5872fb011f4fc0fc8ff2751513dd6f22a9b7cb125ed39bdfffdd996ba1b5d9ea6332e8b4c34e591cb9dcf4efe112a096754db0d723269bb1a758f986d5e0cfbdcc22f8678f72f1804459c98be59ee7632c666206255dcaa816188cf2b
|
||||
cd8ccf5c229e37a4a4b5490c84882af890cdc4c70170ad5f0ee2f3a86ffa3080:05caf3:83b4087858c3585a2f978fe1c79b94d9eb927500066e6c793392f1d5be2eff1ebfdd893555f6a89934f4e27ec810489a07f0740124c065fb82246a6d6f924f70069edfaf04fc4d1021f3314b9d09dfadc344fd2dcafaeb09586b194b3ea73374
|
||||
43a5b55a3823acebca9e55face42697b5cd0e2398a44a56ebc22d936a05c3893:94b0b9:8b4f817e0815a9ca1fb91a5fd9e88714d72c2d6b4ea037ab43cde4149691109336edca72fb55936b5ba8f4576ffd49780dde24d48f9a9d5a07d1527ac3a9bc38c05a0fc58bac710cd4983c6cd21e56175a6e597954ac68207db1a8b86efe84cf
|
||||
e2654a38c0148b5f0de1b8266737fdb6706fedc436d5fb70dc34bebe25b43d01:06a63bfb:b4a224ac879b67d20f452c40adac0b993560842e4dce928ace30751bc38d2a3a46e1f84dd1c04c0417ebaf069f5618f210c0dce7ae478f83a664f231e141b3fc677842bae20df43409476dde8c6a81cd1067999e6fae2896afe9630bc7441d3a
|
||||
736057053101fbb9240808bfe83121382a8cd559a97f8633ae170b3e1ac9efee:0d83b078:b028a3c5877113519d0da87fd67edebcb80b37869f58505997c459fad745194407e004503fb49f4d9e0ea289d5cd9c63151c2d40e09cd3988cf7b0191718d4f4d07fa149c965fdc4a25fece97efd72fb9337099b5f47979c6acb9b30f0c2fbe3
|
||||
dc7f613ec82e641c58d8390963ccb4cd307da37417aca9eec15b060fccdf73f3:0611983835:b4d7a115e96b4da4616b54bff471d5a9f7002100b61214337662f0aabf08a45ecdcdb581325cba3b5141a4083c301dcc10eeac2da4cd430ab1882e44cec5f8f08a789eb670653ab8072795e3d5724405bb6ffebde2e73229b353b17119f46e9c
|
||||
ba4eeeefe05a4515509d64f21639c24dde05122815a9d89f1d8d31ba90f7e7aa:64726e3da8:8d6d9d1ee5febfb549e1f7a2f3e69f01918fc105ea710bae881b60fec8dcdbbb2ae3e00249d5b82eb4c598f557c139e00bcc5dd098afc74303a54937a81e98b4d2e75ee792021200f291918980ea274ef8ea2d712e265089230042348dd4b872
|
||||
5737b8adab24e7ec10fdd0a420c603392cb2c43f6466d6033eb14d1012470dbb:07d6e7a31a2f:99d2bc134b268397759e77b7f59c26862264454a659b90664cd7ff9fd5701b083ef6aee3df959643816958515059e42205abf0c959ea64910c3bdbb447a1afca4caf271f7dbd50085d886c2e3f5294167ea3631767acfee5d89cb6e04def2dd8
|
||||
ecca05ab2c52c1b4861357c01d628a8a7b0ca0b6c72219cf47822e72858752bc:aa07552a7358:9023090506aa3ec0b14b0650d302baa54976e26104d011f3e131a066f3f7dacbd8831e4bcefe5702e4c83323e4e6f7700b343a29e7d4cb7277712c59e83fe6ee788967c4721f783b81024c8317b4042e0f4fad3c41fd861b6050654bc529af70
|
||||
b54f380ef6485006e52c279335e9aeb7adcf1dd24b02f6be0a25b6d0a70627b0:04583025f1b7da:897da4929a4ed71b70ba65e68f39f6f7967dbecbb97b610bd3ab23f6a08906ca44661523212a598f9a1e12e128c184440d1a56c2b64260c871e25ae5135b53944f7820aa74d20d48d90976cf60090427a442fa61e20f45ec6d0f348f6684fd32
|
||||
7865bb94878bac2960a60393588ce3c0e92d6d8eda6c4ac2da5fd4d2fbffa48f:9398f8937e1821:b8d60310a2c5cc322ed412f340c3fc05723c446c47cc529f7e914916a5cb7d78e8af8400a6d07d62bc280daca12988cb1073a88ea7b4aa2dff821ae011342aa8a8de691ddd370a8ba942fd5cc6892acec84db889f6421bb1d71f02f5b7830a0a
|
||||
97ec105f9f2487fa4b360eb484c4398add4c1fe8e274853e530292290e9b7a59:00dd6efc58fcd4ee:86c7fd60798ddc58d59de487a1ac4221e61efe70c188e78ac50b4d89ea022b592e472895595aa4725c9be82770cc05050fb0feacd6e1a3c062dfed9e6e63ae58838025cae35dcd8b1eaa90a3714e800b2cd0740d7262119e7abec3b5822d4497
|
||||
8e9b0e1280b0433182df7eca995a7279e704f728a88ad0b26518ed0a19f62113:1b3d4c68e007f478:ab1832ae67d695f941decf959ebbce93bb33e70d60dfb53321f582f81be7d4177d0aef680c56a587e905c051355a78ad14574e0adcb083e2d6c972dbc54b68290abfc8c7abb9472ee210078eb62a3148764defb967768ab5be36d36c5aaf6455
|
||||
281c1297034c8aaa2ea6368dd038833429673b99dd4da4622908de8d9674f99d:033d69a90f6073fceb:8bd05333f0d076558b8a25a75b76b14af7454f69452918d363a905a49089663e23c0ede69b4882790178a02ff83b8a3d0c945e6ce0e18c5c3abfb22c32e2bee71145fd319f4daef46463471df9691a372a8f30427c427fb025155109269ef363
|
||||
6fbbae45973a06226abf29b6d978429cc2775b4af6c736f6fa1eecb042c3b089:b28bfd61695d25590c:90f9298f281b350add0e8b1789e99d38a42021ea971d1a0b1a28f8d11906602bd0a22eeee4b149443541f149721a926b0ddd2a496a88ac47a9f59e0a80aa91f88baa129035d2f2d38028ab024ac38ec0ae1768c1bcd156c2349a26e01b94a516
|
||||
91a60d4b2440622e10f5ba7dc9585894b2125980fd5072cec4bbcd47ea49c57a:00581bba4bc7f26227a7:a95a631b6ea74646d9659f0d27a1e8c877e4018d47f81a32d0d0b203a724b980597880a84cdbe88cf41be05a58101e7a11b6de7b9bf7433e6c947e571b595b4496fff37f8a48d3eccab904ee824b31dd984c3f6c2a19acb52e895f1e326e788e
|
||||
b211045d27b3c191a7961f521dedbb6ac8f6a362ab19ec28969d583c9a2eb128:e02c048d0609137492b9:a1e3e50c7a70c9d1028996c5bc79343c5780b16310a8b930704d3107e93bc92f7b927393fcf55d64461369f95aff557d0f346db8d83d02f0d914b50b706908cb631114c279be622bbc801bf5bd93245827a3c7ac06a30fa88e579ba2c5adbf99
|
||||
342fb513e70e2a7cdee072a9d8c1cfc86aa9691687dbef91fca2d15870e4adaa:011ddb2e7d45df2e05fb8a:96324a72624c99ae74fc334cb8fe70885d7e9c840e4608e5b19a8a5ef8fe68277e7cac7c4b6889e206f6244dc49fc19a0a3ac2992e51d0f0076a528fa6c11afb4a3f127286714c1548a3c4c9eac7e67eb32bcd2c480e2c7d36504a5fa52d6ea1
|
||||
498f8139fa03ac326e5ff321a9c8083d22eb048de74fcec128de3621a1dd5675:64024e14b436cb94e3209c:8723e4effda2455dd5d552bcf6116f88dd70187b031edb7660fa673ce22bd0fbe9ccaf28be6d9c78b783fa6310a0fda00b29cbce1adcef4204d31694bb47cc84de102d2dfab833e907887bcc8371119244b5b69b791c9dcd667e899971a37295
|
||||
e5bcc31a88b1d23772bb5a282b8d8f7c0dd645b45b940027c1111ee13e62cfdf:00ca1d50caa232ab9ad64644:ab1e90fecee91a4c12537041281e91190e8bba02d503c491da48ab7b2fc9af11b01b168c83154c04f59c3e6d815665d6120d2547f7fba57d43ad9993c99e54c0b5488166c41416e29e9588d6b7e6d67c7d93c9be7ba3c7d769e0ccedec71b3a4
|
||||
e5bfacb0667cd3db0634fd1eaa35b362d827a205db6cdce6daecbd83413ac6cf:3f1e6ffc1d7ec3e890d52615:ac3dcdb2751d982d80b77a749cf2f1f698f4dee8c9007043766c602104cbb0f633a4ce437098775062bf64aff77b2d66071dbc770e6ea04b11809f24ef50e6ec3ae5a58d58896bf9e78de80194eb67ce0d44e0232014ec300b63f90ef5c335bb
|
||||
055873520343a11f937aa23abfdfee0d1929c461bd2fcfc85d8d07ef44230c69:04f00076b77983d6ee7ab6979d:afd0d6908f62ce579dde390b463d535dcfd1f5ee6664d46a583952c50178a61f15cf072153a21b4e6044dece53a755b1025170d84046c57252ea6c0a9c45ca42b0c77544e80856634e552c1e2b86eabf1f92535e1b27ea43281f8dc3a8672211
|
||||
d58dd7364d214cd9ca9a5188ff8ad95486f65bf642d857c902fc6fd32a843510:49c83ddfa5b465abca1a8b5c78:a087f6bb963265cb95ff4914d4bae832a4fc89ff0616bcd8a529badca39a2c85b0ff3e1c418ec7979bcaf93a6d3dfc35108c420956c0795bdd81d2ce6f53a2f0a0bc37876db80bd0b59ce2210404a5c84d16330621aaaaad718e518dff1ef3cb
|
||||
13ed1173e146edb9ae6a77e289155354d6e0107aa2fcd4dc89441619553448a3:07c50e920e060f06243084d32afe:a89faa2c99e76386d80f709e1af822e830385d07b0cc4bf8b46315273f0b11c9f77845e431d5bbb86d07e4b0e15c66bb1958e8d0728a0a0961e5f233fcba72278f5b0ffbbd67fbf62aa7b7a1572d9dababed755a60d37906dc30bdfc3d9d4c2e
|
||||
5c3f7aef904cd9aa5cf093f993f49d46c3f20b7450552d52b23569239849f31b:6f455d61ee48d1990ec61dd70dbd:aaede5d58e5c71c170b2fbff350cb596bf43f2d0ee6b0e83f8863350ea4fd756129150e856c83e45734db8649a3617150c4a7a37ec596d89ff6cc6749dbe6d54f41cb36662279b3a82335e3f4b946afd94740e3214e93a45643bbabdac93a25c
|
||||
00cc17223e74b58d2e465bad2f5d0ecc5a85081d143fc4b8ab8eb10b44c6c45f:0800350f624966388e327b17cbb9fa:8333c0c7d9da5f79c67ed5fd13d92bbc91c5680837cd0cf816f2876106720a93323477ba28dbce0f554ffc0f37db9fc20386aa12d005be7a2ce5a660ef8ff46c7381bd0446cabcc4a3f4b8b75b9608615ab2497beb425415c778c278f38a6d81
|
||||
21fa64295c0fc47d81f69ba31d4661604c4d9eae6d2077c094ff758b1757e3c1::845c89e3bc5350275cc5b2669bda8ae127b8bf731517bb1bd5ebf0670add6df037f6b8c382aa03f729c5e8049e817dab0cc310e8af80d78cff447f034d32e7e7a1e8f27c8df390c5b640a7e341d6ab94311c4ae35a754f3990371c9186f97f0e
|
||||
dd7466232c0fc5581e319721d4e0c7b773417432b0a0b756c3dc4e5cdff4723b:06:95f8a6c56e2de4742144e2213e13411f1a2d03ca783e509353276292fc97e087062b3050e967593e569e6ef80741adae0c5a7ab5bf0b0f0e7cd92d5e17181176ec2fe111e8306b9643901e228f0187bc9d429ca8cbd23a39be4bbb99bf29d84b
|
||||
fe7eab6ef7c43c8ced6e9b7524667c79f129eda2e8585328fde3b18b4eedddab:57:ae257f78c59769a67de12fab413c4ec6a6668eedf45c4bf6d5928f05acfa77cb12caf36fa9e42830519dbf816655fbd012472d84bab2d4f8c99d684f9652675493a4436258a881f0e9e27558f5125f614e38835a87ee0ee61dd7a946a3b13996
|
||||
93cc9ed7f1507a817608255cd036d6b1d10a974e7547d7100be15f70702e3e4b:0b76:8792277cf0d7d0318174e23356cd311a737169b08f52c65fc8ce7af4fc3cbc5ad75223d15f43a2caa3862c6b4ab39c140f2571804296c90f27f5ebdec3f135fc458cb1a441c4dcf4953273cc77947d604ceca8c10dda4f68874716f2684cd52f
|
||||
9f388e9e5e98b2cdbb28cfa3011be14cd658d0395d7c737ccc50679dce316d88:0c5f:959299104d5905f91d081e1ddeeb1ef4dec0013d3f961daa4e38db5367ad81acb657021dd540d96920188f1f1ad4ba39163fc9575652c3cf3bde0bd7533a505a7282777fbbae405e0f967806b4e903b9134ccd5fb5d090ea66ff26c69a1f5aff
|
||||
ff060b6cfcee3546fcaa93c4867bf97e56099949a3eadb4c4011ca544000c1b6:0f5459:8b694a9f0b96aef6766ec5d4f471ada3810d30fbd84fd12aec8a9b579568b27a4b21794e7c545f3f9d86603a51fed940007bd3fae9bc793b47e1c5ba2d18e7b39f75d52b0722dc60d537a9c437b28d766cc39cc7a2c0747fc4af09d4adb208aa
|
||||
8d750998b2143613209a3284da5d9bb2d63c5b7504f0ded55cba58d99902ba68:d626a5:8ab12e4ebbebbc60760f61eed87a65fc221abb342fe3909483db1dffe132ab2cd208568955821e7167f29bd2fed824f309904e2e77577ca6cb8a59e16077cd2847985a083838af48b0820336cea6011c6a7dbdea166fc3a733a8941ab53bf3f3
|
||||
4f35aaddd4587dcde04341ecfdb62636fb140bd363738c9dd8f53b45fe740d09:07d29e93:a20dc2b369dcf1f609e24f795ded8d606bd5931a2f3e8e045840eae489da759f4e00a036ac2eb678c61fab587dccb55f164241799be62a63958df72533fdac653fe23983ece98119991c3a7e7910d9f837ffb3b0579c326fb46a5c3b55527a09
|
||||
a81a2a4d890e39dc2ca7720ed6c301b1ee0addfc6a609d3282cfba541ac9639a:6f3b5edc:8c32cc120080a1b17b342e64bfecd79b45fcbe71a27cd1037135eb8b97326f971b89d84c03dddfe01249e5ac3472487915d7055b6b4f06177dfc5e66c88c2bd7c8929153c335e0afd0f230a97cbeeda238df6a31825649f46bfed3985bdd6180
|
||||
275d76e250f6f44585d23c95f9984ffe762afb7bec52906657ad4ffdbf264e7d:050c5aff03:85ca53a9b9ac376b09c3538f40ea50cd0ab4b16b205fd434befc6aece17e807204ef8333a63522a1df41b4c8f38a3d3c086565227513ffa50e31d3bcc9870f693d9527d10e9c26386dafd48cd8bca9e39363ec220e1196edd636fd2248ad113a
|
||||
7e363965c6d3a02c07f5b33b37617dc2b2843bec249968a7958ad55fa64fc0be:ea1a2c2541:ac3dd4ca0e6b6310217f163d5c5dbd771228febc96aeeef31bfb605431d1a23e37297bcdf5f684a2936980213497d561081c38a01c273dc0f53a1b50bf561e9fc2c7f5e0d55ce7537ce995addb6b20caa30e3840952a5f14aff90731c0d7612f
|
||||
697ef015b81f5a3c31ba3ba4482b1182f2a106aba7bd94948a073861297e9c4b:0caf34f67e39:a5aa61367ef1f50257c1614863c9a41f493e01487e522bd83fffa8c2d7eac5656ab355db421e4a3e9c6a325e8fa8ae4e05875a490b3baec6529799c8f65efd7526aa7e9fd33ebb1e7506ed36012b35ffbabddaa63748cbed227bebc2738eb647
|
||||
986e36b32e2a4cb454eb84c8e135b1568488d57ad35d5c2e8793572bdf5643ae:bb586523bbe7:af3d68b8da23dd29ee307bec34839ba5117477178ed2d752339dee1e5dd93199bd4c05680400cbf6b8553db1bb3e0f280aabc043eefad31d7c575947ae78fc4dc672374e1a8cc5cc04ffc63d0b1a53f4fe8b39cdc3c111085cea5f8456121842
|
||||
f0b6be124d8f563ef3411d87a7c42796a5675d4da1e4875d25b523aa772d48ca:00377779a4f4b7:85088daf12e34adf4f2f108c12b9c20a938df6923d3a1b94feb2e38a1eae6dbdcaf48e464936583ecfa12c45c116ba79001aa41ff2aeb628659cc0f70db863a9820b81594ac4f6051d64b5bcf9c6aa78fc5c81382884783718571d08680f5209
|
||||
daddd3b1096023b2435a20a435aa827b80c8978f827dd1d845078b5c197c769e:8c7f2a39715ef4:a61be5df8d598c6ff2785fbb9bef821a688b7b79b429a1897d4ac3db02705572694305a423bf2621a866cf7a985f810011201783f6154c4108b85234e2ae9b1a21cd4df0f48cef1d93a539fbcdef3fa001dac9be7643f37dd1bb6cf5e67e02fe
|
||||
930bc625ef72fd47e2a7d60801aefbbd98f1ad56353deae4b2e4830833f8c77b:0d290ab1a4b5fdc3:8552042e6132000eb3c44674e8e4e71c0f097bfb13cd367662a150b07fb7b670e166f738a7819377411b5eb5dde0ea950dcfd102b3718f84b071f14007560e5679ebc006fe76432e15fab2d18535f39b3fbf00bf7ce9572e5cbe5694c743ae71
|
||||
41dabe002f7aa9792a9f04527048159e6f1be97c7e0207ed1566c4262a12f789:968e85352fc3df11:8962a7d1541633a888526a8d3d010280a7c6c8c268074ef489019a8651ed0099c1c2ff60a99146b74a47f4c432d5d04a08c05fa9be0e048cdc283da719dd0fa1c7032c8353ad6846f81dce05f92ea083f75f1fd09ea67462bc8c8d46943654ac
|
||||
c4b3162757f21d8b57f9d701d416b5bf90a709f55557d19a8fe72c8bd4d01fd6:0c041934df4821a898:b88b710f7809f3901df4e877f03153f77fd1c41ce44abb0d4ff1b546ebaed40b5a80a4e383655fb188c38eedf2ab962c0e1b2dcf7bdcc781b21f1b8cfe0dd846269207a8a051b53c262ffe1c14d1d3a3e07d471780b638804219402e844e3513
|
||||
b786a05a2204a23bf247986914e09e60220ad345dfbb0082e31290b80f348dd6:29f5877b9dfe13722b:b1535e3fb429a8012516b23ce79664707a0a99a824ffee7e226090b0c41bf9005f2c72bca703ca27694adf585e9c7082024b8be701b5f9541f3e6e3f353facd33b9d0532a120fe029f4fdad84ccf1bc92e5a01995237036304bc167aad541dd7
|
||||
7a7a26440695378207f8d039d198c0a8bae7d174297a69bc566a9453e76fb2fe:0d7d8481e00dffd22bf7:a3be6cff0f954ce3c20feccd23808bb650e2b9618f3d9c52fb173521ab89b2654af7f2ec103e0c6be4336571ac203a2c0b0189887c7b06cb5738d10fbd84865dd24ae555ba3b3f46adaff5d3e99e8b417440f5d377408e05ac69e4b2fd690b84
|
||||
8789e7f56b38b17acfe2532a8516a43817a2dcc2e5037718171fa61c32f9b294:f495212d34a5343641b9:99bf5bd4cf4fa381db42f5bf214424709c5c1b282bbf63e75ed1d5420eb5c2f1eb5ddabcdf6cbaebad66b04f7293a0280f13a53175e02e5f6801be278fd2639e211aec2b268cf95d1b0300df63a9eb051c1f05d15f6ec1a8c5588b3682c69ebc
|
||||
944922d8040d748b4c77a9779b68e0e19816845e5969715377c88c760fbaa3b5:0a2ff5abcb19784fd8b111:885761f8d921cf5a6cecd94c26619157d2f548458ac36f5287dc205fc2cf091592cfa48d1e06544bd9bb04fc938917ec04d7df0752ebb314f0bbaa29cbe12d84bd9528cadc71d077497bfb04e44b64d2e08ec7630490950329425ff6f7a87eb9
|
||||
27d3382462061f32036e9f25746697298c03ac135eb53cce40e6c8d0b61a38e5:5c3c39865260362265879f:8e234853e19f022389dc7dd7240798c45f81c7be9e650088d380f3498743f30c961e856bf9579c21f280061cd087609b15f91f02936e082bee165690c5e2a792d336bbab9c6bc5f27256889953744b81d685356cd6f23827aed5e8a9a23236f8
|
||||
1e13a5be7f36189f5ffcf35c210de27b6571d64aa3d00111fa0831f48c4fa165:08ed73f10fd0e2fa0ebe1932:b1aa7f5fa8af643ebcd8410b580fb93dbd2ba82d64bf9a802846606b39d3a4fcd651f80736a9f189694a6910b41ab6ef0fc2b90bd374410feb42496002e435f6c11b18ebe8897d8e64630a1290398bd11d36bf83e398db9932bb7e0e94cd54cb
|
||||
9f2048b10d757490f72ca10e0ef4b380b57ce15afe83470e6109faca7b847921:ce013f91232820a5a3c4e275:98c52bbe5b1da89a930c4452e5b01f4359945d3e96ebb655d15fb8763a2d747d52f2628abb72459a302dd6a017ae0317031e99fffb2539ad6432ab1a09c51d2e70c0ce431e5fb53431ab963d4d23687718847455b53e389bd6faa919855c716f
|
||||
6ce4f45b393a54d6e12064738e740c870fc3066655827af9f071dadc7554a45f:0cb23a6f4693b24a16a0e5d11f:8a5e73d0e38f3e8786fdc7e2fb313b9a6b34ea7658e1eeb63c4270ac1ed80c42f22716283843ea29f72c599b1b69edd002903b75545342fd3f94c5633216cdf4e7a39d3aa146119f5c6fd555c359068ce15a3c344e18bc631d1f9ed94e266e2c
|
||||
83db8a3fd3891ee06a9a4fca5a694d76f78813fcc7fe0a1b19f1b86fb6524b7e:fa1183015e443acc22d5df8131:81cec4d2a64afb634e02b3b4d3986e1c6a360dfefef370224afffa15be78370f775ff0e617ad62fc21624275b84c3ba00f203e3b60b4de91b51a80750fa1aa609b99f49ab9fd638caa423bca2c0d2c9da90988e189953af2085d0a763c06f7e3
|
||||
80327a9a08e410b0749a2bf141579799e8cb9dcafc3c91245f8e8c98653b873c:0acb153156dbb95b071e3c79602e:80764c588d161cc35775e811b17484d1ec138ca72fb7be6d382ba0b0674e684e6dce4fd04c25db12520d3fd3d5e944d50f6bf07a63bbef2ade761de3c0b210b7cc9d2e95906d889df312ec062e67c703b56f5e572e1f808c1b57ee983579638a
|
||||
7d0de3987f99eedbb2ac0536ed6ddecff5600ebeecce340a9d5000005d8122dc:3353cacdf3a5d86bf7610061a6fb:920ccad897aec4302997390e7150ea9082782428be08ae4d0124ecc776aa458bc913a47192b3a02055527018e87f9c6417ed3d9cc17e813ba24265eb4dbbaa4746c62adb1e2d3c9a7a4d8c2dac4c6a14851358c6eb8a4e19e785dcc5b533d752
|
||||
abc26c442a73f260a1f7e41644a9904a58d47a50ff545fa5a5bc3b81dcc0e312:09fa75a09eeab060869233747305f5:83c41f6246d829bf19be3accf362e65bf102316e4882f57df3b8abc06bd9e0dd8080ff807326c10443383bda8760c252193cbce2f8ecbdb5b278413ce8fccb20e25bcb036454b7621bf630ae988b1652eb9b686a428a2d7ceefd9e18322e5a12
|
||||
330d6be474e54d85deec0aff3afa587eb4c5f803a94077d9ee86bd74a034a40d::a8492b918727dfe480e954c52126666872e243489ec6ef42d669c4483c3d09c83d5a49b8092685aa3410d1a1fab33fb6004c07e312df7faa3e88a53b414dd653fe4f417ef9450c7220a02ae99936a0a18b264ed1cfade17ffffe4f6c0b334dbb
|
||||
fdf519fe3b983dbd660f1dcc7c53b9b4003c54b0d4815cd5242c4b61bcaf9b58:02:9396ffec586fa35dc2a6659729a012f450bc83468900e3de53295af31cc8c6378c2ef7bd4a02e4417bbbb7c5aec566370aab2bb3681c1ba192716c90a1026042e648ab3dd6437273aabbd7285b77a2d2e2b0dd8dbc260c347a90e005b7dfd412
|
||||
8eb2ff351ded50e79a4bede161069ac6025e6e8cd0f081dd7af5228136c24e9e:d2:b56374f5b8a57d0f81013307a603785d54b6c2ed49f2f838901f3130a9569c8e0195a3490554c87f6620168ba1768bd20860894ba866c71b5769a6087d63ca3638b75ebae6c444fc5c52c317b5bba76ab020f55f3d673dc3aa6367889ea02461
|
||||
9a5eae3b2fc45fed7631c3c65e4d6668dce6f1eebc40ca19ae585ed1fd226ed2:0239:8b90f69f6e3db9277e4a6addd63903f306a6257752895925fda34253980aa0315cf221a67fcbbdd5ab1ce372ef5978bb0541117dc8fc497d6b4bfb6bcbff532971f8adae492c4c037fd5bc00d145787f9361ac005069873fb0cf102ad8d69660
|
||||
d20f1f3e536ed11959af2da39840eddadcb6dc50dd473c805989328c032b60ed:67c8:ad40bb4249dbf738e6fd8eec7e74c8a4516766e46b12c116030c4da28c41c2a224106195069bbb6364f28a8f8b6973bd03ee5a73e8066d6d27ebfcd88c47d9d24416f2209843700c91938e1c3a5d33e5245c7f9280a6474b4397d0af01a15f89
|
||||
d8ea32d81ddcbbe90a2f3df961c723da168001bda98d68820a7d3cb42e325ef4:0c9be6:8f956ef6e12de0b6ba15be54c8523ea25e6c9b94ec91326b9d9bda6a529c239e22888bd01f8b5f6ed13427345de3dcd80c9919783447a3ce70d261070cc0a1ee1bf3b3265ca25eeb39e9c54c32408f21a96121be5c91f4a36fc3946eabc80640
|
||||
461fbcff221f0655c19f9c5e1c2a5437c8842ba0910a983be007cff9df19f627:92e6e8:857d69d8830474de73df377034c57e619c954041b80b6c23ae769ea5dae40a5d42d8f855248d4f78c8703970435042110b256d1de0c1061c05e5a544de326035ece92e7bebc665f1575d5d8f0183303a8a7e1478a6600db96d47eeac05ef5645
|
||||
69a75aca260d679aa24f49481164930b71e72fdb5db887cf484a6db6852a72a4:0428b032:91f8b2609fd551c13eda568f103f5be9f7b2a2b42e2cf263da628c6cb735ad04d436b878fc7363baf969f415550d02800f562e606085ad0962be2adbe8c617b36a418c31d81bb10577f0e3743be8f39142e7fdf5d3637a120dced8b73ff79262
|
||||
182733a6720089b476c298a084a30a2a4a717b2a16ecb3b7be894b222c3ca5e1:26a7d91d:a39166d0499752ff885611e994ee3d39f8a9a6d734327ff43045535cfc882e3c4c99d62bc75da26474981013fa5214d6068dae1b90637e8ea5cad091d364badc6934288339c600059124d347a7a09b7a674435e1c7ba9d519d6b6d0b04051700
|
||||
75aae7b43b7315fe0ffca6f6255f62a815a83226cb16bfd12436f8599a59bd80:09abe5ed5f:ae30c591e798621380b1a5fb93b12e5a2b56bcb8937d3c78f67883a9e941dd301871ccfe57273a6ee6e5f0cdefcaa07b12318afb8d46c3ca85485c5f406e0501c02a58cd72ca766eecd7000fb222f12c95ee2c3d6e3a600bd205272dad25065e
|
||||
9c7b850171efc1bcc5d866ff6533fd7cba462b6f0523a223fb94f857f2ed5a16:42ead34e98:acec746ebb567eefe291695266d131cc81044899fb1fd2fdcc04757d8466e0e93bca13ad47364fbc0ac143c086a674af145ed5f793c50975db8ef9cce33cfdab065d6b9fc4c6442483f387f0af911933f789b00dba8f39f8d6d6fd3f04fab3f7
|
||||
53438f53eb749aba12412357262d5445e4cfb69ba645b30a9f116d6ec45a1994:0251be974654:80480c5941ae1fdfd3ffcb429a1b9928ffd08d8a759e5284dab6b5b73724b50bf76deae9d2dee2bc4250ba65feb9de620c2d7691e116476b81facfc873f8842a27c3de5f0730b480dabe0aaa4d24bca4df3564b71090e280191daba77c607089
|
||||
d7db36a4a43f7e91f27282937a4280a1eebdd67b18fce8b4ec5f581f14af66eb:aaa6cb92433d:8cd313fdc1ee2f5a15e1a66ccca3ed4236cdecb69951ef56cda437da8ff3f37288ef6a1e9756cc1dbd8718cdb060a8c8023ea48aae987d687486bc9c677073fc62526da457aca1b31fca39daade9978318ecc3ecd1273f883d064927795e3225
|
||||
e557e1443650a1ed64f17d9913dfe3f7ea8fa5b9b22b4175ac69d02faaa591d8:0020f39be6abdd:ae504f56ea36a8dd6c5792fe7ef70bd5bf61e45178319c85532bfd27bb775b213e1ed04a3c4ed087e95eb0880c1b11c715394287d1077ada5a3c0b7db4954d2145aad6b74ddd117c73f3b7850f900992e4b66590cac34e9f67b92eb032458a06
|
||||
566f89bee9480150bd9cd346e9fe7f681af96562ca82a98ab9be4cd319401a16:315a32bba44f89:aa8a8bedcb31ea6d67957fc7e09c336e561f63fd085c84c8bafafb610b961921fe1aca3c6b7c2a104fe84a72fd771dc20f51d9c28cfb7fbf842dbc9343d3cb4861f187c7ad02032f3a347dbff315233c3b2c12b8cae7dc40ce3bb3ae0cf28633
|
||||
ac8093326f925831b5c813c0f36749ab6f85f8e3b4a80920ca524cb1187ec8da:000268a1ab986936:a712a7352cfde24ae04b0187cf7c27d24cf993f6d415d01b8d4bc8d7f46d1773575038d0363dc5f1b6c61b119185f2cf13de4c13b42c5fbe5257588ba386d3ff2992d6f7f3e3c67972565d70ce7894bb9f7304969e2e9b7f7735f1ba9b2f100f
|
||||
e014a2800cbb1df2e42dc40bce9b81a84e6ec7f5ce1c1cb84f6de463607f58f1:e52a2f5a63181f64:aa83a49ad0dfab7c4683bf8363170b836b5c69952a20057167799e57c154de91440fc3da9a9a651fd0e815c583af9e970bd900743a2154145a4b5040f4a5e8b134d89412d9c2113dc9151e4754b2fae7c8a80ad3ecdca6df31b3be67ce8a0f6f
|
||||
6bb60100e45c2a7601a1075a70a8f804eaf016bdb2cfb67c76bea74c49c6a99f:07ce73a170e9e3b5d3:8c87485bbffeb5033466993d3924100696c90bbb6cb8a7cc25e92f1e72fc93dd65eced2046b35165278a41c75c261a310590bd11ecd4b79be049fa201c1387962912dff8d309a9d4ffb0a192bccd3fd51a43edb42447d86162e6c5e367a0ebb0
|
||||
ac514ecd85c4bc9c7bb5dd74d675a3d7e0ac5725ab8707743d69a4a4efd0d463:e479f849946dde9711:b8f4e70a28a300bda27525092ef417aabc44b0965a1b66e0fb9d0d85283d34d756ee28f5b8b0d4e2cba31a01ef1b97201603e8b11527dd3d59c04a1a49e6aec69caec7c825f32e8478ff685e7626aebf49972957da93c6e75328182d27e28c59
|
||||
0c5e59158036e95517480734dd946ccd840a2ae0d7bfd04afb561eb07b651f65:097fba98b1044aa38ecc:8b92528bb299945e6eaa1c1543982b4719ce6ffeaa46182b31f5fb12d04bc52d1edd242f26bbbd1d6bca7df14a6e713f07047747eb44048db73e17dd0cd86944525641e439686c0d926fa6aac347956b76448f6aed53cf5e150b26f62697eb0a
|
||||
482f5eec6aab3190b3e85c3358e906470e29f5028c1c1ff27334744a5389b046:f1903bd31ed169bd2ed5:b1bd64412e722ff2568737f965458f12923a38d94dbb9d08413a0122a993f159a4e69322bd142ffba038abf617809f4c183d1bc8397bb0d4e755854b06df29be5290b068bdaeb6a3bf66af947f9de650fc992b24795e109d66e1c1b8597c0e4d
|
||||
6cf0808dd7e4aafedc33bca4bdc5cd2ea5b199f09e60f818874d06edd808b711:053d7b09d32505e7f8a86a:915bbe14cd1bc66d46c572217d7834da1396304f1a00964717eb9fd078954db38ac2d3cfee23a2cadf2e239cbab2dd4004879ceaf6d2a0484284e8bb939e707f83166527df1b7f07f5b55e987e400183e051bcd02eaca19c8a825405f25a5fa0
|
||||
516a6fc917c2677b196e831913c67137d99bfbfcd279dab6c8189b8235777958:6244fe979e6507bf1affd7:96329a5e5c8c2f96941f8281b85f884fbf36732b9c20a497dbf2364ab5c885fdd2ea901a0b8142965643123b9959e6a0032fab81535cccec3f89f2f5743ab18ade1681b339dceb146a653356b676ba5044fd338a313edf9a1506c42a8eec2ec0
|
||||
db541ca7b63dd509c46a82844abab2e3fb63b41dc6f0aedd012dd5ee825ab336:0605a5861b234595538a364f:85f71fbbcb7e1bc833ac68121c3b255e92d54bce8c9f3daf4a51068f9f8ec830744c3fa2e0249a729724edab8d91370104d00bdb4e517bfde3c37ce445cc0a5382026ba0027f4645949b0a586dd12aeb8a4dc82047ad2e876faca9c5ed4b0f9c
|
||||
cfcdec94ca11b0a8964477d8f1cd2d991d9d5378ca7f03fb7838e85e013dac91:86d5eba501326894509e34a3:ad8ed6d864bcd3247b9939905d82d17623227754fdf0242de0abfbeab1f0560982e353238dfc43d654753908e13c0338073ad74b329a6058a89ecec84735b123cca657f9cf9d71d7cb2f8416a1599a275c848d6abea10123b27f3334aea2a94d
|
||||
64c8a98a1d399e67005062aa67492603ae501ecb1a954d61a30a4ebe4d161f2f:082fa093ef30ed114342696f1a:ae8d8bebf524ffb11e11ed6c29cdefab488749c11c2ee5cf3cbb02731d3b936ea11f4e41902d29cf977e483a21f398a20d904494d3ab7305015b4b8f6032df5240b29278689b72fb4a9496458879c00815fa3e29b3b5f3df78765e161ed3dc64
|
||||
2544f3764d9102fb80bb5fa446f4d9b9050e229f42e92cd36b1e17b8f91c850d:feb1f3d7e800a829cca384707f:afdee7bc926e4df643a69a431bfc91aadc659e912e83fc20a7d162ad675e37d07e95b04ea17ada1ddecda83799c7dddf0cc95db48879e6f694d7198f4d0637327df4d5d29b6542b71bfa773f66e6d518d8c700b58a677a089f82a1a838097ef4
|
||||
c8718d6afc9955bf189039c0e72adce0fa342f9830746a92092a7658835a0282:0a134902c0656d0b86458d182718:a2bd54f4fe5a95d32dbb9bc94fb4ad87d8a99d89057fbf571c7b1438023dea2d1894649fc3f68c221d99f01f9b50d5e714ae03b3fbf390ffce54b3a12041a664777a43f96351ee8988624599d07b2a9fd8b2542d136442a106e3dab3f04c369c
|
||||
6004e1aea40b85274c75b056608d372ce8f4fb1710e8f5a6ba6da20f9b559605:cb80b0a3621bb0528735ddb062a8:97d80bd51856d3efba40917d7463dcfd49411a00951b19f35eaf21b470fcbfbec7dcfabc4542146003ab4c691ce565670d49c7405f5cb3e40d4cd13808738c5f9c5da520ae8c8d664af17bdccc87872da5e314dc51455a7816e197dac9f3c37f
|
||||
aa30b992fb91f3e8d07f7cf58356d84b694c454086c662603f950df1280f4175:01beab7f3bf92b1f7effa24f8b5e9e:9233f8530094e2f779260f126eb3571f796dc41c9d9bbbb788d5a52f5e3ef903960cc187d4cea0f4ee00af8e64ef88e6029097775218ecb72270fe946c2bb7f9c9c3f00125f321afdaf90d01bc0452171f759409e4e435feb353a8753cd34c92
|
||||
06db1da0e8e44d06028401ff614557bc44d04330ebdeffacbef03278630f3f49::b82b0511b133a0723fcc1643c6ae16b16acb8328fa10782c3d8dd532bea9e6c3e5758bdfbcdaaf37771ad70989e107f309adabc1dd10359caabfc0471db16d5d9abd47e8e48c3a2ef07483989fc0babf6080e8a156d432b9bd2323d3b9beb152
|
||||
c00642364807d4df508cd504ca3787239e6c00ae8db91c98d21aef6de2fa7662:09:95f9f6599b49da7ed8024a42543593b695385b8d834b707afeb062d91736f94ea087d498ae64070e439c43841a2901a502b25cb6003751e637ba0a39bbf5814ea8140e4676414d1cc67d8f3319e0b8d0568c4c57e83e2482cd11bf5e919a6924
|
||||
4f9bd257d3cdd870d0774c460a7a819fcb05b328606c33d541843c4062631d1f:57:a5178ee9b4f18bab44f49dae208cc1c9a387b518d25fd0c9ab8c5545d3f8aa9802764dba201683b4fb36bb3f5f95a8150bfd63971e086acd76eb2ec7a941c454c8f32152dd0894ffed21265982f3da9f6f47c2aa76ee526fe252b5f921c59a95
|
||||
dd2422149b9bbeb9e915f6725f01c0c03dbbce8b031970e777e205cdd0b62a5d:05ca:b11972fa5d063b53503c809e26006d5c03d803527622d293c630f1337af957002a0644cda5a28659260929a4a76ee25c05cbfbeed58549955edd0d5a70f1a170f8484fccd69ca5241591bc1ecd9d636f324270d06ee7bf64b73e5a43efa4b327
|
||||
37114bc315ea4daed2d27c47dafe0b8c9a9280f3e9c5628ce6196d3e444b3a48:2e62:81c8811fe65a4528384d8f5a6f7840ac530d9d66a58888e8e550e73cf03b2d0695b3794dd8e2ccf7936407ee6bc3487d169a8f3c99718f1e8884032477e212c53427a7b5f18c02dfe52a14e73cce697c21fa210fb2c9d0b093347a82ed4a09eb
|
||||
952840582e0d1e7645c08401ed6fde3e63f9307c7e45815c0a71d37cccec3a50:0aab66:a760062f799ac72cb69d633e41457d7094f356d6b20d8d6635b906b31c1ed1e31fe88c6d249bc669b4b400e25131fbbc0e0d2dbbcf7d4881c809a24dd7a1f2ef26c42f327a23083303a7b3e05e53771306c5c706c3b6cc44e050b0c55aaef06f
|
||||
9cf6e3c7b9ec13b2d1e10082d36668eab962ce02d19b7ea1f0a876a0dcace272:cdc4bc:b5d3c46fdbdb27e20868aa8bf292cd0d5eddb67cec04408d21b54ad0a127070d78633846c50c757b7d14ccbcfebee4a102048d3885159afb3655e330593d37e9480480cf84e6e7fdc8a0a4fd0e4c658bcbbce79d4a091037912712808ad6dd30
|
||||
55be56ae7328ccf31edcfec667c1fadccde36d44c4f7d420cd13b563478163e2:09d14ad8:86b20e8dc583fd7727e1a1afe20b205a14fcc27339d7871db9ec5347dbde1818357c825c1d8158e730df80de1bc6979a037dfab2f893f710a201dc61792bc4e1f3291fbbd99babaa8ee17afd2b6abc6b9341edd3392c738876bedadbfa3f1c87
|
||||
0ce187daaf68a1af9fa954c1b00dfa0b4a7f99d72f2c0417dcbeb01bf3abbba1:06cf3372:878c0c0dbcf4810933c3033e0bc70b58a53e761ab2946e45c1806f8f2bc8228ca944794c59378e1775adb9b7e647e2c9108de40b3b067e82c6c2e432fff08925a1d97670403ea80318e0b1c51765c390594667db46e076e2141fce896cbe606a
|
||||
9efc5c31f466e255ab606debbea016a0d8c36c59e343af468a92aaabac08b9a1:0cd3d0bcb9:9895e0c9a3639ae728c5d21bca58c3ad87d2b7cbf728b3421f8fc92262835605a3edae741f4205564328adb71db3cf7c14fcc4bf52ea08affaa9fe780b7caac7615e7696da1029b7c9e44012b9941fc06d63e62360b74c553e87b180915527bb
|
||||
320f214da563ab7020bf54c97ae7c86868bc5c89abed25159c90896ab9fcd72c:14110a5a07:90799eb2c1b7f0970f1fef2d1de9f9c66be0992658b73f3c7690dc35f3923a9502c45bcfff360affb554d6469818622e035136a8acd2a73918ae85abf6379f22c8343bd7a2039ea2998cb5c47c68b6cd85408452983d5faf70fb4b1d3c8c00f8
|
||||
cf561deae5deca76ddb136de64d7ffafaa0dadfa0c1eaa3e402b98cbbbe77194:095f9457406a:99b7e34d2f4620cd7c3a28677b3936bceeba317a66bffc9220a2db122a6a5737bb4eea8dc197e4c359178d97cdbefdb6150dcbf76e0b72f13eeb0afb61c34a49aecece57c7448144deac3d213b60940aac157f7a9323ca8eca94f992bdc323b7
|
||||
6bc5dad1ad7f6cbda1f1817da2dbaaa1d35bad490ad2ead25cd2eea895324ead:42ed6e9eba7c:a95e3f826879865c2479853984da1075164dd2cd84cecf66ba253d16561510456dc346d1257cccb12155331c072bce5b05b294c2bc870d21c0ab9055f92e70dd880ce8c7c144a5f956c5395aa49d8a5186b45627c2c56f41fdae021da95f26ea
|
||||
fcdee7c031f2f14478368bcaa3fb3a0199e017942899c26cb5b2832e708a8c50:0010037b577fad:8e60fe3cdc55cffa121ef09dc84a8332e1d321b5a53809ffeb0de2ec41be7190f681a9b466a8f219c9980600fd05491f039338f9c6dffebaa05631910fcbd32119660809b901cf19ea844771ffbf61b007a1f89b1604471808beb58eb65509cc
|
||||
4223e4d4129f4b89380844bb31b46288ba449b37a9fb376d96cce1eaa628e2b2:a192e9b18da043:b47e432e1c6158e0c17620c61e801a1401dfe8578db5b61cb131567800f40ef1f5c125f1df5ef171770165481047f09117b2ba7ca45f5caebed2777cec8858db2a5bafec8f7adce972044429437b3afc7831640ea9181ed20ca023b109a056fc
|
||||
9f7c1e5075dcff0084434d9970267968f9d0b69fecbbd5899c4da5745b083811:0aa9c73dd809000d:affbdf547120be416186444b617a4a8f9b3d38f95ae1179fc1efe933aac187c415a62395ef8626a6b8e1f5a56d89e608155d5c52fa2a4b56870cf98e07e21b3511c26fc7ca0da24a4860b1193b7ad3a0d0377d895da05725a28e4062da7984d2
|
||||
85bcee14fccb75ed024df71d8c7136bc75c4bd2e904ff6e05a044b4da1605b9e:e58d1bf3c64e6fdc:895105813f080161615181296a5b882c490bc3be0fae374eae53314d26ca10e47b3a31d6578e9b101a2c66bcae723106022e6cc01a8b3b7a7a46bc0e6430a0f940db73f006b29848c424904b7dc3adb19d50494dd41f52aa514db537c5965223
|
||||
569d72679eb7a0f07797892b09fcf7a1dbb61fae4a73d4e798ef7cb35fc99f77:01ec22b832611852c2:883e8e05f6e32dd24c9640666d58f1952ccb32afcabe0eb7960a18abc20bdbcd3f5e00f1b633e4d35424a8cc71a341380fa31634c7f5e8f3d3c173b4fdfcced456d9d5dfadcf9a71fb8ad2182734f9aee6fe0b11e3c7331279d2530e5a042f71
|
||||
6f3c9137e679a12e1cbd241b7436e8bb6807aa491bbf083c6b68398894cadb4f:580e2bb1668220c7f7:848be794b037494823c76cae9de6083a69902dceee2979893d27b04efc18eee6b28a4754288d7e20f5970e540709cc4f040fc33482c6be06311d1793fbecd66194fc97f9b491631257e19babb61bb58a464888a02924d5e10ba4113b2e9d990f
|
||||
34ab9c6ba4a97fe9ef761c6f8ad6f4afe5dc390bf159e213b58e3f2175c142b7:0e30de7147d7eb5e2458:adea87d3e463b6a97e05dfd57b45a8f1a21953e2747bb0b324c54e8904da0e16a1e83565426ef32852d70af76dd654ac050c4c27b708066f52cff440196502e3ec527a6fedc68f21f1dda783bda9f09d415a4d47384836cae99b417089a3179d
|
||||
a95f51550aa2b053c006523bb3793568848725fdd96c513c47f411f71b344e3d:b0ded16e59492cad4ae0:9329d8054b71e8db5b6223f76e23bb76974524e5569e5f82f21ef812f4b52b2ecabf5f60d1f96cf533da962c9f3002b10a50459a031a11d7c0e25f2fd4c38d99f8c1a22aa3b90b2f1fe333bf185b8dec40725ce47c4ed2be32b19279de1d63f9
|
||||
0589e72a73238a9973bed6260ce69db89e210806dd01619cc1ccc9dc695a0f74:04e9af42b0a27a52d319d9:8d622962af2e158c2a363822c72616d6d071aaa93f628b50573d856a04da48ae8c907d1f42e680828b34fb70b53ca73f0bfe51ca9afe03f7892eb2ae754d247c7974949f4c35e7a21800d5e4b5cd7a6efe4f3bcc7b1a3a99d8bcf8164f47cde5
|
||||
d64f5aa8ac3c4e6acfac48c8966794c38b69cc56a3fafcf5629a1adb59225a71:a5947a1e1ea080371b227d:908fb9f48bbf4bec043a36c547a2369d6f9ea5e5b27dbf2d9e1a9e5db4f951865686830e072309e05fbb454b6c787f2916f5d24ad4dd231749f0bff9a5906a10674cddb9e6615a1d26421123b64e8439ca111e93b299f5b89dfd74002e8dfa53
|
||||
394fb7dd9c5847027d1c9cf411a2386e1f42adaaef4ec8a1b50204976189bf5a:04be6e8b23f4bcc91a8624d6:b8a5acf1925863fcebe3d59d5426186e852d14e93fc24910cef1a3d356a8279ef3dc6ab622ff23ab977a90c203587a000840ab5561de0713cc495cc35f1f00909435562d42ce852cc75776aee6b06b88e86920ae2cdf3f36bab3175c44018a7c
|
||||
ae01be984e0af84bcb741f19b395300fd4a4f3ecab6b2d59b1de8a65622b7351:10297f7bf93a1ef627b2b3fa:ae8f8c4c0b047c014e6d6e4d597a8ff350b57d653c8c02ea36970e2ebd6d52d0157601567768e72797f9f89b3599ce79120f34e50f82600ac3af5878bc6807f7e552604247702cfc7049926a86df04728dd9aaf64e9249886ce8e1492e93ad3e
|
||||
3750907c1368d256e95ff098a026cf81aaa0e8aab92560cb0cde140eabde4095:0e5665dad423cd2d935a3832ae:a9e64f0739ef9addd3bde83650b5b372562222d7c81db9c7c49c14fe8224ab18de355d23964dee080ed66d93a72f171901bb78cf7146957efecb006c5f7d49369569b02055389694f9ab44aca690eef31e3a0cc670dfdb53dcd4644de805c95e
|
||||
32812bafbe9535c8530406a5f81d88f9d677ee0693d6c5c63271b3e154ffdf23:a61dc6c0c4ff587b31ef4b0cba:86b48e37dd075088b860e7c04d0101ec1ba8705dd9e7e4d6db16c23a250a3628a3b904570f95598ea286c2ce7acebe22139fa6320fd132423b163cf76e34329145a609e1cb9e17133175df426ca598495e6f4962baef021e7ab6013143d47527
|
||||
768c79e74d0074c4c7c3ad74dbd62bfcca46bf2516d037f2b766e6b372109ca2:03acf045a0b276a634a185e97860:a423b892f8be1efcc5316e312f315575f2d2010457bb46dfea66fac971288b1d30ea103293244d4ee6ebb91d16f0e2ec07fff3f3071968bebf893bb98667da19ec22b5a621b0f9727870dfcc3d525ddc3f34f8bccbde06bb30dc46929f53ff3e
|
||||
e92bb67b632f0cba53b3eee8ec19e2bb92356452fb217a18a65433fe1a8cc6bd:247f00c23d0e934ccb565b29c778:a4e454e97466e5cb8f7ae7c6941c66bac5ad16a794e1d1d733002ee0fdecf87fef6566984acf2cc03e7abf0f3286e32001dbc86802d1033512aa74eec687ee1513fea97b511bf55241fe918849c6725782f54c8ccaf30fb463a4267edabd4ad6
|
||||
2ad285390978c933fda0b3d51bb58e6251f59083e89ebca66a565689eb373cc2:0d0470c09284578db66c65d1ed7117:9562202c7186f6c8a91e2284f7ce16546c8e9c29d9016caa9d3d8b2510b3af30c379f3fc459c8ec370bea57010df69051836658aa5d4fe2ab7d3748fcf1cc7a65996e157d83a522b5c7a09256024938ab32712e1dabc937b1b0e566202302377
|
||||
a2820ab3c2ba9df56defa674dd6cb563b577e1dd2f9a788ee2de6b9819853222::ab29cd6f87e1fe1417237ec813bf3e26adac7df06dcf75f4bc7991706f802f59a3790f0ba6e1c8be3893e48fefd6b30d1219bb6063ecebf140cbd0175eb0ed4d33064ee1801ec1b263c1af6c83301d5fe294fc76009254ff2fcc7bddc8524d58
|
||||
adc7da1db78381a3fcee8f0efa0dcef72b64fd2baf73fbb331ca10c6c8e2e1e1:04:87a58e28277301d79af6559d1468a2e295ddf214788c10e0614562ba88b2db7b6fc807047fb863373e8561ffc2c8ae9610d62061b56265aa493860731221dff6549aa5fdafd81dc8e1bcd4cd77647d5dfab1557fbdddcd245abbac2a75d7b7c1
|
||||
deb39c2509ba781594323f75ac114d1f1b50f22695f60919869b2c46b1c9c6c4:a3:ae6a680307044ef6123a79406e39bef49af1a27a9e8689ecbae6de92498fb530669efa9d6d74e00afa2f90fadaa3491f010c1d2e15b557c8bf646bc08ada2a9f708468d2b13b1a316114a970058f428c1e327faaf2711c406b7be5ad5754a4d2
|
||||
1d41aed618eb90a7a481032fc0624c3b381f899b5aba3ecf4945ecb7bcbba248:042a:8f48ff4108ae64b1d6475bb156fbdad895c6a38954ddbad95fafac32c9046800565bc80d05382072d3fa790275680850194effaf3c8f4c33e74e451bb4fed479f08bba1b25c70a3eed0236fe773cffcecd5136ca78793dfb6317b7bbebfcaeff
|
||||
166ab7cc55be4235e4dbdff65beb5dc78eb3bdcf74531ddf43c5dcf9231ab5b6:1894:aed80a028af501c35a3607f83a405d40695b0247856f615d87a5effc041bed61994d5ade2a446649ecfb53d35c802a6e1407e7eb7f580723dfa4472cec745b33972920a4e391ac8cd24081be533a0f77f82e92056edde55034fdb5a1e62cdc67
|
||||
b4c18feeb2ed734bbb97f2fd07bcf2b35c38aaef27b018ac20feb8c14c4990be:018426:b26329f66abf3d00f25c0ae8e4a94e3395b6550f9b9991e7ee9172f75de000167d84d02194af324a05b2f284eede6660143838070a7fc976e73c5ec443aae831f2f1656be1644aa006f153894dd488748e18c645da305a3bab7699654fa4cd43
|
||||
b8b35235736a2044338a01512b9caf41f9e8f747d957136fb1ada889b8c6808e:ae614a:a11a7ad28918d05c5746305b83f1a50aebbdeb1e82d2cb7b30ff8d370a52f9cef163338a7be4c0446e396af2f0bf43130e99d450879124884452ccf3b4b25cc84a955ce6e80c81c8a34b459fca1f0b6bacbb27a2135adf6fafe7473eb218c917
|
||||
868a1e248f596caa36ae397726d79456fdb69341c619191940a244af6690e0b1:0e3e0406:91d463c1a0bdd8dd9d2adc0cde8b8a54572f6b9b530978a52a2562d448a1ba741e403a58dbe2ecc34876b1ed5117aef009daaa1271fdba64fe820e5e93a47d29403479e5417b6199b84356f8ab6f0d7006a2f7e79c97bcba57a489cdef4e0f10
|
||||
6c3639c6647ea53eaa46bc577bbba99b305b2cb9853dfb2cfdc702665fbcb546:7ec9dcd7:85cdb3b39c6db0633cd69f414d984a990149d391314a179a8df5ca53aec19d99ff5589bc6ac1ead6194a176450760eb518631ccf74397565fe7d0f141c33c5d990df1d92aec61c7774673e6db2bc9c010660d1a960bd9bf04b34cfbbe7ec16fd
|
||||
efe2fd6210ad7b47bc60b935a23a60aab8c4abd54ae765db22a339228595180f:0a0eb3d674:976186898bf01a16c788b5622c088fc1f4e56c48d704a7c4a6a580e7674b9554bc606cbdb2a1ecaa825956bf4384bb8d019abe98d85610e5bebfddd35b306f9b375e45c136366335ff2db930da723058abd3d708d324f70065da480c42c01ce5
|
||||
d6baf02a6ca31e6e8c4194ee80eae4137ac267a7f0389eed15cbe814c934f34a:43e20cfa8e:8f9487a6ce3a9b5153009a606de649d36148180d50efad4b0655fef459cd34b92fe8b729d7935479f6276fc9a7364cb9022939ec84463c080f9d161b990e2d8c79ecb013b6d3913ec37e8a21f1515a9d9c07679bff74b182e5ef0b325b83fbd9
|
||||
49fa1f7a79dfa239e804f5e320337a708862416bb909bb9caec81301f2fe451e:0025641feaaa:a51b7b4da153ac896f5e9eeec421a1d61bc915fe349334644f7315d9bf74dfb46b24808c0874ee61f003173d678b59bc041fcb22788e0cb292b3ee98d827b476e0081fb63cd99441736d4ae6bf04d6b78de252825c42457c1415914cbe997ce9
|
||||
3c0bdcd071ba70b2ea73d1a4c5768a3cbbf3e3642f8ce5e3fbc62b558a1693d0:c43263af0875:9592ef2b65a5312262ed8dd2128f8ab8e610003c459b1eab81e93aa0a97316a327b9f8d2b894e70e585a93aaa82b79fb0c4b2ef732646fd290a388f5ed453ed27b038d0a62e7c5d22023cabbab6278884564721b56342eb0bbf3cb839bacf7d8
|
||||
faa3ef6ad535221fe8eaf077b796a4b92f67d13ce78a933d477ffd348180f30e:05207d5c5195b9:93bdb10c35d990b4a1ca7c8378df7416fe913664ae1a4f318ea05bac99d99ea74d0fcd8c2f5cf4a4066b89d9bbf44f750b625d04a0ebdbf844eb5e1df3e6da24db5a5532d00f00d0a2c3003dfe0354e2a59c187d50b6369a32d1c683a1f981a7
|
||||
177d9b3bb86c602d76157c078bf48e764ed0ef61a65a953e078fd13abd89c883:19b6771ccd870f:b1e8c3c34a731873f24420b7375304df17dc7162e70fb9c2f3899c30a012b01816edf2ae231554762db8f19a74eeb9681981bcd70b87bb078968f12de45537c4401524508de636975b038a9494ee47e324f842ddf19517a0be5bff0b4b5142b9
|
||||
0e98cba458139123b6478608980bfcbbac2a71b7b27c4a71757cf3b6b775eef5:07724a519ed1b1ec:92bed7e9beeb8d14899246a1f8b7212e10155a413e4c8e09436a6a3a2a8858b99410f4f06afe005f71de6caa9ae9858a123bbd12ef19f123a3de91811525dd41c5be9b87e07ded826c0130a85d3b3fb4f88fdf99cfe3b565b799fcfe85789d4b
|
||||
6412cd26afd7b8774454ac305e8a32ab2dc489c33ab2dd853ea23d5d7c2dd741:531f475669c44d40:941462a5e2ff1eb47f4ae8467fe10161dcfb5bd04cbe0249b6bd29f46f04dc82057681af846e76e6aba3f052db1008af043f532601dcb71cbf3635763191035a33f68d4c3b33a9ddff0ca041fae49c17154d5a0df5a56eaa9686a560e27c2576
|
||||
b13dfae119e4d416646328c7784d0f1f6fc9cdda06093d198048e6a287269857:097958dba547d1ddf8:96bddfdfb88baf179ed07c461805fa538981f9bda26607e0d99bc24bb07cdb187a13ad1aaf60d17104c683b8370e944112f65143415f0d29c7c5f906c070f5b1b8923c71755372f76c4f9417f3062654c4b149d5d4c5b4a086e324962d0a9916
|
||||
bbc9784021c00a44a4993b096d87d7ef6c6e927baf1b21bdf45b474fc521b189:245434316d187b4f02:8d402e4b9c300346551c93dd8ef883a27dc5536ec394d47e0b45d8ce852071d33c496206f22908e49dc0dec9d9e6261f17d37607caacf48e9fd490e5235439114138c672f5e9affd1c474f82888406f0608e6b144567935ea0793d24f307aa5c
|
||||
80ab4ace3bcb0d664d75716c39c533cbdbddac74795927b82ba6c7a56f7f7455:0322eb451950a34f9704:b33bb7eed3efb1ddab34f1de18dec549a84939f43dc388be6c9f43b3fc627c70e13ad188c26c0a295fa6b06749330b8302e814a0c7b20d4d468d8eb2ea2af377be9a6a5ded2f74029e2470a303e202062ab534fe07bb8f83c5ea6071bc820d9e
|
||||
f2e4181f779b7c3ce0e24dc2e5630191020a7b9d04ba132d5dae95f7c4010dae:97430a39a825c623505e:9282cee78bf7ca36a252185679e6bdd147897f02e5b731f1b79936211308aa0eb9a81e1aee31593790c4341fd64c684e0481933bb5a5dbe6ebffe87a4bd2ce471bcafb85c16dc65698209ee18a290e046e97bbe287b2f207b0847692a78bb54b
|
||||
a910c35660c25b2c636f26fe23349babc219db594ea73895e6fdcb4bebd8be75:0c24de4b18c3bd1206de31:80eaf929b05fcba00b04db3a8163a6d520c2f41b41f7287013c5c5949cd655fdaf591c75a46004e032a10dd73c28ce8610a6d542f69ed27f51ea4c1c0b7430ff4436f5df10336687c783f22ff1598d409834a86a78fae268dc0a2190ae4c77b2
|
||||
c860f534570ffa8c21b1d80e59139db3e12ba66af7674b0e3eddfc92ecbafb01:fbbe246ccb3c50f9d19dcc:b5da8cd719f062511d558d6977415121cb4413f2b6ef9480945050286909b5e283547c1b8bb13c80777ecb31e82687911958c5e91195494b20dd10e863ae9981cc40a089c15a8eaabe014c08fee5f77c2864532ca71d02f8bf404d4cb39815ce
|
||||
2b4736db74d642173c2e685c02b9ce4c4cf415334fa2ae0ff6dea6e475f0e6fe:07896277799fa172688b9d4f:8972f8c3910f79643f026bb5551fc9096bda8cf94efd19add195524dad7fbdbc7c28aa6b5f40175519f9b6117fef50b5015a920196b7a02943d6b01c77dc411872ed74a65fee33952f0f899ecce37d5d47adb8c0a9766da7d2c41f3f60a29d58
|
||||
b1033ef71917d3cd58731b284431a83cfd13c58efd0cde09c552bbab1588faa4:45be6616a653de4c8697d5d1:8b2cc66aba7f601320a79aea0d4c72a922311c3bc25114075e7ad9a6bc2f425542269b08b25549e608d47cc7ad0ed34919da4ea212de347edcf7a7bfe1ecdea3e8200a804071afcbffe0f06477a5fe8d581a1abbf87f7b41b127149094fb5a11
|
||||
9025178a2165d4905c38c9509e64c4df887b8b1c9a9e924106a23abec0229f1c:0717517ff121d2931a623d4de4:b17f3eb77eefa04ffb764934c6f95964ea969124a3d98637e5abae81d42464ee3af4da26a102e20c193d8b2f0e2469020774fca2745dfaf5ca1f8cdc7588adb7911461b722c74519d859d93717032b9d0a2aad506327908b651b8ed107c19259
|
||||
923b79bc1f6b0fe9448821ac98d51cac6c3a2850ef0b58daab63b768a4fce80a:0b101498ee27350dc7a5ab4123:85a22e44caf87c1e77d9ce041660659843dd2d377ec5e944cfea666d47c38678e1854ae7b1b501ed2eefd1aaaebf27830487d3a5c10375c07c427bb20f5c00815d366be7c31c7b0f92241c2ae86a11bf7da35ef77cf99cd8ff032a87c8a0a65f
|
||||
6886577263e5f25976f323beec475ba37e4060056ae6c32cd10aa3a47d17131d:0419e98cd72a702b453801a8cc73:96a39e6a1c6a3f2b282f4cd65d8e490c9d5117f9dd5503feb83b6cb44bbf3fa3993ea2d107297637a476ad7037679f5210802c078e65d791ff741d61986b8854ad3abf21323a5a9a2d6728dbdcd8c341dfcb3a2ac1c7535868b476c7d0258d8b
|
||||
4e0239f3665744032462d5e5999b62e4a224c4de38552e06d96fe0afc8a56579:2a5e3e96548d9a9a35ed8d497b54:b8bb08d7c5abed07781cc5d3120a6c62a5a41514eab9580be86007e0049c0cd2f8622bcf30a93d43752e1256310ec0e80895f6dd37df67140340be45743a0fd92089a174f4cf550b988a4e717f65b823fdef076a25d521402b6962198b6f81b4
|
||||
1cabe26d6ce80e9e03c326d02decd6970947a0e79f8e89b0ae3d31a96a79c698:0ffcc1f7376eedceef0e1195bf735f:b06db65ebc8cfbc7899b10a2c706d585783f3f10547f919b9d9460de50d292172813838b61c75fb1f409c833c98ceb2c1698a5c414ac31d60928ca4253ad36a90808e74797a11e1d50ed132b3278bf30669790ec6499b8e9eacfbe22a1790c44
|
||||
b719dc5db6dfea9bec433b77bc3461ac68c2ef86f61e3d1440c8ee1660aacfc2::a6a0083be79c89593156082c57931032aa8f726eaa8c88ff7841f703a85a4e28ea2848ed44c98aad04aa17e176063f0d13661c19c70b2e23a14482f737c391411cd46c9e6f156cc02bdd0c6be9f6837d45423eb98de094eae78c96e5b06ecd58
|
||||
1c9ed5349162e2d667b1972293b551b9e847b4cf5a0b271d8da70ec586f14186:0d:a103483d0dc05ad0a66d99f4faac54eb4a4e763ffb3aa337a84843f4c7be4b3010c10f9c8d0f0bca4813d9f5d1efe50917a587c6fed3a21fdc2e3f6cadfd1b7738d19434f54d370a2fc8672a9dce11b50c38c69b9eaccbbeba5f80af6d371edf
|
||||
4fa311dc95281b95c653d295510303839d609cfab1ae20e42f6ecdd8222b0232:96:8a153cd16762f07269ef6b019eece8e79d7590681d9ba154a4424531f6ba697ec0f8c773a445a6c1b6607bc904f8d4e60e6b4b05e152395ad25db09f6baab0d7d8b5979047a439566cbe19b9ef28d020c3272ecff416cc13a94ab0d12c2263ca
|
||||
f29461b0b0936131d4a1c6791f5f64ce17f9b2cf5c729230884375535f230e3b:0dab:990eb5e5d2c76a5189be57f2d96fc5194c73726303c2a31380e7bec1ee38ac220df2b82a1b7b53b4947c7e599cbd470809bf29fcf2dd846a9e2b9a16bfab547e44a43d680643333c96688be240b9dda7cf6dba812cdaa40dfb9d387f90a1cf8b
|
||||
17b308d35f2b2107ea16bb5805456c49829f328a25360b371003a91a33c02d1a:e3f4:a1da28132bd68317dce7f6a4b10e64e2fc6917829d50c4a8700c1493bea394e2926cd47c315f97900007f877d25b8156074a1acdcaec936a04ef3b7ce18e4145afee3977d3ba18c760becd1a0fb7c81c4ef0dec32d0aec97ce0a1cc8946fb793
|
||||
a1bcd7368293c73133680bc8d241e4350174e87f730876d588095384b20f2e87:05afe9:a624238c3447d01ad6a6f548346402adce9e9b8e8f0b0e94fc78135894df3a9054eba9ce8ba8f642cfbcf65c4954d7bc0fdbcc428528e13bbbd8c93d67575c1b9fe1d1b0033feb44ce97a3bf4ee1662a0030cb1b84ce0cffa79b68f60a6ca9d9
|
||||
d44e4344c56472510fe84340b9b601ba7d92c8794e8c5cea127ecc01abed98bb:2acdfb:b0f0a8a9fb3527699e71ddb9e9d7dc7f9a51dcb14d4f9eecb2ccc775adefbdf6d70f6dfafcea0119558c41fa4f56833f1253fa92472061c46cee4de504e9779a80b59f6f9a62136cd7665d28fb885bf97729c5da76a87385582d9059669810b9
|
||||
7bb733a9a83f79cca1407fc798df02075e1b747fd1537c66aaf68bc35c604f2c:0c344c30:882a49978a874f0afbf464218eeb219d846d90a23b32fc37c2c72e629958a7ab345e72f771c39bc7868d6c8f5fd03d4403ceca9781e6b19632d2ad287ee73c6c4edbd1b65af50b4740d5292cfbeb74c4086dc55f355e471e24664a5732f244bf
|
||||
0a5c7cfd06a465381127918d0d1ea38c1e4c933444dcb7b62262d87fa08b95cc:926bfa1a:a71c91e486195316156f3d78740a93421d8a8c03c4c37bba17f971cd14d964ed66973c9934acfb06478f0d76a26eb04410fb8aac44abfad7835cca9a2a8f4d21ba3b6364dd710c8e58ab1f06184126aadefbe10b1b5a82c0af6266ccf2d82f98
|
||||
bdca0d60906fd02276f1fa17b40a874ec15e70793b6cad48b0a7dd9cc26eb139:029a6c3bce:a645c427f86d68b0230eb7e01f406b2496b2723a5133ada2b744dee00d8adace24e084eabfe16de82466eb63130dbf3b067762c79586bcac0becc4f14f71f349a3811490832d46159420258416a22f6bcc3065d944999fb44441ce150e826545
|
||||
ae17e14c12b1b9c68cb127a8e6807ede5ad4ea0a8c74e6a3338a36568ebab6c9:fca00f9558:8af98e40a45f24b71942e86f89ea245c2bd7f91923dc60b365c7df6125ba95a6693c89767c8b7f34f2ba7c02c42467e410ca9809680bcef8f22d736e1a90e14ca171028746bb2ca12ad8217e945bfec3e004fb1a81b9c6bff55802811a829599
|
||||
d727fc289ff1790569cca790cccca75ef6f8a86a0a681be1a063d33c3795aa25:0a10f0e0d2dd:aa2a0cb8383c1a89d8659c7fc034d17feca0261e2193999d36a74a811c31cd7f891077ebb7e5d4fe7574f16b62057cb115c671c77063134e767aa5db0b91bd1e274e4f254c0b6586522724aa6ae1753d5b786fb04c0dee7f2cabb143f8c4efa0
|
||||
fa50baf847fab14a085aceafbb6759fba66ee9ee1bb94c5476ab3cd8d5f6c8c5:21477040a415:b62ba9af86a3a404a81ebc1af12fad9c2199c6a9417ff45e11abbca7b912bc656216e31213d4446132483cba4ab22c8015e6fddffaaefb767d6039e1a7c7ca6ea1c7cad2da6bac7c9a0a13e6f9a91d8704026996875e72b895a7016f2b82411c
|
||||
6459107c9acc6d52cc5fe0e1a7601e6f8004d5c78fd89d41bd4999aa5eb1a551:009e79cfe03cc0:8bce396182f6e23370ebe56bcb26284e082f0b07f6473be655c39863db041630c75ad570dc0edcad57d1ace944b44e6218ab9c714bebc6e5f81026b9fd53c736579e2287fc0760acacef4f20922ad7204656eb282d4f861f0e46ea23fa6c61e2
|
||||
ac03c6e5086c5bd204c1c1236f90d0dea9e4dda727fb946c5780d60b16be4d03:c677ddae3453c8:8a437767f8aa83872b6a56b7eea75a3e61bb8a86990fec00d16a319e302c5ef3c2b8667a3a5a09a208550dac2245abdb18fdf3abe7c2bdaaf358d9c5609a0214772f1050301828cb147a5968931e570a18cb4bdc90b1eeefa2d994357b907a9c
|
||||
df27dd0739187f28ea241dc88d467cf624e7ca97c41561f818fb354b3774d874:0efa46539d3159a2:ad04f726bfb5191cdc972f8f6b970c0728cfe44fc941eb54fb185f72d3fed33943c91918744ca0d68ac2e7f3849fbd7d0493ef9f621b217cf8d49d433ef8196c1123841b81d155f4b6cea59a27a01a1565380dec60626036d43d5fae915a15b7
|
||||
aca92bff9877bfc35d4c25cf9af70cc41cf0816b17cb1a51089aafb9b5bd7d88:31c9c23a9cc42236:81d8d25d277c486cab2ce34efe06b468f59a56b4c0e4d5d3119647d881aa3dc871d0cf131dfca3ed811149eb5ec53a35079293d27e8cdd03d7543934633c368f4311424a2b5a6af33855c428ab901a0ecdaf594465cdd85264d635029dd73bf1
|
||||
21bffeb6ce5ca75da4665264c683fa70fe0570d95a481dde0ea9aecd3cf53565:0a1c395c722f4fd83e:b98d13103b26b3728d140d535be1997e6125c204ee09e0ec5420718b34ce5bca87c5ca5df9b327128e124a458d4ab375128af9b687e55742931d9df5796b74c2bc10e772a5a849588baf8f8e805a5fcb431d2d2b2b646c3f0b9d9ecec29e9238
|
||||
3fcabeab0355751e59abbfcfaba97d1c018aadfdf56c9bfe6152a3554db48bd7:e6809c7244d39b55e2:93a0f2f5b469ee5396552e7a9038bbe989092d5fcbf6627e035f7107f362ffa212140fb8718b0c182b5f24e3bec720f30fee24cb1a3321ecd333a5380a64d691ba71365ba385b727d2b82f6185498ae4a6506c70b65a623fed121665ec95c891
|
||||
ced96826415c753d6220c495f8189342da0d3b7b2c98411303b60bb3c8836efd:0b7cb2a6fcf257ee62bf:9656dd2a188920a2d24e5c003fc86392f7fbcbe8868827ac984f10cf57379ef214a408bb2849d19560e39a1c54b38d300627b2370298b69dbe28bc4b455177d569b03082048692daae19cd89be763ca56384462f1e2669748754adb9db515ac3
|
||||
241762137d3743ecbe71f1cf05391a1a371399c2c8254f4c138aa1d362d795ec:c7f22dbd191d66754852:90fc4ef59d11bc5fd47f20fa97f8d7cdfd10c9569d2bb352c5ae521b0310d8d8b220914ae087b207c61ccadc53c7bf4019f524a1079f9868dbab853dc69a34de7cba72d7540be146282ab20a43add794d8a66032ac64e5d072ae492322176d88
|
||||
a251d29b73b0b81bd22b1da683807231569a3c339de9cf38198489ca91c4ae95:0efa18547d60e8d370006e:96df624e538d177c55d91c26ba6d678e3a3180a68aa9a11bf9e45760e726b9fdb303488564f879fc91b7129a0e14a3ff15e6c26a968dabe07b38773da43edb26657ec6c286db93c8ab0618e915fc8570c6b2b4f1ce53cef963e067a9d20082ae
|
||||
6f463430d2e2baeec5e16c4fbdce282a80db31b3a6cdf1fad692d261ba78821a:2122e2d2571c6649a02801:9353963e93194b91c1aa71ef9e9d66dddd868f368d58456effcf266024f131d1ff35e0adc9a6959b338049a4fc40b20619d0f509cbaef3bf5743890a414d6e7d39f2c4cf7e66e85aec70a33bfee3b58f3e84ebeb71c4e4edcb88e460783aa8f5
|
||||
ae68c25fa3d2d5186ef818270dd4738f122858e0431bb562370a55488b7ba4a0:05489e98fd13bf202586ac41:b4e67eb25699533de411c7d072a60ad42e916b26d8b9b779e7bebb4657d52fc079553ed98968e9d81ad7ed77e324fb4915d7124b3f006ea12370ca904d2ffd75506c54120a7ea3f901596e44c3ec5782e458624fa6561a20f895430fbf363695
|
||||
59e8933963a382d0d1634b52f6d789d09afe9f411de832caa89c88622470f70c:5264749d484be5119deec774:b716c49e3aec7684f8aaa1f61012cb8af522d73749717534c8097d95056611e3475e351e0a294937071c644dbe9db238023dc1a740bcb55c79ddec3b3b2cac01c8c8d975a4887166b7600ed1fe454b203b4e5ee49906dc7988bc72fb8b629d36
|
||||
328cac74a8f771183690de87e99ddb3be023ca62c37c243aa2ecb3ab096c32c0:0d9caae939afd6f2036b4c6466:908cced630b0c17a0b862479d99eaaf1773b6053b8f5b6fbb044ace6722da5d1fb4668fdf4e468c4dc5407718bfa490b0d7cbe01c0919a8b8a5f342c8fc3ba06e2c4529f82536122061281e4c3ca1f607cd9c2b75eba03585a5689b9427877ed
|
||||
760c5fc9f942cfb114ff0ec23d0fc22acdbecb31d5b15b57d1ad3a9459c40b8e:3a3573a3a6cdff2d2f2313addd:aac2acaed63652d44369876813daf3cd24e66d3cd667c03f3de977bb17be92ecaf15354c31447a51805f7c0381c8a4750d7e4edcbe3c7160382eb54390f7b29fc5fa125a625ce31f41f93c49c50cb5af0f9ab2d493f7cd28d54d1962060f0676
|
||||
2060526e5e104aaa6f56144304a6f4e2953b231fdc97ade6435835ac9d3ba7e4:0ceba10020c42ab9cf4d64ae3486:951fae47292841fd1b50ee4b32b06f961ab29d12a57c156a7fc2868b2a0b4bf42a472453a782d63bb7ef789c1e337faa040703b34f967e2446330b6120766266c70acdb659654daddf6446d80afa984cf89901149bc039cb7e541992363d3909
|
||||
f3fe92129f14598e7ce8231966fcdd535e77278b767149016a502c7483aba788:42a85f4ca158b692eccb2dbce8c6:b2bee8b5790c28a0ce3954fe06694f4c81051a08c6fe91c844d057d514c7d9de2be61bf02c80d73376ac5cf9fc21827b03e85aa71584963c418dd6cf0ab453d644303ff3b2e8148bdc7ec4d13f405e89dcbc685a48c9cf06cce43cc9d5f8f5eb
|
||||
95c22ab56885211c159714cf80c3336685ae64009db9d621c154e50761559ab0:0de6482e4597ce042879305f4f07a5:b32c8a3b62cad3eb41f9f83630e49b88a914a5df2b28cc624f028f7778d33d47fa4f01cf5269c1f3b45453ed0aeee2a909077803aa37814866a62b449dfd89770a05939d273aaffe33bf178e0526657c928ecbd0f80ceeffef9aea2dc1488dc2
|
||||
e2e213db79a576da7d0a616666f4a28038f37e3d70b389c75bfccc0404e1b023::8aedfb44ff3d22ce2d0b27fefb61b4aaa7f44456b7151375262cb4fba097dce4ebd54353e9f1048d7ae9b0bcf4166d7319b6055c2ee1a2a36cc32432f1195dc88112203108e4db786540e1334157e90aabdbd26ed3e0c9abe2e26150f5e65757
|
||||
f392a0265d6224ab1823f2923dd5da25af361e4c87734cd408632c0e34dd4166:0d:a232bfc8c1eba16b6092619432d5c9ca0ea2165a0cd83a4a7b2cc43bed4b283429d5f3d1f94d18ba89799f67ffc07050099d10d6c805adeded8aad6e082588caa3aacc1c1a1a9605fc682fb9ff582b83a44daaa65161b22f501e33fa32fd2f87
|
||||
c70726356fcb2dd2bb9a9ae6bb80868b2ef8e441f8bb651e0710bbe22bc182a5:a6:b449329a45d35461b1f0cedcc20906481121ca4ab8e04ba5e8dd8e6681b57d9ad0c40defee9357c189ff155796a9aeb503c5b1dd296c0545dd03e337cc6281ab5be61e433352b3cd65be0f245e475fe4d9369129a87849e78d3a2851b17ab77f
|
||||
0c87d91d1d69e322839804c1cf3c90034f39a9279014ee549d284a20e232bc7c:07cc:88ba6e38e788cf59896005510a3396bf326be507d91e9c45d10aadde83513996011b4d2eb100197d2d9c10783a5ea27b138adae4497a49af8439329062d7bf3da2a3bec50661aacec7d916e5da0484a9e58a8c0b054717dbe30eae80013f9e82
|
||||
97a7ca86ad085154ed4dfa215ded151b0188c16e3de7d488dcddb202c044483d:444a:acb0568ec50cdbc01213b93bace3522d3072bc13e1c577d161f5029845ad549b71d08c158c98078418900a6c9daabc5c16bc6bdaf9f6b749263f6f6d6a687418cdf0495e49c406ec4bbbc586b96bee78760c9aa2aba4e11cbf32c8e77b21f13d
|
||||
b8f5eb74435a252b35b172f7c7b863c78bff7e60e9c7c9368d33636300faf5da:05d89c:8eefab0eab1c9f12ec661d9b512cbffdc823c3a1f33555421f859818daa9f5542962d9265f297f6b2454bf9e9ef7876806b1783ae641cd1df807b4823cada155f7c849c23709f2c1191743dd7ac842e1e96df8fd7e165c61d8103bad131c4da4
|
||||
15981c773dca2cc1948c4614f26e6d6cd0beec3eb672dd7ca5b1ebb2d38b6430:350fd6:aed8d80da4ab66cf0dabed854284e88de19a97663698c0dd91e59120b363411e46fd455827cbcc933f97a781a035546301ba0f1bc2d5fa9d48416eb6c00cc2c673529009e89034c10a40fb9baa4da241e20e8bb01f33e675a4f01ae527761167
|
||||
14d83b474474caaf07e920cda1919759593bb48e125da09ac7013825b613942f:0db5516c:8ca43cd2679bbac2d9de3763aa28612e89a746fc2227b72e212a725c9acd6d9ecb983e4d665d64d76d64bc1c67d22ad701af6d74cbfeebebda30ba5c00de436c6f78b2163ee4fab88561e4121dcca80ac56df3379267e3be26c06a1034edff7d
|
||||
29f5e89e7a6afab3da8c1ad738665a9da193af9a647e47753c235bd043e9d8b2:095ce9c7:81057773b78041728ae80f63e3bff13d9253414f592162945995ee98a8beddbd5b61f2753a7ea62c53cbb80f935d3d530a143945ac5b3532589253e2b7cb42bf2a0e463b0de9027f89cbdf710195c2c6c0cf823ec3333360fce1c0e6349a5093
|
||||
4213489df97e792eda26d981492a7cdc3100e3cf4bbda19cf13676bfa5140584:020d6ab3af:81d792916be49cacb0d4f3950367bff32c035dfb083634912fd9bc043c0c5e60efd22199de3cc93374c1cced2e836b3e0c678e9b94b277734be7e127ede167c6051907587e43fa4532420ff77cc23e84e9622a16aa0e4c69de7c72da3d6ae605
|
||||
4db4f6404c0c0fadcee5f26717ece570d846f5d0bba9ea9d93713a067c54e03a:3b8cefb4a9:ae1a72ee38dc209ba1c6fe7a295abd821e2898e18db1a479edddfbc2cf889159b8355472d301c905619b170b91e20cb7161a5c823d6ae8090c90f6846b0fd0fb930c28a2fd03c293737a1568b3a135ce04009757287e58a4a3e914a14b13467d
|
||||
f7494e2b206323a2c626a625214dbf342affe585f1bbb0bd54b2c4f9ba7e86d1:012752047481:b3aaff35d780f9100b37f16a7f0c3a4e0b2306e2a5afd1486ae05b2dddedaf7c0de5abb96100166e38ec56fc34672cc418269e05261d2ae952386c08527ca7d89d1c4ee07ef2d6ef0e3412f52e1a0fe868c99e359926bf32ec9b3caf9631d2d9
|
||||
7101cdcf4291ca054a76be43a72be2e7c57b142d697d5f4591c416a2ba20a6ae:dd2ccabadb72:84a751209648d7dfdf43bb68863a3ed0a2c07281c5b8557ead46cb0168d4ff1d8491edb55cc69a0ea4eb06359a23285e0d844c8b0da3d91f7f7543e251f8652f210c0bce4f819f55ca1dac972fd4eddeb5277c9be73974df310fbfdd42090e9e
|
||||
dcdbfe35dd9694986d220b00450ad1c85a416fbdbb15fd5f0ba11c908c4e2242:0fae62a316d518:9037982e4aaf6e7f9894cc267ddc26114e5db5189b09c1e5401f1fb040fcf32efe5799f461f140af85553144b6f930ef0a89e83a1438f85b63e20dc82b00d223384a6c9120b56c6dbeb607ded2d7b268fb8d6d06f9d526ca701dfe409ffcea15
|
||||
5833ac79250158123f356effd33c11b69f4970480a1724b2c0a0a1f3c5d86e48:6fe2514b0b040a:a655dfcb28d84ffcefae998f1d0c87359d4c522d549f1d18307c374d54f189403c4f95065a2b5b366272c1a0e1938b2a0fb4ba410290ed83ac3b55532d406d02a34001d6c6f150721c21cc86792a9ef94a3c1e498092c318957f4559aa3fb4aa
|
||||
60759490c3c1dbc40d682ac8ec5b23e79df8679f527ce5bcd4b98da79172579a:03d670b0a31bb074:88adcbe23b4538911ca0555c28c4667b65993141ae797a71ee54573ee9b2d450c8f5902f24ec0dbf98a32ca7a4c84ba00c1675075b8804244f9ee5c8e746ab0ac18653802fa7eb2e8f44a1346b28a0299fe17fab2a2100d1932c1c8017c04790
|
||||
0c8beec5b19b6d49422b9be911384dfdb5f7b784fb7931a9fee03f2b2b1435ab:52d257e3246a8717:9602df4f595bda5df4fd932daac3ec093fdc743d3b3880e3099324ef3d33b87385ff8fe7b4932044c726645cec05911d0586eda7726ac6b96dd8a7fe19f75b98bd21c926433a2995bbb75aea2c1cd6ad443de37d64fdd54b8711b225813a6efb
|
||||
3e5ea9be9e47d5c03426c6b23851b839462cf2792e62c12ae9057785f0bfaacb:0edc3a78b6d6190566:b7aba102c730342367a96b64920ebe60f749b0d42ed4e91d51c18e31d791142895275fcd39ef09c7a6759d13651bdcc4022f8c93c77a0968a77e46202f8621ae7969e1410ff6cf5ed9ecf6df14905322a3c7dfdcd01afaeb0bf1bdd72545e7b7
|
||||
4bf3c40acac842af8eaffabbe90ef74faaa20030a57e029137a61663db033997:0ae34aa529a1053f8c:b2de94c41c453ff9b60696043f6ed76a3431bc1ab53bbd9e7c89eb482423872a2b59e8546c8fb9b8b37a1c8b76f43e29147b10e64485ba5db48c0012c7a969ba99fa7718b7540252d9e49968b5f41722f454cc4b1785551ad7c7427e49ca4012
|
||||
250d8a3e1d48cb69ae2841db1b6ba57cc0db311bc03570143204f9884bc5324d:0a9e59fb4f4d4ba10ec2:a0e4a43be108ddb82fddef1e59a6e7dd9fc84ad183ce393015d472b596b8bcf84a16b9a54a1b340ea001776bcc8d5e6502624aa4cc16bb3817da98669796dec60fb23c9d0a003cb78aae4c2b690d56e98026fb5a06257e39fe01e6530ed177f9
|
||||
480a573b009ad6847742cf6eb26226401a21fcb00d15605d61d07cb2dd36ce16:a450b2f5e5993ef50a4c:970893411b7a3187dd195dd078cb9d49e64d6fa70adbb2b0e900a82048ecfc2d95dc60cb2cbb066a04c2b036e9d8c952155197e6dad3ea08385f7c5e8ebfcffac5dee95a3ec24a894e9471341f7ec40ed9d51db2985d491fa90b959b952f8be1
|
||||
b17c398c3b5690a5f2d9df93f528879f720a32f5443c455e68c1ee600e1e3c73:0a8b1c86fc50e996c7a251:ae60f93c097e49ed430e9d4f13e67f601431032b980d5604774bf3c179182f8b9fe2bc7510daa71c7cf3cdaafda7748800e7eb19e250c640f54194fb979ea41d8657b545c4f4baa95503ae06848f6fa957b7951b4f38f72654f0a0f664b057f5
|
||||
6f3d3d9ae77d068a241ef8832a9532f77c810f5fb66837401cf9824a77fdfc4a:8ebaad7cb6874e96ac767b:99e80404714e26ac20dc0c1d87b548a08fd427723dd4bf8093eca93c7903657b49c7c8eaf36cc98de460fff8b5dd0055169f9a58b0a249cfb335ebc06318bb1a81ab24fe7df3aa2d299a23298e9b29b98bc5c0d64d349b398fa763398ee9ddfc
|
||||
fa93887ccdb277f5017081f848cf7fec935c112ccce72275c9a7b6b4758a6b54:083d040e50f2fd72f2ea77cf:8ae387dadb7cb41a776e39ba1e205686987f2171e5d9aef3bd2d9806e269a511e67b9cadc6c20d7d6b1f49fe7bac09000cdc5c6e765ed381b12cfde05e3134cbe8b51c26142e424bc26822a235f722332f71b4ed2c89999c05e2890f8411d7f8
|
||||
23bc491c2142f7ddee2e8985a3175857f897c399f697411762554cbeb00de659:91b32862312873e4b7b3cba7:82a5feea0abebef1b71659cbbb51e396d1d6a9bdaf3dbc45790023d6a5b46b20dbbb6c368af1b034c6e6e5f8039d1c28099ddcadf7b4153d4411af1f79277571764467f1d083f5815ad45d265184f431b5c05166e708d55ba049c6882683d331
|
||||
7272daf5146e93e068b6cce38fd07be2c254f6d2dc02c7d078f9e080bdf5408f:089e270bb1a4308c4578e0f6c0:916be2b7d46f009d2439a4c8b83caa6877b100cb0af4170ba0c5837bc92047d84e883295e441b44e0195dbefafcf8892126b27ca5bd2b126b6115b2a53ad8c5c889d3c78807dff9d72bc4e9a064743465ad025c1e2c08fbf99b0101b15264417
|
||||
47655f711cd82a199e9418d4a5baa779d206d939f7f41a9b6ffb9f87d6ceea07:d90c4391d34e0b2b40366115d1:a33b21611a27397b7c02e0891582c1f5023d2cbc69e0643a7c32d7267e6d8042ff8e65839e5093d1a753e97da63ea7d600ff1c5957771f57850c574d167a8ee54cc986096f32ccc40cbc42d9fdd83acbe11f4e4ef9db36b9e41f7aa558f4eed8
|
||||
f056b12559a6358e99a2c6a1d86f267dd162c3012e4788a314e298e7c416444a:0cc73ebec823353215affb7bacd5:ac150f8b9456801a2838d467ea2fea5f02f8a96cdfa4411df3d9fc30721468540f372e70f00607dee69270deedf7e39e0c6af55691fa12fb1300bb68289f351ed1d0d49aa745217c05533ca46db53192c3655a50fd169a41477346228096410d
|
||||
59014aad89bd97fa2489c2b43508c31347ae8437240d8306987e63eca954dc6b:b29de70979d3459bf0f52480634a:94a813a737aab6aa68919278613a28c7a79e6e64b3f925538a498338e7eae29c0f73ab43a2d1f0e9a99d06ceadf57f8d166e8c4295b50269a117aff566ddaa02a5e6d4fd40834a96e3257ee219089e5843c3d1e1fa97f7a6b3119d4a55a0693c
|
||||
079cb55cbf7d8668c79aa7be998336c9e44232f2040c19fe44b28651956888f3:06884140ea3d1aa1afa058dd19602f:add5d4e8f20484f247dbe0ae2705ff8a84f98ee988ee14d0398bf58ff2711c78064c3f9a284089267dfb1ad9828ae6f116f7118e93978f1c8ff92f1cc52c8860b509270a39523ad6473bc48029877a26df0f074f959532a5aafcbb348ad4f712
|
||||
86e665d99c887dc7b90a0c0a1eee2da0f559cf83a89f0b5867bae358a4f85122::8330d06e9c3958920fd81bc143c324a31048d97a4179ceed71af96e02db2b6c2fc78445142d3d7e7b930b38ea511f17509db0bff92a6f58aa332470db5149ed741f091f545cce07decc9028ac4ce1166392717f0919e0a035fde449bdd462084
|
||||
1d56829c94f18e598084ccc64e4d2fff82566d80a0d00446078fe2744ea47c29:04:8cc2f05194bb4fea2eb6c816626d6b17c33de7961c0597a74aadb51585d41fc0b04eea200fa70da10ba6701abe128a5409c374cc6ee11e516c408c11233a54175aba1f9acf49907560da8389745f9c3fe2622be20a68c9bc733d6a5ba63fed2b
|
||||
1e243e4a9db47f767b6c9dc99f211312c3dde97b50c7bed9ad6585d5bbd2be78:2b:a8f31f44ad30aeccb0d801adc3d0d6c850532eb82baeaea38cf3829cffbe9936a4ce0b76bf158ef2e011245c4c9b7f5307c47379f4767efb52366dad98393d67fa56defb7831cd786375558f2c1b4fc76d3338a468859c014c8563d7be49ac97
|
||||
785d7dc139f866d0809a4072cf6545e79e285347321349ee6d38126ccb5f0a33:05dd:ada77e687c122d58da63e7ad6b1612891d99e3d88302c861e1cf1917f48b49bf531c189ac2dae7dae09db6f6b10f0128016cac0d0caa55342ac8229c42e3d2b27913481989146b977eae6b323895ffaed10814a0314891edce5208c835e2b65a
|
||||
fbe9ade713df63e2d1f592c750cca4fe187e974cd1a03c60dc2aee1779d8db2e:e8d1:adea816b1732c2448f5af1679623dc11f3d8aea1ac75a07fc6ad287433b3223e123473f6d8bbdd59a4ad4db7148f3af61753a2b0e8419ea39a5b1018c24b76e6e72622b1b3cc5d05c02efc421560d6c35f3845a7020030f65a580ee0048adf6a
|
||||
d7aca7251337ac082a9e885f862c3e52af0daa44244444f9ad2a290937d46347:0b5cf4:849d9160feb1423868715cfde8a3d35a014cda0d02fa9ebb2ec0604393d9e61a4912e18fcd423af2db277cd2c4e3f8e81617e131f647f4f1165bf93fbc7cde92dd7056e027d21ef9e8f353941ff4726045ef32d4375ba5f43c5b5fa368a1fbb6
|
||||
3fa39be7a361c621ce0e944e01727db44e74baa23c82b4a48d9c0b350c680eb2:1de37a:ae2c347f8718815b992d93c9a8f8db741ec2958ec95123aba339537fdbc63f802c06f6cf41e65f0f6e3e5d567d3cda0207c9223f7144b1bdcc6a575b3e667f3d22724bea3e7bcacf28458e7112c96898d0bf5695159a7bdb5d7799834eba3fb9
|
||||
fc40ab6dece2a42366b1418dd249e808d376b5b63d9c15018ef7285d440d46b3:0edc1d2b:902ad68fe321ec263d0303b10546790399c5def45b7017b9b46a0261f0d3e907b3239eb63ecb9134285fe0b0d51c04210ac5d4b1c095b608223468e57edc61cc57e50385a4c471bb4a5e57d185d8404942ac0f5ef84c8914fffbbf2e9ae24e80
|
||||
3463763af0f0745e8e5ccecc3448d54521ec6360b31cd1f61461baa8d9430d85:81a2b9cf:b86cc9994a7664a88cc678bdc8074ef6fed1fd9d67487aaf51d11fba9c9677a8317bc3c6b93ebcd15faeaee195497a0e19393efb8a53aae96610701b7d827fbc72869c454bc3ed54abd119ce51873262e96c00e378778b7d6d7c44e8afd3da5f
|
||||
7875b2180b7a07743b340a85acc9096fc3b60f3774fc7d12af17761f6472574b:092a75c121:9352ad15bef39e8610dfee782301736b630b2cae357eb56dd16e8c32d2a4927e758f2e78ebe482c4162aad170ee8edbe0f73c90eb7705fb97b5c6c86df6d1928825ceac93e56dce8a61fa495179f14d9ceb794eaf6e1e18314c609ad7fe5348b
|
||||
43635608d29694b3fbe8c491bd2f56aafc95017e99a7c53028fc8aba1a6a655d:cc326cb7df:951d25da783cefe075e22de837614c0f03791a0e7113a6a6f5505a39c199538ccdf58e08a0e4f39acbb9459be5fcb4e30db05466f472c7cafa8cca9d0fa7a50d2644dd71c6c1f212d9fcda2a4038fbba2f16c8acc2af3098dd42257cf1953f6e
|
||||
c831f94ed4e49c83e82c311d298399e56bb64cea460418833a7f17deea072265:05d9bb10f795:98553a642571c558264f1c167e4f11753e7ce32eb5ec00cda23232ab6b1e84d9b2770fe73611604042b2575765ccd6201996223c32fee3fd37eec9012c949cdcbf56e1067f184bc3bbbab3a9143715a546e3f5ca8d91ebebe9bcdb93078ec941
|
||||
5062a749d8f40402f17c8793aa929f5cf33faed38663561a38d590bd26d1bd93:7bd0c2a0cd58:8e666a772334f4a599fc3360efd49c00e0062071dd6aab348acaab791a9faeee4c5156a7771cbf5342d49dca753f312d0e436cdb2d00003d25d41e06ed593d5dfe59f2a231a5fc890c59f6c784be18ec502eefe1fe90c2ad6c2f7f1b3ef561ce
|
||||
785215acd386bda56d7c58d543e0e31bcf5f87488dba7bd46642fceaf26e8d24:0b65e1b2eb4fcb:86621d09e52dd8f4c15d44000274483b93e2f3f9920a1f30e65c84cbdaa8f6e793c1e830a30d209e2c7a84ad14c14aa506291893da4c05fe16710d55c40ebbe2827ef67da4fff0520579f0273be8279a3b4f3d5343df8007d3f6161bf5c73723
|
||||
01064d4e8efdc6631fbfbcbf7389572e82cd5107f47356989b9eeb1626ae277d:1db604a6a3737f:8c8891f0bcd2331d4395a75f47d9206da3553c839054ca8e7e59ee64f991d69b0ed42e43e2c96956b216626a3da15e2403a620650189b389a13f14c39a75c44cda966f7dc69a93e79d6678f0420407d66e7916057ba8e2eeb19d0bebd508058a
|
||||
7e52d56764d5b7bd14d576913a63b04f28e3cfb816b3afc549e1190a2fcd7cd5:003ea498258fac12:8bd52db56c313ac3f0bddf4d11dda4e6d81716e212c9e82fa32ccf0dd0b1e2359e3e12c6e988b17d4f9882a58dac083f15c2ff4f1f8f82047e8ae8e5503d1d84c864163656f7136aa106d627aac5881461433f30230e378dff674ac9c7e31809
|
||||
07247477ab86d4b41a3ad3bced6c08f93bf4dafe52bb88215faebef0de956746:8fdebf997b921d22:b50e9f99992a08959991fcda9654f5462ecc015d3b894c3477752b29a65dc05248c75d7acf152d7cac32ec45df93671d0fc07dc7e0a46ab0f5246951575e290b74ea6483ce7512a106529dc5f342d172ace7f5a72c6cfa9a929b00f616411251
|
||||
49bc2b3d85e073e9d9bca649fe7d77624cd0c4186cc816ec767ee5907be6d4c7:08a6d70240e42b76c2:aa666c6474f8550ab282b480c15355737b1c3c3f496d0924e6dece36d052eb6b8c37adba328759dc6f930c1bf40e866a04cf9306d728be9d00d56115509c74c54a62b0456de48556e728335864f4f99f3835d03e5742219a0ba1fc135976ac0d
|
||||
6e1ee2e476dc25bb44a8ce9a100ba3719b0be25802292723688b6094fa1e47fc:9ab597b9bc1f9f0c04:98bb5a200468cc4a7bfff04f913d87c386a5f42fa67d39c22924b24c985726db18c066b45fd4715fd94c339246cd683312120e2d6abe091f5fd3b0d75c4621fb716e88588e9449db8ea0754a06fb5372000391c781aa9109e0675b210d8a6399
|
||||
912aec300cac053bf9e8dc0173d46c7ca7c5b6ba23bfb18b9fb681b56dd3dbba:00707016258cef3a42d9:88adc406bd477056f5aeb694effb0cfb816675b45e28904fb1e701a3ee87e8f75d49643ac1e3e1b688a6a2acff48d7be12f3374968a86f7451ca35d8a1c0fc835986e78e954b117b6dc12b074c0419fd462f606de08ad153836e83f70f9f6227
|
||||
9544249f393171d85c19e23a203e820974074033151070206931df1f104f44de:5e69f3e560c6e63050de:99c2d4a99976691da1f4bf084dfb86f62d10a48d6316e7fca5b0c1024fa2547f7c02f6d3b775ec4943f88b72779ecc7417c8390b4624435bd7826be5e9b06994224e17640a3a54818deca8bbc11f04fc7c694dcb84e533560978420185389d83
|
||||
51951b1c9e647dd724bbb68c7dd976d9e10f0eae1ac3f6fc1df04446c8f6558b:0d01c99a3ebabb5bb8d241:8a902cb59d6ded491e703682530990074ac486fc8ea5308f8797df59019e429a536f10a2acb5b9906d3a26bbf38c6bdc005bbf81104edd3b384b46553d6b66b2db8568c00e74037ce07eb9fca764850e9921d412e0287d9ed2a1bb7c3660d7fd
|
||||
106b77fe23dda6e79c770e3e7d8d0dc5f01f6a21859f1ea2e37211b7e3e9d20c:9778045c939a60ba245568:84586f8b09fd69b3a38d317e89d3f3f5885bc6aac18c9a3ed5d0801df91f07c95bd77db9864ea986ceb9a4bd19fb4ea419ec7c46c35e477251fa47c05d7b0a6175e3ccfbb24196aa3b2b2cb48ddf9c8c0882a6fb32707a83d0260980a9b5528d
|
||||
cb71f393c33749f189741023f86905a494811e69753ec416c4a0572167e8a8f8:062c15949918898fae30d13a:b9a2b6288eff5db9ccc9dee7c243d13d7331d6a146bd62b5f1be093c9e077554d9a414a4ac53372348717750543ab2a90151bd7fa36fd84132bb2c80dbf45ff37993656d91914d10ecfe87e4b664f5a569c440ec0be6dc98bb27ee78fbbfc103
|
||||
24182d5dcebb1f234add96901337c0b173a5dfc0735ab8476a44e8d1497eee11:2a590d539dbcd9cdb8dca9af:8b10c6a7efdf6afbbf600543bde5d43ca322a83e6b085e5dc08c0eb9b2cec92a69776e1dbc64de47a4d2f4d091426d79182531706ca25ef3ec81306da03edf70161bddc53df3bfd1447530da7ae1b94344cab0d829060abf14827a87568c114a
|
||||
29f81c0bdcb8098de92efc9aca45df19b581174bdddfa7f9dd4eafa217f46231:0c413b91f979ef7e3e3d0c2a43:8dcc40e3267a209ecdb869a11199a018acd9bc872a2738296a46769ba1f3d5f6ebb75471b2c063dcd3ee89ee34eb032918d78468608500ec66c6496c28d3f56f1baf87a4097de60617c0938895a55f10d54c362ed86b3899edf48fef00f0607e
|
||||
e44651d84d62555d5a6f5b432b51c4fd8440803bae8b0d477bd366b12a61dbd7:40c7087d70ab2ead5992c3dbbb:9750f6d6d5a53cf4ffe61047c9d9d2bf9f3bc6a727093b5d648b3abebe6c496bc30b1af8b8abf21d678a0054c03efd85105c36fe1cc61da2b5b18f6b71623db10bf93dca5bdc39c53b33e5cec5988da228218767a30bbb7d0d80abae1782f9b5
|
||||
bc16d0b8102bce82811b6d56ff13dffbe690577e70a36ad607d48ce77592432c:0ba94d4fe8655980c0caa90e3309:ac55fd7f2635a0ba937eef6176741b21533fea6d8a8b5dc3678f4269ba1e1e06d9e3824a226f7b130546c048db9eedda15bfc486d9ea7a69f4eb04d515627d839bf3fbb6cd252f2adad65c127eacd362ce7b842cc2052fad14d8e6c3299230ff
|
||||
2a9c0a14191b6c8d9da54c2e7323197fc5972d6c2113b8d3f4aba8eb2419f402:80d1192fbe8c7edd9ae58a5fa715:84b02c4f728778a29ce1273b6e77a393941a87173764e4e10593faffca0a04b97e444b1f512e6f92de1fc9096ce991a90f389e78e5745f64c5b589a331aa9e157a71a993c96917024e67f13c97ba2e070fe1e3b2db91e0b95882f1f3d64727ef
|
||||
344bb9ed7b08f405ac402c210d6ce9a251700f8f39d9c13e72921f993b0fa657:078698bed3b7f59cf6041cc5bbc27f:a0946c200a29a99ad8d348d3ec627c0944cb42a6ae105f18815ac85798d656b33acacdbb954adbbd65ba6bf031896e1c016a0dc7b667ec3662e54b8951d93a3e03a2c8bf3c3b88af29c02e5e3bc6d221166902d98a94842d855ec65506ad6911
|
||||
a5b50c63c3061e2e61ce3df7c5d2b67f666e3d0ed10529a9f2cbc475f836c4e3::99990d0c901c913e8385a4ac7a4d5808ab07e68cda6c891af55ef2e69afe6ca8310b9de5c1525dfe86c94e33c51f40541518a6065f6fb036c4804fa68e1c2f5d5fcdd5d1ff4d9f41d0f814baba6b2a00eea0ccb4d7d4ca6c3a87cc811efb60ec
|
||||
41e6f409f3a9ec0d1b53ec441b6302e388941b23005ac48c750924bffc28c95d:09:8002a5f881006ea6f1c6f318e7529b1c8d9d1cb7cc93d75fce7d14286f125e03c47090f9e2bb89350ab85ead94e172230cdf1e9d76265579cee29c487e8a15884d6ff78646e634d01f7d66a9e155bde7908657f655aa711ec53fff05d31a3d55
|
||||
c3eee1c7204b843714622abc2d7ac09747e8e95e0ee2e9217230cd97934bd46e:8a:b6eebbfa763dd3729a18836f1a8177ed6ca43cde55410880c23a0eb26363a1f807e02605f367899f361fe1a5bd6ea6110ec26a58fef050249a27e5d929262b12370c2fd8a7ae35abe35f8381a0c56c07a0774bd5dbda0293b165c6e9eb4a1a3c
|
||||
ca9f5cb4bbed875f6fda371f86d523b577622cf57c6df9aaf7b5a0a0ee68846d:0831:8971b2289e864164a53b6901e14c3faa35e1c6a68bd5eb81a8cc897bc8d17c0383ad617519b4dfadf5ba43a69c56077608ab6ff3508bd0d71f9738a53be7a907fb9f9f1bc41ff8b370e900fd70ae63da49e2186899631a8220023aab2f4ba1c2
|
||||
01ef1ede58b87f0f257a1cd96d71c1eb98fac782ee687a639833fc73cb64df93:79c2:afcea670ffff566a171fabc5892ce1c974aaecca3d86a968c479f9689ef37b7980614a837207e53c2f7ec0701daf17bc13ed6e80f50853a606c8d6d690cb3778094c161ad162666f46c2f76d315f24b8ff90cc57c1e57e15bbc27aa94d41049d
|
||||
e982fcad4de4d9e09a025864b9c254b4932c6b65441383e93509f48deec1b742:04a8e1:b1689c1450faa975c63fc9b23306020c89f9b855cda3d40a99c9f591e2c05ef2e8bb0983d9989193e52c4c58716bc13e0c0908f73922b0dafaaef2ebe7209c53efda40ef23ab6534c335b504288fcbecc3cd6ecb370cc55d1faf350cd9a50129
|
||||
1bb7932556e42f4f4fe9ba0f59ff17bb2245fd79203f78e8bc3de488fee40f11:8d0ef3:97dea1e05ef0d1af9289e64866c91e7b8fe6275aa87f6f70c3a9f16b411692332a0d1e86666799faa91eada62e23ba6705a69a55de44696b2d2de12bb8bafe1529217c87bfac57bac8d866b09aa208ca8ae62156568fb7172ceb0f411a171299
|
||||
6730284b18c2d383fedf4e0c32480b06e9d05b380530e7acb9bb055400fa33ee:05866e46:a81e828917d5e25475db2e23e35f36c069150f5ebd846061f00bfcf270d3124b42103b48f915bd73236fff0f88afab460508c356998e8951806ca54967f26eba9ac1e68ce22da4119b1b3ef4721bc286a0455048a7542df4af460e1b53d9c351
|
||||
1b538e8f7f079ccd4a564273a913e96a54c654a0c028e39d2e9597c9ff2a9813:c20027c1:b0636af64caa68aa331a61d5b6d6f826ee3a4838a6d1ec9693559227e80737b244829f72976c7908948e633040f0a47b073979d05bdbeebad1c49acaab6aec7a1dfbc45554bc102e0e88e924f49bb7ab492f7e1011da3814ea05071bb722c8eb
|
||||
4adb9229610309100770fca18fd5e6e707e7f27f4b911ec0f53a6114a906230e:02c7973ed4:94e16548d624b5493cb0449579376d234c2ae597b347d681f394ef3e55fb3279bd361d83e3194b32676c1210d616db8204064b33a8f0d67a21859db0689da9447b3fce39972996967e6a85a0839f9a0253bb63265ad751661e035c8326ad1fff
|
||||
c8eb027495c259329813356f1b9138f98bfa589b0f6aef6f9d57523b96e10863:2be4521856:af7790ac25ba5a6c789e81559619c89f9d2b48015add999c73efe4d2d87cf809e82874628672de403c7271f51b302a611773b67961db04d5328729b499e610aff65a8aacefd0eea0dd431c80abc242b409a65eadbdc1e8d63a4489e7d468c2d6
|
||||
fd5922ade6bb2ed28516a13ce17198222809c55ee9730a3d4a3172228a1740ad:02dfcd963c93:b1713a07caf39bc408abfa53b235ef610692f7990ebc61f28af2369ad690f20ad73562374f3101a9893401c22252e3c20bd5baefbe97f15afc68b411125cb0fb0a22b00f8f262964e07a4521ae0baf3cca7772334b180499827cbfd243d8faad
|
||||
0fc195c56cd4f54fc81f4f78a4abc2ba834b5b0018bfc150a64e7c6a5823933c:ed0afd7c4881:a40286e1cc833d2adde1d0640abbcc2199b2767b27ef540420dc96f12deb14af17eb655cd2e958a52a68ba2bed2e3e160344101b101eacbc33f3c5277fb1ee6bf6d9b866b5b8f5794f55a5d7236d3ca0de4356bc1e8cac30a2cb87f94eff4817
|
||||
64813900e765c40ab4e7eb9522e2c21c1c30756fd5fbe40489441f11c6908ed4:021256b10a08ae:a01a1eed626ffdb57dcfaf3123c4ebcf03eb441f287bf36f2209f4d36ea874ff42c3bf8f90a7fa164f0d133692e0cee50ae42593571b8b876152fd37ae62af446ac1b9f2aacd9e335e67e7735ec92e3b5aa85fc4b97379a08dd2c8cad23cbf30
|
||||
4a06c487852299ff3e247514706ef7aa6da0d2c1a1f7176b3317cc095d01a51e:5a04c28464f32d:b8b7111ca66dec968135c1b9716a3d162ad946f8e24d7587b27c0db7a39c70bf7d97c1d968691c569f913ae5255c3bb1120cf1f87fff3014a37d5f8f79a5ef9f9d1f86bbbc6c5b3662d1fa3de2fbdb3c20d0960671cd6dbc1336f16f3222f399
|
||||
e9d0db97e7573a44825b69d0fed6fa0a9587b947604d9740e44c1d59af929db0:083cf7dcc2603ac4:8b38447c730130d59c991a9e64601523d69ef43b05dd019dddf10e2fcf48a6de7574da216c9fd27013764c86a266c22219099e3f2b88adeeb528b4ce995c846288c2a368f78b40517f969e8f44fc42ae8ca8144e093b767e87abbe2f6d093e8c
|
||||
19ae9daeb0826f765cd2fee0f6678724da5cc4f8ad39a339fbeca86754f8b19e:39c99c18e1c62745:8b04d6db47c8acea29079dee12e9e31e435930bbac9ecd2dfb425898829b629ce3264661e16e6993be9540aa52828061079055fa69ce690fbfde7befc621147a02b94c86e43f2d7066e986f7f6857ac521e005e08c70a8558a19d549067bbe68
|
||||
c913eb03046a76eff671a21d6832ef1ce54845df87964c133b9cc9cdf0bde2ec:0dfe207168723748ad:b60d540d859105b3aff4a383ca545e0c5d9c1d799ec24986406de3079694d4e46dd0caf90b7543dc8e01c346f7331e5f15f0174b7c03dc164c76040b9c64e0771fb7724567dc93d3c686cfce08b34ce351f7e88cdd57101679600a27adb24c1b
|
||||
0a39e99b16a69b706fce5095dd0e7fe85b4dc521702e3bc99a6fa919415c73a5:619b95b11e4f8c670e:ae67f2f1f4d8134691100ad694bba172b1997f4d1888bffe4e0386382f09bfbcd56520a7a3647d2cf3565c7f8fd47d1808d7ea678acc1c17e272484296378fcf44f1719af50db7ff6ea3d64d5435e33bc20658b4fd6294ce6103138be0d74401
|
||||
d1094f56040bff0aac7f1e86ff4c599b61b7d2a1a190498920b00defa717511b:085bdf67568eaad8e6c1:982c5233aee8dbadc89f13e8190d3cbc630103edbf845320ff56eb1479334f4564bea9025d89a32536ac300e06d19809127283b6f9dab6e196f08fe9e32bf4456441fea4eda70e8b4bdf1aa1306ace1c3731432bc17ed0e1a3c29ea36724a506
|
||||
26828c6e8108d8e5965e8b91fc59b95dea696580517437c42c27bdeb650d3cc8:65267bef23e56c1361b4:843e467dc7ba66fa39dc0daf8cdbaaba07dc8c38493779320f8b7d148f9554e1a4eebfa8589f3fa403ce1fef29f649f00692a0342041527416e476ad36181eddda07556639f921c1d09b4f53767c9436c1b69925a3b391475580796bf449a960
|
||||
b70b1e21a37aa421a9f522ca818787ac9f13f9362c9b481f0394e4619c0beb54:0c3639a554e91d04d73f2d:9209ca4bd6a9e95853d16dcb42b8436730d4ee39b32dfc1f40cddbafb2f737ac89d19bb75b51c1c473560d6339b4e02f089bf22094a5870e37f6df236a72eeb6daae4b8d8fc56d53c2825e392306bd8d8ad1bb1d2198332a6ec0dd7121743549
|
||||
28cae903780d94f5a17c6f07cc27c0c55d8860decf2f923e1bac274533f04509:ebdabd1cb56e3150770e59:85075ccf9926542cf2f6e13463f4ac970cbb8d65711f84911c31fd0639a009102745cb328ce660cbd9b63b2acf87fa2b0e65f7416691f14bbba4b4e8e5a46b35435a2290e43022bb799bae0c697891ea4a0ae90022d7efcf192ba2ff730b9183
|
||||
9b2bdd74952263a3ada2b584d98bd92515897cd1708f1cb2061a71f567235228:0c89a5a5c90178ea4669327a:9952900b3581d96024159ec648da19985318dd89bc2917119b09e1f9b8619ed2078f58239ce74a9c13bb5027f1566ed30ec6ffcb65aa6c0e3a85581702e91a4fe360f8fa98db4ac513c8e53a8143c5d43f1780de901cbd03a8754d577d0d3bab
|
||||
e138142f55e120ea4bfceefa69fdd4b44f2e746120d2ac2071c78c003a6158bb:21fec9adfc423f5b7ec4ce42:84253268af8162cbab69b7e67e8510dfdae04478d2606500e2775d546c637542a50ecf5a2fdb6f567dedf7bc7831ae5a0f6b19f11fd2d1277628e7a9ac3ff9bd093891b844229ee245f606931e47e6c62c1b8a664f790d2cf708ec6863ca54a1
|
||||
e6f3222f95df5c99700e01e5458eb013f47cb0d9c25c5b882738ed1bad7891ae:0843c07218e88e9054dd0c0bcf:a8a7ff07c12969275cf9f554fbc0eb40d21dc03a106292f0862e1462b72f394fe9dda61a2bba28ffc7cf8bd0c56c505112a43474029ff8e2c6cfefcfed0680ebc87499b9ee11ba5474e71f7f6b2472531023b0cb1770aee6238941196ab56255
|
||||
43b47b97088f55c15c22418b81078b9678c7539d5b6ef30b3dceeb248fd7d610:e0f4c7d85159379b8d4dfa2ed3:8f0e1fcaa287321526d7f7974f68236187022c8ffe12e3dca46423745a4796292224f4e875824df2f2d5944dd547c80817e4bf1c4bb5f98dc2b17b2367bf048bedae6c0827be5f2128949fffa9787e4f9b2aaac78f19128ced220cb1cdce9376
|
||||
77c94ea4197d049d0b6ed62005679b2af50998d2c44d8be8f7b1652a3ac934b2:046a16c08199f8b28cb69fa7b095:a4a493b13b268772f674650dbf359c6a73bf664ff68ab288c650f0d4b4140b917c726b879bea1b50ffac35868a3aa268154ae245c5159620e727ec6e4b7eb8617331e35394ea26f0aa1dfcff87f0840f8976c5e95641df951d66b43d02d31f1c
|
||||
365b875da7ee5cf2a37716770bcd2a49012b03b5bbe828026ba4a17a999b2b1f:d5cdf315f32aa5e54d3b993e15ef:a0dc1746699105974d79a75f5a051bca821dc341d5e2921ea45ace70828d87ee672c293854fc18921f56ea6edf067e8209c2692b9e1365483d4dc9c6e70e1092a5b678318778975aa44e51a6c273283d66348915a9b1f66230dfc1a4f41b0423
|
||||
793c2fff43bdf604941341dc4d2d6d7e4c64d3f3d5b21efd8736b025fd657f5f:042704c4811785813258ae148ee2cb:b69e8bd1a4e57514ddb3722b3e4b43ac57cc71cabf6bdda81234f8d82ce1a371375457ba812ca6b22d0db5991eca2f5302184128fa38e67f53868d09cc4e76209a6c71e9b9341dc72312daa1ed826c74252111c3f100eb7209c8a6ed0e82495e
|
||||
4ae51471cb64596dddd4ba384f6914c62e635fe7fe2b48bfed3560b9853c9c5f::80d9dfb35f77f8087eb5bb5bb7b73b3361c7547aa9ce1e640052b348b61f113d22be6344300458369b64d5bc16bbdad20c13c1c0a7310fdac807c9660c5ce709a837d487d0bcc69d247b5973e470d982cafe077ab1a5244fe7a21fe99af4fdce
|
||||
24e5956ce7e1c26764a1212f5b70c8c635f53313eb8ffa24bd4b22178a70400e:0e:a1bade1469fd0949d6916cf467a67ad56245a9c234a9fb1da011489f5819a01da10b40983151650a3baff01d4931f117084e15225f8b2143196f8c55323e5e1dbcaed2c9339083504b97dfa31d01fe5b320660ac4b348867d97aa5bfae4708c3
|
||||
f1c2156e0f353a0e05564f455af66d94dae7e425ab5e9950362bb910aeaa6f05:5b:8c0b7235ba1291e802a58a4cb855215cb24cac84211bbd1b3d0a92a1553aaf360faf5b7d4f8e7bfe3c1866a4b44eda0d0900f3ec49b751ea68d1bf0817afaf15a0db7c25227d8946194df6c3cb2a2b10c2960d57df9e343b84c6c6df579695d6
|
||||
1d25ef5627abdf5331c07eb922d70e8c141a952a16aaa63602a664e30e193964:02a8:80970283042e91719fce9271122ae72d780709ae2bfe8476f37abf6384e4c1d741585f0679010a15f18aa87e132bd120030618a443a25096f1beca1958c93f28696f2e9938242f7f83d6287eae5e3f1093c63bd3c8c9841ab9a3f9d6afddbae6
|
||||
2f5307f7723b2702ef203499e5f01314f62ffbd448c859debab940d0d13acddf:9b71:83c20f7dfd803feab7b92e4619d3fcdeedd617056d3f4a863d2aa8c762ae2f0e9d10fb639fb1cb24cf775da646c887cd170e169aa3f99665227a8be8b74f37eb64c45d431afbb453a10c1059dec817550eca3ac5798fe97b6fcac44b05c3f39e
|
||||
4fc8dced9af2d9b5839fc71f2242f29b210a75012360b76fb73e7a0f67236ab8:0518a3:8282811085e6a7532edb00ce977b1cc0ca00c5c482d572764350f0e15e5ecd745bc0ba1f124906b72f10e704d7ad091805b1990e4f5749526bb3f33f3e145ff3a364bb0850efe302dd3f1de79e77df272b27c8a33d1bd1bc9dd594590949f92a
|
||||
d4b047a745d29f10977f7f85f2335e9e6cdbc9419e7f7c54f389eccba9222a8a:093d97:adf10bc3bf7673880aa95b623f4ac4e1eea1b4ab8d603823f88f5702979f251866511dd70df1e9214095cf281de5e6af18806fbed85d4286cabf4a2ea5f03af3666a25efef653f758c67a7e8ebeb312f22f43dd6f2dd7b50dd2c37b4202eeb4a
|
||||
110f155f50537bd283dcf6a0b32d76e33369875d25522912c8ac5c5999d15c92:060ce567:b6344848642b6fd3b15d5cfe8f58ba33803bdaf8d2499fb6cfebba69932fed5a25cebc0873cf7cae39ad0317e2cd62de069eb4563cf7efc33a644eea6bc6f3788805bdf3ca2371814854223fe970c39d66d7216da597865c7371ff3b3af6c7fa
|
||||
7222141d6c07c9311bd3ed536a0a9038844c025fe2241ba3e172a74c5dd055a6:a6623761:b1ddbf83dc85a9f597a16cded7074f8aec09c5260c7d4d896fcc5b9857c81c77a9f48339f65e916c5e464b02ee4275521072edadb67d97bfa0e01250e5236f90cddc5afd7c4731ea9a4cd97c54c229c4a1f0793f62d124abc6801c392bd84394
|
||||
80a54ce355ee0c2920098a860731eb59bd33962bbd8bd3978bfafab8fe206d21:0cd2734ce7:810dd97c12e3cebdb8a338515e592371a29c6f6370a668752994c1ede906852137f888e7fbfe03225185f54e987c14f3046e0b61c444097c24ba199117bffa055c0108e255fabe99d1076d96bb8897cb9f4edf03cca655b45631082b0111dbeb
|
||||
8bd743963ade02ea63fc37a7a733c39999e7d1b11b2318557ac0a135035d08fb:8eadfc5e31:997002df650fce37af6f759312169a6cbf015b17a3065f29cb181a327f6a56e5614667cb84da7e82b7c49a62fb587a990c892549fae72e5463e0eac0835b2bb82abfb485d90ac66a0ab4be07c10ad35eb9e63a83ff02e9f3292e2350880fc168
|
||||
f3b983c9ba5a887173e0f65b9c96b48ca00c24c95357af87e1eb94718c14a3e1:0d8386794920:a04c1eb2dc027397e5e5c139e3427637ed78d78065a6e498a2fb5510a0d98fa760f0fecc8190f14238e2cb5987b84cbe12b1adadb8fe5e5f6880419d6544b0b0f9a167c3e4134cba975f9bef6b73719d7e462b215172ac2ebde69784455f7226
|
||||
39643613cc7ca678aea24c2350bdfef54da2740dc84bea3eb0f5086d8f3757ae:ff5a601d9ae5:93694096221d3ce0fbb2ae96d606102bafccf7f4b286a44cba04dd41ac7ac52d2fd20a87f0757313d2b9cf16eba1ae68176845a18688852eb7fca668232088e707cd9367c7638ff586240b3012602f114740b8f23142fe5eb4d1c92a0aa3cdb7
|
||||
896f12deccc815f37571bd16a9875d191b4065446bb7a41e81363783d22d7bdc:0977015917af38:b668c89c8ef9e1a9e66770b569693c30f0baacac1a51d5bd50e79eb2217b3e676d4543a2e427c1ea6a706aaae32a0b090bfef45a18612fe33a531b04cfb91a9a835e5156d88f25b6fb739b09840fe02838a5fdf4ccdf5c0dd461f63823c3b5a1
|
||||
2f48137f2c80335ceedb56aea36d1d37630ceb603d25dc38c5aaad9edd6740f2:c596c4507b8c21:8b29ed205d9763ebe6f59787bd54490ccdeab56855382ab985cf6dcf02d3ab01b3074b858d2493917b156a9caa7dc0d513f3616b61f279410580ac6286175a8326ead7fb8b9319d3063da2d94dcc9331f85c9ac82d84ad1a3c0c14c00cbaf106
|
||||
5e104f67360bd7be86562856628f7ca8d6f6090e58d78d1bad5faf7b6d01ba96:0ddd0c7f788fa3c2:8abbf1c71d4b4d62046e7557f34ddefcf0ddf8b7991ae8674fa3d73de1865065e98f914fa49772348b4665f102f2ca1515d21364050ab724a0ae95002ac7f2bdfbbe7d7ec1bb8f6b343c4409ad993b39b0d2ebd4a1a001909a1570760d29c246
|
||||
f41439fd6f3c477089e6e6ea9a1e91e11ce62998db83b07ad2e0f114f9acdcbe:662c4514041b22a7:a23e7d4af64aee50d4bea6adb1ed6797e26613753c8dcf7d4aff5136ac8bab0be75dbe3d60d95f8639914dfc73fe620419a6288d6920d3bf95b86537acd12aac5be76804edd064e2a55af43ec73e42b4aefd10f01b64867f14bd452e34ce03dd
|
||||
2301e3208dc15a69334232fa6249a28238e7eebcbabca532719b50dcbb6eab16:03c1ad665dea01bfa5:820ef925b76285789c449fece5f0765661cf3ce95ef7b6482c6c35151e61f5be1f7f08a25cc647d1e2539e5e4811fe771829d666c84f6db43f351c41252e3fa27432a399af25272dade4b6d1da95aec40d6b83a5b82dee79b7ea3568e8a8dd6c
|
||||
a812cc9efa293804c8dd535d4d8c6ad424cf0b82855b58ea5dbc9dcc432aa311:3249c17e4e56f7b787:a1fb4d9bf530927b578d8317f7045c5531d03e9dcffb3cf4467953119f8d96c4c6fd094ad34b742daee909ed59e7f9340eacf47ee9cf353cc63f18748f86fcf237a893543acf9fa96ebdbeca5ef189a4e8f780c1c402017aa0ae9e0fec11c0a2
|
||||
d9a329774f9b39f814fde151cc32bf74e8a1cff727f83646f55bf001d2a6f603:055cdabebdb7c39371a4:b81b341a8a1f8ea7bfa3ae218f74eebf251526b9d2243247dd9b097521deab083ffe10a877f349a890d74a82c78240cb0929fdedd37e4eee257688adbbd921f7e3d30d32daa6924afc8172988490829a022a769517cca57feaab140f3ed91458
|
||||
5a0155ddda1e372e176dd4841998d8373a4db70f720e13f8191a323dae9151f8:ed74bc9283fe9f0df46a:97bf50cf9ce75ddb14e7fe58fbe911aba7f2ff24c5982ac33803ffc578aa7f956c2cca4d436ee7cc0f66c3378470251a05b6570964abbdfaee44f9761581b89468833d000ff8f4f6432c5bbb7f084757328ce3501c055d9b8d1a44a797e7b93b
|
||||
1620bf3cc64af7a12e3bf1a65859c37c0deceabc9765295f24294e5e408ad93f:0723c6a62f4e556ad97947:8abf62b2bf3d9c3524cb6639f3c94cb4e215aaead42ac8608d0a8c1495f766d7626299bed2eb309e3b3566d76ca87de7168bb651726d0427f6395ff81bea526afe56614486444fd1fdf01a2f836e35fd7dc740be034b02a2ccf585bb490e6f07
|
||||
25eaab4800d7b399f81ed647c1c2062db996f9edaeba7411c9b1e47936963816:51410ca4fbc1eef3fe15e8:8d0e31286039c789bc46dc89914a3a7afb47bf3c1b6e3e06b618e5310f8efbbd43f484bd182b1a25d4977fb4d6965e670db5b4fbb9be287d8f3a5596e118c43032d199f93fcc8a60546d45c4b0745b4fd8432534175e9a620782bbf5c72b6c79
|
||||
872cdcc462f7c537801beda2a5ab2490f2ccdecd0c075d05a7562b718d88bd76:046b1e0da58edc394def89fd:86f901ad63d6e46fcf31e6933b76300d355a23ff08710f34b8d20eb8ed7e1ab3a1a2536d10d4f8b307b36041de380769185a831dbd6bfb44cd40da1d7771379c9ad8fac09ccbc2ac67a92cfbed25848cc4aa32511b1c2739434c0c6599398418
|
||||
ac8fbd5b0a2a1d7a18279a4a77781f1176125de642bb3532db38fd1b9029caab:4e99b2a8d76e3a8599f34e0f:a30b77a191250947cd5653b09b21c0766aab216ba514e78027ce01e428211cd5c3c4268a546a51e0953e0ab1a278fcdf0f19285b85dc15b479e47ead63398d87272545c1928f0d62a6d7a7ffa507ca5a6a3738ffa341556aeaffd6a94268a2d4
|
||||
838dcf72e258d2a77bd369353baa2209c1c2f40812803bc74c7bd1c696260ae0:0155257765b6d64a092ca412d9:98c0da445f6f0e4b03d6a3c956ef55c9c77bd7828c84085a4c776b88963d2d190f05ba5834697bfcddd734850c55c99d07c932d98fa4cecff22c887d19837cb6a67122e96f2f58103c5baabe21da9d03efcdb7d91d58e1c7b6d5bf231b6628eb
|
||||
1c37c9dfbce948e9b854a16e5705d39d6814c99db8cd4d21bd17e4b489be8ec0:f29274076eb714c9a1e0cc7c4a:90436ee33fc91061cfeeec29ee065bbf0fb1504c588a057bc7a47e6d706826a03eb75916b5a0802e6bccd600e479579709af6bf0e69892f863cea2d17c7cee0b4aa0d01ad38a100c1f0a92a0d9bb8a662a4802e68fc61a6f89ae5a967e2ade24
|
||||
d588173ab8a6de5b4026218d4860ce9f7796dd05a6333caab951c1ee113f4418:00d7ea9c8a165b4dfd71242abc84:b3bbac928f55a5bc88d9fcfa166d3d5445efb48d5fb564d6fdb13aab32a443764994913dabdcf103c51999ee1abdf011117d77221165cfa0455c56a690a99aad5ecf0429c09fbf6d18facf5762cb1d2c759e2cca4fb1db3e23a54cb85d554750
|
||||
9044a9f62013273404561e373509bb12950260013cfaaf455036174611c62d4b:feb386e695739cd3a97061627019:b9f61eba10d0876ee182a899a5e09b78e1db4436960ceb6a9c7e56a133b1adbd3c46711d0e50f854b7839f07984b19a800ba90bdc779327e045ceba39caf33c6ddff31ed7a2b59de65b1361bf787ff05a7e09b706699d150a6e4225a9a3e0cb0
|
||||
78558ec1b78bada4d8ce4b1816eca078e19f96891b1198418c36306db8d013a0:0287a3353e386d8fa1a6477424dcf1:84df1942271b5488ccf46f85ea23391a54734fb778dcdc26b0c4472290496c02f82e28e28157ffc742006fd5f8cad89d16303b802ee4c0ec6b52a998c80fa848c90e7ed5f89349bfd8899ce0f4856f956db7f9e34f7b28b6374dc3e6d5426c95
|
||||
e491b15ebad91fb2e487850ad754edbe4e9542a699acd3d5dd186ddb65c57844::a019419fde4a1436a79fcdf62919000cde8cdfc1c3c827edb03b2224fd66951bdc168f74a02231ad3cc6fe821616b5b409e2dad609dc6175287d355a56dc8cbf34811a3cb89242c451ed69dc451fe8f32784fc1e84d078733eb3e43abc916f9c
|
||||
4e6237d14a3cd9ea629413caa7c05627220e7f4e87ad60fa17a35916e111d5b3:0b:ad095916915d21a753c5ed1036f8ce695bc763c753dacf18fc696a691cb2d9d4d305255f0371ed05459225b52f45a9ce102fced5a32e0776ef97b2f047c73833a90196bf6e7cfc424dc3b9538e4a49a41c584c093be2851d08f3ef7118e4a71c
|
||||
0d1bf48acabe43f47aa49c94e212dba63a3d375a788df8905cfb624c6e7a2f0b:ea:96c1a767ef41d3b3ea6fb01cc5c76951fc28189a8e34ebd0a5dadc330242ecac0fad824f4c6ed4bda3bcfda260b8e2b40b4a9f7c1a27976edb4a92e4cbdd4316dbf58bfe8e3224324a9a5c1e5e1fcadf4550f6c95ff446c1242e94b8cd84cae3
|
||||
2e5cd6061fa48f1596cd81dbe4e689696a8cd79f70194d18d1992404244a1395:0388:83ed89345a2f35aabffbfe3e386351928087554e65d611365620360707e0d7d772379afe3565f5d40ec75977f3a24edc1172fbe9e78a8392934b67934c81729cd3de2cefda2ae13a749d20e89492091b71d56b23e113a5caa28a6392c56f6a35
|
||||
89c35a9d863242f0766d20141a09432393f7dc85f9976f98983d66a45c21ed72:8c93:98395ae57556a60221b79b810f32e29768d48fe074b4cf7814e64ee18dae7c43fb7d457fa9db3c0d9e89f57586a407d6050c66c01c68d7061d487ac94047f351d6bf17fcfbcdec2362b035130b9b2bc93a6b293465d21c57d46d8aa72b6e6d3f
|
||||
ffe35fd644e7468e3385c959e280a1f7a17472a54ffd6d7c56277ca5f3f20eef:09edc2:909162428d6558bae348f8dd487794b4efa2bfa4600ad02d36caeecfb7d7b803f108e4a0f7b5f02d8785f45be26325a60091bc6912b98209418e0f9f6468361f6b37fb27c139050e0b993ea5bc31d57163969dc12b355c04e0decde0c51a2ef1
|
||||
9e3d51608a4a15a906873dd2b6582a6b313b1fc9d50c9f393813578b3a05dccd:eeeb52:96aab69f0e209470e58393d2101598c37b5b42282c8b5ec7cac7e49e2cd1c29c07a733c3b5cf839b20d71a2d589ce9f50ac2e34d06bff422aa23b5e5c6802edd8d1bfe59b4ffe005b826c082e4a6840c5251e53840acf1dfd0edea4d004f7d2a
|
||||
cb8c06b21c49cc95e1156ffbd2dd883ed907dac4b7eb42ac550062b5d71bc91b:088fe06a:aff958bed7a12d800f6fb300f47345697d9e6a0c1b2d95de6e187995865ea9ba0fdf72c19c92a6af6075be2f99c0e51c125d65fadab50af20acf9700f1c841af100aa8778a90f5410cfc06c4ae90ee2f08b91093ad72d274fd16ec3eb89dcd56
|
||||
c0dc13f11da239c34822ed610dafe71c5b0e4155e2793eed6d9c2d52d2ddacf6:d8e4e21e:a933a08cd8a869b373494a2c5c90a49faa8bde9f305416aafb3420d99babbbb5489fe184c76421d22c1956dc09b626da054e0a1bc4aea27a8f71740f4cd1eccf0c0bcf14ef0ba5504359be4dfd2315e8cc4c1050c084bd9de97a1a21f4ae44a6
|
||||
ef9cd845cdc661c88fb7de72bda8aaa98eedc17bd28fe7ea83d3cd5c7886b50c:0f56e8baf3:8e5c457a6e9a8e4bca3a055b0293f261ce05caa99364ebce72146caf286f945845eb0ccf0466cbdbb27b1603a259d08e0668dca7a32ad3c676822c7751cfc0848be1d6872cc1eb3cd2e4b420d5d5272222f6031b0c9270f230ebec20c3c7fe0b
|
||||
9d4df22f7b6fb59ab64767c21736b94dedd52cad168248e03b727a59bdcb0f20:d382c5149b:8ae1fd65d241b44a15c0c12bd3851d68ea160c775b6357bc147db64dbe665bd9f5eda00cb9cd6ec0ba3b19d5fa940062002bfc51c1fd69bf50c79d5cefc07f722635b3694ab327892d0c0824e3a36d81acb26e509c8761038cf1399380e29895
|
||||
584f578299fdedd0311bab4134250c8b3ef4580aeaffecb540a3050ab09bca6d:047eefc2ff88:8b67172d81f3ddd80ec9ef70a36629546639638086d97269bcf8d1d28c15a33dfd6ec0fda6a06277b0d9ed68537e92050d184ffd30e108e28e33c3d3c21e31f537f6eaa58652ff4c91326cc8faad3d3a705b8a66d4b4287fdb17db3caa0e1d9e
|
||||
cbaa74ed39b54e6a193da8992e923730e01893316da2fdd6c8d413b84607f793:d08941a7c302:98941b687685713412f11c82a2ca3f86189de56352e88e5f2888c7b323cfd782beeb6e5e75ed705576a90386411a2e3e125c257a00bcf698104695607a2394085bfc4aaec1f48bd4709be442dbfe1d2ed2d32e35cdd1b4759757d49cb1c7e387
|
||||
368f0355b86d025ed847ebba2b7fba334ba98eb7d3e1dd7a4225d550434fb67a:0b64f53253494b:a96613ec8e861672d7f25356e438682cbdd2fda9f1cf0e64662b770910203b25dc886fb02474b8c9baef1e91d9bdb6ad0402c5702d1aaf4c640679e7a9c54fad7d0069226cc74da8bfbac94bc4397cc1f1c9c39f5e2d9e2d7fe40145b2905aa1
|
||||
f78bc9ff5cc76fd74a0ab855f0fa03b65feb61ab466cc2e04213be30586a9a9a:80b4b35128ccd2:addc47e9ac39538d21ae3a98335f8b230902fa3bc1fa1861afcf195138443ebdab420dbd88967fb5ebc355200ef0d13f11d2f91eea7d8a04fee7c1f6e2baefb0435b6e8d09539f61c7ffca19af900367e898cafa119f4a587e78eee1be966758
|
||||
0126eedaf3dcec0112ce5f44f181618cc5eb70ef0ef899f7329b3f10067c932d:09577238413c7bcd:a15c5c64ec5e4efd56363ae703343f1d87a8571347562d3aaca2ca4ea24c71249a55e9fbc393207bddfc696c151dfc420feb0f33f27fd24f184ed877bab13a5cce779f0a446ad0dc7577d5658dddf0179ef5bdc604d492d9a3a062194c4b5cbd
|
||||
9973eb6a3eb08827754ce8088763e853cc97e6eaa1812bc32d08fc9ab26992f6:1413b6179c2d166b:b6629ea9d32194dc73ce3ac4e02858c7e62a09f039370c3c98b73a1ddb14c29fb59b9b10fa1809b38e4a6105c5aec96509ba4c83178297f17e05bc70ee1e0d06569c4bb276b3a335f076140787c466fe4a6bcfbf7d0de813133fd731e5b49187
|
||||
8dc01c9f5983c93e04e4eff82cc4a79676fd247b2a144640566fae5c9e3cfca4:00b47ee092f96fbe70:98e8172d6f676503c6f31a73c3e45ede4d53bb73d10668ad1d04d1d0e1f8601dfb171fa41b19cc4253b18d85a76afff604ef55b8128924d6fe8e76926b4718682a5bdea2da6fba97731f418442b31897b749e88839ed04a9a8312dc4969d2899
|
||||
ccbd235f576d3bc3d28b97334eca7a05d3cc5f2a709a1fece99976fdd2b9d773:198079f8da3599c376:a3ee5959fdd7143a9de5a759f28f7299ea48ed2fda18654d351591457c2f8d1961100e8cb17d5f974af2f3d4ed2d1f9003f3348a4db481614232949b0068f4b46e80e15479d28fabb883ada7404a2fd820064138a47d2f814af7ba06d80af0e9
|
||||
06123d03bdc50fb3bdfdc8fe60892ecc110cfd9b941d1c183470e79ab184fd64:010c6409424adb9edaf5:854031eef2a80b533862df645b40fa90c50c5e9572ae5a5732b9686db5a479282b0d46bede9df391a55f220c322369a900a8c3ce642af7154f5ea728711da75a6463608f3eac64af631b47561abad7a30d758fbe0379ccc545839fb3775bf5c2
|
||||
29dcd911b82d242702e281f02493107eda90028b53efd067f5a8b1b3b402f87f:9919aea3f2c254e0af98:91308917daa0c1f3833a3de67893c754e2f362eed5f6df9d410200fb9d0ba0e4587546cc88d241a1a0cb496960524f440ffabfc0d17126c8941a5cbf9913f547cd3fb59f856b46bd5d6880f566b88e419cac04a49c6ccf37b539eb3a80b4e7c7
|
||||
bfbd2cdf05e105f2a71640421904875a1378f733d07611d6d7dc5576dd1d11f5:0c9e846d9c1b4dcc7e6b7a:8c7d64a8dcaac26a2e121204f40d2fd67fb6358d597603dc9ccff91e705f6706f0087938d1838abfab4f663f2f44b5da172572afa50585a26245fbeb0a25ffa20aea55c955eb311575cf8bfd5934fa6b139ce4cbde6fea3990309ab15c210807
|
||||
f1f54419ce4518089b8e270ad7dcefef3cc06fc1b061febc5cdeb754d889edd2:3852a159c4ba27e465a83c:8b048ab27778fe7c52d1b62e3bee96a4eff22f9a53d76f767a60ac7bb5264e5278d9072f41db284d936109c47daa84dd172e41701bf9a44060a2ae91eab324a6f695d75aa786ceb0af68f2e109c9fe49ff12a01041da22560bc90570f4461518
|
||||
a20a9c53f69394593e823610c1bdcfe10fae21cd42b9e6e59f683aa5cf86e7ec:016db3c02fac44b97af92c2e:860c4c3ddfb15c3d8f57c5cb41a9e8114135ff2ace9fcf55a9a95a676073e0b87705c56ac3676ef280d00f4b86e9208409e54f0d4ea7ea1aa90b40c835ec3e8f44d0c8e968fe0201a11312f9e309847add0433420fd47d8c43214ebfadc148fc
|
||||
f4e297d963163769b5aaf4aafdd1969e78ac101fbb5f08f48d62f21b4dca91c2:a8d74c3c2d54faff2095a18c:81008cb4621bf919e027aaf6877618444953723e24625e6d1330554c599072d0fa9ac69d513d330cc102b6ae79220af10fd084898192663a701c599050c8cad6b7a37240ccecc2cd680474ae70d121cd64413d7428f32822467d6b695c890385
|
||||
3caf69b84927248e842ccbf1e5cf6f793cdc69b0966ba04df1f7a2669e7a9a38:07b4ed6bedd1e2ef2db8488baf:8dfaa7179531aabbd23bba0e27d43e9eab3de719e966b47c0a76493092947137815b23f4fa5c74f4d2bd96ef6d2430ce0c5dabcef379d98395caafa8e68739fcf2c1f3e840e1dac9ad703b2e090dc5ea437e008d5b8fe2f0b1be6708552033fe
|
||||
88dc6b21810e2bc476305c8a706b75062a0e199726041468cb8c4238771d4029:f1b293206aea9b717e147594cf:8de151ec56c6b65c5d93f6295f6a247a2ef2060f428b3f4e90ec9e5bbe3731a98af021c9f9bad0b7db054a45d17cbc37055fdc72b2683d27205ff95dd2dc33b5da84c1211e43052c8025f94c68a53423e5a283ff19cdfdc441e0a9917bce27bd
|
||||
cc25cd8691f46fa1780253ef5a2354bc1ff302d1577dcbbd3ac419d48742f812:0cc78d7d6e414102c4ed549dd1f2:93c03bc32480bcc4defca136f6e668f683d54b6e11c3ca537c23c142844f9ef441beb1d7f6269001aac6dd1ab996aaa50011e8e18eb3a03f71f4a6a0b36b01109fb242e0b5e4ab161e4edf67c46dd0b3684c92cb0860ec07d766f36affa0b7d8
|
||||
4d4792f59fe96d8f7418dee1d043e49f62ee63f0a2ab4b6271314f34bcb9409c:6930e7a417e42a0eae0debfdf30d:aae8cd57c22303af560fb04e7798bb68c649abb0fc1bbaed005db7b148e0a0df674ce75b8f023c31b8d4f35961c9712c0d6854d78d19f465ba844547acd18fb873cc1013b6f187ca491e5accaa20aac9fe43d254c916c9563d4ceb56b058836d
|
||||
1431fe22a4ca0320403bbab6c29089ca1591c5fb447f6dc35d102959594a6d16:028773ab2e2754ac5a75a715d78bff:a53aea82c839d80b8603699e271df8c7ae119be1ef69c912d3c1a68b3e1c419fa50f10435497853206c41524cb97ccef19eeded83fe6b4af2392e16ca7e660d3e2c79232665c396ab9b5fd3594ff2ea93067d8c1080df6dc8ff55c9cce9b35e5
|
||||
1f4d0636ba8bdd4ea49221a270176378c01a7458e3a7fe0ce4d4ffb088d1d4c0::99781a5e42b7dd8c022bd519ea9acc6008a7aa116245e8f14a12f40d87b02bd3ea071d3dbbc09db01395e6dd8b3485ed12ce0d5943637cae60e682e3d2b7530fc1966dee8b53b4f6f6f755865778691a7b5b3911801be279a0731a9aefaf8351
|
||||
ff8045cb4d0a119bab9221ad343aa802467c900101920b332c0c2492bea4b475:07:acc9f6b5d331dfc9e76a94edc08333780f8242013cf98fd946a3d3043d42af7c70013529e6d5caaa4a402c30563bad4b05c1259a914dd0f6ad4e853b08cb5f52f6394cb6ae7c3f458bd2c50db77aea76fa09c63d243c7cf0c8d79d4ce8be6251
|
||||
81561f34e382891d3094cf6b50f5f3fdcab90cd2d9330f8b56b8a0c9136767bb:1d:91a62de3f2b1d596ac3edf651d73c28ce925f0be6354118bd1504b69538ad81c571919ffbf2b08721cad0fb527c6d8af05e7f25478e6fa8523e7523d9fe79b2461dc283ad844a22934444f8c5d0b3a5a1d46d2a1491d6ba9819e968c5819c924
|
||||
f67f2d294d27e9a26fbf9a1324a199adbacd044ccea3a20799618fd3d242729b:0062:91c2ecf6692da57fb464aa61fd49eeb398c58a443e473a7fe9c481ad10b8d8ea5f141329604fbf7267cf2a3b57a5529506719721259a3f5feffdc6a6800dd32e6ed44edc7a018218ae1cc72e1787604c41e7ce43c59c7c644327402a51062b98
|
||||
2c8dba24af03feb0bd91fcf67d8b1ef2000305bbb8d4e0851ef151c21457c49b:aa4a:94442f44bd4ea1447f776ceb43590dcca856f02c1220147ab020438c7d52e61d002c4833198994b207422ab6d408fa9110b3d2316c740ebc11352c2658e0176fbfe9ef2fb880ad61c6ddc4ad362a5c806534ad8a37885ebafe89b2eaeebeb35b
|
||||
9229f4eaafb7d35ef0d5a820b911ddf5fc6d3b2c3b49c745dade597025f8680d:0c0efb:8345abb6eecf90c13c93990b54ed628f9e052bd622c3eb6e66bbbe6ce8cda13b4d9c4c1c85094fb44fe308f7efdf009604a9bb1d0dc54eca54ed353293928b59ab9a4909bbf284d95f4f9cee588cc1f21abc5d506b2e7058c51163e0202afe1f
|
||||
6968eed29d12fd07d53fba6e07fde6bf6f37d8a3d9f53673f6bd1db6c28e2cdd:84f05a:8ca8d57e7189f7648c2f2163d71b7868aca21ec8f196bb067f43aba576301282023ebbdb688ec4baf1bee5da5b719b1600a529c1169b0dbe796fd79714ad4ce6b67cce01c3fc955a33570923ad95a13b8ef0e7a953d56fbe3bd9f3fffdb8ec2d
|
||||
dd1b8907a547de4826115194b15ac42558a2c4559f1b236c6bcde09401777b24:0a95e2f2:add320ae8567ac9902990d75dd7c1ea3a053e80f7b924d9d68fecc4d5569f341bc665939f8b9695d310273d93f730793159844b008684883620ef11496a624c28b11b92efaf57226263182fcde837482ab61d5b2ae5daf78b3a7a7c0c97d7c27
|
||||
98d07d9f94dfbebafbb10c3411428262750973ac8f5bfff4f3218ddcd09d95e3:01ae77fc:b2553ee7517479b60dc95c0feabf6e60ff04d1576b1de291a220047ba19116fafba681efbad874fbe5b6080f5972adbb075e1ccede0df5f0bb87b0dce1bc0e78fcafd0ad06fef2332d415329ad1afdabc8b33d26c06baecd4d3f55923fdc9890
|
||||
5770504add317933bdbe89f35463e784d798ce20b5b1dd258569955e8df4068d:0f709c6798:817f1def1b321a6cb1d47dd1558e00692605b0072f9fe2ac07859fa30d1b9da5d8b8fe09a0f7eed404190a72778609e1010ca80ad5528cbdf5d54e4981a52534c096631e38a9533e52bc18b2d52309cc452f03949f6d50fd96f0251c765aaf8d
|
||||
24612966cd6601308edbd27423d622dfbcb27746b31b3e9f6939b571cc865f14:5c2b9e06cf:b6066c1bdd416fa78630fb1073c20fc1813596b6ce0bbd36c407ab18fbf488ad2f4cbe7526bfbf168c2014ad2f887dcd04825625e8a83728a7940c46a689512cd4a2025830a70df7ab84f2b76964f7acb839fd562def8b9021d3575a9d794d82
|
||||
e058866deca74d7becf8ad839ab19345c6fffbeba03bb5551569e6a77fc271a6:0b1412c98979:b300256fe69effc5bcf218426c36c3b863cc092d087dff27ea21d57e63f994c7df97498a37382c01aadbf6556b50403f00f09614134b80e3f777ab8737bbf61a4399a29bee437113fbcb8062fceccc3ea6a5461b3716fee446a2101b0dfc13f6
|
||||
6716da7e6965ea890857c0fae1c57828ce35279eb69f7dd8ba29c8aef11fbeec:2657f15d8adc:88198312d9975e2ec4823c5a0e490323e745c4fe41e75e25c4ba0c5dd32030b02597c90b24d2952e78c6cb91b90f920d13514e193eccd54212f7cd3a0dca90197f920fa7c0e85dd0c8a8009f1c98deb823a5eeb632b73bf44b102ed38c68eb67
|
||||
ff076024d1dcd908540d3cff13e39a12544e033e5e3fe033e351850fd75fec62:0f831b8f177833:849a8c12b4f619a87284b881808e806b5b810b90938d0fa1df01cab27896374542ecf8698f20725ad9f013400d11643f140ba02c03bdb318f06ee71b9ada27aa1024d6a9a51c19b25e302c7243f67a07ab5accd504e16e6cc08093d58619e5f7
|
||||
893af0a540d8972ffb5b0a7fa4d24fb180230acc3960f9f30d654cf6ae5c1531:58f13d5001e1de:b73f09066a90916c14f93d6027f78c1ef75f3cc0fd7b1d2a40708665960d9b6b09019a8652ac21fa30b8fa4195fc34261839beddc50af794652f0f3fd32513483564887f9ab1d81e9b1767d19211108882683e874a41fdcb193a9e82e741f147
|
||||
c81191beccf7c48bef093eb0fe53536d02ac32d01ecb86358ba90303d0fcc10f:01d6170490dead4b:877ad867bc97004fa2deff244bd2e356bb30129b1c0cb0c7f25e9429ec6527ed564288f1b83a8bb144ce75d4bcab189005349b397fe1d8d219bd8bc07c6b3af414e02f83180fce1853005fbf3b3e8eb62e7ec1f202db1b86b7fe5b3d23bf2da4
|
||||
a3f68634413db07bc22c448748011efddc9c0ff5e3ddff037559299f16199373:9d97a98ed3345f53:98b8056aefca86c699804c92ce7d1d72c4457c12b58e8768755e64bc4be94eb05e25e0587495c469f129210c2b6308620fcddff4ef61db0b3fc77b6c765c83291edc33a34e3d18e8cfcb7f0f51a89c0908a617bea3613f8f91caa47071d47aa9
|
||||
6a6f8a98610a5a4acdf6da669ea3990fb299e1aedf2ac327c97b0ce96adc753b:057de0b81f4f9a736c:b834e23d96490775c3f0b2d674d2506149d2345f94f157c3b124759ff61fe2f3d0773b6b9bb0e1566d370fdaf273f55808fff04433d5f8a5537a3142cb299e8996c42a420ae36e6c9335d2e630600c287bf283b745f5d5985b7819a6e889efbd
|
||||
6422d62c14662cc8ad1fc10875ae58813fa9ee349c019c452a917d2b7ec98404:8956593d05c7b5814d:b6abb8bf4ce2feea01a0f6fdb881cd276c6576bdd92e460e3827f6081d44263bf21498d5bad1c3b534753214f30b15500b0bced8b763ebc1b292d5676021c1a2db09e35d5d3f306b4d1436087bdf8b4720e4ddf3bf89c323804dc006ce9a6a91
|
||||
67cb55964dfc93f1ea615a89ea49b26c677ccb4a2a0f512935b45b3a54bf70a2:02c10d2e5e685de181b0:adda564e2367e13037727867cfdfc0a22be7ada7670a01a66f3954b54745256ea89ffea82dd5e68e98f4663fdcb4ca3d017fd21d25b491191c69fc3eedcf8064a5991ae58ae6ca81e05605212e166a6cb5d53f6f89fa96a0764c26674092ad45
|
||||
80e2aa0ce9bf22a06147e0b3d5dec44922422e976eec32493bb4f70a2c205082:385d300a9ac9f61a367d:acd05f67bd58438b7c4b1fce46505437ae7829a1d2f114e806cc46d2ce5adc07fa5cf6d0a08da486c9fb792bbbf62db5106294c6524db1838225eee010bf6e70bb99ce54efdf74e7deb544cac38f9b741412c0c061aa70fd0e151781746a08b7
|
||||
f8722dd9394845c2744e556933d4d7ed838e983f7088fd2ad69a769385005509:0ee559b4340c968008cfef:8c96413e8262e36871d252ab2060117c8590f4b3accb11db0c702a7bc6d206c4d767c4127591e17fbe81a0f2f6cdf436089005dbb0ab266fc81da3cd416580228cebc1e48349894886856993f43bf1a0b5e62fd89ad0f205917f295f2edde990
|
||||
d9ecf27ad6dd98e0ff55c5f8562eb5a7e4f46ef38a9245dffd788d6bb638cbe1:b8ca56c4258c05963bbd68:afbe6f9dff95a5d29af76a07b7400c75ca49e066186b76274182507aed8a9c32bc90f863eac72d22ff69e170caf58e5708f6ebba8aa69d61da0e1bb5f7b7b364e38fb6fca3ed27c8588a6077e89adb11087ed0e773aad50fa57a06e7ebe3c64b
|
||||
295b144cdec443e032d21c906e46b3594a1e50b3e6f29118028767f189ce12b6:07d1ad37496c013d3f099071:ab4b0c1a0402c5a63a76c88a9e2c2f36b20f22f1a1de61f620ee9634605d7d9dd12e27dc2d04f1d96538f9d28a1e93a10d5fb540051787346a2633759c2fa8a2f85db615b1e901158b4c22455402cfed378f4acdd4524de4a39ca4b18644bd35
|
||||
2b614a7871bf0d74e53bc6c7714372353b4a22ed47f1f627d3bbb1ef7532dc77:624a8baf7884b4568d2e6b31:85aa088a9bc03c585a4238a49e5e6aa36434609590a3fb8611d012442ff6b841d23aaed5011df2eb61e2be3389f684f600f219ddf20da10f8cde2dda151c74153020e2cb7e804999c9a99bd02b12a11ed65f8b1e73f8b27dd819faeb46ebc7bd
|
||||
422ad85c60720ef2d06cfc26ad0e7ee1af49cfd6ba025692d405b1cb41fcf71f:0ddbe34431448b194f1b29bb60:b8fa03a4ddcf857e50f142ed3949c3c43937ddab3b67491634137a478b0f74ff12a4eb17d030bdb3859ce2a3ceff5c13136b61832182c1808fe914c5471cdb963870f2477a6d59c842e4e23fd7558488fdfbb46899aaaa67c55b48b9c94f594e
|
||||
a7f1e76ab8164099b21ff25319a62b0b77afa45746dea6c57964eb605e6ddfe2:f817dc1a64750b045dd8145104:933e398eb69ca41ed5c34a4270bbcfd64bc0446e23c754703925b354097ca7a2ee8ca253eb279af79a5e4d2d907acf1b0ce632630899607a6a67fae6654b90fb7bb37578a1c828ac3ac650c752a645808592304fc7a32d6c1a0ab530fa3165ac
|
||||
b0eb65f46ed2a9931220920e3ec70edb39cfa90d04de48f53bde65e2fa3c7eb9:01cdea387f4c40da7949aa79fab4:b9a0c6a68ae34cb6d2646d9c14655b5259942cadfc7cd0982af5842894ef4fcd3e9136e83a1b6bdc1d9705e5843092c308fcf46df2e5e4b99534ae6acdac11aac1d558073cb0632f496307df850cbb8c199893bb8313f1db890cca245a174c61
|
||||
3a6ccf539c217a904fd7a718d2815c985325e3c9cfb7bf458a219b8ae78f775e:df33154deaa3d687d45a694ab80e:a269482d849517a2fffb267782152bf07daa7bbded7df8a18b7d74c9e5a4f46c09d6f795f7a9eefb8df107d10e5598f203cad912865152985d407f3d7303287fe9b0c16c650016bfd9dab49da95665e98442ac1e10ce427bb16c8bbe81130c08
|
||||
41c836e9c4069d15ad4e871a12a81fd91fa062ba39905b659ece6a8000dfb125:01214f40af921429a48897d9d286de:95a2dfaaf34691b69b9df2a3356bb25ccb9f416e0c619a5f6bc1a25b267d95de7c5fcbc50d0e6de1d79afbb083255b22158ede7ceeca628a162d3b7d4887574e7cd947e1ee5704b3970aaaf92e47697623089bbb032ee1ca15505604beaedeca
|
||||
25563baa30cdb1664317a7f6a11fadf24dbd7e33f758ae9edffb4a3bc6e47809::ae9b09587dde61b31dc3a252ee5da28b118778ea40e6940695c0cb14e927810dc1bdc3580421e6a6349770e468ef624a0b1edf2a2fca77e3afb1d4cecddd443db8c5b1e92d0bbf123f9a7d3ecbb94b6d7a72bd0754bb5339e807baec26fe6688
|
||||
324c59624d455e439661cd33bf2691779493f51ab154942bceaeaf9a3f8d2e5d:0c:89243606a295632aee72da9fa717b04274ca61ca99279b75705fdca338a6712f9d92939b9c868210ae1a80c2a315f9a10944326c7e753c7f7a62ed69fd2a0e27321a52f1305facfc2fb091722bda6f1edc3ffae29a990907d7340715dd763e0a
|
||||
e4168522cbb5b48039f1010ca723f64b540683a964b9d1ace259e814f946cc4a:58:ae7062fe9c1fd3eda7ea4aebfc3076f105a975cbbe9203dce3014a905fbfb753d94ad6d0bfc6a4ba564e376b422c326312c26c7f4eebe2737cd55098abab896823ba0862c6a064fb0eb814d773ff08199ae30cd992b8fdb3a98f155b8ff85f87
|
||||
3d7eff177604e52315b47e30500f9d1419496f5da2d9d2b4691b9e840b5a07fa:07c5:b5b0f787446da8bae5a3468d5efac5b06769486650d42ca5d0e8a9b1a7b4c47b9e84def60984469ec8fa311753fae2ff0feb1f42f107114031d8e6c25ed3d7ce8b882d05bc169c2fb30e301b5555211d31e24c4eb67242d7ae71770426336f4e
|
||||
cb047e496e0b4826382c35e58dd5b83157e070ff2ab4a500c775878b14af1382:6dcd:a38eb229aedee1a3f23afbab228165432c06180a41b5b8ad600a4d8ca734106de42e83d67d045c3dd5e5877fdca506b10a1128f199cc98bc826e3d42c57cee4b118af6be1b14eaaf0f76ed7bc02835a69065489d0054c74d4bdb342ac5e6d540
|
||||
90cc186f844b3e92ac371f89edcf9b55077ab4c43e2994d5824cd1a869969639:0f9f81:86f99b1a30d90328fe106eb036e4016ce2f58ac11c312e863f67886e89db2f61317696cf32f994df2a3a15d4acf654d2115681df1f4c99a5c581da34ccd08c408b8fccceea7f23daafe8a2e3797d768e04407121227d46a77a2e6464ca8d2dbf
|
||||
9a88979f86f9b645c18435713d1d9962e00b7eb668c9990063cddf048c5a833a:e35fd9:af1e6549066d0e1e1c795e05ad4efc277cf63ad5628b944294bda5c6c2cab553cf3c16ef35525190d6b6ae838d8d5c88007e4b33fff1d66857248606a4fd7cc6f3878265745a9e1874a1cc03a870b192e2b1bd1974eb380937222f4390463020
|
||||
dabed287fd58fa6e4f66d4ee5b1761f660e3bd29021c1887b317cd0a5ea8beaf:0ad95982:afa79271194f2d89f7ddd9af9db947211f24ce7ad576a157b1d4910c8c0b6f87eecb28f6f18a111f74f144fd0b1724a8007027c1033b055d2fd467f7c1ad60af663fbfea59d13d16fbc291828a8f11757fcfca6f26b6f3567dc42e05d9feb70f
|
||||
da069623c0621d0e18beba8609d0020c85893c4929b5500743101b87874cde8e:85c588cb:b7431c652478c889a562a8a1d3babfc1037cc065c2c850b334ecdeaec04311cbe3abc764a465ccc54d7afddc27b1d443085b32d605f1e4cdeff84782b2ce844efab05f2b4474ff70c037f5790897748d6af6b6417e8087c5b0c8e6cac0276e59
|
||||
a0f21a36aa3e9393082a284bd74357c31dfc34e332dfaedc0f06f45423fc495f:0121789325:b0c1a71f1a74a1e8c9cab9f51bf300ba198a135e759cb1845de10ff7160d13b5f3e0edbd63b023d32a178b9c598ff48d1366afc2b8f0bdca4c2f1572377baffe19daa9ea0b81eab56eb8589a6278ac57ad9210b763d9726073a091b4e3dbb9c2
|
||||
017efc554478e7f73876fb6ed0b036ba4c6c653f5baa2c13c8a705e8d936900d:5298548f3f:973c337a1e2632ee2355af6a1b259c764e3d1f99ba9e1c9840b1e3df0d27e3eb477b670976e3d0099c49b4eff639260c07f19d0c474d152ce3656f422ab27e65c6288d61760d5a96e8af9560f4460ef4dd53a802536fb19eef9abd257653332f
|
||||
4d7f9479becad152a443f2c759aab6e02a1f0feb15dfd49c11804d2a104b39f8:07bd8740d5e5:93b4364b292786fb255cb06ba55cfb0805923229ce394fb5370a3571c4773b7d8b6801318e6262a4499d73ff181b3bdb09347f73aa4a2ca7f6e99df8be366346ae43ca8faad4458e2d30d26adf049a7542e3f0ca72f86006cdbac3ceaf038515
|
||||
b2e5bee63c6c00e5f8fd15703ded33d45037da065cf3f498ecaf72a8e9a8f23e:7d202c324585:b0981781fcb2e04e418d7043602a61b7a14e8d5cb2151b40adf729689729aefecfa1063ba1b43ae571ffaa492bf81c14121fbb6c2292fcd0d1c853c37b9605c0f05a2647279de3d07c2f6855b5a81e019badf9d813757dad66eda78d02aa072a
|
||||
63c95845cf70d1470e0f6de57729b5838f977a8706c1979388829f9b5b3700e9:08aa3ec1c57996:a950729885949d9a8b50a031ad184d1887b2992601c0abaa9e5b6ed71e5beaac0534ea2c9d93a7c564b77d0c5c77bc5818fa164575d3d58714687c7f549058eaf3d0fb432d328e3bc8da3ae7646ffde2297421a2c418dff28026da3d29d1d498
|
||||
22059d7b3332f4def25399ce17b1e1481028ec4d2d8ab835a69b7ebdaa16b461:4195fc080b251a:91ca4b0a098ab6678c54643b2546a3535696b109bc49f3e50d8e6966a56ffa61ad37d2eb29b1c6a19793aeb30edfae53021b2a322a300bdae1ce9e9f67267727e682a4568845b1312e652ba439f6d0432c36342151234eb639c9cc8153ecf743
|
||||
6bc4bc3efec07ce22fa5a5f0e0fc4a4142f8fc4c078e6915ab7f14c9743752da:0fdc2eb64cd67bee:933de772ca7a3f1fa61c87a5a4ef914b1f6074facdc6a98c6e8fdb886a3e53e5acd2766390d9c6c8e8b48a268c4c227b056a5f4f7895590e48b44863d26c44677091acd4585a85c88c8de2ddcc1c530b918233d7655e858ead521bdf1d66b526
|
||||
9caa571a916d4005e08af68c36b8a65bb7ffd9890758ec276d30278a2107ff64:5067f524af933a64:843b7097035540b7c219e82760cb94aa749cb6579301110ee51984b8b63428207108871ed1fca275ab05850e3563a09a19b32457285f15c1a3c1f74abf105ede27dc47ccaea5c90623f5d038bb00e8a2277441e165cb8327e86f03c2f0dbc1c0
|
||||
2178be06e144b58fc271dd130182d6ce562fce547c545adae7df409c61262876:0f72ecc940599630cc:abb38edc8b7232a479a51b23e3d0d5fce3e6967190e2e68df73fb95e3e2367b2b1b6360fa0b06c508c664d90f8cc345a09e8b8255945b850ce8c1c5e389258767a709810e519220abad9ea7d9fc37d947038634ad059821d591a671595df762b
|
||||
1a1924318927acc40cd3cb8265dbe703db0386b0d94199dba5d67cfcbb497032:387376ba00fc30b6c0:a2e6514012c1fe9484cb9df2925a80c1451d33cda78b89302cee7f59aea190ff34a71a6c4a46a77652785b44dcbcee100aba9beb37612e961bf83139abb690449e6e05a351d8408939585b026fc83b1fa0ca0d0303295503c65a40bce402d12c
|
||||
9e203efa8eb1e65d053eaf644f9c3ae67c084af1a3aa7b2f4cd051f4ff870bc9:0c41bee51ab6c3976cf1:8f6b876d190c548c8cf130bf3c5c315fd6f0a8f6610d1cc6c0f5f199912fcee078f5e4f9d8b2d8b239fdcdf43c6efa9e0fb4fbb894a1fcd464321affbd64f07cfc63968fc5fe77d8c5cfe2ddade49f28ae60b7b26d97049b5964aaee79f244af
|
||||
30e446fc468b579fdda3a09ede2c456f9799fadd07c069c44794c1cabae3d555:25538c2c57aa03118f9f:98eafa9da5b2802b9932fa056ac3c81f09b4c4dddcfd5ad963de9374731c11720d7b85bfb5e3955c71f81a86f32b4e7611022aa8717dbd032e4fa4635dae9209df6ee3dd34598fdf504cdd4aa3fff1292d11f74f17af500703ccc127faec4c48
|
||||
6440fb50661c3b9c45c557d216accce15185891f98080b6a7c1c6dd701e029d4:0a9333dc2d78c73c53507e:8e633dee7c8fa3270472078f93dd5181f92f43e7b42929a9acf42563367256c59b3355d23c18ca8dcdfced828b5009e4133de13a3e875d2a6880977f9a0f00d17649550419ad5da3194df083f685162ac7241d864c8c72082cac5ecfbc581db8
|
||||
b0bd58b8665f372d71003e10b5c11d2e01f69d2daf5ba56e301f9cf433bf6a21:16cc073e29547abb287b26:a8080f4cdd6d89dcb03bb389be65930c6161d881d149673e8feb89ae07e70265016458b74734ec83d15099767e0c0e4e175501ed542691e4acb3446d060ac6ae971ebd85ee25a507528dd3f4211c608ef572f49d2ee894a5eefcd5ab86db9c50
|
||||
084caa7f9ee6060620c5db1416f5cadd4a54984c23dc804cf23ac5ec645cac2b:0f3cf7f7ffe9279288b56ab8:922c3c5844803907b8b2bd08df8edd00018df0ccc9e515faf8814ed865850fe7cae1240495bf4e947540c325a536d0020f1f15f5583cb6e5a127de49856515b933425ede9aad615c9007c533c85cf25a6380c7f7e45b48d644871f7f72152a27
|
||||
2581c1782074316f855d5d184ed4066962371b58935c672672943aab3a67d005:0d85756630cfa82ed2cd35ef:8ff6a1d75fe9ac8362c40d9405b1d8d3633eb6ae08e12b9008da03eddf47f632d780e6f7f257d27569ded6414ebbc7330f3d3eee1b1bfeed420288ae89511afe701d34e6973df7f9379cf5027ba456cc958b09288191b4a7ae157db428363a99
|
||||
bfed6cdc36912d4f49a87cd108d0f8e51ced50d5870dd80ce98a030d0b46fb9d:0c3255c7a617e8d3f717371300:98a6004ccee00c914b915f5f48a2875fa7f5849bf1bb02b41fef83712ed2e352c1eb3f1613697b3b5b77c0e99a99b6550a5e76d894529566c649ae4fd29d869b84ba5dfeff543db07047867329fa3f307dd4befd03f0fe71143ee46160f2887f
|
||||
a4ba0fe9090e0018df0e0d763fbd11aebc12b3f0c807ad0995db08a6bdc9b160:27842d981fd9a812efe6391c71:88b5e9dec395c4fe67641a618c4512e082abb8ea302755128ee6d2c0669b91424308b3bcc0ce6cb3058af4099cfa820603d93b557ad60c3e29f96131c8838eb1dbe9bc404abceb50f1ce22cebd6f970c107323731ef9ce736d30ebdc8e59ff7e
|
||||
ac42165d2ac95f081108888a94d0a56460400941c57f3145ff2fb6900a7b0c8b:0260471f10e5f35305906cb94df8:b62cb0b876a1edf2dbc35eb4df5627ad09c8e6d8d9da83a154c4c8d93e70ecea0794f412d53c50677bb064a4038abe12106e3581e622fbaa6fff3f86e06653b890defbc8cc4d190280ebc5bb4431a27677e0e52049ffaca5649cf75f22239a0a
|
||||
396f95f097863db7d343484be8ea7c26d2db9e022397e42845a3aba66eac2165:e46812d0412dbf137a84b49d4b0b:abd154aac031f055c524185d56e1e4f259800a87bf234b04fcc509181626d4e519e97c7a32da1fba04e6e322e0a8760b0424065e8b99348548ceafea44d107bebdd119d47f7df4d27ae0e14b5fff497408e8ce381256c41721477971925345bf
|
||||
a94eff505560f2686a73b2b56598b1d43956c93b54c05e8e04e845a517d2f454:03e19ddb791c70b3bbb0646679efa0:862897bd1566b53a083100384352ccc4477030f463c21135800255d3812876f33388007080aa431d84e70119b9c46759013b6ce9f5b68004085f1fc009ac06d3747c9ff008395ae6de90417a43e5f0dcdc00345bd14e8e1cb2b7598e1eb91bc4
|
||||
3b79d30b7558a89767dec3f3d1f3393d13ee5e648786ed6bac49186f8a2ca2c3::83ecd612c577ef99af50938c218bee6b7693d2d5aa1a06144346f6c8e46e5f741ca66a154106ad512bf5a2d9357b89da13b797530e42d298f6f74559cf5452694de538328301df16a8c91ffa5a6737befaced0d81ba45f68f3587639890f6ce7
|
||||
164811a45674f804c655c8c5ad3863b359ac9041c7f1e72c0ae20f80f41170c3:0e:9359a49c73685f2a8a9b6c46fb2773a56061a586ad1b7eb38d7789d23260f96741f4046ebbd119c06ebf64e9ed7b81f510cf95305be70c83193faa2d16866e76cfeab918c608d9b4dce6fff60e807358ae142eff4a8b55a01bb5da982e89aa37
|
||||
07b300ed4a2db3bc21642adc74521eb70ba2c81a5e0f07b7759a80ecd27033aa:05:a9a3b90336d9ef805992939d52302e641c74c10216cf320696ce6262dd1ce58ae82099c2d0575892650a13c6daf2017c11c84edae1256b035f82d467737c7586992d84d0d521882ac2c0babe65e06d8d0df64963667972ed2670fe25b8dd2804
|
||||
ed01008602bff20ae9a170fba17b328d675136e194d29e4663f9fbfb02433de8:0fac:8c25576acc891e64003d756e0d74e11b03b08d5e56db3dd39303e589cd8037d21be1fc217a94e040a9d5cf544f2bdf36083f8eda0481dd96b84df5d598d9f8e717cbb5c749b1278e6c023413d58ba47b8b513160f84b407f22c73392ad6fbd67
|
||||
1ebe5d4cde886b9f5f4555e7c02bc14987dd021999a713d020cf3c08ff9a4f60:405e:a49cb23f9b25095c9d28d94ff6b1763cdc257e5824350ee79c726fc4dfa4307ce365283342978bf2534782898afa949204e5ff271d495a577dce076bc8b42ecffcf5cc6219955a4e914c42f41c3fafe35a1464ad06bb35032b56408e44fa8ac9
|
||||
34df86999c7c40e1f0d423e8b788e5a617132c37dfe7865e4e6052b7b7c0c08f:09c6ab:99aca067bd01d52542141bee5e7941265cb45d058b090e3b5f2965d2c92d17f691e10f489148cac52a72c0428c470af2071d2f484b6bc772a4ec04cd9c9910bba345603371925c1c29789417f507d8539cf5981f07a77185b0adf8c9f7704199
|
||||
8edbb41c9d6f871f1148006b1047388eba52393561f71c41840861108bc0baf9:6e29a7:a061b2b9f869374ff143dda1e43f011f9326009c7f791b561358cd32605f7fe7c12b5822cbb3154c8e145eec99c0a9e510a3bb32c906331bafc87cf84bc90633bc61c4db5eb38941ba76567a7e29f3b9167d1ddf2d089a770e1f4f66ffc760b2
|
||||
74f0fde07929f00fdaed639fc0d108b53e44bcc264326b5be114dc766784837a:02b3c8ea:b2eba7ea2a3d079ed7ee8b151d66999a2e0038793f4659bed206c8911f2dc98397d7f2c9e97f1d7a9c687f4b0572d3f6084739d944f38d1fb01a0055a4c346ac54766c497991e8779d0f563d9678a5b47acdb753b1820a82f1295f984ab0ab08
|
||||
028927e8f7fa65d681ea43b9f38590748308f9f304e54f52de2ba454d0bf966b:fc76ab2e:8163b7efeed623df2c44a5cd27568bda4a11b66192fce2b1d46ed98f8b33c7823fe124632bdb42abbb6e1d0a0780d1cc0ee9e9ed28aa5e818bc8aa24bbd8befc01f8448f4b02cab157a3d6c46cb52e085ae5c67fd8ebdba1077c8eb87520d1f5
|
||||
ef9d9a26bca8d75efa517f150e8da7bdd568e59c2f82ed4fc5212e72910cdea5:0382c632af:b8e3126b58b22a853cb838c737237f1a527bcd4c2c8a4aff94d8e3a30b1c53181c0d28a8e8c46fed2e083a3a6219ce78030eec3bc926efb24b65a541e5715849398039d974381bba842a25210b1d6b699721cc82c4f0cd43d5bd268602eda42d
|
||||
ab5f317da1690eddc25786c39b496f06dc6e5a45c250c0d16ff6d02feb448463:3190dee04f:b263b2d49e3f384e2c73e0a55030b3cb479c0d7a10f6860cf148c3bce659d971f8b60c1265705e18a98d8b7f3949a0410e3b34dba3ec3ae66065bed68744281a5722cae8042fb094b03ceaf4435bd6bd1b4a3c6a277b613c24d1dd0aaf6425ca
|
||||
2dd2d83fe918f321e588516529cb8d8e2f9dfdfc7e24b03ddf4de7d68feff2c6:0eee5a001b13:8ec481206906594421366b291c9921d6044044b40c5a43f45a603eca52de182cc744b38d80d1e1f2346119d3a127bdf0084369d7d317a0664aadb36b0fc421c6ba61bdc97a406ce1bd9a05a351ffca89a78f21de6c06f9da474098c343918c39
|
||||
62f441d4421c9e841f5e6afa99346dd757ce3cf4d958815107f80ec965d52fe6:dbd901bfaeeb:85b1619d9be7bffa4fa4dfd3be3161d1be679a48c3e0bb5d637f55ef35ce43c86611a21d078f178908ffd329c709dc8214784af6b2603b944d84a6b70837a7c5b0c38baa97f0b0705c4619f8bb44d1f91f4b248d60ba3bbeb65f3fa189044216
|
||||
ccba9a32e4ad8827d36c5cf800d1536efc96f13bfb04646d39af25fb710880cc:086f8a51380947:a9d85d39f4a330011e6f7efb91ddac0164ace73e1dce16798c41e55fa7318a04f32700f690c95ae10542d19370e583c00e004e18ed3b4161c59e51e14fcfebf5608f403da4d0115a81cf5026d50b1f63aabb90002e89e47e0b55c136d5af98b5
|
||||
bb8d4790ca2b403a262c3aa0569c12abcc3e29e39caf9bc427508a146765b67b:310a7e2f80896b:ac5c0a6ed31609f8066f35826f23864fc373abb0ee7903e21890e21606b28c8ae6c3f2e85053f0b373c055d3caef41cb19a6f4076acf0298be6bfc5639dcb472f8380a88f73d48ac61b2abe134258124a9e7679a71c9aca322a1f69ee2ccbf75
|
||||
2ca95104bc934be172b9738942c9d929aa6c63e8fb38be3435aba875613fbfd7:0fb528fd90c1075b:ae6ecfe94e796391077d18644f61bdd6e9ca6e45c18856af798811199a8ce77dc408bd139c92a086b1a8541104b3b7e6187f5e6484fd5b3bc6fe125a78a8778ae7a658d74cf0b8bd29509996acae061af6c1cd26365defab654390b8fd130c41
|
||||
d02dda8a8f2a6934fdfdde0f0ce44c42c32d035e5befee776e151a1bb6dc947f:a5f1004395f76923:b4755f76590e56910f262b9e3203ea371da798a81899c0418a9ae5da53f0465119c4c3c76d3af1eda9777a5e69716aef01112a650817413353df188420956d5e8883b9625d38126f2c9d8e655a499358198c72a3a8702ba14ba4b5d7b177f264
|
||||
89a57207563f897d97f8b0f4db4b7ade769af29a08978a4732498e7d7865afdb:0914983e4f1f86c26b:95ec831076cf9d05010609f689a864ffc41af5dfcc4b58d7e7b49c9f362c2beddc46b872611a6abbcab9ef7ad80780c9005536dc992a0e06d162f54a561d089636b732c67a4faae391ab31868959f7e777ba44c24efa5778bbb719f7b25a5bbc
|
||||
2cb2345b9fe58baeec3e0d35f6c2bd71f7a460eecc1c1f24687b71c6ee8dac6b:8890d3f6a2efd9c8e5:94e89bb4e2da9fc43ef06ee1f02377b7645ff17d8c02e1c3035417c445279d0ad26dc4622fc864de7b93599dde21135218024b6d8e9bbeaca09d51b4b616c13788c7ec29b63eb8f9f87701010c7f6146e33a37a7c8bfa5920dcba068a304f1d4
|
||||
c9d26fa9f3309740961cea69700981cf51e500d068e5728846710136c4b8beb3:0a4515657fb50f595c50:a435a4692f4f8befe3bc270e38ad14878020d0486887ebcb25b066109312eb51b498813f0324e41b4bbf48297d2b52500938a84c94971178cb05da675fda6fece7a9411e835db608a85ea53340c560e0be32ed4869d00621a15e43b64ad16d0a
|
||||
54079aec7ad7a051158086c3986871746ba540c53c519617a01e559a5cb96360:d449f821249be81a006f:9679c59342a6b68f9350777c5a85d30dce3a9d51082406f39fd21a695a9014175e9b61ab668a1ecf06b0f571b3d5f6a80c5c8d53062129cf3665032c36d9a743a452f0366bad6de34a8264de28a1283f7d1cd584a070611db23322af5472349c
|
||||
aa3b143ce985e2d67b716e5288b0c764e67b93f0e3794f65da0216999d7059d9:0f765189834cd02d2cc4d1:af2de4278f8b0c3eccc5ecff9b35efa7215d32abed6af041bfbde73e60137bc283a68666909668b9ddb2dbb0c9691b75045357dbe068f9cc723177630b0e8d19eaf3d3b6ed1c695b658b0c7732b6e5da17a8372cdb72e8b8a58ea72687935eff
|
||||
608544d7bdda540aaccfc89a03a47946636c732226f4841b31f47a247e4a29ed:5dca12c82d6470eba98ac1:8dae26cfdec9849d7d4701e85c160f3db109aa9e4e26d9f4ab2c158008df740fa526f71541daefbfe61553d23b3fc94c194a3bc097ae33be51480c8f91804147f88e95b054e88ee0faf3ae718135fdbc92cbaa26277f76cae42315771599b2e9
|
||||
7368161af24ad459f868fb847e287532a3d7625fbdc97f912b513f5ce525a9f0:0d43de10726e1ded2f111aa8:8bbabb617042316158491db3e4f83ac5b9ea8acefaad2225b2663d500b6119e48fac354adcf994968e3ddd88e20684f805a88ce038caf4bdab372fa9444a471636e979f1862b1519efed6cf003af1ab9cd66b9707a8ffe4d9e1f9e4a4c59ee8f
|
||||
694d55ee8633e2f3ab91c1f79953d6368875e40afbb6e4674109132d5612aa9a:a72ea58ebdf4589cc1b0dd9b:b89f66033ab23bd10456d1cf977d9fc87dce07e1390f876815875a909128f4f5e5f5f1617c8862b01daffa868661a764097139b2198472db19448e7eb9449d32334193c10af650f56626dfa5f2a670ebd2eb1af484afde7f0410c2695a485280
|
||||
bcccaf8728a31871e0bb250ef42ffd55bb708774779ce59ff38679228312960e:077df870cf7308776ebdf15493:8018593b2946f374536067db76f1a45109b9cd7ed67d9b808c095ef51234c563e9715c62deb7779fb9779604f90c5b4f0509d43078bbc6cde4de440b9409619bd198b0e1bcc29f1ed9fd23f64dea82a888ac53d5f4e5ab2658b01360af8db42d
|
||||
30ddb0c578ed5b6d16b7c923efcc5003494faeebbdc509704126599ed93ba6d2:f2fbf39b84983f5edbdaceb18c:ae7880c31a54ab6c30fbe220415fbbd33a9e005d565f9f875c879b8e9ba20b22d6e054456f8e780faef0d30658b5e7920a9619f6b7608a9f84fe37ec1cf890f2382e8b77d570d6ff7cbf595e091cad7b74e70248c974825f8a93e9299ab2139f
|
||||
a2ad294f7cd59bb04df59146e2924d7f212f8ef4a06a9fdb95bf33ce7344d017:03290c3fded14b5450e5b983a389:af9c61b820c1cfd192e134f0976a949c7ff86d8c558f5fd0a5ec70b0672861494f9f32413379b915896ff7c7e4ed479910d1046b001ac0a6d3597b6f5b8e5ac08b532481dea5e2a79d09f9467b930461cd4efad286d141d81682eb04127462cf
|
||||
abd98b2f6a1b3223890745d67beec62637812d962b69cd589575d4d1edb81f17:3fdc0e101ad52086e0f85568d583:8640c6cbcbd2cdb1ca8ae5436cf1f6f27f9a17bf1d8c9f3e95b2120ec4ce91ae3a7aa3433a0842277b856691ff7f220a18ada5cb83dfb0fcd1f47435292f34b48806921ee2f5956e166f04505c5c3c407a08516c24a27e8973e579547095cfe9
|
||||
8bd98c4549f6d08588cd6cee5866c71696437da734c0835c3da9fac963de1a54:08a83444ae127c9fb9e9df7c73a82f:845f8391ab33e4a0fc29c5e8d9519397765c043e1a9d8eb506052808838266857a70109c2c890e3a815fce66a3e3a8c618131ca4717579997357a346ecd4e4beab44e005fdf929a9db37e80c8e70c89114ce7527141ce0652e24e22b2569db8f
|
||||
4a7a6e21534410573a72d8af48f592489ba283a9ddf4cf8844783b0e4e076694::a630c152277ba70a0316f42a01e07b875bc31b8c5dce53dd5001818ff5c4144017c848c6679004a9eca6edda08dbf64c0fcf94f891d2e957dd2988f2a459a51836483813f211690295dced48aaf19ac31a1bed284ec16b6465eb1fa9c8ab67ae
|
||||
ce3bf80673ace59c43bba9866fd2285c0ff341f05f19339873e6cccf740c6f9a:0a:8791fe3d88f99ee59e1e56685201568c78562199d4473a2f8f0a22e48d4bd8c0fde0e203a93f37584fc629beb3e6ff4b0a80c2bb4c91fc60f64e4c61a98851e7ea103e679b6a90add7290cf655ea9a32441babb5604e56a9006ff0b36552dcc5
|
||||
ef5f9e3816346d71607ee1482d862a27bbad5fac8eff68fc8c09b3bcd79fec6d:a6:899653bd64772ff175f0e4f209edd6a09cbd434a58b624053b5856f4b52f20f189bfa257ebdf5e1e7abb61d7ba3b8f19052aecd1f18fdef84cc5b85fc155fd333007338de79113efe2788f8b4e54d0ad5d453fc649809612140d63920e85a5f5
|
||||
f2ef5731a993762ccf4762e355e37c13d33f7d17a8edbd404ab7555924a88bbc:017b:b8d6ef60ac2c7c1cb84a6158a9c734b5ae008023e94b074ced09df46a61f9e296180b5c77da3c93f35fd6d13850fc081118403118f9ecd22332fb0daf53a0c3e87c148bdf91ae849b1736be9116ac1c0f9d5fdb6e8335a7543f11281a96e2c18
|
||||
7a0e9e9f87d909f7d3107156107407223e538f05069990969db2248e8aafd2b1:3b70:8e7bb94a73839d0149d443672d2db2527c59975054a79bef9f07166d309f497d1b72a3e63cb6379b783bfcfced66c764023baa16abff7722463871a7dc88df8cbe00eab89ea0cba5159582b52c07c4fbb4dcd724b3945995de8dc8f9ac97a2cc
|
||||
bb788ad68da2e63b9091d7e4ac152265f75da7f4a47e53725ba7775fd47d0406:0fb581:acd56cb90039ed1a35a8cd6c49bdfd09cd38bbedcd597030fa06dfaf2719a67b195dcc347e03208d5e1a3950f50f76230cc308702645765d38975bc6363f659bcbca47fd61e09f1f4a7cf9883326d464a3c3a5f37b3253e4a1a28e7cf65ebd95
|
||||
064588d00f156a6708a9fc75c95e25050d795f89f427be6df0948500f7d5665f:b16a2d:865a1462974af0147f0f382dbd9661f5864d7f18d309b19e332d2445b8c150b3c16dc7870b5aa2b1d5df89bfd600f24e177c08e1009c9e666d755797d8d220fbc35171c1415c9e183e86cbf2a06f9ec574e4a462fd942d1801e7da6dfa931972
|
||||
e1b5abd337c95cc49b620e155e5e48e1a65c26ffaeb3715a11c3f8c4b451d531:0b3d05b1:8e6c2eb8d543f81bf0699af4dec440da5a33e3a15151ea108acf9e78cf56edd5596976c662d94a93a8b0b9f4b58e55e10d36b24e3fb4df67e5ec54e6a79848cb01b43c1d82edf8ad8d5c3b3d08891c791b6aaa4ba86e27adada8f259ec18dd1c
|
||||
4c7469ccb41795860f7e228a4a50665828cf1ea62f64ca5af3dbcc90026b5173:e444ff3e:b06c465da8342a430774e64595e567e03a905735f443afd74e0d2dd06b99f8ae460062271e1e41ca7dad9e78ead9404e0e9f626b8af3275c84111956a7a146b29619435f357f5310276221c8c425023a792a561f7159ae4bea27eb6be013fb28
|
||||
7ec0f9ca06f01d5cdf11d9be1aa4ecd04875f9fda11322649f15048aeeeb4c1e:0beb32803e:8e87b48955886958dfbb1970eb1a01e8b84507de02be17a95fec0065c3c3d9274c6800f36297246c3264484fa8080b5903781ee5480e6ccc57872821e5905ef297730364a9c877573799ce0b38d6b24497e09e4200df46e228de05ab4f1568c4
|
||||
fab9d07eef72aeb16536abc68bd311f6a67fe0e8bffbb900a8ea40bc9239a652:412bd122c9:a1955d63b0b78e1bb0c1e661f918d21ce9f9a35a47ac6032e622525bd48fa5f32b84f0671b92fb157004972ab6b7041313410ab2e13c61ff7e0f50a6a3c4e552bb55978dfd631d11a2e0a26e337f6e91e9db53fa702c0477760349ae56167401
|
||||
d7c2c99aa03c9383559987e2887af33d8173834d4edbc4cdc536ea55a612a05f:03bcb81c4791:8a6884f75b3f2b3d6d27137d4a74fc8b04f9a4ad132776dc4e2baafd790354f364226947fa7d1da570d5cfea85dac9e30febeda1445f91580570334e4626bc91757dccb7e53c2a71ee540613d232274fd5c0a7e49c70e0711f3bf72adaa2c9e1
|
||||
31e6a9f2bfd89057675b9986a2326af50fc5b4fa6900e06392500d6a7cb8281e:41e77882d77d:83a3cf3e0e9b4726f76ce301c93db6d15e563bfdb5f93e885c37f0fcf28362e54c86e30d0e6a63f831f097eb624c153e15f8061c8dfd215e7d3a3da513b8f35061b2376457391db393bbafcf43e032f4b3c39a8dd20a1f4e8df3a217113ca007
|
||||
4fdfb35d853e9b99ce5bf7211f55d15aebb153258109c22be3cae0161928159b:053633d112c82e:b42f071afa8cd509dbfb7f4a4cdaa57d1d0910e2ad9307beadcf6ea5bd9518a2095d68cca7dad010907341aca3770134010b8fcae728a60d27f821d759107cfe8fafb2ed9aaf09f1765e3be3d758880b243c5377be3ab293ab6bafc85442f147
|
||||
fc02b27cdaab567346a3fb31e21e5280cf7dfc8caed228152cb602b2f5fefaa3:6b78dfecbe686c:99a058012e607d0a350e8b66193d0f0eefbad1fd31184ae01178a08a4959efa329a82666156d6ad81b6d97cca66ae3851630e61fd629e7f003d71a22389cab9ecb0533a4fe8c59b45f7f80d29080a9c0b90ee7d4b351cb1258c7b3a57fb6cf4c
|
||||
3c4a5789f7d5a24505f69fde12f2157e066612ce25e54c000812718f7b360a5f:038845e18495f26a:a141c5d16c5720fe2c37f0b79ed69ff6b0f92267d7b4b4acccc015876943d692174dae68b9bbf8c152e57f3fa1af159e000d2bd8ad67e5a884daf0a8c0fa9206b3f72c9d5e1a0464b2240b9b6eb22263e457c7c5c0b20564a79ae488178fe475
|
||||
bac507dc6edf7569f366512af88237d356ce017d89b78c5f7f9cd286d14781db:adabc96525ebb16a:af76b85670c18945cf66f8b5a16bc542ef1626d81cd47a68e4efbdbbc1e60a0c3947d4fb6e101c05b58f1c8cbabf5feb0e52127fdf6d268ef7bc9f9fd153d6a86d5f93441e60051348e3197b85bd5c565270cdd491572d4975b1a4e8a0852b7b
|
||||
a4716ee56d0e7e65c8627236f7bab717fd7238c95fcc293902ad5c5974bd0734:00f46038365090f18f:8b2a0c5fb54ab319262fc707efc46c093029e463864bb3e8ba7e9c5813cb4356354b797b8a006202dbd48fc86ffae84b174246ed951642cd1c41722652bd1d4f3f1859c2d0bf1f9d799bcab4f14729ab8b7e3d518122089db9dbf153cc882a5e
|
||||
764e65205f49486a2412d73a620c9cc56337b8b30efd0a6254085738095215f3:17582f469cfed9598c:9613a905fbd8e1f4ada58df87c91ab9335d5f72d813949ad14977d4a524660f00c12f63e4e65d16456c227de3bba02df14a4d61362fe8a7af7d7fe679e5d51cd1b979a81facb26d2501303d41f161c3443a975605fb0daee341fba692e3ef4d3
|
||||
da5402cffede58f9c3e0b1d54af0d230e22e670167b1df94b37a5dfc8ef274eb:040fb6fe593b255bb0f4:b18b19d8fc3fe426d25d759a6bf8127f71e77201a3c0b00953cdb39eba0f08f2f2dee147f2d079d296f7ff26a2c3ae1a11fbbb3f983f55bf5d9018c8c4723f42ab4166ec19be5f0299a9a58c321db4069801f6ee414324dd400e26f81be1165c
|
||||
bd2056e3125f653fa473265980d9c7e3f1a067466373baf59afaa1f62e448ee4:e9c6493ea4cc32c62780:80098bfd48c4026acb497e9bfcd33439f97aef045eb269cf271eca64a0631d99eb3a470ba53c2cde1c3b353760778ac8052311a016f8fc68de6520fce68228b56fd467b0f8527ef9ae0f50f42a28da05a3f27255be97c040a989be480df348f7
|
||||
2cf6644db3ab59850d71010dc15b65ac7e5741f6bff4d9034bb65b499d9ed4a3:064263c5a80c376f18b1cf:ae86f1e1d6d95316820b7c9ca82b2c642ee2fa2894ba52690817b571dbe031b7eb608cff31af60febbbec43a71a55add10944382f9037bd4c9294dd8403810992253f743ceca93e9a9c02390e7d12d5d1f0de8cd03572eb401309e3898e76528
|
||||
c3e1b5e8bbd163deb75cc4603809a7f186d6abed4bd868b3807c583492ee4d2e:d6cf8d3b69b4fc9784127f:96cd710812c0d6c46835430536690b1636a9fd2a8a554eb65d99f991849af4159bf00dca18a458f4df45bc474c4bb916056eb413bc1305a7399a2eb0c4a1aa7a060dada885b9fe64213fadb87135c51785c42048d0705bca81c06692722aacb9
|
||||
85aca5189ce1219ac39e67279fc7055d694b5ad8282f415a181bf09eca566c0d:0a6b5a5a1941892e20e40957:83ca28da0a089a592ed0622f9f025ba4c14231230c8c48880e447cfd3877da50c3eaf2beb193df8c86f674fe7b92a98616ee593a9ab67ca83004ab044038a10a0836e6ebf36293b18f0cd18c13febde11333c3567ea08690748c105445696c38
|
||||
29bcd632044c3f3d1f2b6c37b60a1fa531cbc380902ca7ea5e417081337631a4:5dd355519020c4a2979f09a3:b6400ded257d0e63d8ce4ff8935e6b312be17f24395b26563fe4e532e176906aa0d60d5efe7cdb8855f900dff31bb4b017b7675545f874d80e1e5fb4c0ca85d64b4bdb439a723c337226f70ea3fd9509b364665b3aac65b2e272a3f6a5e902ad
|
||||
a25735a8c6438183a3bf3d2e11a10b18b5bab9788fc7f571f6a5d7428b0bec57:0b43c1734bd438087ee7b95309:b485e3cbfdfb5ed78f9e7a7b70173710c0df336ed80b605403cc4da0d845a6511dba84f9e071f0dbb63a6c95e9e0de7d0496e3837f88c5cb34b653c8bcddfa5c5b9739769a872e58b8791bdbce97348dd00e1a6e52d52ff80a8323ba428b1e62
|
||||
fad6179f7388a19c0b15861cddc147d5b5a9f964a939139b271087352f6b2a94:65f21999adf89d3208de7441c8:b9928bcfd736386dd31bdd395ef2c2653682cc58c0479c1ae4051eba74b55fdc71cdeea3c8763b8d4dbbc965fe52a823011ec528a8d7ac213608ac1b42c135db749aaf3ac5b32fe5b00c3f7d58fbf4cb0acf77728e202c672c2b8dc6e8c791b3
|
||||
e36c61d05679845ead833c11fe2a8efe565d7e0cac6d92b73eecd6663a5e8598:0b4897ef020da13d0b8fd060408a:987c40a7feec7f3bb92f4f159e916224b963374e8815a615a2653aaf175f4de0a0ce63f30aed60761cad310bfe24934d11372881b3b2f6afda7dbd7a99bbaf46f3fb4890e902776e704bee74ef77b0c8217b80bb2ae833ab2d3e83d0166cfebe
|
||||
420594483d27e3b09be201b4d447480d41e61748f5b1ac863ac5b5b8349986f6:66f576cac592391bb05fec22e72b:b121a5242c9ac3c6ae0c5801b9823bcffcab4b9a0f5a507196e29c55941397c526f9c47569bc5f077bdfee8085a7ea0200d31cd16c8071c5a8816e3b2fe90f196fbfc4cd3c1c0bfdb972e93f88b1e9b10ca5853f79c780ab6b799819f71d8830
|
||||
3a7f21f4ad9cde926ff41a5b657d3665ca5391f50427bbbb397c7197aa465e34:0173f8cb823680bedb605f5faf82e8:a3bb11f1159447f09fef369475daf7cf10d51cc93f060d737d77a24268139f121a504ec373d094ce92f290d43a87f1ed136939270f0c1c33d57c285173ba3fb448990e908e5bbc9fdcf41096dd1684a5d0ac811ff3c85ace8ec7c35c80fd2d10
|
||||
7143d5b6a3a6475478b34b5317d3acd571bab149986804b50381cc326550689c::b04c05cb1b41a8a683b07fc0c768496bae0b4ec8f4b509101e1c581297ab12cf6341df1cfc5496cd7d0edd5f41903f9e1440e655fe2e9ade8d2e09ff4ba64576423a00712b6f66112d72b792c2238944f6b5a6d12ffca7ead0ad1217c2a68ccd
|
||||
5107fc58427eb056153b4c8e26e41b0de05d78339821f91bdc56cfc3f261f62b:00:8ceb7e8cbfbf9b3b04e70bc7e49df066799e6ab312ac17df4603c6af4ec3f5a0e0f6caa19916cf711bd15b3f54bc2837046d7e85b97f5570c3d13f1dc5d791db9a9089b61264aff25f3f4c5834dc41e1ca6d91bdc2e8b3bc33cdf4a5c3909f47
|
||||
d9cd4f44d0f610aa8d8bebc850b98a54a1a7d6965882d053218751922c8adb3f:eb:911cd633cfcf561e24754efda0ecd89483d058fb715ab3c149fe64d7f7ad5fc6269271364d195ed4694dc32b8bcabf57196ec07d0aeabc11a601c2b19060c586545a9e784c009fb60995825068a6271c9b080b35bba5e8fe65b0d7382dbdad9f
|
||||
a145fa89810ea439afe5263b79444c5e12629c04fc4a29feb802fd4707e1e091:0a09:949afe2cb8d74dfc2b160302a1f8c44c80480875821f275b73798a0e07adcf358f985b2c783f692b6f2195e0419d213d0fcbaad2355ca05aae0371b071bf805122152d106392a8c9c51f16a2399a2396fea84049ff4d3a171e02f092751b9d09
|
||||
bc386e77aaad8f0629cff07f33e35a1b989f900c58b971dc9c09a4edd0a40cfb:e910:b183d730da3d52afd07e28689e8be17b0df5d89cfd74c4ad2edf796fc905924ffaca94cd633554213ead81efcef7eb3c137fc90b5906c1b5dbd2c195c68634b60ac4f7eb7ec6df44e4b0c9da9cc2d9ba22e8701722b1eb21ada0f98af7334e6f
|
||||
d94a000a40b98acc52901f8ca0ccdfdc0497390eb7f5cc739c91516b219cf7a5:00e3c8:952405861daa32b0f47b829e08b4cab83bc8effbbf62a9e0a640de551dfa64a4739454312df4bfdebd84271dd0b43cfa15e2cf940e2c15877f7a2f7d88ed097ccbfcd60195b32029ff0498ec23a2acad986c3d201a707afe169ad5d7fa724ff9
|
||||
48b4784f1e9e070b95cb181904e3ecb7cf6234e327e2666ba598b88904cf0960:48ec55:ace8ac4ea4040d382f6bd290498940bffb49a25bca1903dfec23f0eca9edc0848bc6c1e6c1ccb7ea71732ff09ae369500e944bd739ebb760e41965978d0ecc6815a1174e3ec4c9fdd5967656953714b0c31f5a546fbe4505934f77628b554363
|
||||
c28db28412e04efbb248b34e127ce163ae3d7450accb3e493f24362d9e01fa85:09aebeb0:82ad16e002985a12132955fb034b8222f8d45a4cfe8a3def59e1ebb6de074d89980d2314cc7ae3a79795c29bb1d3394114cf923376778654ab8873c3ca0436f04b6ef0df0b8b7cf25eae993dc297e9c0375f64aa8c49188baf8687d630fbb2c5
|
||||
4bc72dda1b98ff6e1722ebe5ca4ae11940483948f73a6d44b87cdb93675b2cec:9883069a:a7499c26f769bc11a65e32e3c274987f5d272242016069882a28946854af8625eaa38953f1c35e4c8af78bdf3652a88a10a7c1a52be2dde6af14fd6298da96f8b7c9329b5cbf4e725528fafc813a8bb6151d7e9fb15123c7b60a2db34463fde9
|
||||
25e95bec8613b28e98fc135365d012acb38c72551d71f41989033a59aabb75c3:0d8db89e47:aba0be6046df2a730f3f00284c64b8121f77c0b10cdf8ea0f60c7b38e1a2cc583acbf5a27819ce7e510503ade8149ca8198793f2d84ce1c071655da4795a7281b3dbb6a522ba9a091f8b5a37262ec1a43935fb89bf0a9dd2ae59390bec7c605f
|
||||
fbef93b0f2ed1ff76d1bd67b99044cf6a39b435d5b623ad8d8ee28169b0a2393:2547fa99df:a572707d5056e22c14d314e741cec99e03b5d6a086966fe39d952812694ee0f673e23f13cf5518b19d2bdf3779fd53621719c43e1112f5ab9c2838ff299773b4308ae52cfdfe0dc672ae42fd7b9f13813149b9024427def6f4a72c1dd4f97a7f
|
||||
4e1a6cca760e6b46c90b190da25d4277d07ed704d4377a414a0d7aebb38c5962:05161ae4b3c2:b72f19ff530219ff699a73e523564e36254e73eaedbf22d9c7a354dc3945dee58deb89a1c095779a12df44a1b4a6c9560001d978c499eabb966d477560f5d171276a44c94bbebe3461c2b6c576f0e3861e9ea76931a4f3949399a514b2a49b3f
|
||||
cc3869b0f33e91780e12fc8d1d240b950776ca546f7d5f212f9c8a758ba9bfbc:5692a95e3a3c:90303542c2c4e4be801a2079acf3dcb5017da834d4fbc3a65e4ca90fc2ab2b3ff0ef98fcc57c16f6de07b1ac0b7bcc6409b7cd60e74cfe6545bf54b9e8585b120381994a5bc3f572490e3a5eda3e5caf4c7a6e8238d65f858a8f5665c29d8548
|
||||
c5bbd44adad8cf07a1ee21a19ed6648edcc0da89c8cfee9d04eb74340aca2829:00c21979aee718:b682fe36524f3ea36039a3d5e9791db535e410f69c55d4e7c97c28beab85fbe10a09fa806f783d634aca926ffb4a392b153094e6829a642bcd13c4664a97a6bc23d87c0f356530fee3411e910a92a52e221e61edc03d18d3ba9bdf325f57b9ea
|
||||
4b063743b91c96b198a889e2d68cc9cafdda87c4e49ebc7904eb3fe516e78a15:bdd472d8486708:a28e113b23dbf0c2faae0ec7755c9f826845f85827ed0e3d4d2033c818fbccba06d5645db7afe08ee18b92a2046019a911f3fbfdc84ed796181c76506c636e4f07a32dd2b6b4cc03d59ca0272dbebe4f2addd35f9b24ed7d880314ddfd30b9c6
|
||||
2d7b35ebbe2e91a94cd857f349142b354941e34c30916493307068d8a6cf2ebe:0ea8b5464c8ffdfd:824252f8347eb299d1105323304e2b7f6985ed6ab1860baee4a5cbcc476d49db56e1d834f5f6293d0e1c1143fa60bccd1551af939d5435d514afa710ff8f3dd80b76bd7c75f728c9abe76c636ed588f406efe7b509c1b747496bbb6b18ffefb0
|
||||
3e88b2286bc087bc7f6476652e444155922e8e239af3a1ebaea2ee36cd0dad1a:d0e9ee7908a105c0:ab625e2a5abdc53a9b882caba06492c661233c7e4fac9bafc8c1db9ea44cad455cbfd618e917703fb732e0540e3208fb0f198420380962c078d15304a7bbe9c1a259e8cf2ec49fdca4dbb39ff69f1ab5c58f97fec90e1756666115fb0b63219c
|
||||
5e3d08aeafc50403c0de0166ae2fc6f39615e6012a04f03552e6c8869a702a5e:02f34cdeaa6f8e5cbe:b5b111acd6950b2862627f2d0ba6fe5b24cd3541be4ee2ae887c86ddcdd480a0a09c8003f9639c88b35c2d233b75d2ee101a66be894f438e4e1dc87e9bf2c80db7b34a3486c213281aac163a276f0850ff8b6d7681ee73a7b2fdd0f7b832caa7
|
||||
276b38d5aa2723f4cefa785cfc077559323a5c98328b3caeff1884c0367cab4f:4dadca20bba5e6776b:8a8b0a03047d87df975304f41187c006a310858272d6aa84f37c8f4a44e78ebcfa70f968dcf5b5a6b308c9aceb8bc9b4113901fe031e4deddc7fd40d85759b38df88d8e22b29166f2deae074320a742ef10610cf4793255ebf5eb456606c583b
|
||||
fa5426eb33077b1b099667fe2d695b2711a44266c22788ebcc3bf1c5237f4809:0139fb2a7aaf639501ad:8f8139e53fdfa59cacde3b5821deb75c7b6f9f153b0e9fdd044ce79bbb7770398a8061278359d97f63ef52c4fa41da71170db14a99f48ee899702e62beaf09e2be453f9bb8adefac38dad3076835a9e12ef6b7f48e30413d53e728938413d9ac
|
||||
11c5ef8785ec31234ef347fdce2a1534a49967245245f9523c319938daaf0a53:b936534e227a3c5cf272:98ceb3072a2bf95c95c6523451c3ef7f2e5e852e7e3ef77e60dbd26ae6a4020230c558b1d044792e48f6ab2cc755143102e9a2d79e2047d90c1c1dc2c7e1d0befe1b9249bf9026f74e4aa229c6798721a694fc1204df374a52465fd1d85360bf
|
||||
dd9da6df2c114902adaf5c0b90f0a30ed497da31233b16b9fa0ba48aaa9c7d18:073f5b3bcdf9fc462d6fa9:aa11b0e66c652b9a3b638da4a6702d10edf774f6c704c0ae427805f01c3532c5e2ad48dd0bc345ccfdc496635876177b0ca105b77a4dec4a5d4d1b341bde0e61a04e38d88cc91e707fc269e2a47fbdbfeb536fb999994ef2fcb9b5f42eaa8c26
|
||||
e98729f51b9943d4ab9bfd2057feb4725c962a72d6af4849da9a79681858beac:d364782af1bd76a74a5860:b0bd5532f822f65c5ad300a13fd8a8ee76784f9295eb98a630082a708473d40a4a390e9857888d0c4cda282699ba8334173b25ef088a7b4d23967bed053dab15b9f6f9b1ad071a71e7fff14416b2cc7f59437e0a0e3bac09b695f27f44d56d8d
|
||||
33a895e2e1d632737f6f11ff5a6857f971cf37873c1b95df2cab888c6bd582db:0acf93e56587dc54e775f1dc:85f3f86e176ef7934ded7f5cbc419f99d08727770b7172645b94c235d73f1311451dcc54a8735e8d2bceb15caa53a04a0a402b14af9e7b49323cdb728b004a09a695761b5051eb944bc861ac7b656c162d0e4a9578559883f9419b3033dc0c83
|
||||
826621ca2a9a206f403d92d3cc6ae1df509ded64ee5a37749473fb4089b21b24:21f41b0f651e420444caa733:a6ae1976dcc46c1f038fc300f0236c07a375bbf3ec982fdc492c14132aa2107331136ab4de36917da8680885e0c76bf912f6faa529581980d9c379cfa4d5786b8a64adedecd5e7c7f3ef4b273ce886ca916ca87d3d8d0cd004c437e6f6750410
|
||||
356522ef840b1ac132686085f346558a94f2943b48b75988c2cf512cbdfeb678:07b7666dfcf9541697392813a2:903225b431efb0f426aa962edb914c1182e6bd208aab9ffa0f9e502ad0edf4f7cd1fe139ec67597c0c9ba2f2b96b890216aadc7fca55a57c38b236056fbe2aba71f033b143fcc73abff454269a8de40e7c92777c5b0391fd3bb4d6991de096bb
|
||||
2724b641a54745be949a396375b50735b1e4bba8b5c9df6df1ada80c4f9edebf:7e959c39b0c4f95e90e05d4e6b:8359dcc9a9c233b2d871991cd5587f83f2544bd1c0bf83e006dbe148609ee40c5fa7c72e4861061b6e226d8a3d28736d08820f8f8cbde45af586ce9877e8783df86094e0b28d3cd40c04fbf5450961d26e9b61901ccb80e457da79ee1687d53a
|
||||
bc4227976367e5b3906682af2f4c12e2334ec96b02f84ab8adbc8d6df156ac1a:0b3d791d2ef361575d5e20daab74:807ea26a6d18624ed13f0ba940f914d1552550054195d9cc82125dc7c5c77d1923af45e062971a92224e3d31a8b4f7c10a65d1dab9bb7a526181cfd9ad17d0c1d4b571a0f0ca4f67fe967940a37bf63a5c96926da314f0aee4bc157511c94eca
|
||||
e62a19ed9fcc12b49964ed582e1e4ec9206ead22fb3352802c9ed124ca6fe99b:353c45917ca7cc233906934ca47a:b31abceb41227aa7b3975ed26822644e601edd9fef05fa590b36d9e5db58f01677ab7607ad6437ecf93ccb6d3e73f8660a92edc51a8db71dc75702d4fb984ce458eea6be357bcdaa1eacf6c0860afb389c6cfa76a137ce6dfbc8b73f3f93814c
|
||||
de94b6b59425a13582b2884b5643ef3dc0687e562324ef16ce60ab915ee999d4:094448d5868efe496f6416638e3b6b:967dee15785d4825563c26be491b30e1e44235e5618e2139dc419d031528900afa5c20380a61d58df87c7a40c2f7b17b174c1547c6a73836fcf2ba795dce10b1a00baa630021529d5e7dbbb31e8f24d36d202b1b76af9738a2e7e39b1789f5f1
|
||||
beacb441f1d0df37e9ed5eb637f722b63d43a051279c6b4eb0896356448f922a::866a698873fef803bc935885148c8c84996881585e21207a2479f55376911c17eec651d876efc84419556abe1a169c4c17b290a8dce65ec8321c43676f5dba40edb177adf83f61b27d91fb1cfd941e160db1e53be16a56b9e4f6b232b8a66810
|
||||
a2e573f800a2ebdd162cf8140e809b345840b21a5902dc2e866f9115b8e4cfd2:03:884754c37d989ab3a8f22760666d109e39f02fd43b7d9f6b56b151de79a5ccd04bb7e161917a5db009c466bd646d9e9f0b014fc58d0b8b3c4fcf7a696117c085638196a060012a4f2c98fea11a8dba8300edc7b8d0d6caf64e2f076040adc729
|
||||
69e59beafbff787b405498a1c4258811a7855cee59cd24100cbc29e9a5338890:af:9899c81ec05be74370c381d6da9e537ab96b94a3a140baf23bef0a8ed396c885ac83355c0e4636f16fc609de2954952f110a5a9e928729a7baa9bfe7cc91151f1243e4e3e109c6828dd3a4b847fbb9ec0b950640dec5706e09fd97f00ea85c89
|
||||
3732ed34c394b61efbe6762470519f7cbc01b3238ccd16bb3811e76f78b28969:0f07:90b715bae0ff837187f346b8312a03450a61a6bc13f4b65e788570e4d04dad2098f29ec0024b4318792c4d276c5ebb8f176555d6eda15b985714cf68946d40f8ebd451e9d01ce383cde7c14e0701cadc68fb0bfd3d43f69ed3159b24f73b0ad5
|
||||
4e4e37b3e34497a6a2b9f29dc48bcc66c68b108ab5ae3ec7de6b9163c8089f53:dd2c:84386746faefd739875a51b6bf0a3f10ab8fd8ac06e7f9d3fc8be1140416429c33ba4e9617982cd9bebbff8b3b40f06c16627e316c6f4828d771314e56b2ca0fdde30b7ab5d7ed0c2046c70d1416cdbaf68a760fc9c3f16578a588c743f1e5e8
|
||||
840f953ed1e17c5676dbf8969c92416d2806f74fe0cb8149cb85366e51f8ea56:048edf:a4a727d126f064d49c6abbd0811ba5b728b03770fa4abb4961a56cdcd60a2ed14b7f52385697ac524166a9279957595a0df740cf1c8ae3d5974fc48bd23383d87ff96f70e62ffc5ef1455f2eefe1fcf99b8c07d063b8ccdaedae3a43ec37645f
|
||||
ac1eea17174be2d21133916f1649763e7ba8c183a23f7f01e8595c413fa9f796:8afdba:a541bcf10e028b7359ce47a7be89a8614483b9ecf852251376367d871f529ca6c279348def2ed815e56da57f148e551c021c0de8ba3295dbd8fbaa1fd4a95178549a12ce54503e5d65c281533247cc479c1eb3706f2c52430697a851776a6117
|
||||
0d64a2304ab3d884c758a634c8e02a39df28d28f45326ffcfa227a4d09d317dc:0c57df3a:8e666a9f47f8b5f671e69c2aa41bc1db30a397555509fba48b1d017010ee52970b190bd133ff5a33459b700602a13df20079005abf2d1273d64fecb6ecf0bb61c6f1d6f6cc89666aa102accce758bf8fdb2fcd82fb1fd7955c1256d18c7da5d8
|
||||
90496775585cd9ebb1f11a7cdca5c9f5aa77b8f54cc1a04629744a6efc793c0c:94d33984:ab566969389b382ab1360b06691c99089d5bd4a0d02d92ecfc47af5b6bc14ae6699ca2f269b970713e6e9f36d300e0f90bbcf2dc71feb1d47db99916bfee0608c15c9a8a714f84d0b16073adc87967aa1c468d4d3a05d3a8639043496db48d1a
|
||||
897f90e55ce1dbd9aa3dc72ceb0f890d63e97326df0e7049641ba99505ff3f71:0c5acbd21e:865d3cb8351aa4545138a31662a9f60b31fff86186021c4cbbbf46ceb0ef9365634ac48700a9516d1a3b49294b49cf8b1705cc8f57f3d814d827e1ef915bbc49285cdb83ff61a334b7296bb1d7f6bf0c11e39e84360809463aa15372b198d33d
|
||||
d7d223e28a2fdc60e284f4a894cd713fd3b5106396db99eb77fd0e3ad3450be2:644b9aca5c:88dc952ecf62f5f7f875a2365a61ec00fc4989056467454246dfbd4e5f559190b98a744e28e346ad1859853db7de2a69100c648fa64b05ac0529958ca80b7f97c386d3009ebfc6addfed32bb55f216b1c3b1294d0a14722bf4edb19da6d9272a
|
||||
be1fd55d56ec81af5becfc86a2e0cfb7378223f4cb272561648c230d27d68c8b:095c77b908da:a44e6cd4a6081c9c71948c6be2755ac271c1069ef3772f4470a7e138b596b75d7cb055e99950aa21eaa5cdc35353edf010a04dc39554730a690af15b998404456935b9c52d52e9a2467db9916d7824aa9746bb850b000d5bb9d22bab1dbbbd17
|
||||
58298a7fde5847078d221ac45fe91d7a5cacbe6facc6b0d1c1c846bdec788bf8:71d0ada1a638:9017e5e0d91dcda6a826f290bab407db01e3163d4f1bb47d6a2b9d8ec455006e078dcd193f8fa27655f6991b512e92130fb0e9b6d168a7d1df3c63b476cac683c10e061081c54ed0c648a07616a1de01f0a39d5b8c68bbea4253b1dd260e9a2d
|
||||
1f7d8693d3e0e5f58120e12386830ab8278db6af93a9aea5e317009d5c7abd90:0a9f29d796cf7d:942bffd18f0d166ecd548b79aefd37590814cfc02d793125d7e01f3f46e83ac50c9e4d4a7d7dbab364411ee8c3f57c200d05c047af7859678c8776d98de90f6830a74649d917ce8f950242b05a1b33f164970bd1aabdcc66f2070536ed175d9f
|
||||
e116f7c628880c89edddfe2ed67a99f4db7c1702271a635f9c62731574f3b07d:b46ee7f0cdc911:b317d9515771038a31d1574a61a700da81d5e143648342013803272b60d71bd61d92fb4d5b7018b9dc4ed0227b56d30c14d51c9d84914f6d53ebf296fe8932d086a0cd27bfcddbf8239b465ff9be41cfaf9828db2f6c4c263f09a57c596016a1
|
||||
2ef3156af349a534508e4448c8eb2cb32f38bf79061ee4960affee1592fe8a33:0f8cdbb84ee69ea1:b115204c338f8930528efe7c5d3a4a42018fe1944b738edf3128cb04c804ef73ffa2209f0f5eafe2d825ce73604db3a503cf47cf3b34b613ed5fe10a3f5e9de3c27d8ef2a3894d1287fc045b01b97a4d17ceee0f03d31b81cded5a52758e1fb9
|
||||
6087f431c3cf8344bd95e09c9b5891150c4dc82ab8cf49d4edb3445848525787:06930ab93e2941fb:b8aaa4968d500766e2cc15e5eb3b6841bf90fa2208b2699a1498d824509b79bbbed192e2e5142a6562d49826d020dbd30d06f3804c321b560c81b4ea02e281ae2d635cff541f82e5cbe2c96f22dcc8b41eb01e4c21957092c7bacfd4cbd367e3
|
||||
98fa7b94541ab754e6eef1b67714e04f324d25ca7fba72263a74ae705fe56ce2:0d5319c4e04c108b43:8567089bca14b9cd5336556283f3119c70bf2e2a649eb72e33f2de62314dee52d270854382e2851c23704c90cedeb5440692b5bc28d71364fdcb9e13ab51886a30e067ebc7b873f26ec31c1439d58ae87add0cbf970587b4ff929bf14f86fd87
|
||||
ce27a9320ce91af5cb25db85e49ef48c889cd2cd1876f1bd6a33577e89d01a9d:456502c375d647b287:8fb103caf39bde35ab3c9dfafe2cc93355d7745866ca999d93b311a5231f0f898fcb8da735c3b90e5631b043616229cf13ca431a73079e16dd4c65ceb54c8ee06f4c60fc0c143b734391db2422d035cdb98c637b2f53885da84f61fb3fb4fd8e
|
||||
82ec12537be95b513523032353671a31bfc30fa874394854f18fc22a83edfc08:0a0ad6660fb6b9360758:996c339f73f866376bcad28a65440154c3161013109a95fae84f3c7cc531bf072e661f099a23350aa84a7c64bafefe730e14c5939e4797decc3c49af9c5538d1d02fcf27f714c8de6aa14c4a51da1891ac076014b0c2b0d114ff673df6b39495
|
||||
e20cad243ac923e408ceac8701dc75b6a4901fba43ccf5d8834569437555ec88:93fe4e5afe409cf5779f:a7ea309bb1ade75ae5bfb6215aabecd1f734b85ec9523491aeafb7d3d31e7cdcb0c79e15838a75a5d5800685ee36bd6b0117a46d2dc83364f6ee1bf0164ffa02089f6d3d921b0a1aa9d62eef95bc17257aa2e1f4c969e546145acac32e05ec2a
|
||||
88385fadd78308b14a845f904a22fb8ef155004381611983af1a97dfbadd4cfe:03c626fa420c8ca589184e:a4fcc04bbbc6b6f5a67a4f20ac9d3359d2fe9d7e26e276276a50361c3f5d2aba5a5945b774c4eff1ad2bc0b71039fd56120cff7dce6d31289ee09df92f7216e327caf71259c55d095694fe892e8974296f18a370596ee0f9d77fd874df5a49f3
|
||||
2fa90ec2bb82b7523acd10174510e9e1f3cd8d914d5df1c1add12294f4201b55:31116320fd8ffbf65edf62:820727a6167a7d5d65e5718f3a8003e0a1bd19f82439f2398a0f7ea568aed18e177c8562806785afbb4dfc8625c5ab9c0a0afca6fc38309ed111ce68f3780fa49b1a48625fd960436c8033b0fbf78c58077633a964a513d95db6a0f22471df30
|
||||
fc9bb165ada95b2cff23e332c0b9f6b6a9e684c38677584e4c5ce5b16c78f66f:0915034dc3615740490ff744:ada0438d237761c391d3aae9b10fcd0b8ed03ce09e8414859642050dd88e03ddd69691efa26cf68b4f4aa051e01cd9cd08efe42f1346c952bf5d47a5a9cccb8c23fa2a667bcdcabcbc04ecd444e5215dba18397a22190424358b9fabd7579591
|
||||
3967f728a6fc9b97d815a8a76c5df791d8252cb44fbab8a52bee1aa59228f26a:96dc2c37e0f9efb8f177873b:8dda9f419ff275828006089d7e4e1342b5eb17dcf7c51a2fb7c5cd6ebfcc2064b987c3b2d100c166b8499d82d705905511682b1210616c5674b11c3f6b472fd92879b1532d2c60a2c05535d8224832efcfbae410cdeeaff9428af6159f07621f
|
||||
c0bf0882e28ae3ca0f4c9fa55f0e8c48f5cf4d5fb888005be03941b083e2bd75:0dfc99df951bacffe40d17fa40:a666faf2bbeae3b0ad5f6cc18fe8bddfe7ae77b63c2befe176bc2f18a3ceecb78e91453a989642b73d2a18f5e1883df2173313f9e68d968cf3d3cc1d65c6ba4da837f2a93a4700afe996d0b7e0ab3b0d9f9aeb4da76db355ac99f21901af7c9c
|
||||
926f0d9c037207a2ef042fc01888164837e999b668b22e72d1e090c030f2ac14:042fd0ac0b5cea9347f8bd6696:88c271e6a393f3ef9cfbc3022578197690d93b1cd7e90e14e1aedaa8f4f9372dd0df5f2be74c5f1ed7adfa3467f5e94617729d08f0339e0c7fcdbcf74fd0e375f0ef85df8c4a7031f4471af7bdc72a692f290c2f23a361a471e7f8e7892d688f
|
||||
1cc92dbca460512827bb5ae49b2f5ff3b0aa556470ebc4e08d06006794fa95e4:0cee8bc396fe6f2e44bb0c608bed:923613d71c89bedf640787cdb031492059309a702410308fd904c2b29c6d78a75d2fd5e6758e759a91c07c8dc55310120651f208d9f1184ce02f02bf287c20f85f05c660838b0baf964b1785dd4b72ad18a4c86410f14d79d5b6aaf8a8093c9b
|
||||
2d94bebfcdf3a3adf32af3036e6098bf51bacf2d8e97fbe53ecaf302fa176076:c1f3a335ed2198cf83bd46540c43:a40961a61862c95fa04a3327b9ba847d986cbc1e789b9a4009182a1921fd728e051cc3f879ed6fbae67b7ed40f8cd3350de0d91a7a58cb9ed3c9b6cf267a84c7021a7a83931c0834a79a432e75a8ff1603e974a3654da2bafdfd8d122ed6c4ef
|
||||
f223072deeabef9597b9404215b3b1f0ded345552365df94d7b92bb78593fe26:0f381538c11dfb0ef9bd9b585ef2cc:a6e4ca0f2fabe91fd4f67db13d8a52de8b09455e22b001246f9afb50dd48f31c3c249644544eca500b2042c824460803182c8a0d92797f16f3c45cbe16d7e40cae3b1f7102fbbbb45fb2c66413890836b7cdd3e685348bca4987c514c05c2299
|
||||
16c7703dbff0bc635e0f1616f11ccdae9c50c48030b50d17f40a583f4b8a8a42::afc773584e0e50446d784ff525edad44d3c774dd141e13346c7db92be76f34b356844d2206473f75c5b66f8962ec9cef082fa43a05398273bd066ce7620f59ee443f663c9c278ae9a64f181d332eb0cca3fbe3616bef48d5ad881f12301c4012
|
||||
2bc35b91d5972e10dbf0160c138ac436079d6c43e4eefbf3fcc9c06767bb31da:06:af9b614adc4f80d9554b0167e1361d0ffa413f9f36e16930d707c4da190fb83701984916a2584fd24d65f350a6dc93e606877656031e847dc9b31485213ddd3c318fbf27addfd209e80deef7c23e174be7e7f34639a1af09dd6fa018bd4ed1db
|
||||
4456acde3242387fce74bb201e5624c1097686e3ac5ce87d212f8fd1d2d4378c:85:99b45e3ed1021db6bc869adb284f025bb9b930a8782dc9646d1d5840b67b2c1e957b6a1200cd67e2c05b1e2a016bf58206d0067bfb59b47946e99fe99bbf8d1689ec20cb1bcd3312600b24e8345e43c1cac95f03c742e9cfc4629465a35643ee
|
||||
c7ac6866828fceba14885b50fc4b29275565231008fc8db8c33f0730493d7cc3:06ea:91e550dbc99350364a3722e2af1ef9f922d5c094faf39ec18649ad190ef13835038eb5201e25276d3a5f124f049610810e4157b4204d19da5a50ac38d913990e5c9402bffd51576f5509047922151ee6fbbc5760e588cef3296a805d65bf2495
|
||||
9cc0024de1d0ecc27bab1155a99eed06131d3db6748b96f72d04501a22a4c13d:7a98:99890de7549f5fcf2c0699b55bcb0bcee6e080339678c6e5b61cf5d00684a4070f8bf9d16d2211b0292cca06c255da3406623a84cd0da3044c8f190e132763ee62acc2f60a7a20a8f8c94a237ab72fcf4c9b08f4d36c0198be735ec0698106e3
|
||||
3a161a88b0434351865dc4b322ae2db86d38e26b354a8072ecb007bd8397c08c:0eea0b:962a8ab094224d90904a2a48d6b63efff7bb702ed993d9cac630dd219988cdbe264be9505ecc24c82821591e3c70b385093bb570ecfeb81f50f66f74b9d19335fab464b782f98ec0c7233b83b895458616ba23205478c048c7f43187353e5159
|
||||
93c67f70207b5707881aea562f3261f1415c8b6af2e4c95590986b12c8a7832d:5a638c:b5cc880c00f50b09ab58081251e0001ad0f091c1fc3ecd9cd6753004d1a2ad82056b61cf7ac64b3fde2bca8ed02b5cdc052035ab0af0d17f78f6ec97dc55b67d2a0a4627543b0b42aae01bade567eedd41154d254036accbc2820a280e8dca09
|
||||
4b9dfc470db493399476bd07c30de9b8463e6ff0e1a5461d7cb25920caa74e9e:0a77069c:a2ea5c1c6917c5c74352fdcbbf0320c86f09ad9ac0c29b44941d1c2fcf094a03105a3a1c7829f70c21282750f912f64a16b0d077b38e2e94b3841f3ddbbe29538bed0c3a15b9f3fb3365812c26423ed8769588ccb0ce4007500bcda73e934c5c
|
||||
182d193ba7412d09b8cd8b486c72f7163ab7d572b08b95b4aa8e41118072b63f:8f1ee0cb:a9eeb586a08cad5422594833c53cec8826e1ee18d62eb695226df14d68e8973c067c5a88522d72a424170733b05723f41925613e55bf883158bbb77a7944e867a71f5350558594467329ea8381f9f8ea064300f46e0b2436fb177af41b6465dc
|
||||
4a373adf9961e3ef98ae8009188e948ce309d3582d63d850a13fe2c304dd7065:08cbc08a8e:81664cbbfbee94ca1c567f980bb39e686e390e94e527a30d4e4f3dbf3f5a48c4adb5fdab07992633788a45750ddbbb1916d3ab5e77ee56d166ac28e81a3246dcb5e183a3692d7eb7f192a0487d219d79514c657d20db0c4ff1ac3d4af5fdf33f
|
||||
520133987bf9a4eccaa0da403ba0a0c44dc83d25ed8345976ddecfffe207fcb0:4f03ee2e2a:a1d71d93ff022b10538bad0580e0fe30c476abcdab5ed8114a5ebf1c5ff8b2818bf6bd963c9c69f38ca8fca73da91c1612fbdb7b3323396d1b27afcd05679dfb360bf79dbc0e2bd9b6afb8e64dad7f00ff9e50ed2dd199f53c45a58cc2d09cc2
|
||||
b1c3f3d39a291acc244b9614b505030bff47295fe8ded28458d62248098688e7:0d737d559984:938ea7b377846d5240727a706999b425e6420c2a2a6ee4603c66235b3b51301dc784faff02a55ada8d150f4ce50e2bf205b4853cd9a98e757027778d4884b4473f346d2781eb3e8d38205b9c93627e0bfea2c9414cd9da5e689526a076d754e6
|
||||
f43d8e4018143f5035008a1009a0a489a94791a6767051f13ebccb137638cf6a:914018d2bc6f:81c8d737713175d9539decce0ba7ec9fa8b2a1bec70bfcf0e4226fbff51a19cc3efefbfc157746500e5b316f836051a109e150906a9febc7d2471de3c94fe037b78bb68c8e8960d5793003b0545779554358b1c3479a6bd255ee9db60be335da
|
||||
5bbe2155b1ca1a37d4cb75762dabccdce894cec7452561bac5651f92b4ac1fe3:0cdde70cf2bf55:8474f69d3efaf0005b1c62e54650c5d49ea3117049923d108f00e7c67f9d57aa967e675d5b72b9619cafeaeb11ff057f10f952ddf35de97125a062874492aa7f90836bc1bdd1b942d877410706547f6a0ae0ab25e993c3a4aa65de7a180237a6
|
||||
123a411e3335542f1dc720d8354437476c9b81d568daf817b2db83981629c3d9:fd67000db24705:a5d2ff627c1a4b7f52a71d158926f2949aae9fdc3e206f9fdf9117ec88ae8c8cbe4d23d17c713b2e09e82d557d996dd71847b7e86bc1c74015c09abeeafb72873da6945e0fdf5b5cd91c622a1cfa9bc258cc6eff0125377d2e44b16630360381
|
||||
85d140112f583ab2ff5c04d3f1f3944efa63b0a34b3979bf9aff0a3241165e5a:01172e0a402caa46:8fee0a19081b0adef228ec3cce2cc069911ea922845aef15c97a919108bbd860cb241be476cae84e0149abb305981ba4045751809c174b2f89fc36e0a498ee7f325e062121267ffe27c0261e416ac7bdcbee7f9d19e37cf54fbeb9e57f23d26c
|
||||
498848b5fd8f6fe2008c039e5f972cf6d6ab2e909acd594ba8cddf7da3233167:640a244c2ecbeb26:ace162832f586c088e3ef9d558228a99c6475e1eaed0f875c512fed3f800f876409e8f5b28831a6563511ec1edbf16fe067cd73fa6413030c0892e6c67b8ca3a14451642959e50cbf18c7e6c0052dd7ac9b98145694cb5f83feb506c13238811
|
||||
f861f548187099ae19317eeea551a0fb9881485e0adde98e6a260d7b4604c755:0fd5f6f3687ebd0622:895925c8e398877ee20341c41f703d355eec6e1fa7cb8d9062379f693f489c325c94105d41848ef94b1700b5555128720ce287d39ea693dcb99127d764385d242f4a93c6e038e3defd68f791a013e3a2958e7ceda6f695969f5bfb31af826ef1
|
||||
370642447c6763c7f6ce66b4013df4b46a4de47ca9f34d2c2d1fc130b4e2c9e1:395025a2d1d88e0635:9259229b65e9c1e95c876ecac32d33acec12d5ba217d9aacb30f52d356338954feadd6f9fec797d974b79bc2ef0e41f60a82c3d4cfdcf3c399bef3ff026f0082cff184a3300d0de1a863fbb498cbc6c87e28967ae4250c8ebacb8ed3f4a4bfd9
|
||||
3832a8792ea9547d7fc8b3fe8d5df2f35660272dce5bf6ccbe7941ac7700b194:0ea3967ee0e677fce984:8b135befb49f3fc8ca4472935515b3c90c2d9ac6e13b0ed17da999fbdd5981b580ca387c0ffb3fab8c2b44559cff3c211404f792f243d32f5b775db0bab61ee480238540e2281ef0953cce57457d78ea77ff1342f695c16af62b5a9f97e94961
|
||||
9e052fc09efdc8a7ecea5545fce87ad988a42239e321ea0831ada650a76f63d0:4ab7c1680c49b6f0283e:b0c39cf1b66cb385f233ce068e7f81099d4de1709a8cd4bb7ace275ed49373217f57ec5cbf894db122481e2eb5f660440e612edb12feae8d7c82508f057bf4c5ac8e6fa54f400c261ca07416570295e6c9732be44c30c1f522fb3785292fb1aa
|
||||
409c98029b0014f8ee36ba5040a2e96deece25c632cf48aa97b58d95648be79f:0177c0f8148194de3e6477:91e278b31a481a970895fc0e5dccaa045a05cdd70bda29f64ec239a5c4fc0d5189eb6c3cbce3affb3294ff4251a2e84c0633db7d2363fb53250d092d3f3b59121dc6ad3a4a5b8455f280b03d173d71a18275e7817936016e7db825540885081b
|
||||
3174e6aaabd794e3be89e48aedd486ed9d9aecac2f8a3d5f7a179883765e136b:fd1c24b053333e986927fd:93176d6cb5987f8912225a77166a053f7de30345718c4c081f8dcd71c1b6560a4c8a1cd096e7458073d7b42084b0ba9b15f2e378e7a2a2f3df81b29e594aef47e877545b9d56e2427364e4adfcd6dbe5d6ffd2190fea6e791a695a3135e8111e
|
||||
49d8f16c96e0bd5c151911fe49f9d3125188b7461168badd9256066863490658:0e2c67ef06692c5c01ee1881:88b6ccc20bcb7bfda958cdb80ef563d8364655bac922d065a05579b9de50b81c5d72e9f3b7ec5b9a64306e79d67d48500f89e80ad1e06c1f94a2cdf1d4522ef8f19467cb7206cda4ba86f9c111cabf418cc60e46b3e2ca8e841f7cd2e4d66e48
|
||||
18e90f391db888d2173eece1532225b2c3eb31011772322ef7db8985db83c5e2:3cf06f1f7bf3f1fd5c1c34e0:98090e7c9348e3bddaeba1a423c1dd5d34ff397d48d9b295f7725f9cfeec287c34ef032a7a1017e98aa2b8db17d8894e0b0b72559cbeab2a3a6af1ff5b33373c24602ebf87c2341078d54c6d825ed6f883693a69b46dedb9e812fbe8627eb5ce
|
||||
a0d5b377c5a369e4770764fc42f1ab42ccd51b004b7456ba5855e95ddfc7415e:0a108577679816e1c20fab4aab:98392ab3b9465813b8b4af724c28dabf62be6327e89ffd80c328f251634a240adc893bee6ceb320a6e6dcc5fa4638dd9191aff395421d815486f86afcc3b8289f0f3b8456ad10296e31333b1ada7b3869e4562dfc8b81353ccd1410570af383e
|
||||
2f171467ffed42c0aad55340a3d29f42132032b4b1c0cafbbfe267d5d9b9d975:ff0fbc6886cf7119c13cac2047:ae45427a61d4acea474a57867e7276ebaf10f1065478c6cbec3861d14ccfcee9d91b2052fe976e145ef8c88518fafcf812cb469d5881ef0fd8ef4563634e498041e7cd2b0d269bfe592aed2d7cae94f9787de91528e15a18efa74715bfb8f289
|
||||
675943c3633d2906548ab8fd99d59c902c3613d931316631df8d892d21971f37:0662c76b721017ba5a676b65b5b3:b44020ba6ea5bb53aecc946da3422dcab97cbd38678043b3476d3e5570d5c55a422f5bf7981fad6ef90b15a13bb904bf17eb164d5e1824956e3972bf2971257b051593be8d2bf025b01938216bd30d65142a40575d2d2c752f5eae06e5eaeb1d
|
||||
de79fa57fa8b20d8f5c9d8760d7edbccac81d0e5ed6db1c1db3bc70142439f81:4f8b3d03d50fdd4428d90fb8a1ed:969eeaec43bf81bb610c8c0447f41798bc7e558f3ea5aa9147a4cf651e22fc99b1dc9343a4c0efd61945b1b8a1d92a8419abd88575783f0577c2548069e7f28661bcf702e851e9de2d735e6ad545bee4765c6498a2f7891ebd0690986aa3de74
|
||||
cc8b41dd972d7003bc57f06efd6287ba04ff88b532a1c9698337a751a29ea562:03c572d43837c86b2d5ab55f602e34:88974f2099572aff379b487255507b9347097baadf902f283c58137e4ed4af6d285dd63ab554ccef48790229d4fac08e1717572c08c4dce5cc7530659aa23eba1a680fff339f138f11ff06b0817623fc904b4e95ffa6ee186eed0376a933e3f2
|
||||
3d9039b23297115dba92c2d7b4ad882749bbb47bbc378da7a2e2308fe97762af::b68588e7e1728b2fe5769dd3c936c209059f05d89fa1c97e73de4d6ebae113d25a3ff152d59e8e080644b9ff405b60a5016700792fd7b3e15e1644492d5b49c9d529f75ff089483975721c55405de377d4601b983d4151f86b11ff7f259b2880
|
||||
360763630528bf256a78b0c8c0b8bde84d1db6edea081a08d7a9903eddb9a85f:0f:b70412c89cc6041217c89898d9b4902c38988d80018c29b5c9a160f641ac867a5b6e7460efe1e807d4b16927ba057abf0ad222b6c81eb3cf46bb18ea5a1f4640b62ed3436360f359baf3dd7443f68fbd490acbd7a25901bf8f3daef6157426e5
|
||||
673f104c3fda7085a1b6afb787ea36dda1eecb87b45375e4204919b19bdb4f0d:ce:a3097321693e4dc5f56e65dc09014d517c942f731b6d7aa2a630cbaa5616298cb589475134f6333c8fd3c95a851c9c0b0e300cda7469cfa3e426b1d393361738077e8610f1b61ea3a75ed9dc8d7c19e804dba831dcde6fb5180b272f336f7778
|
||||
165ccbe631f789288f180dd299248be3019185f0326aa2cb5c01b0f381e3f952:0858:b42d38c4a715d724b80a8ba5ba3937d51ef57b82c473fc0e363b68112c61fda0c0a51d252d5893075db03f96b46458420af2dbb16b2890d27ece7710d5a16bc208a903ad0ad0173b35c40bcc0abff09c6871382ad936aae88464320667edfd45
|
||||
3e0db6c5848ea10fbe9dfb7fa937cf57e96cb947f4d47b4f7dad8da1ad718a75:b696:8c36fccafcb8221a13835cf8f2ef34207e62d82ae27b35f9c24c16c12ef4d24d45a253a0ace92b3260dd63a65b4e22af14fd2e743951349401c770ec39060e926ba076a4ae4ba9be82761b891956254585fa8e2e73ab101a8cc80a1ab523c16f
|
||||
4efc64d65ec6317d11c98d299bdbb177b48afafb4c77276885a5bad19e86d898:0013ab:84ec582064629c67d7f2cd893680e3f1296c666fc23309063d8a26144cd0075abaaddddf2835f41ef971cdb3c8929d1e0637b3bbfd1f01ee02b94750fead9b7f331e145cf4551bdbe9e77ee7e1a7c18b81792d02437f23c8a14b90883f044961
|
||||
933acbc31ca221dad3677776e0b7b64a2d7c1ece1d9440b84cc7e77449d97163:5a0113:b3639ac94326001c2902bdd4ed1336dee41dbc5168b3d42cc7e7ddd6d05dcf4828ecd6d03e24388665f37413b48352b203b35af2f073a6b2e613ee6ab62e026643dfa8c4c4cc93126b2739517487d3bce138ccddb16cff765608bbdfdff8e3ab
|
||||
1aa58cd8fe28bc296fdfca3d5af1841643527635d15d7ba7b9f52781f920503c:0276ce38:8fa25f0ec24a14482424d15128f365ca70adef6c497c6a3f2ad3a4129e0f44d0552adda1a2242e7936cc38014475a2d402794449c904b8db66387d4fa6cf938f040e9adb4ca3fa0fba4ae3c2a4a74881c261d3dbfb155ea922936a2238789c33
|
||||
20213ae7786685baef612a88f1ef008dffb01d185db47155300674b934996e68:19b49baf:8678b97a5e70c4287cc3ce06ff106b811ee91a7fe2b4a2ada4e933c17bbbfda3fa99be519b80e2a3ca7777eec5127e740a3c6d0f5fbbb3a125aba2bdfd325c1de980e2ccbc34023d06afcda5c4d70cabef3961cd73eeda2ffbfaa7146848bdb5
|
||||
0bac27b57ca7109489235328a4fdf27ba4a84ac64cb3d89f76c3c53d148d83d4:09c78eb62a:afc8c64ca140a9706f972319f48edffee405b5eed88dbad1c946d9bb8bab48bec8547d066bde4cb1cc7e99eee0d53faf01057a99d49bee517d424d0156e02486733a0fd4f311951ed4420a2125b092fa9041a3e01fd3e642e1c2d844b3dd64d3
|
||||
ea697bc01540c1b708f03c9369d2ad84ac0e2ff087a17bf9c868b64d6076c6c0:f7a40db556:8151b87961f1f4f6a33993469131fa7d02f40ea3d7191fc72aee115a8bf8454e57f12b7c67fa4b56fcfb9767276c2c66017a25f362b59067a313a61fac44e6940bc82e445befb85e20f51f1444e54e353d641537b21e6d6fb2a865228b58edd1
|
||||
fda3cf7385cf4bb164645966281a68f0447a0fdcd1ec7e29bf7313860f4a3394:03d67ac13cee:a81fd948bd75d7fb1b9744bd12a83288d1794bce09a8d7a63cb39758b090296356c6290e3cd63d4cb1ebbd169bdfe1991063d3d323bf87af7c469cb5947a93870400518b1a48d96f98456211b706be4073a34f0af9bfeb86c2adccb64a005656
|
||||
b382e373ff8da48348d38447ef337570a9bafd91fab84c2a439f71880ea5e480:c89dc4de1fbc:8d3a93cbf8bce107c2dce15ddac3252792dfe2e9e9050e99100aae4d42ca1687b1a72abb372da6e01c761e7f37b6c6790ec1260c4e8052c3b21fc21c8a79fff22dbced49349f554f8efb34a20bc1aab0f252660eca89ece65a67097622e7e547
|
||||
d15ae5df8ca3c5e64b38d24653fc9bf809534e98f3c7162623b65d9e70d8d2c5:0ae955dfad3573:8ecfa5cd8164188ddbad47d4f7600751116c6ac96d5bf74cd8feccdd59366ceba5bceaba2241f0b4355b9ca7b3963e54076b31e58f38d9a8dbf8ef3c887514fec83bf2f3a82fa2d2bffced10fe7113388c86d9d441867b499caed7e2e45cd98e
|
||||
bdb098850c669ddde2018c5cea8b9f9a356c317868ddfc61ebf120d2ee9b6627:477405798be816:8108bdda52459a367f5ee6d2fb92a62144d2134cbf6755cc6c6ae4fde35f3d8c5a1ac6b5feb86290a76ffe5972cba95118dd0d095473e8d2e2027f9f10c67a388b4802f190ef8900eaef3246b26e2ab642c317a66f9571f339744dda641b9248
|
||||
f62d28e6fc14fb70610228ee1f4f7d2e065e05caaf18b766892eeabf7c05f924:06097228065d18c0:b82649d765a3fff1d72ee15b7906579c4f0a608fd03adb53c6214de0e5095383ea00b66d75b6a12b8c433251af517a61053d69cf3dfeebdd929275984d9d3b1f8eaadd308824fffb9bb4e5437539a2f3d68330dbb021524a1d0d4523e5adc34a
|
||||
27826e51f6e6446065e32c5b8e60aaf0109008d4eb9c2336a437ecb6fe415618:4f77125824409934:894e75525f6c5067b5274b52f39f3d0991ef27b9396ead5555f0dac07d07a962f3cc00b20e8324b69873abff1f8285d904428f93fc42354bb1cc50d95149014dd25b7000b161c4dbaaae54a90bcbde7e8c99c2111181e4e1e08648b4bec81cb4
|
||||
984cfc344dd7da98dc2dcbcb8427e0195989e6b06380dd7dde4d73e289e1013c:093906e014849826bb:b74fbc224468498a680c923e1e9e8b90e7e55e44ffcb7cf1d2cf5bcbac1964e238025e30565325f2a1854244fa4ab233091c298fb9d5ba2525620f900960819e21f2e3d364eeac93f82c1303a141b883d29bbf4de2796daeb41f20cc05f0cd48
|
||||
ac47cf8395c7858c34896e1501c77b1028bb00f15721d92b4208a13cad2fbdac:3c65e5bd83d0464de9:9414a283286bb2eebde7e00e5510e406e96750a3595a104b0a003fa181ca8022eb688d6ed5363711b59d86f3f0cc696d08ee7c6939b9d7ec44a8d597880e15700d6cdff0fdd76ff814797b7b928f123a8dc22425333064821992559baf7f4b4c
|
||||
3
test/bls12-381/bls12-381-scalar-test-vectors.txt
Normal file
3
test/bls12-381/bls12-381-scalar-test-vectors.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
:0000000000000000000000000000000000000000000000000000000000000000
|
||||
aaaaaabbbbbbccccccddddddeeeeeeffffffgggggghhhhhh:2228450bf55d8fe62395161bd3677ff6fc28e45b89bc87e02a818eda11a8c5da
|
||||
111111222222333333444444555555666666777777888888:4aa543cbd2f0c8f37f8a375ce2e383eb343e7e3405f61e438b0a15fb8899d1ae
|
||||
8
test/bls12-381/go_pairing_vectors/go.mod
Normal file
8
test/bls12-381/go_pairing_vectors/go.mod
Normal file
@@ -0,0 +1,8 @@
|
||||
module blstests
|
||||
|
||||
go 1.19
|
||||
|
||||
require (
|
||||
github.com/kilic/bls12-381 v0.1.0 // indirect
|
||||
golang.org/x/sys v0.0.0-20201101102859-da207088b7d1 // indirect
|
||||
)
|
||||
4
test/bls12-381/go_pairing_vectors/go.sum
Normal file
4
test/bls12-381/go_pairing_vectors/go.sum
Normal file
@@ -0,0 +1,4 @@
|
||||
github.com/kilic/bls12-381 v0.1.0 h1:encrdjqKMEvabVQ7qYOKu1OvhqpK4s47wDYtNiPtlp4=
|
||||
github.com/kilic/bls12-381 v0.1.0/go.mod h1:vDTTHJONJ6G+P2R74EhnyotQDTliQDnFEwhdmfzw1ig=
|
||||
golang.org/x/sys v0.0.0-20201101102859-da207088b7d1 h1:a/mKvvZr9Jcc8oKfcmgzyp7OwF73JPWsQLvH1z2Kxck=
|
||||
golang.org/x/sys v0.0.0-20201101102859-da207088b7d1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
1
test/bls12-381/go_pairing_vectors/pairing.json
Normal file
1
test/bls12-381/go_pairing_vectors/pairing.json
Normal file
File diff suppressed because one or more lines are too long
29
test/bls12-381/go_pairing_vectors/t.go
Normal file
29
test/bls12-381/go_pairing_vectors/t.go
Normal file
@@ -0,0 +1,29 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
kilic "github.com/kilic/bls12-381"
|
||||
)
|
||||
|
||||
func main() {
|
||||
g1 := kilic.NewG1()
|
||||
g2 := kilic.NewG2()
|
||||
gt := kilic.NewGT()
|
||||
p1 := g1.One()
|
||||
p2 := g2.One()
|
||||
bls := kilic.NewEngine()
|
||||
out := []string{}
|
||||
for i := 0; i < 1000; i++ {
|
||||
res := bls.AddPair(p1, p2).Result()
|
||||
out = append(out, hex.EncodeToString(gt.ToBytes(res)))
|
||||
g1.Add(p1, p1, g1.One())
|
||||
g2.Add(p2, p2, g2.One())
|
||||
|
||||
}
|
||||
bytes, _ := json.Marshal(out)
|
||||
fmt.Println(string(bytes))
|
||||
|
||||
}
|
||||
25
test/bls12-381/zkcrypto/convert.js
Normal file
25
test/bls12-381/zkcrypto/convert.js
Normal file
@@ -0,0 +1,25 @@
|
||||
// This can be done inside of tests, but ESM is broken, jest doesn't want to work with it,
|
||||
// and ESM itself contaminates everything it touches
|
||||
|
||||
(async () => {
|
||||
const P = await import('micro-packed');
|
||||
const { readFileSync } = require('fs');
|
||||
|
||||
const CompresedG1 = P.array(null, P.hex(48));
|
||||
const UncompresedG1 = P.array(null, P.hex(2 * 48));
|
||||
const CompresedG2 = P.array(null, P.hex(2 * 48));
|
||||
const UncompresedG2 = P.array(null, P.hex(4 * 48));
|
||||
|
||||
const out = {
|
||||
G1_Compressed: CompresedG1.decode(readFileSync('./g1_compressed_valid_test_vectors.dat')),
|
||||
G1_Uncompressed: UncompresedG1.decode(readFileSync('./g1_uncompressed_valid_test_vectors.dat')),
|
||||
G2_Compressed: CompresedG2.decode(readFileSync('./g2_compressed_valid_test_vectors.dat')),
|
||||
G2_Uncompressed: UncompresedG2.decode(readFileSync('./g2_uncompressed_valid_test_vectors.dat')),
|
||||
};
|
||||
// Should be 1000
|
||||
// console.log(
|
||||
// 'T',
|
||||
// Object.values(out).map((i) => i.length)
|
||||
// );
|
||||
console.log(JSON.stringify(out));
|
||||
})();
|
||||
1
test/bls12-381/zkcrypto/converted.json
Normal file
1
test/bls12-381/zkcrypto/converted.json
Normal file
File diff suppressed because one or more lines are too long
BIN
test/bls12-381/zkcrypto/g1_compressed_valid_test_vectors.dat
Normal file
BIN
test/bls12-381/zkcrypto/g1_compressed_valid_test_vectors.dat
Normal file
Binary file not shown.
BIN
test/bls12-381/zkcrypto/g1_uncompressed_valid_test_vectors.dat
Normal file
BIN
test/bls12-381/zkcrypto/g1_uncompressed_valid_test_vectors.dat
Normal file
Binary file not shown.
BIN
test/bls12-381/zkcrypto/g2_compressed_valid_test_vectors.dat
Normal file
BIN
test/bls12-381/zkcrypto/g2_compressed_valid_test_vectors.dat
Normal file
Binary file not shown.
BIN
test/bls12-381/zkcrypto/g2_uncompressed_valid_test_vectors.dat
Normal file
BIN
test/bls12-381/zkcrypto/g2_uncompressed_valid_test_vectors.dat
Normal file
Binary file not shown.
672
test/ed25519.test.js
Normal file
672
test/ed25519.test.js
Normal file
@@ -0,0 +1,672 @@
|
||||
import { deepEqual, deepStrictEqual, strictEqual, throws } from 'assert';
|
||||
import { describe, should } from 'micro-should';
|
||||
import * as fc from 'fast-check';
|
||||
import {
|
||||
ed25519,
|
||||
ed25519ctx,
|
||||
ed25519ph,
|
||||
x25519,
|
||||
RistrettoPoint,
|
||||
ED25519_TORSION_SUBGROUP,
|
||||
} from '../lib/esm/ed25519.js';
|
||||
import { readFileSync } from 'fs';
|
||||
import { default as zip215 } from './ed25519/zip215.json' assert { type: 'json' };
|
||||
import { hexToBytes, bytesToHex, randomBytes } from '@noble/hashes/utils';
|
||||
import { numberToBytesLE } from '../lib/esm/abstract/utils.js';
|
||||
import { sha512 } from '@noble/hashes/sha512';
|
||||
import { default as ed25519vectors } from './wycheproof/eddsa_test.json' assert { type: 'json' };
|
||||
import { default as x25519vectors } from './wycheproof/x25519_test.json' assert { type: 'json' };
|
||||
|
||||
describe('ed25519', () => {
|
||||
const ed = ed25519;
|
||||
const hex = bytesToHex;
|
||||
const Point = ed.ExtendedPoint;
|
||||
|
||||
function to32Bytes(numOrStr) {
|
||||
let hex = typeof numOrStr === 'string' ? numOrStr : numOrStr.toString(16);
|
||||
return hexToBytes(hex.padStart(64, '0'));
|
||||
}
|
||||
|
||||
function utf8ToBytes(str) {
|
||||
if (typeof str !== 'string') {
|
||||
throw new Error(`utf8ToBytes expected string, got ${typeof str}`);
|
||||
}
|
||||
return new TextEncoder().encode(str);
|
||||
}
|
||||
|
||||
ed.utils.precompute(8);
|
||||
|
||||
should('not accept >32byte private keys', () => {
|
||||
const invalidPriv =
|
||||
100000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000090000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800073278156000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000n;
|
||||
throws(() => ed.getPublicKey(invalidPriv));
|
||||
});
|
||||
should('verify recent signature', () => {
|
||||
fc.assert(
|
||||
fc.property(
|
||||
fc.hexaString({ minLength: 2, maxLength: 32 }),
|
||||
fc.bigInt(2n, ed.CURVE.n),
|
||||
(message, privateKey) => {
|
||||
const publicKey = ed.getPublicKey(to32Bytes(privateKey));
|
||||
const signature = ed.sign(to32Bytes(message), to32Bytes(privateKey));
|
||||
deepStrictEqual(publicKey.length, 32);
|
||||
deepStrictEqual(signature.length, 64);
|
||||
deepStrictEqual(ed.verify(signature, to32Bytes(message), publicKey), true);
|
||||
}
|
||||
),
|
||||
{ numRuns: 5 }
|
||||
);
|
||||
});
|
||||
should('not verify signature with wrong message', () => {
|
||||
fc.assert(
|
||||
fc.property(
|
||||
fc.array(fc.integer({ min: 0x00, max: 0xff })),
|
||||
fc.array(fc.integer({ min: 0x00, max: 0xff })),
|
||||
fc.bigInt(1n, ed.CURVE.n),
|
||||
(bytes, wrongBytes, privateKey) => {
|
||||
const privKey = to32Bytes(privateKey);
|
||||
const message = new Uint8Array(bytes);
|
||||
const wrongMessage = new Uint8Array(wrongBytes);
|
||||
const publicKey = ed.getPublicKey(privKey);
|
||||
const signature = ed.sign(message, privKey);
|
||||
deepStrictEqual(
|
||||
ed.verify(signature, wrongMessage, publicKey),
|
||||
bytes.toString() === wrongBytes.toString()
|
||||
);
|
||||
}
|
||||
),
|
||||
{ numRuns: 5 }
|
||||
);
|
||||
});
|
||||
const privKey = to32Bytes('a665a45920422f9d417e4867ef');
|
||||
const wrongPriv = to32Bytes('a675a45920422f9d417e4867ef');
|
||||
const msg = hexToBytes('874f9960c5d2b7a9b5fad383e1ba44719ebb743a');
|
||||
const wrongMsg = hexToBytes('589d8c7f1da0a24bc07b7381ad48b1cfc211af1c');
|
||||
describe('basic methods', () => {
|
||||
should('sign and verify', () => {
|
||||
const publicKey = ed.getPublicKey(privKey);
|
||||
const signature = ed.sign(msg, privKey);
|
||||
deepStrictEqual(ed.verify(signature, msg, publicKey), true);
|
||||
});
|
||||
});
|
||||
describe('sync methods', () => {
|
||||
should('sign and verify', () => {
|
||||
const publicKey = ed.getPublicKey(privKey);
|
||||
const signature = ed.sign(msg, privKey);
|
||||
deepStrictEqual(ed.verify(signature, msg, publicKey), true);
|
||||
});
|
||||
should('not verify signature with wrong public key', () => {
|
||||
const publicKey = ed.getPublicKey(wrongPriv);
|
||||
const signature = ed.sign(msg, privKey);
|
||||
deepStrictEqual(ed.verify(signature, msg, publicKey), false);
|
||||
});
|
||||
should('not verify signature with wrong hash', () => {
|
||||
const publicKey = ed.getPublicKey(privKey);
|
||||
const signature = ed.sign(msg, privKey);
|
||||
deepStrictEqual(ed.verify(signature, wrongMsg, publicKey), false);
|
||||
});
|
||||
});
|
||||
describe('BASE_POINT.multiply()', () => {
|
||||
// https://xmr.llcoins.net/addresstests.html
|
||||
should('create right publicKey without SHA-512 hashing TEST 1', () => {
|
||||
const publicKey =
|
||||
Point.BASE.multiply(0x90af56259a4b6bfbc4337980d5d75fbe3c074630368ff3804d33028e5dbfa77n);
|
||||
deepStrictEqual(
|
||||
publicKey.toHex(),
|
||||
'0f3b913371411b27e646b537e888f685bf929ea7aab93c950ed84433f064480d'
|
||||
);
|
||||
});
|
||||
should('create right publicKey without SHA-512 hashing TEST 2', () => {
|
||||
const publicKey =
|
||||
Point.BASE.multiply(0x364e8711a60780382a5d57b061c126f039940f28a9e91fe039d4d3094d8b88n);
|
||||
deepStrictEqual(
|
||||
publicKey.toHex(),
|
||||
'ad545340b58610f0cd62f17d55af1ab11ecde9c084d5476865ddb4dbda015349'
|
||||
);
|
||||
});
|
||||
should('create right publicKey without SHA-512 hashing TEST 3', () => {
|
||||
const publicKey =
|
||||
Point.BASE.multiply(0xb9bf90ff3abec042752cac3a07a62f0c16cfb9d32a3fc2305d676ec2d86e941n);
|
||||
deepStrictEqual(
|
||||
publicKey.toHex(),
|
||||
'e097c4415fe85724d522b2e449e8fd78dd40d20097bdc9ae36fe8ec6fe12cb8c'
|
||||
);
|
||||
});
|
||||
should('create right publicKey without SHA-512 hashing TEST 4', () => {
|
||||
const publicKey =
|
||||
Point.BASE.multiply(0x69d896f02d79524c9878e080308180e2859d07f9f54454e0800e8db0847a46en);
|
||||
deepStrictEqual(
|
||||
publicKey.toHex(),
|
||||
'f12cb7c43b59971395926f278ce7c2eaded9444fbce62ca717564cb508a0db1d'
|
||||
);
|
||||
});
|
||||
should('throw Point#multiply on TEST 5', () => {
|
||||
for (const num of [0n, 0, -1n, -1, 1.1]) {
|
||||
throws(() => Point.BASE.multiply(num));
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// https://ed25519.cr.yp.to/python/sign.py
|
||||
// https://ed25519.cr.yp.to/python/sign.input
|
||||
const data = readFileSync('./test/ed25519/vectors.txt', 'utf-8');
|
||||
const vectors = data
|
||||
.trim()
|
||||
.split('\n')
|
||||
.map((line) => line.split(':'));
|
||||
should('ed25519 official vectors/should match 1024 official vectors', () => {
|
||||
for (let i = 0; i < vectors.length; i++) {
|
||||
const vector = vectors[i];
|
||||
// Extract.
|
||||
const priv = vector[0].slice(0, 64);
|
||||
const expectedPub = vector[1];
|
||||
const msg = vector[2];
|
||||
const expectedSignature = vector[3].slice(0, 128);
|
||||
|
||||
// Calculate
|
||||
const pub = ed.getPublicKey(to32Bytes(priv));
|
||||
deepStrictEqual(hex(pub), expectedPub);
|
||||
deepStrictEqual(pub, Point.fromHex(pub).toRawBytes());
|
||||
|
||||
const signature = hex(ed.sign(msg, priv));
|
||||
// console.log('vector', i);
|
||||
// expect(pub).toBe(expectedPub);
|
||||
deepStrictEqual(signature, expectedSignature);
|
||||
}
|
||||
});
|
||||
|
||||
// https://tools.ietf.org/html/rfc8032#section-7
|
||||
should('rfc8032 vectors/should create right signature for 0x9d and empty string', () => {
|
||||
const privateKey = '9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60';
|
||||
const publicKey = ed.getPublicKey(privateKey);
|
||||
const message = '';
|
||||
const signature = ed.sign(message, privateKey);
|
||||
deepStrictEqual(
|
||||
hex(publicKey),
|
||||
'd75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a'
|
||||
);
|
||||
deepStrictEqual(
|
||||
hex(signature),
|
||||
'e5564300c360ac729086e2cc806e828a84877f1eb8e5d974d873e065224901555fb8821590a33bacc61e39701cf9b46bd25bf5f0595bbe24655141438e7a100b'
|
||||
);
|
||||
});
|
||||
should('rfc8032 vectors/should create right signature for 0x4c and 72', () => {
|
||||
const privateKey = '4ccd089b28ff96da9db6c346ec114e0f5b8a319f35aba624da8cf6ed4fb8a6fb';
|
||||
const publicKey = ed.getPublicKey(privateKey);
|
||||
const message = '72';
|
||||
const signature = ed.sign(message, privateKey);
|
||||
deepStrictEqual(
|
||||
hex(publicKey),
|
||||
'3d4017c3e843895a92b70aa74d1b7ebc9c982ccf2ec4968cc0cd55f12af4660c'
|
||||
);
|
||||
deepStrictEqual(
|
||||
hex(signature),
|
||||
'92a009a9f0d4cab8720e820b5f642540a2b27b5416503f8fb3762223ebdb69da085ac1e43e15996e458f3613d0f11d8c387b2eaeb4302aeeb00d291612bb0c00'
|
||||
);
|
||||
});
|
||||
should('rfc8032 vectors/should create right signature for 0x00 and 5a', () => {
|
||||
const privateKey = '002fdd1f7641793ab064bb7aa848f762e7ec6e332ffc26eeacda141ae33b1783';
|
||||
const publicKey = ed.getPublicKey(privateKey);
|
||||
const message =
|
||||
'5ac1dfc324f43e6cb79a87ab0470fa857b51fb944982e19074ca44b1e40082c1d07b92efa7ea55ad42b7c027e0b9e33756d95a2c1796a7c2066811dc41858377d4b835c1688d638884cd2ad8970b74c1a54aadd27064163928a77988b24403aa85af82ceab6b728e554761af7175aeb99215b7421e4474c04d213e01ff03e3529b11077cdf28964b8c49c5649e3a46fa0a09dcd59dcad58b9b922a83210acd5e65065531400234f5e40cddcf9804968e3e9ac6f5c44af65001e158067fc3a660502d13fa8874fa93332138d9606bc41b4cee7edc39d753dae12a873941bb357f7e92a4498847d6605456cb8c0b425a47d7d3ca37e54e903a41e6450a35ebe5237c6f0c1bbbc1fd71fb7cd893d189850295c199b7d88af26bc8548975fda1099ffefee42a52f3428ddff35e0173d3339562507ac5d2c45bbd2c19cfe89b';
|
||||
const signature = ed.sign(message, privateKey);
|
||||
deepStrictEqual(
|
||||
hex(publicKey),
|
||||
'77d1d8ebacd13f4e2f8a40e28c4a63bc9ce3bfb69716334bcb28a33eb134086c'
|
||||
);
|
||||
deepStrictEqual(
|
||||
hex(signature),
|
||||
'0df3aa0d0999ad3dc580378f52d152700d5b3b057f56a66f92112e441e1cb9123c66f18712c87efe22d2573777296241216904d7cdd7d5ea433928bd2872fa0c'
|
||||
);
|
||||
});
|
||||
should('rfc8032 vectors/should create right signature for 0xf5 and long msg', () => {
|
||||
const privateKey = 'f5e5767cf153319517630f226876b86c8160cc583bc013744c6bf255f5cc0ee5';
|
||||
const publicKey = ed.getPublicKey(privateKey);
|
||||
const message =
|
||||
'08b8b2b733424243760fe426a4b54908632110a66c2f6591eabd3345e3e4eb98fa6e264bf09efe12ee50f8f54e9f77b1e355f6c50544e23fb1433ddf73be84d879de7c0046dc4996d9e773f4bc9efe5738829adb26c81b37c93a1b270b20329d658675fc6ea534e0810a4432826bf58c941efb65d57a338bbd2e26640f89ffbc1a858efcb8550ee3a5e1998bd177e93a7363c344fe6b199ee5d02e82d522c4feba15452f80288a821a579116ec6dad2b3b310da903401aa62100ab5d1a36553e06203b33890cc9b832f79ef80560ccb9a39ce767967ed628c6ad573cb116dbefefd75499da96bd68a8a97b928a8bbc103b6621fcde2beca1231d206be6cd9ec7aff6f6c94fcd7204ed3455c68c83f4a41da4af2b74ef5c53f1d8ac70bdcb7ed185ce81bd84359d44254d95629e9855a94a7c1958d1f8ada5d0532ed8a5aa3fb2d17ba70eb6248e594e1a2297acbbb39d502f1a8c6eb6f1ce22b3de1a1f40cc24554119a831a9aad6079cad88425de6bde1a9187ebb6092cf67bf2b13fd65f27088d78b7e883c8759d2c4f5c65adb7553878ad575f9fad878e80a0c9ba63bcbcc2732e69485bbc9c90bfbd62481d9089beccf80cfe2df16a2cf65bd92dd597b0707e0917af48bbb75fed413d238f5555a7a569d80c3414a8d0859dc65a46128bab27af87a71314f318c782b23ebfe808b82b0ce26401d2e22f04d83d1255dc51addd3b75a2b1ae0784504df543af8969be3ea7082ff7fc9888c144da2af58429ec96031dbcad3dad9af0dcbaaaf268cb8fcffead94f3c7ca495e056a9b47acdb751fb73e666c6c655ade8297297d07ad1ba5e43f1bca32301651339e22904cc8c42f58c30c04aafdb038dda0847dd988dcda6f3bfd15c4b4c4525004aa06eeff8ca61783aacec57fb3d1f92b0fe2fd1a85f6724517b65e614ad6808d6f6ee34dff7310fdc82aebfd904b01e1dc54b2927094b2db68d6f903b68401adebf5a7e08d78ff4ef5d63653a65040cf9bfd4aca7984a74d37145986780fc0b16ac451649de6188a7dbdf191f64b5fc5e2ab47b57f7f7276cd419c17a3ca8e1b939ae49e488acba6b965610b5480109c8b17b80e1b7b750dfc7598d5d5011fd2dcc5600a32ef5b52a1ecc820e308aa342721aac0943bf6686b64b2579376504ccc493d97e6aed3fb0f9cd71a43dd497f01f17c0e2cb3797aa2a2f256656168e6c496afc5fb93246f6b1116398a346f1a641f3b041e989f7914f90cc2c7fff357876e506b50d334ba77c225bc307ba537152f3f1610e4eafe595f6d9d90d11faa933a15ef1369546868a7f3a45a96768d40fd9d03412c091c6315cf4fde7cb68606937380db2eaaa707b4c4185c32eddcdd306705e4dc1ffc872eeee475a64dfac86aba41c0618983f8741c5ef68d3a101e8a3b8cac60c905c15fc910840b94c00a0b9d0';
|
||||
const signature = ed.sign(message, privateKey);
|
||||
deepStrictEqual(
|
||||
hex(publicKey),
|
||||
'278117fc144c72340f67d0f2316e8386ceffbf2b2428c9c51fef7c597f1d426e'
|
||||
);
|
||||
deepStrictEqual(
|
||||
hex(signature),
|
||||
'0aab4c900501b3e24d7cdf4663326a3a87df5e4843b2cbdb67cbf6e460fec350aa5371b1508f9f4528ecea23c436d94b5e8fcd4f681e30a6ac00a9704a188a03'
|
||||
);
|
||||
});
|
||||
|
||||
// const PRIVATE_KEY = 0xa665a45920422f9d417e4867efn;
|
||||
// const MESSAGE = ripemd160(new Uint8Array([97, 98, 99, 100, 101, 102, 103]));
|
||||
// prettier-ignore
|
||||
// const MESSAGE = new Uint8Array([
|
||||
// 135, 79, 153, 96, 197, 210, 183, 169, 181, 250, 211, 131, 225, 186, 68, 113, 158, 187, 116, 58,
|
||||
// ]);
|
||||
// const WRONG_MESSAGE = ripemd160(new Uint8Array([98, 99, 100, 101, 102, 103]));
|
||||
// prettier-ignore
|
||||
// const WRONG_MESSAGE = new Uint8Array([
|
||||
// 88, 157, 140, 127, 29, 160, 162, 75, 192, 123, 115, 129, 173, 72, 177, 207, 194, 17, 175, 28,
|
||||
// ]);
|
||||
// // it("should verify just signed message", async () => {
|
||||
// // await fc.assert(fc.asyncProperty(
|
||||
// // fc.hexa(),
|
||||
// // fc.bigInt(2n, ristretto25519.PRIME_ORDER),
|
||||
// // async (message, privateKey) => {
|
||||
// // const publicKey = await ristretto25519.getPublicKey(privateKey);
|
||||
// // const signature = await ristretto25519.sign(message, privateKey);
|
||||
// // expect(publicKey.length).toBe(32);
|
||||
// // expect(signature.length).toBe(64);
|
||||
// // expect(await ristretto25519.verify(signature, message, publicKey)).toBe(true);
|
||||
// // }),
|
||||
// // { numRuns: 1 }
|
||||
// // );
|
||||
// // });
|
||||
// // it("should not verify sign with wrong message", async () => {
|
||||
// // await fc.assert(fc.asyncProperty(
|
||||
// // fc.array(fc.integer(0x00, 0xff)),
|
||||
// // fc.array(fc.integer(0x00, 0xff)),
|
||||
// // fc.bigInt(2n, ristretto25519.PRIME_ORDER),
|
||||
// // async (bytes, wrongBytes, privateKey) => {
|
||||
// // const message = new Uint8Array(bytes);
|
||||
// // const wrongMessage = new Uint8Array(wrongBytes);
|
||||
// // const publicKey = await ristretto25519.getPublicKey(privateKey);
|
||||
// // const signature = await ristretto25519.sign(message, privateKey);
|
||||
// // expect(await ristretto25519.verify(signature, wrongMessage, publicKey)).toBe(
|
||||
// // bytes.toString() === wrongBytes.toString()
|
||||
// // );
|
||||
// // }),
|
||||
// // { numRuns: 1 }
|
||||
// // );
|
||||
// // });
|
||||
// // it("should sign and verify", async () => {
|
||||
// // const publicKey = await ristretto25519.getPublicKey(PRIVATE_KEY);
|
||||
// // const signature = await ristretto25519.sign(MESSAGE, PRIVATE_KEY);
|
||||
// // expect(await ristretto25519.verify(signature, MESSAGE, publicKey)).toBe(true);
|
||||
// // });
|
||||
// // it("should not verify signature with wrong public key", async () => {
|
||||
// // const publicKey = await ristretto25519.getPublicKey(12);
|
||||
// // const signature = await ristretto25519.sign(MESSAGE, PRIVATE_KEY);
|
||||
// // expect(await ristretto25519.verify(signature, MESSAGE, publicKey)).toBe(false);
|
||||
// // });
|
||||
// // it("should not verify signature with wrong hash", async () => {
|
||||
// // const publicKey = await ristretto25519.getPublicKey(PRIVATE_KEY);
|
||||
// // const signature = await ristretto25519.sign(MESSAGE, PRIVATE_KEY);
|
||||
// // expect(await ristretto25519.verify(signature, WRONG_MESSAGE, publicKey)).toBe(false);
|
||||
// // });
|
||||
should('ristretto255/should follow the byte encodings of small multiples', () => {
|
||||
const encodingsOfSmallMultiples = [
|
||||
// This is the identity point
|
||||
'0000000000000000000000000000000000000000000000000000000000000000',
|
||||
// This is the basepoint
|
||||
'e2f2ae0a6abc4e71a884a961c500515f58e30b6aa582dd8db6a65945e08d2d76',
|
||||
// These are small multiples of the basepoint
|
||||
'6a493210f7499cd17fecb510ae0cea23a110e8d5b901f8acadd3095c73a3b919',
|
||||
'94741f5d5d52755ece4f23f044ee27d5d1ea1e2bd196b462166b16152a9d0259',
|
||||
'da80862773358b466ffadfe0b3293ab3d9fd53c5ea6c955358f568322daf6a57',
|
||||
'e882b131016b52c1d3337080187cf768423efccbb517bb495ab812c4160ff44e',
|
||||
'f64746d3c92b13050ed8d80236a7f0007c3b3f962f5ba793d19a601ebb1df403',
|
||||
'44f53520926ec81fbd5a387845beb7df85a96a24ece18738bdcfa6a7822a176d',
|
||||
'903293d8f2287ebe10e2374dc1a53e0bc887e592699f02d077d5263cdd55601c',
|
||||
'02622ace8f7303a31cafc63f8fc48fdc16e1c8c8d234b2f0d6685282a9076031',
|
||||
'20706fd788b2720a1ed2a5dad4952b01f413bcf0e7564de8cdc816689e2db95f',
|
||||
'bce83f8ba5dd2fa572864c24ba1810f9522bc6004afe95877ac73241cafdab42',
|
||||
'e4549ee16b9aa03099ca208c67adafcafa4c3f3e4e5303de6026e3ca8ff84460',
|
||||
'aa52e000df2e16f55fb1032fc33bc42742dad6bd5a8fc0be0167436c5948501f',
|
||||
'46376b80f409b29dc2b5f6f0c52591990896e5716f41477cd30085ab7f10301e',
|
||||
'e0c418f7c8d9c4cdd7395b93ea124f3ad99021bb681dfc3302a9d99a2e53e64e',
|
||||
];
|
||||
let B = RistrettoPoint.BASE;
|
||||
let P = RistrettoPoint.ZERO;
|
||||
for (const encoded of encodingsOfSmallMultiples) {
|
||||
deepStrictEqual(P.toHex(), encoded);
|
||||
deepStrictEqual(RistrettoPoint.fromHex(encoded).toHex(), encoded);
|
||||
P = P.add(B);
|
||||
}
|
||||
});
|
||||
should('ristretto255/should not convert bad bytes encoding', () => {
|
||||
const badEncodings = [
|
||||
// These are all bad because they're non-canonical field encodings.
|
||||
'00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff',
|
||||
'ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f',
|
||||
'f3ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f',
|
||||
'edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f',
|
||||
// These are all bad because they're negative field elements.
|
||||
'0100000000000000000000000000000000000000000000000000000000000000',
|
||||
'01ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f',
|
||||
'ed57ffd8c914fb201471d1c3d245ce3c746fcbe63a3679d51b6a516ebebe0e20',
|
||||
'c34c4e1826e5d403b78e246e88aa051c36ccf0aafebffe137d148a2bf9104562',
|
||||
'c940e5a4404157cfb1628b108db051a8d439e1a421394ec4ebccb9ec92a8ac78',
|
||||
'47cfc5497c53dc8e61c91d17fd626ffb1c49e2bca94eed052281b510b1117a24',
|
||||
'f1c6165d33367351b0da8f6e4511010c68174a03b6581212c71c0e1d026c3c72',
|
||||
'87260f7a2f12495118360f02c26a470f450dadf34a413d21042b43b9d93e1309',
|
||||
// These are all bad because they give a nonsquare x².
|
||||
'26948d35ca62e643e26a83177332e6b6afeb9d08e4268b650f1f5bbd8d81d371',
|
||||
'4eac077a713c57b4f4397629a4145982c661f48044dd3f96427d40b147d9742f',
|
||||
'de6a7b00deadc788eb6b6c8d20c0ae96c2f2019078fa604fee5b87d6e989ad7b',
|
||||
'bcab477be20861e01e4a0e295284146a510150d9817763caf1a6f4b422d67042',
|
||||
'2a292df7e32cababbd9de088d1d1abec9fc0440f637ed2fba145094dc14bea08',
|
||||
'f4a9e534fc0d216c44b218fa0c42d99635a0127ee2e53c712f70609649fdff22',
|
||||
'8268436f8c4126196cf64b3c7ddbda90746a378625f9813dd9b8457077256731',
|
||||
'2810e5cbc2cc4d4eece54f61c6f69758e289aa7ab440b3cbeaa21995c2f4232b',
|
||||
// These are all bad because they give a negative xy value.
|
||||
'3eb858e78f5a7254d8c9731174a94f76755fd3941c0ac93735c07ba14579630e',
|
||||
'a45fdc55c76448c049a1ab33f17023edfb2be3581e9c7aade8a6125215e04220',
|
||||
'd483fe813c6ba647ebbfd3ec41adca1c6130c2beeee9d9bf065c8d151c5f396e',
|
||||
'8a2e1d30050198c65a54483123960ccc38aef6848e1ec8f5f780e8523769ba32',
|
||||
'32888462f8b486c68ad7dd9610be5192bbeaf3b443951ac1a8118419d9fa097b',
|
||||
'227142501b9d4355ccba290404bde41575b037693cef1f438c47f8fbf35d1165',
|
||||
'5c37cc491da847cfeb9281d407efc41e15144c876e0170b499a96a22ed31e01e',
|
||||
'445425117cb8c90edcbc7c1cc0e74f747f2c1efa5630a967c64f287792a48a4b',
|
||||
// This is s = -1, which causes y = 0.
|
||||
'ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f',
|
||||
];
|
||||
for (const badBytes of badEncodings) {
|
||||
const b = hexToBytes(badBytes);
|
||||
throws(() => RistrettoPoint.fromHex(b), badBytes);
|
||||
}
|
||||
});
|
||||
should('ristretto255/should create right points from uniform hash', () => {
|
||||
const labels = [
|
||||
'Ristretto is traditionally a short shot of espresso coffee',
|
||||
'made with the normal amount of ground coffee but extracted with',
|
||||
'about half the amount of water in the same amount of time',
|
||||
'by using a finer grind.',
|
||||
'This produces a concentrated shot of coffee per volume.',
|
||||
'Just pulling a normal shot short will produce a weaker shot',
|
||||
'and is not a Ristretto as some believe.',
|
||||
];
|
||||
const encodedHashToPoints = [
|
||||
'3066f82a1a747d45120d1740f14358531a8f04bbffe6a819f86dfe50f44a0a46',
|
||||
'f26e5b6f7d362d2d2a94c5d0e7602cb4773c95a2e5c31a64f133189fa76ed61b',
|
||||
'006ccd2a9e6867e6a2c5cea83d3302cc9de128dd2a9a57dd8ee7b9d7ffe02826',
|
||||
'f8f0c87cf237953c5890aec3998169005dae3eca1fbb04548c635953c817f92a',
|
||||
'ae81e7dedf20a497e10c304a765c1767a42d6e06029758d2d7e8ef7cc4c41179',
|
||||
'e2705652ff9f5e44d3e841bf1c251cf7dddb77d140870d1ab2ed64f1a9ce8628',
|
||||
'80bd07262511cdde4863f8a7434cef696750681cb9510eea557088f76d9e5065',
|
||||
];
|
||||
|
||||
for (let i = 0; i < labels.length; i++) {
|
||||
const hash = sha512(utf8ToBytes(labels[i]));
|
||||
const point = RistrettoPoint.hashToCurve(hash);
|
||||
deepStrictEqual(point.toHex(), encodedHashToPoints[i]);
|
||||
}
|
||||
});
|
||||
|
||||
should('input immutability: sign/verify are immutable', () => {
|
||||
const privateKey = ed.utils.randomPrivateKey();
|
||||
const publicKey = ed.getPublicKey(privateKey);
|
||||
|
||||
for (let i = 0; i < 100; i++) {
|
||||
let payload = randomBytes(100);
|
||||
let signature = ed.sign(payload, privateKey);
|
||||
if (!ed.verify(signature, payload, publicKey)) {
|
||||
throw new Error('Signature verification failed');
|
||||
}
|
||||
const signatureCopy = Buffer.alloc(signature.byteLength);
|
||||
signatureCopy.set(signature, 0); // <-- breaks
|
||||
payload = payload.slice();
|
||||
signature = signature.slice();
|
||||
|
||||
if (!ed.verify(signatureCopy, payload, publicKey))
|
||||
throw new Error('Copied signature verification failed');
|
||||
}
|
||||
});
|
||||
|
||||
// https://zips.z.cash/zip-0215
|
||||
// Vectors from https://gist.github.com/hdevalence/93ed42d17ecab8e42138b213812c8cc7
|
||||
should('ZIP-215 compliance tests/should pass all of them', () => {
|
||||
const str = utf8ToBytes('Zcash');
|
||||
for (let v of zip215) {
|
||||
let noble = false;
|
||||
try {
|
||||
noble = ed.verify(v.sig_bytes, str, v.vk_bytes);
|
||||
} catch (e) {
|
||||
noble = false;
|
||||
}
|
||||
deepStrictEqual(noble, v.valid_zip215, JSON.stringify(v));
|
||||
}
|
||||
});
|
||||
should('ZIP-215 compliance tests/disallows sig.s >= CURVE.n', () => {
|
||||
// sig.R = BASE, sig.s = N+1
|
||||
const sig =
|
||||
'5866666666666666666666666666666666666666666666666666666666666666eed3f55c1a631258d69cf7a2def9de1400000000000000000000000000000010';
|
||||
throws(() => ed.verify(sig, 'deadbeef', Point.BASE));
|
||||
});
|
||||
|
||||
const rfc7748Mul = [
|
||||
{
|
||||
scalar: 'a546e36bf0527c9d3b16154b82465edd62144c0ac1fc5a18506a2244ba449ac4',
|
||||
u: 'e6db6867583030db3594c1a424b15f7c726624ec26b3353b10a903a6d0ab1c4c',
|
||||
outputU: 'c3da55379de9c6908e94ea4df28d084f32eccf03491c71f754b4075577a28552',
|
||||
},
|
||||
{
|
||||
scalar: '4b66e9d4d1b4673c5ad22691957d6af5c11b6421e0ea01d42ca4169e7918ba0d',
|
||||
u: 'e5210f12786811d3f4b7959d0538ae2c31dbe7106fc03c3efc4cd549c715a493',
|
||||
outputU: '95cbde9476e8907d7aade45cb4b873f88b595a68799fa152e6f8f7647aac7957',
|
||||
},
|
||||
];
|
||||
for (let i = 0; i < rfc7748Mul.length; i++) {
|
||||
const v = rfc7748Mul[i];
|
||||
should(`RFC7748: scalarMult (${i})`, () => {
|
||||
deepStrictEqual(hex(x25519.scalarMult(v.scalar, v.u)), v.outputU);
|
||||
});
|
||||
}
|
||||
|
||||
const rfc7748Iter = [
|
||||
{ scalar: '422c8e7a6227d7bca1350b3e2bb7279f7897b87bb6854b783c60e80311ae3079', iters: 1 },
|
||||
{ scalar: '684cf59ba83309552800ef566f2f4d3c1c3887c49360e3875f2eb94d99532c51', iters: 1000 },
|
||||
// { scalar: '7c3911e0ab2586fd864497297e575e6f3bc601c0883c30df5f4dd2d24f665424', iters: 1000000 },
|
||||
];
|
||||
for (let i = 0; i < rfc7748Iter.length; i++) {
|
||||
const { scalar, iters } = rfc7748Iter[i];
|
||||
should(`RFC7748: scalarMult iteration (${i})`, () => {
|
||||
let k = x25519.Gu;
|
||||
for (let i = 0, u = k; i < iters; i++) [k, u] = [x25519.scalarMult(k, u), k];
|
||||
deepStrictEqual(hex(k), scalar);
|
||||
});
|
||||
}
|
||||
|
||||
should('RFC7748 getSharedKey', () => {
|
||||
const alicePrivate = '77076d0a7318a57d3c16c17251b26645df4c2f87ebc0992ab177fba51db92c2a';
|
||||
const alicePublic = '8520f0098930a754748b7ddcb43ef75a0dbf3a0d26381af4eba4a98eaa9b4e6a';
|
||||
const bobPrivate = '5dab087e624a8a4b79e17f8b83800ee66f3bb1292618b6fd1c2f8b27ff88e0eb';
|
||||
const bobPublic = 'de9edb7d7b7dc1b4d35b61c2ece435373f8343c85b78674dadfc7e146f882b4f';
|
||||
const shared = '4a5d9d5ba4ce2de1728e3bf480350f25e07e21c947d19e3376f09b3c1e161742';
|
||||
deepStrictEqual(alicePublic, hex(x25519.getPublicKey(alicePrivate)));
|
||||
deepStrictEqual(bobPublic, hex(x25519.getPublicKey(bobPrivate)));
|
||||
deepStrictEqual(hex(x25519.scalarMult(alicePrivate, bobPublic)), shared);
|
||||
deepStrictEqual(hex(x25519.scalarMult(bobPrivate, alicePublic)), shared);
|
||||
});
|
||||
|
||||
// should('X25519/getSharedSecret() should be commutative', () => {
|
||||
// for (let i = 0; i < 512; i++) {
|
||||
// const asec = ed.utils.randomPrivateKey();
|
||||
// const apub = ed.getPublicKey(asec);
|
||||
// const bsec = ed.utils.randomPrivateKey();
|
||||
// const bpub = ed.getPublicKey(bsec);
|
||||
// try {
|
||||
// deepStrictEqual(ed.getSharedSecret(asec, bpub), ed.getSharedSecret(bsec, apub));
|
||||
// } catch (error) {
|
||||
// console.error('not commutative', { asec, apub, bsec, bpub });
|
||||
// throw error;
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
|
||||
// should('X25519: should convert base point to montgomery using fromPoint', () => {
|
||||
// deepStrictEqual(
|
||||
// hex(ed.montgomeryCurve.UfromPoint(Point.BASE)),
|
||||
// ed.montgomeryCurve.BASE_POINT_U
|
||||
// );
|
||||
// });
|
||||
|
||||
{
|
||||
const group = x25519vectors.testGroups[0];
|
||||
should(`Wycheproof/X25519`, () => {
|
||||
for (let i = 0; i < group.tests.length; i++) {
|
||||
const v = group.tests[i];
|
||||
const comment = `(${i}, ${v.result}) ${v.comment}`;
|
||||
if (v.result === 'valid' || v.result === 'acceptable') {
|
||||
try {
|
||||
const shared = hex(x25519.scalarMult(v.private, v.public));
|
||||
deepStrictEqual(shared, v.shared, comment);
|
||||
} catch (e) {
|
||||
// We are more strict
|
||||
if (e.message.includes('Expected valid scalar')) return;
|
||||
if (e.message.includes('Invalid private or public key received')) return;
|
||||
throw e;
|
||||
}
|
||||
} else if (v.result === 'invalid') {
|
||||
let failed = false;
|
||||
try {
|
||||
x25519.scalarMult(v.private, v.public);
|
||||
} catch (error) {
|
||||
failed = true;
|
||||
}
|
||||
deepStrictEqual(failed, true, comment);
|
||||
} else throw new Error('unknown test result');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
should(`Wycheproof/ED25519`, () => {
|
||||
for (let g = 0; g < ed25519vectors.testGroups.length; g++) {
|
||||
const group = ed25519vectors.testGroups[g];
|
||||
const key = group.key;
|
||||
deepStrictEqual(hex(ed.getPublicKey(key.sk)), key.pk, `(${g}, public)`);
|
||||
for (let i = 0; i < group.tests.length; i++) {
|
||||
const v = group.tests[i];
|
||||
const comment = `(${g}/${i}, ${v.result}): ${v.comment}`;
|
||||
if (v.result === 'valid' || v.result === 'acceptable') {
|
||||
deepStrictEqual(hex(ed.sign(v.msg, key.sk)), v.sig, comment);
|
||||
deepStrictEqual(ed.verify(v.sig, v.msg, key.pk), true, comment);
|
||||
} else if (v.result === 'invalid') {
|
||||
let failed = false;
|
||||
try {
|
||||
failed = !ed.verify(v.sig, v.msg, key.pk);
|
||||
} catch (error) {
|
||||
failed = true;
|
||||
}
|
||||
deepStrictEqual(failed, true, comment);
|
||||
} else throw new Error('unknown test result');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
should('Property test issue #1', () => {
|
||||
const message = new Uint8Array([12, 12, 12]);
|
||||
const signature = ed.sign(message, to32Bytes(1n));
|
||||
const publicKey = ed.getPublicKey(to32Bytes(1n)); // <- was 1n
|
||||
deepStrictEqual(ed.verify(signature, message, publicKey), true);
|
||||
});
|
||||
|
||||
const VECTORS_RFC8032_CTX = [
|
||||
{
|
||||
secretKey: '0305334e381af78f141cb666f6199f57bc3495335a256a95bd2a55bf546663f6',
|
||||
publicKey: 'dfc9425e4f968f7f0c29f0259cf5f9aed6851c2bb4ad8bfb860cfee0ab248292',
|
||||
message: 'f726936d19c800494e3fdaff20b276a8',
|
||||
context: '666f6f',
|
||||
signature:
|
||||
'55a4cc2f70a54e04288c5f4cd1e45a7b' +
|
||||
'b520b36292911876cada7323198dd87a' +
|
||||
'8b36950b95130022907a7fb7c4e9b2d5' +
|
||||
'f6cca685a587b4b21f4b888e4e7edb0d',
|
||||
},
|
||||
{
|
||||
secretKey: '0305334e381af78f141cb666f6199f57bc3495335a256a95bd2a55bf546663f6',
|
||||
publicKey: 'dfc9425e4f968f7f0c29f0259cf5f9aed6851c2bb4ad8bfb860cfee0ab248292',
|
||||
message: 'f726936d19c800494e3fdaff20b276a8',
|
||||
context: '626172',
|
||||
signature:
|
||||
'fc60d5872fc46b3aa69f8b5b4351d580' +
|
||||
'8f92bcc044606db097abab6dbcb1aee3' +
|
||||
'216c48e8b3b66431b5b186d1d28f8ee1' +
|
||||
'5a5ca2df6668346291c2043d4eb3e90d',
|
||||
},
|
||||
{
|
||||
secretKey: '0305334e381af78f141cb666f6199f57bc3495335a256a95bd2a55bf546663f6',
|
||||
publicKey: 'dfc9425e4f968f7f0c29f0259cf5f9aed6851c2bb4ad8bfb860cfee0ab248292',
|
||||
message: '508e9e6882b979fea900f62adceaca35',
|
||||
context: '666f6f',
|
||||
signature:
|
||||
'8b70c1cc8310e1de20ac53ce28ae6e72' +
|
||||
'07f33c3295e03bb5c0732a1d20dc6490' +
|
||||
'8922a8b052cf99b7c4fe107a5abb5b2c' +
|
||||
'4085ae75890d02df26269d8945f84b0b',
|
||||
},
|
||||
{
|
||||
secretKey: 'ab9c2853ce297ddab85c993b3ae14bcad39b2c682beabc27d6d4eb20711d6560',
|
||||
publicKey: '0f1d1274943b91415889152e893d80e93275a1fc0b65fd71b4b0dda10ad7d772',
|
||||
message: 'f726936d19c800494e3fdaff20b276a8',
|
||||
context: '666f6f',
|
||||
signature:
|
||||
'21655b5f1aa965996b3f97b3c849eafb' +
|
||||
'a922a0a62992f73b3d1b73106a84ad85' +
|
||||
'e9b86a7b6005ea868337ff2d20a7f5fb' +
|
||||
'd4cd10b0be49a68da2b2e0dc0ad8960f',
|
||||
},
|
||||
];
|
||||
|
||||
for (let i = 0; i < VECTORS_RFC8032_CTX.length; i++) {
|
||||
const v = VECTORS_RFC8032_CTX[i];
|
||||
should(`RFC8032ctx/${i}`, () => {
|
||||
deepStrictEqual(hex(ed25519ctx.getPublicKey(v.secretKey)), v.publicKey);
|
||||
deepStrictEqual(hex(ed25519ctx.sign(v.message, v.secretKey, v.context)), v.signature);
|
||||
deepStrictEqual(ed25519ctx.verify(v.signature, v.message, v.publicKey, v.context), true);
|
||||
});
|
||||
}
|
||||
|
||||
const VECTORS_RFC8032_PH = [
|
||||
{
|
||||
secretKey: '833fe62409237b9d62ec77587520911e9a759cec1d19755b7da901b96dca3d42',
|
||||
publicKey: 'ec172b93ad5e563bf4932c70e1245034c35467ef2efd4d64ebf819683467e2bf',
|
||||
message: '616263',
|
||||
signature:
|
||||
'98a70222f0b8121aa9d30f813d683f80' +
|
||||
'9e462b469c7ff87639499bb94e6dae41' +
|
||||
'31f85042463c2a355a2003d062adf5aa' +
|
||||
'a10b8c61e636062aaad11c2a26083406',
|
||||
},
|
||||
];
|
||||
|
||||
for (let i = 0; i < VECTORS_RFC8032_PH.length; i++) {
|
||||
const v = VECTORS_RFC8032_PH[i];
|
||||
should(`RFC8032ph/${i}`, () => {
|
||||
deepStrictEqual(hex(ed25519ph.getPublicKey(v.secretKey)), v.publicKey);
|
||||
deepStrictEqual(hex(ed25519ph.sign(v.message, v.secretKey)), v.signature);
|
||||
deepStrictEqual(ed25519ph.verify(v.signature, v.message, v.publicKey), true);
|
||||
});
|
||||
}
|
||||
|
||||
should('X25519 base point', () => {
|
||||
const { y } = ed25519.ExtendedPoint.BASE;
|
||||
const { Fp } = ed25519.CURVE;
|
||||
const u = Fp.create((y + 1n) * Fp.inv(1n - y));
|
||||
deepStrictEqual(hex(numberToBytesLE(u, 32)), x25519.Gu);
|
||||
});
|
||||
|
||||
should('isTorsionFree()', () => {
|
||||
const orig = ed.utils.getExtendedPublicKey(ed.utils.randomPrivateKey()).point;
|
||||
for (const hex of ED25519_TORSION_SUBGROUP.slice(1)) {
|
||||
const dirty = orig.add(Point.fromHex(hex));
|
||||
const cleared = dirty.clearCofactor();
|
||||
strictEqual(orig.isTorsionFree(), true, `orig must be torsionFree: ${hex}`);
|
||||
strictEqual(dirty.isTorsionFree(), false, `dirty must not be torsionFree: ${hex}`);
|
||||
strictEqual(cleared.isTorsionFree(), true, `cleared must be torsionFree: ${hex}`);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
should('ed25519 bug', () => {
|
||||
const t = 81718630521762619991978402609047527194981150691135404693881672112315521837062n;
|
||||
const point = ed25519.ExtendedPoint.fromAffine({ x: t, y: t });
|
||||
throws(() => point.assertValidity());
|
||||
// Otherwise (without assertValidity):
|
||||
// const point2 = point.double();
|
||||
// point2.toAffine(); // crash!
|
||||
});
|
||||
|
||||
// ESM is broken.
|
||||
import url from 'url';
|
||||
if (import.meta.url === url.pathToFileURL(process.argv[1]).href) {
|
||||
should.run();
|
||||
}
|
||||
1024
test/ed25519/vectors.txt
Normal file
1024
test/ed25519/vectors.txt
Normal file
File diff suppressed because it is too large
Load Diff
1178
test/ed25519/zip215.json
Normal file
1178
test/ed25519/zip215.json
Normal file
File diff suppressed because it is too large
Load Diff
675
test/ed448.test.js
Normal file
675
test/ed448.test.js
Normal file
@@ -0,0 +1,675 @@
|
||||
import { deepStrictEqual, throws } from 'assert';
|
||||
import { describe, should } from 'micro-should';
|
||||
import * as fc from 'fast-check';
|
||||
import { ed448, ed448ph, x448 } from '../lib/esm/ed448.js';
|
||||
import { hexToBytes, bytesToHex, randomBytes } from '@noble/hashes/utils';
|
||||
import { numberToBytesLE } from '../lib/esm/abstract/utils.js';
|
||||
import { default as ed448vectors } from './wycheproof/ed448_test.json' assert { type: 'json' };
|
||||
import { default as x448vectors } from './wycheproof/x448_test.json' assert { type: 'json' };
|
||||
|
||||
describe('ed448', () => {
|
||||
const ed = ed448;
|
||||
const hex = bytesToHex;
|
||||
ed.utils.precompute(4);
|
||||
const Point = ed.ExtendedPoint;
|
||||
|
||||
should(`Basic`, () => {
|
||||
const G1 = Point.BASE.toAffine();
|
||||
deepStrictEqual(
|
||||
G1.x,
|
||||
224580040295924300187604334099896036246789641632564134246125461686950415467406032909029192869357953282578032075146446173674602635247710n
|
||||
);
|
||||
deepStrictEqual(
|
||||
G1.y,
|
||||
298819210078481492676017930443930673437544040154080242095928241372331506189835876003536878655418784733982303233503462500531545062832660n
|
||||
);
|
||||
const G2 = Point.BASE.multiply(2n).toAffine();
|
||||
deepStrictEqual(
|
||||
G2.x,
|
||||
484559149530404593699549205258669689569094240458212040187660132787056912146709081364401144455726350866276831544947397859048262938744149n
|
||||
);
|
||||
deepStrictEqual(
|
||||
G2.y,
|
||||
494088759867433727674302672526735089350544552303727723746126484473087719117037293890093462157703888342865036477787453078312060500281069n
|
||||
);
|
||||
const G3 = Point.BASE.multiply(3n).toAffine();
|
||||
deepStrictEqual(
|
||||
G3.x,
|
||||
23839778817283171003887799738662344287085130522697782688245073320169861206004018274567429238677677920280078599146891901463786155880335n
|
||||
);
|
||||
deepStrictEqual(
|
||||
G3.y,
|
||||
636046652612779686502873775776967954190574036985351036782021535703553242737829645273154208057988851307101009474686328623630835377952508n
|
||||
);
|
||||
});
|
||||
|
||||
should('Basic/decompress', () => {
|
||||
const G1 = Point.BASE;
|
||||
const G2 = Point.BASE.multiply(2n);
|
||||
const G3 = Point.BASE.multiply(3n);
|
||||
const points = [G1, G2, G3];
|
||||
const getXY = (p) => p.toAffine();
|
||||
for (const p of points) deepStrictEqual(getXY(Point.fromHex(p.toHex())), getXY(p));
|
||||
});
|
||||
|
||||
const VECTORS_RFC8032 = [
|
||||
{
|
||||
secretKey:
|
||||
'6c82a562cb808d10d632be89c8513ebf' +
|
||||
'6c929f34ddfa8c9f63c9960ef6e348a3' +
|
||||
'528c8a3fcc2f044e39a3fc5b94492f8f' +
|
||||
'032e7549a20098f95b',
|
||||
publicKey:
|
||||
'5fd7449b59b461fd2ce787ec616ad46a' +
|
||||
'1da1342485a70e1f8a0ea75d80e96778' +
|
||||
'edf124769b46c7061bd6783df1e50f6c' +
|
||||
'd1fa1abeafe8256180',
|
||||
message: '',
|
||||
signature:
|
||||
'533a37f6bbe457251f023c0d88f976ae' +
|
||||
'2dfb504a843e34d2074fd823d41a591f' +
|
||||
'2b233f034f628281f2fd7a22ddd47d78' +
|
||||
'28c59bd0a21bfd3980ff0d2028d4b18a' +
|
||||
'9df63e006c5d1c2d345b925d8dc00b41' +
|
||||
'04852db99ac5c7cdda8530a113a0f4db' +
|
||||
'b61149f05a7363268c71d95808ff2e65' +
|
||||
'2600',
|
||||
},
|
||||
{
|
||||
secretKey:
|
||||
'c4eab05d357007c632f3dbb48489924d' +
|
||||
'552b08fe0c353a0d4a1f00acda2c463a' +
|
||||
'fbea67c5e8d2877c5e3bc397a659949e' +
|
||||
'f8021e954e0a12274e',
|
||||
publicKey:
|
||||
'43ba28f430cdff456ae531545f7ecd0a' +
|
||||
'c834a55d9358c0372bfa0c6c6798c086' +
|
||||
'6aea01eb00742802b8438ea4cb82169c' +
|
||||
'235160627b4c3a9480',
|
||||
|
||||
message: '03',
|
||||
signature:
|
||||
'26b8f91727bd62897af15e41eb43c377' +
|
||||
'efb9c610d48f2335cb0bd0087810f435' +
|
||||
'2541b143c4b981b7e18f62de8ccdf633' +
|
||||
'fc1bf037ab7cd779805e0dbcc0aae1cb' +
|
||||
'cee1afb2e027df36bc04dcecbf154336' +
|
||||
'c19f0af7e0a6472905e799f1953d2a0f' +
|
||||
'f3348ab21aa4adafd1d234441cf807c0' +
|
||||
'3a00',
|
||||
},
|
||||
{
|
||||
secretKey:
|
||||
'cd23d24f714274e744343237b93290f5' +
|
||||
'11f6425f98e64459ff203e8985083ffd' +
|
||||
'f60500553abc0e05cd02184bdb89c4cc' +
|
||||
'd67e187951267eb328',
|
||||
publicKey:
|
||||
'dcea9e78f35a1bf3499a831b10b86c90' +
|
||||
'aac01cd84b67a0109b55a36e9328b1e3' +
|
||||
'65fce161d71ce7131a543ea4cb5f7e9f' +
|
||||
'1d8b00696447001400',
|
||||
message: '0c3e544074ec63b0265e0c',
|
||||
signature:
|
||||
'1f0a8888ce25e8d458a21130879b840a' +
|
||||
'9089d999aaba039eaf3e3afa090a09d3' +
|
||||
'89dba82c4ff2ae8ac5cdfb7c55e94d5d' +
|
||||
'961a29fe0109941e00b8dbdeea6d3b05' +
|
||||
'1068df7254c0cdc129cbe62db2dc957d' +
|
||||
'bb47b51fd3f213fb8698f064774250a5' +
|
||||
'028961c9bf8ffd973fe5d5c206492b14' +
|
||||
'0e00',
|
||||
},
|
||||
{
|
||||
secretKey:
|
||||
'258cdd4ada32ed9c9ff54e63756ae582' +
|
||||
'fb8fab2ac721f2c8e676a72768513d93' +
|
||||
'9f63dddb55609133f29adf86ec9929dc' +
|
||||
'cb52c1c5fd2ff7e21b',
|
||||
publicKey:
|
||||
'3ba16da0c6f2cc1f30187740756f5e79' +
|
||||
'8d6bc5fc015d7c63cc9510ee3fd44adc' +
|
||||
'24d8e968b6e46e6f94d19b945361726b' +
|
||||
'd75e149ef09817f580',
|
||||
message: '64a65f3cdedcdd66811e2915',
|
||||
signature:
|
||||
'7eeeab7c4e50fb799b418ee5e3197ff6' +
|
||||
'bf15d43a14c34389b59dd1a7b1b85b4a' +
|
||||
'e90438aca634bea45e3a2695f1270f07' +
|
||||
'fdcdf7c62b8efeaf00b45c2c96ba457e' +
|
||||
'b1a8bf075a3db28e5c24f6b923ed4ad7' +
|
||||
'47c3c9e03c7079efb87cb110d3a99861' +
|
||||
'e72003cbae6d6b8b827e4e6c143064ff' +
|
||||
'3c00',
|
||||
},
|
||||
{
|
||||
secretKey:
|
||||
'7ef4e84544236752fbb56b8f31a23a10' +
|
||||
'e42814f5f55ca037cdcc11c64c9a3b29' +
|
||||
'49c1bb60700314611732a6c2fea98eeb' +
|
||||
'c0266a11a93970100e',
|
||||
publicKey:
|
||||
'b3da079b0aa493a5772029f0467baebe' +
|
||||
'e5a8112d9d3a22532361da294f7bb381' +
|
||||
'5c5dc59e176b4d9f381ca0938e13c6c0' +
|
||||
'7b174be65dfa578e80',
|
||||
message: '64a65f3cdedcdd66811e2915e7',
|
||||
signature:
|
||||
'6a12066f55331b6c22acd5d5bfc5d712' +
|
||||
'28fbda80ae8dec26bdd306743c5027cb' +
|
||||
'4890810c162c027468675ecf645a8317' +
|
||||
'6c0d7323a2ccde2d80efe5a1268e8aca' +
|
||||
'1d6fbc194d3f77c44986eb4ab4177919' +
|
||||
'ad8bec33eb47bbb5fc6e28196fd1caf5' +
|
||||
'6b4e7e0ba5519234d047155ac727a105' +
|
||||
'3100',
|
||||
},
|
||||
{
|
||||
secretKey:
|
||||
'd65df341ad13e008567688baedda8e9d' +
|
||||
'cdc17dc024974ea5b4227b6530e339bf' +
|
||||
'f21f99e68ca6968f3cca6dfe0fb9f4fa' +
|
||||
'b4fa135d5542ea3f01',
|
||||
publicKey:
|
||||
'df9705f58edbab802c7f8363cfe5560a' +
|
||||
'b1c6132c20a9f1dd163483a26f8ac53a' +
|
||||
'39d6808bf4a1dfbd261b099bb03b3fb5' +
|
||||
'0906cb28bd8a081f00',
|
||||
message:
|
||||
'bd0f6a3747cd561bdddf4640a332461a' +
|
||||
'4a30a12a434cd0bf40d766d9c6d458e5' +
|
||||
'512204a30c17d1f50b5079631f64eb31' +
|
||||
'12182da3005835461113718d1a5ef944',
|
||||
signature:
|
||||
'554bc2480860b49eab8532d2a533b7d5' +
|
||||
'78ef473eeb58c98bb2d0e1ce488a98b1' +
|
||||
'8dfde9b9b90775e67f47d4a1c3482058' +
|
||||
'efc9f40d2ca033a0801b63d45b3b722e' +
|
||||
'f552bad3b4ccb667da350192b61c508c' +
|
||||
'f7b6b5adadc2c8d9a446ef003fb05cba' +
|
||||
'5f30e88e36ec2703b349ca229c267083' +
|
||||
'3900',
|
||||
},
|
||||
{
|
||||
secretKey:
|
||||
'2ec5fe3c17045abdb136a5e6a913e32a' +
|
||||
'b75ae68b53d2fc149b77e504132d3756' +
|
||||
'9b7e766ba74a19bd6162343a21c8590a' +
|
||||
'a9cebca9014c636df5',
|
||||
publicKey:
|
||||
'79756f014dcfe2079f5dd9e718be4171' +
|
||||
'e2ef2486a08f25186f6bff43a9936b9b' +
|
||||
'fe12402b08ae65798a3d81e22e9ec80e' +
|
||||
'7690862ef3d4ed3a00',
|
||||
message:
|
||||
'15777532b0bdd0d1389f636c5f6b9ba7' +
|
||||
'34c90af572877e2d272dd078aa1e567c' +
|
||||
'fa80e12928bb542330e8409f31745041' +
|
||||
'07ecd5efac61ae7504dabe2a602ede89' +
|
||||
'e5cca6257a7c77e27a702b3ae39fc769' +
|
||||
'fc54f2395ae6a1178cab4738e543072f' +
|
||||
'c1c177fe71e92e25bf03e4ecb72f47b6' +
|
||||
'4d0465aaea4c7fad372536c8ba516a60' +
|
||||
'39c3c2a39f0e4d832be432dfa9a706a6' +
|
||||
'e5c7e19f397964ca4258002f7c0541b5' +
|
||||
'90316dbc5622b6b2a6fe7a4abffd9610' +
|
||||
'5eca76ea7b98816af0748c10df048ce0' +
|
||||
'12d901015a51f189f3888145c03650aa' +
|
||||
'23ce894c3bd889e030d565071c59f409' +
|
||||
'a9981b51878fd6fc110624dcbcde0bf7' +
|
||||
'a69ccce38fabdf86f3bef6044819de11',
|
||||
signature:
|
||||
'c650ddbb0601c19ca11439e1640dd931' +
|
||||
'f43c518ea5bea70d3dcde5f4191fe53f' +
|
||||
'00cf966546b72bcc7d58be2b9badef28' +
|
||||
'743954e3a44a23f880e8d4f1cfce2d7a' +
|
||||
'61452d26da05896f0a50da66a239a8a1' +
|
||||
'88b6d825b3305ad77b73fbac0836ecc6' +
|
||||
'0987fd08527c1a8e80d5823e65cafe2a' +
|
||||
'3d00',
|
||||
},
|
||||
{
|
||||
secretKey:
|
||||
'872d093780f5d3730df7c212664b37b8' +
|
||||
'a0f24f56810daa8382cd4fa3f77634ec' +
|
||||
'44dc54f1c2ed9bea86fafb7632d8be19' +
|
||||
'9ea165f5ad55dd9ce8',
|
||||
publicKey:
|
||||
'a81b2e8a70a5ac94ffdbcc9badfc3feb' +
|
||||
'0801f258578bb114ad44ece1ec0e799d' +
|
||||
'a08effb81c5d685c0c56f64eecaef8cd' +
|
||||
'f11cc38737838cf400',
|
||||
message:
|
||||
'6ddf802e1aae4986935f7f981ba3f035' +
|
||||
'1d6273c0a0c22c9c0e8339168e675412' +
|
||||
'a3debfaf435ed651558007db4384b650' +
|
||||
'fcc07e3b586a27a4f7a00ac8a6fec2cd' +
|
||||
'86ae4bf1570c41e6a40c931db27b2faa' +
|
||||
'15a8cedd52cff7362c4e6e23daec0fbc' +
|
||||
'3a79b6806e316efcc7b68119bf46bc76' +
|
||||
'a26067a53f296dafdbdc11c77f7777e9' +
|
||||
'72660cf4b6a9b369a6665f02e0cc9b6e' +
|
||||
'dfad136b4fabe723d2813db3136cfde9' +
|
||||
'b6d044322fee2947952e031b73ab5c60' +
|
||||
'3349b307bdc27bc6cb8b8bbd7bd32321' +
|
||||
'9b8033a581b59eadebb09b3c4f3d2277' +
|
||||
'd4f0343624acc817804728b25ab79717' +
|
||||
'2b4c5c21a22f9c7839d64300232eb66e' +
|
||||
'53f31c723fa37fe387c7d3e50bdf9813' +
|
||||
'a30e5bb12cf4cd930c40cfb4e1fc6225' +
|
||||
'92a49588794494d56d24ea4b40c89fc0' +
|
||||
'596cc9ebb961c8cb10adde976a5d602b' +
|
||||
'1c3f85b9b9a001ed3c6a4d3b1437f520' +
|
||||
'96cd1956d042a597d561a596ecd3d173' +
|
||||
'5a8d570ea0ec27225a2c4aaff26306d1' +
|
||||
'526c1af3ca6d9cf5a2c98f47e1c46db9' +
|
||||
'a33234cfd4d81f2c98538a09ebe76998' +
|
||||
'd0d8fd25997c7d255c6d66ece6fa56f1' +
|
||||
'1144950f027795e653008f4bd7ca2dee' +
|
||||
'85d8e90f3dc315130ce2a00375a318c7' +
|
||||
'c3d97be2c8ce5b6db41a6254ff264fa6' +
|
||||
'155baee3b0773c0f497c573f19bb4f42' +
|
||||
'40281f0b1f4f7be857a4e59d416c06b4' +
|
||||
'c50fa09e1810ddc6b1467baeac5a3668' +
|
||||
'd11b6ecaa901440016f389f80acc4db9' +
|
||||
'77025e7f5924388c7e340a732e554440' +
|
||||
'e76570f8dd71b7d640b3450d1fd5f041' +
|
||||
'0a18f9a3494f707c717b79b4bf75c984' +
|
||||
'00b096b21653b5d217cf3565c9597456' +
|
||||
'f70703497a078763829bc01bb1cbc8fa' +
|
||||
'04eadc9a6e3f6699587a9e75c94e5bab' +
|
||||
'0036e0b2e711392cff0047d0d6b05bd2' +
|
||||
'a588bc109718954259f1d86678a579a3' +
|
||||
'120f19cfb2963f177aeb70f2d4844826' +
|
||||
'262e51b80271272068ef5b3856fa8535' +
|
||||
'aa2a88b2d41f2a0e2fda7624c2850272' +
|
||||
'ac4a2f561f8f2f7a318bfd5caf969614' +
|
||||
'9e4ac824ad3460538fdc25421beec2cc' +
|
||||
'6818162d06bbed0c40a387192349db67' +
|
||||
'a118bada6cd5ab0140ee273204f628aa' +
|
||||
'd1c135f770279a651e24d8c14d75a605' +
|
||||
'9d76b96a6fd857def5e0b354b27ab937' +
|
||||
'a5815d16b5fae407ff18222c6d1ed263' +
|
||||
'be68c95f32d908bd895cd76207ae7264' +
|
||||
'87567f9a67dad79abec316f683b17f2d' +
|
||||
'02bf07e0ac8b5bc6162cf94697b3c27c' +
|
||||
'd1fea49b27f23ba2901871962506520c' +
|
||||
'392da8b6ad0d99f7013fbc06c2c17a56' +
|
||||
'9500c8a7696481c1cd33e9b14e40b82e' +
|
||||
'79a5f5db82571ba97bae3ad3e0479515' +
|
||||
'bb0e2b0f3bfcd1fd33034efc6245eddd' +
|
||||
'7ee2086ddae2600d8ca73e214e8c2b0b' +
|
||||
'db2b047c6a464a562ed77b73d2d841c4' +
|
||||
'b34973551257713b753632efba348169' +
|
||||
'abc90a68f42611a40126d7cb21b58695' +
|
||||
'568186f7e569d2ff0f9e745d0487dd2e' +
|
||||
'b997cafc5abf9dd102e62ff66cba87',
|
||||
signature:
|
||||
'e301345a41a39a4d72fff8df69c98075' +
|
||||
'a0cc082b802fc9b2b6bc503f926b65bd' +
|
||||
'df7f4c8f1cb49f6396afc8a70abe6d8a' +
|
||||
'ef0db478d4c6b2970076c6a0484fe76d' +
|
||||
'76b3a97625d79f1ce240e7c576750d29' +
|
||||
'5528286f719b413de9ada3e8eb78ed57' +
|
||||
'3603ce30d8bb761785dc30dbc320869e' +
|
||||
'1a00',
|
||||
},
|
||||
];
|
||||
|
||||
describe('RFC8032', () => {
|
||||
for (let i = 0; i < VECTORS_RFC8032.length; i++) {
|
||||
const v = VECTORS_RFC8032[i];
|
||||
should(`${i}`, () => {
|
||||
deepStrictEqual(hex(ed.getPublicKey(v.secretKey)), v.publicKey);
|
||||
deepStrictEqual(hex(ed.sign(v.message, v.secretKey)), v.signature);
|
||||
deepStrictEqual(ed.verify(v.signature, v.message, v.publicKey), true);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
should('not accept >57byte private keys', () => {
|
||||
const invalidPriv =
|
||||
100000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000090000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800073278156000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000n;
|
||||
throws(() => ed.getPublicKey(invalidPriv));
|
||||
});
|
||||
|
||||
function to57Bytes(numOrStr) {
|
||||
let hex = typeof numOrStr === 'string' ? numOrStr : numOrStr.toString(16);
|
||||
return hexToBytes(hex.padStart(114, '0'));
|
||||
}
|
||||
|
||||
should('verify recent signature', () => {
|
||||
fc.assert(
|
||||
fc.property(
|
||||
fc.hexaString({ minLength: 2, maxLength: 57 }),
|
||||
fc.bigInt(2n, ed.CURVE.n),
|
||||
(message, privateKey) => {
|
||||
const publicKey = ed.getPublicKey(to57Bytes(privateKey));
|
||||
const signature = ed.sign(to57Bytes(message), to57Bytes(privateKey));
|
||||
deepStrictEqual(publicKey.length, 57);
|
||||
deepStrictEqual(signature.length, 114);
|
||||
deepStrictEqual(ed.verify(signature, to57Bytes(message), publicKey), true);
|
||||
}
|
||||
),
|
||||
{ numRuns: 5 }
|
||||
);
|
||||
});
|
||||
should('not verify signature with wrong message', () => {
|
||||
fc.assert(
|
||||
fc.property(
|
||||
fc.array(fc.integer({ min: 0x00, max: 0xff })),
|
||||
fc.array(fc.integer({ min: 0x00, max: 0xff })),
|
||||
fc.bigInt(1n, ed.CURVE.n),
|
||||
(bytes, wrongBytes, privateKey) => {
|
||||
const message = new Uint8Array(bytes);
|
||||
const wrongMessage = new Uint8Array(wrongBytes);
|
||||
const priv = to57Bytes(privateKey);
|
||||
const publicKey = ed.getPublicKey(priv);
|
||||
const signature = ed.sign(message, priv);
|
||||
deepStrictEqual(
|
||||
ed.verify(signature, wrongMessage, publicKey),
|
||||
bytes.toString() === wrongBytes.toString()
|
||||
);
|
||||
}
|
||||
),
|
||||
{ numRuns: 5 }
|
||||
);
|
||||
});
|
||||
const privKey = to57Bytes('a665a45920422f9d417e4867ef');
|
||||
const msg = hexToBytes('874f9960c5d2b7a9b5fad383e1ba44719ebb743a');
|
||||
const wrongMsg = hexToBytes('589d8c7f1da0a24bc07b7381ad48b1cfc211af1c');
|
||||
describe('basic methods', () => {
|
||||
should('sign and verify', () => {
|
||||
const publicKey = ed.getPublicKey(privKey);
|
||||
const signature = ed.sign(msg, privKey);
|
||||
deepStrictEqual(ed.verify(signature, msg, publicKey), true);
|
||||
});
|
||||
should('not verify signature with wrong public key', () => {
|
||||
const publicKey = ed.getPublicKey(ed.utils.randomPrivateKey());
|
||||
const signature = ed.sign(msg, privKey);
|
||||
deepStrictEqual(ed.verify(signature, msg, publicKey), false);
|
||||
});
|
||||
should('not verify signature with wrong hash', () => {
|
||||
const publicKey = ed.getPublicKey(privKey);
|
||||
const signature = ed.sign(msg, privKey);
|
||||
deepStrictEqual(ed.verify(signature, wrongMsg, publicKey), false);
|
||||
});
|
||||
});
|
||||
describe('sync methods', () => {
|
||||
should('sign and verify', () => {
|
||||
const publicKey = ed.getPublicKey(privKey);
|
||||
const signature = ed.sign(msg, privKey);
|
||||
deepStrictEqual(ed.verify(signature, msg, publicKey), true);
|
||||
});
|
||||
should('not verify signature with wrong public key', () => {
|
||||
const publicKey = ed.getPublicKey(ed.utils.randomPrivateKey());
|
||||
const signature = ed.sign(msg, privKey);
|
||||
deepStrictEqual(ed.verify(signature, msg, publicKey), false);
|
||||
});
|
||||
should('not verify signature with wrong hash', () => {
|
||||
const publicKey = ed.getPublicKey(privKey);
|
||||
const signature = ed.sign(msg, privKey);
|
||||
deepStrictEqual(ed.verify(signature, wrongMsg, publicKey), false);
|
||||
});
|
||||
});
|
||||
|
||||
should('BASE_POINT.multiply() throws in Point#multiply on TEST 5', () => {
|
||||
for (const num of [0n, 0, -1n, -1, 1.1]) {
|
||||
throws(() => ed.ExtendedPoint.BASE.multiply(num));
|
||||
}
|
||||
});
|
||||
|
||||
should('input immutability: sign/verify are immutable', () => {
|
||||
const privateKey = ed.utils.randomPrivateKey();
|
||||
const publicKey = ed.getPublicKey(privateKey);
|
||||
|
||||
for (let i = 0; i < 100; i++) {
|
||||
let payload = randomBytes(100);
|
||||
let signature = ed.sign(payload, privateKey);
|
||||
if (!ed.verify(signature, payload, publicKey)) {
|
||||
throw new Error('Signature verification failed');
|
||||
}
|
||||
const signatureCopy = Buffer.alloc(signature.byteLength);
|
||||
signatureCopy.set(signature, 0); // <-- breaks
|
||||
payload = payload.slice();
|
||||
signature = signature.slice();
|
||||
|
||||
if (!ed.verify(signatureCopy, payload, publicKey))
|
||||
throw new Error('Copied signature verification failed');
|
||||
}
|
||||
});
|
||||
|
||||
describe('wycheproof', () => {
|
||||
for (let g = 0; g < ed448vectors.testGroups.length; g++) {
|
||||
const group = ed448vectors.testGroups[g];
|
||||
const key = group.key;
|
||||
should(`ED448(${g}, public)`, () => {
|
||||
deepStrictEqual(hex(ed.getPublicKey(key.sk)), key.pk);
|
||||
});
|
||||
should(`ED448`, () => {
|
||||
for (let i = 0; i < group.tests.length; i++) {
|
||||
const v = group.tests[i];
|
||||
const index = `${g}/${i} ${v.comment}`;
|
||||
if (v.result === 'valid' || v.result === 'acceptable') {
|
||||
deepStrictEqual(hex(ed.sign(v.msg, key.sk)), v.sig, index);
|
||||
deepStrictEqual(ed.verify(v.sig, v.msg, key.pk), true, index);
|
||||
} else if (v.result === 'invalid') {
|
||||
let failed = false;
|
||||
try {
|
||||
failed = !ed.verify(v.sig, v.msg, key.pk);
|
||||
} catch (error) {
|
||||
failed = true;
|
||||
}
|
||||
deepStrictEqual(failed, true, index);
|
||||
} else throw new Error('unknown test result');
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// ECDH
|
||||
const rfc7748Mul = [
|
||||
{
|
||||
scalar:
|
||||
'3d262fddf9ec8e88495266fea19a34d28882acef045104d0d1aae121700a779c984c24f8cdd78fbff44943eba368f54b29259a4f1c600ad3',
|
||||
u: '06fce640fa3487bfda5f6cf2d5263f8aad88334cbd07437f020f08f9814dc031ddbdc38c19c6da2583fa5429db94ada18aa7a7fb4ef8a086',
|
||||
outputU:
|
||||
'ce3e4ff95a60dc6697da1db1d85e6afbdf79b50a2412d7546d5f239fe14fbaadeb445fc66a01b0779d98223961111e21766282f73dd96b6f',
|
||||
},
|
||||
{
|
||||
scalar:
|
||||
'203d494428b8399352665ddca42f9de8fef600908e0d461cb021f8c538345dd77c3e4806e25f46d3315c44e0a5b4371282dd2c8d5be3095f',
|
||||
u: '0fbcc2f993cd56d3305b0b7d9e55d4c1a8fb5dbb52f8e9a1e9b6201b165d015894e56c4d3570bee52fe205e28a78b91cdfbde71ce8d157db',
|
||||
outputU:
|
||||
'884a02576239ff7a2f2f63b2db6a9ff37047ac13568e1e30fe63c4a7ad1b3ee3a5700df34321d62077e63633c575c1c954514e99da7c179d',
|
||||
},
|
||||
];
|
||||
describe('RFC7748', () => {
|
||||
for (let i = 0; i < rfc7748Mul.length; i++) {
|
||||
const v = rfc7748Mul[i];
|
||||
should(`scalarMult (${i})`, () => {
|
||||
deepStrictEqual(hex(x448.scalarMult(v.scalar, v.u)), v.outputU);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
const rfc7748Iter = [
|
||||
{
|
||||
scalar:
|
||||
'3f482c8a9f19b01e6c46ee9711d9dc14fd4bf67af30765c2ae2b846a4d23a8cd0db897086239492caf350b51f833868b9bc2b3bca9cf4113',
|
||||
iters: 1,
|
||||
},
|
||||
{
|
||||
scalar:
|
||||
'aa3b4749d55b9daf1e5b00288826c467274ce3ebbdd5c17b975e09d4af6c67cf10d087202db88286e2b79fceea3ec353ef54faa26e219f38',
|
||||
iters: 1000,
|
||||
},
|
||||
// { scalar: '077f453681caca3693198420bbe515cae0002472519b3e67661a7e89cab94695c8f4bcd66e61b9b9c946da8d524de3d69bd9d9d66b997e37', iters: 1000000 },
|
||||
];
|
||||
for (let i = 0; i < rfc7748Iter.length; i++) {
|
||||
const { scalar, iters } = rfc7748Iter[i];
|
||||
should(`RFC7748: scalarMult iteration (${i})`, () => {
|
||||
let k = x448.Gu;
|
||||
for (let i = 0, u = k; i < iters; i++) [k, u] = [x448.scalarMult(k, u), k];
|
||||
deepStrictEqual(hex(k), scalar);
|
||||
});
|
||||
}
|
||||
|
||||
should('RFC7748 getSharedKey', () => {
|
||||
const alicePrivate =
|
||||
'9a8f4925d1519f5775cf46b04b5800d4ee9ee8bae8bc5565d498c28dd9c9baf574a9419744897391006382a6f127ab1d9ac2d8c0a598726b';
|
||||
const alicePublic =
|
||||
'9b08f7cc31b7e3e67d22d5aea121074a273bd2b83de09c63faa73d2c22c5d9bbc836647241d953d40c5b12da88120d53177f80e532c41fa0';
|
||||
const bobPrivate =
|
||||
'1c306a7ac2a0e2e0990b294470cba339e6453772b075811d8fad0d1d6927c120bb5ee8972b0d3e21374c9c921b09d1b0366f10b65173992d';
|
||||
const bobPublic =
|
||||
'3eb7a829b0cd20f5bcfc0b599b6feccf6da4627107bdb0d4f345b43027d8b972fc3e34fb4232a13ca706dcb57aec3dae07bdc1c67bf33609';
|
||||
const shared =
|
||||
'07fff4181ac6cc95ec1c16a94a0f74d12da232ce40a77552281d282bb60c0b56fd2464c335543936521c24403085d59a449a5037514a879d';
|
||||
deepStrictEqual(alicePublic, hex(x448.getPublicKey(alicePrivate)));
|
||||
deepStrictEqual(bobPublic, hex(x448.getPublicKey(bobPrivate)));
|
||||
deepStrictEqual(hex(x448.scalarMult(alicePrivate, bobPublic)), shared);
|
||||
deepStrictEqual(hex(x448.scalarMult(bobPrivate, alicePublic)), shared);
|
||||
});
|
||||
|
||||
describe('wycheproof', () => {
|
||||
const group = x448vectors.testGroups[0];
|
||||
should(`X448`, () => {
|
||||
for (let i = 0; i < group.tests.length; i++) {
|
||||
const v = group.tests[i];
|
||||
const index = `(${i}, ${v.result}) ${v.comment}`;
|
||||
if (v.result === 'valid' || v.result === 'acceptable') {
|
||||
try {
|
||||
const shared = hex(x448.scalarMult(v.private, v.public));
|
||||
deepStrictEqual(shared, v.shared, index);
|
||||
} catch (e) {
|
||||
// We are more strict
|
||||
if (e.message.includes('Expected valid scalar')) return;
|
||||
if (e.message.includes('Invalid private or public key received')) return;
|
||||
if (e.message.includes('Expected 56 bytes')) return;
|
||||
throw e;
|
||||
}
|
||||
} else if (v.result === 'invalid') {
|
||||
let failed = false;
|
||||
try {
|
||||
x448.scalarMult(v.private, v.public);
|
||||
} catch (error) {
|
||||
failed = true;
|
||||
}
|
||||
deepStrictEqual(failed, true, index);
|
||||
} else throw new Error('unknown test result');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// should('X448: should convert base point to montgomery using fromPoint', () => {
|
||||
// deepStrictEqual(
|
||||
// hex(ed.montgomeryCurve.UfromPoint(Point.BASE)),
|
||||
// ed.montgomeryCurve.BASE_POINT_U
|
||||
// );
|
||||
// });
|
||||
|
||||
// should('X448/getSharedSecret() should be commutative', async () => {
|
||||
// for (let i = 0; i < 512; i++) {
|
||||
// const asec = ed.utils.randomPrivateKey();
|
||||
// const apub = ed.getPublicKey(asec);
|
||||
// const bsec = ed.utils.randomPrivateKey();
|
||||
// const bpub = ed.getPublicKey(bsec);
|
||||
// try {
|
||||
// deepStrictEqual(ed.getSharedSecret(asec, bpub), ed.getSharedSecret(bsec, apub));
|
||||
// } catch (error) {
|
||||
// console.error('not commutative', { asec, apub, bsec, bpub });
|
||||
// throw error;
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
|
||||
const VECTORS_RFC8032_CTX = [
|
||||
{
|
||||
secretKey:
|
||||
'c4eab05d357007c632f3dbb48489924d552b08fe0c353a0d4a1f00acda2c463afbea67c5e8d2877c5e3bc397a659949ef8021e954e0a12274e',
|
||||
publicKey:
|
||||
'43ba28f430cdff456ae531545f7ecd0ac834a55d9358c0372bfa0c6c6798c0866aea01eb00742802b8438ea4cb82169c235160627b4c3a9480',
|
||||
message: '03',
|
||||
context: '666f6f',
|
||||
signature:
|
||||
'd4f8f6131770dd46f40867d6fd5d5055' +
|
||||
'de43541f8c5e35abbcd001b32a89f7d2' +
|
||||
'151f7647f11d8ca2ae279fb842d60721' +
|
||||
'7fce6e042f6815ea000c85741de5c8da' +
|
||||
'1144a6a1aba7f96de42505d7a7298524' +
|
||||
'fda538fccbbb754f578c1cad10d54d0d' +
|
||||
'5428407e85dcbc98a49155c13764e66c' +
|
||||
'3c00',
|
||||
},
|
||||
];
|
||||
|
||||
for (let i = 0; i < VECTORS_RFC8032_CTX.length; i++) {
|
||||
const v = VECTORS_RFC8032_CTX[i];
|
||||
should(`RFC8032ctx/${i}`, () => {
|
||||
deepStrictEqual(hex(ed.getPublicKey(v.secretKey)), v.publicKey);
|
||||
deepStrictEqual(hex(ed.sign(v.message, v.secretKey, v.context)), v.signature);
|
||||
deepStrictEqual(ed.verify(v.signature, v.message, v.publicKey, v.context), true);
|
||||
});
|
||||
}
|
||||
|
||||
const VECTORS_RFC8032_PH = [
|
||||
{
|
||||
secretKey:
|
||||
'833fe62409237b9d62ec77587520911e9a759cec1d19755b7da901b96dca3d42ef7822e0d5104127dc05d6dbefde69e3ab2cec7c867c6e2c49',
|
||||
publicKey:
|
||||
'259b71c19f83ef77a7abd26524cbdb3161b590a48f7d17de3ee0ba9c52beb743c09428a131d6b1b57303d90d8132c276d5ed3d5d01c0f53880',
|
||||
message: '616263',
|
||||
signature:
|
||||
'822f6901f7480f3d5f562c592994d969' +
|
||||
'3602875614483256505600bbc281ae38' +
|
||||
'1f54d6bce2ea911574932f52a4e6cadd' +
|
||||
'78769375ec3ffd1b801a0d9b3f4030cd' +
|
||||
'433964b6457ea39476511214f97469b5' +
|
||||
'7dd32dbc560a9a94d00bff07620464a3' +
|
||||
'ad203df7dc7ce360c3cd3696d9d9fab9' +
|
||||
'0f00',
|
||||
},
|
||||
{
|
||||
secretKey:
|
||||
'833fe62409237b9d62ec77587520911e9a759cec1d19755b7da901b96dca3d42ef7822e0d5104127dc05d6dbefde69e3ab2cec7c867c6e2c49',
|
||||
publicKey:
|
||||
'259b71c19f83ef77a7abd26524cbdb3161b590a48f7d17de3ee0ba9c52beb743c09428a131d6b1b57303d90d8132c276d5ed3d5d01c0f53880',
|
||||
message: '616263',
|
||||
context: '666f6f',
|
||||
signature:
|
||||
'c32299d46ec8ff02b54540982814dce9' +
|
||||
'a05812f81962b649d528095916a2aa48' +
|
||||
'1065b1580423ef927ecf0af5888f90da' +
|
||||
'0f6a9a85ad5dc3f280d91224ba9911a3' +
|
||||
'653d00e484e2ce232521481c8658df30' +
|
||||
'4bb7745a73514cdb9bf3e15784ab7128' +
|
||||
'4f8d0704a608c54a6b62d97beb511d13' +
|
||||
'2100',
|
||||
},
|
||||
];
|
||||
|
||||
for (let i = 0; i < VECTORS_RFC8032_PH.length; i++) {
|
||||
const v = VECTORS_RFC8032_PH[i];
|
||||
should(`RFC8032ph/${i}`, () => {
|
||||
deepStrictEqual(hex(ed448ph.getPublicKey(v.secretKey)), v.publicKey);
|
||||
deepStrictEqual(hex(ed448ph.sign(v.message, v.secretKey, v.context)), v.signature);
|
||||
deepStrictEqual(ed448ph.verify(v.signature, v.message, v.publicKey, v.context), true);
|
||||
});
|
||||
}
|
||||
|
||||
should('X448 base point', () => {
|
||||
const { x, y } = Point.BASE;
|
||||
const { Fp } = ed448.CURVE;
|
||||
// const invX = Fp.invert(x * x); // x²
|
||||
const u = Fp.div(Fp.create(y * y), Fp.create(x * x)); // (y²/x²)
|
||||
// const u = Fp.create(y * y * invX);
|
||||
deepStrictEqual(hex(numberToBytesLE(u, 56)), x448.Gu);
|
||||
});
|
||||
});
|
||||
|
||||
// ESM is broken.
|
||||
import url from 'url';
|
||||
if (import.meta.url === url.pathToFileURL(process.argv[1]).href) {
|
||||
should.run();
|
||||
}
|
||||
@@ -28,16 +28,16 @@
|
||||
"Uy": "EEAB6F3DEBE455E3DBF85416F7030CBD94F34F2D6F232C69F3C1385A",
|
||||
"cases": [
|
||||
{
|
||||
"k": "AD3029E0278F80643DE33917CE6908C70A8FF50A411F06E41DEDFCDC",
|
||||
"k": "C1D1F2F10881088301880506805FEB4825FE09ACB6816C36991AA06D",
|
||||
"message": "sample",
|
||||
"r": "61AA3DA010E8E8406C656BC477A7A7189895E7E840CDFE8FF42307BA",
|
||||
"s": "BC814050DAB5D23770879494F9E0A680DC1AF7161991BDE692B10101"
|
||||
"r": "1CDFE6662DDE1E4A1EC4CDEDF6A1F5A2FB7FBD9145C12113E6ABFD3E",
|
||||
"s": "A6694FD7718A21053F225D3F46197CA699D45006C06F871808F43EBC"
|
||||
},
|
||||
{
|
||||
"k": "FF86F57924DA248D6E44E8154EB69F0AE2AEBAEE9931D0B5A969F904",
|
||||
"k": "DF8B38D40DCA3E077D0AC520BF56B6D565134D9B5F2EAE0D34900524",
|
||||
"message": "test",
|
||||
"r": "AD04DDE87B84747A243A631EA47A1BA6D1FAA059149AD2440DE6FBA6",
|
||||
"s": "178D49B1AE90E3D8B629BE3DB5683915F4E8C99FDF6E666CF37ADCFD"
|
||||
"r": "C441CE8E261DED634E4CF84910E4C5D1D22C5CF3B732BB204DBEF019",
|
||||
"s": "902F42847A63BDC5F6046ADA114953120F99442D76510150F372A3F4"
|
||||
}
|
||||
]
|
||||
},
|
||||
153
test/hash-to-curve.test.js
Normal file
153
test/hash-to-curve.test.js
Normal file
@@ -0,0 +1,153 @@
|
||||
import { deepStrictEqual } from 'assert';
|
||||
import { describe, should } from 'micro-should';
|
||||
import { bytesToHex } from '@noble/hashes/utils';
|
||||
// Generic tests for all curves in package
|
||||
import { sha256 } from '@noble/hashes/sha256';
|
||||
import { sha512 } from '@noble/hashes/sha512';
|
||||
import { shake128, shake256 } from '@noble/hashes/sha3';
|
||||
import * as secp256r1 from '../lib/esm/p256.js';
|
||||
import * as secp384r1 from '../lib/esm/p384.js';
|
||||
import * as secp521r1 from '../lib/esm/p521.js';
|
||||
import * as ed25519 from '../lib/esm/ed25519.js';
|
||||
import * as ed448 from '../lib/esm/ed448.js';
|
||||
import * as secp256k1 from '../lib/esm/secp256k1.js';
|
||||
import { bls12_381 } from '../lib/esm/bls12-381.js';
|
||||
import {
|
||||
stringToBytes,
|
||||
expand_message_xmd,
|
||||
expand_message_xof,
|
||||
} from '../lib/esm/abstract/hash-to-curve.js';
|
||||
// XMD
|
||||
import { default as xmd_sha256_38 } from './hash-to-curve/expand_message_xmd_SHA256_38.json' assert { type: 'json' };
|
||||
import { default as xmd_sha256_256 } from './hash-to-curve/expand_message_xmd_SHA256_256.json' assert { type: 'json' };
|
||||
import { default as xmd_sha512_38 } from './hash-to-curve/expand_message_xmd_SHA512_38.json' assert { type: 'json' };
|
||||
// XOF
|
||||
import { default as xof_shake128_36 } from './hash-to-curve/expand_message_xof_SHAKE128_36.json' assert { type: 'json' };
|
||||
import { default as xof_shake128_256 } from './hash-to-curve/expand_message_xof_SHAKE128_256.json' assert { type: 'json' };
|
||||
import { default as xof_shake256_36 } from './hash-to-curve/expand_message_xof_SHAKE256_36.json' assert { type: 'json' };
|
||||
// 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' };
|
||||
// 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' };
|
||||
// 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' };
|
||||
// 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' };
|
||||
// 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' };
|
||||
// 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' };
|
||||
// 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' };
|
||||
// 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' };
|
||||
|
||||
function testExpandXMD(hash, vectors) {
|
||||
describe(`${vectors.hash}/${vectors.DST.length}`, () => {
|
||||
for (let i = 0; i < vectors.tests.length; i++) {
|
||||
const t = vectors.tests[i];
|
||||
should(`${vectors.hash}/${vectors.DST.length}/${i}`, () => {
|
||||
const p = expand_message_xmd(
|
||||
stringToBytes(t.msg),
|
||||
stringToBytes(vectors.DST),
|
||||
t.len_in_bytes,
|
||||
hash
|
||||
);
|
||||
deepStrictEqual(bytesToHex(p), t.uniform_bytes);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
describe('expand_message_xmd', () => {
|
||||
testExpandXMD(sha256, xmd_sha256_38);
|
||||
testExpandXMD(sha256, xmd_sha256_256);
|
||||
testExpandXMD(sha512, xmd_sha512_38);
|
||||
});
|
||||
|
||||
function testExpandXOF(hash, vectors) {
|
||||
describe(`${vectors.hash}/${vectors.DST.length}`, () => {
|
||||
for (let i = 0; i < vectors.tests.length; i++) {
|
||||
const t = vectors.tests[i];
|
||||
should(`${i}`, () => {
|
||||
const p = expand_message_xof(
|
||||
stringToBytes(t.msg),
|
||||
stringToBytes(vectors.DST),
|
||||
+t.len_in_bytes,
|
||||
vectors.k,
|
||||
hash
|
||||
);
|
||||
deepStrictEqual(bytesToHex(p), t.uniform_bytes);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
describe('expand_message_xof', () => {
|
||||
testExpandXOF(shake128, xof_shake128_36);
|
||||
testExpandXOF(shake128, xof_shake128_256);
|
||||
testExpandXOF(shake256, xof_shake256_36);
|
||||
});
|
||||
|
||||
function stringToFp(s) {
|
||||
// bls-G2 support
|
||||
if (s.includes(',')) {
|
||||
const [c0, c1] = s.split(',').map(BigInt);
|
||||
return { c0, c1 };
|
||||
}
|
||||
return BigInt(s);
|
||||
}
|
||||
|
||||
function testCurve(curve, ro, nu) {
|
||||
describe(`${ro.curve}/${ro.ciphersuite}`, () => {
|
||||
for (let i = 0; i < ro.vectors.length; i++) {
|
||||
const t = ro.vectors[i];
|
||||
should(`(${i})`, () => {
|
||||
const p = curve
|
||||
.hashToCurve(stringToBytes(t.msg), {
|
||||
DST: ro.dst,
|
||||
})
|
||||
.toAffine();
|
||||
deepStrictEqual(p.x, stringToFp(t.P.x), 'Px');
|
||||
deepStrictEqual(p.y, stringToFp(t.P.y), 'Py');
|
||||
});
|
||||
}
|
||||
});
|
||||
describe(`${nu.curve}/${nu.ciphersuite}`, () => {
|
||||
for (let i = 0; i < nu.vectors.length; i++) {
|
||||
const t = nu.vectors[i];
|
||||
should(`(${i})`, () => {
|
||||
const p = curve
|
||||
.encodeToCurve(stringToBytes(t.msg), {
|
||||
DST: nu.dst,
|
||||
})
|
||||
.toAffine();
|
||||
deepStrictEqual(p.x, stringToFp(t.P.x), 'Px');
|
||||
deepStrictEqual(p.y, stringToFp(t.P.y), 'Py');
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
testCurve(secp256r1, p256_ro, p256_nu);
|
||||
testCurve(secp384r1, p384_ro, p384_nu);
|
||||
testCurve(secp521r1, p521_ro, p521_nu);
|
||||
testCurve(bls12_381.hashToCurve.G1, g1_ro, g1_nu);
|
||||
testCurve(bls12_381.hashToCurve.G2, g2_ro, g2_nu);
|
||||
testCurve(secp256k1, secp256k1_ro, secp256k1_nu);
|
||||
testCurve(ed25519, ed25519_ro, ed25519_nu);
|
||||
testCurve(ed448, ed448_ro, ed448_nu);
|
||||
|
||||
// ESM is broken.
|
||||
import url from 'url';
|
||||
if (import.meta.url === url.pathToFileURL(process.argv[1]).href) {
|
||||
should.run();
|
||||
}
|
||||
90
test/hash-to-curve/BLS12381G1_XMD:SHA-256_SSWU_NU_.json
Normal file
90
test/hash-to-curve/BLS12381G1_XMD:SHA-256_SSWU_NU_.json
Normal file
@@ -0,0 +1,90 @@
|
||||
{
|
||||
"L": "0x40",
|
||||
"Z": "0xb",
|
||||
"ciphersuite": "BLS12381G1_XMD:SHA-256_SSWU_NU_",
|
||||
"curve": "BLS12-381 G1",
|
||||
"dst": "QUUX-V01-CS02-with-BLS12381G1_XMD:SHA-256_SSWU_NU_",
|
||||
"expand": "XMD",
|
||||
"field": {
|
||||
"m": "0x1",
|
||||
"p": "0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab"
|
||||
},
|
||||
"hash": "sha256",
|
||||
"k": "0x80",
|
||||
"map": {
|
||||
"name": "SSWU"
|
||||
},
|
||||
"randomOracle": false,
|
||||
"vectors": [
|
||||
{
|
||||
"P": {
|
||||
"x": "0x184bb665c37ff561a89ec2122dd343f20e0f4cbcaec84e3c3052ea81d1834e192c426074b02ed3dca4e7676ce4ce48ba",
|
||||
"y": "0x04407b8d35af4dacc809927071fc0405218f1401a6d15af775810e4e460064bcc9468beeba82fdc751be70476c888bf3"
|
||||
},
|
||||
"Q": {
|
||||
"x": "0x11398d3b324810a1b093f8e35aa8571cced95858207e7f49c4fd74656096d61d8a2f9a23cdb18a4dd11cd1d66f41f709",
|
||||
"y": "0x19316b6fb2ba7717355d5d66a361899057e1e84a6823039efc7beccefe09d023fb2713b1c415fcf278eb0c39a89b4f72"
|
||||
},
|
||||
"msg": "",
|
||||
"u": [
|
||||
"0x156c8a6a2c184569d69a76be144b5cdc5141d2d2ca4fe341f011e25e3969c55ad9e9b9ce2eb833c81a908e5fa4ac5f03"
|
||||
]
|
||||
},
|
||||
{
|
||||
"P": {
|
||||
"x": "0x009769f3ab59bfd551d53a5f846b9984c59b97d6842b20a2c565baa167945e3d026a3755b6345df8ec7e6acb6868ae6d",
|
||||
"y": "0x1532c00cf61aa3d0ce3e5aa20c3b531a2abd2c770a790a2613818303c6b830ffc0ecf6c357af3317b9575c567f11cd2c"
|
||||
},
|
||||
"Q": {
|
||||
"x": "0x1998321bc27ff6d71df3051b5aec12ff47363d81a5e9d2dff55f444f6ca7e7d6af45c56fd029c58237c266ef5cda5254",
|
||||
"y": "0x034d274476c6307ae584f951c82e7ea85b84f72d28f4d6471732356121af8d62a49bc263e8eb913a6cf6f125995514ee"
|
||||
},
|
||||
"msg": "abc",
|
||||
"u": [
|
||||
"0x147e1ed29f06e4c5079b9d14fc89d2820d32419b990c1c7bb7dbea2a36a045124b31ffbde7c99329c05c559af1c6cc82"
|
||||
]
|
||||
},
|
||||
{
|
||||
"P": {
|
||||
"x": "0x1974dbb8e6b5d20b84df7e625e2fbfecb2cdb5f77d5eae5fb2955e5ce7313cae8364bc2fff520a6c25619739c6bdcb6a",
|
||||
"y": "0x15f9897e11c6441eaa676de141c8d83c37aab8667173cbe1dfd6de74d11861b961dccebcd9d289ac633455dfcc7013a3"
|
||||
},
|
||||
"Q": {
|
||||
"x": "0x17d502fa43bd6a4cad2859049a0c3ecefd60240d129be65da271a4c03a9c38fa78163b9d2a919d2beb57df7d609b4919",
|
||||
"y": "0x109019902ae93a8732abecf2ff7fecd2e4e305eb91f41c9c3267f16b6c19de138c7272947f25512745da6c466cdfd1ac"
|
||||
},
|
||||
"msg": "abcdef0123456789",
|
||||
"u": [
|
||||
"0x04090815ad598a06897dd89bcda860f25837d54e897298ce31e6947378134d3761dc59a572154963e8c954919ecfa82d"
|
||||
]
|
||||
},
|
||||
{
|
||||
"P": {
|
||||
"x": "0x0a7a047c4a8397b3446450642c2ac64d7239b61872c9ae7a59707a8f4f950f101e766afe58223b3bff3a19a7f754027c",
|
||||
"y": "0x1383aebba1e4327ccff7cf9912bda0dbc77de048b71ef8c8a81111d71dc33c5e3aa6edee9cf6f5fe525d50cc50b77cc9"
|
||||
},
|
||||
"Q": {
|
||||
"x": "0x112eb92dd2b3aa9cd38b08de4bef603f2f9fb0ca226030626a9a2e47ad1e9847fe0a5ed13766c339e38f514bba143b21",
|
||||
"y": "0x17542ce2f8d0a54f2c5ba8c4b14e10b22d5bcd7bae2af3c965c8c872b571058c720eac448276c99967ded2bf124490e1"
|
||||
},
|
||||
"msg": "q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq",
|
||||
"u": [
|
||||
"0x08dccd088ca55b8bfbc96fb50bb25c592faa867a8bb78d4e94a8cc2c92306190244532e91feba2b7fed977e3c3bb5a1f"
|
||||
]
|
||||
},
|
||||
{
|
||||
"P": {
|
||||
"x": "0x0e7a16a975904f131682edbb03d9560d3e48214c9986bd50417a77108d13dc957500edf96462a3d01e62dc6cd468ef11",
|
||||
"y": "0x0ae89e677711d05c30a48d6d75e76ca9fb70fe06c6dd6ff988683d89ccde29ac7d46c53bb97a59b1901abf1db66052db"
|
||||
},
|
||||
"Q": {
|
||||
"x": "0x1775d400a1bacc1c39c355da7e96d2d1c97baa9430c4a3476881f8521c09a01f921f592607961efc99c4cd46bd78ca19",
|
||||
"y": "0x1109b5d59f65964315de65a7a143e86eabc053104ed289cf480949317a5685fad7254ff8e7fe6d24d3104e5d55ad6370"
|
||||
},
|
||||
"msg": "a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
||||
"u": [
|
||||
"0x0dd824886d2123a96447f6c56e3a3fa992fbfefdba17b6673f9f630ff19e4d326529db37e1c1be43f905bf9202e0278d"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
115
test/hash-to-curve/BLS12381G1_XMD:SHA-256_SSWU_RO_.json
Normal file
115
test/hash-to-curve/BLS12381G1_XMD:SHA-256_SSWU_RO_.json
Normal file
@@ -0,0 +1,115 @@
|
||||
{
|
||||
"L": "0x40",
|
||||
"Z": "0xb",
|
||||
"ciphersuite": "BLS12381G1_XMD:SHA-256_SSWU_RO_",
|
||||
"curve": "BLS12-381 G1",
|
||||
"dst": "QUUX-V01-CS02-with-BLS12381G1_XMD:SHA-256_SSWU_RO_",
|
||||
"expand": "XMD",
|
||||
"field": {
|
||||
"m": "0x1",
|
||||
"p": "0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab"
|
||||
},
|
||||
"hash": "sha256",
|
||||
"k": "0x80",
|
||||
"map": {
|
||||
"name": "SSWU"
|
||||
},
|
||||
"randomOracle": true,
|
||||
"vectors": [
|
||||
{
|
||||
"P": {
|
||||
"x": "0x052926add2207b76ca4fa57a8734416c8dc95e24501772c814278700eed6d1e4e8cf62d9c09db0fac349612b759e79a1",
|
||||
"y": "0x08ba738453bfed09cb546dbb0783dbb3a5f1f566ed67bb6be0e8c67e2e81a4cc68ee29813bb7994998f3eae0c9c6a265"
|
||||
},
|
||||
"Q0": {
|
||||
"x": "0x11a3cce7e1d90975990066b2f2643b9540fa40d6137780df4e753a8054d07580db3b7f1f03396333d4a359d1fe3766fe",
|
||||
"y": "0x0eeaf6d794e479e270da10fdaf768db4c96b650a74518fc67b04b03927754bac66f3ac720404f339ecdcc028afa091b7"
|
||||
},
|
||||
"Q1": {
|
||||
"x": "0x160003aaf1632b13396dbad518effa00fff532f604de1a7fc2082ff4cb0afa2d63b2c32da1bef2bf6c5ca62dc6b72f9c",
|
||||
"y": "0x0d8bb2d14e20cf9f6036152ed386d79189415b6d015a20133acb4e019139b94e9c146aaad5817f866c95d609a361735e"
|
||||
},
|
||||
"msg": "",
|
||||
"u": [
|
||||
"0x0ba14bd907ad64a016293ee7c2d276b8eae71f25a4b941eece7b0d89f17f75cb3ae5438a614fb61d6835ad59f29c564f",
|
||||
"0x019b9bd7979f12657976de2884c7cce192b82c177c80e0ec604436a7f538d231552f0d96d9f7babe5fa3b19b3ff25ac9"
|
||||
]
|
||||
},
|
||||
{
|
||||
"P": {
|
||||
"x": "0x03567bc5ef9c690c2ab2ecdf6a96ef1c139cc0b2f284dca0a9a7943388a49a3aee664ba5379a7655d3c68900be2f6903",
|
||||
"y": "0x0b9c15f3fe6e5cf4211f346271d7b01c8f3b28be689c8429c85b67af215533311f0b8dfaaa154fa6b88176c229f2885d"
|
||||
},
|
||||
"Q0": {
|
||||
"x": "0x125435adce8e1cbd1c803e7123f45392dc6e326d292499c2c45c5865985fd74fe8f042ecdeeec5ecac80680d04317d80",
|
||||
"y": "0x0e8828948c989126595ee30e4f7c931cbd6f4570735624fd25aef2fa41d3f79cfb4b4ee7b7e55a8ce013af2a5ba20bf2"
|
||||
},
|
||||
"Q1": {
|
||||
"x": "0x11def93719829ecda3b46aa8c31fc3ac9c34b428982b898369608e4f042babee6c77ab9218aad5c87ba785481eff8ae4",
|
||||
"y": "0x0007c9cef122ccf2efd233d6eb9bfc680aa276652b0661f4f820a653cec1db7ff69899f8e52b8e92b025a12c822a6ce6"
|
||||
},
|
||||
"msg": "abc",
|
||||
"u": [
|
||||
"0x0d921c33f2bad966478a03ca35d05719bdf92d347557ea166e5bba579eea9b83e9afa5c088573c2281410369fbd32951",
|
||||
"0x003574a00b109ada2f26a37a91f9d1e740dffd8d69ec0c35e1e9f4652c7dba61123e9dd2e76c655d956e2b3462611139"
|
||||
]
|
||||
},
|
||||
{
|
||||
"P": {
|
||||
"x": "0x11e0b079dea29a68f0383ee94fed1b940995272407e3bb916bbf268c263ddd57a6a27200a784cbc248e84f357ce82d98",
|
||||
"y": "0x03a87ae2caf14e8ee52e51fa2ed8eefe80f02457004ba4d486d6aa1f517c0889501dc7413753f9599b099ebcbbd2d709"
|
||||
},
|
||||
"Q0": {
|
||||
"x": "0x08834484878c217682f6d09a4b51444802fdba3d7f2df9903a0ddadb92130ebbfa807fffa0eabf257d7b48272410afff",
|
||||
"y": "0x0b318f7ecf77f45a0f038e62d7098221d2dbbca2a394164e2e3fe953dc714ac2cde412d8f2d7f0c03b259e6795a2508e"
|
||||
},
|
||||
"Q1": {
|
||||
"x": "0x158418ed6b27e2549f05531a8281b5822b31c3bf3144277fbb977f8d6e2694fedceb7011b3c2b192f23e2a44b2bd106e",
|
||||
"y": "0x1879074f344471fac5f839e2b4920789643c075792bec5af4282c73f7941cda5aa77b00085eb10e206171b9787c4169f"
|
||||
},
|
||||
"msg": "abcdef0123456789",
|
||||
"u": [
|
||||
"0x062d1865eb80ebfa73dcfc45db1ad4266b9f3a93219976a3790ab8d52d3e5f1e62f3b01795e36834b17b70e7b76246d4",
|
||||
"0x0cdc3e2f271f29c4ff75020857ce6c5d36008c9b48385ea2f2bf6f96f428a3deb798aa033cd482d1cdc8b30178b08e3a"
|
||||
]
|
||||
},
|
||||
{
|
||||
"P": {
|
||||
"x": "0x15f68eaa693b95ccb85215dc65fa81038d69629f70aeee0d0f677cf22285e7bf58d7cb86eefe8f2e9bc3f8cb84fac488",
|
||||
"y": "0x1807a1d50c29f430b8cafc4f8638dfeeadf51211e1602a5f184443076715f91bb90a48ba1e370edce6ae1062f5e6dd38"
|
||||
},
|
||||
"Q0": {
|
||||
"x": "0x0cbd7f84ad2c99643fea7a7ac8f52d63d66cefa06d9a56148e58b984b3dd25e1f41ff47154543343949c64f88d48a710",
|
||||
"y": "0x052c00e4ed52d000d94881a5638ae9274d3efc8bc77bc0e5c650de04a000b2c334a9e80b85282a00f3148dfdface0865"
|
||||
},
|
||||
"Q1": {
|
||||
"x": "0x06493fb68f0d513af08be0372f849436a787e7b701ae31cb964d968021d6ba6bd7d26a38aaa5a68e8c21a6b17dc8b579",
|
||||
"y": "0x02e98f2ccf5802b05ffaac7c20018bc0c0b2fd580216c4aa2275d2909dc0c92d0d0bdc979226adeb57a29933536b6bb4"
|
||||
},
|
||||
"msg": "q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq",
|
||||
"u": [
|
||||
"0x010476f6a060453c0b1ad0b628f3e57c23039ee16eea5e71bb87c3b5419b1255dc0e5883322e563b84a29543823c0e86",
|
||||
"0x0b1a912064fb0554b180e07af7e787f1f883a0470759c03c1b6509eb8ce980d1670305ae7b928226bb58fdc0a419f46e"
|
||||
]
|
||||
},
|
||||
{
|
||||
"P": {
|
||||
"x": "0x082aabae8b7dedb0e78aeb619ad3bfd9277a2f77ba7fad20ef6aabdc6c31d19ba5a6d12283553294c1825c4b3ca2dcfe",
|
||||
"y": "0x05b84ae5a942248eea39e1d91030458c40153f3b654ab7872d779ad1e942856a20c438e8d99bc8abfbf74729ce1f7ac8"
|
||||
},
|
||||
"Q0": {
|
||||
"x": "0x0cf97e6dbd0947857f3e578231d07b309c622ade08f2c08b32ff372bd90db19467b2563cc997d4407968d4ac80e154f8",
|
||||
"y": "0x127f0cddf2613058101a5701f4cb9d0861fd6c2a1b8e0afe194fccf586a3201a53874a2761a9ab6d7220c68661a35ab3"
|
||||
},
|
||||
"Q1": {
|
||||
"x": "0x092f1acfa62b05f95884c6791fba989bbe58044ee6355d100973bf9553ade52b47929264e6ae770fb264582d8dce512a",
|
||||
"y": "0x028e6d0169a72cfedb737be45db6c401d3adfb12c58c619c82b93a5dfcccef12290de530b0480575ddc8397cda0bbebf"
|
||||
},
|
||||
"msg": "a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
||||
"u": [
|
||||
"0x0a8ffa7447f6be1c5a2ea4b959c9454b431e29ccc0802bc052413a9c5b4f9aac67a93431bd480d15be1e057c8a08e8c6",
|
||||
"0x05d487032f602c90fa7625dbafe0f4a49ef4a6b0b33d7bb349ff4cf5410d297fd6241876e3e77b651cfc8191e40a68b7"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
90
test/hash-to-curve/BLS12381G2_XMD:SHA-256_SSWU_NU_.json
Normal file
90
test/hash-to-curve/BLS12381G2_XMD:SHA-256_SSWU_NU_.json
Normal file
@@ -0,0 +1,90 @@
|
||||
{
|
||||
"L": "0x40",
|
||||
"Z": "0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaa9,0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaaa",
|
||||
"ciphersuite": "BLS12381G2_XMD:SHA-256_SSWU_NU_",
|
||||
"curve": "BLS12-381 G2",
|
||||
"dst": "QUUX-V01-CS02-with-BLS12381G2_XMD:SHA-256_SSWU_NU_",
|
||||
"expand": "XMD",
|
||||
"field": {
|
||||
"m": "0x2",
|
||||
"p": "0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab"
|
||||
},
|
||||
"hash": "sha256",
|
||||
"k": "0x80",
|
||||
"map": {
|
||||
"name": "SSWU"
|
||||
},
|
||||
"randomOracle": false,
|
||||
"vectors": [
|
||||
{
|
||||
"P": {
|
||||
"x": "0x00e7f4568a82b4b7dc1f14c6aaa055edf51502319c723c4dc2688c7fe5944c213f510328082396515734b6612c4e7bb7,0x126b855e9e69b1f691f816e48ac6977664d24d99f8724868a184186469ddfd4617367e94527d4b74fc86413483afb35b",
|
||||
"y": "0x0caead0fd7b6176c01436833c79d305c78be307da5f6af6c133c47311def6ff1e0babf57a0fb5539fce7ee12407b0a42,0x1498aadcf7ae2b345243e281ae076df6de84455d766ab6fcdaad71fab60abb2e8b980a440043cd305db09d283c895e3d"
|
||||
},
|
||||
"Q": {
|
||||
"x": "0x18ed3794ad43c781816c523776188deafba67ab773189b8f18c49bc7aa841cd81525171f7a5203b2a340579192403bef,0x0727d90785d179e7b5732c8a34b660335fed03b913710b60903cf4954b651ed3466dc3728e21855ae822d4a0f1d06587",
|
||||
"y": "0x00764a5cf6c5f61c52c838523460eb2168b5a5b43705e19cb612e006f29b717897facfd15dd1c8874c915f6d53d0342d,0x19290bb9797c12c1d275817aa2605ebe42275b66860f0e4d04487ebc2e47c50b36edd86c685a60c20a2bd584a82b011a"
|
||||
},
|
||||
"msg": "",
|
||||
"u": [
|
||||
"0x07355d25caf6e7f2f0cb2812ca0e513bd026ed09dda65b177500fa31714e09ea0ded3a078b526bed3307f804d4b93b04,0x02829ce3c021339ccb5caf3e187f6370e1e2a311dec9b75363117063ab2015603ff52c3d3b98f19c2f65575e99e8b78c"
|
||||
]
|
||||
},
|
||||
{
|
||||
"P": {
|
||||
"x": "0x108ed59fd9fae381abfd1d6bce2fd2fa220990f0f837fa30e0f27914ed6e1454db0d1ee957b219f61da6ff8be0d6441f,0x0296238ea82c6d4adb3c838ee3cb2346049c90b96d602d7bb1b469b905c9228be25c627bffee872def773d5b2a2eb57d",
|
||||
"y": "0x033f90f6057aadacae7963b0a0b379dd46750c1c94a6357c99b65f63b79e321ff50fe3053330911c56b6ceea08fee656,0x153606c417e59fb331b7ae6bce4fbf7c5190c33ce9402b5ebe2b70e44fca614f3f1382a3625ed5493843d0b0a652fc3f"
|
||||
},
|
||||
"Q": {
|
||||
"x": "0x0f40e1d5025ecef0d850aa0bb7bbeceab21a3d4e85e6bee857805b09693051f5b25428c6be343edba5f14317fcc30143,0x02e0d261f2b9fee88b82804ec83db330caa75fbb12719cfa71ccce1c532dc4e1e79b0a6a281ed8d3817524286c8bc04c",
|
||||
"y": "0x0cf4a4adc5c66da0bca4caddc6a57ecd97c8252d7526a8ff478e0dfed816c4d321b5c3039c6683ae9b1e6a3a38c9c0ae,0x11cad1646bb3768c04be2ab2bbe1f80263b7ff6f8f9488f5bc3b6850e5a3e97e20acc583613c69cf3d2bfe8489744ebb"
|
||||
},
|
||||
"msg": "abc",
|
||||
"u": [
|
||||
"0x138879a9559e24cecee8697b8b4ad32cced053138ab913b99872772dc753a2967ed50aabc907937aefb2439ba06cc50c,0x0a1ae7999ea9bab1dcc9ef8887a6cb6e8f1e22566015428d220b7eec90ffa70ad1f624018a9ad11e78d588bd3617f9f2"
|
||||
]
|
||||
},
|
||||
{
|
||||
"P": {
|
||||
"x": "0x038af300ef34c7759a6caaa4e69363cafeed218a1f207e93b2c70d91a1263d375d6730bd6b6509dcac3ba5b567e85bf3,0x0da75be60fb6aa0e9e3143e40c42796edf15685cafe0279afd2a67c3dff1c82341f17effd402e4f1af240ea90f4b659b",
|
||||
"y": "0x19b148cbdf163cf0894f29660d2e7bfb2b68e37d54cc83fd4e6e62c020eaa48709302ef8e746736c0e19342cc1ce3df4,0x0492f4fed741b073e5a82580f7c663f9b79e036b70ab3e51162359cec4e77c78086fe879b65ca7a47d34374c8315ac5e"
|
||||
},
|
||||
"Q": {
|
||||
"x": "0x13a9d4a738a85c9f917c7be36b240915434b58679980010499b9ae8d7a1bf7fbe617a15b3cd6060093f40d18e0f19456,0x16fa88754e7670366a859d6f6899ad765bf5a177abedb2740aacc9252c43f90cd0421373fbd5b2b76bb8f5c4886b5d37",
|
||||
"y": "0x0a7fa7d82c46797039398253e8765a4194100b330dfed6d7fbb46d6fbf01e222088779ac336e3675c7a7a0ee05bbb6e3,0x0c6ee170ab766d11fa9457cef53253f2628010b2cffc102b3b28351eb9df6c281d3cfc78e9934769d661b72a5265338d"
|
||||
},
|
||||
"msg": "abcdef0123456789",
|
||||
"u": [
|
||||
"0x18c16fe362b7dbdfa102e42bdfd3e2f4e6191d479437a59db4eb716986bf08ee1f42634db66bde97d6c16bbfd342b3b8,0x0e37812ce1b146d998d5f92bdd5ada2a31bfd63dfe18311aa91637b5f279dd045763166aa1615e46a50d8d8f475f184e"
|
||||
]
|
||||
},
|
||||
{
|
||||
"P": {
|
||||
"x": "0x0c5ae723be00e6c3f0efe184fdc0702b64588fe77dda152ab13099a3bacd3876767fa7bbad6d6fd90b3642e902b208f9,0x12c8c05c1d5fc7bfa847f4d7d81e294e66b9a78bc9953990c358945e1f042eedafce608b67fdd3ab0cb2e6e263b9b1ad",
|
||||
"y": "0x04e77ddb3ede41b5ec4396b7421dd916efc68a358a0d7425bddd253547f2fb4830522358491827265dfc5bcc1928a569,0x11c624c56dbe154d759d021eec60fab3d8b852395a89de497e48504366feedd4662d023af447d66926a28076813dd646"
|
||||
},
|
||||
"Q": {
|
||||
"x": "0x0a08b2f639855dfdeaaed972702b109e2241a54de198b2b4cd12ad9f88fa419a6086a58d91fc805de812ea29bee427c2,0x04a7442e4cb8b42ef0f41dac9ee74e65ecad3ce0851f0746dc47568b0e7a8134121ed09ba054509232c49148aef62cda",
|
||||
"y": "0x05d60b1f04212b2c87607458f71d770f43973511c260f0540eef3a565f42c7ce59aa1cea684bb2a7bcab84acd2f36c8c,0x1017aa5747ba15505ece266a86b0ca9c712f41a254b76ca04094ca442ce45ecd224bd5544cd16685d0d1b9d156dd0531"
|
||||
},
|
||||
"msg": "q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq",
|
||||
"u": [
|
||||
"0x08d4a0997b9d52fecf99427abb721f0fa779479963315fe21c6445250de7183e3f63bfdf86570da8929489e421d4ee95,0x16cb4ccad91ec95aab070f22043916cd6a59c4ca94097f7f510043d48515526dc8eaaea27e586f09151ae613688d5a89"
|
||||
]
|
||||
},
|
||||
{
|
||||
"P": {
|
||||
"x": "0x0ea4e7c33d43e17cc516a72f76437c4bf81d8f4eac69ac355d3bf9b71b8138d55dc10fd458be115afa798b55dac34be1,0x1565c2f625032d232f13121d3cfb476f45275c303a037faa255f9da62000c2c864ea881e2bcddd111edc4a3c0da3e88d",
|
||||
"y": "0x043b6f5fe4e52c839148dc66f2b3751e69a0f6ebb3d056d6465d50d4108543ecd956e10fa1640dfd9bc0030cc2558d28,0x0f8991d2a1ad662e7b6f58ab787947f1fa607fce12dde171bc17903b012091b657e15333e11701edcf5b63ba2a561247"
|
||||
},
|
||||
"Q": {
|
||||
"x": "0x19592c812d5a50c5601062faba14c7d670711745311c879de1235a0a11c75aab61327bf2d1725db07ec4d6996a682886,0x0eef4fa41ddc17ed47baf447a2c498548f3c72a02381313d13bef916e240b61ce125539090d62d9fbb14a900bf1b8e90",
|
||||
"y": "0x1260d6e0987eae96af9ebe551e08de22b37791d53f4db9e0d59da736e66699735793e853e26362531fe4adf99c1883e3,0x0dbace5df0a4ac4ac2f45d8fdf8aee45484576fdd6efc4f98ab9b9f4112309e628255e183022d98ea5ed6e47ca00306c"
|
||||
},
|
||||
"msg": "a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
||||
"u": [
|
||||
"0x03f80ce4ff0ca2f576d797a3660e3f65b274285c054feccc3215c879e2c0589d376e83ede13f93c32f05da0f68fd6a10,0x006488a837c5413746d868d1efb7232724da10eca410b07d8b505b9363bdccf0a1fc0029bad07d65b15ccfe6dd25e20d"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
115
test/hash-to-curve/BLS12381G2_XMD:SHA-256_SSWU_RO_.json
Normal file
115
test/hash-to-curve/BLS12381G2_XMD:SHA-256_SSWU_RO_.json
Normal file
@@ -0,0 +1,115 @@
|
||||
{
|
||||
"L": "0x40",
|
||||
"Z": "0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaa9,0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaaa",
|
||||
"ciphersuite": "BLS12381G2_XMD:SHA-256_SSWU_RO_",
|
||||
"curve": "BLS12-381 G2",
|
||||
"dst": "QUUX-V01-CS02-with-BLS12381G2_XMD:SHA-256_SSWU_RO_",
|
||||
"expand": "XMD",
|
||||
"field": {
|
||||
"m": "0x2",
|
||||
"p": "0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab"
|
||||
},
|
||||
"hash": "sha256",
|
||||
"k": "0x80",
|
||||
"map": {
|
||||
"name": "SSWU"
|
||||
},
|
||||
"randomOracle": true,
|
||||
"vectors": [
|
||||
{
|
||||
"P": {
|
||||
"x": "0x0141ebfbdca40eb85b87142e130ab689c673cf60f1a3e98d69335266f30d9b8d4ac44c1038e9dcdd5393faf5c41fb78a,0x05cb8437535e20ecffaef7752baddf98034139c38452458baeefab379ba13dff5bf5dd71b72418717047f5b0f37da03d",
|
||||
"y": "0x0503921d7f6a12805e72940b963c0cf3471c7b2a524950ca195d11062ee75ec076daf2d4bc358c4b190c0c98064fdd92,0x12424ac32561493f3fe3c260708a12b7c620e7be00099a974e259ddc7d1f6395c3c811cdd19f1e8dbf3e9ecfdcbab8d6"
|
||||
},
|
||||
"Q0": {
|
||||
"x": "0x019ad3fc9c72425a998d7ab1ea0e646a1f6093444fc6965f1cad5a3195a7b1e099c050d57f45e3fa191cc6d75ed7458c,0x171c88b0b0efb5eb2b88913a9e74fe111a4f68867b59db252ce5868af4d1254bfab77ebde5d61cd1a86fb2fe4a5a1c1d",
|
||||
"y": "0x0ba10604e62bdd9eeeb4156652066167b72c8d743b050fb4c1016c31b505129374f76e03fa127d6a156213576910fef3,0x0eb22c7a543d3d376e9716a49b72e79a89c9bfe9feee8533ed931cbb5373dde1fbcd7411d8052e02693654f71e15410a"
|
||||
},
|
||||
"Q1": {
|
||||
"x": "0x113d2b9cd4bd98aee53470b27abc658d91b47a78a51584f3d4b950677cfb8a3e99c24222c406128c91296ef6b45608be,0x13855912321c5cb793e9d1e88f6f8d342d49c0b0dbac613ee9e17e3c0b3c97dfbb5a49cc3fb45102fdbaf65e0efe2632",
|
||||
"y": "0x0fd3def0b7574a1d801be44fde617162aa2e89da47f464317d9bb5abc3a7071763ce74180883ad7ad9a723a9afafcdca,0x056f617902b3c0d0f78a9a8cbda43a26b65f602f8786540b9469b060db7b38417915b413ca65f875c130bebfaa59790c"
|
||||
},
|
||||
"msg": "",
|
||||
"u": [
|
||||
"0x03dbc2cce174e91ba93cbb08f26b917f98194a2ea08d1cce75b2b9cc9f21689d80bd79b594a613d0a68eb807dfdc1cf8,0x05a2acec64114845711a54199ea339abd125ba38253b70a92c876df10598bd1986b739cad67961eb94f7076511b3b39a",
|
||||
"0x02f99798e8a5acdeed60d7e18e9120521ba1f47ec090984662846bc825de191b5b7641148c0dbc237726a334473eee94,0x145a81e418d4010cc027a68f14391b30074e89e60ee7a22f87217b2f6eb0c4b94c9115b436e6fa4607e95a98de30a435"
|
||||
]
|
||||
},
|
||||
{
|
||||
"P": {
|
||||
"x": "0x02c2d18e033b960562aae3cab37a27ce00d80ccd5ba4b7fe0e7a210245129dbec7780ccc7954725f4168aff2787776e6,0x139cddbccdc5e91b9623efd38c49f81a6f83f175e80b06fc374de9eb4b41dfe4ca3a230ed250fbe3a2acf73a41177fd8",
|
||||
"y": "0x1787327b68159716a37440985269cf584bcb1e621d3a7202be6ea05c4cfe244aeb197642555a0645fb87bf7466b2ba48,0x00aa65dae3c8d732d10ecd2c50f8a1baf3001578f71c694e03866e9f3d49ac1e1ce70dd94a733534f106d4cec0eddd16"
|
||||
},
|
||||
"Q0": {
|
||||
"x": "0x12b2e525281b5f4d2276954e84ac4f42cf4e13b6ac4228624e17760faf94ce5706d53f0ca1952f1c5ef75239aeed55ad,0x05d8a724db78e570e34100c0bc4a5fa84ad5839359b40398151f37cff5a51de945c563463c9efbdda569850ee5a53e77",
|
||||
"y": "0x02eacdc556d0bdb5d18d22f23dcb086dd106cad713777c7e6407943edbe0b3d1efe391eedf11e977fac55f9b94f2489c,0x04bbe48bfd5814648d0b9e30f0717b34015d45a861425fabc1ee06fdfce36384ae2c808185e693ae97dcde118f34de41"
|
||||
},
|
||||
"Q1": {
|
||||
"x": "0x19f18cc5ec0c2f055e47c802acc3b0e40c337256a208001dde14b25afced146f37ea3d3ce16834c78175b3ed61f3c537,0x15b0dadc256a258b4c68ea43605dffa6d312eef215c19e6474b3e101d33b661dfee43b51abbf96fee68fc6043ac56a58",
|
||||
"y": "0x05e47c1781286e61c7ade887512bd9c2cb9f640d3be9cf87ea0bad24bd0ebfe946497b48a581ab6c7d4ca74b5147287f,0x19f98db2f4a1fcdf56a9ced7b320ea9deecf57c8e59236b0dc21f6ee7229aa9705ce9ac7fe7a31c72edca0d92370c096"
|
||||
},
|
||||
"msg": "abc",
|
||||
"u": [
|
||||
"0x15f7c0aa8f6b296ab5ff9c2c7581ade64f4ee6f1bf18f55179ff44a2cf355fa53dd2a2158c5ecb17d7c52f63e7195771,0x01c8067bf4c0ba709aa8b9abc3d1cef589a4758e09ef53732d670fd8739a7274e111ba2fcaa71b3d33df2a3a0c8529dd",
|
||||
"0x187111d5e088b6b9acfdfad078c4dacf72dcd17ca17c82be35e79f8c372a693f60a033b461d81b025864a0ad051a06e4,0x08b852331c96ed983e497ebc6dee9b75e373d923b729194af8e72a051ea586f3538a6ebb1e80881a082fa2b24df9f566"
|
||||
]
|
||||
},
|
||||
{
|
||||
"P": {
|
||||
"x": "0x121982811d2491fde9ba7ed31ef9ca474f0e1501297f68c298e9f4c0028add35aea8bb83d53c08cfc007c1e005723cd0,0x190d119345b94fbd15497bcba94ecf7db2cbfd1e1fe7da034d26cbba169fb3968288b3fafb265f9ebd380512a71c3f2c",
|
||||
"y": "0x05571a0f8d3c08d094576981f4a3b8eda0a8e771fcdcc8ecceaf1356a6acf17574518acb506e435b639353c2e14827c8,0x0bb5e7572275c567462d91807de765611490205a941a5a6af3b1691bfe596c31225d3aabdf15faff860cb4ef17c7c3be"
|
||||
},
|
||||
"Q0": {
|
||||
"x": "0x0f48f1ea1318ddb713697708f7327781fb39718971d72a9245b9731faaca4dbaa7cca433d6c434a820c28b18e20ea208,0x06051467c8f85da5ba2540974758f7a1e0239a5981de441fdd87680a995649c211054869c50edbac1f3a86c561ba3162",
|
||||
"y": "0x168b3d6df80069dbbedb714d41b32961ad064c227355e1ce5fac8e105de5e49d77f0c64867f3834848f152497eb76333,0x134e0e8331cee8cb12f9c2d0742714ed9eee78a84d634c9a95f6a7391b37125ed48bfc6e90bf3546e99930ff67cc97bc"
|
||||
},
|
||||
"Q1": {
|
||||
"x": "0x004fd03968cd1c99a0dd84551f44c206c84dcbdb78076c5bfee24e89a92c8508b52b88b68a92258403cbe1ea2da3495f,0x1674338ea298281b636b2eb0fe593008d03171195fd6dcd4531e8a1ed1f02a72da238a17a635de307d7d24aa2d969a47",
|
||||
"y": "0x0dc7fa13fff6b12558419e0a1e94bfc3cfaf67238009991c5f24ee94b632c3d09e27eca329989aee348a67b50d5e236c,0x169585e164c131103d85324f2d7747b23b91d66ae5d947c449c8194a347969fc6bbd967729768da485ba71868df8aed2"
|
||||
},
|
||||
"msg": "abcdef0123456789",
|
||||
"u": [
|
||||
"0x0313d9325081b415bfd4e5364efaef392ecf69b087496973b229303e1816d2080971470f7da112c4eb43053130b785e1,0x062f84cb21ed89406890c051a0e8b9cf6c575cf6e8e18ecf63ba86826b0ae02548d83b483b79e48512b82a6c0686df8f",
|
||||
"0x1739123845406baa7be5c5dc74492051b6d42504de008c635f3535bb831d478a341420e67dcc7b46b2e8cba5379cca97,0x01897665d9cb5db16a27657760bbea7951f67ad68f8d55f7113f24ba6ddd82caef240a9bfa627972279974894701d975"
|
||||
]
|
||||
},
|
||||
{
|
||||
"P": {
|
||||
"x": "0x19a84dd7248a1066f737cc34502ee5555bd3c19f2ecdb3c7d9e24dc65d4e25e50d83f0f77105e955d78f4762d33c17da,0x0934aba516a52d8ae479939a91998299c76d39cc0c035cd18813bec433f587e2d7a4fef038260eef0cef4d02aae3eb91",
|
||||
"y": "0x14f81cd421617428bc3b9fe25afbb751d934a00493524bc4e065635b0555084dd54679df1536101b2c979c0152d09192,0x09bcccfa036b4847c9950780733633f13619994394c23ff0b32fa6b795844f4a0673e20282d07bc69641cee04f5e5662"
|
||||
},
|
||||
"Q0": {
|
||||
"x": "0x09eccbc53df677f0e5814e3f86e41e146422834854a224bf5a83a50e4cc0a77bfc56718e8166ad180f53526ea9194b57,0x0c3633943f91daee715277bd644fba585168a72f96ded64fc5a384cce4ec884a4c3c30f08e09cd2129335dc8f67840ec",
|
||||
"y": "0x0eb6186a0457d5b12d132902d4468bfeb7315d83320b6c32f1c875f344efcba979952b4aa418589cb01af712f98cc555,0x119e3cf167e69eb16c1c7830e8df88856d48be12e3ff0a40791a5cd2f7221311d4bf13b1847f371f467357b3f3c0b4c7"
|
||||
},
|
||||
"Q1": {
|
||||
"x": "0x0eb3aabc1ddfce17ff18455fcc7167d15ce6b60ddc9eb9b59f8d40ab49420d35558686293d046fc1e42f864b7f60e381,0x198bdfb19d7441ebcca61e8ff774b29d17da16547d2c10c273227a635cacea3f16826322ae85717630f0867539b5ed8b",
|
||||
"y": "0x0aaf1dee3adf3ed4c80e481c09b57ea4c705e1b8d25b897f0ceeec3990748716575f92abff22a1c8f4582aff7b872d52,0x0d058d9061ed27d4259848a06c96c5ca68921a5d269b078650c882cb3c2bd424a8702b7a6ee4e0ead9982baf6843e924"
|
||||
},
|
||||
"msg": "q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq",
|
||||
"u": [
|
||||
"0x025820cefc7d06fd38de7d8e370e0da8a52498be9b53cba9927b2ef5c6de1e12e12f188bbc7bc923864883c57e49e253,0x034147b77ce337a52e5948f66db0bab47a8d038e712123bb381899b6ab5ad20f02805601e6104c29df18c254b8618c7b",
|
||||
"0x0930315cae1f9a6017c3f0c8f2314baa130e1cf13f6532bff0a8a1790cd70af918088c3db94bda214e896e1543629795,0x10c4df2cacf67ea3cb3108b00d4cbd0b3968031ebc8eac4b1ebcefe84d6b715fde66bef0219951ece29d1facc8a520ef"
|
||||
]
|
||||
},
|
||||
{
|
||||
"P": {
|
||||
"x": "0x01a6ba2f9a11fa5598b2d8ace0fbe0a0eacb65deceb476fbbcb64fd24557c2f4b18ecfc5663e54ae16a84f5ab7f62534,0x11fca2ff525572795a801eed17eb12785887c7b63fb77a42be46ce4a34131d71f7a73e95fee3f812aea3de78b4d01569",
|
||||
"y": "0x0b6798718c8aed24bc19cb27f866f1c9effcdbf92397ad6448b5c9db90d2b9da6cbabf48adc1adf59a1a28344e79d57e,0x03a47f8e6d1763ba0cad63d6114c0accbef65707825a511b251a660a9b3994249ae4e63fac38b23da0c398689ee2ab52"
|
||||
},
|
||||
"Q0": {
|
||||
"x": "0x17cadf8d04a1a170f8347d42856526a24cc466cb2ddfd506cff01191666b7f944e31244d662c904de5440516a2b09004,0x0d13ba91f2a8b0051cf3279ea0ee63a9f19bc9cb8bfcc7d78b3cbd8cc4fc43ba726774b28038213acf2b0095391c523e",
|
||||
"y": "0x17ef19497d6d9246fa94d35575c0f8d06ee02f21a284dbeaa78768cb1e25abd564e3381de87bda26acd04f41181610c5,0x12c3c913ba4ed03c24f0721a81a6be7430f2971ffca8fd1729aafe496bb725807531b44b34b59b3ae5495e5a2dcbd5c8"
|
||||
},
|
||||
"Q1": {
|
||||
"x": "0x16ec57b7fe04c71dfe34fb5ad84dbce5a2dbbd6ee085f1d8cd17f45e8868976fc3c51ad9eeda682c7869024d24579bfd,0x13103f7aace1ae1420d208a537f7d3a9679c287208026e4e3439ab8cd534c12856284d95e27f5e1f33eec2ce656533b0",
|
||||
"y": "0x0958b2c4c2c10fcef5a6c59b9e92c4a67b0fae3e2e0f1b6b5edad9c940b8f3524ba9ebbc3f2ceb3cfe377655b3163bd7,0x0ccb594ed8bd14ca64ed9cb4e0aba221be540f25dd0d6ba15a4a4be5d67bcf35df7853b2d8dad3ba245f1ea3697f66aa"
|
||||
},
|
||||
"msg": "a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
||||
"u": [
|
||||
"0x190b513da3e66fc9a3587b78c76d1d132b1152174d0b83e3c1114066392579a45824c5fa17649ab89299ddd4bda54935,0x12ab625b0fe0ebd1367fe9fac57bb1168891846039b4216b9d94007b674de2d79126870e88aeef54b2ec717a887dcf39",
|
||||
"0x0e6a42010cf435fb5bacc156a585e1ea3294cc81d0ceb81924d95040298380b164f702275892cedd81b62de3aba3f6b5,0x117d9a0defc57a33ed208428cb84e54c85a6840e7648480ae428838989d25d97a0af8e3255be62b25c2a85630d2dddd8"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
90
test/hash-to-curve/P256_XMD:SHA-256_SSWU_NU_.json
Normal file
90
test/hash-to-curve/P256_XMD:SHA-256_SSWU_NU_.json
Normal file
@@ -0,0 +1,90 @@
|
||||
{
|
||||
"L": "0x30",
|
||||
"Z": "0xffffffff00000001000000000000000000000000fffffffffffffffffffffff5",
|
||||
"ciphersuite": "P256_XMD:SHA-256_SSWU_NU_",
|
||||
"curve": "NIST P-256",
|
||||
"dst": "QUUX-V01-CS02-with-P256_XMD:SHA-256_SSWU_NU_",
|
||||
"expand": "XMD",
|
||||
"field": {
|
||||
"m": "0x1",
|
||||
"p": "0xffffffff00000001000000000000000000000000ffffffffffffffffffffffff"
|
||||
},
|
||||
"hash": "sha256",
|
||||
"k": "0x80",
|
||||
"map": {
|
||||
"name": "SSWU"
|
||||
},
|
||||
"randomOracle": false,
|
||||
"vectors": [
|
||||
{
|
||||
"P": {
|
||||
"x": "0xf871caad25ea3b59c16cf87c1894902f7e7b2c822c3d3f73596c5ace8ddd14d1",
|
||||
"y": "0x87b9ae23335bee057b99bac1e68588b18b5691af476234b8971bc4f011ddc99b"
|
||||
},
|
||||
"Q": {
|
||||
"x": "0xf871caad25ea3b59c16cf87c1894902f7e7b2c822c3d3f73596c5ace8ddd14d1",
|
||||
"y": "0x87b9ae23335bee057b99bac1e68588b18b5691af476234b8971bc4f011ddc99b"
|
||||
},
|
||||
"msg": "",
|
||||
"u": [
|
||||
"0xb22d487045f80e9edcb0ecc8d4bf77833e2bf1f3a54004d7df1d57f4802d311f"
|
||||
]
|
||||
},
|
||||
{
|
||||
"P": {
|
||||
"x": "0xfc3f5d734e8dce41ddac49f47dd2b8a57257522a865c124ed02b92b5237befa4",
|
||||
"y": "0xfe4d197ecf5a62645b9690599e1d80e82c500b22ac705a0b421fac7b47157866"
|
||||
},
|
||||
"Q": {
|
||||
"x": "0xfc3f5d734e8dce41ddac49f47dd2b8a57257522a865c124ed02b92b5237befa4",
|
||||
"y": "0xfe4d197ecf5a62645b9690599e1d80e82c500b22ac705a0b421fac7b47157866"
|
||||
},
|
||||
"msg": "abc",
|
||||
"u": [
|
||||
"0xc7f96eadac763e176629b09ed0c11992225b3a5ae99479760601cbd69c221e58"
|
||||
]
|
||||
},
|
||||
{
|
||||
"P": {
|
||||
"x": "0xf164c6674a02207e414c257ce759d35eddc7f55be6d7f415e2cc177e5d8faa84",
|
||||
"y": "0x3aa274881d30db70485368c0467e97da0e73c18c1d00f34775d012b6fcee7f97"
|
||||
},
|
||||
"Q": {
|
||||
"x": "0xf164c6674a02207e414c257ce759d35eddc7f55be6d7f415e2cc177e5d8faa84",
|
||||
"y": "0x3aa274881d30db70485368c0467e97da0e73c18c1d00f34775d012b6fcee7f97"
|
||||
},
|
||||
"msg": "abcdef0123456789",
|
||||
"u": [
|
||||
"0x314e8585fa92068b3ea2c3bab452d4257b38be1c097d58a21890456c2929614d"
|
||||
]
|
||||
},
|
||||
{
|
||||
"P": {
|
||||
"x": "0x324532006312be4f162614076460315f7a54a6f85544da773dc659aca0311853",
|
||||
"y": "0x8d8197374bcd52de2acfefc8a54fe2c8d8bebd2a39f16be9b710e4b1af6ef883"
|
||||
},
|
||||
"Q": {
|
||||
"x": "0x324532006312be4f162614076460315f7a54a6f85544da773dc659aca0311853",
|
||||
"y": "0x8d8197374bcd52de2acfefc8a54fe2c8d8bebd2a39f16be9b710e4b1af6ef883"
|
||||
},
|
||||
"msg": "q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq",
|
||||
"u": [
|
||||
"0x752d8eaa38cd785a799a31d63d99c2ae4261823b4a367b133b2c6627f48858ab"
|
||||
]
|
||||
},
|
||||
{
|
||||
"P": {
|
||||
"x": "0x5c4bad52f81f39c8e8de1260e9a06d72b8b00a0829a8ea004a610b0691bea5d9",
|
||||
"y": "0xc801e7c0782af1f74f24fc385a8555da0582032a3ce038de637ccdcb16f7ef7b"
|
||||
},
|
||||
"Q": {
|
||||
"x": "0x5c4bad52f81f39c8e8de1260e9a06d72b8b00a0829a8ea004a610b0691bea5d9",
|
||||
"y": "0xc801e7c0782af1f74f24fc385a8555da0582032a3ce038de637ccdcb16f7ef7b"
|
||||
},
|
||||
"msg": "a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
||||
"u": [
|
||||
"0x0e1527840b9df2dfbef966678ff167140f2b27c4dccd884c25014dce0e41dfa3"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
115
test/hash-to-curve/P256_XMD:SHA-256_SSWU_RO_.json
Normal file
115
test/hash-to-curve/P256_XMD:SHA-256_SSWU_RO_.json
Normal file
@@ -0,0 +1,115 @@
|
||||
{
|
||||
"L": "0x30",
|
||||
"Z": "0xffffffff00000001000000000000000000000000fffffffffffffffffffffff5",
|
||||
"ciphersuite": "P256_XMD:SHA-256_SSWU_RO_",
|
||||
"curve": "NIST P-256",
|
||||
"dst": "QUUX-V01-CS02-with-P256_XMD:SHA-256_SSWU_RO_",
|
||||
"expand": "XMD",
|
||||
"field": {
|
||||
"m": "0x1",
|
||||
"p": "0xffffffff00000001000000000000000000000000ffffffffffffffffffffffff"
|
||||
},
|
||||
"hash": "sha256",
|
||||
"k": "0x80",
|
||||
"map": {
|
||||
"name": "SSWU"
|
||||
},
|
||||
"randomOracle": true,
|
||||
"vectors": [
|
||||
{
|
||||
"P": {
|
||||
"x": "0x2c15230b26dbc6fc9a37051158c95b79656e17a1a920b11394ca91c44247d3e4",
|
||||
"y": "0x8a7a74985cc5c776cdfe4b1f19884970453912e9d31528c060be9ab5c43e8415"
|
||||
},
|
||||
"Q0": {
|
||||
"x": "0xab640a12220d3ff283510ff3f4b1953d09fad35795140b1c5d64f313967934d5",
|
||||
"y": "0xdccb558863804a881d4fff3455716c836cef230e5209594ddd33d85c565b19b1"
|
||||
},
|
||||
"Q1": {
|
||||
"x": "0x51cce63c50d972a6e51c61334f0f4875c9ac1cd2d3238412f84e31da7d980ef5",
|
||||
"y": "0xb45d1a36d00ad90e5ec7840a60a4de411917fbe7c82c3949a6e699e5a1b66aac"
|
||||
},
|
||||
"msg": "",
|
||||
"u": [
|
||||
"0xad5342c66a6dd0ff080df1da0ea1c04b96e0330dd89406465eeba11582515009",
|
||||
"0x8c0f1d43204bd6f6ea70ae8013070a1518b43873bcd850aafa0a9e220e2eea5a"
|
||||
]
|
||||
},
|
||||
{
|
||||
"P": {
|
||||
"x": "0x0bb8b87485551aa43ed54f009230450b492fead5f1cc91658775dac4a3388a0f",
|
||||
"y": "0x5c41b3d0731a27a7b14bc0bf0ccded2d8751f83493404c84a88e71ffd424212e"
|
||||
},
|
||||
"Q0": {
|
||||
"x": "0x5219ad0ddef3cc49b714145e91b2f7de6ce0a7a7dc7406c7726c7e373c58cb48",
|
||||
"y": "0x7950144e52d30acbec7b624c203b1996c99617d0b61c2442354301b191d93ecf"
|
||||
},
|
||||
"Q1": {
|
||||
"x": "0x019b7cb4efcfeaf39f738fe638e31d375ad6837f58a852d032ff60c69ee3875f",
|
||||
"y": "0x589a62d2b22357fed5449bc38065b760095ebe6aeac84b01156ee4252715446e"
|
||||
},
|
||||
"msg": "abc",
|
||||
"u": [
|
||||
"0xafe47f2ea2b10465cc26ac403194dfb68b7f5ee865cda61e9f3e07a537220af1",
|
||||
"0x379a27833b0bfe6f7bdca08e1e83c760bf9a338ab335542704edcd69ce9e46e0"
|
||||
]
|
||||
},
|
||||
{
|
||||
"P": {
|
||||
"x": "0x65038ac8f2b1def042a5df0b33b1f4eca6bff7cb0f9c6c1526811864e544ed80",
|
||||
"y": "0xcad44d40a656e7aff4002a8de287abc8ae0482b5ae825822bb870d6df9b56ca3"
|
||||
},
|
||||
"Q0": {
|
||||
"x": "0xa17bdf2965eb88074bc01157e644ed409dac97cfcf0c61c998ed0fa45e79e4a2",
|
||||
"y": "0x4f1bc80c70d411a3cc1d67aeae6e726f0f311639fee560c7f5a664554e3c9c2e"
|
||||
},
|
||||
"Q1": {
|
||||
"x": "0x7da48bb67225c1a17d452c983798113f47e438e4202219dd0715f8419b274d66",
|
||||
"y": "0xb765696b2913e36db3016c47edb99e24b1da30e761a8a3215dc0ec4d8f96e6f9"
|
||||
},
|
||||
"msg": "abcdef0123456789",
|
||||
"u": [
|
||||
"0x0fad9d125a9477d55cf9357105b0eb3a5c4259809bf87180aa01d651f53d312c",
|
||||
"0xb68597377392cd3419d8fcc7d7660948c8403b19ea78bbca4b133c9d2196c0fb"
|
||||
]
|
||||
},
|
||||
{
|
||||
"P": {
|
||||
"x": "0x4be61ee205094282ba8a2042bcb48d88dfbb609301c49aa8b078533dc65a0b5d",
|
||||
"y": "0x98f8df449a072c4721d241a3b1236d3caccba603f916ca680f4539d2bfb3c29e"
|
||||
},
|
||||
"Q0": {
|
||||
"x": "0xc76aaa823aeadeb3f356909cb08f97eee46ecb157c1f56699b5efebddf0e6398",
|
||||
"y": "0x776a6f45f528a0e8d289a4be12c4fab80762386ec644abf2bffb9b627e4352b1"
|
||||
},
|
||||
"Q1": {
|
||||
"x": "0x418ac3d85a5ccc4ea8dec14f750a3a9ec8b85176c95a7022f391826794eb5a75",
|
||||
"y": "0xfd6604f69e9d9d2b74b072d14ea13050db72c932815523305cb9e807cc900aff"
|
||||
},
|
||||
"msg": "q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq",
|
||||
"u": [
|
||||
"0x3bbc30446f39a7befad080f4d5f32ed116b9534626993d2cc5033f6f8d805919",
|
||||
"0x76bb02db019ca9d3c1e02f0c17f8baf617bbdae5c393a81d9ce11e3be1bf1d33"
|
||||
]
|
||||
},
|
||||
{
|
||||
"P": {
|
||||
"x": "0x457ae2981f70ca85d8e24c308b14db22f3e3862c5ea0f652ca38b5e49cd64bc5",
|
||||
"y": "0xecb9f0eadc9aeed232dabc53235368c1394c78de05dd96893eefa62b0f4757dc"
|
||||
},
|
||||
"Q0": {
|
||||
"x": "0xd88b989ee9d1295df413d4456c5c850b8b2fb0f5402cc5c4c7e815412e926db8",
|
||||
"y": "0xbb4a1edeff506cf16def96afff41b16fc74f6dbd55c2210e5b8f011ba32f4f40"
|
||||
},
|
||||
"Q1": {
|
||||
"x": "0xa281e34e628f3a4d2a53fa87ff973537d68ad4fbc28d3be5e8d9f6a2571c5a4b",
|
||||
"y": "0xf6ed88a7aab56a488100e6f1174fa9810b47db13e86be999644922961206e184"
|
||||
},
|
||||
"msg": "a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
||||
"u": [
|
||||
"0x4ebc95a6e839b1ae3c63b847798e85cb3c12d3817ec6ebc10af6ee51adb29fec",
|
||||
"0x4e21af88e22ea80156aff790750121035b3eefaa96b425a8716e0d20b4e269ee"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
90
test/hash-to-curve/P384_XMD:SHA-384_SSWU_NU_.json
Normal file
90
test/hash-to-curve/P384_XMD:SHA-384_SSWU_NU_.json
Normal file
@@ -0,0 +1,90 @@
|
||||
{
|
||||
"L": "0x48",
|
||||
"Z": "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000fffffff3",
|
||||
"ciphersuite": "P384_XMD:SHA-384_SSWU_NU_",
|
||||
"curve": "NIST P-384",
|
||||
"dst": "QUUX-V01-CS02-with-P384_XMD:SHA-384_SSWU_NU_",
|
||||
"expand": "XMD",
|
||||
"field": {
|
||||
"m": "0x1",
|
||||
"p": "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000ffffffff"
|
||||
},
|
||||
"hash": "sha384",
|
||||
"k": "0xc0",
|
||||
"map": {
|
||||
"name": "SSWU"
|
||||
},
|
||||
"randomOracle": false,
|
||||
"vectors": [
|
||||
{
|
||||
"P": {
|
||||
"x": "0xde5a893c83061b2d7ce6a0d8b049f0326f2ada4b966dc7e72927256b033ef61058029a3bfb13c1c7ececd6641881ae20",
|
||||
"y": "0x63f46da6139785674da315c1947e06e9a0867f5608cf24724eb3793a1f5b3809ee28eb21a0c64be3be169afc6cdb38ca"
|
||||
},
|
||||
"Q": {
|
||||
"x": "0xde5a893c83061b2d7ce6a0d8b049f0326f2ada4b966dc7e72927256b033ef61058029a3bfb13c1c7ececd6641881ae20",
|
||||
"y": "0x63f46da6139785674da315c1947e06e9a0867f5608cf24724eb3793a1f5b3809ee28eb21a0c64be3be169afc6cdb38ca"
|
||||
},
|
||||
"msg": "",
|
||||
"u": [
|
||||
"0xbc7dc1b2cdc5d588a66de3276b0f24310d4aca4977efda7d6272e1be25187b001493d267dc53b56183c9e28282368e60"
|
||||
]
|
||||
},
|
||||
{
|
||||
"P": {
|
||||
"x": "0x1f08108b87e703c86c872ab3eb198a19f2b708237ac4be53d7929fb4bd5194583f40d052f32df66afe5249c9915d139b",
|
||||
"y": "0x1369dc8d5bf038032336b989994874a2270adadb67a7fcc32f0f8824bc5118613f0ac8de04a1041d90ff8a5ad555f96c"
|
||||
},
|
||||
"Q": {
|
||||
"x": "0x1f08108b87e703c86c872ab3eb198a19f2b708237ac4be53d7929fb4bd5194583f40d052f32df66afe5249c9915d139b",
|
||||
"y": "0x1369dc8d5bf038032336b989994874a2270adadb67a7fcc32f0f8824bc5118613f0ac8de04a1041d90ff8a5ad555f96c"
|
||||
},
|
||||
"msg": "abc",
|
||||
"u": [
|
||||
"0x9de6cf41e6e41c03e4a7784ac5c885b4d1e49d6de390b3cdd5a1ac5dd8c40afb3dfd7bb2686923bab644134483fc1926"
|
||||
]
|
||||
},
|
||||
{
|
||||
"P": {
|
||||
"x": "0x4dac31ec8a82ee3c02ba2d7c9fa431f1e59ffe65bf977b948c59e1d813c2d7963c7be81aa6db39e78ff315a10115c0d0",
|
||||
"y": "0x845333cdb5702ad5c525e603f302904d6fc84879f0ef2ee2014a6b13edd39131bfd66f7bd7cdc2d9ccf778f0c8892c3f"
|
||||
},
|
||||
"Q": {
|
||||
"x": "0x4dac31ec8a82ee3c02ba2d7c9fa431f1e59ffe65bf977b948c59e1d813c2d7963c7be81aa6db39e78ff315a10115c0d0",
|
||||
"y": "0x845333cdb5702ad5c525e603f302904d6fc84879f0ef2ee2014a6b13edd39131bfd66f7bd7cdc2d9ccf778f0c8892c3f"
|
||||
},
|
||||
"msg": "abcdef0123456789",
|
||||
"u": [
|
||||
"0x84e2d430a5e2543573e58e368af41821ca3ccc97baba7e9aab51a84543d5a0298638a22ceee6090d9d642921112af5b7"
|
||||
]
|
||||
},
|
||||
{
|
||||
"P": {
|
||||
"x": "0x13c1f8c52a492183f7c28e379b0475486718a7e3ac1dfef39283b9ce5fb02b73f70c6c1f3dfe0c286b03e2af1af12d1d",
|
||||
"y": "0x57e101887e73e40eab8963324ed16c177d55eb89f804ec9df06801579820420b5546b579008df2145fd770f584a1a54c"
|
||||
},
|
||||
"Q": {
|
||||
"x": "0x13c1f8c52a492183f7c28e379b0475486718a7e3ac1dfef39283b9ce5fb02b73f70c6c1f3dfe0c286b03e2af1af12d1d",
|
||||
"y": "0x57e101887e73e40eab8963324ed16c177d55eb89f804ec9df06801579820420b5546b579008df2145fd770f584a1a54c"
|
||||
},
|
||||
"msg": "q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq",
|
||||
"u": [
|
||||
"0x504e4d5a529333b9205acaa283107bd1bffde753898f7744161f7dd19ba57fbb6a64214a2e00ddd2613d76cd508ddb30"
|
||||
]
|
||||
},
|
||||
{
|
||||
"P": {
|
||||
"x": "0xaf129727a4207a8cb9e9dce656d88f79fce25edbcea350499d65e9bf1204537bdde73c7cefb752a6ed5ebcd44e183302",
|
||||
"y": "0xce68a3d5e161b2e6a968e4ddaa9e51504ad1516ec170c7eef3ca6b5327943eca95d90b23b009ba45f58b72906f2a99e2"
|
||||
},
|
||||
"Q": {
|
||||
"x": "0xaf129727a4207a8cb9e9dce656d88f79fce25edbcea350499d65e9bf1204537bdde73c7cefb752a6ed5ebcd44e183302",
|
||||
"y": "0xce68a3d5e161b2e6a968e4ddaa9e51504ad1516ec170c7eef3ca6b5327943eca95d90b23b009ba45f58b72906f2a99e2"
|
||||
},
|
||||
"msg": "a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
||||
"u": [
|
||||
"0x7b01ce9b8c5a60d9fbc202d6dde92822e46915d8c17e03fcb92ece1ed6074d01e149fc9236def40d673de903c1d4c166"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
115
test/hash-to-curve/P384_XMD:SHA-384_SSWU_RO_.json
Normal file
115
test/hash-to-curve/P384_XMD:SHA-384_SSWU_RO_.json
Normal file
@@ -0,0 +1,115 @@
|
||||
{
|
||||
"L": "0x48",
|
||||
"Z": "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000fffffff3",
|
||||
"ciphersuite": "P384_XMD:SHA-384_SSWU_RO_",
|
||||
"curve": "NIST P-384",
|
||||
"dst": "QUUX-V01-CS02-with-P384_XMD:SHA-384_SSWU_RO_",
|
||||
"expand": "XMD",
|
||||
"field": {
|
||||
"m": "0x1",
|
||||
"p": "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000ffffffff"
|
||||
},
|
||||
"hash": "sha384",
|
||||
"k": "0xc0",
|
||||
"map": {
|
||||
"name": "SSWU"
|
||||
},
|
||||
"randomOracle": true,
|
||||
"vectors": [
|
||||
{
|
||||
"P": {
|
||||
"x": "0xeb9fe1b4f4e14e7140803c1d99d0a93cd823d2b024040f9c067a8eca1f5a2eeac9ad604973527a356f3fa3aeff0e4d83",
|
||||
"y": "0x0c21708cff382b7f4643c07b105c2eaec2cead93a917d825601e63c8f21f6abd9abc22c93c2bed6f235954b25048bb1a"
|
||||
},
|
||||
"Q0": {
|
||||
"x": "0xe4717e29eef38d862bee4902a7d21b44efb58c464e3e1f0d03894d94de310f8ffc6de86786dd3e15a1541b18d4eb2846",
|
||||
"y": "0x6b95a6e639822312298a47526bb77d9cd7bcf76244c991c8cd70075e2ee6e8b9a135c4a37e3c0768c7ca871c0ceb53d4"
|
||||
},
|
||||
"Q1": {
|
||||
"x": "0x509527cfc0750eedc53147e6d5f78596c8a3b7360e0608e2fab0563a1670d58d8ae107c9f04bcf90e89489ace5650efd",
|
||||
"y": "0x33337b13cb35e173fdea4cb9e8cce915d836ff57803dbbeb7998aa49d17df2ff09b67031773039d09fbd9305a1566bc4"
|
||||
},
|
||||
"msg": "",
|
||||
"u": [
|
||||
"0x25c8d7dc1acd4ee617766693f7f8829396065d1b447eedb155871feffd9c6653279ac7e5c46edb7010a0e4ff64c9f3b4",
|
||||
"0x59428be4ed69131df59a0c6a8e188d2d4ece3f1b2a3a02602962b47efa4d7905945b1e2cc80b36aa35c99451073521ac"
|
||||
]
|
||||
},
|
||||
{
|
||||
"P": {
|
||||
"x": "0xe02fc1a5f44a7519419dd314e29863f30df55a514da2d655775a81d413003c4d4e7fd59af0826dfaad4200ac6f60abe1",
|
||||
"y": "0x01f638d04d98677d65bef99aef1a12a70a4cbb9270ec55248c04530d8bc1f8f90f8a6a859a7c1f1ddccedf8f96d675f6"
|
||||
},
|
||||
"Q0": {
|
||||
"x": "0xfc853b69437aee9a19d5acf96a4ee4c5e04cf7b53406dfaa2afbdd7ad2351b7f554e4bbc6f5db4177d4d44f933a8f6ee",
|
||||
"y": "0x7e042547e01834c9043b10f3a8221c4a879cb156f04f72bfccab0c047a304e30f2aa8b2e260d34c4592c0c33dd0c6482"
|
||||
},
|
||||
"Q1": {
|
||||
"x": "0x57912293709b3556b43a2dfb137a315d256d573b82ded120ef8c782d607c05d930d958e50cb6dc1cc480b9afc38c45f1",
|
||||
"y": "0xde9387dab0eef0bda219c6f168a92645a84665c4f2137c14270fb424b7532ff84843c3da383ceea24c47fa343c227bb8"
|
||||
},
|
||||
"msg": "abc",
|
||||
"u": [
|
||||
"0x53350214cb6bef0b51abb791b1c4209a2b4c16a0c67e1ab1401017fad774cd3b3f9a8bcdf7f6229dd8dd5a075cb149a0",
|
||||
"0xc0473083898f63e03f26f14877a2407bd60c75ad491e7d26cbc6cc5ce815654075ec6b6898c7a41d74ceaf720a10c02e"
|
||||
]
|
||||
},
|
||||
{
|
||||
"P": {
|
||||
"x": "0xbdecc1c1d870624965f19505be50459d363c71a699a496ab672f9a5d6b78676400926fbceee6fcd1780fe86e62b2aa89",
|
||||
"y": "0x57cf1f99b5ee00f3c201139b3bfe4dd30a653193778d89a0accc5e0f47e46e4e4b85a0595da29c9494c1814acafe183c"
|
||||
},
|
||||
"Q0": {
|
||||
"x": "0x0ceece45b73f89844671df962ad2932122e878ad2259e650626924e4e7f132589341dec1480ebcbbbe3509d11fb570b7",
|
||||
"y": "0xfafd71a3115298f6be4ae5c6dfc96c400cfb55760f185b7b03f3fa45f3f91eb65d27628b3c705cafd0466fafa54883ce"
|
||||
},
|
||||
"Q1": {
|
||||
"x": "0xdea1be8d3f9be4cbf4fab9d71d549dde76875b5d9b876832313a083ec81e528cbc2a0a1d0596b3bcb0ba77866b129776",
|
||||
"y": "0xeb15fe71662214fb03b65541f40d3eb0f4cf5c3b559f647da138c9f9b7484c48a08760e02c16f1992762cb7298fa52cf"
|
||||
},
|
||||
"msg": "abcdef0123456789",
|
||||
"u": [
|
||||
"0xaab7fb87238cf6b2ab56cdcca7e028959bb2ea599d34f68484139dde85ec6548a6e48771d17956421bdb7790598ea52e",
|
||||
"0x26e8d833552d7844d167833ca5a87c35bcfaa5a0d86023479fb28e5cd6075c18b168bf1f5d2a0ea146d057971336d8d1"
|
||||
]
|
||||
},
|
||||
{
|
||||
"P": {
|
||||
"x": "0x03c3a9f401b78c6c36a52f07eeee0ec1289f178adf78448f43a3850e0456f5dd7f7633dd31676d990eda32882ab486c0",
|
||||
"y": "0xcc183d0d7bdfd0a3af05f50e16a3f2de4abbc523215bf57c848d5ea662482b8c1f43dc453a93b94a8026db58f3f5d878"
|
||||
},
|
||||
"Q0": {
|
||||
"x": "0x051a22105e0817a35d66196338c8d85bd52690d79bba373ead8a86dd9899411513bb9f75273f6483395a7847fb21edb4",
|
||||
"y": "0xf168295c1bbcff5f8b01248e9dbc885335d6d6a04aea960f7384f746ba6502ce477e624151cc1d1392b00df0f5400c06"
|
||||
},
|
||||
"Q1": {
|
||||
"x": "0x6ad7bc8ed8b841efd8ad0765c8a23d0b968ec9aa360a558ff33500f164faa02bee6c704f5f91507c4c5aad2b0dc5b943",
|
||||
"y": "0x47313cc0a873ade774048338fc34ca5313f96bbf6ae22ac6ef475d85f03d24792dc6afba8d0b4a70170c1b4f0f716629"
|
||||
},
|
||||
"msg": "q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq",
|
||||
"u": [
|
||||
"0x04c00051b0de6e726d228c85bf243bf5f4789efb512b22b498cde3821db9da667199b74bd5a09a79583c6d353a3bb41c",
|
||||
"0x97580f218255f899f9204db64cd15e6a312cb4d8182375d1e5157c8f80f41d6a1a4b77fb1ded9dce56c32058b8d5202b"
|
||||
]
|
||||
},
|
||||
{
|
||||
"P": {
|
||||
"x": "0x7b18d210b1f090ac701f65f606f6ca18fb8d081e3bc6cbd937c5604325f1cdea4c15c10a54ef303aabf2ea58bd9947a4",
|
||||
"y": "0xea857285a33abb516732915c353c75c576bf82ccc96adb63c094dde580021eddeafd91f8c0bfee6f636528f3d0c47fd2"
|
||||
},
|
||||
"Q0": {
|
||||
"x": "0x42e6666f505e854187186bad3011598d9278b9d6e3e4d2503c3d236381a56748dec5d139c223129b324df53fa147c4df",
|
||||
"y": "0x8ee51dbda46413bf621838cc935d18d617881c6f33f3838a79c767a1e5618e34b22f79142df708d2432f75c7366c8512"
|
||||
},
|
||||
"Q1": {
|
||||
"x": "0x4ff01ceeba60484fa1bc0d825fe1e5e383d8f79f1e5bb78e5fb26b7a7ef758153e31e78b9d60ce75c5e32e43869d4e12",
|
||||
"y": "0x0f84b978fac8ceda7304b47e229d6037d32062e597dc7a9b95bcd9af441f3c56c619a901d21635f9ec6ab4710b9fcd0e"
|
||||
},
|
||||
"msg": "a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
||||
"u": [
|
||||
"0x480cb3ac2c389db7f9dac9c396d2647ae946db844598971c26d1afd53912a1491199c0a5902811e4b809c26fcd37a014",
|
||||
"0xd28435eb34680e148bf3908536e42231cba9e1f73ae2c6902a222a89db5c49c97db2f8fa4d4cd6e424b17ac60bdb9bb6"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
90
test/hash-to-curve/P521_XMD:SHA-512_SSWU_NU_.json
Normal file
90
test/hash-to-curve/P521_XMD:SHA-512_SSWU_NU_.json
Normal file
@@ -0,0 +1,90 @@
|
||||
{
|
||||
"L": "0x62",
|
||||
"Z": "0x1fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb",
|
||||
"ciphersuite": "P521_XMD:SHA-512_SSWU_NU_",
|
||||
"curve": "NIST P-521",
|
||||
"dst": "QUUX-V01-CS02-with-P521_XMD:SHA-512_SSWU_NU_",
|
||||
"expand": "XMD",
|
||||
"field": {
|
||||
"m": "0x1",
|
||||
"p": "0x1ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
|
||||
},
|
||||
"hash": "sha512",
|
||||
"k": "0x100",
|
||||
"map": {
|
||||
"name": "SSWU"
|
||||
},
|
||||
"randomOracle": false,
|
||||
"vectors": [
|
||||
{
|
||||
"P": {
|
||||
"x": "0x01ec604b4e1e3e4c7449b7a41e366e876655538acf51fd40d08b97be066f7d020634e906b1b6942f9174b417027c953d75fb6ec64b8cee2a3672d4f1987d13974705",
|
||||
"y": "0x00944fc439b4aad2463e5c9cfa0b0707af3c9a42e37c5a57bb4ecd12fef9fb21508568aedcdd8d2490472df4bbafd79081c81e99f4da3286eddf19be47e9c4cf0e91"
|
||||
},
|
||||
"Q": {
|
||||
"x": "0x01ec604b4e1e3e4c7449b7a41e366e876655538acf51fd40d08b97be066f7d020634e906b1b6942f9174b417027c953d75fb6ec64b8cee2a3672d4f1987d13974705",
|
||||
"y": "0x00944fc439b4aad2463e5c9cfa0b0707af3c9a42e37c5a57bb4ecd12fef9fb21508568aedcdd8d2490472df4bbafd79081c81e99f4da3286eddf19be47e9c4cf0e91"
|
||||
},
|
||||
"msg": "",
|
||||
"u": [
|
||||
"0x01e4947fe62a4e47792cee2798912f672fff820b2556282d9843b4b465940d7683a986f93ccb0e9a191fbc09a6e770a564490d2a4ae51b287ca39f69c3d910ba6a4f"
|
||||
]
|
||||
},
|
||||
{
|
||||
"P": {
|
||||
"x": "0x00c720ab56aa5a7a4c07a7732a0a4e1b909e32d063ae1b58db5f0eb5e09f08a9884bff55a2bef4668f715788e692c18c1915cd034a6b998311fcf46924ce66a2be9a",
|
||||
"y": "0x003570e87f91a4f3c7a56be2cb2a078ffc153862a53d5e03e5dad5bccc6c529b8bab0b7dbb157499e1949e4edab21cf5d10b782bc1e945e13d7421ad8121dbc72b1d"
|
||||
},
|
||||
"Q": {
|
||||
"x": "0x00c720ab56aa5a7a4c07a7732a0a4e1b909e32d063ae1b58db5f0eb5e09f08a9884bff55a2bef4668f715788e692c18c1915cd034a6b998311fcf46924ce66a2be9a",
|
||||
"y": "0x003570e87f91a4f3c7a56be2cb2a078ffc153862a53d5e03e5dad5bccc6c529b8bab0b7dbb157499e1949e4edab21cf5d10b782bc1e945e13d7421ad8121dbc72b1d"
|
||||
},
|
||||
"msg": "abc",
|
||||
"u": [
|
||||
"0x0019b85ef78596efc84783d42799e80d787591fe7432dee1d9fa2b7651891321be732ddf653fa8fefa34d86fb728db569d36b5b6ed3983945854b2fc2dc6a75aa25b"
|
||||
]
|
||||
},
|
||||
{
|
||||
"P": {
|
||||
"x": "0x00bcaf32a968ff7971b3bbd9ce8edfbee1309e2019d7ff373c38387a782b005dce6ceffccfeda5c6511c8f7f312f343f3a891029c5858f45ee0bf370aba25fc990cc",
|
||||
"y": "0x00923517e767532d82cb8a0b59705eec2b7779ce05f9181c7d5d5e25694ef8ebd4696343f0bc27006834d2517215ecf79482a84111f50c1bae25044fe1dd77744bbd"
|
||||
},
|
||||
"Q": {
|
||||
"x": "0x00bcaf32a968ff7971b3bbd9ce8edfbee1309e2019d7ff373c38387a782b005dce6ceffccfeda5c6511c8f7f312f343f3a891029c5858f45ee0bf370aba25fc990cc",
|
||||
"y": "0x00923517e767532d82cb8a0b59705eec2b7779ce05f9181c7d5d5e25694ef8ebd4696343f0bc27006834d2517215ecf79482a84111f50c1bae25044fe1dd77744bbd"
|
||||
},
|
||||
"msg": "abcdef0123456789",
|
||||
"u": [
|
||||
"0x01dba0d7fa26a562ee8a9014ebc2cca4d66fd9de036176aca8fc11ef254cd1bc208847ab7701dbca7af328b3f601b11a1737a899575a5c14f4dca5aaca45e9935e07"
|
||||
]
|
||||
},
|
||||
{
|
||||
"P": {
|
||||
"x": "0x001ac69014869b6c4ad7aa8c443c255439d36b0e48a0f57b03d6fe9c40a66b4e2eaed2a93390679a5cc44b3a91862b34b673f0e92c83187da02bf3db967d867ce748",
|
||||
"y": "0x00d5603d530e4d62b30fccfa1d90c2206654d74291c1db1c25b86a051ee3fffc294e5d56f2e776853406bd09206c63d40f37ad8829524cf89ad70b5d6e0b4a3b7341"
|
||||
},
|
||||
"Q": {
|
||||
"x": "0x001ac69014869b6c4ad7aa8c443c255439d36b0e48a0f57b03d6fe9c40a66b4e2eaed2a93390679a5cc44b3a91862b34b673f0e92c83187da02bf3db967d867ce748",
|
||||
"y": "0x00d5603d530e4d62b30fccfa1d90c2206654d74291c1db1c25b86a051ee3fffc294e5d56f2e776853406bd09206c63d40f37ad8829524cf89ad70b5d6e0b4a3b7341"
|
||||
},
|
||||
"msg": "q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq",
|
||||
"u": [
|
||||
"0x00844da980675e1244cb209dcf3ea0aabec23bd54b2cda69fff86eb3acc318bf3d01bae96e9cd6f4c5ceb5539df9a7ad7fcc5e9d54696081ba9782f3a0f6d14987e3"
|
||||
]
|
||||
},
|
||||
{
|
||||
"P": {
|
||||
"x": "0x01801de044c517a80443d2bd4f503a9e6866750d2f94a22970f62d721f96e4310e4a828206d9cdeaa8f2d476705cc3bbc490a6165c687668f15ec178a17e3d27349b",
|
||||
"y": "0x0068889ea2e1442245fe42bfda9e58266828c0263119f35a61631a3358330f3bb84443fcb54fcd53a1d097fccbe310489b74ee143fc2938959a83a1f7dd4a6fd395b"
|
||||
},
|
||||
"Q": {
|
||||
"x": "0x01801de044c517a80443d2bd4f503a9e6866750d2f94a22970f62d721f96e4310e4a828206d9cdeaa8f2d476705cc3bbc490a6165c687668f15ec178a17e3d27349b",
|
||||
"y": "0x0068889ea2e1442245fe42bfda9e58266828c0263119f35a61631a3358330f3bb84443fcb54fcd53a1d097fccbe310489b74ee143fc2938959a83a1f7dd4a6fd395b"
|
||||
},
|
||||
"msg": "a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
||||
"u": [
|
||||
"0x01aab1fb7e5cd44ba4d9f32353a383cb1bb9eb763ed40b32bdd5f666988970205998c0e44af6e2b5f6f8e48e969b3f649cae3c6ab463e1b274d968d91c02f00cce91"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
115
test/hash-to-curve/P521_XMD:SHA-512_SSWU_RO_.json
Normal file
115
test/hash-to-curve/P521_XMD:SHA-512_SSWU_RO_.json
Normal file
@@ -0,0 +1,115 @@
|
||||
{
|
||||
"L": "0x62",
|
||||
"Z": "0x1fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb",
|
||||
"ciphersuite": "P521_XMD:SHA-512_SSWU_RO_",
|
||||
"curve": "NIST P-521",
|
||||
"dst": "QUUX-V01-CS02-with-P521_XMD:SHA-512_SSWU_RO_",
|
||||
"expand": "XMD",
|
||||
"field": {
|
||||
"m": "0x1",
|
||||
"p": "0x1ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
|
||||
},
|
||||
"hash": "sha512",
|
||||
"k": "0x100",
|
||||
"map": {
|
||||
"name": "SSWU"
|
||||
},
|
||||
"randomOracle": true,
|
||||
"vectors": [
|
||||
{
|
||||
"P": {
|
||||
"x": "0x00fd767cebb2452030358d0e9cf907f525f50920c8f607889a6a35680727f64f4d66b161fafeb2654bea0d35086bec0a10b30b14adef3556ed9f7f1bc23cecc9c088",
|
||||
"y": "0x0169ba78d8d851e930680322596e39c78f4fe31b97e57629ef6460ddd68f8763fd7bd767a4e94a80d3d21a3c2ee98347e024fc73ee1c27166dc3fe5eeef782be411d"
|
||||
},
|
||||
"Q0": {
|
||||
"x": "0x00b70ae99b6339fffac19cb9bfde2098b84f75e50ac1e80d6acb954e4534af5f0e9c4a5b8a9c10317b8e6421574bae2b133b4f2b8c6ce4b3063da1d91d34fa2b3a3c",
|
||||
"y": "0x007f368d98a4ddbf381fb354de40e44b19e43bb11a1278759f4ea7b485e1b6db33e750507c071250e3e443c1aaed61f2c28541bb54b1b456843eda1eb15ec2a9b36e"
|
||||
},
|
||||
"Q1": {
|
||||
"x": "0x01143d0e9cddcdacd6a9aafe1bcf8d218c0afc45d4451239e821f5d2a56df92be942660b532b2aa59a9c635ae6b30e803c45a6ac871432452e685d661cd41cf67214",
|
||||
"y": "0x00ff75515df265e996d702a5380defffab1a6d2bc232234c7bcffa433cd8aa791fbc8dcf667f08818bffa739ae25773b32073213cae9a0f2a917a0b1301a242dda0c"
|
||||
},
|
||||
"msg": "",
|
||||
"u": [
|
||||
"0x01e5f09974e5724f25286763f00ce76238c7a6e03dc396600350ee2c4135fb17dc555be99a4a4bae0fd303d4f66d984ed7b6a3ba386093752a855d26d559d69e7e9e",
|
||||
"0x00ae593b42ca2ef93ac488e9e09a5fe5a2f6fb330d18913734ff602f2a761fcaaf5f596e790bcc572c9140ec03f6cccc38f767f1c1975a0b4d70b392d95a0c7278aa"
|
||||
]
|
||||
},
|
||||
{
|
||||
"P": {
|
||||
"x": "0x002f89a1677b28054b50d15e1f81ed6669b5a2158211118ebdef8a6efc77f8ccaa528f698214e4340155abc1fa08f8f613ef14a043717503d57e267d57155cf784a4",
|
||||
"y": "0x010e0be5dc8e753da8ce51091908b72396d3deed14ae166f66d8ebf0a4e7059ead169ea4bead0232e9b700dd380b316e9361cfdba55a08c73545563a80966ecbb86d"
|
||||
},
|
||||
"Q0": {
|
||||
"x": "0x01b254e1c99c835836f0aceebba7d77750c48366ecb07fb658e4f5b76e229ae6ca5d271bb0006ffcc42324e15a6d3daae587f9049de2dbb0494378ffb60279406f56",
|
||||
"y": "0x01845f4af72fc2b1a5a2fe966f6a97298614288b456cfc385a425b686048b25c952fbb5674057e1eb055d04568c0679a8e2dda3158dc16ac598dbb1d006f5ad915b0"
|
||||
},
|
||||
"Q1": {
|
||||
"x": "0x007f08e813c620e527c961b717ffc74aac7afccb9158cebc347d5715d5c2214f952c97e194f11d114d80d3481ed766ac0a3dba3eb73f6ff9ccb9304ad10bbd7b4a36",
|
||||
"y": "0x0022468f92041f9970a7cc025d71d5b647f822784d29ca7b3bc3b0829d6bb8581e745f8d0cc9dc6279d0450e779ac2275c4c3608064ad6779108a7828ebd9954caeb"
|
||||
},
|
||||
"msg": "abc",
|
||||
"u": [
|
||||
"0x003d00c37e95f19f358adeeaa47288ec39998039c3256e13c2a4c00a7cb61a34c8969472960150a27276f2390eb5e53e47ab193351c2d2d9f164a85c6a5696d94fe8",
|
||||
"0x01f3cbd3df3893a45a2f1fecdac4d525eb16f345b03e2820d69bc580f5cbe9cb89196fdf720ef933c4c0361fcfe29940fd0db0a5da6bafb0bee8876b589c41365f15"
|
||||
]
|
||||
},
|
||||
{
|
||||
"P": {
|
||||
"x": "0x006e200e276a4a81760099677814d7f8794a4a5f3658442de63c18d2244dcc957c645e94cb0754f95fcf103b2aeaf94411847c24187b89fb7462ad3679066337cbc4",
|
||||
"y": "0x001dd8dfa9775b60b1614f6f169089d8140d4b3e4012949b52f98db2deff3e1d97bf73a1fa4d437d1dcdf39b6360cc518d8ebcc0f899018206fded7617b654f6b168"
|
||||
},
|
||||
"Q0": {
|
||||
"x": "0x0021482e8622aac14da60e656043f79a6a110cbae5012268a62dd6a152c41594549f373910ebed170ade892dd5a19f5d687fae7095a461d583f8c4295f7aaf8cd7da",
|
||||
"y": "0x0177e2d8c6356b7de06e0b5712d8387d529b848748e54a8bc0ef5f1475aa569f8f492fa85c3ad1c5edc51faf7911f11359bfa2a12d2ef0bd73df9cb5abd1b101c8b1"
|
||||
},
|
||||
"Q1": {
|
||||
"x": "0x00abeafb16fdbb5eb95095678d5a65c1f293291dfd20a3751dbe05d0a9bfe2d2eef19449fe59ec32cdd4a4adc3411177c0f2dffd0159438706159a1bbd0567d9b3d0",
|
||||
"y": "0x007cc657f847db9db651d91c801741060d63dab4056d0a1d3524e2eb0e819954d8f677aa353bd056244a88f00017e00c3ce8beeedb4382d83d74418bd48930c6c182"
|
||||
},
|
||||
"msg": "abcdef0123456789",
|
||||
"u": [
|
||||
"0x00183ee1a9bbdc37181b09ec336bcaa34095f91ef14b66b1485c166720523dfb81d5c470d44afcb52a87b704dbc5c9bc9d0ef524dec29884a4795f55c1359945baf3",
|
||||
"0x00504064fd137f06c81a7cf0f84aa7e92b6b3d56c2368f0a08f44776aa8930480da1582d01d7f52df31dca35ee0a7876500ece3d8fe0293cd285f790c9881c998d5e"
|
||||
]
|
||||
},
|
||||
{
|
||||
"P": {
|
||||
"x": "0x01b264a630bd6555be537b000b99a06761a9325c53322b65bdc41bf196711f9708d58d34b3b90faf12640c27b91c70a507998e55940648caa8e71098bf2bc8d24664",
|
||||
"y": "0x01ea9f445bee198b3ee4c812dcf7b0f91e0881f0251aab272a12201fd89b1a95733fd2a699c162b639e9acdcc54fdc2f6536129b6beb0432be01aa8da02df5e59aaa"
|
||||
},
|
||||
"Q0": {
|
||||
"x": "0x0005eac7b0b81e38727efcab1e375f6779aea949c3e409b53a1d37aa2acbac87a7e6ad24aafbf3c52f82f7f0e21b872e88c55e17b7fa21ce08a94ea2121c42c2eb73",
|
||||
"y": "0x00a173b6a53a7420dbd61d4a21a7c0a52de7a5c6ce05f31403bef747d16cc8604a039a73bdd6e114340e55dacd6bea8e217ffbadfb8c292afa3e1b2afc839a6ce7bb"
|
||||
},
|
||||
"Q1": {
|
||||
"x": "0x01881e3c193a69e4d88d8180a6879b74782a0bc7e529233e9f84bf7f17d2f319c36920ffba26f9e57a1e045cc7822c834c239593b6e142a694aa00c757b0db79e5e8",
|
||||
"y": "0x01558b16d396d866e476e001f2dd0758927655450b84e12f154032c7c2a6db837942cd9f44b814f79b4d729996ced61eec61d85c675139cbffe3fbf071d2c21cfecb"
|
||||
},
|
||||
"msg": "q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq",
|
||||
"u": [
|
||||
"0x0159871e222689aad7694dc4c3480a49807b1eedd9c8cb4ae1b219d5ba51655ea5b38e2e4f56b36bf3e3da44a7b139849d28f598c816fe1bc7ed15893b22f63363c3",
|
||||
"0x004ef0cffd475152f3858c0a8ccbdf7902d8261da92744e98df9b7fadb0a5502f29c5086e76e2cf498f47321434a40b1504911552ce44ad7356a04e08729ad9411f5"
|
||||
]
|
||||
},
|
||||
{
|
||||
"P": {
|
||||
"x": "0x00c12bc3e28db07b6b4d2a2b1167ab9e26fc2fa85c7b0498a17b0347edf52392856d7e28b8fa7a2dd004611159505835b687ecf1a764857e27e9745848c436ef3925",
|
||||
"y": "0x01cd287df9a50c22a9231beb452346720bb163344a41c5f5a24e8335b6ccc595fd436aea89737b1281aecb411eb835f0b939073fdd1dd4d5a2492e91ef4a3c55bcbd"
|
||||
},
|
||||
"Q0": {
|
||||
"x": "0x00041f6eb92af8777260718e4c22328a7d74203350c6c8f5794d99d5789766698f459b83d5068276716f01429934e40af3d1111a22780b1e07e72238d2207e5386be",
|
||||
"y": "0x001c712f0182813942b87cab8e72337db017126f52ed797dd234584ac9ae7e80dfe7abea11db02cf1855312eae1447dbaecc9d7e8c880a5e76a39f6258074e1bc2e0"
|
||||
},
|
||||
"Q1": {
|
||||
"x": "0x0125c0b69bcf55eab49280b14f707883405028e05c927cd7625d4e04115bd0e0e6323b12f5d43d0d6d2eff16dbcf244542f84ec058911260dc3bb6512ab5db285fbd",
|
||||
"y": "0x008bddfb803b3f4c761458eb5f8a0aee3e1f7f68e9d7424405fa69172919899317fb6ac1d6903a432d967d14e0f80af63e7035aaae0c123e56862ce969456f99f102"
|
||||
},
|
||||
"msg": "a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
||||
"u": [
|
||||
"0x0033d06d17bc3b9a3efc081a05d65805a14a3050a0dd4dfb4884618eb5c73980a59c5a246b18f58ad022dd3630faa22889fbb8ba1593466515e6ab4aeb7381c26334",
|
||||
"0x0092290ab99c3fea1a5b8fb2ca49f859994a04faee3301cefab312d34227f6a2d0c3322cf76861c6a3683bdaa2dd2a6daa5d6906c663e065338b2344d20e313f1114"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
90
test/hash-to-curve/curve25519_XMD:SHA-512_ELL2_NU_.json
Normal file
90
test/hash-to-curve/curve25519_XMD:SHA-512_ELL2_NU_.json
Normal file
@@ -0,0 +1,90 @@
|
||||
{
|
||||
"L": "0x30",
|
||||
"Z": "0x2",
|
||||
"ciphersuite": "curve25519_XMD:SHA-512_ELL2_NU_",
|
||||
"curve": "curve25519",
|
||||
"dst": "QUUX-V01-CS02-with-curve25519_XMD:SHA-512_ELL2_NU_",
|
||||
"expand": "XMD",
|
||||
"field": {
|
||||
"m": "0x1",
|
||||
"p": "0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffed"
|
||||
},
|
||||
"hash": "sha512",
|
||||
"k": "0x80",
|
||||
"map": {
|
||||
"name": "ELL2"
|
||||
},
|
||||
"randomOracle": false,
|
||||
"vectors": [
|
||||
{
|
||||
"P": {
|
||||
"x": "0x1bb913f0c9daefa0b3375378ffa534bda5526c97391952a7789eb976edfe4d08",
|
||||
"y": "0x4548368f4f983243e747b62a600840ae7c1dab5c723991f85d3a9768479f3ec4"
|
||||
},
|
||||
"Q": {
|
||||
"x": "0x51125222da5e763d97f3c10fcc92ea6860b9ccbbd2eb1285728f566721c1e65b",
|
||||
"y": "0x343d2204f812d3dfc5304a5808c6c0d81a903a5d228b342442aa3c9ba5520a3d"
|
||||
},
|
||||
"msg": "",
|
||||
"u": [
|
||||
"0x608d892b641f0328523802a6603427c26e55e6f27e71a91a478148d45b5093cd"
|
||||
]
|
||||
},
|
||||
{
|
||||
"P": {
|
||||
"x": "0x7c22950b7d900fa866334262fcaea47a441a578df43b894b4625c9b450f9a026",
|
||||
"y": "0x5547bc00e4c09685dcbc6cb6765288b386d8bdcb595fa5a6e3969e08097f0541"
|
||||
},
|
||||
"Q": {
|
||||
"x": "0x7d56d1e08cb0ccb92baf069c18c49bb5a0dcd927eff8dcf75ca921ef7f3e6eeb",
|
||||
"y": "0x404d9a7dc25c9c05c44ab9a94590e7c3fe2dcec74533a0b24b188a5d5dacf429"
|
||||
},
|
||||
"msg": "abc",
|
||||
"u": [
|
||||
"0x46f5b22494bfeaa7f232cc8d054be68561af50230234d7d1d63d1d9abeca8da5"
|
||||
]
|
||||
},
|
||||
{
|
||||
"P": {
|
||||
"x": "0x31ad08a8b0deeb2a4d8b0206ca25f567ab4e042746f792f4b7973f3ae2096c52",
|
||||
"y": "0x405070c28e78b4fa269427c82827261991b9718bd6c6e95d627d701a53c30db1"
|
||||
},
|
||||
"Q": {
|
||||
"x": "0x3fbe66b9c9883d79e8407150e7c2a1c8680bee496c62fabe4619a72b3cabe90f",
|
||||
"y": "0x08ec476147c9a0a3ff312d303dbbd076abb7551e5fce82b48ab14b433f8d0a7b"
|
||||
},
|
||||
"msg": "abcdef0123456789",
|
||||
"u": [
|
||||
"0x235fe40c443766ce7e18111c33862d66c3b33267efa50d50f9e8e5d252a40aaa"
|
||||
]
|
||||
},
|
||||
{
|
||||
"P": {
|
||||
"x": "0x027877759d155b1997d0d84683a313eb78bdb493271d935b622900459d52ceaa",
|
||||
"y": "0x54d691731a53baa30707f4a87121d5169fb5d587d70fb0292b5830dedbec4c18"
|
||||
},
|
||||
"Q": {
|
||||
"x": "0x227e0bb89de700385d19ec40e857db6e6a3e634b1c32962f370d26f84ff19683",
|
||||
"y": "0x5f86ff3851d262727326a32c1bf7655a03665830fa7f1b8b1e5a09d85bc66e4a"
|
||||
},
|
||||
"msg": "q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq",
|
||||
"u": [
|
||||
"0x001e92a544463bda9bd04ddbe3d6eed248f82de32f522669efc5ddce95f46f5b"
|
||||
]
|
||||
},
|
||||
{
|
||||
"P": {
|
||||
"x": "0x5fd892c0958d1a75f54c3182a18d286efab784e774d1e017ba2fb252998b5dc1",
|
||||
"y": "0x750af3c66101737423a4519ac792fb93337bd74ee751f19da4cf1e94f4d6d0b8"
|
||||
},
|
||||
"Q": {
|
||||
"x": "0x3bcd651ee54d5f7b6013898aab251ee8ecc0688166fce6e9548d38472f6bd196",
|
||||
"y": "0x1bb36ad9197299f111b4ef21271c41f4b7ecf5543db8bb5931307ebdb2eaa465"
|
||||
},
|
||||
"msg": "a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
||||
"u": [
|
||||
"0x1a68a1af9f663592291af987203393f707305c7bac9c8d63d6a729bdc553dc19"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
115
test/hash-to-curve/curve25519_XMD:SHA-512_ELL2_RO_.json
Normal file
115
test/hash-to-curve/curve25519_XMD:SHA-512_ELL2_RO_.json
Normal file
@@ -0,0 +1,115 @@
|
||||
{
|
||||
"L": "0x30",
|
||||
"Z": "0x2",
|
||||
"ciphersuite": "curve25519_XMD:SHA-512_ELL2_RO_",
|
||||
"curve": "curve25519",
|
||||
"dst": "QUUX-V01-CS02-with-curve25519_XMD:SHA-512_ELL2_RO_",
|
||||
"expand": "XMD",
|
||||
"field": {
|
||||
"m": "0x1",
|
||||
"p": "0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffed"
|
||||
},
|
||||
"hash": "sha512",
|
||||
"k": "0x80",
|
||||
"map": {
|
||||
"name": "ELL2"
|
||||
},
|
||||
"randomOracle": true,
|
||||
"vectors": [
|
||||
{
|
||||
"P": {
|
||||
"x": "0x2de3780abb67e861289f5749d16d3e217ffa722192d16bbd9d1bfb9d112b98c0",
|
||||
"y": "0x3b5dc2a498941a1033d176567d457845637554a2fe7a3507d21abd1c1bd6e878"
|
||||
},
|
||||
"Q0": {
|
||||
"x": "0x36b4df0c864c64707cbf6cf36e9ee2c09a6cb93b28313c169be29561bb904f98",
|
||||
"y": "0x6cd59d664fb58c66c892883cd0eb792e52055284dac3907dd756b45d15c3983d"
|
||||
},
|
||||
"Q1": {
|
||||
"x": "0x3fa114783a505c0b2b2fbeef0102853c0b494e7757f2a089d0daae7ed9a0db2b",
|
||||
"y": "0x76c0fe7fec932aaafb8eefb42d9cbb32eb931158f469ff3050af15cfdbbeff94"
|
||||
},
|
||||
"msg": "",
|
||||
"u": [
|
||||
"0x005fe8a7b8fef0a16c105e6cadf5a6740b3365e18692a9c05bfbb4d97f645a6a",
|
||||
"0x1347edbec6a2b5d8c02e058819819bee177077c9d10a4ce165aab0fd0252261a"
|
||||
]
|
||||
},
|
||||
{
|
||||
"P": {
|
||||
"x": "0x2b4419f1f2d48f5872de692b0aca72cc7b0a60915dd70bde432e826b6abc526d",
|
||||
"y": "0x1b8235f255a268f0a6fa8763e97eb3d22d149343d495da1160eff9703f2d07dd"
|
||||
},
|
||||
"Q0": {
|
||||
"x": "0x16b3d86e056b7970fa00165f6f48d90b619ad618791661b7b5e1ec78be10eac1",
|
||||
"y": "0x4ab256422d84c5120b278cbdfc4e1facc5baadffeccecf8ee9bf3946106d50ca"
|
||||
},
|
||||
"Q1": {
|
||||
"x": "0x7ec29ddbf34539c40adfa98fcb39ec36368f47f30e8f888cc7e86f4d46e0c264",
|
||||
"y": "0x10d1abc1cae2d34c06e247f2141ba897657fb39f1080d54f09ce0af128067c74"
|
||||
},
|
||||
"msg": "abc",
|
||||
"u": [
|
||||
"0x49bed021c7a3748f09fa8cdfcac044089f7829d3531066ac9e74e0994e05bc7d",
|
||||
"0x5c36525b663e63389d886105cee7ed712325d5a97e60e140aba7e2ce5ae851b6"
|
||||
]
|
||||
},
|
||||
{
|
||||
"P": {
|
||||
"x": "0x68ca1ea5a6acf4e9956daa101709b1eee6c1bb0df1de3b90d4602382a104c036",
|
||||
"y": "0x2a375b656207123d10766e68b938b1812a4a6625ff83cb8d5e86f58a4be08353"
|
||||
},
|
||||
"Q0": {
|
||||
"x": "0x71de3dadfe268872326c35ac512164850860567aea0e7325e6b91a98f86533ad",
|
||||
"y": "0x26a08b6e9a18084c56f2147bf515414b9b63f1522e1b6c5649f7d4b0324296ec"
|
||||
},
|
||||
"Q1": {
|
||||
"x": "0x5704069021f61e41779e2ba6b932268316d6d2a6f064f997a22fef16d1eaeaca",
|
||||
"y": "0x50483c7540f64fb4497619c050f2c7fe55454ec0f0e79870bb44302e34232210"
|
||||
},
|
||||
"msg": "abcdef0123456789",
|
||||
"u": [
|
||||
"0x6412b7485ba26d3d1b6c290a8e1435b2959f03721874939b21782df17323d160",
|
||||
"0x24c7b46c1c6d9a21d32f5707be1380ab82db1054fde82865d5c9e3d968f287b2"
|
||||
]
|
||||
},
|
||||
{
|
||||
"P": {
|
||||
"x": "0x096e9c8bae6c06b554c1ee69383bb0e82267e064236b3a30608d4ed20b73ac5a",
|
||||
"y": "0x1eb5a62612cafb32b16c3329794645b5b948d9f8ffe501d4e26b073fef6de355"
|
||||
},
|
||||
"Q0": {
|
||||
"x": "0x7a94d45a198fb5daa381f45f2619ab279744efdd8bd8ed587fc5b65d6cea1df0",
|
||||
"y": "0x67d44f85d376e64bb7d713585230cdbfafc8e2676f7568e0b6ee59361116a6e1"
|
||||
},
|
||||
"Q1": {
|
||||
"x": "0x30506fb7a32136694abd61b6113770270debe593027a968a01f271e146e60c18",
|
||||
"y": "0x7eeee0e706b40c6b5174e551426a67f975ad5a977ee2f01e8e20a6d612458c3b"
|
||||
},
|
||||
"msg": "q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq",
|
||||
"u": [
|
||||
"0x5e123990f11bbb5586613ffabdb58d47f64bb5f2fa115f8ea8df0188e0c9e1b5",
|
||||
"0x5e8553eb00438a0bb1e7faa59dec6d8087f9c8011e5fb8ed9df31cb6c0d4ac19"
|
||||
]
|
||||
},
|
||||
{
|
||||
"P": {
|
||||
"x": "0x1bc61845a138e912f047b5e70ba9606ba2a447a4dade024c8ef3dd42b7bbc5fe",
|
||||
"y": "0x623d05e47b70e25f7f1d51dda6d7c23c9a18ce015fe3548df596ea9e38c69bf1"
|
||||
},
|
||||
"Q0": {
|
||||
"x": "0x02d606e2699b918ee36f2818f2bc5013e437e673c9f9b9cdc15fd0c5ee913970",
|
||||
"y": "0x29e9dc92297231ef211245db9e31767996c5625dfbf92e1c8107ef887365de1e"
|
||||
},
|
||||
"Q1": {
|
||||
"x": "0x38920e9b988d1ab7449c0fa9a6058192c0c797bb3d42ac345724341a1aa98745",
|
||||
"y": "0x24dcc1be7c4d591d307e89049fd2ed30aae8911245a9d8554bf6032e5aa40d3d"
|
||||
},
|
||||
"msg": "a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
||||
"u": [
|
||||
"0x20f481e85da7a3bf60ac0fb11ed1d0558fc6f941b3ac5469aa8b56ec883d6d7d",
|
||||
"0x017d57fd257e9a78913999a23b52ca988157a81b09c5442501d07fed20869465"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
90
test/hash-to-curve/curve448_XOF:SHAKE256_ELL2_NU_.json
Normal file
90
test/hash-to-curve/curve448_XOF:SHAKE256_ELL2_NU_.json
Normal file
@@ -0,0 +1,90 @@
|
||||
{
|
||||
"L": "0x54",
|
||||
"Z": "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffffffffffffffffffffffffffffffffffffffffffffffffffffe",
|
||||
"ciphersuite": "curve448_XOF:SHAKE256_ELL2_NU_",
|
||||
"curve": "curve448",
|
||||
"dst": "QUUX-V01-CS02-with-curve448_XOF:SHAKE256_ELL2_NU_",
|
||||
"expand": "XOF",
|
||||
"field": {
|
||||
"m": "0x1",
|
||||
"p": "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
|
||||
},
|
||||
"hash": "shake_256",
|
||||
"k": "0xe0",
|
||||
"map": {
|
||||
"name": "ELL2"
|
||||
},
|
||||
"randomOracle": false,
|
||||
"vectors": [
|
||||
{
|
||||
"P": {
|
||||
"x": "0xb65e8dbb279fd656f926f68d463b13ca7a982b32f5da9c7cc58afcf6199e4729863fb75ca9ae3c95c6887d95a5102637a1c5c40ff0aafadc",
|
||||
"y": "0xea1ea211cf29eca11c057fe8248181591a19f6ac51d45843a65d4bb8b71bc83a64c771ed7686218a278ef1c5d620f3d26b53162188645453"
|
||||
},
|
||||
"Q": {
|
||||
"x": "0xe6304424de5af3f556d3e645600530c53ad949891c3e60ba041dd5f68a93901beff8440164477d348c13d28e27bfcd360c44c80b4c7d4cea",
|
||||
"y": "0x4160a8f2043a347185406a6a7e50973b98b82edbdfa3209b0e1c90118e10eeb45045b0990d4b2b0708a30eca17df40ad53c9100f20c10b44"
|
||||
},
|
||||
"msg": "",
|
||||
"u": [
|
||||
"0x242c70f74eac8184116c71630d284cf8a742fc463e710545847ff64d8e9161cb9f599728a18a32dbd8b67c3bec5d64c9b1d2f2cde7b5888d"
|
||||
]
|
||||
},
|
||||
{
|
||||
"P": {
|
||||
"x": "0x51aceca4fa95854bbaba58d8a5e17a86c07acadef32e1188cafda26232131800002cc2f27c7aec454e5e0c615bddffb7df6a5f7f0f14793f",
|
||||
"y": "0xc590c9246eb28b08dee816d608ef233ea5d76e305dc458774a1e1bd880387e6734219e2018e4aa50a49486dce0ba8740065da37e6cf5212c"
|
||||
},
|
||||
"Q": {
|
||||
"x": "0xde0dc93df9ce7953452f20e270699c1e7dacd5d571c226d77f53b7e3053d16f8a81b1601efb362054e973c8e733b663af93f00cb81baf130",
|
||||
"y": "0x8c5bdec6fa6690905f6eff966b0f98f5a8161493bd04976684d4ec1f4512fa8743d86860b2ff2c5d67e9c145fd906f2cb89ff812c6b9883f"
|
||||
},
|
||||
"msg": "abc",
|
||||
"u": [
|
||||
"0xef6dcb75b696d325fb36d66b104700df1480c4c17ea9190d447eee1e7e4c9b7f36bbfb8ba7ba7c4cb6b07fed16531c1ac7a26a3618b40b34"
|
||||
]
|
||||
},
|
||||
{
|
||||
"P": {
|
||||
"x": "0xc6d65987f146b8d0cb5d2c44e1872ac3af1f458f6a8bd8c232ffe8b9d09496229a5a27f350eb7d97305bcc4e0f38328718352e8e3129ed71",
|
||||
"y": "0x4d2f901bf333fdc4135b954f20d59207e9f6a4ecf88ce5af11c892b44f79766ec4ecc9f60d669b95ca8940f39b1b7044140ac2040c1bf659"
|
||||
},
|
||||
"Q": {
|
||||
"x": "0xdc29532761f03c24d57f530da4c24acc4c676d185becaa89fcc083266541fb7f10ecec91dac64a34cd988274633ae25c4d784aee52de47a8",
|
||||
"y": "0xa5f6da11259c69f2e07fce6a7b6afec4c25bd2df83426765f9c0704111da24c6a0550d5c7aac7d648d55f7640d50be99c926195e852adaac"
|
||||
},
|
||||
"msg": "abcdef0123456789",
|
||||
"u": [
|
||||
"0x3012ba5d9b3bb648e4613833a26ecaeadb3e8c8bba07fc90ac3da0375769289c44d3dc87474b23df7f45f9a4030892cda689e343aeeea6ad"
|
||||
]
|
||||
},
|
||||
{
|
||||
"P": {
|
||||
"x": "0x9b8d008863beb4a02fb9e4efefd2eba867307fb1c7ce01746115d32e1db551bb254e8e3e4532d5c74a83949a69a60519ecc9178083cbe943",
|
||||
"y": "0x346a1fca454d1e67c628437c270ec0f0c4256bb774fe6c0e49de7004ff6d9199e2cd99d8f7575a96aafc4dc8db1811ba0a44317581f41371"
|
||||
},
|
||||
"Q": {
|
||||
"x": "0x512803d89f59c57376e6570cd54c4e901643e089cd9456f549daa4372b8b52679860b68aa8bedfaa88970f15ab6098d5f252083ac98a58c9",
|
||||
"y": "0x3d9b6593c7941a20d76161c9a171f1e507495a08f03dfcae33a2ac3602698e46a74d1039b583c984036f590eaa43d20ba5aada3ffb552f77"
|
||||
},
|
||||
"msg": "q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq",
|
||||
"u": [
|
||||
"0xfe952ac0149f92436bba12ea2e542aa226f4fc074d79ff462c41b327968a649a495a8a93b6c3044af2273456abb5e166ce4fb8c9b10c8c2e"
|
||||
]
|
||||
},
|
||||
{
|
||||
"P": {
|
||||
"x": "0x8746dc34799112d1f20acda9d7f722c9abb29b1fb6b7e9e566983843c20bd7c9bfad21b45c5166b808d2f5d44e188f1fdaf29cdee8a72e4c",
|
||||
"y": "0x7c1293484c9287c298a1a0600c64347eee8530acf563cd8705e05728274d8cd8101835f8003b6f3b78b5beb28f5be188a3d7bce1ec5a36b1"
|
||||
},
|
||||
"Q": {
|
||||
"x": "0x08aed6480793218034fd3b3b0867943d7e0bd1b6f76b4929e0885bd082b84d4449341da6038bb08229ad9eb7d518dff2c7ea50148e70a4db",
|
||||
"y": "0xe00d32244561ebd4b5f4ef70fcac75a06416be0a1c1b304e7bd361a6a6586915bb902a323eaf73cf7738e70d34282f61485395ab2833d2c1"
|
||||
},
|
||||
"msg": "a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
||||
"u": [
|
||||
"0xafd3d7ad9d819be7561706e050d4f30b634b203387ab682739365f62cd7393ca2cf18cd07a3d3af8dd163f043ac7457c2eb145b4a56170a9"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
115
test/hash-to-curve/curve448_XOF:SHAKE256_ELL2_RO_.json
Normal file
115
test/hash-to-curve/curve448_XOF:SHAKE256_ELL2_RO_.json
Normal file
@@ -0,0 +1,115 @@
|
||||
{
|
||||
"L": "0x54",
|
||||
"Z": "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffffffffffffffffffffffffffffffffffffffffffffffffffffe",
|
||||
"ciphersuite": "curve448_XOF:SHAKE256_ELL2_RO_",
|
||||
"curve": "curve448",
|
||||
"dst": "QUUX-V01-CS02-with-curve448_XOF:SHAKE256_ELL2_RO_",
|
||||
"expand": "XOF",
|
||||
"field": {
|
||||
"m": "0x1",
|
||||
"p": "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
|
||||
},
|
||||
"hash": "shake_256",
|
||||
"k": "0xe0",
|
||||
"map": {
|
||||
"name": "ELL2"
|
||||
},
|
||||
"randomOracle": true,
|
||||
"vectors": [
|
||||
{
|
||||
"P": {
|
||||
"x": "0x5ea5ff623d27c75e73717514134e73e419f831a875ca9e82915fdfc7069d0a9f8b532cfb32b1d8dd04ddeedbe3fa1d0d681c01e825d6a9ea",
|
||||
"y": "0xafadd8de789f8f8e3516efbbe313a7eba364c939ecba00dabf4ced5c563b18e70a284c17d8f46b564c4e6ce11784a3825d941116622128c1"
|
||||
},
|
||||
"Q0": {
|
||||
"x": "0x3ba318806f89c19cc019f51e33eb6b8c038dab892e858ce7c7f2c2ac58618d06146a5fef31e49af49588d4d3db1bcf02bd4e4a733e37065d",
|
||||
"y": "0xb30b4cfc2fd14d9d4b70456c0f5c6f6070be551788893d570e7955675a20f6c286d01d6e90d2fb500d2efb8f4e18db7f8268bb9b7fbc5975"
|
||||
},
|
||||
"Q1": {
|
||||
"x": "0xf03a48cf003f63be61ca055fec87c750434da07a15f8aa6210389ff85943b5166484339c8bea1af9fc571313d35ed2fbb779408b760c4cbd",
|
||||
"y": "0x23943a33b2954dc54b76a8222faf5b7e18405a41f5ecc61bf1b8df1f9cbfad057307ed0c7b721f19c0390b8ee3a2dec223671f9ff905fda7"
|
||||
},
|
||||
"msg": "",
|
||||
"u": [
|
||||
"0xc704c7b3d3b36614cf3eedd0324fe6fe7d1402c50efd16cff89ff63f50938506280d3843478c08e24f7842f4e3ef45f6e3c4897f9d976148",
|
||||
"0xc25427dc97fff7a5ad0a78654e2c6c27b1c1127b5b53c7950cd1fd6edd2703646b25f341e73deedfebf022d1d3cecd02b93b4d585ead3ed7"
|
||||
]
|
||||
},
|
||||
{
|
||||
"P": {
|
||||
"x": "0x9b2f7ce34878d7cebf34c582db14958308ea09366d1ec71f646411d3de0ae564d082b06f40cd30dfc08d9fb7cb21df390cf207806ad9d0e4",
|
||||
"y": "0x138a0eef0a4993ea696152ed7db61f7ddb4e8100573591e7466d61c0c568ecaec939e36a84d276f34c402526d8989a96e99760c4869ed633"
|
||||
},
|
||||
"Q0": {
|
||||
"x": "0x26714783887ec444fbade9ae350dc13e8d5a64150679232560726a73d36e28bd56766d7d0b0899d79c8d1c889ae333f601c57532ff3c4f09",
|
||||
"y": "0x080e486f8f5740dbbe82305160cab9fac247b0b22a54d961de675037c3036fa68464c8756478c322ae0aeb9ba386fe626cebb0bcca46840c"
|
||||
},
|
||||
"Q1": {
|
||||
"x": "0x0d9741d10421691a8ebc7778b5f623260fdf8b28ae28d776efcb8e0d5fbb65139a2f828617835f527cb2ca24a8f5fc8e84378343c43d096d",
|
||||
"y": "0x54f4c499bf3d5b154511913f9615bd914969b65cfb74508d7ae5a169e9595b7cbcab9a1485e07b2ce426e4fbed052f03842c4313b7dbe39a"
|
||||
},
|
||||
"msg": "abc",
|
||||
"u": [
|
||||
"0x2dd95593dfee26fe0d218d3d9a0a23d9e1a262fd1d0b602483d08415213e75e2db3c69b0a5bc89e71bcefc8c723d2b6a0cf263f02ad2aa70",
|
||||
"0x272e4c79a1290cc6d2bc4f4f9d31bf7fbe956ca303c04518f117d77c0e9d850796fc3e1e2bcb9c75e8eaaded5e150333cae9931868047c9d"
|
||||
]
|
||||
},
|
||||
{
|
||||
"P": {
|
||||
"x": "0xf54ecd14b85a50eeeee0618452df3a75be7bfba11da5118774ae4ea55ac204e153f77285d780c4acee6c96abe3577a0c0b00be6e790cf194",
|
||||
"y": "0x935247a64bf78c107069943c7e3ecc52acb27ce4a3230407c8357341685ea2152e8c3da93f8cd77da1bddb5bb759c6e7ae7d516dced42850"
|
||||
},
|
||||
"Q0": {
|
||||
"x": "0x946d91bd50c90ef70743e0dd194bddd68bb630f4e67e5b93e15a9b94e62cb85134467993501759525c1f4fdbf06f10ddaf817847d735e062",
|
||||
"y": "0x185cf511262ec1e9b3c3cbdc015ab93df4e71cbe87766917d81c9f3419d480407c1462385122c84982d4dae60c3ae4acce0089e37ad65934"
|
||||
},
|
||||
"Q1": {
|
||||
"x": "0x01778f4797b717cd6f83c193b2dfb92a1606a36ede941b0f6ab0ac71ad0eac756d17604bf054398887da907e41065d3595f178ae802f2087",
|
||||
"y": "0xb4ca727d0bda895e0eee7eb3cbc28710fa2e90a73b568cae26bd7c2e73b70a9fa0affe1096f0810198890ed65d8935886b6e60dc4c569dc6"
|
||||
},
|
||||
"msg": "abcdef0123456789",
|
||||
"u": [
|
||||
"0x6aab71a38391639f27e49eae8b1cb6b7172a1f478190ece293957e7cdb2391e7cc1c4261970d9c1bbf9c3915438f74fbd7eb5cd4d4d17ace",
|
||||
"0xc80b8380ca47a3bcbf76caa75cef0e09f3d270d5ee8f676cde11aedf41aaca6741bd81a86232bd336ccb42efad39f06542bc06a67b65909e"
|
||||
]
|
||||
},
|
||||
{
|
||||
"P": {
|
||||
"x": "0x5bd67c4f88adf6beb10f7e0d0054659776a55c97b809ec8b3101729e104fd0f684e103792f267fd87cc4afc25a073956ef4f268fb02824d5",
|
||||
"y": "0xda1f5cb16a352719e4cb064cf47ba72aeba7752d03e8ca2c56229f419b4ef378785a5af1a53dd7ab4d467c1f92f7b139b3752faf29c96432"
|
||||
},
|
||||
"Q0": {
|
||||
"x": "0xc2d275826d6ad55e41a22318f6b6240f1f862a2e231120ff41eadbec319756032e8cef2a7ac6c10214fa0608c17fcaf61ec2694a8a2b358b",
|
||||
"y": "0x93d2e092762b135509840e609d413200df800d99da91d8b82840666cac30e7a3520adbaa4b089bfdc86132e42729f651d022f4782502f12c"
|
||||
},
|
||||
"Q1": {
|
||||
"x": "0x3c0880ece7244036e9a45944a85599f9809d772f770cc237ac41b21aa71615e4f3bb08f64fca618896e4f6cf5bd92e16b89d2cf6e1956bfb",
|
||||
"y": "0x45cce4beb96505cac5976b3d2673641e9bcd18d3462bbb453d293e5282740a6389cfeae610adc7bd425c728541ceec83fcc999164af43fb5"
|
||||
},
|
||||
"msg": "q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq",
|
||||
"u": [
|
||||
"0xcb5c27e51f9c18ee8ffdb6be230f4eb4f2c2481963b2293484f08da2241c1ff59f80978e6defe9d70e34abba2fcbe12dc3a1eb2c5d3d2e4a",
|
||||
"0xc895e8afecec5466e126fa70fc4aa784b8009063afb10e3ee06a9b22318256aa8693b0c85b955cf2d6540b8ed71e729af1b8d5ca3b116cd7"
|
||||
]
|
||||
},
|
||||
{
|
||||
"P": {
|
||||
"x": "0xea441c10b3636ecedd5c0dfcae96384cc40de8390a0ab648765b4508da12c586d55dc981275776507ebca0e4d1bcaa302bb69dcfa31b3451",
|
||||
"y": "0xfee0192d49bcc0c28d954763c2cbe739b9265c4bebe3883803c64971220cfda60b9ac99ad986cd908c0534b260b5cfca46f6c2b0f3f21bda"
|
||||
},
|
||||
"Q0": {
|
||||
"x": "0x4321ab02a9849128691e9b80a5c5576793a218de14885fddccb91f17ceb1646ea00a28b69ad211e1f14f17739612dbde3782319bdf009689",
|
||||
"y": "0x1b8a7b539519eec0ea9f7a46a43822e16cba39a439733d6847ac44a806b8adb3e1a75ea48a1228b8937ba85c6cb6ee01046e10cad8953b1e"
|
||||
},
|
||||
"Q1": {
|
||||
"x": "0x126d744da6a14fddec0f78a9cee4571c1320ac7645b600187812e4d7021f98fc4703732c54daec787206e1f34d9dbbf4b292c68160b8bfbd",
|
||||
"y": "0x136eebe6020f2389d448923899a1a38a4c8ad74254e0686e91c4f93c1f8f8e1bd619ffb7c1281467882a9c957d22d50f65c5b72b2aee11af"
|
||||
},
|
||||
"msg": "a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
||||
"u": [
|
||||
"0x8cba93a007bb2c801b1769e026b1fa1640b14a34cf3029db3c7fd6392745d6fec0f7870b5071d6da4402cedbbde28ae4e50ab30e1049a238",
|
||||
"0x4223746145069e4b8a981acc3404259d1a2c3ecfed5d864798a89d45f81a2c59e2d40eb1d5f0fe11478cbb2bb30246dd388cb932ad7bb330"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
90
test/hash-to-curve/edwards25519_XMD:SHA-512_ELL2_NU_.json
Normal file
90
test/hash-to-curve/edwards25519_XMD:SHA-512_ELL2_NU_.json
Normal file
@@ -0,0 +1,90 @@
|
||||
{
|
||||
"L": "0x30",
|
||||
"Z": "0x2",
|
||||
"ciphersuite": "edwards25519_XMD:SHA-512_ELL2_NU_",
|
||||
"curve": "edwards25519",
|
||||
"dst": "QUUX-V01-CS02-with-edwards25519_XMD:SHA-512_ELL2_NU_",
|
||||
"expand": "XMD",
|
||||
"field": {
|
||||
"m": "0x1",
|
||||
"p": "0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffed"
|
||||
},
|
||||
"hash": "sha512",
|
||||
"k": "0x80",
|
||||
"map": {
|
||||
"name": "ELL2"
|
||||
},
|
||||
"randomOracle": false,
|
||||
"vectors": [
|
||||
{
|
||||
"P": {
|
||||
"x": "0x1ff2b70ecf862799e11b7ae744e3489aa058ce805dd323a936375a84695e76da",
|
||||
"y": "0x222e314d04a4d5725e9f2aff9fb2a6b69ef375a1214eb19021ceab2d687f0f9b"
|
||||
},
|
||||
"Q": {
|
||||
"x": "0x42836f691d05211ebc65ef8fcf01e0fb6328ec9c4737c26050471e50803022eb",
|
||||
"y": "0x22cb4aaa555e23bd460262d2130d6a3c9207aa8bbb85060928beb263d6d42a95"
|
||||
},
|
||||
"msg": "",
|
||||
"u": [
|
||||
"0x7f3e7fb9428103ad7f52db32f9df32505d7b427d894c5093f7a0f0374a30641d"
|
||||
]
|
||||
},
|
||||
{
|
||||
"P": {
|
||||
"x": "0x5f13cc69c891d86927eb37bd4afc6672360007c63f68a33ab423a3aa040fd2a8",
|
||||
"y": "0x67732d50f9a26f73111dd1ed5dba225614e538599db58ba30aaea1f5c827fa42"
|
||||
},
|
||||
"Q": {
|
||||
"x": "0x333e41b61c6dd43af220c1ac34a3663e1cf537f996bab50ab66e33c4bd8e4e19",
|
||||
"y": "0x51b6f178eb08c4a782c820e306b82c6e273ab22e258d972cd0c511787b2a3443"
|
||||
},
|
||||
"msg": "abc",
|
||||
"u": [
|
||||
"0x09cfa30ad79bd59456594a0f5d3a76f6b71c6787b04de98be5cd201a556e253b"
|
||||
]
|
||||
},
|
||||
{
|
||||
"P": {
|
||||
"x": "0x1dd2fefce934ecfd7aae6ec998de088d7dd03316aa1847198aecf699ba6613f1",
|
||||
"y": "0x2f8a6c24dd1adde73909cada6a4a137577b0f179d336685c4a955a0a8e1a86fb"
|
||||
},
|
||||
"Q": {
|
||||
"x": "0x55186c242c78e7d0ec5b6c9553f04c6aeef64e69ec2e824472394da32647cfc6",
|
||||
"y": "0x5b9ea3c265ee42256a8f724f616307ef38496ef7eba391c08f99f3bea6fa88f0"
|
||||
},
|
||||
"msg": "abcdef0123456789",
|
||||
"u": [
|
||||
"0x475ccff99225ef90d78cc9338e9f6a6bb7b17607c0c4428937de75d33edba941"
|
||||
]
|
||||
},
|
||||
{
|
||||
"P": {
|
||||
"x": "0x35fbdc5143e8a97afd3096f2b843e07df72e15bfca2eaf6879bf97c5d3362f73",
|
||||
"y": "0x2af6ff6ef5ebba128b0774f4296cb4c2279a074658b083b8dcca91f57a603450"
|
||||
},
|
||||
"Q": {
|
||||
"x": "0x024b6e1621606dca8071aa97b43dce4040ca78284f2a527dcf5d0fbfac2b07e7",
|
||||
"y": "0x5102353883d739bdc9f8a3af650342b171217167dcce34f8db57208ec1dfdbf2"
|
||||
},
|
||||
"msg": "q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq",
|
||||
"u": [
|
||||
"0x049a1c8bd51bcb2aec339f387d1ff51428b88d0763a91bcdf6929814ac95d03d"
|
||||
]
|
||||
},
|
||||
{
|
||||
"P": {
|
||||
"x": "0x6e5e1f37e99345887fc12111575fc1c3e36df4b289b8759d23af14d774b66bff",
|
||||
"y": "0x2c90c3d39eb18ff291d33441b35f3262cdd307162cc97c31bfcc7a4245891a37"
|
||||
},
|
||||
"Q": {
|
||||
"x": "0x3e6368cff6e88a58e250c54bd27d2c989ae9b3acb6067f2651ad282ab8c21cd9",
|
||||
"y": "0x38fb39f1566ca118ae6c7af42810c0bb9767ae5960abb5a8ca792530bfb9447d"
|
||||
},
|
||||
"msg": "a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
||||
"u": [
|
||||
"0x3cb0178a8137cefa5b79a3a57c858d7eeeaa787b2781be4a362a2f0750d24fa0"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
115
test/hash-to-curve/edwards25519_XMD:SHA-512_ELL2_RO_.json
Normal file
115
test/hash-to-curve/edwards25519_XMD:SHA-512_ELL2_RO_.json
Normal file
@@ -0,0 +1,115 @@
|
||||
{
|
||||
"L": "0x30",
|
||||
"Z": "0x2",
|
||||
"ciphersuite": "edwards25519_XMD:SHA-512_ELL2_RO_",
|
||||
"curve": "edwards25519",
|
||||
"dst": "QUUX-V01-CS02-with-edwards25519_XMD:SHA-512_ELL2_RO_",
|
||||
"expand": "XMD",
|
||||
"field": {
|
||||
"m": "0x1",
|
||||
"p": "0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffed"
|
||||
},
|
||||
"hash": "sha512",
|
||||
"k": "0x80",
|
||||
"map": {
|
||||
"name": "ELL2"
|
||||
},
|
||||
"randomOracle": true,
|
||||
"vectors": [
|
||||
{
|
||||
"P": {
|
||||
"x": "0x3c3da6925a3c3c268448dcabb47ccde5439559d9599646a8260e47b1e4822fc6",
|
||||
"y": "0x09a6c8561a0b22bef63124c588ce4c62ea83a3c899763af26d795302e115dc21"
|
||||
},
|
||||
"Q0": {
|
||||
"x": "0x6549118f65bb617b9e8b438decedc73c496eaed496806d3b2eb9ee60b88e09a7",
|
||||
"y": "0x7315bcc8cf47ed68048d22bad602c6680b3382a08c7c5d3f439a973fb4cf9feb"
|
||||
},
|
||||
"Q1": {
|
||||
"x": "0x31dcfc5c58aa1bee6e760bf78cbe71c2bead8cebb2e397ece0f37a3da19c9ed2",
|
||||
"y": "0x7876d81474828d8a5928b50c82420b2bd0898d819e9550c5c82c39fc9bafa196"
|
||||
},
|
||||
"msg": "",
|
||||
"u": [
|
||||
"0x03fef4813c8cb5f98c6eef88fae174e6e7d5380de2b007799ac7ee712d203f3a",
|
||||
"0x780bdddd137290c8f589dc687795aafae35f6b674668d92bf92ae793e6a60c75"
|
||||
]
|
||||
},
|
||||
{
|
||||
"P": {
|
||||
"x": "0x608040b42285cc0d72cbb3985c6b04c935370c7361f4b7fbdb1ae7f8c1a8ecad",
|
||||
"y": "0x1a8395b88338f22e435bbd301183e7f20a5f9de643f11882fb237f88268a5531"
|
||||
},
|
||||
"Q0": {
|
||||
"x": "0x5c1525bd5d4b4e034512949d187c39d48e8cd84242aa4758956e4adc7d445573",
|
||||
"y": "0x2bf426cf7122d1a90abc7f2d108befc2ef415ce8c2d09695a7407240faa01f29"
|
||||
},
|
||||
"Q1": {
|
||||
"x": "0x37b03bba828860c6b459ddad476c83e0f9285787a269df2156219b7e5c86210c",
|
||||
"y": "0x285ebf5412f84d0ad7bb4e136729a9ffd2195d5b8e73c0dc85110ce06958f432"
|
||||
},
|
||||
"msg": "abc",
|
||||
"u": [
|
||||
"0x5081955c4141e4e7d02ec0e36becffaa1934df4d7a270f70679c78f9bd57c227",
|
||||
"0x005bdc17a9b378b6272573a31b04361f21c371b256252ae5463119aa0b925b76"
|
||||
]
|
||||
},
|
||||
{
|
||||
"P": {
|
||||
"x": "0x6d7fabf47a2dc03fe7d47f7dddd21082c5fb8f86743cd020f3fb147d57161472",
|
||||
"y": "0x53060a3d140e7fbcda641ed3cf42c88a75411e648a1add71217f70ea8ec561a6"
|
||||
},
|
||||
"Q0": {
|
||||
"x": "0x3ac463dd7fddb773b069c5b2b01c0f6b340638f54ee3bd92d452fcec3015b52d",
|
||||
"y": "0x7b03ba1e8db9ec0b390d5c90168a6a0b7107156c994c674b61fe696cbeb46baf"
|
||||
},
|
||||
"Q1": {
|
||||
"x": "0x0757e7e904f5e86d2d2f4acf7e01c63827fde2d363985aa7432106f1b3a444ec",
|
||||
"y": "0x50026c96930a24961e9d86aa91ea1465398ff8e42015e2ec1fa397d416f6a1c0"
|
||||
},
|
||||
"msg": "abcdef0123456789",
|
||||
"u": [
|
||||
"0x285ebaa3be701b79871bcb6e225ecc9b0b32dff2d60424b4c50642636a78d5b3",
|
||||
"0x2e253e6a0ef658fedb8e4bd6a62d1544fd6547922acb3598ec6b369760b81b31"
|
||||
]
|
||||
},
|
||||
{
|
||||
"P": {
|
||||
"x": "0x5fb0b92acedd16f3bcb0ef83f5c7b7a9466b5f1e0d8d217421878ea3686f8524",
|
||||
"y": "0x2eca15e355fcfa39d2982f67ddb0eea138e2994f5956ed37b7f72eea5e89d2f7"
|
||||
},
|
||||
"Q0": {
|
||||
"x": "0x703e69787ea7524541933edf41f94010a201cc841c1cce60205ec38513458872",
|
||||
"y": "0x32bb192c4f89106466f0874f5fd56a0d6b6f101cb714777983336c159a9bec75"
|
||||
},
|
||||
"Q1": {
|
||||
"x": "0x0c9077c5c31720ed9413abe59bf49ce768506128d810cb882435aa90f713ef6b",
|
||||
"y": "0x7d5aec5210db638c53f050597964b74d6dda4be5b54fa73041bf909ccb3826cb"
|
||||
},
|
||||
"msg": "q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq",
|
||||
"u": [
|
||||
"0x4fedd25431c41f2a606952e2945ef5e3ac905a42cf64b8b4d4a83c533bf321af",
|
||||
"0x02f20716a5801b843987097a8276b6d869295b2e11253751ca72c109d37485a9"
|
||||
]
|
||||
},
|
||||
{
|
||||
"P": {
|
||||
"x": "0x0efcfde5898a839b00997fbe40d2ebe950bc81181afbd5cd6b9618aa336c1e8c",
|
||||
"y": "0x6dc2fc04f266c5c27f236a80b14f92ccd051ef1ff027f26a07f8c0f327d8f995"
|
||||
},
|
||||
"Q0": {
|
||||
"x": "0x21091b2e3f9258c7dfa075e7ae513325a94a3d8a28e1b1cb3b5b6f5d65675592",
|
||||
"y": "0x41a33d324c89f570e0682cdf7bdb78852295daf8084c669f2cc9692896ab5026"
|
||||
},
|
||||
"Q1": {
|
||||
"x": "0x4c07ec48c373e39a23bd7954f9e9b66eeab9e5ee1279b867b3d5315aa815454f",
|
||||
"y": "0x67ccac7c3cb8d1381242d8d6585c57eabaddbb5dca5243a68a8aeb5477d94b3a"
|
||||
},
|
||||
"msg": "a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
||||
"u": [
|
||||
"0x6e34e04a5106e9bd59f64aba49601bf09d23b27f7b594e56d5de06df4a4ea33b",
|
||||
"0x1c1c2cb59fc053f44b86c5d5eb8c1954b64976d0302d3729ff66e84068f5fd96"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
90
test/hash-to-curve/edwards448_XOF:SHAKE256_ELL2_NU_.json
Normal file
90
test/hash-to-curve/edwards448_XOF:SHAKE256_ELL2_NU_.json
Normal file
@@ -0,0 +1,90 @@
|
||||
{
|
||||
"L": "0x54",
|
||||
"Z": "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffffffffffffffffffffffffffffffffffffffffffffffffffffe",
|
||||
"ciphersuite": "edwards448_XOF:SHAKE256_ELL2_NU_",
|
||||
"curve": "edwards448",
|
||||
"dst": "QUUX-V01-CS02-with-edwards448_XOF:SHAKE256_ELL2_NU_",
|
||||
"expand": "XOF",
|
||||
"field": {
|
||||
"m": "0x1",
|
||||
"p": "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
|
||||
},
|
||||
"hash": "shake_256",
|
||||
"k": "0xe0",
|
||||
"map": {
|
||||
"name": "ELL2"
|
||||
},
|
||||
"randomOracle": false,
|
||||
"vectors": [
|
||||
{
|
||||
"P": {
|
||||
"x": "0xeb5a1fc376fd73230af2de0f3374087cc7f279f0460114cf0a6c12d6d044c16de34ec2350c34b26bf110377655ab77936869d085406af71e",
|
||||
"y": "0xdf5dcea6d42e8f494b279a500d09e895d26ac703d75ca6d118e8ca58bf6f608a2a383f292fce1563ff995dce75aede1fdc8e7c0c737ae9ad"
|
||||
},
|
||||
"Q": {
|
||||
"x": "0x4b2abf8c0fca49d027c2a81bf73bb5990e05f3e76c7ba137cc0b89415ccd55ce7f191cc0c11b0560c1cdc2a8085dd56996079e05a3cd8dde",
|
||||
"y": "0x82532f5b0cb3bfb8542d3228d055bfe61129dbeae8bace80cf61f17725e8ec8226a24f0e687f78f01da88e3b2715194a03dca7c0a96bbf04"
|
||||
},
|
||||
"msg": "",
|
||||
"u": [
|
||||
"0x1368aefc0416867ea2cfc515416bcbeecc9ec81c4ecbd52ccdb91e06996b3f359bc930eef6743c7a2dd7adb785bc7093ed044efed95086d7"
|
||||
]
|
||||
},
|
||||
{
|
||||
"P": {
|
||||
"x": "0x4623a64bceaba3202df76cd8b6e3daf70164f3fcbda6d6e340f7fab5cdf89140d955f722524f5fe4d968fef6ba2853ff4ea086c2f67d8110",
|
||||
"y": "0xabaac321a169761a8802ab5b5d10061fec1a83c670ac6bc95954700317ee5f82870120e0e2c5a21b12a0c7ad17ebd343363604c4bcecafd1"
|
||||
},
|
||||
"Q": {
|
||||
"x": "0xb1ca5bef2f157673a210f56c9b0039db8399e4749585abac64f831f74ed1ec5f591928976c687c06d57686bacb98440e77af878349cdf2d2",
|
||||
"y": "0x5bbfd6a3730d517b03c3cd9e2eed94af12891334ec090e0495c2edc588e9e10b6f63b03a62076808cbcd6da95adfb5af76c136b2d42e0dac"
|
||||
},
|
||||
"msg": "abc",
|
||||
"u": [
|
||||
"0xcda3b0ecfe054c4077007d7300969ec24f4c741300b630ec9188ebab31a5ae0065612ee22d9f793733179ffc2e10c53ca5b539057aafdc2f"
|
||||
]
|
||||
},
|
||||
{
|
||||
"P": {
|
||||
"x": "0xe9eb562e76db093baa43a31b7edd04ec4aadcef3389a7b9c58a19cf87f8ae3d154e134b6b3ed45847a741e33df51903da681629a4b8bcc2e",
|
||||
"y": "0x0cf6606927ad7eb15dbc193993bc7e4dda744b311a8ec4274c8f738f74f605934582474c79260f60280fe35bd37d4347e59184cbfa12cbc4"
|
||||
},
|
||||
"Q": {
|
||||
"x": "0x958a51e2f02e0dfd3930709010d5d16f869adb9d8a8f7c01139911d206c20cdb7bfb40ee33ba30536a99f49362fa7633d0f417fc3914fe21",
|
||||
"y": "0xf4307a36ab6612fa97501497f01afa109733ce85875935551c3ca90f0fa7e0097a8640bb7e5dbcc38ab32b23b748790f2261f2c44c3bf3ba"
|
||||
},
|
||||
"msg": "abcdef0123456789",
|
||||
"u": [
|
||||
"0xd36bae98351512c382c7a3e1eba22497574f11fef9867901b1a2700b39fa2cd0d38ed4380387a99162b7ba0240c743f0532ef60d577c413d"
|
||||
]
|
||||
},
|
||||
{
|
||||
"P": {
|
||||
"x": "0x122a3234d34b26c69749f23356452bf9501efa2d94859d5ef741fef024156d9d191a03a2ad24c38186f93e02d05572575968b083d8a39738",
|
||||
"y": "0xddf55e74eb4414c2c1fa4aa6bc37c4ab470a3fed6bb5af1e43570309b162fb61879bb15f9ea49c712efd42d0a71666430f9f0d4a20505050"
|
||||
},
|
||||
"Q": {
|
||||
"x": "0xe7e1f2d13548ac2c8fcd346e4c63606545bf93652011721e83ac3b64226f77a8823d3881e164bc6ca45505b236e8e3721c028052fcc9ade5",
|
||||
"y": "0x7e0f340501bf25f018b9d374c2acbdd43c07261d85a6ef3c855113d4e023634db59a87b8fab9efe04ed1fee302c8a4994e83bdda32bd9c0b"
|
||||
},
|
||||
"msg": "q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq",
|
||||
"u": [
|
||||
"0x5945744d27122f89da3daf76ab4db9616053df64e25d30ec9a00667ee6710240579c1db8f8ef3386f3f4f413cfb325ac14094d582026a971"
|
||||
]
|
||||
},
|
||||
{
|
||||
"P": {
|
||||
"x": "0x221704949b1ce1ab8dd174dc9b8c56fcffa27179569ce9219c0c2fe183d3d23343a4c42a0e2e9d6b9d0feb1df3883ec489b6671d1fa64089",
|
||||
"y": "0xebdecfdc87142d1a919034bf22ecfad934c9a85effff14b594ae2c00943ca62a39d6ee3be9df0bb504ce8a9e1669bc6959c42ad6a1d3b686"
|
||||
},
|
||||
"Q": {
|
||||
"x": "0x0fd3bb833c1d7a5b319d1d4117406a23b9aece976186ecb18a11a635e6fbdb920d47e04762b1f2a8c59d2f8435d0fdefe501f544cda23dbf",
|
||||
"y": "0xf13b0dad4d5eeb120f2443ac4392f8096a1396f5014ec2a3506a347fef8076a7282035cf619599b1919cf29df5ce87711c11688aab7700a6"
|
||||
},
|
||||
"msg": "a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
||||
"u": [
|
||||
"0x1192e378043f01cedc7ea0209321519213b0184ea0d8575816bcd9182a367823e1eecc2faf1df8f79b24027a4b9bfa208cd320e79bef06ea"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
115
test/hash-to-curve/edwards448_XOF:SHAKE256_ELL2_RO_.json
Normal file
115
test/hash-to-curve/edwards448_XOF:SHAKE256_ELL2_RO_.json
Normal file
@@ -0,0 +1,115 @@
|
||||
{
|
||||
"L": "0x54",
|
||||
"Z": "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffffffffffffffffffffffffffffffffffffffffffffffffffffe",
|
||||
"ciphersuite": "edwards448_XOF:SHAKE256_ELL2_RO_",
|
||||
"curve": "edwards448",
|
||||
"dst": "QUUX-V01-CS02-with-edwards448_XOF:SHAKE256_ELL2_RO_",
|
||||
"expand": "XOF",
|
||||
"field": {
|
||||
"m": "0x1",
|
||||
"p": "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
|
||||
},
|
||||
"hash": "shake_256",
|
||||
"k": "0xe0",
|
||||
"map": {
|
||||
"name": "ELL2"
|
||||
},
|
||||
"randomOracle": true,
|
||||
"vectors": [
|
||||
{
|
||||
"P": {
|
||||
"x": "0x73036d4a88949c032f01507005c133884e2f0d81f9a950826245dda9e844fc78186c39daaa7147ead3e462cff60e9c6340b58134480b4d17",
|
||||
"y": "0x94c1d61b43728e5d784ef4fcb1f38e1075f3aef5e99866911de5a234f1aafdc26b554344742e6ba0420b71b298671bbeb2b7736618634610"
|
||||
},
|
||||
"Q0": {
|
||||
"x": "0xc08177330869db17fb81a5e6e53b36d29086d806269760f2e4cabaa4015f5dbadb7ca2ba594d96a89d0ca4f0944489e1ef393d53db85096f",
|
||||
"y": "0x02e894598c050eeb7195f5791f1a5f65da3776b7534be37640bcbf95d4b915bd22333c50387583507169708fbd7bea0d7aa385dcc614be9c"
|
||||
},
|
||||
"Q1": {
|
||||
"x": "0x770877fd3b6c5503398157b68a9d3609f585f40e1ebebdd69bb0e4d3d9aa811995ce75333fdadfa50db886a35959cc59cffd5c9710daca25",
|
||||
"y": "0xb27fef77aa6231fbbc27538fa90eaca8abd03eb1e62fdae4ec5e828117c3b8b3ff8c34d0a6e6d79fff16d339b94ae8ede33331d5b464c792"
|
||||
},
|
||||
"msg": "",
|
||||
"u": [
|
||||
"0x0847c5ebf957d3370b1f98fde499fb3e659996d9fc9b5707176ade785ba72cd84b8a5597c12b1024be5f510fa5ba99642c4cec7f3f69d3e7",
|
||||
"0xf8cbd8a7ae8c8deed071f3ac4b93e7cfcb8f1eac1645d699fd6d3881cb295a5d3006d9449ed7cad412a77a1fe61e84a9e41d59ef384d6f9a"
|
||||
]
|
||||
},
|
||||
{
|
||||
"P": {
|
||||
"x": "0x4e0158acacffa545adb818a6ed8e0b870e6abc24dfc1dc45cf9a052e98469275d9ff0c168d6a5ac7ec05b742412ee090581f12aa398f9f8c",
|
||||
"y": "0x894d3fa437b2d2e28cdc3bfaade035430f350ec5239b6b406b5501da6f6d6210ff26719cad83b63e97ab26a12df6dec851d6bf38e294af9a"
|
||||
},
|
||||
"Q0": {
|
||||
"x": "0x7544612a97f4419c94ab0f621a1ee8ccf46c6657b8e0778ec9718bf4b41bc774487ad87d9b1e617aa49d3a4dd35a3cf57cd390ebf0429952",
|
||||
"y": "0xd3ab703e60267d796b485bb58a28f934bd0133a6d1bbdfeda5277fa293310be262d7f653a5adffa608c37ed45c0e6008e54a16e1a342e4df"
|
||||
},
|
||||
"Q1": {
|
||||
"x": "0x6262f18d064bc131ade1b8bbcf1cbdf984f4f88153fcc9f94c888af35d5e41aae84c12f169a55d8abf06e6de6c5b23079e587a58cf73303e",
|
||||
"y": "0x6d57589e901abe7d947c93ab02c307ad9093ed9a83eb0b6e829fb7318d590381ca25f3cc628a36a924a9ddfcf3cbedf94edf3b338ea77403"
|
||||
},
|
||||
"msg": "abc",
|
||||
"u": [
|
||||
"0x04d975cd938ab49be3e81703d6a57cca84ed80d2ff6d4756d3f22947fb5b70ab0231f0087cbfb4b7cae73b41b0c9396b356a4831d9a14322",
|
||||
"0x2547ca887ac3db7b5fad3a098aa476e90078afe1358af6c63d677d6edfd2100bc004e0f5db94dd2560fc5b308e223241d00488c9ca6b0ef2"
|
||||
]
|
||||
},
|
||||
{
|
||||
"P": {
|
||||
"x": "0x2c25b4503fadc94b27391933b557abdecc601c13ed51c5de68389484f93dbd6c22e5f962d9babf7a39f39f994312f8ca23344847e1fbf176",
|
||||
"y": "0xd5e6f5350f430e53a110f5ac7fcc82a96cb865aeca982029522d32601e41c042a9dfbdfbefa2b0bdcdc3bc58cca8a7cd546803083d3a8548"
|
||||
},
|
||||
"Q0": {
|
||||
"x": "0x1457b60c12e00e47ceb3ce64b57e7c3c61636475443d704a8e2b2ab0a5ac7e4b3909435416784e16e19929c653b1bdcd9478a8e5331ca9ae",
|
||||
"y": "0x935d9f75f7a0babbc39c0a1c3b412518ed8a24bc2c4886722fb4b7d4a747af98e4e2528c75221e2dffd3424abb436e10539a74caaafa3ea3"
|
||||
},
|
||||
"Q1": {
|
||||
"x": "0xb44d9e34211b4028f24117e856585ed81448f3c8b934987a1c5939c86048737a08d85934fec6b3c2ef9f09cbd365cf22744f2e4ce69762a4",
|
||||
"y": "0xdc996c1736f4319868f897d9a27c45b02dd3bc6b7ca356a039606e5406e131a0bbe8238208b327b00853e8af84b58b13443e705425563323"
|
||||
},
|
||||
"msg": "abcdef0123456789",
|
||||
"u": [
|
||||
"0x10659ce25588db4e4be6f7c791a79eb21a7f24aaaca76a6ca3b83b80aaf95aa328fe7d569a1ac99f9cd216edf3915d72632f1a8b990e250c",
|
||||
"0x9243e5b6c480683fd533e81f4a778349a309ce00bd163a29eb9fa8dbc8f549242bef33e030db21cffacd408d2c4264b93e476c6a8590e7aa"
|
||||
]
|
||||
},
|
||||
{
|
||||
"P": {
|
||||
"x": "0xa1861a9464ae31249a0e60bf38791f3663049a3f5378998499a83292e159a2fecff838eb9bc6939e5c6ae76eb074ad4aae39b55b72ca0b9a",
|
||||
"y": "0x580a2798c5b904f8adfec5bd29fb49b4633cd9f8c2935eb4a0f12e5dfa0285680880296bb729c6405337525fb5ed3dff930c137314f60401"
|
||||
},
|
||||
"Q0": {
|
||||
"x": "0x9d355251e245e4b13ed4ea3e5a3c55bf9b7211f1704771f2e1d8f1a65610c468b1cf70c6c2ce30dcaad54ad9e5439471ec554b862ec8875a",
|
||||
"y": "0x6689ba36a242af69ac2aadb955d15e982d9b04f5d77f7609ebf7429587feb7e5ce27490b9c72114509f89565122074e46a614d7fd7c800bd"
|
||||
},
|
||||
"Q1": {
|
||||
"x": "0xc4b3d3ad4d2d62739a62989532992c1081e9474a201085b4616da5706cab824693b9fb428a201bcd1639a4588cc43b9eb841dbca74219b1f",
|
||||
"y": "0x265286f5dee8f3d894b5649da8565b58e96b4cfd44b462a2883ea64dbcda21a00706ea3fea53fc2d769084b0b74589e91d0384d7118909fb"
|
||||
},
|
||||
"msg": "q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq",
|
||||
"u": [
|
||||
"0xc80390020e578f009ead417029eff6cd0926110922db63ab98395e3bdfdd5d8a65b1a2b8d495dc8c5e59b7f3518731f7dfc0f93ace5dee4b",
|
||||
"0x1c4dc6653a445bbef2add81d8e90a6c8591a788deb91d0d3f1519a2e4a460313041b77c1b0817f2e80b388e5c3e49f37d787dc1f85e4324a"
|
||||
]
|
||||
},
|
||||
{
|
||||
"P": {
|
||||
"x": "0x987c5ac19dd4b47835466a50b2d9feba7c8491b8885a04edf577e15a9f2c98b203ec2cd3e5390b3d20bba0fa6fc3eecefb5029a317234401",
|
||||
"y": "0x5e273fcfff6b007bb6771e90509275a71ff1480c459ded26fc7b10664db0a68aaa98bc7ecb07e49cf05b80ae5ac653fbdd14276bbd35ccbc"
|
||||
},
|
||||
"Q0": {
|
||||
"x": "0xd1a5eba4a332514b69760948af09ceaeddbbb9fd4cb1f19b78349c2ee4cf9ee86dbcf9064659a4a0566fe9c34d90aec86f0801edc131ad9b",
|
||||
"y": "0x5d0a75a3014c3269c33b1b5da80706a4f097893461df286353484d8031cd607c98edc2a846c77a841f057c7251eb45077853c7b205957e52"
|
||||
},
|
||||
"Q1": {
|
||||
"x": "0x69583b00dc6b2aced6ffa44630cc8c8cd0dd0649f57588dd0fb1daad2ce132e281d01e3f25ccd3f405be759975c6484268bfe8f5e5f23c30",
|
||||
"y": "0x8418484035f60bdccf48cb488634c2dfb40272123435f7e654fb6f254c6c42e7e38f1fa79a637a168a28de6c275232b704f9ded0ff76dd94"
|
||||
},
|
||||
"msg": "a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
||||
"u": [
|
||||
"0x163c79ab0210a4b5e4f44fb19437ea965bf5431ab233ef16606f0b03c5f16a3feb7d46a5a675ce8f606e9c2bf74ee5336c54a1e54919f13f",
|
||||
"0xf99666bde4995c4088333d6c2734687e815f80a99c6da02c47df4b51f6c9d9ed466b4fecf7d9884990a8e0d0be6907fa437e0b1a27f49265"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
78
test/hash-to-curve/expand_message_xmd_SHA256_256.json
Normal file
78
test/hash-to-curve/expand_message_xmd_SHA256_256.json
Normal file
@@ -0,0 +1,78 @@
|
||||
{
|
||||
"DST": "QUUX-V01-CS02-with-expander-SHA256-128-long-DST-1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111",
|
||||
"hash": "SHA256",
|
||||
"k": 128,
|
||||
"name": "expand_message_xmd",
|
||||
"tests": [
|
||||
{
|
||||
"DST_prime": "412717974da474d0f8c420f320ff81e8432adb7c927d9bd082b4fb4d16c0a23620",
|
||||
"len_in_bytes": "0x20",
|
||||
"msg": "",
|
||||
"msg_prime": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000412717974da474d0f8c420f320ff81e8432adb7c927d9bd082b4fb4d16c0a23620",
|
||||
"uniform_bytes": "e8dc0c8b686b7ef2074086fbdd2f30e3f8bfbd3bdf177f73f04b97ce618a3ed3"
|
||||
},
|
||||
{
|
||||
"DST_prime": "412717974da474d0f8c420f320ff81e8432adb7c927d9bd082b4fb4d16c0a23620",
|
||||
"len_in_bytes": "0x20",
|
||||
"msg": "abc",
|
||||
"msg_prime": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000616263002000412717974da474d0f8c420f320ff81e8432adb7c927d9bd082b4fb4d16c0a23620",
|
||||
"uniform_bytes": "52dbf4f36cf560fca57dedec2ad924ee9c266341d8f3d6afe5171733b16bbb12"
|
||||
},
|
||||
{
|
||||
"DST_prime": "412717974da474d0f8c420f320ff81e8432adb7c927d9bd082b4fb4d16c0a23620",
|
||||
"len_in_bytes": "0x20",
|
||||
"msg": "abcdef0123456789",
|
||||
"msg_prime": "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000061626364656630313233343536373839002000412717974da474d0f8c420f320ff81e8432adb7c927d9bd082b4fb4d16c0a23620",
|
||||
"uniform_bytes": "35387dcf22618f3728e6c686490f8b431f76550b0b2c61cbc1ce7001536f4521"
|
||||
},
|
||||
{
|
||||
"DST_prime": "412717974da474d0f8c420f320ff81e8432adb7c927d9bd082b4fb4d16c0a23620",
|
||||
"len_in_bytes": "0x20",
|
||||
"msg": "q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq",
|
||||
"msg_prime": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000713132385f7171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171002000412717974da474d0f8c420f320ff81e8432adb7c927d9bd082b4fb4d16c0a23620",
|
||||
"uniform_bytes": "01b637612bb18e840028be900a833a74414140dde0c4754c198532c3a0ba42bc"
|
||||
},
|
||||
{
|
||||
"DST_prime": "412717974da474d0f8c420f320ff81e8432adb7c927d9bd082b4fb4d16c0a23620",
|
||||
"len_in_bytes": "0x20",
|
||||
"msg": "a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
||||
"msg_prime": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000613531325f6161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161002000412717974da474d0f8c420f320ff81e8432adb7c927d9bd082b4fb4d16c0a23620",
|
||||
"uniform_bytes": "20cce7033cabc5460743180be6fa8aac5a103f56d481cf369a8accc0c374431b"
|
||||
},
|
||||
{
|
||||
"DST_prime": "412717974da474d0f8c420f320ff81e8432adb7c927d9bd082b4fb4d16c0a23620",
|
||||
"len_in_bytes": "0x80",
|
||||
"msg": "",
|
||||
"msg_prime": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000412717974da474d0f8c420f320ff81e8432adb7c927d9bd082b4fb4d16c0a23620",
|
||||
"uniform_bytes": "14604d85432c68b757e485c8894db3117992fc57e0e136f71ad987f789a0abc287c47876978e2388a02af86b1e8d1342e5ce4f7aaa07a87321e691f6fba7e0072eecc1218aebb89fb14a0662322d5edbd873f0eb35260145cd4e64f748c5dfe60567e126604bcab1a3ee2dc0778102ae8a5cfd1429ebc0fa6bf1a53c36f55dfc"
|
||||
},
|
||||
{
|
||||
"DST_prime": "412717974da474d0f8c420f320ff81e8432adb7c927d9bd082b4fb4d16c0a23620",
|
||||
"len_in_bytes": "0x80",
|
||||
"msg": "abc",
|
||||
"msg_prime": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000616263008000412717974da474d0f8c420f320ff81e8432adb7c927d9bd082b4fb4d16c0a23620",
|
||||
"uniform_bytes": "1a30a5e36fbdb87077552b9d18b9f0aee16e80181d5b951d0471d55b66684914aef87dbb3626eaabf5ded8cd0686567e503853e5c84c259ba0efc37f71c839da2129fe81afdaec7fbdc0ccd4c794727a17c0d20ff0ea55e1389d6982d1241cb8d165762dbc39fb0cee4474d2cbbd468a835ae5b2f20e4f959f56ab24cd6fe267"
|
||||
},
|
||||
{
|
||||
"DST_prime": "412717974da474d0f8c420f320ff81e8432adb7c927d9bd082b4fb4d16c0a23620",
|
||||
"len_in_bytes": "0x80",
|
||||
"msg": "abcdef0123456789",
|
||||
"msg_prime": "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000061626364656630313233343536373839008000412717974da474d0f8c420f320ff81e8432adb7c927d9bd082b4fb4d16c0a23620",
|
||||
"uniform_bytes": "d2ecef3635d2397f34a9f86438d772db19ffe9924e28a1caf6f1c8f15603d4028f40891044e5c7e39ebb9b31339979ff33a4249206f67d4a1e7c765410bcd249ad78d407e303675918f20f26ce6d7027ed3774512ef5b00d816e51bfcc96c3539601fa48ef1c07e494bdc37054ba96ecb9dbd666417e3de289d4f424f502a982"
|
||||
},
|
||||
{
|
||||
"DST_prime": "412717974da474d0f8c420f320ff81e8432adb7c927d9bd082b4fb4d16c0a23620",
|
||||
"len_in_bytes": "0x80",
|
||||
"msg": "q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq",
|
||||
"msg_prime": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000713132385f7171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171008000412717974da474d0f8c420f320ff81e8432adb7c927d9bd082b4fb4d16c0a23620",
|
||||
"uniform_bytes": "ed6e8c036df90111410431431a232d41a32c86e296c05d426e5f44e75b9a50d335b2412bc6c91e0a6dc131de09c43110d9180d0a70f0d6289cb4e43b05f7ee5e9b3f42a1fad0f31bac6a625b3b5c50e3a83316783b649e5ecc9d3b1d9471cb5024b7ccf40d41d1751a04ca0356548bc6e703fca02ab521b505e8e45600508d32"
|
||||
},
|
||||
{
|
||||
"DST_prime": "412717974da474d0f8c420f320ff81e8432adb7c927d9bd082b4fb4d16c0a23620",
|
||||
"len_in_bytes": "0x80",
|
||||
"msg": "a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
||||
"msg_prime": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000613531325f6161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161008000412717974da474d0f8c420f320ff81e8432adb7c927d9bd082b4fb4d16c0a23620",
|
||||
"uniform_bytes": "78b53f2413f3c688f07732c10e5ced29a17c6a16f717179ffbe38d92d6c9ec296502eb9889af83a1928cd162e845b0d3c5424e83280fed3d10cffb2f8431f14e7a23f4c68819d40617589e4c41169d0b56e0e3535be1fd71fbb08bb70c5b5ffed953d6c14bf7618b35fc1f4c4b30538236b4b08c9fbf90462447a8ada60be495"
|
||||
}
|
||||
]
|
||||
}
|
||||
78
test/hash-to-curve/expand_message_xmd_SHA256_38.json
Normal file
78
test/hash-to-curve/expand_message_xmd_SHA256_38.json
Normal file
@@ -0,0 +1,78 @@
|
||||
{
|
||||
"DST": "QUUX-V01-CS02-with-expander-SHA256-128",
|
||||
"hash": "SHA256",
|
||||
"k": 128,
|
||||
"name": "expand_message_xmd",
|
||||
"tests": [
|
||||
{
|
||||
"DST_prime": "515555582d5630312d435330322d776974682d657870616e6465722d5348413235362d31323826",
|
||||
"len_in_bytes": "0x20",
|
||||
"msg": "",
|
||||
"msg_prime": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000515555582d5630312d435330322d776974682d657870616e6465722d5348413235362d31323826",
|
||||
"uniform_bytes": "68a985b87eb6b46952128911f2a4412bbc302a9d759667f87f7a21d803f07235"
|
||||
},
|
||||
{
|
||||
"DST_prime": "515555582d5630312d435330322d776974682d657870616e6465722d5348413235362d31323826",
|
||||
"len_in_bytes": "0x20",
|
||||
"msg": "abc",
|
||||
"msg_prime": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000616263002000515555582d5630312d435330322d776974682d657870616e6465722d5348413235362d31323826",
|
||||
"uniform_bytes": "d8ccab23b5985ccea865c6c97b6e5b8350e794e603b4b97902f53a8a0d605615"
|
||||
},
|
||||
{
|
||||
"DST_prime": "515555582d5630312d435330322d776974682d657870616e6465722d5348413235362d31323826",
|
||||
"len_in_bytes": "0x20",
|
||||
"msg": "abcdef0123456789",
|
||||
"msg_prime": "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000061626364656630313233343536373839002000515555582d5630312d435330322d776974682d657870616e6465722d5348413235362d31323826",
|
||||
"uniform_bytes": "eff31487c770a893cfb36f912fbfcbff40d5661771ca4b2cb4eafe524333f5c1"
|
||||
},
|
||||
{
|
||||
"DST_prime": "515555582d5630312d435330322d776974682d657870616e6465722d5348413235362d31323826",
|
||||
"len_in_bytes": "0x20",
|
||||
"msg": "q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq",
|
||||
"msg_prime": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000713132385f7171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171002000515555582d5630312d435330322d776974682d657870616e6465722d5348413235362d31323826",
|
||||
"uniform_bytes": "b23a1d2b4d97b2ef7785562a7e8bac7eed54ed6e97e29aa51bfe3f12ddad1ff9"
|
||||
},
|
||||
{
|
||||
"DST_prime": "515555582d5630312d435330322d776974682d657870616e6465722d5348413235362d31323826",
|
||||
"len_in_bytes": "0x20",
|
||||
"msg": "a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
||||
"msg_prime": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000613531325f6161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161002000515555582d5630312d435330322d776974682d657870616e6465722d5348413235362d31323826",
|
||||
"uniform_bytes": "4623227bcc01293b8c130bf771da8c298dede7383243dc0993d2d94823958c4c"
|
||||
},
|
||||
{
|
||||
"DST_prime": "515555582d5630312d435330322d776974682d657870616e6465722d5348413235362d31323826",
|
||||
"len_in_bytes": "0x80",
|
||||
"msg": "",
|
||||
"msg_prime": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000515555582d5630312d435330322d776974682d657870616e6465722d5348413235362d31323826",
|
||||
"uniform_bytes": "af84c27ccfd45d41914fdff5df25293e221afc53d8ad2ac06d5e3e29485dadbee0d121587713a3e0dd4d5e69e93eb7cd4f5df4cd103e188cf60cb02edc3edf18eda8576c412b18ffb658e3dd6ec849469b979d444cf7b26911a08e63cf31f9dcc541708d3491184472c2c29bb749d4286b004ceb5ee6b9a7fa5b646c993f0ced"
|
||||
},
|
||||
{
|
||||
"DST_prime": "515555582d5630312d435330322d776974682d657870616e6465722d5348413235362d31323826",
|
||||
"len_in_bytes": "0x80",
|
||||
"msg": "abc",
|
||||
"msg_prime": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000616263008000515555582d5630312d435330322d776974682d657870616e6465722d5348413235362d31323826",
|
||||
"uniform_bytes": "abba86a6129e366fc877aab32fc4ffc70120d8996c88aee2fe4b32d6c7b6437a647e6c3163d40b76a73cf6a5674ef1d890f95b664ee0afa5359a5c4e07985635bbecbac65d747d3d2da7ec2b8221b17b0ca9dc8a1ac1c07ea6a1e60583e2cb00058e77b7b72a298425cd1b941ad4ec65e8afc50303a22c0f99b0509b4c895f40"
|
||||
},
|
||||
{
|
||||
"DST_prime": "515555582d5630312d435330322d776974682d657870616e6465722d5348413235362d31323826",
|
||||
"len_in_bytes": "0x80",
|
||||
"msg": "abcdef0123456789",
|
||||
"msg_prime": "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000061626364656630313233343536373839008000515555582d5630312d435330322d776974682d657870616e6465722d5348413235362d31323826",
|
||||
"uniform_bytes": "ef904a29bffc4cf9ee82832451c946ac3c8f8058ae97d8d629831a74c6572bd9ebd0df635cd1f208e2038e760c4994984ce73f0d55ea9f22af83ba4734569d4bc95e18350f740c07eef653cbb9f87910d833751825f0ebefa1abe5420bb52be14cf489b37fe1a72f7de2d10be453b2c9d9eb20c7e3f6edc5a60629178d9478df"
|
||||
},
|
||||
{
|
||||
"DST_prime": "515555582d5630312d435330322d776974682d657870616e6465722d5348413235362d31323826",
|
||||
"len_in_bytes": "0x80",
|
||||
"msg": "q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq",
|
||||
"msg_prime": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000713132385f7171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171008000515555582d5630312d435330322d776974682d657870616e6465722d5348413235362d31323826",
|
||||
"uniform_bytes": "80be107d0884f0d881bb460322f0443d38bd222db8bd0b0a5312a6fedb49c1bbd88fd75d8b9a09486c60123dfa1d73c1cc3169761b17476d3c6b7cbbd727acd0e2c942f4dd96ae3da5de368d26b32286e32de7e5a8cb2949f866a0b80c58116b29fa7fabb3ea7d520ee603e0c25bcaf0b9a5e92ec6a1fe4e0391d1cdbce8c68a"
|
||||
},
|
||||
{
|
||||
"DST_prime": "515555582d5630312d435330322d776974682d657870616e6465722d5348413235362d31323826",
|
||||
"len_in_bytes": "0x80",
|
||||
"msg": "a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
||||
"msg_prime": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000613531325f6161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161008000515555582d5630312d435330322d776974682d657870616e6465722d5348413235362d31323826",
|
||||
"uniform_bytes": "546aff5444b5b79aa6148bd81728704c32decb73a3ba76e9e75885cad9def1d06d6792f8a7d12794e90efed817d96920d728896a4510864370c207f99bd4a608ea121700ef01ed879745ee3e4ceef777eda6d9e5e38b90c86ea6fb0b36504ba4a45d22e86f6db5dd43d98a294bebb9125d5b794e9d2a81181066eb954966a487"
|
||||
}
|
||||
]
|
||||
}
|
||||
78
test/hash-to-curve/expand_message_xmd_SHA512_38.json
Normal file
78
test/hash-to-curve/expand_message_xmd_SHA512_38.json
Normal file
@@ -0,0 +1,78 @@
|
||||
{
|
||||
"DST": "QUUX-V01-CS02-with-expander-SHA512-256",
|
||||
"hash": "SHA512",
|
||||
"k": 256,
|
||||
"name": "expand_message_xmd",
|
||||
"tests": [
|
||||
{
|
||||
"DST_prime": "515555582d5630312d435330322d776974682d657870616e6465722d5348413531322d32353626",
|
||||
"len_in_bytes": "0x20",
|
||||
"msg": "",
|
||||
"msg_prime": "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000515555582d5630312d435330322d776974682d657870616e6465722d5348413531322d32353626",
|
||||
"uniform_bytes": "6b9a7312411d92f921c6f68ca0b6380730a1a4d982c507211a90964c394179ba"
|
||||
},
|
||||
{
|
||||
"DST_prime": "515555582d5630312d435330322d776974682d657870616e6465722d5348413531322d32353626",
|
||||
"len_in_bytes": "0x20",
|
||||
"msg": "abc",
|
||||
"msg_prime": "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000616263002000515555582d5630312d435330322d776974682d657870616e6465722d5348413531322d32353626",
|
||||
"uniform_bytes": "0da749f12fbe5483eb066a5f595055679b976e93abe9be6f0f6318bce7aca8dc"
|
||||
},
|
||||
{
|
||||
"DST_prime": "515555582d5630312d435330322d776974682d657870616e6465722d5348413531322d32353626",
|
||||
"len_in_bytes": "0x20",
|
||||
"msg": "abcdef0123456789",
|
||||
"msg_prime": "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000061626364656630313233343536373839002000515555582d5630312d435330322d776974682d657870616e6465722d5348413531322d32353626",
|
||||
"uniform_bytes": "087e45a86e2939ee8b91100af1583c4938e0f5fc6c9db4b107b83346bc967f58"
|
||||
},
|
||||
{
|
||||
"DST_prime": "515555582d5630312d435330322d776974682d657870616e6465722d5348413531322d32353626",
|
||||
"len_in_bytes": "0x20",
|
||||
"msg": "q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq",
|
||||
"msg_prime": "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000713132385f7171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171002000515555582d5630312d435330322d776974682d657870616e6465722d5348413531322d32353626",
|
||||
"uniform_bytes": "7336234ee9983902440f6bc35b348352013becd88938d2afec44311caf8356b3"
|
||||
},
|
||||
{
|
||||
"DST_prime": "515555582d5630312d435330322d776974682d657870616e6465722d5348413531322d32353626",
|
||||
"len_in_bytes": "0x20",
|
||||
"msg": "a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
||||
"msg_prime": "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000613531325f6161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161002000515555582d5630312d435330322d776974682d657870616e6465722d5348413531322d32353626",
|
||||
"uniform_bytes": "57b5f7e766d5be68a6bfe1768e3c2b7f1228b3e4b3134956dd73a59b954c66f4"
|
||||
},
|
||||
{
|
||||
"DST_prime": "515555582d5630312d435330322d776974682d657870616e6465722d5348413531322d32353626",
|
||||
"len_in_bytes": "0x80",
|
||||
"msg": "",
|
||||
"msg_prime": "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000515555582d5630312d435330322d776974682d657870616e6465722d5348413531322d32353626",
|
||||
"uniform_bytes": "41b037d1734a5f8df225dd8c7de38f851efdb45c372887be655212d07251b921b052b62eaed99b46f72f2ef4cc96bfaf254ebbbec091e1a3b9e4fb5e5b619d2e0c5414800a1d882b62bb5cd1778f098b8eb6cb399d5d9d18f5d5842cf5d13d7eb00a7cff859b605da678b318bd0e65ebff70bec88c753b159a805d2c89c55961"
|
||||
},
|
||||
{
|
||||
"DST_prime": "515555582d5630312d435330322d776974682d657870616e6465722d5348413531322d32353626",
|
||||
"len_in_bytes": "0x80",
|
||||
"msg": "abc",
|
||||
"msg_prime": "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000616263008000515555582d5630312d435330322d776974682d657870616e6465722d5348413531322d32353626",
|
||||
"uniform_bytes": "7f1dddd13c08b543f2e2037b14cefb255b44c83cc397c1786d975653e36a6b11bdd7732d8b38adb4a0edc26a0cef4bb45217135456e58fbca1703cd6032cb1347ee720b87972d63fbf232587043ed2901bce7f22610c0419751c065922b488431851041310ad659e4b23520e1772ab29dcdeb2002222a363f0c2b1c972b3efe1"
|
||||
},
|
||||
{
|
||||
"DST_prime": "515555582d5630312d435330322d776974682d657870616e6465722d5348413531322d32353626",
|
||||
"len_in_bytes": "0x80",
|
||||
"msg": "abcdef0123456789",
|
||||
"msg_prime": "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000061626364656630313233343536373839008000515555582d5630312d435330322d776974682d657870616e6465722d5348413531322d32353626",
|
||||
"uniform_bytes": "3f721f208e6199fe903545abc26c837ce59ac6fa45733f1baaf0222f8b7acb0424814fcb5eecf6c1d38f06e9d0a6ccfbf85ae612ab8735dfdf9ce84c372a77c8f9e1c1e952c3a61b7567dd0693016af51d2745822663d0c2367e3f4f0bed827feecc2aaf98c949b5ed0d35c3f1023d64ad1407924288d366ea159f46287e61ac"
|
||||
},
|
||||
{
|
||||
"DST_prime": "515555582d5630312d435330322d776974682d657870616e6465722d5348413531322d32353626",
|
||||
"len_in_bytes": "0x80",
|
||||
"msg": "q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq",
|
||||
"msg_prime": "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000713132385f7171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171008000515555582d5630312d435330322d776974682d657870616e6465722d5348413531322d32353626",
|
||||
"uniform_bytes": "b799b045a58c8d2b4334cf54b78260b45eec544f9f2fb5bd12fb603eaee70db7317bf807c406e26373922b7b8920fa29142703dd52bdf280084fb7ef69da78afdf80b3586395b433dc66cde048a258e476a561e9deba7060af40adf30c64249ca7ddea79806ee5beb9a1422949471d267b21bc88e688e4014087a0b592b695ed"
|
||||
},
|
||||
{
|
||||
"DST_prime": "515555582d5630312d435330322d776974682d657870616e6465722d5348413531322d32353626",
|
||||
"len_in_bytes": "0x80",
|
||||
"msg": "a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
||||
"msg_prime": "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000613531325f6161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161008000515555582d5630312d435330322d776974682d657870616e6465722d5348413531322d32353626",
|
||||
"uniform_bytes": "05b0bfef265dcee87654372777b7c44177e2ae4c13a27f103340d9cd11c86cb2426ffcad5bd964080c2aee97f03be1ca18e30a1f14e27bc11ebbd650f305269cc9fb1db08bf90bfc79b42a952b46daf810359e7bc36452684784a64952c343c52e5124cd1f71d474d5197fefc571a92929c9084ffe1112cf5eea5192ebff330b"
|
||||
}
|
||||
]
|
||||
}
|
||||
78
test/hash-to-curve/expand_message_xof_SHAKE128_256.json
Normal file
78
test/hash-to-curve/expand_message_xof_SHAKE128_256.json
Normal file
@@ -0,0 +1,78 @@
|
||||
{
|
||||
"DST": "QUUX-V01-CS02-with-expander-SHAKE128-long-DST-111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111",
|
||||
"hash": "SHAKE128",
|
||||
"k": 128,
|
||||
"name": "expand_message_xof",
|
||||
"tests": [
|
||||
{
|
||||
"DST_prime": "acb9736c0867fdfbd6385519b90fc8c034b5af04a958973212950132d035792f20",
|
||||
"len_in_bytes": "0x20",
|
||||
"msg": "",
|
||||
"msg_prime": "0020acb9736c0867fdfbd6385519b90fc8c034b5af04a958973212950132d035792f20",
|
||||
"uniform_bytes": "827c6216330a122352312bccc0c8d6e7a146c5257a776dbd9ad9d75cd880fc53"
|
||||
},
|
||||
{
|
||||
"DST_prime": "acb9736c0867fdfbd6385519b90fc8c034b5af04a958973212950132d035792f20",
|
||||
"len_in_bytes": "0x20",
|
||||
"msg": "abc",
|
||||
"msg_prime": "6162630020acb9736c0867fdfbd6385519b90fc8c034b5af04a958973212950132d035792f20",
|
||||
"uniform_bytes": "690c8d82c7213b4282c6cb41c00e31ea1d3e2005f93ad19bbf6da40f15790c5c"
|
||||
},
|
||||
{
|
||||
"DST_prime": "acb9736c0867fdfbd6385519b90fc8c034b5af04a958973212950132d035792f20",
|
||||
"len_in_bytes": "0x20",
|
||||
"msg": "abcdef0123456789",
|
||||
"msg_prime": "616263646566303132333435363738390020acb9736c0867fdfbd6385519b90fc8c034b5af04a958973212950132d035792f20",
|
||||
"uniform_bytes": "979e3a15064afbbcf99f62cc09fa9c85028afcf3f825eb0711894dcfc2f57057"
|
||||
},
|
||||
{
|
||||
"DST_prime": "acb9736c0867fdfbd6385519b90fc8c034b5af04a958973212950132d035792f20",
|
||||
"len_in_bytes": "0x20",
|
||||
"msg": "q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq",
|
||||
"msg_prime": "713132385f71717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171710020acb9736c0867fdfbd6385519b90fc8c034b5af04a958973212950132d035792f20",
|
||||
"uniform_bytes": "c5a9220962d9edc212c063f4f65b609755a1ed96e62f9db5d1fd6adb5a8dc52b"
|
||||
},
|
||||
{
|
||||
"DST_prime": "acb9736c0867fdfbd6385519b90fc8c034b5af04a958973212950132d035792f20",
|
||||
"len_in_bytes": "0x20",
|
||||
"msg": "a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
||||
"msg_prime": "613531325f61616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161610020acb9736c0867fdfbd6385519b90fc8c034b5af04a958973212950132d035792f20",
|
||||
"uniform_bytes": "f7b96a5901af5d78ce1d071d9c383cac66a1dfadb508300ec6aeaea0d62d5d62"
|
||||
},
|
||||
{
|
||||
"DST_prime": "acb9736c0867fdfbd6385519b90fc8c034b5af04a958973212950132d035792f20",
|
||||
"len_in_bytes": "0x80",
|
||||
"msg": "",
|
||||
"msg_prime": "0080acb9736c0867fdfbd6385519b90fc8c034b5af04a958973212950132d035792f20",
|
||||
"uniform_bytes": "3890dbab00a2830be398524b71c2713bbef5f4884ac2e6f070b092effdb19208c7df943dc5dcbaee3094a78c267ef276632ee2c8ea0c05363c94b6348500fae4208345dd3475fe0c834c2beac7fa7bc181692fb728c0a53d809fc8111495222ce0f38468b11becb15b32060218e285c57a60162c2c8bb5b6bded13973cd41819"
|
||||
},
|
||||
{
|
||||
"DST_prime": "acb9736c0867fdfbd6385519b90fc8c034b5af04a958973212950132d035792f20",
|
||||
"len_in_bytes": "0x80",
|
||||
"msg": "abc",
|
||||
"msg_prime": "6162630080acb9736c0867fdfbd6385519b90fc8c034b5af04a958973212950132d035792f20",
|
||||
"uniform_bytes": "41b7ffa7a301b5c1441495ebb9774e2a53dbbf4e54b9a1af6a20fd41eafd69ef7b9418599c5545b1ee422f363642b01d4a53449313f68da3e49dddb9cd25b97465170537d45dcbdf92391b5bdff344db4bd06311a05bca7dcd360b6caec849c299133e5c9194f4e15e3e23cfaab4003fab776f6ac0bfae9144c6e2e1c62e7d57"
|
||||
},
|
||||
{
|
||||
"DST_prime": "acb9736c0867fdfbd6385519b90fc8c034b5af04a958973212950132d035792f20",
|
||||
"len_in_bytes": "0x80",
|
||||
"msg": "abcdef0123456789",
|
||||
"msg_prime": "616263646566303132333435363738390080acb9736c0867fdfbd6385519b90fc8c034b5af04a958973212950132d035792f20",
|
||||
"uniform_bytes": "55317e4a21318472cd2290c3082957e1242241d9e0d04f47026f03401643131401071f01aa03038b2783e795bdfa8a3541c194ad5de7cb9c225133e24af6c86e748deb52e560569bd54ef4dac03465111a3a44b0ea490fb36777ff8ea9f1a8a3e8e0de3cf0880b4b2f8dd37d3a85a8b82375aee4fa0e909f9763319b55778e71"
|
||||
},
|
||||
{
|
||||
"DST_prime": "acb9736c0867fdfbd6385519b90fc8c034b5af04a958973212950132d035792f20",
|
||||
"len_in_bytes": "0x80",
|
||||
"msg": "q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq",
|
||||
"msg_prime": "713132385f71717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171710080acb9736c0867fdfbd6385519b90fc8c034b5af04a958973212950132d035792f20",
|
||||
"uniform_bytes": "19fdd2639f082e31c77717ac9bb032a22ff0958382b2dbb39020cdc78f0da43305414806abf9a561cb2d0067eb2f7bc544482f75623438ed4b4e39dd9e6e2909dd858bd8f1d57cd0fce2d3150d90aa67b4498bdf2df98c0100dd1a173436ba5d0df6be1defb0b2ce55ccd2f4fc05eb7cb2c019c35d5398b85adc676da4238bc7"
|
||||
},
|
||||
{
|
||||
"DST_prime": "acb9736c0867fdfbd6385519b90fc8c034b5af04a958973212950132d035792f20",
|
||||
"len_in_bytes": "0x80",
|
||||
"msg": "a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
||||
"msg_prime": "613531325f61616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161610080acb9736c0867fdfbd6385519b90fc8c034b5af04a958973212950132d035792f20",
|
||||
"uniform_bytes": "945373f0b3431a103333ba6a0a34f1efab2702efde41754c4cb1d5216d5b0a92a67458d968562bde7fa6310a83f53dda1383680a276a283438d58ceebfa7ab7ba72499d4a3eddc860595f63c93b1c5e823ea41fc490d938398a26db28f61857698553e93f0574eb8c5017bfed6249491f9976aaa8d23d9485339cc85ca329308"
|
||||
}
|
||||
]
|
||||
}
|
||||
78
test/hash-to-curve/expand_message_xof_SHAKE128_36.json
Normal file
78
test/hash-to-curve/expand_message_xof_SHAKE128_36.json
Normal file
@@ -0,0 +1,78 @@
|
||||
{
|
||||
"DST": "QUUX-V01-CS02-with-expander-SHAKE128",
|
||||
"hash": "SHAKE128",
|
||||
"k": 128,
|
||||
"name": "expand_message_xof",
|
||||
"tests": [
|
||||
{
|
||||
"DST_prime": "515555582d5630312d435330322d776974682d657870616e6465722d5348414b4531323824",
|
||||
"len_in_bytes": "0x20",
|
||||
"msg": "",
|
||||
"msg_prime": "0020515555582d5630312d435330322d776974682d657870616e6465722d5348414b4531323824",
|
||||
"uniform_bytes": "86518c9cd86581486e9485aa74ab35ba150d1c75c88e26b7043e44e2acd735a2"
|
||||
},
|
||||
{
|
||||
"DST_prime": "515555582d5630312d435330322d776974682d657870616e6465722d5348414b4531323824",
|
||||
"len_in_bytes": "0x20",
|
||||
"msg": "abc",
|
||||
"msg_prime": "6162630020515555582d5630312d435330322d776974682d657870616e6465722d5348414b4531323824",
|
||||
"uniform_bytes": "8696af52a4d862417c0763556073f47bc9b9ba43c99b505305cb1ec04a9ab468"
|
||||
},
|
||||
{
|
||||
"DST_prime": "515555582d5630312d435330322d776974682d657870616e6465722d5348414b4531323824",
|
||||
"len_in_bytes": "0x20",
|
||||
"msg": "abcdef0123456789",
|
||||
"msg_prime": "616263646566303132333435363738390020515555582d5630312d435330322d776974682d657870616e6465722d5348414b4531323824",
|
||||
"uniform_bytes": "912c58deac4821c3509dbefa094df54b34b8f5d01a191d1d3108a2c89077acca"
|
||||
},
|
||||
{
|
||||
"DST_prime": "515555582d5630312d435330322d776974682d657870616e6465722d5348414b4531323824",
|
||||
"len_in_bytes": "0x20",
|
||||
"msg": "q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq",
|
||||
"msg_prime": "713132385f71717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171710020515555582d5630312d435330322d776974682d657870616e6465722d5348414b4531323824",
|
||||
"uniform_bytes": "1adbcc448aef2a0cebc71dac9f756b22e51839d348e031e63b33ebb50faeaf3f"
|
||||
},
|
||||
{
|
||||
"DST_prime": "515555582d5630312d435330322d776974682d657870616e6465722d5348414b4531323824",
|
||||
"len_in_bytes": "0x20",
|
||||
"msg": "a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
||||
"msg_prime": "613531325f61616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161610020515555582d5630312d435330322d776974682d657870616e6465722d5348414b4531323824",
|
||||
"uniform_bytes": "df3447cc5f3e9a77da10f819218ddf31342c310778e0e4ef72bbaecee786a4fe"
|
||||
},
|
||||
{
|
||||
"DST_prime": "515555582d5630312d435330322d776974682d657870616e6465722d5348414b4531323824",
|
||||
"len_in_bytes": "0x80",
|
||||
"msg": "",
|
||||
"msg_prime": "0080515555582d5630312d435330322d776974682d657870616e6465722d5348414b4531323824",
|
||||
"uniform_bytes": "7314ff1a155a2fb99a0171dc71b89ab6e3b2b7d59e38e64419b8b6294d03ffee42491f11370261f436220ef787f8f76f5b26bdcd850071920ce023f3ac46847744f4612b8714db8f5db83205b2e625d95afd7d7b4d3094d3bdde815f52850bb41ead9822e08f22cf41d615a303b0d9dde73263c049a7b9898208003a739a2e57"
|
||||
},
|
||||
{
|
||||
"DST_prime": "515555582d5630312d435330322d776974682d657870616e6465722d5348414b4531323824",
|
||||
"len_in_bytes": "0x80",
|
||||
"msg": "abc",
|
||||
"msg_prime": "6162630080515555582d5630312d435330322d776974682d657870616e6465722d5348414b4531323824",
|
||||
"uniform_bytes": "c952f0c8e529ca8824acc6a4cab0e782fc3648c563ddb00da7399f2ae35654f4860ec671db2356ba7baa55a34a9d7f79197b60ddae6e64768a37d699a78323496db3878c8d64d909d0f8a7de4927dcab0d3dbbc26cb20a49eceb0530b431cdf47bc8c0fa3e0d88f53b318b6739fbed7d7634974f1b5c386d6230c76260d5337a"
|
||||
},
|
||||
{
|
||||
"DST_prime": "515555582d5630312d435330322d776974682d657870616e6465722d5348414b4531323824",
|
||||
"len_in_bytes": "0x80",
|
||||
"msg": "abcdef0123456789",
|
||||
"msg_prime": "616263646566303132333435363738390080515555582d5630312d435330322d776974682d657870616e6465722d5348414b4531323824",
|
||||
"uniform_bytes": "19b65ee7afec6ac06a144f2d6134f08eeec185f1a890fe34e68f0e377b7d0312883c048d9b8a1d6ecc3b541cb4987c26f45e0c82691ea299b5e6889bbfe589153016d8131717ba26f07c3c14ffbef1f3eff9752e5b6183f43871a78219a75e7000fbac6a7072e2b83c790a3a5aecd9d14be79f9fd4fb180960a3772e08680495"
|
||||
},
|
||||
{
|
||||
"DST_prime": "515555582d5630312d435330322d776974682d657870616e6465722d5348414b4531323824",
|
||||
"len_in_bytes": "0x80",
|
||||
"msg": "q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq",
|
||||
"msg_prime": "713132385f71717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171710080515555582d5630312d435330322d776974682d657870616e6465722d5348414b4531323824",
|
||||
"uniform_bytes": "ca1b56861482b16eae0f4a26212112362fcc2d76dcc80c93c4182ed66c5113fe41733ed68be2942a3487394317f3379856f4822a611735e50528a60e7ade8ec8c71670fec6661e2c59a09ed36386513221688b35dc47e3c3111ee8c67ff49579089d661caa29db1ef10eb6eace575bf3dc9806e7c4016bd50f3c0e2a6481ee6d"
|
||||
},
|
||||
{
|
||||
"DST_prime": "515555582d5630312d435330322d776974682d657870616e6465722d5348414b4531323824",
|
||||
"len_in_bytes": "0x80",
|
||||
"msg": "a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
||||
"msg_prime": "613531325f61616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161610080515555582d5630312d435330322d776974682d657870616e6465722d5348414b4531323824",
|
||||
"uniform_bytes": "9d763a5ce58f65c91531b4100c7266d479a5d9777ba761693d052acd37d149e7ac91c796a10b919cd74a591a1e38719fb91b7203e2af31eac3bff7ead2c195af7d88b8bc0a8adf3d1e90ab9bed6ddc2b7f655dd86c730bdeaea884e73741097142c92f0e3fc1811b699ba593c7fbd81da288a29d423df831652e3a01a9374999"
|
||||
}
|
||||
]
|
||||
}
|
||||
78
test/hash-to-curve/expand_message_xof_SHAKE256_36.json
Normal file
78
test/hash-to-curve/expand_message_xof_SHAKE256_36.json
Normal file
@@ -0,0 +1,78 @@
|
||||
{
|
||||
"DST": "QUUX-V01-CS02-with-expander-SHAKE256",
|
||||
"hash": "SHAKE256",
|
||||
"k": 256,
|
||||
"name": "expand_message_xof",
|
||||
"tests": [
|
||||
{
|
||||
"DST_prime": "515555582d5630312d435330322d776974682d657870616e6465722d5348414b4532353624",
|
||||
"len_in_bytes": "0x20",
|
||||
"msg": "",
|
||||
"msg_prime": "0020515555582d5630312d435330322d776974682d657870616e6465722d5348414b4532353624",
|
||||
"uniform_bytes": "2ffc05c48ed32b95d72e807f6eab9f7530dd1c2f013914c8fed38c5ccc15ad76"
|
||||
},
|
||||
{
|
||||
"DST_prime": "515555582d5630312d435330322d776974682d657870616e6465722d5348414b4532353624",
|
||||
"len_in_bytes": "0x20",
|
||||
"msg": "abc",
|
||||
"msg_prime": "6162630020515555582d5630312d435330322d776974682d657870616e6465722d5348414b4532353624",
|
||||
"uniform_bytes": "b39e493867e2767216792abce1f2676c197c0692aed061560ead251821808e07"
|
||||
},
|
||||
{
|
||||
"DST_prime": "515555582d5630312d435330322d776974682d657870616e6465722d5348414b4532353624",
|
||||
"len_in_bytes": "0x20",
|
||||
"msg": "abcdef0123456789",
|
||||
"msg_prime": "616263646566303132333435363738390020515555582d5630312d435330322d776974682d657870616e6465722d5348414b4532353624",
|
||||
"uniform_bytes": "245389cf44a13f0e70af8665fe5337ec2dcd138890bb7901c4ad9cfceb054b65"
|
||||
},
|
||||
{
|
||||
"DST_prime": "515555582d5630312d435330322d776974682d657870616e6465722d5348414b4532353624",
|
||||
"len_in_bytes": "0x20",
|
||||
"msg": "q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq",
|
||||
"msg_prime": "713132385f71717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171710020515555582d5630312d435330322d776974682d657870616e6465722d5348414b4532353624",
|
||||
"uniform_bytes": "719b3911821e6428a5ed9b8e600f2866bcf23c8f0515e52d6c6c019a03f16f0e"
|
||||
},
|
||||
{
|
||||
"DST_prime": "515555582d5630312d435330322d776974682d657870616e6465722d5348414b4532353624",
|
||||
"len_in_bytes": "0x20",
|
||||
"msg": "a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
||||
"msg_prime": "613531325f61616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161610020515555582d5630312d435330322d776974682d657870616e6465722d5348414b4532353624",
|
||||
"uniform_bytes": "9181ead5220b1963f1b5951f35547a5ea86a820562287d6ca4723633d17ccbbc"
|
||||
},
|
||||
{
|
||||
"DST_prime": "515555582d5630312d435330322d776974682d657870616e6465722d5348414b4532353624",
|
||||
"len_in_bytes": "0x80",
|
||||
"msg": "",
|
||||
"msg_prime": "0080515555582d5630312d435330322d776974682d657870616e6465722d5348414b4532353624",
|
||||
"uniform_bytes": "7a1361d2d7d82d79e035b8880c5a3c86c5afa719478c007d96e6c88737a3f631dd74a2c88df79a4cb5e5d9f7504957c70d669ec6bfedc31e01e2bacc4ff3fdf9b6a00b17cc18d9d72ace7d6b81c2e481b4f73f34f9a7505dccbe8f5485f3d20c5409b0310093d5d6492dea4e18aa6979c23c8ea5de01582e9689612afbb353df"
|
||||
},
|
||||
{
|
||||
"DST_prime": "515555582d5630312d435330322d776974682d657870616e6465722d5348414b4532353624",
|
||||
"len_in_bytes": "0x80",
|
||||
"msg": "abc",
|
||||
"msg_prime": "6162630080515555582d5630312d435330322d776974682d657870616e6465722d5348414b4532353624",
|
||||
"uniform_bytes": "a54303e6b172909783353ab05ef08dd435a558c3197db0c132134649708e0b9b4e34fb99b92a9e9e28fc1f1d8860d85897a8e021e6382f3eea10577f968ff6df6c45fe624ce65ca25932f679a42a404bc3681efe03fcd45ef73bb3a8f79ba784f80f55ea8a3c367408f30381299617f50c8cf8fbb21d0f1e1d70b0131a7b6fbe"
|
||||
},
|
||||
{
|
||||
"DST_prime": "515555582d5630312d435330322d776974682d657870616e6465722d5348414b4532353624",
|
||||
"len_in_bytes": "0x80",
|
||||
"msg": "abcdef0123456789",
|
||||
"msg_prime": "616263646566303132333435363738390080515555582d5630312d435330322d776974682d657870616e6465722d5348414b4532353624",
|
||||
"uniform_bytes": "e42e4d9538a189316e3154b821c1bafb390f78b2f010ea404e6ac063deb8c0852fcd412e098e231e43427bd2be1330bb47b4039ad57b30ae1fc94e34993b162ff4d695e42d59d9777ea18d3848d9d336c25d2acb93adcad009bcfb9cde12286df267ada283063de0bb1505565b2eb6c90e31c48798ecdc71a71756a9110ff373"
|
||||
},
|
||||
{
|
||||
"DST_prime": "515555582d5630312d435330322d776974682d657870616e6465722d5348414b4532353624",
|
||||
"len_in_bytes": "0x80",
|
||||
"msg": "q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq",
|
||||
"msg_prime": "713132385f71717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171717171710080515555582d5630312d435330322d776974682d657870616e6465722d5348414b4532353624",
|
||||
"uniform_bytes": "4ac054dda0a38a65d0ecf7afd3c2812300027c8789655e47aecf1ecc1a2426b17444c7482c99e5907afd9c25b991990490bb9c686f43e79b4471a23a703d4b02f23c669737a886a7ec28bddb92c3a98de63ebf878aa363a501a60055c048bea11840c4717beae7eee28c3cfa42857b3d130188571943a7bd747de831bd6444e0"
|
||||
},
|
||||
{
|
||||
"DST_prime": "515555582d5630312d435330322d776974682d657870616e6465722d5348414b4532353624",
|
||||
"len_in_bytes": "0x80",
|
||||
"msg": "a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
||||
"msg_prime": "613531325f61616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161610080515555582d5630312d435330322d776974682d657870616e6465722d5348414b4532353624",
|
||||
"uniform_bytes": "09afc76d51c2cccbc129c2315df66c2be7295a231203b8ab2dd7f95c2772c68e500bc72e20c602abc9964663b7a03a389be128c56971ce81001a0b875e7fd17822db9d69792ddf6a23a151bf470079c518279aef3e75611f8f828994a9988f4a8a256ddb8bae161e658d5a2a09bcfe839c6396dc06ee5c8ff3c22d3b1f9deb7e"
|
||||
}
|
||||
]
|
||||
}
|
||||
90
test/hash-to-curve/secp256k1_XMD:SHA-256_SSWU_NU_.json
Normal file
90
test/hash-to-curve/secp256k1_XMD:SHA-256_SSWU_NU_.json
Normal file
@@ -0,0 +1,90 @@
|
||||
{
|
||||
"L": "0x30",
|
||||
"Z": "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc24",
|
||||
"ciphersuite": "secp256k1_XMD:SHA-256_SSWU_NU_",
|
||||
"curve": "secp256k1",
|
||||
"dst": "QUUX-V01-CS02-with-secp256k1_XMD:SHA-256_SSWU_NU_",
|
||||
"expand": "XMD",
|
||||
"field": {
|
||||
"m": "0x1",
|
||||
"p": "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f"
|
||||
},
|
||||
"hash": "sha256",
|
||||
"k": "0x80",
|
||||
"map": {
|
||||
"name": "SSWU"
|
||||
},
|
||||
"randomOracle": false,
|
||||
"vectors": [
|
||||
{
|
||||
"P": {
|
||||
"x": "0xa4792346075feae77ac3b30026f99c1441b4ecf666ded19b7522cf65c4c55c5b",
|
||||
"y": "0x62c59e2a6aeed1b23be5883e833912b08ba06be7f57c0e9cdc663f31639ff3a7"
|
||||
},
|
||||
"Q": {
|
||||
"x": "0xa4792346075feae77ac3b30026f99c1441b4ecf666ded19b7522cf65c4c55c5b",
|
||||
"y": "0x62c59e2a6aeed1b23be5883e833912b08ba06be7f57c0e9cdc663f31639ff3a7"
|
||||
},
|
||||
"msg": "",
|
||||
"u": [
|
||||
"0x0137fcd23bc3da962e8808f97474d097a6c8aa2881fceef4514173635872cf3b"
|
||||
]
|
||||
},
|
||||
{
|
||||
"P": {
|
||||
"x": "0x3f3b5842033fff837d504bb4ce2a372bfeadbdbd84a1d2b678b6e1d7ee426b9d",
|
||||
"y": "0x902910d1fef15d8ae2006fc84f2a5a7bda0e0407dc913062c3a493c4f5d876a5"
|
||||
},
|
||||
"Q": {
|
||||
"x": "0x3f3b5842033fff837d504bb4ce2a372bfeadbdbd84a1d2b678b6e1d7ee426b9d",
|
||||
"y": "0x902910d1fef15d8ae2006fc84f2a5a7bda0e0407dc913062c3a493c4f5d876a5"
|
||||
},
|
||||
"msg": "abc",
|
||||
"u": [
|
||||
"0xe03f894b4d7caf1a50d6aa45cac27412c8867a25489e32c5ddeb503229f63a2e"
|
||||
]
|
||||
},
|
||||
{
|
||||
"P": {
|
||||
"x": "0x07644fa6281c694709f53bdd21bed94dab995671e4a8cd1904ec4aa50c59bfdf",
|
||||
"y": "0xc79f8d1dad79b6540426922f7fbc9579c3018dafeffcd4552b1626b506c21e7b"
|
||||
},
|
||||
"Q": {
|
||||
"x": "0x07644fa6281c694709f53bdd21bed94dab995671e4a8cd1904ec4aa50c59bfdf",
|
||||
"y": "0xc79f8d1dad79b6540426922f7fbc9579c3018dafeffcd4552b1626b506c21e7b"
|
||||
},
|
||||
"msg": "abcdef0123456789",
|
||||
"u": [
|
||||
"0xe7a6525ae7069ff43498f7f508b41c57f80563c1fe4283510b322446f32af41b"
|
||||
]
|
||||
},
|
||||
{
|
||||
"P": {
|
||||
"x": "0xb734f05e9b9709ab631d960fa26d669c4aeaea64ae62004b9d34f483aa9acc33",
|
||||
"y": "0x03fc8a4a5a78632e2eb4d8460d69ff33c1d72574b79a35e402e801f2d0b1d6ee"
|
||||
},
|
||||
"Q": {
|
||||
"x": "0xb734f05e9b9709ab631d960fa26d669c4aeaea64ae62004b9d34f483aa9acc33",
|
||||
"y": "0x03fc8a4a5a78632e2eb4d8460d69ff33c1d72574b79a35e402e801f2d0b1d6ee"
|
||||
},
|
||||
"msg": "q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq",
|
||||
"u": [
|
||||
"0xd97cf3d176a2f26b9614a704d7d434739d194226a706c886c5c3c39806bc323c"
|
||||
]
|
||||
},
|
||||
{
|
||||
"P": {
|
||||
"x": "0x17d22b867658977b5002dbe8d0ee70a8cfddec3eec50fb93f36136070fd9fa6c",
|
||||
"y": "0xe9178ff02f4dab73480f8dd590328aea99856a7b6cc8e5a6cdf289ecc2a51718"
|
||||
},
|
||||
"Q": {
|
||||
"x": "0x17d22b867658977b5002dbe8d0ee70a8cfddec3eec50fb93f36136070fd9fa6c",
|
||||
"y": "0xe9178ff02f4dab73480f8dd590328aea99856a7b6cc8e5a6cdf289ecc2a51718"
|
||||
},
|
||||
"msg": "a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
||||
"u": [
|
||||
"0xa9ffbeee1d6e41ac33c248fb3364612ff591b502386c1bf6ac4aaf1ea51f8c3b"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
115
test/hash-to-curve/secp256k1_XMD:SHA-256_SSWU_RO_.json
Normal file
115
test/hash-to-curve/secp256k1_XMD:SHA-256_SSWU_RO_.json
Normal file
@@ -0,0 +1,115 @@
|
||||
{
|
||||
"L": "0x30",
|
||||
"Z": "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc24",
|
||||
"ciphersuite": "secp256k1_XMD:SHA-256_SSWU_RO_",
|
||||
"curve": "secp256k1",
|
||||
"dst": "QUUX-V01-CS02-with-secp256k1_XMD:SHA-256_SSWU_RO_",
|
||||
"expand": "XMD",
|
||||
"field": {
|
||||
"m": "0x1",
|
||||
"p": "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f"
|
||||
},
|
||||
"hash": "sha256",
|
||||
"k": "0x80",
|
||||
"map": {
|
||||
"name": "SSWU"
|
||||
},
|
||||
"randomOracle": true,
|
||||
"vectors": [
|
||||
{
|
||||
"P": {
|
||||
"x": "0xc1cae290e291aee617ebaef1be6d73861479c48b841eaba9b7b5852ddfeb1346",
|
||||
"y": "0x64fa678e07ae116126f08b022a94af6de15985c996c3a91b64c406a960e51067"
|
||||
},
|
||||
"Q0": {
|
||||
"x": "0x74519ef88b32b425a095e4ebcc84d81b64e9e2c2675340a720bb1a1857b99f1e",
|
||||
"y": "0xc174fa322ab7c192e11748beed45b508e9fdb1ce046dee9c2cd3a2a86b410936"
|
||||
},
|
||||
"Q1": {
|
||||
"x": "0x44548adb1b399263ded3510554d28b4bead34b8cf9a37b4bd0bd2ba4db87ae63",
|
||||
"y": "0x96eb8e2faf05e368efe5957c6167001760233e6dd2487516b46ae725c4cce0c6"
|
||||
},
|
||||
"msg": "",
|
||||
"u": [
|
||||
"0x6b0f9910dd2ba71c78f2ee9f04d73b5f4c5f7fc773a701abea1e573cab002fb3",
|
||||
"0x1ae6c212e08fe1a5937f6202f929a2cc8ef4ee5b9782db68b0d5799fd8f09e16"
|
||||
]
|
||||
},
|
||||
{
|
||||
"P": {
|
||||
"x": "0x3377e01eab42db296b512293120c6cee72b6ecf9f9205760bd9ff11fb3cb2c4b",
|
||||
"y": "0x7f95890f33efebd1044d382a01b1bee0900fb6116f94688d487c6c7b9c8371f6"
|
||||
},
|
||||
"Q0": {
|
||||
"x": "0x07dd9432d426845fb19857d1b3a91722436604ccbbbadad8523b8fc38a5322d7",
|
||||
"y": "0x604588ef5138cffe3277bbd590b8550bcbe0e523bbaf1bed4014a467122eb33f"
|
||||
},
|
||||
"Q1": {
|
||||
"x": "0xe9ef9794d15d4e77dde751e06c182782046b8dac05f8491eb88764fc65321f78",
|
||||
"y": "0xcb07ce53670d5314bf236ee2c871455c562dd76314aa41f012919fe8e7f717b3"
|
||||
},
|
||||
"msg": "abc",
|
||||
"u": [
|
||||
"0x128aab5d3679a1f7601e3bdf94ced1f43e491f544767e18a4873f397b08a2b61",
|
||||
"0x5897b65da3b595a813d0fdcc75c895dc531be76a03518b044daaa0f2e4689e00"
|
||||
]
|
||||
},
|
||||
{
|
||||
"P": {
|
||||
"x": "0xbac54083f293f1fe08e4a70137260aa90783a5cb84d3f35848b324d0674b0e3a",
|
||||
"y": "0x4436476085d4c3c4508b60fcf4389c40176adce756b398bdee27bca19758d828"
|
||||
},
|
||||
"Q0": {
|
||||
"x": "0x576d43ab0260275adf11af990d130a5752704f79478628761720808862544b5d",
|
||||
"y": "0x643c4a7fb68ae6cff55edd66b809087434bbaff0c07f3f9ec4d49bb3c16623c3"
|
||||
},
|
||||
"Q1": {
|
||||
"x": "0xf89d6d261a5e00fe5cf45e827b507643e67c2a947a20fd9ad71039f8b0e29ff8",
|
||||
"y": "0xb33855e0cc34a9176ead91c6c3acb1aacb1ce936d563bc1cee1dcffc806caf57"
|
||||
},
|
||||
"msg": "abcdef0123456789",
|
||||
"u": [
|
||||
"0xea67a7c02f2cd5d8b87715c169d055a22520f74daeb080e6180958380e2f98b9",
|
||||
"0x7434d0d1a500d38380d1f9615c021857ac8d546925f5f2355319d823a478da18"
|
||||
]
|
||||
},
|
||||
{
|
||||
"P": {
|
||||
"x": "0xe2167bc785333a37aa562f021f1e881defb853839babf52a7f72b102e41890e9",
|
||||
"y": "0xf2401dd95cc35867ffed4f367cd564763719fbc6a53e969fb8496a1e6685d873"
|
||||
},
|
||||
"Q0": {
|
||||
"x": "0x9c91513ccfe9520c9c645588dff5f9b4e92eaf6ad4ab6f1cd720d192eb58247a",
|
||||
"y": "0xc7371dcd0134412f221e386f8d68f49e7fa36f9037676e163d4a063fbf8a1fb8"
|
||||
},
|
||||
"Q1": {
|
||||
"x": "0x10fee3284d7be6bd5912503b972fc52bf4761f47141a0015f1c6ae36848d869b",
|
||||
"y": "0x0b163d9b4bf21887364332be3eff3c870fa053cf508732900fc69a6eb0e1b672"
|
||||
},
|
||||
"msg": "q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq",
|
||||
"u": [
|
||||
"0xeda89a5024fac0a8207a87e8cc4e85aa3bce10745d501a30deb87341b05bcdf5",
|
||||
"0xdfe78cd116818fc2c16f3837fedbe2639fab012c407eac9dfe9245bf650ac51d"
|
||||
]
|
||||
},
|
||||
{
|
||||
"P": {
|
||||
"x": "0xe3c8d35aaaf0b9b647e88a0a0a7ee5d5bed5ad38238152e4e6fd8c1f8cb7c998",
|
||||
"y": "0x8446eeb6181bf12f56a9d24e262221cc2f0c4725c7e3803024b5888ee5823aa6"
|
||||
},
|
||||
"Q0": {
|
||||
"x": "0xb32b0ab55977b936f1e93fdc68cec775e13245e161dbfe556bbb1f72799b4181",
|
||||
"y": "0x2f5317098360b722f132d7156a94822641b615c91f8663be69169870a12af9e8"
|
||||
},
|
||||
"Q1": {
|
||||
"x": "0x148f98780f19388b9fa93e7dc567b5a673e5fca7079cd9cdafd71982ec4c5e12",
|
||||
"y": "0x3989645d83a433bc0c001f3dac29af861f33a6fd1e04f4b36873f5bff497298a"
|
||||
},
|
||||
"msg": "a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
||||
"u": [
|
||||
"0x8d862e7e7e23d7843fe16d811d46d7e6480127a6b78838c277bca17df6900e9f",
|
||||
"0x68071d2530f040f081ba818d3c7188a94c900586761e9115efa47ae9bd847938"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
14
test/index.test.js
Normal file
14
test/index.test.js
Normal file
@@ -0,0 +1,14 @@
|
||||
import { should } from 'micro-should';
|
||||
|
||||
// Should be first to catch obvious things
|
||||
import './basic.test.js';
|
||||
import './nist.test.js';
|
||||
import './ed448.test.js';
|
||||
import './ed25519.test.js';
|
||||
import './secp256k1.test.js';
|
||||
import './stark/index.test.js';
|
||||
import './jubjub.test.js';
|
||||
import './bls12-381.test.js';
|
||||
import './hash-to-curve.test.js';
|
||||
|
||||
should.run();
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user