From d49e061848d000019c72729928fcafb2ccea47d2 Mon Sep 17 00:00:00 2001 From: Chris Duncan Date: Sun, 30 Nov 2025 23:01:29 -0800 Subject: [PATCH] Remove redundant string type check. Remove redundant hex string padding. Remove checks for subtle crypto since this entire library assumes it is available. --- src/lib/crypto/secp256k1.ts | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/src/lib/crypto/secp256k1.ts b/src/lib/crypto/secp256k1.ts index a656a9b..791ce9d 100644 --- a/src/lib/crypto/secp256k1.ts +++ b/src/lib/crypto/secp256k1.ts @@ -33,7 +33,7 @@ type Point = { type Signature = ReturnType /** Alias to Uint8Array. */ -export type Bytes = Uint8Array +export type Bytes = Uint8Array /** Signature instance, which allows recovering pubkey from it. */ export type RecoveredSignature = Signature & { recovery: number } /** Weierstrass elliptic curve options. */ @@ -46,7 +46,6 @@ export type WeierstrassOpts = Readonly<{ Gx: T Gy: T }> -declare const globalThis: Record | undefined // Typescript symbol present in browsers /** Point in 2d xy affine coordinates. */ export type AffinePoint = { x: bigint @@ -155,7 +154,6 @@ export class Secp256k1 { this.captureTrace(e, this.err) throw e } - static isStr = (s: unknown): s is string => typeof s === 'string' // is string static isBytes = (a: unknown): a is Uint8Array => a instanceof Uint8Array || (ArrayBuffer.isView(a) && a.constructor.name === 'Uint8Array') /** Asserts something is Uint8Array. */ @@ -173,10 +171,9 @@ export class Secp256k1 { } /** create Uint8Array */ static u8n = (len: number): Bytes => new Uint8Array(len) - static padh = (n: number | bigint, pad: number) => n.toString(16).padStart(pad, '0') static bytesToHex = (b: Bytes): string => Array.from(this.abytes(b)) - .map((e) => this.padh(e, 2)) + .map((e) => e.toString(16).padStart(2, '0')) .join('') static C = { _0: 48, _9: 57, A: 65, F: 70, a: 97, f: 102 } as const // ASCII characters static _ch = (ch: number): number | undefined => { @@ -187,7 +184,7 @@ export class Secp256k1 { } static hexToBytes = (hex: string): Bytes => { const e = 'hex invalid' - if (!this.isStr(hex)) return this.err(e) + if (hex !== 'string') return this.err(e) const hl = hex.length const al = hl / 2 if (hl % 2) return this.err(e) @@ -201,8 +198,6 @@ export class Secp256k1 { } return array } - static cr = () => globalThis?.crypto // WebCrypto is available in all modern environments - static subtle = () => this.cr()?.subtle ?? this.err('crypto.subtle must be defined, consider polyfill') // prettier-ignore static concatBytes = (...arrs: Bytes[]): Bytes => { const r = this.u8n(arrs.reduce((sum, a) => sum + this.abytes(a).length, 0)) // create u8a of summed length @@ -212,8 +207,7 @@ export class Secp256k1 { } /** WebCrypto OS-level CSPRNG (random number generator). Will throw when not available. */ static randomBytes = (len: number = this.L): Bytes => { - const c = this.cr() - return c.getRandomValues(this.u8n(len)) + return crypto.getRandomValues(this.u8n(len)) } static arange = (n: bigint, min: bigint, max: bigint, msg = 'bad number: out of range'): bigint => typeof n === 'bigint' && min <= n && n < max ? n : this.err(msg) @@ -446,7 +440,13 @@ export class Secp256k1 { static sliceBytesNumBE = (b: Bytes, from: number, to: number) => this.bytesToNumBE(b.subarray(from, to)) static B256 = 2n ** 256n // secp256k1 is weierstrass curve. Equation is x³ + ax + b. /** Number to 32b. Must be 0 <= num < B256. validate, pad, to bytes. */ - static numTo32b = (num: bigint): Bytes => this.hexToBytes(this.padh(this.arange(num, 0n, this.B256), this.L2)) + static numTo32b = (num: bigint): Bytes => { + return this.hexToBytes(this + .arange(num, 0n, this.B256) + .toString(16) + .padStart(this.L2, '0') + ) + } /** Normalize private key to scalar (bigint). Verifies scalar is in range 1 { const num = this.bytesToNumBE(this.abytes(secretKey, this.L, 'secret key')) @@ -577,13 +577,12 @@ export class Secp256k1 { static _sha = 'SHA-256' static hashes = { hmacSha256Async: async (key: Bytes, message: Bytes): Promise => { - const s = this.subtle() const name = 'HMAC' - const k = await s.importKey('raw', key, { name, hash: { name: this._sha } }, false, ['sign']) - return this.u8n(await s.sign(name, k, message)) + const k = await crypto.subtle.importKey('raw', key, { name, hash: { name: this._sha } }, false, ['sign']) + return new Uint8Array(await crypto.subtle.sign(name, k, message)) }, hmacSha256: undefined as undefined | ((key: Bytes, message: Bytes) => Bytes), - sha256Async: async (msg: Bytes): Promise => this.u8n(await this.subtle().digest(this._sha, msg)), + sha256Async: async (msg: Bytes): Promise => new Uint8Array(await crypto.subtle.digest(this._sha, msg)), sha256: undefined as undefined | ((message: Bytes) => Bytes), } -- 2.47.3