@gsknnft/bigint-buffer 1.3.2 → 1.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (106) hide show
  1. package/README.md +123 -126
  2. package/build/Release/bigint_buffer.exp +0 -0
  3. package/build/Release/bigint_buffer.iobj +0 -0
  4. package/build/Release/bigint_buffer.ipdb +0 -0
  5. package/build/Release/bigint_buffer.lib +0 -0
  6. package/build/Release/bigint_buffer.node +0 -0
  7. package/build/Release/bigint_buffer.pdb +0 -0
  8. package/build/Release/obj/bigint_buffer/bigint_buffer.node.recipe +11 -0
  9. package/build/Release/obj/bigint_buffer/bigint_buffer.tlog/CL.command.1.tlog +0 -0
  10. package/build/Release/obj/bigint_buffer/bigint_buffer.tlog/CL.read.1.tlog +0 -0
  11. package/build/Release/obj/bigint_buffer/bigint_buffer.tlog/CL.write.1.tlog +0 -0
  12. package/build/Release/obj/bigint_buffer/bigint_buffer.tlog/Cl.items.tlog +2 -0
  13. package/build/Release/obj/bigint_buffer/bigint_buffer.tlog/bigint_buffer.lastbuildstate +2 -0
  14. package/build/Release/obj/bigint_buffer/bigint_buffer.tlog/link.command.1.tlog +0 -0
  15. package/build/Release/obj/bigint_buffer/bigint_buffer.tlog/link.read.1.tlog +0 -0
  16. package/build/Release/obj/bigint_buffer/bigint_buffer.tlog/link.secondary.1.tlog +5 -0
  17. package/build/Release/obj/bigint_buffer/bigint_buffer.tlog/link.write.1.tlog +0 -0
  18. package/build/Release/obj/bigint_buffer/src/bigint-buffer.obj +0 -0
  19. package/build/Release/obj/bigint_buffer/win_delay_load_hook.obj +0 -0
  20. package/build/bigint_buffer.vcxproj +148 -0
  21. package/build/bigint_buffer.vcxproj.filters +67 -0
  22. package/build/binding.sln +19 -0
  23. package/build/config.gypi +522 -0
  24. package/dist/index.cjs +1 -205
  25. package/dist/index.js +347 -202
  26. package/dist/index.umd.js +1 -0
  27. package/dist/tsconfig.tsbuildinfo +1 -0
  28. package/dist/types/bigint-buffer.test.d.ts +1 -0
  29. package/dist/types/conversion/index.d.ts +1 -0
  30. package/dist/types/conversion/src/ts/index.d.ts +168 -0
  31. package/dist/types/conversion/test/bigintToBase64.test.d.ts +1 -0
  32. package/dist/types/conversion/test/bigintToBuf.test.d.ts +1 -0
  33. package/dist/types/conversion/test/bigintToHex.test.d.ts +1 -0
  34. package/dist/types/conversion/test/bigintToText.test.d.ts +1 -0
  35. package/dist/types/conversion/test/bufToBigint.test.d.ts +1 -0
  36. package/dist/types/conversion/test/hexToBigint.test.d.ts +1 -0
  37. package/dist/types/conversion/test/hexToBuf.test.d.ts +1 -0
  38. package/dist/types/conversion/test/parseHex.test.d.ts +1 -0
  39. package/dist/types/conversion/test/setup.test.d.ts +1 -0
  40. package/dist/types/conversion/test/textToBuf.test.d.ts +1 -0
  41. package/dist/types/conversion/vite.config.d.ts +2 -0
  42. package/dist/types/conversion/vitest.config.d.ts +2 -0
  43. package/dist/types/dist/dist/conversion/conversion/index.d.ts +1 -0
  44. package/dist/{index.d.ts → types/dist/dist/index.d.ts} +2 -0
  45. package/dist/types/index.bench.d.ts +1 -0
  46. package/dist/types/index.d.ts +80 -0
  47. package/dist/types/index.spec.d.ts +1 -0
  48. package/package.json +83 -49
  49. package/src/bigint-buffer.test.ts +11 -0
  50. package/src/conversion/.github/workflows/build-and-test.yml +116 -0
  51. package/src/conversion/CODE_OF_CONDUCT.md +134 -0
  52. package/src/conversion/LICENSE +21 -0
  53. package/src/conversion/README.md +48 -0
  54. package/src/conversion/docs/README.md +34 -0
  55. package/src/conversion/docs/functions/base64ToBigint.md +27 -0
  56. package/src/conversion/docs/functions/bigintToBase64.md +43 -0
  57. package/src/conversion/docs/functions/bigintToBuf.md +35 -0
  58. package/src/conversion/docs/functions/bigintToHex.md +43 -0
  59. package/src/conversion/docs/functions/bigintToText.md +31 -0
  60. package/src/conversion/docs/functions/bufToBigint.md +25 -0
  61. package/src/conversion/docs/functions/bufToHex.md +37 -0
  62. package/src/conversion/docs/functions/bufToText.md +27 -0
  63. package/src/conversion/docs/functions/hexToBigint.md +29 -0
  64. package/src/conversion/docs/functions/hexToBuf.md +37 -0
  65. package/src/conversion/docs/functions/parseHex.md +45 -0
  66. package/src/conversion/docs/functions/textToBigint.md +27 -0
  67. package/src/conversion/docs/functions/textToBuf.md +33 -0
  68. package/src/conversion/docs/functions/toBigIntBE.md +27 -0
  69. package/src/conversion/docs/functions/toBigIntLE.md +27 -0
  70. package/src/conversion/docs/functions/toBufferBE.md +33 -0
  71. package/src/conversion/docs/functions/toBufferLE.md +33 -0
  72. package/src/conversion/docs/functions/validateBigIntBuffer.md +15 -0
  73. package/src/conversion/docs/type-aliases/TypedArray.md +11 -0
  74. package/src/conversion/docs/variables/isNative.md +11 -0
  75. package/src/conversion/example.cjs +9 -0
  76. package/src/conversion/example.esm.js +11 -0
  77. package/src/conversion/index.ts +1 -0
  78. package/src/conversion/package.json +163 -0
  79. package/src/conversion/src/docs/index.md +47 -0
  80. package/src/conversion/src/ts/index.ts +514 -0
  81. package/src/conversion/test/bigintToBase64.test.ts +37 -0
  82. package/src/conversion/test/bigintToBuf.test.ts +43 -0
  83. package/src/conversion/test/bigintToHex.test.ts +52 -0
  84. package/src/conversion/test/bigintToText.test.ts +30 -0
  85. package/src/conversion/test/bufToBigint.test.ts +20 -0
  86. package/src/conversion/test/hexToBigint.test.ts +22 -0
  87. package/src/conversion/test/hexToBuf.test.ts +39 -0
  88. package/src/conversion/test/parseHex.test.ts +35 -0
  89. package/src/conversion/test/setup.test.ts +9 -0
  90. package/src/conversion/test/textToBuf.test.ts +26 -0
  91. package/src/conversion/tsconfig.json +57 -0
  92. package/src/conversion/tsconfig.rollup.json +9 -0
  93. package/src/conversion/typedoc.json +5 -0
  94. package/src/conversion/types/bindings.d.t.s +4 -0
  95. package/src/conversion/vite.config.ts +10 -0
  96. package/src/conversion/vitest.config.ts +15 -0
  97. package/src/index.bench.ts +5 -6
  98. package/src/index.spec.ts +232 -358
  99. package/src/index.ts +33 -28
  100. package/.travis.yml +0 -51
  101. package/PR_TEMPLATE.md +0 -53
  102. package/dist/node.js +0 -94
  103. package/karma.conf.js +0 -62
  104. package/rollup.cjs.config.js +0 -8
  105. package/rollup.esm.config.js +0 -15
  106. package/tsconfig.json +0 -20
@@ -0,0 +1,47 @@
1
+ [![Licence: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
2
+ [![Contributor Covenant](https://img.shields.io/badge/Contributor%20Covenant-2.1-4baaaa.svg)](CODE_OF_CONDUCT.md)
3
+ [![JavaScript Style Guide](https://img.shields.io/badge/code_style-standard-brightgreen.svg)](https://standardjs.com)
4
+ {{GITHUB_ACTIONS_BADGES}}
5
+
6
+ # {{PKG_NAME}}
7
+
8
+ Convert to/from non-negative integers represented with [ES-2020 native JS implementation of BigInt](https://tc39.es/ecma262/#sec-bigint-objects) from/to:
9
+
10
+ - `Buffer` (node.js) or `ArrayBuffer|TypedArray` (native js),
11
+ - hex `string`,
12
+ - utf8-encoded text `string`,
13
+ - standard and url-safe base64 with and without padding.
14
+
15
+ It provides a common interface for the conversions that works for both **node.js** and **native javascript**.
16
+
17
+ > Note that there is not a directly visible `TypedArray()` constructor, but a set of typed array ones: `Int8Array()`, `Uint8Array()`, `Uint8ClampedArray()`, `Int16Array()`, `Uint16Array()`, `Int32Array()`, `Uint32Array()`, `Float32Array()`, `Float64Array()`, `BigInt64Array()`, `BigUint64Array()`.
18
+
19
+ ## Usage
20
+
21
+ `{{PKG_NAME}}` can be imported to your project with `npm`:
22
+
23
+ ```console
24
+ npm install {{PKG_NAME}}
25
+ ```
26
+
27
+ Then either require (Node.js CJS):
28
+
29
+ ```javascript
30
+ const {{PKG_CAMELCASE}} = require('{{PKG_NAME}}')
31
+ ```
32
+
33
+ or import (JavaScript ES module):
34
+
35
+ ```javascript
36
+ import * as {{PKG_CAMELCASE}} from '{{PKG_NAME}}'
37
+ ```
38
+
39
+ The appropriate version for browser or node is automatically exported.
40
+
41
+ > BigInt is [ES-2020](https://tc39.es/ecma262/#sec-bigint-objects). In order to use it with TypeScript you should set `target` (and probably also `lib`) to at least `es2020` in `tsconfig.json`.
42
+
43
+ You can also download the {{IIFE_BUNDLE}}, the {{ESM_BUNDLE}} or the {{UMD_BUNDLE}} and manually add it to your project, or, if you have already installed `{{PKG_NAME}}` in your project, just get the bundles from `node_modules/{{PKG_NAME}}/dist/bundles/`.
44
+
45
+ ## API reference documentation
46
+
47
+ [Check the API](./docs/API.md)
@@ -0,0 +1,514 @@
1
+ import { Buffer } from 'buffer';
2
+ import path from 'path';
3
+ import fs from 'fs';
4
+
5
+ interface ConverterInterface {
6
+ toBigInt: (buf: Buffer, bigEndian?: boolean) => bigint;
7
+ fromBigInt: (num: bigint, buf: Buffer, bigEndian?: boolean) => Buffer;
8
+ }
9
+
10
+ export let isNative = false;
11
+ let converter: ConverterInterface | undefined;
12
+ let nativeLoadError: unknown;
13
+
14
+ const IS_BROWSER =
15
+ typeof globalThis !== "undefined" &&
16
+ typeof (globalThis as { document?: unknown }).document !== "undefined";
17
+
18
+ const candidateRoots = [
19
+ // when running from dist/
20
+ path.resolve(__dirname, ".."),
21
+ // when running from build/conversion/src/ts
22
+ path.resolve(__dirname, "../../.."),
23
+ // when running from src/conversion/src/ts
24
+ path.resolve(__dirname, "../../../../"),
25
+ ];
26
+
27
+ const findModuleRoot = (): string => {
28
+ for (const root of candidateRoots) {
29
+ const candidate = path.join(root, "build", "Release", "bigint_buffer.node");
30
+ if (fs.existsSync(candidate)) return root;
31
+ }
32
+ return candidateRoots[0];
33
+ };
34
+
35
+ function loadNative(): ConverterInterface | undefined {
36
+ try {
37
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
38
+ const bindings = require("bindings");
39
+ const moduleRoot = findModuleRoot();
40
+ return bindings({
41
+ bindings: "bigint_buffer",
42
+ module_root: moduleRoot,
43
+ }) as ConverterInterface;
44
+ } catch (err) {
45
+ nativeLoadError = err;
46
+ return undefined;
47
+ }
48
+ }
49
+
50
+ if (!IS_BROWSER) {
51
+ converter = loadNative();
52
+ isNative = converter !== undefined;
53
+ if (
54
+ !isNative &&
55
+ nativeLoadError !== undefined &&
56
+ process.env?.BIGINT_BUFFER_SILENT_NATIVE_FAIL !== "1"
57
+ ) {
58
+ console.warn(
59
+ "bigint-buffer: Failed to load native bindings; using pure JS fallback. Run npm run rebuild to restore native.",
60
+ nativeLoadError
61
+ );
62
+ }
63
+ }
64
+
65
+ if (converter === undefined) {
66
+ // fallback to pure JS if needed (browser or when native load fails)
67
+ converter = {
68
+ toBigInt: (buf: Buffer, bigEndian = true) => {
69
+ const copy = Buffer.from(buf);
70
+ if (!bigEndian) copy.reverse();
71
+ const hex = copy.toString("hex");
72
+ return hex.length === 0 ? 0n : BigInt(`0x${hex}`);
73
+ },
74
+ fromBigInt: (num: bigint, buf: Buffer, bigEndian = true) => {
75
+ const hex = num.toString(16);
76
+ const width = buf.length;
77
+ const filled = hex.padStart(width * 2, "0").slice(0, width * 2);
78
+ const tmp = Buffer.from(filled, "hex");
79
+ if (!bigEndian) tmp.reverse();
80
+ tmp.copy(buf);
81
+ return buf;
82
+ },
83
+ };
84
+ }
85
+
86
+ /**
87
+ * Convert a little-endian buffer into a BigInt.
88
+ * @param buf The little-endian buffer to convert
89
+ * @returns A BigInt with the little-endian representation of buf.
90
+ */
91
+ export function toBigIntLE(buf: Buffer): bigint {
92
+ if (IS_BROWSER || converter === undefined) {
93
+ const reversed = Buffer.from(buf);
94
+ reversed.reverse();
95
+ const hex = reversed.toString("hex");
96
+ if (hex.length === 0) {
97
+ return BigInt(0);
98
+ }
99
+ return BigInt(`0x${hex}`);
100
+ }
101
+ return converter.toBigInt(buf, false);
102
+ }
103
+
104
+ export function validateBigIntBuffer(): boolean {
105
+ try {
106
+ const test = toBigIntLE(Buffer.from([0x01, 0x00]));
107
+ return test === BigInt(1);
108
+ } catch {
109
+ return false;
110
+ }
111
+ }
112
+
113
+ /**
114
+ * Convert a big-endian buffer into a BigInt
115
+ * @param buf The big-endian buffer to convert.
116
+ * @returns A BigInt with the big-endian representation of buf.
117
+ */
118
+ export function toBigIntBE(buf: Buffer): bigint {
119
+ if (IS_BROWSER || converter === undefined) {
120
+ const hex = buf.toString("hex");
121
+ if (hex.length === 0) {
122
+ return BigInt(0);
123
+ }
124
+ return BigInt(`0x${hex}`);
125
+ }
126
+ return converter.toBigInt(buf, true);
127
+ }
128
+
129
+ /**
130
+ * Convert a BigInt to a little-endian buffer.
131
+ * @param num The BigInt to convert.
132
+ * @param width The number of bytes that the resulting buffer should be.
133
+ * @returns A little-endian buffer representation of num.
134
+ */
135
+ export function toBufferLE(num: bigint, width: number): Buffer {
136
+ if (IS_BROWSER || converter === undefined) {
137
+ const hex = num.toString(16);
138
+ const buffer = Buffer.from(
139
+ hex.padStart(width * 2, "0").slice(0, width * 2),
140
+ "hex"
141
+ );
142
+ buffer.reverse();
143
+ return buffer;
144
+ }
145
+ // Allocation is done here, since it is slower using napi in C
146
+ return converter.fromBigInt(num, Buffer.allocUnsafe(width), false);
147
+ }
148
+
149
+ /**
150
+ * Convert a BigInt to a big-endian buffer.
151
+ * @param num The BigInt to convert.
152
+ * @param width The number of bytes that the resulting buffer should be.
153
+ * @returns A big-endian buffer representation of num.
154
+ */
155
+ export function toBufferBE(num: bigint, width: number): Buffer {
156
+ if (IS_BROWSER || converter === undefined) {
157
+ const hex = num.toString(16);
158
+ return Buffer.from(hex.padStart(width * 2, "0").slice(0, width * 2), "hex");
159
+ }
160
+ return converter.fromBigInt(num, Buffer.allocUnsafe(width), true);
161
+ }
162
+
163
+ export type TypedArray =
164
+ | Int8Array
165
+ | Uint8Array
166
+ | Uint8ClampedArray
167
+ | Int16Array
168
+ | Uint16Array
169
+ | Int32Array
170
+ | Uint32Array
171
+ | Float32Array
172
+ | Float64Array
173
+ | BigInt64Array
174
+ | BigUint64Array;
175
+
176
+ /**
177
+ * Parses a hexadecimal string for correctness and returns it with or without
178
+ * '0x' prefix, and/or with the specified byte length
179
+ * @param a - the string with an hexadecimal number to be parsed
180
+ * @param prefix0x - set to true to prefix the output with '0x'
181
+ * @param byteLength - pad the output to have the desired byte length. Notice
182
+ * that the hex length is double the byte length.
183
+ *
184
+ * @returns
185
+ *
186
+ * @throws {@link RangeError} if input string does not hold an hexadecimal number
187
+ * @throws {@link RangeError} if requested byte length is less than the input byte length
188
+ */
189
+ export function parseHex(
190
+ a: string,
191
+ prefix0x = false,
192
+ byteLength?: number
193
+ ): string {
194
+ const hexMatch = a.match(/^(0x)?([\da-fA-F]+)$/);
195
+ if (hexMatch == null) {
196
+ throw new RangeError(
197
+ "input must be a hexadecimal string, e.g. '0x124fe3a' or '0214f1b2'"
198
+ );
199
+ }
200
+ let hex = hexMatch[2];
201
+ if (byteLength !== undefined) {
202
+ if (byteLength < hex.length / 2) {
203
+ throw new RangeError(
204
+ `expected byte length ${byteLength} < input hex byte length ${Math.ceil(
205
+ hex.length / 2
206
+ )}`
207
+ );
208
+ }
209
+ hex = hex.padStart(byteLength * 2, "0");
210
+ }
211
+ return prefix0x ? "0x" + hex : hex;
212
+ }
213
+
214
+ /**
215
+ * Converts an arbitrary-size non-negative bigint to an ArrayBuffer or a Buffer
216
+ * (default for Node.js)
217
+ *
218
+ * @param a
219
+ * @param returnArrayBuffer - In Node.js, it forces the output to be an
220
+ * ArrayBuffer instead of a Buffer.
221
+ *
222
+ * @returns an ArrayBuffer or a Buffer with a binary representation of the input
223
+ * bigint
224
+ *
225
+ * @throws {@link RangeError} if a < 0.
226
+ */
227
+ export function bigintToBuf(
228
+ a: bigint,
229
+ returnArrayBuffer = false
230
+ ): ArrayBuffer | Buffer {
231
+ if (a < 0) {
232
+ throw RangeError(
233
+ "a should be a non-negative integer. Negative values are not supported"
234
+ );
235
+ }
236
+ return hexToBuf(bigintToHex(a), returnArrayBuffer);
237
+ }
238
+
239
+ /**
240
+ * Converts an ArrayBuffer, TypedArray or Buffer (node.js) to a bigint
241
+ * @param buf
242
+ * @returns a bigint
243
+ */
244
+ export function bufToBigint(buf: ArrayBuffer | TypedArray | Buffer): bigint {
245
+ let bits = 8n;
246
+ if (ArrayBuffer.isView(buf)) {
247
+ bits = BigInt(buf.BYTES_PER_ELEMENT * 8);
248
+ } else {
249
+ buf = new Uint8Array(buf);
250
+ }
251
+
252
+ let ret = 0n;
253
+ for (const i of buf.values()) {
254
+ const bi = BigInt(i);
255
+ ret = (ret << bits) + bi;
256
+ }
257
+ return ret;
258
+ }
259
+
260
+ /**
261
+ * Converts a non-negative bigint to a hexadecimal string
262
+ * @param a - a non negative bigint
263
+ * @param prefix0x - set to true to prefix the output with '0x'
264
+ * @param byteLength - pad the output to have the desired byte length. Notice
265
+ * that the hex length is double the byte length.
266
+ *
267
+ * @returns hexadecimal representation of the input bigint
268
+ *
269
+ * @throws {@link RangeError} if a < 0
270
+ */
271
+ export function bigintToHex(
272
+ a: bigint,
273
+ prefix0x = false,
274
+ byteLength?: number
275
+ ): string {
276
+ if (a < 0) {
277
+ throw RangeError(
278
+ "a should be a non-negative integer. Negative values are not supported"
279
+ );
280
+ }
281
+ return parseHex(a.toString(16), prefix0x, byteLength);
282
+ }
283
+
284
+ /**
285
+ * Converts a hexadecimal string to a bigint
286
+ *
287
+ * @param hexStr
288
+ *
289
+ * @returns a bigint
290
+ *
291
+ * @throws {@link RangeError} if input string does not hold an hexadecimal number
292
+ */
293
+ export function hexToBigint(hexStr: string): bigint {
294
+ return BigInt(parseHex(hexStr, true));
295
+ }
296
+
297
+ /**
298
+ * Converts a non-negative bigint representing a binary array of utf-8 encoded
299
+ * text to a string of utf-8 text
300
+ *
301
+ * @param a - A non-negative bigint representing a binary array of utf-8 encoded
302
+ * text.
303
+ *
304
+ * @returns a string text with utf-8 encoding
305
+ *
306
+ * @throws {@link RangeError} if a < 0.
307
+ */
308
+ export function bigintToText(a: bigint): string {
309
+ if (a < 0) {
310
+ throw RangeError(
311
+ "a should be a non-negative integer. Negative values are not supported"
312
+ );
313
+ }
314
+ return bufToText(hexToBuf(a.toString(16)));
315
+ }
316
+
317
+ /**
318
+ * Converts a utf-8 string to a bigint (from its binary representaion)
319
+ *
320
+ * @param text - A string text with utf-8 encoding
321
+ *
322
+ * @returns a bigint representing a binary array of the input utf-8 encoded text
323
+ */
324
+ export function textToBigint(text: string): bigint {
325
+ return hexToBigint(bufToHex(textToBuf(text)));
326
+ }
327
+ function toBuffer(input: ArrayBuffer | TypedArray | Buffer): Buffer {
328
+ if (Buffer.isBuffer(input)) {
329
+ return input;
330
+ }
331
+
332
+ if (ArrayBuffer.isView(input)) {
333
+ return Buffer.from(input.buffer, input.byteOffset, input.byteLength);
334
+ }
335
+
336
+ if (input instanceof ArrayBuffer) {
337
+ return Buffer.from(new Uint8Array(input));
338
+ }
339
+
340
+ throw new TypeError("Unsupported input type for Buffer.from");
341
+ }
342
+ /**
343
+ * Converts an ArrayBuffer, TypedArray or Buffer (in Node.js) containing utf-8
344
+ * encoded text to a string of utf-8 text
345
+ *
346
+ * @param buf - A buffer containing utf-8 encoded text
347
+ *
348
+ * @returns a string text with utf-8 encoding
349
+ */
350
+ export function bufToText(buf: ArrayBuffer | TypedArray | Buffer): string {
351
+ const input = toBuffer(buf);
352
+ if (IS_BROWSER) {
353
+ return new TextDecoder().decode(new Uint8Array(input));
354
+ } else {
355
+ return Buffer.from(input).toString();
356
+ }
357
+ }
358
+
359
+ /**
360
+ * Converts a string of utf-8 encoded text to an ArrayBuffer or a Buffer
361
+ * (default in Node.js)
362
+ *
363
+ * @param str - A string of text (with utf-8 encoding)
364
+ * @param returnArrayBuffer - When invoked in Node.js, it can force the output
365
+ * to be an ArrayBuffer instead of a Buffer.
366
+ *
367
+ * @returns an ArrayBuffer or a Buffer containing the utf-8 encoded text
368
+ */
369
+ export function textToBuf(
370
+ str: string,
371
+ returnArrayBuffer = false
372
+ ): ArrayBuffer | Buffer {
373
+ if (!IS_BROWSER && !returnArrayBuffer) {
374
+ return Buffer.from(new TextEncoder().encode(str).buffer);
375
+ }
376
+ return new TextEncoder().encode(str).buffer;
377
+ }
378
+
379
+ /**
380
+ * Returns the hexadecimal representation of a buffer.
381
+ *
382
+ * @param buf
383
+ * @param prefix0x - set to true to prefix the output with '0x'
384
+ * @param byteLength - pad the output to have the desired byte length. Notice
385
+ * that the hex length is double the byte length.
386
+ *
387
+ * @returns a string with a hexadecimal representation of the input buffer
388
+ */
389
+ export function bufToHex(
390
+ buf: ArrayBuffer | TypedArray | Buffer,
391
+ prefix0x = false,
392
+ byteLength?: number
393
+ ): string {
394
+ if (IS_BROWSER) {
395
+ let s = "";
396
+ const h = "0123456789abcdef";
397
+ if (ArrayBuffer.isView(buf)) {
398
+ buf = new Uint8Array(
399
+ buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.byteLength)
400
+ );
401
+ } else {
402
+ buf = new Uint8Array(buf);
403
+ }
404
+
405
+ (buf as Uint8Array).forEach((v) => {
406
+ s += h[v >> 4] + h[v & 15];
407
+ });
408
+
409
+ return parseHex(s, prefix0x, byteLength);
410
+ } else {
411
+ const input = toBuffer(buf);
412
+ if (ArrayBuffer.isView(input)) {
413
+ buf = new Uint8Array(
414
+ input.buffer.slice(
415
+ input.byteOffset,
416
+ input.byteOffset + input.byteLength
417
+ )
418
+ );
419
+ }
420
+ return parseHex(
421
+ Buffer.from(toBuffer(buf)).toString("hex"),
422
+ prefix0x,
423
+ byteLength
424
+ );
425
+ }
426
+ }
427
+
428
+ /**
429
+ * Converts a hexadecimal string to a buffer
430
+ *
431
+ * @param hexStr - A string representing a number with hexadecimal notation
432
+ * @param returnArrayBuffer - In Node.js, it forces the output to be an
433
+ * ArrayBuffer instead of a Buffer.
434
+ *
435
+ * @returns An ArrayBuffer or a Buffer
436
+ *
437
+ * @throws {@link RangeError} if input string does not hold an hexadecimal number
438
+ */
439
+ export function hexToBuf(
440
+ hexStr: string,
441
+ returnArrayBuffer = false
442
+ ): ArrayBuffer | Buffer {
443
+ let hex = parseHex(hexStr);
444
+ hex = parseHex(hexStr, false, Math.ceil(hex.length / 2)); // pad to have a length in bytes
445
+ if (IS_BROWSER) {
446
+ return Uint8Array.from(
447
+ hex.match(/[\da-fA-F]{2}/g)!.map((h) => {
448
+ // ...existing code...
449
+ return Number("0x" + h);
450
+ })
451
+ ).buffer;
452
+ } else {
453
+ const b = Buffer.from(hex, "hex");
454
+ return returnArrayBuffer
455
+ ? b.buffer.slice(b.byteOffset, b.byteOffset + b.byteLength)
456
+ : b;
457
+ }
458
+ }
459
+
460
+ /**
461
+ * Converts an arbitrary-size non-negative bigint to a base64 string
462
+ * @param a - a non negative bigint
463
+ * @param urlsafe - if true Base64 URL encoding is used ('+' and '/' are
464
+ * replaced by '-', '_')
465
+ * @param padding - if false, padding (trailing '=') is removed
466
+ * @returns a base64 representation of the input bigint
467
+ *
468
+ * @throws {RangeError}
469
+ * Thrown if a < 0
470
+ */
471
+ export function bigintToBase64(
472
+ a: bigint,
473
+ urlsafe = false,
474
+ padding = true
475
+ ): string {
476
+ if (a < 0n) {
477
+ throw new RangeError("negative bigint");
478
+ }
479
+ const buf = bigintToBuf(a);
480
+ let base64 = Buffer.isBuffer(buf)
481
+ ? buf.toString("base64")
482
+ : Buffer.from(buf as ArrayBuffer).toString("base64");
483
+ if (urlsafe) {
484
+ base64 = base64.replace(/\+/g, "-").replace(/\//g, "_");
485
+ }
486
+ if (!padding) {
487
+ base64 = base64.replace(/=+$/, "");
488
+ }
489
+ return base64;
490
+ }
491
+
492
+ /**
493
+ * Converts a base64 string to bigint.
494
+ * @param a base64 string. It accepts standard and URL-safe base64 with and
495
+ * without padding
496
+ * @returns a bigint
497
+ */
498
+ export function base64ToBigint(a: string): bigint {
499
+ if (!a || a.trim() === "") {
500
+ return 0n;
501
+ }
502
+ const cleaned = a.trim();
503
+ if (!/^[A-Za-z0-9+/=_-]*$/.test(cleaned)) {
504
+ throw new RangeError("invalid base64");
505
+ }
506
+ // Implementation now uses Buffer, see above
507
+ let base64 = cleaned.replace(/-/g, "+").replace(/_/g, "/");
508
+ // Pad base64 string if necessary
509
+ while (base64.length % 4 !== 0) {
510
+ base64 += "=";
511
+ }
512
+ const buf = Buffer.from(base64, "base64");
513
+ return bufToBigint(buf);
514
+ }
@@ -0,0 +1,37 @@
1
+ import * as bc from '#pkg';
2
+ import {describe, expect, it} from 'vitest';
3
+
4
+ describe('bigintToBase64', () => {
5
+ const inputs = [
6
+ {bi: BigInt(1), base64: 'AQ', urlsafe: true, padding: false},
7
+ {bi: BigInt(31), base64: 'Hw==', urlsafe: true, padding: undefined},
8
+ {bi: BigInt(3855), base64: 'Dw8', urlsafe: undefined, padding: false}, {
9
+ bi: BigInt('12485413541784539569456874935679853424678352483761'),
10
+ base64: 'CIr5Tmsemfi/OwHtthnKqmVqXHWx',
11
+ urlsafe: false,
12
+ padding: true
13
+ },
14
+ {bi: BigInt('-4'), base64: '', urlsafe: true, padding: false}
15
+ ];
16
+
17
+ for (const input of inputs) {
18
+ if (input.bi >= 0) {
19
+ describe(`bigintToBase64(${input.bi})`, () => {
20
+ it(`should return ${input.base64}`, () => {
21
+ const ret = bc.bigintToBase64(input.bi, input.urlsafe, input.padding);
22
+ expect(ret).to.equal(input.base64);
23
+ });
24
+ });
25
+ describe(`base64ToBigint(${input.base64})`, () => {
26
+ it(`should return ${input.bi}`, () => {
27
+ const ret = bc.base64ToBigint(input.base64);
28
+ expect(ret).to.equal(input.bi);
29
+ });
30
+ });
31
+ } else {
32
+ it('should throw RangeError', () => {
33
+ expect(() => bc.bigintToHex(input.bi)).to.throw(RangeError);
34
+ });
35
+ }
36
+ }
37
+ });
@@ -0,0 +1,43 @@
1
+ import * as bc from '#pkg';
2
+ import {describe, expect, it} from 'vitest';
3
+
4
+ describe('bigintToBuf', () => {
5
+ const inputs = [
6
+ BigInt(0), BigInt(3855), BigInt(19),
7
+ BigInt(
8
+ '987597451974567914535761247965237569172456791242479651917245614514261463156346357315735752714364354354647135713476134634753735714534636'),
9
+ BigInt(-5)
10
+ ];
11
+
12
+ for (const input of inputs) {
13
+ describe(`bufToBigint(bigintToBuf(${input}))`, () => {
14
+ if (input < 0) {
15
+ it('should throw RangeError', () => {
16
+ expect(() => bc.bufToBigint(bc.bigintToBuf(input)))
17
+ .to.throw(RangeError);
18
+ });
19
+ it('should throw RangeError', () => {
20
+ expect(() => bc.bufToBigint(bc.bigintToBuf(input, true)))
21
+ .to.throw(RangeError);
22
+ });
23
+ it('should throw RangeError', () => {
24
+ expect(() => bc.bufToBigint(bc.bigintToBuf(input, false)))
25
+ .to.throw(RangeError);
26
+ });
27
+ } else {
28
+ it(`should return ${input}`, () => {
29
+ const ret = bc.bufToBigint(bc.bigintToBuf(input));
30
+ expect(ret).to.equal(input);
31
+ });
32
+ it(`should return ${input}`, () => {
33
+ const ret = bc.bufToBigint(bc.bigintToBuf(input, true));
34
+ expect(ret).to.equal(input);
35
+ });
36
+ it(`should return ${input}`, () => {
37
+ const ret = bc.bufToBigint(bc.bigintToBuf(input, false));
38
+ expect(ret).to.equal(input);
39
+ });
40
+ }
41
+ });
42
+ }
43
+ });
@@ -0,0 +1,52 @@
1
+ import * as bc from '#pkg';
2
+ import {describe, expect, it} from 'vitest';
3
+
4
+ describe('bigintToHex', () => {
5
+ const inputs = [
6
+ {bi: BigInt(1), hex: '1'}, {bi: BigInt(31), hex: '1f'},
7
+ {bi: BigInt(3855), hex: 'f0f'}, {
8
+ bi: BigInt('12485413541784539569456874935679853424678352483761'),
9
+ hex: '88af94e6b1e99f8bf3b01edb619caaa656a5c75b1'
10
+ },
11
+ {bi: BigInt('-4'), hex: ''}
12
+ ];
13
+
14
+ describe('bigintToHex', () => {
15
+ for (const input of inputs) {
16
+ if (input.bi >= 0) {
17
+ describe(`bigintToHex(${input.bi})`, () => {
18
+ it(`should return ${input.hex}`, () => {
19
+ const ret = bc.bigintToHex(input.bi);
20
+ expect(ret).to.equal(input.hex);
21
+ });
22
+ });
23
+ } else {
24
+ it('should throw RangeError', () => {
25
+ expect(() => bc.bigintToHex(input.bi)).to.throw(RangeError);
26
+ });
27
+ }
28
+ }
29
+ it('bigintToHex(1214371n, undefined, 4) should return \'001287a3\'', () => {
30
+ const ret = bc.bigintToHex(1214371n, undefined, 4);
31
+ expect(ret).to.equal('001287a3');
32
+ });
33
+ it('bigintToHex(1214371n, true) should return \'0x1287a3\'', () => {
34
+ const ret = bc.bigintToHex(1214371n, true);
35
+ expect(ret).to.equal('0x1287a3');
36
+ });
37
+ it('bigintToHex(1214371n, true, 5) should return \'0x00001287a3\'', () => {
38
+ const ret = bc.bigintToHex(1214371n, true, 5);
39
+ expect(ret).to.equal('0x00001287a3');
40
+ });
41
+ it('bigintToHex(hexToBigint(\'1287542fe21\'), true, 4) should throw error',
42
+ () => {
43
+ expect(() => {
44
+ bc.bigintToHex(bc.hexToBigint('1287542fe21'), true, 4);
45
+ }).to.throw(RangeError);
46
+ });
47
+ it('bigintToHex(1132n, true) should return \'0x46c\'', () => {
48
+ const ret = bc.bigintToHex(1132n, true);
49
+ expect(ret).to.equal('0x46c');
50
+ });
51
+ });
52
+ });