diff --git a/src/blst/privateKey.ts b/src/blst/privateKey.ts index 05a68ec..8716f99 100644 --- a/src/blst/privateKey.ts +++ b/src/blst/privateKey.ts @@ -1,5 +1,5 @@ import * as blst from "@chainsafe/blst"; -import {bytesToHex, hexToBytes, randomBytes} from "../helpers/utils"; +import {bytesToHex, hexToBytes, randomBytes} from "../helpers"; import {SECRET_KEY_LENGTH} from "../constants"; import {IPrivateKey} from "../interface"; import {PublicKey} from "./publicKey"; diff --git a/src/blst/publicKey.ts b/src/blst/publicKey.ts index 6301cf2..c5e45bb 100644 --- a/src/blst/publicKey.ts +++ b/src/blst/publicKey.ts @@ -1,5 +1,5 @@ import * as blst from "@chainsafe/blst"; -import {bytesToHex, hexToBytes} from "../helpers/utils"; +import {bytesToHex, hexToBytes} from "../helpers"; import {IPublicKey} from "../interface"; import {Signature} from "./signature"; diff --git a/src/blst/signature.ts b/src/blst/signature.ts index 8316c96..d3a74f4 100644 --- a/src/blst/signature.ts +++ b/src/blst/signature.ts @@ -1,5 +1,5 @@ import * as blst from "@chainsafe/blst"; -import {bytesToHex, hexToBytes} from "../helpers/utils"; +import {bytesToHex, hexToBytes} from "../helpers"; import {ISignature} from "../interface"; import {PublicKey} from "./publicKey"; diff --git a/src/helpers/hex.ts b/src/helpers/hex.ts new file mode 100644 index 0000000..9470cb8 --- /dev/null +++ b/src/helpers/hex.ts @@ -0,0 +1,38 @@ +/** + * Browser compatible fromHex method + * From https://github.com/herumi/bls-eth-wasm/blob/04eedb77aa96e66b4f65a0ab477228adf8090c36/src/bls.js#L62 + */ +export function hexToBytes(hex: string): Uint8Array { + if (hex.startsWith("0x")) { + hex = hex.slice(2); + } + + if (hex.length & 1) { + throw Error("hexToBytes:length must be even " + hex.length); + } + + const n = hex.length / 2; + const a = new Uint8Array(n); + + for (let i = 0; i < n; i++) { + a[i] = parseInt(hex.slice(i * 2, i * 2 + 2), 16); + } + + return a; +} + +/** + * Browser compatible toHex method + * From https://github.com/herumi/bls-eth-wasm/blob/04eedb77aa96e66b4f65a0ab477228adf8090c36/src/bls.js#L50 + */ +export function bytesToHex(bytes: Uint8Array): string { + // return "0x" + Buffer.from(bytes).toString("hex"); + let s = ""; + const n = bytes.length; + + for (let i = 0; i < n; i++) { + s += ("0" + bytes[i].toString(16)).slice(-2); + } + + return "0x" + s; +} diff --git a/src/helpers/index.ts b/src/helpers/index.ts index 178cd64..daf81b5 100644 --- a/src/helpers/index.ts +++ b/src/helpers/index.ts @@ -1 +1,2 @@ +export * from "./hex"; export * from "./utils"; diff --git a/src/helpers/utils.ts b/src/helpers/utils.ts index fb0e5d8..a724b0d 100644 --- a/src/helpers/utils.ts +++ b/src/helpers/utils.ts @@ -9,14 +9,6 @@ export function assert(condition: unknown, message = "Assertion failed"): assert } } -export function hexToBytes(hex: string): Uint8Array { - return Buffer.from(hex.replace("0x", ""), "hex"); -} - -export function bytesToHex(bytes: Uint8Array): string { - return "0x" + Buffer.from(bytes).toString("hex"); -} - export function isEqualBytes(a: Buffer | Uint8Array, b: Buffer | Uint8Array): boolean { return toBuffer(a).equals(toBuffer(b)); } diff --git a/src/herumi/privateKey.ts b/src/herumi/privateKey.ts index 9b8b8d6..177d886 100644 --- a/src/herumi/privateKey.ts +++ b/src/herumi/privateKey.ts @@ -5,7 +5,7 @@ import {SECRET_KEY_LENGTH} from "../constants"; import {getContext} from "./context"; import {PublicKey} from "./publicKey"; import {Signature} from "./signature"; -import {bytesToHex, hexToBytes} from "../helpers/utils"; +import {bytesToHex, hexToBytes} from "../helpers"; import {IPrivateKey} from "../interface"; export class PrivateKey implements IPrivateKey { diff --git a/src/herumi/publicKey.ts b/src/herumi/publicKey.ts index 3d102a3..c927728 100644 --- a/src/herumi/publicKey.ts +++ b/src/herumi/publicKey.ts @@ -2,7 +2,7 @@ import {PublicKeyType} from "bls-eth-wasm"; import {getContext} from "./context"; import {EMPTY_PUBLIC_KEY} from "../constants"; import {Signature} from "./signature"; -import {bytesToHex, hexToBytes, isEqualBytes} from "../helpers/utils"; +import {bytesToHex, hexToBytes, isEqualBytes} from "../helpers"; import {IPublicKey} from "../interface"; export class PublicKey implements IPublicKey { diff --git a/src/herumi/signature.ts b/src/herumi/signature.ts index 13995c9..5b16719 100644 --- a/src/herumi/signature.ts +++ b/src/herumi/signature.ts @@ -3,7 +3,7 @@ import {SIGNATURE_LENGTH, EMPTY_SIGNATURE} from "../constants"; import {SignatureType} from "bls-eth-wasm"; import {getContext} from "./context"; import {PublicKey} from "./publicKey"; -import {bytesToHex, hexToBytes, isEqualBytes} from "../helpers/utils"; +import {bytesToHex, hexToBytes, isEqualBytes} from "../helpers"; import {ISignature} from "../interface"; export class Signature implements ISignature { diff --git a/test/spec/aggregate_sigs.test.ts b/test/spec/aggregate_sigs.test.ts index 50af3fa..a825e74 100644 --- a/test/spec/aggregate_sigs.test.ts +++ b/test/spec/aggregate_sigs.test.ts @@ -1,6 +1,6 @@ import path from "path"; import {describeDirectorySpecTest, InputType} from "@chainsafe/lodestar-spec-test-util"; -import {bytesToHex, hexToBytes} from "../../src/helpers/utils"; +import {bytesToHex, hexToBytes} from "../../src/helpers"; import {SPEC_TESTS_DIR} from "../params"; import {describeForAllImplementations} from "../switch"; diff --git a/test/spec/aggregate_sigs_verify.test.ts b/test/spec/aggregate_sigs_verify.test.ts index a2f0676..f7478d8 100644 --- a/test/spec/aggregate_sigs_verify.test.ts +++ b/test/spec/aggregate_sigs_verify.test.ts @@ -1,6 +1,6 @@ import path from "path"; import {describeDirectorySpecTest, InputType} from "@chainsafe/lodestar-spec-test-util"; -import {hexToBytes} from "../../src/helpers/utils"; +import {hexToBytes} from "../../src/helpers"; import {SPEC_TESTS_DIR} from "../params"; import {describeForAllImplementations} from "../switch"; diff --git a/test/spec/fast_aggregate_verify.test.ts b/test/spec/fast_aggregate_verify.test.ts index 6cf9906..8be9ed9 100644 --- a/test/spec/fast_aggregate_verify.test.ts +++ b/test/spec/fast_aggregate_verify.test.ts @@ -1,6 +1,6 @@ import path from "path"; import {describeDirectorySpecTest, InputType} from "@chainsafe/lodestar-spec-test-util"; -import {hexToBytes} from "../../src/helpers/utils"; +import {hexToBytes} from "../../src/helpers"; import {SPEC_TESTS_DIR} from "../params"; import {describeForAllImplementations} from "../switch"; diff --git a/test/spec/sign.test.ts b/test/spec/sign.test.ts index f525e5d..a90f21b 100644 --- a/test/spec/sign.test.ts +++ b/test/spec/sign.test.ts @@ -1,6 +1,6 @@ import path from "path"; import {describeDirectorySpecTest, InputType} from "@chainsafe/lodestar-spec-test-util"; -import {bytesToHex, hexToBytes} from "../../src/helpers/utils"; +import {bytesToHex, hexToBytes} from "../../src/helpers"; import {SPEC_TESTS_DIR} from "../params"; import {describeForAllImplementations} from "../switch"; diff --git a/test/spec/verify.test.ts b/test/spec/verify.test.ts index 59e65f8..06288d3 100644 --- a/test/spec/verify.test.ts +++ b/test/spec/verify.test.ts @@ -1,6 +1,6 @@ import path from "path"; import {describeDirectorySpecTest, InputType} from "@chainsafe/lodestar-spec-test-util"; -import {hexToBytes} from "../../src/helpers/utils"; +import {hexToBytes} from "../../src/helpers"; import {SPEC_TESTS_DIR} from "../params"; import {describeForAllImplementations} from "../switch"; diff --git a/test/unit/helpers/hex.test.ts b/test/unit/helpers/hex.test.ts new file mode 100644 index 0000000..93d5c09 --- /dev/null +++ b/test/unit/helpers/hex.test.ts @@ -0,0 +1,29 @@ +import {expect} from "chai"; +import {hexToBytes, bytesToHex} from "../../../src/helpers/hex"; + +describe("helpers / hex", () => { + const testCases: {id: string; hex: string}[] = [ + { + id: "pubkey", + hex: "0xb6f21199594b56d77670564bf422cb331d5281ca2c1f9a45588a56881d8287ef8619efa6456d6cd2ef61306aa5b21311", + }, + ]; + + for (const {id, hex} of testCases) { + it(`${id} hexToBytes`, () => { + const expectedBytes = hexToBytesNode(hex); + const bytes = hexToBytes(hex); + expect(expectedBytes.equals(bytes)).to.be.true; + }); + + it(`${id} bytesToHex`, () => { + const bytes = hexToBytesNode(hex); + const _hex = bytesToHex(bytes); + expect(_hex).to.equal(hex); + }); + } +}); + +function hexToBytesNode(hex: string): Buffer { + return Buffer.from(hex.replace("0x", ""), "hex"); +} diff --git a/test/unit/privateKey.test.ts b/test/unit/privateKey.test.ts index 75aad31..b5060e2 100644 --- a/test/unit/privateKey.test.ts +++ b/test/unit/privateKey.test.ts @@ -16,7 +16,7 @@ export function runPrivateKeyTests(bls: IBls): void { }); it("should export private key to hex string from non-prefixed hex", () => { - expect(bls.PrivateKey.fromHex(privateKey.replace("0x", "")).toHex()).to.be.equal(privateKey); + expect(bls.PrivateKey.fromHex(privateKey).toHex()).to.be.equal(privateKey); }); it("should not accept too short private key", () => { diff --git a/test/unit/publicKey.test.ts b/test/unit/publicKey.test.ts index cb139c1..23a52c0 100644 --- a/test/unit/publicKey.test.ts +++ b/test/unit/publicKey.test.ts @@ -11,7 +11,7 @@ export function runPublicKeyTests(bls: IBls): void { }); it("should export public key to hex string from non-prefixed hex", () => { - expect(bls.PublicKey.fromHex(publicKey.replace("0x", "")).toHex()).to.be.equal(publicKey); + expect(bls.PublicKey.fromHex(publicKey).toHex()).to.be.equal(publicKey); }); it("from private key", () => { diff --git a/test/util.ts b/test/util.ts index a122ed7..b929188 100644 --- a/test/util.ts +++ b/test/util.ts @@ -1,13 +1,5 @@ import {randomBytes} from "../src/helpers"; -export function fromHexString(hex: string): Uint8Array { - return Buffer.from(hex.replace("0x", ""), "hex"); -} - -export function toHexString(bytes: Buffer | Uint8Array): string { - return `0x${Buffer.from(bytes).toString("hex")}`; -} - export function randomMessage(): Uint8Array { return randomBytes(32); }