Define common implementation

This commit is contained in:
dapplion 2020-11-20 19:03:17 +00:00
parent c354386dab
commit 4424bed87d
19 changed files with 143 additions and 96 deletions

View File

@ -4,6 +4,7 @@ import {PrivateKey} from "./privateKey";
import {PublicKey} from "./publicKey";
import {Signature} from "./signature";
import {toBuffer} from "../helpers/utils";
import {IBls} from "../interface";
export * from "../constants";
export {Keypair, PrivateKey, PublicKey, Signature};
@ -15,23 +16,6 @@ export function destroy(): void {
// Native bindings require no destroy() call
}
/**
* Generates new secret and public key
*/
export function generateKeyPair(): Keypair {
return Keypair.generate();
}
/**
* Generates public key from given secret.
* @param {BLSSecretKey} secretKey
*/
export function generatePublicKey(secretKey: Uint8Array): Buffer {
assert(secretKey, "secretKey is null or undefined");
const keypair = new Keypair(PrivateKey.fromBytes(toBuffer(secretKey)));
return keypair.publicKey.toBytes();
}
/**
* Signs given message using secret key.
* @param secretKey
@ -127,9 +111,7 @@ export function verifyMultiple(publicKeys: Uint8Array[], messageHashes: Uint8Arr
}
}
export default {
generateKeyPair,
generatePublicKey,
const bls: IBls = {
sign,
aggregateSignatures,
aggregatePubkeys,
@ -137,10 +119,12 @@ export default {
verifyAggregate,
verifyMultiple,
Keypair,
// Keypair,
PrivateKey,
PublicKey,
Signature,
initBLS,
destroy,
};
export default bls;

View File

@ -1,7 +1,8 @@
import {PublicKey} from "./publicKey";
import {PrivateKey} from "./privateKey";
import {IKeypair} from "../interface";
export class Keypair {
export class Keypair implements IKeypair {
private readonly _publicKey: PublicKey;
private readonly _privateKey: PrivateKey;

View File

@ -1,9 +1,10 @@
import * as blst from "@chainsafe/blst";
import {bytesToHex, getRandomBytes, hexToBytes} from "../helpers/utils";
import {IPrivateKey} from "../interface";
import {PublicKey} from "./publicKey";
import {Signature} from "./signature";
export class PrivateKey {
export class PrivateKey implements IPrivateKey {
readonly value: blst.SecretKey;
constructor(value: blst.SecretKey) {
@ -25,7 +26,7 @@ export class PrivateKey {
}
signMessage(message: Uint8Array): Signature {
return Signature.fromValue(this.value.sign(message));
return new Signature(this.value.sign(message));
}
toPublicKey(): PublicKey {

View File

@ -1,8 +1,9 @@
import * as blst from "@chainsafe/blst";
import {bytesToHex, hexToBytes} from "../helpers/utils";
import {IPublicKey} from "../interface";
import {Signature} from "./signature";
export class PublicKey {
export class PublicKey implements IPublicKey {
readonly affine: blst.PublicKey;
readonly jacobian: blst.AggregatePublicKey;

View File

@ -1,8 +1,9 @@
import * as blst from "@chainsafe/blst";
import {bytesToHex, hexToBytes} from "../helpers/utils";
import {ISignature} from "../interface";
import {PublicKey} from "./publicKey";
export class Signature {
export class Signature implements ISignature {
readonly affine: blst.Signature;
constructor(value: blst.Signature) {
@ -17,10 +18,6 @@ export class Signature {
return this.fromBytes(hexToBytes(hex));
}
static fromValue(signature: blst.Signature): Signature {
return new Signature(signature);
}
static aggregate(signatures: Signature[]): Signature {
const agg = blst.AggregateSignature.fromSignatures(signatures.map((sig) => sig.affine));
return new Signature(agg.toSignature());

View File

@ -3,18 +3,17 @@ import bls from "@chainsafe/eth2-bls-wasm";
type Bls = typeof bls;
let blsGlobal: Bls | null = null;
let blsGlobalPromise: Promise<Bls> | null = null;
let blsGlobalPromise: Promise<void> | null = null;
export async function setupBls(): Promise<Bls> {
export async function setupBls(): Promise<void> {
if (!blsGlobal) {
await bls.init();
blsGlobal = bls;
}
return blsGlobal;
}
// Cache a promise for Bls instead of Bls to make sure it is initialized only once
export async function initBLS(): Promise<Bls> {
export async function initBLS(): Promise<void> {
if (!blsGlobalPromise) {
blsGlobalPromise = setupBls();
}

View File

@ -5,26 +5,10 @@ import {Signature} from "./signature";
import {initBLS, destroy} from "./context";
import assert from "assert";
import {toBuffer} from "../helpers/utils";
import {IBls} from "../interface";
export {Keypair, PrivateKey, PublicKey, Signature, initBLS, destroy};
/**
* Generates new secret and public key
*/
export function generateKeyPair(): Keypair {
return Keypair.generate();
}
/**
* Generates public key from given secret.
* @param {BLSSecretKey} secretKey
*/
export function generatePublicKey(secretKey: Uint8Array): Buffer {
assert(secretKey, "secretKey is null or undefined");
const keypair = new Keypair(PrivateKey.fromBytes(toBuffer(secretKey)));
return keypair.publicKey.toBytes();
}
/**
* Signs given message using secret key.
* @param secretKey
@ -121,9 +105,7 @@ export function verifyMultiple(publicKeys: Uint8Array[], messageHashes: Uint8Arr
}
}
export default {
generateKeyPair,
generatePublicKey,
const bls: IBls = {
sign,
aggregateSignatures,
aggregatePubkeys,
@ -131,10 +113,12 @@ export default {
verifyAggregate,
verifyMultiple,
Keypair,
// Keypair,
PrivateKey,
PublicKey,
Signature,
initBLS,
destroy,
};
export default bls;

View File

@ -1,7 +1,8 @@
import {PublicKey} from "./publicKey";
import {PrivateKey} from "./privateKey";
import {IKeypair} from "../interface";
export class Keypair {
export class Keypair implements IKeypair {
private readonly _publicKey: PublicKey;
private readonly _privateKey: PrivateKey;

View File

@ -6,8 +6,9 @@ import {getContext} from "./context";
import {PublicKey} from "./publicKey";
import {Signature} from "./signature";
import {bytesToHex, hexToBytes} from "../helpers/utils";
import {IPrivateKey} from "../interface";
export class PrivateKey {
export class PrivateKey implements IPrivateKey {
readonly value: SecretKeyType;
constructor(value: SecretKeyType) {

View File

@ -3,8 +3,9 @@ import {getContext} from "./context";
import {EMPTY_PUBLIC_KEY} from "../constants";
import {Signature} from "./signature";
import {bytesToHex, hexToBytes, isEqualBytes} from "../helpers/utils";
import {IPublicKey} from "../interface";
export class PublicKey {
export class PublicKey implements IPublicKey {
readonly value: PublicKeyType;
constructor(value: PublicKeyType) {

View File

@ -4,8 +4,9 @@ import {SignatureType} from "@chainsafe/eth2-bls-wasm";
import {getContext} from "./context";
import {PublicKey} from "./publicKey";
import {bytesToHex, hexToBytes, isEqualBytes} from "../helpers/utils";
import {ISignature} from "../interface";
export class Signature {
export class Signature implements ISignature {
readonly value: SignatureType;
constructor(value: SignatureType) {

53
src/interface.ts Normal file
View File

@ -0,0 +1,53 @@
export interface IBls {
PrivateKey: {
fromBytes(bytes: Uint8Array): IPrivateKey;
fromHex(hex: string): IPrivateKey;
fromKeygen(): IPrivateKey;
};
PublicKey: {
fromBytes(bytes: Uint8Array): IPublicKey;
fromHex(hex: string): IPublicKey;
aggregate(pubkeys: IPublicKey[]): IPublicKey;
};
Signature: {
fromBytes(bytes: Uint8Array): ISignature;
fromHex(hex: string): ISignature;
aggregate(signatures: ISignature[]): ISignature;
};
sign(secretKey: Uint8Array, messageHash: Uint8Array): Buffer;
aggregatePubkeys(publicKeys: Uint8Array[]): Buffer;
aggregateSignatures(signatures: Uint8Array[]): Buffer;
verify(publicKey: Uint8Array, messageHash: Uint8Array, signature: Uint8Array): boolean;
verifyAggregate(publicKeys: Uint8Array[], messageHash: Uint8Array, signature: Uint8Array): boolean;
verifyMultiple(publicKeys: Uint8Array[], messageHashes: Uint8Array[], signature: Uint8Array): boolean;
initBLS: () => Promise<void>;
destroy: () => void;
}
export interface IKeypair {
publicKey: IPublicKey;
privateKey: IPrivateKey;
}
export interface IPublicKey {
toBytes(): Buffer;
toHex(): string;
}
export interface ISignature {
toBytes(): Buffer;
toHex(): string;
verify(publicKey: IPublicKey, message: Uint8Array): boolean;
verifyAggregate(publicKeys: IPublicKey[], message: Uint8Array): boolean;
verifyMultiple(publicKeys: IPublicKey[], messages: Uint8Array[]): boolean;
}
export interface IPrivateKey {
value: any;
toPublicKey(): IPublicKey;
signMessage(message: Uint8Array): ISignature;
toBytes(): Buffer;
toHex(): string;
}

View File

@ -1,11 +1,11 @@
import blst from "../src/blst";
import herumi from "../src/herumi";
import {IBls} from "../src/interface";
export type Implementation = "blst" | "herumi";
export const implementations: Implementation[] = ["blst", "herumi"];
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
export function getBls(implementation: Implementation) {
export function getBls(implementation: Implementation): IBls {
switch (implementation) {
case "blst":
return blst;
@ -15,17 +15,16 @@ export function getBls(implementation: Implementation) {
}
export function forEachImplementation(
implementations: Implementation[],
callback: (bls: ReturnType<typeof getBls>, implementation: Implementation) => void
): void {
for (const implementation of implementations) {
describe(implementation, () => {
const bls = getBls(implementation);
if (implementation === "herumi") {
before(async () => {
await bls.initBLS();
});
}
before(async () => {
await bls.initBLS();
});
callback(bls, implementation);
});

View File

@ -1,8 +1,8 @@
import {expect} from "chai";
import {forEachImplementation} from "../switch";
import {IBls} from "../../src/interface";
import {getN, randomMessage} from "../util";
forEachImplementation((bls) => {
export function runIndexTests(bls: IBls) {
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
function getRandomData() {
const sk = bls.PrivateKey.fromKeygen();
@ -95,4 +95,4 @@ forEachImplementation((bls) => {
expect(isValid).to.be.false;
});
});
});
}

View File

@ -1,27 +1,27 @@
import {expect} from "chai";
import {forEachImplementation} from "../switch";
// import {expect} from "chai";
// import {IBls} from "../../src/interface";
forEachImplementation((bls) => {
describe("Keypair", () => {
it("should create from private and public key", () => {
const sk = bls.PrivateKey.fromKeygen();
const sk2 = bls.PrivateKey.fromKeygen();
const pk = sk.toPublicKey();
// export function runKeypairTests(bls: IBls) {
// describe("Keypair", () => {
// it("should create from private and public key", () => {
// const sk = bls.PrivateKey.fromKeygen();
// const sk2 = bls.PrivateKey.fromKeygen();
// const pk = sk.toPublicKey();
const keypair = new bls.Keypair(sk as any, pk as any);
// const keypair = new bls.Keypair(sk, pk);
expect(keypair.publicKey).to.be.equal(pk);
expect(keypair.privateKey).to.be.equal(sk);
expect(keypair.privateKey).to.not.be.equal(sk2);
});
// expect(keypair.publicKey).to.be.equal(pk);
// expect(keypair.privateKey).to.be.equal(sk);
// expect(keypair.privateKey).to.not.be.equal(sk2);
// });
it("should create from PrivateKey", () => {
const sk = bls.PrivateKey.fromKeygen();
const pk = sk.toPublicKey();
// it("should create from PrivateKey", () => {
// const sk = bls.PrivateKey.fromKeygen();
// const pk = sk.toPublicKey();
const keypair = new bls.Keypair(sk as any);
// const keypair = new bls.Keypair(sk as any);
expect(keypair.publicKey.toHex()).to.equal(pk.toHex());
});
});
});
// expect(keypair.publicKey.toHex()).to.equal(pk.toHex());
// });
// });
// }

View File

@ -1,7 +1,7 @@
import {expect} from "chai";
import {forEachImplementation} from "../switch";
import {IBls} from "../../src/interface";
forEachImplementation((bls) => {
export function runPrivateKeyTests(bls: IBls) {
describe("PrivateKey", () => {
it("should generate fromKeygen private key", () => {
const privateKey1 = bls.PrivateKey.fromKeygen();
@ -23,4 +23,4 @@ forEachImplementation((bls) => {
expect(() => bls.PrivateKey.fromHex("0x2123")).to.throw();
});
});
});
}

View File

@ -1,7 +1,7 @@
import {expect} from "chai";
import {forEachImplementation} from "../switch";
import {IBls} from "../../src/interface";
forEachImplementation((bls) => {
export function runPublicKeyTests(bls: IBls) {
describe("PublicKey", () => {
const publicKey =
"0xb6f21199594b56d77670564bf422cb331d5281ca2c1f9a45588a56881d8287ef8619efa6456d6cd2ef61306aa5b21311";
@ -18,4 +18,4 @@ forEachImplementation((bls) => {
bls.PrivateKey.fromKeygen().toPublicKey();
});
});
});
}

View File

@ -0,0 +1,12 @@
import {runPrivateKeyTests} from "./privateKey.test";
import {runPublicKeyTests} from "./publicKey.test";
// import {runKeypairTests} from "./keypair.test";
import {runIndexTests} from "./index.test";
import {forEachImplementation} from "../switch";
forEachImplementation(["blst", "herumi"], (bls) => {
runPrivateKeyTests(bls);
runPublicKeyTests(bls);
// runKeypairTests(bls);
runIndexTests(bls);
});

View File

@ -0,0 +1,12 @@
import {runPrivateKeyTests} from "./privateKey.test";
import {runPublicKeyTests} from "./publicKey.test";
// import {runKeypairTests} from "./keypair.test";
import {runIndexTests} from "./index.test";
import {forEachImplementation} from "../switch";
forEachImplementation(["herumi"], (bls) => {
runPrivateKeyTests(bls);
runPublicKeyTests(bls);
// runKeypairTests(bls);
runIndexTests(bls);
});