Merge remote-tracking branch 'origin/master' into cayman/style-guide
# Conflicts: # .eslintrc # package.json # packages/bls/src/@types/keccak256/index.d.ts # packages/bls/src/helpers/g1point.ts # packages/bls/src/helpers/g2point.ts # packages/bls/src/index.ts # packages/bls/src/privateKey.ts # packages/bls/test/spec/spec-tests # packages/eth2.0-types/src/validator.ts # packages/eth2.0-types/src/wire.ts # packages/lodestar/package.json # packages/lodestar/src/api/rpc/api/beacon/beacon.ts # packages/lodestar/src/api/rpc/api/beacon/interface.ts # packages/lodestar/src/api/rpc/api/validator/interface.ts # packages/lodestar/src/api/rpc/transport/http.ts # packages/lodestar/src/api/rpc/transport/ws.ts # packages/lodestar/src/chain/chain.ts # packages/lodestar/src/chain/factory/attestation/index.ts # packages/lodestar/src/chain/factory/block/eth1Data.ts # packages/lodestar/src/chain/factory/duties/index.ts # packages/lodestar/src/chain/forkChoice/interface.ts # packages/lodestar/src/chain/forkChoice/statefulDag/lmdGhost.ts # packages/lodestar/src/chain/stateTransition/block/randao.ts # packages/lodestar/src/chain/stateTransition/util/attestation.ts # packages/lodestar/src/chain/stateTransition/util/domain.ts # packages/lodestar/src/cli/commands/beacon.ts # packages/lodestar/src/cli/commands/create-config.ts # packages/lodestar/src/cli/commands/deposit.ts # packages/lodestar/src/cli/commands/eth1-private-network.ts # packages/lodestar/src/cli/commands/validator.ts # packages/lodestar/src/cli/commands/wallet.ts # packages/lodestar/src/db/api/beacon/interface.ts # packages/lodestar/src/db/api/validator/interface.ts # packages/lodestar/src/db/api/validator/validator.ts # packages/lodestar/src/db/controller/impl/level.ts # packages/lodestar/src/eth1/dev/network.ts # packages/lodestar/src/eth1/impl/ethers.ts # packages/lodestar/src/logger/abstract.ts # packages/lodestar/src/logger/winston.ts # packages/lodestar/src/network/codec.ts # packages/lodestar/src/network/gossip.ts # packages/lodestar/src/network/interface.ts # packages/lodestar/src/network/libp2p/peer.ts # packages/lodestar/src/network/libp2p/rpc.ts # packages/lodestar/src/network/libp2p/syncRpc.ts # packages/lodestar/src/network/libp2p/util.ts # packages/lodestar/src/node/nodejs.ts # packages/lodestar/src/rpc/api/interface.ts # packages/lodestar/src/rpc/api/validator/validator.ts # packages/lodestar/src/rpc/options.ts # packages/lodestar/src/rpc/protocol/jsonRpc.ts # packages/lodestar/src/sync/index.ts # packages/lodestar/src/sync/initial.ts # packages/lodestar/src/sync/regular.ts # packages/lodestar/src/sync/rpc/interface.ts # packages/lodestar/src/util/bytes.ts # packages/lodestar/src/util/io.ts # packages/lodestar/src/util/merkleTree/merkleTree.ts # packages/lodestar/src/validator/options.ts # packages/lodestar/src/validator/rpc/abstract.ts # packages/lodestar/src/validator/services/attestation.ts # packages/lodestar/src/validator/services/block.ts # packages/lodestar/src/validator/validator.ts # packages/lodestar/test/e2e/sync/reqResp.test.ts # packages/lodestar/test/unit/sync/index.test.ts # packages/lodestar/test/unit/sync/rpc.test.ts # packages/ssz/src/hashTreeRoot.ts # packages/ssz/test/unit/hashTreeRoot.test.ts # yarn.lock
This commit is contained in:
commit
6143104204
7
.babelrc
7
.babelrc
|
@ -1,3 +1,8 @@
|
||||||
{
|
{
|
||||||
"extends": "../../.babelrc"
|
"extends": "../../.babelrc",
|
||||||
|
"plugins": [
|
||||||
|
"@babel/proposal-class-properties",
|
||||||
|
"@babel/proposal-object-rest-spread",
|
||||||
|
"rewire-exports"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,3 +64,4 @@ typings/
|
||||||
|
|
||||||
dist/
|
dist/
|
||||||
lib/
|
lib/
|
||||||
|
benchmark-reports
|
||||||
|
|
14
package.json
14
package.json
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@chainsafe/bls",
|
"name": "@chainsafe/bls",
|
||||||
"version": "0.1.6",
|
"version": "0.1.7",
|
||||||
"description": "Implementation of bls signature verification for ethereum 2.0",
|
"description": "Implementation of bls signature verification for ethereum 2.0",
|
||||||
"main": "lib/index.js",
|
"main": "lib/index.js",
|
||||||
"types": "lib/index.d.ts",
|
"types": "lib/index.d.ts",
|
||||||
|
@ -27,12 +27,15 @@
|
||||||
"lint:fix": "eslint --ext .ts src/ --fix",
|
"lint:fix": "eslint --ext .ts src/ --fix",
|
||||||
"pretest": "yarn check-types",
|
"pretest": "yarn check-types",
|
||||||
"prepublishOnly": "yarn build",
|
"prepublishOnly": "yarn build",
|
||||||
"test:unit": "nyc --cache-dir .nyc_output/.cache -r lcov -e .ts mocha -r ./.babel-register 'test/unit/**/*.test.ts' && nyc report",
|
"test:unit": "nyc --cache-dir .nyc_output/.cache -r lcov -e .ts mocha --colors -r ./.babel-register 'test/unit/**/*.test.ts' && nyc report",
|
||||||
"test:spec": "mocha -r ./.babel-register 'test/spec/**/*.test.ts'",
|
"test:spec": "mocha --colors -r ./.babel-register 'test/spec/**/*.test.ts'",
|
||||||
|
"test:spec-min": "yarn run test:spec",
|
||||||
"test": "yarn test:unit && yarn test:spec",
|
"test": "yarn test:unit && yarn test:spec",
|
||||||
"coverage": "codecov -F bls"
|
"coverage": "codecov -F bls",
|
||||||
|
"benchmark": "node -r ./.babel-register test/benchmarks"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@chainsafe/eth2.0-types": "^0.1.0",
|
||||||
"@chainsafe/milagro-crypto-js": "0.1.3",
|
"@chainsafe/milagro-crypto-js": "0.1.3",
|
||||||
"assert": "^1.4.1",
|
"assert": "^1.4.1",
|
||||||
"js-sha256": "^0.9.0",
|
"js-sha256": "^0.9.0",
|
||||||
|
@ -48,11 +51,12 @@
|
||||||
"@babel/preset-typescript": "^7.3.3",
|
"@babel/preset-typescript": "^7.3.3",
|
||||||
"@babel/register": "^7.0.0",
|
"@babel/register": "^7.0.0",
|
||||||
"@babel/runtime": "^7.4.4",
|
"@babel/runtime": "^7.4.4",
|
||||||
|
"@chainsafe/benchmark-utils": "^0.1.0",
|
||||||
"@chainsafe/eth2.0-spec-test-util": "^0.2.3",
|
"@chainsafe/eth2.0-spec-test-util": "^0.2.3",
|
||||||
"@types/assert": "^1.4.2",
|
"@types/assert": "^1.4.2",
|
||||||
"@types/chai": "^4.1.7",
|
"@types/chai": "^4.1.7",
|
||||||
"@types/mocha": "^5.2.5",
|
"@types/mocha": "^5.2.5",
|
||||||
"@types/node": "^10.12.17",
|
"@types/node": "^12.7.2",
|
||||||
"@typescript-eslint/eslint-plugin": "^1.3.0",
|
"@typescript-eslint/eslint-plugin": "^1.3.0",
|
||||||
"@typescript-eslint/parser": "^1.3.0",
|
"@typescript-eslint/parser": "^1.3.0",
|
||||||
"babel-plugin-rewire-exports": "^1.1.0",
|
"babel-plugin-rewire-exports": "^1.1.0",
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
declare module "keccak256" {
|
|
||||||
|
|
||||||
export default function hash(a: Buffer | (Buffer | string | number)[]): Buffer;
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,11 +1,11 @@
|
||||||
import {BIG} from "@chainsafe/milagro-crypto-js/src/big";
|
import {BIG} from "@chainsafe/milagro-crypto-js/src/big";
|
||||||
import {ECP} from "@chainsafe/milagro-crypto-js/src/ecp";
|
import {ECP} from "@chainsafe/milagro-crypto-js/src/ecp";
|
||||||
import ctx from "../ctx";
|
import ctx from "../ctx";
|
||||||
import {bytes48} from "../types";
|
|
||||||
import assert from "assert";
|
import assert from "assert";
|
||||||
import {calculateYFlag, getModulus} from "./utils";
|
import {calculateYFlag, getModulus} from "./utils";
|
||||||
import * as random from "secure-random";
|
import * as random from "secure-random";
|
||||||
import {FP_POINT_LENGTH} from "../constants";
|
import {FP_POINT_LENGTH} from "../constants";
|
||||||
|
import {BLSPubkey, bytes48} from "@chainsafe/eth2.0-types";
|
||||||
|
|
||||||
export class G1point {
|
export class G1point {
|
||||||
|
|
||||||
|
@ -15,6 +15,50 @@ export class G1point {
|
||||||
this.point = point;
|
this.point = point;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public mul(value: BIG): G1point {
|
||||||
|
const newPoint = this.point.mul(value);
|
||||||
|
return new G1point(newPoint);
|
||||||
|
}
|
||||||
|
|
||||||
|
public add(other: G1point): G1point {
|
||||||
|
const sum = new ctx.ECP();
|
||||||
|
sum.add(this.point);
|
||||||
|
sum.add(other.point);
|
||||||
|
sum.affine();
|
||||||
|
return new G1point(sum);
|
||||||
|
}
|
||||||
|
|
||||||
|
public addRaw(other: bytes48): G1point {
|
||||||
|
return this.add(G1point.fromBytesCompressed(other));
|
||||||
|
}
|
||||||
|
|
||||||
|
public equal(other: G1point): boolean {
|
||||||
|
return this.point.equals(other.point);
|
||||||
|
}
|
||||||
|
|
||||||
|
public toBytes(): bytes48 {
|
||||||
|
const buffer = Buffer.alloc(FP_POINT_LENGTH, 0);
|
||||||
|
this.point.getX().tobytearray(buffer, 0);
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getPoint(): ECP {
|
||||||
|
return this.point;
|
||||||
|
}
|
||||||
|
|
||||||
|
public toBytesCompressed(): bytes48 {
|
||||||
|
const output = this.toBytes();
|
||||||
|
const c = true;
|
||||||
|
const b = this.point.is_infinity();
|
||||||
|
const a = !b && calculateYFlag(this.point.getY());
|
||||||
|
|
||||||
|
const flags = ((a ? 1 << 5 : 0) | (b ? 1 << 6 : 0) | (c ? 1 << 7 : 0));
|
||||||
|
const mask = 31;
|
||||||
|
output[0] &= mask;
|
||||||
|
output[0] |= flags;
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
public static fromBytesCompressed(value: bytes48): G1point {
|
public static fromBytesCompressed(value: bytes48): G1point {
|
||||||
assert(value.length === FP_POINT_LENGTH, `Expected g1 compressed input to have ${FP_POINT_LENGTH} bytes`);
|
assert(value.length === FP_POINT_LENGTH, `Expected g1 compressed input to have ${FP_POINT_LENGTH} bytes`);
|
||||||
value = Buffer.from(value);
|
value = Buffer.from(value);
|
||||||
|
@ -62,6 +106,14 @@ export class G1point {
|
||||||
return new G1point(point);
|
return new G1point(point);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static aggregate(values: bytes48[]): G1point {
|
||||||
|
return values.map((value) => {
|
||||||
|
return G1point.fromBytesCompressed(value);
|
||||||
|
}).reduce((previousValue, currentValue): G1point => {
|
||||||
|
return previousValue.add(currentValue);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
public static generator(): G1point {
|
public static generator(): G1point {
|
||||||
return new G1point(ctx.ECP.generator());
|
return new G1point(ctx.ECP.generator());
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
import {BIG} from "@chainsafe/milagro-crypto-js/src/big";
|
import {BIG} from "@chainsafe/milagro-crypto-js/src/big";
|
||||||
import {ECP2} from "@chainsafe/milagro-crypto-js/src/ecp2";
|
import {ECP2} from "@chainsafe/milagro-crypto-js/src/ecp2";
|
||||||
import {BLSDomain, bytes32, bytes96} from "../types";
|
import {sha256} from 'js-sha256';
|
||||||
import {sha256} from "js-sha256";
|
|
||||||
import ctx from "../ctx";
|
import ctx from "../ctx";
|
||||||
import * as random from "secure-random";
|
import * as random from "secure-random";
|
||||||
import {calculateYFlag, getModulus, padLeft} from "./utils";
|
import {calculateYFlag, getModulus, padLeft} from "./utils";
|
||||||
import assert from "assert";
|
import assert from "assert";
|
||||||
import {FP_POINT_LENGTH, G2_HASH_PADDING} from "../constants";
|
import {FP_POINT_LENGTH, G2_HASH_PADDING} from "../constants";
|
||||||
|
import {bytes48, Domain, Hash} from "@chainsafe/eth2.0-types";
|
||||||
|
|
||||||
export class G2point {
|
export class G2point {
|
||||||
|
|
||||||
|
@ -16,8 +16,49 @@ export class G2point {
|
||||||
this.point = point;
|
this.point = point;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public add(other: G2point): G2point {
|
||||||
|
const sum = new ctx.ECP2();
|
||||||
|
sum.add(this.point);
|
||||||
|
sum.add(other.point);
|
||||||
|
sum.affine();
|
||||||
|
return new G2point(sum);
|
||||||
|
}
|
||||||
|
|
||||||
public static hashToG2(message: bytes32, domain: BLSDomain): G2point {
|
public mul(value: BIG): G2point {
|
||||||
|
const newPoint = this.point.mul(value);
|
||||||
|
return new G2point(newPoint);
|
||||||
|
}
|
||||||
|
|
||||||
|
public equal(other: G2point): boolean {
|
||||||
|
return this.point.equals(other.point);
|
||||||
|
}
|
||||||
|
|
||||||
|
public getPoint(): ECP2 {
|
||||||
|
return this.point;
|
||||||
|
}
|
||||||
|
|
||||||
|
public toBytesCompressed(): bytes48 {
|
||||||
|
const xReBytes = Buffer.alloc(FP_POINT_LENGTH, 0);
|
||||||
|
const xImBytes = Buffer.alloc(FP_POINT_LENGTH, 0);
|
||||||
|
this.point.getX().getA().tobytearray(xReBytes, 0);
|
||||||
|
this.point.getX().getB().tobytearray(xImBytes, 0);
|
||||||
|
const c1 = true;
|
||||||
|
const b1 = this.point.is_infinity();
|
||||||
|
const a1 = !b1 && calculateYFlag(this.point.getY().getB());
|
||||||
|
|
||||||
|
const flags = ((a1 ? 1 << 5 : 0) | (b1 ? 1 << 6 : 0) | (c1 ? 1 << 7 : 0));
|
||||||
|
const mask = 31;
|
||||||
|
xImBytes[0] &= mask;
|
||||||
|
xImBytes[0] |= flags;
|
||||||
|
xReBytes[0] &= mask;
|
||||||
|
|
||||||
|
return Buffer.concat([
|
||||||
|
xImBytes,
|
||||||
|
xReBytes
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static hashToG2(message: Hash, domain: Domain): G2point {
|
||||||
const padding = Buffer.alloc(G2_HASH_PADDING, 0);
|
const padding = Buffer.alloc(G2_HASH_PADDING, 0);
|
||||||
const xReBytes = Buffer.concat([
|
const xReBytes = Buffer.concat([
|
||||||
padding,
|
padding,
|
||||||
|
@ -53,8 +94,8 @@ export class G2point {
|
||||||
return new G2point(G2point.scaleWithCofactor(G2point.normaliseY(point)));
|
return new G2point(G2point.scaleWithCofactor(G2point.normaliseY(point)));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static fromCompressedBytes(value: bytes96): G2point {
|
public static fromCompressedBytes(value: bytes48): G2point {
|
||||||
assert(value.length === 2 * FP_POINT_LENGTH, "Expected signature of 96 bytes");
|
assert(value.length === 2 * FP_POINT_LENGTH, 'Expected signature of 96 bytes');
|
||||||
value = Buffer.from(value);
|
value = Buffer.from(value);
|
||||||
const xImBytes = value.slice(0, FP_POINT_LENGTH);
|
const xImBytes = value.slice(0, FP_POINT_LENGTH);
|
||||||
const xReBytes = value.slice(FP_POINT_LENGTH);
|
const xReBytes = value.slice(FP_POINT_LENGTH);
|
||||||
|
|
89
src/index.ts
89
src/index.ts
|
@ -1,11 +1,3 @@
|
||||||
import {
|
|
||||||
BLSDomain,
|
|
||||||
BLSSecretKey,
|
|
||||||
BLSPubkey,
|
|
||||||
BLSSignature,
|
|
||||||
bytes32,
|
|
||||||
bytes8
|
|
||||||
} from "./types";
|
|
||||||
import {Keypair} from "./keypair";
|
import {Keypair} from "./keypair";
|
||||||
import {PrivateKey} from "./privateKey";
|
import {PrivateKey} from "./privateKey";
|
||||||
import {G2point} from "./helpers/g2point";
|
import {G2point} from "./helpers/g2point";
|
||||||
|
@ -14,11 +6,14 @@ import {PublicKey} from "./publicKey";
|
||||||
import {Signature} from "./signature";
|
import {Signature} from "./signature";
|
||||||
import {ElipticCurvePairing} from "./helpers/ec-pairing";
|
import {ElipticCurvePairing} from "./helpers/ec-pairing";
|
||||||
import ctx from "./ctx";
|
import ctx from "./ctx";
|
||||||
|
import {BLSPubkey, BLSSecretKey, BLSSignature, Domain, Hash} from "@chainsafe/eth2.0-types";
|
||||||
|
|
||||||
|
export {Keypair, PrivateKey, PublicKey, Signature};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates new secret and public key
|
* Generates new secret and public key
|
||||||
*/
|
*/
|
||||||
function generateKeyPair(): Keypair {
|
export function generateKeyPair(): Keypair {
|
||||||
return Keypair.generate();
|
return Keypair.generate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,7 +21,7 @@ function generateKeyPair(): Keypair {
|
||||||
* Generates public key from given secret.
|
* Generates public key from given secret.
|
||||||
* @param {BLSSecretKey} secretKey
|
* @param {BLSSecretKey} secretKey
|
||||||
*/
|
*/
|
||||||
function generatePublicKey(secretKey: BLSSecretKey): BLSPubkey {
|
export function generatePublicKey(secretKey: BLSSecretKey): BLSPubkey {
|
||||||
const keypair = new Keypair(PrivateKey.fromBytes(secretKey));
|
const keypair = new Keypair(PrivateKey.fromBytes(secretKey));
|
||||||
return keypair.publicKey.toBytesCompressed();
|
return keypair.publicKey.toBytesCompressed();
|
||||||
}
|
}
|
||||||
|
@ -37,7 +32,7 @@ function generatePublicKey(secretKey: BLSSecretKey): BLSPubkey {
|
||||||
* @param messageHash
|
* @param messageHash
|
||||||
* @param domain
|
* @param domain
|
||||||
*/
|
*/
|
||||||
function sign(secretKey: BLSSecretKey, messageHash: bytes32, domain: BLSDomain): BLSSignature {
|
export function sign(secretKey: BLSSecretKey, messageHash: Hash, domain: Domain): BLSSignature {
|
||||||
const privateKey = PrivateKey.fromBytes(secretKey);
|
const privateKey = PrivateKey.fromBytes(secretKey);
|
||||||
const hash = G2point.hashToG2(messageHash, domain);
|
const hash = G2point.hashToG2(messageHash, domain);
|
||||||
return privateKey.sign(hash).toBytesCompressed();
|
return privateKey.sign(hash).toBytesCompressed();
|
||||||
|
@ -47,7 +42,7 @@ function sign(secretKey: BLSSecretKey, messageHash: bytes32, domain: BLSDomain):
|
||||||
* Compines all given signature into one.
|
* Compines all given signature into one.
|
||||||
* @param signatures
|
* @param signatures
|
||||||
*/
|
*/
|
||||||
function aggregateSignatures(signatures: BLSSignature[]): BLSSignature {
|
export function aggregateSignatures(signatures: BLSSignature[]): BLSSignature {
|
||||||
return signatures.map((signature): Signature => {
|
return signatures.map((signature): Signature => {
|
||||||
return Signature.fromCompressedBytes(signature);
|
return Signature.fromCompressedBytes(signature);
|
||||||
}).reduce((previousValue, currentValue): Signature => {
|
}).reduce((previousValue, currentValue): Signature => {
|
||||||
|
@ -59,15 +54,11 @@ function aggregateSignatures(signatures: BLSSignature[]): BLSSignature {
|
||||||
* Combines all given public keys into single one
|
* Combines all given public keys into single one
|
||||||
* @param publicKeys
|
* @param publicKeys
|
||||||
*/
|
*/
|
||||||
function aggregatePubkeys(publicKeys: BLSPubkey[]): BLSPubkey {
|
export function aggregatePubkeys(publicKeys: BLSPubkey[]): BLSPubkey {
|
||||||
if(publicKeys.length === 0) {
|
if(publicKeys.length === 0) {
|
||||||
return new G1point(new ctx.ECP()).toBytesCompressed();
|
return new G1point(new ctx.ECP()).toBytesCompressed();
|
||||||
}
|
}
|
||||||
return publicKeys.map((publicKey): G1point => {
|
return G1point.aggregate(publicKeys).toBytesCompressed();
|
||||||
return G1point.fromBytesCompressed(publicKey);
|
|
||||||
}).reduce((previousValue, currentValue): G1point => {
|
|
||||||
return previousValue.add(currentValue);
|
|
||||||
}).toBytesCompressed();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -77,11 +68,13 @@ function aggregatePubkeys(publicKeys: BLSPubkey[]): BLSPubkey {
|
||||||
* @param signature
|
* @param signature
|
||||||
* @param domain
|
* @param domain
|
||||||
*/
|
*/
|
||||||
function verify(publicKey: BLSPubkey, messageHash: bytes32, signature: BLSSignature, domain: bytes8): boolean {
|
export function verify(publicKey: BLSPubkey, messageHash: Hash, signature: BLSSignature, domain: Domain): boolean {
|
||||||
try {
|
try {
|
||||||
const key = PublicKey.fromBytes(publicKey);
|
const key = PublicKey.fromBytes(publicKey);
|
||||||
const sig = Signature.fromCompressedBytes(signature);
|
const sig = Signature.fromCompressedBytes(signature);
|
||||||
|
|
||||||
|
key.getPoint().getPoint().affine();
|
||||||
|
sig.getPoint().getPoint().affine();
|
||||||
const g1Generated = G1point.generator();
|
const g1Generated = G1point.generator();
|
||||||
const e1 = ElipticCurvePairing.pair(key.getPoint(), G2point.hashToG2(messageHash, domain));
|
const e1 = ElipticCurvePairing.pair(key.getPoint(), G2point.hashToG2(messageHash, domain));
|
||||||
const e2 = ElipticCurvePairing.pair(g1Generated, sig.getPoint());
|
const e2 = ElipticCurvePairing.pair(g1Generated, sig.getPoint());
|
||||||
|
@ -98,28 +91,52 @@ function verify(publicKey: BLSPubkey, messageHash: bytes32, signature: BLSSignat
|
||||||
* @param signature
|
* @param signature
|
||||||
* @param domain
|
* @param domain
|
||||||
*/
|
*/
|
||||||
function verifyMultiple(
|
export function verifyMultiple(publicKeys: BLSPubkey[], messageHashes: Hash[], signature: BLSSignature, domain: Domain): boolean {
|
||||||
publicKeys: BLSPubkey[],
|
|
||||||
messageHashes: bytes32[],
|
|
||||||
signature: BLSSignature,
|
|
||||||
domain: bytes8
|
|
||||||
): boolean {
|
|
||||||
if(publicKeys.length === 0 || publicKeys.length != messageHashes.length) {
|
if(publicKeys.length === 0 || publicKeys.length != messageHashes.length) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
const g1Generated = G1point.generator();
|
const sig = Signature.fromCompressedBytes(signature).getPoint();
|
||||||
|
sig.getPoint().affine();
|
||||||
|
|
||||||
const eCombined = new ctx.FP12(1);
|
const eCombined = new ctx.FP12(1);
|
||||||
publicKeys.forEach((publicKey, index): void => {
|
|
||||||
const g2 = G2point.hashToG2(messageHashes[index], domain);
|
const reduction = messageHashes.reduce((previous, current, index) => {
|
||||||
eCombined.mul(
|
if(previous.hash && current.equals(previous.hash)) {
|
||||||
ElipticCurvePairing.pair(
|
return {
|
||||||
PublicKey.fromBytes(publicKey).getPoint(),
|
hash: previous.hash,
|
||||||
g2
|
publicKey: previous.publicKey ?
|
||||||
)
|
previous.publicKey.addRaw(publicKeys[index])
|
||||||
);
|
:
|
||||||
});
|
G1point.fromBytesCompressed(publicKeys[index]),
|
||||||
const e2 = ElipticCurvePairing.pair(g1Generated, Signature.fromCompressedBytes(signature).getPoint());
|
};
|
||||||
|
} else if(!!previous.hash) {
|
||||||
|
const g2 = G2point.hashToG2(previous.hash, domain);
|
||||||
|
eCombined.mul(
|
||||||
|
ElipticCurvePairing.pair(
|
||||||
|
previous.publicKey,
|
||||||
|
g2
|
||||||
|
)
|
||||||
|
);
|
||||||
|
return {hash: current, publicKey: G1point.fromBytesCompressed(publicKeys[index])};
|
||||||
|
} else {
|
||||||
|
return {
|
||||||
|
hash: current,
|
||||||
|
publicKey: G1point.fromBytesCompressed(publicKeys[index])
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}, {hash: null, publicKey: null});
|
||||||
|
|
||||||
|
const g2Final = G2point.hashToG2(reduction.hash, domain);
|
||||||
|
const keyFinal = reduction.publicKey;
|
||||||
|
eCombined.mul(
|
||||||
|
ElipticCurvePairing.pair(
|
||||||
|
keyFinal,
|
||||||
|
g2Final
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
const e2 = ElipticCurvePairing.pair(G1point.generator(), sig);
|
||||||
return e2.equals(eCombined);
|
return e2.equals(eCombined);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -5,7 +5,7 @@ import ctx from "./ctx";
|
||||||
import {padLeft} from "./helpers/utils";
|
import {padLeft} from "./helpers/utils";
|
||||||
import {G2point} from "./helpers/g2point";
|
import {G2point} from "./helpers/g2point";
|
||||||
import * as random from "secure-random";
|
import * as random from "secure-random";
|
||||||
import {BLSDomain, BLSSecretKey, bytes32} from "./types";
|
import {BLSSecretKey, Hash, Domain} from "@chainsafe/eth2.0-types";
|
||||||
|
|
||||||
export class PrivateKey {
|
export class PrivateKey {
|
||||||
|
|
||||||
|
@ -15,9 +15,30 @@ export class PrivateKey {
|
||||||
this.value = value;
|
this.value = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public getValue(): BIG {
|
||||||
|
return this.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public sign(message: G2point): G2point {
|
||||||
|
return message.mul(this.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public signMessage(message: Hash, domain: Domain): G2point {
|
||||||
|
return G2point.hashToG2(message, domain).mul(this.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public toBytes(): BLSSecretKey {
|
||||||
|
const buffer = Buffer.alloc(FP_POINT_LENGTH, 0);
|
||||||
|
this.value.tobytearray(buffer, 0);
|
||||||
|
return buffer.slice(FP_POINT_LENGTH - SECRET_KEY_LENGTH);
|
||||||
|
}
|
||||||
|
|
||||||
|
public toHexString(): string {
|
||||||
|
return `0x${this.toBytes().toString('hex')}`;
|
||||||
|
}
|
||||||
|
|
||||||
public static fromBytes(bytes: Uint8Array): PrivateKey {
|
public static fromBytes(bytes: Uint8Array): PrivateKey {
|
||||||
assert(bytes.length === SECRET_KEY_LENGTH, "Private key should have 32 bytes");
|
assert(bytes.length === SECRET_KEY_LENGTH, 'Private key should have 32 bytes');
|
||||||
const value = Buffer.from(bytes);
|
const value = Buffer.from(bytes);
|
||||||
return new PrivateKey(
|
return new PrivateKey(
|
||||||
ctx.BIG.frombytearray(
|
ctx.BIG.frombytearray(
|
||||||
|
@ -32,7 +53,7 @@ export class PrivateKey {
|
||||||
|
|
||||||
public static fromHexString(value: string): PrivateKey {
|
public static fromHexString(value: string): PrivateKey {
|
||||||
return PrivateKey.fromBytes(
|
return PrivateKey.fromBytes(
|
||||||
Buffer.from(value.replace("0x", ""), "hex")
|
Buffer.from(value.replace('0x', ''), 'hex')
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,26 +61,4 @@ export class PrivateKey {
|
||||||
return PrivateKey.fromBytes(random.randomBuffer(SECRET_KEY_LENGTH));
|
return PrivateKey.fromBytes(random.randomBuffer(SECRET_KEY_LENGTH));
|
||||||
}
|
}
|
||||||
|
|
||||||
public getValue(): BIG {
|
|
||||||
return this.value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public sign(message: G2point): G2point {
|
|
||||||
return message.mul(this.value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public signMessage(message: bytes32, domain: BLSDomain): G2point {
|
|
||||||
return G2point.hashToG2(message, domain).mul(this.value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public toBytes(): BLSSecretKey {
|
|
||||||
const buffer = Buffer.alloc(FP_POINT_LENGTH, 0);
|
|
||||||
this.value.tobytearray(buffer, 0);
|
|
||||||
return buffer.slice(FP_POINT_LENGTH - SECRET_KEY_LENGTH);
|
|
||||||
}
|
|
||||||
|
|
||||||
public toHexString(): string {
|
|
||||||
return `0x${this.toBytes().toString("hex")}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import {G1point} from "./helpers/g1point";
|
import {G1point} from "./helpers/g1point";
|
||||||
import {PrivateKey} from "./privateKey";
|
import {PrivateKey} from "./privateKey";
|
||||||
import {BLSPubkey} from "./types";
|
import {BLSPubkey} from "@chainsafe/eth2.0-types";
|
||||||
|
|
||||||
export class PublicKey {
|
export class PublicKey {
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import {G2point} from "./helpers/g2point";
|
import {G2point} from "./helpers/g2point";
|
||||||
import {BLSSignature} from "./types";
|
|
||||||
import assert from "assert";
|
import assert from "assert";
|
||||||
import {FP_POINT_LENGTH} from "./constants";
|
import {FP_POINT_LENGTH} from "./constants";
|
||||||
|
import {BLSSignature} from "@chainsafe/eth2.0-types";
|
||||||
|
|
||||||
export class Signature {
|
export class Signature {
|
||||||
|
|
||||||
|
|
|
@ -1,9 +0,0 @@
|
||||||
export type bytes8 = Buffer;
|
|
||||||
export type bytes32 = Buffer;
|
|
||||||
export type bytes48 = Buffer;
|
|
||||||
export type bytes96 = Buffer;
|
|
||||||
|
|
||||||
export type BLSDomain = bytes8;
|
|
||||||
export type BLSPubkey = bytes48;
|
|
||||||
export type BLSSecretKey = bytes32;
|
|
||||||
export type BLSSignature = bytes96;
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
// Import benchmarks
|
||||||
|
import * as suites from "./suites";
|
||||||
|
import {createReportDir, runSuite} from "@chainsafe/benchmark-utils";
|
||||||
|
// Create file
|
||||||
|
const directory: string = createReportDir();
|
||||||
|
|
||||||
|
|
||||||
|
// Run benchmarks
|
||||||
|
Object.values(suites).forEach((suite) => {
|
||||||
|
runSuite(suite(directory));
|
||||||
|
});
|
|
@ -0,0 +1,5 @@
|
||||||
|
// export {verifyInValidSignatureBenchmark} from './verifyInValidSignature';
|
||||||
|
// export {verifyValidSignatureBenchmark} from './verifyValidSignature';
|
||||||
|
export {verifyValidAggregatedSignature} from './verifyValidAggregatedSignature';
|
||||||
|
// export {verifyInvalidAggregatedSignature} from './verifyInvalidAggregatedSignature';
|
||||||
|
// export {aggregateSignaturesBenchmark} from './signatureAggregation';
|
|
@ -0,0 +1,39 @@
|
||||||
|
/* eslint-disable @typescript-eslint/no-require-imports,@typescript-eslint/no-var-requires */
|
||||||
|
|
||||||
|
import {BenchSuite} from "@chainsafe/benchmark-utils";
|
||||||
|
import {aggregateSignatures} from "../../../src";
|
||||||
|
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-namespace
|
||||||
|
declare namespace global {
|
||||||
|
export let signatures: Buffer[];
|
||||||
|
export let aggregateSignatures: Function;
|
||||||
|
}
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
|
global.require = require;
|
||||||
|
|
||||||
|
global.aggregateSignatures = aggregateSignatures;
|
||||||
|
|
||||||
|
export function aggregateSignaturesBenchmark(dir: string): BenchSuite {
|
||||||
|
|
||||||
|
// Set the function test
|
||||||
|
const FUNCTION_NAME = "verifyValidSignature"; // PLEASE FILL THIS OUT
|
||||||
|
|
||||||
|
const aggregateSignatures = function (): void {
|
||||||
|
global.aggregateSignatures(global.signatures);
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
testFunctions: [aggregateSignatures],
|
||||||
|
setup: function() {
|
||||||
|
global.signatures = [];
|
||||||
|
const {Keypair} = require("../../../src");
|
||||||
|
const {sha256} = require('js-sha256');
|
||||||
|
const keypair = Keypair.generate();
|
||||||
|
const message = Buffer.from(sha256.arrayBuffer(Math.random().toString(36)));
|
||||||
|
global.signatures.push(keypair.privateKey.signMessage(Buffer.from(message), Buffer.alloc(8)).toBytesCompressed());
|
||||||
|
},
|
||||||
|
file: dir + FUNCTION_NAME + ".txt"
|
||||||
|
};
|
||||||
|
}
|
|
@ -0,0 +1,42 @@
|
||||||
|
import {BenchSuite} from "@chainsafe/benchmark-utils";
|
||||||
|
import {verify} from "../../../src";
|
||||||
|
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-namespace
|
||||||
|
declare namespace global {
|
||||||
|
export let domain: Buffer;
|
||||||
|
export let message: Buffer;
|
||||||
|
export let signature: Buffer;
|
||||||
|
export let publicKey: Buffer;
|
||||||
|
export let verify: Function;
|
||||||
|
}
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
|
global.require = require;
|
||||||
|
|
||||||
|
global.domain = Buffer.alloc(8);
|
||||||
|
global.verify = verify;
|
||||||
|
|
||||||
|
export function verifyInValidSignatureBenchmark(dir: string): BenchSuite {
|
||||||
|
|
||||||
|
// Set the function test
|
||||||
|
const FUNCTION_NAME = "verifyInValidSignature"; // PLEASE FILL THIS OUT
|
||||||
|
|
||||||
|
const verifyInValidSignature = function (): void {
|
||||||
|
global.verify(global.publicKey, global.message, global.signature, global.domain);
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
testFunctions: [verifyInValidSignature],
|
||||||
|
setup: function() {
|
||||||
|
const {Keypair} = require("../../../src");
|
||||||
|
const {sha256} = require('js-sha256');
|
||||||
|
const keypair = Keypair.generate();
|
||||||
|
const keypair2 = Keypair.generate();
|
||||||
|
global.publicKey = keypair2.publicKey.toBytesCompressed();
|
||||||
|
global.message = Buffer.from(sha256.arrayBuffer(Math.random().toString(36)));
|
||||||
|
global.signature = keypair.privateKey.signMessage(Buffer.from(global.message), global.domain).toBytesCompressed();
|
||||||
|
},
|
||||||
|
file: dir + FUNCTION_NAME + ".txt"
|
||||||
|
};
|
||||||
|
}
|
|
@ -0,0 +1,48 @@
|
||||||
|
import {BenchSuite} from "@chainsafe/benchmark-utils";
|
||||||
|
import {aggregateSignatures, verifyMultiple} from "../../../src";
|
||||||
|
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-namespace
|
||||||
|
declare namespace global {
|
||||||
|
export let domain: Buffer;
|
||||||
|
export let messages: Buffer[];
|
||||||
|
export let signature: Buffer;
|
||||||
|
export let publicKeys: Buffer[];
|
||||||
|
export let verify: Function;
|
||||||
|
}
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
|
global.require = require;
|
||||||
|
|
||||||
|
global.domain = Buffer.alloc(8);
|
||||||
|
global.verify = verifyMultiple;
|
||||||
|
|
||||||
|
export function verifyInvalidAggregatedSignature(dir: string): BenchSuite {
|
||||||
|
|
||||||
|
// Set the function test
|
||||||
|
const FUNCTION_NAME = "verifyInvalidAggregatedSignature"; // PLEASE FILL THIS OUT
|
||||||
|
|
||||||
|
const verifyInvalidAggregatedSignature = function (): void {
|
||||||
|
global.verify(global.publicKeys, global.messages, global.signature, global.domain);
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
testFunctions: [verifyInvalidAggregatedSignature],
|
||||||
|
setup: function() {
|
||||||
|
const {Keypair, aggregateSignatures} = require("../../../src");
|
||||||
|
const {sha256} = require('js-sha256');
|
||||||
|
const signatures = [];
|
||||||
|
global.publicKeys = [];
|
||||||
|
const message = Buffer.from(sha256.arrayBuffer(Math.random().toString(36)));
|
||||||
|
const message2 = Buffer.from(sha256.arrayBuffer(Math.random().toString(36)));
|
||||||
|
for(let i = 0; i < 128; i++) {
|
||||||
|
const keypair = Keypair.generate();
|
||||||
|
global.publicKeys.push(keypair.publicKey.toBytesCompressed());
|
||||||
|
signatures.push(keypair.privateKey.signMessage(Buffer.from(message), global.domain).toBytesCompressed());
|
||||||
|
}
|
||||||
|
global.messages = global.publicKeys.map(() => message2);
|
||||||
|
global.signature = aggregateSignatures(signatures);
|
||||||
|
},
|
||||||
|
file: dir + FUNCTION_NAME + ".txt"
|
||||||
|
};
|
||||||
|
}
|
|
@ -0,0 +1,56 @@
|
||||||
|
import {BenchSuite} from "@chainsafe/benchmark-utils";
|
||||||
|
import {aggregateSignatures, Keypair, verifyMultiple} from "../../../src";
|
||||||
|
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-namespace
|
||||||
|
declare namespace global {
|
||||||
|
export let domain: Buffer;
|
||||||
|
export let messages: Buffer[];
|
||||||
|
export let signature: Buffer;
|
||||||
|
export let publicKeys: Buffer[];
|
||||||
|
export let keypairs: Keypair[];
|
||||||
|
export let verify: Function;
|
||||||
|
}
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
|
global.require = require;
|
||||||
|
|
||||||
|
global.domain = Buffer.alloc(8);
|
||||||
|
global.verify = verifyMultiple;
|
||||||
|
|
||||||
|
export function verifyValidAggregatedSignature(dir: string): BenchSuite {
|
||||||
|
|
||||||
|
global.publicKeys = [];
|
||||||
|
global.keypairs = [];
|
||||||
|
for(let i = 0; i < 128; i++) {
|
||||||
|
const keypair = Keypair.generate();
|
||||||
|
global.keypairs.push(keypair);
|
||||||
|
global.publicKeys.push(keypair.publicKey.toBytesCompressed());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the function test
|
||||||
|
const FUNCTION_NAME = "verifyValidAggregatedSignature"; // PLEASE FILL THIS OUT
|
||||||
|
|
||||||
|
const verifyValidAggregatedSignature = function (): void {
|
||||||
|
global.verify(global.publicKeys, global.messages, global.signature, global.domain)
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
testFunctions: [verifyValidAggregatedSignature],
|
||||||
|
setup: function() {
|
||||||
|
const sha256 = require('js-sha256');
|
||||||
|
const {aggregateSignatures} = require("../../../src");
|
||||||
|
const message = Buffer.from(sha256.arrayBuffer(Math.random().toString(36)));
|
||||||
|
const signatures = [];
|
||||||
|
global.messages = [];
|
||||||
|
global.keypairs.forEach((keypair) => {
|
||||||
|
signatures.push(keypair.privateKey.signMessage(message, global.domain).toBytesCompressed());
|
||||||
|
global.messages.push(message);
|
||||||
|
});
|
||||||
|
global.signature = aggregateSignatures(signatures);
|
||||||
|
},
|
||||||
|
file: dir + FUNCTION_NAME + ".txt",
|
||||||
|
// profile: true,
|
||||||
|
name: FUNCTION_NAME,
|
||||||
|
};
|
||||||
|
}
|
|
@ -0,0 +1,43 @@
|
||||||
|
/* eslint-disable @typescript-eslint/no-require-imports,@typescript-eslint/no-var-requires */
|
||||||
|
|
||||||
|
import {BenchSuite} from "@chainsafe/benchmark-utils";
|
||||||
|
import {verify} from "../../../src";
|
||||||
|
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-namespace
|
||||||
|
declare namespace global {
|
||||||
|
export let domain: Buffer;
|
||||||
|
export let message: Buffer;
|
||||||
|
export let signature: Buffer;
|
||||||
|
export let publicKey: Buffer;
|
||||||
|
export let verify: Function;
|
||||||
|
}
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
|
global.require = require;
|
||||||
|
|
||||||
|
global.domain = Buffer.alloc(8);
|
||||||
|
global.verify = verify;
|
||||||
|
|
||||||
|
export function verifyValidSignatureBenchmark(dir: string): BenchSuite {
|
||||||
|
|
||||||
|
// Set the function test
|
||||||
|
const FUNCTION_NAME = "verifyValidSignature"; // PLEASE FILL THIS OUT
|
||||||
|
|
||||||
|
const verifyValidSignature = function (): void {
|
||||||
|
global.verify(global.publicKey, global.message, global.signature, global.domain);
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
testFunctions: [verifyValidSignature],
|
||||||
|
setup: function() {
|
||||||
|
const {Keypair} = require("../../../src");
|
||||||
|
const {sha256} = require('js-sha256');
|
||||||
|
const keypair = Keypair.generate();
|
||||||
|
global.publicKey = keypair.publicKey.toBytesCompressed();
|
||||||
|
global.message = Buffer.from(sha256.arrayBuffer(Math.random().toString(36)));
|
||||||
|
global.signature = keypair.privateKey.signMessage(Buffer.from(global.message), global.domain).toBytesCompressed();
|
||||||
|
},
|
||||||
|
file: dir + FUNCTION_NAME + ".txt"
|
||||||
|
};
|
||||||
|
}
|
|
@ -1,21 +1,21 @@
|
||||||
import {join} from "path";
|
import {join} from "path";
|
||||||
import {describeSpecTest} from "@chainsafe/eth2.0-spec-test-util";
|
import {describeSpecTest} from "@chainsafe/eth2.0-spec-test-util";
|
||||||
import bls from "../../src";
|
import bls from "../../src";
|
||||||
import {BLSSignature} from "../../src/types";
|
import {BLSSignature} from "@chainsafe/eth2.0-types";
|
||||||
|
|
||||||
describeSpecTest(
|
describeSpecTest(
|
||||||
join(__dirname, "./spec-tests/tests/bls/aggregate_pubkeys/aggregate_pubkeys.yaml"),
|
join(__dirname, "../../../spec-test-cases/tests/bls/aggregate_pubkeys/aggregate_pubkeys.yaml"),
|
||||||
bls.aggregatePubkeys,
|
bls.aggregatePubkeys,
|
||||||
({input}) => {
|
({input}) => {
|
||||||
const sigs: BLSSignature[] = [];
|
const sigs: BLSSignature[] = [];
|
||||||
input.forEach((sig: string) => {
|
input.forEach((sig: string) => {
|
||||||
sigs.push(Buffer.from(sig.replace('0x', ''), 'hex'))
|
sigs.push(Buffer.from(sig.replace('0x', ''), 'hex'));
|
||||||
});
|
});
|
||||||
return [
|
return [
|
||||||
sigs
|
sigs
|
||||||
];
|
];
|
||||||
},
|
},
|
||||||
({output}) => output,
|
({output}) => output,
|
||||||
(result) => `0x${result.toString('hex')}`,
|
(result) => `0x${result.toString('hex')}`,
|
||||||
() => false,
|
() => false,
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,22 +1,21 @@
|
||||||
import {join} from "path";
|
import {join} from "path";
|
||||||
import {describeSpecTest} from "@chainsafe/eth2.0-spec-test-util";
|
import {describeSpecTest} from "@chainsafe/eth2.0-spec-test-util";
|
||||||
import bls from "../../src";
|
import bls from "../../src";
|
||||||
import {G2point} from "../../src/helpers/g2point";
|
|
||||||
import {BLSPubkey} from "../../src/types";
|
import {BLSPubkey} from "../../src/types";
|
||||||
|
|
||||||
describeSpecTest(
|
describeSpecTest(
|
||||||
join(__dirname, "./spec-tests/tests/bls/aggregate_sigs/aggregate_sigs.yaml"),
|
join(__dirname, "../../../spec-test-cases/tests/bls/aggregate_sigs/aggregate_sigs.yaml"),
|
||||||
bls.aggregateSignatures,
|
bls.aggregateSignatures,
|
||||||
({input}) => {
|
({input}) => {
|
||||||
const pubKeys: BLSPubkey[] = [];
|
const pubKeys: BLSPubkey[] = [];
|
||||||
input.forEach((pubKey: string) => {
|
input.forEach((pubKey: string) => {
|
||||||
pubKeys.push(Buffer.from(pubKey.replace('0x', ''), 'hex'))
|
pubKeys.push(Buffer.from(pubKey.replace('0x', ''), 'hex'));
|
||||||
});
|
});
|
||||||
return [
|
return [
|
||||||
pubKeys
|
pubKeys
|
||||||
];
|
];
|
||||||
},
|
},
|
||||||
({output}) => output,
|
({output}) => output,
|
||||||
(result) => `0x${result.toString('hex')}`,
|
(result) => `0x${result.toString('hex')}`,
|
||||||
() => false,
|
() => false,
|
||||||
);
|
);
|
||||||
|
|
|
@ -4,20 +4,20 @@ import {padLeft} from "../../src/helpers/utils";
|
||||||
import {G2point} from "../../src/helpers/g2point";
|
import {G2point} from "../../src/helpers/g2point";
|
||||||
|
|
||||||
describeSpecTest(
|
describeSpecTest(
|
||||||
join(__dirname, "./spec-tests/tests/bls/msg_hash_g2_compressed/g2_compressed.yaml"),
|
join(__dirname, "../../../spec-test-cases/tests/bls/msg_hash_g2_compressed/g2_compressed.yaml"),
|
||||||
G2point.hashToG2,
|
G2point.hashToG2,
|
||||||
({input}) => {
|
({input}) => {
|
||||||
const domain = padLeft(Buffer.from(input.domain.replace('0x', ''), 'hex'), 8);
|
const domain = padLeft(Buffer.from(input.domain.replace('0x', ''), 'hex'), 8);
|
||||||
return [
|
return [
|
||||||
Buffer.from(input.message.replace('0x', ''), 'hex'),
|
Buffer.from(input.message.replace('0x', ''), 'hex'),
|
||||||
domain
|
domain
|
||||||
];
|
];
|
||||||
},
|
},
|
||||||
({output}) => {
|
({output}) => {
|
||||||
const xReExpected = padLeft(Buffer.from(output[0].replace('0x', ''), 'hex'), 48);
|
const xReExpected = padLeft(Buffer.from(output[0].replace('0x', ''), 'hex'), 48);
|
||||||
const xImExpected = padLeft(Buffer.from(output[1].replace('0x', ''), 'hex'), 48);
|
const xImExpected = padLeft(Buffer.from(output[1].replace('0x', ''), 'hex'), 48);
|
||||||
return '0x' + Buffer.concat([xReExpected, xImExpected]).toString('hex')
|
return '0x' + Buffer.concat([xReExpected, xImExpected]).toString('hex');
|
||||||
},
|
},
|
||||||
(result:G2point) => `0x${result.toBytesCompressed().toString('hex')}`,
|
(result: G2point) => `0x${result.toBytesCompressed().toString('hex')}`,
|
||||||
() => false,
|
() => false,
|
||||||
);
|
);
|
||||||
|
|
|
@ -4,25 +4,25 @@ import {padLeft} from "../../src/helpers/utils";
|
||||||
import {G2point} from "../../src/helpers/g2point";
|
import {G2point} from "../../src/helpers/g2point";
|
||||||
|
|
||||||
describeSpecTest(
|
describeSpecTest(
|
||||||
join(__dirname, "./spec-tests/tests/bls/msg_hash_g2_uncompressed/g2_uncompressed.yaml"),
|
join(__dirname, "../../../spec-test-cases/tests/bls/msg_hash_g2_uncompressed/g2_uncompressed.yaml"),
|
||||||
G2point.hashToG2,
|
G2point.hashToG2,
|
||||||
({input}) => {
|
({input}) => {
|
||||||
const domain = padLeft(Buffer.from(input.domain.replace('0x', ''), 'hex'), 8);
|
const domain = padLeft(Buffer.from(input.domain.replace('0x', ''), 'hex'), 8);
|
||||||
return [
|
return [
|
||||||
Buffer.from(input.message.replace('0x', ''), 'hex'),
|
Buffer.from(input.message.replace('0x', ''), 'hex'),
|
||||||
domain
|
domain
|
||||||
];
|
];
|
||||||
},
|
},
|
||||||
({output}) => {
|
({output}) => {
|
||||||
return '0x' + G2point.fromUncompressedInput(
|
return '0x' + G2point.fromUncompressedInput(
|
||||||
Buffer.from(output[0][0].replace('0x', ''), 'hex'),
|
Buffer.from(output[0][0].replace('0x', ''), 'hex'),
|
||||||
Buffer.from(output[0][1].replace('0x', ''), 'hex'),
|
Buffer.from(output[0][1].replace('0x', ''), 'hex'),
|
||||||
Buffer.from(output[1][0].replace('0x', ''), 'hex'),
|
Buffer.from(output[1][0].replace('0x', ''), 'hex'),
|
||||||
Buffer.from(output[1][1].replace('0x', ''), 'hex'),
|
Buffer.from(output[1][1].replace('0x', ''), 'hex'),
|
||||||
Buffer.from(output[2][0].replace('0x', ''), 'hex'),
|
Buffer.from(output[2][0].replace('0x', ''), 'hex'),
|
||||||
Buffer.from(output[2][1].replace('0x', ''), 'hex'),
|
Buffer.from(output[2][1].replace('0x', ''), 'hex'),
|
||||||
).toBytesCompressed().toString('hex');
|
).toBytesCompressed().toString('hex');
|
||||||
},
|
},
|
||||||
(result:G2point) => `0x${result.toBytesCompressed().toString('hex')}`,
|
(result: G2point) => `0x${result.toBytesCompressed().toString('hex')}`,
|
||||||
() => false,
|
() => false,
|
||||||
);
|
);
|
||||||
|
|
|
@ -3,12 +3,12 @@ import {describeSpecTest} from "@chainsafe/eth2.0-spec-test-util";
|
||||||
import bls from "../../src";
|
import bls from "../../src";
|
||||||
|
|
||||||
describeSpecTest(
|
describeSpecTest(
|
||||||
join(__dirname, "./spec-tests/tests/bls/priv_to_pub/priv_to_pub.yaml"),
|
join(__dirname, "../../../spec-test-cases/tests/bls/priv_to_pub/priv_to_pub.yaml"),
|
||||||
bls.generatePublicKey,
|
bls.generatePublicKey,
|
||||||
({input}) => {
|
({input}) => {
|
||||||
return [Buffer.from(input.replace('0x', ''), 'hex')];
|
return [Buffer.from(input.replace('0x', ''), 'hex')];
|
||||||
},
|
},
|
||||||
({output}) => output,
|
({output}) => output,
|
||||||
(result) => `0x${result.toString('hex')}`,
|
(result) => `0x${result.toString('hex')}`,
|
||||||
() => false,
|
() => false,
|
||||||
);
|
);
|
||||||
|
|
|
@ -4,17 +4,17 @@ import bls from "../../src";
|
||||||
import {padLeft} from "../../src/helpers/utils";
|
import {padLeft} from "../../src/helpers/utils";
|
||||||
|
|
||||||
describeSpecTest(
|
describeSpecTest(
|
||||||
join(__dirname, "./spec-tests/tests/bls/sign_msg/sign_msg.yaml"),
|
join(__dirname, "../../../spec-test-cases/tests/bls/sign_msg/sign_msg.yaml"),
|
||||||
bls.sign,
|
bls.sign,
|
||||||
({input}) => {
|
({input}) => {
|
||||||
const domain = padLeft(Buffer.from(input.domain.replace('0x', ''), 'hex'), 8);
|
const domain = padLeft(Buffer.from(input.domain.replace('0x', ''), 'hex'), 8);
|
||||||
return [
|
return [
|
||||||
Buffer.from(input.privkey.replace('0x', ''), 'hex'),
|
Buffer.from(input.privkey.replace('0x', ''), 'hex'),
|
||||||
Buffer.from(input.message.replace('0x', ''), 'hex'),
|
Buffer.from(input.message.replace('0x', ''), 'hex'),
|
||||||
domain
|
domain
|
||||||
];
|
];
|
||||||
},
|
},
|
||||||
({output}) => output,
|
({output}) => output,
|
||||||
(result) => `0x${result.toString('hex')}`,
|
(result) => `0x${result.toString('hex')}`,
|
||||||
() => false,
|
() => false,
|
||||||
);
|
);
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
Subproject commit 15a1d85125682d3ffc09a1ee9639f46c4a1653f6
|
|
|
@ -1,6 +1,6 @@
|
||||||
import bls from "../../src";
|
import bls from "../../src";
|
||||||
import {Keypair} from "../../src/keypair";
|
import {Keypair} from "../../src/keypair";
|
||||||
import { sha256 } from 'js-sha256';
|
import {sha256} from 'js-sha256';
|
||||||
import {G2point} from "../../src/helpers/g2point";
|
import {G2point} from "../../src/helpers/g2point";
|
||||||
import {expect} from "chai";
|
import {expect} from "chai";
|
||||||
|
|
||||||
|
@ -65,7 +65,7 @@ describe('test bls', function () {
|
||||||
it('should fail verify signature of different message', () => {
|
it('should fail verify signature of different message', () => {
|
||||||
const keypair = Keypair.generate();
|
const keypair = Keypair.generate();
|
||||||
const messageHash = Buffer.from(sha256.arrayBuffer("Test message"));
|
const messageHash = Buffer.from(sha256.arrayBuffer("Test message"));
|
||||||
const messageHash2 = Buffer.from(sha256.arrayBuffer("Test message2"))
|
const messageHash2 = Buffer.from(sha256.arrayBuffer("Test message2"));
|
||||||
const domain = Buffer.from("01", 'hex');
|
const domain = Buffer.from("01", 'hex');
|
||||||
const signature = keypair.privateKey.sign(
|
const signature = keypair.privateKey.sign(
|
||||||
G2point.hashToG2(messageHash, domain)
|
G2point.hashToG2(messageHash, domain)
|
||||||
|
@ -117,7 +117,7 @@ describe('test bls', function () {
|
||||||
describe('verify multiple', function() {
|
describe('verify multiple', function() {
|
||||||
|
|
||||||
it('should verify aggregated signatures', function () {
|
it('should verify aggregated signatures', function () {
|
||||||
this.timeout(5000)
|
this.timeout(5000);
|
||||||
|
|
||||||
|
|
||||||
const domain = Buffer.alloc(8, 0);
|
const domain = Buffer.alloc(8, 0);
|
||||||
|
@ -162,8 +162,48 @@ describe('test bls', function () {
|
||||||
expect(result).to.be.true;
|
expect(result).to.be.true;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should verify aggregated signatures - same message', function () {
|
||||||
|
this.timeout(5000);
|
||||||
|
|
||||||
|
|
||||||
|
const domain = Buffer.alloc(8, 0);
|
||||||
|
|
||||||
|
const keypair1 = Keypair.generate();
|
||||||
|
const keypair2 = Keypair.generate();
|
||||||
|
const keypair3 = Keypair.generate();
|
||||||
|
const keypair4 = Keypair.generate();
|
||||||
|
|
||||||
|
const message = Buffer.from("Test1", 'utf-8');
|
||||||
|
|
||||||
|
const signature1 = keypair1.privateKey.signMessage(message, domain);
|
||||||
|
const signature2 = keypair2.privateKey.signMessage(message, domain);
|
||||||
|
const signature3 = keypair3.privateKey.signMessage(message, domain);
|
||||||
|
const signature4 = keypair4.privateKey.signMessage(message, domain);
|
||||||
|
|
||||||
|
const aggregateSignature = bls.aggregateSignatures([
|
||||||
|
signature1.toBytesCompressed(),
|
||||||
|
signature2.toBytesCompressed(),
|
||||||
|
signature3.toBytesCompressed(),
|
||||||
|
signature4.toBytesCompressed(),
|
||||||
|
]);
|
||||||
|
|
||||||
|
const result = bls.verifyMultiple(
|
||||||
|
[
|
||||||
|
keypair1.publicKey.toBytesCompressed(),
|
||||||
|
keypair2.publicKey.toBytesCompressed(),
|
||||||
|
keypair3.publicKey.toBytesCompressed(),
|
||||||
|
keypair4.publicKey.toBytesCompressed()
|
||||||
|
],
|
||||||
|
[message, message, message, message],
|
||||||
|
aggregateSignature,
|
||||||
|
domain
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(result).to.be.true;
|
||||||
|
});
|
||||||
|
|
||||||
it('should fail to verify aggregated signatures - swapped messages', function () {
|
it('should fail to verify aggregated signatures - swapped messages', function () {
|
||||||
this.timeout(5000)
|
this.timeout(5000);
|
||||||
|
|
||||||
const domain = Buffer.alloc(8, 0);
|
const domain = Buffer.alloc(8, 0);
|
||||||
|
|
||||||
|
|
Reference in New Issue