mirror of
https://github.com/logos-messaging/js-waku.git
synced 2026-01-03 06:13:08 +00:00
135 lines
3.4 KiB
TypeScript
135 lines
3.4 KiB
TypeScript
export class BytesUtils {
|
|
/**
|
|
* Concatenate Uint8Arrays
|
|
* @param input
|
|
* @returns concatenation of all Uint8Array received as input
|
|
*/
|
|
public static concatenate(...input: Uint8Array[]): Uint8Array {
|
|
let totalLength = 0;
|
|
for (const arr of input) {
|
|
totalLength += arr.length;
|
|
}
|
|
const result = new Uint8Array(totalLength);
|
|
let offset = 0;
|
|
for (const arr of input) {
|
|
result.set(arr, offset);
|
|
offset += arr.length;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Convert a Uint8Array to a BigInt with configurable input endianness
|
|
* @param bytes - The byte array to convert
|
|
* @param inputEndianness - Endianness of the input bytes ('big' or 'little')
|
|
* @returns BigInt representation of the bytes
|
|
*/
|
|
public static toBigInt(
|
|
bytes: Uint8Array,
|
|
inputEndianness: "big" | "little" = "little"
|
|
): bigint {
|
|
if (bytes.length === 0) {
|
|
return 0n;
|
|
}
|
|
|
|
// Create a copy to avoid modifying the original array
|
|
const workingBytes = new Uint8Array(bytes);
|
|
|
|
// Reverse bytes if input is little-endian to work with big-endian internally
|
|
if (inputEndianness === "little") {
|
|
workingBytes.reverse();
|
|
}
|
|
|
|
// Convert to BigInt
|
|
let result = 0n;
|
|
for (let i = 0; i < workingBytes.length; i++) {
|
|
result = (result << 8n) | BigInt(workingBytes[i]);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Convert a BigInt to a bytes32 (32-byte Uint8Array)
|
|
* @param value - The BigInt to convert (must fit in 32 bytes)
|
|
* @param outputEndianness - Endianness of the output bytes ('big' or 'little')
|
|
* @returns 32-byte Uint8Array representation of the BigInt
|
|
*/
|
|
public static bytes32FromBigInt(
|
|
value: bigint,
|
|
outputEndianness: "big" | "little" = "little"
|
|
): Uint8Array {
|
|
if (value < 0n) {
|
|
throw new Error("Cannot convert negative BigInt to bytes");
|
|
}
|
|
|
|
if (value >> 256n !== 0n) {
|
|
throw new Error(
|
|
`BigInt value is too large to fit in 32 bytes (max bit length: 256)`
|
|
);
|
|
}
|
|
|
|
if (value === 0n) {
|
|
return new Uint8Array(32);
|
|
}
|
|
|
|
const result = new Uint8Array(32);
|
|
let workingValue = value;
|
|
|
|
// Extract bytes in big-endian order
|
|
for (let i = 31; i >= 0; i--) {
|
|
result[i] = Number(workingValue & 0xffn);
|
|
workingValue = workingValue >> 8n;
|
|
}
|
|
|
|
// If we need little-endian output, reverse the array
|
|
if (outputEndianness === "little") {
|
|
result.reverse();
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Writes an unsigned integer to a buffer in little-endian format
|
|
*/
|
|
public static writeUIntLE(
|
|
buf: Uint8Array,
|
|
value: number,
|
|
offset: number,
|
|
byteLength: number,
|
|
noAssert?: boolean
|
|
): Uint8Array {
|
|
value = +value;
|
|
offset = offset >>> 0;
|
|
byteLength = byteLength >>> 0;
|
|
if (!noAssert) {
|
|
const maxBytes = Math.pow(2, 8 * byteLength) - 1;
|
|
BytesUtils.checkInt(buf, value, offset, byteLength, maxBytes, 0);
|
|
}
|
|
|
|
let mul = 1;
|
|
let i = 0;
|
|
buf[offset] = value & 0xff;
|
|
while (++i < byteLength && (mul *= 0x100)) {
|
|
buf[offset + i] = (value / mul) & 0xff;
|
|
}
|
|
|
|
return buf;
|
|
}
|
|
|
|
// Adapted from https://github.com/feross/buffer
|
|
public static checkInt(
|
|
buf: Uint8Array,
|
|
value: number,
|
|
offset: number,
|
|
ext: number,
|
|
max: number,
|
|
min: number
|
|
): void {
|
|
if (value > max || value < min)
|
|
throw new RangeError('"value" argument is out of bounds');
|
|
if (offset + ext > buf.length) throw new RangeError("Index out of range");
|
|
}
|
|
}
|