Run prettier
This commit is contained in:
parent
fd4c67b67d
commit
c22069335f
|
@ -10,13 +10,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||||
## [4.0.0] - 2020-08-31
|
## [4.0.0] - 2020-08-31
|
||||||
|
|
||||||
### BREAKING CHANGES
|
### BREAKING CHANGES
|
||||||
* Signature.verifyAggregate now takes decompressed pubkeys instead of raw bytes of compressed key
|
|
||||||
|
- Signature.verifyAggregate now takes decompressed pubkeys instead of raw bytes of compressed key
|
||||||
|
|
||||||
## [3.0.0] - 2020-07-31
|
## [3.0.0] - 2020-07-31
|
||||||
|
|
||||||
### BREAKING CHANGES
|
### BREAKING CHANGES
|
||||||
|
|
||||||
* Update bls-keygen to latest EIP-2333 standard ([55dd5d](https://github.com/chainsafe/bls/commit/55dd5d))
|
- Update bls-keygen to latest EIP-2333 standard ([55dd5d](https://github.com/chainsafe/bls/commit/55dd5d))
|
||||||
|
|
||||||
## [2.0.0] - 2020-05-21
|
## [2.0.0] - 2020-05-21
|
||||||
|
|
||||||
|
@ -42,4 +43,5 @@ and [IETF draft bls specification](https://github.com/ethereum/eth2.0-specs/blob
|
||||||
## [0.2.2] - 2020-02-12
|
## [0.2.2] - 2020-02-12
|
||||||
|
|
||||||
###Bugfixes:
|
###Bugfixes:
|
||||||
|
|
||||||
- updated bls wasm binding version - it isn't catching unhandled rejections and modify stacktraces
|
- updated bls wasm binding version - it isn't catching unhandled rejections and modify stacktraces
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
This is a Javascript library that implements BLS (Boneh-Lynn-Shacham) signatures and supports signature aggregation.
|
This is a Javascript library that implements BLS (Boneh-Lynn-Shacham) signatures and supports signature aggregation.
|
||||||
|
|
||||||
| Version | Bls spec version |
|
| Version | Bls spec version |
|
||||||
|----------|:-------------:|
|
| ------- | :--------------: |
|
||||||
| 0.3.x | initial version |
|
| 0.3.x | initial version |
|
||||||
| 1.x.x | draft #6 |
|
| 1.x.x | draft #6 |
|
||||||
| 2.x.x | draft #7 |
|
| 2.x.x | draft #7 |
|
||||||
|
@ -19,6 +19,7 @@ This is a Javascript library that implements BLS (Boneh-Lynn-Shacham) signatures
|
||||||
> [test vectors](https://github.com/ethereum/eth2.0-spec-tests/tree/master/tests/bls)
|
> [test vectors](https://github.com/ethereum/eth2.0-spec-tests/tree/master/tests/bls)
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
- `yarn add @chainsafe/bls`
|
- `yarn add @chainsafe/bls`
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
|
@ -8,7 +8,10 @@ import {PUBLIC_KEY_LENGTH, SIGNATURE_LENGTH} from "../constants";
|
||||||
* @param length
|
* @param length
|
||||||
*/
|
*/
|
||||||
export function padLeft(source: Uint8Array, length: number): Buffer {
|
export function padLeft(source: Uint8Array, length: number): Buffer {
|
||||||
assert(source.length <= length, "Given array must be smaller or equal to desired array size");
|
assert(
|
||||||
|
source.length <= length,
|
||||||
|
"Given array must be smaller or equal to desired array size"
|
||||||
|
);
|
||||||
const result = Buffer.alloc(length, 0);
|
const result = Buffer.alloc(length, 0);
|
||||||
result.set(source, length - source.length);
|
result.set(source, length - source.length);
|
||||||
return result;
|
return result;
|
||||||
|
|
43
src/index.ts
43
src/index.ts
|
@ -47,11 +47,16 @@ export function sign(secretKey: Uint8Array, messageHash: Uint8Array): Buffer {
|
||||||
* @param signatures
|
* @param signatures
|
||||||
*/
|
*/
|
||||||
export function aggregateSignatures(signatures: Uint8Array[]): Buffer {
|
export function aggregateSignatures(signatures: Uint8Array[]): Buffer {
|
||||||
assert(signatures && signatures.length > 0, "signatures is null or undefined or empty array");
|
assert(
|
||||||
|
signatures && signatures.length > 0,
|
||||||
|
"signatures is null or undefined or empty array"
|
||||||
|
);
|
||||||
return Signature.aggregate(
|
return Signature.aggregate(
|
||||||
signatures.map((signature): Signature => {
|
signatures.map(
|
||||||
|
(signature): Signature => {
|
||||||
return Signature.fromCompressedBytes(signature);
|
return Signature.fromCompressedBytes(signature);
|
||||||
})
|
}
|
||||||
|
)
|
||||||
).toBytesCompressed();
|
).toBytesCompressed();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -76,14 +81,19 @@ export function aggregatePubkeys(publicKeys: Uint8Array[]): Buffer {
|
||||||
* @param messageHash
|
* @param messageHash
|
||||||
* @param signature
|
* @param signature
|
||||||
*/
|
*/
|
||||||
export function verify(publicKey: Uint8Array, messageHash: Uint8Array, signature: Uint8Array): boolean {
|
export function verify(
|
||||||
|
publicKey: Uint8Array,
|
||||||
|
messageHash: Uint8Array,
|
||||||
|
signature: Uint8Array
|
||||||
|
): boolean {
|
||||||
assert(publicKey, "publicKey is null or undefined");
|
assert(publicKey, "publicKey is null or undefined");
|
||||||
assert(messageHash, "messageHash is null or undefined");
|
assert(messageHash, "messageHash is null or undefined");
|
||||||
assert(signature, "signature is null or undefined");
|
assert(signature, "signature is null or undefined");
|
||||||
try {
|
try {
|
||||||
return PublicKey
|
return PublicKey.fromBytes(publicKey).verifyMessage(
|
||||||
.fromBytes(publicKey)
|
Signature.fromCompressedBytes(toBuffer(signature)),
|
||||||
.verifyMessage(Signature.fromCompressedBytes(toBuffer(signature)), toBuffer(messageHash));
|
toBuffer(messageHash)
|
||||||
|
);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -95,14 +105,19 @@ export function verify(publicKey: Uint8Array, messageHash: Uint8Array, signature
|
||||||
* @param messageHash
|
* @param messageHash
|
||||||
* @param signature
|
* @param signature
|
||||||
*/
|
*/
|
||||||
export function verifyAggregate(publicKeys: Uint8Array[], messageHash: Uint8Array, signature: Uint8Array): boolean {
|
export function verifyAggregate(
|
||||||
|
publicKeys: Uint8Array[],
|
||||||
|
messageHash: Uint8Array,
|
||||||
|
signature: Uint8Array
|
||||||
|
): boolean {
|
||||||
assert(publicKeys, "publicKey is null or undefined");
|
assert(publicKeys, "publicKey is null or undefined");
|
||||||
assert(messageHash, "messageHash is null or undefined");
|
assert(messageHash, "messageHash is null or undefined");
|
||||||
assert(signature, "signature is null or undefined");
|
assert(signature, "signature is null or undefined");
|
||||||
try {
|
try {
|
||||||
return Signature
|
return Signature.fromCompressedBytes(signature).verifyAggregate(
|
||||||
.fromCompressedBytes(signature)
|
publicKeys.map((pubkey) => PublicKey.fromBytes(pubkey)),
|
||||||
.verifyAggregate(publicKeys.map(pubkey => PublicKey.fromBytes(pubkey)), messageHash);
|
messageHash
|
||||||
|
);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -129,9 +144,7 @@ export function verifyMultiple(
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
return Signature
|
return Signature.fromCompressedBytes(toBuffer(signature)).verifyMultiple(
|
||||||
.fromCompressedBytes(toBuffer(signature))
|
|
||||||
.verifyMultiple(
|
|
||||||
publicKeys.map((key) => PublicKey.fromBytes(toBuffer(key))),
|
publicKeys.map((key) => PublicKey.fromBytes(toBuffer(key))),
|
||||||
messageHashes.map((m) => toBuffer(m)),
|
messageHashes.map((m) => toBuffer(m)),
|
||||||
fast
|
fast
|
||||||
|
@ -149,5 +162,5 @@ export default {
|
||||||
aggregatePubkeys,
|
aggregatePubkeys,
|
||||||
verify,
|
verify,
|
||||||
verifyAggregate,
|
verifyAggregate,
|
||||||
verifyMultiple
|
verifyMultiple,
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,9 +1,7 @@
|
||||||
import { PublicKey } from "./publicKey";
|
import { PublicKey } from "./publicKey";
|
||||||
import { PrivateKey } from "./privateKey";
|
import { PrivateKey } from "./privateKey";
|
||||||
|
|
||||||
|
|
||||||
export class Keypair {
|
export class Keypair {
|
||||||
|
|
||||||
private readonly _publicKey: PublicKey;
|
private readonly _publicKey: PublicKey;
|
||||||
|
|
||||||
private readonly _privateKey: PrivateKey;
|
private readonly _privateKey: PrivateKey;
|
||||||
|
|
|
@ -7,7 +7,6 @@ import {PublicKey} from "./publicKey";
|
||||||
import { Signature } from "./signature";
|
import { Signature } from "./signature";
|
||||||
|
|
||||||
export class PrivateKey {
|
export class PrivateKey {
|
||||||
|
|
||||||
private value: SecretKeyType;
|
private value: SecretKeyType;
|
||||||
|
|
||||||
protected constructor(value: SecretKeyType) {
|
protected constructor(value: SecretKeyType) {
|
||||||
|
@ -15,7 +14,10 @@ export class PrivateKey {
|
||||||
}
|
}
|
||||||
|
|
||||||
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 context = getContext();
|
const context = getContext();
|
||||||
const secretKey = new context.SecretKey();
|
const secretKey = new context.SecretKey();
|
||||||
secretKey.deserialize(Buffer.from(bytes));
|
secretKey.deserialize(Buffer.from(bytes));
|
||||||
|
@ -24,7 +26,10 @@ export class PrivateKey {
|
||||||
|
|
||||||
public static fromHexString(value: string): PrivateKey {
|
public static fromHexString(value: string): 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));
|
return new PrivateKey(context.deserializeHexStrToSecretKey(value));
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,6 @@ import {Signature} from "./signature";
|
||||||
import { EMPTY_PUBLIC_KEY } from "./helpers/utils";
|
import { EMPTY_PUBLIC_KEY } from "./helpers/utils";
|
||||||
|
|
||||||
export class PublicKey {
|
export class PublicKey {
|
||||||
|
|
||||||
private value: PublicKeyType;
|
private value: PublicKeyType;
|
||||||
|
|
||||||
protected constructor(value: PublicKeyType) {
|
protected constructor(value: PublicKeyType) {
|
||||||
|
@ -24,18 +23,14 @@ export class PublicKey {
|
||||||
if (!EMPTY_PUBLIC_KEY.equals(bytes)) {
|
if (!EMPTY_PUBLIC_KEY.equals(bytes)) {
|
||||||
publicKey.deserialize(bytes);
|
publicKey.deserialize(bytes);
|
||||||
}
|
}
|
||||||
return new PublicKey(
|
return new PublicKey(publicKey);
|
||||||
publicKey
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static fromHex(value: string): PublicKey {
|
public static fromHex(value: string): 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(
|
return new PublicKey(context.deserializeHexStrToPublicKey(value));
|
||||||
context.deserializeHexStrToPublicKey(value)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static fromPublicKeyType(value: PublicKeyType): PublicKey {
|
public static fromPublicKeyType(value: PublicKeyType): PublicKey {
|
||||||
|
|
|
@ -6,7 +6,6 @@ import {PublicKey} from "./publicKey";
|
||||||
import { EMPTY_SIGNATURE } from "./helpers/utils";
|
import { EMPTY_SIGNATURE } from "./helpers/utils";
|
||||||
|
|
||||||
export class Signature {
|
export class Signature {
|
||||||
|
|
||||||
private value: SignatureType;
|
private value: SignatureType;
|
||||||
|
|
||||||
protected constructor(value: SignatureType) {
|
protected constructor(value: SignatureType) {
|
||||||
|
@ -35,31 +34,34 @@ export class Signature {
|
||||||
const context = getContext();
|
const context = getContext();
|
||||||
const signature = new context.Signature();
|
const signature = new context.Signature();
|
||||||
signature.aggregate(signatures.map((sig) => sig.getValue()));
|
signature.aggregate(signatures.map((sig) => sig.getValue()));
|
||||||
return new Signature(
|
return new Signature(signature);
|
||||||
signature
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public add(other: Signature): Signature {
|
public add(other: Signature): Signature {
|
||||||
const agg = this.value.clone();
|
const agg = this.value.clone();
|
||||||
agg.add(other.value);
|
agg.add(other.value);
|
||||||
return new Signature(
|
return new Signature(agg);
|
||||||
agg
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public getValue(): SignatureType {
|
public getValue(): SignatureType {
|
||||||
return this.value;
|
return this.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public verifyAggregate(publicKeys: PublicKey[], message: Uint8Array): boolean {
|
public verifyAggregate(
|
||||||
|
publicKeys: PublicKey[],
|
||||||
|
message: Uint8Array
|
||||||
|
): boolean {
|
||||||
return this.value.fastAggregateVerify(
|
return this.value.fastAggregateVerify(
|
||||||
publicKeys.map((key) => key.getValue()),
|
publicKeys.map((key) => key.getValue()),
|
||||||
message
|
message
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public verifyMultiple(publicKeys: PublicKey[], messages: Uint8Array[], fast = false): boolean {
|
public verifyMultiple(
|
||||||
|
publicKeys: PublicKey[],
|
||||||
|
messages: Uint8Array[],
|
||||||
|
fast = false
|
||||||
|
): boolean {
|
||||||
const msgs = Buffer.concat(messages);
|
const msgs = Buffer.concat(messages);
|
||||||
if (!fast && !getContext().areAllMsgDifferent(msgs)) {
|
if (!fast && !getContext().areAllMsgDifferent(msgs)) {
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
import path from "path";
|
import path from "path";
|
||||||
import bls, { initBLS } from "../../src";
|
import bls, { initBLS } from "../../src";
|
||||||
import {describeDirectorySpecTest, InputType} from "@chainsafe/lodestar-spec-test-util";
|
import {
|
||||||
|
describeDirectorySpecTest,
|
||||||
|
InputType,
|
||||||
|
} from "@chainsafe/lodestar-spec-test-util";
|
||||||
|
|
||||||
interface IAggregateSigsTestCase {
|
interface IAggregateSigsTestCase {
|
||||||
data: {
|
data: {
|
||||||
|
@ -19,11 +22,13 @@ describeDirectorySpecTest<IAggregateSigsTestCase, string>(
|
||||||
__dirname,
|
__dirname,
|
||||||
"../../node_modules/@chainsafe/eth2-spec-tests/tests/general/phase0/bls/aggregate/small"
|
"../../node_modules/@chainsafe/eth2-spec-tests/tests/general/phase0/bls/aggregate/small"
|
||||||
),
|
),
|
||||||
(testCase => {
|
(testCase) => {
|
||||||
try {
|
try {
|
||||||
const result = bls.aggregateSignatures(testCase.data.input.map(pubKey => {
|
const result = bls.aggregateSignatures(
|
||||||
|
testCase.data.input.map((pubKey) => {
|
||||||
return Buffer.from(pubKey.replace("0x", ""), "hex");
|
return Buffer.from(pubKey.replace("0x", ""), "hex");
|
||||||
}));
|
})
|
||||||
|
);
|
||||||
return `0x${result.toString("hex")}`;
|
return `0x${result.toString("hex")}`;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (e.message === "signatures is null or undefined or empty array") {
|
if (e.message === "signatures is null or undefined or empty array") {
|
||||||
|
@ -31,11 +36,11 @@ describeDirectorySpecTest<IAggregateSigsTestCase, string>(
|
||||||
}
|
}
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
}),
|
},
|
||||||
{
|
{
|
||||||
inputTypes: {
|
inputTypes: {
|
||||||
data: InputType.YAML,
|
data: InputType.YAML,
|
||||||
},
|
},
|
||||||
getExpected: (testCase => testCase.data.output)
|
getExpected: (testCase) => testCase.data.output,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
import path from "path";
|
import path from "path";
|
||||||
import bls, { initBLS } from "../../src";
|
import bls, { initBLS } from "../../src";
|
||||||
import {describeDirectorySpecTest, InputType} from "@chainsafe/lodestar-spec-test-util";
|
import {
|
||||||
|
describeDirectorySpecTest,
|
||||||
|
InputType,
|
||||||
|
} from "@chainsafe/lodestar-spec-test-util";
|
||||||
|
|
||||||
interface AggregateSigsVerifyTestCase {
|
interface AggregateSigsVerifyTestCase {
|
||||||
data: {
|
data: {
|
||||||
|
@ -27,23 +30,23 @@ describeDirectorySpecTest<AggregateSigsVerifyTestCase, boolean>(
|
||||||
__dirname,
|
__dirname,
|
||||||
"../../node_modules/@chainsafe/eth2-spec-tests/tests/general/phase0/bls/aggregate_verify/small"
|
"../../node_modules/@chainsafe/eth2-spec-tests/tests/general/phase0/bls/aggregate_verify/small"
|
||||||
),
|
),
|
||||||
(testCase => {
|
(testCase) => {
|
||||||
const pubkeys = testCase.data.input.pubkeys.map(pubkey => {
|
const pubkeys = testCase.data.input.pubkeys.map((pubkey) => {
|
||||||
return Buffer.from(pubkey.replace("0x", ""), "hex");
|
return Buffer.from(pubkey.replace("0x", ""), "hex");
|
||||||
});
|
});
|
||||||
const messages = testCase.data.input.messages.map(msg => {
|
const messages = testCase.data.input.messages.map((msg) => {
|
||||||
return Buffer.from(msg.replace("0x", ""), "hex");
|
return Buffer.from(msg.replace("0x", ""), "hex");
|
||||||
});
|
});
|
||||||
return bls.verifyMultiple(
|
return bls.verifyMultiple(
|
||||||
pubkeys,
|
pubkeys,
|
||||||
messages,
|
messages,
|
||||||
Buffer.from(testCase.data.input.signature.replace("0x", ""), "hex"),
|
Buffer.from(testCase.data.input.signature.replace("0x", ""), "hex")
|
||||||
);
|
);
|
||||||
}),
|
},
|
||||||
{
|
{
|
||||||
inputTypes: {
|
inputTypes: {
|
||||||
data: InputType.YAML,
|
data: InputType.YAML,
|
||||||
},
|
},
|
||||||
getExpected: (testCase => testCase.data.output)
|
getExpected: (testCase) => testCase.data.output,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
import path from "path";
|
import path from "path";
|
||||||
import bls, { initBLS } from "../../src";
|
import bls, { initBLS } from "../../src";
|
||||||
import {describeDirectorySpecTest, InputType} from "@chainsafe/lodestar-spec-test-util";
|
import {
|
||||||
|
describeDirectorySpecTest,
|
||||||
|
InputType,
|
||||||
|
} from "@chainsafe/lodestar-spec-test-util";
|
||||||
|
|
||||||
interface AggregateSigsVerifyTestCase {
|
interface AggregateSigsVerifyTestCase {
|
||||||
data: {
|
data: {
|
||||||
|
@ -27,17 +30,19 @@ describeDirectorySpecTest<AggregateSigsVerifyTestCase, boolean>(
|
||||||
__dirname,
|
__dirname,
|
||||||
"../../node_modules/@chainsafe/eth2-spec-tests/tests/general/phase0/bls/fast_aggregate_verify/small"
|
"../../node_modules/@chainsafe/eth2-spec-tests/tests/general/phase0/bls/fast_aggregate_verify/small"
|
||||||
),
|
),
|
||||||
(testCase => {
|
(testCase) => {
|
||||||
return bls.verifyAggregate(
|
return bls.verifyAggregate(
|
||||||
testCase.data.input.pubkeys.map((key) => Buffer.from(key.replace("0x", ""), "hex")),
|
testCase.data.input.pubkeys.map((key) =>
|
||||||
|
Buffer.from(key.replace("0x", ""), "hex")
|
||||||
|
),
|
||||||
Buffer.from(testCase.data.input.message.replace("0x", ""), "hex"),
|
Buffer.from(testCase.data.input.message.replace("0x", ""), "hex"),
|
||||||
Buffer.from(testCase.data.input.signature.replace("0x", ""), "hex"),
|
Buffer.from(testCase.data.input.signature.replace("0x", ""), "hex")
|
||||||
);
|
);
|
||||||
}),
|
},
|
||||||
{
|
{
|
||||||
inputTypes: {
|
inputTypes: {
|
||||||
data: InputType.YAML,
|
data: InputType.YAML,
|
||||||
},
|
},
|
||||||
getExpected: (testCase => testCase.data.output)
|
getExpected: (testCase) => testCase.data.output,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
import path from "path";
|
import path from "path";
|
||||||
import bls, { initBLS } from "../../src";
|
import bls, { initBLS } from "../../src";
|
||||||
import {describeDirectorySpecTest, InputType} from "@chainsafe/lodestar-spec-test-util";
|
import {
|
||||||
|
describeDirectorySpecTest,
|
||||||
|
InputType,
|
||||||
|
} from "@chainsafe/lodestar-spec-test-util";
|
||||||
|
|
||||||
interface ISignMessageTestCase {
|
interface ISignMessageTestCase {
|
||||||
data: {
|
data: {
|
||||||
|
@ -22,17 +25,17 @@ describeDirectorySpecTest<ISignMessageTestCase, string>(
|
||||||
__dirname,
|
__dirname,
|
||||||
"../../node_modules/@chainsafe/eth2-spec-tests/tests/general/phase0/bls/sign/small"
|
"../../node_modules/@chainsafe/eth2-spec-tests/tests/general/phase0/bls/sign/small"
|
||||||
),
|
),
|
||||||
(testCase => {
|
(testCase) => {
|
||||||
const signature = bls.sign(
|
const signature = bls.sign(
|
||||||
Buffer.from(testCase.data.input.privkey.replace("0x", ""), "hex"),
|
Buffer.from(testCase.data.input.privkey.replace("0x", ""), "hex"),
|
||||||
Buffer.from(testCase.data.input.message.replace("0x", ""), "hex")
|
Buffer.from(testCase.data.input.message.replace("0x", ""), "hex")
|
||||||
);
|
);
|
||||||
return `0x${signature.toString("hex")}`;
|
return `0x${signature.toString("hex")}`;
|
||||||
}),
|
},
|
||||||
{
|
{
|
||||||
inputTypes: {
|
inputTypes: {
|
||||||
data: InputType.YAML,
|
data: InputType.YAML,
|
||||||
},
|
},
|
||||||
getExpected: (testCase => testCase.data.output)
|
getExpected: (testCase) => testCase.data.output,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
import path from "path";
|
import path from "path";
|
||||||
import bls, { initBLS } from "../../src";
|
import bls, { initBLS } from "../../src";
|
||||||
import {describeDirectorySpecTest, InputType} from "@chainsafe/lodestar-spec-test-util";
|
import {
|
||||||
|
describeDirectorySpecTest,
|
||||||
|
InputType,
|
||||||
|
} from "@chainsafe/lodestar-spec-test-util";
|
||||||
|
|
||||||
interface IVerifyTestCase {
|
interface IVerifyTestCase {
|
||||||
data: {
|
data: {
|
||||||
|
@ -23,17 +26,17 @@ describeDirectorySpecTest<IVerifyTestCase, boolean>(
|
||||||
__dirname,
|
__dirname,
|
||||||
"../../node_modules/@chainsafe/eth2-spec-tests/tests/general/phase0/bls/verify/small"
|
"../../node_modules/@chainsafe/eth2-spec-tests/tests/general/phase0/bls/verify/small"
|
||||||
),
|
),
|
||||||
(testCase => {
|
(testCase) => {
|
||||||
return bls.verify(
|
return bls.verify(
|
||||||
Buffer.from(testCase.data.input.pubkey.replace("0x", ""), "hex"),
|
Buffer.from(testCase.data.input.pubkey.replace("0x", ""), "hex"),
|
||||||
Buffer.from(testCase.data.input.message.replace("0x", ""), "hex"),
|
Buffer.from(testCase.data.input.message.replace("0x", ""), "hex"),
|
||||||
Buffer.from(testCase.data.input.signature.replace("0x", ""), "hex")
|
Buffer.from(testCase.data.input.signature.replace("0x", ""), "hex")
|
||||||
);
|
);
|
||||||
}),
|
},
|
||||||
{
|
{
|
||||||
inputTypes: {
|
inputTypes: {
|
||||||
data: InputType.YAML,
|
data: InputType.YAML,
|
||||||
},
|
},
|
||||||
getExpected: (testCase => testCase.data.output)
|
getExpected: (testCase) => testCase.data.output,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
|
@ -2,19 +2,18 @@ import {init, getContext, destroy} from "../../src/context";
|
||||||
import { expect } from "chai";
|
import { expect } from "chai";
|
||||||
|
|
||||||
describe("bls wasm constext", function () {
|
describe("bls wasm constext", function () {
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
destroy();
|
destroy();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("initializes and works", async function () {
|
it("initializes and works", async function () {
|
||||||
await init();
|
await init();
|
||||||
expect(getContext().getCurveOrder())
|
expect(getContext().getCurveOrder()).to.be.equal(
|
||||||
.to.be.equal("52435875175126190479447740508185965837690552500527637822603658699938581184513");
|
"52435875175126190479447740508185965837690552500527637822603658699938581184513"
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("throws if context not initialized", async function () {
|
it("throws if context not initialized", async function () {
|
||||||
expect(() => getContext().getCurveOrder()).to.throw();
|
expect(() => getContext().getCurveOrder()).to.throw();
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
|
@ -1,11 +1,17 @@
|
||||||
import bls, {aggregatePubkeys, aggregateSignatures, initBLS, Keypair, verify, verifyMultiple} from "../../src";
|
import bls, {
|
||||||
|
aggregatePubkeys,
|
||||||
|
aggregateSignatures,
|
||||||
|
initBLS,
|
||||||
|
Keypair,
|
||||||
|
verify,
|
||||||
|
verifyMultiple,
|
||||||
|
} from "../../src";
|
||||||
import SHA256 from "@chainsafe/as-sha256";
|
import SHA256 from "@chainsafe/as-sha256";
|
||||||
import { expect } from "chai";
|
import { expect } from "chai";
|
||||||
import { destroy } from "../../src/context";
|
import { destroy } from "../../src/context";
|
||||||
import { padLeft } from "../../src/helpers/utils";
|
import { padLeft } from "../../src/helpers/utils";
|
||||||
|
|
||||||
describe("test bls", function () {
|
describe("test bls", function () {
|
||||||
|
|
||||||
before(async function () {
|
before(async function () {
|
||||||
await initBLS();
|
await initBLS();
|
||||||
});
|
});
|
||||||
|
@ -24,57 +30,53 @@ describe("test bls", function () {
|
||||||
it("should verify signature", () => {
|
it("should verify signature", () => {
|
||||||
const keypair = Keypair.generate();
|
const keypair = Keypair.generate();
|
||||||
const messageHash = Buffer.from(SHA256.digest(Buffer.from("Test")));
|
const messageHash = Buffer.from(SHA256.digest(Buffer.from("Test")));
|
||||||
const signature = keypair.privateKey.signMessage(
|
const signature = keypair.privateKey.signMessage(messageHash);
|
||||||
messageHash,
|
|
||||||
);
|
|
||||||
const result = verify(
|
const result = verify(
|
||||||
keypair.publicKey.toBytesCompressed(),
|
keypair.publicKey.toBytesCompressed(),
|
||||||
messageHash,
|
messageHash,
|
||||||
signature.toBytesCompressed(),
|
signature.toBytesCompressed()
|
||||||
);
|
);
|
||||||
expect(result).to.be.true;
|
expect(result).to.be.true;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
it("should not modify original pubkey when verifying", () => {
|
it("should not modify original pubkey when verifying", () => {
|
||||||
const keypair = Keypair.generate();
|
const keypair = Keypair.generate();
|
||||||
const messageHash = Buffer.from(SHA256.digest(Buffer.from("Test")));
|
const messageHash = Buffer.from(SHA256.digest(Buffer.from("Test")));
|
||||||
const signature = keypair.privateKey.signMessage(
|
const signature = keypair.privateKey.signMessage(messageHash);
|
||||||
messageHash,
|
|
||||||
);
|
|
||||||
const pubKey = keypair.publicKey.toBytesCompressed();
|
const pubKey = keypair.publicKey.toBytesCompressed();
|
||||||
verify(
|
verify(pubKey, messageHash, signature.toBytesCompressed());
|
||||||
pubKey,
|
expect("0x" + pubKey.toString("hex")).to.be.equal(
|
||||||
messageHash,
|
keypair.publicKey.toHexString()
|
||||||
signature.toBytesCompressed(),
|
|
||||||
);
|
);
|
||||||
expect("0x" + pubKey.toString("hex")).to.be.equal(keypair.publicKey.toHexString());
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
it("should fail verify empty signature", () => {
|
it("should fail verify empty signature", () => {
|
||||||
const keypair = Keypair.generate();
|
const keypair = Keypair.generate();
|
||||||
const messageHash2 = Buffer.from(SHA256.digest(Buffer.from("Test message2")));
|
const messageHash2 = Buffer.from(
|
||||||
|
SHA256.digest(Buffer.from("Test message2"))
|
||||||
|
);
|
||||||
const signature = Buffer.alloc(96);
|
const signature = Buffer.alloc(96);
|
||||||
const result = verify(
|
const result = verify(
|
||||||
keypair.publicKey.toBytesCompressed(),
|
keypair.publicKey.toBytesCompressed(),
|
||||||
messageHash2,
|
messageHash2,
|
||||||
signature,
|
signature
|
||||||
);
|
);
|
||||||
expect(result).to.be.false;
|
expect(result).to.be.false;
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should fail verify signature of different message", () => {
|
it("should fail verify signature of different message", () => {
|
||||||
const keypair = Keypair.generate();
|
const keypair = Keypair.generate();
|
||||||
const messageHash = Buffer.from(SHA256.digest(Buffer.from("Test message")));
|
const messageHash = Buffer.from(
|
||||||
const messageHash2 = Buffer.from(SHA256.digest(Buffer.from("Test message2")));
|
SHA256.digest(Buffer.from("Test message"))
|
||||||
const signature = keypair.privateKey.signMessage(
|
|
||||||
messageHash,
|
|
||||||
);
|
);
|
||||||
|
const messageHash2 = Buffer.from(
|
||||||
|
SHA256.digest(Buffer.from("Test message2"))
|
||||||
|
);
|
||||||
|
const signature = keypair.privateKey.signMessage(messageHash);
|
||||||
const result = verify(
|
const result = verify(
|
||||||
keypair.publicKey.toBytesCompressed(),
|
keypair.publicKey.toBytesCompressed(),
|
||||||
messageHash2,
|
messageHash2,
|
||||||
signature.toBytesCompressed(),
|
signature.toBytesCompressed()
|
||||||
);
|
);
|
||||||
expect(result).to.be.false;
|
expect(result).to.be.false;
|
||||||
});
|
});
|
||||||
|
@ -82,26 +84,23 @@ describe("test bls", function () {
|
||||||
it("should fail verify signature signed by different key", () => {
|
it("should fail verify signature signed by different key", () => {
|
||||||
const keypair = Keypair.generate();
|
const keypair = Keypair.generate();
|
||||||
const keypair2 = Keypair.generate();
|
const keypair2 = Keypair.generate();
|
||||||
const messageHash = Buffer.from(SHA256.digest(Buffer.from("Test message")));
|
const messageHash = Buffer.from(
|
||||||
const signature = keypair.privateKey.signMessage(
|
SHA256.digest(Buffer.from("Test message"))
|
||||||
messageHash,
|
|
||||||
);
|
);
|
||||||
|
const signature = keypair.privateKey.signMessage(messageHash);
|
||||||
const result = verify(
|
const result = verify(
|
||||||
keypair2.publicKey.toBytesCompressed(),
|
keypair2.publicKey.toBytesCompressed(),
|
||||||
messageHash,
|
messageHash,
|
||||||
signature.toBytesCompressed(),
|
signature.toBytesCompressed()
|
||||||
);
|
);
|
||||||
expect(result).to.be.false;
|
expect(result).to.be.false;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("verify multiple", function () {
|
describe("verify multiple", function () {
|
||||||
|
|
||||||
it("should verify aggregated signatures", function () {
|
it("should verify aggregated signatures", function () {
|
||||||
this.timeout(5000);
|
this.timeout(5000);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const keypair1 = Keypair.generate();
|
const keypair1 = Keypair.generate();
|
||||||
const keypair2 = Keypair.generate();
|
const keypair2 = Keypair.generate();
|
||||||
const keypair3 = Keypair.generate();
|
const keypair3 = Keypair.generate();
|
||||||
|
@ -135,7 +134,7 @@ describe("test bls", function () {
|
||||||
const result = verifyMultiple(
|
const result = verifyMultiple(
|
||||||
[aggregatePubKey12, aggregatePubKey34],
|
[aggregatePubKey12, aggregatePubKey34],
|
||||||
[message1, message2],
|
[message1, message2],
|
||||||
aggregateSignature,
|
aggregateSignature
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(result).to.be.true;
|
expect(result).to.be.true;
|
||||||
|
@ -144,8 +143,6 @@ describe("test bls", function () {
|
||||||
it("should verify aggregated signatures - same message", function () {
|
it("should verify aggregated signatures - same message", function () {
|
||||||
this.timeout(5000);
|
this.timeout(5000);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const keypair1 = Keypair.generate();
|
const keypair1 = Keypair.generate();
|
||||||
const keypair2 = Keypair.generate();
|
const keypair2 = Keypair.generate();
|
||||||
const keypair3 = Keypair.generate();
|
const keypair3 = Keypair.generate();
|
||||||
|
@ -170,11 +167,11 @@ describe("test bls", function () {
|
||||||
keypair1.publicKey.toBytesCompressed(),
|
keypair1.publicKey.toBytesCompressed(),
|
||||||
keypair2.publicKey.toBytesCompressed(),
|
keypair2.publicKey.toBytesCompressed(),
|
||||||
keypair3.publicKey.toBytesCompressed(),
|
keypair3.publicKey.toBytesCompressed(),
|
||||||
keypair4.publicKey.toBytesCompressed()
|
keypair4.publicKey.toBytesCompressed(),
|
||||||
],
|
],
|
||||||
[message, message, message, message],
|
[message, message, message, message],
|
||||||
aggregateSignature,
|
aggregateSignature,
|
||||||
true,
|
true
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(result).to.be.true;
|
expect(result).to.be.true;
|
||||||
|
@ -183,7 +180,6 @@ describe("test bls", function () {
|
||||||
it("should fail to verify aggregated signatures - swapped messages", function () {
|
it("should fail to verify aggregated signatures - swapped messages", function () {
|
||||||
this.timeout(5000);
|
this.timeout(5000);
|
||||||
|
|
||||||
|
|
||||||
const keypair1 = Keypair.generate();
|
const keypair1 = Keypair.generate();
|
||||||
const keypair2 = Keypair.generate();
|
const keypair2 = Keypair.generate();
|
||||||
const keypair3 = Keypair.generate();
|
const keypair3 = Keypair.generate();
|
||||||
|
@ -217,15 +213,13 @@ describe("test bls", function () {
|
||||||
const result = bls.verifyMultiple(
|
const result = bls.verifyMultiple(
|
||||||
[aggregatePubKey12, aggregatePubKey34],
|
[aggregatePubKey12, aggregatePubKey34],
|
||||||
[message2, message1],
|
[message2, message1],
|
||||||
aggregateSignature,
|
aggregateSignature
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(result).to.be.false;
|
expect(result).to.be.false;
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should fail to verify aggregated signatures - different pubkeys and messsages", () => {
|
it("should fail to verify aggregated signatures - different pubkeys and messsages", () => {
|
||||||
|
|
||||||
|
|
||||||
const keypair1 = Keypair.generate();
|
const keypair1 = Keypair.generate();
|
||||||
const keypair2 = Keypair.generate();
|
const keypair2 = Keypair.generate();
|
||||||
const keypair3 = Keypair.generate();
|
const keypair3 = Keypair.generate();
|
||||||
|
@ -244,7 +238,6 @@ describe("test bls", function () {
|
||||||
keypair2.publicKey.toBytesCompressed(),
|
keypair2.publicKey.toBytesCompressed(),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
|
||||||
const aggregateSignature = bls.aggregateSignatures([
|
const aggregateSignature = bls.aggregateSignatures([
|
||||||
signature1.toBytesCompressed(),
|
signature1.toBytesCompressed(),
|
||||||
signature2.toBytesCompressed(),
|
signature2.toBytesCompressed(),
|
||||||
|
@ -255,29 +248,21 @@ describe("test bls", function () {
|
||||||
const result = bls.verifyMultiple(
|
const result = bls.verifyMultiple(
|
||||||
[aggregatePubKey12],
|
[aggregatePubKey12],
|
||||||
[message2, message1],
|
[message2, message1],
|
||||||
aggregateSignature,
|
aggregateSignature
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(result).to.be.false;
|
expect(result).to.be.false;
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should fail to verify aggregated signatures - no public keys", () => {
|
it("should fail to verify aggregated signatures - no public keys", () => {
|
||||||
|
|
||||||
|
|
||||||
const signature = Buffer.alloc(96);
|
const signature = Buffer.alloc(96);
|
||||||
|
|
||||||
const message1 = Buffer.from(SHA256.digest(Buffer.from("Test1")));
|
const message1 = Buffer.from(SHA256.digest(Buffer.from("Test1")));
|
||||||
const message2 = Buffer.from(SHA256.digest(Buffer.from("Test2")));
|
const message2 = Buffer.from(SHA256.digest(Buffer.from("Test2")));
|
||||||
|
|
||||||
const result = bls.verifyMultiple(
|
const result = bls.verifyMultiple([], [message2, message1], signature);
|
||||||
[],
|
|
||||||
[message2, message1],
|
|
||||||
signature,
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(result).to.be.false;
|
expect(result).to.be.false;
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
|
@ -3,7 +3,6 @@ import {expect} from "chai";
|
||||||
import { destroy, init } from "../../src/context";
|
import { destroy, init } from "../../src/context";
|
||||||
|
|
||||||
describe("keypair", function () {
|
describe("keypair", function () {
|
||||||
|
|
||||||
before(async function () {
|
before(async function () {
|
||||||
await init();
|
await init();
|
||||||
});
|
});
|
||||||
|
@ -15,7 +14,9 @@ describe("keypair", function() {
|
||||||
it("should create from private and public key", () => {
|
it("should create from private and public key", () => {
|
||||||
const secret = PrivateKey.random();
|
const secret = PrivateKey.random();
|
||||||
const secret2 = PrivateKey.random();
|
const secret2 = PrivateKey.random();
|
||||||
const publicKey = PublicKey.fromBytes(PublicKey.fromPrivateKey(secret2).toBytesCompressed());
|
const publicKey = PublicKey.fromBytes(
|
||||||
|
PublicKey.fromPrivateKey(secret2).toBytesCompressed()
|
||||||
|
);
|
||||||
const keypair = new Keypair(secret, publicKey);
|
const keypair = new Keypair(secret, publicKey);
|
||||||
expect(keypair.publicKey).to.be.equal(publicKey);
|
expect(keypair.publicKey).to.be.equal(publicKey);
|
||||||
expect(keypair.privateKey).to.be.equal(secret);
|
expect(keypair.privateKey).to.be.equal(secret);
|
||||||
|
@ -26,7 +27,8 @@ describe("keypair", function() {
|
||||||
const secret = PrivateKey.random();
|
const secret = PrivateKey.random();
|
||||||
const publicKey = PublicKey.fromPrivateKey(secret);
|
const publicKey = PublicKey.fromPrivateKey(secret);
|
||||||
const keypair = new Keypair(secret);
|
const keypair = new Keypair(secret);
|
||||||
expect(keypair.publicKey.toBytesCompressed().toString("hex"))
|
expect(keypair.publicKey.toBytesCompressed().toString("hex")).to.be.equal(
|
||||||
.to.be.equal(publicKey.toBytesCompressed().toString("hex"));
|
publicKey.toBytesCompressed().toString("hex")
|
||||||
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -4,7 +4,6 @@ import {SECRET_KEY_LENGTH} from "../../src/constants";
|
||||||
import { destroy, init } from "../../src/context";
|
import { destroy, init } from "../../src/context";
|
||||||
|
|
||||||
describe("privateKey", function () {
|
describe("privateKey", function () {
|
||||||
|
|
||||||
before(async function () {
|
before(async function () {
|
||||||
await init();
|
await init();
|
||||||
});
|
});
|
||||||
|
@ -16,17 +15,25 @@ describe("privateKey", function() {
|
||||||
it("should generate random private key", function () {
|
it("should generate random private key", function () {
|
||||||
const privateKey1 = PrivateKey.random();
|
const privateKey1 = PrivateKey.random();
|
||||||
const privateKey2 = PrivateKey.random();
|
const privateKey2 = PrivateKey.random();
|
||||||
expect(privateKey1.toHexString()).to.not.be.equal(privateKey2.toHexString());
|
expect(privateKey1.toHexString()).to.not.be.equal(
|
||||||
|
privateKey2.toHexString()
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should export private key to hex string", function () {
|
it("should export private key to hex string", function () {
|
||||||
const privateKey = "0x07656fd676da43883d163f49566c72b9cbf0a5a294f26808c807700732456da7";
|
const privateKey =
|
||||||
|
"0x07656fd676da43883d163f49566c72b9cbf0a5a294f26808c807700732456da7";
|
||||||
|
|
||||||
expect(PrivateKey.fromHexString(privateKey).toHexString()).to.be.equal(privateKey);
|
expect(PrivateKey.fromHexString(privateKey).toHexString()).to.be.equal(
|
||||||
|
privateKey
|
||||||
|
);
|
||||||
|
|
||||||
const privateKey2 = "07656fd676da43883d163f49566c72b9cbf0a5a294f26808c807700732456da7";
|
const privateKey2 =
|
||||||
|
"07656fd676da43883d163f49566c72b9cbf0a5a294f26808c807700732456da7";
|
||||||
|
|
||||||
expect(PrivateKey.fromHexString(privateKey2).toHexString()).to.be.equal(privateKey);
|
expect(PrivateKey.fromHexString(privateKey2).toHexString()).to.be.equal(
|
||||||
|
privateKey
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should export private key to bytes", function () {
|
it("should export private key to bytes", function () {
|
||||||
|
@ -36,5 +43,4 @@ describe("privateKey", function() {
|
||||||
it("should not accept too short private key", function () {
|
it("should not accept too short private key", function () {
|
||||||
expect(() => PrivateKey.fromHexString("0x2123")).to.throw();
|
expect(() => PrivateKey.fromHexString("0x2123")).to.throw();
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
|
@ -3,7 +3,6 @@ import {PublicKey, PrivateKey} from "../../src";
|
||||||
import { expect } from "chai";
|
import { expect } from "chai";
|
||||||
|
|
||||||
describe("public key", function () {
|
describe("public key", function () {
|
||||||
|
|
||||||
before(async function f() {
|
before(async function f() {
|
||||||
await init();
|
await init();
|
||||||
});
|
});
|
||||||
|
@ -21,11 +20,12 @@ describe("public key", function () {
|
||||||
it("from bytes", function () {
|
it("from bytes", function () {
|
||||||
const publicKey =
|
const publicKey =
|
||||||
"b6f21199594b56d77670564bf422cb331d5281ca2c1f9a45588a56881d8287ef8619efa6456d6cd2ef61306aa5b21311";
|
"b6f21199594b56d77670564bf422cb331d5281ca2c1f9a45588a56881d8287ef8619efa6456d6cd2ef61306aa5b21311";
|
||||||
expect(PublicKey.fromBytes(Buffer.from(publicKey, "hex")).toHexString()).to.be.equal(`0x${publicKey}`);
|
expect(
|
||||||
|
PublicKey.fromBytes(Buffer.from(publicKey, "hex")).toHexString()
|
||||||
|
).to.be.equal(`0x${publicKey}`);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("from private key", function () {
|
it("from private key", function () {
|
||||||
PublicKey.fromPrivateKey(PrivateKey.random());
|
PublicKey.fromPrivateKey(PrivateKey.random());
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
Reference in New Issue