bls wasm context and private key converted to wasm implementation

This commit is contained in:
Marin Petrunić 2019-11-27 19:21:37 +01:00
parent 654db6864d
commit d5d8284be5
7 changed files with 109 additions and 46 deletions

View File

@ -41,6 +41,7 @@
"@chainsafe/eth2.0-types": "^0.1.0",
"@chainsafe/milagro-crypto-js": "0.1.3",
"assert": "^1.4.1",
"bls-wasm": "^0.2.7",
"js-sha256": "^0.9.0",
"secure-random": "^1.1.1"
},

21
src/context.ts Normal file
View File

@ -0,0 +1,21 @@
// eslint-disable-next-line import/no-extraneous-dependencies
import blsWasmWrapper from "@chainsafe/eth2-bls-wasm";
let blsWrapper: typeof blsWasmWrapper | null = null;
export async function init(): Promise<typeof blsWasmWrapper> {
await blsWasmWrapper.init();
blsWrapper = blsWasmWrapper;
return blsWrapper;
}
export function destroy(): void {
blsWrapper = null;
}
export function getContext(): typeof blsWasmWrapper{
if(blsWrapper) {
return blsWrapper;
}
throw new Error("BLS not initialized");
}

View File

@ -1,63 +1,56 @@
import {BIG} from "@chainsafe/milagro-crypto-js/src/big";
import {FP_POINT_LENGTH, SECRET_KEY_LENGTH} from "./constants";
import {SECRET_KEY_LENGTH} from "./constants";
import assert from "assert";
import ctx from "./ctx";
import {padLeft} from "./helpers/utils";
import {G2point} from "./helpers/g2point";
import * as random from "secure-random";
import {BLSSecretKey, Hash, Domain} from "@chainsafe/eth2.0-types";
import {BLSSecretKey, Domain, Hash} from "@chainsafe/eth2.0-types";
import {SecretKeyType, SignatureType} from "@chainsafe/eth2-bls-wasm";
import {getContext} from "./context";
export class PrivateKey {
private value: BIG;
private value: SecretKeyType;
public constructor(value: BIG) {
protected constructor(value: SecretKeyType) {
this.value = value;
}
public static fromBytes(bytes: Uint8Array): PrivateKey {
assert(bytes.length === SECRET_KEY_LENGTH, "Private key should have 32 bytes");
const value = Buffer.from(bytes);
return new PrivateKey(
ctx.BIG.frombytearray(
padLeft(
value,
48
),
0
)
);
const context = getContext();
const secretKey = new context.SecretKey();
secretKey.deserialize(Buffer.from(bytes));
return new PrivateKey(secretKey);
}
public static fromHexString(value: string): PrivateKey {
return PrivateKey.fromBytes(
Buffer.from(value.replace("0x", ""), "hex")
);
value = value.replace("0x", "");
assert(value.length === SECRET_KEY_LENGTH * 2, "secret key must have 32 bytes");
const context = getContext();
return new PrivateKey(context.deserializeHexStrToSecretKey(value));
}
public static random(): PrivateKey {
return PrivateKey.fromBytes(random.randomBuffer(SECRET_KEY_LENGTH));
const context = getContext();
const secretKey = new context.SecretKey();
secretKey.setByCSPRNG();
return new PrivateKey(secretKey);
}
public getValue(): BIG {
public getValue(): SecretKeyType {
return this.value;
}
public sign(message: G2point): G2point {
return message.mul(this.value);
public sign(message: Uint8Array): SignatureType {
return this.value.sign(message);
}
public signMessage(message: Hash, domain: Domain): G2point {
return G2point.hashToG2(message, domain).mul(this.value);
public signMessage(message: Hash, domain: Domain): SignatureType {
return this.value.signHashWithDomain(Buffer.concat([message, domain]));
}
public toBytes(): BLSSecretKey {
const buffer = Buffer.alloc(FP_POINT_LENGTH, 0);
this.value.tobytearray(buffer, 0);
return buffer.slice(FP_POINT_LENGTH - SECRET_KEY_LENGTH);
return Buffer.from(this.value.serialize());
}
public toHexString(): string {
return `0x${this.toBytes().toString("hex")}`;
return `0x${this.value.serializeToHexStr()}`;
}
}

20
test/unit/context.test.ts Normal file
View File

@ -0,0 +1,20 @@
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();
});
});

View File

@ -1,22 +1,40 @@
import {PrivateKey} from "../../src/privateKey";
import {expect} from "chai";
import {SECRET_KEY_LENGTH} from "../../src/constants";
import {destroy, init} from "../../src/context";
describe('privateKey', function() {
describe("privateKey", function() {
it('should generate random private key', function () {
const privateKey1 = PrivateKey.random();
const privateKey2 = PrivateKey.random();
expect(privateKey1).to.not.be.equal(privateKey2);
});
before(async function () {
await init();
});
it('should export private key to hex string', function () {
const privateKey = '0x9a88071ff0634f6515c7699c97d069dc4b2fa28455f6b457e92d1c1302f0c6bb';
expect(PrivateKey.fromHexString(privateKey).toHexString()).to.be.equal(privateKey);
});
after(function () {
destroy();
});
it('should export private key to bytes', function () {
expect(PrivateKey.random().toBytes().length).to.be.equal(SECRET_KEY_LENGTH);
});
it("should generate random private key", function () {
const privateKey1 = PrivateKey.random();
const privateKey2 = PrivateKey.random();
expect(privateKey1.toHexString()).to.not.be.equal(privateKey2.toHexString());
});
it("should export private key to hex string", function () {
const privateKey = "0x07656fd676da43883d163f49566c72b9cbf0a5a294f26808c807700732456da7";
expect(PrivateKey.fromHexString(privateKey).toHexString()).to.be.equal(privateKey);
const privateKey2 = "07656fd676da43883d163f49566c72b9cbf0a5a294f26808c807700732456da7";
expect(PrivateKey.fromHexString(privateKey2).toHexString()).to.be.equal(privateKey);
});
it("should export private key to bytes", function () {
expect(PrivateKey.random().toBytes().length).to.be.equal(SECRET_KEY_LENGTH);
});
it("should not accept too short private key", function () {
expect(() => PrivateKey.fromHexString("0x2123")).to.throw();
});
});

10
tsconfig.build.json Normal file
View File

@ -0,0 +1,10 @@
{
"extends": "../../tsconfig",
"include": ["src"],
"compilerOptions": {
"typeRoots": [
"src/@types",
"../../node_modules/@types"
]
}
}

View File

@ -1,6 +1,6 @@
{
"extends": "../../tsconfig",
"include": ["src"],
"include": ["src", "test"],
"compilerOptions": {
"typeRoots": [
"src/@types",