@metamask-previews/byte-utils 0.0.0-preview-f64052a

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.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"numbers.d.ts","sourceRoot":"","sources":["../../src/__fixtures__/numbers.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,aAAa;;;;GAmDzB,CAAC"}
@@ -0,0 +1,53 @@
1
+ export const NUMBER_VALUES = [
2
+ {
3
+ number: 0,
4
+ bigint: BigInt(0),
5
+ hexadecimal: '0x0',
6
+ },
7
+ {
8
+ number: 1,
9
+ bigint: BigInt(1),
10
+ hexadecimal: '0x1',
11
+ },
12
+ {
13
+ number: 16,
14
+ bigint: BigInt(16),
15
+ hexadecimal: '0x10',
16
+ },
17
+ {
18
+ number: 255,
19
+ bigint: BigInt(255),
20
+ hexadecimal: '0xff',
21
+ },
22
+ {
23
+ number: 256,
24
+ bigint: BigInt(256),
25
+ hexadecimal: '0x100',
26
+ },
27
+ {
28
+ number: 65535,
29
+ bigint: BigInt(65535),
30
+ hexadecimal: '0xffff',
31
+ },
32
+ {
33
+ number: 65536,
34
+ bigint: BigInt(65536),
35
+ hexadecimal: '0x10000',
36
+ },
37
+ {
38
+ number: 4294967295,
39
+ bigint: BigInt(4294967295),
40
+ hexadecimal: '0xffffffff',
41
+ },
42
+ {
43
+ number: 4294967296,
44
+ bigint: BigInt(4294967296),
45
+ hexadecimal: '0x100000000',
46
+ },
47
+ {
48
+ number: 9007199254740991,
49
+ bigint: BigInt(9007199254740991),
50
+ hexadecimal: '0x1fffffffffffff',
51
+ },
52
+ ];
53
+ //# sourceMappingURL=numbers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"numbers.js","sourceRoot":"","sources":["../../src/__fixtures__/numbers.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,aAAa,GAAG;IAC3B;QACE,MAAM,EAAE,CAAC;QACT,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;QACjB,WAAW,EAAE,KAAK;KACnB;IACD;QACE,MAAM,EAAE,CAAC;QACT,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;QACjB,WAAW,EAAE,KAAK;KACnB;IACD;QACE,MAAM,EAAE,EAAE;QACV,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC;QAClB,WAAW,EAAE,MAAM;KACpB;IACD;QACE,MAAM,EAAE,GAAG;QACX,MAAM,EAAE,MAAM,CAAC,GAAG,CAAC;QACnB,WAAW,EAAE,MAAM;KACpB;IACD;QACE,MAAM,EAAE,GAAG;QACX,MAAM,EAAE,MAAM,CAAC,GAAG,CAAC;QACnB,WAAW,EAAE,OAAO;KACrB;IACD;QACE,MAAM,EAAE,KAAK;QACb,MAAM,EAAE,MAAM,CAAC,KAAK,CAAC;QACrB,WAAW,EAAE,QAAQ;KACtB;IACD;QACE,MAAM,EAAE,KAAK;QACb,MAAM,EAAE,MAAM,CAAC,KAAK,CAAC;QACrB,WAAW,EAAE,SAAS;KACvB;IACD;QACE,MAAM,EAAE,UAAU;QAClB,MAAM,EAAE,MAAM,CAAC,UAAU,CAAC;QAC1B,WAAW,EAAE,YAAY;KAC1B;IACD;QACE,MAAM,EAAE,UAAU;QAClB,MAAM,EAAE,MAAM,CAAC,UAAU,CAAC;QAC1B,WAAW,EAAE,aAAa;KAC3B;IACD;QACE,MAAM,EAAE,gBAAgB;QACxB,MAAM,EAAE,MAAM,CAAC,gBAAgB,CAAC;QAChC,WAAW,EAAE,kBAAkB;KAChC;CACF,CAAC","sourcesContent":["export const NUMBER_VALUES = [\n {\n number: 0,\n bigint: BigInt(0),\n hexadecimal: '0x0',\n },\n {\n number: 1,\n bigint: BigInt(1),\n hexadecimal: '0x1',\n },\n {\n number: 16,\n bigint: BigInt(16),\n hexadecimal: '0x10',\n },\n {\n number: 255,\n bigint: BigInt(255),\n hexadecimal: '0xff',\n },\n {\n number: 256,\n bigint: BigInt(256),\n hexadecimal: '0x100',\n },\n {\n number: 65535,\n bigint: BigInt(65535),\n hexadecimal: '0xffff',\n },\n {\n number: 65536,\n bigint: BigInt(65536),\n hexadecimal: '0x10000',\n },\n {\n number: 4294967295,\n bigint: BigInt(4294967295),\n hexadecimal: '0xffffffff',\n },\n {\n number: 4294967296,\n bigint: BigInt(4294967296),\n hexadecimal: '0x100000000',\n },\n {\n number: 9007199254740991,\n bigint: BigInt(9007199254740991),\n hexadecimal: '0x1fffffffffffff',\n },\n];\n"]}
@@ -0,0 +1,198 @@
1
+ import type { Hex } from './hex.js';
2
+ export type Bytes = bigint | number | string | Uint8Array;
3
+ /**
4
+ * Check if a value is a `Uint8Array`.
5
+ *
6
+ * @param value - The value to check.
7
+ * @returns Whether the value is a `Uint8Array`.
8
+ */
9
+ export declare function isBytes(value: unknown): value is Uint8Array;
10
+ /**
11
+ * Assert that a value is a `Uint8Array`.
12
+ *
13
+ * @param value - The value to check.
14
+ * @throws If the value is not a `Uint8Array`.
15
+ */
16
+ export declare function assertIsBytes(value: unknown): asserts value is Uint8Array;
17
+ /**
18
+ * Convert a `Uint8Array` to a hexadecimal string.
19
+ *
20
+ * @param bytes - The bytes to convert to a hexadecimal string.
21
+ * @returns The hexadecimal string.
22
+ */
23
+ export declare function bytesToHex(bytes: Uint8Array): Hex;
24
+ /**
25
+ * Convert a `Uint8Array` to a `bigint`.
26
+ *
27
+ * To convert a `Uint8Array` to a `number` instead, use {@link bytesToNumber}.
28
+ * To convert a two's complement encoded `Uint8Array` to a `bigint`, use
29
+ * {@link bytesToSignedBigInt}.
30
+ *
31
+ * @param bytes - The bytes to convert to a `bigint`.
32
+ * @returns The `bigint`.
33
+ */
34
+ export declare function bytesToBigInt(bytes: Uint8Array): bigint;
35
+ /**
36
+ * Convert a `Uint8Array` to a signed `bigint`. This assumes that the bytes are
37
+ * encoded in two's complement.
38
+ *
39
+ * To convert a `Uint8Array` to an unsigned `bigint` instead, use
40
+ * {@link bytesToBigInt}.
41
+ *
42
+ * @see https://en.wikipedia.org/wiki/Two%27s_complement
43
+ * @param bytes - The bytes to convert to a signed `bigint`.
44
+ * @returns The signed `bigint`.
45
+ */
46
+ export declare function bytesToSignedBigInt(bytes: Uint8Array): bigint;
47
+ /**
48
+ * Convert a `Uint8Array` to a `number`.
49
+ *
50
+ * To convert a `Uint8Array` to a `bigint` instead, use {@link bytesToBigInt}.
51
+ *
52
+ * @param bytes - The bytes to convert to a number.
53
+ * @returns The number.
54
+ * @throws If the resulting number is not a safe integer.
55
+ */
56
+ export declare function bytesToNumber(bytes: Uint8Array): number;
57
+ /**
58
+ * Convert a UTF-8 encoded `Uint8Array` to a `string`.
59
+ *
60
+ * @param bytes - The bytes to convert to a string.
61
+ * @returns The string.
62
+ */
63
+ export declare function bytesToString(bytes: Uint8Array): string;
64
+ /**
65
+ * Convert a `Uint8Array` to a base64 encoded string.
66
+ *
67
+ * @param bytes - The bytes to convert to a base64 encoded string.
68
+ * @returns The base64 encoded string.
69
+ */
70
+ export declare function bytesToBase64(bytes: Uint8Array): string;
71
+ /**
72
+ * Convert a hexadecimal string to a `Uint8Array`. The string can optionally be
73
+ * prefixed with `0x`. It accepts even and odd length strings.
74
+ *
75
+ * If the value is "0x", an empty `Uint8Array` is returned.
76
+ *
77
+ * @param value - The hexadecimal string to convert to bytes.
78
+ * @returns The bytes as `Uint8Array`.
79
+ */
80
+ export declare function hexToBytes(value: string): Uint8Array<ArrayBuffer>;
81
+ /**
82
+ * Convert a `bigint` to a `Uint8Array`.
83
+ *
84
+ * This assumes that the `bigint` is an unsigned integer. To convert a signed
85
+ * `bigint` instead, use {@link signedBigIntToBytes}.
86
+ *
87
+ * @param value - The bigint to convert to bytes.
88
+ * @returns The bytes as `Uint8Array`.
89
+ */
90
+ export declare function bigIntToBytes(value: bigint): Uint8Array<ArrayBuffer>;
91
+ /**
92
+ * Convert a signed `bigint` to a `Uint8Array`. This uses two's complement
93
+ * encoding to represent negative numbers.
94
+ *
95
+ * To convert an unsigned `bigint` to a `Uint8Array` instead, use
96
+ * {@link bigIntToBytes}.
97
+ *
98
+ * @see https://en.wikipedia.org/wiki/Two%27s_complement
99
+ * @param value - The number to convert to bytes.
100
+ * @param byteLength - The length of the resulting `Uint8Array`. If the number
101
+ * is larger than the maximum value that can be represented by the given length,
102
+ * an error is thrown.
103
+ * @returns The bytes as `Uint8Array`.
104
+ */
105
+ export declare function signedBigIntToBytes(value: bigint, byteLength: number): Uint8Array<ArrayBuffer>;
106
+ /**
107
+ * Convert a `number` to a `Uint8Array`.
108
+ *
109
+ * @param value - The number to convert to bytes.
110
+ * @returns The bytes as `Uint8Array`.
111
+ * @throws If the number is not a safe integer.
112
+ */
113
+ export declare function numberToBytes(value: number): Uint8Array<ArrayBuffer>;
114
+ /**
115
+ * Convert a `string` to a UTF-8 encoded `Uint8Array`.
116
+ *
117
+ * @param value - The string to convert to bytes.
118
+ * @returns The bytes as `Uint8Array`.
119
+ */
120
+ export declare function stringToBytes(value: string): Uint8Array<ArrayBuffer>;
121
+ /**
122
+ * Convert a base64 encoded string to a `Uint8Array`.
123
+ *
124
+ * @param value - The base64 encoded string to convert to bytes.
125
+ * @returns The bytes as `Uint8Array`.
126
+ */
127
+ export declare function base64ToBytes(value: string): Uint8Array<ArrayBuffer>;
128
+ /**
129
+ * Convert a byte-like value to a `Uint8Array`. The value can be a `Uint8Array`,
130
+ * a `bigint`, a `number`, or a `string`.
131
+ *
132
+ * This will attempt to guess the type of the value based on its type and
133
+ * contents. For more control over the conversion, use the more specific
134
+ * conversion functions, such as {@link hexToBytes} or {@link stringToBytes}.
135
+ *
136
+ * If the value is a `string`, and it is prefixed with `0x`, it will be
137
+ * interpreted as a hexadecimal string. Otherwise, it will be interpreted as a
138
+ * UTF-8 string. To convert a hexadecimal string to bytes without interpreting
139
+ * it as a UTF-8 string, use {@link hexToBytes} instead.
140
+ *
141
+ * If the value is a `bigint`, it is assumed to be unsigned. To convert a signed
142
+ * `bigint` to bytes, use {@link signedBigIntToBytes} instead.
143
+ *
144
+ * If the value is a `Uint8Array`, it will be returned as-is.
145
+ *
146
+ * @param value - The value to convert to bytes.
147
+ * @returns The bytes as `Uint8Array`.
148
+ */
149
+ export declare function valueToBytes(value: Bytes): Uint8Array<ArrayBuffer>;
150
+ /**
151
+ * Concatenate multiple byte-like values into a single `Uint8Array`. The values
152
+ * can be `Uint8Array`, `bigint`, `number`, or `string`. This uses
153
+ * {@link valueToBytes} under the hood to convert each value to bytes. Refer to
154
+ * the documentation of that function for more information.
155
+ *
156
+ * @param values - The values to concatenate.
157
+ * @returns The concatenated bytes as `Uint8Array`.
158
+ */
159
+ export declare function concatBytes(values: Bytes[]): Uint8Array<ArrayBuffer>;
160
+ /**
161
+ * Create a {@link DataView} from a {@link Uint8Array}. This is a convenience
162
+ * function that avoids having to create a {@link DataView} manually, which
163
+ * requires passing the `byteOffset` and `byteLength` parameters every time.
164
+ *
165
+ * Not passing the `byteOffset` and `byteLength` parameters can result in
166
+ * unexpected behavior when the {@link Uint8Array} is a view of a larger
167
+ * {@link ArrayBuffer}, e.g., when using {@link Uint8Array.subarray}.
168
+ *
169
+ * This function also supports Node.js {@link Buffer}s.
170
+ *
171
+ * @example
172
+ * ```typescript
173
+ * const bytes = new Uint8Array([1, 2, 3]);
174
+ *
175
+ * // This is equivalent to:
176
+ * // const dataView = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
177
+ * const dataView = createDataView(bytes);
178
+ * ```
179
+ * @param bytes - The bytes to create the {@link DataView} from.
180
+ * @returns The {@link DataView}.
181
+ */
182
+ export declare function createDataView<ArrayBufferImplementation extends ArrayBufferLike>(bytes: Uint8Array<ArrayBufferImplementation>): DataView<ArrayBufferImplementation>;
183
+ /**
184
+ * Compare two Uint8Arrays using a constant-time style loop to reduce timing
185
+ * side-channels when comparing sensitive data (e.g., mnemonic bytes, keys,
186
+ * authentication tags). Does not early-return on the first difference:
187
+ * work done depends only on the input lengths, so byte content does not affect timing.
188
+ *
189
+ * When to use:
190
+ * - Use for secret or security-sensitive byte comparisons to avoid content-based timing leaks.
191
+ * - Prefer when inputs are fixed-length (or validated to equal length) at the API boundary.
192
+ *
193
+ * @param a - The first Uint8Array to compare.
194
+ * @param b - The second Uint8Array to compare.
195
+ * @returns Whether the Uint8Arrays are equal.
196
+ */
197
+ export declare function areUint8ArraysEqual(a: Uint8Array, b: Uint8Array): boolean;
198
+ //# sourceMappingURL=bytes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bytes.d.ts","sourceRoot":"","sources":["../src/bytes.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAUpC,MAAM,MAAM,KAAK,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,UAAU,CAAC;AAwC1D;;;;;GAKG;AACH,wBAAgB,OAAO,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,UAAU,CAE3D;AAYD;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC,KAAK,IAAI,UAAU,CAEzE;AAED;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,UAAU,GAAG,GAAG,CAgBjD;AAED;;;;;;;;;GASG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAKvD;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAU7D;AAED;;;;;;;;GAQG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAWvD;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAIvD;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAIvD;AAED;;;;;;;;GAQG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,UAAU,CAAC,WAAW,CAAC,CAoCjE;AAED;;;;;;;;GAQG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,UAAU,CAAC,WAAW,CAAC,CAMpE;AAkBD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,MAAM,EACb,UAAU,EAAE,MAAM,GACjB,UAAU,CAAC,WAAW,CAAC,CAqBzB;AAED;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,UAAU,CAAC,WAAW,CAAC,CAUpE;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,UAAU,CAAC,WAAW,CAAC,CAIpE;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,UAAU,CAAC,WAAW,CAAC,CAIpE;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,KAAK,GAAG,UAAU,CAAC,WAAW,CAAC,CA0BlE;AAED;;;;;;;;GAQG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,KAAK,EAAE,GAAG,UAAU,CAAC,WAAW,CAAC,CAsBpE;AASD;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,cAAc,CAC5B,yBAAyB,SAAS,eAAe,EAEjD,KAAK,EAAE,UAAU,CAAC,yBAAyB,CAAC,GAC3C,QAAQ,CAAC,yBAAyB,CAAC,CAmBrC;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,mBAAmB,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,UAAU,GAAG,OAAO,CAazE"}
package/dist/bytes.js ADDED
@@ -0,0 +1,423 @@
1
+ import { assert } from '@metamask/type-utils';
2
+ import { base64 } from '@scure/base';
3
+ import { add0x, assertIsHexString, remove0x } from './hex.js';
4
+ // '0'.charCodeAt(0) === 48
5
+ const HEX_MINIMUM_NUMBER_CHARACTER = 48;
6
+ // '9'.charCodeAt(0) === 57
7
+ const HEX_MAXIMUM_NUMBER_CHARACTER = 58;
8
+ const HEX_CHARACTER_OFFSET = 87;
9
+ /**
10
+ * Memoized function that returns an array to be used as a lookup table for
11
+ * converting bytes to hexadecimal values.
12
+ *
13
+ * The array is created lazily and then cached for future use. The benefit of
14
+ * this approach is that the performance of converting bytes to hex is much
15
+ * better than if we were to call `toString(16)` on each byte.
16
+ *
17
+ * The downside is that the array is created once and then never garbage
18
+ * collected. This is not a problem in practice because the array is only 256
19
+ * elements long.
20
+ *
21
+ * @returns A function that returns the lookup table.
22
+ */
23
+ function getPrecomputedHexValuesBuilder() {
24
+ // To avoid issues with tree shaking, we need to use a function to return the
25
+ // array. This is because the array is only used in the `bytesToHex` function
26
+ // and if we were to use a global variable, the array might be removed by the
27
+ // tree shaker.
28
+ const lookupTable = [];
29
+ return () => {
30
+ if (lookupTable.length === 0) {
31
+ for (let i = 0; i < 256; i++) {
32
+ lookupTable.push(i.toString(16).padStart(2, '0'));
33
+ }
34
+ }
35
+ return lookupTable;
36
+ };
37
+ }
38
+ /**
39
+ * Function implementation of the {@link getPrecomputedHexValuesBuilder}
40
+ * function.
41
+ */
42
+ const getPrecomputedHexValues = getPrecomputedHexValuesBuilder();
43
+ /**
44
+ * Check if a value is a `Uint8Array`.
45
+ *
46
+ * @param value - The value to check.
47
+ * @returns Whether the value is a `Uint8Array`.
48
+ */
49
+ export function isBytes(value) {
50
+ return value instanceof Uint8Array;
51
+ }
52
+ /**
53
+ * Check if a value is a `Uint8Array` backed by an `ArrayBuffer`.
54
+ *
55
+ * @param value - The value to check.
56
+ * @returns Whether the value is a `Uint8Array` backed by an `ArrayBuffer`.
57
+ */
58
+ function isArrayBufferBytes(value) {
59
+ return isBytes(value) && value.buffer instanceof ArrayBuffer;
60
+ }
61
+ /**
62
+ * Assert that a value is a `Uint8Array`.
63
+ *
64
+ * @param value - The value to check.
65
+ * @throws If the value is not a `Uint8Array`.
66
+ */
67
+ export function assertIsBytes(value) {
68
+ assert(isBytes(value), 'Value must be a Uint8Array.');
69
+ }
70
+ /**
71
+ * Convert a `Uint8Array` to a hexadecimal string.
72
+ *
73
+ * @param bytes - The bytes to convert to a hexadecimal string.
74
+ * @returns The hexadecimal string.
75
+ */
76
+ export function bytesToHex(bytes) {
77
+ assertIsBytes(bytes);
78
+ if (bytes.length === 0) {
79
+ return '0x';
80
+ }
81
+ const lookupTable = getPrecomputedHexValues();
82
+ const hexadecimal = new Array(bytes.length);
83
+ for (let i = 0; i < bytes.length; i++) {
84
+ // oxlint-disable-next-line typescript/no-non-null-assertion
85
+ hexadecimal[i] = lookupTable[bytes[i]];
86
+ }
87
+ return add0x(hexadecimal.join(''));
88
+ }
89
+ /**
90
+ * Convert a `Uint8Array` to a `bigint`.
91
+ *
92
+ * To convert a `Uint8Array` to a `number` instead, use {@link bytesToNumber}.
93
+ * To convert a two's complement encoded `Uint8Array` to a `bigint`, use
94
+ * {@link bytesToSignedBigInt}.
95
+ *
96
+ * @param bytes - The bytes to convert to a `bigint`.
97
+ * @returns The `bigint`.
98
+ */
99
+ export function bytesToBigInt(bytes) {
100
+ assertIsBytes(bytes);
101
+ const hexadecimal = bytesToHex(bytes);
102
+ return BigInt(hexadecimal);
103
+ }
104
+ /**
105
+ * Convert a `Uint8Array` to a signed `bigint`. This assumes that the bytes are
106
+ * encoded in two's complement.
107
+ *
108
+ * To convert a `Uint8Array` to an unsigned `bigint` instead, use
109
+ * {@link bytesToBigInt}.
110
+ *
111
+ * @see https://en.wikipedia.org/wiki/Two%27s_complement
112
+ * @param bytes - The bytes to convert to a signed `bigint`.
113
+ * @returns The signed `bigint`.
114
+ */
115
+ export function bytesToSignedBigInt(bytes) {
116
+ assertIsBytes(bytes);
117
+ let value = BigInt(0);
118
+ for (const byte of bytes) {
119
+ // eslint-disable-next-line no-bitwise
120
+ value = (value << BigInt(8)) + BigInt(byte);
121
+ }
122
+ return BigInt.asIntN(bytes.length * 8, value);
123
+ }
124
+ /**
125
+ * Convert a `Uint8Array` to a `number`.
126
+ *
127
+ * To convert a `Uint8Array` to a `bigint` instead, use {@link bytesToBigInt}.
128
+ *
129
+ * @param bytes - The bytes to convert to a number.
130
+ * @returns The number.
131
+ * @throws If the resulting number is not a safe integer.
132
+ */
133
+ export function bytesToNumber(bytes) {
134
+ assertIsBytes(bytes);
135
+ const bigint = bytesToBigInt(bytes);
136
+ assert(bigint <= BigInt(Number.MAX_SAFE_INTEGER), 'Number is not a safe integer. Use `bytesToBigInt` instead.');
137
+ return Number(bigint);
138
+ }
139
+ /**
140
+ * Convert a UTF-8 encoded `Uint8Array` to a `string`.
141
+ *
142
+ * @param bytes - The bytes to convert to a string.
143
+ * @returns The string.
144
+ */
145
+ export function bytesToString(bytes) {
146
+ assertIsBytes(bytes);
147
+ return new TextDecoder().decode(bytes);
148
+ }
149
+ /**
150
+ * Convert a `Uint8Array` to a base64 encoded string.
151
+ *
152
+ * @param bytes - The bytes to convert to a base64 encoded string.
153
+ * @returns The base64 encoded string.
154
+ */
155
+ export function bytesToBase64(bytes) {
156
+ assertIsBytes(bytes);
157
+ return base64.encode(bytes);
158
+ }
159
+ /**
160
+ * Convert a hexadecimal string to a `Uint8Array`. The string can optionally be
161
+ * prefixed with `0x`. It accepts even and odd length strings.
162
+ *
163
+ * If the value is "0x", an empty `Uint8Array` is returned.
164
+ *
165
+ * @param value - The hexadecimal string to convert to bytes.
166
+ * @returns The bytes as `Uint8Array`.
167
+ */
168
+ export function hexToBytes(value) {
169
+ // "0x" is often used as empty byte array.
170
+ if (value?.toLowerCase?.() === '0x') {
171
+ return new Uint8Array();
172
+ }
173
+ assertIsHexString(value);
174
+ // Remove the `0x` prefix if it exists, and pad the string to have an even
175
+ // number of characters.
176
+ const strippedValue = remove0x(value).toLowerCase();
177
+ const normalizedValue = strippedValue.length % 2 === 0 ? strippedValue : `0${strippedValue}`;
178
+ const bytes = new Uint8Array(normalizedValue.length / 2);
179
+ for (let i = 0; i < bytes.length; i++) {
180
+ // While this is not the prettiest way to convert a hexadecimal string to a
181
+ // `Uint8Array`, it is a lot faster than using `parseInt` to convert each
182
+ // character.
183
+ const c1 = normalizedValue.charCodeAt(i * 2);
184
+ const c2 = normalizedValue.charCodeAt(i * 2 + 1);
185
+ const n1 = c1 -
186
+ (c1 < HEX_MAXIMUM_NUMBER_CHARACTER
187
+ ? HEX_MINIMUM_NUMBER_CHARACTER
188
+ : HEX_CHARACTER_OFFSET);
189
+ const n2 = c2 -
190
+ (c2 < HEX_MAXIMUM_NUMBER_CHARACTER
191
+ ? HEX_MINIMUM_NUMBER_CHARACTER
192
+ : HEX_CHARACTER_OFFSET);
193
+ bytes[i] = n1 * 16 + n2;
194
+ }
195
+ return bytes;
196
+ }
197
+ /**
198
+ * Convert a `bigint` to a `Uint8Array`.
199
+ *
200
+ * This assumes that the `bigint` is an unsigned integer. To convert a signed
201
+ * `bigint` instead, use {@link signedBigIntToBytes}.
202
+ *
203
+ * @param value - The bigint to convert to bytes.
204
+ * @returns The bytes as `Uint8Array`.
205
+ */
206
+ export function bigIntToBytes(value) {
207
+ assert(typeof value === 'bigint', 'Value must be a bigint.');
208
+ assert(value >= BigInt(0), 'Value must be a non-negative bigint.');
209
+ const hexadecimal = value.toString(16);
210
+ return hexToBytes(hexadecimal);
211
+ }
212
+ /**
213
+ * Check if a `bigint` fits in a certain number of bytes.
214
+ *
215
+ * @param value - The `bigint` to check.
216
+ * @param bytes - The number of bytes.
217
+ * @returns Whether the `bigint` fits in the number of bytes.
218
+ */
219
+ function bigIntFits(value, bytes) {
220
+ assert(bytes > 0);
221
+ /* eslint-disable no-bitwise */
222
+ const mask = value >> BigInt(31);
223
+ return !(((~value & mask) + (value & ~mask)) >> BigInt(bytes * 8 + ~0));
224
+ /* eslint-enable no-bitwise */
225
+ }
226
+ /**
227
+ * Convert a signed `bigint` to a `Uint8Array`. This uses two's complement
228
+ * encoding to represent negative numbers.
229
+ *
230
+ * To convert an unsigned `bigint` to a `Uint8Array` instead, use
231
+ * {@link bigIntToBytes}.
232
+ *
233
+ * @see https://en.wikipedia.org/wiki/Two%27s_complement
234
+ * @param value - The number to convert to bytes.
235
+ * @param byteLength - The length of the resulting `Uint8Array`. If the number
236
+ * is larger than the maximum value that can be represented by the given length,
237
+ * an error is thrown.
238
+ * @returns The bytes as `Uint8Array`.
239
+ */
240
+ export function signedBigIntToBytes(value, byteLength) {
241
+ assert(typeof value === 'bigint', 'Value must be a bigint.');
242
+ assert(typeof byteLength === 'number', 'Byte length must be a number.');
243
+ assert(byteLength > 0, 'Byte length must be greater than 0.');
244
+ assert(bigIntFits(value, byteLength), 'Byte length is too small to represent the given value.');
245
+ // ESLint doesn't like mutating function parameters, so to avoid having to
246
+ // disable the rule, we create a new variable.
247
+ let numberValue = value;
248
+ const bytes = new Uint8Array(byteLength);
249
+ for (let i = 0; i < bytes.length; i++) {
250
+ bytes[i] = Number(BigInt.asUintN(8, numberValue));
251
+ // eslint-disable-next-line no-bitwise
252
+ numberValue >>= BigInt(8);
253
+ }
254
+ return bytes.reverse();
255
+ }
256
+ /**
257
+ * Convert a `number` to a `Uint8Array`.
258
+ *
259
+ * @param value - The number to convert to bytes.
260
+ * @returns The bytes as `Uint8Array`.
261
+ * @throws If the number is not a safe integer.
262
+ */
263
+ export function numberToBytes(value) {
264
+ assert(typeof value === 'number', 'Value must be a number.');
265
+ assert(value >= 0, 'Value must be a non-negative number.');
266
+ assert(Number.isSafeInteger(value), 'Value is not a safe integer. Use `bigIntToBytes` instead.');
267
+ const hexadecimal = value.toString(16);
268
+ return hexToBytes(hexadecimal);
269
+ }
270
+ /**
271
+ * Convert a `string` to a UTF-8 encoded `Uint8Array`.
272
+ *
273
+ * @param value - The string to convert to bytes.
274
+ * @returns The bytes as `Uint8Array`.
275
+ */
276
+ export function stringToBytes(value) {
277
+ assert(typeof value === 'string', 'Value must be a string.');
278
+ return new TextEncoder().encode(value);
279
+ }
280
+ /**
281
+ * Convert a base64 encoded string to a `Uint8Array`.
282
+ *
283
+ * @param value - The base64 encoded string to convert to bytes.
284
+ * @returns The bytes as `Uint8Array`.
285
+ */
286
+ export function base64ToBytes(value) {
287
+ assert(typeof value === 'string', 'Value must be a string.');
288
+ return base64.decode(value);
289
+ }
290
+ /**
291
+ * Convert a byte-like value to a `Uint8Array`. The value can be a `Uint8Array`,
292
+ * a `bigint`, a `number`, or a `string`.
293
+ *
294
+ * This will attempt to guess the type of the value based on its type and
295
+ * contents. For more control over the conversion, use the more specific
296
+ * conversion functions, such as {@link hexToBytes} or {@link stringToBytes}.
297
+ *
298
+ * If the value is a `string`, and it is prefixed with `0x`, it will be
299
+ * interpreted as a hexadecimal string. Otherwise, it will be interpreted as a
300
+ * UTF-8 string. To convert a hexadecimal string to bytes without interpreting
301
+ * it as a UTF-8 string, use {@link hexToBytes} instead.
302
+ *
303
+ * If the value is a `bigint`, it is assumed to be unsigned. To convert a signed
304
+ * `bigint` to bytes, use {@link signedBigIntToBytes} instead.
305
+ *
306
+ * If the value is a `Uint8Array`, it will be returned as-is.
307
+ *
308
+ * @param value - The value to convert to bytes.
309
+ * @returns The bytes as `Uint8Array`.
310
+ */
311
+ export function valueToBytes(value) {
312
+ if (typeof value === 'bigint') {
313
+ return bigIntToBytes(value);
314
+ }
315
+ if (typeof value === 'number') {
316
+ return numberToBytes(value);
317
+ }
318
+ if (typeof value === 'string') {
319
+ if (value.startsWith('0x')) {
320
+ return hexToBytes(value);
321
+ }
322
+ return stringToBytes(value);
323
+ }
324
+ if (isArrayBufferBytes(value)) {
325
+ return value;
326
+ }
327
+ if (isBytes(value)) {
328
+ return new Uint8Array(value);
329
+ }
330
+ throw new TypeError(`Unsupported value type: "${typeof value}".`);
331
+ }
332
+ /**
333
+ * Concatenate multiple byte-like values into a single `Uint8Array`. The values
334
+ * can be `Uint8Array`, `bigint`, `number`, or `string`. This uses
335
+ * {@link valueToBytes} under the hood to convert each value to bytes. Refer to
336
+ * the documentation of that function for more information.
337
+ *
338
+ * @param values - The values to concatenate.
339
+ * @returns The concatenated bytes as `Uint8Array`.
340
+ */
341
+ export function concatBytes(values) {
342
+ const normalizedValues = new Array(values.length);
343
+ let byteLength = 0;
344
+ for (let i = 0; i < values.length; i++) {
345
+ // oxlint-disable-next-line typescript/no-non-null-assertion
346
+ const value = valueToBytes(values[i]);
347
+ normalizedValues[i] = value;
348
+ byteLength += value.length;
349
+ }
350
+ const bytes = new Uint8Array(byteLength);
351
+ let offset = 0;
352
+ for (const normalizedValue of normalizedValues) {
353
+ // While we could simply spread the values into an array and use
354
+ // `Uint8Array.from`, that is a lot slower than using `Uint8Array.set`.
355
+ bytes.set(normalizedValue, offset);
356
+ offset += normalizedValue.length;
357
+ }
358
+ return bytes;
359
+ }
360
+ function isBuffer(bytes) {
361
+ // oxlint-disable-next-line no-undef
362
+ return typeof Buffer !== 'undefined' && bytes instanceof Buffer;
363
+ }
364
+ /**
365
+ * Create a {@link DataView} from a {@link Uint8Array}. This is a convenience
366
+ * function that avoids having to create a {@link DataView} manually, which
367
+ * requires passing the `byteOffset` and `byteLength` parameters every time.
368
+ *
369
+ * Not passing the `byteOffset` and `byteLength` parameters can result in
370
+ * unexpected behavior when the {@link Uint8Array} is a view of a larger
371
+ * {@link ArrayBuffer}, e.g., when using {@link Uint8Array.subarray}.
372
+ *
373
+ * This function also supports Node.js {@link Buffer}s.
374
+ *
375
+ * @example
376
+ * ```typescript
377
+ * const bytes = new Uint8Array([1, 2, 3]);
378
+ *
379
+ * // This is equivalent to:
380
+ * // const dataView = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
381
+ * const dataView = createDataView(bytes);
382
+ * ```
383
+ * @param bytes - The bytes to create the {@link DataView} from.
384
+ * @returns The {@link DataView}.
385
+ */
386
+ export function createDataView(bytes) {
387
+ // To maintain compatibility with Node.js, we need to check if the bytes are
388
+ // a Buffer. If so, we need to slice the buffer to get the underlying
389
+ // ArrayBuffer.
390
+ // eslint-disable-next-line no-restricted-globals, no-undef
391
+ if (isBuffer(bytes)) {
392
+ const buffer = bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength);
393
+ return new DataView(buffer);
394
+ }
395
+ return new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
396
+ }
397
+ /**
398
+ * Compare two Uint8Arrays using a constant-time style loop to reduce timing
399
+ * side-channels when comparing sensitive data (e.g., mnemonic bytes, keys,
400
+ * authentication tags). Does not early-return on the first difference:
401
+ * work done depends only on the input lengths, so byte content does not affect timing.
402
+ *
403
+ * When to use:
404
+ * - Use for secret or security-sensitive byte comparisons to avoid content-based timing leaks.
405
+ * - Prefer when inputs are fixed-length (or validated to equal length) at the API boundary.
406
+ *
407
+ * @param a - The first Uint8Array to compare.
408
+ * @param b - The second Uint8Array to compare.
409
+ * @returns Whether the Uint8Arrays are equal.
410
+ */
411
+ export function areUint8ArraysEqual(a, b) {
412
+ // eslint-disable-next-line no-bitwise
413
+ let diff = a.byteLength ^ b.byteLength;
414
+ const len = Math.max(a.byteLength, b.byteLength);
415
+ for (let i = 0; i < len; i++) {
416
+ const aByte = a[i] ?? 0;
417
+ const bByte = b[i] ?? 0;
418
+ // eslint-disable-next-line no-bitwise
419
+ diff |= aByte ^ bByte;
420
+ }
421
+ return diff === 0;
422
+ }
423
+ //# sourceMappingURL=bytes.js.map