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/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"
|
||||
},
|
||||
|
|
|
@ -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 {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()}`;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 {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();
|
||||
});
|
||||
|
||||
});
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"extends": "../../tsconfig",
|
||||
"include": ["src"],
|
||||
"compilerOptions": {
|
||||
"typeRoots": [
|
||||
"src/@types",
|
||||
"../../node_modules/@types"
|
||||
]
|
||||
}
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"extends": "../../tsconfig",
|
||||
"include": ["src"],
|
||||
"include": ["src", "test"],
|
||||
"compilerOptions": {
|
||||
"typeRoots": [
|
||||
"src/@types",
|
||||
|
|
Reference in New Issue