From aca18fbcda95bd1be36bd09ced4742efdccb2228 Mon Sep 17 00:00:00 2001 From: dapplion Date: Fri, 13 Nov 2020 21:43:20 +0000 Subject: [PATCH 01/51] Test blst-ts with spec tests --- package.json | 1 + test/spec-blst/aggregate_sigs.test.ts | 29 ++++++++++++++ test/spec-blst/aggregate_sigs_verify.test.ts | 39 ++++++++++++++++++ test/spec-blst/fast_aggregate_verify.test.ts | 42 ++++++++++++++++++++ test/spec-blst/sign.test.ts | 34 ++++++++++++++++ test/spec-blst/verify.test.ts | 39 ++++++++++++++++++ test/util.ts | 7 ++++ yarn.lock | 3 ++ 8 files changed, 194 insertions(+) create mode 100644 test/spec-blst/aggregate_sigs.test.ts create mode 100644 test/spec-blst/aggregate_sigs_verify.test.ts create mode 100644 test/spec-blst/fast_aggregate_verify.test.ts create mode 100644 test/spec-blst/sign.test.ts create mode 100644 test/spec-blst/verify.test.ts create mode 100644 test/util.ts diff --git a/package.json b/package.json index 65ba239..996b109 100644 --- a/package.json +++ b/package.json @@ -40,6 +40,7 @@ }, "dependencies": { "@chainsafe/bls-keygen": "^0.2.0", + "@chainsafe/blst-ts": "file:../blst-ts", "@chainsafe/eth2-bls-wasm": "^0.5.0", "assert": "^1.4.1" }, diff --git a/test/spec-blst/aggregate_sigs.test.ts b/test/spec-blst/aggregate_sigs.test.ts new file mode 100644 index 0000000..80a4eed --- /dev/null +++ b/test/spec-blst/aggregate_sigs.test.ts @@ -0,0 +1,29 @@ +import path from "path"; +import {describeDirectorySpecTest, InputType} from "@chainsafe/lodestar-spec-test-util"; +import {AggregateSignature} from "@chainsafe/blst-ts"; +import {fromHexString, toHexString} from "../util"; + +interface IAggregateSigsTestCase { + data: { + input: string[]; + output: string; + }; +} + +describeDirectorySpecTest( + "BLS - aggregate sigs", + path.join(__dirname, "../../node_modules/@chainsafe/eth2-spec-tests/tests/general/phase0/bls/aggregate/small"), + (testCase) => { + const signaturesHex = testCase.data.input; + const signaturesBytes = signaturesHex.map(fromHexString); + const aggSig = AggregateSignature.fromSignaturesBytes(signaturesBytes); + const aggSigHex = aggSig.toSignature().toBytes(); + return toHexString(aggSigHex); + }, + { + inputTypes: { + data: InputType.YAML, + }, + getExpected: (testCase) => testCase.data.output, + } +); diff --git a/test/spec-blst/aggregate_sigs_verify.test.ts b/test/spec-blst/aggregate_sigs_verify.test.ts new file mode 100644 index 0000000..de4cb74 --- /dev/null +++ b/test/spec-blst/aggregate_sigs_verify.test.ts @@ -0,0 +1,39 @@ +import path from "path"; +import {describeDirectorySpecTest, InputType} from "@chainsafe/lodestar-spec-test-util"; +import {aggregateVerify, Signature, PublicKey} from "@chainsafe/blst-ts"; +import {fromHexString} from "../util"; + +interface IAggregateSigsVerifyTestCase { + data: { + input: { + pubkeys: string[]; + messages: string[]; + signature: string; + }; + output: boolean; + }; +} + +describeDirectorySpecTest( + "BLS - aggregate sigs verify", + path.join(__dirname, "../../node_modules/@chainsafe/eth2-spec-tests/tests/general/phase0/bls/aggregate_verify/small"), + (testCase) => { + const {pubkeys, messages, signature} = testCase.data.input; + + try { + const msgs = messages.map(fromHexString); + const pks = pubkeys.map((pubkey) => PublicKey.fromBytes(fromHexString(pubkey))); + const sig = Signature.fromBytes(fromHexString(signature)); + + return aggregateVerify(msgs, pks, sig); + } catch (e) { + return false; + } + }, + { + inputTypes: { + data: InputType.YAML, + }, + getExpected: (testCase) => testCase.data.output, + } +); diff --git a/test/spec-blst/fast_aggregate_verify.test.ts b/test/spec-blst/fast_aggregate_verify.test.ts new file mode 100644 index 0000000..2982a73 --- /dev/null +++ b/test/spec-blst/fast_aggregate_verify.test.ts @@ -0,0 +1,42 @@ +import path from "path"; +import {describeDirectorySpecTest, InputType} from "@chainsafe/lodestar-spec-test-util"; +import {fastAggregateVerify, Signature, PublicKey} from "@chainsafe/blst-ts"; +import {fromHexString} from "../util"; + +interface IAggregateSigsVerifyTestCase { + data: { + input: { + pubkeys: string[]; + message: string; + signature: string; + }; + output: boolean; + }; +} + +describeDirectorySpecTest( + "BLS - aggregate sigs verify", + path.join( + __dirname, + "../../node_modules/@chainsafe/eth2-spec-tests/tests/general/phase0/bls/fast_aggregate_verify/small" + ), + (testCase) => { + const {pubkeys, message, signature} = testCase.data.input; + + try { + const msg = fromHexString(message); + const pks = pubkeys.map((pubkey) => PublicKey.fromBytes(fromHexString(pubkey))); + const sig = Signature.fromBytes(fromHexString(signature)); + + return fastAggregateVerify(msg, pks, sig); + } catch (e) { + return false; + } + }, + { + inputTypes: { + data: InputType.YAML, + }, + getExpected: (testCase) => testCase.data.output, + } +); diff --git a/test/spec-blst/sign.test.ts b/test/spec-blst/sign.test.ts new file mode 100644 index 0000000..8108ad8 --- /dev/null +++ b/test/spec-blst/sign.test.ts @@ -0,0 +1,34 @@ +import path from "path"; +import {describeDirectorySpecTest, InputType} from "@chainsafe/lodestar-spec-test-util"; +import {SecretKey} from "@chainsafe/blst-ts"; +import {fromHexString, toHexString} from "../util"; + +interface ISignMessageTestCase { + data: { + input: { + privkey: string; + message: string; + }; + output: string; + }; +} + +describeDirectorySpecTest( + "BLS - sign", + path.join(__dirname, "../../node_modules/@chainsafe/eth2-spec-tests/tests/general/phase0/bls/sign/small"), + (testCase) => { + const {privkey, message} = testCase.data.input; + + const sk = SecretKey.fromBytes(fromHexString(privkey)); + const msg = fromHexString(message); + const sig = sk.sign(msg); + + return toHexString(sig.toBytes()); + }, + { + inputTypes: { + data: InputType.YAML, + }, + getExpected: (testCase) => testCase.data.output, + } +); diff --git a/test/spec-blst/verify.test.ts b/test/spec-blst/verify.test.ts new file mode 100644 index 0000000..fd914ac --- /dev/null +++ b/test/spec-blst/verify.test.ts @@ -0,0 +1,39 @@ +import path from "path"; +import {describeDirectorySpecTest, InputType} from "@chainsafe/lodestar-spec-test-util"; +import {verify, Signature, PublicKey} from "@chainsafe/blst-ts"; +import {fromHexString} from "../util"; + +interface IVerifyTestCase { + data: { + input: { + pubkey: string; + message: string; + signature: string; + }; + output: boolean; + }; +} + +describeDirectorySpecTest( + "BLS - verify", + path.join(__dirname, "../../node_modules/@chainsafe/eth2-spec-tests/tests/general/phase0/bls/verify/small"), + (testCase) => { + const {pubkey, message, signature} = testCase.data.input; + + try { + const msg = fromHexString(message); + const pk = PublicKey.fromBytes(fromHexString(pubkey)); + const sig = Signature.fromBytes(fromHexString(signature)); + + return verify(msg, pk, sig); + } catch (e) { + return false; + } + }, + { + inputTypes: { + data: InputType.YAML, + }, + getExpected: (testCase) => testCase.data.output, + } +); diff --git a/test/util.ts b/test/util.ts new file mode 100644 index 0000000..50478de --- /dev/null +++ b/test/util.ts @@ -0,0 +1,7 @@ +export function fromHexString(hex: string): Buffer { + return Buffer.from(hex.replace("0x", ""), "hex"); +} + +export function toHexString(bytes: Buffer | Uint8Array): string { + return `0x${Buffer.from(bytes).toString("hex")}`; +} diff --git a/yarn.lock b/yarn.lock index 296f5d6..dd7013f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -820,6 +820,9 @@ bip39 "^3.0.2" buffer "^5.4.3" +"@chainsafe/blst-ts@file:../blst-ts": + version "1.0.0" + "@chainsafe/eth2-bls-wasm@^0.5.0": version "0.5.0" resolved "https://registry.yarnpkg.com/@chainsafe/eth2-bls-wasm/-/eth2-bls-wasm-0.5.0.tgz#45d0cb8807b569537d1e0099922a9617e0410b3a" From 928b86a9fbc7566bb699774c746caa67cb628140 Mon Sep 17 00:00:00 2001 From: dapplion Date: Fri, 13 Nov 2020 23:09:13 +0000 Subject: [PATCH 02/51] Benchmark BLST --- test/benchmark/index.ts | 141 +++++++++++++++++++++++++++++++++++++++ test/benchmark/runner.ts | 33 +++++++++ 2 files changed, 174 insertions(+) create mode 100644 test/benchmark/index.ts create mode 100644 test/benchmark/runner.ts diff --git a/test/benchmark/index.ts b/test/benchmark/index.ts new file mode 100644 index 0000000..5aa1b65 --- /dev/null +++ b/test/benchmark/index.ts @@ -0,0 +1,141 @@ +import crypto from "crypto"; +import * as blst from "@chainsafe/blst-ts"; +import * as herumi from "../../src"; +import {runBenchmark} from "./runner"; + +(async function () { + await herumi.initBLS(); + + const aggCount = 30; + + // verify + + runBenchmark<{pk: blst.PublicKey; msg: Uint8Array; sig: blst.Signature}, boolean>({ + id: "BLST verify", + + prepareTest: () => { + const msg = randomMsg(); + const sk = blst.SecretKey.fromKeygen(crypto.randomBytes(32)); + const pk = sk.toPublicKey(); + const sig = sk.sign(msg); + return { + input: {pk, msg, sig}, + resultCheck: (valid) => valid === true, + }; + }, + testRunner: ({pk, msg, sig}) => { + return blst.verify(msg, pk, sig); + }, + }); + + runBenchmark<{pk: herumi.PublicKey; msg: Uint8Array; sig: herumi.Signature}, boolean>({ + id: "HERUMI verify", + + prepareTest: () => { + const msg = randomMsg(); + const keypair = herumi.generateKeyPair(); + const pk = keypair.publicKey; + const sig = keypair.privateKey.signMessage(msg); + return { + input: {pk, msg, sig}, + resultCheck: (valid) => valid === true, + }; + }, + testRunner: ({pk, msg, sig}) => { + return pk.verifyMessage(sig, msg); + }, + }); + + // Fast aggregate + + runBenchmark<{pks: blst.PublicKey[]; msg: Uint8Array; sig: blst.Signature}, boolean>({ + id: "BLST fastAggregateVerify", + + prepareTest: () => { + const msg = randomMsg(); + + const dataArr = range(aggCount).map(() => { + const sk = blst.SecretKey.fromKeygen(crypto.randomBytes(32)); + const pk = sk.toPublicKey(); + const sig = sk.sign(msg); + return {pk, sig}; + }); + + const pks = dataArr.map((data) => data.pk); + const aggSig = blst.AggregateSignature.fromSignatures(dataArr.map((data) => data.sig)); + const sig = aggSig.toSignature(); + + return { + input: {pks, msg, sig}, + resultCheck: (valid) => valid === true, + }; + }, + testRunner: ({pks, msg, sig}) => { + return blst.fastAggregateVerify(msg, pks, sig); + }, + }); + + runBenchmark<{pks: herumi.PublicKey[]; msg: Uint8Array; sig: herumi.Signature}, boolean>({ + id: "HERUMI fastAggregateVerify", + + prepareTest: () => { + const msg = randomMsg(); + + const dataArr = range(aggCount).map(() => { + const keypair = herumi.generateKeyPair(); + const pk = keypair.publicKey; + const sig = keypair.privateKey.signMessage(msg); + return {pk, sig}; + }); + + const pks = dataArr.map((data) => data.pk); + const sig = herumi.Signature.aggregate(dataArr.map((data) => data.sig)); + + return { + input: {pks, msg, sig}, + resultCheck: (valid) => valid === true, + }; + }, + testRunner: ({pks, msg, sig}) => { + return sig.verifyAggregate(pks, msg); + }, + }); + + // Aggregate sigs + + runBenchmark({ + id: `BLST aggregatePubkeys (${aggCount})`, + + prepareTest: () => { + return { + input: range(aggCount).map(() => blst.SecretKey.fromKeygen(crypto.randomBytes(32)).toPublicKey()), + }; + }, + testRunner: (pks) => { + blst.AggregatePublicKey.fromPublicKeys(pks); + }, + }); + + runBenchmark({ + id: `HERUMI aggregatePubkeys (${aggCount})`, + + prepareTest: () => { + return { + input: range(aggCount).map(() => herumi.generateKeyPair().publicKey), + }; + }, + testRunner: (pks) => { + pks.reduce((agg, pk) => agg.add(pk)); + }, + }); +})(); + +function range(n: number): number[] { + const nums: number[] = []; + for (let i = 0; i < n; i++) nums.push(i); + return nums; +} + +function randomMsg(): Uint8Array { + return Uint8Array.from(crypto.randomBytes(32)); +} diff --git a/test/benchmark/runner.ts b/test/benchmark/runner.ts new file mode 100644 index 0000000..19f06fa --- /dev/null +++ b/test/benchmark/runner.ts @@ -0,0 +1,33 @@ +export function runBenchmark({ + prepareTest, + testRunner, + runs = 100, + id, +}: { + prepareTest: (i: number) => {input: T; resultCheck?: (result: R) => boolean}; + testRunner: (input: T) => R; + runs?: number; + id: string; +}) { + const diffsNanoSec: bigint[] = []; + + for (let i = 0; i < runs; i++) { + const {input, resultCheck} = prepareTest(i); + + const start = process.hrtime.bigint(); + const result = testRunner(input); + const end = process.hrtime.bigint(); + + if (resultCheck && !resultCheck(result)) throw Error("Result fails check test"); + diffsNanoSec.push(end - start); + } + + const average = averageBigint(diffsNanoSec); + const opsPerSec = 1e9 / Number(average); + console.log(`${id}: ${opsPerSec.toPrecision(5)} ops/sec (${runs} runs)`); // ±1.74% +} + +function averageBigint(arr: bigint[]): bigint { + const total = arr.reduce((total, value) => total + value); + return total / BigInt(arr.length); +} From f29898d9dc39b624622072e08b8b6027f6ed8b81 Mon Sep 17 00:00:00 2001 From: dapplion Date: Sat, 14 Nov 2020 22:25:22 +0000 Subject: [PATCH 03/51] benchmark as jacobian --- test/benchmark/index.ts | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/test/benchmark/index.ts b/test/benchmark/index.ts index 5aa1b65..c790a9f 100644 --- a/test/benchmark/index.ts +++ b/test/benchmark/index.ts @@ -1,5 +1,6 @@ import crypto from "crypto"; import * as blst from "@chainsafe/blst-ts"; +import {blst as blstBindings} from "@chainsafe/blst-ts/dist/bindings"; import * as herumi from "../../src"; import {runBenchmark} from "./runner"; @@ -116,6 +117,25 @@ import {runBenchmark} from "./runner"; }, }); + runBenchmark({ + id: `BLST aggregatePubkeys as jacobian (${aggCount})`, + + prepareTest: () => { + return { + input: range(aggCount).map(() => { + const pk = blst.SecretKey.fromKeygen(crypto.randomBytes(32)).toPublicKey(); + return blst.AggregatePublicKey.fromPublicKey(pk); + }), + }; + }, + testRunner: (pks) => { + const p1Arr = pks.map((pk) => pk.value); + p1Arr.reduce((agg, pk) => { + return blstBindings.P1.add(agg, pk); + }); + }, + }); + runBenchmark({ id: `HERUMI aggregatePubkeys (${aggCount})`, From 5b06e4f61e7172d512f78d50c31f1016e964fdf6 Mon Sep 17 00:00:00 2001 From: dapplion Date: Thu, 19 Nov 2020 00:23:34 +0000 Subject: [PATCH 04/51] Replace herumi src with BLST --- src/helpers/utils.ts | 13 ++++++ src/index.ts | 45 ++++++++------------ src/keypair.ts | 4 +- src/privateKey.ts | 66 ++++++++++------------------- src/publicKey.ts | 72 +++++++++++++------------------ src/signature.ts | 81 ++++++++++++++--------------------- test/benchmark/index.ts | 2 +- test/unit/index.test.ts | 82 +++++++++++++++--------------------- test/unit/keypair.test.ts | 14 +++--- test/unit/privateKey.test.ts | 16 +++---- test/unit/publicKey.test.ts | 6 +-- yarn.lock | 9 +++- 12 files changed, 174 insertions(+), 236 deletions(-) diff --git a/src/helpers/utils.ts b/src/helpers/utils.ts index 7430d7d..2e829ed 100644 --- a/src/helpers/utils.ts +++ b/src/helpers/utils.ts @@ -1,4 +1,5 @@ import assert from "assert"; +import crypto from "crypto"; import {PUBLIC_KEY_LENGTH, SIGNATURE_LENGTH} from "../constants"; /** @@ -14,5 +15,17 @@ export function padLeft(source: Uint8Array, length: number): Buffer { return result; } +export function hexToBytes(hex: string): Uint8Array { + return Uint8Array.from(Buffer.from(hex.replace("0x", ""), "hex")); +} + +export function bytesToHex(bytes: Uint8Array): string { + return "0x" + Buffer.from(bytes).toString("hex"); +} + +export function getRandomBytes(size: number): Uint8Array { + return Uint8Array.from(crypto.randomBytes(size)); +} + export const EMPTY_PUBLIC_KEY = Buffer.alloc(PUBLIC_KEY_LENGTH); export const EMPTY_SIGNATURE = Buffer.alloc(SIGNATURE_LENGTH); diff --git a/src/index.ts b/src/index.ts index b398620..7dcedbf 100644 --- a/src/index.ts +++ b/src/index.ts @@ -27,7 +27,7 @@ export function generateKeyPair(): Keypair { export function generatePublicKey(secretKey: Uint8Array): Buffer { assert(secretKey, "secretKey is null or undefined"); const keypair = new Keypair(PrivateKey.fromBytes(toBuffer(secretKey))); - return keypair.publicKey.toBytesCompressed(); + return keypair.publicKey.toBytes(); } /** @@ -39,7 +39,7 @@ export function sign(secretKey: Uint8Array, messageHash: Uint8Array): Buffer { assert(secretKey, "secretKey is null or undefined"); assert(messageHash, "messageHash is null or undefined"); const privateKey = PrivateKey.fromBytes(toBuffer(secretKey)); - return privateKey.signMessage(toBuffer(messageHash)).toBytesCompressed(); + return privateKey.signMessage(toBuffer(messageHash)).toBytes(); } /** @@ -48,13 +48,14 @@ export function sign(secretKey: Uint8Array, messageHash: Uint8Array): Buffer { */ export function aggregateSignatures(signatures: Uint8Array[]): Buffer { assert(signatures && signatures.length > 0, "signatures is null or undefined or empty array"); - return Signature.aggregate( - signatures.map( - (signature): Signature => { - return Signature.fromCompressedBytes(signature); - } - ) - ).toBytesCompressed(); + // return Signature.aggregate( + // signatures.map( + // (signature): Signature => { + // return Signature.fromBytes(signature); + // } + // ) + // ).toBytes(); + return Buffer.alloc(0); } /** @@ -62,14 +63,8 @@ export function aggregateSignatures(signatures: Uint8Array[]): Buffer { * @param publicKeys */ export function aggregatePubkeys(publicKeys: Uint8Array[]): Buffer { - assert(publicKeys, "publicKeys is null or undefined"); - if (publicKeys.length === 0) { - return Buffer.alloc(PUBLIC_KEY_LENGTH); - } - return publicKeys - .map((p) => PublicKey.fromBytes(toBuffer(p))) - .reduce((agg, pubKey) => agg.add(pubKey)) - .toBytesCompressed(); + const agg = PublicKey.aggregate(publicKeys.map((p) => PublicKey.fromBytes(p))); + return agg.toBytes(); } /** @@ -84,7 +79,7 @@ export function verify(publicKey: Uint8Array, messageHash: Uint8Array, signature assert(signature, "signature is null or undefined"); try { return PublicKey.fromBytes(publicKey).verifyMessage( - Signature.fromCompressedBytes(toBuffer(signature)), + Signature.fromBytes(toBuffer(signature)), toBuffer(messageHash) ); } catch (e) { @@ -103,7 +98,7 @@ export function verifyAggregate(publicKeys: Uint8Array[], messageHash: Uint8Arra assert(messageHash, "messageHash is null or undefined"); assert(signature, "signature is null or undefined"); try { - return Signature.fromCompressedBytes(signature).verifyAggregate( + return Signature.fromBytes(signature).verifyAggregate( publicKeys.map((pubkey) => PublicKey.fromBytes(pubkey)), messageHash ); @@ -119,12 +114,7 @@ export function verifyAggregate(publicKeys: Uint8Array[], messageHash: Uint8Arra * @param signature * @param fast Check if all messages are different */ -export function verifyMultiple( - publicKeys: Uint8Array[], - messageHashes: Uint8Array[], - signature: Uint8Array, - fast = false -): boolean { +export function verifyMultiple(publicKeys: Uint8Array[], messageHashes: Uint8Array[], signature: Uint8Array): boolean { assert(publicKeys, "publicKey is null or undefined"); assert(messageHashes, "messageHash is null or undefined"); assert(signature, "signature is null or undefined"); @@ -133,10 +123,9 @@ export function verifyMultiple( return false; } try { - return Signature.fromCompressedBytes(toBuffer(signature)).verifyMultiple( + return Signature.fromBytes(toBuffer(signature)).verifyMultiple( publicKeys.map((key) => PublicKey.fromBytes(toBuffer(key))), - messageHashes.map((m) => toBuffer(m)), - fast + messageHashes.map((m) => toBuffer(m)) ); } catch (e) { return false; diff --git a/src/keypair.ts b/src/keypair.ts index ca862b3..2e34c54 100644 --- a/src/keypair.ts +++ b/src/keypair.ts @@ -9,7 +9,7 @@ export class Keypair { public constructor(privateKey: PrivateKey, publicKey?: PublicKey) { this._privateKey = privateKey; if (!publicKey) { - this._publicKey = PublicKey.fromPrivateKey(this._privateKey); + this._publicKey = privateKey.toPublicKey(); } else { this._publicKey = publicKey; } @@ -24,6 +24,6 @@ export class Keypair { } public static generate(): Keypair { - return new Keypair(PrivateKey.random()); + return new Keypair(PrivateKey.fromKeygen()); } } diff --git a/src/privateKey.ts b/src/privateKey.ts index deb8029..21d513c 100644 --- a/src/privateKey.ts +++ b/src/privateKey.ts @@ -1,66 +1,46 @@ -import {SECRET_KEY_LENGTH} from "./constants"; -import assert from "assert"; -import {SecretKeyType} from "@chainsafe/eth2-bls-wasm"; -import {generateRandomSecretKey} from "@chainsafe/bls-keygen"; -import {getContext} from "./context"; +import * as blst from "@chainsafe/blst-ts"; +import {blst as blstBindings} from "@chainsafe/blst-ts/dist/bindings"; +import {bytesToHex, getRandomBytes, hexToBytes} from "./helpers/utils"; import {PublicKey} from "./publicKey"; import {Signature} from "./signature"; export class PrivateKey { - private value: SecretKeyType; + readonly value: blst.SecretKey; - protected constructor(value: SecretKeyType) { + constructor(value: blst.SecretKey) { this.value = value; } - public static fromBytes(bytes: Uint8Array): PrivateKey { - assert(bytes.length === SECRET_KEY_LENGTH, "Private key should have 32 bytes"); - const context = getContext(); - const secretKey = new context.SecretKey(); - secretKey.deserialize(Buffer.from(bytes)); - return new PrivateKey(secretKey); + static fromBytes(bytes: Uint8Array): PrivateKey { + const sk = blst.SecretKey.fromBytes(bytes); + return new PrivateKey(sk); } - public static fromHexString(value: string): PrivateKey { - value = value.replace("0x", ""); - assert(value.length === SECRET_KEY_LENGTH * 2, "secret key must have 32 bytes"); - const context = getContext(); - return new PrivateKey(context.deserializeHexStrToSecretKey(value)); + static fromHex(hex: string): PrivateKey { + return this.fromBytes(hexToBytes(hex)); } - public static fromInt(num: number): PrivateKey { - const context = getContext(); - const secretKey = new context.SecretKey(); - secretKey.setInt(num); - return new PrivateKey(secretKey); + static fromKeygen(entropy?: Uint8Array): PrivateKey { + const sk = blst.SecretKey.fromKeygen(entropy || getRandomBytes(32)); + return new PrivateKey(sk); } - public static random(): PrivateKey { - const randomKey: Buffer = generateRandomSecretKey(); - return this.fromBytes(randomKey); - } - - public getValue(): SecretKeyType { - return this.value; - } - - // public sign(message: Uint8Array): Signature { - // return Signature.fromValue(this.value.sign(message)); - // } - - public signMessage(message: Uint8Array): Signature { + signMessage(message: Uint8Array): Signature { return Signature.fromValue(this.value.sign(message)); } - public toPublicKey(): PublicKey { - return PublicKey.fromPublicKeyType(this.value.getPublicKey()); + toPublicKey(): PublicKey { + const p1 = new blstBindings.P1(this.value.value); + const jacobian = new blst.AggregatePublicKey(p1); + const affine = jacobian.toPublicKey(); + return new PublicKey(affine, jacobian); } - public toBytes(): Buffer { - return Buffer.from(this.value.serialize()); + toBytes(): Buffer { + return Buffer.from(this.value.toBytes()); } - public toHexString(): string { - return `0x${this.value.serializeToHexStr()}`; + toHex(): string { + return bytesToHex(this.toBytes()); } } diff --git a/src/publicKey.ts b/src/publicKey.ts index c994489..203e4bb 100644 --- a/src/publicKey.ts +++ b/src/publicKey.ts @@ -1,61 +1,47 @@ -import {PrivateKey} from "./privateKey"; -import {PublicKeyType} from "@chainsafe/eth2-bls-wasm"; -import {getContext} from "./context"; -import {PUBLIC_KEY_LENGTH} from "./constants"; -import assert from "assert"; +import * as blst from "@chainsafe/blst-ts"; +import {blst as blstBindings} from "@chainsafe/blst-ts/dist/bindings"; import {Signature} from "./signature"; -import {EMPTY_PUBLIC_KEY} from "./helpers/utils"; +import {bytesToHex, hexToBytes} from "./helpers/utils"; export class PublicKey { - private value: PublicKeyType; + readonly affine: blst.PublicKey; + readonly jacobian: blst.AggregatePublicKey; - protected constructor(value: PublicKeyType) { - this.value = value; + constructor(affine: blst.PublicKey, jacobian: blst.AggregatePublicKey) { + this.affine = affine; + this.jacobian = jacobian; } - public static fromPrivateKey(privateKey: PrivateKey): PublicKey { - return privateKey.toPublicKey(); + static fromBytes(bytes: Uint8Array): PublicKey { + const affine = blst.PublicKey.fromBytes(bytes); + const jacobian = blst.AggregatePublicKey.fromPublicKey(affine); + return new PublicKey(affine, jacobian); } - public static fromBytes(bytes: Uint8Array): PublicKey { - const context = getContext(); - const publicKey = new context.PublicKey(); - if (!EMPTY_PUBLIC_KEY.equals(bytes)) { - publicKey.deserialize(bytes); - } - return new PublicKey(publicKey); + static fromHex(hex: string): PublicKey { + return this.fromBytes(hexToBytes(hex)); } - public static fromHex(value: string): PublicKey { - value = value.replace("0x", ""); - assert(value.length === PUBLIC_KEY_LENGTH * 2); - const context = getContext(); - return new PublicKey(context.deserializeHexStrToPublicKey(value)); + static aggregate(pubkeys: PublicKey[]): PublicKey { + const p1Arr = pubkeys.map((pk) => pk.jacobian.value); + const aggP1 = p1Arr.reduce((_agg, pk) => { + return blstBindings.P1.add(_agg, pk); + }); + + const jacobian = new blst.AggregatePublicKey(aggP1); + const affine = jacobian.toPublicKey(); + return new PublicKey(affine, jacobian); } - public static fromPublicKeyType(value: PublicKeyType): PublicKey { - return new PublicKey(value); + verifyMessage(signature: Signature, message: Uint8Array): boolean { + return blst.verify(message, this.affine, signature.value); } - public add(other: PublicKey): PublicKey { - const agg = new PublicKey(this.value.clone()); - agg.value.add(other.value); - return agg; + toBytes(): Buffer { + return Buffer.from(this.affine.toBytes()); } - public verifyMessage(signature: Signature, messageHash: Uint8Array): boolean { - return this.value.verify(signature.getValue(), messageHash); - } - - public toBytesCompressed(): Buffer { - return Buffer.from(this.value.serialize()); - } - - public toHexString(): string { - return `0x${this.toBytesCompressed().toString("hex")}`; - } - - public getValue(): PublicKeyType { - return this.value; + toHex(): string { + return bytesToHex(this.toBytes()); } } diff --git a/src/signature.ts b/src/signature.ts index 08c38e6..60ae9f0 100644 --- a/src/signature.ts +++ b/src/signature.ts @@ -1,72 +1,53 @@ -import assert from "assert"; -import {FP_POINT_LENGTH} from "./constants"; -import {SignatureType} from "@chainsafe/eth2-bls-wasm"; -import {getContext} from "./context"; +import * as blst from "@chainsafe/blst-ts"; +import {blst as blstBindings} from "@chainsafe/blst-ts/dist/bindings"; +import {bytesToHex, hexToBytes} from "./helpers/utils"; import {PublicKey} from "./publicKey"; -import {EMPTY_SIGNATURE} from "./helpers/utils"; export class Signature { - private value: SignatureType; + readonly value: blst.Signature; - protected constructor(value: SignatureType) { + constructor(value: blst.Signature) { this.value = value; - assert(this.value.isValidOrder()); } - public static fromCompressedBytes(value: Uint8Array): Signature { - assert(value.length === 2 * FP_POINT_LENGTH, `Signature must have ${2 * FP_POINT_LENGTH} bytes`); - const context = getContext(); - const signature = new context.Signature(); - if (!EMPTY_SIGNATURE.equals(value)) { - signature.deserialize(value); - } + static fromBytes(bytes: Uint8Array): Signature { + return new Signature(blst.Signature.fromBytes(bytes)); + } + + static fromHex(hex: string): Signature { + return this.fromBytes(hexToBytes(hex)); + } + + static fromValue(signature: blst.Signature): Signature { return new Signature(signature); } - public static fromValue(signature: SignatureType): Signature { - return new Signature(signature); + static aggregate(signatures: Signature[]): Signature { + const agg = blst.AggregateSignature.fromSignatures(signatures.map((sig) => sig.value)); + return new Signature(agg.toSignature()); } - public static aggregate(signatures: Signature[]): Signature { - const context = getContext(); - const signature = new context.Signature(); - signature.aggregate(signatures.map((sig) => sig.getValue())); - return new Signature(signature); - } - - public add(other: Signature): Signature { - const agg = this.value.clone(); - agg.add(other.value); - return new Signature(agg); - } - - public getValue(): SignatureType { - return this.value; - } - - public verifyAggregate(publicKeys: PublicKey[], message: Uint8Array): boolean { - return this.value.fastAggregateVerify( - publicKeys.map((key) => key.getValue()), - message + verifyAggregate(publicKeys: PublicKey[], message: Uint8Array): boolean { + return blst.fastAggregateVerify( + message, + publicKeys.map((pk) => pk.affine), + this.value ); } - public verifyMultiple(publicKeys: PublicKey[], messages: Uint8Array[], fast = false): boolean { - const msgs = Buffer.concat(messages); - if (!fast && !getContext().areAllMsgDifferent(msgs)) { - return false; - } - return this.value.aggregateVerifyNoCheck( - publicKeys.map((key) => key.getValue()), - msgs + verifyMultiple(publicKeys: PublicKey[], messages: Uint8Array[]): boolean { + return blst.aggregateVerify( + messages, + publicKeys.map((pk) => pk.affine), + this.value ); } - public toBytesCompressed(): Buffer { - return Buffer.from(this.value.serialize()); + toBytes(): Buffer { + return Buffer.from(this.value.toBytes()); } - public toHex(): string { - return "0x" + this.value.serializeToHexStr(); + toHex(): string { + return bytesToHex(this.toBytes()); } } diff --git a/test/benchmark/index.ts b/test/benchmark/index.ts index c790a9f..bcda706 100644 --- a/test/benchmark/index.ts +++ b/test/benchmark/index.ts @@ -145,7 +145,7 @@ import {runBenchmark} from "./runner"; }; }, testRunner: (pks) => { - pks.reduce((agg, pk) => agg.add(pk)); + herumi.PublicKey.aggregate(pks); }, }); })(); diff --git a/test/unit/index.test.ts b/test/unit/index.test.ts index af18eb2..5298689 100644 --- a/test/unit/index.test.ts +++ b/test/unit/index.test.ts @@ -23,7 +23,7 @@ describe("test bls", function () { const keypair = Keypair.generate(); const messageHash = Buffer.from(SHA256.digest(Buffer.from("Test"))); const signature = keypair.privateKey.signMessage(messageHash); - const result = verify(keypair.publicKey.toBytesCompressed(), messageHash, signature.toBytesCompressed()); + const result = verify(keypair.publicKey.toBytes(), messageHash, signature.toBytes()); expect(result).to.be.true; }); @@ -31,16 +31,16 @@ describe("test bls", function () { const keypair = Keypair.generate(); const messageHash = Buffer.from(SHA256.digest(Buffer.from("Test"))); const signature = keypair.privateKey.signMessage(messageHash); - const pubKey = keypair.publicKey.toBytesCompressed(); - verify(pubKey, messageHash, signature.toBytesCompressed()); - expect("0x" + pubKey.toString("hex")).to.be.equal(keypair.publicKey.toHexString()); + const pubKey = keypair.publicKey.toBytes(); + verify(pubKey, messageHash, signature.toBytes()); + expect("0x" + pubKey.toString("hex")).to.be.equal(keypair.publicKey.toHex()); }); it("should fail verify empty signature", () => { const keypair = Keypair.generate(); const messageHash2 = Buffer.from(SHA256.digest(Buffer.from("Test message2"))); const signature = Buffer.alloc(96); - const result = verify(keypair.publicKey.toBytesCompressed(), messageHash2, signature); + const result = verify(keypair.publicKey.toBytes(), messageHash2, signature); expect(result).to.be.false; }); @@ -49,7 +49,7 @@ describe("test bls", function () { const messageHash = Buffer.from(SHA256.digest(Buffer.from("Test message"))); const messageHash2 = Buffer.from(SHA256.digest(Buffer.from("Test message2"))); const signature = keypair.privateKey.signMessage(messageHash); - const result = verify(keypair.publicKey.toBytesCompressed(), messageHash2, signature.toBytesCompressed()); + const result = verify(keypair.publicKey.toBytes(), messageHash2, signature.toBytes()); expect(result).to.be.false; }); @@ -58,7 +58,7 @@ describe("test bls", function () { const keypair2 = Keypair.generate(); const messageHash = Buffer.from(SHA256.digest(Buffer.from("Test message"))); const signature = keypair.privateKey.signMessage(messageHash); - const result = verify(keypair2.publicKey.toBytesCompressed(), messageHash, signature.toBytesCompressed()); + const result = verify(keypair2.publicKey.toBytes(), messageHash, signature.toBytes()); expect(result).to.be.false; }); }); @@ -80,21 +80,15 @@ describe("test bls", function () { const signature3 = keypair3.privateKey.signMessage(message2); const signature4 = keypair4.privateKey.signMessage(message2); - const aggregatePubKey12 = aggregatePubkeys([ - keypair1.publicKey.toBytesCompressed(), - keypair2.publicKey.toBytesCompressed(), - ]); + const aggregatePubKey12 = aggregatePubkeys([keypair1.publicKey.toBytes(), keypair2.publicKey.toBytes()]); - const aggregatePubKey34 = aggregatePubkeys([ - keypair3.publicKey.toBytesCompressed(), - keypair4.publicKey.toBytesCompressed(), - ]); + const aggregatePubKey34 = aggregatePubkeys([keypair3.publicKey.toBytes(), keypair4.publicKey.toBytes()]); const aggregateSignature = aggregateSignatures([ - signature1.toBytesCompressed(), - signature2.toBytesCompressed(), - signature3.toBytesCompressed(), - signature4.toBytesCompressed(), + signature1.toBytes(), + signature2.toBytes(), + signature3.toBytes(), + signature4.toBytes(), ]); const result = verifyMultiple([aggregatePubKey12, aggregatePubKey34], [message1, message2], aggregateSignature); @@ -118,22 +112,21 @@ describe("test bls", function () { const signature4 = keypair4.privateKey.signMessage(message); const aggregateSignature = aggregateSignatures([ - signature1.toBytesCompressed(), - signature2.toBytesCompressed(), - signature3.toBytesCompressed(), - signature4.toBytesCompressed(), + signature1.toBytes(), + signature2.toBytes(), + signature3.toBytes(), + signature4.toBytes(), ]); const result = verifyMultiple( [ - keypair1.publicKey.toBytesCompressed(), - keypair2.publicKey.toBytesCompressed(), - keypair3.publicKey.toBytesCompressed(), - keypair4.publicKey.toBytesCompressed(), + keypair1.publicKey.toBytes(), + keypair2.publicKey.toBytes(), + keypair3.publicKey.toBytes(), + keypair4.publicKey.toBytes(), ], [message, message, message, message], - aggregateSignature, - true + aggregateSignature ); expect(result).to.be.true; @@ -155,21 +148,15 @@ describe("test bls", function () { const signature3 = keypair3.privateKey.signMessage(message2); const signature4 = keypair4.privateKey.signMessage(message2); - const aggregatePubKey12 = bls.aggregatePubkeys([ - keypair1.publicKey.toBytesCompressed(), - keypair2.publicKey.toBytesCompressed(), - ]); + const aggregatePubKey12 = bls.aggregatePubkeys([keypair1.publicKey.toBytes(), keypair2.publicKey.toBytes()]); - const aggregatePubKey34 = bls.aggregatePubkeys([ - keypair3.publicKey.toBytesCompressed(), - keypair4.publicKey.toBytesCompressed(), - ]); + const aggregatePubKey34 = bls.aggregatePubkeys([keypair3.publicKey.toBytes(), keypair4.publicKey.toBytes()]); const aggregateSignature = bls.aggregateSignatures([ - signature1.toBytesCompressed(), - signature2.toBytesCompressed(), - signature3.toBytesCompressed(), - signature4.toBytesCompressed(), + signature1.toBytes(), + signature2.toBytes(), + signature3.toBytes(), + signature4.toBytes(), ]); const result = bls.verifyMultiple( @@ -195,16 +182,13 @@ describe("test bls", function () { const signature3 = keypair3.privateKey.signMessage(message2); const signature4 = keypair4.privateKey.signMessage(message2); - const aggregatePubKey12 = bls.aggregatePubkeys([ - keypair1.publicKey.toBytesCompressed(), - keypair2.publicKey.toBytesCompressed(), - ]); + const aggregatePubKey12 = bls.aggregatePubkeys([keypair1.publicKey.toBytes(), keypair2.publicKey.toBytes()]); const aggregateSignature = bls.aggregateSignatures([ - signature1.toBytesCompressed(), - signature2.toBytesCompressed(), - signature3.toBytesCompressed(), - signature4.toBytesCompressed(), + signature1.toBytes(), + signature2.toBytes(), + signature3.toBytes(), + signature4.toBytes(), ]); const result = bls.verifyMultiple([aggregatePubKey12], [message2, message1], aggregateSignature); diff --git a/test/unit/keypair.test.ts b/test/unit/keypair.test.ts index 8cbbddf..984a684 100644 --- a/test/unit/keypair.test.ts +++ b/test/unit/keypair.test.ts @@ -12,9 +12,9 @@ describe("keypair", function () { }); it("should create from private and public key", () => { - const secret = PrivateKey.random(); - const secret2 = PrivateKey.random(); - const publicKey = PublicKey.fromBytes(PublicKey.fromPrivateKey(secret2).toBytesCompressed()); + const secret = PrivateKey.fromKeygen(); + const secret2 = PrivateKey.fromKeygen(); + const publicKey = PublicKey.fromBytes(secret2.toPublicKey().toBytes()); const keypair = new Keypair(secret, publicKey); expect(keypair.publicKey).to.be.equal(publicKey); expect(keypair.privateKey).to.be.equal(secret); @@ -22,11 +22,9 @@ describe("keypair", function () { }); it("should create from private", () => { - const secret = PrivateKey.random(); - const publicKey = PublicKey.fromPrivateKey(secret); + const secret = PrivateKey.fromKeygen(); + const publicKey = secret.toPublicKey(); const keypair = new Keypair(secret); - expect(keypair.publicKey.toBytesCompressed().toString("hex")).to.be.equal( - publicKey.toBytesCompressed().toString("hex") - ); + expect(keypair.publicKey.toBytes().toString("hex")).to.be.equal(publicKey.toBytes().toString("hex")); }); }); diff --git a/test/unit/privateKey.test.ts b/test/unit/privateKey.test.ts index 0fa9e4d..c02b479 100644 --- a/test/unit/privateKey.test.ts +++ b/test/unit/privateKey.test.ts @@ -12,27 +12,27 @@ describe("privateKey", function () { destroy(); }); - it("should generate random private key", function () { - const privateKey1 = PrivateKey.random(); - const privateKey2 = PrivateKey.random(); - expect(privateKey1.toHexString()).to.not.be.equal(privateKey2.toHexString()); + it("should generate fromKeygen private key", function () { + const privateKey1 = PrivateKey.fromKeygen(); + const privateKey2 = PrivateKey.fromKeygen(); + expect(privateKey1.toHex()).to.not.be.equal(privateKey2.toHex()); }); it("should export private key to hex string", function () { const privateKey = "0x07656fd676da43883d163f49566c72b9cbf0a5a294f26808c807700732456da7"; - expect(PrivateKey.fromHexString(privateKey).toHexString()).to.be.equal(privateKey); + expect(PrivateKey.fromHex(privateKey).toHex()).to.be.equal(privateKey); const privateKey2 = "07656fd676da43883d163f49566c72b9cbf0a5a294f26808c807700732456da7"; - expect(PrivateKey.fromHexString(privateKey2).toHexString()).to.be.equal(privateKey); + expect(PrivateKey.fromHex(privateKey2).toHex()).to.be.equal(privateKey); }); it("should export private key to bytes", function () { - expect(PrivateKey.random().toBytes().length).to.be.equal(SECRET_KEY_LENGTH); + expect(PrivateKey.fromKeygen().toBytes().length).to.be.equal(SECRET_KEY_LENGTH); }); it("should not accept too short private key", function () { - expect(() => PrivateKey.fromHexString("0x2123")).to.throw(); + expect(() => PrivateKey.fromHex("0x2123")).to.throw(); }); }); diff --git a/test/unit/publicKey.test.ts b/test/unit/publicKey.test.ts index 485148e..28091bf 100644 --- a/test/unit/publicKey.test.ts +++ b/test/unit/publicKey.test.ts @@ -14,16 +14,16 @@ describe("public key", function () { it("from hex", function () { const publicKey = "0xb6f21199594b56d77670564bf422cb331d5281ca2c1f9a45588a56881d8287ef8619efa6456d6cd2ef61306aa5b21311"; - expect(PublicKey.fromHex(publicKey).toHexString()).to.be.equal(publicKey); + expect(PublicKey.fromHex(publicKey).toHex()).to.be.equal(publicKey); }); it("from bytes", function () { const publicKey = "b6f21199594b56d77670564bf422cb331d5281ca2c1f9a45588a56881d8287ef8619efa6456d6cd2ef61306aa5b21311"; - expect(PublicKey.fromBytes(Buffer.from(publicKey, "hex")).toHexString()).to.be.equal(`0x${publicKey}`); + expect(PublicKey.fromBytes(Buffer.from(publicKey, "hex")).toHex()).to.be.equal(`0x${publicKey}`); }); it("from private key", function () { - PublicKey.fromPrivateKey(PrivateKey.random()); + PrivateKey.fromKeygen().toPublicKey(); }); }); diff --git a/yarn.lock b/yarn.lock index dd7013f..cc97422 100644 --- a/yarn.lock +++ b/yarn.lock @@ -821,7 +821,9 @@ buffer "^5.4.3" "@chainsafe/blst-ts@file:../blst-ts": - version "1.0.0" + version "0.1.1" + dependencies: + node-fetch "^2.6.1" "@chainsafe/eth2-bls-wasm@^0.5.0": version "0.5.0" @@ -4415,6 +4417,11 @@ node-environment-flags@1.0.5: object.getownpropertydescriptors "^2.0.3" semver "^5.7.0" +node-fetch@^2.6.1: + version "2.6.1" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052" + integrity sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw== + node-libs-browser@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/node-libs-browser/-/node-libs-browser-2.2.1.tgz#b64f513d18338625f90346d27b0d235e631f6425" From 57694c2e5401b1213020017f272a7d68896f35be Mon Sep 17 00:00:00 2001 From: dapplion Date: Thu, 19 Nov 2020 13:22:41 +0000 Subject: [PATCH 05/51] Co-exist implementations --- package.json | 2 +- src/blst/index.ts | 146 ++++++++++++++++++ src/{ => blst}/keypair.ts | 0 src/{ => blst}/privateKey.ts | 8 +- src/{ => blst}/publicKey.ts | 14 +- src/blst/signature.ts | 63 ++++++++ src/constants.ts | 2 + src/helpers/utils.ts | 6 +- src/{ => herumi}/context.ts | 2 +- src/herumi/index.ts | 146 ++++++++++++++++++ src/herumi/keypair.ts | 29 ++++ src/herumi/privateKey.ts | 52 +++++++ src/herumi/publicKey.ts | 44 ++++++ src/herumi/signature.ts | 69 +++++++++ src/{ => herumi}/web.ts | 0 src/index.ts | 147 +------------------ src/signature.ts | 53 ------- test/benchmark/index.ts | 12 +- test/params.ts | 2 + test/spec-blst/aggregate_sigs.test.ts | 29 ---- test/spec-blst/aggregate_sigs_verify.test.ts | 39 ----- test/spec-blst/fast_aggregate_verify.test.ts | 42 ------ test/spec-blst/sign.test.ts | 34 ----- test/spec-blst/verify.test.ts | 39 ----- test/spec/aggregate_sigs.test.ts | 49 +++---- test/spec/aggregate_sigs_verify.test.ts | 43 ++---- test/spec/fast_aggregate_verify.test.ts | 44 ++---- test/spec/sign.test.ts | 38 +++-- test/spec/verify.test.ts | 37 ++--- test/switch.ts | 30 ++++ test/unit/context.test.ts | 19 --- test/unit/index.test.ts | 33 ++--- test/unit/keypair.test.ts | 5 +- test/unit/privateKey.test.ts | 6 +- test/unit/publicKey.test.ts | 5 +- yarn.lock | 13 +- 36 files changed, 707 insertions(+), 595 deletions(-) create mode 100644 src/blst/index.ts rename src/{ => blst}/keypair.ts (100%) rename src/{ => blst}/privateKey.ts (76%) rename src/{ => blst}/publicKey.ts (68%) create mode 100644 src/blst/signature.ts rename src/{ => herumi}/context.ts (93%) create mode 100644 src/herumi/index.ts create mode 100644 src/herumi/keypair.ts create mode 100644 src/herumi/privateKey.ts create mode 100644 src/herumi/publicKey.ts create mode 100644 src/herumi/signature.ts rename src/{ => herumi}/web.ts (100%) delete mode 100644 src/signature.ts create mode 100644 test/params.ts delete mode 100644 test/spec-blst/aggregate_sigs.test.ts delete mode 100644 test/spec-blst/aggregate_sigs_verify.test.ts delete mode 100644 test/spec-blst/fast_aggregate_verify.test.ts delete mode 100644 test/spec-blst/sign.test.ts delete mode 100644 test/spec-blst/verify.test.ts create mode 100644 test/switch.ts delete mode 100644 test/unit/context.test.ts diff --git a/package.json b/package.json index 996b109..56666ad 100644 --- a/package.json +++ b/package.json @@ -40,7 +40,7 @@ }, "dependencies": { "@chainsafe/bls-keygen": "^0.2.0", - "@chainsafe/blst-ts": "file:../blst-ts", + "@chainsafe/blst": "^0.1.0", "@chainsafe/eth2-bls-wasm": "^0.5.0", "assert": "^1.4.1" }, diff --git a/src/blst/index.ts b/src/blst/index.ts new file mode 100644 index 0000000..380f1d7 --- /dev/null +++ b/src/blst/index.ts @@ -0,0 +1,146 @@ +import assert from "assert"; +import {Keypair} from "./keypair"; +import {PrivateKey} from "./privateKey"; +import {PublicKey} from "./publicKey"; +import {Signature} from "./signature"; +import {toBuffer} from "../helpers/utils"; +export * from "../constants"; + +export {Keypair, PrivateKey, PublicKey, Signature}; + +export async function initBLS() { + // Native bindings require no init() call +} +export function destroy() { + // Native bindings require no destroy() call +} + +/** + * Generates new secret and public key + */ +export function generateKeyPair(): Keypair { + return Keypair.generate(); +} + +/** + * Generates public key from given secret. + * @param {BLSSecretKey} secretKey + */ +export function generatePublicKey(secretKey: Uint8Array): Buffer { + assert(secretKey, "secretKey is null or undefined"); + const keypair = new Keypair(PrivateKey.fromBytes(toBuffer(secretKey))); + return keypair.publicKey.toBytes(); +} + +/** + * Signs given message using secret key. + * @param secretKey + * @param messageHash + */ +export function sign(secretKey: Uint8Array, messageHash: Uint8Array): Buffer { + assert(secretKey, "secretKey is null or undefined"); + assert(messageHash, "messageHash is null or undefined"); + const privateKey = PrivateKey.fromBytes(toBuffer(secretKey)); + return privateKey.signMessage(toBuffer(messageHash)).toBytes(); +} + +/** + * Compines all given signature into one. + * @param signatures + */ +export function aggregateSignatures(signatures: Uint8Array[]): Buffer { + const agg = Signature.aggregate(signatures.map((p) => Signature.fromBytes(p))); + return agg.toBytes(); +} + +/** + * Combines all given public keys into single one + * @param publicKeys + */ +export function aggregatePubkeys(publicKeys: Uint8Array[]): Buffer { + const agg = PublicKey.aggregate(publicKeys.map((p) => PublicKey.fromBytes(p))); + return agg.toBytes(); +} + +/** + * Verifies if signature is message signed with given public key. + * @param publicKey + * @param messageHash + * @param signature + */ +export function verify(publicKey: Uint8Array, messageHash: Uint8Array, signature: Uint8Array): boolean { + assert(publicKey, "publicKey is null or undefined"); + assert(messageHash, "messageHash is null or undefined"); + assert(signature, "signature is null or undefined"); + try { + return PublicKey.fromBytes(publicKey).verifyMessage( + Signature.fromBytes(toBuffer(signature)), + toBuffer(messageHash) + ); + } catch (e) { + return false; + } +} + +/** + * Verifies if aggregated signature is same message signed with given public keys. + * @param publicKeys + * @param messageHash + * @param signature + */ +export function verifyAggregate(publicKeys: Uint8Array[], messageHash: Uint8Array, signature: Uint8Array): boolean { + assert(publicKeys, "publicKey is null or undefined"); + assert(messageHash, "messageHash is null or undefined"); + assert(signature, "signature is null or undefined"); + try { + return Signature.fromBytes(signature).verifyAggregate( + publicKeys.map((pubkey) => PublicKey.fromBytes(pubkey)), + messageHash + ); + } catch (e) { + return false; + } +} + +/** + * Verifies if signature is list of message signed with corresponding public key. + * @param publicKeys + * @param messageHashes + * @param signature + * @param fast Check if all messages are different + */ +export function verifyMultiple(publicKeys: Uint8Array[], messageHashes: Uint8Array[], signature: Uint8Array): boolean { + assert(publicKeys, "publicKey is null or undefined"); + assert(messageHashes, "messageHash is null or undefined"); + assert(signature, "signature is null or undefined"); + + if (publicKeys.length === 0 || publicKeys.length != messageHashes.length) { + return false; + } + try { + return Signature.fromBytes(toBuffer(signature)).verifyMultiple( + publicKeys.map((key) => PublicKey.fromBytes(toBuffer(key))), + messageHashes.map((m) => toBuffer(m)) + ); + } catch (e) { + return false; + } +} + +export default { + generateKeyPair, + generatePublicKey, + sign, + aggregateSignatures, + aggregatePubkeys, + verify, + verifyAggregate, + verifyMultiple, + + Keypair, + PrivateKey, + PublicKey, + Signature, + initBLS, + destroy, +}; diff --git a/src/keypair.ts b/src/blst/keypair.ts similarity index 100% rename from src/keypair.ts rename to src/blst/keypair.ts diff --git a/src/privateKey.ts b/src/blst/privateKey.ts similarity index 76% rename from src/privateKey.ts rename to src/blst/privateKey.ts index 21d513c..c375cf6 100644 --- a/src/privateKey.ts +++ b/src/blst/privateKey.ts @@ -1,6 +1,5 @@ -import * as blst from "@chainsafe/blst-ts"; -import {blst as blstBindings} from "@chainsafe/blst-ts/dist/bindings"; -import {bytesToHex, getRandomBytes, hexToBytes} from "./helpers/utils"; +import * as blst from "@chainsafe/blst"; +import {bytesToHex, getRandomBytes, hexToBytes} from "../helpers/utils"; import {PublicKey} from "./publicKey"; import {Signature} from "./signature"; @@ -30,8 +29,7 @@ export class PrivateKey { } toPublicKey(): PublicKey { - const p1 = new blstBindings.P1(this.value.value); - const jacobian = new blst.AggregatePublicKey(p1); + const jacobian = this.value.toAggregatePublicKey(); const affine = jacobian.toPublicKey(); return new PublicKey(affine, jacobian); } diff --git a/src/publicKey.ts b/src/blst/publicKey.ts similarity index 68% rename from src/publicKey.ts rename to src/blst/publicKey.ts index 203e4bb..67f5281 100644 --- a/src/publicKey.ts +++ b/src/blst/publicKey.ts @@ -1,7 +1,6 @@ -import * as blst from "@chainsafe/blst-ts"; -import {blst as blstBindings} from "@chainsafe/blst-ts/dist/bindings"; +import * as blst from "@chainsafe/blst"; +import {bytesToHex, hexToBytes} from "../helpers/utils"; import {Signature} from "./signature"; -import {bytesToHex, hexToBytes} from "./helpers/utils"; export class PublicKey { readonly affine: blst.PublicKey; @@ -23,18 +22,13 @@ export class PublicKey { } static aggregate(pubkeys: PublicKey[]): PublicKey { - const p1Arr = pubkeys.map((pk) => pk.jacobian.value); - const aggP1 = p1Arr.reduce((_agg, pk) => { - return blstBindings.P1.add(_agg, pk); - }); - - const jacobian = new blst.AggregatePublicKey(aggP1); + const jacobian = blst.aggregatePubkeys(pubkeys.map((pk) => pk.jacobian)); const affine = jacobian.toPublicKey(); return new PublicKey(affine, jacobian); } verifyMessage(signature: Signature, message: Uint8Array): boolean { - return blst.verify(message, this.affine, signature.value); + return signature.verify(this, message); } toBytes(): Buffer { diff --git a/src/blst/signature.ts b/src/blst/signature.ts new file mode 100644 index 0000000..508fedf --- /dev/null +++ b/src/blst/signature.ts @@ -0,0 +1,63 @@ +import * as blst from "@chainsafe/blst"; +import {bytesToHex, hexToBytes} from "../helpers/utils"; +import {PublicKey} from "./publicKey"; + +export class Signature { + readonly affine: blst.Signature; + + constructor(value: blst.Signature) { + this.affine = value; + } + + static fromBytes(bytes: Uint8Array): Signature { + return new Signature(blst.Signature.fromBytes(bytes)); + } + + static fromHex(hex: string): Signature { + return this.fromBytes(hexToBytes(hex)); + } + + static fromValue(signature: blst.Signature): Signature { + return new Signature(signature); + } + + static aggregate(signatures: Signature[]): Signature { + const agg = blst.AggregateSignature.fromSignatures(signatures.map((sig) => sig.affine)); + return new Signature(agg.toSignature()); + } + + verify(publicKey: PublicKey, message: Uint8Array): boolean { + return this.aggregateVerify([message], [publicKey.affine]); + } + + verifyAggregate(publicKeys: PublicKey[], message: Uint8Array): boolean { + const agg = PublicKey.aggregate(publicKeys); + return this.aggregateVerify([message], [agg.affine]); + } + + verifyMultiple(publicKeys: PublicKey[], messages: Uint8Array[]): boolean { + return this.aggregateVerify( + messages, + publicKeys.map((pk) => pk.affine) + ); + } + + private aggregateVerify(msgs: Uint8Array[], pks: blst.PublicKey[]): boolean { + // If this set is simply an infinity signature and infinity pubkey then skip verification. + // This has the effect of always declaring that this sig/pubkey combination is valid. + // for Eth2.0 specs tests + if (this.affine.value.is_inf() && pks.length === 1 && pks[0].value.is_inf()) { + return true; + } + + return blst.aggregateVerify(msgs, pks, this.affine); + } + + toBytes(): Buffer { + return Buffer.from(this.affine.toBytes()); + } + + toHex(): string { + return bytesToHex(this.toBytes()); + } +} diff --git a/src/constants.ts b/src/constants.ts index 2243a76..cf34046 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -3,3 +3,5 @@ export const SIGNATURE_LENGTH = 96; export const FP_POINT_LENGTH = 48; export const PUBLIC_KEY_LENGTH = FP_POINT_LENGTH; export const G2_HASH_PADDING = 16; +export const EMPTY_PUBLIC_KEY = Buffer.alloc(PUBLIC_KEY_LENGTH); +export const EMPTY_SIGNATURE = Buffer.alloc(SIGNATURE_LENGTH); diff --git a/src/helpers/utils.ts b/src/helpers/utils.ts index 2e829ed..50a34d9 100644 --- a/src/helpers/utils.ts +++ b/src/helpers/utils.ts @@ -1,6 +1,5 @@ import assert from "assert"; import crypto from "crypto"; -import {PUBLIC_KEY_LENGTH, SIGNATURE_LENGTH} from "../constants"; /** * Pads byte array with zeroes on left side up to desired length. @@ -27,5 +26,6 @@ export function getRandomBytes(size: number): Uint8Array { return Uint8Array.from(crypto.randomBytes(size)); } -export const EMPTY_PUBLIC_KEY = Buffer.alloc(PUBLIC_KEY_LENGTH); -export const EMPTY_SIGNATURE = Buffer.alloc(SIGNATURE_LENGTH); +export function toBuffer(input: Uint8Array): Buffer { + return Buffer.from(input.buffer, input.byteOffset, input.length); +} diff --git a/src/context.ts b/src/herumi/context.ts similarity index 93% rename from src/context.ts rename to src/herumi/context.ts index aceb809..65992a4 100644 --- a/src/context.ts +++ b/src/herumi/context.ts @@ -14,7 +14,7 @@ export async function setupBls(): Promise { } // Cache a promise for Bls instead of Bls to make sure it is initialized only once -export async function init(): Promise { +export async function initBLS(): Promise { if (!blsGlobalPromise) { blsGlobalPromise = setupBls(); } diff --git a/src/herumi/index.ts b/src/herumi/index.ts new file mode 100644 index 0000000..0d80cc7 --- /dev/null +++ b/src/herumi/index.ts @@ -0,0 +1,146 @@ +import {Keypair} from "./keypair"; +import {PrivateKey} from "./privateKey"; +import {PublicKey} from "./publicKey"; +import {Signature} from "./signature"; +import {initBLS, destroy} from "./context"; +import {PUBLIC_KEY_LENGTH} from "../constants"; +import assert from "assert"; +import {toBuffer} from "../helpers/utils"; + +export {Keypair, PrivateKey, PublicKey, Signature, initBLS, destroy}; + +/** + * Generates new secret and public key + */ +export function generateKeyPair(): Keypair { + return Keypair.generate(); +} + +/** + * Generates public key from given secret. + * @param {BLSSecretKey} secretKey + */ +export function generatePublicKey(secretKey: Uint8Array): Buffer { + assert(secretKey, "secretKey is null or undefined"); + const keypair = new Keypair(PrivateKey.fromBytes(toBuffer(secretKey))); + return keypair.publicKey.toBytes(); +} + +/** + * Signs given message using secret key. + * @param secretKey + * @param messageHash + */ +export function sign(secretKey: Uint8Array, messageHash: Uint8Array): Buffer { + assert(secretKey, "secretKey is null or undefined"); + assert(messageHash, "messageHash is null or undefined"); + const privateKey = PrivateKey.fromBytes(toBuffer(secretKey)); + return privateKey.signMessage(toBuffer(messageHash)).toBytes(); +} + +/** + * Compines all given signature into one. + * @param signatures + */ +export function aggregateSignatures(signatures: Uint8Array[]): Buffer { + assert(signatures && signatures.length > 0, "EMPTY_AGGREGATE_ARRAY"); + const agg = Signature.aggregate(signatures.map((signature): Signature => Signature.fromBytes(signature))); + return agg.toBytes(); +} + +/** + * Combines all given public keys into single one + * @param publicKeys + */ +export function aggregatePubkeys(publicKeys: Uint8Array[]): Buffer { + assert(publicKeys, "publicKeys is null or undefined"); + if (publicKeys.length === 0) { + return Buffer.alloc(PUBLIC_KEY_LENGTH); + } + return publicKeys + .map((p) => PublicKey.fromBytes(toBuffer(p))) + .reduce((agg, pubKey) => agg.add(pubKey)) + .toBytes(); +} + +/** + * Verifies if signature is message signed with given public key. + * @param publicKey + * @param messageHash + * @param signature + */ +export function verify(publicKey: Uint8Array, messageHash: Uint8Array, signature: Uint8Array): boolean { + assert(publicKey, "publicKey is null or undefined"); + assert(messageHash, "messageHash is null or undefined"); + assert(signature, "signature is null or undefined"); + try { + return PublicKey.fromBytes(publicKey).verifyMessage( + Signature.fromBytes(toBuffer(signature)), + toBuffer(messageHash) + ); + } catch (e) { + return false; + } +} + +/** + * Verifies if aggregated signature is same message signed with given public keys. + * @param publicKeys + * @param messageHash + * @param signature + */ +export function verifyAggregate(publicKeys: Uint8Array[], messageHash: Uint8Array, signature: Uint8Array): boolean { + assert(publicKeys, "publicKey is null or undefined"); + assert(messageHash, "messageHash is null or undefined"); + assert(signature, "signature is null or undefined"); + try { + return Signature.fromBytes(signature).verifyAggregate( + publicKeys.map((pubkey) => PublicKey.fromBytes(pubkey)), + messageHash + ); + } catch (e) { + return false; + } +} + +/** + * Verifies if signature is list of message signed with corresponding public key. + * @param publicKeys + * @param messageHashes + * @param signature + */ +export function verifyMultiple(publicKeys: Uint8Array[], messageHashes: Uint8Array[], signature: Uint8Array): boolean { + assert(publicKeys, "publicKey is null or undefined"); + assert(messageHashes, "messageHash is null or undefined"); + assert(signature, "signature is null or undefined"); + + if (publicKeys.length === 0 || publicKeys.length != messageHashes.length) { + return false; + } + try { + return Signature.fromBytes(toBuffer(signature)).verifyMultiple( + publicKeys.map((key) => PublicKey.fromBytes(toBuffer(key))), + messageHashes.map((m) => toBuffer(m)) + ); + } catch (e) { + return false; + } +} + +export default { + generateKeyPair, + generatePublicKey, + sign, + aggregateSignatures, + aggregatePubkeys, + verify, + verifyAggregate, + verifyMultiple, + + Keypair, + PrivateKey, + PublicKey, + Signature, + initBLS, + destroy, +}; diff --git a/src/herumi/keypair.ts b/src/herumi/keypair.ts new file mode 100644 index 0000000..2e34c54 --- /dev/null +++ b/src/herumi/keypair.ts @@ -0,0 +1,29 @@ +import {PublicKey} from "./publicKey"; +import {PrivateKey} from "./privateKey"; + +export class Keypair { + private readonly _publicKey: PublicKey; + + private readonly _privateKey: PrivateKey; + + public constructor(privateKey: PrivateKey, publicKey?: PublicKey) { + this._privateKey = privateKey; + if (!publicKey) { + this._publicKey = privateKey.toPublicKey(); + } else { + this._publicKey = publicKey; + } + } + + public get publicKey(): PublicKey { + return this._publicKey; + } + + public get privateKey(): PrivateKey { + return this._privateKey; + } + + public static generate(): Keypair { + return new Keypair(PrivateKey.fromKeygen()); + } +} diff --git a/src/herumi/privateKey.ts b/src/herumi/privateKey.ts new file mode 100644 index 0000000..43a0668 --- /dev/null +++ b/src/herumi/privateKey.ts @@ -0,0 +1,52 @@ +import assert from "assert"; +import {SecretKeyType} from "@chainsafe/eth2-bls-wasm"; +import {generateRandomSecretKey} from "@chainsafe/bls-keygen"; +import {SECRET_KEY_LENGTH} from "../constants"; +import {getContext} from "./context"; +import {PublicKey} from "./publicKey"; +import {Signature} from "./signature"; +import {bytesToHex, hexToBytes} from "../helpers/utils"; + +export class PrivateKey { + readonly value: SecretKeyType; + + constructor(value: SecretKeyType) { + this.value = value; + } + + static fromBytes(bytes: Uint8Array): PrivateKey { + assert(bytes.length === SECRET_KEY_LENGTH, "Private key should have 32 bytes"); + const context = getContext(); + const secretKey = new context.SecretKey(); + secretKey.deserialize(Buffer.from(bytes)); + return new PrivateKey(secretKey); + } + + static fromHex(hex: string): PrivateKey { + return this.fromBytes(hexToBytes(hex)); + } + + static fromKeygen(entropy?: Uint8Array): PrivateKey { + return this.fromBytes(generateRandomSecretKey(Buffer.from(entropy))); + } + + getValue(): SecretKeyType { + return this.value; + } + + signMessage(message: Uint8Array): Signature { + return new Signature(this.value.sign(message)); + } + + toPublicKey(): PublicKey { + return new PublicKey(this.value.getPublicKey()); + } + + toBytes(): Buffer { + return Buffer.from(this.value.serialize()); + } + + toHex(): string { + return bytesToHex(this.toBytes()); + } +} diff --git a/src/herumi/publicKey.ts b/src/herumi/publicKey.ts new file mode 100644 index 0000000..140fd0f --- /dev/null +++ b/src/herumi/publicKey.ts @@ -0,0 +1,44 @@ +import {PublicKeyType} from "@chainsafe/eth2-bls-wasm"; +import {getContext} from "./context"; +import {EMPTY_PUBLIC_KEY} from "../constants"; +import {Signature} from "./signature"; +import {bytesToHex, hexToBytes} from "../helpers/utils"; + +export class PublicKey { + readonly value: PublicKeyType; + + constructor(value: PublicKeyType) { + this.value = value; + } + + static fromBytes(bytes: Uint8Array): PublicKey { + const context = getContext(); + const publicKey = new context.PublicKey(); + if (!EMPTY_PUBLIC_KEY.equals(bytes)) { + publicKey.deserialize(bytes); + } + return new PublicKey(publicKey); + } + + static fromHex(hex: string): PublicKey { + return this.fromBytes(hexToBytes(hex)); + } + + add(other: PublicKey): PublicKey { + const agg = new PublicKey(this.value.clone()); + agg.value.add(other.value); + return agg; + } + + verifyMessage(signature: Signature, messageHash: Uint8Array): boolean { + return this.value.verify(signature.value, messageHash); + } + + toBytes(): Buffer { + return Buffer.from(this.value.serialize()); + } + + toHex(): string { + return bytesToHex(this.toBytes()); + } +} diff --git a/src/herumi/signature.ts b/src/herumi/signature.ts new file mode 100644 index 0000000..dd804c2 --- /dev/null +++ b/src/herumi/signature.ts @@ -0,0 +1,69 @@ +import assert from "assert"; +import {SIGNATURE_LENGTH, EMPTY_SIGNATURE} from "../constants"; +import {SignatureType} from "@chainsafe/eth2-bls-wasm"; +import {getContext} from "./context"; +import {PublicKey} from "./publicKey"; +import {bytesToHex, hexToBytes} from "../helpers/utils"; + +export class Signature { + readonly value: SignatureType; + + constructor(value: SignatureType) { + this.value = value; + assert(this.value.isValidOrder()); + } + + static fromBytes(bytes: Uint8Array): Signature { + assert(bytes.length === SIGNATURE_LENGTH, `Signature must have ${SIGNATURE_LENGTH} bytes`); + const context = getContext(); + const signature = new context.Signature(); + if (!EMPTY_SIGNATURE.equals(bytes)) { + signature.deserialize(bytes); + } + return new Signature(signature); + } + + static fromHex(hex: string): Signature { + return this.fromBytes(hexToBytes(hex)); + } + + static aggregate(signatures: Signature[]): Signature { + const context = getContext(); + const signature = new context.Signature(); + signature.aggregate(signatures.map((sig) => sig.value)); + return new Signature(signature); + } + + add(other: Signature): Signature { + const agg = this.value.clone(); + agg.add(other.value); + return new Signature(agg); + } + + verify(publicKey: PublicKey, message: Uint8Array): boolean { + return publicKey.value.verify(this.value, message); + } + + verifyAggregate(publicKeys: PublicKey[], message: Uint8Array): boolean { + return this.value.fastAggregateVerify( + publicKeys.map((key) => key.value), + message + ); + } + + verifyMultiple(publicKeys: PublicKey[], messages: Uint8Array[]): boolean { + const msgs = Buffer.concat(messages); + return this.value.aggregateVerifyNoCheck( + publicKeys.map((key) => key.value), + msgs + ); + } + + toBytes(): Buffer { + return Buffer.from(this.value.serialize()); + } + + toHex(): string { + return bytesToHex(this.toBytes()); + } +} diff --git a/src/web.ts b/src/herumi/web.ts similarity index 100% rename from src/web.ts rename to src/herumi/web.ts diff --git a/src/index.ts b/src/index.ts index 7dcedbf..f03d4ab 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,144 +1,3 @@ -import {Keypair} from "./keypair"; -import {PrivateKey} from "./privateKey"; -import {PublicKey} from "./publicKey"; -import {Signature} from "./signature"; -import {PUBLIC_KEY_LENGTH} from "./constants"; -import assert from "assert"; - -export {Keypair, PrivateKey, PublicKey, Signature}; - -export {init as initBLS} from "./context"; - -function toBuffer(input: Uint8Array): Buffer { - return Buffer.from(input.buffer, input.byteOffset, input.length); -} - -/** - * Generates new secret and public key - */ -export function generateKeyPair(): Keypair { - return Keypair.generate(); -} - -/** - * Generates public key from given secret. - * @param {BLSSecretKey} secretKey - */ -export function generatePublicKey(secretKey: Uint8Array): Buffer { - assert(secretKey, "secretKey is null or undefined"); - const keypair = new Keypair(PrivateKey.fromBytes(toBuffer(secretKey))); - return keypair.publicKey.toBytes(); -} - -/** - * Signs given message using secret key. - * @param secretKey - * @param messageHash - */ -export function sign(secretKey: Uint8Array, messageHash: Uint8Array): Buffer { - assert(secretKey, "secretKey is null or undefined"); - assert(messageHash, "messageHash is null or undefined"); - const privateKey = PrivateKey.fromBytes(toBuffer(secretKey)); - return privateKey.signMessage(toBuffer(messageHash)).toBytes(); -} - -/** - * Compines all given signature into one. - * @param signatures - */ -export function aggregateSignatures(signatures: Uint8Array[]): Buffer { - assert(signatures && signatures.length > 0, "signatures is null or undefined or empty array"); - // return Signature.aggregate( - // signatures.map( - // (signature): Signature => { - // return Signature.fromBytes(signature); - // } - // ) - // ).toBytes(); - return Buffer.alloc(0); -} - -/** - * Combines all given public keys into single one - * @param publicKeys - */ -export function aggregatePubkeys(publicKeys: Uint8Array[]): Buffer { - const agg = PublicKey.aggregate(publicKeys.map((p) => PublicKey.fromBytes(p))); - return agg.toBytes(); -} - -/** - * Verifies if signature is message signed with given public key. - * @param publicKey - * @param messageHash - * @param signature - */ -export function verify(publicKey: Uint8Array, messageHash: Uint8Array, signature: Uint8Array): boolean { - assert(publicKey, "publicKey is null or undefined"); - assert(messageHash, "messageHash is null or undefined"); - assert(signature, "signature is null or undefined"); - try { - return PublicKey.fromBytes(publicKey).verifyMessage( - Signature.fromBytes(toBuffer(signature)), - toBuffer(messageHash) - ); - } catch (e) { - return false; - } -} - -/** - * Verifies if aggregated signature is same message signed with given public keys. - * @param publicKeys - * @param messageHash - * @param signature - */ -export function verifyAggregate(publicKeys: Uint8Array[], messageHash: Uint8Array, signature: Uint8Array): boolean { - assert(publicKeys, "publicKey is null or undefined"); - assert(messageHash, "messageHash is null or undefined"); - assert(signature, "signature is null or undefined"); - try { - return Signature.fromBytes(signature).verifyAggregate( - publicKeys.map((pubkey) => PublicKey.fromBytes(pubkey)), - messageHash - ); - } catch (e) { - return false; - } -} - -/** - * Verifies if signature is list of message signed with corresponding public key. - * @param publicKeys - * @param messageHashes - * @param signature - * @param fast Check if all messages are different - */ -export function verifyMultiple(publicKeys: Uint8Array[], messageHashes: Uint8Array[], signature: Uint8Array): boolean { - assert(publicKeys, "publicKey is null or undefined"); - assert(messageHashes, "messageHash is null or undefined"); - assert(signature, "signature is null or undefined"); - - if (publicKeys.length === 0 || publicKeys.length != messageHashes.length) { - return false; - } - try { - return Signature.fromBytes(toBuffer(signature)).verifyMultiple( - publicKeys.map((key) => PublicKey.fromBytes(toBuffer(key))), - messageHashes.map((m) => toBuffer(m)) - ); - } catch (e) { - return false; - } -} - -export default { - generateKeyPair, - generatePublicKey, - sign, - aggregateSignatures, - aggregatePubkeys, - verify, - verifyAggregate, - verifyMultiple, -}; +import blst from "./blst"; +export default blst; +export * from "./blst"; diff --git a/src/signature.ts b/src/signature.ts deleted file mode 100644 index 60ae9f0..0000000 --- a/src/signature.ts +++ /dev/null @@ -1,53 +0,0 @@ -import * as blst from "@chainsafe/blst-ts"; -import {blst as blstBindings} from "@chainsafe/blst-ts/dist/bindings"; -import {bytesToHex, hexToBytes} from "./helpers/utils"; -import {PublicKey} from "./publicKey"; - -export class Signature { - readonly value: blst.Signature; - - constructor(value: blst.Signature) { - this.value = value; - } - - static fromBytes(bytes: Uint8Array): Signature { - return new Signature(blst.Signature.fromBytes(bytes)); - } - - static fromHex(hex: string): Signature { - return this.fromBytes(hexToBytes(hex)); - } - - static fromValue(signature: blst.Signature): Signature { - return new Signature(signature); - } - - static aggregate(signatures: Signature[]): Signature { - const agg = blst.AggregateSignature.fromSignatures(signatures.map((sig) => sig.value)); - return new Signature(agg.toSignature()); - } - - verifyAggregate(publicKeys: PublicKey[], message: Uint8Array): boolean { - return blst.fastAggregateVerify( - message, - publicKeys.map((pk) => pk.affine), - this.value - ); - } - - verifyMultiple(publicKeys: PublicKey[], messages: Uint8Array[]): boolean { - return blst.aggregateVerify( - messages, - publicKeys.map((pk) => pk.affine), - this.value - ); - } - - toBytes(): Buffer { - return Buffer.from(this.value.toBytes()); - } - - toHex(): string { - return bytesToHex(this.toBytes()); - } -} diff --git a/test/benchmark/index.ts b/test/benchmark/index.ts index bcda706..b726098 100644 --- a/test/benchmark/index.ts +++ b/test/benchmark/index.ts @@ -1,6 +1,5 @@ import crypto from "crypto"; -import * as blst from "@chainsafe/blst-ts"; -import {blst as blstBindings} from "@chainsafe/blst-ts/dist/bindings"; +import * as blst from "@chainsafe/blst"; import * as herumi from "../../src"; import {runBenchmark} from "./runner"; @@ -49,7 +48,7 @@ import {runBenchmark} from "./runner"; // Fast aggregate - runBenchmark<{pks: blst.PublicKey[]; msg: Uint8Array; sig: blst.Signature}, boolean>({ + runBenchmark<{pks: blst.AggregatePublicKey[]; msg: Uint8Array; sig: blst.Signature}, boolean>({ id: "BLST fastAggregateVerify", prepareTest: () => { @@ -57,7 +56,7 @@ import {runBenchmark} from "./runner"; const dataArr = range(aggCount).map(() => { const sk = blst.SecretKey.fromKeygen(crypto.randomBytes(32)); - const pk = sk.toPublicKey(); + const pk = sk.toAggregatePublicKey(); const sig = sk.sign(msg); return {pk, sig}; }); @@ -129,10 +128,7 @@ import {runBenchmark} from "./runner"; }; }, testRunner: (pks) => { - const p1Arr = pks.map((pk) => pk.value); - p1Arr.reduce((agg, pk) => { - return blstBindings.P1.add(agg, pk); - }); + blst.aggregatePubkeys(pks); }, }); diff --git a/test/params.ts b/test/params.ts new file mode 100644 index 0000000..513cc91 --- /dev/null +++ b/test/params.ts @@ -0,0 +1,2 @@ +import path from "path"; +export const SPEC_TESTS_DIR = path.join(__dirname, "../node_modules/@chainsafe/eth2-spec-tests/tests"); diff --git a/test/spec-blst/aggregate_sigs.test.ts b/test/spec-blst/aggregate_sigs.test.ts deleted file mode 100644 index 80a4eed..0000000 --- a/test/spec-blst/aggregate_sigs.test.ts +++ /dev/null @@ -1,29 +0,0 @@ -import path from "path"; -import {describeDirectorySpecTest, InputType} from "@chainsafe/lodestar-spec-test-util"; -import {AggregateSignature} from "@chainsafe/blst-ts"; -import {fromHexString, toHexString} from "../util"; - -interface IAggregateSigsTestCase { - data: { - input: string[]; - output: string; - }; -} - -describeDirectorySpecTest( - "BLS - aggregate sigs", - path.join(__dirname, "../../node_modules/@chainsafe/eth2-spec-tests/tests/general/phase0/bls/aggregate/small"), - (testCase) => { - const signaturesHex = testCase.data.input; - const signaturesBytes = signaturesHex.map(fromHexString); - const aggSig = AggregateSignature.fromSignaturesBytes(signaturesBytes); - const aggSigHex = aggSig.toSignature().toBytes(); - return toHexString(aggSigHex); - }, - { - inputTypes: { - data: InputType.YAML, - }, - getExpected: (testCase) => testCase.data.output, - } -); diff --git a/test/spec-blst/aggregate_sigs_verify.test.ts b/test/spec-blst/aggregate_sigs_verify.test.ts deleted file mode 100644 index de4cb74..0000000 --- a/test/spec-blst/aggregate_sigs_verify.test.ts +++ /dev/null @@ -1,39 +0,0 @@ -import path from "path"; -import {describeDirectorySpecTest, InputType} from "@chainsafe/lodestar-spec-test-util"; -import {aggregateVerify, Signature, PublicKey} from "@chainsafe/blst-ts"; -import {fromHexString} from "../util"; - -interface IAggregateSigsVerifyTestCase { - data: { - input: { - pubkeys: string[]; - messages: string[]; - signature: string; - }; - output: boolean; - }; -} - -describeDirectorySpecTest( - "BLS - aggregate sigs verify", - path.join(__dirname, "../../node_modules/@chainsafe/eth2-spec-tests/tests/general/phase0/bls/aggregate_verify/small"), - (testCase) => { - const {pubkeys, messages, signature} = testCase.data.input; - - try { - const msgs = messages.map(fromHexString); - const pks = pubkeys.map((pubkey) => PublicKey.fromBytes(fromHexString(pubkey))); - const sig = Signature.fromBytes(fromHexString(signature)); - - return aggregateVerify(msgs, pks, sig); - } catch (e) { - return false; - } - }, - { - inputTypes: { - data: InputType.YAML, - }, - getExpected: (testCase) => testCase.data.output, - } -); diff --git a/test/spec-blst/fast_aggregate_verify.test.ts b/test/spec-blst/fast_aggregate_verify.test.ts deleted file mode 100644 index 2982a73..0000000 --- a/test/spec-blst/fast_aggregate_verify.test.ts +++ /dev/null @@ -1,42 +0,0 @@ -import path from "path"; -import {describeDirectorySpecTest, InputType} from "@chainsafe/lodestar-spec-test-util"; -import {fastAggregateVerify, Signature, PublicKey} from "@chainsafe/blst-ts"; -import {fromHexString} from "../util"; - -interface IAggregateSigsVerifyTestCase { - data: { - input: { - pubkeys: string[]; - message: string; - signature: string; - }; - output: boolean; - }; -} - -describeDirectorySpecTest( - "BLS - aggregate sigs verify", - path.join( - __dirname, - "../../node_modules/@chainsafe/eth2-spec-tests/tests/general/phase0/bls/fast_aggregate_verify/small" - ), - (testCase) => { - const {pubkeys, message, signature} = testCase.data.input; - - try { - const msg = fromHexString(message); - const pks = pubkeys.map((pubkey) => PublicKey.fromBytes(fromHexString(pubkey))); - const sig = Signature.fromBytes(fromHexString(signature)); - - return fastAggregateVerify(msg, pks, sig); - } catch (e) { - return false; - } - }, - { - inputTypes: { - data: InputType.YAML, - }, - getExpected: (testCase) => testCase.data.output, - } -); diff --git a/test/spec-blst/sign.test.ts b/test/spec-blst/sign.test.ts deleted file mode 100644 index 8108ad8..0000000 --- a/test/spec-blst/sign.test.ts +++ /dev/null @@ -1,34 +0,0 @@ -import path from "path"; -import {describeDirectorySpecTest, InputType} from "@chainsafe/lodestar-spec-test-util"; -import {SecretKey} from "@chainsafe/blst-ts"; -import {fromHexString, toHexString} from "../util"; - -interface ISignMessageTestCase { - data: { - input: { - privkey: string; - message: string; - }; - output: string; - }; -} - -describeDirectorySpecTest( - "BLS - sign", - path.join(__dirname, "../../node_modules/@chainsafe/eth2-spec-tests/tests/general/phase0/bls/sign/small"), - (testCase) => { - const {privkey, message} = testCase.data.input; - - const sk = SecretKey.fromBytes(fromHexString(privkey)); - const msg = fromHexString(message); - const sig = sk.sign(msg); - - return toHexString(sig.toBytes()); - }, - { - inputTypes: { - data: InputType.YAML, - }, - getExpected: (testCase) => testCase.data.output, - } -); diff --git a/test/spec-blst/verify.test.ts b/test/spec-blst/verify.test.ts deleted file mode 100644 index fd914ac..0000000 --- a/test/spec-blst/verify.test.ts +++ /dev/null @@ -1,39 +0,0 @@ -import path from "path"; -import {describeDirectorySpecTest, InputType} from "@chainsafe/lodestar-spec-test-util"; -import {verify, Signature, PublicKey} from "@chainsafe/blst-ts"; -import {fromHexString} from "../util"; - -interface IVerifyTestCase { - data: { - input: { - pubkey: string; - message: string; - signature: string; - }; - output: boolean; - }; -} - -describeDirectorySpecTest( - "BLS - verify", - path.join(__dirname, "../../node_modules/@chainsafe/eth2-spec-tests/tests/general/phase0/bls/verify/small"), - (testCase) => { - const {pubkey, message, signature} = testCase.data.input; - - try { - const msg = fromHexString(message); - const pk = PublicKey.fromBytes(fromHexString(pubkey)); - const sig = Signature.fromBytes(fromHexString(signature)); - - return verify(msg, pk, sig); - } catch (e) { - return false; - } - }, - { - inputTypes: { - data: InputType.YAML, - }, - getExpected: (testCase) => testCase.data.output, - } -); diff --git a/test/spec/aggregate_sigs.test.ts b/test/spec/aggregate_sigs.test.ts index 70f69da..2baa1e7 100644 --- a/test/spec/aggregate_sigs.test.ts +++ b/test/spec/aggregate_sigs.test.ts @@ -1,6 +1,8 @@ import path from "path"; -import bls, {initBLS} from "../../src"; import {describeDirectorySpecTest, InputType} from "@chainsafe/lodestar-spec-test-util"; +import {bytesToHex, hexToBytes} from "../../src/helpers/utils"; +import {SPEC_TESTS_DIR} from "../params"; +import {forEachImplementation} from "../switch"; interface IAggregateSigsTestCase { data: { @@ -9,32 +11,23 @@ interface IAggregateSigsTestCase { }; } -before(async function f() { - await initBLS(); -}); - -describeDirectorySpecTest( - "BLS - aggregate sigs", - path.join(__dirname, "../../node_modules/@chainsafe/eth2-spec-tests/tests/general/phase0/bls/aggregate/small"), - (testCase) => { - try { - const result = bls.aggregateSignatures( - testCase.data.input.map((pubKey) => { - return Buffer.from(pubKey.replace("0x", ""), "hex"); - }) - ); - return `0x${result.toString("hex")}`; - } catch (e) { - if (e.message === "signatures is null or undefined or empty array") { - return null; +forEachImplementation((bls, implementation) => { + describeDirectorySpecTest( + `${implementation} - bls/aggregate/small`, + path.join(SPEC_TESTS_DIR, "general/phase0/bls/aggregate/small"), + (testCase) => { + try { + const signatures = testCase.data.input; + const agg = bls.aggregateSignatures(signatures.map(hexToBytes)); + return bytesToHex(agg); + } catch (e) { + if (e.message === "EMPTY_AGGREGATE_ARRAY") return null; + throw e; } - throw e; - } - }, - { - inputTypes: { - data: InputType.YAML, }, - getExpected: (testCase) => testCase.data.output, - } -); + { + inputTypes: {data: InputType.YAML}, + getExpected: (testCase) => testCase.data.output, + } + ); +}); diff --git a/test/spec/aggregate_sigs_verify.test.ts b/test/spec/aggregate_sigs_verify.test.ts index 8079830..fd56bbb 100644 --- a/test/spec/aggregate_sigs_verify.test.ts +++ b/test/spec/aggregate_sigs_verify.test.ts @@ -1,6 +1,8 @@ import path from "path"; -import bls, {initBLS} from "../../src"; import {describeDirectorySpecTest, InputType} from "@chainsafe/lodestar-spec-test-util"; +import {hexToBytes} from "../../src/helpers/utils"; +import {SPEC_TESTS_DIR} from "../params"; +import {forEachImplementation} from "../switch"; interface IAggregateSigsVerifyTestCase { data: { @@ -13,30 +15,17 @@ interface IAggregateSigsVerifyTestCase { }; } -before(async function f() { - try { - await initBLS(); - } catch (e) { - console.log(e); - } -}); - -describeDirectorySpecTest( - "BLS - aggregate sigs verify", - path.join(__dirname, "../../node_modules/@chainsafe/eth2-spec-tests/tests/general/phase0/bls/aggregate_verify/small"), - (testCase) => { - const pubkeys = testCase.data.input.pubkeys.map((pubkey) => { - return Buffer.from(pubkey.replace("0x", ""), "hex"); - }); - const messages = testCase.data.input.messages.map((msg) => { - return Buffer.from(msg.replace("0x", ""), "hex"); - }); - return bls.verifyMultiple(pubkeys, messages, Buffer.from(testCase.data.input.signature.replace("0x", ""), "hex")); - }, - { - inputTypes: { - data: InputType.YAML, +forEachImplementation((bls, implementation) => { + describeDirectorySpecTest( + `${implementation} - bls/aggregate_verify/small`, + path.join(SPEC_TESTS_DIR, "general/phase0/bls/aggregate_verify/small"), + (testCase) => { + const {pubkeys, messages, signature} = testCase.data.input; + return bls.verifyMultiple(pubkeys.map(hexToBytes), messages.map(hexToBytes), hexToBytes(signature)); }, - getExpected: (testCase) => testCase.data.output, - } -); + { + inputTypes: {data: InputType.YAML}, + getExpected: (testCase) => testCase.data.output, + } + ); +}); diff --git a/test/spec/fast_aggregate_verify.test.ts b/test/spec/fast_aggregate_verify.test.ts index d4f8322..fe38c06 100644 --- a/test/spec/fast_aggregate_verify.test.ts +++ b/test/spec/fast_aggregate_verify.test.ts @@ -1,6 +1,8 @@ import path from "path"; -import bls, {initBLS} from "../../src"; import {describeDirectorySpecTest, InputType} from "@chainsafe/lodestar-spec-test-util"; +import {hexToBytes} from "../../src/helpers/utils"; +import {SPEC_TESTS_DIR} from "../params"; +import {forEachImplementation} from "../switch"; interface IAggregateSigsVerifyTestCase { data: { @@ -13,31 +15,17 @@ interface IAggregateSigsVerifyTestCase { }; } -before(async function f() { - try { - await initBLS(); - } catch (e) { - console.log(e); - } -}); - -describeDirectorySpecTest( - "BLS - aggregate sigs verify", - path.join( - __dirname, - "../../node_modules/@chainsafe/eth2-spec-tests/tests/general/phase0/bls/fast_aggregate_verify/small" - ), - (testCase) => { - return bls.verifyAggregate( - testCase.data.input.pubkeys.map((key) => Buffer.from(key.replace("0x", ""), "hex")), - Buffer.from(testCase.data.input.message.replace("0x", ""), "hex"), - Buffer.from(testCase.data.input.signature.replace("0x", ""), "hex") - ); - }, - { - inputTypes: { - data: InputType.YAML, +forEachImplementation((bls, implementation) => { + describeDirectorySpecTest( + `${implementation} - bls/fast_aggregate_verify/small`, + path.join(SPEC_TESTS_DIR, "general/phase0/bls/fast_aggregate_verify/small"), + (testCase) => { + const {pubkeys, message, signature} = testCase.data.input; + return bls.verifyAggregate(pubkeys.map(hexToBytes), hexToBytes(message), hexToBytes(signature)); }, - getExpected: (testCase) => testCase.data.output, - } -); + { + inputTypes: {data: InputType.YAML}, + getExpected: (testCase) => testCase.data.output, + } + ); +}); diff --git a/test/spec/sign.test.ts b/test/spec/sign.test.ts index 84d8e83..63856ba 100644 --- a/test/spec/sign.test.ts +++ b/test/spec/sign.test.ts @@ -1,6 +1,8 @@ import path from "path"; -import bls, {initBLS} from "../../src"; import {describeDirectorySpecTest, InputType} from "@chainsafe/lodestar-spec-test-util"; +import {bytesToHex, hexToBytes} from "../../src/helpers/utils"; +import {SPEC_TESTS_DIR} from "../params"; +import {forEachImplementation} from "../switch"; interface ISignMessageTestCase { data: { @@ -12,24 +14,18 @@ interface ISignMessageTestCase { }; } -before(async function f() { - await initBLS(); -}); - -describeDirectorySpecTest( - "BLS - sign", - path.join(__dirname, "../../node_modules/@chainsafe/eth2-spec-tests/tests/general/phase0/bls/sign/small"), - (testCase) => { - const signature = bls.sign( - Buffer.from(testCase.data.input.privkey.replace("0x", ""), "hex"), - Buffer.from(testCase.data.input.message.replace("0x", ""), "hex") - ); - return `0x${signature.toString("hex")}`; - }, - { - inputTypes: { - data: InputType.YAML, +forEachImplementation((bls, implementation) => { + describeDirectorySpecTest( + `${implementation} - bls/sign/small`, + path.join(SPEC_TESTS_DIR, "general/phase0/bls/sign/small"), + (testCase) => { + const {privkey, message} = testCase.data.input; + const signature = bls.sign(hexToBytes(privkey), hexToBytes(message)); + return bytesToHex(signature); }, - getExpected: (testCase) => testCase.data.output, - } -); + { + inputTypes: {data: InputType.YAML}, + getExpected: (testCase) => testCase.data.output, + } + ); +}); diff --git a/test/spec/verify.test.ts b/test/spec/verify.test.ts index 5f98fc8..d4adba2 100644 --- a/test/spec/verify.test.ts +++ b/test/spec/verify.test.ts @@ -1,6 +1,8 @@ import path from "path"; -import bls, {initBLS} from "../../src"; import {describeDirectorySpecTest, InputType} from "@chainsafe/lodestar-spec-test-util"; +import {hexToBytes} from "../../src/helpers/utils"; +import {SPEC_TESTS_DIR} from "../params"; +import {forEachImplementation} from "../switch"; interface IVerifyTestCase { data: { @@ -13,24 +15,17 @@ interface IVerifyTestCase { }; } -before(async function f() { - await initBLS(); -}); - -describeDirectorySpecTest( - "BLS - verify", - path.join(__dirname, "../../node_modules/@chainsafe/eth2-spec-tests/tests/general/phase0/bls/verify/small"), - (testCase) => { - return bls.verify( - Buffer.from(testCase.data.input.pubkey.replace("0x", ""), "hex"), - Buffer.from(testCase.data.input.message.replace("0x", ""), "hex"), - Buffer.from(testCase.data.input.signature.replace("0x", ""), "hex") - ); - }, - { - inputTypes: { - data: InputType.YAML, +forEachImplementation((bls, implementation) => { + describeDirectorySpecTest( + `${implementation} - bls/verify/small`, + path.join(SPEC_TESTS_DIR, "general/phase0/bls/verify/small"), + (testCase) => { + const {pubkey, message, signature} = testCase.data.input; + return bls.verify(hexToBytes(pubkey), hexToBytes(message), hexToBytes(signature)); }, - getExpected: (testCase) => testCase.data.output, - } -); + { + inputTypes: {data: InputType.YAML}, + getExpected: (testCase) => testCase.data.output, + } + ); +}); diff --git a/test/switch.ts b/test/switch.ts new file mode 100644 index 0000000..9b82587 --- /dev/null +++ b/test/switch.ts @@ -0,0 +1,30 @@ +import blst from "../src/blst"; +import herumi from "../src/herumi"; + +export type Implementation = "blst" | "herumi"; +export const implementations: Implementation[] = ["blst", "herumi"]; + +export function getBls(implementation: Implementation) { + switch (implementation) { + case "blst": + return blst; + case "herumi": + return herumi; + } +} + +export function forEachImplementation( + callback: (bls: ReturnType, implementation: Implementation) => void +): void { + for (const implementation of implementations) { + const bls = getBls(implementation); + + if (implementation === "herumi") { + before(async () => { + await bls.initBLS(); + }); + } + + callback(bls, implementation); + } +} diff --git a/test/unit/context.test.ts b/test/unit/context.test.ts deleted file mode 100644 index 1942c54..0000000 --- a/test/unit/context.test.ts +++ /dev/null @@ -1,19 +0,0 @@ -import {init, getContext, destroy} from "../../src/context"; -import {expect} from "chai"; - -describe("bls wasm constext", function () { - afterEach(() => { - destroy(); - }); - - it("initializes and works", async function () { - await init(); - expect(getContext().getCurveOrder()).to.be.equal( - "52435875175126190479447740508185965837690552500527637822603658699938581184513" - ); - }); - - it("throws if context not initialized", async function () { - expect(() => getContext().getCurveOrder()).to.throw(); - }); -}); diff --git a/test/unit/index.test.ts b/test/unit/index.test.ts index 5298689..3aef062 100644 --- a/test/unit/index.test.ts +++ b/test/unit/index.test.ts @@ -1,23 +1,12 @@ -import bls, {aggregatePubkeys, aggregateSignatures, initBLS, Keypair, verify, verifyMultiple} from "../../src"; +import {aggregatePubkeys, aggregateSignatures, initBLS, Keypair, verify, verifyMultiple} from "../../src"; import SHA256 from "@chainsafe/as-sha256"; import {expect} from "chai"; -import {destroy} from "../../src/context"; describe("test bls", function () { before(async function () { await initBLS(); }); - after(function () { - destroy(); - }); - - describe("aggregate pubkey", function () { - it("should aggregate empty array", function () { - expect(bls.aggregatePubkeys([])).to.not.throw; - }); - }); - describe("verify", function () { it("should verify signature", () => { const keypair = Keypair.generate(); @@ -148,22 +137,18 @@ describe("test bls", function () { const signature3 = keypair3.privateKey.signMessage(message2); const signature4 = keypair4.privateKey.signMessage(message2); - const aggregatePubKey12 = bls.aggregatePubkeys([keypair1.publicKey.toBytes(), keypair2.publicKey.toBytes()]); + const aggregatePubKey12 = aggregatePubkeys([keypair1.publicKey.toBytes(), keypair2.publicKey.toBytes()]); - const aggregatePubKey34 = bls.aggregatePubkeys([keypair3.publicKey.toBytes(), keypair4.publicKey.toBytes()]); + const aggregatePubKey34 = aggregatePubkeys([keypair3.publicKey.toBytes(), keypair4.publicKey.toBytes()]); - const aggregateSignature = bls.aggregateSignatures([ + const aggregateSignature = aggregateSignatures([ signature1.toBytes(), signature2.toBytes(), signature3.toBytes(), signature4.toBytes(), ]); - const result = bls.verifyMultiple( - [aggregatePubKey12, aggregatePubKey34], - [message2, message1], - aggregateSignature - ); + const result = verifyMultiple([aggregatePubKey12, aggregatePubKey34], [message2, message1], aggregateSignature); expect(result).to.be.false; }); @@ -182,16 +167,16 @@ describe("test bls", function () { const signature3 = keypair3.privateKey.signMessage(message2); const signature4 = keypair4.privateKey.signMessage(message2); - const aggregatePubKey12 = bls.aggregatePubkeys([keypair1.publicKey.toBytes(), keypair2.publicKey.toBytes()]); + const aggregatePubKey12 = aggregatePubkeys([keypair1.publicKey.toBytes(), keypair2.publicKey.toBytes()]); - const aggregateSignature = bls.aggregateSignatures([ + const aggregateSignature = aggregateSignatures([ signature1.toBytes(), signature2.toBytes(), signature3.toBytes(), signature4.toBytes(), ]); - const result = bls.verifyMultiple([aggregatePubKey12], [message2, message1], aggregateSignature); + const result = verifyMultiple([aggregatePubKey12], [message2, message1], aggregateSignature); expect(result).to.be.false; }); @@ -202,7 +187,7 @@ describe("test bls", function () { const message1 = Buffer.from(SHA256.digest(Buffer.from("Test1"))); const message2 = Buffer.from(SHA256.digest(Buffer.from("Test2"))); - const result = bls.verifyMultiple([], [message2, message1], signature); + const result = verifyMultiple([], [message2, message1], signature); expect(result).to.be.false; }); diff --git a/test/unit/keypair.test.ts b/test/unit/keypair.test.ts index 984a684..ab4a9ef 100644 --- a/test/unit/keypair.test.ts +++ b/test/unit/keypair.test.ts @@ -1,10 +1,9 @@ -import {PrivateKey, PublicKey, Keypair} from "../../src"; +import {PrivateKey, PublicKey, Keypair, destroy, initBLS} from "../../src"; import {expect} from "chai"; -import {destroy, init} from "../../src/context"; describe("keypair", function () { before(async function () { - await init(); + await initBLS(); }); after(function () { diff --git a/test/unit/privateKey.test.ts b/test/unit/privateKey.test.ts index c02b479..81b131a 100644 --- a/test/unit/privateKey.test.ts +++ b/test/unit/privateKey.test.ts @@ -1,11 +1,9 @@ -import {PrivateKey} from "../../src"; +import {PrivateKey, initBLS, destroy, SECRET_KEY_LENGTH} from "../../src"; import {expect} from "chai"; -import {SECRET_KEY_LENGTH} from "../../src/constants"; -import {destroy, init} from "../../src/context"; describe("privateKey", function () { before(async function () { - await init(); + await initBLS(); }); after(function () { diff --git a/test/unit/publicKey.test.ts b/test/unit/publicKey.test.ts index 28091bf..17b3a50 100644 --- a/test/unit/publicKey.test.ts +++ b/test/unit/publicKey.test.ts @@ -1,10 +1,9 @@ -import {destroy, init} from "../../src/context"; -import {PublicKey, PrivateKey} from "../../src"; +import {PublicKey, PrivateKey, initBLS, destroy} from "../../src"; import {expect} from "chai"; describe("public key", function () { before(async function f() { - await init(); + await initBLS(); }); after(function () { diff --git a/yarn.lock b/yarn.lock index cc97422..b2a7e71 100644 --- a/yarn.lock +++ b/yarn.lock @@ -820,10 +820,10 @@ bip39 "^3.0.2" buffer "^5.4.3" -"@chainsafe/blst-ts@file:../blst-ts": - version "0.1.1" - dependencies: - node-fetch "^2.6.1" +"@chainsafe/blst@^0.1.0": + version "0.1.0" + resolved "https://registry.yarnpkg.com/@chainsafe/blst/-/blst-0.1.0.tgz#6aa0ea5e91a0f7ae2d4358fb432eb9a558a4de31" + integrity sha512-sJXrADkWNA06xM5udoPr7cdNgzSBAjHaN1XbwLkbJ637eVSsEzip+P7Uz0ajfUu2pVsqReoEOBnpFJpUOHAEtg== "@chainsafe/eth2-bls-wasm@^0.5.0": version "0.5.0" @@ -4417,11 +4417,6 @@ node-environment-flags@1.0.5: object.getownpropertydescriptors "^2.0.3" semver "^5.7.0" -node-fetch@^2.6.1: - version "2.6.1" - resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052" - integrity sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw== - node-libs-browser@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/node-libs-browser/-/node-libs-browser-2.2.1.tgz#b64f513d18338625f90346d27b0d235e631f6425" From f8cd6e7afadea8bbfa0904b01da8750a67fc6fee Mon Sep 17 00:00:00 2001 From: dapplion Date: Thu, 19 Nov 2020 14:41:45 +0000 Subject: [PATCH 06/51] Update tests to run both implementations --- package.json | 1 - src/herumi/index.ts | 11 +- src/herumi/privateKey.ts | 3 +- src/herumi/publicKey.ts | 12 ++ src/herumi/signature.ts | 4 + test/spec/aggregate_sigs.test.ts | 4 +- test/spec/aggregate_sigs_verify.test.ts | 4 +- test/spec/fast_aggregate_verify.test.ts | 4 +- test/spec/sign.test.ts | 4 +- test/spec/verify.test.ts | 4 +- test/switch.ts | 16 +- test/unit/index.test.ts | 232 ++++++++---------------- test/unit/keypair.test.ts | 29 --- test/unit/privateKey.test.ts | 44 ++--- test/unit/publicKey.test.ts | 33 ++-- yarn.lock | 13 -- 16 files changed, 141 insertions(+), 277 deletions(-) delete mode 100644 test/unit/keypair.test.ts diff --git a/package.json b/package.json index 56666ad..df8fde2 100644 --- a/package.json +++ b/package.json @@ -53,7 +53,6 @@ "@babel/preset-env": "^7.8.4", "@babel/preset-typescript": "^7.8.3", "@babel/register": "^7.8.3", - "@chainsafe/as-sha256": "0.2.0", "@chainsafe/eth2-spec-tests": "0.12.0", "@chainsafe/lodestar-spec-test-util": "^0.5.0", "@types/chai": "^4.2.9", diff --git a/src/herumi/index.ts b/src/herumi/index.ts index 0d80cc7..c4de6f8 100644 --- a/src/herumi/index.ts +++ b/src/herumi/index.ts @@ -43,7 +43,7 @@ export function sign(secretKey: Uint8Array, messageHash: Uint8Array): Buffer { * @param signatures */ export function aggregateSignatures(signatures: Uint8Array[]): Buffer { - assert(signatures && signatures.length > 0, "EMPTY_AGGREGATE_ARRAY"); + assert(signatures, "signatures is null or undefined"); const agg = Signature.aggregate(signatures.map((signature): Signature => Signature.fromBytes(signature))); return agg.toBytes(); } @@ -54,13 +54,8 @@ export function aggregateSignatures(signatures: Uint8Array[]): Buffer { */ export function aggregatePubkeys(publicKeys: Uint8Array[]): Buffer { assert(publicKeys, "publicKeys is null or undefined"); - if (publicKeys.length === 0) { - return Buffer.alloc(PUBLIC_KEY_LENGTH); - } - return publicKeys - .map((p) => PublicKey.fromBytes(toBuffer(p))) - .reduce((agg, pubKey) => agg.add(pubKey)) - .toBytes(); + const agg = PublicKey.aggregate(publicKeys.map((pk) => PublicKey.fromBytes(pk))); + return agg.toBytes(); } /** diff --git a/src/herumi/privateKey.ts b/src/herumi/privateKey.ts index 43a0668..a1ba0d9 100644 --- a/src/herumi/privateKey.ts +++ b/src/herumi/privateKey.ts @@ -27,7 +27,8 @@ export class PrivateKey { } static fromKeygen(entropy?: Uint8Array): PrivateKey { - return this.fromBytes(generateRandomSecretKey(Buffer.from(entropy))); + const sk = generateRandomSecretKey(entropy && Buffer.from(entropy)); + return this.fromBytes(sk); } getValue(): SecretKeyType { diff --git a/src/herumi/publicKey.ts b/src/herumi/publicKey.ts index 140fd0f..82dfe58 100644 --- a/src/herumi/publicKey.ts +++ b/src/herumi/publicKey.ts @@ -24,6 +24,18 @@ export class PublicKey { return this.fromBytes(hexToBytes(hex)); } + static aggregate(pubkeys: PublicKey[]): PublicKey { + if (pubkeys.length === 0) { + throw Error("EMPTY_AGGREGATE_ARRAY"); + } + + const agg = new PublicKey(pubkeys[0].value.clone()); + for (const pk of pubkeys.slice(1)) { + agg.value.add(pk.value); + } + return agg; + } + add(other: PublicKey): PublicKey { const agg = new PublicKey(this.value.clone()); agg.value.add(other.value); diff --git a/src/herumi/signature.ts b/src/herumi/signature.ts index dd804c2..971e3d3 100644 --- a/src/herumi/signature.ts +++ b/src/herumi/signature.ts @@ -28,6 +28,10 @@ export class Signature { } static aggregate(signatures: Signature[]): Signature { + if (signatures.length === 0) { + throw Error("EMPTY_AGGREGATE_ARRAY"); + } + const context = getContext(); const signature = new context.Signature(); signature.aggregate(signatures.map((sig) => sig.value)); diff --git a/test/spec/aggregate_sigs.test.ts b/test/spec/aggregate_sigs.test.ts index 2baa1e7..c2a0e9c 100644 --- a/test/spec/aggregate_sigs.test.ts +++ b/test/spec/aggregate_sigs.test.ts @@ -11,9 +11,9 @@ interface IAggregateSigsTestCase { }; } -forEachImplementation((bls, implementation) => { +forEachImplementation((bls) => { describeDirectorySpecTest( - `${implementation} - bls/aggregate/small`, + "bls/aggregate/small", path.join(SPEC_TESTS_DIR, "general/phase0/bls/aggregate/small"), (testCase) => { try { diff --git a/test/spec/aggregate_sigs_verify.test.ts b/test/spec/aggregate_sigs_verify.test.ts index fd56bbb..5757ab7 100644 --- a/test/spec/aggregate_sigs_verify.test.ts +++ b/test/spec/aggregate_sigs_verify.test.ts @@ -15,9 +15,9 @@ interface IAggregateSigsVerifyTestCase { }; } -forEachImplementation((bls, implementation) => { +forEachImplementation((bls) => { describeDirectorySpecTest( - `${implementation} - bls/aggregate_verify/small`, + "bls/aggregate_verify/small", path.join(SPEC_TESTS_DIR, "general/phase0/bls/aggregate_verify/small"), (testCase) => { const {pubkeys, messages, signature} = testCase.data.input; diff --git a/test/spec/fast_aggregate_verify.test.ts b/test/spec/fast_aggregate_verify.test.ts index fe38c06..53f036c 100644 --- a/test/spec/fast_aggregate_verify.test.ts +++ b/test/spec/fast_aggregate_verify.test.ts @@ -15,9 +15,9 @@ interface IAggregateSigsVerifyTestCase { }; } -forEachImplementation((bls, implementation) => { +forEachImplementation((bls) => { describeDirectorySpecTest( - `${implementation} - bls/fast_aggregate_verify/small`, + "bls/fast_aggregate_verify/small", path.join(SPEC_TESTS_DIR, "general/phase0/bls/fast_aggregate_verify/small"), (testCase) => { const {pubkeys, message, signature} = testCase.data.input; diff --git a/test/spec/sign.test.ts b/test/spec/sign.test.ts index 63856ba..1e488f0 100644 --- a/test/spec/sign.test.ts +++ b/test/spec/sign.test.ts @@ -14,9 +14,9 @@ interface ISignMessageTestCase { }; } -forEachImplementation((bls, implementation) => { +forEachImplementation((bls) => { describeDirectorySpecTest( - `${implementation} - bls/sign/small`, + "bls/sign/small", path.join(SPEC_TESTS_DIR, "general/phase0/bls/sign/small"), (testCase) => { const {privkey, message} = testCase.data.input; diff --git a/test/spec/verify.test.ts b/test/spec/verify.test.ts index d4adba2..7e2e779 100644 --- a/test/spec/verify.test.ts +++ b/test/spec/verify.test.ts @@ -15,9 +15,9 @@ interface IVerifyTestCase { }; } -forEachImplementation((bls, implementation) => { +forEachImplementation((bls) => { describeDirectorySpecTest( - `${implementation} - bls/verify/small`, + "bls/verify/small", path.join(SPEC_TESTS_DIR, "general/phase0/bls/verify/small"), (testCase) => { const {pubkey, message, signature} = testCase.data.input; diff --git a/test/switch.ts b/test/switch.ts index 9b82587..06ce9c6 100644 --- a/test/switch.ts +++ b/test/switch.ts @@ -17,14 +17,16 @@ export function forEachImplementation( callback: (bls: ReturnType, implementation: Implementation) => void ): void { for (const implementation of implementations) { - const bls = getBls(implementation); + describe(implementation, () => { + const bls = getBls(implementation); - if (implementation === "herumi") { - before(async () => { - await bls.initBLS(); - }); - } + if (implementation === "herumi") { + before(async () => { + await bls.initBLS(); + }); + } - callback(bls, implementation); + callback(bls, implementation); + }); } } diff --git a/test/unit/index.test.ts b/test/unit/index.test.ts index 3aef062..0733edc 100644 --- a/test/unit/index.test.ts +++ b/test/unit/index.test.ts @@ -1,195 +1,105 @@ -import {aggregatePubkeys, aggregateSignatures, initBLS, Keypair, verify, verifyMultiple} from "../../src"; -import SHA256 from "@chainsafe/as-sha256"; import {expect} from "chai"; +import {forEachImplementation} from "../switch"; +import {getRandomBytes} from "../../src/helpers/utils"; -describe("test bls", function () { - before(async function () { - await initBLS(); - }); +function randomMessage(): Uint8Array { + return getRandomBytes(32); +} - describe("verify", function () { +function getN(n: number, getter: () => T): T[] { + return Array.from({length: n}, () => getter()); +} + +forEachImplementation((bls) => { + function getRandomData() { + const sk = bls.PrivateKey.fromKeygen(); + const pk = sk.toPublicKey(); + const msg = randomMessage(); + const sig = sk.signMessage(msg); + return {sk, pk, msg, sig}; + } + + describe("verify", () => { it("should verify signature", () => { - const keypair = Keypair.generate(); - const messageHash = Buffer.from(SHA256.digest(Buffer.from("Test"))); - const signature = keypair.privateKey.signMessage(messageHash); - const result = verify(keypair.publicKey.toBytes(), messageHash, signature.toBytes()); - expect(result).to.be.true; - }); + const {pk, msg, sig} = getRandomData(); + const pkHex = pk.toHex(); + const isValid = bls.verify(pk.toBytes(), msg, sig.toBytes()); + expect(isValid, "fail verify").to.be.true; - it("should not modify original pubkey when verifying", () => { - const keypair = Keypair.generate(); - const messageHash = Buffer.from(SHA256.digest(Buffer.from("Test"))); - const signature = keypair.privateKey.signMessage(messageHash); - const pubKey = keypair.publicKey.toBytes(); - verify(pubKey, messageHash, signature.toBytes()); - expect("0x" + pubKey.toString("hex")).to.be.equal(keypair.publicKey.toHex()); + // Make sure to not modify original pubkey when verifying + expect(pk.toHex()).to.be.equal(pkHex, "pubkey modified when verifying"); }); it("should fail verify empty signature", () => { - const keypair = Keypair.generate(); - const messageHash2 = Buffer.from(SHA256.digest(Buffer.from("Test message2"))); - const signature = Buffer.alloc(96); - const result = verify(keypair.publicKey.toBytes(), messageHash2, signature); - expect(result).to.be.false; + const {pk, msg} = getRandomData(); + const emptySig = Buffer.alloc(96); + const isValid = bls.verify(pk.toBytes(), msg, emptySig); + expect(isValid).to.be.false; }); it("should fail verify signature of different message", () => { - const keypair = Keypair.generate(); - const messageHash = Buffer.from(SHA256.digest(Buffer.from("Test message"))); - const messageHash2 = Buffer.from(SHA256.digest(Buffer.from("Test message2"))); - const signature = keypair.privateKey.signMessage(messageHash); - const result = verify(keypair.publicKey.toBytes(), messageHash2, signature.toBytes()); - expect(result).to.be.false; + const {pk, sig} = getRandomData(); + const msg2 = randomMessage(); + const isValid = bls.verify(pk.toBytes(), msg2, sig.toBytes()); + expect(isValid).to.be.false; }); it("should fail verify signature signed by different key", () => { - const keypair = Keypair.generate(); - const keypair2 = Keypair.generate(); - const messageHash = Buffer.from(SHA256.digest(Buffer.from("Test message"))); - const signature = keypair.privateKey.signMessage(messageHash); - const result = verify(keypair2.publicKey.toBytes(), messageHash, signature.toBytes()); - expect(result).to.be.false; + const {msg, sig} = getRandomData(); + const {pk: pk2} = getRandomData(); + const isValid = bls.verify(pk2.toBytes(), msg, sig.toBytes()); + expect(isValid).to.be.false; }); }); - describe("verify multiple", function () { - it("should verify aggregated signatures", function () { - this.timeout(5000); + describe("verify multiple", () => { + it(`should verify aggregated signatures`, () => { + const sks = getN(4, () => bls.PrivateKey.fromKeygen()); + const msgs = getN(2, () => randomMessage()); + const pks = sks.map((sk) => sk.toPublicKey()); - const keypair1 = Keypair.generate(); - const keypair2 = Keypair.generate(); - const keypair3 = Keypair.generate(); - const keypair4 = Keypair.generate(); + const sigs = [ + sks[0].signMessage(msgs[0]), + sks[1].signMessage(msgs[0]), + sks[2].signMessage(msgs[1]), + sks[3].signMessage(msgs[1]), + ]; - const message1 = Buffer.from(SHA256.digest(Buffer.from("Test1"))); - const message2 = Buffer.from(SHA256.digest(Buffer.from("Test2"))); + const aggPubkeys = [ + bls.aggregatePubkeys([pks[0], pks[1]].map((pk) => pk.toBytes())), + bls.aggregatePubkeys([pks[2], pks[3]].map((pk) => pk.toBytes())), + ]; - const signature1 = keypair1.privateKey.signMessage(message1); - const signature2 = keypair2.privateKey.signMessage(message1); - const signature3 = keypair3.privateKey.signMessage(message2); - const signature4 = keypair4.privateKey.signMessage(message2); + const aggSig = bls.aggregateSignatures(sigs.map((sig) => sig.toBytes())); - const aggregatePubKey12 = aggregatePubkeys([keypair1.publicKey.toBytes(), keypair2.publicKey.toBytes()]); - - const aggregatePubKey34 = aggregatePubkeys([keypair3.publicKey.toBytes(), keypair4.publicKey.toBytes()]); - - const aggregateSignature = aggregateSignatures([ - signature1.toBytes(), - signature2.toBytes(), - signature3.toBytes(), - signature4.toBytes(), - ]); - - const result = verifyMultiple([aggregatePubKey12, aggregatePubKey34], [message1, message2], aggregateSignature); - - expect(result).to.be.true; + expect(bls.verifyMultiple(aggPubkeys, msgs, aggSig), "should be valid").to.be.true; + expect(bls.verifyMultiple(aggPubkeys.reverse(), msgs, aggSig), "should fail - swaped pubkeys").to.be.false; }); - it("should verify aggregated signatures - same message", function () { - this.timeout(5000); + it("should verify aggregated signatures - same message", () => { + const n = 4; + const msg = randomMessage(); + const sks = getN(n, () => bls.PrivateKey.fromKeygen()); + const pks = sks.map((sk) => sk.toPublicKey()); + const sigs = sks.map((sk) => sk.signMessage(msg)); - const keypair1 = Keypair.generate(); - const keypair2 = Keypair.generate(); - const keypair3 = Keypair.generate(); - const keypair4 = Keypair.generate(); + const aggregateSignature = bls.aggregateSignatures(sigs.map((sig) => sig.toBytes())); - const message = Buffer.from(SHA256.digest(Buffer.from("Test1"))); - - const signature1 = keypair1.privateKey.signMessage(message); - const signature2 = keypair2.privateKey.signMessage(message); - const signature3 = keypair3.privateKey.signMessage(message); - const signature4 = keypair4.privateKey.signMessage(message); - - const aggregateSignature = aggregateSignatures([ - signature1.toBytes(), - signature2.toBytes(), - signature3.toBytes(), - signature4.toBytes(), - ]); - - const result = verifyMultiple( - [ - keypair1.publicKey.toBytes(), - keypair2.publicKey.toBytes(), - keypair3.publicKey.toBytes(), - keypair4.publicKey.toBytes(), - ], - [message, message, message, message], + const isValid = bls.verifyMultiple( + pks.map((pk) => pk.toBytes()), + getN(4, () => msg), // Same message n times aggregateSignature ); - - expect(result).to.be.true; - }); - - it("should fail to verify aggregated signatures - swapped messages", function () { - this.timeout(5000); - - const keypair1 = Keypair.generate(); - const keypair2 = Keypair.generate(); - const keypair3 = Keypair.generate(); - const keypair4 = Keypair.generate(); - - const message1 = Buffer.from(SHA256.digest(Buffer.from("Test1"))); - const message2 = Buffer.from(SHA256.digest(Buffer.from("Test2"))); - - const signature1 = keypair1.privateKey.signMessage(message1); - const signature2 = keypair2.privateKey.signMessage(message1); - const signature3 = keypair3.privateKey.signMessage(message2); - const signature4 = keypair4.privateKey.signMessage(message2); - - const aggregatePubKey12 = aggregatePubkeys([keypair1.publicKey.toBytes(), keypair2.publicKey.toBytes()]); - - const aggregatePubKey34 = aggregatePubkeys([keypair3.publicKey.toBytes(), keypair4.publicKey.toBytes()]); - - const aggregateSignature = aggregateSignatures([ - signature1.toBytes(), - signature2.toBytes(), - signature3.toBytes(), - signature4.toBytes(), - ]); - - const result = verifyMultiple([aggregatePubKey12, aggregatePubKey34], [message2, message1], aggregateSignature); - - expect(result).to.be.false; - }); - - it("should fail to verify aggregated signatures - different pubkeys and messsages", () => { - const keypair1 = Keypair.generate(); - const keypair2 = Keypair.generate(); - const keypair3 = Keypair.generate(); - const keypair4 = Keypair.generate(); - - const message1 = Buffer.from(SHA256.digest(Buffer.from("Test1"))); - const message2 = Buffer.from(SHA256.digest(Buffer.from("Test2"))); - - const signature1 = keypair1.privateKey.signMessage(message1); - const signature2 = keypair2.privateKey.signMessage(message1); - const signature3 = keypair3.privateKey.signMessage(message2); - const signature4 = keypair4.privateKey.signMessage(message2); - - const aggregatePubKey12 = aggregatePubkeys([keypair1.publicKey.toBytes(), keypair2.publicKey.toBytes()]); - - const aggregateSignature = aggregateSignatures([ - signature1.toBytes(), - signature2.toBytes(), - signature3.toBytes(), - signature4.toBytes(), - ]); - - const result = verifyMultiple([aggregatePubKey12], [message2, message1], aggregateSignature); - - expect(result).to.be.false; + expect(isValid).to.be.true; }); it("should fail to verify aggregated signatures - no public keys", () => { - const signature = Buffer.alloc(96); + const sig = Buffer.alloc(96); + const msg1 = randomMessage(); + const msg2 = randomMessage(); - const message1 = Buffer.from(SHA256.digest(Buffer.from("Test1"))); - const message2 = Buffer.from(SHA256.digest(Buffer.from("Test2"))); - - const result = verifyMultiple([], [message2, message1], signature); - - expect(result).to.be.false; + const isValid = bls.verifyMultiple([], [msg2, msg1], sig); + expect(isValid).to.be.false; }); }); }); diff --git a/test/unit/keypair.test.ts b/test/unit/keypair.test.ts deleted file mode 100644 index ab4a9ef..0000000 --- a/test/unit/keypair.test.ts +++ /dev/null @@ -1,29 +0,0 @@ -import {PrivateKey, PublicKey, Keypair, destroy, initBLS} from "../../src"; -import {expect} from "chai"; - -describe("keypair", function () { - before(async function () { - await initBLS(); - }); - - after(function () { - destroy(); - }); - - it("should create from private and public key", () => { - const secret = PrivateKey.fromKeygen(); - const secret2 = PrivateKey.fromKeygen(); - const publicKey = PublicKey.fromBytes(secret2.toPublicKey().toBytes()); - const keypair = new Keypair(secret, publicKey); - expect(keypair.publicKey).to.be.equal(publicKey); - expect(keypair.privateKey).to.be.equal(secret); - expect(keypair.privateKey).to.not.be.equal(secret2); - }); - - it("should create from private", () => { - const secret = PrivateKey.fromKeygen(); - const publicKey = secret.toPublicKey(); - const keypair = new Keypair(secret); - expect(keypair.publicKey.toBytes().toString("hex")).to.be.equal(publicKey.toBytes().toString("hex")); - }); -}); diff --git a/test/unit/privateKey.test.ts b/test/unit/privateKey.test.ts index 81b131a..f68cfb1 100644 --- a/test/unit/privateKey.test.ts +++ b/test/unit/privateKey.test.ts @@ -1,36 +1,26 @@ -import {PrivateKey, initBLS, destroy, SECRET_KEY_LENGTH} from "../../src"; import {expect} from "chai"; +import {forEachImplementation} from "../switch"; -describe("privateKey", function () { - before(async function () { - await initBLS(); - }); +forEachImplementation((bls) => { + describe("PrivateKey", () => { + it("should generate fromKeygen private key", () => { + const privateKey1 = bls.PrivateKey.fromKeygen(); + const privateKey2 = bls.PrivateKey.fromKeygen(); + expect(privateKey1.toHex()).to.not.be.equal(privateKey2.toHex()); + }); - after(function () { - destroy(); - }); - - it("should generate fromKeygen private key", function () { - const privateKey1 = PrivateKey.fromKeygen(); - const privateKey2 = PrivateKey.fromKeygen(); - expect(privateKey1.toHex()).to.not.be.equal(privateKey2.toHex()); - }); - - it("should export private key to hex string", function () { const privateKey = "0x07656fd676da43883d163f49566c72b9cbf0a5a294f26808c807700732456da7"; - expect(PrivateKey.fromHex(privateKey).toHex()).to.be.equal(privateKey); + it("should export private key to hex string", () => { + expect(bls.PrivateKey.fromHex(privateKey).toHex()).to.be.equal(privateKey); + }); - const privateKey2 = "07656fd676da43883d163f49566c72b9cbf0a5a294f26808c807700732456da7"; + it("should export private key to hex string from non-prefixed hex", () => { + expect(bls.PrivateKey.fromHex(privateKey.replace("0x", "")).toHex()).to.be.equal(privateKey); + }); - expect(PrivateKey.fromHex(privateKey2).toHex()).to.be.equal(privateKey); - }); - - it("should export private key to bytes", function () { - expect(PrivateKey.fromKeygen().toBytes().length).to.be.equal(SECRET_KEY_LENGTH); - }); - - it("should not accept too short private key", function () { - expect(() => PrivateKey.fromHex("0x2123")).to.throw(); + it("should not accept too short private key", () => { + expect(() => bls.PrivateKey.fromHex("0x2123")).to.throw(); + }); }); }); diff --git a/test/unit/publicKey.test.ts b/test/unit/publicKey.test.ts index 17b3a50..5ef7616 100644 --- a/test/unit/publicKey.test.ts +++ b/test/unit/publicKey.test.ts @@ -1,28 +1,21 @@ -import {PublicKey, PrivateKey, initBLS, destroy} from "../../src"; import {expect} from "chai"; +import {forEachImplementation} from "../switch"; -describe("public key", function () { - before(async function f() { - await initBLS(); - }); - - after(function () { - destroy(); - }); - - it("from hex", function () { +forEachImplementation((bls) => { + describe("PublicKey", () => { const publicKey = "0xb6f21199594b56d77670564bf422cb331d5281ca2c1f9a45588a56881d8287ef8619efa6456d6cd2ef61306aa5b21311"; - expect(PublicKey.fromHex(publicKey).toHex()).to.be.equal(publicKey); - }); - it("from bytes", function () { - const publicKey = - "b6f21199594b56d77670564bf422cb331d5281ca2c1f9a45588a56881d8287ef8619efa6456d6cd2ef61306aa5b21311"; - expect(PublicKey.fromBytes(Buffer.from(publicKey, "hex")).toHex()).to.be.equal(`0x${publicKey}`); - }); + it("should export public key to hex string", () => { + expect(bls.PublicKey.fromHex(publicKey).toHex()).to.be.equal(publicKey); + }); - it("from private key", function () { - PrivateKey.fromKeygen().toPublicKey(); + it("should export public key to hex string from non-prefixed hex", () => { + expect(bls.PublicKey.fromHex(publicKey.replace("0x", "")).toHex()).to.be.equal(publicKey); + }); + + it("from private key", () => { + bls.PrivateKey.fromKeygen().toPublicKey(); + }); }); }); diff --git a/yarn.lock b/yarn.lock index b2a7e71..bab06e5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,11 +2,6 @@ # yarn lockfile v1 -"@assemblyscript/loader@^0.9.2": - version "0.9.2" - resolved "https://registry.yarnpkg.com/@assemblyscript/loader/-/loader-0.9.2.tgz#5e1563c9bb5839ff9c8b3ae667e9255d8a166a37" - integrity sha512-fSt+ARVyhRwtqYUcFaLP2LUQ3DRHTsE6V9I2Iw7xaxop1ryePEaCcctIzHspvthww/2RVgtBIbmf/ICDZWkcLw== - "@babel/cli@^7.8.4": version "7.8.4" resolved "https://registry.yarnpkg.com/@babel/cli/-/cli-7.8.4.tgz#505fb053721a98777b2b175323ea4f090b7d3c1c" @@ -791,14 +786,6 @@ lodash "^4.17.13" to-fast-properties "^2.0.0" -"@chainsafe/as-sha256@0.2.0": - version "0.2.0" - resolved "https://registry.yarnpkg.com/@chainsafe/as-sha256/-/as-sha256-0.2.0.tgz#3ebe061d59d30af9e95a8c22ff4813cbf0e89dbc" - integrity sha512-reKklZhY4jSj7JdxdAjUfsaiMt2pdm8V/IqlOR5c4m6Y4tRCxt4f0HBMfyiE2ZQF4tqPPqRVf/ulXwK+LjLIxw== - dependencies: - "@assemblyscript/loader" "^0.9.2" - buffer "^5.4.3" - "@chainsafe/bls-hd-key@^0.1.0": version "0.1.0" resolved "https://registry.yarnpkg.com/@chainsafe/bls-hd-key/-/bls-hd-key-0.1.0.tgz#5e51de16801f4b4b421e418f0d1ef0692df0c585" From 523d54717162079d018889a09468e9f0910ae4c3 Mon Sep 17 00:00:00 2001 From: dapplion Date: Thu, 19 Nov 2020 14:50:08 +0000 Subject: [PATCH 07/51] Add Keypair test --- src/herumi/privateKey.ts | 4 ---- test/unit/keypair.test.ts | 27 +++++++++++++++++++++++++++ 2 files changed, 27 insertions(+), 4 deletions(-) create mode 100644 test/unit/keypair.test.ts diff --git a/src/herumi/privateKey.ts b/src/herumi/privateKey.ts index a1ba0d9..c791d2f 100644 --- a/src/herumi/privateKey.ts +++ b/src/herumi/privateKey.ts @@ -31,10 +31,6 @@ export class PrivateKey { return this.fromBytes(sk); } - getValue(): SecretKeyType { - return this.value; - } - signMessage(message: Uint8Array): Signature { return new Signature(this.value.sign(message)); } diff --git a/test/unit/keypair.test.ts b/test/unit/keypair.test.ts new file mode 100644 index 0000000..4884217 --- /dev/null +++ b/test/unit/keypair.test.ts @@ -0,0 +1,27 @@ +import {expect} from "chai"; +import {forEachImplementation} from "../switch"; + +forEachImplementation((bls) => { + describe("Keypair", () => { + it("should create from private and public key", () => { + const sk = bls.PrivateKey.fromKeygen(); + const sk2 = bls.PrivateKey.fromKeygen(); + const pk = sk.toPublicKey(); + + const keypair = new bls.Keypair(sk as any, pk as any); + + expect(keypair.publicKey).to.be.equal(pk); + expect(keypair.privateKey).to.be.equal(sk); + expect(keypair.privateKey).to.not.be.equal(sk2); + }); + + it("should create from PrivateKey", () => { + const sk = bls.PrivateKey.fromKeygen(); + const pk = sk.toPublicKey(); + + const keypair = new bls.Keypair(sk as any); + + expect(keypair.publicKey.toHex()).to.equal(pk.toHex()); + }); + }); +}); From fa12879651ea7b4e8ab25c9dc73dba096899e682 Mon Sep 17 00:00:00 2001 From: dapplion Date: Thu, 19 Nov 2020 21:46:18 +0000 Subject: [PATCH 08/51] Bump blst-ts --- package.json | 2 +- yarn.lock | 15 +++++++++++---- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index df8fde2..0e77874 100644 --- a/package.json +++ b/package.json @@ -40,7 +40,7 @@ }, "dependencies": { "@chainsafe/bls-keygen": "^0.2.0", - "@chainsafe/blst": "^0.1.0", + "@chainsafe/blst": "^0.1.1", "@chainsafe/eth2-bls-wasm": "^0.5.0", "assert": "^1.4.1" }, diff --git a/yarn.lock b/yarn.lock index bab06e5..9d23bcb 100644 --- a/yarn.lock +++ b/yarn.lock @@ -807,10 +807,12 @@ bip39 "^3.0.2" buffer "^5.4.3" -"@chainsafe/blst@^0.1.0": - version "0.1.0" - resolved "https://registry.yarnpkg.com/@chainsafe/blst/-/blst-0.1.0.tgz#6aa0ea5e91a0f7ae2d4358fb432eb9a558a4de31" - integrity sha512-sJXrADkWNA06xM5udoPr7cdNgzSBAjHaN1XbwLkbJ637eVSsEzip+P7Uz0ajfUu2pVsqReoEOBnpFJpUOHAEtg== +"@chainsafe/blst@^0.1.1": + version "0.1.1" + resolved "https://registry.yarnpkg.com/@chainsafe/blst/-/blst-0.1.1.tgz#547eb9a492aa9a7efc89df7393f4a804624155af" + integrity sha512-B+uNrxkBFYwx0oxlXTrxZECQ+Xa40WNU03syIMfiCASvq0EZE++e9egf5dzH0TcOKujZnkwDVo4lTB86G7BiKA== + dependencies: + node-fetch "^2.6.1" "@chainsafe/eth2-bls-wasm@^0.5.0": version "0.5.0" @@ -4404,6 +4406,11 @@ node-environment-flags@1.0.5: object.getownpropertydescriptors "^2.0.3" semver "^5.7.0" +node-fetch@^2.6.1: + version "2.6.1" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052" + integrity sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw== + node-libs-browser@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/node-libs-browser/-/node-libs-browser-2.2.1.tgz#b64f513d18338625f90346d27b0d235e631f6425" From 1e9f778846e2dfb94f4562a730d94a2105d09a2c Mon Sep 17 00:00:00 2001 From: dapplion Date: Fri, 20 Nov 2020 09:37:44 +0000 Subject: [PATCH 09/51] Use isEqualBytes helper --- src/helpers/utils.ts | 4 ++++ src/herumi/publicKey.ts | 4 ++-- src/herumi/signature.ts | 4 ++-- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/helpers/utils.ts b/src/helpers/utils.ts index 50a34d9..357078d 100644 --- a/src/helpers/utils.ts +++ b/src/helpers/utils.ts @@ -26,6 +26,10 @@ export function getRandomBytes(size: number): Uint8Array { return Uint8Array.from(crypto.randomBytes(size)); } +export function isEqualBytes(a: Buffer | Uint8Array, b: Buffer | Uint8Array): boolean { + return Buffer.from(a).equals(Buffer.from(b)); +} + export function toBuffer(input: Uint8Array): Buffer { return Buffer.from(input.buffer, input.byteOffset, input.length); } diff --git a/src/herumi/publicKey.ts b/src/herumi/publicKey.ts index 82dfe58..f104a09 100644 --- a/src/herumi/publicKey.ts +++ b/src/herumi/publicKey.ts @@ -2,7 +2,7 @@ import {PublicKeyType} from "@chainsafe/eth2-bls-wasm"; import {getContext} from "./context"; import {EMPTY_PUBLIC_KEY} from "../constants"; import {Signature} from "./signature"; -import {bytesToHex, hexToBytes} from "../helpers/utils"; +import {bytesToHex, hexToBytes, isEqualBytes} from "../helpers/utils"; export class PublicKey { readonly value: PublicKeyType; @@ -14,7 +14,7 @@ export class PublicKey { static fromBytes(bytes: Uint8Array): PublicKey { const context = getContext(); const publicKey = new context.PublicKey(); - if (!EMPTY_PUBLIC_KEY.equals(bytes)) { + if (!isEqualBytes(EMPTY_PUBLIC_KEY, bytes)) { publicKey.deserialize(bytes); } return new PublicKey(publicKey); diff --git a/src/herumi/signature.ts b/src/herumi/signature.ts index 971e3d3..4995ba1 100644 --- a/src/herumi/signature.ts +++ b/src/herumi/signature.ts @@ -3,7 +3,7 @@ import {SIGNATURE_LENGTH, EMPTY_SIGNATURE} from "../constants"; import {SignatureType} from "@chainsafe/eth2-bls-wasm"; import {getContext} from "./context"; import {PublicKey} from "./publicKey"; -import {bytesToHex, hexToBytes} from "../helpers/utils"; +import {bytesToHex, hexToBytes, isEqualBytes} from "../helpers/utils"; export class Signature { readonly value: SignatureType; @@ -17,7 +17,7 @@ export class Signature { assert(bytes.length === SIGNATURE_LENGTH, `Signature must have ${SIGNATURE_LENGTH} bytes`); const context = getContext(); const signature = new context.Signature(); - if (!EMPTY_SIGNATURE.equals(bytes)) { + if (!isEqualBytes(EMPTY_SIGNATURE, bytes)) { signature.deserialize(bytes); } return new Signature(signature); From 6e7782b306e22d58c14b331a356b450dac776f8e Mon Sep 17 00:00:00 2001 From: dapplion Date: Fri, 20 Nov 2020 09:38:44 +0000 Subject: [PATCH 10/51] Bump blst-ts to v0.1.2 --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 0e77874..64d3785 100644 --- a/package.json +++ b/package.json @@ -40,7 +40,7 @@ }, "dependencies": { "@chainsafe/bls-keygen": "^0.2.0", - "@chainsafe/blst": "^0.1.1", + "@chainsafe/blst": "^0.1.2", "@chainsafe/eth2-bls-wasm": "^0.5.0", "assert": "^1.4.1" }, diff --git a/yarn.lock b/yarn.lock index 9d23bcb..7625814 100644 --- a/yarn.lock +++ b/yarn.lock @@ -807,10 +807,10 @@ bip39 "^3.0.2" buffer "^5.4.3" -"@chainsafe/blst@^0.1.1": - version "0.1.1" - resolved "https://registry.yarnpkg.com/@chainsafe/blst/-/blst-0.1.1.tgz#547eb9a492aa9a7efc89df7393f4a804624155af" - integrity sha512-B+uNrxkBFYwx0oxlXTrxZECQ+Xa40WNU03syIMfiCASvq0EZE++e9egf5dzH0TcOKujZnkwDVo4lTB86G7BiKA== +"@chainsafe/blst@^0.1.2": + version "0.1.2" + resolved "https://registry.yarnpkg.com/@chainsafe/blst/-/blst-0.1.2.tgz#5d2ee91609c0f799be4b4de2ea8ed67209bf4201" + integrity sha512-doQ4sFGthNR9WzLlFUvtOx1ReqIMNNjS0JC3NNg7NSkRMvzpIinFcHlcABmCJODofreU11GYext77WFCzoSKNA== dependencies: node-fetch "^2.6.1" From 1e92f6311bc84448eff4339fd3617ccf5c4238ff Mon Sep 17 00:00:00 2001 From: dapplion Date: Fri, 20 Nov 2020 12:16:25 +0000 Subject: [PATCH 11/51] Setup NodeJS 12 on CI --- .github/workflows/test.yml | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 1f1ed3a..2021c6b 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -1,18 +1,22 @@ -name: CI Tests +name: Main on: [pull_request, push] jobs: - lint: - name: Quick tests + tests: + name: Tests runs-on: ubuntu-latest steps: - - uses: actions/checkout@v1 - - name: Bootstrap - run: yarn - - name: Check types - run: yarn check-types - - name: Lint - run: yarn lint - - name: Tests - run: yarn test + - uses: actions/checkout@v2 + - uses: actions/setup-node@v1 + with: + node-version: "12.x" + registry-url: "https://registry.npmjs.org" + - name: Install deps + run: yarn + - name: Check types + run: yarn check-types + - name: Lint + run: yarn lint + - name: Tests + run: yarn test From c354386dab0f87461f69be5da47275f24e0a615c Mon Sep 17 00:00:00 2001 From: dapplion Date: Fri, 20 Nov 2020 12:27:30 +0000 Subject: [PATCH 12/51] Fix lint errors --- src/blst/index.ts | 4 ++-- src/blst/signature.ts | 16 ++++++++-------- src/herumi/index.ts | 1 - test/benchmark/runner.ts | 2 +- test/switch.ts | 1 + test/unit/index.test.ts | 13 +++---------- test/util.ts | 10 ++++++++++ 7 files changed, 25 insertions(+), 22 deletions(-) diff --git a/src/blst/index.ts b/src/blst/index.ts index 380f1d7..49d9bbf 100644 --- a/src/blst/index.ts +++ b/src/blst/index.ts @@ -8,10 +8,10 @@ export * from "../constants"; export {Keypair, PrivateKey, PublicKey, Signature}; -export async function initBLS() { +export async function initBLS(): Promise { // Native bindings require no init() call } -export function destroy() { +export function destroy(): void { // Native bindings require no destroy() call } diff --git a/src/blst/signature.ts b/src/blst/signature.ts index 508fedf..eed4ded 100644 --- a/src/blst/signature.ts +++ b/src/blst/signature.ts @@ -42,6 +42,14 @@ export class Signature { ); } + toBytes(): Buffer { + return Buffer.from(this.affine.toBytes()); + } + + toHex(): string { + return bytesToHex(this.toBytes()); + } + private aggregateVerify(msgs: Uint8Array[], pks: blst.PublicKey[]): boolean { // If this set is simply an infinity signature and infinity pubkey then skip verification. // This has the effect of always declaring that this sig/pubkey combination is valid. @@ -52,12 +60,4 @@ export class Signature { return blst.aggregateVerify(msgs, pks, this.affine); } - - toBytes(): Buffer { - return Buffer.from(this.affine.toBytes()); - } - - toHex(): string { - return bytesToHex(this.toBytes()); - } } diff --git a/src/herumi/index.ts b/src/herumi/index.ts index c4de6f8..4ee3138 100644 --- a/src/herumi/index.ts +++ b/src/herumi/index.ts @@ -3,7 +3,6 @@ import {PrivateKey} from "./privateKey"; import {PublicKey} from "./publicKey"; import {Signature} from "./signature"; import {initBLS, destroy} from "./context"; -import {PUBLIC_KEY_LENGTH} from "../constants"; import assert from "assert"; import {toBuffer} from "../helpers/utils"; diff --git a/test/benchmark/runner.ts b/test/benchmark/runner.ts index 19f06fa..6b28931 100644 --- a/test/benchmark/runner.ts +++ b/test/benchmark/runner.ts @@ -8,7 +8,7 @@ export function runBenchmark({ testRunner: (input: T) => R; runs?: number; id: string; -}) { +}): void { const diffsNanoSec: bigint[] = []; for (let i = 0; i < runs; i++) { diff --git a/test/switch.ts b/test/switch.ts index 06ce9c6..19765bb 100644 --- a/test/switch.ts +++ b/test/switch.ts @@ -4,6 +4,7 @@ import herumi from "../src/herumi"; export type Implementation = "blst" | "herumi"; export const implementations: Implementation[] = ["blst", "herumi"]; +// eslint-disable-next-line @typescript-eslint/explicit-function-return-type export function getBls(implementation: Implementation) { switch (implementation) { case "blst": diff --git a/test/unit/index.test.ts b/test/unit/index.test.ts index 0733edc..4001b82 100644 --- a/test/unit/index.test.ts +++ b/test/unit/index.test.ts @@ -1,16 +1,9 @@ import {expect} from "chai"; import {forEachImplementation} from "../switch"; -import {getRandomBytes} from "../../src/helpers/utils"; - -function randomMessage(): Uint8Array { - return getRandomBytes(32); -} - -function getN(n: number, getter: () => T): T[] { - return Array.from({length: n}, () => getter()); -} +import {getN, randomMessage} from "../util"; forEachImplementation((bls) => { + // eslint-disable-next-line @typescript-eslint/explicit-function-return-type function getRandomData() { const sk = bls.PrivateKey.fromKeygen(); const pk = sk.toPublicKey(); @@ -53,7 +46,7 @@ forEachImplementation((bls) => { }); describe("verify multiple", () => { - it(`should verify aggregated signatures`, () => { + it("should verify aggregated signatures", () => { const sks = getN(4, () => bls.PrivateKey.fromKeygen()); const msgs = getN(2, () => randomMessage()); const pks = sks.map((sk) => sk.toPublicKey()); diff --git a/test/util.ts b/test/util.ts index 50478de..2a97bf4 100644 --- a/test/util.ts +++ b/test/util.ts @@ -1,3 +1,5 @@ +import {getRandomBytes} from "../src/helpers/utils"; + export function fromHexString(hex: string): Buffer { return Buffer.from(hex.replace("0x", ""), "hex"); } @@ -5,3 +7,11 @@ export function fromHexString(hex: string): Buffer { export function toHexString(bytes: Buffer | Uint8Array): string { return `0x${Buffer.from(bytes).toString("hex")}`; } + +export function randomMessage(): Uint8Array { + return getRandomBytes(32); +} + +export function getN(n: number, getter: () => T): T[] { + return Array.from({length: n}, () => getter()); +} From 4424bed87d8d1fa7bd16f93c33263ac9c092351a Mon Sep 17 00:00:00 2001 From: dapplion Date: Fri, 20 Nov 2020 19:03:17 +0000 Subject: [PATCH 13/51] Define common implementation --- src/blst/index.ts | 26 +++-------- src/blst/keypair.ts | 3 +- src/blst/privateKey.ts | 5 ++- src/blst/publicKey.ts | 3 +- src/blst/signature.ts | 7 +-- src/herumi/context.ts | 7 ++- src/herumi/index.ts | 26 +++-------- src/herumi/keypair.ts | 3 +- src/herumi/privateKey.ts | 3 +- src/herumi/publicKey.ts | 3 +- src/herumi/signature.ts | 3 +- src/interface.ts | 53 +++++++++++++++++++++++ test/switch.ts | 13 +++--- test/unit/index.test.ts | 6 +-- test/unit/keypair.test.ts | 42 +++++++++--------- test/unit/privateKey.test.ts | 6 +-- test/unit/publicKey.test.ts | 6 +-- test/unit/run-all-implementations.test.ts | 12 +++++ test/unit/run-web-implementation.test.ts | 12 +++++ 19 files changed, 143 insertions(+), 96 deletions(-) create mode 100644 src/interface.ts create mode 100644 test/unit/run-all-implementations.test.ts create mode 100644 test/unit/run-web-implementation.test.ts diff --git a/src/blst/index.ts b/src/blst/index.ts index 49d9bbf..83d05a4 100644 --- a/src/blst/index.ts +++ b/src/blst/index.ts @@ -4,6 +4,7 @@ import {PrivateKey} from "./privateKey"; import {PublicKey} from "./publicKey"; import {Signature} from "./signature"; import {toBuffer} from "../helpers/utils"; +import {IBls} from "../interface"; export * from "../constants"; export {Keypair, PrivateKey, PublicKey, Signature}; @@ -15,23 +16,6 @@ export function destroy(): void { // Native bindings require no destroy() call } -/** - * Generates new secret and public key - */ -export function generateKeyPair(): Keypair { - return Keypair.generate(); -} - -/** - * Generates public key from given secret. - * @param {BLSSecretKey} secretKey - */ -export function generatePublicKey(secretKey: Uint8Array): Buffer { - assert(secretKey, "secretKey is null or undefined"); - const keypair = new Keypair(PrivateKey.fromBytes(toBuffer(secretKey))); - return keypair.publicKey.toBytes(); -} - /** * Signs given message using secret key. * @param secretKey @@ -127,9 +111,7 @@ export function verifyMultiple(publicKeys: Uint8Array[], messageHashes: Uint8Arr } } -export default { - generateKeyPair, - generatePublicKey, +const bls: IBls = { sign, aggregateSignatures, aggregatePubkeys, @@ -137,10 +119,12 @@ export default { verifyAggregate, verifyMultiple, - Keypair, + // Keypair, PrivateKey, PublicKey, Signature, initBLS, destroy, }; + +export default bls; diff --git a/src/blst/keypair.ts b/src/blst/keypair.ts index 2e34c54..db3928e 100644 --- a/src/blst/keypair.ts +++ b/src/blst/keypair.ts @@ -1,7 +1,8 @@ import {PublicKey} from "./publicKey"; import {PrivateKey} from "./privateKey"; +import {IKeypair} from "../interface"; -export class Keypair { +export class Keypair implements IKeypair { private readonly _publicKey: PublicKey; private readonly _privateKey: PrivateKey; diff --git a/src/blst/privateKey.ts b/src/blst/privateKey.ts index c375cf6..a421147 100644 --- a/src/blst/privateKey.ts +++ b/src/blst/privateKey.ts @@ -1,9 +1,10 @@ import * as blst from "@chainsafe/blst"; import {bytesToHex, getRandomBytes, hexToBytes} from "../helpers/utils"; +import {IPrivateKey} from "../interface"; import {PublicKey} from "./publicKey"; import {Signature} from "./signature"; -export class PrivateKey { +export class PrivateKey implements IPrivateKey { readonly value: blst.SecretKey; constructor(value: blst.SecretKey) { @@ -25,7 +26,7 @@ export class PrivateKey { } signMessage(message: Uint8Array): Signature { - return Signature.fromValue(this.value.sign(message)); + return new Signature(this.value.sign(message)); } toPublicKey(): PublicKey { diff --git a/src/blst/publicKey.ts b/src/blst/publicKey.ts index 67f5281..ee28c5c 100644 --- a/src/blst/publicKey.ts +++ b/src/blst/publicKey.ts @@ -1,8 +1,9 @@ import * as blst from "@chainsafe/blst"; import {bytesToHex, hexToBytes} from "../helpers/utils"; +import {IPublicKey} from "../interface"; import {Signature} from "./signature"; -export class PublicKey { +export class PublicKey implements IPublicKey { readonly affine: blst.PublicKey; readonly jacobian: blst.AggregatePublicKey; diff --git a/src/blst/signature.ts b/src/blst/signature.ts index eed4ded..5bad9d1 100644 --- a/src/blst/signature.ts +++ b/src/blst/signature.ts @@ -1,8 +1,9 @@ import * as blst from "@chainsafe/blst"; import {bytesToHex, hexToBytes} from "../helpers/utils"; +import {ISignature} from "../interface"; import {PublicKey} from "./publicKey"; -export class Signature { +export class Signature implements ISignature { readonly affine: blst.Signature; constructor(value: blst.Signature) { @@ -17,10 +18,6 @@ export class Signature { return this.fromBytes(hexToBytes(hex)); } - static fromValue(signature: blst.Signature): Signature { - return new Signature(signature); - } - static aggregate(signatures: Signature[]): Signature { const agg = blst.AggregateSignature.fromSignatures(signatures.map((sig) => sig.affine)); return new Signature(agg.toSignature()); diff --git a/src/herumi/context.ts b/src/herumi/context.ts index 65992a4..65d5248 100644 --- a/src/herumi/context.ts +++ b/src/herumi/context.ts @@ -3,18 +3,17 @@ import bls from "@chainsafe/eth2-bls-wasm"; type Bls = typeof bls; let blsGlobal: Bls | null = null; -let blsGlobalPromise: Promise | null = null; +let blsGlobalPromise: Promise | null = null; -export async function setupBls(): Promise { +export async function setupBls(): Promise { if (!blsGlobal) { await bls.init(); blsGlobal = bls; } - return blsGlobal; } // Cache a promise for Bls instead of Bls to make sure it is initialized only once -export async function initBLS(): Promise { +export async function initBLS(): Promise { if (!blsGlobalPromise) { blsGlobalPromise = setupBls(); } diff --git a/src/herumi/index.ts b/src/herumi/index.ts index 4ee3138..6c03481 100644 --- a/src/herumi/index.ts +++ b/src/herumi/index.ts @@ -5,26 +5,10 @@ import {Signature} from "./signature"; import {initBLS, destroy} from "./context"; import assert from "assert"; import {toBuffer} from "../helpers/utils"; +import {IBls} from "../interface"; export {Keypair, PrivateKey, PublicKey, Signature, initBLS, destroy}; -/** - * Generates new secret and public key - */ -export function generateKeyPair(): Keypair { - return Keypair.generate(); -} - -/** - * Generates public key from given secret. - * @param {BLSSecretKey} secretKey - */ -export function generatePublicKey(secretKey: Uint8Array): Buffer { - assert(secretKey, "secretKey is null or undefined"); - const keypair = new Keypair(PrivateKey.fromBytes(toBuffer(secretKey))); - return keypair.publicKey.toBytes(); -} - /** * Signs given message using secret key. * @param secretKey @@ -121,9 +105,7 @@ export function verifyMultiple(publicKeys: Uint8Array[], messageHashes: Uint8Arr } } -export default { - generateKeyPair, - generatePublicKey, +const bls: IBls = { sign, aggregateSignatures, aggregatePubkeys, @@ -131,10 +113,12 @@ export default { verifyAggregate, verifyMultiple, - Keypair, + // Keypair, PrivateKey, PublicKey, Signature, initBLS, destroy, }; + +export default bls; diff --git a/src/herumi/keypair.ts b/src/herumi/keypair.ts index 2e34c54..db3928e 100644 --- a/src/herumi/keypair.ts +++ b/src/herumi/keypair.ts @@ -1,7 +1,8 @@ import {PublicKey} from "./publicKey"; import {PrivateKey} from "./privateKey"; +import {IKeypair} from "../interface"; -export class Keypair { +export class Keypair implements IKeypair { private readonly _publicKey: PublicKey; private readonly _privateKey: PrivateKey; diff --git a/src/herumi/privateKey.ts b/src/herumi/privateKey.ts index c791d2f..facdd59 100644 --- a/src/herumi/privateKey.ts +++ b/src/herumi/privateKey.ts @@ -6,8 +6,9 @@ import {getContext} from "./context"; import {PublicKey} from "./publicKey"; import {Signature} from "./signature"; import {bytesToHex, hexToBytes} from "../helpers/utils"; +import {IPrivateKey} from "../interface"; -export class PrivateKey { +export class PrivateKey implements IPrivateKey { readonly value: SecretKeyType; constructor(value: SecretKeyType) { diff --git a/src/herumi/publicKey.ts b/src/herumi/publicKey.ts index f104a09..4cd01cc 100644 --- a/src/herumi/publicKey.ts +++ b/src/herumi/publicKey.ts @@ -3,8 +3,9 @@ import {getContext} from "./context"; import {EMPTY_PUBLIC_KEY} from "../constants"; import {Signature} from "./signature"; import {bytesToHex, hexToBytes, isEqualBytes} from "../helpers/utils"; +import {IPublicKey} from "../interface"; -export class PublicKey { +export class PublicKey implements IPublicKey { readonly value: PublicKeyType; constructor(value: PublicKeyType) { diff --git a/src/herumi/signature.ts b/src/herumi/signature.ts index 4995ba1..3bf8a22 100644 --- a/src/herumi/signature.ts +++ b/src/herumi/signature.ts @@ -4,8 +4,9 @@ import {SignatureType} from "@chainsafe/eth2-bls-wasm"; import {getContext} from "./context"; import {PublicKey} from "./publicKey"; import {bytesToHex, hexToBytes, isEqualBytes} from "../helpers/utils"; +import {ISignature} from "../interface"; -export class Signature { +export class Signature implements ISignature { readonly value: SignatureType; constructor(value: SignatureType) { diff --git a/src/interface.ts b/src/interface.ts new file mode 100644 index 0000000..756362a --- /dev/null +++ b/src/interface.ts @@ -0,0 +1,53 @@ +export interface IBls { + PrivateKey: { + fromBytes(bytes: Uint8Array): IPrivateKey; + fromHex(hex: string): IPrivateKey; + fromKeygen(): IPrivateKey; + }; + PublicKey: { + fromBytes(bytes: Uint8Array): IPublicKey; + fromHex(hex: string): IPublicKey; + aggregate(pubkeys: IPublicKey[]): IPublicKey; + }; + Signature: { + fromBytes(bytes: Uint8Array): ISignature; + fromHex(hex: string): ISignature; + aggregate(signatures: ISignature[]): ISignature; + }; + + sign(secretKey: Uint8Array, messageHash: Uint8Array): Buffer; + aggregatePubkeys(publicKeys: Uint8Array[]): Buffer; + aggregateSignatures(signatures: Uint8Array[]): Buffer; + verify(publicKey: Uint8Array, messageHash: Uint8Array, signature: Uint8Array): boolean; + verifyAggregate(publicKeys: Uint8Array[], messageHash: Uint8Array, signature: Uint8Array): boolean; + verifyMultiple(publicKeys: Uint8Array[], messageHashes: Uint8Array[], signature: Uint8Array): boolean; + + initBLS: () => Promise; + destroy: () => void; +} + +export interface IKeypair { + publicKey: IPublicKey; + privateKey: IPrivateKey; +} + +export interface IPublicKey { + toBytes(): Buffer; + toHex(): string; +} + +export interface ISignature { + toBytes(): Buffer; + toHex(): string; + verify(publicKey: IPublicKey, message: Uint8Array): boolean; + verifyAggregate(publicKeys: IPublicKey[], message: Uint8Array): boolean; + verifyMultiple(publicKeys: IPublicKey[], messages: Uint8Array[]): boolean; +} + +export interface IPrivateKey { + value: any; + toPublicKey(): IPublicKey; + signMessage(message: Uint8Array): ISignature; + toBytes(): Buffer; + toHex(): string; +} diff --git a/test/switch.ts b/test/switch.ts index 19765bb..4fb8799 100644 --- a/test/switch.ts +++ b/test/switch.ts @@ -1,11 +1,11 @@ import blst from "../src/blst"; import herumi from "../src/herumi"; +import {IBls} from "../src/interface"; export type Implementation = "blst" | "herumi"; -export const implementations: Implementation[] = ["blst", "herumi"]; // eslint-disable-next-line @typescript-eslint/explicit-function-return-type -export function getBls(implementation: Implementation) { +export function getBls(implementation: Implementation): IBls { switch (implementation) { case "blst": return blst; @@ -15,17 +15,16 @@ export function getBls(implementation: Implementation) { } export function forEachImplementation( + implementations: Implementation[], callback: (bls: ReturnType, implementation: Implementation) => void ): void { for (const implementation of implementations) { describe(implementation, () => { const bls = getBls(implementation); - if (implementation === "herumi") { - before(async () => { - await bls.initBLS(); - }); - } + before(async () => { + await bls.initBLS(); + }); callback(bls, implementation); }); diff --git a/test/unit/index.test.ts b/test/unit/index.test.ts index 4001b82..32da4a0 100644 --- a/test/unit/index.test.ts +++ b/test/unit/index.test.ts @@ -1,8 +1,8 @@ import {expect} from "chai"; -import {forEachImplementation} from "../switch"; +import {IBls} from "../../src/interface"; import {getN, randomMessage} from "../util"; -forEachImplementation((bls) => { +export function runIndexTests(bls: IBls) { // eslint-disable-next-line @typescript-eslint/explicit-function-return-type function getRandomData() { const sk = bls.PrivateKey.fromKeygen(); @@ -95,4 +95,4 @@ forEachImplementation((bls) => { expect(isValid).to.be.false; }); }); -}); +} diff --git a/test/unit/keypair.test.ts b/test/unit/keypair.test.ts index 4884217..82b2deb 100644 --- a/test/unit/keypair.test.ts +++ b/test/unit/keypair.test.ts @@ -1,27 +1,27 @@ -import {expect} from "chai"; -import {forEachImplementation} from "../switch"; +// import {expect} from "chai"; +// import {IBls} from "../../src/interface"; -forEachImplementation((bls) => { - describe("Keypair", () => { - it("should create from private and public key", () => { - const sk = bls.PrivateKey.fromKeygen(); - const sk2 = bls.PrivateKey.fromKeygen(); - const pk = sk.toPublicKey(); +// export function runKeypairTests(bls: IBls) { +// describe("Keypair", () => { +// it("should create from private and public key", () => { +// const sk = bls.PrivateKey.fromKeygen(); +// const sk2 = bls.PrivateKey.fromKeygen(); +// const pk = sk.toPublicKey(); - const keypair = new bls.Keypair(sk as any, pk as any); +// const keypair = new bls.Keypair(sk, pk); - expect(keypair.publicKey).to.be.equal(pk); - expect(keypair.privateKey).to.be.equal(sk); - expect(keypair.privateKey).to.not.be.equal(sk2); - }); +// expect(keypair.publicKey).to.be.equal(pk); +// expect(keypair.privateKey).to.be.equal(sk); +// expect(keypair.privateKey).to.not.be.equal(sk2); +// }); - it("should create from PrivateKey", () => { - const sk = bls.PrivateKey.fromKeygen(); - const pk = sk.toPublicKey(); +// it("should create from PrivateKey", () => { +// const sk = bls.PrivateKey.fromKeygen(); +// const pk = sk.toPublicKey(); - const keypair = new bls.Keypair(sk as any); +// const keypair = new bls.Keypair(sk as any); - expect(keypair.publicKey.toHex()).to.equal(pk.toHex()); - }); - }); -}); +// expect(keypair.publicKey.toHex()).to.equal(pk.toHex()); +// }); +// }); +// } diff --git a/test/unit/privateKey.test.ts b/test/unit/privateKey.test.ts index f68cfb1..b849cf9 100644 --- a/test/unit/privateKey.test.ts +++ b/test/unit/privateKey.test.ts @@ -1,7 +1,7 @@ import {expect} from "chai"; -import {forEachImplementation} from "../switch"; +import {IBls} from "../../src/interface"; -forEachImplementation((bls) => { +export function runPrivateKeyTests(bls: IBls) { describe("PrivateKey", () => { it("should generate fromKeygen private key", () => { const privateKey1 = bls.PrivateKey.fromKeygen(); @@ -23,4 +23,4 @@ forEachImplementation((bls) => { expect(() => bls.PrivateKey.fromHex("0x2123")).to.throw(); }); }); -}); +} diff --git a/test/unit/publicKey.test.ts b/test/unit/publicKey.test.ts index 5ef7616..0c66cf1 100644 --- a/test/unit/publicKey.test.ts +++ b/test/unit/publicKey.test.ts @@ -1,7 +1,7 @@ import {expect} from "chai"; -import {forEachImplementation} from "../switch"; +import {IBls} from "../../src/interface"; -forEachImplementation((bls) => { +export function runPublicKeyTests(bls: IBls) { describe("PublicKey", () => { const publicKey = "0xb6f21199594b56d77670564bf422cb331d5281ca2c1f9a45588a56881d8287ef8619efa6456d6cd2ef61306aa5b21311"; @@ -18,4 +18,4 @@ forEachImplementation((bls) => { bls.PrivateKey.fromKeygen().toPublicKey(); }); }); -}); +} diff --git a/test/unit/run-all-implementations.test.ts b/test/unit/run-all-implementations.test.ts new file mode 100644 index 0000000..854d6e3 --- /dev/null +++ b/test/unit/run-all-implementations.test.ts @@ -0,0 +1,12 @@ +import {runPrivateKeyTests} from "./privateKey.test"; +import {runPublicKeyTests} from "./publicKey.test"; +// import {runKeypairTests} from "./keypair.test"; +import {runIndexTests} from "./index.test"; +import {forEachImplementation} from "../switch"; + +forEachImplementation(["blst", "herumi"], (bls) => { + runPrivateKeyTests(bls); + runPublicKeyTests(bls); + // runKeypairTests(bls); + runIndexTests(bls); +}); diff --git a/test/unit/run-web-implementation.test.ts b/test/unit/run-web-implementation.test.ts new file mode 100644 index 0000000..ea06044 --- /dev/null +++ b/test/unit/run-web-implementation.test.ts @@ -0,0 +1,12 @@ +import {runPrivateKeyTests} from "./privateKey.test"; +import {runPublicKeyTests} from "./publicKey.test"; +// import {runKeypairTests} from "./keypair.test"; +import {runIndexTests} from "./index.test"; +import {forEachImplementation} from "../switch"; + +forEachImplementation(["herumi"], (bls) => { + runPrivateKeyTests(bls); + runPublicKeyTests(bls); + // runKeypairTests(bls); + runIndexTests(bls); +}); From 70ccbfbe5b04a576af968fb332191138a20817c2 Mon Sep 17 00:00:00 2001 From: dapplion Date: Fri, 20 Nov 2020 19:08:53 +0000 Subject: [PATCH 14/51] Run only web implementation in Karma --- karma.conf.js | 41 +++++++++++------------ test/unit/run-all-implementations.test.ts | 1 + test/unit/run-web-implementation.test.ts | 17 +++++++--- 3 files changed, 33 insertions(+), 26 deletions(-) diff --git a/karma.conf.js b/karma.conf.js index c1e73de..9e9100b 100644 --- a/karma.conf.js +++ b/karma.conf.js @@ -1,26 +1,25 @@ // eslint-disable-next-line @typescript-eslint/no-require-imports const webpackConfig = require("./webpack.config"); -module.exports = function(config) { - config.set({ +module.exports = function (config) { + config.set({ + basePath: "", + frameworks: ["mocha", "chai"], + files: ["test/unit/*.ts"], + exclude: [], + preprocessors: { + "test/unit/run-web-implementation.test.ts": ["webpack"], + }, + webpack: { + mode: "production", + node: webpackConfig.node, + module: webpackConfig.module, + resolve: webpackConfig.resolve, + }, + reporters: ["spec"], - basePath: "", - frameworks: ["mocha", "chai"], - files: ["test/unit/*.ts"], - exclude: [], - preprocessors: { - "test/**/*.ts": ["webpack"] - }, - webpack: { - mode: "production", - node: webpackConfig.node, - module: webpackConfig.module, - resolve: webpackConfig.resolve - }, - reporters: ["spec"], + browsers: ["ChromeHeadless"], - browsers: ["ChromeHeadless"], - - singleRun: true - }); -}; \ No newline at end of file + singleRun: true, + }); +}; diff --git a/test/unit/run-all-implementations.test.ts b/test/unit/run-all-implementations.test.ts index 854d6e3..ea90530 100644 --- a/test/unit/run-all-implementations.test.ts +++ b/test/unit/run-all-implementations.test.ts @@ -4,6 +4,7 @@ import {runPublicKeyTests} from "./publicKey.test"; import {runIndexTests} from "./index.test"; import {forEachImplementation} from "../switch"; +// Import test's bls lib lazily to prevent breaking test with Karma forEachImplementation(["blst", "herumi"], (bls) => { runPrivateKeyTests(bls); runPublicKeyTests(bls); diff --git a/test/unit/run-web-implementation.test.ts b/test/unit/run-web-implementation.test.ts index ea06044..31d18e0 100644 --- a/test/unit/run-web-implementation.test.ts +++ b/test/unit/run-web-implementation.test.ts @@ -1,12 +1,19 @@ +import herumi from "../../src/herumi"; import {runPrivateKeyTests} from "./privateKey.test"; import {runPublicKeyTests} from "./publicKey.test"; // import {runKeypairTests} from "./keypair.test"; import {runIndexTests} from "./index.test"; -import {forEachImplementation} from "../switch"; -forEachImplementation(["herumi"], (bls) => { - runPrivateKeyTests(bls); - runPublicKeyTests(bls); +// This file is intended to be compiled and run by Karma +// Do not import the node.bindings or it will break with: +// Error: BLST bindings loader should only run in a NodeJS context: process.platform +describe("herumi", () => { + before(async () => { + await herumi.initBLS(); + }); + + runPrivateKeyTests(herumi); + runPublicKeyTests(herumi); // runKeypairTests(bls); - runIndexTests(bls); + runIndexTests(herumi); }); From 990258dbd96d7719c72190252a3107eb03139d33 Mon Sep 17 00:00:00 2001 From: dapplion Date: Fri, 20 Nov 2020 19:35:32 +0000 Subject: [PATCH 15/51] Fix type errors in benchmark runner Lint issues --- src/interface.ts | 5 +- test/benchmark/index.ts | 137 +++++++--------------- test/spec/aggregate_sigs.test.ts | 4 +- test/spec/aggregate_sigs_verify.test.ts | 4 +- test/spec/fast_aggregate_verify.test.ts | 4 +- test/spec/sign.test.ts | 4 +- test/spec/verify.test.ts | 4 +- test/switch.ts | 22 ++-- test/unit/index.test.ts | 2 +- test/unit/privateKey.test.ts | 2 +- test/unit/publicKey.test.ts | 2 +- test/unit/run-all-implementations.test.ts | 4 +- test/unit/run-web-implementation.test.ts | 2 + 13 files changed, 73 insertions(+), 123 deletions(-) diff --git a/src/interface.ts b/src/interface.ts index 756362a..0b4aebf 100644 --- a/src/interface.ts +++ b/src/interface.ts @@ -22,8 +22,8 @@ export interface IBls { verifyAggregate(publicKeys: Uint8Array[], messageHash: Uint8Array, signature: Uint8Array): boolean; verifyMultiple(publicKeys: Uint8Array[], messageHashes: Uint8Array[], signature: Uint8Array): boolean; - initBLS: () => Promise; - destroy: () => void; + initBLS(): Promise; + destroy(): void; } export interface IKeypair { @@ -45,7 +45,6 @@ export interface ISignature { } export interface IPrivateKey { - value: any; toPublicKey(): IPublicKey; signMessage(message: Uint8Array): ISignature; toBytes(): Buffer; diff --git a/test/benchmark/index.ts b/test/benchmark/index.ts index b726098..18dc9ed 100644 --- a/test/benchmark/index.ts +++ b/test/benchmark/index.ts @@ -1,95 +1,49 @@ import crypto from "crypto"; -import * as blst from "@chainsafe/blst"; -import * as herumi from "../../src"; import {runBenchmark} from "./runner"; +import {runForAllImplementations} from "../switch"; +import {IPublicKey, ISignature} from "../../src/interface"; -(async function () { - await herumi.initBLS(); +runForAllImplementations(async (bls, implementation) => { + await bls.initBLS(); const aggCount = 30; // verify - runBenchmark<{pk: blst.PublicKey; msg: Uint8Array; sig: blst.Signature}, boolean>({ - id: "BLST verify", + runBenchmark<{pk: IPublicKey; msg: Uint8Array; sig: ISignature}, boolean>({ + id: `${implementation} verify`, prepareTest: () => { const msg = randomMsg(); - const sk = blst.SecretKey.fromKeygen(crypto.randomBytes(32)); + const sk = bls.PrivateKey.fromKeygen(); const pk = sk.toPublicKey(); - const sig = sk.sign(msg); + const sig = sk.signMessage(msg); return { input: {pk, msg, sig}, resultCheck: (valid) => valid === true, }; }, testRunner: ({pk, msg, sig}) => { - return blst.verify(msg, pk, sig); - }, - }); - - runBenchmark<{pk: herumi.PublicKey; msg: Uint8Array; sig: herumi.Signature}, boolean>({ - id: "HERUMI verify", - - prepareTest: () => { - const msg = randomMsg(); - const keypair = herumi.generateKeyPair(); - const pk = keypair.publicKey; - const sig = keypair.privateKey.signMessage(msg); - return { - input: {pk, msg, sig}, - resultCheck: (valid) => valid === true, - }; - }, - testRunner: ({pk, msg, sig}) => { - return pk.verifyMessage(sig, msg); + return sig.verify(pk, msg); }, }); // Fast aggregate - runBenchmark<{pks: blst.AggregatePublicKey[]; msg: Uint8Array; sig: blst.Signature}, boolean>({ - id: "BLST fastAggregateVerify", + runBenchmark<{pks: IPublicKey[]; msg: Uint8Array; sig: ISignature}, boolean>({ + id: `${implementation} verifyAggregate`, prepareTest: () => { const msg = randomMsg(); - const dataArr = range(aggCount).map(() => { - const sk = blst.SecretKey.fromKeygen(crypto.randomBytes(32)); - const pk = sk.toAggregatePublicKey(); - const sig = sk.sign(msg); + const sk = bls.PrivateKey.fromKeygen(); + const pk = sk.toPublicKey(); + const sig = sk.signMessage(msg); return {pk, sig}; }); const pks = dataArr.map((data) => data.pk); - const aggSig = blst.AggregateSignature.fromSignatures(dataArr.map((data) => data.sig)); - const sig = aggSig.toSignature(); - - return { - input: {pks, msg, sig}, - resultCheck: (valid) => valid === true, - }; - }, - testRunner: ({pks, msg, sig}) => { - return blst.fastAggregateVerify(msg, pks, sig); - }, - }); - - runBenchmark<{pks: herumi.PublicKey[]; msg: Uint8Array; sig: herumi.Signature}, boolean>({ - id: "HERUMI fastAggregateVerify", - - prepareTest: () => { - const msg = randomMsg(); - - const dataArr = range(aggCount).map(() => { - const keypair = herumi.generateKeyPair(); - const pk = keypair.publicKey; - const sig = keypair.privateKey.signMessage(msg); - return {pk, sig}; - }); - - const pks = dataArr.map((data) => data.pk); - const sig = herumi.Signature.aggregate(dataArr.map((data) => data.sig)); + const sig = bls.Signature.aggregate(dataArr.map((data) => data.sig)); return { input: {pks, msg, sig}, @@ -101,50 +55,41 @@ import {runBenchmark} from "./runner"; }, }); + // Aggregate pubkeys + + runBenchmark({ + id: `${implementation} aggregate pubkeys (${aggCount})`, + + prepareTest: () => { + return { + input: range(aggCount).map(() => bls.PrivateKey.fromKeygen().toPublicKey()), + }; + }, + testRunner: (pks) => { + bls.PublicKey.aggregate(pks); + }, + }); + // Aggregate sigs - runBenchmark({ - id: `BLST aggregatePubkeys (${aggCount})`, + runBenchmark({ + id: `${implementation} aggregate signatures (${aggCount})`, prepareTest: () => { + const msg = randomMsg(); + const sigs = range(aggCount).map(() => { + const sk = bls.PrivateKey.fromKeygen(); + return sk.signMessage(msg); + }); return { - input: range(aggCount).map(() => blst.SecretKey.fromKeygen(crypto.randomBytes(32)).toPublicKey()), + input: sigs, }; }, - testRunner: (pks) => { - blst.AggregatePublicKey.fromPublicKeys(pks); + testRunner: (sigs) => { + bls.Signature.aggregate(sigs); }, }); - - runBenchmark({ - id: `BLST aggregatePubkeys as jacobian (${aggCount})`, - - prepareTest: () => { - return { - input: range(aggCount).map(() => { - const pk = blst.SecretKey.fromKeygen(crypto.randomBytes(32)).toPublicKey(); - return blst.AggregatePublicKey.fromPublicKey(pk); - }), - }; - }, - testRunner: (pks) => { - blst.aggregatePubkeys(pks); - }, - }); - - runBenchmark({ - id: `HERUMI aggregatePubkeys (${aggCount})`, - - prepareTest: () => { - return { - input: range(aggCount).map(() => herumi.generateKeyPair().publicKey), - }; - }, - testRunner: (pks) => { - herumi.PublicKey.aggregate(pks); - }, - }); -})(); +}); function range(n: number): number[] { const nums: number[] = []; diff --git a/test/spec/aggregate_sigs.test.ts b/test/spec/aggregate_sigs.test.ts index c2a0e9c..50af3fa 100644 --- a/test/spec/aggregate_sigs.test.ts +++ b/test/spec/aggregate_sigs.test.ts @@ -2,7 +2,7 @@ import path from "path"; import {describeDirectorySpecTest, InputType} from "@chainsafe/lodestar-spec-test-util"; import {bytesToHex, hexToBytes} from "../../src/helpers/utils"; import {SPEC_TESTS_DIR} from "../params"; -import {forEachImplementation} from "../switch"; +import {describeForAllImplementations} from "../switch"; interface IAggregateSigsTestCase { data: { @@ -11,7 +11,7 @@ interface IAggregateSigsTestCase { }; } -forEachImplementation((bls) => { +describeForAllImplementations((bls) => { describeDirectorySpecTest( "bls/aggregate/small", path.join(SPEC_TESTS_DIR, "general/phase0/bls/aggregate/small"), diff --git a/test/spec/aggregate_sigs_verify.test.ts b/test/spec/aggregate_sigs_verify.test.ts index 5757ab7..a2f0676 100644 --- a/test/spec/aggregate_sigs_verify.test.ts +++ b/test/spec/aggregate_sigs_verify.test.ts @@ -2,7 +2,7 @@ import path from "path"; import {describeDirectorySpecTest, InputType} from "@chainsafe/lodestar-spec-test-util"; import {hexToBytes} from "../../src/helpers/utils"; import {SPEC_TESTS_DIR} from "../params"; -import {forEachImplementation} from "../switch"; +import {describeForAllImplementations} from "../switch"; interface IAggregateSigsVerifyTestCase { data: { @@ -15,7 +15,7 @@ interface IAggregateSigsVerifyTestCase { }; } -forEachImplementation((bls) => { +describeForAllImplementations((bls) => { describeDirectorySpecTest( "bls/aggregate_verify/small", path.join(SPEC_TESTS_DIR, "general/phase0/bls/aggregate_verify/small"), diff --git a/test/spec/fast_aggregate_verify.test.ts b/test/spec/fast_aggregate_verify.test.ts index 53f036c..6cf9906 100644 --- a/test/spec/fast_aggregate_verify.test.ts +++ b/test/spec/fast_aggregate_verify.test.ts @@ -2,7 +2,7 @@ import path from "path"; import {describeDirectorySpecTest, InputType} from "@chainsafe/lodestar-spec-test-util"; import {hexToBytes} from "../../src/helpers/utils"; import {SPEC_TESTS_DIR} from "../params"; -import {forEachImplementation} from "../switch"; +import {describeForAllImplementations} from "../switch"; interface IAggregateSigsVerifyTestCase { data: { @@ -15,7 +15,7 @@ interface IAggregateSigsVerifyTestCase { }; } -forEachImplementation((bls) => { +describeForAllImplementations((bls) => { describeDirectorySpecTest( "bls/fast_aggregate_verify/small", path.join(SPEC_TESTS_DIR, "general/phase0/bls/fast_aggregate_verify/small"), diff --git a/test/spec/sign.test.ts b/test/spec/sign.test.ts index 1e488f0..f525e5d 100644 --- a/test/spec/sign.test.ts +++ b/test/spec/sign.test.ts @@ -2,7 +2,7 @@ import path from "path"; import {describeDirectorySpecTest, InputType} from "@chainsafe/lodestar-spec-test-util"; import {bytesToHex, hexToBytes} from "../../src/helpers/utils"; import {SPEC_TESTS_DIR} from "../params"; -import {forEachImplementation} from "../switch"; +import {describeForAllImplementations} from "../switch"; interface ISignMessageTestCase { data: { @@ -14,7 +14,7 @@ interface ISignMessageTestCase { }; } -forEachImplementation((bls) => { +describeForAllImplementations((bls) => { describeDirectorySpecTest( "bls/sign/small", path.join(SPEC_TESTS_DIR, "general/phase0/bls/sign/small"), diff --git a/test/spec/verify.test.ts b/test/spec/verify.test.ts index 7e2e779..59e65f8 100644 --- a/test/spec/verify.test.ts +++ b/test/spec/verify.test.ts @@ -2,7 +2,7 @@ import path from "path"; import {describeDirectorySpecTest, InputType} from "@chainsafe/lodestar-spec-test-util"; import {hexToBytes} from "../../src/helpers/utils"; import {SPEC_TESTS_DIR} from "../params"; -import {forEachImplementation} from "../switch"; +import {describeForAllImplementations} from "../switch"; interface IVerifyTestCase { data: { @@ -15,7 +15,7 @@ interface IVerifyTestCase { }; } -forEachImplementation((bls) => { +describeForAllImplementations((bls) => { describeDirectorySpecTest( "bls/verify/small", path.join(SPEC_TESTS_DIR, "general/phase0/bls/verify/small"), diff --git a/test/switch.ts b/test/switch.ts index 4fb8799..66a6f45 100644 --- a/test/switch.ts +++ b/test/switch.ts @@ -14,19 +14,23 @@ export function getBls(implementation: Implementation): IBls { } } -export function forEachImplementation( - implementations: Implementation[], - callback: (bls: ReturnType, implementation: Implementation) => void -): void { - for (const implementation of implementations) { - describe(implementation, () => { - const bls = getBls(implementation); +export async function runForAllImplementations( + callback: (bls: IBls, implementation: Implementation) => Promise | void +): Promise { + for (const implementation of ["blst", "herumi"] as Implementation[]) { + const bls = getBls(implementation); + await callback(bls, implementation); + } +} +export function describeForAllImplementations(callback: (bls: IBls) => void): void { + runForAllImplementations((bls, implementation) => { + describe(implementation, () => { before(async () => { await bls.initBLS(); }); - callback(bls, implementation); + callback(bls); }); - } + }); } diff --git a/test/unit/index.test.ts b/test/unit/index.test.ts index 32da4a0..b7ef13b 100644 --- a/test/unit/index.test.ts +++ b/test/unit/index.test.ts @@ -2,7 +2,7 @@ import {expect} from "chai"; import {IBls} from "../../src/interface"; import {getN, randomMessage} from "../util"; -export function runIndexTests(bls: IBls) { +export function runIndexTests(bls: IBls): void { // eslint-disable-next-line @typescript-eslint/explicit-function-return-type function getRandomData() { const sk = bls.PrivateKey.fromKeygen(); diff --git a/test/unit/privateKey.test.ts b/test/unit/privateKey.test.ts index b849cf9..75aad31 100644 --- a/test/unit/privateKey.test.ts +++ b/test/unit/privateKey.test.ts @@ -1,7 +1,7 @@ import {expect} from "chai"; import {IBls} from "../../src/interface"; -export function runPrivateKeyTests(bls: IBls) { +export function runPrivateKeyTests(bls: IBls): void { describe("PrivateKey", () => { it("should generate fromKeygen private key", () => { const privateKey1 = bls.PrivateKey.fromKeygen(); diff --git a/test/unit/publicKey.test.ts b/test/unit/publicKey.test.ts index 0c66cf1..cb139c1 100644 --- a/test/unit/publicKey.test.ts +++ b/test/unit/publicKey.test.ts @@ -1,7 +1,7 @@ import {expect} from "chai"; import {IBls} from "../../src/interface"; -export function runPublicKeyTests(bls: IBls) { +export function runPublicKeyTests(bls: IBls): void { describe("PublicKey", () => { const publicKey = "0xb6f21199594b56d77670564bf422cb331d5281ca2c1f9a45588a56881d8287ef8619efa6456d6cd2ef61306aa5b21311"; diff --git a/test/unit/run-all-implementations.test.ts b/test/unit/run-all-implementations.test.ts index ea90530..f42a3f1 100644 --- a/test/unit/run-all-implementations.test.ts +++ b/test/unit/run-all-implementations.test.ts @@ -2,10 +2,10 @@ import {runPrivateKeyTests} from "./privateKey.test"; import {runPublicKeyTests} from "./publicKey.test"; // import {runKeypairTests} from "./keypair.test"; import {runIndexTests} from "./index.test"; -import {forEachImplementation} from "../switch"; +import {describeForAllImplementations} from "../switch"; // Import test's bls lib lazily to prevent breaking test with Karma -forEachImplementation(["blst", "herumi"], (bls) => { +describeForAllImplementations((bls) => { runPrivateKeyTests(bls); runPublicKeyTests(bls); // runKeypairTests(bls); diff --git a/test/unit/run-web-implementation.test.ts b/test/unit/run-web-implementation.test.ts index 31d18e0..b70e9bd 100644 --- a/test/unit/run-web-implementation.test.ts +++ b/test/unit/run-web-implementation.test.ts @@ -9,6 +9,8 @@ import {runIndexTests} from "./index.test"; // Error: BLST bindings loader should only run in a NodeJS context: process.platform describe("herumi", () => { before(async () => { + // For consistency with describeForAllImplementations + // eslint-disable-next-line import/no-named-as-default-member await herumi.initBLS(); }); From 2073d31a159f417ea81c51cb717cfbeee150eec5 Mon Sep 17 00:00:00 2001 From: dapplion Date: Fri, 20 Nov 2020 19:37:07 +0000 Subject: [PATCH 16/51] Run benchmarks on CI --- .github/workflows/test.yml | 2 ++ package.json | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 2021c6b..63b9e5b 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -20,3 +20,5 @@ jobs: run: yarn lint - name: Tests run: yarn test + - name: Benchmark + run: yarn benchmark diff --git a/package.json b/package.json index 64d3785..25c5add 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "test:spec": "mocha --colors -r ts-node/register 'test/spec/**/*.test.ts'", "test": "yarn run test:unit && yarn run test:spec", "coverage": "codecov -F bls", - "benchmark": "node -r ./.babel-register test/benchmarks" + "benchmark": "ts-node test/benchmark" }, "dependencies": { "@chainsafe/bls-keygen": "^0.2.0", From 426316ddc268b27a945135bbc85001d725d3cb33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marin=20Petruni=C4=87?= Date: Mon, 23 Nov 2020 12:06:20 +0100 Subject: [PATCH 17/51] remove @chainsafe/eth2-bls-wasm dep --- package.json | 13 +- src/context.ts | 2 +- src/privateKey.ts | 2 +- src/publicKey.ts | 2 +- src/signature.ts | 4 +- tsconfig.json | 1 + types/bls-eth-wasm/index.d.ts | 111 ++++++++ yarn.lock | 487 ++++++++++++++++++---------------- 8 files changed, 387 insertions(+), 235 deletions(-) create mode 100644 types/bls-eth-wasm/index.d.ts diff --git a/package.json b/package.json index 65ba239..bc2afd0 100644 --- a/package.json +++ b/package.json @@ -40,8 +40,8 @@ }, "dependencies": { "@chainsafe/bls-keygen": "^0.2.0", - "@chainsafe/eth2-bls-wasm": "^0.5.0", - "assert": "^1.4.1" + "assert": "^1.4.1", + "bls-eth-wasm": "^0.4.1" }, "devDependencies": { "@babel/cli": "^7.8.4", @@ -54,9 +54,9 @@ "@babel/register": "^7.8.3", "@chainsafe/as-sha256": "0.2.0", "@chainsafe/eth2-spec-tests": "0.12.0", - "@chainsafe/lodestar-spec-test-util": "^0.5.0", + "@chainsafe/lodestar-spec-test-util": "^0.11.0", "@types/chai": "^4.2.9", - "@types/mocha": "^7.0.1", + "@types/mocha": "^8.0.4", "@typescript-eslint/eslint-plugin": "^2.20.0", "@typescript-eslint/parser": "^2.20.0", "chai": "^4.2.0", @@ -70,7 +70,7 @@ "karma-mocha": "^1.3.0", "karma-spec-reporter": "^0.0.32", "karma-webpack": "^4.0.2", - "mocha": "^6.2.0", + "mocha": "^8.2.1", "nyc": "^15.0.0", "prettier": "^2.1.2", "ts-loader": "^6.2.1", @@ -78,5 +78,8 @@ "typescript": "^3.7.5", "webpack": "^4.30.0", "webpack-cli": "^3.3.2" + }, + "resolutions": { + "mocha": "^8.2.1" } } diff --git a/src/context.ts b/src/context.ts index aceb809..38e0c18 100644 --- a/src/context.ts +++ b/src/context.ts @@ -1,5 +1,5 @@ /* eslint-disable require-atomic-updates */ -import bls from "@chainsafe/eth2-bls-wasm"; +import bls from "bls-eth-wasm"; type Bls = typeof bls; let blsGlobal: Bls | null = null; diff --git a/src/privateKey.ts b/src/privateKey.ts index deb8029..dbf3160 100644 --- a/src/privateKey.ts +++ b/src/privateKey.ts @@ -1,6 +1,6 @@ import {SECRET_KEY_LENGTH} from "./constants"; import assert from "assert"; -import {SecretKeyType} from "@chainsafe/eth2-bls-wasm"; +import {SecretKeyType} from "bls-eth-wasm"; import {generateRandomSecretKey} from "@chainsafe/bls-keygen"; import {getContext} from "./context"; import {PublicKey} from "./publicKey"; diff --git a/src/publicKey.ts b/src/publicKey.ts index c994489..c7537c7 100644 --- a/src/publicKey.ts +++ b/src/publicKey.ts @@ -1,5 +1,5 @@ import {PrivateKey} from "./privateKey"; -import {PublicKeyType} from "@chainsafe/eth2-bls-wasm"; +import {PublicKeyType} from "bls-eth-wasm"; import {getContext} from "./context"; import {PUBLIC_KEY_LENGTH} from "./constants"; import assert from "assert"; diff --git a/src/signature.ts b/src/signature.ts index 08c38e6..5da9104 100644 --- a/src/signature.ts +++ b/src/signature.ts @@ -1,6 +1,6 @@ import assert from "assert"; import {FP_POINT_LENGTH} from "./constants"; -import {SignatureType} from "@chainsafe/eth2-bls-wasm"; +import {SignatureType} from "bls-eth-wasm"; import {getContext} from "./context"; import {PublicKey} from "./publicKey"; import {EMPTY_SIGNATURE} from "./helpers/utils"; @@ -53,7 +53,7 @@ export class Signature { public verifyMultiple(publicKeys: PublicKey[], messages: Uint8Array[], fast = false): boolean { const msgs = Buffer.concat(messages); - if (!fast && !getContext().areAllMsgDifferent(msgs)) { + if (!fast && !getContext().areAllMsgDifferent(msgs, messages[0].length)) { return false; } return this.value.aggregateVerifyNoCheck( diff --git a/tsconfig.json b/tsconfig.json index a083043..dd24356 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -7,6 +7,7 @@ "lib": [ "esnext.bigint" ], + "typeRoots": ["./node_modules/@types", "./types"], "declaration": true, "strict": true, "strictNullChecks": false, diff --git a/types/bls-eth-wasm/index.d.ts b/types/bls-eth-wasm/index.d.ts new file mode 100644 index 0000000..a41515e --- /dev/null +++ b/types/bls-eth-wasm/index.d.ts @@ -0,0 +1,111 @@ +declare module "bls-eth-wasm" { + export class Common { + + constructor(size: number); + + deserializeHexStr(s: string): void; + + serializeToHexStr(): string; + + dump(msg?: string): string; + + clear(): void; + + clone(): this; + + isEqual(rhs: this): boolean + + deserialize(v: Uint8Array): void; + + serialize(): Uint8Array; + + add(rhs: this): void; + } + + export class SecretKeyType extends Common { + + constructor(); + + setInt(x: number): void; + + setHashOf(a: Uint8Array): void; + + setLittleEndian(a: Uint8Array): void; + + setByCSPRNG(): void; + + getPublicKey(): PublicKeyType; + + sign(m: string | Uint8Array): SignatureType; + + /** + * + * @param m must have 40 bytes + */ + signHashWithDomain(m: Uint8Array): SignatureType; + } + + export class PublicKeyType extends Common { + + constructor(); + + verify(signature: SignatureType, m: Uint8Array | string): boolean; + isValidOrder(): boolean; + deserializeUncompressed (s: Uint8Array): void; + serializeUncompressed (): Uint8Array; + deserializeUncompressedHexStr (s:string): void; + serializeUncompressedToHexStr(): string; + /** + * + * @param signature + * @param m must have 40 bytes + */ + verifyHashWithDomain(signature: SignatureType, m: Uint8Array): boolean; + } + + export class SignatureType extends Common { + constructor(); + + deserializeUncompressed (s: Uint8Array): void; + serializeUncompressed (): Uint8Array; + deserializeUncompressedHexStr (s:string): void; + serializeUncompressedToHexStr(): string; + isValidOrder(): boolean; + aggregate(others: SignatureType[]): boolean; + aggregateVerifyNoCheck(publicKeys: PublicKeyType[], messages: Uint8Array): boolean; + fastAggregateVerify(publicKeys: PublicKeyType[], message: Uint8Array): boolean; + /** + * + * @param publicKeys + * @param messages each message must have 40bytes + */ + verifyAggregatedHashWithDomain(publicKeys: PublicKeyType[], messages: Uint8Array[]): boolean + + } + + export function init(): Promise; + + export function toHex(a: Uint8Array, start: number, length: number): string; + export function toHexStr(a: Uint8Array): string; + export function fromHexStr(s: string): Uint8Array; + export function getCurveOrder(): string; + export function getFieldOrder(): string; + export function verifySignatureOrder(doVerify: boolean): void; + export function verifyPublicKeyOrder(doVerify: boolean): void; + + /** + * + * @param msgs single array with concatenated messages + * @param msgSize defaults to MSG_SIZE + */ + export function areAllMsgDifferent(msgs: Uint8Array, msgSize?: number): boolean; + export function shouldVerifyBlsSignatureOrder(b: string): void; + export function shouldVerifyBlsPublicKeyOrder(b: string): void; + export function deserializeHexStrToSecretKey(s: string): SecretKeyType; + export function deserializeHexStrToPublicKey(s: string): PublicKeyType; + export function deserializeHexStrToSignature(s: string): SignatureType; + + export const SecretKey: typeof SecretKeyType; + export const PublicKey: typeof PublicKeyType; + export const Signature: typeof SignatureType; +} \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index 296f5d6..c86e326 100644 --- a/yarn.lock +++ b/yarn.lock @@ -791,7 +791,7 @@ lodash "^4.17.13" to-fast-properties "^2.0.0" -"@chainsafe/as-sha256@0.2.0": +"@chainsafe/as-sha256@0.2.0", "@chainsafe/as-sha256@^0.2.0": version "0.2.0" resolved "https://registry.yarnpkg.com/@chainsafe/as-sha256/-/as-sha256-0.2.0.tgz#3ebe061d59d30af9e95a8c22ff4813cbf0e89dbc" integrity sha512-reKklZhY4jSj7JdxdAjUfsaiMt2pdm8V/IqlOR5c4m6Y4tRCxt4f0HBMfyiE2ZQF4tqPPqRVf/ulXwK+LjLIxw== @@ -820,81 +820,53 @@ bip39 "^3.0.2" buffer "^5.4.3" -"@chainsafe/eth2-bls-wasm@^0.5.0": - version "0.5.0" - resolved "https://registry.yarnpkg.com/@chainsafe/eth2-bls-wasm/-/eth2-bls-wasm-0.5.0.tgz#45d0cb8807b569537d1e0099922a9617e0410b3a" - integrity sha512-7aHphmg504W4YTvAEvGscODrr1Fo5Mf9NxB72fuFv2BKUS/0BPgkoxG9tA+KxcFQq1hs/VUeLhq6qVdI5WfNNA== - dependencies: - buffer "^5.4.3" - "@chainsafe/eth2-spec-tests@0.12.0": version "0.12.0" resolved "https://registry.yarnpkg.com/@chainsafe/eth2-spec-tests/-/eth2-spec-tests-0.12.0.tgz#f95ffe5bc20ddaa4d2240cffe1e417877adc8055" integrity sha512-EECbmI/1SdjSPUaQOkZqBOA6AfhviS7jlXVmAs3P2biJTeH2p0p31V4fZImR2NXAgGVFAP16sRx2OCwflOq0mw== -"@chainsafe/lodestar-params@^0.5.0": - version "0.5.0" - resolved "https://registry.yarnpkg.com/@chainsafe/lodestar-params/-/lodestar-params-0.5.0.tgz#c0be10277510e9f34159f30da0e3c47444bcfcfb" - integrity sha512-5cmadp2dDlTDozejsSq6IbOUXzp3jEiBUvxehkZ+O2ezc3SsFMun4FkJs81jn8LMvsZwAq+0ZkALjh/brTIHJg== - -"@chainsafe/lodestar-spec-test-util@^0.5.0": - version "0.5.0" - resolved "https://registry.yarnpkg.com/@chainsafe/lodestar-spec-test-util/-/lodestar-spec-test-util-0.5.0.tgz#7fd0523389835ce0cd2029f0ce11b1a66fa07d6d" - integrity sha512-35im6FcE/c5a9PVEDbGtDo4cLcqzTRe1/EULhBFQoXRaHQ0iRM5ldd9W78FzXA38ztv72rbF2lhjjmCbHnFMRQ== +"@chainsafe/lodestar-spec-test-util@^0.11.0": + version "0.11.0" + resolved "https://registry.yarnpkg.com/@chainsafe/lodestar-spec-test-util/-/lodestar-spec-test-util-0.11.0.tgz#23d6d5edf7d1fbea3662a1919857d9ea85fe86a0" + integrity sha512-KlnW2emffpEFMIuaP+Ulr1FSMfm5hg0H2NmJjUE4LTs1U7Vtrp/1e9ALzObYLAT3u9bA5byDtqikg4L3RitbMQ== dependencies: - "@chainsafe/lodestar-utils" "^0.5.0" - "@chainsafe/ssz" "^0.6.0" + "@chainsafe/lodestar-utils" "^0.11.0" + "@chainsafe/ssz" "^0.6.11" camelcase "^5.3.1" chai "^4.2.0" deepmerge "^4.0.0" js-yaml "^3.13.1" - mocha "^6.2.0" + mocha "^6.2.2" v8-profiler-next "^1.1.1" -"@chainsafe/lodestar-types@^0.5.0": - version "0.5.0" - resolved "https://registry.yarnpkg.com/@chainsafe/lodestar-types/-/lodestar-types-0.5.0.tgz#4ed800556719f12bfc539ed09530744a7fb8aa4b" - integrity sha512-SKVopypp3IoQthBKQzfKPr5W+jJazP6Gs37v4uvK3/U8ShA6cIuAZDU8swu3mSbRXFVDaYIYNANIkA0vMbuEaw== +"@chainsafe/lodestar-utils@^0.11.0": + version "0.11.0" + resolved "https://registry.yarnpkg.com/@chainsafe/lodestar-utils/-/lodestar-utils-0.11.0.tgz#3b16d20646fbca1ee6796684d191e17928556524" + integrity sha512-2hQxkl7H2qHOXb2elxNW5nsenQW/0CWRoZEzyRmJd53jWjkyHOIVwymhKnXp9oy7LsJfPsvlbnbdleLZ/ymqSA== dependencies: - "@chainsafe/lodestar-params" "^0.5.0" - "@chainsafe/ssz" "0.6.0" - -"@chainsafe/lodestar-utils@^0.5.0": - version "0.5.0" - resolved "https://registry.yarnpkg.com/@chainsafe/lodestar-utils/-/lodestar-utils-0.5.0.tgz#698f6ad563477c4c5aa6e9b2a92bccd38454193b" - integrity sha512-3WY+iCZCanoYKvOOwV3Wyy0ES7Ffg0w56RSH9ina/Hbay8BVP9fphO9p1ee0ZMrHf3MtfTHHK4bRSRGRScWjmg== - dependencies: - "@chainsafe/lodestar-types" "^0.5.0" - bcrypto "^4.2.6" + "@chainsafe/ssz" "^0.6.11" bigint-buffer "^1.1.5" camelcase "^5.3.1" chalk "^2.4.2" js-yaml "^3.13.1" - snake-case "^2.1.0" winston "^3.2.1" + winston-transport "^4.3.0" -"@chainsafe/persistent-merkle-tree@^0.1.1": - version "0.1.1" - resolved "https://registry.yarnpkg.com/@chainsafe/persistent-merkle-tree/-/persistent-merkle-tree-0.1.1.tgz#6a8384b80595ea87dc8b6aee11e4ee236d9854b1" - integrity sha512-bUjUEBFMPx+r/RHAhWJXvHnsfYEHfIVHkwMxdgjMUt4gcMHxiFciaIQBD/FRvAffft/8B5+S5ASknqPvGVk1kA== +"@chainsafe/persistent-merkle-tree@^0.2.1": + version "0.2.1" + resolved "https://registry.yarnpkg.com/@chainsafe/persistent-merkle-tree/-/persistent-merkle-tree-0.2.1.tgz#38eb5fd5772fd256e94639d0621fa606addebab1" + integrity sha512-07Hi5QiogeTuwNiZXxg7PQnwNyEqV3ArfITpEloGJ8JVOHxQ2Tha1fo4oNBF54628vTDMcDpMVFGrfnIMsQnxg== dependencies: - bcrypto "^4.2.8" + "@chainsafe/as-sha256" "^0.2.0" -"@chainsafe/ssz@0.6.0": - version "0.6.0" - resolved "https://registry.yarnpkg.com/@chainsafe/ssz/-/ssz-0.6.0.tgz#9f496cc70abc9c7f7802c727396508e539d94697" - integrity sha512-i0lo6SFeg7mn8LXrHpZ9Wo730M04nYMItaJAx4kYFu3E3IEcEDQH/Aon8+MHQ6nVHAAPaVLs9zyhNUvgNUAofA== +"@chainsafe/ssz@^0.6.11": + version "0.6.13" + resolved "https://registry.yarnpkg.com/@chainsafe/ssz/-/ssz-0.6.13.tgz#94333993b9eb5e8ae7798fc3e4a5db36f846e5ec" + integrity sha512-pKb1nlIRD3YvVlgbgB5kir+H2tu1pUhiZd9SIrwUr3xq/vQvoYcs3z+DBrhl1WtW5zwQorxgMe/1pnXp7raLtA== dependencies: - "@chainsafe/persistent-merkle-tree" "^0.1.1" - bcrypto "^4.1.0" - -"@chainsafe/ssz@^0.6.0": - version "0.6.1" - resolved "https://registry.yarnpkg.com/@chainsafe/ssz/-/ssz-0.6.1.tgz#07944684befd557d9e2e85942da5534d38be67d2" - integrity sha512-ycSA0HPflbh5MJt9heRHc4adD835KMx/Vqiu/aM1LNMDyMgrRUmVSem+8xtqigROyfi4J/cUiN1j7L5aTygilA== - dependencies: - "@chainsafe/persistent-merkle-tree" "^0.1.1" - bcrypto "^4.1.0" + "@chainsafe/as-sha256" "^0.2.0" + "@chainsafe/persistent-merkle-tree" "^0.2.1" + case "^1.6.3" "@istanbuljs/load-nyc-config@^1.0.0": version "1.0.0" @@ -931,10 +903,10 @@ resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.4.tgz#38fd73ddfd9b55abb1e1b2ed578cb55bd7b7d339" integrity sha512-8+KAKzEvSUdeo+kmqnKrqgeE+LcA0tjYWFY7RPProVYwnqDjukzO+3b6dLD56rYX5TdWejnEOLJYOIeh4CXKuA== -"@types/mocha@^7.0.1": - version "7.0.1" - resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-7.0.1.tgz#5d7ec2a789a1f77c59b7ad071b9d50bf1abbfc9e" - integrity sha512-L/Nw/2e5KUaprNJoRA33oly+M8X8n0K+FwLTbYqwTcR14wdPWeRkigBLfSFpN/Asf9ENZTMZwLxjtjeYucAA4Q== +"@types/mocha@^8.0.4": + version "8.0.4" + resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-8.0.4.tgz#b840c2dce46bacf286e237bfb59a29e843399148" + integrity sha512-M4BwiTJjHmLq6kjON7ZoI2JMlBvpY3BYSdiP6s/qCT3jb1s9/DeJF0JELpAxiVSIxXDzfNKe+r7yedMIoLbknQ== "@types/node@11.11.6": version "11.11.6" @@ -984,6 +956,11 @@ semver "^6.3.0" tsutils "^3.17.1" +"@ungap/promise-all-settled@1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz#aa58042711d6e3275dd37dc597e5d31e8c290a44" + integrity sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q== + "@webassemblyjs/ast@1.8.5": version "1.8.5" resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.8.5.tgz#51b1c5fe6576a34953bf4b253df9f0d490d9e359" @@ -1196,10 +1173,10 @@ ajv@^6.1.0, ajv@^6.10.0, ajv@^6.10.2: json-schema-traverse "^0.4.1" uri-js "^4.2.2" -ansi-colors@3.2.3: - version "3.2.3" - resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-3.2.3.tgz#57d35b8686e851e2cc04c403f1c00203976a1813" - integrity sha512-LEHHyuhlPY3TmuUYMh2oz89lTShfvgbmzaBcxve9t/9Wuy7Dwf4yoAKcND7KFT1HAQfqZ12qtc+DUrBMeKF9nw== +ansi-colors@4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.1.tgz#cbb9ae256bf750af1eab344f229aa27fe94ba348" + integrity sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA== ansi-colors@^3.0.0: version "3.2.4" @@ -1243,6 +1220,13 @@ ansi-styles@^4.0.0: "@types/color-name" "^1.1.1" color-convert "^2.0.1" +ansi-styles@^4.1.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" + integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== + dependencies: + color-convert "^2.0.1" + anymatch@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-2.0.0.tgz#bcb24b4f37934d9aa7ac17b4adaf89e7c76ef2eb" @@ -1439,16 +1423,6 @@ base@^0.11.1: mixin-deep "^1.2.0" pascalcase "^0.1.1" -bcrypto@^4.1.0, bcrypto@^4.2.6, bcrypto@^4.2.8: - version "4.3.2" - resolved "https://registry.yarnpkg.com/bcrypto/-/bcrypto-4.3.2.tgz#50d4543cc16c39a9fca1d7f457a3850703867814" - integrity sha512-uGmeiqLvLYUPRa0XoACDgXwxZY9wE1uiFHpdtGSs7FI2YYkakqIWZklkF8sKMzXM/HaHRIjulzQ8xuDoqptjVQ== - dependencies: - bsert "~0.0.10" - bufio "~1.0.6" - loady "~0.0.1" - nan "^2.14.0" - bcrypto@^5.0.4: version "5.2.0" resolved "https://registry.yarnpkg.com/bcrypto/-/bcrypto-5.2.0.tgz#7cc944d2cc2b7beeff04c74f8611a001612a981d" @@ -1508,6 +1482,11 @@ blob@0.0.5: resolved "https://registry.yarnpkg.com/blob/-/blob-0.0.5.tgz#d680eeef25f8cd91ad533f5b01eed48e64caf683" integrity sha512-gaqbzQPqOoamawKg0LGVd7SzLgXS+JH61oWprSLH+P+abTczqJbhTR8CmJ2u9/bUYNmHTGJx/UEmn6doAvvuig== +bls-eth-wasm@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/bls-eth-wasm/-/bls-eth-wasm-0.4.1.tgz#7a1bac9d36f117ad4a8c7e741d667b51a6c31e68" + integrity sha512-BBM+t/RNZSOZKiLmz+wmz58kzK9CDjH6K2o2QuUKUkJNUaDo8g4vsqay0SvbmxinhpSxL/epkVel9+KNXcFnlw== + bluebird@^3.3.0, bluebird@^3.5.5: version "3.7.2" resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f" @@ -1648,11 +1627,6 @@ browserslist@^4.8.3, browserslist@^4.8.5: electron-to-chromium "^1.3.349" node-releases "^1.1.49" -bsert@~0.0.10: - version "0.0.10" - resolved "https://registry.yarnpkg.com/bsert/-/bsert-0.0.10.tgz#231ac82873a1418c6ade301ab5cd9ae385895597" - integrity sha512-NHNwlac+WPy4t2LoNh8pXk8uaIGH3NSaIUbTTRXGpE2WEbq0te/tDykYHkFK57YKLPjv/aGHmbqvnGeVWDz57Q== - buffer-alloc-unsafe@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz#bd7dc26ae2972d0eda253be061dba992349c19f0" @@ -1698,11 +1672,6 @@ buffer@^5.4.3: base64-js "^1.0.2" ieee754 "^1.1.4" -bufio@~1.0.6: - version "1.0.6" - resolved "https://registry.yarnpkg.com/bufio/-/bufio-1.0.6.tgz#e0eb6d70b2efcc997b6f8872173540967f90fa4d" - integrity sha512-mjYZFRHmI9bk3Oeexu0rWjHFY+w6hGLabdmwSFzq+EFr4MHHsNOYduDVdYl71NG5pTPL7GGzUCMk9cYuV34/Qw== - bufio@~1.0.7: version "1.0.7" resolved "https://registry.yarnpkg.com/bufio/-/bufio-1.0.7.tgz#b7f63a1369a0829ed64cc14edf0573b3e382a33e" @@ -1779,11 +1748,21 @@ camelcase@^5.0.0, camelcase@^5.3.1: resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== +camelcase@^6.0.0: + version "6.2.0" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.2.0.tgz#924af881c9d525ac9d87f40d964e5cea982a1809" + integrity sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg== + caniuse-lite@^1.0.30001027: version "1.0.30001028" resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001028.tgz#f2241242ac70e0fa9cda55c2776d32a0867971c2" integrity sha512-Vnrq+XMSHpT7E+LWoIYhs3Sne8h9lx9YJV3acH3THNCwU/9zV93/ta4xVfzTtnqd3rvnuVpVjE3DFqf56tr3aQ== +case@^1.6.3: + version "1.6.3" + resolved "https://registry.yarnpkg.com/case/-/case-1.6.3.tgz#0a4386e3e9825351ca2e6216c60467ff5f1ea1c9" + integrity sha512-mzDSXIPaFwVDvZAHqZ9VlbyF4yyXRuX6IvB06WvPYkqJVO24kX1PPhv9bfpKNFZyxYFmmgo03HUiD8iklmJYRQ== + chai@^4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/chai/-/chai-4.2.0.tgz#760aa72cf20e3795e84b12877ce0e83737aa29e5" @@ -1796,7 +1775,7 @@ chai@^4.2.0: pathval "^1.1.0" type-detect "^4.0.5" -chalk@2.4.2, chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0, chalk@^2.3.0, chalk@^2.4.2: +chalk@2.4.2, chalk@^2.0.0, chalk@^2.1.0, chalk@^2.3.0, chalk@^2.4.2: version "2.4.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== @@ -1805,6 +1784,14 @@ chalk@2.4.2, chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0, chalk@^2.3.0, chalk@^2.4. escape-string-regexp "^1.0.5" supports-color "^5.3.0" +chalk@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.0.tgz#4e14870a618d9e2edd97dd8345fd9d9dc315646a" + integrity sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + chardet@^0.7.0: version "0.7.0" resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" @@ -1815,6 +1802,21 @@ check-error@^1.0.2: resolved "https://registry.yarnpkg.com/check-error/-/check-error-1.0.2.tgz#574d312edd88bb5dd8912e9286dd6c0aed4aac82" integrity sha1-V00xLt2Iu13YkS6Sht1sCu1KrII= +chokidar@3.4.3: + version "3.4.3" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.4.3.tgz#c1df38231448e45ca4ac588e6c79573ba6a57d5b" + integrity sha512-DtM3g7juCXQxFVSNPNByEC2+NImtBuxQQvWlHunpJIS5Ocr0lG306cC7FCi7cEA0fzmybPUIl4txBIobk1gGOQ== + dependencies: + anymatch "~3.1.1" + braces "~3.0.2" + glob-parent "~5.1.0" + is-binary-path "~2.1.0" + is-glob "~4.0.1" + normalize-path "~3.0.0" + readdirp "~3.5.0" + optionalDependencies: + fsevents "~2.1.2" + chokidar@^2.0.2, chokidar@^2.1.8: version "2.1.8" resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.1.8.tgz#804b3a7b6a99358c3c5c61e71d8728f041cff917" @@ -2201,7 +2203,14 @@ debug@2.6.9, debug@^2.2.0, debug@^2.3.3, debug@^2.6.9: dependencies: ms "2.0.0" -debug@3.2.6, debug@^3.0.0, debug@^3.2.6: +debug@4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.2.0.tgz#7f150f93920e94c58f5574c2fd01a3110effe7f1" + integrity sha512-IX2ncY78vDTjZMFUdmsvIRFY2Cf4FnD0wRs+nQwJU8Lu99/tPFdb0VybiiMTPe3I6rQmwsqQqRBvxU+bZ/I8sg== + dependencies: + ms "2.1.2" + +debug@^3.0.0, debug@^3.2.6: version "3.2.6" resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b" integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ== @@ -2227,6 +2236,11 @@ decamelize@^1.2.0: resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA= +decamelize@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-4.0.0.tgz#aa472d7bf660eb15f3494efd531cab7f2a709837" + integrity sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ== + decode-uri-component@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" @@ -2317,12 +2331,7 @@ diagnostics@^1.1.1: enabled "1.0.x" kuler "1.0.x" -diff@3.5.0: - version "3.5.0" - resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12" - integrity sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA== - -diff@^4.0.1: +diff@4.0.2, diff@^4.0.1: version "4.0.2" resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== @@ -2561,7 +2570,12 @@ escape-html@~1.0.3: resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" integrity sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg= -escape-string-regexp@1.0.5, escape-string-regexp@^1.0.5: +escape-string-regexp@4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" + integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== + +escape-string-regexp@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= @@ -2912,12 +2926,13 @@ find-cache-dir@^3.2.0: make-dir "^3.0.0" pkg-dir "^4.1.0" -find-up@3.0.0, find-up@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73" - integrity sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg== +find-up@5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc" + integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== dependencies: - locate-path "^3.0.0" + locate-path "^6.0.0" + path-exists "^4.0.0" find-up@^2.0.0, find-up@^2.1.0: version "2.1.0" @@ -2926,6 +2941,13 @@ find-up@^2.0.0, find-up@^2.1.0: dependencies: locate-path "^2.0.0" +find-up@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73" + integrity sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg== + dependencies: + locate-path "^3.0.0" + find-up@^4.0.0, find-up@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" @@ -2953,12 +2975,10 @@ flat-cache@^2.0.1: rimraf "2.6.3" write "1.0.3" -flat@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/flat/-/flat-4.1.0.tgz#090bec8b05e39cba309747f1d588f04dbaf98db2" - integrity sha512-Px/TiLIznH7gEDlPXcUD4KnBusa6kR6ayRUVcnEAbreRIuhkqow/mun59BuRXwoYk7ZQOLW1ZM05ilIvK38hFw== - dependencies: - is-buffer "~2.0.3" +flat@^5.0.2: + version "5.0.2" + resolved "https://registry.yarnpkg.com/flat/-/flat-5.0.2.tgz#8ca6fe332069ffa9d324c327198c598259ceb241" + integrity sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ== flatted@^2.0.0: version "2.0.1" @@ -3107,19 +3127,7 @@ glob-parent@^5.0.0, glob-parent@~5.1.0: dependencies: is-glob "^4.0.1" -glob@7.1.3: - version "7.1.3" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.3.tgz#3960832d3f1574108342dafd3a67b332c0969df1" - integrity sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ== - dependencies: - fs.realpath "^1.0.0" - inflight "^1.0.4" - inherits "2" - minimatch "^3.0.4" - once "^1.3.0" - path-is-absolute "^1.0.0" - -glob@^7.0.0, glob@^7.1.1, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6: +glob@7.1.6, glob@^7.0.0, glob@^7.1.1, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6: version "7.1.6" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6" integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA== @@ -3504,11 +3512,6 @@ is-buffer@^1.1.5: resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== -is-buffer@~2.0.3: - version "2.0.4" - resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-2.0.4.tgz#3e572f23c8411a5cfd9557c849e3665e0b290623" - integrity sha512-Kq1rokWXOPXWuaMAqZiJW4XxsmD9zGx9q4aePabbn3qCRGedtH7Cm+zV8WETitMfu1wdh+Rvd6w5egwSngUX2A== - is-callable@^1.1.4, is-callable@^1.1.5: version "1.1.5" resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.5.tgz#f7e46b596890456db74e7f6e976cb3273d06faab" @@ -3616,6 +3619,11 @@ is-number@^7.0.0: resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== +is-plain-obj@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-2.1.0.tgz#45e42e37fccf1f40da8e5f76ee21515840c09287" + integrity sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA== + is-plain-object@^2.0.3, is-plain-object@^2.0.4: version "2.0.4" resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" @@ -3775,7 +3783,15 @@ istanbul-reports@^3.0.0: resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== -js-yaml@3.13.1, js-yaml@^3.13.1: +js-yaml@3.14.0: + version "3.14.0" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.0.tgz#a7a34170f26a21bb162424d8adacb4113a69e482" + integrity sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A== + dependencies: + argparse "^1.0.7" + esprima "^4.0.0" + +js-yaml@^3.13.1: version "3.13.1" resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.13.1.tgz#aff151b30bfdfa8e49e05da22e7415e9dfa37847" integrity sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw== @@ -4025,6 +4041,13 @@ locate-path@^5.0.0: dependencies: p-locate "^4.1.0" +locate-path@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286" + integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw== + dependencies: + p-locate "^5.0.0" + lodash.flattendeep@^4.4.0: version "4.4.0" resolved "https://registry.yarnpkg.com/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz#fb030917f86a3134e5bc9bec0d69e0013ddfedb2" @@ -4035,12 +4058,12 @@ lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15: resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.19.tgz#e48ddedbe30b3321783c5b4301fbd353bc1e4a4b" integrity sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ== -log-symbols@2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-2.2.0.tgz#5740e1c5d6f0dfda4ad9323b5332107ef6b4c40a" - integrity sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg== +log-symbols@4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-4.0.0.tgz#69b3cc46d20f448eccdb75ea1fa733d9e821c920" + integrity sha512-FN8JBzLx6CzeMrB0tg6pqlGU1wCrXW+ZXGH481kfsBqer0hToTIiHdjH4Mq8xJUbvATujKCvaREGWpGUionraA== dependencies: - chalk "^2.0.1" + chalk "^4.0.0" log4js@^4.0.0: version "4.5.1" @@ -4071,11 +4094,6 @@ loose-envify@^1.0.0: dependencies: js-tokens "^3.0.0 || ^4.0.0" -lower-case@^1.1.1: - version "1.1.4" - resolved "https://registry.yarnpkg.com/lower-case/-/lower-case-1.1.4.tgz#9a2cabd1b9e8e0ae993a4bf7d5875c39c42e8eac" - integrity sha1-miyr0bno4K6ZOkv31YdcOcQujqw= - lru-cache@4.1.x: version "4.1.5" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.5.tgz#8bbe50ea85bed59bc9e33dcab8235ee9bcf443cd" @@ -4287,41 +4305,43 @@ mixin-deep@^1.2.0: for-in "^1.0.2" is-extendable "^1.0.1" -mkdirp@0.5.1, mkdirp@^0.5.1: +mkdirp@^0.5.1: version "0.5.1" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" integrity sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM= dependencies: minimist "0.0.8" -mocha@^6.2.0: - version "6.2.2" - resolved "https://registry.yarnpkg.com/mocha/-/mocha-6.2.2.tgz#5d8987e28940caf8957a7d7664b910dc5b2fea20" - integrity sha512-FgDS9Re79yU1xz5d+C4rv1G7QagNGHZ+iXF81hO8zY35YZZcLEsJVfFolfsqKFWunATEvNzMK0r/CwWd/szO9A== +mocha@^6.2.2, mocha@^8.2.1: + version "8.2.1" + resolved "https://registry.yarnpkg.com/mocha/-/mocha-8.2.1.tgz#f2fa68817ed0e53343d989df65ccd358bc3a4b39" + integrity sha512-cuLBVfyFfFqbNR0uUKbDGXKGk+UDFe6aR4os78XIrMQpZl/nv7JYHcvP5MFIAb374b2zFXsdgEGwmzMtP0Xg8w== dependencies: - ansi-colors "3.2.3" + "@ungap/promise-all-settled" "1.1.2" + ansi-colors "4.1.1" browser-stdout "1.3.1" - debug "3.2.6" - diff "3.5.0" - escape-string-regexp "1.0.5" - find-up "3.0.0" - glob "7.1.3" + chokidar "3.4.3" + debug "4.2.0" + diff "4.0.2" + escape-string-regexp "4.0.0" + find-up "5.0.0" + glob "7.1.6" growl "1.10.5" he "1.2.0" - js-yaml "3.13.1" - log-symbols "2.2.0" + js-yaml "3.14.0" + log-symbols "4.0.0" minimatch "3.0.4" - mkdirp "0.5.1" - ms "2.1.1" - node-environment-flags "1.0.5" - object.assign "4.1.0" - strip-json-comments "2.0.1" - supports-color "6.0.0" - which "1.3.1" + ms "2.1.2" + nanoid "3.1.12" + serialize-javascript "5.0.1" + strip-json-comments "3.1.1" + supports-color "7.2.0" + which "2.0.2" wide-align "1.1.3" - yargs "13.3.0" - yargs-parser "13.1.1" - yargs-unparser "1.6.0" + workerpool "6.0.2" + yargs "13.3.2" + yargs-parser "13.1.2" + yargs-unparser "2.0.0" move-concurrently@^1.0.1: version "1.0.1" @@ -4340,12 +4360,7 @@ ms@2.0.0: resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= -ms@2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a" - integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg== - -ms@^2.1.1: +ms@2.1.2, ms@^2.1.1: version "2.1.2" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== @@ -4360,6 +4375,11 @@ nan@^2.12.1, nan@^2.14.0: resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.0.tgz#7818f722027b2459a86f0295d434d1fc2336c52c" integrity sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg== +nanoid@3.1.12: + version "3.1.12" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.1.12.tgz#6f7736c62e8d39421601e4a0c77623a97ea69654" + integrity sha512-1qstj9z5+x491jfiC4Nelk+f8XBad7LN20PmyWINJEMRSf3wcAjAWysw1qaA8z6NSKe2sjq1hRSDpBH5paCb6A== + nanomatch@^1.2.9: version "1.2.13" resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119" @@ -4397,21 +4417,6 @@ nice-try@^1.0.4: resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== -no-case@^2.2.0: - version "2.3.2" - resolved "https://registry.yarnpkg.com/no-case/-/no-case-2.3.2.tgz#60b813396be39b3f1288a4c1ed5d1e7d28b464ac" - integrity sha512-rmTZ9kz+f3rCvK2TD1Ue/oZlns7OGoIWP4fc3llxxRXlOkHKoWPPWJOfFYpITabSow43QJbRIoHQXtt10VldyQ== - dependencies: - lower-case "^1.1.1" - -node-environment-flags@1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/node-environment-flags/-/node-environment-flags-1.0.5.tgz#fa930275f5bf5dae188d6192b24b4c8bbac3d76a" - integrity sha512-VNYPRfGfmZLx0Ye20jWzHUjyTW/c+6Wq+iLhDzUI4XmhrDd9l/FozXV3F2xOaXjvp0co0+v1YSR3CMP6g+VvLQ== - dependencies: - object.getownpropertydescriptors "^2.0.3" - semver "^5.7.0" - node-libs-browser@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/node-libs-browser/-/node-libs-browser-2.2.1.tgz#b64f513d18338625f90346d27b0d235e631f6425" @@ -4564,7 +4569,7 @@ object-visit@^1.0.0: dependencies: isobject "^3.0.0" -object.assign@4.1.0, object.assign@^4.1.0: +object.assign@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.0.tgz#968bf1100d7956bb3ca086f006f846b3bc4008da" integrity sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w== @@ -4584,14 +4589,6 @@ object.entries@^1.1.0: function-bind "^1.1.1" has "^1.0.3" -object.getownpropertydescriptors@^2.0.3: - version "2.1.0" - resolved "https://registry.yarnpkg.com/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.0.tgz#369bf1f9592d8ab89d712dced5cb81c7c5352649" - integrity sha512-Z53Oah9A3TdLoblT7VKJaTDdXdT+lQO+cNpKVnya5JDe9uLvzu1YyY1yFDFrcxrlRgWrEFH0jJtD/IbuwjcEVg== - dependencies: - define-properties "^1.1.3" - es-abstract "^1.17.0-next.1" - object.pick@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747" @@ -4703,6 +4700,13 @@ p-limit@^2.0.0, p-limit@^2.2.0: dependencies: p-try "^2.0.0" +p-limit@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.0.2.tgz#1664e010af3cadc681baafd3e2a437be7b0fb5fe" + integrity sha512-iwqZSOoWIW+Ew4kAGUlN16J4M7OB3ysMLSZtnhmqx7njIHFPlxWBX8xo3lVTyFVq6mI/lL9qt2IsN1sHwaxJkg== + dependencies: + p-try "^2.0.0" + p-locate@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43" @@ -4724,6 +4728,13 @@ p-locate@^4.1.0: dependencies: p-limit "^2.2.0" +p-locate@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834" + integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw== + dependencies: + p-limit "^3.0.2" + p-map@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/p-map/-/p-map-3.0.0.tgz#d704d9af8a2ba684e2600d9a215983d4141a979d" @@ -4888,6 +4899,11 @@ picomatch@^2.0.4, picomatch@^2.0.5, picomatch@^2.0.7: resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.2.1.tgz#21bac888b6ed8601f831ce7816e335bc779f0a4a" integrity sha512-ISBaA8xQNmwELC7eOjqFKMESB2VIqt4PPDD0nsS95b/9dZXvVKOlz9keMSnoGGKcOHXfTvDD6WMaRoSc9UuhRA== +picomatch@^2.2.1: + version "2.2.2" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.2.2.tgz#21f333e9b6b8eaff02468f5146ea406d345f4dad" + integrity sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg== + pify@^2.0.0: version "2.3.0" resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" @@ -5062,7 +5078,7 @@ querystring@0.2.0: resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" integrity sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA= -randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5: +randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5, randombytes@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== @@ -5147,6 +5163,13 @@ readdirp@~3.3.0: dependencies: picomatch "^2.0.7" +readdirp@~3.5.0: + version "3.5.0" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.5.0.tgz#9ba74c019b15d365278d2e91bb8c48d7b4d42c9e" + integrity sha512-cMhu7c/8rdhkHXWsY+osBhfSy0JikwpHK/5+imo+LpeasTF8ouErHrlYkwT0++njiyuDvc7OFY5T3ukvZ8qmFQ== + dependencies: + picomatch "^2.2.1" + regenerate-unicode-properties@^8.1.0: version "8.1.0" resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-8.1.0.tgz#ef51e0f0ea4ad424b77bf7cb41f3e015c70a3f0e" @@ -5386,7 +5409,7 @@ schema-utils@^1.0.0: ajv-errors "^1.0.0" ajv-keywords "^3.1.0" -"semver@2 || 3 || 4 || 5", semver@^5.4.1, semver@^5.5.0, semver@^5.6.0, semver@^5.7.0: +"semver@2 || 3 || 4 || 5", semver@^5.4.1, semver@^5.5.0, semver@^5.6.0: version "5.7.1" resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== @@ -5401,6 +5424,13 @@ semver@^6.0.0, semver@^6.1.2, semver@^6.3.0: resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== +serialize-javascript@5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-5.0.1.tgz#7886ec848049a462467a97d3d918ebb2aaf934f4" + integrity sha512-SaaNal9imEO737H2c05Og0/8LUXG7EnsZyMa8MzkmuHoELfT6txuj0cMqRj6zfPKnmQ1yasR4PCJc8x+M4JSPA== + dependencies: + randombytes "^2.1.0" + serialize-javascript@^2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-2.1.2.tgz#ecec53b0e0317bdc95ef76ab7074b7384785fa61" @@ -5496,13 +5526,6 @@ slice-ansi@^2.1.0: astral-regex "^1.0.0" is-fullwidth-code-point "^2.0.0" -snake-case@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/snake-case/-/snake-case-2.1.0.tgz#41bdb1b73f30ec66a04d4e2cad1b76387d4d6d9f" - integrity sha1-Qb2xtz8w7GagTU4srRt2OH1NbZ8= - dependencies: - no-case "^2.2.0" - snapdragon-node@^2.0.1: version "2.1.1" resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b" @@ -5833,23 +5856,16 @@ strip-eof@^1.0.0: resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" integrity sha1-u0P/VZim6wXYm1n80SnJgzE2Br8= -strip-json-comments@2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" - integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo= +strip-json-comments@3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" + integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== strip-json-comments@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.0.1.tgz#85713975a91fb87bf1b305cca77395e40d2a64a7" integrity sha512-VTyMAUfdm047mwKl+u79WIdrZxtFtn+nBxHeb844XBQ9uMNTuTHdx2hc5RiAJYqwTj3wc/xe5HLSdJSkJ+WfZw== -supports-color@6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-6.0.0.tgz#76cfe742cf1f41bb9b1c29ad03068c05b4c0e40a" - integrity sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg== - dependencies: - has-flag "^3.0.0" - supports-color@6.1.0: version "6.1.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-6.1.0.tgz#0764abc69c63d5ac842dd4867e8d025e880df8f3" @@ -5857,6 +5873,13 @@ supports-color@6.1.0: dependencies: has-flag "^3.0.0" +supports-color@7.2.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" + integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== + dependencies: + has-flag "^4.0.0" + supports-color@^5.3.0: version "5.5.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" @@ -6364,20 +6387,20 @@ which-module@^2.0.0: resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" integrity sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho= -which@1.3.1, which@^1.2.1, which@^1.2.14, which@^1.2.9, which@^1.3.1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" - integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== - dependencies: - isexe "^2.0.0" - -which@^2.0.1: +which@2.0.2, which@^2.0.1: version "2.0.2" resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== dependencies: isexe "^2.0.0" +which@^1.2.1, which@^1.2.14, which@^1.2.9, which@^1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" + integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== + dependencies: + isexe "^2.0.0" + wide-align@1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457" @@ -6425,6 +6448,11 @@ worker-farm@^1.7.0: dependencies: errno "~0.1.7" +workerpool@6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-6.0.2.tgz#e241b43d8d033f1beb52c7851069456039d1d438" + integrity sha512-DSNyvOpFKrNusaaUwk+ej6cBj1bmhLcBfj80elGk+ZIo5JSkq+unB1dLKEOcNfJDZgjGICfhQ0Q5TbP0PvF4+Q== + wrap-ansi@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-5.1.0.tgz#1fd1f67235d5b6d0fee781056001bfb694c03b09" @@ -6499,7 +6527,15 @@ yallist@^3.0.2: resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== -yargs-parser@13.1.1, yargs-parser@^13.1.0, yargs-parser@^13.1.1: +yargs-parser@13.1.2, yargs-parser@^13.1.2: + version "13.1.2" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-13.1.2.tgz#130f09702ebaeef2650d54ce6e3e5706f7a4fb38" + integrity sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg== + dependencies: + camelcase "^5.0.0" + decamelize "^1.2.0" + +yargs-parser@^13.1.0: version "13.1.1" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-13.1.1.tgz#d26058532aa06d365fe091f6a1fc06b2f7e5eca0" integrity sha512-oVAVsHz6uFrg3XQheFII8ESO2ssAf9luWuAd6Wexsu4F3OtIW0o8IribPXYrD4WC24LWtPrJlGy87y5udK+dxQ== @@ -6515,14 +6551,15 @@ yargs-parser@^16.1.0: camelcase "^5.0.0" decamelize "^1.2.0" -yargs-unparser@1.6.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/yargs-unparser/-/yargs-unparser-1.6.0.tgz#ef25c2c769ff6bd09e4b0f9d7c605fb27846ea9f" - integrity sha512-W9tKgmSn0DpSatfri0nx52Joq5hVXgeLiqR/5G0sZNDoLZFOr/xjBUDcShCOGNsBnEMNo1KAMBkTej1Hm62HTw== +yargs-unparser@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/yargs-unparser/-/yargs-unparser-2.0.0.tgz#f131f9226911ae5d9ad38c432fe809366c2325eb" + integrity sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA== dependencies: - flat "^4.1.0" - lodash "^4.17.15" - yargs "^13.3.0" + camelcase "^6.0.0" + decamelize "^4.0.0" + flat "^5.0.2" + is-plain-obj "^2.1.0" yargs@13.2.4: version "13.2.4" @@ -6541,10 +6578,10 @@ yargs@13.2.4: y18n "^4.0.0" yargs-parser "^13.1.0" -yargs@13.3.0, yargs@^13.3.0: - version "13.3.0" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-13.3.0.tgz#4c657a55e07e5f2cf947f8a366567c04a0dedc83" - integrity sha512-2eehun/8ALW8TLoIl7MVaRUrg+yCnenu8B4kBlRxj3GJGDKU1Og7sMXPNm1BYyM1DOJmTZ4YeN/Nwxv+8XJsUA== +yargs@13.3.2: + version "13.3.2" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-13.3.2.tgz#ad7ffefec1aa59565ac915f82dccb38a9c31a2dd" + integrity sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw== dependencies: cliui "^5.0.0" find-up "^3.0.0" @@ -6555,7 +6592,7 @@ yargs@13.3.0, yargs@^13.3.0: string-width "^3.0.0" which-module "^2.0.0" y18n "^4.0.0" - yargs-parser "^13.1.1" + yargs-parser "^13.1.2" yargs@^15.0.2: version "15.1.0" From 34f285e779ee51fcd2ca7d6dc48b2c7537af554a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marin=20Petruni=C4=87?= Date: Mon, 23 Nov 2020 12:11:00 +0100 Subject: [PATCH 18/51] force latest v8 profile version --- package.json | 3 ++- yarn.lock | 17 +++++++++++------ 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/package.json b/package.json index bc2afd0..645288a 100644 --- a/package.json +++ b/package.json @@ -80,6 +80,7 @@ "webpack-cli": "^3.3.2" }, "resolutions": { - "mocha": "^8.2.1" + "mocha": "^8.2.1", + "v8-profiler-next": "1.3.0" } } diff --git a/yarn.lock b/yarn.lock index c86e326..4699931 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4370,11 +4370,16 @@ mute-stream@0.0.8: resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d" integrity sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA== -nan@^2.12.1, nan@^2.14.0: +nan@^2.12.1: version "2.14.0" resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.0.tgz#7818f722027b2459a86f0295d434d1fc2336c52c" integrity sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg== +nan@^2.14.1: + version "2.14.2" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.2.tgz#f5376400695168f4cc694ac9393d0c9585eeea19" + integrity sha512-M2ufzIiINKCuDfBSAUr1vWQ+vuVcA9kqx8JJUsbQi6yf1uGRyb7HfpdfUr5qLXf3B/t8dPvcjhKMmlfnP47EzQ== + nanoid@3.1.12: version "3.1.12" resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.1.12.tgz#6f7736c62e8d39421601e4a0c77623a97ea69654" @@ -6275,12 +6280,12 @@ v8-compile-cache@^2.0.3: resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.1.0.tgz#e14de37b31a6d194f5690d67efc4e7f6fc6ab30e" integrity sha512-usZBT3PW+LOjM25wbqIlZwPeJV+3OSz3M1k1Ws8snlW39dZyYL9lOGC5FgPVHfk0jKmjiDV8Z0mIbVQPiwFs7g== -v8-profiler-next@^1.1.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/v8-profiler-next/-/v8-profiler-next-1.2.1.tgz#4dad63273503f180cdec8bf80c458c61d78e49c7" - integrity sha512-5YyzfBycl5HA3dx7AnmRosxr7m77OzhCANGl7AkeciHFw03NThHSerCpPgD1bztRvnQhmYrp7sAnwdQm+WwCfQ== +v8-profiler-next@1.3.0, v8-profiler-next@^1.1.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/v8-profiler-next/-/v8-profiler-next-1.3.0.tgz#7b8b01c353a5e4675eadcd720957f84a2882c84c" + integrity sha512-UrG750R9s43a3vInsLFHBnL8EbkSJ8d/yovYRKLk1myDeW2xdcQgcEKzVzlxLNDgULgDoLALn02VSw8BTH8M3w== dependencies: - nan "^2.14.0" + nan "^2.14.1" validate-npm-package-license@^3.0.1: version "3.0.4" From ea01f269670871961304dfb1b7bfc7e1e0aa24b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marin=20Petruni=C4=87?= Date: Mon, 23 Nov 2020 12:34:19 +0100 Subject: [PATCH 19/51] remove assert dep --- package.json | 8 +++++--- src/helpers/index.ts | 1 + src/helpers/utils.ts | 16 ++++------------ src/index.ts | 2 +- src/privateKey.ts | 2 +- src/publicKey.ts | 2 +- src/signature.ts | 2 +- yarn.lock | 40 ++++++++++++++++++++++------------------ 8 files changed, 36 insertions(+), 37 deletions(-) create mode 100644 src/helpers/index.ts diff --git a/package.json b/package.json index 65ba239..ff3441b 100644 --- a/package.json +++ b/package.json @@ -39,9 +39,8 @@ "benchmark": "node -r ./.babel-register test/benchmarks" }, "dependencies": { - "@chainsafe/bls-keygen": "^0.2.0", - "@chainsafe/eth2-bls-wasm": "^0.5.0", - "assert": "^1.4.1" + "@chainsafe/bls-keygen": "^0.3.0", + "@chainsafe/eth2-bls-wasm": "^0.5.0" }, "devDependencies": { "@babel/cli": "^7.8.4", @@ -78,5 +77,8 @@ "typescript": "^3.7.5", "webpack": "^4.30.0", "webpack-cli": "^3.3.2" + }, + "resolutions": { + "v8-profiler-next": "1.3.0" } } diff --git a/src/helpers/index.ts b/src/helpers/index.ts new file mode 100644 index 0000000..037b90c --- /dev/null +++ b/src/helpers/index.ts @@ -0,0 +1 @@ +export * from "./utils"; \ No newline at end of file diff --git a/src/helpers/utils.ts b/src/helpers/utils.ts index 7430d7d..1f768bc 100644 --- a/src/helpers/utils.ts +++ b/src/helpers/utils.ts @@ -1,17 +1,9 @@ -import assert from "assert"; import {PUBLIC_KEY_LENGTH, SIGNATURE_LENGTH} from "../constants"; -/** - * Pads byte array with zeroes on left side up to desired length. - * Throws if source is larger than desired result. - * @param source - * @param length - */ -export function padLeft(source: Uint8Array, length: number): Buffer { - assert(source.length <= length, "Given array must be smaller or equal to desired array size"); - const result = Buffer.alloc(length, 0); - result.set(source, length - source.length); - return result; +export function assert(condition: unknown, message = "Assertion failed"): asserts condition { + if(!condition) { + throw new Error(message) + } } export const EMPTY_PUBLIC_KEY = Buffer.alloc(PUBLIC_KEY_LENGTH); diff --git a/src/index.ts b/src/index.ts index b398620..6dfc0ac 100644 --- a/src/index.ts +++ b/src/index.ts @@ -3,7 +3,7 @@ import {PrivateKey} from "./privateKey"; import {PublicKey} from "./publicKey"; import {Signature} from "./signature"; import {PUBLIC_KEY_LENGTH} from "./constants"; -import assert from "assert"; +import {assert} from "./helpers"; export {Keypair, PrivateKey, PublicKey, Signature}; diff --git a/src/privateKey.ts b/src/privateKey.ts index deb8029..dfce61e 100644 --- a/src/privateKey.ts +++ b/src/privateKey.ts @@ -1,5 +1,5 @@ import {SECRET_KEY_LENGTH} from "./constants"; -import assert from "assert"; +import {assert} from "./helpers"; import {SecretKeyType} from "@chainsafe/eth2-bls-wasm"; import {generateRandomSecretKey} from "@chainsafe/bls-keygen"; import {getContext} from "./context"; diff --git a/src/publicKey.ts b/src/publicKey.ts index c994489..725ed76 100644 --- a/src/publicKey.ts +++ b/src/publicKey.ts @@ -2,7 +2,7 @@ import {PrivateKey} from "./privateKey"; import {PublicKeyType} from "@chainsafe/eth2-bls-wasm"; import {getContext} from "./context"; import {PUBLIC_KEY_LENGTH} from "./constants"; -import assert from "assert"; +import {assert} from "./helpers"; import {Signature} from "./signature"; import {EMPTY_PUBLIC_KEY} from "./helpers/utils"; diff --git a/src/signature.ts b/src/signature.ts index 08c38e6..897c96b 100644 --- a/src/signature.ts +++ b/src/signature.ts @@ -1,4 +1,4 @@ -import assert from "assert"; +import {assert} from "./helpers"; import {FP_POINT_LENGTH} from "./constants"; import {SignatureType} from "@chainsafe/eth2-bls-wasm"; import {getContext} from "./context"; diff --git a/yarn.lock b/yarn.lock index 296f5d6..3c0a153 100644 --- a/yarn.lock +++ b/yarn.lock @@ -799,26 +799,25 @@ "@assemblyscript/loader" "^0.9.2" buffer "^5.4.3" -"@chainsafe/bls-hd-key@^0.1.0": - version "0.1.0" - resolved "https://registry.yarnpkg.com/@chainsafe/bls-hd-key/-/bls-hd-key-0.1.0.tgz#5e51de16801f4b4b421e418f0d1ef0692df0c585" - integrity sha512-VZj+Ml4YTPz+d/K2n9q/9bLlIJnTr/xdAC5w1eCvIFtcQrZCY1Zw+bCcXKX1q6sbZpO9xhyuoepJzJX9VkMPqw== +"@chainsafe/bls-hd-key@^0.2.0": + version "0.2.0" + resolved "https://registry.yarnpkg.com/@chainsafe/bls-hd-key/-/bls-hd-key-0.2.0.tgz#90aaf030150de64099e1fb27582b27bbe5ce5309" + integrity sha512-ps10jd99UWcm1qPo4spD/6hxFor9fsDgB0s2wJuFKqPdM2R+4LCowhv5kdGgGs3VIN1H8l+CgO08yC7X0WlBDQ== dependencies: assert "^2.0.0" bcrypto "^5.0.4" bn.js "^5.1.1" buffer "^5.4.3" -"@chainsafe/bls-keygen@^0.2.0": - version "0.2.0" - resolved "https://registry.yarnpkg.com/@chainsafe/bls-keygen/-/bls-keygen-0.2.0.tgz#2089da875caff4334723c5ee45495e366dc57a2e" - integrity sha512-IcgOJ1UTiHX3T1FnSqTdf4gtavjpINPtmAwLZFQUxSuLPOfmxPPVN/yhAIYw5xCh9/mWkaFQ/dFUk6ys+BkfGQ== +"@chainsafe/bls-keygen@^0.3.0": + version "0.3.0" + resolved "https://registry.yarnpkg.com/@chainsafe/bls-keygen/-/bls-keygen-0.3.0.tgz#d7472a945f6f49b5cb357241bfba2f5c12a635c5" + integrity sha512-5Iq6E5E987hyio74G1fXPYI3t9iVeHxRX1tDMpnCV9T82rPz061yFsMz3W3aXE26+k6+fcz0bsYX3ijOizkx+A== dependencies: - "@chainsafe/bls-hd-key" "^0.1.0" - assert "^2.0.0" - bcrypto "^5.0.4" + "@chainsafe/bls-hd-key" "^0.2.0" bip39 "^3.0.2" buffer "^5.4.3" + randombytes "^2.1.0" "@chainsafe/eth2-bls-wasm@^0.5.0": version "0.5.0" @@ -1339,7 +1338,7 @@ asn1.js@^4.0.0: inherits "^2.0.1" minimalistic-assert "^1.0.0" -assert@^1.1.1, assert@^1.4.1: +assert@^1.1.1: version "1.5.0" resolved "https://registry.yarnpkg.com/assert/-/assert-1.5.0.tgz#55c109aaf6e0aefdb3dc4b71240c70bf574b18eb" integrity sha512-EDsgawzwoun2CZkCgtxJbv392v4nbk9XDD06zI+kQYoBM/3RBWLlEyJARDOmhAAosBjWACEkKL6S+lIZtcAubA== @@ -4360,6 +4359,11 @@ nan@^2.12.1, nan@^2.14.0: resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.0.tgz#7818f722027b2459a86f0295d434d1fc2336c52c" integrity sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg== +nan@^2.14.1: + version "2.14.2" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.2.tgz#f5376400695168f4cc694ac9393d0c9585eeea19" + integrity sha512-M2ufzIiINKCuDfBSAUr1vWQ+vuVcA9kqx8JJUsbQi6yf1uGRyb7HfpdfUr5qLXf3B/t8dPvcjhKMmlfnP47EzQ== + nanomatch@^1.2.9: version "1.2.13" resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119" @@ -5062,7 +5066,7 @@ querystring@0.2.0: resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" integrity sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA= -randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5: +randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5, randombytes@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== @@ -6252,12 +6256,12 @@ v8-compile-cache@^2.0.3: resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.1.0.tgz#e14de37b31a6d194f5690d67efc4e7f6fc6ab30e" integrity sha512-usZBT3PW+LOjM25wbqIlZwPeJV+3OSz3M1k1Ws8snlW39dZyYL9lOGC5FgPVHfk0jKmjiDV8Z0mIbVQPiwFs7g== -v8-profiler-next@^1.1.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/v8-profiler-next/-/v8-profiler-next-1.2.1.tgz#4dad63273503f180cdec8bf80c458c61d78e49c7" - integrity sha512-5YyzfBycl5HA3dx7AnmRosxr7m77OzhCANGl7AkeciHFw03NThHSerCpPgD1bztRvnQhmYrp7sAnwdQm+WwCfQ== +v8-profiler-next@1.3.0, v8-profiler-next@^1.1.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/v8-profiler-next/-/v8-profiler-next-1.3.0.tgz#7b8b01c353a5e4675eadcd720957f84a2882c84c" + integrity sha512-UrG750R9s43a3vInsLFHBnL8EbkSJ8d/yovYRKLk1myDeW2xdcQgcEKzVzlxLNDgULgDoLALn02VSw8BTH8M3w== dependencies: - nan "^2.14.0" + nan "^2.14.1" validate-npm-package-license@^3.0.1: version "3.0.4" From 51f0cb7c1b512aca198b479abadaa56e9b2537a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marin=20Petruni=C4=87?= Date: Tue, 24 Nov 2020 20:59:33 +0100 Subject: [PATCH 20/51] fix lint --- src/helpers/index.ts | 2 +- src/helpers/utils.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/helpers/index.ts b/src/helpers/index.ts index 037b90c..178cd64 100644 --- a/src/helpers/index.ts +++ b/src/helpers/index.ts @@ -1 +1 @@ -export * from "./utils"; \ No newline at end of file +export * from "./utils"; diff --git a/src/helpers/utils.ts b/src/helpers/utils.ts index 1f768bc..b81b6ae 100644 --- a/src/helpers/utils.ts +++ b/src/helpers/utils.ts @@ -1,8 +1,8 @@ import {PUBLIC_KEY_LENGTH, SIGNATURE_LENGTH} from "../constants"; export function assert(condition: unknown, message = "Assertion failed"): asserts condition { - if(!condition) { - throw new Error(message) + if (!condition) { + throw new Error(message); } } From 52fb0c3fdd9ace2284fb4f1f683e5bb012643fc6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marin=20Petruni=C4=87?= Date: Tue, 24 Nov 2020 21:05:25 +0100 Subject: [PATCH 21/51] update lock file --- yarn.lock | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/yarn.lock b/yarn.lock index 4c70fcb..48d79da 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4379,6 +4379,11 @@ nan@^2.14.1: resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.2.tgz#f5376400695168f4cc694ac9393d0c9585eeea19" integrity sha512-M2ufzIiINKCuDfBSAUr1vWQ+vuVcA9kqx8JJUsbQi6yf1uGRyb7HfpdfUr5qLXf3B/t8dPvcjhKMmlfnP47EzQ== +nanoid@3.1.12: + version "3.1.12" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.1.12.tgz#6f7736c62e8d39421601e4a0c77623a97ea69654" + integrity sha512-1qstj9z5+x491jfiC4Nelk+f8XBad7LN20PmyWINJEMRSf3wcAjAWysw1qaA8z6NSKe2sjq1hRSDpBH5paCb6A== + nanomatch@^1.2.9: version "1.2.13" resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119" From 4da10180d9cfb5969f037d4af6bef61ec2af43ac Mon Sep 17 00:00:00 2001 From: dapplion Date: Wed, 25 Nov 2020 10:41:52 +0000 Subject: [PATCH 22/51] Remove code duplication in the functional interface --- src/blst/index.ts | 109 ++------------------------------------------ src/functional.ts | 109 ++++++++++++++++++++++++++++++++++++++++++++ src/herumi/index.ts | 108 ++----------------------------------------- 3 files changed, 116 insertions(+), 210 deletions(-) create mode 100644 src/functional.ts diff --git a/src/blst/index.ts b/src/blst/index.ts index 83d05a4..f4d8b1b 100644 --- a/src/blst/index.ts +++ b/src/blst/index.ts @@ -1,11 +1,10 @@ -import assert from "assert"; import {Keypair} from "./keypair"; import {PrivateKey} from "./privateKey"; import {PublicKey} from "./publicKey"; import {Signature} from "./signature"; -import {toBuffer} from "../helpers/utils"; import {IBls} from "../interface"; export * from "../constants"; +import {functionalInterfaceFactory} from "../functional"; export {Keypair, PrivateKey, PublicKey, Signature}; @@ -16,113 +15,13 @@ export function destroy(): void { // Native bindings require no destroy() call } -/** - * Signs given message using secret key. - * @param secretKey - * @param messageHash - */ -export function sign(secretKey: Uint8Array, messageHash: Uint8Array): Buffer { - assert(secretKey, "secretKey is null or undefined"); - assert(messageHash, "messageHash is null or undefined"); - const privateKey = PrivateKey.fromBytes(toBuffer(secretKey)); - return privateKey.signMessage(toBuffer(messageHash)).toBytes(); -} - -/** - * Compines all given signature into one. - * @param signatures - */ -export function aggregateSignatures(signatures: Uint8Array[]): Buffer { - const agg = Signature.aggregate(signatures.map((p) => Signature.fromBytes(p))); - return agg.toBytes(); -} - -/** - * Combines all given public keys into single one - * @param publicKeys - */ -export function aggregatePubkeys(publicKeys: Uint8Array[]): Buffer { - const agg = PublicKey.aggregate(publicKeys.map((p) => PublicKey.fromBytes(p))); - return agg.toBytes(); -} - -/** - * Verifies if signature is message signed with given public key. - * @param publicKey - * @param messageHash - * @param signature - */ -export function verify(publicKey: Uint8Array, messageHash: Uint8Array, signature: Uint8Array): boolean { - assert(publicKey, "publicKey is null or undefined"); - assert(messageHash, "messageHash is null or undefined"); - assert(signature, "signature is null or undefined"); - try { - return PublicKey.fromBytes(publicKey).verifyMessage( - Signature.fromBytes(toBuffer(signature)), - toBuffer(messageHash) - ); - } catch (e) { - return false; - } -} - -/** - * Verifies if aggregated signature is same message signed with given public keys. - * @param publicKeys - * @param messageHash - * @param signature - */ -export function verifyAggregate(publicKeys: Uint8Array[], messageHash: Uint8Array, signature: Uint8Array): boolean { - assert(publicKeys, "publicKey is null or undefined"); - assert(messageHash, "messageHash is null or undefined"); - assert(signature, "signature is null or undefined"); - try { - return Signature.fromBytes(signature).verifyAggregate( - publicKeys.map((pubkey) => PublicKey.fromBytes(pubkey)), - messageHash - ); - } catch (e) { - return false; - } -} - -/** - * Verifies if signature is list of message signed with corresponding public key. - * @param publicKeys - * @param messageHashes - * @param signature - * @param fast Check if all messages are different - */ -export function verifyMultiple(publicKeys: Uint8Array[], messageHashes: Uint8Array[], signature: Uint8Array): boolean { - assert(publicKeys, "publicKey is null or undefined"); - assert(messageHashes, "messageHash is null or undefined"); - assert(signature, "signature is null or undefined"); - - if (publicKeys.length === 0 || publicKeys.length != messageHashes.length) { - return false; - } - try { - return Signature.fromBytes(toBuffer(signature)).verifyMultiple( - publicKeys.map((key) => PublicKey.fromBytes(toBuffer(key))), - messageHashes.map((m) => toBuffer(m)) - ); - } catch (e) { - return false; - } -} - -const bls: IBls = { - sign, - aggregateSignatures, - aggregatePubkeys, - verify, - verifyAggregate, - verifyMultiple, - +export const bls: IBls = { // Keypair, PrivateKey, PublicKey, Signature, + + ...functionalInterfaceFactory({PrivateKey, PublicKey, Signature}), initBLS, destroy, }; diff --git a/src/functional.ts b/src/functional.ts new file mode 100644 index 0000000..ef78f8c --- /dev/null +++ b/src/functional.ts @@ -0,0 +1,109 @@ +import assert from "assert"; +import {IBls} from "./interface"; + +export function functionalInterfaceFactory({ + PrivateKey, + PublicKey, + Signature, +}: Pick) { + /** + * Signs given message using secret key. + * @param secretKey + * @param messageHash + */ + function sign(secretKey: Uint8Array, messageHash: Uint8Array): Buffer { + assert(secretKey, "secretKey is null or undefined"); + assert(messageHash, "messageHash is null or undefined"); + const privateKey = PrivateKey.fromBytes(secretKey); + return privateKey.signMessage(messageHash).toBytes(); + } + + /** + * Compines all given signature into one. + * @param signatures + */ + function aggregateSignatures(signatures: Uint8Array[]): Buffer { + const agg = Signature.aggregate(signatures.map((p) => Signature.fromBytes(p))); + return agg.toBytes(); + } + + /** + * Combines all given public keys into single one + * @param publicKeys + */ + function aggregatePubkeys(publicKeys: Uint8Array[]): Buffer { + const agg = PublicKey.aggregate(publicKeys.map((p) => PublicKey.fromBytes(p))); + return agg.toBytes(); + } + + /** + * Verifies if signature is message signed with given public key. + * @param publicKey + * @param messageHash + * @param signature + */ + function verify(publicKey: Uint8Array, messageHash: Uint8Array, signature: Uint8Array): boolean { + assert(publicKey, "publicKey is null or undefined"); + assert(messageHash, "messageHash is null or undefined"); + assert(signature, "signature is null or undefined"); + try { + return Signature.fromBytes(signature).verify(PublicKey.fromBytes(publicKey), messageHash); + } catch (e) { + return false; + } + } + + /** + * Verifies if aggregated signature is same message signed with given public keys. + * @param publicKeys + * @param messageHash + * @param signature + */ + function verifyAggregate(publicKeys: Uint8Array[], messageHash: Uint8Array, signature: Uint8Array): boolean { + assert(publicKeys, "publicKey is null or undefined"); + assert(messageHash, "messageHash is null or undefined"); + assert(signature, "signature is null or undefined"); + try { + return Signature.fromBytes(signature).verifyAggregate( + publicKeys.map((pubkey) => PublicKey.fromBytes(pubkey)), + messageHash + ); + } catch (e) { + return false; + } + } + + /** + * Verifies if signature is list of message signed with corresponding public key. + * @param publicKeys + * @param messageHashes + * @param signature + * @param fast Check if all messages are different + */ + function verifyMultiple(publicKeys: Uint8Array[], messageHashes: Uint8Array[], signature: Uint8Array): boolean { + assert(publicKeys, "publicKey is null or undefined"); + assert(messageHashes, "messageHash is null or undefined"); + assert(signature, "signature is null or undefined"); + + if (publicKeys.length === 0 || publicKeys.length != messageHashes.length) { + return false; + } + try { + return Signature.fromBytes(signature).verifyMultiple( + publicKeys.map((publicKey) => PublicKey.fromBytes(publicKey)), + messageHashes.map((msg) => msg) + ); + } catch (e) { + return false; + } + } + + return { + sign, + aggregateSignatures, + aggregatePubkeys, + verify, + verifyAggregate, + verifyMultiple, + }; +} diff --git a/src/herumi/index.ts b/src/herumi/index.ts index 6c03481..a8afed8 100644 --- a/src/herumi/index.ts +++ b/src/herumi/index.ts @@ -3,120 +3,18 @@ import {PrivateKey} from "./privateKey"; import {PublicKey} from "./publicKey"; import {Signature} from "./signature"; import {initBLS, destroy} from "./context"; -import assert from "assert"; -import {toBuffer} from "../helpers/utils"; import {IBls} from "../interface"; +import {functionalInterfaceFactory} from "../functional"; export {Keypair, PrivateKey, PublicKey, Signature, initBLS, destroy}; -/** - * Signs given message using secret key. - * @param secretKey - * @param messageHash - */ -export function sign(secretKey: Uint8Array, messageHash: Uint8Array): Buffer { - assert(secretKey, "secretKey is null or undefined"); - assert(messageHash, "messageHash is null or undefined"); - const privateKey = PrivateKey.fromBytes(toBuffer(secretKey)); - return privateKey.signMessage(toBuffer(messageHash)).toBytes(); -} - -/** - * Compines all given signature into one. - * @param signatures - */ -export function aggregateSignatures(signatures: Uint8Array[]): Buffer { - assert(signatures, "signatures is null or undefined"); - const agg = Signature.aggregate(signatures.map((signature): Signature => Signature.fromBytes(signature))); - return agg.toBytes(); -} - -/** - * Combines all given public keys into single one - * @param publicKeys - */ -export function aggregatePubkeys(publicKeys: Uint8Array[]): Buffer { - assert(publicKeys, "publicKeys is null or undefined"); - const agg = PublicKey.aggregate(publicKeys.map((pk) => PublicKey.fromBytes(pk))); - return agg.toBytes(); -} - -/** - * Verifies if signature is message signed with given public key. - * @param publicKey - * @param messageHash - * @param signature - */ -export function verify(publicKey: Uint8Array, messageHash: Uint8Array, signature: Uint8Array): boolean { - assert(publicKey, "publicKey is null or undefined"); - assert(messageHash, "messageHash is null or undefined"); - assert(signature, "signature is null or undefined"); - try { - return PublicKey.fromBytes(publicKey).verifyMessage( - Signature.fromBytes(toBuffer(signature)), - toBuffer(messageHash) - ); - } catch (e) { - return false; - } -} - -/** - * Verifies if aggregated signature is same message signed with given public keys. - * @param publicKeys - * @param messageHash - * @param signature - */ -export function verifyAggregate(publicKeys: Uint8Array[], messageHash: Uint8Array, signature: Uint8Array): boolean { - assert(publicKeys, "publicKey is null or undefined"); - assert(messageHash, "messageHash is null or undefined"); - assert(signature, "signature is null or undefined"); - try { - return Signature.fromBytes(signature).verifyAggregate( - publicKeys.map((pubkey) => PublicKey.fromBytes(pubkey)), - messageHash - ); - } catch (e) { - return false; - } -} - -/** - * Verifies if signature is list of message signed with corresponding public key. - * @param publicKeys - * @param messageHashes - * @param signature - */ -export function verifyMultiple(publicKeys: Uint8Array[], messageHashes: Uint8Array[], signature: Uint8Array): boolean { - assert(publicKeys, "publicKey is null or undefined"); - assert(messageHashes, "messageHash is null or undefined"); - assert(signature, "signature is null or undefined"); - - if (publicKeys.length === 0 || publicKeys.length != messageHashes.length) { - return false; - } - try { - return Signature.fromBytes(toBuffer(signature)).verifyMultiple( - publicKeys.map((key) => PublicKey.fromBytes(toBuffer(key))), - messageHashes.map((m) => toBuffer(m)) - ); - } catch (e) { - return false; - } -} - const bls: IBls = { - sign, - aggregateSignatures, - aggregatePubkeys, - verify, - verifyAggregate, - verifyMultiple, - // Keypair, PrivateKey, PublicKey, Signature, + + ...functionalInterfaceFactory({PrivateKey, PublicKey, Signature}), initBLS, destroy, }; From 84c95ba069577e5211c303f2e777b5c49c41ab1a Mon Sep 17 00:00:00 2001 From: dapplion Date: Wed, 25 Nov 2020 10:45:19 +0000 Subject: [PATCH 23/51] Remove Keypair class --- src/blst/index.ts | 4 +--- src/blst/keypair.ts | 30 ------------------------------ src/herumi/index.ts | 4 +--- src/herumi/keypair.ts | 30 ------------------------------ 4 files changed, 2 insertions(+), 66 deletions(-) delete mode 100644 src/blst/keypair.ts delete mode 100644 src/herumi/keypair.ts diff --git a/src/blst/index.ts b/src/blst/index.ts index f4d8b1b..f2093cf 100644 --- a/src/blst/index.ts +++ b/src/blst/index.ts @@ -1,4 +1,3 @@ -import {Keypair} from "./keypair"; import {PrivateKey} from "./privateKey"; import {PublicKey} from "./publicKey"; import {Signature} from "./signature"; @@ -6,7 +5,7 @@ import {IBls} from "../interface"; export * from "../constants"; import {functionalInterfaceFactory} from "../functional"; -export {Keypair, PrivateKey, PublicKey, Signature}; +export {PrivateKey, PublicKey, Signature}; export async function initBLS(): Promise { // Native bindings require no init() call @@ -16,7 +15,6 @@ export function destroy(): void { } export const bls: IBls = { - // Keypair, PrivateKey, PublicKey, Signature, diff --git a/src/blst/keypair.ts b/src/blst/keypair.ts deleted file mode 100644 index db3928e..0000000 --- a/src/blst/keypair.ts +++ /dev/null @@ -1,30 +0,0 @@ -import {PublicKey} from "./publicKey"; -import {PrivateKey} from "./privateKey"; -import {IKeypair} from "../interface"; - -export class Keypair implements IKeypair { - private readonly _publicKey: PublicKey; - - private readonly _privateKey: PrivateKey; - - public constructor(privateKey: PrivateKey, publicKey?: PublicKey) { - this._privateKey = privateKey; - if (!publicKey) { - this._publicKey = privateKey.toPublicKey(); - } else { - this._publicKey = publicKey; - } - } - - public get publicKey(): PublicKey { - return this._publicKey; - } - - public get privateKey(): PrivateKey { - return this._privateKey; - } - - public static generate(): Keypair { - return new Keypair(PrivateKey.fromKeygen()); - } -} diff --git a/src/herumi/index.ts b/src/herumi/index.ts index a8afed8..67b5688 100644 --- a/src/herumi/index.ts +++ b/src/herumi/index.ts @@ -1,4 +1,3 @@ -import {Keypair} from "./keypair"; import {PrivateKey} from "./privateKey"; import {PublicKey} from "./publicKey"; import {Signature} from "./signature"; @@ -6,10 +5,9 @@ import {initBLS, destroy} from "./context"; import {IBls} from "../interface"; import {functionalInterfaceFactory} from "../functional"; -export {Keypair, PrivateKey, PublicKey, Signature, initBLS, destroy}; +export {PrivateKey, PublicKey, Signature, initBLS, destroy}; const bls: IBls = { - // Keypair, PrivateKey, PublicKey, Signature, diff --git a/src/herumi/keypair.ts b/src/herumi/keypair.ts deleted file mode 100644 index db3928e..0000000 --- a/src/herumi/keypair.ts +++ /dev/null @@ -1,30 +0,0 @@ -import {PublicKey} from "./publicKey"; -import {PrivateKey} from "./privateKey"; -import {IKeypair} from "../interface"; - -export class Keypair implements IKeypair { - private readonly _publicKey: PublicKey; - - private readonly _privateKey: PrivateKey; - - public constructor(privateKey: PrivateKey, publicKey?: PublicKey) { - this._privateKey = privateKey; - if (!publicKey) { - this._publicKey = privateKey.toPublicKey(); - } else { - this._publicKey = publicKey; - } - } - - public get publicKey(): PublicKey { - return this._publicKey; - } - - public get privateKey(): PrivateKey { - return this._privateKey; - } - - public static generate(): Keypair { - return new Keypair(PrivateKey.fromKeygen()); - } -} From ec859a1c3261319053425f972e141a3d6afaa652 Mon Sep 17 00:00:00 2001 From: dapplion Date: Wed, 25 Nov 2020 11:39:49 +0000 Subject: [PATCH 24/51] Fix backing dependencies --- package.json | 10 +++++++--- src/herumi/privateKey.ts | 2 +- src/herumi/publicKey.ts | 2 +- src/herumi/signature.ts | 2 +- yarn.lock | 19 ++++++++++++++++++- 5 files changed, 28 insertions(+), 7 deletions(-) diff --git a/package.json b/package.json index 03f6306..4c21044 100644 --- a/package.json +++ b/package.json @@ -30,9 +30,9 @@ "lint:fix": "yarn run lint --fix", "pretest": "yarn check-types", "prepublishOnly": "yarn build", - "test:web:unit": "karma start", - "test:node:unit": "nyc --cache-dir .nyc_output/.cache -r lcov -e .ts mocha --colors -r ts-node/register 'test/unit/**/*.test.ts' && nyc report", - "test:unit": "yarn run test:node:unit && yarn run test:web:unit", + "test:web": "karma start", + "test:unit": "mocha --colors -r ts-node/register 'test/unit/**/*.test.ts'", + "test:coverage": "nyc --cache-dir .nyc_output/.cache -r lcov -e .ts mocha --colors -r ts-node/register 'test/unit/**/*.test.ts' && nyc report", "test:spec": "mocha --colors -r ts-node/register 'test/spec/**/*.test.ts'", "test": "yarn run test:unit && yarn run test:spec", "coverage": "codecov -F bls", @@ -51,6 +51,7 @@ "@babel/preset-env": "^7.8.4", "@babel/preset-typescript": "^7.8.3", "@babel/register": "^7.8.3", + "@chainsafe/blst": "^0.1.2", "@chainsafe/eth2-spec-tests": "0.12.0", "@chainsafe/lodestar-spec-test-util": "^0.11.0", "@types/chai": "^4.2.9", @@ -80,5 +81,8 @@ "resolutions": { "mocha": "^8.2.1", "v8-profiler-next": "1.3.0" + }, + "peerDependencies": { + "@chainsafe/blst": "^0.1.2" } } diff --git a/src/herumi/privateKey.ts b/src/herumi/privateKey.ts index facdd59..4e1a91e 100644 --- a/src/herumi/privateKey.ts +++ b/src/herumi/privateKey.ts @@ -1,5 +1,5 @@ import assert from "assert"; -import {SecretKeyType} from "@chainsafe/eth2-bls-wasm"; +import {SecretKeyType} from "bls-eth-wasm"; import {generateRandomSecretKey} from "@chainsafe/bls-keygen"; import {SECRET_KEY_LENGTH} from "../constants"; import {getContext} from "./context"; diff --git a/src/herumi/publicKey.ts b/src/herumi/publicKey.ts index 4cd01cc..d889eeb 100644 --- a/src/herumi/publicKey.ts +++ b/src/herumi/publicKey.ts @@ -1,4 +1,4 @@ -import {PublicKeyType} from "@chainsafe/eth2-bls-wasm"; +import {PublicKeyType} from "bls-eth-wasm"; import {getContext} from "./context"; import {EMPTY_PUBLIC_KEY} from "../constants"; import {Signature} from "./signature"; diff --git a/src/herumi/signature.ts b/src/herumi/signature.ts index 3bf8a22..9198d43 100644 --- a/src/herumi/signature.ts +++ b/src/herumi/signature.ts @@ -1,6 +1,6 @@ import assert from "assert"; import {SIGNATURE_LENGTH, EMPTY_SIGNATURE} from "../constants"; -import {SignatureType} from "@chainsafe/eth2-bls-wasm"; +import {SignatureType} from "bls-eth-wasm"; import {getContext} from "./context"; import {PublicKey} from "./publicKey"; import {bytesToHex, hexToBytes, isEqualBytes} from "../helpers/utils"; diff --git a/yarn.lock b/yarn.lock index 9878fd4..fb7d8a9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,6 +2,11 @@ # yarn lockfile v1 +"@assemblyscript/loader@^0.9.2": + version "0.9.4" + resolved "https://registry.yarnpkg.com/@assemblyscript/loader/-/loader-0.9.4.tgz#a483c54c1253656bb33babd464e3154a173e1577" + integrity sha512-HazVq9zwTVwGmqdwYzu7WyQ6FQVZ7SwET0KKQuKm55jD0IfUpZgN0OPIiZG3zV1iSrVYcN0bdwLRXI/VNCYsUA== + "@babel/cli@^7.8.4": version "7.8.4" resolved "https://registry.yarnpkg.com/@babel/cli/-/cli-7.8.4.tgz#505fb053721a98777b2b175323ea4f090b7d3c1c" @@ -786,7 +791,7 @@ lodash "^4.17.13" to-fast-properties "^2.0.0" -"@chainsafe/as-sha256@0.2.0", "@chainsafe/as-sha256@^0.2.0": +"@chainsafe/as-sha256@^0.2.0": version "0.2.0" resolved "https://registry.yarnpkg.com/@chainsafe/as-sha256/-/as-sha256-0.2.0.tgz#3ebe061d59d30af9e95a8c22ff4813cbf0e89dbc" integrity sha512-reKklZhY4jSj7JdxdAjUfsaiMt2pdm8V/IqlOR5c4m6Y4tRCxt4f0HBMfyiE2ZQF4tqPPqRVf/ulXwK+LjLIxw== @@ -814,6 +819,13 @@ buffer "^5.4.3" randombytes "^2.1.0" +"@chainsafe/blst@^0.1.2": + version "0.1.2" + resolved "https://registry.yarnpkg.com/@chainsafe/blst/-/blst-0.1.2.tgz#5d2ee91609c0f799be4b4de2ea8ed67209bf4201" + integrity sha512-doQ4sFGthNR9WzLlFUvtOx1ReqIMNNjS0JC3NNg7NSkRMvzpIinFcHlcABmCJODofreU11GYext77WFCzoSKNA== + dependencies: + node-fetch "^2.6.1" + "@chainsafe/eth2-spec-tests@0.12.0": version "0.12.0" resolved "https://registry.yarnpkg.com/@chainsafe/eth2-spec-tests/-/eth2-spec-tests-0.12.0.tgz#f95ffe5bc20ddaa4d2240cffe1e417877adc8055" @@ -4416,6 +4428,11 @@ nice-try@^1.0.4: resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== +node-fetch@^2.6.1: + version "2.6.1" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052" + integrity sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw== + node-libs-browser@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/node-libs-browser/-/node-libs-browser-2.2.1.tgz#b64f513d18338625f90346d27b0d235e631f6425" From 507ed949955da18d52b8cce8f5de0fe8a7d6954d Mon Sep 17 00:00:00 2001 From: dapplion Date: Wed, 25 Nov 2020 11:41:28 +0000 Subject: [PATCH 25/51] Split CI test steps --- .github/workflows/test.yml | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 63b9e5b..2bfdb7b 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -18,7 +18,15 @@ jobs: run: yarn check-types - name: Lint run: yarn lint - - name: Tests - run: yarn test + - name: Test build + run: yarn build + + - name: Unit tests + run: yarn test:unit + - name: Spec tests + run: yarn test:spec + - name: Web tests + run: yarn test:web + - name: Benchmark run: yarn benchmark From 6b1fdb0971f64fffc7216c062918d3c284d7d51f Mon Sep 17 00:00:00 2001 From: dapplion Date: Wed, 25 Nov 2020 11:50:47 +0000 Subject: [PATCH 26/51] Fix lint issues --- .eslintrc.js | 2 +- .prettierignore | 1 + src/functional.ts | 2 ++ 3 files changed, 4 insertions(+), 1 deletion(-) create mode 100644 .prettierignore diff --git a/.eslintrc.js b/.eslintrc.js index a9f9b74..924ad0a 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -55,7 +55,7 @@ module.exports = { "import/no-extraneous-dependencies": ["error", { "devDependencies": false, "optionalDependencies": false, - "peerDependencies": false + "peerDependencies": true }], "func-call-spacing": "off", "max-len": ["error", { diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000..82a9a73 --- /dev/null +++ b/.prettierignore @@ -0,0 +1 @@ +.eslintrc.js \ No newline at end of file diff --git a/src/functional.ts b/src/functional.ts index ef78f8c..f25e670 100644 --- a/src/functional.ts +++ b/src/functional.ts @@ -1,6 +1,8 @@ import assert from "assert"; import {IBls} from "./interface"; +// Returned type is enforced at each implementation's index +// eslint-disable-next-line @typescript-eslint/explicit-function-return-type export function functionalInterfaceFactory({ PrivateKey, PublicKey, From cd5b7cba4701690a3602ddb74c1aeb43a9ec5d72 Mon Sep 17 00:00:00 2001 From: dapplion Date: Wed, 25 Nov 2020 14:00:18 +0000 Subject: [PATCH 27/51] Update bls-eth-wasm types --- src/herumi/bls-eth-wasm.d.ts | 97 +++++++++++++++++++++++++++++ src/herumi/context.ts | 2 +- types/bls-eth-wasm/index.d.ts | 111 ---------------------------------- 3 files changed, 98 insertions(+), 112 deletions(-) create mode 100644 src/herumi/bls-eth-wasm.d.ts delete mode 100644 types/bls-eth-wasm/index.d.ts diff --git a/src/herumi/bls-eth-wasm.d.ts b/src/herumi/bls-eth-wasm.d.ts new file mode 100644 index 0000000..4b92724 --- /dev/null +++ b/src/herumi/bls-eth-wasm.d.ts @@ -0,0 +1,97 @@ +declare module "bls-eth-wasm" { + export class Common { + constructor(size: number); + + deserializeHexStr(s: string): void; + serializeToHexStr(): string; + dump(msg?: string): string; + clear(): void; + clone(): this; + isEqual(rhs: this): boolean; + deserialize(v: Uint8Array): void; + serialize(): Uint8Array; + add(rhs: this): void; + } + + export class SecretKeyType extends Common { + constructor(); + + setInt(x: number): void; + isZero(): boolean; + setHashOf(a: Uint8Array): void; + setLittleEndian(a: Uint8Array): void; + setLittleEndianMod(a: Uint8Array): void; + setByCSPRNG(): void; + getPublicKey(): PublicKeyType; + sign(m: string | Uint8Array): SignatureType; + } + + export class PublicKeyType extends Common { + constructor(); + + isZero(): boolean; + deserializeUncompressed(s: Uint8Array): void; + serializeUncompressed(): Uint8Array; + isValidOrder(): boolean; + verify(signature: SignatureType, m: Uint8Array | string): boolean; + } + + export class SignatureType extends Common { + constructor(); + + deserializeUncompressed(s: Uint8Array): void; + serializeUncompressed(): Uint8Array; + isValidOrder(): boolean; + aggregate(others: SignatureType[]): boolean; + fastAggregateVerify(publicKeys: PublicKeyType[], message: Uint8Array): boolean; + aggregateVerifyNoCheck(publicKeys: PublicKeyType[], messages: Uint8Array): boolean; + } + + export function init(curveType: CurveType): Promise; + export function blsInit(curveType: CurveType): void; + export function setETHmode(mode: EthMode): void; + + export function toHex(a: Uint8Array, start: number, length: number): string; + export function toHexStr(a: Uint8Array): string; + export function fromHexStr(s: string): Uint8Array; + export function deserializeHexStrToSecretKey(s: string): SecretKeyType; + export function deserializeHexStrToPublicKey(s: string): PublicKeyType; + export function deserializeHexStrToSignature(s: string): SignatureType; + + export function getCurveOrder(): string; + export function getFieldOrder(): string; + export function verifySignatureOrder(doVerify: boolean): void; + export function verifyPublicKeyOrder(doVerify: boolean): void; + + /** + * + * @param msgs single array with concatenated messages + * @param msgSize defaults to MSG_SIZE + */ + export function areAllMsgDifferent(msgs: Uint8Array, msgSize?: number): boolean; + + /** + * return true if all pub[i].verify(sigs[i], msgs[i]) + * @param msgs msgs is a concatenation of arrays of 32-byte Uint8Array + */ + export function multiVerify(pubs: PublicKeyType[], sigs: SignatureType[], msgs: Uint8Array[]): boolean; + + export const SecretKey: typeof SecretKeyType; + export const PublicKey: typeof PublicKeyType; + export const Signature: typeof SignatureType; + + export enum EthMode { + DRAFT_07 = 3, + } + + export enum CurveType { + BN254 = 0, + BLS12_381 = 5, + } + + export const BN254 = CurveType.BN254; + export const BLS12_381 = CurveType.BLS12_381; + export const ethMode = true; + export const ETH_MODE_DRAFT_07 = EthMode.DRAFT_07; + export const MSG_SIZE = 32; +} diff --git a/src/herumi/context.ts b/src/herumi/context.ts index d8b599e..0ac15fb 100644 --- a/src/herumi/context.ts +++ b/src/herumi/context.ts @@ -7,7 +7,7 @@ let blsGlobalPromise: Promise | null = null; export async function setupBls(): Promise { if (!blsGlobal) { - await bls.init(); + await bls.init(bls.BLS12_381); blsGlobal = bls; } } diff --git a/types/bls-eth-wasm/index.d.ts b/types/bls-eth-wasm/index.d.ts deleted file mode 100644 index a41515e..0000000 --- a/types/bls-eth-wasm/index.d.ts +++ /dev/null @@ -1,111 +0,0 @@ -declare module "bls-eth-wasm" { - export class Common { - - constructor(size: number); - - deserializeHexStr(s: string): void; - - serializeToHexStr(): string; - - dump(msg?: string): string; - - clear(): void; - - clone(): this; - - isEqual(rhs: this): boolean - - deserialize(v: Uint8Array): void; - - serialize(): Uint8Array; - - add(rhs: this): void; - } - - export class SecretKeyType extends Common { - - constructor(); - - setInt(x: number): void; - - setHashOf(a: Uint8Array): void; - - setLittleEndian(a: Uint8Array): void; - - setByCSPRNG(): void; - - getPublicKey(): PublicKeyType; - - sign(m: string | Uint8Array): SignatureType; - - /** - * - * @param m must have 40 bytes - */ - signHashWithDomain(m: Uint8Array): SignatureType; - } - - export class PublicKeyType extends Common { - - constructor(); - - verify(signature: SignatureType, m: Uint8Array | string): boolean; - isValidOrder(): boolean; - deserializeUncompressed (s: Uint8Array): void; - serializeUncompressed (): Uint8Array; - deserializeUncompressedHexStr (s:string): void; - serializeUncompressedToHexStr(): string; - /** - * - * @param signature - * @param m must have 40 bytes - */ - verifyHashWithDomain(signature: SignatureType, m: Uint8Array): boolean; - } - - export class SignatureType extends Common { - constructor(); - - deserializeUncompressed (s: Uint8Array): void; - serializeUncompressed (): Uint8Array; - deserializeUncompressedHexStr (s:string): void; - serializeUncompressedToHexStr(): string; - isValidOrder(): boolean; - aggregate(others: SignatureType[]): boolean; - aggregateVerifyNoCheck(publicKeys: PublicKeyType[], messages: Uint8Array): boolean; - fastAggregateVerify(publicKeys: PublicKeyType[], message: Uint8Array): boolean; - /** - * - * @param publicKeys - * @param messages each message must have 40bytes - */ - verifyAggregatedHashWithDomain(publicKeys: PublicKeyType[], messages: Uint8Array[]): boolean - - } - - export function init(): Promise; - - export function toHex(a: Uint8Array, start: number, length: number): string; - export function toHexStr(a: Uint8Array): string; - export function fromHexStr(s: string): Uint8Array; - export function getCurveOrder(): string; - export function getFieldOrder(): string; - export function verifySignatureOrder(doVerify: boolean): void; - export function verifyPublicKeyOrder(doVerify: boolean): void; - - /** - * - * @param msgs single array with concatenated messages - * @param msgSize defaults to MSG_SIZE - */ - export function areAllMsgDifferent(msgs: Uint8Array, msgSize?: number): boolean; - export function shouldVerifyBlsSignatureOrder(b: string): void; - export function shouldVerifyBlsPublicKeyOrder(b: string): void; - export function deserializeHexStrToSecretKey(s: string): SecretKeyType; - export function deserializeHexStrToPublicKey(s: string): PublicKeyType; - export function deserializeHexStrToSignature(s: string): SignatureType; - - export const SecretKey: typeof SecretKeyType; - export const PublicKey: typeof PublicKeyType; - export const Signature: typeof SignatureType; -} \ No newline at end of file From 530e86d98fa24616314393f27ce85de62afbd987 Mon Sep 17 00:00:00 2001 From: dapplion Date: Wed, 25 Nov 2020 15:03:11 +0000 Subject: [PATCH 28/51] Export strategies --- README.md | 58 ++++++++++++++++++++++++++++++++++++++++++------ blst-native.d.ts | 1 + blst-native.js | 1 + browser.d.ts | 1 + browser.js | 1 + herumi.d.ts | 1 + herumi.js | 1 + node.d.ts | 1 + node.js | 1 + package.json | 2 ++ src/index.ts | 37 +++++++++++++++++++++++++++--- 11 files changed, 95 insertions(+), 10 deletions(-) create mode 100644 blst-native.d.ts create mode 100644 blst-native.js create mode 100644 browser.d.ts create mode 100644 browser.js create mode 100644 herumi.d.ts create mode 100644 herumi.js create mode 100644 node.d.ts create mode 100644 node.js diff --git a/README.md b/README.md index b075bd5..9dbd68d 100644 --- a/README.md +++ b/README.md @@ -6,22 +6,66 @@ ![ES Version](https://img.shields.io/badge/ES-2017-yellow) ![Node Version](https://img.shields.io/badge/node-12.x-green) -This is a Javascript library that implements BLS (Boneh-Lynn-Shacham) signatures and supports signature aggregation. +Javascript library for BLS (Boneh-Lynn-Shacham) signatures and signature aggregation. + +## Usage + +```ts +import {PrivateKey} from "@chainsafe/bls"; + +const secretKey = PrivateKey.fromKeygen(); +const publicKey = secretKey.toPublicKey(); +const message = new Uint8Array(32); + +const signature = secretKey.sign(message); +console.log("Is valid: ", signature.verify(publicKey, message)); +``` + +### Browser + +If you are in the browser, import from `/browser` + +```ts +import bls from "@chainsafe/bls/browser"; +``` + +### Native bindings only + +If you are in NodeJS, import from `/node` to skip browser specific code + +```ts +import bls from "@chainsafe/bls/node"; +``` + +### Native bindings + WASM fallback + +If you want to offer a fallback in NodeJS, first try to load native bindings and then fallback to WASM + +```ts +import bls from "@chainsafe/bls"; + +try { + await bls.init("blst-native"); +} catch (e) { + await bls.init("herumi"); + console.warn("Using WASM"); +} +``` + +The API is identical for all implementations. + +## Spec versioning | Version | Bls spec version | | ------- | :--------------: | -| 0.3.x | initial version | -| 1.x.x | draft #6 | | 2.x.x | draft #7 | +| 1.x.x | draft #6 | +| 0.3.x | initial version | > [spec](https://github.com/ethereum/eth2.0-specs/blob/v0.11.1/specs/phase0/beacon-chain.md#bls-signatures) > [test vectors](https://github.com/ethereum/eth2.0-spec-tests/tree/master/tests/bls) -## Usage - -- `yarn add @chainsafe/bls` - ## License Apache-2.0 diff --git a/blst-native.d.ts b/blst-native.d.ts new file mode 100644 index 0000000..d04a0da --- /dev/null +++ b/blst-native.d.ts @@ -0,0 +1 @@ +export * from "./lib/blst"; diff --git a/blst-native.js b/blst-native.js new file mode 100644 index 0000000..9536e1f --- /dev/null +++ b/blst-native.js @@ -0,0 +1 @@ +module.exports = require("./lib/blst"); diff --git a/browser.d.ts b/browser.d.ts new file mode 100644 index 0000000..29b91b7 --- /dev/null +++ b/browser.d.ts @@ -0,0 +1 @@ +export * from "./lib/herumi"; diff --git a/browser.js b/browser.js new file mode 100644 index 0000000..29b91b7 --- /dev/null +++ b/browser.js @@ -0,0 +1 @@ +export * from "./lib/herumi"; diff --git a/herumi.d.ts b/herumi.d.ts new file mode 100644 index 0000000..29b91b7 --- /dev/null +++ b/herumi.d.ts @@ -0,0 +1 @@ +export * from "./lib/herumi"; diff --git a/herumi.js b/herumi.js new file mode 100644 index 0000000..e39c7a4 --- /dev/null +++ b/herumi.js @@ -0,0 +1 @@ +module.exports = require("./lib/herumi"); diff --git a/node.d.ts b/node.d.ts new file mode 100644 index 0000000..d04a0da --- /dev/null +++ b/node.d.ts @@ -0,0 +1 @@ +export * from "./lib/blst"; diff --git a/node.js b/node.js new file mode 100644 index 0000000..9536e1f --- /dev/null +++ b/node.js @@ -0,0 +1 @@ +module.exports = require("./lib/blst"); diff --git a/package.json b/package.json index 4c21044..8491d2f 100644 --- a/package.json +++ b/package.json @@ -4,6 +4,8 @@ "description": "Implementation of bls signature verification for ethereum 2.0", "main": "lib/index.js", "types": "lib/index.d.ts", + "module": "./browser", + "browser": "./browser", "homepage": "https://github.com/chainsafe/bls", "author": "ChainSafe Systems", "license": "Apache-2.0", diff --git a/src/index.ts b/src/index.ts index f03d4ab..9a5d642 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,3 +1,34 @@ -import blst from "./blst"; -export default blst; -export * from "./blst"; +import {IBls} from "./interface"; +import blsHerumi from "./herumi"; + +export type Implementation = "herumi" | "blst-native"; + +// This proxy makes sure a nice error is printed if BLS is used before init() +export let bls: IBls = new Proxy({} as IBls, { + get: function () { + throw Error("BLS not initialized, call init() before"); + }, +}); + +async function getImplementation(impl: Implementation) { + switch (impl) { + case "herumi": + await blsHerumi.initBLS(); + return blsHerumi; + + case "blst-native": + if (typeof require !== "function") { + throw Error("blst-native is only supported in NodeJS"); + } + return require("./blst"); + + default: + throw new Error(`Unsupported implementation - ${impl}`); + } +} + +export async function init(impl: Implementation) { + bls = await getImplementation(impl); +} + +export default bls; From 847ec46ac9aac80722f603ce3ae8ece98bd9a633 Mon Sep 17 00:00:00 2001 From: dapplion Date: Wed, 25 Nov 2020 15:06:05 +0000 Subject: [PATCH 29/51] Remove crypto from common helpers --- src/blst/privateKey.ts | 5 +++-- src/functional.ts | 2 +- src/helpers/utils.ts | 6 ------ 3 files changed, 4 insertions(+), 9 deletions(-) diff --git a/src/blst/privateKey.ts b/src/blst/privateKey.ts index a421147..c9d7a29 100644 --- a/src/blst/privateKey.ts +++ b/src/blst/privateKey.ts @@ -1,5 +1,6 @@ +import crypto from "crypto"; import * as blst from "@chainsafe/blst"; -import {bytesToHex, getRandomBytes, hexToBytes} from "../helpers/utils"; +import {bytesToHex, hexToBytes} from "../helpers/utils"; import {IPrivateKey} from "../interface"; import {PublicKey} from "./publicKey"; import {Signature} from "./signature"; @@ -21,7 +22,7 @@ export class PrivateKey implements IPrivateKey { } static fromKeygen(entropy?: Uint8Array): PrivateKey { - const sk = blst.SecretKey.fromKeygen(entropy || getRandomBytes(32)); + const sk = blst.SecretKey.fromKeygen(entropy || crypto.randomBytes(32)); return new PrivateKey(sk); } diff --git a/src/functional.ts b/src/functional.ts index f25e670..ddc84bc 100644 --- a/src/functional.ts +++ b/src/functional.ts @@ -1,4 +1,4 @@ -import assert from "assert"; +import {assert} from "./helpers"; import {IBls} from "./interface"; // Returned type is enforced at each implementation's index diff --git a/src/helpers/utils.ts b/src/helpers/utils.ts index fecda8c..2451c50 100644 --- a/src/helpers/utils.ts +++ b/src/helpers/utils.ts @@ -1,5 +1,3 @@ -import crypto from "crypto"; - export function assert(condition: unknown, message = "Assertion failed"): asserts condition { if (!condition) { throw new Error(message); @@ -14,10 +12,6 @@ export function bytesToHex(bytes: Uint8Array): string { return "0x" + Buffer.from(bytes).toString("hex"); } -export function getRandomBytes(size: number): Uint8Array { - return Uint8Array.from(crypto.randomBytes(size)); -} - export function isEqualBytes(a: Buffer | Uint8Array, b: Buffer | Uint8Array): boolean { return Buffer.from(a).equals(Buffer.from(b)); } From 4cb49674d56d10951608a2abbcaabe55865535b7 Mon Sep 17 00:00:00 2001 From: dapplion Date: Wed, 25 Nov 2020 15:11:02 +0000 Subject: [PATCH 30/51] Fix test util import --- test/util.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/util.ts b/test/util.ts index 2a97bf4..e25f4b5 100644 --- a/test/util.ts +++ b/test/util.ts @@ -1,4 +1,4 @@ -import {getRandomBytes} from "../src/helpers/utils"; +import crypto from "crypto"; export function fromHexString(hex: string): Buffer { return Buffer.from(hex.replace("0x", ""), "hex"); @@ -9,7 +9,7 @@ export function toHexString(bytes: Buffer | Uint8Array): string { } export function randomMessage(): Uint8Array { - return getRandomBytes(32); + return crypto.randomBytes(32); } export function getN(n: number, getter: () => T): T[] { From b424842cd55f09a7104364e445ea28a945d3f6a2 Mon Sep 17 00:00:00 2001 From: dapplion Date: Wed, 25 Nov 2020 15:16:19 +0000 Subject: [PATCH 31/51] Reduce karma.conf.js diff --- karma.conf.js | 41 +++++++++++++++++++++-------------------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/karma.conf.js b/karma.conf.js index 9e9100b..4599b2a 100644 --- a/karma.conf.js +++ b/karma.conf.js @@ -1,25 +1,26 @@ // eslint-disable-next-line @typescript-eslint/no-require-imports const webpackConfig = require("./webpack.config"); -module.exports = function (config) { - config.set({ - basePath: "", - frameworks: ["mocha", "chai"], - files: ["test/unit/*.ts"], - exclude: [], - preprocessors: { - "test/unit/run-web-implementation.test.ts": ["webpack"], - }, - webpack: { - mode: "production", - node: webpackConfig.node, - module: webpackConfig.module, - resolve: webpackConfig.resolve, - }, - reporters: ["spec"], +module.exports = function(config) { + config.set({ - browsers: ["ChromeHeadless"], + basePath: "", + frameworks: ["mocha", "chai"], + files: ["test/unit/run-web-implementation.test.ts"], + exclude: [], + preprocessors: { + "test/**/*.ts": ["webpack"] + }, + webpack: { + mode: "production", + node: webpackConfig.node, + module: webpackConfig.module, + resolve: webpackConfig.resolve + }, + reporters: ["spec"], - singleRun: true, - }); -}; + browsers: ["ChromeHeadless"], + + singleRun: true + }); +}; \ No newline at end of file From 021e741d17fc754813867154286f63bb7a6b9b1f Mon Sep 17 00:00:00 2001 From: dapplion Date: Wed, 25 Nov 2020 15:35:53 +0000 Subject: [PATCH 32/51] Move bls-eth-wasm to the root dir --- src/herumi/bls-eth-wasm.d.ts => types/bls-eth-wasm/index.d.ts | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/herumi/bls-eth-wasm.d.ts => types/bls-eth-wasm/index.d.ts (100%) diff --git a/src/herumi/bls-eth-wasm.d.ts b/types/bls-eth-wasm/index.d.ts similarity index 100% rename from src/herumi/bls-eth-wasm.d.ts rename to types/bls-eth-wasm/index.d.ts From 49d509aca4805ddabe0319de8ab88099af5ffdfe Mon Sep 17 00:00:00 2001 From: dapplion Date: Wed, 25 Nov 2020 16:09:44 +0000 Subject: [PATCH 33/51] Clean interface --- README.md | 16 ++++++++++------ src/blst/index.ts | 4 ++-- src/blst/privateKey.ts | 6 +++--- src/blst/publicKey.ts | 4 ++-- src/blst/signature.ts | 4 ++-- src/constants.ts | 4 ++-- src/functional.ts | 8 ++++---- src/herumi/context.ts | 2 +- src/herumi/index.ts | 6 +++--- src/herumi/privateKey.ts | 8 ++++---- src/herumi/publicKey.ts | 4 ++-- src/herumi/signature.ts | 4 ++-- src/index.ts | 10 +++------- src/interface.ts | 16 ++++++++-------- test/benchmark/index.ts | 8 ++++---- test/switch.ts | 2 +- test/unit/index.test.ts | 11 +++-------- test/unit/run-web-implementation.test.ts | 2 +- test/util.ts | 4 ++-- 19 files changed, 59 insertions(+), 64 deletions(-) diff --git a/README.md b/README.md index 9dbd68d..e01a155 100644 --- a/README.md +++ b/README.md @@ -11,14 +11,18 @@ Javascript library for BLS (Boneh-Lynn-Shacham) signatures and signature aggrega ## Usage ```ts -import {PrivateKey} from "@chainsafe/bls"; +import bls, {init} from "@chainsafe/bls"; -const secretKey = PrivateKey.fromKeygen(); -const publicKey = secretKey.toPublicKey(); -const message = new Uint8Array(32); +(async () => { + await init("herumi"); -const signature = secretKey.sign(message); -console.log("Is valid: ", signature.verify(publicKey, message)); + const secretKey = bls.PrivateKey.fromKeygen(); + const publicKey = secretKey.toPublicKey(); + const message = new Uint8Array(32); + + const signature = secretKey.sign(message); + console.log("Is valid: ", signature.verify(publicKey, message)); +})(); ``` ### Browser diff --git a/src/blst/index.ts b/src/blst/index.ts index f2093cf..75af81d 100644 --- a/src/blst/index.ts +++ b/src/blst/index.ts @@ -7,7 +7,7 @@ import {functionalInterfaceFactory} from "../functional"; export {PrivateKey, PublicKey, Signature}; -export async function initBLS(): Promise { +export async function init(): Promise { // Native bindings require no init() call } export function destroy(): void { @@ -20,7 +20,7 @@ export const bls: IBls = { Signature, ...functionalInterfaceFactory({PrivateKey, PublicKey, Signature}), - initBLS, + init, destroy, }; diff --git a/src/blst/privateKey.ts b/src/blst/privateKey.ts index c9d7a29..aeafde8 100644 --- a/src/blst/privateKey.ts +++ b/src/blst/privateKey.ts @@ -26,7 +26,7 @@ export class PrivateKey implements IPrivateKey { return new PrivateKey(sk); } - signMessage(message: Uint8Array): Signature { + sign(message: Uint8Array): Signature { return new Signature(this.value.sign(message)); } @@ -36,8 +36,8 @@ export class PrivateKey implements IPrivateKey { return new PublicKey(affine, jacobian); } - toBytes(): Buffer { - return Buffer.from(this.value.toBytes()); + toBytes(): Uint8Array { + return this.value.toBytes(); } toHex(): string { diff --git a/src/blst/publicKey.ts b/src/blst/publicKey.ts index ee28c5c..6301cf2 100644 --- a/src/blst/publicKey.ts +++ b/src/blst/publicKey.ts @@ -32,8 +32,8 @@ export class PublicKey implements IPublicKey { return signature.verify(this, message); } - toBytes(): Buffer { - return Buffer.from(this.affine.toBytes()); + toBytes(): Uint8Array { + return this.affine.toBytes(); } toHex(): string { diff --git a/src/blst/signature.ts b/src/blst/signature.ts index 5bad9d1..8316c96 100644 --- a/src/blst/signature.ts +++ b/src/blst/signature.ts @@ -39,8 +39,8 @@ export class Signature implements ISignature { ); } - toBytes(): Buffer { - return Buffer.from(this.affine.toBytes()); + toBytes(): Uint8Array { + return this.affine.toBytes(); } toHex(): string { diff --git a/src/constants.ts b/src/constants.ts index cf34046..1169bdd 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -3,5 +3,5 @@ export const SIGNATURE_LENGTH = 96; export const FP_POINT_LENGTH = 48; export const PUBLIC_KEY_LENGTH = FP_POINT_LENGTH; export const G2_HASH_PADDING = 16; -export const EMPTY_PUBLIC_KEY = Buffer.alloc(PUBLIC_KEY_LENGTH); -export const EMPTY_SIGNATURE = Buffer.alloc(SIGNATURE_LENGTH); +export const EMPTY_PUBLIC_KEY = Uint8Array.from(Buffer.alloc(PUBLIC_KEY_LENGTH)); +export const EMPTY_SIGNATURE = Uint8Array.from(Buffer.alloc(SIGNATURE_LENGTH)); diff --git a/src/functional.ts b/src/functional.ts index ddc84bc..7c7be12 100644 --- a/src/functional.ts +++ b/src/functional.ts @@ -13,18 +13,18 @@ export function functionalInterfaceFactory({ * @param secretKey * @param messageHash */ - function sign(secretKey: Uint8Array, messageHash: Uint8Array): Buffer { + function sign(secretKey: Uint8Array, messageHash: Uint8Array): Uint8Array { assert(secretKey, "secretKey is null or undefined"); assert(messageHash, "messageHash is null or undefined"); const privateKey = PrivateKey.fromBytes(secretKey); - return privateKey.signMessage(messageHash).toBytes(); + return privateKey.sign(messageHash).toBytes(); } /** * Compines all given signature into one. * @param signatures */ - function aggregateSignatures(signatures: Uint8Array[]): Buffer { + function aggregateSignatures(signatures: Uint8Array[]): Uint8Array { const agg = Signature.aggregate(signatures.map((p) => Signature.fromBytes(p))); return agg.toBytes(); } @@ -33,7 +33,7 @@ export function functionalInterfaceFactory({ * Combines all given public keys into single one * @param publicKeys */ - function aggregatePubkeys(publicKeys: Uint8Array[]): Buffer { + function aggregatePubkeys(publicKeys: Uint8Array[]): Uint8Array { const agg = PublicKey.aggregate(publicKeys.map((p) => PublicKey.fromBytes(p))); return agg.toBytes(); } diff --git a/src/herumi/context.ts b/src/herumi/context.ts index 0ac15fb..a35a59f 100644 --- a/src/herumi/context.ts +++ b/src/herumi/context.ts @@ -13,7 +13,7 @@ export async function setupBls(): Promise { } // Cache a promise for Bls instead of Bls to make sure it is initialized only once -export async function initBLS(): Promise { +export async function init(): Promise { if (!blsGlobalPromise) { blsGlobalPromise = setupBls(); } diff --git a/src/herumi/index.ts b/src/herumi/index.ts index 67b5688..ce40cfc 100644 --- a/src/herumi/index.ts +++ b/src/herumi/index.ts @@ -1,11 +1,11 @@ import {PrivateKey} from "./privateKey"; import {PublicKey} from "./publicKey"; import {Signature} from "./signature"; -import {initBLS, destroy} from "./context"; +import {init, destroy} from "./context"; import {IBls} from "../interface"; import {functionalInterfaceFactory} from "../functional"; -export {PrivateKey, PublicKey, Signature, initBLS, destroy}; +export {PrivateKey, PublicKey, Signature, init, destroy}; const bls: IBls = { PrivateKey, @@ -13,7 +13,7 @@ const bls: IBls = { Signature, ...functionalInterfaceFactory({PrivateKey, PublicKey, Signature}), - initBLS, + init, destroy, }; diff --git a/src/herumi/privateKey.ts b/src/herumi/privateKey.ts index 4e1a91e..9b8b8d6 100644 --- a/src/herumi/privateKey.ts +++ b/src/herumi/privateKey.ts @@ -19,7 +19,7 @@ export class PrivateKey implements IPrivateKey { assert(bytes.length === SECRET_KEY_LENGTH, "Private key should have 32 bytes"); const context = getContext(); const secretKey = new context.SecretKey(); - secretKey.deserialize(Buffer.from(bytes)); + secretKey.deserialize(bytes); return new PrivateKey(secretKey); } @@ -32,7 +32,7 @@ export class PrivateKey implements IPrivateKey { return this.fromBytes(sk); } - signMessage(message: Uint8Array): Signature { + sign(message: Uint8Array): Signature { return new Signature(this.value.sign(message)); } @@ -40,8 +40,8 @@ export class PrivateKey implements IPrivateKey { return new PublicKey(this.value.getPublicKey()); } - toBytes(): Buffer { - return Buffer.from(this.value.serialize()); + toBytes(): Uint8Array { + return this.value.serialize(); } toHex(): string { diff --git a/src/herumi/publicKey.ts b/src/herumi/publicKey.ts index d889eeb..79532c3 100644 --- a/src/herumi/publicKey.ts +++ b/src/herumi/publicKey.ts @@ -47,8 +47,8 @@ export class PublicKey implements IPublicKey { return this.value.verify(signature.value, messageHash); } - toBytes(): Buffer { - return Buffer.from(this.value.serialize()); + toBytes(): Uint8Array { + return this.value.serialize(); } toHex(): string { diff --git a/src/herumi/signature.ts b/src/herumi/signature.ts index 9198d43..13995c9 100644 --- a/src/herumi/signature.ts +++ b/src/herumi/signature.ts @@ -64,8 +64,8 @@ export class Signature implements ISignature { ); } - toBytes(): Buffer { - return Buffer.from(this.value.serialize()); + toBytes(): Uint8Array { + return this.value.serialize(); } toHex(): string { diff --git a/src/index.ts b/src/index.ts index 9a5d642..99476e6 100644 --- a/src/index.ts +++ b/src/index.ts @@ -3,17 +3,13 @@ import blsHerumi from "./herumi"; export type Implementation = "herumi" | "blst-native"; -// This proxy makes sure a nice error is printed if BLS is used before init() -export let bls: IBls = new Proxy({} as IBls, { - get: function () { - throw Error("BLS not initialized, call init() before"); - }, -}); +// TODO: Use a Proxy for example to throw an error if it's not initialized yet +export let bls: IBls; async function getImplementation(impl: Implementation) { switch (impl) { case "herumi": - await blsHerumi.initBLS(); + await blsHerumi.init(); return blsHerumi; case "blst-native": diff --git a/src/interface.ts b/src/interface.ts index 0b4aebf..ee34ad2 100644 --- a/src/interface.ts +++ b/src/interface.ts @@ -15,14 +15,14 @@ export interface IBls { aggregate(signatures: ISignature[]): ISignature; }; - sign(secretKey: Uint8Array, messageHash: Uint8Array): Buffer; - aggregatePubkeys(publicKeys: Uint8Array[]): Buffer; - aggregateSignatures(signatures: Uint8Array[]): Buffer; + sign(secretKey: Uint8Array, messageHash: Uint8Array): Uint8Array; + aggregatePubkeys(publicKeys: Uint8Array[]): Uint8Array; + aggregateSignatures(signatures: Uint8Array[]): Uint8Array; verify(publicKey: Uint8Array, messageHash: Uint8Array, signature: Uint8Array): boolean; verifyAggregate(publicKeys: Uint8Array[], messageHash: Uint8Array, signature: Uint8Array): boolean; verifyMultiple(publicKeys: Uint8Array[], messageHashes: Uint8Array[], signature: Uint8Array): boolean; - initBLS(): Promise; + init(): Promise; destroy(): void; } @@ -32,12 +32,12 @@ export interface IKeypair { } export interface IPublicKey { - toBytes(): Buffer; + toBytes(): Uint8Array; toHex(): string; } export interface ISignature { - toBytes(): Buffer; + toBytes(): Uint8Array; toHex(): string; verify(publicKey: IPublicKey, message: Uint8Array): boolean; verifyAggregate(publicKeys: IPublicKey[], message: Uint8Array): boolean; @@ -46,7 +46,7 @@ export interface ISignature { export interface IPrivateKey { toPublicKey(): IPublicKey; - signMessage(message: Uint8Array): ISignature; - toBytes(): Buffer; + sign(message: Uint8Array): ISignature; + toBytes(): Uint8Array; toHex(): string; } diff --git a/test/benchmark/index.ts b/test/benchmark/index.ts index 18dc9ed..dd50290 100644 --- a/test/benchmark/index.ts +++ b/test/benchmark/index.ts @@ -4,7 +4,7 @@ import {runForAllImplementations} from "../switch"; import {IPublicKey, ISignature} from "../../src/interface"; runForAllImplementations(async (bls, implementation) => { - await bls.initBLS(); + await bls.init(); const aggCount = 30; @@ -17,7 +17,7 @@ runForAllImplementations(async (bls, implementation) => { const msg = randomMsg(); const sk = bls.PrivateKey.fromKeygen(); const pk = sk.toPublicKey(); - const sig = sk.signMessage(msg); + const sig = sk.sign(msg); return { input: {pk, msg, sig}, resultCheck: (valid) => valid === true, @@ -38,7 +38,7 @@ runForAllImplementations(async (bls, implementation) => { const dataArr = range(aggCount).map(() => { const sk = bls.PrivateKey.fromKeygen(); const pk = sk.toPublicKey(); - const sig = sk.signMessage(msg); + const sig = sk.sign(msg); return {pk, sig}; }); @@ -79,7 +79,7 @@ runForAllImplementations(async (bls, implementation) => { const msg = randomMsg(); const sigs = range(aggCount).map(() => { const sk = bls.PrivateKey.fromKeygen(); - return sk.signMessage(msg); + return sk.sign(msg); }); return { input: sigs, diff --git a/test/switch.ts b/test/switch.ts index 66a6f45..942f6ae 100644 --- a/test/switch.ts +++ b/test/switch.ts @@ -27,7 +27,7 @@ export function describeForAllImplementations(callback: (bls: IBls) => void): vo runForAllImplementations((bls, implementation) => { describe(implementation, () => { before(async () => { - await bls.initBLS(); + await bls.init(); }); callback(bls); diff --git a/test/unit/index.test.ts b/test/unit/index.test.ts index b7ef13b..68714ea 100644 --- a/test/unit/index.test.ts +++ b/test/unit/index.test.ts @@ -8,7 +8,7 @@ export function runIndexTests(bls: IBls): void { const sk = bls.PrivateKey.fromKeygen(); const pk = sk.toPublicKey(); const msg = randomMessage(); - const sig = sk.signMessage(msg); + const sig = sk.sign(msg); return {sk, pk, msg, sig}; } @@ -51,12 +51,7 @@ export function runIndexTests(bls: IBls): void { const msgs = getN(2, () => randomMessage()); const pks = sks.map((sk) => sk.toPublicKey()); - const sigs = [ - sks[0].signMessage(msgs[0]), - sks[1].signMessage(msgs[0]), - sks[2].signMessage(msgs[1]), - sks[3].signMessage(msgs[1]), - ]; + const sigs = [sks[0].sign(msgs[0]), sks[1].sign(msgs[0]), sks[2].sign(msgs[1]), sks[3].sign(msgs[1])]; const aggPubkeys = [ bls.aggregatePubkeys([pks[0], pks[1]].map((pk) => pk.toBytes())), @@ -74,7 +69,7 @@ export function runIndexTests(bls: IBls): void { const msg = randomMessage(); const sks = getN(n, () => bls.PrivateKey.fromKeygen()); const pks = sks.map((sk) => sk.toPublicKey()); - const sigs = sks.map((sk) => sk.signMessage(msg)); + const sigs = sks.map((sk) => sk.sign(msg)); const aggregateSignature = bls.aggregateSignatures(sigs.map((sig) => sig.toBytes())); diff --git a/test/unit/run-web-implementation.test.ts b/test/unit/run-web-implementation.test.ts index b70e9bd..159c0f2 100644 --- a/test/unit/run-web-implementation.test.ts +++ b/test/unit/run-web-implementation.test.ts @@ -11,7 +11,7 @@ describe("herumi", () => { before(async () => { // For consistency with describeForAllImplementations // eslint-disable-next-line import/no-named-as-default-member - await herumi.initBLS(); + await herumi.init(); }); runPrivateKeyTests(herumi); diff --git a/test/util.ts b/test/util.ts index e25f4b5..1ae5cc0 100644 --- a/test/util.ts +++ b/test/util.ts @@ -1,7 +1,7 @@ import crypto from "crypto"; -export function fromHexString(hex: string): Buffer { - return Buffer.from(hex.replace("0x", ""), "hex"); +export function fromHexString(hex: string): Uint8Array { + return Uint8Array.from(Buffer.from(hex.replace("0x", ""), "hex")); } export function toHexString(bytes: Buffer | Uint8Array): string { From 0e69b819e0bd3c7e27944f6eed299d95468aef20 Mon Sep 17 00:00:00 2001 From: dapplion Date: Wed, 25 Nov 2020 16:11:44 +0000 Subject: [PATCH 34/51] Remove keypair test --- test/unit/keypair.test.ts | 27 --------------------------- 1 file changed, 27 deletions(-) delete mode 100644 test/unit/keypair.test.ts diff --git a/test/unit/keypair.test.ts b/test/unit/keypair.test.ts deleted file mode 100644 index 82b2deb..0000000 --- a/test/unit/keypair.test.ts +++ /dev/null @@ -1,27 +0,0 @@ -// import {expect} from "chai"; -// import {IBls} from "../../src/interface"; - -// export function runKeypairTests(bls: IBls) { -// describe("Keypair", () => { -// it("should create from private and public key", () => { -// const sk = bls.PrivateKey.fromKeygen(); -// const sk2 = bls.PrivateKey.fromKeygen(); -// const pk = sk.toPublicKey(); - -// const keypair = new bls.Keypair(sk, pk); - -// expect(keypair.publicKey).to.be.equal(pk); -// expect(keypair.privateKey).to.be.equal(sk); -// expect(keypair.privateKey).to.not.be.equal(sk2); -// }); - -// it("should create from PrivateKey", () => { -// const sk = bls.PrivateKey.fromKeygen(); -// const pk = sk.toPublicKey(); - -// const keypair = new bls.Keypair(sk as any); - -// expect(keypair.publicKey.toHex()).to.equal(pk.toHex()); -// }); -// }); -// } From 591105c5532782edaa60395d4817004541aeb83f Mon Sep 17 00:00:00 2001 From: dapplion Date: Wed, 25 Nov 2020 16:17:48 +0000 Subject: [PATCH 35/51] Document peer dependency in README --- README.md | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index e01a155..b069428 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,12 @@ Javascript library for BLS (Boneh-Lynn-Shacham) signatures and signature aggrega ## Usage +```bash +yarn add @chainsafe/bls +``` + +You must initialize the library once in your application before using it. The result is cached and use across all your imports + ```ts import bls, {init} from "@chainsafe/bls"; @@ -27,7 +33,7 @@ import bls, {init} from "@chainsafe/bls"; ### Browser -If you are in the browser, import from `/browser` +If you are in the browser, import from `/browser` to import directly the WASM version ```ts import bls from "@chainsafe/bls/browser"; @@ -35,7 +41,11 @@ import bls from "@chainsafe/bls/browser"; ### Native bindings only -If you are in NodeJS, import from `/node` to skip browser specific code +If you are in NodeJS, import from `/node` to skip browser specific code. Also install peer dependency `@chainsafe/blst` which has the native bindings + +```bash +yarn add @chainsafe/bls @chainsafe/blst +``` ```ts import bls from "@chainsafe/bls/node"; @@ -43,7 +53,11 @@ import bls from "@chainsafe/bls/node"; ### Native bindings + WASM fallback -If you want to offer a fallback in NodeJS, first try to load native bindings and then fallback to WASM +If you want to offer a fallback in NodeJS, first try to load native bindings and then fallback to WASM. Also install peer dependency `@chainsafe/blst` which has the native bindings + +```bash +yarn add @chainsafe/bls @chainsafe/blst +``` ```ts import bls from "@chainsafe/bls"; From ca5cac64b31199403c37d53fdfaf91bd42731a09 Mon Sep 17 00:00:00 2001 From: dapplion Date: Wed, 25 Nov 2020 16:23:53 +0000 Subject: [PATCH 36/51] Fix lint warnings and errors --- src/herumi/index.ts | 2 +- src/herumi/web.ts | 2 +- src/index.ts | 8 +++++--- test/benchmark/runner.ts | 1 + 4 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/herumi/index.ts b/src/herumi/index.ts index ce40cfc..43d150a 100644 --- a/src/herumi/index.ts +++ b/src/herumi/index.ts @@ -7,7 +7,7 @@ import {functionalInterfaceFactory} from "../functional"; export {PrivateKey, PublicKey, Signature, init, destroy}; -const bls: IBls = { +export const bls: IBls = { PrivateKey, PublicKey, Signature, diff --git a/src/herumi/web.ts b/src/herumi/web.ts index 0217e53..9a348f2 100644 --- a/src/herumi/web.ts +++ b/src/herumi/web.ts @@ -1,4 +1,4 @@ -import bls from "./index"; +import {bls} from "./index"; // eslint-disable-next-line @typescript-eslint/no-explicit-any (function (window: any) { diff --git a/src/index.ts b/src/index.ts index 99476e6..90d00ef 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,14 +1,15 @@ import {IBls} from "./interface"; -import blsHerumi from "./herumi"; +import {bls as blsHerumi} from "./herumi"; export type Implementation = "herumi" | "blst-native"; // TODO: Use a Proxy for example to throw an error if it's not initialized yet export let bls: IBls; -async function getImplementation(impl: Implementation) { +async function getImplementation(impl: Implementation): Promise { switch (impl) { case "herumi": + // eslint-disable-next-line @typescript-eslint/no-require-imports await blsHerumi.init(); return blsHerumi; @@ -16,6 +17,7 @@ async function getImplementation(impl: Implementation) { if (typeof require !== "function") { throw Error("blst-native is only supported in NodeJS"); } + // eslint-disable-next-line @typescript-eslint/no-require-imports return require("./blst"); default: @@ -23,7 +25,7 @@ async function getImplementation(impl: Implementation) { } } -export async function init(impl: Implementation) { +export async function init(impl: Implementation): Promise { bls = await getImplementation(impl); } diff --git a/test/benchmark/runner.ts b/test/benchmark/runner.ts index 6b28931..b7c32bc 100644 --- a/test/benchmark/runner.ts +++ b/test/benchmark/runner.ts @@ -24,6 +24,7 @@ export function runBenchmark({ const average = averageBigint(diffsNanoSec); const opsPerSec = 1e9 / Number(average); + // eslint-disable-next-line no-console console.log(`${id}: ${opsPerSec.toPrecision(5)} ops/sec (${runs} runs)`); // ±1.74% } From e32ea6d7a5e7c2a1664ceebb0b75590e89fdcc32 Mon Sep 17 00:00:00 2001 From: dapplion Date: Wed, 25 Nov 2020 17:56:33 +0000 Subject: [PATCH 37/51] Buffer is subclass of Uint8Array --- src/helpers/utils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/helpers/utils.ts b/src/helpers/utils.ts index 2451c50..683b098 100644 --- a/src/helpers/utils.ts +++ b/src/helpers/utils.ts @@ -5,7 +5,7 @@ export function assert(condition: unknown, message = "Assertion failed"): assert } export function hexToBytes(hex: string): Uint8Array { - return Uint8Array.from(Buffer.from(hex.replace("0x", ""), "hex")); + return Buffer.from(hex.replace("0x", ""), "hex"); } export function bytesToHex(bytes: Uint8Array): string { From 4ca653217158de5ee7a0889cb3deadd590e56324 Mon Sep 17 00:00:00 2001 From: dapplion Date: Wed, 25 Nov 2020 17:57:33 +0000 Subject: [PATCH 38/51] Use toBuffer to prevent allocation --- src/helpers/utils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/helpers/utils.ts b/src/helpers/utils.ts index 683b098..d69ae97 100644 --- a/src/helpers/utils.ts +++ b/src/helpers/utils.ts @@ -13,7 +13,7 @@ export function bytesToHex(bytes: Uint8Array): string { } export function isEqualBytes(a: Buffer | Uint8Array, b: Buffer | Uint8Array): boolean { - return Buffer.from(a).equals(Buffer.from(b)); + return toBuffer(a).equals(toBuffer(b)); } export function toBuffer(input: Uint8Array): Buffer { From 406419cac760a5af3c9bf7eefa0620d05f66179d Mon Sep 17 00:00:00 2001 From: dapplion Date: Wed, 25 Nov 2020 17:58:03 +0000 Subject: [PATCH 39/51] Set default value for implementation --- src/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/index.ts b/src/index.ts index 90d00ef..5d876a7 100644 --- a/src/index.ts +++ b/src/index.ts @@ -6,7 +6,7 @@ export type Implementation = "herumi" | "blst-native"; // TODO: Use a Proxy for example to throw an error if it's not initialized yet export let bls: IBls; -async function getImplementation(impl: Implementation): Promise { +async function getImplementation(impl: Implementation = "herumi"): Promise { switch (impl) { case "herumi": // eslint-disable-next-line @typescript-eslint/no-require-imports From 104d6dd2695c12829ad16d03b1cc3a8d824777dc Mon Sep 17 00:00:00 2001 From: dapplion Date: Sat, 28 Nov 2020 19:05:34 +0000 Subject: [PATCH 40/51] Use upstream types for bls-eth-wasm --- package.json | 2 +- tsconfig.json | 8 ++- types/bls-eth-wasm/index.d.ts | 97 ----------------------------------- yarn.lock | 8 +-- 4 files changed, 8 insertions(+), 107 deletions(-) delete mode 100644 types/bls-eth-wasm/index.d.ts diff --git a/package.json b/package.json index 8491d2f..6f6d581 100644 --- a/package.json +++ b/package.json @@ -42,7 +42,7 @@ }, "dependencies": { "@chainsafe/bls-keygen": "^0.3.0", - "bls-eth-wasm": "^0.4.1" + "bls-eth-wasm": "^0.4.4" }, "devDependencies": { "@babel/cli": "^7.8.4", diff --git a/tsconfig.json b/tsconfig.json index dd24356..a15932d 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -4,11 +4,9 @@ "target": "esnext", "module": "commonjs", "pretty": true, - "lib": [ - "esnext.bigint" - ], - "typeRoots": ["./node_modules/@types", "./types"], - "declaration": true, + "lib": ["esnext.bigint"], + "typeRoots": ["./node_modules/@types"], + "declaration": true, "strict": true, "strictNullChecks": false, "esModuleInterop": true diff --git a/types/bls-eth-wasm/index.d.ts b/types/bls-eth-wasm/index.d.ts deleted file mode 100644 index 4b92724..0000000 --- a/types/bls-eth-wasm/index.d.ts +++ /dev/null @@ -1,97 +0,0 @@ -declare module "bls-eth-wasm" { - export class Common { - constructor(size: number); - - deserializeHexStr(s: string): void; - serializeToHexStr(): string; - dump(msg?: string): string; - clear(): void; - clone(): this; - isEqual(rhs: this): boolean; - deserialize(v: Uint8Array): void; - serialize(): Uint8Array; - add(rhs: this): void; - } - - export class SecretKeyType extends Common { - constructor(); - - setInt(x: number): void; - isZero(): boolean; - setHashOf(a: Uint8Array): void; - setLittleEndian(a: Uint8Array): void; - setLittleEndianMod(a: Uint8Array): void; - setByCSPRNG(): void; - getPublicKey(): PublicKeyType; - sign(m: string | Uint8Array): SignatureType; - } - - export class PublicKeyType extends Common { - constructor(); - - isZero(): boolean; - deserializeUncompressed(s: Uint8Array): void; - serializeUncompressed(): Uint8Array; - isValidOrder(): boolean; - verify(signature: SignatureType, m: Uint8Array | string): boolean; - } - - export class SignatureType extends Common { - constructor(); - - deserializeUncompressed(s: Uint8Array): void; - serializeUncompressed(): Uint8Array; - isValidOrder(): boolean; - aggregate(others: SignatureType[]): boolean; - fastAggregateVerify(publicKeys: PublicKeyType[], message: Uint8Array): boolean; - aggregateVerifyNoCheck(publicKeys: PublicKeyType[], messages: Uint8Array): boolean; - } - - export function init(curveType: CurveType): Promise; - export function blsInit(curveType: CurveType): void; - export function setETHmode(mode: EthMode): void; - - export function toHex(a: Uint8Array, start: number, length: number): string; - export function toHexStr(a: Uint8Array): string; - export function fromHexStr(s: string): Uint8Array; - export function deserializeHexStrToSecretKey(s: string): SecretKeyType; - export function deserializeHexStrToPublicKey(s: string): PublicKeyType; - export function deserializeHexStrToSignature(s: string): SignatureType; - - export function getCurveOrder(): string; - export function getFieldOrder(): string; - export function verifySignatureOrder(doVerify: boolean): void; - export function verifyPublicKeyOrder(doVerify: boolean): void; - - /** - * - * @param msgs single array with concatenated messages - * @param msgSize defaults to MSG_SIZE - */ - export function areAllMsgDifferent(msgs: Uint8Array, msgSize?: number): boolean; - - /** - * return true if all pub[i].verify(sigs[i], msgs[i]) - * @param msgs msgs is a concatenation of arrays of 32-byte Uint8Array - */ - export function multiVerify(pubs: PublicKeyType[], sigs: SignatureType[], msgs: Uint8Array[]): boolean; - - export const SecretKey: typeof SecretKeyType; - export const PublicKey: typeof PublicKeyType; - export const Signature: typeof SignatureType; - - export enum EthMode { - DRAFT_07 = 3, - } - - export enum CurveType { - BN254 = 0, - BLS12_381 = 5, - } - - export const BN254 = CurveType.BN254; - export const BLS12_381 = CurveType.BLS12_381; - export const ethMode = true; - export const ETH_MODE_DRAFT_07 = EthMode.DRAFT_07; - export const MSG_SIZE = 32; -} diff --git a/yarn.lock b/yarn.lock index fb7d8a9..9c3d741 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1488,10 +1488,10 @@ blob@0.0.5: resolved "https://registry.yarnpkg.com/blob/-/blob-0.0.5.tgz#d680eeef25f8cd91ad533f5b01eed48e64caf683" integrity sha512-gaqbzQPqOoamawKg0LGVd7SzLgXS+JH61oWprSLH+P+abTczqJbhTR8CmJ2u9/bUYNmHTGJx/UEmn6doAvvuig== -bls-eth-wasm@^0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/bls-eth-wasm/-/bls-eth-wasm-0.4.1.tgz#7a1bac9d36f117ad4a8c7e741d667b51a6c31e68" - integrity sha512-BBM+t/RNZSOZKiLmz+wmz58kzK9CDjH6K2o2QuUKUkJNUaDo8g4vsqay0SvbmxinhpSxL/epkVel9+KNXcFnlw== +bls-eth-wasm@^0.4.4: + version "0.4.4" + resolved "https://registry.yarnpkg.com/bls-eth-wasm/-/bls-eth-wasm-0.4.4.tgz#3d4c99f8ddee6df23e188dc756125268a0f4d525" + integrity sha512-S6XwscKuxxYTANHZX8tZQxZKvj9IhG3aOCEuy1EnNdsAOfuH2pdRIgWrORwpKd4SLdvmPWap9I+TbJRnFx1Yng== bluebird@^3.3.0, bluebird@^3.5.5: version "3.7.2" From b0ed0e8cb55bb0bdb0b7620a393c11912e73e083 Mon Sep 17 00:00:00 2001 From: dapplion Date: Sat, 28 Nov 2020 19:06:29 +0000 Subject: [PATCH 41/51] Include root import files in package.json --- package.json | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 6f6d581..f86c1c1 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,11 @@ "files": [ "lib/**/*.js", "lib/**/*.js.map", - "lib/**/*.d.ts" + "lib/**/*.d.ts", + "blst-native.*", + "browser.*", + "herumi.*", + "node." ], "keywords": [ "ethereum", From bd17160713c9fdf9e5192c3bc6c4c31884658a17 Mon Sep 17 00:00:00 2001 From: dapplion Date: Sat, 28 Nov 2020 19:11:21 +0000 Subject: [PATCH 42/51] Use 'message' arg name consistently --- src/functional.ts | 34 +++++++++++++++++----------------- src/herumi/publicKey.ts | 4 ++-- src/interface.ts | 8 ++++---- 3 files changed, 23 insertions(+), 23 deletions(-) diff --git a/src/functional.ts b/src/functional.ts index 7c7be12..c11ea00 100644 --- a/src/functional.ts +++ b/src/functional.ts @@ -11,13 +11,13 @@ export function functionalInterfaceFactory({ /** * Signs given message using secret key. * @param secretKey - * @param messageHash + * @param message */ - function sign(secretKey: Uint8Array, messageHash: Uint8Array): Uint8Array { + function sign(secretKey: Uint8Array, message: Uint8Array): Uint8Array { assert(secretKey, "secretKey is null or undefined"); - assert(messageHash, "messageHash is null or undefined"); + assert(message, "message is null or undefined"); const privateKey = PrivateKey.fromBytes(secretKey); - return privateKey.sign(messageHash).toBytes(); + return privateKey.sign(message).toBytes(); } /** @@ -41,15 +41,15 @@ export function functionalInterfaceFactory({ /** * Verifies if signature is message signed with given public key. * @param publicKey - * @param messageHash + * @param message * @param signature */ - function verify(publicKey: Uint8Array, messageHash: Uint8Array, signature: Uint8Array): boolean { + function verify(publicKey: Uint8Array, message: Uint8Array, signature: Uint8Array): boolean { assert(publicKey, "publicKey is null or undefined"); - assert(messageHash, "messageHash is null or undefined"); + assert(message, "message is null or undefined"); assert(signature, "signature is null or undefined"); try { - return Signature.fromBytes(signature).verify(PublicKey.fromBytes(publicKey), messageHash); + return Signature.fromBytes(signature).verify(PublicKey.fromBytes(publicKey), message); } catch (e) { return false; } @@ -58,17 +58,17 @@ export function functionalInterfaceFactory({ /** * Verifies if aggregated signature is same message signed with given public keys. * @param publicKeys - * @param messageHash + * @param message * @param signature */ - function verifyAggregate(publicKeys: Uint8Array[], messageHash: Uint8Array, signature: Uint8Array): boolean { + function verifyAggregate(publicKeys: Uint8Array[], message: Uint8Array, signature: Uint8Array): boolean { assert(publicKeys, "publicKey is null or undefined"); - assert(messageHash, "messageHash is null or undefined"); + assert(message, "message is null or undefined"); assert(signature, "signature is null or undefined"); try { return Signature.fromBytes(signature).verifyAggregate( publicKeys.map((pubkey) => PublicKey.fromBytes(pubkey)), - messageHash + message ); } catch (e) { return false; @@ -78,22 +78,22 @@ export function functionalInterfaceFactory({ /** * Verifies if signature is list of message signed with corresponding public key. * @param publicKeys - * @param messageHashes + * @param messages * @param signature * @param fast Check if all messages are different */ - function verifyMultiple(publicKeys: Uint8Array[], messageHashes: Uint8Array[], signature: Uint8Array): boolean { + function verifyMultiple(publicKeys: Uint8Array[], messages: Uint8Array[], signature: Uint8Array): boolean { assert(publicKeys, "publicKey is null or undefined"); - assert(messageHashes, "messageHash is null or undefined"); + assert(messages, "message is null or undefined"); assert(signature, "signature is null or undefined"); - if (publicKeys.length === 0 || publicKeys.length != messageHashes.length) { + if (publicKeys.length === 0 || publicKeys.length != messages.length) { return false; } try { return Signature.fromBytes(signature).verifyMultiple( publicKeys.map((publicKey) => PublicKey.fromBytes(publicKey)), - messageHashes.map((msg) => msg) + messages.map((msg) => msg) ); } catch (e) { return false; diff --git a/src/herumi/publicKey.ts b/src/herumi/publicKey.ts index 79532c3..3d102a3 100644 --- a/src/herumi/publicKey.ts +++ b/src/herumi/publicKey.ts @@ -43,8 +43,8 @@ export class PublicKey implements IPublicKey { return agg; } - verifyMessage(signature: Signature, messageHash: Uint8Array): boolean { - return this.value.verify(signature.value, messageHash); + verifyMessage(signature: Signature, message: Uint8Array): boolean { + return this.value.verify(signature.value, message); } toBytes(): Uint8Array { diff --git a/src/interface.ts b/src/interface.ts index ee34ad2..62c9a53 100644 --- a/src/interface.ts +++ b/src/interface.ts @@ -15,12 +15,12 @@ export interface IBls { aggregate(signatures: ISignature[]): ISignature; }; - sign(secretKey: Uint8Array, messageHash: Uint8Array): Uint8Array; + sign(secretKey: Uint8Array, message: Uint8Array): Uint8Array; aggregatePubkeys(publicKeys: Uint8Array[]): Uint8Array; aggregateSignatures(signatures: Uint8Array[]): Uint8Array; - verify(publicKey: Uint8Array, messageHash: Uint8Array, signature: Uint8Array): boolean; - verifyAggregate(publicKeys: Uint8Array[], messageHash: Uint8Array, signature: Uint8Array): boolean; - verifyMultiple(publicKeys: Uint8Array[], messageHashes: Uint8Array[], signature: Uint8Array): boolean; + verify(publicKey: Uint8Array, message: Uint8Array, signature: Uint8Array): boolean; + verifyAggregate(publicKeys: Uint8Array[], message: Uint8Array, signature: Uint8Array): boolean; + verifyMultiple(publicKeys: Uint8Array[], messages: Uint8Array[], signature: Uint8Array): boolean; init(): Promise; destroy(): void; From 9194769d62202faf4769e2249d556aedb1310eae Mon Sep 17 00:00:00 2001 From: dapplion Date: Sat, 28 Nov 2020 19:14:06 +0000 Subject: [PATCH 43/51] Export constants consistently --- src/blst/index.ts | 2 +- src/herumi/index.ts | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/blst/index.ts b/src/blst/index.ts index 75af81d..88afe2b 100644 --- a/src/blst/index.ts +++ b/src/blst/index.ts @@ -2,8 +2,8 @@ import {PrivateKey} from "./privateKey"; import {PublicKey} from "./publicKey"; import {Signature} from "./signature"; import {IBls} from "../interface"; -export * from "../constants"; import {functionalInterfaceFactory} from "../functional"; +export * from "../constants"; export {PrivateKey, PublicKey, Signature}; diff --git a/src/herumi/index.ts b/src/herumi/index.ts index 43d150a..cfa4e22 100644 --- a/src/herumi/index.ts +++ b/src/herumi/index.ts @@ -4,6 +4,7 @@ import {Signature} from "./signature"; import {init, destroy} from "./context"; import {IBls} from "../interface"; import {functionalInterfaceFactory} from "../functional"; +export * from "../constants"; export {PrivateKey, PublicKey, Signature, init, destroy}; From b507ed28c064147a6229bcf22ff88cf163acc5dc Mon Sep 17 00:00:00 2001 From: dapplion Date: Sat, 28 Nov 2020 19:27:59 +0000 Subject: [PATCH 44/51] Use randombytes instead of node's crypto --- package.json | 4 +++- src/blst/privateKey.ts | 6 +++--- src/helpers/utils.ts | 5 +++++ test/benchmark/index.ts | 4 ++-- test/util.ts | 4 ++-- yarn.lock | 12 ++++++++++++ 6 files changed, 27 insertions(+), 8 deletions(-) diff --git a/package.json b/package.json index f86c1c1..7fae751 100644 --- a/package.json +++ b/package.json @@ -46,7 +46,8 @@ }, "dependencies": { "@chainsafe/bls-keygen": "^0.3.0", - "bls-eth-wasm": "^0.4.4" + "bls-eth-wasm": "^0.4.4", + "randombytes": "^2.1.0" }, "devDependencies": { "@babel/cli": "^7.8.4", @@ -62,6 +63,7 @@ "@chainsafe/lodestar-spec-test-util": "^0.11.0", "@types/chai": "^4.2.9", "@types/mocha": "^8.0.4", + "@types/randombytes": "^2.0.0", "@typescript-eslint/eslint-plugin": "^2.20.0", "@typescript-eslint/parser": "^2.20.0", "chai": "^4.2.0", diff --git a/src/blst/privateKey.ts b/src/blst/privateKey.ts index aeafde8..05a68ec 100644 --- a/src/blst/privateKey.ts +++ b/src/blst/privateKey.ts @@ -1,6 +1,6 @@ -import crypto from "crypto"; import * as blst from "@chainsafe/blst"; -import {bytesToHex, hexToBytes} from "../helpers/utils"; +import {bytesToHex, hexToBytes, randomBytes} from "../helpers/utils"; +import {SECRET_KEY_LENGTH} from "../constants"; import {IPrivateKey} from "../interface"; import {PublicKey} from "./publicKey"; import {Signature} from "./signature"; @@ -22,7 +22,7 @@ export class PrivateKey implements IPrivateKey { } static fromKeygen(entropy?: Uint8Array): PrivateKey { - const sk = blst.SecretKey.fromKeygen(entropy || crypto.randomBytes(32)); + const sk = blst.SecretKey.fromKeygen(entropy || randomBytes(SECRET_KEY_LENGTH)); return new PrivateKey(sk); } diff --git a/src/helpers/utils.ts b/src/helpers/utils.ts index d69ae97..fb0e5d8 100644 --- a/src/helpers/utils.ts +++ b/src/helpers/utils.ts @@ -1,3 +1,8 @@ +import randomBytes from "randombytes"; + +// Single import to ease changing this lib if necessary +export {randomBytes}; + export function assert(condition: unknown, message = "Assertion failed"): asserts condition { if (!condition) { throw new Error(message); diff --git a/test/benchmark/index.ts b/test/benchmark/index.ts index dd50290..e2a4c5d 100644 --- a/test/benchmark/index.ts +++ b/test/benchmark/index.ts @@ -1,7 +1,7 @@ -import crypto from "crypto"; import {runBenchmark} from "./runner"; import {runForAllImplementations} from "../switch"; import {IPublicKey, ISignature} from "../../src/interface"; +import {randomBytes} from "../../src/helpers"; runForAllImplementations(async (bls, implementation) => { await bls.init(); @@ -98,5 +98,5 @@ function range(n: number): number[] { } function randomMsg(): Uint8Array { - return Uint8Array.from(crypto.randomBytes(32)); + return Uint8Array.from(randomBytes(32)); } diff --git a/test/util.ts b/test/util.ts index 1ae5cc0..6741237 100644 --- a/test/util.ts +++ b/test/util.ts @@ -1,4 +1,4 @@ -import crypto from "crypto"; +import {randomBytes} from "../src/helpers"; export function fromHexString(hex: string): Uint8Array { return Uint8Array.from(Buffer.from(hex.replace("0x", ""), "hex")); @@ -9,7 +9,7 @@ export function toHexString(bytes: Buffer | Uint8Array): string { } export function randomMessage(): Uint8Array { - return crypto.randomBytes(32); + return randomBytes(32); } export function getN(n: number, getter: () => T): T[] { diff --git a/yarn.lock b/yarn.lock index 9c3d741..d880af4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -914,11 +914,23 @@ resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-8.0.4.tgz#b840c2dce46bacf286e237bfb59a29e843399148" integrity sha512-M4BwiTJjHmLq6kjON7ZoI2JMlBvpY3BYSdiP6s/qCT3jb1s9/DeJF0JELpAxiVSIxXDzfNKe+r7yedMIoLbknQ== +"@types/node@*": + version "14.14.10" + resolved "https://registry.yarnpkg.com/@types/node/-/node-14.14.10.tgz#5958a82e41863cfc71f2307b3748e3491ba03785" + integrity sha512-J32dgx2hw8vXrSbu4ZlVhn1Nm3GbeCFNw2FWL8S5QKucHGY0cyNwjdQdO+KMBZ4wpmC7KhLCiNsdk1RFRIYUQQ== + "@types/node@11.11.6": version "11.11.6" resolved "https://registry.yarnpkg.com/@types/node/-/node-11.11.6.tgz#df929d1bb2eee5afdda598a41930fe50b43eaa6a" integrity sha512-Exw4yUWMBXM3X+8oqzJNRqZSwUAaS4+7NdvHqQuFi/d+synz++xmX3QIf+BFqneW8N31R8Ky+sikfZUXq07ggQ== +"@types/randombytes@^2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@types/randombytes/-/randombytes-2.0.0.tgz#0087ff5e60ae68023b9bc4398b406fea7ad18304" + integrity sha512-bz8PhAVlwN72vqefzxa14DKNT8jK/mV66CSjwdVQM/k3Th3EPKfUtdMniwZgMedQTFuywAsfjnZsg+pEnltaMA== + dependencies: + "@types/node" "*" + "@typescript-eslint/eslint-plugin@^2.20.0": version "2.20.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-2.20.0.tgz#a522d0e1e4898f7c9c6a8e1ed3579b60867693fa" From 2c34db8b8e599fe1e68113474ce16ecb3c4b250b Mon Sep 17 00:00:00 2001 From: dapplion Date: Sat, 28 Nov 2020 19:30:56 +0000 Subject: [PATCH 45/51] Remove unnecessary casting of Buffer to Unit8Array --- src/constants.ts | 4 ++-- test/benchmark/index.ts | 2 +- test/util.ts | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/constants.ts b/src/constants.ts index 1169bdd..9da09d2 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -3,5 +3,5 @@ export const SIGNATURE_LENGTH = 96; export const FP_POINT_LENGTH = 48; export const PUBLIC_KEY_LENGTH = FP_POINT_LENGTH; export const G2_HASH_PADDING = 16; -export const EMPTY_PUBLIC_KEY = Uint8Array.from(Buffer.alloc(PUBLIC_KEY_LENGTH)); -export const EMPTY_SIGNATURE = Uint8Array.from(Buffer.alloc(SIGNATURE_LENGTH)); +export const EMPTY_PUBLIC_KEY = new Uint8Array(PUBLIC_KEY_LENGTH); +export const EMPTY_SIGNATURE = new Uint8Array(SIGNATURE_LENGTH); diff --git a/test/benchmark/index.ts b/test/benchmark/index.ts index e2a4c5d..9136baa 100644 --- a/test/benchmark/index.ts +++ b/test/benchmark/index.ts @@ -98,5 +98,5 @@ function range(n: number): number[] { } function randomMsg(): Uint8Array { - return Uint8Array.from(randomBytes(32)); + return randomBytes(32); } diff --git a/test/util.ts b/test/util.ts index 6741237..a122ed7 100644 --- a/test/util.ts +++ b/test/util.ts @@ -1,7 +1,7 @@ import {randomBytes} from "../src/helpers"; export function fromHexString(hex: string): Uint8Array { - return Uint8Array.from(Buffer.from(hex.replace("0x", ""), "hex")); + return Buffer.from(hex.replace("0x", ""), "hex"); } export function toHexString(bytes: Buffer | Uint8Array): string { From 8055f73afb0d9230074e22ff114b40673e63b040 Mon Sep 17 00:00:00 2001 From: dapplion Date: Sat, 28 Nov 2020 19:52:32 +0000 Subject: [PATCH 46/51] Use browser friendly hexToBytes, bytesToHex methods --- src/blst/privateKey.ts | 2 +- src/blst/publicKey.ts | 2 +- src/blst/signature.ts | 2 +- src/helpers/hex.ts | 38 +++++++++++++++++++++++++ src/helpers/index.ts | 1 + src/helpers/utils.ts | 8 ------ src/herumi/privateKey.ts | 2 +- src/herumi/publicKey.ts | 2 +- src/herumi/signature.ts | 2 +- test/spec/aggregate_sigs.test.ts | 2 +- test/spec/aggregate_sigs_verify.test.ts | 2 +- test/spec/fast_aggregate_verify.test.ts | 2 +- test/spec/sign.test.ts | 2 +- test/spec/verify.test.ts | 2 +- test/unit/helpers/hex.test.ts | 29 +++++++++++++++++++ test/unit/privateKey.test.ts | 2 +- test/unit/publicKey.test.ts | 2 +- test/util.ts | 8 ------ 18 files changed, 81 insertions(+), 29 deletions(-) create mode 100644 src/helpers/hex.ts create mode 100644 test/unit/helpers/hex.test.ts diff --git a/src/blst/privateKey.ts b/src/blst/privateKey.ts index 05a68ec..8716f99 100644 --- a/src/blst/privateKey.ts +++ b/src/blst/privateKey.ts @@ -1,5 +1,5 @@ import * as blst from "@chainsafe/blst"; -import {bytesToHex, hexToBytes, randomBytes} from "../helpers/utils"; +import {bytesToHex, hexToBytes, randomBytes} from "../helpers"; import {SECRET_KEY_LENGTH} from "../constants"; import {IPrivateKey} from "../interface"; import {PublicKey} from "./publicKey"; diff --git a/src/blst/publicKey.ts b/src/blst/publicKey.ts index 6301cf2..c5e45bb 100644 --- a/src/blst/publicKey.ts +++ b/src/blst/publicKey.ts @@ -1,5 +1,5 @@ import * as blst from "@chainsafe/blst"; -import {bytesToHex, hexToBytes} from "../helpers/utils"; +import {bytesToHex, hexToBytes} from "../helpers"; import {IPublicKey} from "../interface"; import {Signature} from "./signature"; diff --git a/src/blst/signature.ts b/src/blst/signature.ts index 8316c96..d3a74f4 100644 --- a/src/blst/signature.ts +++ b/src/blst/signature.ts @@ -1,5 +1,5 @@ import * as blst from "@chainsafe/blst"; -import {bytesToHex, hexToBytes} from "../helpers/utils"; +import {bytesToHex, hexToBytes} from "../helpers"; import {ISignature} from "../interface"; import {PublicKey} from "./publicKey"; diff --git a/src/helpers/hex.ts b/src/helpers/hex.ts new file mode 100644 index 0000000..9470cb8 --- /dev/null +++ b/src/helpers/hex.ts @@ -0,0 +1,38 @@ +/** + * Browser compatible fromHex method + * From https://github.com/herumi/bls-eth-wasm/blob/04eedb77aa96e66b4f65a0ab477228adf8090c36/src/bls.js#L62 + */ +export function hexToBytes(hex: string): Uint8Array { + if (hex.startsWith("0x")) { + hex = hex.slice(2); + } + + if (hex.length & 1) { + throw Error("hexToBytes:length must be even " + hex.length); + } + + const n = hex.length / 2; + const a = new Uint8Array(n); + + for (let i = 0; i < n; i++) { + a[i] = parseInt(hex.slice(i * 2, i * 2 + 2), 16); + } + + return a; +} + +/** + * Browser compatible toHex method + * From https://github.com/herumi/bls-eth-wasm/blob/04eedb77aa96e66b4f65a0ab477228adf8090c36/src/bls.js#L50 + */ +export function bytesToHex(bytes: Uint8Array): string { + // return "0x" + Buffer.from(bytes).toString("hex"); + let s = ""; + const n = bytes.length; + + for (let i = 0; i < n; i++) { + s += ("0" + bytes[i].toString(16)).slice(-2); + } + + return "0x" + s; +} diff --git a/src/helpers/index.ts b/src/helpers/index.ts index 178cd64..daf81b5 100644 --- a/src/helpers/index.ts +++ b/src/helpers/index.ts @@ -1 +1,2 @@ +export * from "./hex"; export * from "./utils"; diff --git a/src/helpers/utils.ts b/src/helpers/utils.ts index fb0e5d8..a724b0d 100644 --- a/src/helpers/utils.ts +++ b/src/helpers/utils.ts @@ -9,14 +9,6 @@ export function assert(condition: unknown, message = "Assertion failed"): assert } } -export function hexToBytes(hex: string): Uint8Array { - return Buffer.from(hex.replace("0x", ""), "hex"); -} - -export function bytesToHex(bytes: Uint8Array): string { - return "0x" + Buffer.from(bytes).toString("hex"); -} - export function isEqualBytes(a: Buffer | Uint8Array, b: Buffer | Uint8Array): boolean { return toBuffer(a).equals(toBuffer(b)); } diff --git a/src/herumi/privateKey.ts b/src/herumi/privateKey.ts index 9b8b8d6..177d886 100644 --- a/src/herumi/privateKey.ts +++ b/src/herumi/privateKey.ts @@ -5,7 +5,7 @@ import {SECRET_KEY_LENGTH} from "../constants"; import {getContext} from "./context"; import {PublicKey} from "./publicKey"; import {Signature} from "./signature"; -import {bytesToHex, hexToBytes} from "../helpers/utils"; +import {bytesToHex, hexToBytes} from "../helpers"; import {IPrivateKey} from "../interface"; export class PrivateKey implements IPrivateKey { diff --git a/src/herumi/publicKey.ts b/src/herumi/publicKey.ts index 3d102a3..c927728 100644 --- a/src/herumi/publicKey.ts +++ b/src/herumi/publicKey.ts @@ -2,7 +2,7 @@ import {PublicKeyType} from "bls-eth-wasm"; import {getContext} from "./context"; import {EMPTY_PUBLIC_KEY} from "../constants"; import {Signature} from "./signature"; -import {bytesToHex, hexToBytes, isEqualBytes} from "../helpers/utils"; +import {bytesToHex, hexToBytes, isEqualBytes} from "../helpers"; import {IPublicKey} from "../interface"; export class PublicKey implements IPublicKey { diff --git a/src/herumi/signature.ts b/src/herumi/signature.ts index 13995c9..5b16719 100644 --- a/src/herumi/signature.ts +++ b/src/herumi/signature.ts @@ -3,7 +3,7 @@ import {SIGNATURE_LENGTH, EMPTY_SIGNATURE} from "../constants"; import {SignatureType} from "bls-eth-wasm"; import {getContext} from "./context"; import {PublicKey} from "./publicKey"; -import {bytesToHex, hexToBytes, isEqualBytes} from "../helpers/utils"; +import {bytesToHex, hexToBytes, isEqualBytes} from "../helpers"; import {ISignature} from "../interface"; export class Signature implements ISignature { diff --git a/test/spec/aggregate_sigs.test.ts b/test/spec/aggregate_sigs.test.ts index 50af3fa..a825e74 100644 --- a/test/spec/aggregate_sigs.test.ts +++ b/test/spec/aggregate_sigs.test.ts @@ -1,6 +1,6 @@ import path from "path"; import {describeDirectorySpecTest, InputType} from "@chainsafe/lodestar-spec-test-util"; -import {bytesToHex, hexToBytes} from "../../src/helpers/utils"; +import {bytesToHex, hexToBytes} from "../../src/helpers"; import {SPEC_TESTS_DIR} from "../params"; import {describeForAllImplementations} from "../switch"; diff --git a/test/spec/aggregate_sigs_verify.test.ts b/test/spec/aggregate_sigs_verify.test.ts index a2f0676..f7478d8 100644 --- a/test/spec/aggregate_sigs_verify.test.ts +++ b/test/spec/aggregate_sigs_verify.test.ts @@ -1,6 +1,6 @@ import path from "path"; import {describeDirectorySpecTest, InputType} from "@chainsafe/lodestar-spec-test-util"; -import {hexToBytes} from "../../src/helpers/utils"; +import {hexToBytes} from "../../src/helpers"; import {SPEC_TESTS_DIR} from "../params"; import {describeForAllImplementations} from "../switch"; diff --git a/test/spec/fast_aggregate_verify.test.ts b/test/spec/fast_aggregate_verify.test.ts index 6cf9906..8be9ed9 100644 --- a/test/spec/fast_aggregate_verify.test.ts +++ b/test/spec/fast_aggregate_verify.test.ts @@ -1,6 +1,6 @@ import path from "path"; import {describeDirectorySpecTest, InputType} from "@chainsafe/lodestar-spec-test-util"; -import {hexToBytes} from "../../src/helpers/utils"; +import {hexToBytes} from "../../src/helpers"; import {SPEC_TESTS_DIR} from "../params"; import {describeForAllImplementations} from "../switch"; diff --git a/test/spec/sign.test.ts b/test/spec/sign.test.ts index f525e5d..a90f21b 100644 --- a/test/spec/sign.test.ts +++ b/test/spec/sign.test.ts @@ -1,6 +1,6 @@ import path from "path"; import {describeDirectorySpecTest, InputType} from "@chainsafe/lodestar-spec-test-util"; -import {bytesToHex, hexToBytes} from "../../src/helpers/utils"; +import {bytesToHex, hexToBytes} from "../../src/helpers"; import {SPEC_TESTS_DIR} from "../params"; import {describeForAllImplementations} from "../switch"; diff --git a/test/spec/verify.test.ts b/test/spec/verify.test.ts index 59e65f8..06288d3 100644 --- a/test/spec/verify.test.ts +++ b/test/spec/verify.test.ts @@ -1,6 +1,6 @@ import path from "path"; import {describeDirectorySpecTest, InputType} from "@chainsafe/lodestar-spec-test-util"; -import {hexToBytes} from "../../src/helpers/utils"; +import {hexToBytes} from "../../src/helpers"; import {SPEC_TESTS_DIR} from "../params"; import {describeForAllImplementations} from "../switch"; diff --git a/test/unit/helpers/hex.test.ts b/test/unit/helpers/hex.test.ts new file mode 100644 index 0000000..93d5c09 --- /dev/null +++ b/test/unit/helpers/hex.test.ts @@ -0,0 +1,29 @@ +import {expect} from "chai"; +import {hexToBytes, bytesToHex} from "../../../src/helpers/hex"; + +describe("helpers / hex", () => { + const testCases: {id: string; hex: string}[] = [ + { + id: "pubkey", + hex: "0xb6f21199594b56d77670564bf422cb331d5281ca2c1f9a45588a56881d8287ef8619efa6456d6cd2ef61306aa5b21311", + }, + ]; + + for (const {id, hex} of testCases) { + it(`${id} hexToBytes`, () => { + const expectedBytes = hexToBytesNode(hex); + const bytes = hexToBytes(hex); + expect(expectedBytes.equals(bytes)).to.be.true; + }); + + it(`${id} bytesToHex`, () => { + const bytes = hexToBytesNode(hex); + const _hex = bytesToHex(bytes); + expect(_hex).to.equal(hex); + }); + } +}); + +function hexToBytesNode(hex: string): Buffer { + return Buffer.from(hex.replace("0x", ""), "hex"); +} diff --git a/test/unit/privateKey.test.ts b/test/unit/privateKey.test.ts index 75aad31..b5060e2 100644 --- a/test/unit/privateKey.test.ts +++ b/test/unit/privateKey.test.ts @@ -16,7 +16,7 @@ export function runPrivateKeyTests(bls: IBls): void { }); it("should export private key to hex string from non-prefixed hex", () => { - expect(bls.PrivateKey.fromHex(privateKey.replace("0x", "")).toHex()).to.be.equal(privateKey); + expect(bls.PrivateKey.fromHex(privateKey).toHex()).to.be.equal(privateKey); }); it("should not accept too short private key", () => { diff --git a/test/unit/publicKey.test.ts b/test/unit/publicKey.test.ts index cb139c1..23a52c0 100644 --- a/test/unit/publicKey.test.ts +++ b/test/unit/publicKey.test.ts @@ -11,7 +11,7 @@ export function runPublicKeyTests(bls: IBls): void { }); it("should export public key to hex string from non-prefixed hex", () => { - expect(bls.PublicKey.fromHex(publicKey.replace("0x", "")).toHex()).to.be.equal(publicKey); + expect(bls.PublicKey.fromHex(publicKey).toHex()).to.be.equal(publicKey); }); it("from private key", () => { diff --git a/test/util.ts b/test/util.ts index a122ed7..b929188 100644 --- a/test/util.ts +++ b/test/util.ts @@ -1,13 +1,5 @@ import {randomBytes} from "../src/helpers"; -export function fromHexString(hex: string): Uint8Array { - return Buffer.from(hex.replace("0x", ""), "hex"); -} - -export function toHexString(bytes: Buffer | Uint8Array): string { - return `0x${Buffer.from(bytes).toString("hex")}`; -} - export function randomMessage(): Uint8Array { return randomBytes(32); } From d9c83feb1051e986ee79ed1165fc9257c5f0ed01 Mon Sep 17 00:00:00 2001 From: dapplion Date: Sun, 29 Nov 2020 12:19:52 +0000 Subject: [PATCH 47/51] Remove unnecessary eslint-disable --- src/index.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/index.ts b/src/index.ts index 5d876a7..bf811a2 100644 --- a/src/index.ts +++ b/src/index.ts @@ -9,7 +9,6 @@ export let bls: IBls; async function getImplementation(impl: Implementation = "herumi"): Promise { switch (impl) { case "herumi": - // eslint-disable-next-line @typescript-eslint/no-require-imports await blsHerumi.init(); return blsHerumi; From 78f66280dee65c639f0b1d24e17ada13fdf97825 Mon Sep 17 00:00:00 2001 From: dapplion Date: Sun, 29 Nov 2020 12:21:31 +0000 Subject: [PATCH 48/51] Add note in README to install blst --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index b069428..2905abc 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,12 @@ Javascript library for BLS (Boneh-Lynn-Shacham) signatures and signature aggrega yarn add @chainsafe/bls ``` +To use native bindings you must install peer dependency `@chainsafe/blst` + +```bash +yarn add @chainsafe/bls @chainsafe/blst +``` + You must initialize the library once in your application before using it. The result is cached and use across all your imports ```ts From 70574b45c124a367f4f1d831d2d44c327e00b244 Mon Sep 17 00:00:00 2001 From: dapplion Date: Sun, 29 Nov 2020 13:57:08 +0000 Subject: [PATCH 49/51] Fix herumi's bytes length checks --- src/herumi/privateKey.ts | 6 ++++-- src/herumi/publicKey.ts | 6 +++++- src/herumi/signature.ts | 11 ++++++++--- 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/src/herumi/privateKey.ts b/src/herumi/privateKey.ts index 177d886..6fcfb7f 100644 --- a/src/herumi/privateKey.ts +++ b/src/herumi/privateKey.ts @@ -1,4 +1,3 @@ -import assert from "assert"; import {SecretKeyType} from "bls-eth-wasm"; import {generateRandomSecretKey} from "@chainsafe/bls-keygen"; import {SECRET_KEY_LENGTH} from "../constants"; @@ -16,7 +15,10 @@ export class PrivateKey implements IPrivateKey { } static fromBytes(bytes: Uint8Array): PrivateKey { - assert(bytes.length === SECRET_KEY_LENGTH, "Private key should have 32 bytes"); + if (bytes.length !== SECRET_KEY_LENGTH) { + throw Error(`Private key should have ${SECRET_KEY_LENGTH} bytes`); + } + const context = getContext(); const secretKey = new context.SecretKey(); secretKey.deserialize(bytes); diff --git a/src/herumi/publicKey.ts b/src/herumi/publicKey.ts index c927728..a9a40a5 100644 --- a/src/herumi/publicKey.ts +++ b/src/herumi/publicKey.ts @@ -1,6 +1,6 @@ import {PublicKeyType} from "bls-eth-wasm"; import {getContext} from "./context"; -import {EMPTY_PUBLIC_KEY} from "../constants"; +import {EMPTY_PUBLIC_KEY, PUBLIC_KEY_LENGTH} from "../constants"; import {Signature} from "./signature"; import {bytesToHex, hexToBytes, isEqualBytes} from "../helpers"; import {IPublicKey} from "../interface"; @@ -13,6 +13,10 @@ export class PublicKey implements IPublicKey { } static fromBytes(bytes: Uint8Array): PublicKey { + if (bytes.length !== PUBLIC_KEY_LENGTH) { + throw Error(`Public key must have ${PUBLIC_KEY_LENGTH} bytes`); + } + const context = getContext(); const publicKey = new context.PublicKey(); if (!isEqualBytes(EMPTY_PUBLIC_KEY, bytes)) { diff --git a/src/herumi/signature.ts b/src/herumi/signature.ts index 5b16719..e527cf7 100644 --- a/src/herumi/signature.ts +++ b/src/herumi/signature.ts @@ -1,4 +1,3 @@ -import assert from "assert"; import {SIGNATURE_LENGTH, EMPTY_SIGNATURE} from "../constants"; import {SignatureType} from "bls-eth-wasm"; import {getContext} from "./context"; @@ -10,12 +9,18 @@ export class Signature implements ISignature { readonly value: SignatureType; constructor(value: SignatureType) { + if (!value.isValidOrder()) { + throw Error("Signature is not in valid order"); + } + this.value = value; - assert(this.value.isValidOrder()); } static fromBytes(bytes: Uint8Array): Signature { - assert(bytes.length === SIGNATURE_LENGTH, `Signature must have ${SIGNATURE_LENGTH} bytes`); + if (bytes.length !== SIGNATURE_LENGTH) { + throw Error(`Signature must have ${SIGNATURE_LENGTH} bytes`); + } + const context = getContext(); const signature = new context.Signature(); if (!isEqualBytes(EMPTY_SIGNATURE, bytes)) { From 5db911d4706c532666ec34f08811c2bae192eaa0 Mon Sep 17 00:00:00 2001 From: dapplion Date: Sun, 29 Nov 2020 14:06:09 +0000 Subject: [PATCH 50/51] Use validateBytes instead of generic assert --- src/functional.ts | 27 +++++++++++++++------------ src/helpers/utils.ts | 20 ++++++++++++++------ 2 files changed, 29 insertions(+), 18 deletions(-) diff --git a/src/functional.ts b/src/functional.ts index c11ea00..a1287cb 100644 --- a/src/functional.ts +++ b/src/functional.ts @@ -1,4 +1,4 @@ -import {assert} from "./helpers"; +import {validateBytes} from "./helpers"; import {IBls} from "./interface"; // Returned type is enforced at each implementation's index @@ -14,8 +14,9 @@ export function functionalInterfaceFactory({ * @param message */ function sign(secretKey: Uint8Array, message: Uint8Array): Uint8Array { - assert(secretKey, "secretKey is null or undefined"); - assert(message, "message is null or undefined"); + validateBytes(secretKey, "secretKey"); + validateBytes(message, "message"); + const privateKey = PrivateKey.fromBytes(secretKey); return privateKey.sign(message).toBytes(); } @@ -45,9 +46,10 @@ export function functionalInterfaceFactory({ * @param signature */ function verify(publicKey: Uint8Array, message: Uint8Array, signature: Uint8Array): boolean { - assert(publicKey, "publicKey is null or undefined"); - assert(message, "message is null or undefined"); - assert(signature, "signature is null or undefined"); + validateBytes(publicKey, "publicKey"); + validateBytes(message, "message"); + validateBytes(signature, "signature"); + try { return Signature.fromBytes(signature).verify(PublicKey.fromBytes(publicKey), message); } catch (e) { @@ -62,9 +64,10 @@ export function functionalInterfaceFactory({ * @param signature */ function verifyAggregate(publicKeys: Uint8Array[], message: Uint8Array, signature: Uint8Array): boolean { - assert(publicKeys, "publicKey is null or undefined"); - assert(message, "message is null or undefined"); - assert(signature, "signature is null or undefined"); + validateBytes(publicKeys, "publicKey"); + validateBytes(message, "message"); + validateBytes(signature, "signature"); + try { return Signature.fromBytes(signature).verifyAggregate( publicKeys.map((pubkey) => PublicKey.fromBytes(pubkey)), @@ -83,9 +86,9 @@ export function functionalInterfaceFactory({ * @param fast Check if all messages are different */ function verifyMultiple(publicKeys: Uint8Array[], messages: Uint8Array[], signature: Uint8Array): boolean { - assert(publicKeys, "publicKey is null or undefined"); - assert(messages, "message is null or undefined"); - assert(signature, "signature is null or undefined"); + validateBytes(publicKeys, "publicKey"); + validateBytes(messages, "message"); + validateBytes(signature, "signature"); if (publicKeys.length === 0 || publicKeys.length != messages.length) { return false; diff --git a/src/helpers/utils.ts b/src/helpers/utils.ts index a724b0d..6a7c143 100644 --- a/src/helpers/utils.ts +++ b/src/helpers/utils.ts @@ -3,12 +3,6 @@ import randomBytes from "randombytes"; // Single import to ease changing this lib if necessary export {randomBytes}; -export function assert(condition: unknown, message = "Assertion failed"): asserts condition { - if (!condition) { - throw new Error(message); - } -} - export function isEqualBytes(a: Buffer | Uint8Array, b: Buffer | Uint8Array): boolean { return toBuffer(a).equals(toBuffer(b)); } @@ -16,3 +10,17 @@ export function isEqualBytes(a: Buffer | Uint8Array, b: Buffer | Uint8Array): bo export function toBuffer(input: Uint8Array): Buffer { return Buffer.from(input.buffer, input.byteOffset, input.length); } + +/** + * Validate bytes to prevent confusing WASM errors downstream if bytes is null + */ +export function validateBytes( + bytes: Uint8Array | Uint8Array[] | null, + argName?: string +): asserts bytes is NonNullable { + for (const item of Array.isArray(bytes) ? bytes : [bytes]) { + if (item == null) { + throw Error(`${argName || "bytes"} is null or undefined`); + } + } +} From a379898589b4b0bf7557698498357f7cc67c61c9 Mon Sep 17 00:00:00 2001 From: dapplion Date: Sun, 29 Nov 2020 15:08:17 +0000 Subject: [PATCH 51/51] Bump @chainsafe/blst --- package.json | 4 +- yarn.lock | 471 +++++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 457 insertions(+), 18 deletions(-) diff --git a/package.json b/package.json index 7fae751..8e24d39 100644 --- a/package.json +++ b/package.json @@ -58,7 +58,7 @@ "@babel/preset-env": "^7.8.4", "@babel/preset-typescript": "^7.8.3", "@babel/register": "^7.8.3", - "@chainsafe/blst": "^0.1.2", + "@chainsafe/blst": "^0.1.3", "@chainsafe/eth2-spec-tests": "0.12.0", "@chainsafe/lodestar-spec-test-util": "^0.11.0", "@types/chai": "^4.2.9", @@ -91,6 +91,6 @@ "v8-profiler-next": "1.3.0" }, "peerDependencies": { - "@chainsafe/blst": "^0.1.2" + "@chainsafe/blst": "^0.1.3" } } diff --git a/yarn.lock b/yarn.lock index d880af4..910f773 100644 --- a/yarn.lock +++ b/yarn.lock @@ -819,12 +819,13 @@ buffer "^5.4.3" randombytes "^2.1.0" -"@chainsafe/blst@^0.1.2": - version "0.1.2" - resolved "https://registry.yarnpkg.com/@chainsafe/blst/-/blst-0.1.2.tgz#5d2ee91609c0f799be4b4de2ea8ed67209bf4201" - integrity sha512-doQ4sFGthNR9WzLlFUvtOx1ReqIMNNjS0JC3NNg7NSkRMvzpIinFcHlcABmCJODofreU11GYext77WFCzoSKNA== +"@chainsafe/blst@^0.1.3": + version "0.1.3" + resolved "https://registry.yarnpkg.com/@chainsafe/blst/-/blst-0.1.3.tgz#b71b1d2cb327fd9654cd22177d5c2e13241bed5d" + integrity sha512-JSgXahRRrl6GLcp4sxWDgz/1J1uGesLFRrFCQIPEwH2SpWlNAhReiPkjOLr1Kkxuo5a5YaZVL3ZWMya40WxkKQ== dependencies: node-fetch "^2.6.1" + node-gyp "^7.1.2" "@chainsafe/eth2-spec-tests@0.12.0": version "0.12.0" @@ -1135,6 +1136,11 @@ resolved "https://registry.yarnpkg.com/@xtuc/long/-/long-4.2.2.tgz#d291c6a4e97989b5c61d9acf396ae4fe133a718d" integrity sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ== +abbrev@1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" + integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== + accepts@~1.3.4: version "1.3.7" resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.7.tgz#531bc726517a3b2b41f850021c6cc15eaab507cd" @@ -1191,6 +1197,16 @@ ajv@^6.1.0, ajv@^6.10.0, ajv@^6.10.2: json-schema-traverse "^0.4.1" uri-js "^4.2.2" +ajv@^6.12.3: + version "6.12.6" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" + integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== + dependencies: + fast-deep-equal "^3.1.1" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.2" + ansi-colors@4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.1.tgz#cbb9ae256bf750af1eab344f229aa27fe94ba348" @@ -1208,6 +1224,11 @@ ansi-escapes@^4.2.1: dependencies: type-fest "^0.8.1" +ansi-regex@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" + integrity sha1-w7M6te42DYbg5ijwRorn7yfWVN8= + ansi-regex@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" @@ -1268,7 +1289,7 @@ append-transform@^2.0.0: dependencies: default-require-extensions "^3.0.0" -aproba@^1.1.1: +aproba@^1.0.3, aproba@^1.1.1: version "1.2.0" resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" integrity sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw== @@ -1278,6 +1299,14 @@ archy@^1.0.0: resolved "https://registry.yarnpkg.com/archy/-/archy-1.0.0.tgz#f9c8c13757cc1dd7bc379ac77b2c62a5c2868c40" integrity sha1-+cjBN1fMHde8N5rHeyxipcKGjEA= +are-we-there-yet@~1.1.2: + version "1.1.5" + resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz#4b35c2944f062a8bfcda66410760350fe9ddfc21" + integrity sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w== + dependencies: + delegates "^1.0.0" + readable-stream "^2.0.6" + arg@^4.1.0: version "4.1.3" resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089" @@ -1341,6 +1370,18 @@ asn1.js@^4.0.0: inherits "^2.0.1" minimalistic-assert "^1.0.0" +asn1@~0.2.3: + version "0.2.4" + resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.4.tgz#8d2475dfab553bb33e77b54e59e880bb8ce23136" + integrity sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg== + dependencies: + safer-buffer "~2.1.0" + +assert-plus@1.0.0, assert-plus@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" + integrity sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU= + assert@^1.1.1: version "1.5.0" resolved "https://registry.yarnpkg.com/assert/-/assert-1.5.0.tgz#55c109aaf6e0aefdb3dc4b71240c70bf574b18eb" @@ -1391,11 +1432,26 @@ async@^2.6.1, async@^2.6.2: dependencies: lodash "^4.17.14" +asynckit@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + integrity sha1-x57Zf380y48robyXkLzDZkdLS3k= + atob@^2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg== +aws-sign2@~0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" + integrity sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg= + +aws4@^1.8.0: + version "1.11.0" + resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.11.0.tgz#d61f46d83b2519250e2784daf5b09479a8b41c59" + integrity sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA== + babel-plugin-dynamic-import-node@^2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.0.tgz#f00f507bdaa3c3e3ff6e7e5e98d90a7acab96f7f" @@ -1441,6 +1497,13 @@ base@^0.11.1: mixin-deep "^1.2.0" pascalcase "^0.1.1" +bcrypt-pbkdf@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e" + integrity sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4= + dependencies: + tweetnacl "^0.14.3" + bcrypto@^5.0.4: version "5.2.0" resolved "https://registry.yarnpkg.com/bcrypto/-/bcrypto-5.2.0.tgz#7cc944d2cc2b7beeff04c74f8611a001612a981d" @@ -1781,6 +1844,11 @@ case@^1.6.3: resolved "https://registry.yarnpkg.com/case/-/case-1.6.3.tgz#0a4386e3e9825351ca2e6216c60467ff5f1ea1c9" integrity sha512-mzDSXIPaFwVDvZAHqZ9VlbyF4yyXRuX6IvB06WvPYkqJVO24kX1PPhv9bfpKNFZyxYFmmgo03HUiD8iklmJYRQ== +caseless@~0.12.0: + version "0.12.0" + resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" + integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw= + chai@^4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/chai/-/chai-4.2.0.tgz#760aa72cf20e3795e84b12877ce0e83737aa29e5" @@ -1874,6 +1942,11 @@ chownr@^1.1.1: resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b" integrity sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg== +chownr@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/chownr/-/chownr-2.0.0.tgz#15bfbe53d2eab4cf70f18a8cd68ebe5b3cb1dece" + integrity sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ== + chrome-trace-event@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.2.tgz#234090ee97c7d4ad1a2c4beae27505deffc608a4" @@ -1943,6 +2016,11 @@ clone-deep@^4.0.1: kind-of "^6.0.2" shallow-clone "^3.0.0" +code-point-at@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" + integrity sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c= + collection-visit@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0" @@ -2009,6 +2087,13 @@ colorspace@1.1.x: color "3.0.x" text-hex "1.0.x" +combined-stream@^1.0.6, combined-stream@~1.0.6: + version "1.0.8" + resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" + integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== + dependencies: + delayed-stream "~1.0.0" + commander@^2.20.0: version "2.20.3" resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" @@ -2074,6 +2159,11 @@ console-browserify@^1.1.0: resolved "https://registry.yarnpkg.com/console-browserify/-/console-browserify-1.2.0.tgz#67063cef57ceb6cf4993a2ab3a55840ae8c49336" integrity sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA== +console-control-strings@^1.0.0, console-control-strings@~1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" + integrity sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4= + constants-browserify@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/constants-browserify/-/constants-browserify-1.0.0.tgz#c20b96d8c617748aaf1c16021760cd27fcb8cb75" @@ -2126,7 +2216,7 @@ core-js-compat@^3.6.2: browserslist "^4.8.3" semver "7.0.0" -core-util-is@~1.0.0: +core-util-is@1.0.2, core-util-is@~1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= @@ -2209,6 +2299,13 @@ cyclist@^1.0.1: resolved "https://registry.yarnpkg.com/cyclist/-/cyclist-1.0.1.tgz#596e9698fd0c80e12038c2b82d6eb1b35b6224d9" integrity sha1-WW6WmP0MgOEgOMK4LW6xs1tiJNk= +dashdash@^1.12.0: + version "1.14.1" + resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" + integrity sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA= + dependencies: + assert-plus "^1.0.0" + date-format@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/date-format/-/date-format-2.1.0.tgz#31d5b5ea211cf5fd764cd38baf9d033df7e125cf" @@ -2317,6 +2414,16 @@ define-property@^2.0.2: is-descriptor "^1.0.2" isobject "^3.0.1" +delayed-stream@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk= + +delegates@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" + integrity sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o= + depd@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" @@ -2403,6 +2510,14 @@ duplexify@^3.4.2, duplexify@^3.6.0: readable-stream "^2.0.0" stream-shift "^1.0.0" +ecc-jsbn@~0.1.1: + version "0.1.2" + resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9" + integrity sha1-OoOpBOVDUyh4dMVkt1SThoSamMk= + dependencies: + jsbn "~0.1.0" + safer-buffer "^2.1.0" + ee-first@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" @@ -2528,6 +2643,11 @@ ent@~2.2.0: resolved "https://registry.yarnpkg.com/ent/-/ent-2.2.0.tgz#e964219325a21d05f44466a2f686ed6ce5f5dd1d" integrity sha1-6WQhkyWiHQX0RGai9obtbOX13R0= +env-paths@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/env-paths/-/env-paths-2.2.0.tgz#cdca557dc009152917d6166e2febe1f039685e43" + integrity sha512-6u0VYSCo/OW6IoD5WCLLy9JUGARbamfSavcNXry/eu8aHVFei6CD3Sw+VGX5alea1i9pgPHW0mbu6Xj0uBh7gA== + env-variable@0.0.x: version "0.0.6" resolved "https://registry.yarnpkg.com/env-variable/-/env-variable-0.0.6.tgz#74ab20b3786c545b62b4a4813ab8cf22726c9808" @@ -2814,7 +2934,7 @@ extend-shallow@^3.0.0, extend-shallow@^3.0.2: assign-symbols "^1.0.0" is-extendable "^1.0.1" -extend@^3.0.0: +extend@^3.0.0, extend@~3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== @@ -2842,6 +2962,16 @@ extglob@^2.0.4: snapdragon "^0.8.1" to-regex "^3.0.1" +extsprintf@1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" + integrity sha1-lpGEQOMEGnpBT4xS48V06zw+HgU= + +extsprintf@^1.2.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f" + integrity sha1-4mifjzVvrWLMplo6kcXfX5VRaS8= + fast-deep-equal@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.1.tgz#545145077c501491e33b15ec408c294376e94ae4" @@ -3031,6 +3161,20 @@ foreground-child@^2.0.0: cross-spawn "^7.0.0" signal-exit "^3.0.2" +forever-agent@~0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" + integrity sha1-+8cfDEGt6zf5bFd60e1C2P2sypE= + +form-data@~2.3.2: + version "2.3.3" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6" + integrity sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.6" + mime-types "^2.1.12" + fragment-cache@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19" @@ -3060,6 +3204,13 @@ fs-extra@^7.0.1: jsonfile "^4.0.0" universalify "^0.1.0" +fs-minipass@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-2.1.0.tgz#7f5036fdbf12c63c169190cbe4199c852271f9fb" + integrity sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg== + dependencies: + minipass "^3.0.0" + fs-readdir-recursive@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/fs-readdir-recursive/-/fs-readdir-recursive-1.1.0.tgz#e32fc030a2ccee44a6b5371308da54be0b397d27" @@ -3103,6 +3254,20 @@ functional-red-black-tree@^1.0.1: resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc= +gauge@~2.7.3: + version "2.7.4" + resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" + integrity sha1-LANAXHU4w51+s3sxcCLjJfsBi/c= + dependencies: + aproba "^1.0.3" + console-control-strings "^1.0.0" + has-unicode "^2.0.0" + object-assign "^4.1.0" + signal-exit "^3.0.0" + string-width "^1.0.1" + strip-ansi "^3.0.1" + wide-align "^1.1.0" + gensync@^1.0.0-beta.1: version "1.0.0-beta.1" resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.1.tgz#58f4361ff987e5ff6e1e7a210827aa371eaac269" @@ -3130,6 +3295,13 @@ get-value@^2.0.3, get-value@^2.0.6: resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" integrity sha1-3BXKHGcjh8p2vTesCjlbogQqLCg= +getpass@^0.1.1: + version "0.1.7" + resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" + integrity sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo= + dependencies: + assert-plus "^1.0.0" + glob-parent@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-3.1.0.tgz#9e6af6299d8d3bd2bd40430832bd113df906c5ae" @@ -3210,11 +3382,29 @@ graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6 resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.3.tgz#4a12ff1b60376ef09862c2093edd908328be8423" integrity sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ== +graceful-fs@^4.2.3: + version "4.2.4" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.4.tgz#2256bde14d3632958c465ebc96dc467ca07a29fb" + integrity sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw== + growl@1.10.5: version "1.10.5" resolved "https://registry.yarnpkg.com/growl/-/growl-1.10.5.tgz#f2735dc2283674fa67478b10181059355c369e5e" integrity sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA== +har-schema@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92" + integrity sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI= + +har-validator@~5.1.3: + version "5.1.5" + resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.1.5.tgz#1f0803b9f8cb20c0fa13822df1ecddb36bde1efd" + integrity sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w== + dependencies: + ajv "^6.12.3" + har-schema "^2.0.0" + has-binary2@~1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/has-binary2/-/has-binary2-1.0.3.tgz#7776ac627f3ea77250cfc332dab7ddf5e4f5d11d" @@ -3242,6 +3432,11 @@ has-symbols@^1.0.0, has-symbols@^1.0.1: resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.1.tgz#9f5214758a44196c406d9bd76cebf81ec2dd31e8" integrity sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg== +has-unicode@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" + integrity sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk= + has-value@^0.3.1: version "0.3.1" resolved "https://registry.yarnpkg.com/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f" @@ -3355,6 +3550,15 @@ http-proxy@^1.13.0: follow-redirects "^1.0.0" requires-port "^1.0.0" +http-signature@~1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1" + integrity sha1-muzZJRFHcvPZW2WmCruPfBj7rOE= + dependencies: + assert-plus "^1.0.0" + jsprim "^1.2.2" + sshpk "^1.7.0" + https-browserify@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73" @@ -3589,6 +3793,13 @@ is-extglob@^2.1.0, is-extglob@^2.1.1: resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= +is-fullwidth-code-point@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" + integrity sha1-754xOG8DGn8NZDr4L95QxFfvAMs= + dependencies: + number-is-nan "^1.0.0" + is-fullwidth-code-point@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" @@ -3683,7 +3894,7 @@ is-symbol@^1.0.2: dependencies: has-symbols "^1.0.1" -is-typedarray@^1.0.0: +is-typedarray@^1.0.0, is-typedarray@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo= @@ -3732,6 +3943,11 @@ isobject@^3.0.0, isobject@^3.0.1: resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8= +isstream@~0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" + integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo= + istanbul-lib-coverage@^3.0.0, istanbul-lib-coverage@^3.0.0-alpha.1: version "3.0.0" resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.0.0.tgz#f5944a37c70b550b02a78a5c3b2055b280cec8ec" @@ -3817,6 +4033,11 @@ js-yaml@^3.13.1: argparse "^1.0.7" esprima "^4.0.0" +jsbn@~0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" + integrity sha1-peZUwuWi3rXyAdls77yoDA7y9RM= + jsesc@^2.5.1: version "2.5.2" resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" @@ -3837,11 +4058,21 @@ json-schema-traverse@^0.4.1: resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== +json-schema@0.2.3: + version "0.2.3" + resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" + integrity sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM= + json-stable-stringify-without-jsonify@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" integrity sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE= +json-stringify-safe@~5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" + integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus= + json5@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.1.tgz#779fb0018604fa854eacbf6252180d83543e3dbe" @@ -3863,6 +4094,16 @@ jsonfile@^4.0.0: optionalDependencies: graceful-fs "^4.1.6" +jsprim@^1.2.2: + version "1.4.1" + resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2" + integrity sha1-MT5mvB5cwG5Di8G3SZwuXFastqI= + dependencies: + assert-plus "1.0.0" + extsprintf "1.3.0" + json-schema "0.2.3" + verror "1.10.0" + karma-chai@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/karma-chai/-/karma-chai-0.1.0.tgz#bee5ad40400517811ae34bb945f762909108b79a" @@ -4250,6 +4491,18 @@ mime-db@1.43.0: resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.43.0.tgz#0a12e0502650e473d735535050e7c8f4eb4fae58" integrity sha512-+5dsGEEovYbT8UY9yD7eE4XTc4UwJ1jBYlgaQQF38ENsKR3wj/8q8RFZrF9WIZpB2V1ArTVFUva8sAul1NzRzQ== +mime-db@1.44.0: + version "1.44.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.44.0.tgz#fa11c5eb0aca1334b4233cb4d52f10c5a6272f92" + integrity sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg== + +mime-types@^2.1.12, mime-types@~2.1.19: + version "2.1.27" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.27.tgz#47949f98e279ea53119f5722e0f34e529bec009f" + integrity sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w== + dependencies: + mime-db "1.44.0" + mime-types@~2.1.24: version "2.1.26" resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.26.tgz#9c921fc09b7e149a65dfdc0da4d20997200b0a06" @@ -4299,6 +4552,21 @@ minimist@~0.0.1: resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.10.tgz#de3f98543dbf96082be48ad1a0c7cda836301dcf" integrity sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8= +minipass@^3.0.0: + version "3.1.3" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-3.1.3.tgz#7d42ff1f39635482e15f9cdb53184deebd5815fd" + integrity sha512-Mgd2GdMVzY+x3IJ+oHnVM+KG3lA5c8tnabyJKmHSaG2kAGpudxuOf8ToDkhumF7UzME7DecbQE9uOZhNm7PuJg== + dependencies: + yallist "^4.0.0" + +minizlib@^2.1.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-2.1.2.tgz#e90d3466ba209b932451508a11ce3d3632145931" + integrity sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg== + dependencies: + minipass "^3.0.0" + yallist "^4.0.0" + mississippi@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/mississippi/-/mississippi-3.0.0.tgz#ea0a3291f97e0b5e8776b363d5f0a12d94c67022" @@ -4330,6 +4598,11 @@ mkdirp@^0.5.1: dependencies: minimist "0.0.8" +mkdirp@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" + integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== + mocha@^6.2.2, mocha@^8.2.1: version "8.2.1" resolved "https://registry.yarnpkg.com/mocha/-/mocha-8.2.1.tgz#f2fa68817ed0e53343d989df65ccd358bc3a4b39" @@ -4445,6 +4718,22 @@ node-fetch@^2.6.1: resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052" integrity sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw== +node-gyp@^7.1.2: + version "7.1.2" + resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-7.1.2.tgz#21a810aebb187120251c3bcec979af1587b188ae" + integrity sha512-CbpcIo7C3eMu3dL1c3d0xw449fHIGALIJsRP4DDPHpyiW8vcriNY7ubh9TE4zEKfSxscY7PjeFnshE7h75ynjQ== + dependencies: + env-paths "^2.2.0" + glob "^7.1.4" + graceful-fs "^4.2.3" + nopt "^5.0.0" + npmlog "^4.1.2" + request "^2.88.2" + rimraf "^3.0.2" + semver "^7.3.2" + tar "^6.0.2" + which "^2.0.2" + node-libs-browser@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/node-libs-browser/-/node-libs-browser-2.2.1.tgz#b64f513d18338625f90346d27b0d235e631f6425" @@ -4493,6 +4782,13 @@ node-releases@^1.1.49: dependencies: semver "^6.3.0" +nopt@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/nopt/-/nopt-5.0.0.tgz#530942bb58a512fccafe53fe210f13a25355dc88" + integrity sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ== + dependencies: + abbrev "1" + normalize-package-data@^2.3.2: version "2.5.0" resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8" @@ -4522,6 +4818,21 @@ npm-run-path@^2.0.0: dependencies: path-key "^2.0.0" +npmlog@^4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" + integrity sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg== + dependencies: + are-we-there-yet "~1.1.2" + console-control-strings "~1.1.0" + gauge "~2.7.3" + set-blocking "~2.0.0" + +number-is-nan@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" + integrity sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0= + nyc@^15.0.0: version "15.0.0" resolved "https://registry.yarnpkg.com/nyc/-/nyc-15.0.0.tgz#eb32db2c0f29242c2414fe46357f230121cfc162" @@ -4556,7 +4867,12 @@ nyc@^15.0.0: uuid "^3.3.3" yargs "^15.0.2" -object-assign@^4.1.1: +oauth-sign@~0.9.0: + version "0.9.0" + resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455" + integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ== + +object-assign@^4.1.0, object-assign@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= @@ -4922,6 +5238,11 @@ pbkdf2@^3.0.3, pbkdf2@^3.0.9: safe-buffer "^5.0.1" sha.js "^2.4.8" +performance-now@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" + integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns= + picomatch@^2.0.4, picomatch@^2.0.5, picomatch@^2.0.7: version "2.2.1" resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.2.1.tgz#21bac888b6ed8601f831ce7816e335bc779f0a4a" @@ -5034,6 +5355,11 @@ pseudomap@^1.0.2: resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" integrity sha1-8FKijacOYYkX7wqKw0wa5aaChrM= +psl@^1.1.28: + version "1.8.0" + resolved "https://registry.yarnpkg.com/psl/-/psl-1.8.0.tgz#9326f8bcfb013adcc005fdff056acce020e51c24" + integrity sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ== + public-encrypt@^4.0.0: version "4.0.3" resolved "https://registry.yarnpkg.com/public-encrypt/-/public-encrypt-4.0.3.tgz#4fcc9d77a07e48ba7527e7cbe0de33d0701331e0" @@ -5081,7 +5407,7 @@ punycode@^1.2.4: resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" integrity sha1-wNWmOycYgArY4esPpSachN1BhF4= -punycode@^2.1.0: +punycode@^2.1.0, punycode@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== @@ -5096,6 +5422,11 @@ qs@6.7.0: resolved "https://registry.yarnpkg.com/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc" integrity sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ== +qs@~6.5.2: + version "6.5.2" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" + integrity sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA== + querystring-es3@^0.2.0: version "0.2.1" resolved "https://registry.yarnpkg.com/querystring-es3/-/querystring-es3-0.2.1.tgz#9ec61f79049875707d69414596fd907a4d711e73" @@ -5153,7 +5484,7 @@ read-pkg@^2.0.0: normalize-package-data "^2.3.2" path-type "^2.0.0" -"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.3, readable-stream@^2.3.6, readable-stream@~2.3.6: +"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.6, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.3, readable-stream@^2.3.6, readable-stream@~2.3.6: version "2.3.7" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57" integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw== @@ -5281,6 +5612,32 @@ repeat-string@^1.6.1: resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" integrity sha1-jcrkcOHIirwtYA//Sndihtp15jc= +request@^2.88.2: + version "2.88.2" + resolved "https://registry.yarnpkg.com/request/-/request-2.88.2.tgz#d73c918731cb5a87da047e207234146f664d12b3" + integrity sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw== + dependencies: + aws-sign2 "~0.7.0" + aws4 "^1.8.0" + caseless "~0.12.0" + combined-stream "~1.0.6" + extend "~3.0.2" + forever-agent "~0.6.1" + form-data "~2.3.2" + har-validator "~5.1.3" + http-signature "~1.2.0" + is-typedarray "~1.0.0" + isstream "~0.1.2" + json-stringify-safe "~5.0.1" + mime-types "~2.1.19" + oauth-sign "~0.9.0" + performance-now "^2.1.0" + qs "~6.5.2" + safe-buffer "^5.1.2" + tough-cookie "~2.5.0" + tunnel-agent "^0.6.0" + uuid "^3.3.2" + require-directory@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" @@ -5370,7 +5727,7 @@ rimraf@^2.5.4, rimraf@^2.6.0, rimraf@^2.6.3: dependencies: glob "^7.1.3" -rimraf@^3.0.0: +rimraf@^3.0.0, rimraf@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== @@ -5423,7 +5780,7 @@ safe-regex@^1.1.0: dependencies: ret "~0.1.10" -"safer-buffer@>= 2.1.2 < 3": +"safer-buffer@>= 2.1.2 < 3", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0: version "2.1.2" resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== @@ -5452,6 +5809,11 @@ semver@^6.0.0, semver@^6.1.2, semver@^6.3.0: resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== +semver@^7.3.2: + version "7.3.2" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.2.tgz#604962b052b81ed0786aae84389ffba70ffd3938" + integrity sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ== + serialize-javascript@5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-5.0.1.tgz#7886ec848049a462467a97d3d918ebb2aaf934f4" @@ -5464,7 +5826,7 @@ serialize-javascript@^2.1.2: resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-2.1.2.tgz#ecec53b0e0317bdc95ef76ab7074b7384785fa61" integrity sha512-rs9OggEUF0V4jUSecXazOYsLfu7OGK2qIn3c7IPBiffz32XniEp/TX9Xmc9LQfK2nQ2QKHvZ2oygKUGU0lG4jQ== -set-blocking@^2.0.0: +set-blocking@^2.0.0, set-blocking@~2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc= @@ -5724,6 +6086,21 @@ sprintf-js@~1.0.2: resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= +sshpk@^1.7.0: + version "1.16.1" + resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.16.1.tgz#fb661c0bef29b39db40769ee39fa70093d6f6877" + integrity sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg== + dependencies: + asn1 "~0.2.3" + assert-plus "^1.0.0" + bcrypt-pbkdf "^1.0.0" + dashdash "^1.12.0" + ecc-jsbn "~0.1.1" + getpass "^0.1.1" + jsbn "~0.1.0" + safer-buffer "^2.0.2" + tweetnacl "~0.14.0" + ssri@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/ssri/-/ssri-6.0.1.tgz#2a3c41b28dd45b62b63676ecb74001265ae9edd8" @@ -5792,6 +6169,15 @@ streamroller@^1.0.6: fs-extra "^7.0.1" lodash "^4.17.14" +string-width@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" + integrity sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M= + dependencies: + code-point-at "^1.0.0" + is-fullwidth-code-point "^1.0.0" + strip-ansi "^3.0.0" + "string-width@^1.0.2 || 2": version "2.1.1" resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" @@ -5848,6 +6234,13 @@ string_decoder@~1.1.1: dependencies: safe-buffer "~5.1.0" +strip-ansi@^3.0.0, strip-ansi@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" + integrity sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8= + dependencies: + ansi-regex "^2.0.0" + strip-ansi@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" @@ -5937,6 +6330,18 @@ tapable@^1.0.0, tapable@^1.1.3: resolved "https://registry.yarnpkg.com/tapable/-/tapable-1.1.3.tgz#a1fccc06b58db61fd7a45da2da44f5f3a3e67ba2" integrity sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA== +tar@^6.0.2: + version "6.0.5" + resolved "https://registry.yarnpkg.com/tar/-/tar-6.0.5.tgz#bde815086e10b39f1dcd298e89d596e1535e200f" + integrity sha512-0b4HOimQHj9nXNEAA7zWwMM91Zhhba3pspja6sQbgTpynOJf+bkjBnfybNYzbpLbnwXnbyB4LOREvlyXLkCHSg== + dependencies: + chownr "^2.0.0" + fs-minipass "^2.0.0" + minipass "^3.0.0" + minizlib "^2.1.1" + mkdirp "^1.0.3" + yallist "^4.0.0" + terser-webpack-plugin@^1.4.3: version "1.4.3" resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-1.4.3.tgz#5ecaf2dbdc5fb99745fd06791f46fc9ddb1c9a7c" @@ -6059,6 +6464,14 @@ toidentifier@1.0.0: resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.0.tgz#7e1be3470f1e77948bc43d94a3c8f4d7752ba553" integrity sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw== +tough-cookie@~2.5.0: + version "2.5.0" + resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.5.0.tgz#cd9fb2a0aa1d5a12b473bd9fb96fa3dcff65ade2" + integrity sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g== + dependencies: + psl "^1.1.28" + punycode "^2.1.1" + triple-beam@^1.2.0, triple-beam@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/triple-beam/-/triple-beam-1.3.0.tgz#a595214c7298db8339eeeee083e4d10bd8cb8dd9" @@ -6103,6 +6516,18 @@ tty-browserify@0.0.0: resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.0.tgz#a157ba402da24e9bf957f9aa69d524eed42901a6" integrity sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY= +tunnel-agent@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" + integrity sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0= + dependencies: + safe-buffer "^5.0.1" + +tweetnacl@^0.14.3, tweetnacl@~0.14.0: + version "0.14.5" + resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" + integrity sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q= + type-check@~0.3.2: version "0.3.2" resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" @@ -6318,6 +6743,15 @@ validate-npm-package-license@^3.0.1: spdx-correct "^3.0.0" spdx-expression-parse "^3.0.0" +verror@1.10.0: + version "1.10.0" + resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" + integrity sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA= + dependencies: + assert-plus "^1.0.0" + core-util-is "1.0.2" + extsprintf "^1.2.0" + vm-browserify@^1.0.1: version "1.1.2" resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-1.1.2.tgz#78641c488b8e6ca91a75f511e7a3b32a86e5dda0" @@ -6415,7 +6849,7 @@ which-module@^2.0.0: resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" integrity sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho= -which@2.0.2, which@^2.0.1: +which@2.0.2, which@^2.0.1, which@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== @@ -6429,7 +6863,7 @@ which@^1.2.1, which@^1.2.14, which@^1.2.9, which@^1.3.1: dependencies: isexe "^2.0.0" -wide-align@1.1.3: +wide-align@1.1.3, wide-align@^1.1.0: version "1.1.3" resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457" integrity sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA== @@ -6555,6 +6989,11 @@ yallist@^3.0.2: resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== +yallist@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" + integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== + yargs-parser@13.1.2, yargs-parser@^13.1.2: version "13.1.2" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-13.1.2.tgz#130f09702ebaeef2650d54ce6e3e5706f7a4fb38"