abstract herumi
This commit is contained in:
parent
34f285e779
commit
0d273a7d36
|
@ -1,34 +1,38 @@
|
||||||
/* eslint-disable require-atomic-updates */
|
import herumi from "bls-eth-wasm";
|
||||||
import bls from "bls-eth-wasm";
|
import { herumiToIBls } from "./herumi";
|
||||||
|
import { IBls } from "./interface";
|
||||||
|
|
||||||
type Bls = typeof bls;
|
export type Backing = "herumi" | "blst-native" | "blst-wasm";
|
||||||
let blsGlobal: Bls | null = null;
|
|
||||||
let blsGlobalPromise: Promise<Bls> | null = null;
|
|
||||||
|
|
||||||
export async function setupBls(): Promise<Bls> {
|
let backing: Backing|undefined = undefined;
|
||||||
if (!blsGlobal) {
|
let context: IBls|undefined = undefined;
|
||||||
await bls.init();
|
|
||||||
blsGlobal = bls;
|
|
||||||
}
|
|
||||||
return blsGlobal;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cache a promise for Bls instead of Bls to make sure it is initialized only once
|
//to maintain api compatible, add all backing context to return type
|
||||||
export async function init(): Promise<Bls> {
|
export async function init(backing: Backing = "herumi"): Promise<IBls> {
|
||||||
if (!blsGlobalPromise) {
|
if (!context) {
|
||||||
blsGlobalPromise = setupBls();
|
switch(backing) {
|
||||||
|
case "herumi": {
|
||||||
|
context = await herumiToIBls();
|
||||||
|
backing = backing;
|
||||||
|
} break;
|
||||||
|
default: throw new Error(`Unsupported backing - ${backing}`)
|
||||||
}
|
}
|
||||||
return blsGlobalPromise;
|
}
|
||||||
|
await context.init();
|
||||||
|
return context;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function destroy(): void {
|
export function destroy(): void {
|
||||||
blsGlobal = null;
|
if(context) {
|
||||||
blsGlobalPromise = null;
|
context.destroy();
|
||||||
|
}
|
||||||
|
context = undefined;
|
||||||
|
backing = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getContext(): Bls {
|
export function getContext(): IBls {
|
||||||
if (!blsGlobal) {
|
if (!context) {
|
||||||
throw new Error("BLS not initialized");
|
throw new Error("BLS not initialized");
|
||||||
}
|
}
|
||||||
return blsGlobal;
|
return context;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
import herumi from "bls-eth-wasm";
|
||||||
|
import { init as initHerumi, destroy, getContext } from "./context";
|
||||||
|
import { IBls, IPrivateKeyValue, IPublicKeyValue, ISignatureValue } from '../interface';
|
||||||
|
|
||||||
|
export async function herumiToIBls(): Promise<IBls> {
|
||||||
|
await initHerumi();
|
||||||
|
const context: IBls = {
|
||||||
|
SecretKey: getContext().SecretKey as IPrivateKeyValue,
|
||||||
|
PublicKey: getContext().PublicKey as IPublicKeyValue,
|
||||||
|
Signature: getContext().Signature as ISignatureValue,
|
||||||
|
|
||||||
|
toHex: herumi.toHex,
|
||||||
|
toHexStr: herumi.toHexStr,
|
||||||
|
fromHexStr: herumi.fromHexStr,
|
||||||
|
getCurveOrder: herumi.getCurveOrder,
|
||||||
|
getFieldOrder: herumi.getFieldOrder,
|
||||||
|
verifySignatureOrder: herumi.verifySignatureOrder,
|
||||||
|
verifyPublicKeyOrder: herumi.verifyPublicKeyOrder,
|
||||||
|
areAllMsgDifferent: herumi.areAllMsgDifferent,
|
||||||
|
shouldVerifyBlsSignatureOrder: herumi.shouldVerifyBlsSignatureOrder,
|
||||||
|
shouldVerifyBlsPublicKeyOrder: herumi.shouldVerifyBlsPublicKeyOrder,
|
||||||
|
deserializeHexStrToSecretKey: herumi.deserializeHexStrToSecretKey as IBls["deserializeHexStrToSecretKey"],
|
||||||
|
deserializeHexStrToPublicKey: herumi.deserializeHexStrToPublicKey as IBls["deserializeHexStrToPublicKey"],
|
||||||
|
deserializeHexStrToSignature: herumi.deserializeHexStrToSignature as IBls["deserializeHexStrToSignature"],
|
||||||
|
init: async () => {
|
||||||
|
return context;
|
||||||
|
},
|
||||||
|
destroy: () => {
|
||||||
|
destroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return context;
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
/* eslint-disable require-atomic-updates */
|
||||||
|
import bls from "bls-eth-wasm";
|
||||||
|
|
||||||
|
type Bls = typeof bls;
|
||||||
|
let blsGlobal: Bls | null = null;
|
||||||
|
let blsGlobalPromise: Promise<Bls> | null = null;
|
||||||
|
|
||||||
|
export async function setupBls(): Promise<Bls> {
|
||||||
|
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 init(): Promise<Bls> {
|
||||||
|
if (!blsGlobalPromise) {
|
||||||
|
blsGlobalPromise = setupBls();
|
||||||
|
}
|
||||||
|
return blsGlobalPromise;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function destroy(): void {
|
||||||
|
blsGlobal = null;
|
||||||
|
blsGlobalPromise = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getContext(): Bls {
|
||||||
|
if (!blsGlobal) {
|
||||||
|
throw new Error("BLS not initialized");
|
||||||
|
}
|
||||||
|
return blsGlobal;
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
export {herumiToIBls} from "./adapter";
|
|
@ -1,9 +1,9 @@
|
||||||
|
import {PUBLIC_KEY_LENGTH} from "./constants";
|
||||||
|
import assert from "assert";
|
||||||
import { Keypair } from "./keypair";
|
import { Keypair } from "./keypair";
|
||||||
import { PrivateKey } from "./privateKey";
|
import { PrivateKey } from "./privateKey";
|
||||||
import { PublicKey } from "./publicKey";
|
import { PublicKey } from "./publicKey";
|
||||||
import { Signature } from "./signature";
|
import { Signature } from "./signature";
|
||||||
import {PUBLIC_KEY_LENGTH} from "./constants";
|
|
||||||
import assert from "assert";
|
|
||||||
|
|
||||||
export {Keypair, PrivateKey, PublicKey, Signature};
|
export {Keypair, PrivateKey, PublicKey, Signature};
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,90 @@
|
||||||
|
interface Common {
|
||||||
|
|
||||||
|
new(): this;
|
||||||
|
|
||||||
|
deserializeHexStr(s: string): void;
|
||||||
|
|
||||||
|
serializeToHexStr(): string;
|
||||||
|
|
||||||
|
isEqual(rhs: this): boolean
|
||||||
|
|
||||||
|
deserialize(v: Uint8Array): void;
|
||||||
|
|
||||||
|
serialize(): Uint8Array;
|
||||||
|
|
||||||
|
add(rhs: this): void;
|
||||||
|
|
||||||
|
dump(msg?: string): string;
|
||||||
|
|
||||||
|
clear(): void;
|
||||||
|
|
||||||
|
clone(): this;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IPrivateKeyValue extends Common {
|
||||||
|
|
||||||
|
setInt(x: number): void;
|
||||||
|
|
||||||
|
setHashOf(a: Uint8Array): void;
|
||||||
|
|
||||||
|
setLittleEndian(a: Uint8Array): void;
|
||||||
|
|
||||||
|
setByCSPRNG(): void;
|
||||||
|
|
||||||
|
getPublicKey(): IPublicKeyValue;
|
||||||
|
|
||||||
|
sign(m: string | Uint8Array): ISignatureValue;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IPublicKeyValue extends Common {
|
||||||
|
|
||||||
|
verify(signature: ISignatureValue, m: Uint8Array | string): boolean;
|
||||||
|
isValidOrder(): boolean;
|
||||||
|
deserializeUncompressed (s: Uint8Array): void;
|
||||||
|
serializeUncompressed (): Uint8Array;
|
||||||
|
deserializeUncompressedHexStr (s:string): void;
|
||||||
|
serializeUncompressedToHexStr(): string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ISignatureValue extends Common {
|
||||||
|
|
||||||
|
deserializeUncompressed (s: Uint8Array): void;
|
||||||
|
serializeUncompressed (): Uint8Array;
|
||||||
|
deserializeUncompressedHexStr (s:string): void;
|
||||||
|
serializeUncompressedToHexStr(): string;
|
||||||
|
isValidOrder(): boolean;
|
||||||
|
aggregate(others: ISignatureValue[]): boolean;
|
||||||
|
aggregateVerifyNoCheck(publicKeys: IPublicKeyValue[], messages: Uint8Array): boolean;
|
||||||
|
fastAggregateVerify(publicKeys: IPublicKeyValue[], message: Uint8Array): boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IBls {
|
||||||
|
//property names are like that for api compatibility
|
||||||
|
SecretKey: InstanceType<IPrivateKeyValue>;
|
||||||
|
PublicKey: InstanceType<IPublicKeyValue>;
|
||||||
|
Signature: InstanceType<ISignatureValue>;
|
||||||
|
|
||||||
|
toHex(a: Uint8Array, start: number, length: number): string;
|
||||||
|
toHexStr(a: Uint8Array): string;
|
||||||
|
fromHexStr(s: string): Uint8Array;
|
||||||
|
getCurveOrder(): string;
|
||||||
|
getFieldOrder(): string;
|
||||||
|
verifySignatureOrder(doVerify: boolean): void;
|
||||||
|
verifyPublicKeyOrder(doVerify: boolean): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param msgs single array with concatenated messages
|
||||||
|
* @param msgSize defaults to MSG_SIZE
|
||||||
|
*/
|
||||||
|
areAllMsgDifferent(msgs: Uint8Array, msgSize?: number): boolean;
|
||||||
|
shouldVerifyBlsSignatureOrder(b: string): void;
|
||||||
|
shouldVerifyBlsPublicKeyOrder(b: string): void;
|
||||||
|
deserializeHexStrToSecretKey(s: string): IPrivateKeyValue;
|
||||||
|
deserializeHexStrToPublicKey(s: string): IPublicKeyValue;
|
||||||
|
deserializeHexStrToSignature(s: string): ISignatureValue;
|
||||||
|
|
||||||
|
init(): Promise<this>;
|
||||||
|
destroy(): void;
|
||||||
|
}
|
|
@ -1,15 +1,14 @@
|
||||||
import {SECRET_KEY_LENGTH} from "./constants";
|
import {SECRET_KEY_LENGTH} from "./constants";
|
||||||
import assert from "assert";
|
import assert from "assert";
|
||||||
import {SecretKeyType} from "bls-eth-wasm";
|
|
||||||
import {generateRandomSecretKey} from "@chainsafe/bls-keygen";
|
import {generateRandomSecretKey} from "@chainsafe/bls-keygen";
|
||||||
|
import { IPrivateKeyValue } from "./interface";
|
||||||
import { getContext } from "./context";
|
import { getContext } from "./context";
|
||||||
import {PublicKey} from "./publicKey";
|
import { PublicKey, Signature } from ".";
|
||||||
import {Signature} from "./signature";
|
|
||||||
|
|
||||||
export class PrivateKey {
|
export class PrivateKey {
|
||||||
private value: SecretKeyType;
|
private value: IPrivateKeyValue;
|
||||||
|
|
||||||
protected constructor(value: SecretKeyType) {
|
protected constructor(value: IPrivateKeyValue) {
|
||||||
this.value = value;
|
this.value = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,7 +24,9 @@ export class PrivateKey {
|
||||||
value = value.replace("0x", "");
|
value = value.replace("0x", "");
|
||||||
assert(value.length === SECRET_KEY_LENGTH * 2, "secret key must have 32 bytes");
|
assert(value.length === SECRET_KEY_LENGTH * 2, "secret key must have 32 bytes");
|
||||||
const context = getContext();
|
const context = getContext();
|
||||||
return new PrivateKey(context.deserializeHexStrToSecretKey(value));
|
const secretKeyValue = new context.SecretKey();
|
||||||
|
secretKeyValue.deserializeHexStr(value);
|
||||||
|
return new PrivateKey(secretKeyValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static fromInt(num: number): PrivateKey {
|
public static fromInt(num: number): PrivateKey {
|
||||||
|
@ -40,7 +41,7 @@ export class PrivateKey {
|
||||||
return this.fromBytes(randomKey);
|
return this.fromBytes(randomKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
public getValue(): SecretKeyType {
|
public getValue(): IPrivateKeyValue {
|
||||||
return this.value;
|
return this.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,15 +1,15 @@
|
||||||
import {PrivateKey} from "./privateKey";
|
import {PrivateKey} from "./privateKey";
|
||||||
import {PublicKeyType} from "bls-eth-wasm";
|
|
||||||
import {getContext} from "./context";
|
|
||||||
import {PUBLIC_KEY_LENGTH} from "./constants";
|
import {PUBLIC_KEY_LENGTH} from "./constants";
|
||||||
import assert from "assert";
|
import assert from "assert";
|
||||||
import {Signature} from "./signature";
|
import {Signature} from "./signature";
|
||||||
import {EMPTY_PUBLIC_KEY} from "./helpers/utils";
|
import {EMPTY_PUBLIC_KEY} from "./helpers/utils";
|
||||||
|
import { IPublicKeyValue } from './interface';
|
||||||
|
import { getContext } from "./context";
|
||||||
|
|
||||||
export class PublicKey {
|
export class PublicKey {
|
||||||
private value: PublicKeyType;
|
private value: IPublicKeyValue;
|
||||||
|
|
||||||
protected constructor(value: PublicKeyType) {
|
protected constructor(value: IPublicKeyValue) {
|
||||||
this.value = value;
|
this.value = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,10 +30,12 @@ export class PublicKey {
|
||||||
value = value.replace("0x", "");
|
value = value.replace("0x", "");
|
||||||
assert(value.length === PUBLIC_KEY_LENGTH * 2);
|
assert(value.length === PUBLIC_KEY_LENGTH * 2);
|
||||||
const context = getContext();
|
const context = getContext();
|
||||||
return new PublicKey(context.deserializeHexStrToPublicKey(value));
|
const pubkeyValue = new context.PublicKey();
|
||||||
|
pubkeyValue.deserializeHexStr(value)
|
||||||
|
return new PublicKey(pubkeyValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static fromPublicKeyType(value: PublicKeyType): PublicKey {
|
public static fromPublicKeyType(value: IPublicKeyValue): PublicKey {
|
||||||
return new PublicKey(value);
|
return new PublicKey(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -55,7 +57,7 @@ export class PublicKey {
|
||||||
return `0x${this.toBytesCompressed().toString("hex")}`;
|
return `0x${this.toBytesCompressed().toString("hex")}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
public getValue(): PublicKeyType {
|
public getValue(): IPublicKeyValue {
|
||||||
return this.value;
|
return this.value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
import assert from "assert";
|
import assert from "assert";
|
||||||
import { FP_POINT_LENGTH } from "./constants";
|
import { FP_POINT_LENGTH } from "./constants";
|
||||||
import {SignatureType} from "bls-eth-wasm";
|
|
||||||
import { getContext } from "./context";
|
import { getContext } from "./context";
|
||||||
import {PublicKey} from "./publicKey";
|
|
||||||
import { EMPTY_SIGNATURE } from "./helpers/utils";
|
import { EMPTY_SIGNATURE } from "./helpers/utils";
|
||||||
|
import { ISignatureValue } from './interface';
|
||||||
|
import { PublicKey } from "./publicKey";
|
||||||
|
|
||||||
export class Signature {
|
export class Signature {
|
||||||
private value: SignatureType;
|
private value: ISignatureValue;
|
||||||
|
|
||||||
protected constructor(value: SignatureType) {
|
protected constructor(value: ISignatureValue) {
|
||||||
this.value = value;
|
this.value = value;
|
||||||
assert(this.value.isValidOrder());
|
assert(this.value.isValidOrder());
|
||||||
}
|
}
|
||||||
|
@ -23,7 +23,7 @@ export class Signature {
|
||||||
return new Signature(signature);
|
return new Signature(signature);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static fromValue(signature: SignatureType): Signature {
|
public static fromValue(signature: ISignatureValue): Signature {
|
||||||
return new Signature(signature);
|
return new Signature(signature);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,7 +40,7 @@ export class Signature {
|
||||||
return new Signature(agg);
|
return new Signature(agg);
|
||||||
}
|
}
|
||||||
|
|
||||||
public getValue(): SignatureType {
|
public getValue(): ISignatureValue {
|
||||||
return this.value;
|
return this.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -37,12 +37,6 @@ declare module "bls-eth-wasm" {
|
||||||
getPublicKey(): PublicKeyType;
|
getPublicKey(): PublicKeyType;
|
||||||
|
|
||||||
sign(m: string | Uint8Array): SignatureType;
|
sign(m: string | Uint8Array): SignatureType;
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param m must have 40 bytes
|
|
||||||
*/
|
|
||||||
signHashWithDomain(m: Uint8Array): SignatureType;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export class PublicKeyType extends Common {
|
export class PublicKeyType extends Common {
|
||||||
|
@ -55,12 +49,6 @@ declare module "bls-eth-wasm" {
|
||||||
serializeUncompressed (): Uint8Array;
|
serializeUncompressed (): Uint8Array;
|
||||||
deserializeUncompressedHexStr (s:string): void;
|
deserializeUncompressedHexStr (s:string): void;
|
||||||
serializeUncompressedToHexStr(): string;
|
serializeUncompressedToHexStr(): string;
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param signature
|
|
||||||
* @param m must have 40 bytes
|
|
||||||
*/
|
|
||||||
verifyHashWithDomain(signature: SignatureType, m: Uint8Array): boolean;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export class SignatureType extends Common {
|
export class SignatureType extends Common {
|
||||||
|
@ -74,12 +62,6 @@ declare module "bls-eth-wasm" {
|
||||||
aggregate(others: SignatureType[]): boolean;
|
aggregate(others: SignatureType[]): boolean;
|
||||||
aggregateVerifyNoCheck(publicKeys: PublicKeyType[], messages: Uint8Array): boolean;
|
aggregateVerifyNoCheck(publicKeys: PublicKeyType[], messages: Uint8Array): boolean;
|
||||||
fastAggregateVerify(publicKeys: PublicKeyType[], message: Uint8Array): boolean;
|
fastAggregateVerify(publicKeys: PublicKeyType[], message: Uint8Array): boolean;
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param publicKeys
|
|
||||||
* @param messages each message must have 40bytes
|
|
||||||
*/
|
|
||||||
verifyAggregatedHashWithDomain(publicKeys: PublicKeyType[], messages: Uint8Array[]): boolean
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -105,7 +87,7 @@ declare module "bls-eth-wasm" {
|
||||||
export function deserializeHexStrToPublicKey(s: string): PublicKeyType;
|
export function deserializeHexStrToPublicKey(s: string): PublicKeyType;
|
||||||
export function deserializeHexStrToSignature(s: string): SignatureType;
|
export function deserializeHexStrToSignature(s: string): SignatureType;
|
||||||
|
|
||||||
export const SecretKey: typeof SecretKeyType;
|
export const SecretKey: InstanceType<typeof SecretKeyType>;
|
||||||
export const PublicKey: typeof PublicKeyType;
|
export const PublicKey: InstanceType<typeof PublicKeyType>;
|
||||||
export const Signature: typeof SignatureType;
|
export const Signature: InstanceType<typeof SignatureType>;
|
||||||
}
|
}
|
Reference in New Issue