bls wasm context and private key converted to wasm implementation
This commit is contained in:
parent
654db6864d
commit
d5d8284be5
|
@ -41,6 +41,7 @@
|
||||||
"@chainsafe/eth2.0-types": "^0.1.0",
|
"@chainsafe/eth2.0-types": "^0.1.0",
|
||||||
"@chainsafe/milagro-crypto-js": "0.1.3",
|
"@chainsafe/milagro-crypto-js": "0.1.3",
|
||||||
"assert": "^1.4.1",
|
"assert": "^1.4.1",
|
||||||
|
"bls-wasm": "^0.2.7",
|
||||||
"js-sha256": "^0.9.0",
|
"js-sha256": "^0.9.0",
|
||||||
"secure-random": "^1.1.1"
|
"secure-random": "^1.1.1"
|
||||||
},
|
},
|
||||||
|
|
|
@ -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");
|
||||||
|
}
|
|
@ -1,63 +1,56 @@
|
||||||
import {BIG} from "@chainsafe/milagro-crypto-js/src/big";
|
import {SECRET_KEY_LENGTH} from "./constants";
|
||||||
import {FP_POINT_LENGTH, SECRET_KEY_LENGTH} from "./constants";
|
|
||||||
import assert from "assert";
|
import assert from "assert";
|
||||||
import ctx from "./ctx";
|
import {BLSSecretKey, Domain, Hash} from "@chainsafe/eth2.0-types";
|
||||||
import {padLeft} from "./helpers/utils";
|
import {SecretKeyType, SignatureType} from "@chainsafe/eth2-bls-wasm";
|
||||||
import {G2point} from "./helpers/g2point";
|
import {getContext} from "./context";
|
||||||
import * as random from "secure-random";
|
|
||||||
import {BLSSecretKey, Hash, Domain} from "@chainsafe/eth2.0-types";
|
|
||||||
|
|
||||||
export class PrivateKey {
|
export class PrivateKey {
|
||||||
|
|
||||||
private value: BIG;
|
private value: SecretKeyType;
|
||||||
|
|
||||||
public constructor(value: BIG) {
|
protected constructor(value: SecretKeyType) {
|
||||||
this.value = value;
|
this.value = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static fromBytes(bytes: Uint8Array): PrivateKey {
|
public static fromBytes(bytes: Uint8Array): PrivateKey {
|
||||||
assert(bytes.length === SECRET_KEY_LENGTH, "Private key should have 32 bytes");
|
assert(bytes.length === SECRET_KEY_LENGTH, "Private key should have 32 bytes");
|
||||||
const value = Buffer.from(bytes);
|
const context = getContext();
|
||||||
return new PrivateKey(
|
const secretKey = new context.SecretKey();
|
||||||
ctx.BIG.frombytearray(
|
secretKey.deserialize(Buffer.from(bytes));
|
||||||
padLeft(
|
return new PrivateKey(secretKey);
|
||||||
value,
|
|
||||||
48
|
|
||||||
),
|
|
||||||
0
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static fromHexString(value: string): PrivateKey {
|
public static fromHexString(value: string): PrivateKey {
|
||||||
return PrivateKey.fromBytes(
|
value = value.replace("0x", "");
|
||||||
Buffer.from(value.replace("0x", ""), "hex")
|
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 {
|
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;
|
return this.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public sign(message: G2point): G2point {
|
public sign(message: Uint8Array): SignatureType {
|
||||||
return message.mul(this.value);
|
return this.value.sign(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
public signMessage(message: Hash, domain: Domain): G2point {
|
public signMessage(message: Hash, domain: Domain): SignatureType {
|
||||||
return G2point.hashToG2(message, domain).mul(this.value);
|
return this.value.signHashWithDomain(Buffer.concat([message, domain]));
|
||||||
}
|
}
|
||||||
|
|
||||||
public toBytes(): BLSSecretKey {
|
public toBytes(): BLSSecretKey {
|
||||||
const buffer = Buffer.alloc(FP_POINT_LENGTH, 0);
|
return Buffer.from(this.value.serialize());
|
||||||
this.value.tobytearray(buffer, 0);
|
|
||||||
return buffer.slice(FP_POINT_LENGTH - SECRET_KEY_LENGTH);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public toHexString(): string {
|
public toHexString(): string {
|
||||||
return `0x${this.toBytes().toString("hex")}`;
|
return `0x${this.value.serializeToHexStr()}`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
|
@ -1,22 +1,40 @@
|
||||||
import {PrivateKey} from "../../src/privateKey";
|
import {PrivateKey} from "../../src/privateKey";
|
||||||
import {expect} from "chai";
|
import {expect} from "chai";
|
||||||
import {SECRET_KEY_LENGTH} from "../../src/constants";
|
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 () {
|
before(async function () {
|
||||||
const privateKey1 = PrivateKey.random();
|
await init();
|
||||||
const privateKey2 = PrivateKey.random();
|
});
|
||||||
expect(privateKey1).to.not.be.equal(privateKey2);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should export private key to hex string', function () {
|
after(function () {
|
||||||
const privateKey = '0x9a88071ff0634f6515c7699c97d069dc4b2fa28455f6b457e92d1c1302f0c6bb';
|
destroy();
|
||||||
expect(PrivateKey.fromHexString(privateKey).toHexString()).to.be.equal(privateKey);
|
});
|
||||||
});
|
|
||||||
|
|
||||||
it('should export private key to bytes', function () {
|
it("should generate random private key", function () {
|
||||||
expect(PrivateKey.random().toBytes().length).to.be.equal(SECRET_KEY_LENGTH);
|
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();
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
{
|
||||||
|
"extends": "../../tsconfig",
|
||||||
|
"include": ["src"],
|
||||||
|
"compilerOptions": {
|
||||||
|
"typeRoots": [
|
||||||
|
"src/@types",
|
||||||
|
"../../node_modules/@types"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"extends": "../../tsconfig",
|
"extends": "../../tsconfig",
|
||||||
"include": ["src"],
|
"include": ["src", "test"],
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"typeRoots": [
|
"typeRoots": [
|
||||||
"src/@types",
|
"src/@types",
|
||||||
|
|
Reference in New Issue