From 573eab9235fa85100beef5de6d2ffcbd3322ad1e Mon Sep 17 00:00:00 2001 From: Antoine du Hamel Date: Sun, 27 Nov 2022 19:27:21 +0100 Subject: [PATCH] crypto: refactor ArrayBuffer to bigint conversion utils PR-URL: https://github.com/nodejs/node/pull/45567 Refs: https://github.com/nodejs/performance/issues/16 Reviewed-By: Yagiz Nizipli Reviewed-By: James M Snell --- lib/internal/crypto/random.js | 35 ++++++++++++++++++++++--- lib/internal/per_context/primordials.js | 2 ++ typings/primordials.d.ts | 2 ++ 3 files changed, 35 insertions(+), 4 deletions(-) diff --git a/lib/internal/crypto/random.js b/lib/internal/crypto/random.js index 6705bcd2e7d592..fe76cf1a69ef43 100644 --- a/lib/internal/crypto/random.js +++ b/lib/internal/crypto/random.js @@ -2,17 +2,22 @@ const { Array, + ArrayBufferPrototypeGetByteLength, ArrayPrototypeForEach, ArrayPrototypePush, ArrayPrototypeShift, ArrayPrototypeSplice, BigInt, + BigIntPrototypeToString, + DataView, + DataViewPrototypeGetUint8, FunctionPrototypeBind, FunctionPrototypeCall, MathMin, NumberIsNaN, NumberIsSafeInteger, NumberPrototypeToString, + StringFromCharCodeApply, StringPrototypePadStart, } = primordials; @@ -493,8 +498,30 @@ function generatePrimeSync(size, options = kEmptyObject) { return job.result(prime); } -function arrayBufferToUnsignedBigInt(arrayBuffer) { - return BigInt(`0x${Buffer.from(arrayBuffer).toString('hex')}`); +/** + * 48 is the ASCII code for '0', 97 is the ASCII code for 'a'. + * @param {number} number An integer between 0 and 15. + * @returns {number} corresponding to the ASCII code of the hex representation + * of the parameter. + */ +const numberToHexCharCode = (number) => (number < 10 ? 48 : 87) + number; + +/** + * @param {ArrayBuffer} buf An ArrayBuffer. + * @return {bigint} + */ +function arrayBufferToUnsignedBigInt(buf) { + const length = ArrayBufferPrototypeGetByteLength(buf); + const chars = Array(length * 2); + const view = new DataView(buf); + + for (let i = 0; i < length; i++) { + const val = DataViewPrototypeGetUint8(view, i); + chars[2 * i] = numberToHexCharCode(val >> 4); + chars[2 * i + 1] = numberToHexCharCode(val & 0xf); + } + + return BigInt(`0x${StringFromCharCodeApply(chars)}`); } function unsignedBigIntToBuffer(bigint, name) { @@ -502,8 +529,8 @@ function unsignedBigIntToBuffer(bigint, name) { throw new ERR_OUT_OF_RANGE(name, '>= 0', bigint); } - const hex = bigint.toString(16); - const padded = hex.padStart(hex.length + (hex.length % 2), 0); + const hex = BigIntPrototypeToString(bigint, 16); + const padded = StringPrototypePadStart(hex, hex.length + (hex.length % 2), 0); return Buffer.from(padded, 'hex'); } diff --git a/lib/internal/per_context/primordials.js b/lib/internal/per_context/primordials.js index bc903d02849e41..370f5953dc78e5 100644 --- a/lib/internal/per_context/primordials.js +++ b/lib/internal/per_context/primordials.js @@ -45,6 +45,8 @@ const varargsMethods = [ 'MathHypot', 'MathMax', 'MathMin', + 'StringFromCharCode', + 'StringFromCodePoint', 'StringPrototypeConcat', 'TypedArrayOf', ]; diff --git a/typings/primordials.d.ts b/typings/primordials.d.ts index 72d5a36701f651..4dcbac3abc9425 100644 --- a/typings/primordials.d.ts +++ b/typings/primordials.d.ts @@ -422,7 +422,9 @@ declare namespace primordials { export const StringName: typeof String.name export const StringPrototype: typeof String.prototype export const StringFromCharCode: typeof String.fromCharCode + export const StringFromCharCodeApply: StaticApply export const StringFromCodePoint: typeof String.fromCodePoint + export const StringFromCodePointApply: StaticApply export const StringRaw: typeof String.raw export const StringPrototypeAnchor: UncurryThis export const StringPrototypeBig: UncurryThis