From afd48cedb82f64b716f0230c1f7b05cd68774653 Mon Sep 17 00:00:00 2001 From: dynst <148708712+dynst@users.noreply.github.com> Date: Sat, 19 Jul 2025 00:00:00 +0000 Subject: [PATCH 1/9] replace bn.js in Uint64 class --- packages/math/src/integers.ts | 55 +++++++++++++++++++++-------------- 1 file changed, 33 insertions(+), 22 deletions(-) diff --git a/packages/math/src/integers.ts b/packages/math/src/integers.ts index 20fdefbbde..3302f619e9 100644 --- a/packages/math/src/integers.ts +++ b/packages/math/src/integers.ts @@ -1,9 +1,6 @@ /* eslint-disable no-bitwise */ -// eslint-disable-next-line @typescript-eslint/naming-convention -import BN from "bn.js"; - -const uint64MaxValue = new BN("18446744073709551615", 10, "be"); +const uint64MaxValue = 18446744073709551615n; /** Internal interface to ensure all integer types can be used equally */ interface Integer { @@ -201,21 +198,25 @@ export class Uint64 implements Integer, WithByteConverters { throw new Error("Invalid input length. Expected 8 bytes."); } - for (let i = 0; i < bytes.length; ++i) { - if (!Number.isInteger(bytes[i]) || bytes[i] > 255 || bytes[i] < 0) { - throw new Error("Invalid value in byte. Found: " + bytes[i]); + const beBytes = endianess === "be" ? Array.from(bytes) : Array.from(bytes).reverse(); + let value = 0n; + + for (const byte of beBytes) { + value *= 256n; + if (!Number.isInteger(byte) || byte > 255 || byte < 0) { + throw new Error("Invalid value in byte. Found: " + byte); } + value += BigInt(byte); } - const beBytes = endianess === "be" ? Array.from(bytes) : Array.from(bytes).reverse(); - return new Uint64(new BN(beBytes)); + return new Uint64(value); } public static fromString(str: string): Uint64 { if (!str.match(/^[0-9]+$/)) { throw new Error("Invalid string format"); } - return new Uint64(new BN(str, 10, "be")); + return new Uint64(BigInt(str)); } public static fromNumber(input: number): Uint64 { @@ -227,33 +228,39 @@ export class Uint64 implements Integer, WithByteConverters { throw new Error("Input is not an integer"); } - let bigint: BN; - try { - bigint = new BN(input); - } catch { + if (!Number.isSafeInteger(input)) { throw new Error("Input is not a safe integer"); } + + const bigint = BigInt(input); return new Uint64(bigint); } - private readonly data: BN; + private readonly data: bigint; - private constructor(data: BN) { - if (data.isNeg()) { + private constructor(data: bigint) { + if (data < 0n) { throw new Error("Input is negative"); } - if (data.gt(uint64MaxValue)) { + if (data > uint64MaxValue) { throw new Error("Input exceeds uint64 range"); } this.data = data; } public toBytesBigEndian(): Uint8Array { - return Uint8Array.from(this.data.toArray("be", 8)); + return this.toBytesLittleEndian().reverse(); } public toBytesLittleEndian(): Uint8Array { - return Uint8Array.from(this.data.toArray("le", 8)); + const bytes = new Uint8Array(8); + let value = this.data; + for (let i = 0; i < bytes.length; i++) { + bytes[i] = Number(value % 256n); + value /= 256n; + } + + return bytes; } public toString(): string { @@ -261,11 +268,15 @@ export class Uint64 implements Integer, WithByteConverters { } public toBigInt(): bigint { - return BigInt(this.toString()); + return this.data; } public toNumber(): number { - return this.data.toNumber(); + const num = Number(this.data); + if (!Number.isSafeInteger(num)) { + throw new Error("Not safe integer"); + } + return num; } } From c29393934138cb95b2cc73c4d54fcc430ae33298 Mon Sep 17 00:00:00 2001 From: dynst <148708712+dynst@users.noreply.github.com> Date: Sat, 19 Jul 2025 00:00:00 +0000 Subject: [PATCH 2/9] use specific thrown error string --- packages/math/src/integers.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/math/src/integers.ts b/packages/math/src/integers.ts index 3302f619e9..986e6faf1d 100644 --- a/packages/math/src/integers.ts +++ b/packages/math/src/integers.ts @@ -274,7 +274,7 @@ export class Uint64 implements Integer, WithByteConverters { public toNumber(): number { const num = Number(this.data); if (!Number.isSafeInteger(num)) { - throw new Error("Not safe integer"); + throw new Error("number can only safely store up to 53 bits"); } return num; } From 1c2b4c4d9648935ac5279f1dbc913479b2e8767e Mon Sep 17 00:00:00 2001 From: dynst <148708712+dynst@users.noreply.github.com> Date: Sat, 19 Jul 2025 00:00:00 +0000 Subject: [PATCH 3/9] replace bn.js in Decimal --- packages/math/src/decimal.ts | 45 +++++++++++++++++------------------- 1 file changed, 21 insertions(+), 24 deletions(-) diff --git a/packages/math/src/decimal.ts b/packages/math/src/decimal.ts index 8e46e0617b..f59a13b12d 100644 --- a/packages/math/src/decimal.ts +++ b/packages/math/src/decimal.ts @@ -1,6 +1,3 @@ -// eslint-disable-next-line @typescript-eslint/naming-convention -import BN from "bn.js"; - import { Uint32, Uint53, Uint64 } from "./integers"; // Too large values lead to massive memory usage. Limit to something sensible. @@ -94,7 +91,7 @@ export class Decimal { public static compare(a: Decimal, b: Decimal): number { if (a.fractionalDigits !== b.fractionalDigits) throw new Error("Fractional digits do not match"); - return a.data.atomics.cmp(new BN(b.atomics)); + return Math.sign(Number(a.data.atomics - b.data.atomics)); } public get atomics(): string { @@ -106,7 +103,7 @@ export class Decimal { } private readonly data: { - readonly atomics: BN; + readonly atomics: bigint; readonly fractionalDigits: number; }; @@ -118,7 +115,7 @@ export class Decimal { } this.data = { - atomics: new BN(atomics), + atomics: BigInt(atomics), fractionalDigits: fractionalDigits, }; } @@ -130,36 +127,36 @@ export class Decimal { /** Returns the greatest decimal <= this which has no fractional part (rounding down) */ public floor(): Decimal { - const factor = new BN(10).pow(new BN(this.data.fractionalDigits)); - const whole = this.data.atomics.div(factor); - const fractional = this.data.atomics.mod(factor); + const factor = 10n ** BigInt(this.data.fractionalDigits); + const whole = this.data.atomics / factor; + const fractional = this.data.atomics % factor; - if (fractional.isZero()) { + if (fractional === 0n) { return this.clone(); } else { - return Decimal.fromAtomics(whole.mul(factor).toString(), this.fractionalDigits); + return Decimal.fromAtomics((whole * factor).toString(), this.fractionalDigits); } } /** Returns the smallest decimal >= this which has no fractional part (rounding up) */ public ceil(): Decimal { - const factor = new BN(10).pow(new BN(this.data.fractionalDigits)); - const whole = this.data.atomics.div(factor); - const fractional = this.data.atomics.mod(factor); + const factor = 10n ** BigInt(this.data.fractionalDigits); + const whole = this.data.atomics / factor; + const fractional = this.data.atomics % factor; - if (fractional.isZero()) { + if (fractional === 0n) { return this.clone(); } else { - return Decimal.fromAtomics(whole.addn(1).mul(factor).toString(), this.fractionalDigits); + return Decimal.fromAtomics(((whole + 1n) * factor).toString(), this.fractionalDigits); } } public toString(): string { - const factor = new BN(10).pow(new BN(this.data.fractionalDigits)); - const whole = this.data.atomics.div(factor); - const fractional = this.data.atomics.mod(factor); + const factor = 10n ** BigInt(this.data.fractionalDigits); + const whole = this.data.atomics / factor; + const fractional = this.data.atomics % factor; - if (fractional.isZero()) { + if (fractional === 0n) { return whole.toString(); } else { const fullFractionalPart = fractional.toString().padStart(this.data.fractionalDigits, "0"); @@ -185,7 +182,7 @@ export class Decimal { */ public plus(b: Decimal): Decimal { if (this.fractionalDigits !== b.fractionalDigits) throw new Error("Fractional digits do not match"); - const sum = this.data.atomics.add(new BN(b.atomics)); + const sum = this.data.atomics + b.data.atomics; return new Decimal(sum.toString(), this.fractionalDigits); } @@ -197,8 +194,8 @@ export class Decimal { */ public minus(b: Decimal): Decimal { if (this.fractionalDigits !== b.fractionalDigits) throw new Error("Fractional digits do not match"); - const difference = this.data.atomics.sub(new BN(b.atomics)); - if (difference.ltn(0)) throw new Error("Difference must not be negative"); + const difference = this.data.atomics - b.data.atomics; + if (difference < 0n) throw new Error("Difference must not be negative"); return new Decimal(difference.toString(), this.fractionalDigits); } @@ -208,7 +205,7 @@ export class Decimal { * We only allow multiplication by unsigned integers to avoid rounding errors. */ public multiply(b: Uint32 | Uint53 | Uint64): Decimal { - const product = this.data.atomics.mul(new BN(b.toString())); + const product = this.data.atomics * b.toBigInt(); return new Decimal(product.toString(), this.fractionalDigits); } From 647cf93ae5da428d693c989b68b00291535c1760 Mon Sep 17 00:00:00 2001 From: dynst <148708712+dynst@users.noreply.github.com> Date: Sat, 19 Jul 2025 00:00:00 +0000 Subject: [PATCH 4/9] remove bn.js dependency from math package --- .pnp.cjs | 2 -- packages/math/package.json | 4 ---- yarn.lock | 2 -- 3 files changed, 8 deletions(-) diff --git a/.pnp.cjs b/.pnp.cjs index ea69d43bba..66fb69c84c 100644 --- a/.pnp.cjs +++ b/.pnp.cjs @@ -3576,12 +3576,10 @@ const RAW_RUNTIME_STATE = "packageDependencies": [\ ["@cosmjs/math", "workspace:packages/math"],\ ["@istanbuljs/nyc-config-typescript", "virtual:4f1584ad4aba8733a24be7c8aebbffafef25607f2d00f4b314cf96717145c692763628a31c2b85d4686fbb091ff21ebffa3cc337399c042c19a32b9bdb786464#npm:1.0.1"],\ - ["@types/bn.js", "npm:5.1.0"],\ ["@types/jasmine", "npm:4.6.1"],\ ["@types/karma-firefox-launcher", "npm:2.1.0"],\ ["@types/karma-jasmine", "npm:4.0.2"],\ ["@types/karma-jasmine-html-reporter", "npm:1.5.1"],\ - ["bn.js", "npm:5.2.0"],\ ["buffer", "npm:6.0.3"],\ ["eslint", "npm:8.57.1"],\ ["glob", "npm:11.0.3"],\ diff --git a/packages/math/package.json b/packages/math/package.json index 5b0527de6a..6232440ebc 100644 --- a/packages/math/package.json +++ b/packages/math/package.json @@ -39,12 +39,8 @@ "build-or-skip": "[ -n \"$SKIP_BUILD\" ] || yarn build", "pack-web": "yarn build-or-skip && webpack --mode development --config webpack.web.config.js" }, - "dependencies": { - "bn.js": "^5.2.0" - }, "devDependencies": { "@istanbuljs/nyc-config-typescript": "^1.0.1", - "@types/bn.js": "^5", "@types/jasmine": "^4", "@types/karma-firefox-launcher": "^2", "@types/karma-jasmine": "^4", diff --git a/yarn.lock b/yarn.lock index dc02fe03e3..aac9241683 100644 --- a/yarn.lock +++ b/yarn.lock @@ -523,12 +523,10 @@ __metadata: resolution: "@cosmjs/math@workspace:packages/math" dependencies: "@istanbuljs/nyc-config-typescript": "npm:^1.0.1" - "@types/bn.js": "npm:^5" "@types/jasmine": "npm:^4" "@types/karma-firefox-launcher": "npm:^2" "@types/karma-jasmine": "npm:^4" "@types/karma-jasmine-html-reporter": "npm:^1" - bn.js: "npm:^5.2.0" buffer: "npm:^6.0.3" eslint: "npm:^8.57.1" glob: "npm:^11" From 7ddfcf2a5666465530c0a1ca2a5abf534eae2ec9 Mon Sep 17 00:00:00 2001 From: dynst <148708712+dynst@users.noreply.github.com> Date: Sat, 19 Jul 2025 00:00:00 +0000 Subject: [PATCH 5/9] replace bn.js in crypto slip10 code --- packages/crypto/src/slip10.ts | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/packages/crypto/src/slip10.ts b/packages/crypto/src/slip10.ts index 0b3694c025..213435014d 100644 --- a/packages/crypto/src/slip10.ts +++ b/packages/crypto/src/slip10.ts @@ -1,8 +1,6 @@ -import { toAscii, toHex } from "@cosmjs/encoding"; +import { fromHex, toAscii, toHex } from "@cosmjs/encoding"; import { Uint32, Uint53 } from "@cosmjs/math"; import { secp256k1 } from "@noble/curves/secp256k1"; -// eslint-disable-next-line @typescript-eslint/naming-convention -import BN from "bn.js"; import { Hmac } from "./hmac"; import { Sha512 } from "./sha"; @@ -26,6 +24,12 @@ function bytesToUnsignedBigInt(a: Uint8Array): bigint { return BigInt("0x" + toHex(a)); } +function intTo32be(n: bigint): Uint8Array { + // 32 bytes is 64 hexadecimal characters + const hex = n.toString(16).padStart(64, "0"); + return fromHex(hex); +} + /** * Reverse mapping of Slip10Curve */ @@ -174,9 +178,9 @@ export class Slip10 { } // step 5 - const n = this.n(curve); - const returnChildKeyAsNumber = new BN(il).add(new BN(parentPrivkey)).mod(n); - const returnChildKey = Uint8Array.from(returnChildKeyAsNumber.toArray("be", 32)); + const n: bigint = this.n(curve); + const returnChildKeyAsNumber = (bytesToUnsignedBigInt(il) + bytesToUnsignedBigInt(parentPrivkey)) % n; + const returnChildKey = intTo32be(returnChildKeyAsNumber); // step 6 if (this.isGteN(curve, il) || this.isZero(returnChildKey)) { @@ -198,14 +202,14 @@ export class Slip10 { } private static isGteN(curve: Slip10Curve, privkey: Uint8Array): boolean { - const keyAsNumber = new BN(privkey); - return keyAsNumber.gte(this.n(curve)); + const keyAsNumber: bigint = bytesToUnsignedBigInt(privkey); + return keyAsNumber >= this.n(curve); } - private static n(curve: Slip10Curve): BN { + private static n(curve: Slip10Curve): bigint { switch (curve) { case Slip10Curve.Secp256k1: - return new BN("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141", 16); + return 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141n; default: throw new Error("curve not supported"); } From 524f5820e52a91292e6c854c217bdfb5335cddda Mon Sep 17 00:00:00 2001 From: dynst <148708712+dynst@users.noreply.github.com> Date: Sat, 19 Jul 2025 00:00:00 +0000 Subject: [PATCH 6/9] remove bn.js dependency from crypto package --- .pnp.cjs | 29 ------------------- ...-bn.js-npm-5.1.0-4a0335ff4f-04c6705445.zip | 3 -- .../bn.js-npm-5.2.0-11748c0b07-67e17b1934.zip | 3 -- packages/crypto/package.json | 2 -- yarn.lock | 18 ------------ 5 files changed, 55 deletions(-) delete mode 100644 .yarn/cache/@types-bn.js-npm-5.1.0-4a0335ff4f-04c6705445.zip delete mode 100644 .yarn/cache/bn.js-npm-5.2.0-11748c0b07-67e17b1934.zip diff --git a/.pnp.cjs b/.pnp.cjs index 66fb69c84c..88a1e2c592 100644 --- a/.pnp.cjs +++ b/.pnp.cjs @@ -481,10 +481,6 @@ const RAW_RUNTIME_STATE = "@types/base64-js",\ "npm:1.3.0"\ ],\ - [\ - "@types/bn.js",\ - "npm:5.1.0"\ - ],\ [\ "@types/body-parser",\ "npm:1.19.0"\ @@ -893,10 +889,6 @@ const RAW_RUNTIME_STATE = "bl",\ "npm:4.1.0"\ ],\ - [\ - "bn.js",\ - "npm:5.2.0"\ - ],\ [\ "body-parser",\ "npm:1.20.2"\ @@ -3369,14 +3361,12 @@ const RAW_RUNTIME_STATE = ["@istanbuljs/nyc-config-typescript", "virtual:4f1584ad4aba8733a24be7c8aebbffafef25607f2d00f4b314cf96717145c692763628a31c2b85d4686fbb091ff21ebffa3cc337399c042c19a32b9bdb786464#npm:1.0.1"],\ ["@noble/curves", "npm:1.9.2"],\ ["@noble/hashes", "npm:1.8.0"],\ - ["@types/bn.js", "npm:5.1.0"],\ ["@types/jasmine", "npm:4.6.1"],\ ["@types/karma-firefox-launcher", "npm:2.1.0"],\ ["@types/karma-jasmine", "npm:4.0.2"],\ ["@types/karma-jasmine-html-reporter", "npm:1.5.1"],\ ["@types/libsodium-wrappers-sumo", "npm:0.7.5"],\ ["@types/node", "npm:22.10.6"],\ - ["bn.js", "npm:5.2.0"],\ ["buffer", "npm:6.0.3"],\ ["eslint", "npm:8.57.1"],\ ["glob", "npm:11.0.3"],\ @@ -4493,16 +4483,6 @@ const RAW_RUNTIME_STATE = "linkType": "HARD"\ }]\ ]],\ - ["@types/bn.js", [\ - ["npm:5.1.0", {\ - "packageLocation": "./.yarn/cache/@types-bn.js-npm-5.1.0-4a0335ff4f-04c6705445.zip/node_modules/@types/bn.js/",\ - "packageDependencies": [\ - ["@types/bn.js", "npm:5.1.0"],\ - ["@types/node", "npm:22.10.6"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ ["@types/body-parser", [\ ["npm:1.19.0", {\ "packageLocation": "./.yarn/cache/@types-body-parser-npm-1.19.0-3ca4d08a60-ffc4af4869.zip/node_modules/@types/body-parser/",\ @@ -6472,15 +6452,6 @@ const RAW_RUNTIME_STATE = "linkType": "HARD"\ }]\ ]],\ - ["bn.js", [\ - ["npm:5.2.0", {\ - "packageLocation": "./.yarn/cache/bn.js-npm-5.2.0-11748c0b07-67e17b1934.zip/node_modules/bn.js/",\ - "packageDependencies": [\ - ["bn.js", "npm:5.2.0"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ ["body-parser", [\ ["npm:1.20.2", {\ "packageLocation": "./.yarn/cache/body-parser-npm-1.20.2-44738662cf-06f1438fff.zip/node_modules/body-parser/",\ diff --git a/.yarn/cache/@types-bn.js-npm-5.1.0-4a0335ff4f-04c6705445.zip b/.yarn/cache/@types-bn.js-npm-5.1.0-4a0335ff4f-04c6705445.zip deleted file mode 100644 index 696a930d77..0000000000 --- a/.yarn/cache/@types-bn.js-npm-5.1.0-4a0335ff4f-04c6705445.zip +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:b21444439e2316ffca00eae5dd7cca4b8bd1e6d6c93eba3cac6bc9a4d6320c2b -size 14857 diff --git a/.yarn/cache/bn.js-npm-5.2.0-11748c0b07-67e17b1934.zip b/.yarn/cache/bn.js-npm-5.2.0-11748c0b07-67e17b1934.zip deleted file mode 100644 index 248d860148..0000000000 --- a/.yarn/cache/bn.js-npm-5.2.0-11748c0b07-67e17b1934.zip +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:def3f0affc6832c980fc21a50f2fdd4116326cf2d60f85085b69917ce3fcbcd6 -size 101398 diff --git a/packages/crypto/package.json b/packages/crypto/package.json index d627c10df9..a8c21a9cab 100644 --- a/packages/crypto/package.json +++ b/packages/crypto/package.json @@ -46,12 +46,10 @@ "@cosmjs/utils": "workspace:^", "@noble/curves": "^1.9.2", "@noble/hashes": "^1", - "bn.js": "^5.2.0", "libsodium-wrappers-sumo": "^0.7.11" }, "devDependencies": { "@istanbuljs/nyc-config-typescript": "^1.0.1", - "@types/bn.js": "^5", "@types/jasmine": "^4", "@types/karma-firefox-launcher": "^2", "@types/karma-jasmine": "^4", diff --git a/yarn.lock b/yarn.lock index aac9241683..4fb312cb49 100644 --- a/yarn.lock +++ b/yarn.lock @@ -326,14 +326,12 @@ __metadata: "@istanbuljs/nyc-config-typescript": "npm:^1.0.1" "@noble/curves": "npm:^1.9.2" "@noble/hashes": "npm:^1" - "@types/bn.js": "npm:^5" "@types/jasmine": "npm:^4" "@types/karma-firefox-launcher": "npm:^2" "@types/karma-jasmine": "npm:^4" "@types/karma-jasmine-html-reporter": "npm:^1" "@types/libsodium-wrappers-sumo": "npm:^0.7.5" "@types/node": "npm:*" - bn.js: "npm:^5.2.0" buffer: "npm:^6.0.3" eslint: "npm:^8.57.1" glob: "npm:^11" @@ -1300,15 +1298,6 @@ __metadata: languageName: node linkType: hard -"@types/bn.js@npm:^5": - version: 5.1.0 - resolution: "@types/bn.js@npm:5.1.0" - dependencies: - "@types/node": "npm:*" - checksum: 10c0/04c6705445f8588ca54bb1e28bee6a1e3e97fa87551cde45b6f7e1d856d394ae0d36d3c75f11388062562dc0a6f4b4e0d5282ccfbe463d472589f9d1cc95ebd5 - languageName: node - linkType: hard - "@types/body-parser@npm:*": version: 1.19.0 resolution: "@types/body-parser@npm:1.19.0" @@ -2311,13 +2300,6 @@ __metadata: languageName: node linkType: hard -"bn.js@npm:^5.2.0": - version: 5.2.0 - resolution: "bn.js@npm:5.2.0" - checksum: 10c0/67e17b1934d9c7a73aed9b89222dc8c1c8e3aff46cca6609b8c2ab04fa22c6b8db42c7774b039d09fa63136d8866b777ab88af0d64d8ea3839a94e69193a6b13 - languageName: node - linkType: hard - "body-parser@npm:^1.19.0": version: 1.20.2 resolution: "body-parser@npm:1.20.2" From cf40bca1e5ef404c9a68db3e9d89929d574bacbf Mon Sep 17 00:00:00 2001 From: dynst <148708712+dynst@users.noreply.github.com> Date: Tue, 22 Jul 2025 00:00:00 +0000 Subject: [PATCH 7/9] number range assertions --- packages/crypto/src/slip10.ts | 3 +++ packages/math/src/integers.ts | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/packages/crypto/src/slip10.ts b/packages/crypto/src/slip10.ts index 213435014d..16f9394c07 100644 --- a/packages/crypto/src/slip10.ts +++ b/packages/crypto/src/slip10.ts @@ -1,5 +1,6 @@ import { fromHex, toAscii, toHex } from "@cosmjs/encoding"; import { Uint32, Uint53 } from "@cosmjs/math"; +import { assert } from "@cosmjs/utils"; import { secp256k1 } from "@noble/curves/secp256k1"; import { Hmac } from "./hmac"; @@ -25,6 +26,8 @@ function bytesToUnsignedBigInt(a: Uint8Array): bigint { } function intTo32be(n: bigint): Uint8Array { + assert(n >= 0n); + assert(n < 2n ** (32n * 8n)); // 32 bytes is 64 hexadecimal characters const hex = n.toString(16).padStart(64, "0"); return fromHex(hex); diff --git a/packages/math/src/integers.ts b/packages/math/src/integers.ts index 986e6faf1d..954222410e 100644 --- a/packages/math/src/integers.ts +++ b/packages/math/src/integers.ts @@ -272,10 +272,10 @@ export class Uint64 implements Integer, WithByteConverters { } public toNumber(): number { - const num = Number(this.data); - if (!Number.isSafeInteger(num)) { + if (this.data > BigInt(Number.MAX_SAFE_INTEGER)) { throw new Error("number can only safely store up to 53 bits"); } + const num = Number(this.data); return num; } } From 1ef3e7f8c8096da667638fe7ce30117aaeb7a7b0 Mon Sep 17 00:00:00 2001 From: dynst <148708712+dynst@users.noreply.github.com> Date: Tue, 22 Jul 2025 00:00:00 +0000 Subject: [PATCH 8/9] inferred type --- packages/crypto/src/slip10.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/crypto/src/slip10.ts b/packages/crypto/src/slip10.ts index 16f9394c07..0be6d23384 100644 --- a/packages/crypto/src/slip10.ts +++ b/packages/crypto/src/slip10.ts @@ -181,7 +181,7 @@ export class Slip10 { } // step 5 - const n: bigint = this.n(curve); + const n = this.n(curve); const returnChildKeyAsNumber = (bytesToUnsignedBigInt(il) + bytesToUnsignedBigInt(parentPrivkey)) % n; const returnChildKey = intTo32be(returnChildKeyAsNumber); @@ -205,7 +205,7 @@ export class Slip10 { } private static isGteN(curve: Slip10Curve, privkey: Uint8Array): boolean { - const keyAsNumber: bigint = bytesToUnsignedBigInt(privkey); + const keyAsNumber = bytesToUnsignedBigInt(privkey); return keyAsNumber >= this.n(curve); } From f81ec67a81427e9d91530f1a4cc0084802848ee2 Mon Sep 17 00:00:00 2001 From: dynst <148708712+dynst@users.noreply.github.com> Date: Tue, 22 Jul 2025 00:00:00 +0000 Subject: [PATCH 9/9] self-documenting code Number(bigint) will clamp large numbers to positive or negative Infinity so the code works fine but this is simply clearer-looking. --- packages/math/src/decimal.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/math/src/decimal.ts b/packages/math/src/decimal.ts index f59a13b12d..485cd39c03 100644 --- a/packages/math/src/decimal.ts +++ b/packages/math/src/decimal.ts @@ -91,7 +91,10 @@ export class Decimal { public static compare(a: Decimal, b: Decimal): number { if (a.fractionalDigits !== b.fractionalDigits) throw new Error("Fractional digits do not match"); - return Math.sign(Number(a.data.atomics - b.data.atomics)); + const difference = a.data.atomics - b.data.atomics; + if (difference < 0n) return -1; + if (difference > 0n) return 1; + return 0; } public get atomics(): string {