UNPKG

@axiom-crypto/tools

Version:

Useful data, field, and byte manipulation tools for Axiom.

123 lines (122 loc) 4.51 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.ByteStringReader = void 0; const byteLength_1 = require("./byteLength"); class ByteStringReader { constructor(byteString) { this.currentIdx = 0; this.byteString = byteString; if (this.byteString.startsWith("0x")) { this.byteString = this.byteString.slice(2); } } /** * Sets the current index of the reader * @param idx Index value to set `currentIdx` to */ setIndex(idx) { this.currentIdx = idx; } /** * Gets the number of bytes remaining in the hexString */ getNumBytesRemaining() { return Math.ceil((this.byteString.length - this.currentIdx) / 2); } /** * Reads `numBytes` from the byteString as an integer * @param numBytes Number of bytes to read * @returns An integer */ readInt(numBytes) { if (typeof numBytes === "string") { numBytes = (0, byteLength_1.getByteLength)(numBytes); } const numNibbles = numBytes * 2; if (this.currentIdx + numNibbles > this.byteString.length) { throw new Error(`Read past end of byteString: ${this.currentIdx} + ${numNibbles} > ${this.byteString.length}`); } if (numBytes > 6) { const warningMsg = "WARNING: Javascript's integer precision is limited to 53 " + "bits. Reading an int of >6 bytes will lead to a loss of precision. Consider " + "using `readBytes(numBytes)` and converting it to a BigInt instead."; console.warn(warningMsg); } const strSlice = this.byteString.slice(this.currentIdx, this.currentIdx + numNibbles); const value = parseInt(strSlice, 16); if (isNaN(value)) { throw new Error(`Unable to decode byteString slice strSlice`); } this.currentIdx += numNibbles; return value; } /** * Reads numBytes bytes from the byteString and returns them as a hex string * @param numBytes Number of bytes to read * @returns Hex string of the bytes read */ readBytes(numBytes) { if (typeof numBytes === "string") { numBytes = (0, byteLength_1.getByteLength)(numBytes); } const numNibbles = numBytes * 2; if (this.currentIdx + numNibbles > this.byteString.length) { throw new Error(`Read past end of byteString: ${this.currentIdx} + ${numNibbles} > ${this.byteString.length}`); } const value = "0x" + this.byteString.slice(this.currentIdx, this.currentIdx + numNibbles); this.currentIdx += numNibbles; return value; } /** * Moves `currentIdx` forward by `numBytes` bytes * @param numBytes Number of bytes to skip */ skipBytes(numBytes) { this.currentIdx += numBytes * 2; } /** * Reads a variable length amount of bytes, with the first `numLenBytes` bytes representing the * length, and the remaining `len` bytes representing the value. * @param numLenBytes Number of bytes to read for the length * @returns The value from the bytes read */ readVarLenBytes(numLenBytes) { const len = this.readInt(numLenBytes); const value = this.readBytes(len); return value; } /** * Reads a `len` number of bytes32 values from the byteString * @param len Number of bytes32 values to read * @returns An array of bytes32 values */ readFixedLenBytes32(len) { const arr = new Array(len).fill(""); for (let i = 0; i < len; i++) { arr[i] = this.readBytes(32); } return arr; } /** * Checks that all bytes in the byteString have been read * @returns true if all bytes in the byteString have been read, false otherwise */ validateAllBytesRead() { if (this.currentIdx != this.byteString.length) { return false; } return true; } /** * Gets a slice of the current byteString in number of bytes (number of string chars * 2) * @param index Index to start slice * @param numBytes Number of bytes to include in slice * @returns Hexstring of the byte slice */ getByteSlice(index, numBytes) { const numNibbles = numBytes * 2; const slice = this.byteString.slice(index, index + numNibbles); return "0x" + slice; } } exports.ByteStringReader = ByteStringReader;