diff --git a/src/lib/enr/enr.spec.ts b/src/lib/enr/enr.spec.ts index c7d8d30d16..8701c0d838 100644 --- a/src/lib/enr/enr.spec.ts +++ b/src/lib/enr/enr.spec.ts @@ -198,8 +198,8 @@ describe("ENR", function () { ); }); - it("should encode/decode to RLP encoding", () => { - const decoded = ENR.decode(record.encode(privateKey)); + it("should encode/decode to RLP encoding", async () => { + const decoded = ENR.decode(await record.encode(privateKey)); expect(decoded).to.deep.equal(record); }); diff --git a/src/lib/enr/enr.ts b/src/lib/enr/enr.ts index c352f07a2e..cbece23f82 100644 --- a/src/lib/enr/enr.ts +++ b/src/lib/enr/enr.ts @@ -427,10 +427,10 @@ export class ENR extends Map { return v4.verify(this.publicKey, data, signature); } - sign(data: Uint8Array, privateKey: Uint8Array): Uint8Array { + async sign(data: Uint8Array, privateKey: Uint8Array): Promise { switch (this.id) { case "v4": - this.signature = v4.sign(privateKey, data); + this.signature = await v4.sign(privateKey, data); break; default: throw new Error(ERR_INVALID_ID); @@ -438,7 +438,9 @@ export class ENR extends Map { return this.signature; } - encodeToValues(privateKey?: Uint8Array): (ENRKey | ENRValue | number[])[] { + async encodeToValues( + privateKey?: Uint8Array + ): Promise<(ENRKey | ENRValue | number[])[]> { // sort keys and flatten into [k, v, k, v, ...] const content: Array = Array.from(this.keys()) .sort((a, b) => a.localeCompare(b)) @@ -447,7 +449,9 @@ export class ENR extends Map { .flat(); content.unshift(new Uint8Array([Number(this.seq)])); if (privateKey) { - content.unshift(this.sign(hexToBytes(RLP.encode(content)), privateKey)); + content.unshift( + await this.sign(hexToBytes(RLP.encode(content)), privateKey) + ); } else { if (!this.signature) { throw new Error(ERR_NO_SIGNATURE); @@ -457,8 +461,10 @@ export class ENR extends Map { return content; } - encode(privateKey?: Uint8Array): Uint8Array { - const encoded = hexToBytes(RLP.encode(this.encodeToValues(privateKey))); + async encode(privateKey?: Uint8Array): Promise { + const encoded = hexToBytes( + RLP.encode(await this.encodeToValues(privateKey)) + ); if (encoded.length >= MAX_RECORD_SIZE) { throw new Error("ENR must be less than 300 bytes"); } @@ -466,6 +472,8 @@ export class ENR extends Map { } async encodeTxt(privateKey?: Uint8Array): Promise { - return ENR.RECORD_PREFIX + (await bytesToBase64(this.encode(privateKey))); + return ( + ENR.RECORD_PREFIX + (await bytesToBase64(await this.encode(privateKey))) + ); } } diff --git a/src/lib/enr/v4.ts b/src/lib/enr/v4.ts index 0e70dc2640..6b1246f021 100644 --- a/src/lib/enr/v4.ts +++ b/src/lib/enr/v4.ts @@ -1,5 +1,5 @@ +import * as secp from "@noble/secp256k1"; import { keccak256 } from "js-sha3"; -import * as secp256k1 from "secp256k1"; import { randomBytes } from "../crypto"; @@ -15,11 +15,17 @@ export function createPrivateKey(): Uint8Array { } export function publicKey(privKey: Uint8Array): Uint8Array { - return secp256k1.publicKeyCreate(privKey); + return secp.getPublicKey(privKey, false); } -export function sign(privKey: Uint8Array, msg: Uint8Array): Uint8Array { - const { signature } = secp256k1.ecdsaSign(hash(msg), privKey); +export async function sign( + privKey: Uint8Array, + msg: Uint8Array +): Promise { + const [signature] = await secp.sign(hash(msg), privKey, { + recovered: true, + der: false, + }); return signature; } @@ -28,12 +34,17 @@ export function verify( msg: Uint8Array, sig: Uint8Array ): boolean { - // Remove the recovery id if present (byte #65) - return secp256k1.ecdsaVerify(sig.slice(0, 64), hash(msg), pubKey); + try { + const _sig = secp.Signature.fromCompact(sig.slice(0, 64)); + return secp.verify(_sig, hash(msg), pubKey); + } catch { + return false; + } } export function nodeId(pubKey: Uint8Array): NodeId { - const uncompressedPubkey = secp256k1.publicKeyConvert(pubKey, false); + const publicKey = secp.Point.fromHex(pubKey); + const uncompressedPubkey = publicKey.toRawBytes(false); return createNodeId(hash(uncompressedPubkey.slice(1))); } @@ -47,7 +58,7 @@ export class ENRKeyPair { public static create(privateKey?: Uint8Array): ENRKeyPair { if (privateKey) { - if (!secp256k1.privateKeyVerify(privateKey)) { + if (!secp.utils.isValidPrivateKey(privateKey)) { throw new Error("Invalid private key"); } } @@ -58,7 +69,7 @@ export class ENRKeyPair { return new ENRKeyPair(_nodeId, _privateKey, _publicKey); } - public sign(msg: Uint8Array): Uint8Array { + public async sign(msg: Uint8Array): Promise { return sign(this.privateKey, msg); }