Co-exist implementations
This commit is contained in:
parent
5b06e4f61e
commit
57694c2e54
|
@ -40,7 +40,7 @@
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@chainsafe/bls-keygen": "^0.2.0",
|
"@chainsafe/bls-keygen": "^0.2.0",
|
||||||
"@chainsafe/blst-ts": "file:../blst-ts",
|
"@chainsafe/blst": "^0.1.0",
|
||||||
"@chainsafe/eth2-bls-wasm": "^0.5.0",
|
"@chainsafe/eth2-bls-wasm": "^0.5.0",
|
||||||
"assert": "^1.4.1"
|
"assert": "^1.4.1"
|
||||||
},
|
},
|
||||||
|
|
|
@ -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,
|
||||||
|
};
|
|
@ -1,6 +1,5 @@
|
||||||
import * as blst from "@chainsafe/blst-ts";
|
import * as blst from "@chainsafe/blst";
|
||||||
import {blst as blstBindings} from "@chainsafe/blst-ts/dist/bindings";
|
import {bytesToHex, getRandomBytes, hexToBytes} from "../helpers/utils";
|
||||||
import {bytesToHex, getRandomBytes, hexToBytes} from "./helpers/utils";
|
|
||||||
import {PublicKey} from "./publicKey";
|
import {PublicKey} from "./publicKey";
|
||||||
import {Signature} from "./signature";
|
import {Signature} from "./signature";
|
||||||
|
|
||||||
|
@ -30,8 +29,7 @@ export class PrivateKey {
|
||||||
}
|
}
|
||||||
|
|
||||||
toPublicKey(): PublicKey {
|
toPublicKey(): PublicKey {
|
||||||
const p1 = new blstBindings.P1(this.value.value);
|
const jacobian = this.value.toAggregatePublicKey();
|
||||||
const jacobian = new blst.AggregatePublicKey(p1);
|
|
||||||
const affine = jacobian.toPublicKey();
|
const affine = jacobian.toPublicKey();
|
||||||
return new PublicKey(affine, jacobian);
|
return new PublicKey(affine, jacobian);
|
||||||
}
|
}
|
|
@ -1,7 +1,6 @@
|
||||||
import * as blst from "@chainsafe/blst-ts";
|
import * as blst from "@chainsafe/blst";
|
||||||
import {blst as blstBindings} from "@chainsafe/blst-ts/dist/bindings";
|
import {bytesToHex, hexToBytes} from "../helpers/utils";
|
||||||
import {Signature} from "./signature";
|
import {Signature} from "./signature";
|
||||||
import {bytesToHex, hexToBytes} from "./helpers/utils";
|
|
||||||
|
|
||||||
export class PublicKey {
|
export class PublicKey {
|
||||||
readonly affine: blst.PublicKey;
|
readonly affine: blst.PublicKey;
|
||||||
|
@ -23,18 +22,13 @@ export class PublicKey {
|
||||||
}
|
}
|
||||||
|
|
||||||
static aggregate(pubkeys: PublicKey[]): PublicKey {
|
static aggregate(pubkeys: PublicKey[]): PublicKey {
|
||||||
const p1Arr = pubkeys.map((pk) => pk.jacobian.value);
|
const jacobian = blst.aggregatePubkeys(pubkeys.map((pk) => pk.jacobian));
|
||||||
const aggP1 = p1Arr.reduce((_agg, pk) => {
|
|
||||||
return blstBindings.P1.add(_agg, pk);
|
|
||||||
});
|
|
||||||
|
|
||||||
const jacobian = new blst.AggregatePublicKey(aggP1);
|
|
||||||
const affine = jacobian.toPublicKey();
|
const affine = jacobian.toPublicKey();
|
||||||
return new PublicKey(affine, jacobian);
|
return new PublicKey(affine, jacobian);
|
||||||
}
|
}
|
||||||
|
|
||||||
verifyMessage(signature: Signature, message: Uint8Array): boolean {
|
verifyMessage(signature: Signature, message: Uint8Array): boolean {
|
||||||
return blst.verify(message, this.affine, signature.value);
|
return signature.verify(this, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
toBytes(): Buffer {
|
toBytes(): Buffer {
|
|
@ -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());
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,3 +3,5 @@ export const SIGNATURE_LENGTH = 96;
|
||||||
export const FP_POINT_LENGTH = 48;
|
export const FP_POINT_LENGTH = 48;
|
||||||
export const PUBLIC_KEY_LENGTH = FP_POINT_LENGTH;
|
export const PUBLIC_KEY_LENGTH = FP_POINT_LENGTH;
|
||||||
export const G2_HASH_PADDING = 16;
|
export const G2_HASH_PADDING = 16;
|
||||||
|
export const EMPTY_PUBLIC_KEY = Buffer.alloc(PUBLIC_KEY_LENGTH);
|
||||||
|
export const EMPTY_SIGNATURE = Buffer.alloc(SIGNATURE_LENGTH);
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import assert from "assert";
|
import assert from "assert";
|
||||||
import crypto from "crypto";
|
import crypto from "crypto";
|
||||||
import {PUBLIC_KEY_LENGTH, SIGNATURE_LENGTH} from "../constants";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pads byte array with zeroes on left side up to desired length.
|
* 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));
|
return Uint8Array.from(crypto.randomBytes(size));
|
||||||
}
|
}
|
||||||
|
|
||||||
export const EMPTY_PUBLIC_KEY = Buffer.alloc(PUBLIC_KEY_LENGTH);
|
export function toBuffer(input: Uint8Array): Buffer {
|
||||||
export const EMPTY_SIGNATURE = Buffer.alloc(SIGNATURE_LENGTH);
|
return Buffer.from(input.buffer, input.byteOffset, input.length);
|
||||||
|
}
|
||||||
|
|
|
@ -14,7 +14,7 @@ export async function setupBls(): Promise<Bls> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cache a promise for Bls instead of Bls to make sure it is initialized only once
|
// Cache a promise for Bls instead of Bls to make sure it is initialized only once
|
||||||
export async function init(): Promise<Bls> {
|
export async function initBLS(): Promise<Bls> {
|
||||||
if (!blsGlobalPromise) {
|
if (!blsGlobalPromise) {
|
||||||
blsGlobalPromise = setupBls();
|
blsGlobalPromise = setupBls();
|
||||||
}
|
}
|
|
@ -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,
|
||||||
|
};
|
|
@ -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());
|
||||||
|
}
|
||||||
|
}
|
|
@ -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());
|
||||||
|
}
|
||||||
|
}
|
|
@ -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());
|
||||||
|
}
|
||||||
|
}
|
|
@ -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());
|
||||||
|
}
|
||||||
|
}
|
147
src/index.ts
147
src/index.ts
|
@ -1,144 +1,3 @@
|
||||||
import {Keypair} from "./keypair";
|
import blst from "./blst";
|
||||||
import {PrivateKey} from "./privateKey";
|
export default blst;
|
||||||
import {PublicKey} from "./publicKey";
|
export * from "./blst";
|
||||||
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,
|
|
||||||
};
|
|
||||||
|
|
|
@ -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());
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,6 +1,5 @@
|
||||||
import crypto from "crypto";
|
import crypto from "crypto";
|
||||||
import * as blst from "@chainsafe/blst-ts";
|
import * as blst from "@chainsafe/blst";
|
||||||
import {blst as blstBindings} from "@chainsafe/blst-ts/dist/bindings";
|
|
||||||
import * as herumi from "../../src";
|
import * as herumi from "../../src";
|
||||||
import {runBenchmark} from "./runner";
|
import {runBenchmark} from "./runner";
|
||||||
|
|
||||||
|
@ -49,7 +48,7 @@ import {runBenchmark} from "./runner";
|
||||||
|
|
||||||
// Fast aggregate
|
// 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",
|
id: "BLST fastAggregateVerify",
|
||||||
|
|
||||||
prepareTest: () => {
|
prepareTest: () => {
|
||||||
|
@ -57,7 +56,7 @@ import {runBenchmark} from "./runner";
|
||||||
|
|
||||||
const dataArr = range(aggCount).map(() => {
|
const dataArr = range(aggCount).map(() => {
|
||||||
const sk = blst.SecretKey.fromKeygen(crypto.randomBytes(32));
|
const sk = blst.SecretKey.fromKeygen(crypto.randomBytes(32));
|
||||||
const pk = sk.toPublicKey();
|
const pk = sk.toAggregatePublicKey();
|
||||||
const sig = sk.sign(msg);
|
const sig = sk.sign(msg);
|
||||||
return {pk, sig};
|
return {pk, sig};
|
||||||
});
|
});
|
||||||
|
@ -129,10 +128,7 @@ import {runBenchmark} from "./runner";
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
testRunner: (pks) => {
|
testRunner: (pks) => {
|
||||||
const p1Arr = pks.map((pk) => pk.value);
|
blst.aggregatePubkeys(pks);
|
||||||
p1Arr.reduce((agg, pk) => {
|
|
||||||
return blstBindings.P1.add(agg, pk);
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
import path from "path";
|
||||||
|
export const SPEC_TESTS_DIR = path.join(__dirname, "../node_modules/@chainsafe/eth2-spec-tests/tests");
|
|
@ -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<IAggregateSigsTestCase, string>(
|
|
||||||
"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,
|
|
||||||
}
|
|
||||||
);
|
|
|
@ -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<IAggregateSigsVerifyTestCase, boolean>(
|
|
||||||
"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,
|
|
||||||
}
|
|
||||||
);
|
|
|
@ -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<IAggregateSigsVerifyTestCase, boolean>(
|
|
||||||
"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,
|
|
||||||
}
|
|
||||||
);
|
|
|
@ -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<ISignMessageTestCase, string>(
|
|
||||||
"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,
|
|
||||||
}
|
|
||||||
);
|
|
|
@ -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<IVerifyTestCase, boolean>(
|
|
||||||
"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,
|
|
||||||
}
|
|
||||||
);
|
|
|
@ -1,6 +1,8 @@
|
||||||
import path from "path";
|
import path from "path";
|
||||||
import bls, {initBLS} from "../../src";
|
|
||||||
import {describeDirectorySpecTest, InputType} from "@chainsafe/lodestar-spec-test-util";
|
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 {
|
interface IAggregateSigsTestCase {
|
||||||
data: {
|
data: {
|
||||||
|
@ -9,32 +11,23 @@ interface IAggregateSigsTestCase {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
before(async function f() {
|
forEachImplementation((bls, implementation) => {
|
||||||
await initBLS();
|
describeDirectorySpecTest<IAggregateSigsTestCase, string>(
|
||||||
});
|
`${implementation} - bls/aggregate/small`,
|
||||||
|
path.join(SPEC_TESTS_DIR, "general/phase0/bls/aggregate/small"),
|
||||||
describeDirectorySpecTest<IAggregateSigsTestCase, string>(
|
|
||||||
"BLS - aggregate sigs",
|
|
||||||
path.join(__dirname, "../../node_modules/@chainsafe/eth2-spec-tests/tests/general/phase0/bls/aggregate/small"),
|
|
||||||
(testCase) => {
|
(testCase) => {
|
||||||
try {
|
try {
|
||||||
const result = bls.aggregateSignatures(
|
const signatures = testCase.data.input;
|
||||||
testCase.data.input.map((pubKey) => {
|
const agg = bls.aggregateSignatures(signatures.map(hexToBytes));
|
||||||
return Buffer.from(pubKey.replace("0x", ""), "hex");
|
return bytesToHex(agg);
|
||||||
})
|
|
||||||
);
|
|
||||||
return `0x${result.toString("hex")}`;
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (e.message === "signatures is null or undefined or empty array") {
|
if (e.message === "EMPTY_AGGREGATE_ARRAY") return null;
|
||||||
return null;
|
|
||||||
}
|
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
inputTypes: {
|
inputTypes: {data: InputType.YAML},
|
||||||
data: InputType.YAML,
|
|
||||||
},
|
|
||||||
getExpected: (testCase) => testCase.data.output,
|
getExpected: (testCase) => testCase.data.output,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
});
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
import path from "path";
|
import path from "path";
|
||||||
import bls, {initBLS} from "../../src";
|
|
||||||
import {describeDirectorySpecTest, InputType} from "@chainsafe/lodestar-spec-test-util";
|
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 {
|
interface IAggregateSigsVerifyTestCase {
|
||||||
data: {
|
data: {
|
||||||
|
@ -13,30 +15,17 @@ interface IAggregateSigsVerifyTestCase {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
before(async function f() {
|
forEachImplementation((bls, implementation) => {
|
||||||
try {
|
describeDirectorySpecTest<IAggregateSigsVerifyTestCase, boolean>(
|
||||||
await initBLS();
|
`${implementation} - bls/aggregate_verify/small`,
|
||||||
} catch (e) {
|
path.join(SPEC_TESTS_DIR, "general/phase0/bls/aggregate_verify/small"),
|
||||||
console.log(e);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
describeDirectorySpecTest<IAggregateSigsVerifyTestCase, boolean>(
|
|
||||||
"BLS - aggregate sigs verify",
|
|
||||||
path.join(__dirname, "../../node_modules/@chainsafe/eth2-spec-tests/tests/general/phase0/bls/aggregate_verify/small"),
|
|
||||||
(testCase) => {
|
(testCase) => {
|
||||||
const pubkeys = testCase.data.input.pubkeys.map((pubkey) => {
|
const {pubkeys, messages, signature} = testCase.data.input;
|
||||||
return Buffer.from(pubkey.replace("0x", ""), "hex");
|
return bls.verifyMultiple(pubkeys.map(hexToBytes), messages.map(hexToBytes), hexToBytes(signature));
|
||||||
});
|
|
||||||
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: {
|
inputTypes: {data: InputType.YAML},
|
||||||
data: InputType.YAML,
|
|
||||||
},
|
|
||||||
getExpected: (testCase) => testCase.data.output,
|
getExpected: (testCase) => testCase.data.output,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
});
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
import path from "path";
|
import path from "path";
|
||||||
import bls, {initBLS} from "../../src";
|
|
||||||
import {describeDirectorySpecTest, InputType} from "@chainsafe/lodestar-spec-test-util";
|
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 {
|
interface IAggregateSigsVerifyTestCase {
|
||||||
data: {
|
data: {
|
||||||
|
@ -13,31 +15,17 @@ interface IAggregateSigsVerifyTestCase {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
before(async function f() {
|
forEachImplementation((bls, implementation) => {
|
||||||
try {
|
describeDirectorySpecTest<IAggregateSigsVerifyTestCase, boolean>(
|
||||||
await initBLS();
|
`${implementation} - bls/fast_aggregate_verify/small`,
|
||||||
} catch (e) {
|
path.join(SPEC_TESTS_DIR, "general/phase0/bls/fast_aggregate_verify/small"),
|
||||||
console.log(e);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
describeDirectorySpecTest<IAggregateSigsVerifyTestCase, boolean>(
|
|
||||||
"BLS - aggregate sigs verify",
|
|
||||||
path.join(
|
|
||||||
__dirname,
|
|
||||||
"../../node_modules/@chainsafe/eth2-spec-tests/tests/general/phase0/bls/fast_aggregate_verify/small"
|
|
||||||
),
|
|
||||||
(testCase) => {
|
(testCase) => {
|
||||||
return bls.verifyAggregate(
|
const {pubkeys, message, signature} = testCase.data.input;
|
||||||
testCase.data.input.pubkeys.map((key) => Buffer.from(key.replace("0x", ""), "hex")),
|
return bls.verifyAggregate(pubkeys.map(hexToBytes), hexToBytes(message), hexToBytes(signature));
|
||||||
Buffer.from(testCase.data.input.message.replace("0x", ""), "hex"),
|
|
||||||
Buffer.from(testCase.data.input.signature.replace("0x", ""), "hex")
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
inputTypes: {
|
inputTypes: {data: InputType.YAML},
|
||||||
data: InputType.YAML,
|
|
||||||
},
|
|
||||||
getExpected: (testCase) => testCase.data.output,
|
getExpected: (testCase) => testCase.data.output,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
});
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
import path from "path";
|
import path from "path";
|
||||||
import bls, {initBLS} from "../../src";
|
|
||||||
import {describeDirectorySpecTest, InputType} from "@chainsafe/lodestar-spec-test-util";
|
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 {
|
interface ISignMessageTestCase {
|
||||||
data: {
|
data: {
|
||||||
|
@ -12,24 +14,18 @@ interface ISignMessageTestCase {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
before(async function f() {
|
forEachImplementation((bls, implementation) => {
|
||||||
await initBLS();
|
describeDirectorySpecTest<ISignMessageTestCase, string>(
|
||||||
});
|
`${implementation} - bls/sign/small`,
|
||||||
|
path.join(SPEC_TESTS_DIR, "general/phase0/bls/sign/small"),
|
||||||
describeDirectorySpecTest<ISignMessageTestCase, string>(
|
|
||||||
"BLS - sign",
|
|
||||||
path.join(__dirname, "../../node_modules/@chainsafe/eth2-spec-tests/tests/general/phase0/bls/sign/small"),
|
|
||||||
(testCase) => {
|
(testCase) => {
|
||||||
const signature = bls.sign(
|
const {privkey, message} = testCase.data.input;
|
||||||
Buffer.from(testCase.data.input.privkey.replace("0x", ""), "hex"),
|
const signature = bls.sign(hexToBytes(privkey), hexToBytes(message));
|
||||||
Buffer.from(testCase.data.input.message.replace("0x", ""), "hex")
|
return bytesToHex(signature);
|
||||||
);
|
|
||||||
return `0x${signature.toString("hex")}`;
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
inputTypes: {
|
inputTypes: {data: InputType.YAML},
|
||||||
data: InputType.YAML,
|
|
||||||
},
|
|
||||||
getExpected: (testCase) => testCase.data.output,
|
getExpected: (testCase) => testCase.data.output,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
});
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
import path from "path";
|
import path from "path";
|
||||||
import bls, {initBLS} from "../../src";
|
|
||||||
import {describeDirectorySpecTest, InputType} from "@chainsafe/lodestar-spec-test-util";
|
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 {
|
interface IVerifyTestCase {
|
||||||
data: {
|
data: {
|
||||||
|
@ -13,24 +15,17 @@ interface IVerifyTestCase {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
before(async function f() {
|
forEachImplementation((bls, implementation) => {
|
||||||
await initBLS();
|
describeDirectorySpecTest<IVerifyTestCase, boolean>(
|
||||||
});
|
`${implementation} - bls/verify/small`,
|
||||||
|
path.join(SPEC_TESTS_DIR, "general/phase0/bls/verify/small"),
|
||||||
describeDirectorySpecTest<IVerifyTestCase, boolean>(
|
|
||||||
"BLS - verify",
|
|
||||||
path.join(__dirname, "../../node_modules/@chainsafe/eth2-spec-tests/tests/general/phase0/bls/verify/small"),
|
|
||||||
(testCase) => {
|
(testCase) => {
|
||||||
return bls.verify(
|
const {pubkey, message, signature} = testCase.data.input;
|
||||||
Buffer.from(testCase.data.input.pubkey.replace("0x", ""), "hex"),
|
return bls.verify(hexToBytes(pubkey), hexToBytes(message), hexToBytes(signature));
|
||||||
Buffer.from(testCase.data.input.message.replace("0x", ""), "hex"),
|
|
||||||
Buffer.from(testCase.data.input.signature.replace("0x", ""), "hex")
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
inputTypes: {
|
inputTypes: {data: InputType.YAML},
|
||||||
data: InputType.YAML,
|
|
||||||
},
|
|
||||||
getExpected: (testCase) => testCase.data.output,
|
getExpected: (testCase) => testCase.data.output,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
});
|
||||||
|
|
|
@ -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<typeof getBls>, implementation: Implementation) => void
|
||||||
|
): void {
|
||||||
|
for (const implementation of implementations) {
|
||||||
|
const bls = getBls(implementation);
|
||||||
|
|
||||||
|
if (implementation === "herumi") {
|
||||||
|
before(async () => {
|
||||||
|
await bls.initBLS();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
callback(bls, implementation);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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();
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -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 SHA256 from "@chainsafe/as-sha256";
|
||||||
import {expect} from "chai";
|
import {expect} from "chai";
|
||||||
import {destroy} from "../../src/context";
|
|
||||||
|
|
||||||
describe("test bls", function () {
|
describe("test bls", function () {
|
||||||
before(async function () {
|
before(async function () {
|
||||||
await initBLS();
|
await initBLS();
|
||||||
});
|
});
|
||||||
|
|
||||||
after(function () {
|
|
||||||
destroy();
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("aggregate pubkey", function () {
|
|
||||||
it("should aggregate empty array", function () {
|
|
||||||
expect(bls.aggregatePubkeys([])).to.not.throw;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("verify", function () {
|
describe("verify", function () {
|
||||||
it("should verify signature", () => {
|
it("should verify signature", () => {
|
||||||
const keypair = Keypair.generate();
|
const keypair = Keypair.generate();
|
||||||
|
@ -148,22 +137,18 @@ describe("test bls", function () {
|
||||||
const signature3 = keypair3.privateKey.signMessage(message2);
|
const signature3 = keypair3.privateKey.signMessage(message2);
|
||||||
const signature4 = keypair4.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(),
|
signature1.toBytes(),
|
||||||
signature2.toBytes(),
|
signature2.toBytes(),
|
||||||
signature3.toBytes(),
|
signature3.toBytes(),
|
||||||
signature4.toBytes(),
|
signature4.toBytes(),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const result = bls.verifyMultiple(
|
const result = verifyMultiple([aggregatePubKey12, aggregatePubKey34], [message2, message1], aggregateSignature);
|
||||||
[aggregatePubKey12, aggregatePubKey34],
|
|
||||||
[message2, message1],
|
|
||||||
aggregateSignature
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(result).to.be.false;
|
expect(result).to.be.false;
|
||||||
});
|
});
|
||||||
|
@ -182,16 +167,16 @@ describe("test bls", function () {
|
||||||
const signature3 = keypair3.privateKey.signMessage(message2);
|
const signature3 = keypair3.privateKey.signMessage(message2);
|
||||||
const signature4 = keypair4.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(),
|
signature1.toBytes(),
|
||||||
signature2.toBytes(),
|
signature2.toBytes(),
|
||||||
signature3.toBytes(),
|
signature3.toBytes(),
|
||||||
signature4.toBytes(),
|
signature4.toBytes(),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const result = bls.verifyMultiple([aggregatePubKey12], [message2, message1], aggregateSignature);
|
const result = verifyMultiple([aggregatePubKey12], [message2, message1], aggregateSignature);
|
||||||
|
|
||||||
expect(result).to.be.false;
|
expect(result).to.be.false;
|
||||||
});
|
});
|
||||||
|
@ -202,7 +187,7 @@ describe("test bls", function () {
|
||||||
const message1 = Buffer.from(SHA256.digest(Buffer.from("Test1")));
|
const message1 = Buffer.from(SHA256.digest(Buffer.from("Test1")));
|
||||||
const message2 = Buffer.from(SHA256.digest(Buffer.from("Test2")));
|
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;
|
expect(result).to.be.false;
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
import {PrivateKey, PublicKey, Keypair} from "../../src";
|
import {PrivateKey, PublicKey, Keypair, destroy, initBLS} from "../../src";
|
||||||
import {expect} from "chai";
|
import {expect} from "chai";
|
||||||
import {destroy, init} from "../../src/context";
|
|
||||||
|
|
||||||
describe("keypair", function () {
|
describe("keypair", function () {
|
||||||
before(async function () {
|
before(async function () {
|
||||||
await init();
|
await initBLS();
|
||||||
});
|
});
|
||||||
|
|
||||||
after(function () {
|
after(function () {
|
||||||
|
|
|
@ -1,11 +1,9 @@
|
||||||
import {PrivateKey} from "../../src";
|
import {PrivateKey, initBLS, destroy, SECRET_KEY_LENGTH} from "../../src";
|
||||||
import {expect} from "chai";
|
import {expect} from "chai";
|
||||||
import {SECRET_KEY_LENGTH} from "../../src/constants";
|
|
||||||
import {destroy, init} from "../../src/context";
|
|
||||||
|
|
||||||
describe("privateKey", function () {
|
describe("privateKey", function () {
|
||||||
before(async function () {
|
before(async function () {
|
||||||
await init();
|
await initBLS();
|
||||||
});
|
});
|
||||||
|
|
||||||
after(function () {
|
after(function () {
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
import {destroy, init} from "../../src/context";
|
import {PublicKey, PrivateKey, initBLS, destroy} from "../../src";
|
||||||
import {PublicKey, PrivateKey} from "../../src";
|
|
||||||
import {expect} from "chai";
|
import {expect} from "chai";
|
||||||
|
|
||||||
describe("public key", function () {
|
describe("public key", function () {
|
||||||
before(async function f() {
|
before(async function f() {
|
||||||
await init();
|
await initBLS();
|
||||||
});
|
});
|
||||||
|
|
||||||
after(function () {
|
after(function () {
|
||||||
|
|
13
yarn.lock
13
yarn.lock
|
@ -820,10 +820,10 @@
|
||||||
bip39 "^3.0.2"
|
bip39 "^3.0.2"
|
||||||
buffer "^5.4.3"
|
buffer "^5.4.3"
|
||||||
|
|
||||||
"@chainsafe/blst-ts@file:../blst-ts":
|
"@chainsafe/blst@^0.1.0":
|
||||||
version "0.1.1"
|
version "0.1.0"
|
||||||
dependencies:
|
resolved "https://registry.yarnpkg.com/@chainsafe/blst/-/blst-0.1.0.tgz#6aa0ea5e91a0f7ae2d4358fb432eb9a558a4de31"
|
||||||
node-fetch "^2.6.1"
|
integrity sha512-sJXrADkWNA06xM5udoPr7cdNgzSBAjHaN1XbwLkbJ637eVSsEzip+P7Uz0ajfUu2pVsqReoEOBnpFJpUOHAEtg==
|
||||||
|
|
||||||
"@chainsafe/eth2-bls-wasm@^0.5.0":
|
"@chainsafe/eth2-bls-wasm@^0.5.0":
|
||||||
version "0.5.0"
|
version "0.5.0"
|
||||||
|
@ -4417,11 +4417,6 @@ node-environment-flags@1.0.5:
|
||||||
object.getownpropertydescriptors "^2.0.3"
|
object.getownpropertydescriptors "^2.0.3"
|
||||||
semver "^5.7.0"
|
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:
|
node-libs-browser@^2.2.1:
|
||||||
version "2.2.1"
|
version "2.2.1"
|
||||||
resolved "https://registry.yarnpkg.com/node-libs-browser/-/node-libs-browser-2.2.1.tgz#b64f513d18338625f90346d27b0d235e631f6425"
|
resolved "https://registry.yarnpkg.com/node-libs-browser/-/node-libs-browser-2.2.1.tgz#b64f513d18338625f90346d27b0d235e631f6425"
|
||||||
|
|
Reference in New Issue