diff --git a/package.json b/package.json index 2371a27..1de06e3 100644 --- a/package.json +++ b/package.json @@ -51,10 +51,9 @@ ] }, "dependencies": { - "jsbn": "^1.1.0" + "bigint-mod-arith": "^3.3.1" }, "devDependencies": { - "@types/jsbn": "^1.2.33", "arraybuffer-equal": "^1.0.4", "microbundle": "^0.15.1", "prettier": "^3.2.5", diff --git a/src/SRPInt.ts b/src/SRPInt.ts index 3dc36a4..1186441 100644 --- a/src/SRPInt.ts +++ b/src/SRPInt.ts @@ -1,24 +1,26 @@ -import { BigInteger } from "jsbn"; +import { modPow } from "bigint-mod-arith"; import { getRandomValues } from "./crypto"; import { bufferToHex } from "./utils"; const bi = Symbol("big-int"); +const WHITESPACE_RE = /\s+/g; + export class SRPInt { - [bi]: BigInteger; + [bi]: bigint; constructor( - bigInt: BigInteger, + bigInt: bigint, public hexLength: number | null, ) { this[bi] = bigInt; } - static ZERO = new SRPInt(new BigInteger("0"), null); + static ZERO = new SRPInt(0n, null); static fromHex(hex: string): SRPInt { - const sanitized = hex.replace(/\s+/g, "").toLowerCase(); - return new SRPInt(new BigInteger(sanitized, 16), sanitized.length); + const sanitized = hex.replace(WHITESPACE_RE, ""); + return new SRPInt(BigInt(`0x${sanitized}`), sanitized.length); } static getRandom(bytes: number): SRPInt { @@ -28,26 +30,27 @@ export class SRPInt { } add(value: SRPInt): SRPInt { - return new SRPInt(this[bi].add(value[bi]), null); + return new SRPInt(this[bi] + value[bi], null); } equals(value: SRPInt): boolean { - return this[bi].equals(value[bi]); + return this[bi] === value[bi]; } mod(modulus: SRPInt): SRPInt { - return new SRPInt(this[bi].mod(modulus[bi]), modulus.hexLength); + return new SRPInt(this[bi] % modulus[bi], modulus.hexLength); } modPow(exponent: SRPInt, modulus: SRPInt): SRPInt { - return new SRPInt( - this[bi].modPow(exponent[bi], modulus[bi]), - modulus.hexLength, - ); + const b = this[bi]; + const e = exponent[bi]; + const m = modulus[bi]; + + return new SRPInt(modPow(b, e, m), modulus.hexLength); } multiply(value: SRPInt): SRPInt { - return new SRPInt(this[bi].multiply(value[bi]), null); + return new SRPInt(this[bi] * value[bi], null); } pad(paddedHexLength: number): SRPInt { @@ -59,7 +62,7 @@ export class SRPInt { } subtract(value: SRPInt): SRPInt { - return new SRPInt(this[bi].subtract(value[bi]), this.hexLength); + return new SRPInt(this[bi] - value[bi], this.hexLength); } toHex(): string { @@ -71,6 +74,6 @@ export class SRPInt { } xor(value: SRPInt): SRPInt { - return new SRPInt(this[bi].xor(value[bi]), this.hexLength); + return new SRPInt(this[bi] ^ value[bi], this.hexLength); } } diff --git a/src/hash.ts b/src/hash.ts index bcfe217..b95ded4 100644 --- a/src/hash.ts +++ b/src/hash.ts @@ -7,9 +7,12 @@ export const hash = async ( hashAlgorithm: HashAlgorithm, ...input: (SRPInt | string)[] ) => { - const buffers = input.map((item) => - typeof item === "string" ? encodeUtf8(item) : hexToBuffer(item.toHex()), - ); + const buffers = input.map((item) => { + if (typeof item === "string") { + return encodeUtf8(item); + } + return hexToBuffer(item.toHex()); + }); const combined = new Uint8Array( buffers.reduce((offset, item) => offset + item.byteLength, 0), diff --git a/tsconfig.json b/tsconfig.json index de16a1e..a60081e 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,9 +1,9 @@ { "include": ["src/**/*"], "compilerOptions": { - "module": "ES2015", - "target": "ES2015", - "lib": ["ES2015", "DOM"], + "module": "ES2020", + "target": "ES2020", + "lib": ["ES2020", "DOM"], "moduleResolution": "Node", "outDir": "dist/", diff --git a/yarn.lock b/yarn.lock index e2d2fb4..52d1b9c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1347,11 +1347,6 @@ resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.39.tgz#e177e699ee1b8c22d23174caaa7422644389509f" integrity sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw== -"@types/jsbn@^1.2.33": - version "1.2.33" - resolved "https://registry.yarnpkg.com/@types/jsbn/-/jsbn-1.2.33.tgz#470a4ff059f40fa6ca59838a8fa3f30c62a8c5ac" - integrity sha512-ZlLkHfu8xqqVFSbCe1FSPtAMUs7LKxk7TPskMb+sI5IbuzqyVqIEt9SVaQfFD2vrFcQunqKAmEBOuBEkoNLw4g== - "@types/node@*": version "20.11.23" resolved "https://registry.yarnpkg.com/@types/node/-/node-20.11.23.tgz#5c156571ccb4200a2408084f472e1927d719c01e" @@ -1570,6 +1565,11 @@ balanced-match@^1.0.0: resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== +bigint-mod-arith@^3.3.1: + version "3.3.1" + resolved "https://registry.yarnpkg.com/bigint-mod-arith/-/bigint-mod-arith-3.3.1.tgz#8ed33dc9f7886e552a7d47c239e051836e74cfa8" + integrity sha512-pX/cYW3dCa87Jrzv6DAr8ivbbJRzEX5yGhdt8IutnX/PCIXfpx+mabWNK/M8qqh+zQ0J3thftUBHW0ByuUlG0w== + boolbase@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e" @@ -2659,11 +2659,6 @@ js-tokens@^8.0.2: resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-8.0.3.tgz#1c407ec905643603b38b6be6977300406ec48775" integrity sha512-UfJMcSJc+SEXEl9lH/VLHSZbThQyLpw1vLO1Lb+j4RWDvG3N2f7yj3PVQA3cmkTBNldJ9eFnM+xEXxHIXrYiJw== -jsbn@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-1.1.0.tgz#b01307cb29b618a1ed26ec79e911f803c4da0040" - integrity sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A== - jsesc@^2.5.1: version "2.5.2" resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4"