Compare commits
53 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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 |
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
|
||||
|
||||
506
README.md
506
README.md
@@ -1,52 +1,261 @@
|
||||
# noble-curves
|
||||
|
||||
Minimal, zero-dependency JS implementation of elliptic curve cryptography.
|
||||
Minimal, auditable JS implementation of elliptic curve cryptography.
|
||||
|
||||
- Short Weierstrass curve with ECDSA signatures
|
||||
- Twisted Edwards curve with EdDSA signatures
|
||||
- Montgomery curve for ECDH key agreement
|
||||
- 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
|
||||
- Auditable, [fast](#speed)
|
||||
- 🔍 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. Use `micro-curve-definitions` module:
|
||||
There are two parts of the package:
|
||||
|
||||
- It provides P192, P224, P256, P384, P521, secp256k1, stark curve, bn254, pasta (pallas/vesta) short weierstrass curves
|
||||
- It also provides ed25519 and ed448 twisted edwards curves
|
||||
- Main reason for separate package is the fact hashing library (like `@noble/hashes`) is required for full functionality
|
||||
- We may reconsider merging packages in future, when a stable version would be ready
|
||||
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
|
||||
|
||||
Future plans:
|
||||
|
||||
- hash to curve standard
|
||||
- point indistinguishability
|
||||
- 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.
|
||||
The goal is to replace them with lean UMD builds based on single-codebase noble-curves.
|
||||
|
||||
### 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
|
||||
import { weierstrass } from '@noble/curves/weierstrass'; // Short Weierstrass curve
|
||||
// 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/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';
|
||||
@@ -54,102 +263,213 @@ import { concatBytes, randomBytes } from '@noble/hashes/utils';
|
||||
const secp256k1 = weierstrass({
|
||||
a: 0n,
|
||||
b: 7n,
|
||||
P: 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2fn,
|
||||
n: 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141n,
|
||||
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,
|
||||
|
||||
// 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(secp256k1.utils.randomPrivateKey());
|
||||
secp256k1.sign(randomBytes(32), secp256k1.utils.randomPrivateKey());
|
||||
// secp256k1.verify(sig, msg, pub)
|
||||
|
||||
import { twistedEdwards } from '@noble/curves/edwards'; // Twisted Edwards curve
|
||||
import { sha512 } from '@noble/hashes/sha512';
|
||||
|
||||
const ed25519 = twistedEdwards({
|
||||
a: -1n,
|
||||
d: 37095705934669439343138083508754565189542113879843219016388785533085940283555n,
|
||||
P: 57896044618658097711785492504343953926634992332820282019728792003956564819949n,
|
||||
n: 7237005577332262213973186563042994240857116359379907606001950938285454250989n,
|
||||
h: 8n,
|
||||
Gx: 15112221349535400772501151409588531511454012693041857206046113283949847762202n,
|
||||
Gy: 46316835694926478169428394003475163141307993866256225615783033603165251855960n,
|
||||
hash: sha512,
|
||||
randomBytes,
|
||||
adjustScalarBytes(bytes) { // could be no-op
|
||||
bytes[0] &= 248;
|
||||
bytes[31] &= 127;
|
||||
bytes[31] |= 64;
|
||||
return bytes;
|
||||
},
|
||||
} as const);
|
||||
ed25519.getPublicKey(ed25519.utils.randomPrivateKey());
|
||||
// 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);
|
||||
```
|
||||
|
||||
## Performance
|
||||
`weierstrass()` returns `CurveFn`:
|
||||
|
||||
```ts
|
||||
export type CurveFn = {
|
||||
CURVE: ReturnType<typeof validateOpts>;
|
||||
getPublicKey: (privateKey: PrivKey, isCompressed?: boolean) => Uint8Array;
|
||||
getSharedSecret: (privateA: PrivKey, publicB: PubKey, isCompressed?: boolean) => Uint8Array;
|
||||
sign: (msgHash: Hex, privKey: PrivKey, opts?: SignOpts) => SignatureType;
|
||||
signUnhashed: (msg: Uint8Array, privKey: PrivKey, opts?: SignOpts) => SignatureType;
|
||||
verify: (
|
||||
signature: Hex | SignatureType,
|
||||
msgHash: Hex,
|
||||
publicKey: PubKey,
|
||||
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/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 ====
|
||||
- getPublicKey1 (samples: 10000)
|
||||
noble_old x 8,131 ops/sec @ 122μs/op
|
||||
secp256k1 x 7,374 ops/sec @ 135μs/op
|
||||
- getPublicKey255 (samples: 10000)
|
||||
noble_old x 7,894 ops/sec @ 126μs/op
|
||||
secp256k1 x 7,327 ops/sec @ 136μs/op
|
||||
- sign (samples: 5000)
|
||||
noble_old x 5,243 ops/sec @ 190μs/op
|
||||
secp256k1 x 4,834 ops/sec @ 206μs/op
|
||||
- getSharedSecret (samples: 1000)
|
||||
noble_old x 653 ops/sec @ 1ms/op
|
||||
secp256k1 x 634 ops/sec @ 1ms/op
|
||||
- verify (samples: 1000)
|
||||
secp256k1_old x 1,038 ops/sec @ 962μs/op
|
||||
secp256k1 x 1,009 ops/sec @ 990μs/op
|
||||
==== ed25519 ====
|
||||
- getPublicKey (samples: 10000)
|
||||
old x 8,632 ops/sec @ 115μs/op
|
||||
noble x 8,390 ops/sec @ 119μs/op
|
||||
- sign (samples: 5000)
|
||||
old x 4,376 ops/sec @ 228μs/op
|
||||
noble x 4,233 ops/sec @ 236μs/op
|
||||
- verify (samples: 1000)
|
||||
old x 865 ops/sec @ 1ms/op
|
||||
noble x 860 ops/sec @ 1ms/op
|
||||
==== ed448 ====
|
||||
- getPublicKey (samples: 5000)
|
||||
noble x 3,224 ops/sec @ 310μs/op
|
||||
- sign (samples: 2500)
|
||||
noble x 1,561 ops/sec @ 640μs/op
|
||||
- verify (samples: 500)
|
||||
noble x 313 ops/sec @ 3ms/op
|
||||
==== nist ====
|
||||
- getPublicKey (samples: 2500)
|
||||
getPublicKey
|
||||
secp256k1 x 5,241 ops/sec @ 190μs/op
|
||||
P256 x 7,993 ops/sec @ 125μs/op
|
||||
P384 x 3,819 ops/sec @ 261μs/op
|
||||
P521 x 2,074 ops/sec @ 481μs/op
|
||||
- sign (samples: 1000)
|
||||
ed25519 x 8,390 ops/sec @ 119μs/op
|
||||
ed448 x 3,224 ops/sec @ 310μs/op
|
||||
sign
|
||||
secp256k1 x 3,934 ops/sec @ 254μs/op
|
||||
P256 x 5,327 ops/sec @ 187μs/op
|
||||
P384 x 2,728 ops/sec @ 366μs/op
|
||||
P521 x 1,594 ops/sec @ 626μs/op
|
||||
- verify (samples: 250)
|
||||
ed25519 x 4,233 ops/sec @ 236μs/op
|
||||
ed448 x 1,561 ops/sec @ 640μs/op
|
||||
verify
|
||||
secp256k1 x 731 ops/sec @ 1ms/op
|
||||
P256 x 806 ops/sec @ 1ms/op
|
||||
P384 x 353 ops/sec @ 2ms/op
|
||||
P521 x 171 ops/sec @ 5ms/op
|
||||
ed25519 x 860 ops/sec @ 1ms/op
|
||||
ed448 x 313 ops/sec @ 3ms/op
|
||||
getSharedSecret
|
||||
secp256k1 x 445 ops/sec @ 2ms/op
|
||||
recoverPublicKey
|
||||
secp256k1 x 732 ops/sec @ 1ms/op
|
||||
==== bls12-381 ====
|
||||
getPublicKey x 817 ops/sec @ 1ms/op
|
||||
sign x 50 ops/sec @ 19ms/op
|
||||
verify x 34 ops/sec @ 28ms/op
|
||||
pairing x 89 ops/sec @ 11ms/op
|
||||
==== stark ====
|
||||
- pedersen (samples: 500)
|
||||
pedersen
|
||||
old x 85 ops/sec @ 11ms/op
|
||||
noble x 1,216 ops/sec @ 822μs/op
|
||||
- verify (samples: 500)
|
||||
verify
|
||||
old x 302 ops/sec @ 3ms/op
|
||||
noble x 698 ops/sec @ 1ms/op
|
||||
```
|
||||
|
||||
## Contributing & testing
|
||||
|
||||
1. Clone the repository
|
||||
2. `npm install` to install build dependencies like TypeScript
|
||||
3. `npm run build` to compile TypeScript code
|
||||
4. `npm run test` will execute all main tests
|
||||
|
||||
## 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.
|
||||
416
benchmark/index.js
Normal file
416
benchmark/index.js
Normal file
@@ -0,0 +1,416 @@
|
||||
import * as bench from 'micro-bmark';
|
||||
const { run, mark } = bench; // or bench.mark
|
||||
import { readFileSync } from 'fs';
|
||||
|
||||
// Curves
|
||||
import { secp256k1 } from '../lib/secp256k1.js';
|
||||
import { P256 } from '../lib/p256.js';
|
||||
import { P384 } from '../lib/p384.js';
|
||||
import { P521 } from '../lib/p521.js';
|
||||
import { ed25519 } from '../lib/ed25519.js';
|
||||
import { ed448 } from '../lib/ed448.js';
|
||||
import { bls12_381 as bls } from '../lib/bls12-381.js';
|
||||
|
||||
// Others
|
||||
import { hmac } from '@noble/hashes/hmac';
|
||||
import { sha256 } from '@noble/hashes/sha256';
|
||||
import { sha512 } from '@noble/hashes/sha512';
|
||||
|
||||
import * as old_secp from '@noble/secp256k1';
|
||||
import * as old_bls from '@noble/bls12-381';
|
||||
import { concatBytes, hexToBytes } from '@noble/hashes/utils';
|
||||
|
||||
import * as starkwareCrypto from '@starkware-industries/starkware-crypto-utils';
|
||||
import * as stark from '../lib/stark.js';
|
||||
|
||||
old_secp.utils.sha256Sync = (...msgs) =>
|
||||
sha256
|
||||
.create()
|
||||
.update(concatBytes(...msgs))
|
||||
.digest();
|
||||
old_secp.utils.hmacSha256Sync = (key, ...msgs) =>
|
||||
hmac
|
||||
.create(sha256, key)
|
||||
.update(concatBytes(...msgs))
|
||||
.digest();
|
||||
import * as noble_ed25519 from '@noble/ed25519';
|
||||
noble_ed25519.utils.sha512Sync = (...m) => sha512(concatBytes(...m));
|
||||
|
||||
// BLS
|
||||
const G2_VECTORS = readFileSync('../test/bls12-381/bls12-381-g2-test-vectors.txt', 'utf-8')
|
||||
.trim()
|
||||
.split('\n')
|
||||
.map((l) => l.split(':'));
|
||||
let p1, p2, oldp1, oldp2;
|
||||
// /BLS
|
||||
|
||||
for (let item of [secp256k1, ed25519, ed448, P256, P384, P521, old_secp, noble_ed25519]) {
|
||||
item.utils.precompute(8);
|
||||
}
|
||||
|
||||
const ONLY_NOBLE = process.argv[2] === 'noble';
|
||||
|
||||
function generateData(namespace) {
|
||||
const priv = namespace.utils.randomPrivateKey();
|
||||
const pub = namespace.getPublicKey(priv);
|
||||
const msg = namespace.utils.randomPrivateKey();
|
||||
const sig = namespace.sign(msg, priv);
|
||||
return { priv, pub, msg, sig };
|
||||
}
|
||||
|
||||
export const CURVES = {
|
||||
secp256k1: {
|
||||
data: () => {
|
||||
return generateData(secp256k1);
|
||||
},
|
||||
getPublicKey1: {
|
||||
samples: 10000,
|
||||
secp256k1_old: () => old_secp.getPublicKey(3n),
|
||||
secp256k1: () => secp256k1.getPublicKey(3n),
|
||||
},
|
||||
getPublicKey255: {
|
||||
samples: 10000,
|
||||
secp256k1_old: () => old_secp.getPublicKey(2n ** 255n - 1n),
|
||||
secp256k1: () => secp256k1.getPublicKey(2n ** 255n - 1n),
|
||||
},
|
||||
sign: {
|
||||
samples: 5000,
|
||||
secp256k1_old: ({ msg, priv }) => old_secp.signSync(msg, priv),
|
||||
secp256k1: ({ msg, priv }) => secp256k1.sign(msg, priv),
|
||||
},
|
||||
verify: {
|
||||
samples: 1000,
|
||||
secp256k1_old: ({ sig, msg, pub }) => {
|
||||
return old_secp.verify(new old_secp.Signature(sig.r, sig.s), msg, pub);
|
||||
},
|
||||
secp256k1: ({ sig, msg, pub }) => secp256k1.verify(sig, msg, pub),
|
||||
},
|
||||
getSharedSecret: {
|
||||
samples: 1000,
|
||||
secp256k1_old: ({ pub, priv }) => old_secp.getSharedSecret(priv, pub),
|
||||
secp256k1: ({ pub, priv }) => secp256k1.getSharedSecret(priv, pub),
|
||||
},
|
||||
recoverPublicKey: {
|
||||
samples: 1000,
|
||||
secp256k1_old: ({ sig, msg }) =>
|
||||
old_secp.recoverPublicKey(msg, new old_secp.Signature(sig.r, sig.s), sig.recovery),
|
||||
secp256k1: ({ sig, msg }) => sig.recoverPublicKey(msg),
|
||||
},
|
||||
hashToCurve: {
|
||||
samples: 500,
|
||||
noble: () => secp256k1.Point.hashToCurve('abcd'),
|
||||
},
|
||||
},
|
||||
ed25519: {
|
||||
data: () => {
|
||||
function to32Bytes(numOrStr) {
|
||||
const hex = typeof numOrStr === 'string' ? numOrStr : numOrStr.toString(16);
|
||||
return hexToBytes(hex.padStart(64, '0'));
|
||||
}
|
||||
const priv = to32Bytes(0x9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60n);
|
||||
const pub = noble_ed25519.sync.getPublicKey(priv);
|
||||
const msg = to32Bytes('deadbeefdeadbeefdeadbeefdeadbeefdeadbeef');
|
||||
const sig = noble_ed25519.sync.sign(msg, priv);
|
||||
return { pub, priv, msg, sig };
|
||||
},
|
||||
getPublicKey: {
|
||||
samples: 10000,
|
||||
old: () => noble_ed25519.sync.getPublicKey(noble_ed25519.utils.randomPrivateKey()),
|
||||
noble: () => ed25519.getPublicKey(ed25519.utils.randomPrivateKey()),
|
||||
},
|
||||
sign: {
|
||||
samples: 5000,
|
||||
old: ({ msg, priv }) => noble_ed25519.sync.sign(msg, priv),
|
||||
noble: ({ msg, priv }) => ed25519.sign(msg, priv),
|
||||
},
|
||||
verify: {
|
||||
samples: 1000,
|
||||
old: ({ sig, msg, pub }) => noble_ed25519.sync.verify(sig, msg, pub),
|
||||
noble: ({ sig, msg, pub }) => ed25519.verify(sig, msg, pub),
|
||||
},
|
||||
hashToCurve: {
|
||||
samples: 500,
|
||||
noble: () => ed25519.Point.hashToCurve('abcd'),
|
||||
},
|
||||
},
|
||||
ed448: {
|
||||
data: () => {
|
||||
const priv = ed448.utils.randomPrivateKey();
|
||||
const pub = ed448.getPublicKey(priv);
|
||||
const msg = ed448.utils.randomPrivateKey();
|
||||
const sig = ed448.sign(msg, priv);
|
||||
return { priv, pub, msg, sig };
|
||||
},
|
||||
getPublicKey: {
|
||||
samples: 5000,
|
||||
noble: () => ed448.getPublicKey(ed448.utils.randomPrivateKey()),
|
||||
},
|
||||
sign: {
|
||||
samples: 2500,
|
||||
noble: ({ msg, priv }) => ed448.sign(msg, priv),
|
||||
},
|
||||
verify: {
|
||||
samples: 500,
|
||||
noble: ({ sig, msg, pub }) => ed448.verify(sig, msg, pub),
|
||||
},
|
||||
hashToCurve: {
|
||||
samples: 500,
|
||||
noble: () => ed448.Point.hashToCurve('abcd'),
|
||||
},
|
||||
},
|
||||
nist: {
|
||||
data: () => {
|
||||
return { p256: generateData(P256), p384: generateData(P384), p521: generateData(P521) };
|
||||
},
|
||||
getPublicKey: {
|
||||
samples: 2500,
|
||||
P256: () => P256.getPublicKey(P256.utils.randomPrivateKey()),
|
||||
P384: () => P384.getPublicKey(P384.utils.randomPrivateKey()),
|
||||
P521: () => P521.getPublicKey(P521.utils.randomPrivateKey()),
|
||||
},
|
||||
sign: {
|
||||
samples: 1000,
|
||||
P256: ({ p256: { msg, priv } }) => P256.sign(msg, priv),
|
||||
P384: ({ p384: { msg, priv } }) => P384.sign(msg, priv),
|
||||
P521: ({ p521: { msg, priv } }) => P521.sign(msg, priv),
|
||||
},
|
||||
verify: {
|
||||
samples: 250,
|
||||
P256: ({ p256: { sig, msg, pub } }) => P256.verify(sig, msg, pub),
|
||||
P384: ({ p384: { sig, msg, pub } }) => P384.verify(sig, msg, pub),
|
||||
P521: ({ p521: { sig, msg, pub } }) => P521.verify(sig, msg, pub),
|
||||
},
|
||||
hashToCurve: {
|
||||
samples: 500,
|
||||
P256: () => P256.Point.hashToCurve('abcd'),
|
||||
P384: () => P384.Point.hashToCurve('abcd'),
|
||||
P521: () => P521.Point.hashToCurve('abcd'),
|
||||
},
|
||||
},
|
||||
stark: {
|
||||
data: () => {
|
||||
const priv = '2dccce1da22003777062ee0870e9881b460a8b7eca276870f57c601f182136c';
|
||||
const msg = 'c465dd6b1bbffdb05442eb17f5ca38ad1aa78a6f56bf4415bdee219114a47';
|
||||
const pub = stark.getPublicKey(priv);
|
||||
const sig = stark.sign(msg, priv);
|
||||
|
||||
const privateKey = '2dccce1da22003777062ee0870e9881b460a8b7eca276870f57c601f182136c';
|
||||
const msgHash = 'c465dd6b1bbffdb05442eb17f5ca38ad1aa78a6f56bf4415bdee219114a47';
|
||||
const keyPair = starkwareCrypto.default.ec.keyFromPrivate(privateKey, 'hex');
|
||||
const publicKeyStark = starkwareCrypto.default.ec.keyFromPublic(
|
||||
keyPair.getPublic(true, 'hex'),
|
||||
'hex'
|
||||
);
|
||||
|
||||
return { priv, sig, msg, pub, publicKeyStark, msgHash, keyPair };
|
||||
},
|
||||
pedersen: {
|
||||
samples: 500,
|
||||
old: () => {
|
||||
return starkwareCrypto.default.pedersen([
|
||||
'3d937c035c878245caf64531a5756109c53068da139362728feb561405371cb',
|
||||
'208a0a10250e382e1e4bbe2880906c2791bf6275695e02fbbc6aeff9cd8b31a',
|
||||
]);
|
||||
},
|
||||
noble: () => {
|
||||
return stark.pedersen(
|
||||
'3d937c035c878245caf64531a5756109c53068da139362728feb561405371cb',
|
||||
'208a0a10250e382e1e4bbe2880906c2791bf6275695e02fbbc6aeff9cd8b31a'
|
||||
);
|
||||
},
|
||||
},
|
||||
verify: {
|
||||
samples: 500,
|
||||
old: ({ publicKeyStark, msgHash, keyPair }) => {
|
||||
return starkwareCrypto.default.verify(
|
||||
publicKeyStark,
|
||||
msgHash,
|
||||
starkwareCrypto.default.sign(keyPair, msgHash)
|
||||
);
|
||||
},
|
||||
noble: ({ priv, msg, pub }) => {
|
||||
return stark.verify(stark.sign(msg, priv), msg, pub);
|
||||
},
|
||||
},
|
||||
},
|
||||
'bls12-381': {
|
||||
data: async () => {
|
||||
const priv = '28b90deaf189015d3a325908c5e0e4bf00f84f7e639b056ff82d7e70b6eede4c';
|
||||
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);
|
||||
return {
|
||||
priv,
|
||||
pubs,
|
||||
sigs,
|
||||
pub,
|
||||
pub512,
|
||||
pub32,
|
||||
pub128,
|
||||
pub2048,
|
||||
sig32,
|
||||
sig128,
|
||||
sig512,
|
||||
sig2048,
|
||||
};
|
||||
},
|
||||
init: {
|
||||
samples: 1,
|
||||
old: () => {
|
||||
oldp1 =
|
||||
old_bls.PointG1.BASE.multiply(
|
||||
0x28b90deaf189015d3a325908c5e0e4bf00f84f7e639b056ff82d7e70b6eede4cn
|
||||
);
|
||||
oldp2 =
|
||||
old_bls.PointG2.BASE.multiply(
|
||||
0x28b90deaf189015d3a325908c5e0e4bf00f84f7e639b056ff82d7e70b6eede4dn
|
||||
);
|
||||
old_bls.pairing(oldp1, oldp2);
|
||||
},
|
||||
noble: () => {
|
||||
p1 =
|
||||
bls.G1.Point.BASE.multiply(
|
||||
0x28b90deaf189015d3a325908c5e0e4bf00f84f7e639b056ff82d7e70b6eede4cn
|
||||
);
|
||||
p2 =
|
||||
bls.G2.Point.BASE.multiply(
|
||||
0x28b90deaf189015d3a325908c5e0e4bf00f84f7e639b056ff82d7e70b6eede4dn
|
||||
);
|
||||
bls.pairing(p1, p2);
|
||||
},
|
||||
},
|
||||
'getPublicKey (1-bit)': {
|
||||
samples: 1000,
|
||||
old: () => old_bls.getPublicKey('2'.padStart(64, '0')),
|
||||
noble: () => bls.getPublicKey('2'.padStart(64, '0')),
|
||||
},
|
||||
getPublicKey: {
|
||||
samples: 1000,
|
||||
old: ({ priv }) => old_bls.getPublicKey(priv),
|
||||
noble: ({ priv }) => bls.getPublicKey(priv),
|
||||
},
|
||||
sign: {
|
||||
samples: 50,
|
||||
old: ({ priv }) => old_bls.sign('09', priv),
|
||||
noble: ({ priv }) => bls.sign('09', priv),
|
||||
},
|
||||
verify: {
|
||||
samples: 50,
|
||||
old: ({ pub }) =>
|
||||
old_bls.verify(
|
||||
'8647aa9680cd0cdf065b94e818ff2bb948cc97838bcee987b9bc1b76d0a0a6e0d85db4e9d75aaedfc79d4ea2733a21ae0579014de7636dd2943d45b87c82b1c66a289006b0b9767921bb8edd3f6c5c5dec0d54cd65f61513113c50cc977849e5',
|
||||
'09',
|
||||
pub
|
||||
),
|
||||
noble: ({ pub }) =>
|
||||
bls.verify(
|
||||
'8647aa9680cd0cdf065b94e818ff2bb948cc97838bcee987b9bc1b76d0a0a6e0d85db4e9d75aaedfc79d4ea2733a21ae0579014de7636dd2943d45b87c82b1c66a289006b0b9767921bb8edd3f6c5c5dec0d54cd65f61513113c50cc977849e5',
|
||||
'09',
|
||||
pub
|
||||
),
|
||||
},
|
||||
pairing: {
|
||||
samples: 100,
|
||||
old: () => old_bls.pairing(oldp1, oldp2),
|
||||
noble: () => bls.pairing(p1, p2),
|
||||
},
|
||||
'hashToCurve/G1': {
|
||||
samples: 500,
|
||||
old: () => old_bls.PointG1.hashToCurve('abcd'),
|
||||
noble: () => bls.G1.Point.hashToCurve('abcd'),
|
||||
},
|
||||
'hashToCurve/G2': {
|
||||
samples: 200,
|
||||
old: () => old_bls.PointG2.hashToCurve('abcd'),
|
||||
noble: () => bls.G2.Point.hashToCurve('abcd'),
|
||||
},
|
||||
// SLOW PART
|
||||
// Requires points which we cannot init before (data fn same for all)
|
||||
// await mark('sign/nc', 30, () => bls.sign(msgp, priv));
|
||||
// await mark('verify/nc', 30, () => bls.verify(sigp, msgp, pubp));
|
||||
'aggregatePublicKeys/8': {
|
||||
samples: 100,
|
||||
old: ({ pubs }) => old_bls.aggregatePublicKeys(pubs.slice(0, 8)),
|
||||
noble: ({ pubs }) => bls.aggregatePublicKeys(pubs.slice(0, 8)),
|
||||
},
|
||||
'aggregatePublicKeys/32': {
|
||||
samples: 50,
|
||||
old: ({ pub32 }) => old_bls.aggregatePublicKeys(pub32.map(old_bls.PointG1.fromHex)),
|
||||
noble: ({ pub32 }) => bls.aggregatePublicKeys(pub32.map(bls.G1.Point.fromHex)),
|
||||
},
|
||||
'aggregatePublicKeys/128': {
|
||||
samples: 20,
|
||||
old: ({ pub128 }) => old_bls.aggregatePublicKeys(pub128.map(old_bls.PointG1.fromHex)),
|
||||
noble: ({ pub128 }) => bls.aggregatePublicKeys(pub128.map(bls.G1.Point.fromHex)),
|
||||
},
|
||||
'aggregatePublicKeys/512': {
|
||||
samples: 10,
|
||||
old: ({ pub512 }) => old_bls.aggregatePublicKeys(pub512.map(old_bls.PointG1.fromHex)),
|
||||
noble: ({ pub512 }) => bls.aggregatePublicKeys(pub512.map(bls.G1.Point.fromHex)),
|
||||
},
|
||||
'aggregatePublicKeys/2048': {
|
||||
samples: 5,
|
||||
old: ({ pub2048 }) => old_bls.aggregatePublicKeys(pub2048.map(old_bls.PointG1.fromHex)),
|
||||
noble: ({ pub2048 }) => bls.aggregatePublicKeys(pub2048.map(bls.G1.Point.fromHex)),
|
||||
},
|
||||
'aggregateSignatures/8': {
|
||||
samples: 50,
|
||||
old: ({ sigs }) => old_bls.aggregateSignatures(sigs.slice(0, 8)),
|
||||
noble: ({ sigs }) => bls.aggregateSignatures(sigs.slice(0, 8)),
|
||||
},
|
||||
'aggregateSignatures/32': {
|
||||
samples: 10,
|
||||
old: ({ sig32 }) => old_bls.aggregateSignatures(sig32.map(old_bls.PointG2.fromSignature)),
|
||||
noble: ({ sig32 }) => bls.aggregateSignatures(sig32.map(bls.Signature.decode)),
|
||||
},
|
||||
'aggregateSignatures/128': {
|
||||
samples: 5,
|
||||
old: ({ sig128 }) => old_bls.aggregateSignatures(sig128.map(old_bls.PointG2.fromSignature)),
|
||||
noble: ({ sig128 }) => bls.aggregateSignatures(sig128.map(bls.Signature.decode)),
|
||||
},
|
||||
'aggregateSignatures/512': {
|
||||
samples: 3,
|
||||
old: ({ sig512 }) => old_bls.aggregateSignatures(sig512.map(old_bls.PointG2.fromSignature)),
|
||||
noble: ({ sig512 }) => bls.aggregateSignatures(sig512.map(bls.Signature.decode)),
|
||||
},
|
||||
'aggregateSignatures/2048': {
|
||||
samples: 2,
|
||||
old: ({ sig2048 }) => old_bls.aggregateSignatures(sig2048.map(old_bls.PointG2.fromSignature)),
|
||||
noble: ({ sig2048 }) => bls.aggregateSignatures(sig2048.map(bls.Signature.decode)),
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const main = () =>
|
||||
run(async () => {
|
||||
for (const [name, curve] of Object.entries(CURVES)) {
|
||||
console.log(`==== ${name} ====`);
|
||||
const data = await curve.data();
|
||||
for (const [fnName, libs] of Object.entries(curve)) {
|
||||
if (fnName === 'data') continue;
|
||||
const samples = libs.samples;
|
||||
console.log(` - ${fnName} (samples: ${samples})`);
|
||||
for (const [lib, fn] of Object.entries(libs)) {
|
||||
if (lib === 'samples') continue;
|
||||
if (ONLY_NOBLE && lib !== 'noble') continue;
|
||||
await mark(` ${lib}`, samples, () => fn(data));
|
||||
}
|
||||
}
|
||||
}
|
||||
// Log current RAM
|
||||
bench.logMem();
|
||||
});
|
||||
|
||||
// ESM is broken.
|
||||
import url from 'url';
|
||||
if (import.meta.url === url.pathToFileURL(process.argv[1]).href) {
|
||||
main();
|
||||
}
|
||||
@@ -12,11 +12,15 @@
|
||||
"author": "",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"micro-bmark": "0.2.0"
|
||||
"micro-bmark": "0.2.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@noble/bls12-381": "^1.4.0",
|
||||
"@noble/ed25519": "^1.7.1",
|
||||
"@noble/hashes": "^1.1.5",
|
||||
"@noble/secp256k1": "^1.7.0",
|
||||
"@starkware-industries/starkware-crypto-utils": "^0.0.2"
|
||||
"@starkware-industries/starkware-crypto-utils": "^0.0.2",
|
||||
"calculate-correlation": "^1.2.3",
|
||||
"elliptic": "^6.5.4"
|
||||
}
|
||||
}
|
||||
@@ -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,231 +0,0 @@
|
||||
import * as bench from 'micro-bmark';
|
||||
const { run, mark } = bench; // or bench.mark
|
||||
// Curves
|
||||
import { secp256k1 } from '../lib/secp256k1.js';
|
||||
import { P256 } from '../lib/p256.js';
|
||||
import { P384 } from '../lib/p384.js';
|
||||
import { P521 } from '../lib/p521.js';
|
||||
import { ed25519 } from '../lib/ed25519.js';
|
||||
import { ed448 } from '../lib/ed448.js';
|
||||
|
||||
// Others
|
||||
import { hmac } from '@noble/hashes/hmac';
|
||||
import { sha256 } from '@noble/hashes/sha256';
|
||||
import { sha512 } from '@noble/hashes/sha512';
|
||||
|
||||
import * as old_secp from '@noble/secp256k1';
|
||||
import { concatBytes, hexToBytes } from '@noble/hashes/utils';
|
||||
|
||||
import * as starkwareCrypto from '@starkware-industries/starkware-crypto-utils';
|
||||
import * as stark from '../lib/stark.js';
|
||||
|
||||
old_secp.utils.sha256Sync = (...msgs) =>
|
||||
sha256
|
||||
.create()
|
||||
.update(concatBytes(...msgs))
|
||||
.digest();
|
||||
old_secp.utils.hmacSha256Sync = (key, ...msgs) =>
|
||||
hmac
|
||||
.create(sha256, key)
|
||||
.update(concatBytes(...msgs))
|
||||
.digest();
|
||||
import * as noble_ed25519 from '@noble/ed25519';
|
||||
noble_ed25519.utils.sha512Sync = (...m) => sha512(concatBytes(...m));
|
||||
|
||||
for (let item of [secp256k1, ed25519, ed448, P256, P384, P521, old_secp, noble_ed25519]) {
|
||||
item.utils.precompute(8);
|
||||
}
|
||||
|
||||
const ONLY_NOBLE = process.argv[2] === 'noble';
|
||||
|
||||
function generateData(namespace) {
|
||||
const priv = namespace.utils.randomPrivateKey();
|
||||
const pub = namespace.getPublicKey(priv);
|
||||
const msg = namespace.utils.randomPrivateKey();
|
||||
const sig = namespace.sign(msg, priv);
|
||||
return { priv, pub, msg, sig };
|
||||
}
|
||||
|
||||
export const CURVES = {
|
||||
secp256k1: {
|
||||
data: () => {
|
||||
return generateData(secp256k1);
|
||||
},
|
||||
getPublicKey1: {
|
||||
samples: 10000,
|
||||
secp256k1_old: () => old_secp.getPublicKey(3n),
|
||||
secp256k1: () => secp256k1.getPublicKey(3n),
|
||||
},
|
||||
getPublicKey255: {
|
||||
samples: 10000,
|
||||
secp256k1_old: () => old_secp.getPublicKey(2n**255n-1n),
|
||||
secp256k1: () => secp256k1.getPublicKey(2n**255n-1n),
|
||||
},
|
||||
sign: {
|
||||
samples: 5000,
|
||||
secp256k1_old: ({ msg, priv }) => old_secp.signSync(msg, priv),
|
||||
secp256k1: ({ msg, priv }) => secp256k1.sign(msg, priv),
|
||||
},
|
||||
verify: {
|
||||
samples: 1000,
|
||||
secp256k1_old: ({ sig, msg, pub }) => {
|
||||
return old_secp.verify((new old_secp.Signature(sig.r, sig.s)), msg, pub);
|
||||
},
|
||||
secp256k1: ({ sig, msg, pub }) => secp256k1.verify(sig, msg, pub)
|
||||
},
|
||||
getSharedSecret: {
|
||||
samples: 1000,
|
||||
secp256k1_old: ({ pub, priv }) => old_secp.getSharedSecret(priv, pub),
|
||||
secp256k1: ({ pub, priv }) => secp256k1.getSharedSecret(priv, pub),
|
||||
},
|
||||
recoverPublicKey: {
|
||||
samples: 1000,
|
||||
secp256k1_old: ({ sig, msg }) =>
|
||||
old_secp.recoverPublicKey(msg, (new old_secp.Signature(sig.r, sig.s)), sig.recovery),
|
||||
secp256k1: ({ sig, msg }) => sig.recoverPublicKey(msg)
|
||||
}
|
||||
},
|
||||
ed25519: {
|
||||
data: () => {
|
||||
function to32Bytes(numOrStr) {
|
||||
const hex = typeof numOrStr === 'string' ? numOrStr : numOrStr.toString(16);
|
||||
return hexToBytes(hex.padStart(64, '0'));
|
||||
}
|
||||
const priv = to32Bytes(0x9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60n);
|
||||
const pub = noble_ed25519.sync.getPublicKey(priv);
|
||||
const msg = to32Bytes('deadbeefdeadbeefdeadbeefdeadbeefdeadbeef');
|
||||
const sig = noble_ed25519.sync.sign(msg, priv);
|
||||
return { pub, priv, msg, sig };
|
||||
},
|
||||
getPublicKey: {
|
||||
samples: 10000,
|
||||
old: () => noble_ed25519.sync.getPublicKey(noble_ed25519.utils.randomPrivateKey()),
|
||||
noble: () => ed25519.getPublicKey(ed25519.utils.randomPrivateKey()),
|
||||
},
|
||||
sign: {
|
||||
samples: 5000,
|
||||
old: ({ msg, priv }) => noble_ed25519.sync.sign(msg, priv),
|
||||
noble: ({ msg, priv }) => ed25519.sign(msg, priv),
|
||||
},
|
||||
verify: {
|
||||
samples: 1000,
|
||||
old: ({ sig, msg, pub }) => noble_ed25519.sync.verify(sig, msg, pub),
|
||||
noble: ({ sig, msg, pub }) => ed25519.verify(sig, msg, pub),
|
||||
},
|
||||
},
|
||||
ed448: {
|
||||
data: () => {
|
||||
const priv = ed448.utils.randomPrivateKey();
|
||||
const pub = ed448.getPublicKey(priv);
|
||||
const msg = ed448.utils.randomPrivateKey();
|
||||
const sig = ed448.sign(msg, priv);
|
||||
return { priv, pub, msg, sig };
|
||||
},
|
||||
getPublicKey: {
|
||||
samples: 5000,
|
||||
noble: () => ed448.getPublicKey(ed448.utils.randomPrivateKey()),
|
||||
},
|
||||
sign: {
|
||||
samples: 2500,
|
||||
noble: ({ msg, priv }) => ed448.sign(msg, priv),
|
||||
},
|
||||
verify: {
|
||||
samples: 500,
|
||||
noble: ({ sig, msg, pub }) => ed448.verify(sig, msg, pub)
|
||||
}
|
||||
},
|
||||
nist: {
|
||||
data: () => {
|
||||
return { p256: generateData(P256), p384: generateData(P384), p521: generateData(P521) }
|
||||
},
|
||||
getPublicKey: {
|
||||
samples: 2500,
|
||||
P256: () => P256.getPublicKey(P256.utils.randomPrivateKey()),
|
||||
P384: () => P384.getPublicKey(P384.utils.randomPrivateKey()),
|
||||
P521: () => P521.getPublicKey(P521.utils.randomPrivateKey()),
|
||||
},
|
||||
sign: {
|
||||
samples: 1000,
|
||||
P256: ({ p256: {msg, priv} }) => P256.sign(msg, priv),
|
||||
P384: ({ p384: {msg, priv} }) => P384.sign(msg, priv),
|
||||
P521: ({ p521: {msg, priv} }) => P521.sign(msg, priv),
|
||||
},
|
||||
verify: {
|
||||
samples: 250,
|
||||
P256: ({ p256: {sig, msg, pub} }) => P256.verify(sig, msg, pub),
|
||||
P384: ({ p384: {sig, msg, pub} }) => P384.verify(sig, msg, pub),
|
||||
P521: ({ p521: {sig, msg, pub} }) => P521.verify(sig, msg, pub),
|
||||
}
|
||||
},
|
||||
stark: {
|
||||
data: () => {
|
||||
const priv = '2dccce1da22003777062ee0870e9881b460a8b7eca276870f57c601f182136c';
|
||||
const msg = 'c465dd6b1bbffdb05442eb17f5ca38ad1aa78a6f56bf4415bdee219114a47';
|
||||
const pub = stark.getPublicKey(priv);
|
||||
const sig = stark.sign(msg, priv);
|
||||
|
||||
const privateKey = '2dccce1da22003777062ee0870e9881b460a8b7eca276870f57c601f182136c';
|
||||
const msgHash = 'c465dd6b1bbffdb05442eb17f5ca38ad1aa78a6f56bf4415bdee219114a47';
|
||||
const keyPair = starkwareCrypto.default.ec.keyFromPrivate(privateKey, 'hex');
|
||||
const publicKeyStark = starkwareCrypto.default.ec.keyFromPublic(
|
||||
keyPair.getPublic(true, 'hex'), 'hex'
|
||||
);
|
||||
|
||||
return { priv, sig, msg, pub, publicKeyStark, msgHash, keyPair }
|
||||
},
|
||||
pedersen: {
|
||||
samples: 500,
|
||||
old: () => {
|
||||
return starkwareCrypto.default.pedersen([
|
||||
'3d937c035c878245caf64531a5756109c53068da139362728feb561405371cb',
|
||||
'208a0a10250e382e1e4bbe2880906c2791bf6275695e02fbbc6aeff9cd8b31a',
|
||||
])
|
||||
},
|
||||
noble: () => {
|
||||
return stark.pedersen(
|
||||
'3d937c035c878245caf64531a5756109c53068da139362728feb561405371cb',
|
||||
'208a0a10250e382e1e4bbe2880906c2791bf6275695e02fbbc6aeff9cd8b31a'
|
||||
)
|
||||
}
|
||||
},
|
||||
verify: {
|
||||
samples: 500,
|
||||
old: ({ publicKeyStark, msgHash, keyPair }) => {
|
||||
return starkwareCrypto.default.verify(
|
||||
publicKeyStark,
|
||||
msgHash,
|
||||
starkwareCrypto.default.sign(keyPair, msgHash)
|
||||
);
|
||||
},
|
||||
noble: ({ priv, msg, pub }) => {
|
||||
return stark.verify(stark.sign(msg, priv), msg, pub)
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const main = () =>
|
||||
run(async () => {
|
||||
for (const [name, curve] of Object.entries(CURVES)) {
|
||||
console.log(`==== ${name} ====`);
|
||||
const data = curve.data();
|
||||
for (const [fnName, libs] of Object.entries(curve)) {
|
||||
if (fnName === 'data') continue;
|
||||
const samples = libs.samples;
|
||||
console.log(` - ${fnName} (samples: ${samples})`);
|
||||
for (const [lib, fn] of Object.entries(libs)) {
|
||||
if (lib === 'samples') continue;
|
||||
if (ONLY_NOBLE && lib !== 'noble') continue;
|
||||
await mark(` ${lib}`, samples, () => fn(data));
|
||||
}
|
||||
}
|
||||
}
|
||||
// Log current RAM
|
||||
bench.logMem();
|
||||
});
|
||||
|
||||
// ESM is broken.
|
||||
import url from 'url';
|
||||
if (import.meta.url === url.pathToFileURL(process.argv[1]).href) {
|
||||
main();
|
||||
}
|
||||
@@ -1,59 +0,0 @@
|
||||
{
|
||||
"name": "micro-curve-definitions",
|
||||
"version": "0.2.0",
|
||||
"description": "Curve definitions for @noble/curves",
|
||||
"files": [
|
||||
"lib"
|
||||
],
|
||||
"type": "module",
|
||||
"main": "lib/index.js",
|
||||
"module": "lib/index.js",
|
||||
"types": "lib/index.d.ts",
|
||||
"dependencies": {
|
||||
"@noble/curves": "0.2.0",
|
||||
"@noble/hashes": "1.1.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@scure/base": "~1.1.0",
|
||||
"@scure/bip32": "^1.1.1",
|
||||
"@scure/bip39": "^1.1.0",
|
||||
"@types/node": "18.11.3",
|
||||
"fast-check": "3.0.0",
|
||||
"micro-should": "0.2.0",
|
||||
"prettier": "2.6.2",
|
||||
"typescript": "4.7.3"
|
||||
},
|
||||
"author": "Paul Miller (https://paulmillr.com)",
|
||||
"license": "MIT",
|
||||
"homepage": "https://github.com/paulmillr/noble-curves",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/paulmillr/noble-curves.git"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "tsc",
|
||||
"lint": "prettier --check src",
|
||||
"test": "node test/index.test.js"
|
||||
},
|
||||
"keywords": [
|
||||
"secp192r1",
|
||||
"secp224r1",
|
||||
"secp256r1",
|
||||
"secp384r1",
|
||||
"secp521r1",
|
||||
"NIST P192",
|
||||
"NIST P224",
|
||||
"NIST P256",
|
||||
"NIST P384",
|
||||
"NIST P521",
|
||||
"NIST curves",
|
||||
"EC",
|
||||
"elliptic curves"
|
||||
],
|
||||
"funding": [
|
||||
{
|
||||
"type": "individual",
|
||||
"url": "https://paulmillr.com/funding/"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,146 +0,0 @@
|
||||
/*! @noble/curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
||||
import { shake256 } from '@noble/hashes/sha3';
|
||||
import { concatBytes, randomBytes, utf8ToBytes, wrapConstructor } from '@noble/hashes/utils';
|
||||
import { twistedEdwards } from '@noble/curves/edwards';
|
||||
import { mod, pow2 } from '@noble/curves/modular';
|
||||
import { montgomery } from '../../lib/montgomery.js';
|
||||
|
||||
/**
|
||||
* Edwards448 (not Ed448-Goldilocks) curve with following addons:
|
||||
* * X448 ECDH
|
||||
* Conforms to RFC 8032 https://www.rfc-editor.org/rfc/rfc8032.html#section-5.2
|
||||
*/
|
||||
|
||||
const shake256_114 = wrapConstructor(() => shake256.create({ dkLen: 114 }));
|
||||
const shake256_64 = wrapConstructor(() => shake256.create({ dkLen: 64 }));
|
||||
const ed448P = BigInt(
|
||||
'726838724295606890549323807888004534353641360687318060281490199180612328166730772686396383698676545930088884461843637361053498018365439'
|
||||
);
|
||||
|
||||
// powPminus3div4 calculates z = x^k mod p, where k = (p-3)/4.
|
||||
function ed448_pow_Pminus3div4(x: bigint): bigint {
|
||||
const P = ed448P;
|
||||
// prettier-ignore
|
||||
let [_1n, _2n, _3n, _11n, _22n, _44n, _88n, _223n] = [1, 2, 3, 11, 22, 44, 88, 223]
|
||||
.map(n => BigInt(n));
|
||||
// x ** ((P - 3n)/4n) % P
|
||||
// [223 of 1, 0, 222 of 1], almost same as secp!
|
||||
const b2 = (x * x * x) % P;
|
||||
const b3 = (b2 * b2 * x) % P;
|
||||
const b6 = (pow2(b3, _3n, P) * b3) % P;
|
||||
const b9 = (pow2(b6, _3n, P) * b3) % P;
|
||||
const b11 = (pow2(b9, _2n, P) * b2) % P;
|
||||
const b22 = (pow2(b11, _11n, P) * b11) % P;
|
||||
const b44 = (pow2(b22, _22n, P) * b22) % P;
|
||||
const b88 = (pow2(b44, _44n, P) * b44) % P;
|
||||
const b176 = (pow2(b88, _88n, P) * b88) % P;
|
||||
const b220 = (pow2(b176, _44n, P) * b44) % P;
|
||||
const b222 = (pow2(b220, _2n, P) * b2) % P;
|
||||
const b223 = (pow2(b222, _1n, P) * x) % P;
|
||||
return (pow2(b223, _223n, P) * b222) % P;
|
||||
}
|
||||
|
||||
function adjustScalarBytes(bytes: Uint8Array): Uint8Array {
|
||||
// Section 5: Likewise, for X448, set the two least significant bits of the first byte to 0, and the most
|
||||
// significant bit of the last byte to 1.
|
||||
bytes[0] &= 252; // 0b11111100
|
||||
// and the most significant bit of the last byte to 1.
|
||||
bytes[55] |= 128; // 0b10000000
|
||||
// NOTE: is is NOOP for 56 bytes scalars (X25519/X448)
|
||||
bytes[56] = 0; // Byte outside of group (456 buts vs 448 bits)
|
||||
return bytes;
|
||||
}
|
||||
|
||||
const ED448_DEF = {
|
||||
// Param: a
|
||||
a: BigInt(1),
|
||||
// -39081. Negative number is P - number
|
||||
d: BigInt(
|
||||
'726838724295606890549323807888004534353641360687318060281490199180612328166730772686396383698676545930088884461843637361053498018326358'
|
||||
),
|
||||
// Finite field 𝔽p over which we'll do calculations; 2n ** 448n - 2n ** 224n - 1n
|
||||
P: ed448P,
|
||||
// Subgroup order: how many points ed448 has; 2n**446n - 13818066809895115352007386748515426880336692474882178609894547503885n
|
||||
n: BigInt(
|
||||
'181709681073901722637330951972001133588410340171829515070372549795146003961539585716195755291692375963310293709091662304773755859649779'
|
||||
),
|
||||
nBitLength: 456,
|
||||
// Cofactor
|
||||
h: BigInt(4),
|
||||
// Base point (x, y) aka generator point
|
||||
Gx: BigInt(
|
||||
'224580040295924300187604334099896036246789641632564134246125461686950415467406032909029192869357953282578032075146446173674602635247710'
|
||||
),
|
||||
Gy: BigInt(
|
||||
'298819210078481492676017930443930673437544040154080242095928241372331506189835876003536878655418784733982303233503462500531545062832660'
|
||||
),
|
||||
// SHAKE256(dom4(phflag,context)||x, 114)
|
||||
hash: shake256_114,
|
||||
randomBytes,
|
||||
adjustScalarBytes,
|
||||
// dom4
|
||||
domain: (data: Uint8Array, ctx: Uint8Array, phflag: boolean) => {
|
||||
if (ctx.length > 255) throw new Error(`Context is too big: ${ctx.length}`);
|
||||
return concatBytes(
|
||||
utf8ToBytes('SigEd448'),
|
||||
new Uint8Array([phflag ? 1 : 0, ctx.length]),
|
||||
ctx,
|
||||
data
|
||||
);
|
||||
},
|
||||
// Constant-time ratio of u to v. Allows to combine inversion and square root u/√v.
|
||||
// Uses algo from RFC8032 5.1.3.
|
||||
uvRatio: (u: bigint, v: bigint): { isValid: boolean; value: bigint } => {
|
||||
const P = ed448P;
|
||||
// https://datatracker.ietf.org/doc/html/rfc8032#section-5.2.3
|
||||
// To compute the square root of (u/v), the first step is to compute the
|
||||
// candidate root x = (u/v)^((p+1)/4). This can be done using the
|
||||
// following trick, to use a single modular powering for both the
|
||||
// inversion of v and the square root:
|
||||
// (p+1)/4 3 (p-3)/4
|
||||
// x = (u/v) = u v (u^5 v^3) (mod p)
|
||||
const u2v = mod(u * u * v, P);
|
||||
const u3v = mod(u2v * u, P); // u^2v
|
||||
const u5v3 = mod(u3v * u2v * v, P); // u^5v^3
|
||||
const root = ed448_pow_Pminus3div4(u5v3);
|
||||
const x = mod(u3v * root, P);
|
||||
// Verify that root is exists
|
||||
const x2 = mod(x * x, P); // x^2
|
||||
// If v * x^2 = u, the recovered x-coordinate is x. Otherwise, no
|
||||
// square root exists, and the decoding fails.
|
||||
return { isValid: mod(x2 * v, P) === u, value: x };
|
||||
},
|
||||
} as const;
|
||||
|
||||
export const ed448 = twistedEdwards(ED448_DEF);
|
||||
// NOTE: there is no ed448ctx, since ed448 supports ctx by default
|
||||
export const ed448ph = twistedEdwards({ ...ED448_DEF, preHash: shake256_64 });
|
||||
|
||||
export const x448 = montgomery({
|
||||
a24: BigInt(39081),
|
||||
montgomeryBits: 448,
|
||||
nByteLength: 57,
|
||||
P: ed448P,
|
||||
Gu: '0500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000',
|
||||
powPminus2: (x: bigint): bigint => {
|
||||
const P = ed448P;
|
||||
const Pminus3div4 = ed448_pow_Pminus3div4(x);
|
||||
const Pminus3 = pow2(Pminus3div4, BigInt(2), P);
|
||||
return mod(Pminus3 * x, P); // Pminus3 * x = Pminus2
|
||||
},
|
||||
adjustScalarBytes,
|
||||
// The 4-isogeny maps between the Montgomery curve and this Edwards
|
||||
// curve are:
|
||||
// (u, v) = (y^2/x^2, (2 - x^2 - y^2)*y/x^3)
|
||||
// (x, y) = (4*v*(u^2 - 1)/(u^4 - 2*u^2 + 4*v^2 + 1),
|
||||
// -(u^5 - 2*u^3 - 4*u*v^2 + u)/
|
||||
// (u^5 - 2*u^2*v^2 - 2*u^3 - 2*v^2 + u))
|
||||
// xyToU: (p: PointType) => {
|
||||
// const P = ed448P;
|
||||
// const { x, y } = p;
|
||||
// if (x === _0n) throw new Error(`Point with x=0 doesn't have mapping`);
|
||||
// const invX = invert(x * x, P); // x^2
|
||||
// const u = mod(y * y * invX, P); // (y^2/x^2)
|
||||
// return numberToBytesLE(u, 56);
|
||||
// },
|
||||
});
|
||||
@@ -1,24 +0,0 @@
|
||||
/*! @noble/curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
||||
import { createCurve } from './_shortw_utils.js';
|
||||
import { sha256 } from '@noble/hashes/sha256';
|
||||
|
||||
// NIST secp256r1 aka P256
|
||||
// https://www.secg.org/sec2-v2.pdf, https://neuromancer.sk/std/nist/P-256
|
||||
export const P256 = createCurve(
|
||||
{
|
||||
// Params: a, b
|
||||
a: BigInt('0xffffffff00000001000000000000000000000000fffffffffffffffffffffffc'),
|
||||
b: BigInt('0x5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b'),
|
||||
// Field over which we'll do calculations; 2n**224n * (2n**32n-1n) + 2n**192n + 2n**96n-1n
|
||||
P: BigInt('0xffffffff00000001000000000000000000000000ffffffffffffffffffffffff'),
|
||||
// Curve order, total count of valid points in the field
|
||||
n: BigInt('0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551'),
|
||||
// Base point (x, y) aka generator point
|
||||
Gx: BigInt('0x6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296'),
|
||||
Gy: BigInt('0x4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5'),
|
||||
h: BigInt(1),
|
||||
lowS: false,
|
||||
} as const,
|
||||
sha256
|
||||
);
|
||||
export const secp256r1 = P256;
|
||||
@@ -1,22 +0,0 @@
|
||||
/*! @noble/curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
||||
import { createCurve } from './_shortw_utils.js';
|
||||
import { sha384 } from '@noble/hashes/sha512';
|
||||
|
||||
// NIST secp384r1 aka P384
|
||||
// https://www.secg.org/sec2-v2.pdf, https://neuromancer.sk/std/nist/P-384
|
||||
// prettier-ignore
|
||||
export const P384 = createCurve({
|
||||
// Params: a, b
|
||||
a: BigInt('0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000fffffffc'),
|
||||
b: BigInt('0xb3312fa7e23ee7e4988e056be3f82d19181d9c6efe8141120314088f5013875ac656398d8a2ed19d2a85c8edd3ec2aef'),
|
||||
// Field over which we'll do calculations. 2n**384n - 2n**128n - 2n**96n + 2n**32n - 1n
|
||||
P: BigInt('0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000ffffffff'),
|
||||
// Curve order, total count of valid points in the field.
|
||||
n: BigInt('0xffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf581a0db248b0a77aecec196accc52973'),
|
||||
// Base point (x, y) aka generator point
|
||||
Gx: BigInt('0xaa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a385502f25dbf55296c3a545e3872760ab7'),
|
||||
Gy: BigInt('0x3617de4a96262c6f5d9e98bf9292dc29f8f41dbd289a147ce9da3113b5f0b8c00a60b1ce1d7e819d7a431d7c90ea0e5f'),
|
||||
h: BigInt(1),
|
||||
lowS: false,
|
||||
} as const, sha384);
|
||||
export const secp384r1 = P384;
|
||||
@@ -1,23 +0,0 @@
|
||||
/*! @noble/curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
||||
import { createCurve } from './_shortw_utils.js';
|
||||
import { sha512 } from '@noble/hashes/sha512';
|
||||
|
||||
// NIST secp521r1 aka P521
|
||||
// Note that it's 521, which differs from 512 of its hash function.
|
||||
// https://www.secg.org/sec2-v2.pdf, https://neuromancer.sk/std/nist/P-521
|
||||
// prettier-ignore
|
||||
export const P521 = createCurve({
|
||||
// Params: a, b
|
||||
a: BigInt('0x01fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc'),
|
||||
b: BigInt('0x0051953eb9618e1c9a1f929a21a0b68540eea2da725b99b315f3b8b489918ef109e156193951ec7e937b1652c0bd3bb1bf073573df883d2c34f1ef451fd46b503f00'),
|
||||
// Field over which we'll do calculations; 2n**521n - 1n
|
||||
P: BigInt('0x1ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'),
|
||||
// Curve order, total count of valid points in the field
|
||||
n: BigInt('0x01fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa51868783bf2f966b7fcc0148f709a5d03bb5c9b8899c47aebb6fb71e91386409'),
|
||||
// Base point (x, y) aka generator point
|
||||
Gx: BigInt('0x00c6858e06b70404e9cd9e3ecb662395b4429c648139053fb521f828af606b4d3dbaa14b5e77efe75928fe1dc127a2ffa8de3348b3c1856a429bf97e7e31c2e5bd66'),
|
||||
Gy: BigInt('0x011839296a789a3bc0045c8a5fb42c7d1bd998f54449579b446817afbd17273e662c97ee72995ef42640c550b9013fad0761353c7086a272c24088be94769fd16650'),
|
||||
h: BigInt(1),
|
||||
lowS: false,
|
||||
} as const, sha512);
|
||||
export const secp521r1 = P521;
|
||||
@@ -1,317 +0,0 @@
|
||||
import { deepStrictEqual, throws } from 'assert';
|
||||
import { should } from 'micro-should';
|
||||
import * as fc from 'fast-check';
|
||||
import * as mod from '@noble/curves/modular';
|
||||
import { randomBytes } from '@noble/hashes/utils';
|
||||
// Generic tests for all curves in package
|
||||
import { secp192r1 } from '../lib/p192.js';
|
||||
import { secp224r1 } from '../lib/p224.js';
|
||||
import { secp256r1 } from '../lib/p256.js';
|
||||
import { secp384r1 } from '../lib/p384.js';
|
||||
import { secp521r1 } from '../lib/p521.js';
|
||||
import { secp256k1 } from '../lib/secp256k1.js';
|
||||
import { ed25519, ed25519ctx, ed25519ph } from '../lib/ed25519.js';
|
||||
import { ed448, ed448ph } from '../lib/ed448.js';
|
||||
import { starkCurve } from '../lib/stark.js';
|
||||
import { pallas, vesta } from '../lib/pasta.js';
|
||||
import { bn254 } from '../lib/bn.js';
|
||||
import { jubjub } from '../lib/jubjub.js';
|
||||
|
||||
// prettier-ignore
|
||||
const CURVES = {
|
||||
secp192r1, secp224r1, secp256r1, secp384r1, secp521r1,
|
||||
secp256k1,
|
||||
ed25519, ed25519ctx, ed25519ph,
|
||||
ed448, ed448ph,
|
||||
starkCurve,
|
||||
pallas, vesta,
|
||||
bn254,
|
||||
jubjub,
|
||||
};
|
||||
|
||||
const NUM_RUNS = 5;
|
||||
const getXY = (p) => ({ x: p.x, y: p.y });
|
||||
|
||||
function equal(a, b, comment) {
|
||||
deepStrictEqual(a.equals(b), true, `eq(${comment})`);
|
||||
if (a.toAffine && b.toAffine) {
|
||||
deepStrictEqual(getXY(a.toAffine()), getXY(b.toAffine()), `eqToAffine(${comment})`);
|
||||
} else if (!a.toAffine && !b.toAffine) {
|
||||
// Already affine
|
||||
deepStrictEqual(getXY(a), getXY(b), `eqAffine(${comment})`);
|
||||
} else throw new Error('Different point types');
|
||||
}
|
||||
|
||||
for (const name in CURVES) {
|
||||
const C = CURVES[name];
|
||||
const CURVE_ORDER = C.CURVE.n;
|
||||
const FC_BIGINT = fc.bigInt(1n + 1n, CURVE_ORDER - 1n);
|
||||
|
||||
// Check that curve doesn't accept points from other curves
|
||||
const O = name === 'secp256k1' ? secp256r1 : secp256k1;
|
||||
const POINTS = {};
|
||||
const OTHER_POINTS = {};
|
||||
for (const name of ['Point', 'JacobianPoint', 'ExtendedPoint', 'ProjectivePoint']) {
|
||||
POINTS[name] = C[name];
|
||||
OTHER_POINTS[name] = O[name];
|
||||
}
|
||||
|
||||
for (const pointName in POINTS) {
|
||||
const p = POINTS[pointName];
|
||||
const o = OTHER_POINTS[pointName];
|
||||
if (!p) continue;
|
||||
|
||||
const G = [p.ZERO, p.BASE];
|
||||
for (let i = 2; i < 10; i++) G.push(G[1].multiply(i));
|
||||
// Here we check basic group laws, to verify that points works as group
|
||||
should(`${name}/${pointName}/Basic group laws (zero)`, () => {
|
||||
equal(G[0].double(), G[0], '(0*G).double() = 0');
|
||||
equal(G[0].add(G[0]), G[0], '0*G + 0*G = 0');
|
||||
equal(G[0].subtract(G[0]), G[0], '0*G - 0*G = 0');
|
||||
equal(G[0].negate(), G[0], '-0 = 0');
|
||||
for (let i = 0; i < G.length; i++) {
|
||||
const p = G[i];
|
||||
equal(p, p.add(G[0]), `${i}*G + 0 = ${i}*G`);
|
||||
equal(G[0].multiply(i + 1), G[0], `${i + 1}*0 = 0`);
|
||||
}
|
||||
});
|
||||
should(`${name}/${pointName}/Basic group laws (one)`, () => {
|
||||
equal(G[1].double(), G[2], '(1*G).double() = 2*G');
|
||||
equal(G[1].subtract(G[1]), G[0], '1*G - 1*G = 0');
|
||||
equal(G[1].add(G[1]), G[2], '1*G + 1*G = 2*G');
|
||||
});
|
||||
should(`${name}/${pointName}/Basic group laws (sanity tests)`, () => {
|
||||
equal(G[2].double(), G[4], `(2*G).double() = 4*G`);
|
||||
equal(G[2].add(G[2]), G[4], `2*G + 2*G = 4*G`);
|
||||
equal(G[7].add(G[3].negate()), G[4], `7*G - 3*G = 4*G`);
|
||||
});
|
||||
should(`${name}/${pointName}/Basic group laws (addition commutativity)`, () => {
|
||||
equal(G[4].add(G[3]), G[3].add(G[4]), `4*G + 3*G = 3*G + 4*G`);
|
||||
equal(G[4].add(G[3]), G[3].add(G[2]).add(G[2]), `4*G + 3*G = 3*G + 2*G + 2*G`);
|
||||
});
|
||||
should(`${name}/${pointName}/Basic group laws (double)`, () => {
|
||||
equal(G[3].double(), G[6], '(3*G).double() = 6*G');
|
||||
});
|
||||
should(`${name}/${pointName}/Basic group laws (multiply)`, () => {
|
||||
equal(G[2].multiply(3), G[6], '(2*G).multiply(3) = 6*G');
|
||||
});
|
||||
should(`${name}/${pointName}/Basic group laws (same point addition)`, () => {
|
||||
equal(G[3].add(G[3]), G[6], `3*G + 3*G = 6*G`);
|
||||
});
|
||||
should(`${name}/${pointName}/Basic group laws (same point (negative) addition)`, () => {
|
||||
equal(G[3].add(G[3].negate()), G[0], '3*G + (- 3*G) = 0*G');
|
||||
equal(G[3].subtract(G[3]), G[0], '3*G - 3*G = 0*G');
|
||||
});
|
||||
should(`${name}/${pointName}/Basic group laws (curve order)`, () => {
|
||||
equal(G[1].multiply(CURVE_ORDER - 1n).add(G[1]), G[0], '(N-1)*G + G = 0');
|
||||
equal(G[1].multiply(CURVE_ORDER - 1n).add(G[2]), G[1], '(N-1)*G + 2*G = 1*G');
|
||||
equal(G[1].multiply(CURVE_ORDER - 2n).add(G[2]), G[0], '(N-2)*G + 2*G = 0');
|
||||
const half = CURVE_ORDER / 2n;
|
||||
const carry = CURVE_ORDER % 2n === 1n ? G[1] : G[0];
|
||||
equal(G[1].multiply(half).double().add(carry), G[0], '((N/2) * G).double() = 0');
|
||||
});
|
||||
should(`${name}/${pointName}/Basic group laws (inversion)`, () => {
|
||||
const a = 1234n;
|
||||
const b = 5678n;
|
||||
const c = a * b;
|
||||
equal(G[1].multiply(a).multiply(b), G[1].multiply(c), 'a*b*G = c*G');
|
||||
const inv = mod.invert(b, CURVE_ORDER);
|
||||
equal(G[1].multiply(c).multiply(inv), G[1].multiply(a), 'c*G * (1/b)*G = a*G');
|
||||
});
|
||||
should(`${name}/${pointName}/Basic group laws (multiply, rand)`, () =>
|
||||
fc.assert(
|
||||
fc.property(FC_BIGINT, FC_BIGINT, (a, b) => {
|
||||
const c = mod.mod(a + b, CURVE_ORDER);
|
||||
if (c === CURVE_ORDER || c < 1n) return;
|
||||
const pA = G[1].multiply(a);
|
||||
const pB = G[1].multiply(b);
|
||||
const pC = G[1].multiply(c);
|
||||
equal(pA.add(pB), pB.add(pA), `pA + pB = pB + pA`);
|
||||
equal(pA.add(pB), pC, `pA + pB = pC`);
|
||||
}),
|
||||
{ numRuns: NUM_RUNS }
|
||||
)
|
||||
);
|
||||
should(`${name}/${pointName}/Basic group laws (multiply2, rand)`, () =>
|
||||
fc.assert(
|
||||
fc.property(FC_BIGINT, FC_BIGINT, (a, b) => {
|
||||
const c = mod.mod(a * b, CURVE_ORDER);
|
||||
const pA = G[1].multiply(a);
|
||||
const pB = G[1].multiply(b);
|
||||
equal(pA.multiply(b), pB.multiply(a), `b*pA = a*pB`);
|
||||
equal(pA.multiply(b), G[1].multiply(c), `b*pA = c*G`);
|
||||
}),
|
||||
{ numRuns: NUM_RUNS }
|
||||
)
|
||||
);
|
||||
|
||||
for (const op of ['add', 'subtract']) {
|
||||
should(`${name}/${pointName}/${op} type check`, () => {
|
||||
throws(() => G[1][op](0), '0');
|
||||
throws(() => G[1][op](0n), '0n');
|
||||
G[1][op](G[2]);
|
||||
throws(() => G[1][op](CURVE_ORDER), 'CURVE_ORDER');
|
||||
throws(() => G[1][op](123.456), '123.456');
|
||||
throws(() => G[1][op](true), 'true');
|
||||
throws(() => G[1][op]('1'), "'1'");
|
||||
throws(() => G[1][op]({ x: 1n, y: 1n, z: 1n, t: 1n }), '{ x: 1n, y: 1n, z: 1n, t: 1n }');
|
||||
throws(() => G[1][op](new Uint8Array([])), 'ui8a([])');
|
||||
throws(() => G[1][op](new Uint8Array([0])), 'ui8a([0])');
|
||||
throws(() => G[1][op](new Uint8Array([1])), 'ui8a([1])');
|
||||
throws(() => G[1][op](new Uint8Array(4096).fill(1)), 'ui8a(4096*[1])');
|
||||
if (G[1].toAffine) throws(() => G[1][op](C.Point.BASE), `Point ${op} ${pointName}`);
|
||||
throws(() => G[1][op](o.BASE), `${op}/other curve point`);
|
||||
});
|
||||
}
|
||||
|
||||
should(`${name}/${pointName}/equals type check`, () => {
|
||||
throws(() => G[1].equals(0), '0');
|
||||
throws(() => G[1].equals(0n), '0n');
|
||||
deepStrictEqual(G[1].equals(G[2]), false, '1*G != 2*G');
|
||||
deepStrictEqual(G[1].equals(G[1]), true, '1*G == 1*G');
|
||||
deepStrictEqual(G[2].equals(G[2]), true, '2*G == 2*G');
|
||||
throws(() => G[1].equals(CURVE_ORDER), 'CURVE_ORDER');
|
||||
throws(() => G[1].equals(123.456), '123.456');
|
||||
throws(() => G[1].equals(true), 'true');
|
||||
throws(() => G[1].equals('1'), "'1'");
|
||||
throws(() => G[1].equals({ x: 1n, y: 1n, z: 1n, t: 1n }), '{ x: 1n, y: 1n, z: 1n, t: 1n }');
|
||||
throws(() => G[1].equals(new Uint8Array([])), 'ui8a([])');
|
||||
throws(() => G[1].equals(new Uint8Array([0])), 'ui8a([0])');
|
||||
throws(() => G[1].equals(new Uint8Array([1])), 'ui8a([1])');
|
||||
throws(() => G[1].equals(new Uint8Array(4096).fill(1)), 'ui8a(4096*[1])');
|
||||
if (G[1].toAffine) throws(() => G[1].equals(C.Point.BASE), `Point.equals(${pointName})`);
|
||||
throws(() => G[1].equals(o.BASE), 'other curve point');
|
||||
});
|
||||
|
||||
for (const op of ['multiply', 'multiplyUnsafe']) {
|
||||
if (!p.BASE[op]) continue;
|
||||
should(`${name}/${pointName}/${op} type check`, () => {
|
||||
if (op !== 'multiplyUnsafe') {
|
||||
throws(() => G[1][op](0), '0');
|
||||
throws(() => G[1][op](0n), '0n');
|
||||
}
|
||||
G[1][op](1n);
|
||||
G[1][op](CURVE_ORDER - 1n);
|
||||
throws(() => G[1][op](G[2]), 'G[2]');
|
||||
throws(() => G[1][op](CURVE_ORDER), 'CURVE_ORDER');
|
||||
throws(() => G[1][op](CURVE_ORDER + 1n), 'CURVE_ORDER+1');
|
||||
throws(() => G[1][op](123.456), '123.456');
|
||||
throws(() => G[1][op](true), 'true');
|
||||
throws(() => G[1][op]('1'), '1');
|
||||
throws(() => G[1][op](new Uint8Array([])), 'ui8a([])');
|
||||
throws(() => G[1][op](new Uint8Array([0])), 'ui8a([0])');
|
||||
throws(() => G[1][op](new Uint8Array([1])), 'ui8a([1])');
|
||||
throws(() => G[1][op](new Uint8Array(4096).fill(1)), 'ui8a(4096*[1])');
|
||||
throws(() => G[1][op](o.BASE), 'other curve point');
|
||||
});
|
||||
}
|
||||
// Complex point (Extended/Jacobian/Projective?)
|
||||
if (p.BASE.toAffine) {
|
||||
should(`${name}/${pointName}/toAffine()`, () => {
|
||||
equal(p.ZERO.toAffine(), C.Point.ZERO, `0 = 0`);
|
||||
equal(p.BASE.toAffine(), C.Point.BASE, `1 = 1`);
|
||||
});
|
||||
}
|
||||
if (p.fromAffine) {
|
||||
should(`${name}/${pointName}/fromAffine()`, () => {
|
||||
equal(p.ZERO, p.fromAffine(C.Point.ZERO), `0 = 0`);
|
||||
equal(p.BASE, p.fromAffine(C.Point.BASE), `1 = 1`);
|
||||
});
|
||||
}
|
||||
// toHex/fromHex (if available)
|
||||
if (p.fromHex && p.BASE.toHex) {
|
||||
should(`${name}/${pointName}/fromHex(toHex()) roundtrip`, () => {
|
||||
fc.assert(
|
||||
fc.property(FC_BIGINT, (x) => {
|
||||
const hex = p.BASE.multiply(x).toHex();
|
||||
deepStrictEqual(p.fromHex(hex).toHex(), hex);
|
||||
})
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
// Generic complex things (getPublicKey/sign/verify/getSharedSecret)
|
||||
should(`${name}/getPublicKey type check`, () => {
|
||||
throws(() => C.getPublicKey(0), '0');
|
||||
throws(() => C.getPublicKey(0n), '0n');
|
||||
throws(() => C.getPublicKey(false), 'false');
|
||||
throws(() => C.getPublicKey(123.456), '123.456');
|
||||
throws(() => C.getPublicKey(true), 'true');
|
||||
throws(() => C.getPublicKey(''), "''");
|
||||
// NOTE: passes because of disabled hex padding checks for starknet, maybe enable?
|
||||
//throws(() => C.getPublicKey('1'), "'1'");
|
||||
throws(() => C.getPublicKey('key'), "'key'");
|
||||
throws(() => C.getPublicKey(new Uint8Array([])));
|
||||
throws(() => C.getPublicKey(new Uint8Array([0])));
|
||||
throws(() => C.getPublicKey(new Uint8Array([1])));
|
||||
throws(() => C.getPublicKey(new Uint8Array(4096).fill(1)));
|
||||
});
|
||||
should(`${name}.verify()/should verify random signatures`, () =>
|
||||
fc.assert(
|
||||
fc.property(fc.hexaString({ minLength: 64, maxLength: 64 }), (msg) => {
|
||||
const priv = C.utils.randomPrivateKey();
|
||||
const pub = C.getPublicKey(priv);
|
||||
const sig = C.sign(msg, priv);
|
||||
deepStrictEqual(C.verify(sig, msg, pub), true);
|
||||
}),
|
||||
{ numRuns: NUM_RUNS }
|
||||
)
|
||||
);
|
||||
should(`${name}.sign()/edge cases`, () => {
|
||||
throws(() => C.sign());
|
||||
throws(() => C.sign(''));
|
||||
});
|
||||
|
||||
should(`${name}.verify()/should not verify signature with wrong hash`, () => {
|
||||
const MSG = '01'.repeat(32);
|
||||
const PRIV_KEY = 0x2n;
|
||||
const WRONG_MSG = '11'.repeat(32);
|
||||
const signature = C.sign(MSG, PRIV_KEY);
|
||||
const publicKey = C.getPublicKey(PRIV_KEY);
|
||||
deepStrictEqual(C.verify(signature, WRONG_MSG, publicKey), false);
|
||||
});
|
||||
// NOTE: fails for ed, because of empty message. Since we convert it to scalar,
|
||||
// need to check what other implementations do. Empty message != new Uint8Array([0]), but what scalar should be in that case?
|
||||
// should(`${name}/should not verify signature with wrong message`, () => {
|
||||
// fc.assert(
|
||||
// fc.property(
|
||||
// fc.array(fc.integer({ min: 0x00, max: 0xff })),
|
||||
// fc.array(fc.integer({ min: 0x00, max: 0xff })),
|
||||
// (bytes, wrongBytes) => {
|
||||
// const privKey = C.utils.randomPrivateKey();
|
||||
// const message = new Uint8Array(bytes);
|
||||
// const wrongMessage = new Uint8Array(wrongBytes);
|
||||
// const publicKey = C.getPublicKey(privKey);
|
||||
// const signature = C.sign(message, privKey);
|
||||
// deepStrictEqual(
|
||||
// C.verify(signature, wrongMessage, publicKey),
|
||||
// bytes.toString() === wrongBytes.toString()
|
||||
// );
|
||||
// }
|
||||
// ),
|
||||
// { numRuns: NUM_RUNS }
|
||||
// );
|
||||
// });
|
||||
|
||||
if (C.getSharedSecret) {
|
||||
should(`${name}/getSharedSecret() should be commutative`, () => {
|
||||
for (let i = 0; i < NUM_RUNS; i++) {
|
||||
const asec = C.utils.randomPrivateKey();
|
||||
const apub = C.getPublicKey(asec);
|
||||
const bsec = C.utils.randomPrivateKey();
|
||||
const bpub = C.getPublicKey(bsec);
|
||||
try {
|
||||
deepStrictEqual(C.getSharedSecret(asec, bpub), C.getSharedSecret(bsec, apub));
|
||||
} catch (error) {
|
||||
console.error('not commutative', { asec, apub, bsec, bpub });
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
// ESM is broken.
|
||||
import url from 'url';
|
||||
if (import.meta.url === url.pathToFileURL(process.argv[1]).href) {
|
||||
should.run();
|
||||
}
|
||||
@@ -1,657 +0,0 @@
|
||||
import { deepStrictEqual, throws } from 'assert';
|
||||
import { should } from 'micro-should';
|
||||
import * as fc from 'fast-check';
|
||||
import { ed25519, ed25519ctx, ed25519ph, x25519, RistrettoPoint } from '../lib/ed25519.js';
|
||||
import { readFileSync } from 'fs';
|
||||
import { default as zip215 } from './ed25519/zip215.json' assert { type: 'json' };
|
||||
import { hexToBytes, bytesToHex, randomBytes } from '@noble/hashes/utils';
|
||||
import { numberToBytesLE } from '@noble/curves/utils';
|
||||
import { sha512 } from '@noble/hashes/sha512';
|
||||
import { default as ed25519vectors } from './wycheproof/eddsa_test.json' assert { type: 'json' };
|
||||
import { default as x25519vectors } from './wycheproof/x25519_test.json' assert { type: 'json' };
|
||||
|
||||
const ed = ed25519;
|
||||
const hex = bytesToHex;
|
||||
|
||||
function to32Bytes(numOrStr) {
|
||||
let hex = typeof numOrStr === 'string' ? numOrStr : numOrStr.toString(16);
|
||||
return hexToBytes(hex.padStart(64, '0'));
|
||||
}
|
||||
|
||||
function utf8ToBytes(str) {
|
||||
if (typeof str !== 'string') {
|
||||
throw new TypeError(`utf8ToBytes expected string, got ${typeof str}`);
|
||||
}
|
||||
return new TextEncoder().encode(str);
|
||||
}
|
||||
|
||||
ed.utils.precompute(8);
|
||||
|
||||
should('ed25519/should not accept >32byte private keys', () => {
|
||||
const invalidPriv =
|
||||
100000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000090000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800073278156000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000n;
|
||||
throws(() => ed.getPublicKey(invalidPriv));
|
||||
});
|
||||
should('ed25519/should verify recent signature', () => {
|
||||
fc.assert(
|
||||
fc.property(
|
||||
fc.hexaString({ minLength: 2, maxLength: 32 }),
|
||||
fc.bigInt(2n, ed.CURVE.n),
|
||||
(message, privateKey) => {
|
||||
const publicKey = ed.getPublicKey(to32Bytes(privateKey));
|
||||
const signature = ed.sign(to32Bytes(message), to32Bytes(privateKey));
|
||||
deepStrictEqual(publicKey.length, 32);
|
||||
deepStrictEqual(signature.length, 64);
|
||||
deepStrictEqual(ed.verify(signature, to32Bytes(message), publicKey), true);
|
||||
}
|
||||
),
|
||||
{ numRuns: 5 }
|
||||
);
|
||||
});
|
||||
should('ed25519/should not verify signature with wrong message', () => {
|
||||
fc.assert(
|
||||
fc.property(
|
||||
fc.array(fc.integer({ min: 0x00, max: 0xff })),
|
||||
fc.array(fc.integer({ min: 0x00, max: 0xff })),
|
||||
fc.bigInt(1n, ed.CURVE.n),
|
||||
(bytes, wrongBytes, privateKey) => {
|
||||
const privKey = to32Bytes(privateKey);
|
||||
const message = new Uint8Array(bytes);
|
||||
const wrongMessage = new Uint8Array(wrongBytes);
|
||||
const publicKey = ed.getPublicKey(privKey);
|
||||
const signature = ed.sign(message, privKey);
|
||||
deepStrictEqual(
|
||||
ed.verify(signature, wrongMessage, publicKey),
|
||||
bytes.toString() === wrongBytes.toString()
|
||||
);
|
||||
}
|
||||
),
|
||||
{ numRuns: 5 }
|
||||
);
|
||||
});
|
||||
const privKey = to32Bytes('a665a45920422f9d417e4867ef');
|
||||
const msg = hexToBytes('874f9960c5d2b7a9b5fad383e1ba44719ebb743a');
|
||||
const wrongMsg = hexToBytes('589d8c7f1da0a24bc07b7381ad48b1cfc211af1c');
|
||||
should('ed25519/basic methods/should sign and verify', () => {
|
||||
const publicKey = ed.getPublicKey(privKey);
|
||||
const signature = ed.sign(msg, privKey);
|
||||
deepStrictEqual(ed.verify(signature, msg, publicKey), true);
|
||||
});
|
||||
should('ed25519/basic methods/should not verify signature with wrong public key', () => {
|
||||
const publicKey = ed.getPublicKey(12);
|
||||
const signature = ed.sign(msg, privKey);
|
||||
deepStrictEqual(ed.verify(signature, msg, publicKey), false);
|
||||
});
|
||||
should('ed25519/basic methods/should not verify signature with wrong hash', () => {
|
||||
const publicKey = ed.getPublicKey(privKey);
|
||||
const signature = ed.sign(msg, privKey);
|
||||
deepStrictEqual(ed.verify(signature, wrongMsg, publicKey), false);
|
||||
});
|
||||
|
||||
should('ed25519/sync methods/should sign and verify', () => {
|
||||
const publicKey = ed.getPublicKey(privKey);
|
||||
const signature = ed.sign(msg, privKey);
|
||||
deepStrictEqual(ed.verify(signature, msg, publicKey), true);
|
||||
});
|
||||
should('ed25519/sync methods/should not verify signature with wrong public key', () => {
|
||||
const publicKey = ed.getPublicKey(12);
|
||||
const signature = ed.sign(msg, privKey);
|
||||
deepStrictEqual(ed.verify(signature, msg, publicKey), false);
|
||||
});
|
||||
should('ed25519/sync methods/should not verify signature with wrong hash', () => {
|
||||
const publicKey = ed.getPublicKey(privKey);
|
||||
const signature = ed.sign(msg, privKey);
|
||||
deepStrictEqual(ed.verify(signature, wrongMsg, publicKey), false);
|
||||
});
|
||||
|
||||
// https://xmr.llcoins.net/addresstests.html
|
||||
should(
|
||||
'ed25519/BASE_POINT.multiply()/should create right publicKey without SHA-512 hashing TEST 1',
|
||||
() => {
|
||||
const publicKey =
|
||||
ed.Point.BASE.multiply(0x90af56259a4b6bfbc4337980d5d75fbe3c074630368ff3804d33028e5dbfa77n);
|
||||
deepStrictEqual(
|
||||
publicKey.toHex(),
|
||||
'0f3b913371411b27e646b537e888f685bf929ea7aab93c950ed84433f064480d'
|
||||
);
|
||||
}
|
||||
);
|
||||
should(
|
||||
'ed25519/BASE_POINT.multiply()/should create right publicKey without SHA-512 hashing TEST 2',
|
||||
() => {
|
||||
const publicKey =
|
||||
ed.Point.BASE.multiply(0x364e8711a60780382a5d57b061c126f039940f28a9e91fe039d4d3094d8b88n);
|
||||
deepStrictEqual(
|
||||
publicKey.toHex(),
|
||||
'ad545340b58610f0cd62f17d55af1ab11ecde9c084d5476865ddb4dbda015349'
|
||||
);
|
||||
}
|
||||
);
|
||||
should(
|
||||
'ed25519/BASE_POINT.multiply()/should create right publicKey without SHA-512 hashing TEST 3',
|
||||
() => {
|
||||
const publicKey =
|
||||
ed.Point.BASE.multiply(0xb9bf90ff3abec042752cac3a07a62f0c16cfb9d32a3fc2305d676ec2d86e941n);
|
||||
deepStrictEqual(
|
||||
publicKey.toHex(),
|
||||
'e097c4415fe85724d522b2e449e8fd78dd40d20097bdc9ae36fe8ec6fe12cb8c'
|
||||
);
|
||||
}
|
||||
);
|
||||
should(
|
||||
'ed25519/BASE_POINT.multiply()/should create right publicKey without SHA-512 hashing TEST 4',
|
||||
() => {
|
||||
const publicKey =
|
||||
ed.Point.BASE.multiply(0x69d896f02d79524c9878e080308180e2859d07f9f54454e0800e8db0847a46en);
|
||||
deepStrictEqual(
|
||||
publicKey.toHex(),
|
||||
'f12cb7c43b59971395926f278ce7c2eaded9444fbce62ca717564cb508a0db1d'
|
||||
);
|
||||
}
|
||||
);
|
||||
should('ed25519/BASE_POINT.multiply()/should throw Point#multiply on TEST 5', () => {
|
||||
for (const num of [0n, 0, -1n, -1, 1.1]) {
|
||||
throws(() => ed.Point.BASE.multiply(num));
|
||||
}
|
||||
});
|
||||
|
||||
// https://ed25519.cr.yp.to/python/sign.py
|
||||
// https://ed25519.cr.yp.to/python/sign.input
|
||||
const data = readFileSync('./test/ed25519/vectors.txt', 'utf-8');
|
||||
const vectors = data
|
||||
.trim()
|
||||
.split('\n')
|
||||
.map((line) => line.split(':'));
|
||||
should('ed25519 official vectors/should match 1024 official vectors', () => {
|
||||
for (let i = 0; i < vectors.length; i++) {
|
||||
const vector = vectors[i];
|
||||
// Extract.
|
||||
const priv = vector[0].slice(0, 64);
|
||||
const expectedPub = vector[1];
|
||||
const msg = vector[2];
|
||||
const expectedSignature = vector[3].slice(0, 128);
|
||||
|
||||
// Calculate
|
||||
const pub = ed.getPublicKey(to32Bytes(priv));
|
||||
deepStrictEqual(hex(pub), expectedPub);
|
||||
deepStrictEqual(pub, ed.Point.fromHex(pub).toRawBytes());
|
||||
|
||||
const signature = hex(ed.sign(msg, priv));
|
||||
// console.log('vector', i);
|
||||
// expect(pub).toBe(expectedPub);
|
||||
deepStrictEqual(signature, expectedSignature);
|
||||
}
|
||||
});
|
||||
|
||||
// https://tools.ietf.org/html/rfc8032#section-7
|
||||
should('rfc8032 vectors/should create right signature for 0x9d and empty string', () => {
|
||||
const privateKey = '9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60';
|
||||
const publicKey = ed.getPublicKey(privateKey);
|
||||
const message = '';
|
||||
const signature = ed.sign(message, privateKey);
|
||||
deepStrictEqual(
|
||||
hex(publicKey),
|
||||
'd75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a'
|
||||
);
|
||||
deepStrictEqual(
|
||||
hex(signature),
|
||||
'e5564300c360ac729086e2cc806e828a84877f1eb8e5d974d873e065224901555fb8821590a33bacc61e39701cf9b46bd25bf5f0595bbe24655141438e7a100b'
|
||||
);
|
||||
});
|
||||
should('rfc8032 vectors/should create right signature for 0x4c and 72', () => {
|
||||
const privateKey = '4ccd089b28ff96da9db6c346ec114e0f5b8a319f35aba624da8cf6ed4fb8a6fb';
|
||||
const publicKey = ed.getPublicKey(privateKey);
|
||||
const message = '72';
|
||||
const signature = ed.sign(message, privateKey);
|
||||
deepStrictEqual(
|
||||
hex(publicKey),
|
||||
'3d4017c3e843895a92b70aa74d1b7ebc9c982ccf2ec4968cc0cd55f12af4660c'
|
||||
);
|
||||
deepStrictEqual(
|
||||
hex(signature),
|
||||
'92a009a9f0d4cab8720e820b5f642540a2b27b5416503f8fb3762223ebdb69da085ac1e43e15996e458f3613d0f11d8c387b2eaeb4302aeeb00d291612bb0c00'
|
||||
);
|
||||
});
|
||||
should('rfc8032 vectors/should create right signature for 0x00 and 5a', () => {
|
||||
const privateKey = '002fdd1f7641793ab064bb7aa848f762e7ec6e332ffc26eeacda141ae33b1783';
|
||||
const publicKey = ed.getPublicKey(privateKey);
|
||||
const message =
|
||||
'5ac1dfc324f43e6cb79a87ab0470fa857b51fb944982e19074ca44b1e40082c1d07b92efa7ea55ad42b7c027e0b9e33756d95a2c1796a7c2066811dc41858377d4b835c1688d638884cd2ad8970b74c1a54aadd27064163928a77988b24403aa85af82ceab6b728e554761af7175aeb99215b7421e4474c04d213e01ff03e3529b11077cdf28964b8c49c5649e3a46fa0a09dcd59dcad58b9b922a83210acd5e65065531400234f5e40cddcf9804968e3e9ac6f5c44af65001e158067fc3a660502d13fa8874fa93332138d9606bc41b4cee7edc39d753dae12a873941bb357f7e92a4498847d6605456cb8c0b425a47d7d3ca37e54e903a41e6450a35ebe5237c6f0c1bbbc1fd71fb7cd893d189850295c199b7d88af26bc8548975fda1099ffefee42a52f3428ddff35e0173d3339562507ac5d2c45bbd2c19cfe89b';
|
||||
const signature = ed.sign(message, privateKey);
|
||||
deepStrictEqual(
|
||||
hex(publicKey),
|
||||
'77d1d8ebacd13f4e2f8a40e28c4a63bc9ce3bfb69716334bcb28a33eb134086c'
|
||||
);
|
||||
deepStrictEqual(
|
||||
hex(signature),
|
||||
'0df3aa0d0999ad3dc580378f52d152700d5b3b057f56a66f92112e441e1cb9123c66f18712c87efe22d2573777296241216904d7cdd7d5ea433928bd2872fa0c'
|
||||
);
|
||||
});
|
||||
should('rfc8032 vectors/should create right signature for 0xf5 and long msg', () => {
|
||||
const privateKey = 'f5e5767cf153319517630f226876b86c8160cc583bc013744c6bf255f5cc0ee5';
|
||||
const publicKey = ed.getPublicKey(privateKey);
|
||||
const message =
|
||||
'08b8b2b733424243760fe426a4b54908632110a66c2f6591eabd3345e3e4eb98fa6e264bf09efe12ee50f8f54e9f77b1e355f6c50544e23fb1433ddf73be84d879de7c0046dc4996d9e773f4bc9efe5738829adb26c81b37c93a1b270b20329d658675fc6ea534e0810a4432826bf58c941efb65d57a338bbd2e26640f89ffbc1a858efcb8550ee3a5e1998bd177e93a7363c344fe6b199ee5d02e82d522c4feba15452f80288a821a579116ec6dad2b3b310da903401aa62100ab5d1a36553e06203b33890cc9b832f79ef80560ccb9a39ce767967ed628c6ad573cb116dbefefd75499da96bd68a8a97b928a8bbc103b6621fcde2beca1231d206be6cd9ec7aff6f6c94fcd7204ed3455c68c83f4a41da4af2b74ef5c53f1d8ac70bdcb7ed185ce81bd84359d44254d95629e9855a94a7c1958d1f8ada5d0532ed8a5aa3fb2d17ba70eb6248e594e1a2297acbbb39d502f1a8c6eb6f1ce22b3de1a1f40cc24554119a831a9aad6079cad88425de6bde1a9187ebb6092cf67bf2b13fd65f27088d78b7e883c8759d2c4f5c65adb7553878ad575f9fad878e80a0c9ba63bcbcc2732e69485bbc9c90bfbd62481d9089beccf80cfe2df16a2cf65bd92dd597b0707e0917af48bbb75fed413d238f5555a7a569d80c3414a8d0859dc65a46128bab27af87a71314f318c782b23ebfe808b82b0ce26401d2e22f04d83d1255dc51addd3b75a2b1ae0784504df543af8969be3ea7082ff7fc9888c144da2af58429ec96031dbcad3dad9af0dcbaaaf268cb8fcffead94f3c7ca495e056a9b47acdb751fb73e666c6c655ade8297297d07ad1ba5e43f1bca32301651339e22904cc8c42f58c30c04aafdb038dda0847dd988dcda6f3bfd15c4b4c4525004aa06eeff8ca61783aacec57fb3d1f92b0fe2fd1a85f6724517b65e614ad6808d6f6ee34dff7310fdc82aebfd904b01e1dc54b2927094b2db68d6f903b68401adebf5a7e08d78ff4ef5d63653a65040cf9bfd4aca7984a74d37145986780fc0b16ac451649de6188a7dbdf191f64b5fc5e2ab47b57f7f7276cd419c17a3ca8e1b939ae49e488acba6b965610b5480109c8b17b80e1b7b750dfc7598d5d5011fd2dcc5600a32ef5b52a1ecc820e308aa342721aac0943bf6686b64b2579376504ccc493d97e6aed3fb0f9cd71a43dd497f01f17c0e2cb3797aa2a2f256656168e6c496afc5fb93246f6b1116398a346f1a641f3b041e989f7914f90cc2c7fff357876e506b50d334ba77c225bc307ba537152f3f1610e4eafe595f6d9d90d11faa933a15ef1369546868a7f3a45a96768d40fd9d03412c091c6315cf4fde7cb68606937380db2eaaa707b4c4185c32eddcdd306705e4dc1ffc872eeee475a64dfac86aba41c0618983f8741c5ef68d3a101e8a3b8cac60c905c15fc910840b94c00a0b9d0';
|
||||
const signature = ed.sign(message, privateKey);
|
||||
deepStrictEqual(
|
||||
hex(publicKey),
|
||||
'278117fc144c72340f67d0f2316e8386ceffbf2b2428c9c51fef7c597f1d426e'
|
||||
);
|
||||
deepStrictEqual(
|
||||
hex(signature),
|
||||
'0aab4c900501b3e24d7cdf4663326a3a87df5e4843b2cbdb67cbf6e460fec350aa5371b1508f9f4528ecea23c436d94b5e8fcd4f681e30a6ac00a9704a188a03'
|
||||
);
|
||||
});
|
||||
|
||||
// const PRIVATE_KEY = 0xa665a45920422f9d417e4867efn;
|
||||
// const MESSAGE = ripemd160(new Uint8Array([97, 98, 99, 100, 101, 102, 103]));
|
||||
// prettier-ignore
|
||||
// const MESSAGE = new Uint8Array([
|
||||
// 135, 79, 153, 96, 197, 210, 183, 169, 181, 250, 211, 131, 225, 186, 68, 113, 158, 187, 116, 58,
|
||||
// ]);
|
||||
// const WRONG_MESSAGE = ripemd160(new Uint8Array([98, 99, 100, 101, 102, 103]));
|
||||
// prettier-ignore
|
||||
// const WRONG_MESSAGE = new Uint8Array([
|
||||
// 88, 157, 140, 127, 29, 160, 162, 75, 192, 123, 115, 129, 173, 72, 177, 207, 194, 17, 175, 28,
|
||||
// ]);
|
||||
// // it("should verify just signed message", async () => {
|
||||
// // await fc.assert(fc.asyncProperty(
|
||||
// // fc.hexa(),
|
||||
// // fc.bigInt(2n, ristretto25519.PRIME_ORDER),
|
||||
// // async (message, privateKey) => {
|
||||
// // const publicKey = await ristretto25519.getPublicKey(privateKey);
|
||||
// // const signature = await ristretto25519.sign(message, privateKey);
|
||||
// // expect(publicKey.length).toBe(32);
|
||||
// // expect(signature.length).toBe(64);
|
||||
// // expect(await ristretto25519.verify(signature, message, publicKey)).toBe(true);
|
||||
// // }),
|
||||
// // { numRuns: 1 }
|
||||
// // );
|
||||
// // });
|
||||
// // it("should not verify sign with wrong message", async () => {
|
||||
// // await fc.assert(fc.asyncProperty(
|
||||
// // fc.array(fc.integer(0x00, 0xff)),
|
||||
// // fc.array(fc.integer(0x00, 0xff)),
|
||||
// // fc.bigInt(2n, ristretto25519.PRIME_ORDER),
|
||||
// // async (bytes, wrongBytes, privateKey) => {
|
||||
// // const message = new Uint8Array(bytes);
|
||||
// // const wrongMessage = new Uint8Array(wrongBytes);
|
||||
// // const publicKey = await ristretto25519.getPublicKey(privateKey);
|
||||
// // const signature = await ristretto25519.sign(message, privateKey);
|
||||
// // expect(await ristretto25519.verify(signature, wrongMessage, publicKey)).toBe(
|
||||
// // bytes.toString() === wrongBytes.toString()
|
||||
// // );
|
||||
// // }),
|
||||
// // { numRuns: 1 }
|
||||
// // );
|
||||
// // });
|
||||
// // it("should sign and verify", async () => {
|
||||
// // const publicKey = await ristretto25519.getPublicKey(PRIVATE_KEY);
|
||||
// // const signature = await ristretto25519.sign(MESSAGE, PRIVATE_KEY);
|
||||
// // expect(await ristretto25519.verify(signature, MESSAGE, publicKey)).toBe(true);
|
||||
// // });
|
||||
// // it("should not verify signature with wrong public key", async () => {
|
||||
// // const publicKey = await ristretto25519.getPublicKey(12);
|
||||
// // const signature = await ristretto25519.sign(MESSAGE, PRIVATE_KEY);
|
||||
// // expect(await ristretto25519.verify(signature, MESSAGE, publicKey)).toBe(false);
|
||||
// // });
|
||||
// // it("should not verify signature with wrong hash", async () => {
|
||||
// // const publicKey = await ristretto25519.getPublicKey(PRIVATE_KEY);
|
||||
// // const signature = await ristretto25519.sign(MESSAGE, PRIVATE_KEY);
|
||||
// // expect(await ristretto25519.verify(signature, WRONG_MESSAGE, publicKey)).toBe(false);
|
||||
// // });
|
||||
should('ristretto255/should follow the byte encodings of small multiples', () => {
|
||||
const encodingsOfSmallMultiples = [
|
||||
// This is the identity point
|
||||
'0000000000000000000000000000000000000000000000000000000000000000',
|
||||
// This is the basepoint
|
||||
'e2f2ae0a6abc4e71a884a961c500515f58e30b6aa582dd8db6a65945e08d2d76',
|
||||
// These are small multiples of the basepoint
|
||||
'6a493210f7499cd17fecb510ae0cea23a110e8d5b901f8acadd3095c73a3b919',
|
||||
'94741f5d5d52755ece4f23f044ee27d5d1ea1e2bd196b462166b16152a9d0259',
|
||||
'da80862773358b466ffadfe0b3293ab3d9fd53c5ea6c955358f568322daf6a57',
|
||||
'e882b131016b52c1d3337080187cf768423efccbb517bb495ab812c4160ff44e',
|
||||
'f64746d3c92b13050ed8d80236a7f0007c3b3f962f5ba793d19a601ebb1df403',
|
||||
'44f53520926ec81fbd5a387845beb7df85a96a24ece18738bdcfa6a7822a176d',
|
||||
'903293d8f2287ebe10e2374dc1a53e0bc887e592699f02d077d5263cdd55601c',
|
||||
'02622ace8f7303a31cafc63f8fc48fdc16e1c8c8d234b2f0d6685282a9076031',
|
||||
'20706fd788b2720a1ed2a5dad4952b01f413bcf0e7564de8cdc816689e2db95f',
|
||||
'bce83f8ba5dd2fa572864c24ba1810f9522bc6004afe95877ac73241cafdab42',
|
||||
'e4549ee16b9aa03099ca208c67adafcafa4c3f3e4e5303de6026e3ca8ff84460',
|
||||
'aa52e000df2e16f55fb1032fc33bc42742dad6bd5a8fc0be0167436c5948501f',
|
||||
'46376b80f409b29dc2b5f6f0c52591990896e5716f41477cd30085ab7f10301e',
|
||||
'e0c418f7c8d9c4cdd7395b93ea124f3ad99021bb681dfc3302a9d99a2e53e64e',
|
||||
];
|
||||
let B = RistrettoPoint.BASE;
|
||||
let P = RistrettoPoint.ZERO;
|
||||
for (const encoded of encodingsOfSmallMultiples) {
|
||||
deepStrictEqual(P.toHex(), encoded);
|
||||
deepStrictEqual(RistrettoPoint.fromHex(encoded).toHex(), encoded);
|
||||
P = P.add(B);
|
||||
}
|
||||
});
|
||||
should('ristretto255/should not convert bad bytes encoding', () => {
|
||||
const badEncodings = [
|
||||
// These are all bad because they're non-canonical field encodings.
|
||||
'00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff',
|
||||
'ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f',
|
||||
'f3ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f',
|
||||
'edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f',
|
||||
// These are all bad because they're negative field elements.
|
||||
'0100000000000000000000000000000000000000000000000000000000000000',
|
||||
'01ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f',
|
||||
'ed57ffd8c914fb201471d1c3d245ce3c746fcbe63a3679d51b6a516ebebe0e20',
|
||||
'c34c4e1826e5d403b78e246e88aa051c36ccf0aafebffe137d148a2bf9104562',
|
||||
'c940e5a4404157cfb1628b108db051a8d439e1a421394ec4ebccb9ec92a8ac78',
|
||||
'47cfc5497c53dc8e61c91d17fd626ffb1c49e2bca94eed052281b510b1117a24',
|
||||
'f1c6165d33367351b0da8f6e4511010c68174a03b6581212c71c0e1d026c3c72',
|
||||
'87260f7a2f12495118360f02c26a470f450dadf34a413d21042b43b9d93e1309',
|
||||
// These are all bad because they give a nonsquare x^2.
|
||||
'26948d35ca62e643e26a83177332e6b6afeb9d08e4268b650f1f5bbd8d81d371',
|
||||
'4eac077a713c57b4f4397629a4145982c661f48044dd3f96427d40b147d9742f',
|
||||
'de6a7b00deadc788eb6b6c8d20c0ae96c2f2019078fa604fee5b87d6e989ad7b',
|
||||
'bcab477be20861e01e4a0e295284146a510150d9817763caf1a6f4b422d67042',
|
||||
'2a292df7e32cababbd9de088d1d1abec9fc0440f637ed2fba145094dc14bea08',
|
||||
'f4a9e534fc0d216c44b218fa0c42d99635a0127ee2e53c712f70609649fdff22',
|
||||
'8268436f8c4126196cf64b3c7ddbda90746a378625f9813dd9b8457077256731',
|
||||
'2810e5cbc2cc4d4eece54f61c6f69758e289aa7ab440b3cbeaa21995c2f4232b',
|
||||
// These are all bad because they give a negative xy value.
|
||||
'3eb858e78f5a7254d8c9731174a94f76755fd3941c0ac93735c07ba14579630e',
|
||||
'a45fdc55c76448c049a1ab33f17023edfb2be3581e9c7aade8a6125215e04220',
|
||||
'd483fe813c6ba647ebbfd3ec41adca1c6130c2beeee9d9bf065c8d151c5f396e',
|
||||
'8a2e1d30050198c65a54483123960ccc38aef6848e1ec8f5f780e8523769ba32',
|
||||
'32888462f8b486c68ad7dd9610be5192bbeaf3b443951ac1a8118419d9fa097b',
|
||||
'227142501b9d4355ccba290404bde41575b037693cef1f438c47f8fbf35d1165',
|
||||
'5c37cc491da847cfeb9281d407efc41e15144c876e0170b499a96a22ed31e01e',
|
||||
'445425117cb8c90edcbc7c1cc0e74f747f2c1efa5630a967c64f287792a48a4b',
|
||||
// This is s = -1, which causes y = 0.
|
||||
'ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f',
|
||||
];
|
||||
for (const badBytes of badEncodings) {
|
||||
const b = hexToBytes(badBytes);
|
||||
throws(() => RistrettoPoint.fromHex(b), badBytes);
|
||||
}
|
||||
});
|
||||
should('ristretto255/should create right points from uniform hash', async () => {
|
||||
const labels = [
|
||||
'Ristretto is traditionally a short shot of espresso coffee',
|
||||
'made with the normal amount of ground coffee but extracted with',
|
||||
'about half the amount of water in the same amount of time',
|
||||
'by using a finer grind.',
|
||||
'This produces a concentrated shot of coffee per volume.',
|
||||
'Just pulling a normal shot short will produce a weaker shot',
|
||||
'and is not a Ristretto as some believe.',
|
||||
];
|
||||
const encodedHashToPoints = [
|
||||
'3066f82a1a747d45120d1740f14358531a8f04bbffe6a819f86dfe50f44a0a46',
|
||||
'f26e5b6f7d362d2d2a94c5d0e7602cb4773c95a2e5c31a64f133189fa76ed61b',
|
||||
'006ccd2a9e6867e6a2c5cea83d3302cc9de128dd2a9a57dd8ee7b9d7ffe02826',
|
||||
'f8f0c87cf237953c5890aec3998169005dae3eca1fbb04548c635953c817f92a',
|
||||
'ae81e7dedf20a497e10c304a765c1767a42d6e06029758d2d7e8ef7cc4c41179',
|
||||
'e2705652ff9f5e44d3e841bf1c251cf7dddb77d140870d1ab2ed64f1a9ce8628',
|
||||
'80bd07262511cdde4863f8a7434cef696750681cb9510eea557088f76d9e5065',
|
||||
];
|
||||
|
||||
for (let i = 0; i < labels.length; i++) {
|
||||
const hash = sha512(utf8ToBytes(labels[i]));
|
||||
const point = RistrettoPoint.hashToCurve(hash);
|
||||
deepStrictEqual(point.toHex(), encodedHashToPoints[i]);
|
||||
}
|
||||
});
|
||||
|
||||
should('input immutability: sign/verify are immutable', () => {
|
||||
const privateKey = ed.utils.randomPrivateKey();
|
||||
const publicKey = ed.getPublicKey(privateKey);
|
||||
|
||||
for (let i = 0; i < 100; i++) {
|
||||
let payload = randomBytes(100);
|
||||
let signature = ed.sign(payload, privateKey);
|
||||
if (!ed.verify(signature, payload, publicKey)) {
|
||||
throw new Error('Signature verification failed');
|
||||
}
|
||||
const signatureCopy = Buffer.alloc(signature.byteLength);
|
||||
signatureCopy.set(signature, 0); // <-- breaks
|
||||
payload = payload.slice();
|
||||
signature = signature.slice();
|
||||
|
||||
if (!ed.verify(signatureCopy, payload, publicKey))
|
||||
throw new Error('Copied signature verification failed');
|
||||
}
|
||||
});
|
||||
|
||||
// https://zips.z.cash/zip-0215
|
||||
// Vectors from https://gist.github.com/hdevalence/93ed42d17ecab8e42138b213812c8cc7
|
||||
should('ZIP-215 compliance tests/should pass all of them', () => {
|
||||
const str = utf8ToBytes('Zcash');
|
||||
for (let v of zip215) {
|
||||
let noble = false;
|
||||
try {
|
||||
noble = ed.verify(v.sig_bytes, str, v.vk_bytes);
|
||||
} catch (e) {
|
||||
noble = false;
|
||||
}
|
||||
deepStrictEqual(noble, v.valid_zip215);
|
||||
}
|
||||
});
|
||||
should('ZIP-215 compliance tests/disallows sig.s >= CURVE.n', () => {
|
||||
const sig = new ed.Signature(ed.Point.BASE, 1n);
|
||||
sig.s = ed.CURVE.n + 1n;
|
||||
throws(() => ed.verify(sig, 'deadbeef', ed.Point.BASE));
|
||||
});
|
||||
|
||||
const rfc7748Mul = [
|
||||
{
|
||||
scalar: 'a546e36bf0527c9d3b16154b82465edd62144c0ac1fc5a18506a2244ba449ac4',
|
||||
u: 'e6db6867583030db3594c1a424b15f7c726624ec26b3353b10a903a6d0ab1c4c',
|
||||
outputU: 'c3da55379de9c6908e94ea4df28d084f32eccf03491c71f754b4075577a28552',
|
||||
},
|
||||
{
|
||||
scalar: '4b66e9d4d1b4673c5ad22691957d6af5c11b6421e0ea01d42ca4169e7918ba0d',
|
||||
u: 'e5210f12786811d3f4b7959d0538ae2c31dbe7106fc03c3efc4cd549c715a493',
|
||||
outputU: '95cbde9476e8907d7aade45cb4b873f88b595a68799fa152e6f8f7647aac7957',
|
||||
},
|
||||
];
|
||||
for (let i = 0; i < rfc7748Mul.length; i++) {
|
||||
const v = rfc7748Mul[i];
|
||||
should(`RFC7748: scalarMult (${i})`, () => {
|
||||
deepStrictEqual(hex(x25519.scalarMult(v.u, v.scalar)), v.outputU);
|
||||
});
|
||||
}
|
||||
|
||||
const rfc7748Iter = [
|
||||
{ scalar: '422c8e7a6227d7bca1350b3e2bb7279f7897b87bb6854b783c60e80311ae3079', iters: 1 },
|
||||
{ scalar: '684cf59ba83309552800ef566f2f4d3c1c3887c49360e3875f2eb94d99532c51', iters: 1000 },
|
||||
// { scalar: '7c3911e0ab2586fd864497297e575e6f3bc601c0883c30df5f4dd2d24f665424', iters: 1000000 },
|
||||
];
|
||||
for (let i = 0; i < rfc7748Iter.length; i++) {
|
||||
const { scalar, iters } = rfc7748Iter[i];
|
||||
should(`RFC7748: scalarMult iteration (${i})`, () => {
|
||||
let k = x25519.Gu;
|
||||
for (let i = 0, u = k; i < iters; i++) [k, u] = [x25519.scalarMult(u, k), k];
|
||||
deepStrictEqual(hex(k), scalar);
|
||||
});
|
||||
}
|
||||
|
||||
should('RFC7748 getSharedKey', () => {
|
||||
const alicePrivate = '77076d0a7318a57d3c16c17251b26645df4c2f87ebc0992ab177fba51db92c2a';
|
||||
const alicePublic = '8520f0098930a754748b7ddcb43ef75a0dbf3a0d26381af4eba4a98eaa9b4e6a';
|
||||
const bobPrivate = '5dab087e624a8a4b79e17f8b83800ee66f3bb1292618b6fd1c2f8b27ff88e0eb';
|
||||
const bobPublic = 'de9edb7d7b7dc1b4d35b61c2ece435373f8343c85b78674dadfc7e146f882b4f';
|
||||
const shared = '4a5d9d5ba4ce2de1728e3bf480350f25e07e21c947d19e3376f09b3c1e161742';
|
||||
deepStrictEqual(alicePublic, hex(x25519.getPublicKey(alicePrivate)));
|
||||
deepStrictEqual(bobPublic, hex(x25519.getPublicKey(bobPrivate)));
|
||||
deepStrictEqual(hex(x25519.scalarMult(bobPublic, alicePrivate)), shared);
|
||||
deepStrictEqual(hex(x25519.scalarMult(alicePublic, bobPrivate)), shared);
|
||||
});
|
||||
|
||||
// should('X25519/getSharedSecret() should be commutative', () => {
|
||||
// for (let i = 0; i < 512; i++) {
|
||||
// const asec = ed.utils.randomPrivateKey();
|
||||
// const apub = ed.getPublicKey(asec);
|
||||
// const bsec = ed.utils.randomPrivateKey();
|
||||
// const bpub = ed.getPublicKey(bsec);
|
||||
// try {
|
||||
// deepStrictEqual(ed.getSharedSecret(asec, bpub), ed.getSharedSecret(bsec, apub));
|
||||
// } catch (error) {
|
||||
// console.error('not commutative', { asec, apub, bsec, bpub });
|
||||
// throw error;
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
|
||||
// should('X25519: should convert base point to montgomery using fromPoint', () => {
|
||||
// deepStrictEqual(
|
||||
// hex(ed.montgomeryCurve.UfromPoint(ed.Point.BASE)),
|
||||
// ed.montgomeryCurve.BASE_POINT_U
|
||||
// );
|
||||
// });
|
||||
|
||||
{
|
||||
const group = x25519vectors.testGroups[0];
|
||||
should(`Wycheproof/X25519`, () => {
|
||||
for (let i = 0; i < group.tests.length; i++) {
|
||||
const v = group.tests[i];
|
||||
const comment = `(${i}, ${v.result}) ${v.comment}`;
|
||||
if (v.result === 'valid' || v.result === 'acceptable') {
|
||||
try {
|
||||
const shared = hex(x25519.scalarMult(v.public, v.private));
|
||||
deepStrictEqual(shared, v.shared, comment);
|
||||
} catch (e) {
|
||||
// We are more strict
|
||||
if (e.message.includes('Expected valid scalar')) return;
|
||||
if (e.message.includes('Invalid private or public key received')) return;
|
||||
throw e;
|
||||
}
|
||||
} else if (v.result === 'invalid') {
|
||||
let failed = false;
|
||||
try {
|
||||
x25519.scalarMult(v.public, v.private);
|
||||
} catch (error) {
|
||||
failed = true;
|
||||
}
|
||||
deepStrictEqual(failed, true, comment);
|
||||
} else throw new Error('unknown test result');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
should(`Wycheproof/ED25519`, () => {
|
||||
for (let g = 0; g < ed25519vectors.testGroups.length; g++) {
|
||||
const group = ed25519vectors.testGroups[g];
|
||||
const key = group.key;
|
||||
deepStrictEqual(hex(ed.getPublicKey(key.sk)), key.pk, `(${g}, public)`);
|
||||
for (let i = 0; i < group.tests.length; i++) {
|
||||
const v = group.tests[i];
|
||||
const comment = `(${g}/${i}, ${v.result}): ${v.comment}`;
|
||||
if (v.result === 'valid' || v.result === 'acceptable') {
|
||||
deepStrictEqual(hex(ed.sign(v.msg, key.sk)), v.sig, comment);
|
||||
deepStrictEqual(ed.verify(v.sig, v.msg, key.pk), true, comment);
|
||||
} else if (v.result === 'invalid') {
|
||||
let failed = false;
|
||||
try {
|
||||
failed = !ed.verify(v.sig, v.msg, key.pk);
|
||||
} catch (error) {
|
||||
failed = true;
|
||||
}
|
||||
deepStrictEqual(failed, true, comment);
|
||||
} else throw new Error('unknown test result');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
should('Property test issue #1', () => {
|
||||
const message = new Uint8Array([12, 12, 12]);
|
||||
const signature = ed.sign(message, to32Bytes(1n));
|
||||
const publicKey = ed.getPublicKey(to32Bytes(1n)); // <- was 1n
|
||||
deepStrictEqual(ed.verify(signature, message, publicKey), true);
|
||||
});
|
||||
|
||||
const VECTORS_RFC8032_CTX = [
|
||||
{
|
||||
secretKey: '0305334e381af78f141cb666f6199f57bc3495335a256a95bd2a55bf546663f6',
|
||||
publicKey: 'dfc9425e4f968f7f0c29f0259cf5f9aed6851c2bb4ad8bfb860cfee0ab248292',
|
||||
message: 'f726936d19c800494e3fdaff20b276a8',
|
||||
context: '666f6f',
|
||||
signature:
|
||||
'55a4cc2f70a54e04288c5f4cd1e45a7b' +
|
||||
'b520b36292911876cada7323198dd87a' +
|
||||
'8b36950b95130022907a7fb7c4e9b2d5' +
|
||||
'f6cca685a587b4b21f4b888e4e7edb0d',
|
||||
},
|
||||
{
|
||||
secretKey: '0305334e381af78f141cb666f6199f57bc3495335a256a95bd2a55bf546663f6',
|
||||
publicKey: 'dfc9425e4f968f7f0c29f0259cf5f9aed6851c2bb4ad8bfb860cfee0ab248292',
|
||||
message: 'f726936d19c800494e3fdaff20b276a8',
|
||||
context: '626172',
|
||||
signature:
|
||||
'fc60d5872fc46b3aa69f8b5b4351d580' +
|
||||
'8f92bcc044606db097abab6dbcb1aee3' +
|
||||
'216c48e8b3b66431b5b186d1d28f8ee1' +
|
||||
'5a5ca2df6668346291c2043d4eb3e90d',
|
||||
},
|
||||
{
|
||||
secretKey: '0305334e381af78f141cb666f6199f57bc3495335a256a95bd2a55bf546663f6',
|
||||
publicKey: 'dfc9425e4f968f7f0c29f0259cf5f9aed6851c2bb4ad8bfb860cfee0ab248292',
|
||||
message: '508e9e6882b979fea900f62adceaca35',
|
||||
context: '666f6f',
|
||||
signature:
|
||||
'8b70c1cc8310e1de20ac53ce28ae6e72' +
|
||||
'07f33c3295e03bb5c0732a1d20dc6490' +
|
||||
'8922a8b052cf99b7c4fe107a5abb5b2c' +
|
||||
'4085ae75890d02df26269d8945f84b0b',
|
||||
},
|
||||
{
|
||||
secretKey: 'ab9c2853ce297ddab85c993b3ae14bcad39b2c682beabc27d6d4eb20711d6560',
|
||||
publicKey: '0f1d1274943b91415889152e893d80e93275a1fc0b65fd71b4b0dda10ad7d772',
|
||||
message: 'f726936d19c800494e3fdaff20b276a8',
|
||||
context: '666f6f',
|
||||
signature:
|
||||
'21655b5f1aa965996b3f97b3c849eafb' +
|
||||
'a922a0a62992f73b3d1b73106a84ad85' +
|
||||
'e9b86a7b6005ea868337ff2d20a7f5fb' +
|
||||
'd4cd10b0be49a68da2b2e0dc0ad8960f',
|
||||
},
|
||||
];
|
||||
|
||||
for (let i = 0; i < VECTORS_RFC8032_CTX.length; i++) {
|
||||
const v = VECTORS_RFC8032_CTX[i];
|
||||
should(`RFC8032ctx/${i}`, () => {
|
||||
deepStrictEqual(hex(ed25519ctx.getPublicKey(v.secretKey)), v.publicKey);
|
||||
deepStrictEqual(hex(ed25519ctx.sign(v.message, v.secretKey, v.context)), v.signature);
|
||||
deepStrictEqual(ed25519ctx.verify(v.signature, v.message, v.publicKey, v.context), true);
|
||||
});
|
||||
}
|
||||
|
||||
const VECTORS_RFC8032_PH = [
|
||||
{
|
||||
secretKey: '833fe62409237b9d62ec77587520911e9a759cec1d19755b7da901b96dca3d42',
|
||||
publicKey: 'ec172b93ad5e563bf4932c70e1245034c35467ef2efd4d64ebf819683467e2bf',
|
||||
message: '616263',
|
||||
signature:
|
||||
'98a70222f0b8121aa9d30f813d683f80' +
|
||||
'9e462b469c7ff87639499bb94e6dae41' +
|
||||
'31f85042463c2a355a2003d062adf5aa' +
|
||||
'a10b8c61e636062aaad11c2a26083406',
|
||||
},
|
||||
];
|
||||
|
||||
for (let i = 0; i < VECTORS_RFC8032_PH.length; i++) {
|
||||
const v = VECTORS_RFC8032_PH[i];
|
||||
should(`RFC8032ph/${i}`, () => {
|
||||
deepStrictEqual(hex(ed25519ph.getPublicKey(v.secretKey)), v.publicKey);
|
||||
deepStrictEqual(hex(ed25519ph.sign(v.message, v.secretKey)), v.signature);
|
||||
deepStrictEqual(ed25519ph.verify(v.signature, v.message, v.publicKey), true);
|
||||
});
|
||||
}
|
||||
|
||||
should('X25519 base point', () => {
|
||||
const { y } = ed25519.Point.BASE;
|
||||
const u = ed25519.utils.mod((y + 1n) * ed25519.utils.invert(1n - y, ed25519.CURVE.P));
|
||||
deepStrictEqual(hex(numberToBytesLE(u, 32)), x25519.Gu);
|
||||
});
|
||||
|
||||
// ESM is broken.
|
||||
import url from 'url';
|
||||
if (import.meta.url === url.pathToFileURL(process.argv[1]).href) {
|
||||
should.run();
|
||||
}
|
||||
@@ -1,664 +0,0 @@
|
||||
import { deepStrictEqual, throws } from 'assert';
|
||||
import { should } from 'micro-should';
|
||||
import * as fc from 'fast-check';
|
||||
import { ed448, ed448ph, x448 } from '../lib/ed448.js';
|
||||
import { hexToBytes, bytesToHex, randomBytes } from '@noble/hashes/utils';
|
||||
import { numberToBytesLE } from '@noble/curves/utils';
|
||||
import { default as ed448vectors } from './wycheproof/ed448_test.json' assert { type: 'json' };
|
||||
import { default as x448vectors } from './wycheproof/x448_test.json' assert { type: 'json' };
|
||||
|
||||
const ed = ed448;
|
||||
const hex = bytesToHex;
|
||||
ed.utils.precompute(4);
|
||||
|
||||
should(`Basic`, () => {
|
||||
const G1 = ed.Point.BASE;
|
||||
deepStrictEqual(
|
||||
G1.x,
|
||||
224580040295924300187604334099896036246789641632564134246125461686950415467406032909029192869357953282578032075146446173674602635247710n
|
||||
);
|
||||
deepStrictEqual(
|
||||
G1.y,
|
||||
298819210078481492676017930443930673437544040154080242095928241372331506189835876003536878655418784733982303233503462500531545062832660n
|
||||
);
|
||||
const G2 = ed.Point.BASE.multiply(2n);
|
||||
deepStrictEqual(
|
||||
G2.x,
|
||||
484559149530404593699549205258669689569094240458212040187660132787056912146709081364401144455726350866276831544947397859048262938744149n
|
||||
);
|
||||
deepStrictEqual(
|
||||
G2.y,
|
||||
494088759867433727674302672526735089350544552303727723746126484473087719117037293890093462157703888342865036477787453078312060500281069n
|
||||
);
|
||||
const G3 = ed.Point.BASE.multiply(3n);
|
||||
deepStrictEqual(
|
||||
G3.x,
|
||||
23839778817283171003887799738662344287085130522697782688245073320169861206004018274567429238677677920280078599146891901463786155880335n
|
||||
);
|
||||
deepStrictEqual(
|
||||
G3.y,
|
||||
636046652612779686502873775776967954190574036985351036782021535703553242737829645273154208057988851307101009474686328623630835377952508n
|
||||
);
|
||||
});
|
||||
|
||||
should('Basic/decompress', () => {
|
||||
const G1 = ed.Point.BASE;
|
||||
const G2 = ed.Point.BASE.multiply(2n);
|
||||
const G3 = ed.Point.BASE.multiply(3n);
|
||||
const points = [G1, G2, G3];
|
||||
const getXY = (p) => ({ x: p.x, y: p.y });
|
||||
for (const p of points) deepStrictEqual(getXY(ed.Point.fromHex(p.toHex())), getXY(p));
|
||||
});
|
||||
|
||||
const VECTORS_RFC8032 = [
|
||||
{
|
||||
secretKey:
|
||||
'6c82a562cb808d10d632be89c8513ebf' +
|
||||
'6c929f34ddfa8c9f63c9960ef6e348a3' +
|
||||
'528c8a3fcc2f044e39a3fc5b94492f8f' +
|
||||
'032e7549a20098f95b',
|
||||
publicKey:
|
||||
'5fd7449b59b461fd2ce787ec616ad46a' +
|
||||
'1da1342485a70e1f8a0ea75d80e96778' +
|
||||
'edf124769b46c7061bd6783df1e50f6c' +
|
||||
'd1fa1abeafe8256180',
|
||||
message: '',
|
||||
signature:
|
||||
'533a37f6bbe457251f023c0d88f976ae' +
|
||||
'2dfb504a843e34d2074fd823d41a591f' +
|
||||
'2b233f034f628281f2fd7a22ddd47d78' +
|
||||
'28c59bd0a21bfd3980ff0d2028d4b18a' +
|
||||
'9df63e006c5d1c2d345b925d8dc00b41' +
|
||||
'04852db99ac5c7cdda8530a113a0f4db' +
|
||||
'b61149f05a7363268c71d95808ff2e65' +
|
||||
'2600',
|
||||
},
|
||||
{
|
||||
secretKey:
|
||||
'c4eab05d357007c632f3dbb48489924d' +
|
||||
'552b08fe0c353a0d4a1f00acda2c463a' +
|
||||
'fbea67c5e8d2877c5e3bc397a659949e' +
|
||||
'f8021e954e0a12274e',
|
||||
publicKey:
|
||||
'43ba28f430cdff456ae531545f7ecd0a' +
|
||||
'c834a55d9358c0372bfa0c6c6798c086' +
|
||||
'6aea01eb00742802b8438ea4cb82169c' +
|
||||
'235160627b4c3a9480',
|
||||
|
||||
message: '03',
|
||||
signature:
|
||||
'26b8f91727bd62897af15e41eb43c377' +
|
||||
'efb9c610d48f2335cb0bd0087810f435' +
|
||||
'2541b143c4b981b7e18f62de8ccdf633' +
|
||||
'fc1bf037ab7cd779805e0dbcc0aae1cb' +
|
||||
'cee1afb2e027df36bc04dcecbf154336' +
|
||||
'c19f0af7e0a6472905e799f1953d2a0f' +
|
||||
'f3348ab21aa4adafd1d234441cf807c0' +
|
||||
'3a00',
|
||||
},
|
||||
{
|
||||
secretKey:
|
||||
'cd23d24f714274e744343237b93290f5' +
|
||||
'11f6425f98e64459ff203e8985083ffd' +
|
||||
'f60500553abc0e05cd02184bdb89c4cc' +
|
||||
'd67e187951267eb328',
|
||||
publicKey:
|
||||
'dcea9e78f35a1bf3499a831b10b86c90' +
|
||||
'aac01cd84b67a0109b55a36e9328b1e3' +
|
||||
'65fce161d71ce7131a543ea4cb5f7e9f' +
|
||||
'1d8b00696447001400',
|
||||
message: '0c3e544074ec63b0265e0c',
|
||||
signature:
|
||||
'1f0a8888ce25e8d458a21130879b840a' +
|
||||
'9089d999aaba039eaf3e3afa090a09d3' +
|
||||
'89dba82c4ff2ae8ac5cdfb7c55e94d5d' +
|
||||
'961a29fe0109941e00b8dbdeea6d3b05' +
|
||||
'1068df7254c0cdc129cbe62db2dc957d' +
|
||||
'bb47b51fd3f213fb8698f064774250a5' +
|
||||
'028961c9bf8ffd973fe5d5c206492b14' +
|
||||
'0e00',
|
||||
},
|
||||
{
|
||||
secretKey:
|
||||
'258cdd4ada32ed9c9ff54e63756ae582' +
|
||||
'fb8fab2ac721f2c8e676a72768513d93' +
|
||||
'9f63dddb55609133f29adf86ec9929dc' +
|
||||
'cb52c1c5fd2ff7e21b',
|
||||
publicKey:
|
||||
'3ba16da0c6f2cc1f30187740756f5e79' +
|
||||
'8d6bc5fc015d7c63cc9510ee3fd44adc' +
|
||||
'24d8e968b6e46e6f94d19b945361726b' +
|
||||
'd75e149ef09817f580',
|
||||
message: '64a65f3cdedcdd66811e2915',
|
||||
signature:
|
||||
'7eeeab7c4e50fb799b418ee5e3197ff6' +
|
||||
'bf15d43a14c34389b59dd1a7b1b85b4a' +
|
||||
'e90438aca634bea45e3a2695f1270f07' +
|
||||
'fdcdf7c62b8efeaf00b45c2c96ba457e' +
|
||||
'b1a8bf075a3db28e5c24f6b923ed4ad7' +
|
||||
'47c3c9e03c7079efb87cb110d3a99861' +
|
||||
'e72003cbae6d6b8b827e4e6c143064ff' +
|
||||
'3c00',
|
||||
},
|
||||
{
|
||||
secretKey:
|
||||
'7ef4e84544236752fbb56b8f31a23a10' +
|
||||
'e42814f5f55ca037cdcc11c64c9a3b29' +
|
||||
'49c1bb60700314611732a6c2fea98eeb' +
|
||||
'c0266a11a93970100e',
|
||||
publicKey:
|
||||
'b3da079b0aa493a5772029f0467baebe' +
|
||||
'e5a8112d9d3a22532361da294f7bb381' +
|
||||
'5c5dc59e176b4d9f381ca0938e13c6c0' +
|
||||
'7b174be65dfa578e80',
|
||||
message: '64a65f3cdedcdd66811e2915e7',
|
||||
signature:
|
||||
'6a12066f55331b6c22acd5d5bfc5d712' +
|
||||
'28fbda80ae8dec26bdd306743c5027cb' +
|
||||
'4890810c162c027468675ecf645a8317' +
|
||||
'6c0d7323a2ccde2d80efe5a1268e8aca' +
|
||||
'1d6fbc194d3f77c44986eb4ab4177919' +
|
||||
'ad8bec33eb47bbb5fc6e28196fd1caf5' +
|
||||
'6b4e7e0ba5519234d047155ac727a105' +
|
||||
'3100',
|
||||
},
|
||||
{
|
||||
secretKey:
|
||||
'd65df341ad13e008567688baedda8e9d' +
|
||||
'cdc17dc024974ea5b4227b6530e339bf' +
|
||||
'f21f99e68ca6968f3cca6dfe0fb9f4fa' +
|
||||
'b4fa135d5542ea3f01',
|
||||
publicKey:
|
||||
'df9705f58edbab802c7f8363cfe5560a' +
|
||||
'b1c6132c20a9f1dd163483a26f8ac53a' +
|
||||
'39d6808bf4a1dfbd261b099bb03b3fb5' +
|
||||
'0906cb28bd8a081f00',
|
||||
message:
|
||||
'bd0f6a3747cd561bdddf4640a332461a' +
|
||||
'4a30a12a434cd0bf40d766d9c6d458e5' +
|
||||
'512204a30c17d1f50b5079631f64eb31' +
|
||||
'12182da3005835461113718d1a5ef944',
|
||||
signature:
|
||||
'554bc2480860b49eab8532d2a533b7d5' +
|
||||
'78ef473eeb58c98bb2d0e1ce488a98b1' +
|
||||
'8dfde9b9b90775e67f47d4a1c3482058' +
|
||||
'efc9f40d2ca033a0801b63d45b3b722e' +
|
||||
'f552bad3b4ccb667da350192b61c508c' +
|
||||
'f7b6b5adadc2c8d9a446ef003fb05cba' +
|
||||
'5f30e88e36ec2703b349ca229c267083' +
|
||||
'3900',
|
||||
},
|
||||
{
|
||||
secretKey:
|
||||
'2ec5fe3c17045abdb136a5e6a913e32a' +
|
||||
'b75ae68b53d2fc149b77e504132d3756' +
|
||||
'9b7e766ba74a19bd6162343a21c8590a' +
|
||||
'a9cebca9014c636df5',
|
||||
publicKey:
|
||||
'79756f014dcfe2079f5dd9e718be4171' +
|
||||
'e2ef2486a08f25186f6bff43a9936b9b' +
|
||||
'fe12402b08ae65798a3d81e22e9ec80e' +
|
||||
'7690862ef3d4ed3a00',
|
||||
message:
|
||||
'15777532b0bdd0d1389f636c5f6b9ba7' +
|
||||
'34c90af572877e2d272dd078aa1e567c' +
|
||||
'fa80e12928bb542330e8409f31745041' +
|
||||
'07ecd5efac61ae7504dabe2a602ede89' +
|
||||
'e5cca6257a7c77e27a702b3ae39fc769' +
|
||||
'fc54f2395ae6a1178cab4738e543072f' +
|
||||
'c1c177fe71e92e25bf03e4ecb72f47b6' +
|
||||
'4d0465aaea4c7fad372536c8ba516a60' +
|
||||
'39c3c2a39f0e4d832be432dfa9a706a6' +
|
||||
'e5c7e19f397964ca4258002f7c0541b5' +
|
||||
'90316dbc5622b6b2a6fe7a4abffd9610' +
|
||||
'5eca76ea7b98816af0748c10df048ce0' +
|
||||
'12d901015a51f189f3888145c03650aa' +
|
||||
'23ce894c3bd889e030d565071c59f409' +
|
||||
'a9981b51878fd6fc110624dcbcde0bf7' +
|
||||
'a69ccce38fabdf86f3bef6044819de11',
|
||||
signature:
|
||||
'c650ddbb0601c19ca11439e1640dd931' +
|
||||
'f43c518ea5bea70d3dcde5f4191fe53f' +
|
||||
'00cf966546b72bcc7d58be2b9badef28' +
|
||||
'743954e3a44a23f880e8d4f1cfce2d7a' +
|
||||
'61452d26da05896f0a50da66a239a8a1' +
|
||||
'88b6d825b3305ad77b73fbac0836ecc6' +
|
||||
'0987fd08527c1a8e80d5823e65cafe2a' +
|
||||
'3d00',
|
||||
},
|
||||
{
|
||||
secretKey:
|
||||
'872d093780f5d3730df7c212664b37b8' +
|
||||
'a0f24f56810daa8382cd4fa3f77634ec' +
|
||||
'44dc54f1c2ed9bea86fafb7632d8be19' +
|
||||
'9ea165f5ad55dd9ce8',
|
||||
publicKey:
|
||||
'a81b2e8a70a5ac94ffdbcc9badfc3feb' +
|
||||
'0801f258578bb114ad44ece1ec0e799d' +
|
||||
'a08effb81c5d685c0c56f64eecaef8cd' +
|
||||
'f11cc38737838cf400',
|
||||
message:
|
||||
'6ddf802e1aae4986935f7f981ba3f035' +
|
||||
'1d6273c0a0c22c9c0e8339168e675412' +
|
||||
'a3debfaf435ed651558007db4384b650' +
|
||||
'fcc07e3b586a27a4f7a00ac8a6fec2cd' +
|
||||
'86ae4bf1570c41e6a40c931db27b2faa' +
|
||||
'15a8cedd52cff7362c4e6e23daec0fbc' +
|
||||
'3a79b6806e316efcc7b68119bf46bc76' +
|
||||
'a26067a53f296dafdbdc11c77f7777e9' +
|
||||
'72660cf4b6a9b369a6665f02e0cc9b6e' +
|
||||
'dfad136b4fabe723d2813db3136cfde9' +
|
||||
'b6d044322fee2947952e031b73ab5c60' +
|
||||
'3349b307bdc27bc6cb8b8bbd7bd32321' +
|
||||
'9b8033a581b59eadebb09b3c4f3d2277' +
|
||||
'd4f0343624acc817804728b25ab79717' +
|
||||
'2b4c5c21a22f9c7839d64300232eb66e' +
|
||||
'53f31c723fa37fe387c7d3e50bdf9813' +
|
||||
'a30e5bb12cf4cd930c40cfb4e1fc6225' +
|
||||
'92a49588794494d56d24ea4b40c89fc0' +
|
||||
'596cc9ebb961c8cb10adde976a5d602b' +
|
||||
'1c3f85b9b9a001ed3c6a4d3b1437f520' +
|
||||
'96cd1956d042a597d561a596ecd3d173' +
|
||||
'5a8d570ea0ec27225a2c4aaff26306d1' +
|
||||
'526c1af3ca6d9cf5a2c98f47e1c46db9' +
|
||||
'a33234cfd4d81f2c98538a09ebe76998' +
|
||||
'd0d8fd25997c7d255c6d66ece6fa56f1' +
|
||||
'1144950f027795e653008f4bd7ca2dee' +
|
||||
'85d8e90f3dc315130ce2a00375a318c7' +
|
||||
'c3d97be2c8ce5b6db41a6254ff264fa6' +
|
||||
'155baee3b0773c0f497c573f19bb4f42' +
|
||||
'40281f0b1f4f7be857a4e59d416c06b4' +
|
||||
'c50fa09e1810ddc6b1467baeac5a3668' +
|
||||
'd11b6ecaa901440016f389f80acc4db9' +
|
||||
'77025e7f5924388c7e340a732e554440' +
|
||||
'e76570f8dd71b7d640b3450d1fd5f041' +
|
||||
'0a18f9a3494f707c717b79b4bf75c984' +
|
||||
'00b096b21653b5d217cf3565c9597456' +
|
||||
'f70703497a078763829bc01bb1cbc8fa' +
|
||||
'04eadc9a6e3f6699587a9e75c94e5bab' +
|
||||
'0036e0b2e711392cff0047d0d6b05bd2' +
|
||||
'a588bc109718954259f1d86678a579a3' +
|
||||
'120f19cfb2963f177aeb70f2d4844826' +
|
||||
'262e51b80271272068ef5b3856fa8535' +
|
||||
'aa2a88b2d41f2a0e2fda7624c2850272' +
|
||||
'ac4a2f561f8f2f7a318bfd5caf969614' +
|
||||
'9e4ac824ad3460538fdc25421beec2cc' +
|
||||
'6818162d06bbed0c40a387192349db67' +
|
||||
'a118bada6cd5ab0140ee273204f628aa' +
|
||||
'd1c135f770279a651e24d8c14d75a605' +
|
||||
'9d76b96a6fd857def5e0b354b27ab937' +
|
||||
'a5815d16b5fae407ff18222c6d1ed263' +
|
||||
'be68c95f32d908bd895cd76207ae7264' +
|
||||
'87567f9a67dad79abec316f683b17f2d' +
|
||||
'02bf07e0ac8b5bc6162cf94697b3c27c' +
|
||||
'd1fea49b27f23ba2901871962506520c' +
|
||||
'392da8b6ad0d99f7013fbc06c2c17a56' +
|
||||
'9500c8a7696481c1cd33e9b14e40b82e' +
|
||||
'79a5f5db82571ba97bae3ad3e0479515' +
|
||||
'bb0e2b0f3bfcd1fd33034efc6245eddd' +
|
||||
'7ee2086ddae2600d8ca73e214e8c2b0b' +
|
||||
'db2b047c6a464a562ed77b73d2d841c4' +
|
||||
'b34973551257713b753632efba348169' +
|
||||
'abc90a68f42611a40126d7cb21b58695' +
|
||||
'568186f7e569d2ff0f9e745d0487dd2e' +
|
||||
'b997cafc5abf9dd102e62ff66cba87',
|
||||
signature:
|
||||
'e301345a41a39a4d72fff8df69c98075' +
|
||||
'a0cc082b802fc9b2b6bc503f926b65bd' +
|
||||
'df7f4c8f1cb49f6396afc8a70abe6d8a' +
|
||||
'ef0db478d4c6b2970076c6a0484fe76d' +
|
||||
'76b3a97625d79f1ce240e7c576750d29' +
|
||||
'5528286f719b413de9ada3e8eb78ed57' +
|
||||
'3603ce30d8bb761785dc30dbc320869e' +
|
||||
'1a00',
|
||||
},
|
||||
];
|
||||
|
||||
for (let i = 0; i < VECTORS_RFC8032.length; i++) {
|
||||
const v = VECTORS_RFC8032[i];
|
||||
should(`RFC8032/${i}`, () => {
|
||||
deepStrictEqual(hex(ed.getPublicKey(v.secretKey)), v.publicKey);
|
||||
deepStrictEqual(hex(ed.sign(v.message, v.secretKey)), v.signature);
|
||||
deepStrictEqual(ed.verify(v.signature, v.message, v.publicKey), true);
|
||||
});
|
||||
}
|
||||
|
||||
should('ed448/should not accept >57byte private keys', async () => {
|
||||
const invalidPriv =
|
||||
100000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000090000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800073278156000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000n;
|
||||
throws(() => ed.getPublicKey(invalidPriv));
|
||||
});
|
||||
|
||||
function to57Bytes(numOrStr) {
|
||||
let hex = typeof numOrStr === 'string' ? numOrStr : numOrStr.toString(16);
|
||||
return hexToBytes(hex.padStart(114, '0'));
|
||||
}
|
||||
|
||||
should('ed448/should verify recent signature', () => {
|
||||
fc.assert(
|
||||
fc.property(
|
||||
fc.hexaString({ minLength: 2, maxLength: 57 }),
|
||||
fc.bigInt(2n, ed.CURVE.n),
|
||||
(message, privateKey) => {
|
||||
const publicKey = ed.getPublicKey(to57Bytes(privateKey));
|
||||
const signature = ed.sign(to57Bytes(message), to57Bytes(privateKey));
|
||||
deepStrictEqual(publicKey.length, 57);
|
||||
deepStrictEqual(signature.length, 114);
|
||||
deepStrictEqual(ed.verify(signature, to57Bytes(message), publicKey), true);
|
||||
}
|
||||
),
|
||||
{ numRuns: 5 }
|
||||
);
|
||||
});
|
||||
should('ed448/should not verify signature with wrong message', () => {
|
||||
fc.assert(
|
||||
fc.property(
|
||||
fc.array(fc.integer({ min: 0x00, max: 0xff })),
|
||||
fc.array(fc.integer({ min: 0x00, max: 0xff })),
|
||||
fc.bigInt(1n, ed.CURVE.n),
|
||||
(bytes, wrongBytes, privateKey) => {
|
||||
const message = new Uint8Array(bytes);
|
||||
const wrongMessage = new Uint8Array(wrongBytes);
|
||||
const priv = to57Bytes(privateKey);
|
||||
const publicKey = ed.getPublicKey(priv);
|
||||
const signature = ed.sign(message, priv);
|
||||
deepStrictEqual(
|
||||
ed.verify(signature, wrongMessage, publicKey),
|
||||
bytes.toString() === wrongBytes.toString()
|
||||
);
|
||||
}
|
||||
),
|
||||
{ numRuns: 5 }
|
||||
);
|
||||
});
|
||||
const privKey = to57Bytes('a665a45920422f9d417e4867ef');
|
||||
const msg = hexToBytes('874f9960c5d2b7a9b5fad383e1ba44719ebb743a');
|
||||
const wrongMsg = hexToBytes('589d8c7f1da0a24bc07b7381ad48b1cfc211af1c');
|
||||
should('ed25519/basic methods/should sign and verify', () => {
|
||||
const publicKey = ed.getPublicKey(privKey);
|
||||
const signature = ed.sign(msg, privKey);
|
||||
deepStrictEqual(ed.verify(signature, msg, publicKey), true);
|
||||
});
|
||||
should('ed25519/basic methods/should not verify signature with wrong public key', () => {
|
||||
const publicKey = ed.getPublicKey(12);
|
||||
const signature = ed.sign(msg, privKey);
|
||||
deepStrictEqual(ed.verify(signature, msg, publicKey), false);
|
||||
});
|
||||
should('ed25519/basic methods/should not verify signature with wrong hash', () => {
|
||||
const publicKey = ed.getPublicKey(privKey);
|
||||
const signature = ed.sign(msg, privKey);
|
||||
deepStrictEqual(ed.verify(signature, wrongMsg, publicKey), false);
|
||||
});
|
||||
|
||||
should('ed25519/sync methods/should sign and verify', () => {
|
||||
const publicKey = ed.getPublicKey(privKey);
|
||||
const signature = ed.sign(msg, privKey);
|
||||
deepStrictEqual(ed.verify(signature, msg, publicKey), true);
|
||||
});
|
||||
should('ed25519/sync methods/should not verify signature with wrong public key', async () => {
|
||||
const publicKey = ed.getPublicKey(12);
|
||||
const signature = ed.sign(msg, privKey);
|
||||
deepStrictEqual(ed.verify(signature, msg, publicKey), false);
|
||||
});
|
||||
should('ed25519/sync methods/should not verify signature with wrong hash', async () => {
|
||||
const publicKey = ed.getPublicKey(privKey);
|
||||
const signature = ed.sign(msg, privKey);
|
||||
deepStrictEqual(ed.verify(signature, wrongMsg, publicKey), false);
|
||||
});
|
||||
|
||||
should('ed25519/BASE_POINT.multiply()/should throw Point#multiply on TEST 5', () => {
|
||||
for (const num of [0n, 0, -1n, -1, 1.1]) {
|
||||
throws(() => ed.Point.BASE.multiply(num));
|
||||
}
|
||||
});
|
||||
|
||||
should('input immutability: sign/verify are immutable', () => {
|
||||
const privateKey = ed.utils.randomPrivateKey();
|
||||
const publicKey = ed.getPublicKey(privateKey);
|
||||
|
||||
for (let i = 0; i < 100; i++) {
|
||||
let payload = randomBytes(100);
|
||||
let signature = ed.sign(payload, privateKey);
|
||||
if (!ed.verify(signature, payload, publicKey)) {
|
||||
throw new Error('Signature verification failed');
|
||||
}
|
||||
const signatureCopy = Buffer.alloc(signature.byteLength);
|
||||
signatureCopy.set(signature, 0); // <-- breaks
|
||||
payload = payload.slice();
|
||||
signature = signature.slice();
|
||||
|
||||
if (!ed.verify(signatureCopy, payload, publicKey))
|
||||
throw new Error('Copied signature verification failed');
|
||||
}
|
||||
});
|
||||
|
||||
{
|
||||
for (let g = 0; g < ed448vectors.testGroups.length; g++) {
|
||||
const group = ed448vectors.testGroups[g];
|
||||
const key = group.key;
|
||||
should(`Wycheproof/ED448(${g}, public)`, () => {
|
||||
deepStrictEqual(hex(ed.getPublicKey(key.sk)), key.pk);
|
||||
});
|
||||
should(`Wycheproof/ED448`, () => {
|
||||
for (let i = 0; i < group.tests.length; i++) {
|
||||
const v = group.tests[i];
|
||||
const index = `${g}/${i} ${v.comment}`;
|
||||
if (v.result === 'valid' || v.result === 'acceptable') {
|
||||
deepStrictEqual(hex(ed.sign(v.msg, key.sk)), v.sig, index);
|
||||
deepStrictEqual(ed.verify(v.sig, v.msg, key.pk), true, index);
|
||||
} else if (v.result === 'invalid') {
|
||||
let failed = false;
|
||||
try {
|
||||
failed = !ed.verify(v.sig, v.msg, key.pk);
|
||||
} catch (error) {
|
||||
failed = true;
|
||||
}
|
||||
deepStrictEqual(failed, true, index);
|
||||
} else throw new Error('unknown test result');
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// ECDH
|
||||
const rfc7748Mul = [
|
||||
{
|
||||
scalar:
|
||||
'3d262fddf9ec8e88495266fea19a34d28882acef045104d0d1aae121700a779c984c24f8cdd78fbff44943eba368f54b29259a4f1c600ad3',
|
||||
u: '06fce640fa3487bfda5f6cf2d5263f8aad88334cbd07437f020f08f9814dc031ddbdc38c19c6da2583fa5429db94ada18aa7a7fb4ef8a086',
|
||||
outputU:
|
||||
'ce3e4ff95a60dc6697da1db1d85e6afbdf79b50a2412d7546d5f239fe14fbaadeb445fc66a01b0779d98223961111e21766282f73dd96b6f',
|
||||
},
|
||||
{
|
||||
scalar:
|
||||
'203d494428b8399352665ddca42f9de8fef600908e0d461cb021f8c538345dd77c3e4806e25f46d3315c44e0a5b4371282dd2c8d5be3095f',
|
||||
u: '0fbcc2f993cd56d3305b0b7d9e55d4c1a8fb5dbb52f8e9a1e9b6201b165d015894e56c4d3570bee52fe205e28a78b91cdfbde71ce8d157db',
|
||||
outputU:
|
||||
'884a02576239ff7a2f2f63b2db6a9ff37047ac13568e1e30fe63c4a7ad1b3ee3a5700df34321d62077e63633c575c1c954514e99da7c179d',
|
||||
},
|
||||
];
|
||||
for (let i = 0; i < rfc7748Mul.length; i++) {
|
||||
const v = rfc7748Mul[i];
|
||||
should(`RFC7748: scalarMult (${i})`, () => {
|
||||
deepStrictEqual(hex(x448.scalarMult(v.u, v.scalar)), v.outputU);
|
||||
});
|
||||
}
|
||||
|
||||
const rfc7748Iter = [
|
||||
{
|
||||
scalar:
|
||||
'3f482c8a9f19b01e6c46ee9711d9dc14fd4bf67af30765c2ae2b846a4d23a8cd0db897086239492caf350b51f833868b9bc2b3bca9cf4113',
|
||||
iters: 1,
|
||||
},
|
||||
{
|
||||
scalar:
|
||||
'aa3b4749d55b9daf1e5b00288826c467274ce3ebbdd5c17b975e09d4af6c67cf10d087202db88286e2b79fceea3ec353ef54faa26e219f38',
|
||||
iters: 1000,
|
||||
},
|
||||
// { scalar: '077f453681caca3693198420bbe515cae0002472519b3e67661a7e89cab94695c8f4bcd66e61b9b9c946da8d524de3d69bd9d9d66b997e37', iters: 1000000 },
|
||||
];
|
||||
for (let i = 0; i < rfc7748Iter.length; i++) {
|
||||
const { scalar, iters } = rfc7748Iter[i];
|
||||
should(`RFC7748: scalarMult iteration (${i})`, () => {
|
||||
let k = x448.Gu;
|
||||
for (let i = 0, u = k; i < iters; i++) [k, u] = [x448.scalarMult(u, k), k];
|
||||
deepStrictEqual(hex(k), scalar);
|
||||
});
|
||||
}
|
||||
|
||||
should('RFC7748 getSharedKey', () => {
|
||||
const alicePrivate =
|
||||
'9a8f4925d1519f5775cf46b04b5800d4ee9ee8bae8bc5565d498c28dd9c9baf574a9419744897391006382a6f127ab1d9ac2d8c0a598726b';
|
||||
const alicePublic =
|
||||
'9b08f7cc31b7e3e67d22d5aea121074a273bd2b83de09c63faa73d2c22c5d9bbc836647241d953d40c5b12da88120d53177f80e532c41fa0';
|
||||
const bobPrivate =
|
||||
'1c306a7ac2a0e2e0990b294470cba339e6453772b075811d8fad0d1d6927c120bb5ee8972b0d3e21374c9c921b09d1b0366f10b65173992d';
|
||||
const bobPublic =
|
||||
'3eb7a829b0cd20f5bcfc0b599b6feccf6da4627107bdb0d4f345b43027d8b972fc3e34fb4232a13ca706dcb57aec3dae07bdc1c67bf33609';
|
||||
const shared =
|
||||
'07fff4181ac6cc95ec1c16a94a0f74d12da232ce40a77552281d282bb60c0b56fd2464c335543936521c24403085d59a449a5037514a879d';
|
||||
deepStrictEqual(alicePublic, hex(x448.getPublicKey(alicePrivate)));
|
||||
deepStrictEqual(bobPublic, hex(x448.getPublicKey(bobPrivate)));
|
||||
deepStrictEqual(hex(x448.scalarMult(bobPublic, alicePrivate)), shared);
|
||||
deepStrictEqual(hex(x448.scalarMult(alicePublic, bobPrivate)), shared);
|
||||
});
|
||||
|
||||
{
|
||||
const group = x448vectors.testGroups[0];
|
||||
should(`Wycheproof/X448`, () => {
|
||||
for (let i = 0; i < group.tests.length; i++) {
|
||||
const v = group.tests[i];
|
||||
const index = `(${i}, ${v.result}) ${v.comment}`;
|
||||
if (v.result === 'valid' || v.result === 'acceptable') {
|
||||
try {
|
||||
const shared = hex(x448.scalarMult(v.public, v.private));
|
||||
deepStrictEqual(shared, v.shared, index);
|
||||
} catch (e) {
|
||||
// We are more strict
|
||||
if (e.message.includes('Expected valid scalar')) return;
|
||||
if (e.message.includes('Invalid private or public key received')) return;
|
||||
if (e.message.includes('Expected 56 bytes')) return;
|
||||
throw e;
|
||||
}
|
||||
} else if (v.result === 'invalid') {
|
||||
let failed = false;
|
||||
try {
|
||||
x448.scalarMult(v.public, v.private);
|
||||
} catch (error) {
|
||||
failed = true;
|
||||
}
|
||||
deepStrictEqual(failed, true, index);
|
||||
} else throw new Error('unknown test result');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// should('X448: should convert base point to montgomery using fromPoint', () => {
|
||||
// deepStrictEqual(
|
||||
// hex(ed.montgomeryCurve.UfromPoint(ed.Point.BASE)),
|
||||
// ed.montgomeryCurve.BASE_POINT_U
|
||||
// );
|
||||
// });
|
||||
|
||||
// should('X448/getSharedSecret() should be commutative', async () => {
|
||||
// for (let i = 0; i < 512; i++) {
|
||||
// const asec = ed.utils.randomPrivateKey();
|
||||
// const apub = ed.getPublicKey(asec);
|
||||
// const bsec = ed.utils.randomPrivateKey();
|
||||
// const bpub = ed.getPublicKey(bsec);
|
||||
// try {
|
||||
// deepStrictEqual(ed.getSharedSecret(asec, bpub), ed.getSharedSecret(bsec, apub));
|
||||
// } catch (error) {
|
||||
// console.error('not commutative', { asec, apub, bsec, bpub });
|
||||
// throw error;
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
|
||||
const VECTORS_RFC8032_CTX = [
|
||||
{
|
||||
secretKey:
|
||||
'c4eab05d357007c632f3dbb48489924d552b08fe0c353a0d4a1f00acda2c463afbea67c5e8d2877c5e3bc397a659949ef8021e954e0a12274e',
|
||||
publicKey:
|
||||
'43ba28f430cdff456ae531545f7ecd0ac834a55d9358c0372bfa0c6c6798c0866aea01eb00742802b8438ea4cb82169c235160627b4c3a9480',
|
||||
message: '03',
|
||||
context: '666f6f',
|
||||
signature:
|
||||
'd4f8f6131770dd46f40867d6fd5d5055' +
|
||||
'de43541f8c5e35abbcd001b32a89f7d2' +
|
||||
'151f7647f11d8ca2ae279fb842d60721' +
|
||||
'7fce6e042f6815ea000c85741de5c8da' +
|
||||
'1144a6a1aba7f96de42505d7a7298524' +
|
||||
'fda538fccbbb754f578c1cad10d54d0d' +
|
||||
'5428407e85dcbc98a49155c13764e66c' +
|
||||
'3c00',
|
||||
},
|
||||
];
|
||||
|
||||
for (let i = 0; i < VECTORS_RFC8032_CTX.length; i++) {
|
||||
const v = VECTORS_RFC8032_CTX[i];
|
||||
should(`RFC8032ctx/${i}`, () => {
|
||||
deepStrictEqual(hex(ed.getPublicKey(v.secretKey)), v.publicKey);
|
||||
deepStrictEqual(hex(ed.sign(v.message, v.secretKey, v.context)), v.signature);
|
||||
deepStrictEqual(ed.verify(v.signature, v.message, v.publicKey, v.context), true);
|
||||
});
|
||||
}
|
||||
|
||||
const VECTORS_RFC8032_PH = [
|
||||
{
|
||||
secretKey:
|
||||
'833fe62409237b9d62ec77587520911e9a759cec1d19755b7da901b96dca3d42ef7822e0d5104127dc05d6dbefde69e3ab2cec7c867c6e2c49',
|
||||
publicKey:
|
||||
'259b71c19f83ef77a7abd26524cbdb3161b590a48f7d17de3ee0ba9c52beb743c09428a131d6b1b57303d90d8132c276d5ed3d5d01c0f53880',
|
||||
message: '616263',
|
||||
signature:
|
||||
'822f6901f7480f3d5f562c592994d969' +
|
||||
'3602875614483256505600bbc281ae38' +
|
||||
'1f54d6bce2ea911574932f52a4e6cadd' +
|
||||
'78769375ec3ffd1b801a0d9b3f4030cd' +
|
||||
'433964b6457ea39476511214f97469b5' +
|
||||
'7dd32dbc560a9a94d00bff07620464a3' +
|
||||
'ad203df7dc7ce360c3cd3696d9d9fab9' +
|
||||
'0f00',
|
||||
},
|
||||
{
|
||||
secretKey:
|
||||
'833fe62409237b9d62ec77587520911e9a759cec1d19755b7da901b96dca3d42ef7822e0d5104127dc05d6dbefde69e3ab2cec7c867c6e2c49',
|
||||
publicKey:
|
||||
'259b71c19f83ef77a7abd26524cbdb3161b590a48f7d17de3ee0ba9c52beb743c09428a131d6b1b57303d90d8132c276d5ed3d5d01c0f53880',
|
||||
message: '616263',
|
||||
context: '666f6f',
|
||||
signature:
|
||||
'c32299d46ec8ff02b54540982814dce9' +
|
||||
'a05812f81962b649d528095916a2aa48' +
|
||||
'1065b1580423ef927ecf0af5888f90da' +
|
||||
'0f6a9a85ad5dc3f280d91224ba9911a3' +
|
||||
'653d00e484e2ce232521481c8658df30' +
|
||||
'4bb7745a73514cdb9bf3e15784ab7128' +
|
||||
'4f8d0704a608c54a6b62d97beb511d13' +
|
||||
'2100',
|
||||
},
|
||||
];
|
||||
|
||||
for (let i = 0; i < VECTORS_RFC8032_PH.length; i++) {
|
||||
const v = VECTORS_RFC8032_PH[i];
|
||||
should(`RFC8032ph/${i}`, () => {
|
||||
deepStrictEqual(hex(ed448ph.getPublicKey(v.secretKey)), v.publicKey);
|
||||
deepStrictEqual(hex(ed448ph.sign(v.message, v.secretKey, v.context)), v.signature);
|
||||
deepStrictEqual(ed448ph.verify(v.signature, v.message, v.publicKey, v.context), true);
|
||||
});
|
||||
}
|
||||
|
||||
should('X448 base point', () => {
|
||||
const { x, y } = ed448.Point.BASE;
|
||||
const { P } = ed448.CURVE;
|
||||
const invX = ed448.utils.invert(x * x, P); // x^2
|
||||
const u = ed448.utils.mod(y * y * invX, P); // (y^2/x^2)
|
||||
deepStrictEqual(hex(numberToBytesLE(u, 56)), x448.Gu);
|
||||
});
|
||||
|
||||
// ESM is broken.
|
||||
import url from 'url';
|
||||
if (import.meta.url === url.pathToFileURL(process.argv[1]).href) {
|
||||
should.run();
|
||||
}
|
||||
@@ -1,74 +0,0 @@
|
||||
import { jubjub, findGroupHash } from '../lib/jubjub.js';
|
||||
import { should } from 'micro-should';
|
||||
import { deepStrictEqual, throws } from 'assert';
|
||||
import { hexToBytes, bytesToHex } from '@noble/hashes/utils';
|
||||
|
||||
const G_SPEND = new jubjub.ExtendedPoint(
|
||||
0x055f1f24f0f0512287e51c3c5a0a6903fc0baf8711de9eafd7c0e66f69d8d2dbn,
|
||||
0x566178b2505fdd52132a5007d80a04652842e78ffb376897588f406278214ed7n,
|
||||
0x0141fafa1f11088a3b2007c14d652375888f3b37838ba6bdffae096741ceddfen,
|
||||
0x12eada93c0b7d595f5f04f5ebfb4b7d033ef2884136475cab5e41ce17db5be9cn
|
||||
);
|
||||
const G_PROOF = new jubjub.ExtendedPoint(
|
||||
0x0174d54ce9fad258a2f8a86a1deabf15c7a2b51106b0fbcd9d29020f78936f71n,
|
||||
0x16871d6d877dcd222e4ec3bccb3f37cb1865a2d37dd3a5dcbc032a69b62b4445n,
|
||||
0x57a3cd31e496d82bd4aa78bd5ecd751cfb76d54a5d3f4560866379f9fc11c9b3n,
|
||||
0x42cc53f6b519d1f4f52c47ff1256463a616c2c2f49ffe77765481eca04c72081n
|
||||
);
|
||||
|
||||
const getXY = (p) => ({ x: p.x, y: p.y });
|
||||
|
||||
should('toHex/fromHex', () => {
|
||||
// More than field
|
||||
throws(() =>
|
||||
jubjub.Point.fromHex(
|
||||
new Uint8Array([
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
])
|
||||
)
|
||||
);
|
||||
// Multiplicative generator (sqrt == null), not on curve.
|
||||
throws(() =>
|
||||
jubjub.Point.fromHex(
|
||||
new Uint8Array([
|
||||
7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0,
|
||||
])
|
||||
)
|
||||
);
|
||||
const tmp = jubjub.Point.fromHex(
|
||||
new Uint8Array([
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0,
|
||||
])
|
||||
);
|
||||
deepStrictEqual(tmp.x, 0x8d51ccce760304d0ec030002760300000001000000000000n);
|
||||
deepStrictEqual(tmp.y, 0n);
|
||||
|
||||
const S = G_SPEND.toAffine().toRawBytes();
|
||||
const S2 = G_SPEND.double().toAffine().toRawBytes();
|
||||
const P = G_PROOF.toAffine().toRawBytes();
|
||||
const P2 = G_PROOF.double().toAffine().toRawBytes();
|
||||
const S_exp = jubjub.Point.fromHex(S);
|
||||
const S2_exp = jubjub.Point.fromHex(S2);
|
||||
const P_exp = jubjub.Point.fromHex(P);
|
||||
const P2_exp = jubjub.Point.fromHex(P2);
|
||||
deepStrictEqual(getXY(G_SPEND.toAffine()), getXY(S_exp));
|
||||
deepStrictEqual(getXY(G_SPEND.double().toAffine()), getXY(S2_exp));
|
||||
deepStrictEqual(getXY(G_PROOF.toAffine()), getXY(P_exp));
|
||||
deepStrictEqual(getXY(G_PROOF.double().toAffine()), getXY(P2_exp));
|
||||
});
|
||||
|
||||
should('Find generators', () => {
|
||||
const spend = findGroupHash(new Uint8Array(), new Uint8Array([90, 99, 97, 115, 104, 95, 71, 95]));
|
||||
const proof = findGroupHash(new Uint8Array(), new Uint8Array([90, 99, 97, 115, 104, 95, 72, 95]));
|
||||
deepStrictEqual(getXY(spend.toAffine()), getXY(G_SPEND.toAffine()));
|
||||
deepStrictEqual(getXY(proof.toAffine()), getXY(G_PROOF.toAffine()));
|
||||
});
|
||||
|
||||
// ESM is broken.
|
||||
import url from 'url';
|
||||
if (import.meta.url === url.pathToFileURL(process.argv[1]).href) {
|
||||
should.run();
|
||||
}
|
||||
@@ -1,534 +0,0 @@
|
||||
import * as fc from 'fast-check';
|
||||
import { secp256k1, schnorr } from '../lib/secp256k1.js';
|
||||
import { readFileSync } from 'fs';
|
||||
import { default as ecdsa } from './vectors/ecdsa.json' assert { type: 'json' };
|
||||
import { default as ecdh } from './vectors/ecdh.json' assert { type: 'json' };
|
||||
import { default as privates } from './vectors/privates.json' assert { type: 'json' };
|
||||
import { default as points } from './vectors/points.json' assert { type: 'json' };
|
||||
import { default as wp } from './vectors/wychenproof.json' assert { type: 'json' };
|
||||
import { should } from 'micro-should';
|
||||
import { deepStrictEqual, throws } from 'assert';
|
||||
import { hexToBytes, bytesToHex } from '@noble/hashes/utils';
|
||||
|
||||
const hex = bytesToHex;
|
||||
const secp = secp256k1;
|
||||
const privatesTxt = readFileSync('./test/vectors/privates-2.txt', 'utf-8');
|
||||
const schCsv = readFileSync('./test/vectors/schnorr.csv', 'utf-8');
|
||||
|
||||
const FC_BIGINT = fc.bigInt(1n + 1n, secp.CURVE.n - 1n);
|
||||
// prettier-ignore
|
||||
const INVALID_ITEMS = ['deadbeef', Math.pow(2, 53), [1], 'xyzxyzxyxyzxyzxyxyzxyzxyxyzxyzxyxyzxyzxyxyzxyzxyxyzxyzxyxyzxyzxy', secp.CURVE.n + 2n];
|
||||
|
||||
const toBEHex = (n) => n.toString(16).padStart(64, '0');
|
||||
|
||||
function hexToNumber(hex) {
|
||||
if (typeof hex !== 'string') {
|
||||
throw new TypeError('hexToNumber: expected string, got ' + typeof hex);
|
||||
}
|
||||
// Big Endian
|
||||
return BigInt(`0x${hex}`);
|
||||
}
|
||||
|
||||
should('secp256k1.getPublicKey()', () => {
|
||||
const data = privatesTxt
|
||||
.split('\n')
|
||||
.filter((line) => line)
|
||||
.map((line) => line.split(':'));
|
||||
for (let [priv, x, y] of data) {
|
||||
const point = secp.Point.fromPrivateKey(BigInt(priv));
|
||||
deepStrictEqual(toBEHex(point.x), x);
|
||||
deepStrictEqual(toBEHex(point.y), y);
|
||||
|
||||
const point2 = secp.Point.fromHex(secp.getPublicKey(toBEHex(BigInt(priv))));
|
||||
deepStrictEqual(toBEHex(point2.x), x);
|
||||
deepStrictEqual(toBEHex(point2.y), y);
|
||||
|
||||
const point3 = secp.Point.fromHex(secp.getPublicKey(hexToBytes(toBEHex(BigInt(priv)))));
|
||||
deepStrictEqual(toBEHex(point3.x), x);
|
||||
deepStrictEqual(toBEHex(point3.y), y);
|
||||
}
|
||||
});
|
||||
should('secp256k1.getPublicKey() rejects invalid keys', () => {
|
||||
// for (const item of INVALID_ITEMS) {
|
||||
// throws(() => secp.getPublicKey(item));
|
||||
// }
|
||||
});
|
||||
should('secp256k1.precompute', () => {
|
||||
secp.utils.precompute(4);
|
||||
const data = privatesTxt
|
||||
.split('\n')
|
||||
.filter((line) => line)
|
||||
.map((line) => line.split(':'));
|
||||
for (let [priv, x, y] of data) {
|
||||
const point = secp.Point.fromPrivateKey(BigInt(priv));
|
||||
deepStrictEqual(toBEHex(point.x), x);
|
||||
deepStrictEqual(toBEHex(point.y), y);
|
||||
|
||||
const point2 = secp.Point.fromHex(secp.getPublicKey(toBEHex(BigInt(priv))));
|
||||
deepStrictEqual(toBEHex(point2.x), x);
|
||||
deepStrictEqual(toBEHex(point2.y), y);
|
||||
|
||||
const point3 = secp.Point.fromHex(secp.getPublicKey(hexToBytes(toBEHex(BigInt(priv)))));
|
||||
deepStrictEqual(toBEHex(point3.x), x);
|
||||
deepStrictEqual(toBEHex(point3.y), y);
|
||||
}
|
||||
});
|
||||
|
||||
should('secp256k1.Point.isValidPoint()', () => {
|
||||
for (const vector of points.valid.isPoint) {
|
||||
const { P, expected } = vector;
|
||||
if (expected) {
|
||||
secp.Point.fromHex(P);
|
||||
} else {
|
||||
throws(() => secp.Point.fromHex(P));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
should('secp256k1.Point.fromPrivateKey()', () => {
|
||||
for (const vector of points.valid.pointFromScalar) {
|
||||
const { d, expected } = vector;
|
||||
let p = secp.Point.fromPrivateKey(d);
|
||||
deepStrictEqual(p.toHex(true), expected);
|
||||
}
|
||||
});
|
||||
|
||||
should('secp256k1.Point#toHex(compressed)', () => {
|
||||
for (const vector of points.valid.pointCompress) {
|
||||
const { P, compress, expected } = vector;
|
||||
let p = secp.Point.fromHex(P);
|
||||
deepStrictEqual(p.toHex(compress), expected);
|
||||
}
|
||||
});
|
||||
|
||||
should('secp256k1.Point#toHex() roundtrip (failed case)', () => {
|
||||
const point1 =
|
||||
secp.Point.fromPrivateKey(
|
||||
88572218780422190464634044548753414301110513745532121983949500266768436236425n
|
||||
);
|
||||
// const hex = point1.toHex(true);
|
||||
// deepStrictEqual(secp.Point.fromHex(hex).toHex(true), hex);
|
||||
});
|
||||
|
||||
should('secp256k1.Point#toHex() roundtrip', () => {
|
||||
fc.assert(
|
||||
fc.property(FC_BIGINT, (x) => {
|
||||
const point1 = secp.Point.fromPrivateKey(x);
|
||||
const hex = point1.toHex(true);
|
||||
deepStrictEqual(secp.Point.fromHex(hex).toHex(true), hex);
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
should('secp256k1.Point#add(other)', () => {
|
||||
for (const vector of points.valid.pointAdd) {
|
||||
const { P, Q, expected } = vector;
|
||||
let p = secp.Point.fromHex(P);
|
||||
let q = secp.Point.fromHex(Q);
|
||||
if (expected) {
|
||||
deepStrictEqual(p.add(q).toHex(true), expected);
|
||||
} else {
|
||||
if (!p.equals(q.negate())) {
|
||||
throws(() => p.add(q).toHex(true));
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
should('secp256k1.Point#multiply(privateKey)', () => {
|
||||
for (const vector of points.valid.pointMultiply) {
|
||||
const { P, d, expected } = vector;
|
||||
const p = secp.Point.fromHex(P);
|
||||
if (expected) {
|
||||
deepStrictEqual(p.multiply(hexToNumber(d)).toHex(true), expected);
|
||||
} else {
|
||||
throws(() => {
|
||||
p.multiply(hexToNumber(d)).toHex(true);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
for (const vector of points.invalid.pointMultiply) {
|
||||
const { P, d } = vector;
|
||||
if (hexToNumber(d) < secp.CURVE.n) {
|
||||
throws(() => {
|
||||
const p = secp.Point.fromHex(P);
|
||||
p.multiply(hexToNumber(d)).toHex(true);
|
||||
});
|
||||
}
|
||||
}
|
||||
for (const num of [0n, 0, -1n, -1, 1.1]) {
|
||||
throws(() => secp.Point.BASE.multiply(num));
|
||||
}
|
||||
});
|
||||
|
||||
// multiply() should equal multiplyUnsafe()
|
||||
// should('JacobianPoint#multiplyUnsafe', () => {
|
||||
// const p0 = new secp.JacobianPoint(
|
||||
// 55066263022277343669578718895168534326250603453777594175500187360389116729240n,
|
||||
// 32670510020758816978083085130507043184471273380659243275938904335757337482424n,
|
||||
// 1n
|
||||
// );
|
||||
// const z = 106011723082030650010038151861333186846790370053628296836951575624442507889495n;
|
||||
// console.log(p0.multiply(z));
|
||||
// console.log(secp.JacobianPoint.normalizeZ([p0.multiplyUnsafe(z)])[0])
|
||||
// });
|
||||
|
||||
should('secp256k1.Signature.fromCompactHex() roundtrip', () => {
|
||||
fc.assert(
|
||||
fc.property(FC_BIGINT, FC_BIGINT, (r, s) => {
|
||||
const sig = new secp.Signature(r, s);
|
||||
deepStrictEqual(secp.Signature.fromCompact(sig.toCompactHex()), sig);
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
should('secp256k1.Signature.fromDERHex() roundtrip', () => {
|
||||
fc.assert(
|
||||
fc.property(FC_BIGINT, FC_BIGINT, (r, s) => {
|
||||
const sig = new secp.Signature(r, s);
|
||||
deepStrictEqual(secp.Signature.fromDER(sig.toDERHex()), sig);
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
should('secp256k1.sign()/should create deterministic signatures with RFC 6979', () => {
|
||||
for (const vector of ecdsa.valid) {
|
||||
let usig = secp.sign(vector.m, vector.d);
|
||||
let sig = usig.toCompactHex();
|
||||
const vsig = vector.signature;
|
||||
deepStrictEqual(sig.slice(0, 64), vsig.slice(0, 64));
|
||||
deepStrictEqual(sig.slice(64, 128), vsig.slice(64, 128));
|
||||
}
|
||||
});
|
||||
|
||||
should('secp256k1.sign()/should not create invalid deterministic signatures with RFC 6979', () => {
|
||||
for (const vector of ecdsa.invalid.sign) {
|
||||
throws(() => secp.sign(vector.m, vector.d));
|
||||
}
|
||||
});
|
||||
|
||||
should('secp256k1.sign()/edge cases', () => {
|
||||
throws(() => secp.sign());
|
||||
throws(() => secp.sign(''));
|
||||
});
|
||||
|
||||
should('secp256k1.sign()/should create correct DER encoding against libsecp256k1', () => {
|
||||
const CASES = [
|
||||
[
|
||||
'd1a9dc8ed4e46a6a3e5e594615ca351d7d7ef44df1e4c94c1802f3592183794b',
|
||||
'304402203de2559fccb00c148574997f660e4d6f40605acc71267ee38101abf15ff467af02200950abdf40628fd13f547792ba2fc544681a485f2fdafb5c3b909a4df7350e6b',
|
||||
],
|
||||
[
|
||||
'5f97983254982546d3976d905c6165033976ee449d300d0e382099fa74deaf82',
|
||||
'3045022100c046d9ff0bd2845b9aa9dff9f997ecebb31e52349f80fe5a5a869747d31dcb88022011f72be2a6d48fe716b825e4117747b397783df26914a58139c3f4c5cbb0e66c',
|
||||
],
|
||||
[
|
||||
'0d7017a96b97cd9be21cf28aada639827b2814a654a478c81945857196187808',
|
||||
'3045022100d18990bba7832bb283e3ecf8700b67beb39acc73f4200ed1c331247c46edccc602202e5c8bbfe47ae159512c583b30a3fa86575cddc62527a03de7756517ae4c6c73',
|
||||
],
|
||||
];
|
||||
const privKey = hexToBytes('0101010101010101010101010101010101010101010101010101010101010101');
|
||||
for (const [msg, exp] of CASES) {
|
||||
const res = secp.sign(msg, privKey, { extraEntropy: undefined });
|
||||
deepStrictEqual(res.toDERHex(), exp);
|
||||
const rs = secp.Signature.fromDER(res.toDERHex()).toCompactHex();
|
||||
deepStrictEqual(secp.Signature.fromCompact(rs).toDERHex(), exp);
|
||||
}
|
||||
});
|
||||
should('secp256k1.sign()/sign ecdsa extraData', () => {
|
||||
const ent1 = '0000000000000000000000000000000000000000000000000000000000000000';
|
||||
const ent2 = '0000000000000000000000000000000000000000000000000000000000000001';
|
||||
const ent3 = '6e723d3fd94ed5d2b6bdd4f123364b0f3ca52af829988a63f8afe91d29db1c33';
|
||||
const ent4 = 'fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141';
|
||||
const ent5 = 'ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff';
|
||||
|
||||
for (const e of ecdsa.extraEntropy) {
|
||||
const sign = (extraEntropy) => {
|
||||
const s = secp.sign(e.m, e.d, { extraEntropy }).toCompactHex();
|
||||
return s;
|
||||
};
|
||||
deepStrictEqual(sign(), e.signature);
|
||||
deepStrictEqual(sign(ent1), e.extraEntropy0);
|
||||
deepStrictEqual(sign(ent2), e.extraEntropy1);
|
||||
deepStrictEqual(sign(ent3), e.extraEntropyRand);
|
||||
deepStrictEqual(sign(ent4), e.extraEntropyN);
|
||||
deepStrictEqual(sign(ent5), e.extraEntropyMax);
|
||||
}
|
||||
});
|
||||
|
||||
should('secp256k1.verify()/should verify signature', () => {
|
||||
const MSG = '01'.repeat(32);
|
||||
const PRIV_KEY = 0x2n;
|
||||
const signature = secp.sign(MSG, PRIV_KEY);
|
||||
const publicKey = secp.getPublicKey(PRIV_KEY);
|
||||
deepStrictEqual(publicKey.length, 65);
|
||||
deepStrictEqual(secp.verify(signature, MSG, publicKey), true);
|
||||
});
|
||||
should('secp256k1.verify()/should not verify signature with wrong public key', () => {
|
||||
const MSG = '01'.repeat(32);
|
||||
const PRIV_KEY = 0x2n;
|
||||
const WRONG_PRIV_KEY = 0x22n;
|
||||
const signature = secp.sign(MSG, PRIV_KEY);
|
||||
const publicKey = secp.Point.fromPrivateKey(WRONG_PRIV_KEY).toHex();
|
||||
deepStrictEqual(publicKey.length, 130);
|
||||
deepStrictEqual(secp.verify(signature, MSG, publicKey), false);
|
||||
});
|
||||
should('secp256k1.verify()/should not verify signature with wrong hash', () => {
|
||||
const MSG = '01'.repeat(32);
|
||||
const PRIV_KEY = 0x2n;
|
||||
const WRONG_MSG = '11'.repeat(32);
|
||||
const signature = secp.sign(MSG, PRIV_KEY);
|
||||
const publicKey = secp.getPublicKey(PRIV_KEY);
|
||||
deepStrictEqual(publicKey.length, 65);
|
||||
deepStrictEqual(secp.verify(signature, WRONG_MSG, publicKey), false);
|
||||
});
|
||||
should('secp256k1.verify()/should verify random signatures', () =>
|
||||
fc.assert(
|
||||
fc.property(FC_BIGINT, fc.hexaString({ minLength: 64, maxLength: 64 }), (privKey, msg) => {
|
||||
const pub = secp.getPublicKey(privKey);
|
||||
const sig = secp.sign(msg, privKey);
|
||||
deepStrictEqual(secp.verify(sig, msg, pub), true);
|
||||
})
|
||||
)
|
||||
);
|
||||
should('secp256k1.verify()/should not verify signature with invalid r/s', () => {
|
||||
const msg = new Uint8Array([
|
||||
0xbb, 0x5a, 0x52, 0xf4, 0x2f, 0x9c, 0x92, 0x61, 0xed, 0x43, 0x61, 0xf5, 0x94, 0x22, 0xa1, 0xe3,
|
||||
0x00, 0x36, 0xe7, 0xc3, 0x2b, 0x27, 0x0c, 0x88, 0x07, 0xa4, 0x19, 0xfe, 0xca, 0x60, 0x50, 0x23,
|
||||
]);
|
||||
const x = 100260381870027870612475458630405506840396644859280795015145920502443964769584n;
|
||||
const y = 41096923727651821103518389640356553930186852801619204169823347832429067794568n;
|
||||
const r = 1n;
|
||||
const s = 115792089237316195423570985008687907852837564279074904382605163141518162728904n;
|
||||
|
||||
const pub = new secp.Point(x, y);
|
||||
const signature = new secp.Signature(2n, 2n);
|
||||
signature.r = r;
|
||||
signature.s = s;
|
||||
|
||||
const verified = secp.verify(signature, msg, pub);
|
||||
// Verifies, but it shouldn't, because signature S > curve order
|
||||
deepStrictEqual(verified, false);
|
||||
});
|
||||
should('secp256k1.verify()/should not verify msg = curve order', () => {
|
||||
const msg = 'fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141';
|
||||
const x = 55066263022277343669578718895168534326250603453777594175500187360389116729240n;
|
||||
const y = 32670510020758816978083085130507043184471273380659243275938904335757337482424n;
|
||||
const r = 104546003225722045112039007203142344920046999340768276760147352389092131869133n;
|
||||
const s = 96900796730960181123786672629079577025401317267213807243199432755332205217369n;
|
||||
const pub = new secp.Point(x, y);
|
||||
const sig = new secp.Signature(r, s);
|
||||
deepStrictEqual(secp.verify(sig, msg, pub), false);
|
||||
});
|
||||
should('secp256k1.verify()/should verify non-strict msg bb5a...', () => {
|
||||
const msg = 'bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023';
|
||||
const x = 3252872872578928810725465493269682203671229454553002637820453004368632726370n;
|
||||
const y = 17482644437196207387910659778872952193236850502325156318830589868678978890912n;
|
||||
const r = 432420386565659656852420866390673177323n;
|
||||
const s = 115792089237316195423570985008687907852837564279074904382605163141518161494334n;
|
||||
const pub = new secp.Point(x, y);
|
||||
const sig = new secp.Signature(r, s);
|
||||
deepStrictEqual(secp.verify(sig, msg, pub, { strict: false }), true);
|
||||
});
|
||||
should(
|
||||
'secp256k1.verify()/should not verify invalid deterministic signatures with RFC 6979',
|
||||
() => {
|
||||
for (const vector of ecdsa.invalid.verify) {
|
||||
const res = secp.verify(vector.signature, vector.m, vector.Q);
|
||||
deepStrictEqual(res, false);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// index,secret key,public key,aux_rand,message,signature,verification result,comment
|
||||
const vectors = schCsv
|
||||
.split('\n')
|
||||
.map((line) => line.split(','))
|
||||
.slice(1, -1);
|
||||
for (let vec of vectors) {
|
||||
const [index, sec, pub, rnd, msg, expSig, passes, comment] = vec;
|
||||
should(`sign with Schnorr scheme vector ${index}`, () => {
|
||||
if (sec) {
|
||||
deepStrictEqual(hex(schnorr.getPublicKey(sec)), pub.toLowerCase());
|
||||
const sig = schnorr.sign(msg, sec, rnd);
|
||||
deepStrictEqual(hex(sig), expSig.toLowerCase());
|
||||
deepStrictEqual(schnorr.verify(sig, msg, pub), true);
|
||||
} else {
|
||||
const passed = schnorr.verify(expSig, msg, pub);
|
||||
deepStrictEqual(passed, passes === 'TRUE');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
should('secp256k1.recoverPublicKey()/should recover public key from recovery bit', () => {
|
||||
const message = '00000000000000000000000000000000000000000000000000000000deadbeef';
|
||||
const privateKey = 123456789n;
|
||||
const publicKey = secp.Point.fromHex(secp.getPublicKey(privateKey)).toHex(false);
|
||||
const sig = secp.sign(message, privateKey);
|
||||
const recoveredPubkey = sig.recoverPublicKey(message);
|
||||
// const recoveredPubkey = secp.recoverPublicKey(message, signature, recovery);
|
||||
deepStrictEqual(recoveredPubkey !== null, true);
|
||||
deepStrictEqual(recoveredPubkey.toHex(), publicKey);
|
||||
deepStrictEqual(secp.verify(sig, message, publicKey), true);
|
||||
});
|
||||
should('secp256k1.recoverPublicKey()/should not recover zero points', () => {
|
||||
const msgHash = '6b8d2c81b11b2d699528dde488dbdf2f94293d0d33c32e347f255fa4a6c1f0a9';
|
||||
const sig =
|
||||
'79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f817986b8d2c81b11b2d699528dde488dbdf2f94293d0d33c32e347f255fa4a6c1f0a9';
|
||||
const recovery = 0;
|
||||
throws(() => secp.recoverPublicKey(msgHash, sig, recovery));
|
||||
});
|
||||
should('secp256k1.recoverPublicKey()/should handle all-zeros msghash', () => {
|
||||
const privKey = secp.utils.randomPrivateKey();
|
||||
const pub = secp.getPublicKey(privKey);
|
||||
const zeros = '0000000000000000000000000000000000000000000000000000000000000000';
|
||||
const sig = secp.sign(zeros, privKey, { recovered: true });
|
||||
const recoveredKey = sig.recoverPublicKey(zeros);
|
||||
deepStrictEqual(recoveredKey.toRawBytes(), pub);
|
||||
});
|
||||
should('secp256k1.recoverPublicKey()/should handle RFC 6979 vectors', () => {
|
||||
for (const vector of ecdsa.valid) {
|
||||
if (secp.utils.mod(hexToNumber(vector.m), secp.CURVE.n) === 0n) continue;
|
||||
let usig = secp.sign(vector.m, vector.d);
|
||||
let sig = usig.toDERHex();
|
||||
const vpub = secp.getPublicKey(vector.d);
|
||||
const recovered = usig.recoverPublicKey(vector.m);
|
||||
deepStrictEqual(recovered.toHex(), hex(vpub));
|
||||
}
|
||||
});
|
||||
|
||||
// TODO: Real implementation.
|
||||
function derToPub(der) {
|
||||
return der.slice(46);
|
||||
}
|
||||
should('secp256k1.getSharedSecret()/should produce correct results', () => {
|
||||
// TODO: Once der is there, run all tests.
|
||||
for (const vector of ecdh.testGroups[0].tests.slice(0, 230)) {
|
||||
if (vector.result === 'invalid' || vector.private.length !== 64) {
|
||||
// We support eth-like hexes
|
||||
if (vector.private.length < 64) continue;
|
||||
throws(() => {
|
||||
secp.getSharedSecret(vector.private, derToPub(vector.public), true);
|
||||
});
|
||||
} else if (vector.result === 'valid') {
|
||||
const res = secp.getSharedSecret(vector.private, derToPub(vector.public), true);
|
||||
deepStrictEqual(hex(res.slice(1)), `${vector.shared}`);
|
||||
}
|
||||
}
|
||||
});
|
||||
should('secp256k1.getSharedSecret()/priv/pub order matters', () => {
|
||||
for (const vector of ecdh.testGroups[0].tests.slice(0, 100)) {
|
||||
if (vector.result === 'valid') {
|
||||
let priv = vector.private;
|
||||
priv = priv.length === 66 ? priv.slice(2) : priv;
|
||||
throws(() => secp.getSharedSecret(derToPub(vector.public), priv, true));
|
||||
}
|
||||
}
|
||||
});
|
||||
should('secp256k1.getSharedSecret()/rejects invalid keys', () => {
|
||||
throws(() => secp.getSharedSecret('01', '02'));
|
||||
});
|
||||
|
||||
should('secp256k1.utils.isValidPrivateKey()', () => {
|
||||
for (const vector of privates.valid.isPrivate) {
|
||||
const { d, expected } = vector;
|
||||
deepStrictEqual(secp.utils.isValidPrivateKey(d), expected);
|
||||
}
|
||||
});
|
||||
const normal = secp.utils._normalizePrivateKey;
|
||||
const tweakUtils = {
|
||||
privateAdd: (privateKey, tweak) => {
|
||||
const p = normal(privateKey);
|
||||
const t = normal(tweak);
|
||||
return secp.utils._bigintToBytes(secp.utils.mod(p + t, secp.CURVE.n));
|
||||
},
|
||||
|
||||
privateNegate: (privateKey) => {
|
||||
const p = normal(privateKey);
|
||||
return secp.utils._bigintToBytes(secp.CURVE.n - p);
|
||||
},
|
||||
|
||||
pointAddScalar: (p, tweak, isCompressed) => {
|
||||
const P = secp.Point.fromHex(p);
|
||||
const t = normal(tweak);
|
||||
const Q = secp.Point.BASE.multiplyAndAddUnsafe(P, t, 1n);
|
||||
if (!Q) throw new Error('Tweaked point at infinity');
|
||||
return Q.toRawBytes(isCompressed);
|
||||
},
|
||||
|
||||
pointMultiply: (p, tweak, isCompressed) => {
|
||||
const P = secp.Point.fromHex(p);
|
||||
const h = typeof tweak === 'string' ? tweak : bytesToHex(tweak);
|
||||
const t = BigInt(`0x${h}`);
|
||||
return P.multiply(t).toRawBytes(isCompressed);
|
||||
},
|
||||
};
|
||||
|
||||
should('secp256k1.privateAdd()', () => {
|
||||
for (const vector of privates.valid.add) {
|
||||
const { a, b, expected } = vector;
|
||||
deepStrictEqual(bytesToHex(tweakUtils.privateAdd(a, b)), expected);
|
||||
}
|
||||
});
|
||||
should('secp256k1.privateNegate()', () => {
|
||||
for (const vector of privates.valid.negate) {
|
||||
const { a, expected } = vector;
|
||||
deepStrictEqual(bytesToHex(tweakUtils.privateNegate(a)), expected);
|
||||
}
|
||||
});
|
||||
should('secp256k1.pointAddScalar()', () => {
|
||||
for (const vector of points.valid.pointAddScalar) {
|
||||
const { description, P, d, expected } = vector;
|
||||
const compressed = !!expected && expected.length === 66; // compressed === 33 bytes
|
||||
deepStrictEqual(bytesToHex(tweakUtils.pointAddScalar(P, d, compressed)), expected);
|
||||
}
|
||||
});
|
||||
should('secp256k1.pointAddScalar() invalid', () => {
|
||||
for (const vector of points.invalid.pointAddScalar) {
|
||||
const { P, d, exception } = vector;
|
||||
throws(() => tweakUtils.pointAddScalar(P, d));
|
||||
}
|
||||
});
|
||||
should('secp256k1.pointMultiply()', () => {
|
||||
for (const vector of points.valid.pointMultiply) {
|
||||
const { P, d, expected } = vector;
|
||||
deepStrictEqual(bytesToHex(tweakUtils.pointMultiply(P, d, true)), expected);
|
||||
}
|
||||
});
|
||||
should('secp256k1.pointMultiply() invalid', () => {
|
||||
for (const vector of points.invalid.pointMultiply) {
|
||||
const { P, d, exception } = vector;
|
||||
throws(() => tweakUtils.pointMultiply(P, d));
|
||||
}
|
||||
});
|
||||
|
||||
should('secp256k1.wychenproof vectors', () => {
|
||||
for (let group of wp.testGroups) {
|
||||
const pubKey = secp.Point.fromHex(group.key.uncompressed);
|
||||
for (let test of group.tests) {
|
||||
const m = secp.CURVE.hash(hexToBytes(test.msg));
|
||||
if (test.result === 'valid' || test.result === 'acceptable') {
|
||||
const verified = secp.verify(test.sig, m, pubKey);
|
||||
if (secp.Signature.fromDER(test.sig).hasHighS()) {
|
||||
deepStrictEqual(verified, false);
|
||||
} else {
|
||||
deepStrictEqual(verified, true);
|
||||
}
|
||||
} else if (test.result === 'invalid') {
|
||||
let failed = false;
|
||||
try {
|
||||
const verified = secp.verify(test.sig, m, pubKey);
|
||||
if (!verified) failed = true;
|
||||
} catch (error) {
|
||||
failed = true;
|
||||
}
|
||||
deepStrictEqual(failed, true);
|
||||
} else {
|
||||
deepStrictEqual(false, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
should.run();
|
||||
@@ -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"
|
||||
]
|
||||
}
|
||||
175
package.json
175
package.json
@@ -1,19 +1,17 @@
|
||||
{
|
||||
"name": "@noble/curves",
|
||||
"version": "0.2.0",
|
||||
"description": "Minimal, zero-dependency JS implementation of elliptic curve cryptography",
|
||||
"version": "0.5.2",
|
||||
"description": "Minimal, auditable JS implementation of elliptic curve cryptography",
|
||||
"files": [
|
||||
"index.js",
|
||||
"lib",
|
||||
"lib/esm"
|
||||
"lib"
|
||||
],
|
||||
"scripts": {
|
||||
"bench": "node curve-definitions/benchmark/index.js",
|
||||
"bench": "node benchmark/index.js",
|
||||
"build": "tsc && tsc -p tsconfig.esm.json",
|
||||
"build:release": "rollup -c rollup.config.js",
|
||||
"lint": "prettier --check 'src/**/*.{js,ts}' 'curve-definitions/src/**/*.{js,ts}'",
|
||||
"format": "prettier --write 'src/**/*.{js,ts}' 'curve-definitions/src/**/*.{js,ts}'",
|
||||
"test": "cd curve-definitions; node test/index.test.js"
|
||||
"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,56 +20,163 @@
|
||||
"url": "https://github.com/paulmillr/noble-curves.git"
|
||||
},
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@noble/hashes": "1.1.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@rollup/plugin-node-resolve": "13.3.0",
|
||||
"@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.2.0",
|
||||
"micro-should": "0.2.0",
|
||||
"micro-should": "0.3.0",
|
||||
"prettier": "2.6.2",
|
||||
"rollup": "2.75.5",
|
||||
"typescript": "4.7.3"
|
||||
},
|
||||
"main": "index.js",
|
||||
"exports": {
|
||||
"./edwards": {
|
||||
"types": "./lib/edwards.d.ts",
|
||||
"import": "./lib/esm/edwards.js",
|
||||
"default": "./lib/edwards.js"
|
||||
".": {
|
||||
"types": "./lib/index.d.ts",
|
||||
"import": "./lib/esm/index.js",
|
||||
"default": "./lib/index.js"
|
||||
},
|
||||
"./modular": {
|
||||
"types": "./lib/modular.d.ts",
|
||||
"import": "./lib/esm/modular.js",
|
||||
"default": "./lib/modular.js"
|
||||
"./abstract/edwards": {
|
||||
"types": "./lib/abstract/edwards.d.ts",
|
||||
"import": "./lib/esm/abstract/edwards.js",
|
||||
"default": "./lib/abstract/edwards.js"
|
||||
},
|
||||
"./montgomery": {
|
||||
"types": "./lib/montgomery.d.ts",
|
||||
"import": "./lib/esm/montgomery.js",
|
||||
"default": "./lib/montgomery.js"
|
||||
"./abstract/modular": {
|
||||
"types": "./lib/abstract/modular.d.ts",
|
||||
"import": "./lib/esm/abstract/modular.js",
|
||||
"default": "./lib/abstract/modular.js"
|
||||
},
|
||||
"./weierstrass": {
|
||||
"types": "./lib/weierstrass.d.ts",
|
||||
"import": "./lib/esm/weierstrass.js",
|
||||
"default": "./lib/weierstrass.js"
|
||||
"./abstract/montgomery": {
|
||||
"types": "./lib/abstract/montgomery.d.ts",
|
||||
"import": "./lib/esm/abstract/montgomery.js",
|
||||
"default": "./lib/abstract/montgomery.js"
|
||||
},
|
||||
"./utils": {
|
||||
"types": "./lib/utils.d.ts",
|
||||
"import": "./lib/esm/utils.js",
|
||||
"default": "./lib/utils.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/group": {
|
||||
"types": "./lib/abstract/group.d.ts",
|
||||
"import": "./lib/esm/abstract/group.js",
|
||||
"default": "./lib/abstract/group.js"
|
||||
},
|
||||
"./abstract/utils": {
|
||||
"types": "./lib/abstract/utils.d.ts",
|
||||
"import": "./lib/esm/abstract/utils.js",
|
||||
"default": "./lib/abstract/utils.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",
|
||||
"edwards",
|
||||
"montgomery",
|
||||
"secp256k1",
|
||||
"ed25519",
|
||||
"ed448",
|
||||
"edwards",
|
||||
"p256",
|
||||
"p384",
|
||||
"p521",
|
||||
"secp256r1",
|
||||
"secp256k1",
|
||||
"ed25519",
|
||||
"ed448",
|
||||
"bls12-381",
|
||||
"bn254",
|
||||
"pasta",
|
||||
"bls",
|
||||
"nist",
|
||||
"ecc",
|
||||
"ecdsa",
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
/*! 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, CHash } from '@noble/curves/weierstrass';
|
||||
import { weierstrass, CurveType } from './abstract/weierstrass.js';
|
||||
import { CHash } from './abstract/utils.js';
|
||||
|
||||
export function getHash(hash: CHash) {
|
||||
return {
|
||||
377
src/abstract/bls.ts
Normal file
377
src/abstract/bls.ts
Normal file
@@ -0,0 +1,377 @@
|
||||
/*! 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 * as mod from './modular.js';
|
||||
import * as ut from './utils.js';
|
||||
// Types require separate import
|
||||
import { Hex, PrivKey } from './utils.js';
|
||||
import {
|
||||
htfOpts,
|
||||
stringToBytes,
|
||||
hash_to_field as hashToField,
|
||||
expand_message_xmd as expandMessageXMD,
|
||||
} from './hash-to-curve.js';
|
||||
import { CurvePointsType, PointType, CurvePointsRes, weierstrassPoints } from './weierstrass.js';
|
||||
|
||||
type Fp = bigint; // Can be different field?
|
||||
|
||||
export type SignatureCoder<Fp2> = {
|
||||
decode(hex: Hex): PointType<Fp2>;
|
||||
encode(point: PointType<Fp2>): Uint8Array;
|
||||
};
|
||||
|
||||
export type CurveType<Fp, Fp2, Fp6, Fp12> = {
|
||||
r: bigint;
|
||||
G1: Omit<CurvePointsType<Fp>, 'n'>;
|
||||
G2: Omit<CurvePointsType<Fp2>, 'n'> & {
|
||||
Signature: SignatureCoder<Fp2>;
|
||||
};
|
||||
x: bigint;
|
||||
Fp: mod.Field<Fp>;
|
||||
Fr: mod.Field<bigint>;
|
||||
Fp2: mod.Field<Fp2> & {
|
||||
reim: (num: Fp2) => { re: bigint; im: bigint };
|
||||
multiplyByB: (num: Fp2) => Fp2;
|
||||
frobeniusMap(num: Fp2, power: number): Fp2;
|
||||
};
|
||||
Fp6: mod.Field<Fp6>;
|
||||
Fp12: mod.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: htfOpts;
|
||||
hash: ut.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: mod.Field<bigint>;
|
||||
Fp: mod.Field<Fp>;
|
||||
Fp2: mod.Field<Fp2>;
|
||||
Fp6: mod.Field<Fp6>;
|
||||
Fp12: mod.Field<Fp12>;
|
||||
G1: CurvePointsRes<Fp>;
|
||||
G2: CurvePointsRes<Fp2>;
|
||||
Signature: SignatureCoder<Fp2>;
|
||||
millerLoop: (ell: [Fp2, Fp2, Fp2][], g1: [Fp, Fp]) => Fp12;
|
||||
calcPairingPrecomputes: (x: Fp2, y: Fp2) => [Fp2, Fp2, Fp2][];
|
||||
pairing: (P: PointType<Fp>, Q: PointType<Fp2>, withFinalExponent?: boolean) => Fp12;
|
||||
getPublicKey: (privateKey: PrivKey) => Uint8Array;
|
||||
sign: {
|
||||
(message: Hex, privateKey: PrivKey): Uint8Array;
|
||||
(message: PointType<Fp2>, privateKey: PrivKey): PointType<Fp2>;
|
||||
};
|
||||
verify: (
|
||||
signature: Hex | PointType<Fp2>,
|
||||
message: Hex | PointType<Fp2>,
|
||||
publicKey: Hex | PointType<Fp>
|
||||
) => boolean;
|
||||
aggregatePublicKeys: {
|
||||
(publicKeys: Hex[]): Uint8Array;
|
||||
(publicKeys: PointType<Fp>[]): PointType<Fp>;
|
||||
};
|
||||
aggregateSignatures: {
|
||||
(signatures: Hex[]): Uint8Array;
|
||||
(signatures: PointType<Fp2>[]): PointType<Fp2>;
|
||||
};
|
||||
verifyBatch: (
|
||||
signature: Hex | PointType<Fp2>,
|
||||
messages: (Hex | PointType<Fp2>)[],
|
||||
publicKeys: (Hex | PointType<Fp>)[]
|
||||
) => boolean;
|
||||
utils: {
|
||||
stringToBytes: typeof stringToBytes;
|
||||
hashToField: typeof hashToField;
|
||||
expandMessageXMD: typeof expandMessageXMD;
|
||||
getDSTLabel: () => string;
|
||||
setDSTLabel(newLabel: string): void;
|
||||
};
|
||||
};
|
||||
|
||||
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 = ut.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(x: Fp2, y: Fp2) {
|
||||
// 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.square(Ry); // Ry²
|
||||
let t1 = Fp2.square(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.square(Fp2.add(Ry, Rz)), t1), t0); // (Ry + Rz)² - T1 - T0
|
||||
ell_coeff.push([
|
||||
Fp2.sub(t2, t0), // T2 - T0
|
||||
Fp2.mul(Fp2.square(Rx), 3n), // 3 * Rx²
|
||||
Fp2.negate(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.square(Fp2.div(Fp2.add(t0, t3), 2n)), Fp2.mul(Fp2.square(t2), 3n)); // ((T0 + T3) / 2)² - 3 * T2²
|
||||
Rz = Fp2.mul(t0, t4); // T0 * T4
|
||||
if (ut.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.negate(t0), // -T0
|
||||
t1, // T1
|
||||
]);
|
||||
let t2 = Fp2.square(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.square(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 (ut.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.square(f12);
|
||||
}
|
||||
return Fp12.conjugate(f12);
|
||||
}
|
||||
|
||||
const utils = {
|
||||
hexToBytes: ut.hexToBytes,
|
||||
bytesToHex: ut.bytesToHex,
|
||||
stringToBytes: stringToBytes,
|
||||
// TODO: do we need to export it here?
|
||||
hashToField: (
|
||||
msg: Uint8Array,
|
||||
count: number,
|
||||
options: Partial<typeof CURVE.htfDefaults> = {}
|
||||
) => hashToField(msg, count, { ...CURVE.htfDefaults, ...options }),
|
||||
expandMessageXMD: (msg: Uint8Array, DST: Uint8Array, lenInBytes: number, H = CURVE.hash) =>
|
||||
expandMessageXMD(msg, DST, lenInBytes, H),
|
||||
hashToPrivateKey: (hash: Hex): Uint8Array => Fr.toBytes(ut.hashToPrivateScalar(hash, CURVE.r)),
|
||||
randomBytes: (bytesLength: number = groupLen): Uint8Array => CURVE.randomBytes(bytesLength),
|
||||
randomPrivateKey: (): Uint8Array => utils.hashToPrivateKey(utils.randomBytes(groupLen + 8)),
|
||||
getDSTLabel: () => CURVE.htfDefaults.DST,
|
||||
setDSTLabel(newLabel: string) {
|
||||
// https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-11#section-3.1
|
||||
if (typeof newLabel !== 'string' || newLabel.length > 2048 || newLabel.length === 0) {
|
||||
throw new TypeError('Invalid DST');
|
||||
}
|
||||
CURVE.htfDefaults.DST = newLabel;
|
||||
},
|
||||
};
|
||||
|
||||
// Point on G1 curve: (x, y)
|
||||
const G1 = weierstrassPoints({
|
||||
n: Fr.ORDER,
|
||||
...CURVE.G1,
|
||||
});
|
||||
|
||||
// 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(p.x, p.y);
|
||||
return p._PPRECOMPUTES;
|
||||
}
|
||||
|
||||
function clearPairingPrecomputes(point: G2) {
|
||||
const p = point as G2 & withPairingPrecomputes;
|
||||
p._PPRECOMPUTES = undefined;
|
||||
}
|
||||
clearPairingPrecomputes;
|
||||
|
||||
function millerLoopG1(Q: G1, P: G2): Fp12 {
|
||||
return millerLoop(pairingPrecomputes(P), [Q.x, Q.y]);
|
||||
}
|
||||
|
||||
// Point on G2 curve (complex numbers): (x₁, x₂+i), (y₁, y₂+i)
|
||||
const G2 = weierstrassPoints({
|
||||
n: Fr.ORDER,
|
||||
...CURVE.G2,
|
||||
});
|
||||
const { Signature } = CURVE.G2;
|
||||
|
||||
// Calculates bilinear pairing
|
||||
function pairing(P: G1, Q: G2, withFinalExponent: boolean = true): Fp12 {
|
||||
if (P.equals(G1.Point.ZERO) || Q.equals(G2.Point.ZERO))
|
||||
throw new Error('No pairings at point of Infinity');
|
||||
P.assertValidity();
|
||||
Q.assertValidity();
|
||||
// Performance: 9ms for millerLoop and ~14ms for exp.
|
||||
const looped = millerLoopG1(P, Q);
|
||||
return withFinalExponent ? Fp12.finalExponentiate(looped) : looped;
|
||||
}
|
||||
type G1 = typeof G1.Point.BASE;
|
||||
type G2 = typeof G2.Point.BASE;
|
||||
|
||||
type G1Hex = Hex | G1;
|
||||
type G2Hex = Hex | G2;
|
||||
function normP1(point: G1Hex): G1 {
|
||||
return point instanceof G1.Point ? (point as G1) : G1.Point.fromHex(point);
|
||||
}
|
||||
function normP2(point: G2Hex): G2 {
|
||||
return point instanceof G2.Point ? point : Signature.decode(point);
|
||||
}
|
||||
function normP2Hash(point: G2Hex): G2 {
|
||||
return point instanceof G2.Point ? point : G2.Point.hashToCurve(point);
|
||||
}
|
||||
|
||||
// Multiplies generator by private key.
|
||||
// P = pk x G
|
||||
function getPublicKey(privateKey: PrivKey): Uint8Array {
|
||||
return G1.Point.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): Uint8Array;
|
||||
function sign(message: G2, privateKey: PrivKey): G2;
|
||||
function sign(message: G2Hex, privateKey: PrivKey): Uint8Array | G2 {
|
||||
const msgPoint = normP2Hash(message);
|
||||
msgPoint.assertValidity();
|
||||
const sigPoint = msgPoint.multiply(G1.normalizePrivateKey(privateKey));
|
||||
if (message instanceof G2.Point) 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): boolean {
|
||||
const P = normP1(publicKey);
|
||||
const Hm = normP2Hash(message);
|
||||
const G = G1.Point.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.equals(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(G1.ProjectivePoint.fromAffine(p)), G1.ProjectivePoint.ZERO);
|
||||
const aggAffine = agg.toAffine();
|
||||
if (publicKeys[0] instanceof G1.Point) {
|
||||
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(G2.ProjectivePoint.fromAffine(s)), G2.ProjectivePoint.ZERO);
|
||||
const aggAffine = agg.toAffine();
|
||||
if (signatures[0] instanceof G2.Point) {
|
||||
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[]): boolean {
|
||||
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(normP2Hash);
|
||||
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.Point.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.Point.BASE.negate(), sig, false));
|
||||
const product = paired.reduce((a, b) => Fp12.mul(a, b), Fp12.ONE);
|
||||
const exp = Fp12.finalExponentiate(product);
|
||||
return Fp12.equals(exp, Fp12.ONE);
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Pre-compute points. Refer to README.
|
||||
G1.Point.BASE._setWindowSize(4);
|
||||
return {
|
||||
CURVE,
|
||||
Fr,
|
||||
Fp,
|
||||
Fp2,
|
||||
Fp6,
|
||||
Fp12,
|
||||
G1,
|
||||
G2,
|
||||
Signature,
|
||||
millerLoop,
|
||||
calcPairingPrecomputes,
|
||||
pairing,
|
||||
getPublicKey,
|
||||
sign,
|
||||
verify,
|
||||
aggregatePublicKeys,
|
||||
aggregateSignatures,
|
||||
verifyBatch,
|
||||
utils,
|
||||
};
|
||||
}
|
||||
@@ -1,28 +1,19 @@
|
||||
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
||||
// Implementation of Twisted Edwards curve. The formula is: ax² + y² = 1 + dx²y²
|
||||
// Twisted Edwards curve. The formula is: ax² + y² = 1 + dx²y²
|
||||
|
||||
// Differences from @noble/ed25519 1.7:
|
||||
// 1. Different field element lengths in ed448:
|
||||
// 1. Variable field element lengths between EDDSA/ECDH:
|
||||
// EDDSA (RFC8032) is 456 bits / 57 bytes, ECDH (RFC7748) is 448 bits / 56 bytes
|
||||
// 2. Different addition formula (doubling is same)
|
||||
// 3. uvRatio differs between curves (half-expected, not only pow fn changes)
|
||||
// 4. Point decompression code is different too (unexpected), now using generalized formula
|
||||
// 4. Point decompression code is different (unexpected), now using generalized formula
|
||||
// 5. Domain function was no-op for ed25519, but adds some data even with empty context for ed448
|
||||
|
||||
import * as mod from './modular.js';
|
||||
import {
|
||||
bytesToHex,
|
||||
concatBytes,
|
||||
ensureBytes,
|
||||
numberToBytesLE,
|
||||
bytesToNumberLE,
|
||||
hashToPrivateScalar,
|
||||
BasicCurve,
|
||||
validateOpts as utilOpts,
|
||||
Hex,
|
||||
PrivKey,
|
||||
} from './utils.js'; // TODO: import * as u from './utils.js'?
|
||||
import * as ut from './utils.js';
|
||||
import { ensureBytes, Hex, PrivKey } from './utils.js';
|
||||
import { Group, GroupConstructor, wNAF } from './group.js';
|
||||
import { hash_to_field as hashToField, htfOpts, validateHTFOpts } from './hash-to-curve.js';
|
||||
|
||||
// Be friendly to bad ECMAScript parsers by not using bigint literals like 123n
|
||||
const _0n = BigInt(0);
|
||||
@@ -30,42 +21,45 @@ const _1n = BigInt(1);
|
||||
const _2n = BigInt(2);
|
||||
const _8n = BigInt(8);
|
||||
|
||||
export type CHash = {
|
||||
(message: Uint8Array | string): Uint8Array;
|
||||
blockLen: number;
|
||||
outputLen: number;
|
||||
create(): any;
|
||||
};
|
||||
|
||||
export type CurveType = BasicCurve & {
|
||||
// Edwards curves must declare params a & d.
|
||||
export type CurveType = ut.BasicCurve<bigint> & {
|
||||
// Params: a, d
|
||||
a: bigint;
|
||||
d: bigint;
|
||||
// Hashes
|
||||
hash: CHash; // Because we need outputLen for DRBG
|
||||
// The interface, because we need outputLen for DRBG
|
||||
hash: ut.CHash;
|
||||
// CSPRNG
|
||||
randomBytes: (bytesLength?: number) => Uint8Array;
|
||||
// Probably clears bits in a byte array to produce a valid field element
|
||||
adjustScalarBytes?: (bytes: Uint8Array) => Uint8Array;
|
||||
// Used during hashing
|
||||
domain?: (data: Uint8Array, ctx: Uint8Array, phflag: boolean) => Uint8Array;
|
||||
// Ratio √(u/v)
|
||||
uvRatio?: (u: bigint, v: bigint) => { isValid: boolean; value: bigint };
|
||||
preHash?: CHash;
|
||||
// RFC 8032 pre-hashing of messages to sign() / verify()
|
||||
preHash?: ut.CHash;
|
||||
// Hash to field options
|
||||
htfDefaults?: htfOpts;
|
||||
mapToCurve?: (scalar: bigint[]) => { x: bigint; y: bigint };
|
||||
};
|
||||
|
||||
// Should be separate from overrides, since overrides can use information about curve (for example nBits)
|
||||
function validateOpts(curve: CurveType) {
|
||||
const opts = utilOpts(curve);
|
||||
if (typeof opts.hash !== 'function' || !Number.isSafeInteger(opts.hash.outputLen))
|
||||
const opts = ut.validateOpts(curve);
|
||||
if (typeof opts.hash !== 'function' || !ut.isPositiveInt(opts.hash.outputLen))
|
||||
throw new Error('Invalid hash function');
|
||||
for (const i of ['a', 'd'] as const) {
|
||||
if (typeof opts[i] !== 'bigint')
|
||||
throw new Error(`Invalid curve param ${i}=${opts[i]} (${typeof opts[i]})`);
|
||||
const val = opts[i];
|
||||
if (typeof val !== 'bigint') throw new Error(`Invalid curve param ${i}=${val} (${typeof val})`);
|
||||
}
|
||||
for (const fn of ['randomBytes'] as const) {
|
||||
if (typeof opts[fn] !== 'function') throw new Error(`Invalid ${fn} function`);
|
||||
}
|
||||
for (const fn of ['adjustScalarBytes', 'domain', 'uvRatio'] as const) {
|
||||
for (const fn of ['adjustScalarBytes', 'domain', 'uvRatio', 'mapToCurve'] as const) {
|
||||
if (opts[fn] === undefined) continue; // Optional
|
||||
if (typeof opts[fn] !== 'function') throw new Error(`Invalid ${fn} function`);
|
||||
}
|
||||
if (opts.htfDefaults !== undefined) validateHTFOpts(opts.htfDefaults);
|
||||
// Set defaults
|
||||
return Object.freeze({ ...opts } as const);
|
||||
}
|
||||
@@ -84,7 +78,7 @@ export type SignatureConstructor = {
|
||||
fromHex(hex: Hex): SignatureType;
|
||||
};
|
||||
|
||||
// Instance
|
||||
// Instance of Extended Point with coordinates in X, Y, Z, T
|
||||
export interface ExtendedPointType extends Group<ExtendedPointType> {
|
||||
readonly x: bigint;
|
||||
readonly y: bigint;
|
||||
@@ -95,8 +89,9 @@ export interface ExtendedPointType extends Group<ExtendedPointType> {
|
||||
isSmallOrder(): boolean;
|
||||
isTorsionFree(): boolean;
|
||||
toAffine(invZ?: bigint): PointType;
|
||||
clearCofactor(): ExtendedPointType;
|
||||
}
|
||||
// Static methods
|
||||
// Static methods of Extended Point with coordinates in X, Y, Z, T
|
||||
export interface ExtendedPointConstructor extends GroupConstructor<ExtendedPointType> {
|
||||
new (x: bigint, y: bigint, z: bigint, t: bigint): ExtendedPointType;
|
||||
fromAffine(p: PointType): ExtendedPointType;
|
||||
@@ -104,7 +99,7 @@ export interface ExtendedPointConstructor extends GroupConstructor<ExtendedPoint
|
||||
normalizeZ(points: ExtendedPointType[]): ExtendedPointType[];
|
||||
}
|
||||
|
||||
// Instance
|
||||
// Instance of Affine Point with coordinates in X, Y
|
||||
export interface PointType extends Group<PointType> {
|
||||
readonly x: bigint;
|
||||
readonly y: bigint;
|
||||
@@ -112,12 +107,15 @@ export interface PointType extends Group<PointType> {
|
||||
toRawBytes(isCompressed?: boolean): Uint8Array;
|
||||
toHex(isCompressed?: boolean): string;
|
||||
isTorsionFree(): boolean;
|
||||
clearCofactor(): PointType;
|
||||
}
|
||||
// Static methods
|
||||
// Static methods of Affine Point with coordinates in X, Y
|
||||
export interface PointConstructor extends GroupConstructor<PointType> {
|
||||
new (x: bigint, y: bigint): PointType;
|
||||
fromHex(hex: Hex): PointType;
|
||||
fromPrivateKey(privateKey: PrivKey): PointType;
|
||||
hashToCurve(msg: Hex, options?: Partial<htfOpts>): PointType;
|
||||
encodeToCurve(msg: Hex, options?: Partial<htfOpts>): PointType;
|
||||
}
|
||||
|
||||
export type PubKey = Hex | PointType;
|
||||
@@ -132,8 +130,6 @@ export type CurveFn = {
|
||||
ExtendedPoint: ExtendedPointConstructor;
|
||||
Signature: SignatureConstructor;
|
||||
utils: {
|
||||
mod: (a: bigint, b?: bigint) => bigint;
|
||||
invert: (number: bigint, modulo?: bigint) => bigint;
|
||||
randomPrivateKey: () => Uint8Array;
|
||||
getExtendedPublicKey: (key: PrivKey) => {
|
||||
head: Uint8Array;
|
||||
@@ -148,35 +144,31 @@ export type CurveFn = {
|
||||
// NOTE: 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 = CURVE.Fp;
|
||||
const CURVE_ORDER = CURVE.n;
|
||||
const fieldLen = CURVE.nByteLength; // 32 (length of one field element)
|
||||
if (fieldLen > 2048) throw new Error('Field lengths over 2048 are not supported');
|
||||
const groupLen = CURVE.nByteLength;
|
||||
// (2n ** 256n).toString(16);
|
||||
const maxGroupElement = _2n ** BigInt(groupLen * 8); // previous POW_2_256
|
||||
const maxGroupElement = _2n ** BigInt(CURVE.nByteLength * 8);
|
||||
|
||||
// Function overrides
|
||||
const { P, randomBytes } = CURVE;
|
||||
const modP = (a: bigint) => mod.mod(a, P);
|
||||
const { randomBytes } = CURVE;
|
||||
const modP = Fp.create;
|
||||
|
||||
// sqrt(u/v)
|
||||
function _uvRatio(u: bigint, v: bigint) {
|
||||
const uvRatio =
|
||||
CURVE.uvRatio ||
|
||||
((u: bigint, v: bigint) => {
|
||||
try {
|
||||
const value = mod.sqrt(u * mod.invert(v, P), P);
|
||||
return { isValid: true, value };
|
||||
return { isValid: true, value: Fp.sqrt(u * Fp.invert(v)) };
|
||||
} catch (e) {
|
||||
return { isValid: false, value: _0n };
|
||||
}
|
||||
}
|
||||
const uvRatio = CURVE.uvRatio || _uvRatio;
|
||||
|
||||
const _adjustScalarBytes = (bytes: Uint8Array) => bytes; // NOOP
|
||||
const adjustScalarBytes = CURVE.adjustScalarBytes || _adjustScalarBytes;
|
||||
function _domain(data: Uint8Array, ctx: Uint8Array, phflag: boolean) {
|
||||
});
|
||||
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;
|
||||
}
|
||||
const domain = CURVE.domain || _domain; // NOOP
|
||||
}); // NOOP
|
||||
|
||||
/**
|
||||
* Extended Point works in extended coordinates: (x, y, z, t) ∋ (x=x/z, y=y/z, t=xy).
|
||||
@@ -199,10 +191,7 @@ export function twistedEdwards(curveDef: CurveType): CurveFn {
|
||||
// invert on all of them. invert is very slow operation,
|
||||
// so this improves performance massively.
|
||||
static toAffineBatch(points: ExtendedPoint[]): Point[] {
|
||||
const toInv = mod.invertBatch(
|
||||
points.map((p) => p.z),
|
||||
P
|
||||
);
|
||||
const toInv = Fp.invertBatch(points.map((p) => p.z));
|
||||
return points.map((p, i) => p.toAffine(toInv[i]));
|
||||
}
|
||||
|
||||
@@ -265,7 +254,7 @@ export function twistedEdwards(curveDef: CurveType): CurveFn {
|
||||
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.
|
||||
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;
|
||||
@@ -282,7 +271,6 @@ export function twistedEdwards(curveDef: CurveType): CurveFn {
|
||||
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
|
||||
// TODO: do we need to check for same point here? Looks like working without it
|
||||
const F = D - C; // F = D-C
|
||||
const G = D + C; // G = D+C
|
||||
const H = modP(B - a * A); // H = B-a*A
|
||||
@@ -323,25 +311,27 @@ export function twistedEdwards(curveDef: CurveType): CurveFn {
|
||||
// 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.
|
||||
// Allows scalar bigger than curve order, but less than 2^256
|
||||
multiplyUnsafe(scalar: number | bigint): ExtendedPoint {
|
||||
let n = normalizeScalar(scalar, CURVE_ORDER, false);
|
||||
const G = ExtendedPoint.BASE;
|
||||
const P0 = ExtendedPoint.ZERO;
|
||||
if (n === _0n) return P0;
|
||||
if (this.equals(P0) || n === _1n) return this;
|
||||
if (this.equals(G)) return this.wNAF(n);
|
||||
if (this.equals(ExtendedPoint.BASE)) return this.wNAF(n);
|
||||
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(CURVE.h).equals(ExtendedPoint.ZERO);
|
||||
}
|
||||
|
||||
// Multiplies point by a very big scalar n and checks if the result is 0.
|
||||
// Multiplies point by curve order (very big scalar CURVE.n) and checks if the result is 0.
|
||||
// Returns `false` is the point is dirty.
|
||||
isTorsionFree(): boolean {
|
||||
return this.multiplyUnsafe(CURVE_ORDER).equals(ExtendedPoint.ZERO);
|
||||
return wnaf.unsafeLadder(this, CURVE_ORDER).equals(ExtendedPoint.ZERO);
|
||||
}
|
||||
|
||||
// Converts Extended point to default (x, y) coordinates.
|
||||
@@ -349,7 +339,7 @@ export function twistedEdwards(curveDef: CurveType): CurveFn {
|
||||
toAffine(invZ?: bigint): Point {
|
||||
const { x, y, z } = this;
|
||||
const is0 = this.equals(ExtendedPoint.ZERO);
|
||||
if (invZ == null) invZ = is0 ? _8n : mod.invert(z, P); // 8 was chosen arbitrarily
|
||||
if (invZ == null) invZ = is0 ? _8n : (Fp.invert(z) as bigint); // 8 was chosen arbitrarily
|
||||
const ax = modP(x * invZ);
|
||||
const ay = modP(y * invZ);
|
||||
const zz = modP(z * invZ);
|
||||
@@ -357,8 +347,13 @@ export function twistedEdwards(curveDef: CurveType): CurveFn {
|
||||
if (zz !== _1n) throw new Error('invZ was invalid');
|
||||
return new Point(ax, ay);
|
||||
}
|
||||
clearCofactor(): ExtendedPoint {
|
||||
const { h: cofactor } = CURVE;
|
||||
if (cofactor === _1n) return this;
|
||||
return this.multiplyUnsafe(cofactor);
|
||||
}
|
||||
const wnaf = wNAF(ExtendedPoint, groupLen * 8);
|
||||
}
|
||||
const wnaf = wNAF(ExtendedPoint, CURVE.nByteLength * 8);
|
||||
|
||||
function assertExtPoint(other: unknown) {
|
||||
if (!(other instanceof ExtendedPoint)) throw new TypeError('ExtendedPoint expected');
|
||||
@@ -392,20 +387,21 @@ export function twistedEdwards(curveDef: CurveType): CurveFn {
|
||||
// Converts hash string or Uint8Array to Point.
|
||||
// Uses algo from RFC8032 5.1.3.
|
||||
static fromHex(hex: Hex, strict = true) {
|
||||
const { d, P, a } = CURVE;
|
||||
hex = ensureBytes(hex, fieldLen);
|
||||
const { d, a } = CURVE;
|
||||
const len = Fp.BYTES;
|
||||
hex = ensureBytes(hex, len);
|
||||
// 1. First, interpret the string as an integer in little-endian
|
||||
// representation. Bit 255 of this number is the least significant
|
||||
// bit of the x-coordinate and denote this value x_0. The
|
||||
// y-coordinate is recovered simply by clearing this bit. If the
|
||||
// resulting value is >= p, decoding fails.
|
||||
const normed = hex.slice();
|
||||
const lastByte = hex[fieldLen - 1];
|
||||
normed[fieldLen - 1] = lastByte & ~0x80;
|
||||
const y = bytesToNumberLE(normed);
|
||||
const lastByte = hex[len - 1];
|
||||
normed[len - 1] = lastByte & ~0x80;
|
||||
const y = ut.bytesToNumberLE(normed);
|
||||
|
||||
if (strict && y >= P) throw new Error('Expected 0 < hex < P');
|
||||
if (!strict && y >= maxGroupElement) throw new Error('Expected 0 < hex < 2**256');
|
||||
if (strict && y >= Fp.ORDER) throw new Error('Expected 0 < hex < P');
|
||||
if (!strict && y >= maxGroupElement) throw new Error('Expected 0 < hex < CURVE.n');
|
||||
|
||||
// 2. To recover the x-coordinate, the curve equation implies
|
||||
// Ed25519: x² = (y² - 1) / (d y² + 1) (mod p).
|
||||
@@ -439,16 +435,18 @@ export function twistedEdwards(curveDef: CurveType): CurveFn {
|
||||
// When compressing point, it's enough to only store its y coordinate
|
||||
// and use the last byte to encode sign of x.
|
||||
toRawBytes(): Uint8Array {
|
||||
const bytes = numberToBytesLE(this.y, fieldLen);
|
||||
bytes[fieldLen - 1] |= this.x & _1n ? 0x80 : 0;
|
||||
const bytes = ut.numberToBytesLE(this.y, Fp.BYTES);
|
||||
bytes[Fp.BYTES - 1] |= this.x & _1n ? 0x80 : 0;
|
||||
return bytes;
|
||||
}
|
||||
|
||||
// Same as toRawBytes, but returns string.
|
||||
toHex(): string {
|
||||
return bytesToHex(this.toRawBytes());
|
||||
return ut.bytesToHex(this.toRawBytes());
|
||||
}
|
||||
|
||||
// Determines if point is in prime-order subgroup.
|
||||
// Returns `false` is the point is dirty.
|
||||
isTorsionFree(): boolean {
|
||||
return ExtendedPoint.fromAffine(this).isTorsionFree();
|
||||
}
|
||||
@@ -482,6 +480,29 @@ export function twistedEdwards(curveDef: CurveType): CurveFn {
|
||||
multiply(scalar: number | bigint): Point {
|
||||
return ExtendedPoint.fromAffine(this).multiply(scalar, this).toAffine();
|
||||
}
|
||||
|
||||
clearCofactor() {
|
||||
return ExtendedPoint.fromAffine(this).clearCofactor().toAffine();
|
||||
}
|
||||
// Encodes byte string to elliptic curve
|
||||
// https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-11#section-3
|
||||
static hashToCurve(msg: Hex, options?: Partial<htfOpts>) {
|
||||
const { mapToCurve, htfDefaults } = CURVE;
|
||||
if (!mapToCurve) throw new Error('No mapToCurve defined for curve');
|
||||
const u = hashToField(ensureBytes(msg), 2, { ...htfDefaults, ...options } as htfOpts);
|
||||
const { x: x0, y: y0 } = mapToCurve(u[0]);
|
||||
const { x: x1, y: y1 } = mapToCurve(u[1]);
|
||||
const p = new Point(x0, y0).add(new Point(x1, y1)).clearCofactor();
|
||||
return p;
|
||||
}
|
||||
// https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-16#section-3
|
||||
static encodeToCurve(msg: Hex, options?: Partial<htfOpts>) {
|
||||
const { mapToCurve, htfDefaults } = CURVE;
|
||||
if (!mapToCurve) throw new Error('No mapToCurve defined for curve');
|
||||
const u = hashToField(ensureBytes(msg), 1, { ...htfDefaults, ...options } as htfOpts);
|
||||
const { x, y } = mapToCurve(u[0]);
|
||||
return new Point(x, y).clearCofactor();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -493,9 +514,10 @@ export function twistedEdwards(curveDef: CurveType): CurveFn {
|
||||
}
|
||||
|
||||
static fromHex(hex: Hex) {
|
||||
const bytes = ensureBytes(hex, 2 * fieldLen);
|
||||
const r = Point.fromHex(bytes.slice(0, fieldLen), false);
|
||||
const s = bytesToNumberLE(bytes.slice(fieldLen, 2 * fieldLen));
|
||||
const len = Fp.BYTES;
|
||||
const bytes = ensureBytes(hex, 2 * len);
|
||||
const r = Point.fromHex(bytes.slice(0, len), false);
|
||||
const s = ut.bytesToNumberLE(bytes.slice(len, 2 * len));
|
||||
return new Signature(r, s);
|
||||
}
|
||||
|
||||
@@ -508,17 +530,17 @@ export function twistedEdwards(curveDef: CurveType): CurveFn {
|
||||
}
|
||||
|
||||
toRawBytes() {
|
||||
return concatBytes(this.r.toRawBytes(), numberToBytesLE(this.s, fieldLen));
|
||||
return ut.concatBytes(this.r.toRawBytes(), ut.numberToBytesLE(this.s, Fp.BYTES));
|
||||
}
|
||||
|
||||
toHex() {
|
||||
return bytesToHex(this.toRawBytes());
|
||||
return ut.bytesToHex(this.toRawBytes());
|
||||
}
|
||||
}
|
||||
|
||||
// Little-endian SHA512 with modulo n
|
||||
function modlLE(hash: Uint8Array): bigint {
|
||||
return mod.mod(bytesToNumberLE(hash), CURVE_ORDER);
|
||||
function modnLE(hash: Uint8Array): bigint {
|
||||
return mod.mod(ut.bytesToNumberLE(hash), CURVE_ORDER);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -529,7 +551,7 @@ export function twistedEdwards(curveDef: CurveType): CurveFn {
|
||||
*/
|
||||
function normalizeScalar(num: number | bigint, max: bigint, strict = true): bigint {
|
||||
if (!max) throw new TypeError('Specify max value');
|
||||
if (typeof num === 'number' && Number.isSafeInteger(num)) num = BigInt(num);
|
||||
if (ut.isPositiveInt(num)) num = BigInt(num);
|
||||
if (typeof num === 'bigint' && num < max) {
|
||||
if (strict) {
|
||||
if (_0n < num) return num;
|
||||
@@ -537,37 +559,32 @@ export function twistedEdwards(curveDef: CurveType): CurveFn {
|
||||
if (_0n <= num) return num;
|
||||
}
|
||||
}
|
||||
throw new TypeError('Expected valid scalar: 0 < scalar < max');
|
||||
}
|
||||
|
||||
function checkPrivateKey(key: PrivKey) {
|
||||
// Normalize bigint / number / string to Uint8Array
|
||||
key =
|
||||
typeof key === 'bigint' || typeof key === 'number'
|
||||
? numberToBytesLE(normalizeScalar(key, maxGroupElement), groupLen)
|
||||
: ensureBytes(key);
|
||||
if (key.length !== groupLen) throw new Error(`Expected ${groupLen} bytes, got ${key.length}`);
|
||||
return key;
|
||||
}
|
||||
|
||||
// Takes 64 bytes
|
||||
function getKeyFromHash(hashed: Uint8Array) {
|
||||
// First 32 bytes of 64b uniformingly random input are taken,
|
||||
// clears 3 bits of it to produce a random field element.
|
||||
const head = adjustScalarBytes(hashed.slice(0, groupLen));
|
||||
// Second 32 bytes is called key prefix (5.1.6)
|
||||
const prefix = hashed.slice(groupLen, 2 * groupLen);
|
||||
// The actual private scalar
|
||||
const scalar = modlLE(head);
|
||||
// Point on Edwards curve aka public key
|
||||
const point = Point.BASE.multiply(scalar);
|
||||
const pointBytes = point.toRawBytes();
|
||||
return { head, prefix, scalar, point, pointBytes };
|
||||
throw new TypeError(`Expected valid scalar: 0 < scalar < ${max}`);
|
||||
}
|
||||
|
||||
/** Convenience method that creates public key and other stuff. RFC8032 5.1.5 */
|
||||
function getExtendedPublicKey(key: PrivKey) {
|
||||
return getKeyFromHash(CURVE.hash(checkPrivateKey(key)));
|
||||
const groupLen = CURVE.nByteLength;
|
||||
// Normalize bigint / number / string to Uint8Array
|
||||
const keyb =
|
||||
typeof key === 'bigint' || typeof key === 'number'
|
||||
? ut.numberToBytesLE(normalizeScalar(key, maxGroupElement), groupLen)
|
||||
: key;
|
||||
// Hash private key with curve's hash function to produce uniformingly random input
|
||||
// We check byte lengths e.g.: ensureBytes(64, hash(ensureBytes(32, key)))
|
||||
const hashed = ensureBytes(CURVE.hash(ensureBytes(keyb, groupLen)), 2 * groupLen);
|
||||
|
||||
// First half's bits are cleared to produce a random field element.
|
||||
const head = adjustScalarBytes(hashed.slice(0, groupLen));
|
||||
// Second half is called key prefix (5.1.6)
|
||||
const prefix = hashed.slice(groupLen, 2 * groupLen);
|
||||
// The actual private scalar
|
||||
const scalar = modnLE(head);
|
||||
// Point on Edwards curve aka public key
|
||||
const point = Point.BASE.multiply(scalar);
|
||||
// Uint8Array representation
|
||||
const pointBytes = point.toRawBytes();
|
||||
return { head, prefix, scalar, point, pointBytes };
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -582,7 +599,7 @@ export function twistedEdwards(curveDef: CurveType): CurveFn {
|
||||
const EMPTY = new Uint8Array();
|
||||
function hashDomainToScalar(message: Uint8Array, context: Hex = EMPTY) {
|
||||
context = ensureBytes(context);
|
||||
return modlLE(CURVE.hash(domain(message, context, !!CURVE.preHash)));
|
||||
return modnLE(CURVE.hash(domain(message, context, !!CURVE.preHash)));
|
||||
}
|
||||
|
||||
/** Signs message with privateKey. RFC8032 5.1.6 */
|
||||
@@ -590,9 +607,9 @@ export function twistedEdwards(curveDef: CurveType): CurveFn {
|
||||
message = ensureBytes(message);
|
||||
if (CURVE.preHash) message = CURVE.preHash(message);
|
||||
const { prefix, scalar, pointBytes } = getExtendedPublicKey(privateKey);
|
||||
const r = hashDomainToScalar(concatBytes(prefix, message), context);
|
||||
const r = hashDomainToScalar(ut.concatBytes(prefix, message), context);
|
||||
const R = Point.BASE.multiply(r); // R = rG
|
||||
const k = hashDomainToScalar(concatBytes(R.toRawBytes(), pointBytes, message), context); // k = hash(R+P+msg)
|
||||
const k = hashDomainToScalar(ut.concatBytes(R.toRawBytes(), pointBytes, message), context); // k = hash(R+P+msg)
|
||||
const s = mod.mod(r + k * scalar, CURVE_ORDER); // s = r + kp
|
||||
return new Signature(R, s).toRawBytes();
|
||||
}
|
||||
@@ -629,13 +646,13 @@ export function twistedEdwards(curveDef: CurveType): CurveFn {
|
||||
const { r, s } = sig;
|
||||
const SB = ExtendedPoint.BASE.multiplyUnsafe(s);
|
||||
const k = hashDomainToScalar(
|
||||
concatBytes(r.toRawBytes(), publicKey.toRawBytes(), message),
|
||||
ut.concatBytes(r.toRawBytes(), publicKey.toRawBytes(), message),
|
||||
context
|
||||
);
|
||||
const kA = ExtendedPoint.fromAffine(publicKey).multiplyUnsafe(k);
|
||||
const RkA = ExtendedPoint.fromAffine(r).add(kA);
|
||||
// [8][S]B = [8]R + [8][k]A'
|
||||
return RkA.subtract(SB).multiplyUnsafe(CURVE.h).equals(ExtendedPoint.ZERO);
|
||||
return RkA.subtract(SB).clearCofactor().equals(ExtendedPoint.ZERO);
|
||||
}
|
||||
|
||||
// Enable precomputes. Slows down first publicKey computation by 20ms.
|
||||
@@ -643,19 +660,16 @@ export function twistedEdwards(curveDef: CurveType): CurveFn {
|
||||
|
||||
const utils = {
|
||||
getExtendedPublicKey,
|
||||
mod: modP,
|
||||
invert: (a: bigint, m = CURVE.P) => mod.invert(a, m),
|
||||
|
||||
/**
|
||||
* Not needed for ed25519 private keys. Needed if you use scalars directly (rare).
|
||||
*/
|
||||
hashToPrivateScalar: (hash: Hex): bigint => hashToPrivateScalar(hash, CURVE_ORDER, true),
|
||||
hashToPrivateScalar: (hash: Hex): bigint => ut.hashToPrivateScalar(hash, CURVE_ORDER, true),
|
||||
|
||||
/**
|
||||
* ed25519 private keys are uniform 32-bit strings. We do not need to check for
|
||||
* modulo bias like we do in secp256k1 randomPrivateKey()
|
||||
*/
|
||||
randomPrivateKey: (): Uint8Array => randomBytes(fieldLen),
|
||||
randomPrivateKey: (): Uint8Array => randomBytes(Fp.BYTES),
|
||||
|
||||
/**
|
||||
* We're doing scalar multiplication (used in getPublicKey etc) with precomputed BASE_POINT
|
||||
@@ -1,5 +1,5 @@
|
||||
/*! @noble/curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
||||
// Default group related functions
|
||||
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
||||
// Abelian group utilities
|
||||
const _0n = BigInt(0);
|
||||
const _1n = BigInt(1);
|
||||
|
||||
@@ -23,7 +23,6 @@ export function wNAF<T extends Group<T>>(c: GroupConstructor<T>, bits: number) {
|
||||
return condition ? neg : item;
|
||||
};
|
||||
const opts = (W: number) => {
|
||||
if (256 % W) throw new Error('Invalid precomputation window, must be power of 2');
|
||||
const windows = Math.ceil(bits / W) + 1; // +1, because
|
||||
const windowSize = 2 ** (W - 1); // -1 because we skip zero
|
||||
return { windows, windowSize };
|
||||
@@ -68,11 +67,14 @@ export function wNAF<T extends Group<T>>(c: GroupConstructor<T>, bits: number) {
|
||||
|
||||
/**
|
||||
* Implements w-ary non-adjacent form for calculating ec multiplication.
|
||||
* @param n
|
||||
* @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;
|
||||
177
src/abstract/hash-to-curve.ts
Normal file
177
src/abstract/hash-to-curve.ts
Normal file
@@ -0,0 +1,177 @@
|
||||
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
||||
import { CHash, concatBytes } from './utils.js';
|
||||
import * as mod from './modular.js';
|
||||
|
||||
export 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;
|
||||
};
|
||||
|
||||
export function validateHTFOpts(opts: htfOpts) {
|
||||
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');
|
||||
}
|
||||
|
||||
// UTF8 to ui8a
|
||||
// TODO: looks broken, ASCII only, why not TextEncoder/TextDecoder? it is in hashes anyway
|
||||
export function stringToBytes(str: string) {
|
||||
const bytes = new Uint8Array(str.length);
|
||||
for (let i = 0; i < str.length; i++) bytes[i] = str.charCodeAt(i);
|
||||
return bytes;
|
||||
}
|
||||
|
||||
// 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: htfOpts): 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.mod(os2ip(tv), options.p);
|
||||
}
|
||||
u[i] = e;
|
||||
}
|
||||
return u;
|
||||
}
|
||||
|
||||
export function isogenyMap<T, F extends mod.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 };
|
||||
};
|
||||
}
|
||||
383
src/abstract/modular.ts
Normal file
383
src/abstract/modular.ts
Normal file
@@ -0,0 +1,383 @@
|
||||
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
||||
// TODO: remove circular imports
|
||||
import * as utils from './utils.js';
|
||||
// Utilities for modular arithmetics and finite fields
|
||||
// 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)
|
||||
// TODO: Fp version?
|
||||
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.equals(Fp.square(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.negate(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.equals(b, Fp.ONE)) {
|
||||
if (Fp.equals(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.square(b); m < r; m++) {
|
||||
if (Fp.equals(t2, Fp.ONE)) break;
|
||||
t2 = Fp.square(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.square(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.equals(Fp.square(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.equals(Fp.square(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;
|
||||
isZero: (num: T) => boolean;
|
||||
negate(num: T): T;
|
||||
invert(num: T): T;
|
||||
sqrt(num: T): T;
|
||||
square(num: T): T;
|
||||
// 2-args
|
||||
equals(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;
|
||||
squareN(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', 'isZero', 'negate', 'invert', 'sqrt', 'square',
|
||||
'equals', 'add', 'sub', 'mul', 'pow', 'div',
|
||||
'addN', 'subN', 'mulN', 'squareN'
|
||||
] as const;
|
||||
export function validateField<T>(field: Field<T>) {
|
||||
for (const i of ['ORDER', 'MASK'] as const) {
|
||||
if (typeof field[i] !== 'bigint')
|
||||
throw new Error(`Invalid field param ${i}=${field[i]} (${typeof field[i]})`);
|
||||
}
|
||||
for (const i of ['BYTES', 'BITS'] as const) {
|
||||
if (typeof field[i] !== 'number')
|
||||
throw new Error(`Invalid field param ${i}=${field[i]} (${typeof field[i]})`);
|
||||
}
|
||||
for (const i of FIELD_FIELDS) {
|
||||
if (typeof field[i] !== 'function')
|
||||
throw new Error(`Invalid field param ${i}=${field[i]} (${typeof field[i]})`);
|
||||
}
|
||||
}
|
||||
|
||||
// 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.square(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.isZero(num)) return acc;
|
||||
tmp[i] = acc;
|
||||
return f.mul(acc, num);
|
||||
}, f.ONE);
|
||||
// Invert last element
|
||||
const inverted = f.invert(lastMultiplied);
|
||||
// Walk from last to first, multiply them by inverted each other MOD p
|
||||
nums.reduceRight((acc, num, i) => {
|
||||
if (f.isZero(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.invert(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.equals(p, f.ZERO) || f.equals(p, f.ONE);
|
||||
};
|
||||
}
|
||||
|
||||
// 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 } = utils.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: utils.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;
|
||||
},
|
||||
isZero: (num) => num === _0n,
|
||||
isOdd: (num) => (num & _1n) === _1n,
|
||||
negate: (num) => mod(-num, ORDER),
|
||||
equals: (lhs, rhs) => lhs === rhs,
|
||||
|
||||
square: (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
|
||||
squareN: (num) => num * num,
|
||||
addN: (lhs, rhs) => lhs + rhs,
|
||||
subN: (lhs, rhs) => lhs - rhs,
|
||||
mulN: (lhs, rhs) => lhs * rhs,
|
||||
|
||||
invert: (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 ? utils.numberToBytesLE(num, BYTES) : utils.numberToBytesBE(num, BYTES),
|
||||
|
||||
fromBytes: (bytes) => {
|
||||
if (bytes.length !== BYTES)
|
||||
throw new Error(`Fp.fromBytes: expected ${BYTES}, got ${bytes.length}`);
|
||||
return isLE ? utils.bytesToNumberLE(bytes) : utils.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.negate(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.negate(root) : root;
|
||||
}
|
||||
@@ -1,10 +1,6 @@
|
||||
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
||||
import * as mod from './modular.js';
|
||||
import {
|
||||
ensureBytes,
|
||||
numberToBytesLE,
|
||||
bytesToNumberLE,
|
||||
// nLength,
|
||||
} from './utils.js';
|
||||
import { ensureBytes, numberToBytesLE, bytesToNumberLE, isPositiveInt } from './utils.js';
|
||||
|
||||
const _0n = BigInt(0);
|
||||
const _1n = BigInt(1);
|
||||
@@ -23,8 +19,9 @@ export type CurveType = {
|
||||
Gu: string;
|
||||
};
|
||||
export type CurveFn = {
|
||||
scalarMult: (u: Hex, scalar: Hex) => Uint8Array;
|
||||
scalarMult: (scalar: Hex, u: Hex) => Uint8Array;
|
||||
scalarMultBase: (scalar: Hex) => Uint8Array;
|
||||
getSharedSecret: (privateKeyA: Hex, publicKeyB: Hex) => Uint8Array;
|
||||
getPublicKey: (privateKey: Hex) => Uint8Array;
|
||||
Gu: string;
|
||||
};
|
||||
@@ -36,7 +33,7 @@ function validateOpts(curve: CurveType) {
|
||||
}
|
||||
for (const i of ['montgomeryBits', 'nByteLength'] as const) {
|
||||
if (curve[i] === undefined) continue; // Optional
|
||||
if (!Number.isSafeInteger(curve[i]))
|
||||
if (!isPositiveInt(curve[i]))
|
||||
throw new Error(`Invalid curve param ${i}=${curve[i]} (${typeof curve[i]})`);
|
||||
}
|
||||
for (const fn of ['adjustScalarBytes', 'domain', 'powPminus2'] as const) {
|
||||
@@ -185,8 +182,14 @@ export function montgomery(curveDef: CurveType): CurveFn {
|
||||
throw new Error(`Expected ${montgomeryBytes} or ${fieldLen} bytes, got ${bytes.length}`);
|
||||
return bytesToNumberLE(adjustScalarBytes(bytes));
|
||||
}
|
||||
// Multiply point u by scalar
|
||||
function scalarMult(u: Hex, scalar: Hex): Uint8Array {
|
||||
/**
|
||||
* Computes shared secret between private key "scalar" and public key's "u" (x) coordinate.
|
||||
* We can get 'y' coordinate from 'u',
|
||||
* but Point.fromHex also wants 'x' coordinate oddity flag,
|
||||
* and we cannot get 'x' without knowing 'v'.
|
||||
* Need to add generic conversion between twisted edwards and complimentary curve for JubJub.
|
||||
*/
|
||||
function scalarMult(scalar: Hex, u: Hex): Uint8Array {
|
||||
const pointU = decodeUCoordinate(u);
|
||||
const _scalar = decodeScalar(scalar);
|
||||
const pu = montgomeryLadder(pointU, _scalar);
|
||||
@@ -195,18 +198,20 @@ export function montgomery(curveDef: CurveType): CurveFn {
|
||||
if (pu === _0n) throw new Error('Invalid private or public key received');
|
||||
return encodeUCoordinate(pu);
|
||||
}
|
||||
// Multiply base point by scalar
|
||||
/**
|
||||
* Computes public key from private.
|
||||
* Executes scalar multiplication of curve's base point by scalar.
|
||||
* @param scalar private key
|
||||
* @returns new public key
|
||||
*/
|
||||
function scalarMultBase(scalar: Hex): Uint8Array {
|
||||
return scalarMult(CURVE.Gu, scalar);
|
||||
return scalarMult(scalar, CURVE.Gu);
|
||||
}
|
||||
|
||||
return {
|
||||
// NOTE: we can get 'y' coordinate from 'u', but Point.fromHex also wants 'x' coordinate oddity flag, and we cannot get 'x' without knowing 'v'
|
||||
// Need to add generic conversion between twisted edwards and complimentary curve for JubJub
|
||||
scalarMult,
|
||||
scalarMultBase,
|
||||
// NOTE: these function work on complimentary montgomery curve
|
||||
// getSharedSecret: (privateKey: Hex, publicKey: Hex) => scalarMult(publicKey, privateKey),
|
||||
getSharedSecret: (privateKey: Hex, publicKey: Hex) => scalarMult(privateKey, publicKey),
|
||||
getPublicKey: (privateKey: Hex): Uint8Array => scalarMultBase(privateKey),
|
||||
Gu: CURVE.Gu,
|
||||
};
|
||||
@@ -1,15 +1,25 @@
|
||||
/*! @noble/curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
||||
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
||||
import * as mod from './modular.js';
|
||||
const _0n = BigInt(0);
|
||||
const _1n = BigInt(1);
|
||||
const _2n = BigInt(2);
|
||||
|
||||
// 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 | number;
|
||||
export type CHash = {
|
||||
(message: Uint8Array | string): Uint8Array;
|
||||
blockLen: number;
|
||||
outputLen: number;
|
||||
create(opts?: { dkLen?: number }): any; // For shake
|
||||
};
|
||||
|
||||
// NOTE: these are generic, even if curve is on some polynominal field (bls), it will still have P/n/h
|
||||
// But generator can be different (Fp2/Fp6 for bls?)
|
||||
export type BasicCurve = {
|
||||
export type BasicCurve<T> = {
|
||||
// Field over which we'll do calculations (Fp)
|
||||
P: bigint;
|
||||
Fp: mod.Field<T>;
|
||||
// Curve order, total count of valid points in the field
|
||||
n: bigint;
|
||||
// Bit/byte length of curve order
|
||||
@@ -19,27 +29,40 @@ export type BasicCurve = {
|
||||
// NOTE: we can assign default value of 1, but then users will just ignore it, without validating with spec
|
||||
// Has not use for now, but nice to have in API
|
||||
h: bigint;
|
||||
hEff?: bigint; // Number to multiply to clear cofactor
|
||||
// Base point (x, y) aka generator point
|
||||
Gx: bigint;
|
||||
Gy: bigint;
|
||||
Gx: T;
|
||||
Gy: T;
|
||||
// Wrap private key by curve order (% CURVE.n instead of throwing error)
|
||||
wrapPrivateKey?: boolean;
|
||||
// Point at infinity is perfectly valid point, but not valid public key.
|
||||
// Disabled by default because of compatibility reasons with @noble/secp256k1
|
||||
allowInfinityPoint?: boolean;
|
||||
};
|
||||
|
||||
export function validateOpts<T extends BasicCurve>(curve: T) {
|
||||
for (const i of ['P', 'n', 'h', 'Gx', 'Gy'] as const) {
|
||||
if (typeof curve[i] !== 'bigint')
|
||||
throw new Error(`Invalid curve param ${i}=${curve[i]} (${typeof curve[i]})`);
|
||||
// Bans floats and integers above 2^53-1
|
||||
export function isPositiveInt(num: any): num is number {
|
||||
return typeof num === 'number' && Number.isSafeInteger(num) && num > 0;
|
||||
}
|
||||
|
||||
export function validateOpts<FP, T>(curve: BasicCurve<FP> & T) {
|
||||
mod.validateField(curve.Fp);
|
||||
for (const i of ['n', 'h'] as const) {
|
||||
const val = curve[i];
|
||||
if (typeof val !== 'bigint') throw new Error(`Invalid curve param ${i}=${val} (${typeof val})`);
|
||||
}
|
||||
if (!curve.Fp.isValid(curve.Gx)) throw new Error('Invalid generator X coordinate Fp element');
|
||||
if (!curve.Fp.isValid(curve.Gy)) throw new Error('Invalid generator Y coordinate Fp element');
|
||||
|
||||
for (const i of ['nBitLength', 'nByteLength'] as const) {
|
||||
if (curve[i] === undefined) continue; // Optional
|
||||
if (!Number.isSafeInteger(curve[i]))
|
||||
throw new Error(`Invalid curve param ${i}=${curve[i]} (${typeof curve[i]})`);
|
||||
const val = curve[i];
|
||||
if (val === undefined) continue; // Optional
|
||||
if (!isPositiveInt(val)) throw new Error(`Invalid curve param ${i}=${val} (${typeof val})`);
|
||||
}
|
||||
// Set defaults
|
||||
return Object.freeze({ ...nLength(curve.n, curve.nBitLength), ...curve } as const);
|
||||
}
|
||||
|
||||
import * as mod from './modular.js';
|
||||
|
||||
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');
|
||||
@@ -126,22 +149,22 @@ export function nLength(n: bigint, nBitLength?: number) {
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* As per FIPS 186 B.4.1.
|
||||
* 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 sha512, or a similar function
|
||||
* @param hash hash output from SHA3 or a similar function
|
||||
* @returns valid private scalar
|
||||
*/
|
||||
const _1n = BigInt(1);
|
||||
export function hashToPrivateScalar(hash: Hex, CURVE_ORDER: bigint, isLE = false): bigint {
|
||||
export function hashToPrivateScalar(hash: Hex, groupOrder: bigint, isLE = false): bigint {
|
||||
hash = ensureBytes(hash);
|
||||
const orderLen = nLength(CURVE_ORDER).nByteLength;
|
||||
const minLen = orderLen + 8;
|
||||
if (orderLen < 16 || hash.length < minLen || hash.length > 1024)
|
||||
throw new Error('Expected valid bytes of private key as per FIPS 186');
|
||||
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.mod(num, CURVE_ORDER - _1n) + _1n;
|
||||
return mod.mod(num, groupOrder - _1n) + _1n;
|
||||
}
|
||||
|
||||
export function equalBytes(b1: Uint8Array, b2: Uint8Array) {
|
||||
@@ -150,3 +173,21 @@ export function equalBytes(b1: Uint8Array, b2: Uint8Array) {
|
||||
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;
|
||||
1428
src/abstract/weierstrass.ts
Normal file
1428
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
@@ -1,8 +1,8 @@
|
||||
/*! @noble/curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
||||
import { weierstrass } from '@noble/curves/weierstrass';
|
||||
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
||||
import { weierstrass } from './abstract/weierstrass.js';
|
||||
import { sha256 } from '@noble/hashes/sha256';
|
||||
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.
|
||||
@@ -12,7 +12,7 @@ import { getHash } from './_shortw_utils.js';
|
||||
export const bn254 = weierstrass({
|
||||
a: BigInt(0),
|
||||
b: BigInt(3),
|
||||
P: BigInt('0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47'),
|
||||
Fp: Fp(BigInt('0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47')),
|
||||
n: BigInt('0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001'),
|
||||
Gx: BigInt(1),
|
||||
Gy: BigInt(2),
|
||||
@@ -1,9 +1,9 @@
|
||||
/*! @noble/curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
||||
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
||||
import { sha512 } from '@noble/hashes/sha512';
|
||||
import { concatBytes, randomBytes, utf8ToBytes } from '@noble/hashes/utils';
|
||||
import { twistedEdwards, ExtendedPointType } from '@noble/curves/edwards';
|
||||
import { montgomery } from '@noble/curves/montgomery';
|
||||
import { mod, pow2, isNegativeLE } from '@noble/curves/modular';
|
||||
import { twistedEdwards, ExtendedPointType } 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,
|
||||
@@ -11,7 +11,7 @@ import {
|
||||
bytesToNumberLE,
|
||||
numberToBytesLE,
|
||||
Hex,
|
||||
} from '@noble/curves/utils';
|
||||
} from './abstract/utils.js';
|
||||
|
||||
/**
|
||||
* ed25519 Twisted Edwards curve with following addons:
|
||||
@@ -49,18 +49,14 @@ function ed25519_pow_2_252_3(x: bigint) {
|
||||
// ^ To pow to (p+3)/8, multiply it by x.
|
||||
return { pow_p_5_8, b2 };
|
||||
}
|
||||
|
||||
/**
|
||||
* For X25519, in order to decode 32 random bytes as an integer scalar,
|
||||
* set the
|
||||
* three least significant bits of the first byte 0b1111_1000,
|
||||
* and the most significant bit of the last to zero 0b0111_1111,
|
||||
* set the second most significant bit of the last byte to 1 0b0100_0000
|
||||
*/
|
||||
function adjustScalarBytes(bytes: Uint8Array): Uint8Array {
|
||||
bytes[0] &= 248;
|
||||
bytes[31] &= 127;
|
||||
bytes[31] |= 64;
|
||||
// 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)
|
||||
@@ -95,6 +91,81 @@ export const ED25519_TORSION_SUBGROUP = [
|
||||
'c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa',
|
||||
];
|
||||
|
||||
const Fp = Field(ED25519_P, undefined, true);
|
||||
|
||||
// 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.negate(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.square(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.negate(ELL2_J); // 4. x1n = -J # x1 = x1n / xd = -J / (1 + 2 * u^2)
|
||||
let tv2 = Fp.square(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.square(gxd); // 11. tv3 = gxd^2
|
||||
tv2 = Fp.square(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.square(y11); // 19. tv2 = y11^2
|
||||
tv2 = Fp.mul(tv2, gxd); // 20. tv2 = tv2 * gxd
|
||||
let e1 = Fp.equals(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.square(y21); // 28. tv2 = y21^2
|
||||
tv2 = Fp.mul(tv2, gxd); // 29. tv2 = tv2 * gxd
|
||||
let e2 = Fp.equals(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.square(y1); // 32. tv2 = y1^2
|
||||
tv2 = Fp.mul(tv2, gxd); // 33. tv2 = tv2 * gxd
|
||||
let e3 = Fp.equals(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.negate(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.negate(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.equals(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 ED25519_DEF = {
|
||||
// Param: a
|
||||
a: BigInt(-1),
|
||||
@@ -102,7 +173,7 @@ const ED25519_DEF = {
|
||||
// Negative number is P - number, and division is invert(number, P)
|
||||
d: BigInt('37095705934669439343138083508754565189542113879843219016388785533085940283555'),
|
||||
// Finite field 𝔽p over which we'll do calculations; 2n ** 255n - 19n
|
||||
P: ED25519_P,
|
||||
Fp,
|
||||
// Subgroup order: how many points ed25519 has
|
||||
// 2n ** 252n + 27742317777372353535851937790883648493n;
|
||||
n: BigInt('7237005577332262213973186563042994240857116359379907606001950938285454250989'),
|
||||
@@ -118,6 +189,15 @@ const ED25519_DEF = {
|
||||
// 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,
|
||||
htfDefaults: {
|
||||
DST: 'edwards25519_XMD:SHA-512_ELL2_RO_',
|
||||
p: Fp.ORDER,
|
||||
m: 1,
|
||||
k: 128,
|
||||
expand: 'xmd',
|
||||
hash: sha512,
|
||||
},
|
||||
mapToCurve: (scalars: bigint[]) => map_to_curve_elligator2_edwards25519(scalars[0]),
|
||||
} as const;
|
||||
|
||||
export const ed25519 = twistedEdwards(ED25519_DEF);
|
||||
@@ -180,30 +260,16 @@ const invertSqrt = (number: bigint) => uvRatio(_1n, number);
|
||||
|
||||
const MAX_255B = BigInt('0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff');
|
||||
const bytes255ToNumberLE = (bytes: Uint8Array) =>
|
||||
ed25519.utils.mod(bytesToNumberLE(bytes) & MAX_255B);
|
||||
ed25519.CURVE.Fp.create(bytesToNumberLE(bytes) & MAX_255B);
|
||||
|
||||
type ExtendedPoint = ExtendedPointType;
|
||||
|
||||
/**
|
||||
* Each ed25519/ExtendedPoint has 8 different equivalent points. This can be
|
||||
* a source of bugs for protocols like ring signatures. Ristretto was created to solve this.
|
||||
* Ristretto point operates in X:Y:Z:T extended coordinates like ExtendedPoint,
|
||||
* but it should work in its own namespace: do not combine those two.
|
||||
* https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-ristretto255-decaf448
|
||||
*/
|
||||
export class RistrettoPoint {
|
||||
static BASE = new RistrettoPoint(ed25519.ExtendedPoint.BASE);
|
||||
static ZERO = new RistrettoPoint(ed25519.ExtendedPoint.ZERO);
|
||||
|
||||
// Private property to discourage combining ExtendedPoint + RistrettoPoint
|
||||
// Always use Ristretto encoding/decoding instead.
|
||||
constructor(private readonly ep: ExtendedPoint) {}
|
||||
|
||||
// Computes Elligator map for Ristretto
|
||||
// https://ristretto.group/formulas/elligator.html
|
||||
private static calcElligatorRistrettoMap(r0: bigint): ExtendedPoint {
|
||||
const { d, P } = ed25519.CURVE;
|
||||
const { mod } = ed25519.utils;
|
||||
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
|
||||
@@ -222,6 +288,20 @@ export class RistrettoPoint {
|
||||
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.
|
||||
@@ -232,9 +312,9 @@ export class RistrettoPoint {
|
||||
static hashToCurve(hex: Hex): RistrettoPoint {
|
||||
hex = ensureBytes(hex, 64);
|
||||
const r1 = bytes255ToNumberLE(hex.slice(0, 32));
|
||||
const R1 = this.calcElligatorRistrettoMap(r1);
|
||||
const R1 = calcElligatorRistrettoMap(r1);
|
||||
const r2 = bytes255ToNumberLE(hex.slice(32, 64));
|
||||
const R2 = this.calcElligatorRistrettoMap(r2);
|
||||
const R2 = calcElligatorRistrettoMap(r2);
|
||||
return new RistrettoPoint(R1.add(R2));
|
||||
}
|
||||
|
||||
@@ -245,8 +325,9 @@ export class RistrettoPoint {
|
||||
*/
|
||||
static fromHex(hex: Hex): RistrettoPoint {
|
||||
hex = ensureBytes(hex, 32);
|
||||
const { a, d, P } = ed25519.CURVE;
|
||||
const { mod } = ed25519.utils;
|
||||
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.
|
||||
@@ -275,8 +356,8 @@ export class RistrettoPoint {
|
||||
*/
|
||||
toRawBytes(): Uint8Array {
|
||||
let { x, y, z, t } = this.ep;
|
||||
const { P } = ed25519.CURVE;
|
||||
const { mod } = ed25519.utils;
|
||||
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
|
||||
@@ -314,7 +395,7 @@ export class RistrettoPoint {
|
||||
assertRstPoint(other);
|
||||
const a = this.ep;
|
||||
const b = other.ep;
|
||||
const { mod } = ed25519.utils;
|
||||
const mod = ed25519.CURVE.Fp.create;
|
||||
// (x1 * y2 == y1 * x2) | (y1 * y2 == x1 * x2)
|
||||
const one = mod(a.x * b.y) === mod(a.y * b.x);
|
||||
const two = mod(a.y * b.y) === mod(a.x * b.x);
|
||||
234
src/ed448.ts
Normal file
234
src/ed448.ts
Normal file
@@ -0,0 +1,234 @@
|
||||
/*! 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';
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
// 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.square(u); // 1. tv1 = u^2
|
||||
let e1 = Fp.equals(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.negate(ELL2_J); // 5. x1n = -J
|
||||
let tv2 = Fp.square(xd); // 6. tv2 = xd^2
|
||||
let gxd = Fp.mul(tv2, xd); // 7. gxd = tv2 * xd # gxd = xd^3
|
||||
let gx1 = Fp.mul(tv1, Fp.negate(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.square(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.negate(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.square(y1); // 20. tv2 = y1^2
|
||||
tv2 = Fp.mul(tv2, gxd); // 21. tv2 = tv2 * gxd
|
||||
let e2 = Fp.equals(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.negate(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.square(xn); // 2. xn2 = xn^2
|
||||
let xd2 = Fp.square(xd); // 3. xd2 = xd^2
|
||||
let xd4 = Fp.square(xd2); // 4. xd4 = xd2^2
|
||||
let yn2 = Fp.square(yn); // 5. yn2 = yn^2
|
||||
let yd2 = Fp.square(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.equals(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 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 };
|
||||
},
|
||||
htfDefaults: {
|
||||
DST: 'edwards448_XOF:SHAKE256_ELL2_RO_',
|
||||
p: Fp.ORDER,
|
||||
m: 1,
|
||||
k: 224,
|
||||
expand: 'xof',
|
||||
hash: shake256,
|
||||
},
|
||||
mapToCurve: (scalars: bigint[]) => map_to_curve_elligator2_edwards448(scalars[0]),
|
||||
} as const;
|
||||
|
||||
export const ed448 = twistedEdwards(ED448_DEF);
|
||||
// NOTE: there is no ed448ctx, since ed448 supports ctx by default
|
||||
export const ed448ph = twistedEdwards({ ...ED448_DEF, preHash: shake256_64 });
|
||||
|
||||
export const x448 = montgomery({
|
||||
a24: BigInt(39081),
|
||||
montgomeryBits: 448,
|
||||
nByteLength: 57,
|
||||
P: ed448P,
|
||||
Gu: '0500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000',
|
||||
powPminus2: (x: bigint): bigint => {
|
||||
const P = ed448P;
|
||||
const Pminus3div4 = ed448_pow_Pminus3div4(x);
|
||||
const Pminus3 = pow2(Pminus3div4, BigInt(2), P);
|
||||
return mod(Pminus3 * x, P); // Pminus3 * x = Pminus2
|
||||
},
|
||||
adjustScalarBytes,
|
||||
// The 4-isogeny maps between the Montgomery curve and this Edwards
|
||||
// curve are:
|
||||
// (u, v) = (y^2/x^2, (2 - x^2 - y^2)*y/x^3)
|
||||
// (x, y) = (4*v*(u^2 - 1)/(u^4 - 2*u^2 + 4*v^2 + 1),
|
||||
// -(u^5 - 2*u^3 - 4*u*v^2 + u)/
|
||||
// (u^5 - 2*u^2*v^2 - 2*u^3 - 2*v^2 + u))
|
||||
// xyToU: (p: PointType) => {
|
||||
// const P = ed448P;
|
||||
// const { x, y } = p;
|
||||
// if (x === _0n) throw new Error(`Point with x=0 doesn't have mapping`);
|
||||
// const invX = invert(x * x, P); // x^2
|
||||
// const u = mod(y * y * invX, P); // (y^2/x^2)
|
||||
// return numberToBytesLE(u, 56);
|
||||
// },
|
||||
});
|
||||
@@ -1,12 +1,14 @@
|
||||
/*! @noble/curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
||||
import { sha256 } from '@noble/hashes/sha256';
|
||||
/*! 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 '@noble/curves/edwards';
|
||||
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({
|
||||
@@ -14,16 +16,16 @@ export const jubjub = twistedEdwards({
|
||||
a: BigInt('0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000000'),
|
||||
d: BigInt('0x2a9318e74bfa2b48f5fd9207e6bd7fd4292d7f6d37579d2601065fd6d6343eb1'),
|
||||
// Finite field 𝔽p over which we'll do calculations
|
||||
P: BigInt('0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001'),
|
||||
// Subgroup order: how many points ed25519 has
|
||||
// 2n ** 252n + 27742317777372353535851937790883648493n;
|
||||
// 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: sha256,
|
||||
hash: sha512,
|
||||
randomBytes,
|
||||
} as const);
|
||||
|
||||
159
src/modular.ts
159
src/modular.ts
@@ -1,159 +0,0 @@
|
||||
/*! @noble/curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
||||
|
||||
// Utilities for modular arithmetics
|
||||
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.
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
// Little-endian check for first LE bit (last BE bit);
|
||||
export const isNegativeLE = (num: bigint, modulo: bigint) => (mod(num, modulo) & _1n) === _1n;
|
||||
|
||||
// An idea on modular arithmetic for bls12-381:
|
||||
// const FIELD = {add, pow, sqrt, mul};
|
||||
// Functions will take field elements, no need for an additional class
|
||||
// Could be faster. 1 bigint field will just do operations and mod later:
|
||||
// instead of 'r = mod(r * b, P)' we will write r = mul(r, b);
|
||||
// Could be insecure without shape check, so it needs to be done.
|
||||
// Functions could be inlined by JIT.
|
||||
@@ -1,6 +1,7 @@
|
||||
/*! @noble/curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
||||
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
||||
import { createCurve } from './_shortw_utils.js';
|
||||
import { 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
|
||||
@@ -10,7 +11,7 @@ export const P192 = createCurve(
|
||||
a: BigInt('0xfffffffffffffffffffffffffffffffefffffffffffffffc'),
|
||||
b: BigInt('0x64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1'),
|
||||
// Field over which we'll do calculations; 2n ** 192n - 2n ** 64n - 1n
|
||||
P: BigInt('0xfffffffffffffffffffffffffffffffeffffffffffffffff'),
|
||||
Fp: Fp(BigInt('0xfffffffffffffffffffffffffffffffeffffffffffffffff')),
|
||||
// Curve order, total count of valid points in the field.
|
||||
n: BigInt('0xffffffffffffffffffffffff99def836146bc9b1b4d22831'),
|
||||
// Base point (x, y) aka generator point
|
||||
@@ -1,6 +1,7 @@
|
||||
/*! @noble/curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
||||
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
||||
import { createCurve } from './_shortw_utils.js';
|
||||
import { sha256 } from '@noble/hashes/sha256';
|
||||
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
|
||||
@@ -10,7 +11,7 @@ export const P224 = createCurve(
|
||||
a: BigInt('0xfffffffffffffffffffffffffffffffefffffffffffffffffffffffe'),
|
||||
b: BigInt('0xb4050a850c04b3abf54132565044b0b7d7bfd8ba270b39432355ffb4'),
|
||||
// Field over which we'll do calculations; 2n**224n - 2n**96n + 1n
|
||||
P: BigInt('0xffffffffffffffffffffffffffffffff000000000000000000000001'),
|
||||
Fp: Fp(BigInt('0xffffffffffffffffffffffffffffffff000000000000000000000001')),
|
||||
// Curve order, total count of valid points in the field
|
||||
n: BigInt('0xffffffffffffffffffffffffffff16a2e0b8f03e13dd29455c5c2a3d'),
|
||||
// Base point (x, y) aka generator point
|
||||
@@ -19,6 +20,6 @@ export const P224 = createCurve(
|
||||
h: BigInt(1),
|
||||
lowS: false,
|
||||
} as const,
|
||||
sha256 // TODO: replace with sha224 when new @noble/hashes released
|
||||
sha224
|
||||
);
|
||||
export const secp224r1 = P224;
|
||||
46
src/p256.ts
Normal file
46
src/p256.ts
Normal file
@@ -0,0 +1,46 @@
|
||||
/*! 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';
|
||||
|
||||
// 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,
|
||||
mapToCurve: (scalars: bigint[]) => mapSWU(scalars[0]),
|
||||
htfDefaults: {
|
||||
DST: 'P256_XMD:SHA-256_SSWU_RO_',
|
||||
p: Fp.ORDER,
|
||||
m: 1,
|
||||
k: 128,
|
||||
expand: 'xmd',
|
||||
hash: sha256,
|
||||
},
|
||||
} as const,
|
||||
sha256
|
||||
);
|
||||
export const secp256r1 = P256;
|
||||
50
src/p384.ts
Normal file
50
src/p384.ts
Normal file
@@ -0,0 +1,50 @@
|
||||
/*! 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';
|
||||
|
||||
// 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,
|
||||
mapToCurve: (scalars: bigint[]) => mapSWU(scalars[0]),
|
||||
htfDefaults: {
|
||||
DST: 'P384_XMD:SHA-384_SSWU_RO_',
|
||||
p: Fp.ORDER,
|
||||
m: 1,
|
||||
k: 192,
|
||||
expand: 'xmd',
|
||||
hash: sha384,
|
||||
},
|
||||
} as const,
|
||||
sha384
|
||||
);
|
||||
export const secp384r1 = P384;
|
||||
61
src/p521.ts
Normal file
61
src/p521.ts
Normal file
@@ -0,0 +1,61 @@
|
||||
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
||||
import { createCurve } from './_shortw_utils.js';
|
||||
import { sha512 } from '@noble/hashes/sha512';
|
||||
import { bytesToHex, PrivKey } from './abstract/utils.js';
|
||||
import { Fp as Field } from './abstract/modular.js';
|
||||
import { mapToCurveSimpleSWU } from './abstract/weierstrass.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,
|
||||
// P521 keys could be 130, 131, 132 bytes - which doesn't play nicely.
|
||||
// We ensure all keys are 132 bytes.
|
||||
// Does not replace validation; invalid keys would still be rejected.
|
||||
normalizePrivateKey(key: PrivKey) {
|
||||
if (typeof key === 'bigint') return key;
|
||||
if (key instanceof Uint8Array) key = bytesToHex(key);
|
||||
if (typeof key !== 'string' || !([130, 131, 132].includes(key.length))) {
|
||||
throw new Error('Invalid key');
|
||||
}
|
||||
return key.padStart(66 * 2, '0');
|
||||
},
|
||||
mapToCurve: (scalars: bigint[]) => mapSWU(scalars[0]),
|
||||
htfDefaults: {
|
||||
DST: 'P521_XMD:SHA-512_SSWU_RO_',
|
||||
p: Fp.ORDER,
|
||||
m: 1,
|
||||
k: 256,
|
||||
expand: 'xmd',
|
||||
hash: sha512,
|
||||
},
|
||||
} as const, sha512);
|
||||
export const secp521r1 = P521;
|
||||
@@ -1,17 +1,17 @@
|
||||
/*! @noble/curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
||||
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
||||
import { sha256 } from '@noble/hashes/sha256';
|
||||
import { weierstrass } from '@noble/curves/weierstrass';
|
||||
import { weierstrass } from './abstract/weierstrass.js';
|
||||
import { getHash } from './_shortw_utils.js';
|
||||
import * as mod from '@noble/curves/modular';
|
||||
import * as mod from './abstract/modular.js';
|
||||
|
||||
const p = BigInt('0x40000000000000000000000000000000224698fc094cf91b992d30ed00000001');
|
||||
const q = BigInt('0x40000000000000000000000000000000224698fc0994a8dd8c46eb2100000001');
|
||||
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),
|
||||
P: p,
|
||||
Fp: mod.Fp(p),
|
||||
n: q,
|
||||
Gx: mod.mod(BigInt(-1), p),
|
||||
Gy: BigInt(2),
|
||||
@@ -22,7 +22,7 @@ export const pallas = weierstrass({
|
||||
export const vesta = weierstrass({
|
||||
a: BigInt(0),
|
||||
b: BigInt(5),
|
||||
P: q,
|
||||
Fp: mod.Fp(q),
|
||||
n: p,
|
||||
Gx: mod.mod(BigInt(-1), q),
|
||||
Gy: BigInt(2),
|
||||
@@ -1,8 +1,8 @@
|
||||
/*! @noble/curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
||||
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
||||
import { sha256 } from '@noble/hashes/sha256';
|
||||
import { mod, pow2 } from '@noble/curves/modular';
|
||||
import { Fp as Field, mod, pow2 } from './abstract/modular.js';
|
||||
import { createCurve } from './_shortw_utils.js';
|
||||
import { PointType } from '@noble/curves/weierstrass';
|
||||
import { PointType, mapToCurveSimpleSWU } from './abstract/weierstrass.js';
|
||||
import {
|
||||
ensureBytes,
|
||||
concatBytes,
|
||||
@@ -10,15 +10,14 @@ import {
|
||||
hexToBytes,
|
||||
bytesToNumberBE,
|
||||
PrivKey,
|
||||
} from '@noble/curves/utils';
|
||||
} from './abstract/utils.js';
|
||||
import { randomBytes } from '@noble/hashes/utils';
|
||||
import { isogenyMap } from './abstract/hash-to-curve.js';
|
||||
|
||||
/**
|
||||
* secp256k1 belongs to Koblitz curves: it has
|
||||
* efficiently computable Frobenius endomorphism.
|
||||
* Endomorphism improves efficiency:
|
||||
* Uses 2x less RAM, speeds up precomputation by 2x and ECDH / sign key recovery by 20%.
|
||||
* Should always be used for Jacobian's double-and-add multiplication.
|
||||
* 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
|
||||
*/
|
||||
@@ -36,10 +35,11 @@ const divNearest = (a: bigint, b: bigint) => (a + b / _2n) / b;
|
||||
* We are unwrapping the loop and multiplying it bit-by-bit.
|
||||
* (P+1n/4n).toString(2) would produce bits [223x 1, 0, 22x 1, 4x 0, 11, 00]
|
||||
*/
|
||||
// prettier-ignore
|
||||
function sqrtMod(y: bigint): bigint {
|
||||
const P = secp256k1P;
|
||||
const _3n = BigInt(3), _6n = BigInt(6), _11n = BigInt(11); const _22n = BigInt(22);
|
||||
// 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
|
||||
@@ -54,9 +54,53 @@ function sqrtMod(y: bigint): bigint {
|
||||
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);
|
||||
const root = pow2(t2, _2n, P);
|
||||
if (!Fp.equals(Fp.square(root), y)) throw new Error('Cannot find square root');
|
||||
return root;
|
||||
}
|
||||
|
||||
const Fp = Field(secp256k1P, undefined, undefined, { sqrt: sqrtMod });
|
||||
type Fp = bigint;
|
||||
|
||||
const isoMap = 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')),
|
||||
});
|
||||
|
||||
export const secp256k1 = createCurve(
|
||||
{
|
||||
// Params: a, b
|
||||
@@ -65,7 +109,7 @@ export const secp256k1 = createCurve(
|
||||
b: BigInt(7),
|
||||
// Field over which we'll do calculations;
|
||||
// 2n**256n - 2n**32n - 2n**9n - 2n**8n - 2n**7n - 2n**6n - 2n**4n - 1n
|
||||
P: secp256k1P,
|
||||
Fp,
|
||||
// Curve order, total count of valid points in the field
|
||||
n: secp256k1N,
|
||||
// Base point (x, y) aka generator point
|
||||
@@ -74,7 +118,6 @@ export const secp256k1 = createCurve(
|
||||
h: BigInt(1),
|
||||
// Alllow only low-S signatures by default in sign() and verify()
|
||||
lowS: true,
|
||||
sqrtMod,
|
||||
endo: {
|
||||
// Params taken from https://gist.github.com/paulmillr/eb670806793e84df628a7c434a873066
|
||||
beta: BigInt('0x7ae96a2b657c07106e64479eac3434e99cf0497512f58995c1396c28719501ee'),
|
||||
@@ -84,7 +127,7 @@ export const secp256k1 = createCurve(
|
||||
const b1 = -_1n * BigInt('0xe4437ed6010e88286f547fa90abfe4c3');
|
||||
const a2 = BigInt('0x114ca50f7a8e2f3f657c1108d9d44cfd8');
|
||||
const b2 = a1;
|
||||
const POW_2_128 = BigInt('0x100000000000000000000000000000000');
|
||||
const POW_2_128 = BigInt('0x100000000000000000000000000000000'); // (2n**128n).toString(16)
|
||||
|
||||
const c1 = divNearest(b2 * k, n);
|
||||
const c2 = divNearest(-b1 * k, n);
|
||||
@@ -100,6 +143,18 @@ export const secp256k1 = createCurve(
|
||||
return { k1neg, k1, k2neg, k2 };
|
||||
},
|
||||
},
|
||||
mapToCurve: (scalars: bigint[]) => {
|
||||
const { x, y } = mapSWU(Fp.create(scalars[0]));
|
||||
return isoMap(x, y);
|
||||
},
|
||||
htfDefaults: {
|
||||
DST: 'secp256k1_XMD:SHA-256_SSWU_RO_',
|
||||
p: Fp.ORDER,
|
||||
m: 1,
|
||||
k: 128,
|
||||
expand: 'xmd',
|
||||
hash: sha256,
|
||||
},
|
||||
},
|
||||
sha256
|
||||
);
|
||||
@@ -111,28 +166,25 @@ const numTo32bStr = secp256k1.utils._bigintToString;
|
||||
const normalizePrivateKey = secp256k1.utils._normalizePrivateKey;
|
||||
|
||||
// TODO: export?
|
||||
function normalizePublicKey(publicKey: Hex | PointType): PointType {
|
||||
function normalizePublicKey(publicKey: Hex | PointType<bigint>): PointType<bigint> {
|
||||
if (publicKey instanceof secp256k1.Point) {
|
||||
publicKey.assertValidity();
|
||||
return publicKey;
|
||||
} else {
|
||||
const bytes = ensureBytes(publicKey);
|
||||
// Schnorr is 32 bytes
|
||||
if (bytes.length === 32) {
|
||||
if (bytes.length !== 32) throw new Error('Schnorr pubkeys must be 32 bytes');
|
||||
const x = bytesToNumberBE(bytes);
|
||||
if (!isValidFieldElement(x)) throw new Error('Point is not on curve');
|
||||
const y2 = secp256k1.utils._weierstrassEquation(x); // y² = x³ + ax + b
|
||||
let y = sqrtMod(y2); // y = y² ^ (p+1)/4
|
||||
const isYOdd = (y & _1n) === _1n;
|
||||
// Schnorr
|
||||
if (isYOdd) y = mod(-y, secp256k1.CURVE.P);
|
||||
if (isYOdd) y = secp256k1.CURVE.Fp.negate(y);
|
||||
const point = new secp256k1.Point(x, y);
|
||||
point.assertValidity();
|
||||
return point;
|
||||
}
|
||||
// Do we need that in schnorr at all?
|
||||
return secp256k1.Point.fromHex(publicKey);
|
||||
}
|
||||
}
|
||||
|
||||
const isWithinCurveOrder = secp256k1.utils._isWithinCurveOrder;
|
||||
@@ -156,7 +208,7 @@ export function taggedHash(tag: string, ...messages: Uint8Array[]): Uint8Array {
|
||||
return sha256(concatBytes(tagP, ...messages));
|
||||
}
|
||||
|
||||
const toRawX = (point: PointType) => point.toRawBytes(true).slice(1);
|
||||
const toRawX = (point: PointType<bigint>) => point.toRawBytes(true).slice(1);
|
||||
|
||||
// Schnorr signatures are superior to ECDSA from above.
|
||||
// Below is Schnorr-specific code as per BIP0340.
|
||||
@@ -170,10 +222,13 @@ class SchnorrSignature {
|
||||
}
|
||||
static fromHex(hex: Hex) {
|
||||
const bytes = ensureBytes(hex);
|
||||
if (bytes.length !== 64)
|
||||
throw new TypeError(`SchnorrSignature.fromHex: expected 64 bytes, not ${bytes.length}`);
|
||||
const r = bytesToNumberBE(bytes.subarray(0, 32));
|
||||
const s = bytesToNumberBE(bytes.subarray(32, 64));
|
||||
const len = 32; // group length
|
||||
if (bytes.length !== 2 * len)
|
||||
throw new TypeError(
|
||||
`SchnorrSignature.fromHex: expected ${2 * len} bytes, not ${bytes.length}`
|
||||
);
|
||||
const r = bytesToNumberBE(bytes.subarray(0, len));
|
||||
const s = bytesToNumberBE(bytes.subarray(len, 2 * len));
|
||||
return new SchnorrSignature(r, s);
|
||||
}
|
||||
assertValidity() {
|
||||
@@ -1,22 +1,15 @@
|
||||
/*! @noble/curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
||||
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
||||
import { keccak_256 } from '@noble/hashes/sha3';
|
||||
import { sha256 } from '@noble/hashes/sha256';
|
||||
import { hmac } from '@noble/hashes/hmac';
|
||||
import { concatBytes, randomBytes } from '@noble/hashes/utils';
|
||||
import { weierstrass, CHash, JacobianPointType } from '@noble/curves/weierstrass';
|
||||
import * as cutils from '@noble/curves/utils';
|
||||
import { weierstrass, ProjectivePointType } from './abstract/weierstrass.js';
|
||||
import * as cutils from './abstract/utils.js';
|
||||
import { Fp } from './abstract/modular.js';
|
||||
import { getHash } from './_shortw_utils.js';
|
||||
|
||||
type ProjectivePoint = ProjectivePointType<bigint>;
|
||||
// Stark-friendly elliptic curve
|
||||
// https://docs.starkware.co/starkex/stark-curve.html
|
||||
|
||||
function getHash(hash: CHash) {
|
||||
return {
|
||||
hash,
|
||||
hmac: (key: Uint8Array, ...msgs: Uint8Array[]) => hmac(hash, key, concatBytes(...msgs)),
|
||||
randomBytes,
|
||||
};
|
||||
}
|
||||
|
||||
const CURVE_N = BigInt(
|
||||
'3618502788666131213697322783095070105526743751716087489154079457884512865583'
|
||||
);
|
||||
@@ -27,7 +20,7 @@ export const starkCurve = weierstrass({
|
||||
b: BigInt('3141592653589793238462643383279502884197169399375105820974944592307816406665'),
|
||||
// Field over which we'll do calculations; 2n**251n + 17n * 2n**192n + 1n
|
||||
// There is no efficient sqrt for field (P%4==1)
|
||||
P: BigInt('0x800000000000011000000000000000000000000000000000000000000000001'),
|
||||
Fp: Fp(BigInt('0x800000000000011000000000000000000000000000000000000000000000001')),
|
||||
// Curve order, total count of valid points in the field.
|
||||
n: CURVE_N,
|
||||
nBitLength: nBitLength, // len(bin(N).replace('0b',''))
|
||||
@@ -94,23 +87,34 @@ function ensureBytes0x(hex: Hex): Uint8Array {
|
||||
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 normalizePrivateKey(privKey: Hex) {
|
||||
return cutils.bytesToHex(ensureBytes0x(privKey)).padStart(32 * 2, '0');
|
||||
}
|
||||
function getPublicKey0x(privKey: Hex, isCompressed?: boolean) {
|
||||
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, Point, JacobianPoint, Signature, getPublicKey, getSharedSecret } = starkCurve;
|
||||
const { CURVE, Point, ProjectivePoint, Signature } = starkCurve;
|
||||
export const utils = starkCurve.utils;
|
||||
export {
|
||||
CURVE,
|
||||
Point,
|
||||
Signature,
|
||||
JacobianPoint,
|
||||
getPublicKey,
|
||||
getSharedSecret,
|
||||
ProjectivePoint,
|
||||
getPublicKey0x as getPublicKey,
|
||||
getSharedSecret0x as getSharedSecret,
|
||||
sign0x as sign,
|
||||
verify0x as verify,
|
||||
};
|
||||
@@ -134,17 +138,17 @@ function hashKeyWithIndex(key: Uint8Array, index: number) {
|
||||
export function grindKey(seed: Hex) {
|
||||
const _seed = ensureBytes0x(seed);
|
||||
const sha256mask = 2n ** 256n;
|
||||
const limit = sha256mask - starkCurve.utils.mod(sha256mask, starkCurve.CURVE.n);
|
||||
const Fn = Fp(CURVE.n);
|
||||
const limit = sha256mask - Fn.create(sha256mask);
|
||||
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);
|
||||
if (key < limit) return Fn.create(key).toString(16);
|
||||
}
|
||||
}
|
||||
|
||||
export function getStarkKey(privateKey: Hex) {
|
||||
const priv = typeof privateKey === 'string' ? strip0x(privateKey) : privateKey;
|
||||
return bytesToHexEth(Point.fromPrivateKey(priv).toRawBytes(true).slice(1));
|
||||
return bytesToHexEth(getPublicKey0x(privateKey, true).slice(1));
|
||||
}
|
||||
|
||||
export function ethSigToPrivate(signature: string) {
|
||||
@@ -168,7 +172,7 @@ export function getAccountPath(
|
||||
}
|
||||
|
||||
// https://docs.starkware.co/starkex/pedersen-hash-function.html
|
||||
const PEDERSEN_POINTS = [
|
||||
const PEDERSEN_POINTS_AFFINE = [
|
||||
new Point(
|
||||
2089986280348253421170679821480865132823066470938446095505822317253594081284n,
|
||||
1713931329540660377023406109199410414810705867260802078187082345529207694986n
|
||||
@@ -191,15 +195,17 @@ const PEDERSEN_POINTS = [
|
||||
),
|
||||
];
|
||||
// for (const p of PEDERSEN_POINTS) p._setWindowSize(8);
|
||||
const PEDERSEN_POINTS_JACOBIAN = PEDERSEN_POINTS.map(JacobianPoint.fromAffine);
|
||||
const PEDERSEN_POINTS = PEDERSEN_POINTS_AFFINE.map(ProjectivePoint.fromAffine);
|
||||
|
||||
function pedersenPrecompute(p1: JacobianPointType, p2: JacobianPointType): JacobianPointType[] {
|
||||
const out: JacobianPointType[] = [];
|
||||
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);
|
||||
@@ -207,14 +213,8 @@ function pedersenPrecompute(p1: JacobianPointType, p2: JacobianPointType): Jacob
|
||||
}
|
||||
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]
|
||||
);
|
||||
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 {
|
||||
@@ -225,16 +225,12 @@ function pedersenArg(arg: PedersenArg): bigint {
|
||||
value = BigInt(arg);
|
||||
} else value = bytesToNumber0x(ensureBytes0x(arg));
|
||||
// [0..Fp)
|
||||
if (!(0n <= value && value < starkCurve.CURVE.P))
|
||||
if (!(0n <= value && value < starkCurve.CURVE.Fp.ORDER))
|
||||
throw new Error(`PedersenArg should be 0 <= value < CURVE.P: ${value}`);
|
||||
return value;
|
||||
}
|
||||
|
||||
function pedersenSingle(
|
||||
point: JacobianPointType,
|
||||
value: PedersenArg,
|
||||
constants: JacobianPointType[]
|
||||
) {
|
||||
function pedersenSingle(point: ProjectivePoint, value: PedersenArg, constants: ProjectivePoint[]) {
|
||||
let x = pedersenArg(value);
|
||||
for (let j = 0; j < 252; j++) {
|
||||
const pt = constants[j];
|
||||
@@ -247,7 +243,7 @@ function pedersenSingle(
|
||||
|
||||
// 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];
|
||||
let point: ProjectivePoint = PEDERSEN_POINTS[0];
|
||||
point = pedersenSingle(point, x, PEDERSEN_POINTS1);
|
||||
point = pedersenSingle(point, y, PEDERSEN_POINTS2);
|
||||
return bytesToHexEth(point.toAffine().toRawBytes(true).slice(1));
|
||||
1156
src/weierstrass.ts
1156
src/weierstrass.ts
File diff suppressed because it is too large
Load Diff
631
test/basic.test.js
Normal file
631
test/basic.test.js
Normal file
@@ -0,0 +1,631 @@
|
||||
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 } 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.equals(a, b), true);
|
||||
deepStrictEqual(Fp.equals(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.equals(a, b), num1 === num2);
|
||||
deepStrictEqual(Fp.equals(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.negate(a));
|
||||
deepStrictEqual(Fp.sub(a, b), Fp.add(a, Fp.negate(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.negate(a), Fp.sub(Fp.ZERO, a));
|
||||
deepStrictEqual(Fp.negate(a), Fp.mul(a, Fp.create(-1n)));
|
||||
})
|
||||
);
|
||||
});
|
||||
should('negate(0)', () => {
|
||||
deepStrictEqual(Fp.negate(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.square(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.square(Fp.ZERO), Fp.ZERO);
|
||||
deepStrictEqual(Fp.mul(Fp.ZERO, Fp.ZERO), Fp.ZERO);
|
||||
});
|
||||
|
||||
should('square(1)', () => {
|
||||
deepStrictEqual(Fp.square(Fp.ONE), Fp.ONE);
|
||||
deepStrictEqual(Fp.mul(Fp.ONE, Fp.ONE), Fp.ONE);
|
||||
});
|
||||
|
||||
should('square(-1)', () => {
|
||||
const minus1 = Fp.negate(Fp.ONE);
|
||||
deepStrictEqual(Fp.square(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.equals(Fp.square(root), a), true, 'sqrt(a)^2 == a');
|
||||
deepStrictEqual(Fp.equals(Fp.square(Fp.negate(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.equals(sqrt1, Fp.ONE) || Fp.equals(sqrt1, Fp.negate(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.equals(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.invert(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 = 2; i < 10; 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(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('(addition commutativity)', () => {
|
||||
equal(G[4].add(G[3]), G[3].add(G[4]), '4*G + 3*G = 3*G + 4*G');
|
||||
equal(G[4].add(G[3]), G[3].add(G[2]).add(G[2]), '4*G + 3*G = 3*G + 2*G + 2*G');
|
||||
});
|
||||
should('(double)', () => {
|
||||
equal(G[3].double(), G[6], '(3*G).double() = 6*G');
|
||||
});
|
||||
should('(multiply)', () => {
|
||||
equal(G[2].multiply(3), G[6], '(2*G).multiply(3) = 6*G');
|
||||
});
|
||||
should('(same point addition)', () => {
|
||||
equal(G[3].add(G[3]), G[6], '3*G + 3*G = 6*G');
|
||||
});
|
||||
should('(same point (negative) addition)', () => {
|
||||
equal(G[3].add(G[3].negate()), G[0], '3*G + (- 3*G) = 0*G');
|
||||
equal(G[3].subtract(G[3]), G[0], '3*G - 3*G = 0*G');
|
||||
});
|
||||
should('(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](123.456), '123.456');
|
||||
throws(() => G[1][op](true), 'true');
|
||||
throws(() => G[1][op]('1'), "'1'");
|
||||
throws(
|
||||
() => G[1][op]({ x: 1n, y: 1n, z: 1n, t: 1n }),
|
||||
'{ x: 1n, y: 1n, z: 1n, t: 1n }'
|
||||
);
|
||||
throws(() => G[1][op](new Uint8Array([])), 'ui8a([])');
|
||||
throws(() => G[1][op](new Uint8Array([0])), 'ui8a([0])');
|
||||
throws(() => G[1][op](new Uint8Array([1])), 'ui8a([1])');
|
||||
throws(() => G[1][op](new Uint8Array(4096).fill(1)), 'ui8a(4096*[1])');
|
||||
if (G[1].toAffine) throws(() => G[1][op](C.Point.BASE), 'Point ${op} ${pointName}');
|
||||
throws(() => G[1][op](o.BASE), '${op}/other curve point');
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
should('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) {
|
||||
should('toAffine()', () => {
|
||||
equal(p.ZERO.toAffine(), C.Point.ZERO, '0 = 0');
|
||||
equal(p.BASE.toAffine(), C.Point.BASE, '1 = 1');
|
||||
});
|
||||
}
|
||||
if (p.fromAffine) {
|
||||
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(false), 'false');
|
||||
throws(() => C.getPublicKey(123.456), '123.456');
|
||||
throws(() => C.getPublicKey(true), 'true');
|
||||
throws(() => C.getPublicKey(''), "''");
|
||||
// NOTE: passes because of disabled hex padding checks for starknet, maybe enable?
|
||||
//throws(() => C.getPublicKey('1'), "'1'");
|
||||
throws(() => C.getPublicKey('key'), "'key'");
|
||||
throws(() => C.getPublicKey(new Uint8Array([])));
|
||||
throws(() => C.getPublicKey(new Uint8Array([0])));
|
||||
throws(() => C.getPublicKey(new Uint8Array([1])));
|
||||
throws(() => C.getPublicKey(new Uint8Array(4096).fill(1)));
|
||||
});
|
||||
should('.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('.sign() edge cases', () => {
|
||||
throws(() => C.sign());
|
||||
throws(() => C.sign(''));
|
||||
});
|
||||
|
||||
should('.verify() should not verify signature with wrong hash', () => {
|
||||
const MSG = '01'.repeat(32);
|
||||
const PRIV_KEY = 0x2n;
|
||||
const WRONG_MSG = '11'.repeat(32);
|
||||
const signature = C.sign(MSG, PRIV_KEY);
|
||||
const publicKey = C.getPublicKey(PRIV_KEY);
|
||||
deepStrictEqual(C.verify(signature, WRONG_MSG, publicKey), false);
|
||||
});
|
||||
// NOTE: fails for ed, because of empty message. Since we convert it to scalar,
|
||||
// need to check what other implementations do. Empty message != new Uint8Array([0]), but what scalar should be in that case?
|
||||
// should('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.negate(sqrtMinus1),
|
||||
3338362603553219996874421406887633712040719456283732096017030791656n
|
||||
);
|
||||
deepStrictEqual(Fp.square(sqrtMinus1), Fp.create(-1n));
|
||||
});
|
||||
|
||||
// ESM is broken.
|
||||
import url from 'url';
|
||||
if (import.meta.url === url.pathToFileURL(process.argv[1]).href) {
|
||||
should.run();
|
||||
}
|
||||
1946
test/bls12-381.test.js
Normal file
1946
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.
680
test/ed25519.test.js
Normal file
680
test/ed25519.test.js
Normal file
@@ -0,0 +1,680 @@
|
||||
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;
|
||||
|
||||
function to32Bytes(numOrStr) {
|
||||
let hex = typeof numOrStr === 'string' ? numOrStr : numOrStr.toString(16);
|
||||
return hexToBytes(hex.padStart(64, '0'));
|
||||
}
|
||||
|
||||
function utf8ToBytes(str) {
|
||||
if (typeof str !== 'string') {
|
||||
throw new TypeError(`utf8ToBytes expected string, got ${typeof str}`);
|
||||
}
|
||||
return new TextEncoder().encode(str);
|
||||
}
|
||||
|
||||
ed.utils.precompute(8);
|
||||
|
||||
should('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 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(12);
|
||||
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(12);
|
||||
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);
|
||||
});
|
||||
});
|
||||
// https://xmr.llcoins.net/addresstests.html
|
||||
should(
|
||||
'ed25519/BASE_POINT.multiply()/should create right publicKey without SHA-512 hashing TEST 1',
|
||||
() => {
|
||||
const publicKey =
|
||||
ed.Point.BASE.multiply(0x90af56259a4b6bfbc4337980d5d75fbe3c074630368ff3804d33028e5dbfa77n);
|
||||
deepStrictEqual(
|
||||
publicKey.toHex(),
|
||||
'0f3b913371411b27e646b537e888f685bf929ea7aab93c950ed84433f064480d'
|
||||
);
|
||||
}
|
||||
);
|
||||
should(
|
||||
'ed25519/BASE_POINT.multiply()/should create right publicKey without SHA-512 hashing TEST 2',
|
||||
() => {
|
||||
const publicKey =
|
||||
ed.Point.BASE.multiply(0x364e8711a60780382a5d57b061c126f039940f28a9e91fe039d4d3094d8b88n);
|
||||
deepStrictEqual(
|
||||
publicKey.toHex(),
|
||||
'ad545340b58610f0cd62f17d55af1ab11ecde9c084d5476865ddb4dbda015349'
|
||||
);
|
||||
}
|
||||
);
|
||||
should(
|
||||
'ed25519/BASE_POINT.multiply()/should create right publicKey without SHA-512 hashing TEST 3',
|
||||
() => {
|
||||
const publicKey =
|
||||
ed.Point.BASE.multiply(0xb9bf90ff3abec042752cac3a07a62f0c16cfb9d32a3fc2305d676ec2d86e941n);
|
||||
deepStrictEqual(
|
||||
publicKey.toHex(),
|
||||
'e097c4415fe85724d522b2e449e8fd78dd40d20097bdc9ae36fe8ec6fe12cb8c'
|
||||
);
|
||||
}
|
||||
);
|
||||
should(
|
||||
'ed25519/BASE_POINT.multiply()/should create right publicKey without SHA-512 hashing TEST 4',
|
||||
() => {
|
||||
const publicKey =
|
||||
ed.Point.BASE.multiply(0x69d896f02d79524c9878e080308180e2859d07f9f54454e0800e8db0847a46en);
|
||||
deepStrictEqual(
|
||||
publicKey.toHex(),
|
||||
'f12cb7c43b59971395926f278ce7c2eaded9444fbce62ca717564cb508a0db1d'
|
||||
);
|
||||
}
|
||||
);
|
||||
should('ed25519/BASE_POINT.multiply()/should throw Point#multiply on TEST 5', () => {
|
||||
for (const num of [0n, 0, -1n, -1, 1.1]) {
|
||||
throws(() => ed.Point.BASE.multiply(num));
|
||||
}
|
||||
});
|
||||
|
||||
// https://ed25519.cr.yp.to/python/sign.py
|
||||
// https://ed25519.cr.yp.to/python/sign.input
|
||||
const data = readFileSync('./test/ed25519/vectors.txt', 'utf-8');
|
||||
const vectors = data
|
||||
.trim()
|
||||
.split('\n')
|
||||
.map((line) => line.split(':'));
|
||||
should('ed25519 official vectors/should match 1024 official vectors', () => {
|
||||
for (let i = 0; i < vectors.length; i++) {
|
||||
const vector = vectors[i];
|
||||
// Extract.
|
||||
const priv = vector[0].slice(0, 64);
|
||||
const expectedPub = vector[1];
|
||||
const msg = vector[2];
|
||||
const expectedSignature = vector[3].slice(0, 128);
|
||||
|
||||
// Calculate
|
||||
const pub = ed.getPublicKey(to32Bytes(priv));
|
||||
deepStrictEqual(hex(pub), expectedPub);
|
||||
deepStrictEqual(pub, ed.Point.fromHex(pub).toRawBytes());
|
||||
|
||||
const signature = hex(ed.sign(msg, priv));
|
||||
// console.log('vector', i);
|
||||
// expect(pub).toBe(expectedPub);
|
||||
deepStrictEqual(signature, expectedSignature);
|
||||
}
|
||||
});
|
||||
|
||||
// https://tools.ietf.org/html/rfc8032#section-7
|
||||
should('rfc8032 vectors/should create right signature for 0x9d and empty string', () => {
|
||||
const privateKey = '9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60';
|
||||
const publicKey = ed.getPublicKey(privateKey);
|
||||
const message = '';
|
||||
const signature = ed.sign(message, privateKey);
|
||||
deepStrictEqual(
|
||||
hex(publicKey),
|
||||
'd75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a'
|
||||
);
|
||||
deepStrictEqual(
|
||||
hex(signature),
|
||||
'e5564300c360ac729086e2cc806e828a84877f1eb8e5d974d873e065224901555fb8821590a33bacc61e39701cf9b46bd25bf5f0595bbe24655141438e7a100b'
|
||||
);
|
||||
});
|
||||
should('rfc8032 vectors/should create right signature for 0x4c and 72', () => {
|
||||
const privateKey = '4ccd089b28ff96da9db6c346ec114e0f5b8a319f35aba624da8cf6ed4fb8a6fb';
|
||||
const publicKey = ed.getPublicKey(privateKey);
|
||||
const message = '72';
|
||||
const signature = ed.sign(message, privateKey);
|
||||
deepStrictEqual(
|
||||
hex(publicKey),
|
||||
'3d4017c3e843895a92b70aa74d1b7ebc9c982ccf2ec4968cc0cd55f12af4660c'
|
||||
);
|
||||
deepStrictEqual(
|
||||
hex(signature),
|
||||
'92a009a9f0d4cab8720e820b5f642540a2b27b5416503f8fb3762223ebdb69da085ac1e43e15996e458f3613d0f11d8c387b2eaeb4302aeeb00d291612bb0c00'
|
||||
);
|
||||
});
|
||||
should('rfc8032 vectors/should create right signature for 0x00 and 5a', () => {
|
||||
const privateKey = '002fdd1f7641793ab064bb7aa848f762e7ec6e332ffc26eeacda141ae33b1783';
|
||||
const publicKey = ed.getPublicKey(privateKey);
|
||||
const message =
|
||||
'5ac1dfc324f43e6cb79a87ab0470fa857b51fb944982e19074ca44b1e40082c1d07b92efa7ea55ad42b7c027e0b9e33756d95a2c1796a7c2066811dc41858377d4b835c1688d638884cd2ad8970b74c1a54aadd27064163928a77988b24403aa85af82ceab6b728e554761af7175aeb99215b7421e4474c04d213e01ff03e3529b11077cdf28964b8c49c5649e3a46fa0a09dcd59dcad58b9b922a83210acd5e65065531400234f5e40cddcf9804968e3e9ac6f5c44af65001e158067fc3a660502d13fa8874fa93332138d9606bc41b4cee7edc39d753dae12a873941bb357f7e92a4498847d6605456cb8c0b425a47d7d3ca37e54e903a41e6450a35ebe5237c6f0c1bbbc1fd71fb7cd893d189850295c199b7d88af26bc8548975fda1099ffefee42a52f3428ddff35e0173d3339562507ac5d2c45bbd2c19cfe89b';
|
||||
const signature = ed.sign(message, privateKey);
|
||||
deepStrictEqual(
|
||||
hex(publicKey),
|
||||
'77d1d8ebacd13f4e2f8a40e28c4a63bc9ce3bfb69716334bcb28a33eb134086c'
|
||||
);
|
||||
deepStrictEqual(
|
||||
hex(signature),
|
||||
'0df3aa0d0999ad3dc580378f52d152700d5b3b057f56a66f92112e441e1cb9123c66f18712c87efe22d2573777296241216904d7cdd7d5ea433928bd2872fa0c'
|
||||
);
|
||||
});
|
||||
should('rfc8032 vectors/should create right signature for 0xf5 and long msg', () => {
|
||||
const privateKey = 'f5e5767cf153319517630f226876b86c8160cc583bc013744c6bf255f5cc0ee5';
|
||||
const publicKey = ed.getPublicKey(privateKey);
|
||||
const message =
|
||||
'08b8b2b733424243760fe426a4b54908632110a66c2f6591eabd3345e3e4eb98fa6e264bf09efe12ee50f8f54e9f77b1e355f6c50544e23fb1433ddf73be84d879de7c0046dc4996d9e773f4bc9efe5738829adb26c81b37c93a1b270b20329d658675fc6ea534e0810a4432826bf58c941efb65d57a338bbd2e26640f89ffbc1a858efcb8550ee3a5e1998bd177e93a7363c344fe6b199ee5d02e82d522c4feba15452f80288a821a579116ec6dad2b3b310da903401aa62100ab5d1a36553e06203b33890cc9b832f79ef80560ccb9a39ce767967ed628c6ad573cb116dbefefd75499da96bd68a8a97b928a8bbc103b6621fcde2beca1231d206be6cd9ec7aff6f6c94fcd7204ed3455c68c83f4a41da4af2b74ef5c53f1d8ac70bdcb7ed185ce81bd84359d44254d95629e9855a94a7c1958d1f8ada5d0532ed8a5aa3fb2d17ba70eb6248e594e1a2297acbbb39d502f1a8c6eb6f1ce22b3de1a1f40cc24554119a831a9aad6079cad88425de6bde1a9187ebb6092cf67bf2b13fd65f27088d78b7e883c8759d2c4f5c65adb7553878ad575f9fad878e80a0c9ba63bcbcc2732e69485bbc9c90bfbd62481d9089beccf80cfe2df16a2cf65bd92dd597b0707e0917af48bbb75fed413d238f5555a7a569d80c3414a8d0859dc65a46128bab27af87a71314f318c782b23ebfe808b82b0ce26401d2e22f04d83d1255dc51addd3b75a2b1ae0784504df543af8969be3ea7082ff7fc9888c144da2af58429ec96031dbcad3dad9af0dcbaaaf268cb8fcffead94f3c7ca495e056a9b47acdb751fb73e666c6c655ade8297297d07ad1ba5e43f1bca32301651339e22904cc8c42f58c30c04aafdb038dda0847dd988dcda6f3bfd15c4b4c4525004aa06eeff8ca61783aacec57fb3d1f92b0fe2fd1a85f6724517b65e614ad6808d6f6ee34dff7310fdc82aebfd904b01e1dc54b2927094b2db68d6f903b68401adebf5a7e08d78ff4ef5d63653a65040cf9bfd4aca7984a74d37145986780fc0b16ac451649de6188a7dbdf191f64b5fc5e2ab47b57f7f7276cd419c17a3ca8e1b939ae49e488acba6b965610b5480109c8b17b80e1b7b750dfc7598d5d5011fd2dcc5600a32ef5b52a1ecc820e308aa342721aac0943bf6686b64b2579376504ccc493d97e6aed3fb0f9cd71a43dd497f01f17c0e2cb3797aa2a2f256656168e6c496afc5fb93246f6b1116398a346f1a641f3b041e989f7914f90cc2c7fff357876e506b50d334ba77c225bc307ba537152f3f1610e4eafe595f6d9d90d11faa933a15ef1369546868a7f3a45a96768d40fd9d03412c091c6315cf4fde7cb68606937380db2eaaa707b4c4185c32eddcdd306705e4dc1ffc872eeee475a64dfac86aba41c0618983f8741c5ef68d3a101e8a3b8cac60c905c15fc910840b94c00a0b9d0';
|
||||
const signature = ed.sign(message, privateKey);
|
||||
deepStrictEqual(
|
||||
hex(publicKey),
|
||||
'278117fc144c72340f67d0f2316e8386ceffbf2b2428c9c51fef7c597f1d426e'
|
||||
);
|
||||
deepStrictEqual(
|
||||
hex(signature),
|
||||
'0aab4c900501b3e24d7cdf4663326a3a87df5e4843b2cbdb67cbf6e460fec350aa5371b1508f9f4528ecea23c436d94b5e8fcd4f681e30a6ac00a9704a188a03'
|
||||
);
|
||||
});
|
||||
|
||||
// const PRIVATE_KEY = 0xa665a45920422f9d417e4867efn;
|
||||
// const MESSAGE = ripemd160(new Uint8Array([97, 98, 99, 100, 101, 102, 103]));
|
||||
// prettier-ignore
|
||||
// const MESSAGE = new Uint8Array([
|
||||
// 135, 79, 153, 96, 197, 210, 183, 169, 181, 250, 211, 131, 225, 186, 68, 113, 158, 187, 116, 58,
|
||||
// ]);
|
||||
// const WRONG_MESSAGE = ripemd160(new Uint8Array([98, 99, 100, 101, 102, 103]));
|
||||
// prettier-ignore
|
||||
// const WRONG_MESSAGE = new Uint8Array([
|
||||
// 88, 157, 140, 127, 29, 160, 162, 75, 192, 123, 115, 129, 173, 72, 177, 207, 194, 17, 175, 28,
|
||||
// ]);
|
||||
// // it("should verify just signed message", async () => {
|
||||
// // await fc.assert(fc.asyncProperty(
|
||||
// // fc.hexa(),
|
||||
// // fc.bigInt(2n, ristretto25519.PRIME_ORDER),
|
||||
// // async (message, privateKey) => {
|
||||
// // const publicKey = await ristretto25519.getPublicKey(privateKey);
|
||||
// // const signature = await ristretto25519.sign(message, privateKey);
|
||||
// // expect(publicKey.length).toBe(32);
|
||||
// // expect(signature.length).toBe(64);
|
||||
// // expect(await ristretto25519.verify(signature, message, publicKey)).toBe(true);
|
||||
// // }),
|
||||
// // { numRuns: 1 }
|
||||
// // );
|
||||
// // });
|
||||
// // it("should not verify sign with wrong message", async () => {
|
||||
// // await fc.assert(fc.asyncProperty(
|
||||
// // fc.array(fc.integer(0x00, 0xff)),
|
||||
// // fc.array(fc.integer(0x00, 0xff)),
|
||||
// // fc.bigInt(2n, ristretto25519.PRIME_ORDER),
|
||||
// // async (bytes, wrongBytes, privateKey) => {
|
||||
// // const message = new Uint8Array(bytes);
|
||||
// // const wrongMessage = new Uint8Array(wrongBytes);
|
||||
// // const publicKey = await ristretto25519.getPublicKey(privateKey);
|
||||
// // const signature = await ristretto25519.sign(message, privateKey);
|
||||
// // expect(await ristretto25519.verify(signature, wrongMessage, publicKey)).toBe(
|
||||
// // bytes.toString() === wrongBytes.toString()
|
||||
// // );
|
||||
// // }),
|
||||
// // { numRuns: 1 }
|
||||
// // );
|
||||
// // });
|
||||
// // it("should sign and verify", async () => {
|
||||
// // const publicKey = await ristretto25519.getPublicKey(PRIVATE_KEY);
|
||||
// // const signature = await ristretto25519.sign(MESSAGE, PRIVATE_KEY);
|
||||
// // expect(await ristretto25519.verify(signature, MESSAGE, publicKey)).toBe(true);
|
||||
// // });
|
||||
// // it("should not verify signature with wrong public key", async () => {
|
||||
// // const publicKey = await ristretto25519.getPublicKey(12);
|
||||
// // const signature = await ristretto25519.sign(MESSAGE, PRIVATE_KEY);
|
||||
// // expect(await ristretto25519.verify(signature, MESSAGE, publicKey)).toBe(false);
|
||||
// // });
|
||||
// // it("should not verify signature with wrong hash", async () => {
|
||||
// // const publicKey = await ristretto25519.getPublicKey(PRIVATE_KEY);
|
||||
// // const signature = await ristretto25519.sign(MESSAGE, PRIVATE_KEY);
|
||||
// // expect(await ristretto25519.verify(signature, WRONG_MESSAGE, publicKey)).toBe(false);
|
||||
// // });
|
||||
should('ristretto255/should follow the byte encodings of small multiples', () => {
|
||||
const encodingsOfSmallMultiples = [
|
||||
// This is the identity point
|
||||
'0000000000000000000000000000000000000000000000000000000000000000',
|
||||
// This is the basepoint
|
||||
'e2f2ae0a6abc4e71a884a961c500515f58e30b6aa582dd8db6a65945e08d2d76',
|
||||
// These are small multiples of the basepoint
|
||||
'6a493210f7499cd17fecb510ae0cea23a110e8d5b901f8acadd3095c73a3b919',
|
||||
'94741f5d5d52755ece4f23f044ee27d5d1ea1e2bd196b462166b16152a9d0259',
|
||||
'da80862773358b466ffadfe0b3293ab3d9fd53c5ea6c955358f568322daf6a57',
|
||||
'e882b131016b52c1d3337080187cf768423efccbb517bb495ab812c4160ff44e',
|
||||
'f64746d3c92b13050ed8d80236a7f0007c3b3f962f5ba793d19a601ebb1df403',
|
||||
'44f53520926ec81fbd5a387845beb7df85a96a24ece18738bdcfa6a7822a176d',
|
||||
'903293d8f2287ebe10e2374dc1a53e0bc887e592699f02d077d5263cdd55601c',
|
||||
'02622ace8f7303a31cafc63f8fc48fdc16e1c8c8d234b2f0d6685282a9076031',
|
||||
'20706fd788b2720a1ed2a5dad4952b01f413bcf0e7564de8cdc816689e2db95f',
|
||||
'bce83f8ba5dd2fa572864c24ba1810f9522bc6004afe95877ac73241cafdab42',
|
||||
'e4549ee16b9aa03099ca208c67adafcafa4c3f3e4e5303de6026e3ca8ff84460',
|
||||
'aa52e000df2e16f55fb1032fc33bc42742dad6bd5a8fc0be0167436c5948501f',
|
||||
'46376b80f409b29dc2b5f6f0c52591990896e5716f41477cd30085ab7f10301e',
|
||||
'e0c418f7c8d9c4cdd7395b93ea124f3ad99021bb681dfc3302a9d99a2e53e64e',
|
||||
];
|
||||
let B = RistrettoPoint.BASE;
|
||||
let P = RistrettoPoint.ZERO;
|
||||
for (const encoded of encodingsOfSmallMultiples) {
|
||||
deepStrictEqual(P.toHex(), encoded);
|
||||
deepStrictEqual(RistrettoPoint.fromHex(encoded).toHex(), encoded);
|
||||
P = P.add(B);
|
||||
}
|
||||
});
|
||||
should('ristretto255/should not convert bad bytes encoding', () => {
|
||||
const badEncodings = [
|
||||
// These are all bad because they're non-canonical field encodings.
|
||||
'00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff',
|
||||
'ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f',
|
||||
'f3ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f',
|
||||
'edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f',
|
||||
// These are all bad because they're negative field elements.
|
||||
'0100000000000000000000000000000000000000000000000000000000000000',
|
||||
'01ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f',
|
||||
'ed57ffd8c914fb201471d1c3d245ce3c746fcbe63a3679d51b6a516ebebe0e20',
|
||||
'c34c4e1826e5d403b78e246e88aa051c36ccf0aafebffe137d148a2bf9104562',
|
||||
'c940e5a4404157cfb1628b108db051a8d439e1a421394ec4ebccb9ec92a8ac78',
|
||||
'47cfc5497c53dc8e61c91d17fd626ffb1c49e2bca94eed052281b510b1117a24',
|
||||
'f1c6165d33367351b0da8f6e4511010c68174a03b6581212c71c0e1d026c3c72',
|
||||
'87260f7a2f12495118360f02c26a470f450dadf34a413d21042b43b9d93e1309',
|
||||
// These are all bad because they give a nonsquare x².
|
||||
'26948d35ca62e643e26a83177332e6b6afeb9d08e4268b650f1f5bbd8d81d371',
|
||||
'4eac077a713c57b4f4397629a4145982c661f48044dd3f96427d40b147d9742f',
|
||||
'de6a7b00deadc788eb6b6c8d20c0ae96c2f2019078fa604fee5b87d6e989ad7b',
|
||||
'bcab477be20861e01e4a0e295284146a510150d9817763caf1a6f4b422d67042',
|
||||
'2a292df7e32cababbd9de088d1d1abec9fc0440f637ed2fba145094dc14bea08',
|
||||
'f4a9e534fc0d216c44b218fa0c42d99635a0127ee2e53c712f70609649fdff22',
|
||||
'8268436f8c4126196cf64b3c7ddbda90746a378625f9813dd9b8457077256731',
|
||||
'2810e5cbc2cc4d4eece54f61c6f69758e289aa7ab440b3cbeaa21995c2f4232b',
|
||||
// These are all bad because they give a negative xy value.
|
||||
'3eb858e78f5a7254d8c9731174a94f76755fd3941c0ac93735c07ba14579630e',
|
||||
'a45fdc55c76448c049a1ab33f17023edfb2be3581e9c7aade8a6125215e04220',
|
||||
'd483fe813c6ba647ebbfd3ec41adca1c6130c2beeee9d9bf065c8d151c5f396e',
|
||||
'8a2e1d30050198c65a54483123960ccc38aef6848e1ec8f5f780e8523769ba32',
|
||||
'32888462f8b486c68ad7dd9610be5192bbeaf3b443951ac1a8118419d9fa097b',
|
||||
'227142501b9d4355ccba290404bde41575b037693cef1f438c47f8fbf35d1165',
|
||||
'5c37cc491da847cfeb9281d407efc41e15144c876e0170b499a96a22ed31e01e',
|
||||
'445425117cb8c90edcbc7c1cc0e74f747f2c1efa5630a967c64f287792a48a4b',
|
||||
// This is s = -1, which causes y = 0.
|
||||
'ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f',
|
||||
];
|
||||
for (const badBytes of badEncodings) {
|
||||
const b = hexToBytes(badBytes);
|
||||
throws(() => RistrettoPoint.fromHex(b), badBytes);
|
||||
}
|
||||
});
|
||||
should('ristretto255/should create right points from uniform hash', async () => {
|
||||
const labels = [
|
||||
'Ristretto is traditionally a short shot of espresso coffee',
|
||||
'made with the normal amount of ground coffee but extracted with',
|
||||
'about half the amount of water in the same amount of time',
|
||||
'by using a finer grind.',
|
||||
'This produces a concentrated shot of coffee per volume.',
|
||||
'Just pulling a normal shot short will produce a weaker shot',
|
||||
'and is not a Ristretto as some believe.',
|
||||
];
|
||||
const encodedHashToPoints = [
|
||||
'3066f82a1a747d45120d1740f14358531a8f04bbffe6a819f86dfe50f44a0a46',
|
||||
'f26e5b6f7d362d2d2a94c5d0e7602cb4773c95a2e5c31a64f133189fa76ed61b',
|
||||
'006ccd2a9e6867e6a2c5cea83d3302cc9de128dd2a9a57dd8ee7b9d7ffe02826',
|
||||
'f8f0c87cf237953c5890aec3998169005dae3eca1fbb04548c635953c817f92a',
|
||||
'ae81e7dedf20a497e10c304a765c1767a42d6e06029758d2d7e8ef7cc4c41179',
|
||||
'e2705652ff9f5e44d3e841bf1c251cf7dddb77d140870d1ab2ed64f1a9ce8628',
|
||||
'80bd07262511cdde4863f8a7434cef696750681cb9510eea557088f76d9e5065',
|
||||
];
|
||||
|
||||
for (let i = 0; i < labels.length; i++) {
|
||||
const hash = sha512(utf8ToBytes(labels[i]));
|
||||
const point = RistrettoPoint.hashToCurve(hash);
|
||||
deepStrictEqual(point.toHex(), encodedHashToPoints[i]);
|
||||
}
|
||||
});
|
||||
|
||||
should('input immutability: sign/verify are immutable', () => {
|
||||
const privateKey = ed.utils.randomPrivateKey();
|
||||
const publicKey = ed.getPublicKey(privateKey);
|
||||
|
||||
for (let i = 0; i < 100; i++) {
|
||||
let payload = randomBytes(100);
|
||||
let signature = ed.sign(payload, privateKey);
|
||||
if (!ed.verify(signature, payload, publicKey)) {
|
||||
throw new Error('Signature verification failed');
|
||||
}
|
||||
const signatureCopy = Buffer.alloc(signature.byteLength);
|
||||
signatureCopy.set(signature, 0); // <-- breaks
|
||||
payload = payload.slice();
|
||||
signature = signature.slice();
|
||||
|
||||
if (!ed.verify(signatureCopy, payload, publicKey))
|
||||
throw new Error('Copied signature verification failed');
|
||||
}
|
||||
});
|
||||
|
||||
// https://zips.z.cash/zip-0215
|
||||
// Vectors from https://gist.github.com/hdevalence/93ed42d17ecab8e42138b213812c8cc7
|
||||
should('ZIP-215 compliance tests/should pass all of them', () => {
|
||||
const str = utf8ToBytes('Zcash');
|
||||
for (let v of zip215) {
|
||||
let noble = false;
|
||||
try {
|
||||
noble = ed.verify(v.sig_bytes, str, v.vk_bytes);
|
||||
} catch (e) {
|
||||
noble = false;
|
||||
}
|
||||
deepStrictEqual(noble, v.valid_zip215);
|
||||
}
|
||||
});
|
||||
should('ZIP-215 compliance tests/disallows sig.s >= CURVE.n', () => {
|
||||
const sig = new ed.Signature(ed.Point.BASE, 1n);
|
||||
sig.s = ed.CURVE.n + 1n;
|
||||
throws(() => ed.verify(sig, 'deadbeef', ed.Point.BASE));
|
||||
});
|
||||
|
||||
const rfc7748Mul = [
|
||||
{
|
||||
scalar: 'a546e36bf0527c9d3b16154b82465edd62144c0ac1fc5a18506a2244ba449ac4',
|
||||
u: 'e6db6867583030db3594c1a424b15f7c726624ec26b3353b10a903a6d0ab1c4c',
|
||||
outputU: 'c3da55379de9c6908e94ea4df28d084f32eccf03491c71f754b4075577a28552',
|
||||
},
|
||||
{
|
||||
scalar: '4b66e9d4d1b4673c5ad22691957d6af5c11b6421e0ea01d42ca4169e7918ba0d',
|
||||
u: 'e5210f12786811d3f4b7959d0538ae2c31dbe7106fc03c3efc4cd549c715a493',
|
||||
outputU: '95cbde9476e8907d7aade45cb4b873f88b595a68799fa152e6f8f7647aac7957',
|
||||
},
|
||||
];
|
||||
for (let i = 0; i < rfc7748Mul.length; i++) {
|
||||
const v = rfc7748Mul[i];
|
||||
should(`RFC7748: scalarMult (${i})`, () => {
|
||||
deepStrictEqual(hex(x25519.scalarMult(v.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(ed.Point.BASE)),
|
||||
// ed.montgomeryCurve.BASE_POINT_U
|
||||
// );
|
||||
// });
|
||||
|
||||
{
|
||||
const group = x25519vectors.testGroups[0];
|
||||
should(`Wycheproof/X25519`, () => {
|
||||
for (let i = 0; i < group.tests.length; i++) {
|
||||
const v = group.tests[i];
|
||||
const comment = `(${i}, ${v.result}) ${v.comment}`;
|
||||
if (v.result === 'valid' || v.result === 'acceptable') {
|
||||
try {
|
||||
const shared = hex(x25519.scalarMult(v.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.Point.BASE;
|
||||
const { Fp } = ed25519.CURVE;
|
||||
const u = Fp.create((y + 1n) * Fp.invert(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(ed.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}`);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// ESM is broken.
|
||||
import url from 'url';
|
||||
if (import.meta.url === url.pathToFileURL(process.argv[1]).href) {
|
||||
should.run();
|
||||
}
|
||||
671
test/ed448.test.js
Normal file
671
test/ed448.test.js
Normal file
@@ -0,0 +1,671 @@
|
||||
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);
|
||||
|
||||
should(`Basic`, () => {
|
||||
const G1 = ed.Point.BASE;
|
||||
deepStrictEqual(
|
||||
G1.x,
|
||||
224580040295924300187604334099896036246789641632564134246125461686950415467406032909029192869357953282578032075146446173674602635247710n
|
||||
);
|
||||
deepStrictEqual(
|
||||
G1.y,
|
||||
298819210078481492676017930443930673437544040154080242095928241372331506189835876003536878655418784733982303233503462500531545062832660n
|
||||
);
|
||||
const G2 = ed.Point.BASE.multiply(2n);
|
||||
deepStrictEqual(
|
||||
G2.x,
|
||||
484559149530404593699549205258669689569094240458212040187660132787056912146709081364401144455726350866276831544947397859048262938744149n
|
||||
);
|
||||
deepStrictEqual(
|
||||
G2.y,
|
||||
494088759867433727674302672526735089350544552303727723746126484473087719117037293890093462157703888342865036477787453078312060500281069n
|
||||
);
|
||||
const G3 = ed.Point.BASE.multiply(3n);
|
||||
deepStrictEqual(
|
||||
G3.x,
|
||||
23839778817283171003887799738662344287085130522697782688245073320169861206004018274567429238677677920280078599146891901463786155880335n
|
||||
);
|
||||
deepStrictEqual(
|
||||
G3.y,
|
||||
636046652612779686502873775776967954190574036985351036782021535703553242737829645273154208057988851307101009474686328623630835377952508n
|
||||
);
|
||||
});
|
||||
|
||||
should('Basic/decompress', () => {
|
||||
const G1 = ed.Point.BASE;
|
||||
const G2 = ed.Point.BASE.multiply(2n);
|
||||
const G3 = ed.Point.BASE.multiply(3n);
|
||||
const points = [G1, G2, G3];
|
||||
const getXY = (p) => ({ x: p.x, y: p.y });
|
||||
for (const p of points) deepStrictEqual(getXY(ed.Point.fromHex(p.toHex())), getXY(p));
|
||||
});
|
||||
|
||||
const VECTORS_RFC8032 = [
|
||||
{
|
||||
secretKey:
|
||||
'6c82a562cb808d10d632be89c8513ebf' +
|
||||
'6c929f34ddfa8c9f63c9960ef6e348a3' +
|
||||
'528c8a3fcc2f044e39a3fc5b94492f8f' +
|
||||
'032e7549a20098f95b',
|
||||
publicKey:
|
||||
'5fd7449b59b461fd2ce787ec616ad46a' +
|
||||
'1da1342485a70e1f8a0ea75d80e96778' +
|
||||
'edf124769b46c7061bd6783df1e50f6c' +
|
||||
'd1fa1abeafe8256180',
|
||||
message: '',
|
||||
signature:
|
||||
'533a37f6bbe457251f023c0d88f976ae' +
|
||||
'2dfb504a843e34d2074fd823d41a591f' +
|
||||
'2b233f034f628281f2fd7a22ddd47d78' +
|
||||
'28c59bd0a21bfd3980ff0d2028d4b18a' +
|
||||
'9df63e006c5d1c2d345b925d8dc00b41' +
|
||||
'04852db99ac5c7cdda8530a113a0f4db' +
|
||||
'b61149f05a7363268c71d95808ff2e65' +
|
||||
'2600',
|
||||
},
|
||||
{
|
||||
secretKey:
|
||||
'c4eab05d357007c632f3dbb48489924d' +
|
||||
'552b08fe0c353a0d4a1f00acda2c463a' +
|
||||
'fbea67c5e8d2877c5e3bc397a659949e' +
|
||||
'f8021e954e0a12274e',
|
||||
publicKey:
|
||||
'43ba28f430cdff456ae531545f7ecd0a' +
|
||||
'c834a55d9358c0372bfa0c6c6798c086' +
|
||||
'6aea01eb00742802b8438ea4cb82169c' +
|
||||
'235160627b4c3a9480',
|
||||
|
||||
message: '03',
|
||||
signature:
|
||||
'26b8f91727bd62897af15e41eb43c377' +
|
||||
'efb9c610d48f2335cb0bd0087810f435' +
|
||||
'2541b143c4b981b7e18f62de8ccdf633' +
|
||||
'fc1bf037ab7cd779805e0dbcc0aae1cb' +
|
||||
'cee1afb2e027df36bc04dcecbf154336' +
|
||||
'c19f0af7e0a6472905e799f1953d2a0f' +
|
||||
'f3348ab21aa4adafd1d234441cf807c0' +
|
||||
'3a00',
|
||||
},
|
||||
{
|
||||
secretKey:
|
||||
'cd23d24f714274e744343237b93290f5' +
|
||||
'11f6425f98e64459ff203e8985083ffd' +
|
||||
'f60500553abc0e05cd02184bdb89c4cc' +
|
||||
'd67e187951267eb328',
|
||||
publicKey:
|
||||
'dcea9e78f35a1bf3499a831b10b86c90' +
|
||||
'aac01cd84b67a0109b55a36e9328b1e3' +
|
||||
'65fce161d71ce7131a543ea4cb5f7e9f' +
|
||||
'1d8b00696447001400',
|
||||
message: '0c3e544074ec63b0265e0c',
|
||||
signature:
|
||||
'1f0a8888ce25e8d458a21130879b840a' +
|
||||
'9089d999aaba039eaf3e3afa090a09d3' +
|
||||
'89dba82c4ff2ae8ac5cdfb7c55e94d5d' +
|
||||
'961a29fe0109941e00b8dbdeea6d3b05' +
|
||||
'1068df7254c0cdc129cbe62db2dc957d' +
|
||||
'bb47b51fd3f213fb8698f064774250a5' +
|
||||
'028961c9bf8ffd973fe5d5c206492b14' +
|
||||
'0e00',
|
||||
},
|
||||
{
|
||||
secretKey:
|
||||
'258cdd4ada32ed9c9ff54e63756ae582' +
|
||||
'fb8fab2ac721f2c8e676a72768513d93' +
|
||||
'9f63dddb55609133f29adf86ec9929dc' +
|
||||
'cb52c1c5fd2ff7e21b',
|
||||
publicKey:
|
||||
'3ba16da0c6f2cc1f30187740756f5e79' +
|
||||
'8d6bc5fc015d7c63cc9510ee3fd44adc' +
|
||||
'24d8e968b6e46e6f94d19b945361726b' +
|
||||
'd75e149ef09817f580',
|
||||
message: '64a65f3cdedcdd66811e2915',
|
||||
signature:
|
||||
'7eeeab7c4e50fb799b418ee5e3197ff6' +
|
||||
'bf15d43a14c34389b59dd1a7b1b85b4a' +
|
||||
'e90438aca634bea45e3a2695f1270f07' +
|
||||
'fdcdf7c62b8efeaf00b45c2c96ba457e' +
|
||||
'b1a8bf075a3db28e5c24f6b923ed4ad7' +
|
||||
'47c3c9e03c7079efb87cb110d3a99861' +
|
||||
'e72003cbae6d6b8b827e4e6c143064ff' +
|
||||
'3c00',
|
||||
},
|
||||
{
|
||||
secretKey:
|
||||
'7ef4e84544236752fbb56b8f31a23a10' +
|
||||
'e42814f5f55ca037cdcc11c64c9a3b29' +
|
||||
'49c1bb60700314611732a6c2fea98eeb' +
|
||||
'c0266a11a93970100e',
|
||||
publicKey:
|
||||
'b3da079b0aa493a5772029f0467baebe' +
|
||||
'e5a8112d9d3a22532361da294f7bb381' +
|
||||
'5c5dc59e176b4d9f381ca0938e13c6c0' +
|
||||
'7b174be65dfa578e80',
|
||||
message: '64a65f3cdedcdd66811e2915e7',
|
||||
signature:
|
||||
'6a12066f55331b6c22acd5d5bfc5d712' +
|
||||
'28fbda80ae8dec26bdd306743c5027cb' +
|
||||
'4890810c162c027468675ecf645a8317' +
|
||||
'6c0d7323a2ccde2d80efe5a1268e8aca' +
|
||||
'1d6fbc194d3f77c44986eb4ab4177919' +
|
||||
'ad8bec33eb47bbb5fc6e28196fd1caf5' +
|
||||
'6b4e7e0ba5519234d047155ac727a105' +
|
||||
'3100',
|
||||
},
|
||||
{
|
||||
secretKey:
|
||||
'd65df341ad13e008567688baedda8e9d' +
|
||||
'cdc17dc024974ea5b4227b6530e339bf' +
|
||||
'f21f99e68ca6968f3cca6dfe0fb9f4fa' +
|
||||
'b4fa135d5542ea3f01',
|
||||
publicKey:
|
||||
'df9705f58edbab802c7f8363cfe5560a' +
|
||||
'b1c6132c20a9f1dd163483a26f8ac53a' +
|
||||
'39d6808bf4a1dfbd261b099bb03b3fb5' +
|
||||
'0906cb28bd8a081f00',
|
||||
message:
|
||||
'bd0f6a3747cd561bdddf4640a332461a' +
|
||||
'4a30a12a434cd0bf40d766d9c6d458e5' +
|
||||
'512204a30c17d1f50b5079631f64eb31' +
|
||||
'12182da3005835461113718d1a5ef944',
|
||||
signature:
|
||||
'554bc2480860b49eab8532d2a533b7d5' +
|
||||
'78ef473eeb58c98bb2d0e1ce488a98b1' +
|
||||
'8dfde9b9b90775e67f47d4a1c3482058' +
|
||||
'efc9f40d2ca033a0801b63d45b3b722e' +
|
||||
'f552bad3b4ccb667da350192b61c508c' +
|
||||
'f7b6b5adadc2c8d9a446ef003fb05cba' +
|
||||
'5f30e88e36ec2703b349ca229c267083' +
|
||||
'3900',
|
||||
},
|
||||
{
|
||||
secretKey:
|
||||
'2ec5fe3c17045abdb136a5e6a913e32a' +
|
||||
'b75ae68b53d2fc149b77e504132d3756' +
|
||||
'9b7e766ba74a19bd6162343a21c8590a' +
|
||||
'a9cebca9014c636df5',
|
||||
publicKey:
|
||||
'79756f014dcfe2079f5dd9e718be4171' +
|
||||
'e2ef2486a08f25186f6bff43a9936b9b' +
|
||||
'fe12402b08ae65798a3d81e22e9ec80e' +
|
||||
'7690862ef3d4ed3a00',
|
||||
message:
|
||||
'15777532b0bdd0d1389f636c5f6b9ba7' +
|
||||
'34c90af572877e2d272dd078aa1e567c' +
|
||||
'fa80e12928bb542330e8409f31745041' +
|
||||
'07ecd5efac61ae7504dabe2a602ede89' +
|
||||
'e5cca6257a7c77e27a702b3ae39fc769' +
|
||||
'fc54f2395ae6a1178cab4738e543072f' +
|
||||
'c1c177fe71e92e25bf03e4ecb72f47b6' +
|
||||
'4d0465aaea4c7fad372536c8ba516a60' +
|
||||
'39c3c2a39f0e4d832be432dfa9a706a6' +
|
||||
'e5c7e19f397964ca4258002f7c0541b5' +
|
||||
'90316dbc5622b6b2a6fe7a4abffd9610' +
|
||||
'5eca76ea7b98816af0748c10df048ce0' +
|
||||
'12d901015a51f189f3888145c03650aa' +
|
||||
'23ce894c3bd889e030d565071c59f409' +
|
||||
'a9981b51878fd6fc110624dcbcde0bf7' +
|
||||
'a69ccce38fabdf86f3bef6044819de11',
|
||||
signature:
|
||||
'c650ddbb0601c19ca11439e1640dd931' +
|
||||
'f43c518ea5bea70d3dcde5f4191fe53f' +
|
||||
'00cf966546b72bcc7d58be2b9badef28' +
|
||||
'743954e3a44a23f880e8d4f1cfce2d7a' +
|
||||
'61452d26da05896f0a50da66a239a8a1' +
|
||||
'88b6d825b3305ad77b73fbac0836ecc6' +
|
||||
'0987fd08527c1a8e80d5823e65cafe2a' +
|
||||
'3d00',
|
||||
},
|
||||
{
|
||||
secretKey:
|
||||
'872d093780f5d3730df7c212664b37b8' +
|
||||
'a0f24f56810daa8382cd4fa3f77634ec' +
|
||||
'44dc54f1c2ed9bea86fafb7632d8be19' +
|
||||
'9ea165f5ad55dd9ce8',
|
||||
publicKey:
|
||||
'a81b2e8a70a5ac94ffdbcc9badfc3feb' +
|
||||
'0801f258578bb114ad44ece1ec0e799d' +
|
||||
'a08effb81c5d685c0c56f64eecaef8cd' +
|
||||
'f11cc38737838cf400',
|
||||
message:
|
||||
'6ddf802e1aae4986935f7f981ba3f035' +
|
||||
'1d6273c0a0c22c9c0e8339168e675412' +
|
||||
'a3debfaf435ed651558007db4384b650' +
|
||||
'fcc07e3b586a27a4f7a00ac8a6fec2cd' +
|
||||
'86ae4bf1570c41e6a40c931db27b2faa' +
|
||||
'15a8cedd52cff7362c4e6e23daec0fbc' +
|
||||
'3a79b6806e316efcc7b68119bf46bc76' +
|
||||
'a26067a53f296dafdbdc11c77f7777e9' +
|
||||
'72660cf4b6a9b369a6665f02e0cc9b6e' +
|
||||
'dfad136b4fabe723d2813db3136cfde9' +
|
||||
'b6d044322fee2947952e031b73ab5c60' +
|
||||
'3349b307bdc27bc6cb8b8bbd7bd32321' +
|
||||
'9b8033a581b59eadebb09b3c4f3d2277' +
|
||||
'd4f0343624acc817804728b25ab79717' +
|
||||
'2b4c5c21a22f9c7839d64300232eb66e' +
|
||||
'53f31c723fa37fe387c7d3e50bdf9813' +
|
||||
'a30e5bb12cf4cd930c40cfb4e1fc6225' +
|
||||
'92a49588794494d56d24ea4b40c89fc0' +
|
||||
'596cc9ebb961c8cb10adde976a5d602b' +
|
||||
'1c3f85b9b9a001ed3c6a4d3b1437f520' +
|
||||
'96cd1956d042a597d561a596ecd3d173' +
|
||||
'5a8d570ea0ec27225a2c4aaff26306d1' +
|
||||
'526c1af3ca6d9cf5a2c98f47e1c46db9' +
|
||||
'a33234cfd4d81f2c98538a09ebe76998' +
|
||||
'd0d8fd25997c7d255c6d66ece6fa56f1' +
|
||||
'1144950f027795e653008f4bd7ca2dee' +
|
||||
'85d8e90f3dc315130ce2a00375a318c7' +
|
||||
'c3d97be2c8ce5b6db41a6254ff264fa6' +
|
||||
'155baee3b0773c0f497c573f19bb4f42' +
|
||||
'40281f0b1f4f7be857a4e59d416c06b4' +
|
||||
'c50fa09e1810ddc6b1467baeac5a3668' +
|
||||
'd11b6ecaa901440016f389f80acc4db9' +
|
||||
'77025e7f5924388c7e340a732e554440' +
|
||||
'e76570f8dd71b7d640b3450d1fd5f041' +
|
||||
'0a18f9a3494f707c717b79b4bf75c984' +
|
||||
'00b096b21653b5d217cf3565c9597456' +
|
||||
'f70703497a078763829bc01bb1cbc8fa' +
|
||||
'04eadc9a6e3f6699587a9e75c94e5bab' +
|
||||
'0036e0b2e711392cff0047d0d6b05bd2' +
|
||||
'a588bc109718954259f1d86678a579a3' +
|
||||
'120f19cfb2963f177aeb70f2d4844826' +
|
||||
'262e51b80271272068ef5b3856fa8535' +
|
||||
'aa2a88b2d41f2a0e2fda7624c2850272' +
|
||||
'ac4a2f561f8f2f7a318bfd5caf969614' +
|
||||
'9e4ac824ad3460538fdc25421beec2cc' +
|
||||
'6818162d06bbed0c40a387192349db67' +
|
||||
'a118bada6cd5ab0140ee273204f628aa' +
|
||||
'd1c135f770279a651e24d8c14d75a605' +
|
||||
'9d76b96a6fd857def5e0b354b27ab937' +
|
||||
'a5815d16b5fae407ff18222c6d1ed263' +
|
||||
'be68c95f32d908bd895cd76207ae7264' +
|
||||
'87567f9a67dad79abec316f683b17f2d' +
|
||||
'02bf07e0ac8b5bc6162cf94697b3c27c' +
|
||||
'd1fea49b27f23ba2901871962506520c' +
|
||||
'392da8b6ad0d99f7013fbc06c2c17a56' +
|
||||
'9500c8a7696481c1cd33e9b14e40b82e' +
|
||||
'79a5f5db82571ba97bae3ad3e0479515' +
|
||||
'bb0e2b0f3bfcd1fd33034efc6245eddd' +
|
||||
'7ee2086ddae2600d8ca73e214e8c2b0b' +
|
||||
'db2b047c6a464a562ed77b73d2d841c4' +
|
||||
'b34973551257713b753632efba348169' +
|
||||
'abc90a68f42611a40126d7cb21b58695' +
|
||||
'568186f7e569d2ff0f9e745d0487dd2e' +
|
||||
'b997cafc5abf9dd102e62ff66cba87',
|
||||
signature:
|
||||
'e301345a41a39a4d72fff8df69c98075' +
|
||||
'a0cc082b802fc9b2b6bc503f926b65bd' +
|
||||
'df7f4c8f1cb49f6396afc8a70abe6d8a' +
|
||||
'ef0db478d4c6b2970076c6a0484fe76d' +
|
||||
'76b3a97625d79f1ce240e7c576750d29' +
|
||||
'5528286f719b413de9ada3e8eb78ed57' +
|
||||
'3603ce30d8bb761785dc30dbc320869e' +
|
||||
'1a00',
|
||||
},
|
||||
];
|
||||
|
||||
for (let i = 0; i < VECTORS_RFC8032.length; i++) {
|
||||
const v = VECTORS_RFC8032[i];
|
||||
should(`RFC8032/${i}`, () => {
|
||||
deepStrictEqual(hex(ed.getPublicKey(v.secretKey)), v.publicKey);
|
||||
deepStrictEqual(hex(ed.sign(v.message, v.secretKey)), v.signature);
|
||||
deepStrictEqual(ed.verify(v.signature, v.message, v.publicKey), true);
|
||||
});
|
||||
}
|
||||
|
||||
should('not accept >57byte private keys', async () => {
|
||||
const invalidPriv =
|
||||
100000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000090000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800073278156000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000n;
|
||||
throws(() => ed.getPublicKey(invalidPriv));
|
||||
});
|
||||
|
||||
function to57Bytes(numOrStr) {
|
||||
let hex = typeof numOrStr === 'string' ? numOrStr : numOrStr.toString(16);
|
||||
return hexToBytes(hex.padStart(114, '0'));
|
||||
}
|
||||
|
||||
should('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(12);
|
||||
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', async () => {
|
||||
const publicKey = ed.getPublicKey(12);
|
||||
const signature = ed.sign(msg, privKey);
|
||||
deepStrictEqual(ed.verify(signature, msg, publicKey), false);
|
||||
});
|
||||
should('not verify signature with wrong hash', async () => {
|
||||
const publicKey = ed.getPublicKey(privKey);
|
||||
const signature = ed.sign(msg, privKey);
|
||||
deepStrictEqual(ed.verify(signature, wrongMsg, publicKey), false);
|
||||
});
|
||||
});
|
||||
|
||||
should('BASE_POINT.multiply() throws in Point#multiply on TEST 5', () => {
|
||||
for (const num of [0n, 0, -1n, -1, 1.1]) {
|
||||
throws(() => ed.Point.BASE.multiply(num));
|
||||
}
|
||||
});
|
||||
|
||||
should('input immutability: sign/verify are immutable', () => {
|
||||
const privateKey = ed.utils.randomPrivateKey();
|
||||
const publicKey = ed.getPublicKey(privateKey);
|
||||
|
||||
for (let i = 0; i < 100; i++) {
|
||||
let payload = randomBytes(100);
|
||||
let signature = ed.sign(payload, privateKey);
|
||||
if (!ed.verify(signature, payload, publicKey)) {
|
||||
throw new Error('Signature verification failed');
|
||||
}
|
||||
const signatureCopy = Buffer.alloc(signature.byteLength);
|
||||
signatureCopy.set(signature, 0); // <-- breaks
|
||||
payload = payload.slice();
|
||||
signature = signature.slice();
|
||||
|
||||
if (!ed.verify(signatureCopy, payload, publicKey))
|
||||
throw new Error('Copied signature verification failed');
|
||||
}
|
||||
});
|
||||
|
||||
{
|
||||
for (let g = 0; g < ed448vectors.testGroups.length; g++) {
|
||||
const group = ed448vectors.testGroups[g];
|
||||
const key = group.key;
|
||||
should(`Wycheproof/ED448(${g}, public)`, () => {
|
||||
deepStrictEqual(hex(ed.getPublicKey(key.sk)), key.pk);
|
||||
});
|
||||
should(`Wycheproof/ED448`, () => {
|
||||
for (let i = 0; i < group.tests.length; i++) {
|
||||
const v = group.tests[i];
|
||||
const index = `${g}/${i} ${v.comment}`;
|
||||
if (v.result === 'valid' || v.result === 'acceptable') {
|
||||
deepStrictEqual(hex(ed.sign(v.msg, key.sk)), v.sig, index);
|
||||
deepStrictEqual(ed.verify(v.sig, v.msg, key.pk), true, index);
|
||||
} else if (v.result === 'invalid') {
|
||||
let failed = false;
|
||||
try {
|
||||
failed = !ed.verify(v.sig, v.msg, key.pk);
|
||||
} catch (error) {
|
||||
failed = true;
|
||||
}
|
||||
deepStrictEqual(failed, true, index);
|
||||
} else throw new Error('unknown test result');
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// ECDH
|
||||
const rfc7748Mul = [
|
||||
{
|
||||
scalar:
|
||||
'3d262fddf9ec8e88495266fea19a34d28882acef045104d0d1aae121700a779c984c24f8cdd78fbff44943eba368f54b29259a4f1c600ad3',
|
||||
u: '06fce640fa3487bfda5f6cf2d5263f8aad88334cbd07437f020f08f9814dc031ddbdc38c19c6da2583fa5429db94ada18aa7a7fb4ef8a086',
|
||||
outputU:
|
||||
'ce3e4ff95a60dc6697da1db1d85e6afbdf79b50a2412d7546d5f239fe14fbaadeb445fc66a01b0779d98223961111e21766282f73dd96b6f',
|
||||
},
|
||||
{
|
||||
scalar:
|
||||
'203d494428b8399352665ddca42f9de8fef600908e0d461cb021f8c538345dd77c3e4806e25f46d3315c44e0a5b4371282dd2c8d5be3095f',
|
||||
u: '0fbcc2f993cd56d3305b0b7d9e55d4c1a8fb5dbb52f8e9a1e9b6201b165d015894e56c4d3570bee52fe205e28a78b91cdfbde71ce8d157db',
|
||||
outputU:
|
||||
'884a02576239ff7a2f2f63b2db6a9ff37047ac13568e1e30fe63c4a7ad1b3ee3a5700df34321d62077e63633c575c1c954514e99da7c179d',
|
||||
},
|
||||
];
|
||||
for (let i = 0; i < rfc7748Mul.length; i++) {
|
||||
const v = rfc7748Mul[i];
|
||||
should(`RFC7748: scalarMult (${i})`, () => {
|
||||
deepStrictEqual(hex(x448.scalarMult(v.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);
|
||||
});
|
||||
|
||||
{
|
||||
const group = x448vectors.testGroups[0];
|
||||
should(`Wycheproof/X448`, () => {
|
||||
for (let i = 0; i < group.tests.length; i++) {
|
||||
const v = group.tests[i];
|
||||
const index = `(${i}, ${v.result}) ${v.comment}`;
|
||||
if (v.result === 'valid' || v.result === 'acceptable') {
|
||||
try {
|
||||
const shared = hex(x448.scalarMult(v.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(ed.Point.BASE)),
|
||||
// ed.montgomeryCurve.BASE_POINT_U
|
||||
// );
|
||||
// });
|
||||
|
||||
// should('X448/getSharedSecret() should be commutative', async () => {
|
||||
// for (let i = 0; i < 512; i++) {
|
||||
// const asec = ed.utils.randomPrivateKey();
|
||||
// const apub = ed.getPublicKey(asec);
|
||||
// const bsec = ed.utils.randomPrivateKey();
|
||||
// const bpub = ed.getPublicKey(bsec);
|
||||
// try {
|
||||
// deepStrictEqual(ed.getSharedSecret(asec, bpub), ed.getSharedSecret(bsec, apub));
|
||||
// } catch (error) {
|
||||
// console.error('not commutative', { asec, apub, bsec, bpub });
|
||||
// throw error;
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
|
||||
const VECTORS_RFC8032_CTX = [
|
||||
{
|
||||
secretKey:
|
||||
'c4eab05d357007c632f3dbb48489924d552b08fe0c353a0d4a1f00acda2c463afbea67c5e8d2877c5e3bc397a659949ef8021e954e0a12274e',
|
||||
publicKey:
|
||||
'43ba28f430cdff456ae531545f7ecd0ac834a55d9358c0372bfa0c6c6798c0866aea01eb00742802b8438ea4cb82169c235160627b4c3a9480',
|
||||
message: '03',
|
||||
context: '666f6f',
|
||||
signature:
|
||||
'd4f8f6131770dd46f40867d6fd5d5055' +
|
||||
'de43541f8c5e35abbcd001b32a89f7d2' +
|
||||
'151f7647f11d8ca2ae279fb842d60721' +
|
||||
'7fce6e042f6815ea000c85741de5c8da' +
|
||||
'1144a6a1aba7f96de42505d7a7298524' +
|
||||
'fda538fccbbb754f578c1cad10d54d0d' +
|
||||
'5428407e85dcbc98a49155c13764e66c' +
|
||||
'3c00',
|
||||
},
|
||||
];
|
||||
|
||||
for (let i = 0; i < VECTORS_RFC8032_CTX.length; i++) {
|
||||
const v = VECTORS_RFC8032_CTX[i];
|
||||
should(`RFC8032ctx/${i}`, () => {
|
||||
deepStrictEqual(hex(ed.getPublicKey(v.secretKey)), v.publicKey);
|
||||
deepStrictEqual(hex(ed.sign(v.message, v.secretKey, v.context)), v.signature);
|
||||
deepStrictEqual(ed.verify(v.signature, v.message, v.publicKey, v.context), true);
|
||||
});
|
||||
}
|
||||
|
||||
const VECTORS_RFC8032_PH = [
|
||||
{
|
||||
secretKey:
|
||||
'833fe62409237b9d62ec77587520911e9a759cec1d19755b7da901b96dca3d42ef7822e0d5104127dc05d6dbefde69e3ab2cec7c867c6e2c49',
|
||||
publicKey:
|
||||
'259b71c19f83ef77a7abd26524cbdb3161b590a48f7d17de3ee0ba9c52beb743c09428a131d6b1b57303d90d8132c276d5ed3d5d01c0f53880',
|
||||
message: '616263',
|
||||
signature:
|
||||
'822f6901f7480f3d5f562c592994d969' +
|
||||
'3602875614483256505600bbc281ae38' +
|
||||
'1f54d6bce2ea911574932f52a4e6cadd' +
|
||||
'78769375ec3ffd1b801a0d9b3f4030cd' +
|
||||
'433964b6457ea39476511214f97469b5' +
|
||||
'7dd32dbc560a9a94d00bff07620464a3' +
|
||||
'ad203df7dc7ce360c3cd3696d9d9fab9' +
|
||||
'0f00',
|
||||
},
|
||||
{
|
||||
secretKey:
|
||||
'833fe62409237b9d62ec77587520911e9a759cec1d19755b7da901b96dca3d42ef7822e0d5104127dc05d6dbefde69e3ab2cec7c867c6e2c49',
|
||||
publicKey:
|
||||
'259b71c19f83ef77a7abd26524cbdb3161b590a48f7d17de3ee0ba9c52beb743c09428a131d6b1b57303d90d8132c276d5ed3d5d01c0f53880',
|
||||
message: '616263',
|
||||
context: '666f6f',
|
||||
signature:
|
||||
'c32299d46ec8ff02b54540982814dce9' +
|
||||
'a05812f81962b649d528095916a2aa48' +
|
||||
'1065b1580423ef927ecf0af5888f90da' +
|
||||
'0f6a9a85ad5dc3f280d91224ba9911a3' +
|
||||
'653d00e484e2ce232521481c8658df30' +
|
||||
'4bb7745a73514cdb9bf3e15784ab7128' +
|
||||
'4f8d0704a608c54a6b62d97beb511d13' +
|
||||
'2100',
|
||||
},
|
||||
];
|
||||
|
||||
for (let i = 0; i < VECTORS_RFC8032_PH.length; i++) {
|
||||
const v = VECTORS_RFC8032_PH[i];
|
||||
should(`RFC8032ph/${i}`, () => {
|
||||
deepStrictEqual(hex(ed448ph.getPublicKey(v.secretKey)), v.publicKey);
|
||||
deepStrictEqual(hex(ed448ph.sign(v.message, v.secretKey, v.context)), v.signature);
|
||||
deepStrictEqual(ed448ph.verify(v.signature, v.message, v.publicKey, v.context), true);
|
||||
});
|
||||
}
|
||||
|
||||
should('X448 base point', () => {
|
||||
const { x, y } = ed448.Point.BASE;
|
||||
const { 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"
|
||||
}
|
||||
]
|
||||
},
|
||||
150
test/hash-to-curve.test.js
Normal file
150
test/hash-to-curve.test.js
Normal file
@@ -0,0 +1,150 @@
|
||||
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 { secp256r1 } from '../lib/esm/p256.js';
|
||||
import { secp384r1 } from '../lib/esm/p384.js';
|
||||
import { secp521r1 } from '../lib/esm/p521.js';
|
||||
import { ed25519 } from '../lib/esm/ed25519.js';
|
||||
import { ed448 } from '../lib/esm/ed448.js';
|
||||
import { 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.Point.hashToCurve(stringToBytes(t.msg), {
|
||||
DST: ro.dst,
|
||||
});
|
||||
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.Point.encodeToCurve(stringToBytes(t.msg), {
|
||||
DST: nu.dst,
|
||||
});
|
||||
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);
|
||||
// TODO: remove same tests from bls12
|
||||
testCurve(bls12_381.G1, g1_ro, g1_nu);
|
||||
testCurve(bls12_381.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"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -8,5 +8,7 @@ import './ed25519.test.js';
|
||||
import './secp256k1.test.js';
|
||||
import './stark/stark.test.js';
|
||||
import './jubjub.test.js';
|
||||
import './bls12-381.test.js';
|
||||
import './hash-to-curve.test.js';
|
||||
|
||||
should.run();
|
||||
82
test/jubjub.test.js
Normal file
82
test/jubjub.test.js
Normal file
@@ -0,0 +1,82 @@
|
||||
import { jubjub, findGroupHash } from '../lib/esm/jubjub.js';
|
||||
import { describe, should } from 'micro-should';
|
||||
import { deepStrictEqual, throws } from 'assert';
|
||||
import { hexToBytes, bytesToHex } from '@noble/hashes/utils';
|
||||
|
||||
const G_SPEND = new jubjub.ExtendedPoint(
|
||||
0x055f1f24f0f0512287e51c3c5a0a6903fc0baf8711de9eafd7c0e66f69d8d2dbn,
|
||||
0x566178b2505fdd52132a5007d80a04652842e78ffb376897588f406278214ed7n,
|
||||
0x0141fafa1f11088a3b2007c14d652375888f3b37838ba6bdffae096741ceddfen,
|
||||
0x12eada93c0b7d595f5f04f5ebfb4b7d033ef2884136475cab5e41ce17db5be9cn
|
||||
);
|
||||
const G_PROOF = new jubjub.ExtendedPoint(
|
||||
0x0174d54ce9fad258a2f8a86a1deabf15c7a2b51106b0fbcd9d29020f78936f71n,
|
||||
0x16871d6d877dcd222e4ec3bccb3f37cb1865a2d37dd3a5dcbc032a69b62b4445n,
|
||||
0x57a3cd31e496d82bd4aa78bd5ecd751cfb76d54a5d3f4560866379f9fc11c9b3n,
|
||||
0x42cc53f6b519d1f4f52c47ff1256463a616c2c2f49ffe77765481eca04c72081n
|
||||
);
|
||||
|
||||
const getXY = (p) => ({ x: p.x, y: p.y });
|
||||
|
||||
describe('jubjub', () => {
|
||||
should('toHex/fromHex', () => {
|
||||
// More than field
|
||||
throws(() =>
|
||||
jubjub.Point.fromHex(
|
||||
new Uint8Array([
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
])
|
||||
)
|
||||
);
|
||||
// Multiplicative generator (sqrt == null), not on curve.
|
||||
throws(() =>
|
||||
jubjub.Point.fromHex(
|
||||
new Uint8Array([
|
||||
7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0,
|
||||
])
|
||||
)
|
||||
);
|
||||
const tmp = jubjub.Point.fromHex(
|
||||
new Uint8Array([
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0,
|
||||
])
|
||||
);
|
||||
deepStrictEqual(tmp.x, 0x8d51ccce760304d0ec030002760300000001000000000000n);
|
||||
deepStrictEqual(tmp.y, 0n);
|
||||
|
||||
const S = G_SPEND.toAffine().toRawBytes();
|
||||
const S2 = G_SPEND.double().toAffine().toRawBytes();
|
||||
const P = G_PROOF.toAffine().toRawBytes();
|
||||
const P2 = G_PROOF.double().toAffine().toRawBytes();
|
||||
const S_exp = jubjub.Point.fromHex(S);
|
||||
const S2_exp = jubjub.Point.fromHex(S2);
|
||||
const P_exp = jubjub.Point.fromHex(P);
|
||||
const P2_exp = jubjub.Point.fromHex(P2);
|
||||
deepStrictEqual(getXY(G_SPEND.toAffine()), getXY(S_exp));
|
||||
deepStrictEqual(getXY(G_SPEND.double().toAffine()), getXY(S2_exp));
|
||||
deepStrictEqual(getXY(G_PROOF.toAffine()), getXY(P_exp));
|
||||
deepStrictEqual(getXY(G_PROOF.double().toAffine()), getXY(P2_exp));
|
||||
});
|
||||
|
||||
should('Find generators', () => {
|
||||
const spend = findGroupHash(
|
||||
new Uint8Array(),
|
||||
new Uint8Array([90, 99, 97, 115, 104, 95, 71, 95])
|
||||
);
|
||||
const proof = findGroupHash(
|
||||
new Uint8Array(),
|
||||
new Uint8Array([90, 99, 97, 115, 104, 95, 72, 95])
|
||||
);
|
||||
deepStrictEqual(getXY(spend.toAffine()), getXY(G_SPEND.toAffine()));
|
||||
deepStrictEqual(getXY(proof.toAffine()), getXY(G_PROOF.toAffine()));
|
||||
});
|
||||
});
|
||||
|
||||
// ESM is broken.
|
||||
import url from 'url';
|
||||
if (import.meta.url === url.pathToFileURL(process.argv[1]).href) {
|
||||
should.run();
|
||||
}
|
||||
@@ -1,12 +1,12 @@
|
||||
import { deepStrictEqual, throws } from 'assert';
|
||||
import { should } from 'micro-should';
|
||||
import { secp192r1, P192 } from '../lib/p192.js';
|
||||
import { secp224r1, P224 } from '../lib/p224.js';
|
||||
import { secp256r1, P256 } from '../lib/p256.js';
|
||||
import { secp384r1, P384 } from '../lib/p384.js';
|
||||
import { secp521r1, P521 } from '../lib/p521.js';
|
||||
import { secp256k1 } from '../lib/secp256k1.js';
|
||||
import { hexToBytes, bytesToHex } from '@noble/curves/utils';
|
||||
import { describe, should } from 'micro-should';
|
||||
import { secp192r1, P192 } from '../lib/esm/p192.js';
|
||||
import { secp224r1, P224 } from '../lib/esm/p224.js';
|
||||
import { secp256r1, P256 } from '../lib/esm/p256.js';
|
||||
import { secp384r1, P384 } from '../lib/esm/p384.js';
|
||||
import { secp521r1, P521 } from '../lib/esm/p521.js';
|
||||
import { secp256k1 } from '../lib/esm/secp256k1.js';
|
||||
import { hexToBytes, bytesToHex } from '../lib/esm/abstract/utils.js';
|
||||
import { default as ecdsa } from './wycheproof/ecdsa_test.json' assert { type: 'json' };
|
||||
import { default as ecdh } from './wycheproof/ecdh_test.json' assert { type: 'json' };
|
||||
import { default as rfc6979 } from './fixtures/rfc6979.json' assert { type: 'json' };
|
||||
@@ -34,17 +34,18 @@ should('Curve Fields', () => {
|
||||
secp521r1:
|
||||
0x01ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffn,
|
||||
};
|
||||
for (const n in vectors) deepStrictEqual(NIST[n].CURVE.P, vectors[n]);
|
||||
for (const n in vectors) deepStrictEqual(NIST[n].CURVE.Fp.ORDER, 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];
|
||||
let CURVE = NIST[group.key.curve];
|
||||
if (!CURVE) continue;
|
||||
if (group.key.curve === 'secp224r1' && group.sha !== 'SHA-224') {
|
||||
if (group.sha === 'SHA-256') CURVE = CURVE.create(sha256);
|
||||
}
|
||||
const pubKey = CURVE.Point.fromHex(group.key.uncompressed);
|
||||
deepStrictEqual(pubKey.x, BigInt(`0x${group.key.wx}`));
|
||||
deepStrictEqual(pubKey.y, BigInt(`0x${group.key.wy}`));
|
||||
@@ -196,17 +197,16 @@ import { default as secp521r1_sha512_test } from './wycheproof/ecdsa_secp521r1_s
|
||||
|
||||
import { sha3_224, sha3_256, sha3_384, sha3_512 } from '@noble/hashes/sha3';
|
||||
import { sha512, sha384 } from '@noble/hashes/sha512';
|
||||
import { sha256 } from '@noble/hashes/sha256';
|
||||
import { sha224, sha256 } from '@noble/hashes/sha256';
|
||||
|
||||
const WYCHEPROOF_ECDSA = {
|
||||
P224: {
|
||||
curve: P224,
|
||||
hashes: {
|
||||
// sha224 not released yet
|
||||
// sha224: {
|
||||
// hash: sha224,
|
||||
// tests: [secp224r1_sha224_test],
|
||||
// },
|
||||
sha224: {
|
||||
hash: sha224,
|
||||
tests: [secp224r1_sha224_test],
|
||||
},
|
||||
sha256: {
|
||||
hash: sha256,
|
||||
tests: [secp224r1_sha256_test],
|
||||
@@ -330,7 +330,6 @@ function runWycheproof(name, CURVE, group, index) {
|
||||
} else {
|
||||
deepStrictEqual(verified, true, `${index}: valid`);
|
||||
}
|
||||
|
||||
} else if (test.result === 'invalid') {
|
||||
let failed = false;
|
||||
try {
|
||||
@@ -345,10 +344,11 @@ function runWycheproof(name, CURVE, group, index) {
|
||||
|
||||
for (const name in WYCHEPROOF_ECDSA) {
|
||||
const { curve, hashes } = WYCHEPROOF_ECDSA[name];
|
||||
describe('Wycheproof/WYCHEPROOF_ECDSA', () => {
|
||||
for (const hName in hashes) {
|
||||
const { hash, tests } = hashes[hName];
|
||||
const CURVE = curve.create(hash);
|
||||
should(`Wycheproof/WYCHEPROOF_ECDSA ${name}/${hName}`, () => {
|
||||
should(`${name}/${hName}`, () => {
|
||||
for (let i = 0; i < tests.length; i++) {
|
||||
const groups = tests[i].testGroups;
|
||||
for (let j = 0; j < groups.length; j++) {
|
||||
@@ -358,6 +358,7 @@ for (const name in WYCHEPROOF_ECDSA) {
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const hexToBigint = (hex) => BigInt(`0x${hex}`);
|
||||
7
test/package.json
Normal file
7
test/package.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"type": "module",
|
||||
"browser": {
|
||||
"crypto": false,
|
||||
"./crypto": "./esm/cryptoBrowser.js"
|
||||
}
|
||||
}
|
||||
551
test/secp256k1.test.js
Normal file
551
test/secp256k1.test.js
Normal file
@@ -0,0 +1,551 @@
|
||||
import * as fc from 'fast-check';
|
||||
import { secp256k1, schnorr } from '../lib/esm/secp256k1.js';
|
||||
import { Fp } from '../lib/esm/abstract/modular.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, describe } from 'micro-should';
|
||||
import { deepStrictEqual, throws } from 'assert';
|
||||
import { hexToBytes, bytesToHex } from '@noble/hashes/utils';
|
||||
|
||||
const hex = bytesToHex;
|
||||
const secp = secp256k1;
|
||||
const privatesTxt = readFileSync('./test/vectors/privates-2.txt', 'utf-8');
|
||||
const schCsv = readFileSync('./test/vectors/schnorr.csv', 'utf-8');
|
||||
|
||||
const FC_BIGINT = fc.bigInt(1n + 1n, secp.CURVE.n - 1n);
|
||||
// prettier-ignore
|
||||
const INVALID_ITEMS = ['deadbeef', Math.pow(2, 53), [1], 'xyzxyzxyxyzxyzxyxyzxyzxyxyzxyzxyxyzxyzxyxyzxyzxyxyzxyzxyxyzxyzxy', secp.CURVE.n + 2n];
|
||||
|
||||
const toBEHex = (n) => n.toString(16).padStart(64, '0');
|
||||
|
||||
function hexToNumber(hex) {
|
||||
if (typeof hex !== 'string') {
|
||||
throw new TypeError('hexToNumber: expected string, got ' + typeof hex);
|
||||
}
|
||||
// Big Endian
|
||||
return BigInt(`0x${hex}`);
|
||||
}
|
||||
|
||||
describe('secp256k1', () => {
|
||||
should('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('getPublicKey() rejects invalid keys', () => {
|
||||
for (const item of INVALID_ITEMS) {
|
||||
throws(() => secp.getPublicKey(item));
|
||||
}
|
||||
});
|
||||
should('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('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('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('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('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('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('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('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('ProjectivePoint#multiplyUnsafe', () => {
|
||||
// const p0 = new secp.ProjectivePoint(
|
||||
// 55066263022277343669578718895168534326250603453777594175500187360389116729240n,
|
||||
// 32670510020758816978083085130507043184471273380659243275938904335757337482424n,
|
||||
// 1n
|
||||
// );
|
||||
// const z = 106011723082030650010038151861333186846790370053628296836951575624442507889495n;
|
||||
// console.log(p0.multiply(z));
|
||||
// console.log(secp.ProjectivePoint.normalizeZ([p0.multiplyUnsafe(z)])[0])
|
||||
// });
|
||||
|
||||
should('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('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('sign()/should create deterministic signatures with RFC 6979', () => {
|
||||
for (const vector of ecdsa.valid) {
|
||||
let usig = secp.sign(vector.m, vector.d);
|
||||
let sig = usig.toCompactHex();
|
||||
const vsig = vector.signature;
|
||||
deepStrictEqual(sig.slice(0, 64), vsig.slice(0, 64));
|
||||
deepStrictEqual(sig.slice(64, 128), vsig.slice(64, 128));
|
||||
}
|
||||
});
|
||||
|
||||
should(
|
||||
'secp256k1.sign()/should not create invalid deterministic signatures with RFC 6979',
|
||||
() => {
|
||||
for (const vector of ecdsa.invalid.sign) {
|
||||
throws(() => secp.sign(vector.m, vector.d));
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
should('sign()/edge cases', () => {
|
||||
throws(() => secp.sign());
|
||||
throws(() => secp.sign(''));
|
||||
});
|
||||
|
||||
should('sign()/should create correct DER encoding against libsecp256k1', () => {
|
||||
const CASES = [
|
||||
[
|
||||
'd1a9dc8ed4e46a6a3e5e594615ca351d7d7ef44df1e4c94c1802f3592183794b',
|
||||
'304402203de2559fccb00c148574997f660e4d6f40605acc71267ee38101abf15ff467af02200950abdf40628fd13f547792ba2fc544681a485f2fdafb5c3b909a4df7350e6b',
|
||||
],
|
||||
[
|
||||
'5f97983254982546d3976d905c6165033976ee449d300d0e382099fa74deaf82',
|
||||
'3045022100c046d9ff0bd2845b9aa9dff9f997ecebb31e52349f80fe5a5a869747d31dcb88022011f72be2a6d48fe716b825e4117747b397783df26914a58139c3f4c5cbb0e66c',
|
||||
],
|
||||
[
|
||||
'0d7017a96b97cd9be21cf28aada639827b2814a654a478c81945857196187808',
|
||||
'3045022100d18990bba7832bb283e3ecf8700b67beb39acc73f4200ed1c331247c46edccc602202e5c8bbfe47ae159512c583b30a3fa86575cddc62527a03de7756517ae4c6c73',
|
||||
],
|
||||
];
|
||||
const privKey = hexToBytes('0101010101010101010101010101010101010101010101010101010101010101');
|
||||
for (const [msg, exp] of CASES) {
|
||||
const res = secp.sign(msg, privKey, { extraEntropy: undefined });
|
||||
deepStrictEqual(res.toDERHex(), exp);
|
||||
const rs = secp.Signature.fromDER(res.toDERHex()).toCompactHex();
|
||||
deepStrictEqual(secp.Signature.fromCompact(rs).toDERHex(), exp);
|
||||
}
|
||||
});
|
||||
should('sign()/sign ecdsa extraData', () => {
|
||||
const ent1 = '0000000000000000000000000000000000000000000000000000000000000000';
|
||||
const ent2 = '0000000000000000000000000000000000000000000000000000000000000001';
|
||||
const ent3 = '6e723d3fd94ed5d2b6bdd4f123364b0f3ca52af829988a63f8afe91d29db1c33';
|
||||
const ent4 = 'fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141';
|
||||
const ent5 = 'ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff';
|
||||
|
||||
for (const e of ecdsa.extraEntropy) {
|
||||
const sign = (extraEntropy) => {
|
||||
const s = secp.sign(e.m, e.d, { extraEntropy }).toCompactHex();
|
||||
return s;
|
||||
};
|
||||
deepStrictEqual(sign(), e.signature);
|
||||
deepStrictEqual(sign(ent1), e.extraEntropy0);
|
||||
deepStrictEqual(sign(ent2), e.extraEntropy1);
|
||||
deepStrictEqual(sign(ent3), e.extraEntropyRand);
|
||||
deepStrictEqual(sign(ent4), e.extraEntropyN);
|
||||
deepStrictEqual(sign(ent5), e.extraEntropyMax);
|
||||
}
|
||||
});
|
||||
|
||||
should('verify()/should verify signature', () => {
|
||||
const MSG = '01'.repeat(32);
|
||||
const PRIV_KEY = 0x2n;
|
||||
const signature = secp.sign(MSG, PRIV_KEY);
|
||||
const publicKey = secp.getPublicKey(PRIV_KEY);
|
||||
deepStrictEqual(publicKey.length, 65);
|
||||
deepStrictEqual(secp.verify(signature, MSG, publicKey), true);
|
||||
});
|
||||
should('verify()/should not verify signature with wrong public key', () => {
|
||||
const MSG = '01'.repeat(32);
|
||||
const PRIV_KEY = 0x2n;
|
||||
const WRONG_PRIV_KEY = 0x22n;
|
||||
const signature = secp.sign(MSG, PRIV_KEY);
|
||||
const publicKey = secp.Point.fromPrivateKey(WRONG_PRIV_KEY).toHex();
|
||||
deepStrictEqual(publicKey.length, 130);
|
||||
deepStrictEqual(secp.verify(signature, MSG, publicKey), false);
|
||||
});
|
||||
should('verify()/should not verify signature with wrong hash', () => {
|
||||
const MSG = '01'.repeat(32);
|
||||
const PRIV_KEY = 0x2n;
|
||||
const WRONG_MSG = '11'.repeat(32);
|
||||
const signature = secp.sign(MSG, PRIV_KEY);
|
||||
const publicKey = secp.getPublicKey(PRIV_KEY);
|
||||
deepStrictEqual(publicKey.length, 65);
|
||||
deepStrictEqual(secp.verify(signature, WRONG_MSG, publicKey), false);
|
||||
});
|
||||
should('verify()/should verify random signatures', () =>
|
||||
fc.assert(
|
||||
fc.property(FC_BIGINT, fc.hexaString({ minLength: 64, maxLength: 64 }), (privKey, msg) => {
|
||||
const pub = secp.getPublicKey(privKey);
|
||||
const sig = secp.sign(msg, privKey);
|
||||
deepStrictEqual(secp.verify(sig, msg, pub), true);
|
||||
})
|
||||
)
|
||||
);
|
||||
should('verify()/should not verify signature with invalid r/s', () => {
|
||||
const msg = new Uint8Array([
|
||||
0xbb, 0x5a, 0x52, 0xf4, 0x2f, 0x9c, 0x92, 0x61, 0xed, 0x43, 0x61, 0xf5, 0x94, 0x22, 0xa1,
|
||||
0xe3, 0x00, 0x36, 0xe7, 0xc3, 0x2b, 0x27, 0x0c, 0x88, 0x07, 0xa4, 0x19, 0xfe, 0xca, 0x60,
|
||||
0x50, 0x23,
|
||||
]);
|
||||
const x = 100260381870027870612475458630405506840396644859280795015145920502443964769584n;
|
||||
const y = 41096923727651821103518389640356553930186852801619204169823347832429067794568n;
|
||||
const r = 1n;
|
||||
const s = 115792089237316195423570985008687907852837564279074904382605163141518162728904n;
|
||||
|
||||
const pub = new secp.Point(x, y);
|
||||
const signature = new secp.Signature(2n, 2n);
|
||||
signature.r = r;
|
||||
signature.s = s;
|
||||
|
||||
const verified = secp.verify(signature, msg, pub);
|
||||
// Verifies, but it shouldn't, because signature S > curve order
|
||||
deepStrictEqual(verified, false);
|
||||
});
|
||||
should('verify()/should not verify msg = curve order', () => {
|
||||
const msg = 'fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141';
|
||||
const x = 55066263022277343669578718895168534326250603453777594175500187360389116729240n;
|
||||
const y = 32670510020758816978083085130507043184471273380659243275938904335757337482424n;
|
||||
const r = 104546003225722045112039007203142344920046999340768276760147352389092131869133n;
|
||||
const s = 96900796730960181123786672629079577025401317267213807243199432755332205217369n;
|
||||
const pub = new secp.Point(x, y);
|
||||
const sig = new secp.Signature(r, s);
|
||||
deepStrictEqual(secp.verify(sig, msg, pub), false);
|
||||
});
|
||||
should('verify()/should verify non-strict msg bb5a...', () => {
|
||||
const msg = 'bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023';
|
||||
const x = 3252872872578928810725465493269682203671229454553002637820453004368632726370n;
|
||||
const y = 17482644437196207387910659778872952193236850502325156318830589868678978890912n;
|
||||
const r = 432420386565659656852420866390673177323n;
|
||||
const s = 115792089237316195423570985008687907852837564279074904382605163141518161494334n;
|
||||
const pub = new secp.Point(x, y);
|
||||
const sig = new secp.Signature(r, s);
|
||||
deepStrictEqual(secp.verify(sig, msg, pub, { strict: false }), true);
|
||||
});
|
||||
should(
|
||||
'secp256k1.verify()/should not verify invalid deterministic signatures with RFC 6979',
|
||||
() => {
|
||||
for (const vector of ecdsa.invalid.verify) {
|
||||
const res = secp.verify(vector.signature, vector.m, vector.Q);
|
||||
deepStrictEqual(res, false);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// index,secret key,public key,aux_rand,message,signature,verification result,comment
|
||||
const vectors = schCsv
|
||||
.split('\n')
|
||||
.map((line) => line.split(','))
|
||||
.slice(1, -1);
|
||||
for (let vec of vectors) {
|
||||
const [index, sec, pub, rnd, msg, expSig, passes, comment] = vec;
|
||||
should(`sign with Schnorr scheme vector ${index}`, () => {
|
||||
if (sec) {
|
||||
deepStrictEqual(hex(schnorr.getPublicKey(sec)), pub.toLowerCase());
|
||||
const sig = schnorr.sign(msg, sec, rnd);
|
||||
deepStrictEqual(hex(sig), expSig.toLowerCase());
|
||||
deepStrictEqual(schnorr.verify(sig, msg, pub), true);
|
||||
} else {
|
||||
const passed = schnorr.verify(expSig, msg, pub);
|
||||
deepStrictEqual(passed, passes === 'TRUE');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
should('recoverPublicKey()/should recover public key from recovery bit', () => {
|
||||
const message = '00000000000000000000000000000000000000000000000000000000deadbeef';
|
||||
const privateKey = 123456789n;
|
||||
const publicKey = secp.Point.fromHex(secp.getPublicKey(privateKey)).toHex(false);
|
||||
const sig = secp.sign(message, privateKey);
|
||||
const recoveredPubkey = sig.recoverPublicKey(message);
|
||||
// const recoveredPubkey = secp.recoverPublicKey(message, signature, recovery);
|
||||
deepStrictEqual(recoveredPubkey !== null, true);
|
||||
deepStrictEqual(recoveredPubkey.toHex(false), publicKey);
|
||||
deepStrictEqual(secp.verify(sig, message, publicKey), true);
|
||||
});
|
||||
should('recoverPublicKey()/should not recover zero points', () => {
|
||||
const msgHash = '6b8d2c81b11b2d699528dde488dbdf2f94293d0d33c32e347f255fa4a6c1f0a9';
|
||||
const sig =
|
||||
'79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f817986b8d2c81b11b2d699528dde488dbdf2f94293d0d33c32e347f255fa4a6c1f0a9';
|
||||
const recovery = 0;
|
||||
throws(() => secp.recoverPublicKey(msgHash, sig, recovery));
|
||||
});
|
||||
should('recoverPublicKey()/should handle all-zeros msghash', () => {
|
||||
const privKey = secp.utils.randomPrivateKey();
|
||||
const pub = secp.getPublicKey(privKey);
|
||||
const zeros = '0000000000000000000000000000000000000000000000000000000000000000';
|
||||
const sig = secp.sign(zeros, privKey, { recovered: true });
|
||||
const recoveredKey = sig.recoverPublicKey(zeros);
|
||||
deepStrictEqual(recoveredKey.toRawBytes(), pub);
|
||||
});
|
||||
should('recoverPublicKey()/should handle RFC 6979 vectors', () => {
|
||||
for (const vector of ecdsa.valid) {
|
||||
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('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) {
|
||||
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('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('getSharedSecret()/rejects invalid keys', () => {
|
||||
throws(() => secp.getSharedSecret('01', '02'));
|
||||
});
|
||||
|
||||
should('utils.isValidPrivateKey()', () => {
|
||||
for (const vector of privates.valid.isPrivate) {
|
||||
const { d, expected } = vector;
|
||||
deepStrictEqual(secp.utils.isValidPrivateKey(d), expected);
|
||||
}
|
||||
});
|
||||
should('have proper curve equation in assertValidity()', () => {
|
||||
throws(() => {
|
||||
const { Fp } = secp.CURVE;
|
||||
let point = new secp.Point(Fp.create(-2n), Fp.create(-1n));
|
||||
point.assertValidity();
|
||||
});
|
||||
});
|
||||
|
||||
const Fn = Fp(secp.CURVE.n);
|
||||
const normal = secp.utils._normalizePrivateKey;
|
||||
const tweakUtils = {
|
||||
privateAdd: (privateKey, tweak) => {
|
||||
const p = normal(privateKey);
|
||||
const t = normal(tweak);
|
||||
return secp.utils._bigintToBytes(Fn.create(p + t));
|
||||
},
|
||||
|
||||
privateNegate: (privateKey) => {
|
||||
const p = normal(privateKey);
|
||||
return secp.utils._bigintToBytes(Fn.negate(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('privateAdd()', () => {
|
||||
for (const vector of privates.valid.add) {
|
||||
const { a, b, expected } = vector;
|
||||
deepStrictEqual(bytesToHex(tweakUtils.privateAdd(a, b)), expected);
|
||||
}
|
||||
});
|
||||
should('privateNegate()', () => {
|
||||
for (const vector of privates.valid.negate) {
|
||||
const { a, expected } = vector;
|
||||
deepStrictEqual(bytesToHex(tweakUtils.privateNegate(a)), expected);
|
||||
}
|
||||
});
|
||||
should('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('pointAddScalar() invalid', () => {
|
||||
for (const vector of points.invalid.pointAddScalar) {
|
||||
const { P, d, exception } = vector;
|
||||
throws(() => tweakUtils.pointAddScalar(P, d));
|
||||
}
|
||||
});
|
||||
should('pointMultiply()', () => {
|
||||
for (const vector of points.valid.pointMultiply) {
|
||||
const { P, d, expected } = vector;
|
||||
deepStrictEqual(bytesToHex(tweakUtils.pointMultiply(P, d, true)), expected);
|
||||
}
|
||||
});
|
||||
should('pointMultiply() invalid', () => {
|
||||
for (const vector of points.invalid.pointMultiply) {
|
||||
const { P, d, exception } = vector;
|
||||
throws(() => tweakUtils.pointMultiply(P, d));
|
||||
}
|
||||
});
|
||||
|
||||
should('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);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// ESM is broken.
|
||||
import url from 'url';
|
||||
if (import.meta.url === url.pathToFileURL(process.argv[1]).href) {
|
||||
should.run();
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
import { deepStrictEqual, throws } from 'assert';
|
||||
import { should } from 'micro-should';
|
||||
import * as starknet from '../../lib/stark.js';
|
||||
import * as starknet from '../../lib/esm/stark.js';
|
||||
import { default as issue2 } from './fixtures/issue2.json' assert { type: 'json' };
|
||||
|
||||
should('Basic elliptic sanity check', () => {
|
||||
@@ -1,4 +1,4 @@
|
||||
import * as microStark from '../../../lib/stark.js';
|
||||
import * as microStark from '../../../lib/esm/stark.js';
|
||||
import * as starkwareCrypto from '@starkware-industries/starkware-crypto-utils';
|
||||
import * as bench from 'micro-bmark';
|
||||
const { run, mark } = bench; // or bench.mark
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user