"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.minimallyEncode = exports.Reader = exports.Writer = exports.fromBase58Check = exports.toBase58Check = exports.toBase58 = exports.fromBase58 = exports.encode = exports.toUTF8 = exports.toArray = exports.toUint8Array = exports.toHex = exports.zero2 = exports.ReaderUint8Array = exports.WriterUint8Array = void 0;
exports.base64ToArray = base64ToArray;
exports.toBase64 = toBase64;
exports.verifyNotNull = verifyNotNull;
exports.constantTimeEquals = constantTimeEquals;
const BigNumber_js_1 = __importDefault(require("./BigNumber.js"));
const Hash_js_1 = require("./Hash.js");
const hex_js_1 = require("./hex.js");
var WriterUint8Array_js_1 = require("./WriterUint8Array.js");
Object.defineProperty(exports, "WriterUint8Array", { enumerable: true, get: function () { return WriterUint8Array_js_1.WriterUint8Array; } });
var ReaderUint8Array_js_1 = require("./ReaderUint8Array.js");
Object.defineProperty(exports, "ReaderUint8Array", { enumerable: true, get: function () { return ReaderUint8Array_js_1.ReaderUint8Array; } });
const BufferCtor = typeof globalThis === 'undefined' ? undefined : globalThis.Buffer;
const CAN_USE_BUFFER = BufferCtor != null && typeof BufferCtor.from === 'function';
/**
 * Prepends a '0' to an odd character length word to ensure it has an even number of characters.
 * @param {string} word - The input word.
 * @returns {string} - The word with a leading '0' if it's an odd character length; otherwise, the original word.
 */
const zero2 = (word) => {
    if (word.length % 2 === 1) {
        return '0' + word;
    }
    else {
        return word;
    }
};
exports.zero2 = zero2;
/**
 * Converts an array of numbers to a hexadecimal string representation.
 * @param {number[]} msg - The input array of numbers.
 * @returns {string} - The hexadecimal string representation of the input array.
 */
const HEX_DIGITS = '0123456789abcdef';
const HEX_BYTE_STRINGS = new Array(256);
for (let i = 0; i < 256; i++) {
    HEX_BYTE_STRINGS[i] =
        HEX_DIGITS[(i >> 4) & 0xf] + HEX_DIGITS[i & 0xf];
}
const toHex = (msg) => {
    if (CAN_USE_BUFFER) {
        return BufferCtor.from(msg).toString('hex');
    }
    if (msg.length === 0)
        return '';
    const out = new Array(msg.length);
    for (let i = 0; i < msg.length; i++) {
        out[i] = HEX_BYTE_STRINGS[msg[i] & 0xff];
    }
    return out.join('');
};
exports.toHex = toHex;
/**
 * Converts various message formats into a Uint8Array.
 * Supports Uint8Array, arrays of bytes, hexadecimal strings, base64 strings, and UTF-8 strings.
 *
 * @param {any} msg - The input message (Uint8Array, number[], Array or string).
 * @param {('hex' | 'utf8' | 'base64')} enc - Specifies the string encoding, if applicable.
 * @returns {Uint8Array}
 */
const toUint8Array = (msg, enc) => {
    if (msg instanceof Uint8Array)
        return msg;
    return new Uint8Array((0, exports.toArray)(msg, enc));
};
exports.toUint8Array = toUint8Array;
/**
 * Converts various message formats into an array of numbers.
 * Supports arrays, hexadecimal strings, base64 strings, and UTF-8 strings.
 *
 * @param {any} msg - The input message (Uint8Array, number[], Array or string).
 * @param {('hex' | 'utf8' | 'base64')} enc - Specifies the string encoding, if applicable.
 * @returns {any[]} - Array representation of the input.
 */
const toArray = (msg, enc) => {
    if (Array.isArray(msg))
        return msg.slice();
    if (msg === undefined)
        return [];
    if (typeof msg !== 'string') {
        return Array.from(msg, (item) => Math.trunc(item));
    }
    switch (enc) {
        case 'hex':
            return hexToArray(msg);
        case 'base64':
            return base64ToArray(msg);
        default:
            return utf8ToArray(msg);
    }
};
exports.toArray = toArray;
const HEX_CHAR_TO_VALUE = new Int8Array(256).fill(-1);
for (let i = 0; i < 10; i++) {
    HEX_CHAR_TO_VALUE[48 + i] = i; // '0'-'9'
}
for (let i = 0; i < 6; i++) {
    HEX_CHAR_TO_VALUE[65 + i] = 10 + i; // 'A'-'F'
    HEX_CHAR_TO_VALUE[97 + i] = 10 + i; // 'a'-'f'
}
const hexToArray = (msg) => {
    (0, hex_js_1.assertValidHex)(msg);
    const normalized = msg.length % 2 === 0 ? msg : '0' + msg;
    if (CAN_USE_BUFFER) {
        return Array.from(BufferCtor.from(normalized, 'hex'));
    }
    const out = new Array(normalized.length / 2);
    let o = 0;
    for (let i = 0; i < normalized.length; i += 2) {
        const hi = HEX_CHAR_TO_VALUE[normalized.codePointAt(i)];
        const lo = HEX_CHAR_TO_VALUE[normalized.codePointAt(i + 1)];
        out[o++] = (hi << 4) | lo;
    }
    return out;
};
function base64ToArray(msg) {
    if (typeof msg !== 'string') {
        throw new TypeError('msg must be a string');
    }
    // cleanse string
    let s = msg.trim().replaceAll(/[\r\n\t\f\v ]+/g, '');
    s = s.replaceAll('-', '+').replaceAll('_', '/');
    // ensure padding is correct
    const padIndex = s.indexOf('=');
    if (padIndex !== -1) {
        const pad = s.slice(padIndex);
        if (!/^={1,2}$/.test(pad)) {
            throw new Error('Invalid base64 padding');
        }
        if (s.slice(0, padIndex).includes('=')) {
            throw new Error('Invalid base64 padding');
        }
        s = s.slice(0, padIndex);
    }
    const result = [];
    let bitBuffer = 0;
    let bitCount = 0;
    for (let i = 0; i < s.length; i++) {
        const c = s.codePointAt(i);
        // using ascii map values rather than indexOf
        let v = -1;
        if (c >= 65 && c <= 90) {
            v = c - 65; // A-Z
        }
        else if (c >= 97 && c <= 122) {
            v = c - 97 + 26; // a-z
        }
        else if (c >= 48 && c <= 57) {
            v = c - 48 + 52; // 0-9
        }
        else if (c === 43) {
            v = 62; // +
        }
        else if (c === 47) {
            v = 63; // /
        }
        else {
            throw new Error(`Invalid base64 character at index ${i}`);
        }
        bitBuffer = (bitBuffer << 6) | v;
        bitCount += 6;
        while (bitCount >= 8) {
            bitCount -= 8;
            result.push((bitBuffer >> bitCount) & 0xff);
            bitBuffer &= (1 << bitCount) - 1;
        }
    }
    // check for valid padding bits
    // if (bitCount !== 0 && bitBuffer !== 0) {
    //   throw new Error("Invalid base64: non-zero padding bits")
    // }
    return result;
}
/**
 * Encodes a string into an array of bytes representing its UTF-8 encoding.
 * Any lone surrogates are replaced with the Unicode replacement character (U+FFFD).
 *
 * @param str - The string to encode.
 * @returns An array of numbers, each representing a byte in the UTF-8 encoded string.
 */
function utf8ToArray(str) {
    return Array.from(new TextEncoder().encode(str));
}
/**
 * Converts an array of numbers to a UTF-8 encoded string.
 * @param {number[]} arr - The input array of numbers.
 * @returns {string} - The UTF-8 encoded string.
 */
const toUTF8 = (arr) => {
    return new TextDecoder().decode(new Uint8Array(arr));
};
exports.toUTF8 = toUTF8;
/**
 * Encodes an array of numbers into a specified encoding ('hex' or 'utf8'). If no encoding is provided, returns the original array.
 * @param {number[]} arr - The input array of numbers.
 * @param {('hex' | 'utf8')} enc - The desired encoding.
 * @returns {string | number[]} - The encoded message as a string (for 'hex' and 'utf8') or the original array.
 */
const encode = (arr, enc) => {
    switch (enc) {
        case 'hex':
            return (0, exports.toHex)(arr);
        case 'utf8':
            return (0, exports.toUTF8)(arr);
        // If no encoding is provided, return the original array
        default:
            return arr;
    }
};
exports.encode = encode;
/**
 * Converts an array of bytes (each between 0 and 255) into a base64 encoded string.
 *
 * @param {number[]} byteArray - An array of numbers where each number is a byte (0-255).
 * @returns {string} The base64 encoded string.
 *
 * @example
 * const bytes = [72, 101, 108, 108, 111]; // Represents the string "Hello"
 * console.log(toBase64(bytes)); // Outputs: SGVsbG8=
 */
function toBase64(byteArray) {
    const base64Chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
    let result = '';
    let i;
    for (i = 0; i < byteArray.length; i += 3) {
        const byte1 = byteArray[i];
        const byte2 = i + 1 < byteArray.length ? byteArray[i + 1] : 0;
        const byte3 = i + 2 < byteArray.length ? byteArray[i + 2] : 0;
        const encoded1 = byte1 >> 2;
        const encoded2 = ((byte1 & 0x03) << 4) | (byte2 >> 4);
        const encoded3 = ((byte2 & 0x0f) << 2) | (byte3 >> 6);
        const encoded4 = byte3 & 0x3f;
        result += base64Chars.charAt(encoded1) + base64Chars.charAt(encoded2);
        result += i + 1 < byteArray.length ? base64Chars.charAt(encoded3) : '=';
        result += i + 2 < byteArray.length ? base64Chars.charAt(encoded4) : '=';
    }
    return result;
}
const base58chars = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz';
/**
 * Converts a string from base58 to a binary array
 * @param str - The string representation
 * @returns The binary representation
 */
const fromBase58 = (str) => {
    if (str === '' || typeof str !== 'string') {
        throw new Error(`Expected base58 string but got “${str}”`);
    }
    const match = str.match(/[IOl0]/gmu);
    if (match !== null) {
        throw new Error(`Invalid base58 character “${match.join('')}”`);
    }
    const lz = str.match(/^1+/gmu);
    const psz = lz === null ? 0 : lz[0].length;
    const size = ((str.length - psz) * (Math.log(58) / Math.log(256)) + 1) >>> 0;
    const uint8 = new Uint8Array([
        ...new Uint8Array(psz),
        ...(str.match(/./gmu) ?? [] // ✅ Safe Fix: If null, use []
        )
            .map((i) => base58chars.indexOf(i))
            .reduce((acc, i) => {
            acc = acc.map((j) => {
                const x = j * 58 + i;
                i = x >> 8;
                return x;
            });
            return acc;
        }, new Uint8Array(size))
            .reverse()
            .filter(((lastValue) => (value) => 
        // @ts-expect-error
        (lastValue = lastValue || value))(false))
    ]);
    return [...uint8];
};
exports.fromBase58 = fromBase58;
/**
 * Converts a binary array into a base58 string
 * @param bin - The binary array to convert to base58
 * @returns The base58 string representation
 */
const toBase58 = (bin) => {
    const base58Map = new Array(256).fill(-1);
    for (let i = 0; i < base58chars.length; ++i) {
        base58Map[base58chars.codePointAt(i)] = i;
    }
    const result = [];
    for (const byte of bin) {
        let carry = byte;
        for (let j = 0; j < result.length; ++j) {
            const x = (base58Map[result[j]] << 8) + carry;
            result[j] = base58chars.codePointAt(x % 58);
            carry = Math.trunc(x / 58);
        }
        while (carry !== 0) {
            result.push(base58chars.codePointAt(carry % 58));
            carry = Math.trunc(carry / 58);
        }
    }
    for (const byte of bin) {
        if (byte === 0)
            result.push('1'.codePointAt(0));
        else
            break;
    }
    result.reverse();
    return String.fromCodePoint(...result);
};
exports.toBase58 = toBase58;
/**
 * Converts a binary array into a base58check string with a checksum
 * @param bin - The binary array to convert to base58check
 * @returns The base58check string representation
 */
const toBase58Check = (bin, prefix = [0]) => {
    let hash = (0, Hash_js_1.hash256)([...prefix, ...bin]);
    hash = [...prefix, ...bin, ...hash.slice(0, 4)];
    return (0, exports.toBase58)(hash);
};
exports.toBase58Check = toBase58Check;
/**
 * Converts a base58check string into a binary array after validating the checksum
 * @param str - The base58check string to convert to binary
 * @param enc - If hex, the return values will be hex strings, arrays of numbers otherwise
 * @param prefixLength - The length of the prefix. Optional, defaults to 1.
 * @returns The binary array representation
 */
const fromBase58Check = (str, enc, prefixLength = 1) => {
    const bin = (0, exports.fromBase58)(str);
    let prefix = bin.slice(0, prefixLength);
    let data = bin.slice(prefixLength, -4);
    let hash = [...prefix, ...data];
    hash = (0, Hash_js_1.hash256)(hash);
    bin.slice(-4).forEach((check, index) => {
        if (check !== hash[index]) {
            throw new Error('Invalid checksum');
        }
    });
    if (enc === 'hex') {
        prefix = (0, exports.toHex)(prefix);
        data = (0, exports.toHex)(data);
    }
    return { prefix, data };
};
exports.fromBase58Check = fromBase58Check;
class Writer {
    constructor(bufs) {
        this.bufs = bufs ?? [];
        this.length = 0;
        for (const b of this.bufs)
            this.length += b.length;
    }
    getLength() {
        return this.length;
    }
    toUint8Array() {
        const out = new Uint8Array(this.length);
        let offset = 0;
        for (const buf of this.bufs) {
            out.set(buf, offset);
            offset += buf.length;
        }
        return out;
    }
    toArray() {
        const totalLength = this.length;
        const ret = new Array(totalLength);
        let offset = 0;
        for (const buf of this.bufs) {
            if (buf instanceof Uint8Array) {
                for (const byte of buf) {
                    ret[offset++] = byte;
                }
            }
            else {
                const arr = buf;
                for (const item of arr) {
                    ret[offset++] = item;
                }
            }
        }
        return ret;
    }
    toHex() {
        return this.toArray().map((n) => n.toString(16).padStart(2, '0')).join('');
    }
    write(buf) {
        this.bufs.push(buf);
        this.length += buf.length;
        return this;
    }
    writeReverse(buf) {
        const buf2 = new Array(buf.length);
        for (let i = 0; i < buf2.length; i++) {
            buf2[i] = buf[buf.length - 1 - i];
        }
        return this.write(buf2);
    }
    writeUInt8(n) {
        const buf = new Array(1);
        buf[0] = n & 0xff;
        this.write(buf);
        return this;
    }
    writeInt8(n) {
        return this.writeUInt8(n);
    }
    writeUInt16BE(n) {
        const buf = [
            (n >> 8) & 0xff, // shift right 8 bits to get the high byte
            n & 0xff // low byte is just the last 8 bits
        ];
        return this.write(buf);
    }
    writeInt16BE(n) {
        return this.writeUInt16BE(n & 0xffff); // Mask with 0xFFFF to get the lower 16 bits
    }
    writeUInt16LE(n) {
        const buf = [
            n & 0xff, // low byte is just the last 8 bits
            (n >> 8) & 0xff // shift right 8 bits to get the high byte
        ];
        return this.write(buf);
    }
    writeInt16LE(n) {
        return this.writeUInt16LE(n & 0xffff); // Mask with 0xFFFF to get the lower 16 bits
    }
    writeUInt32BE(n) {
        const buf = [
            (n >> 24) & 0xff, // highest byte
            (n >> 16) & 0xff,
            (n >> 8) & 0xff,
            n & 0xff // lowest byte
        ];
        return this.write(buf);
    }
    writeInt32BE(n) {
        return this.writeUInt32BE(n >>> 0); // Using unsigned right shift to handle negative numbers
    }
    writeUInt32LE(n) {
        const buf = [
            n & 0xff, // lowest byte
            (n >> 8) & 0xff,
            (n >> 16) & 0xff,
            (n >> 24) & 0xff // highest byte
        ];
        return this.write(buf);
    }
    writeInt32LE(n) {
        return this.writeUInt32LE(n >>> 0); // Using unsigned right shift to handle negative numbers
    }
    writeUInt64BEBn(bn) {
        const buf = bn.toArray('be', 8);
        this.write(buf);
        return this;
    }
    writeUInt64LEBn(bn) {
        const buf = bn.toArray('be', 8);
        this.writeReverse(buf);
        return this;
    }
    writeUInt64LE(n) {
        if (n === -1) {
            // This value is used as a dummy satoshis value when serializing OTDA placeholder output for SIGHASH_SINGLE
            this.write(new Array(8).fill(0xff));
        }
        else {
            const buf = new BigNumber_js_1.default(n).toArray('be', 8);
            this.writeReverse(buf);
        }
        return this;
    }
    writeVarIntNum(n) {
        const buf = Writer.varIntNum(n);
        this.write(buf);
        return this;
    }
    writeVarIntBn(bn) {
        const buf = Writer.varIntBn(bn);
        this.write(buf);
        return this;
    }
    static varIntNum(n) {
        let buf;
        if (n < 0) {
            return this.varIntBn(new BigNumber_js_1.default(n));
        }
        if (n < 253) {
            buf = [n]; // 1 byte
        }
        else if (n < 0x10000) {
            // 253 followed by the number in little-endian format
            buf = [
                253, // 0xfd
                n & 0xff, // low byte
                (n >> 8) & 0xff // high byte
            ];
        }
        else if (n < 0x100000000) {
            // 254 followed by the number in little-endian format
            buf = [
                254, // 0xfe
                n & 0xff,
                (n >> 8) & 0xff,
                (n >> 16) & 0xff,
                (n >> 24) & 0xff
            ];
        }
        else {
            // 255 followed by the number in little-endian format
            // Since JavaScript bitwise operations work on 32 bits, we need to handle 64-bit numbers in two parts
            const low = n & 0xffffffff;
            const high = Math.floor(n / 0x100000000) & 0xffffffff;
            buf = [
                255, // 0xff
                low & 0xff,
                (low >> 8) & 0xff,
                (low >> 16) & 0xff,
                (low >> 24) & 0xff,
                high & 0xff,
                (high >> 8) & 0xff,
                (high >> 16) & 0xff,
                (high >> 24) & 0xff
            ];
        }
        return buf;
    }
    static varIntBn(bn) {
        let buf;
        if (bn.isNeg()) {
            bn = bn.add(OverflowUint64); // Adjust for negative numbers
        }
        if (bn.ltn(253)) {
            const n = bn.toNumber();
            // No need for bitwise operation as the value is within a byte's range
            buf = [n];
        }
        else if (bn.ltn(0x10000)) {
            const n = bn.toNumber();
            // Value fits in a uint16
            buf = [253, n & 0xff, (n >> 8) & 0xff];
        }
        else if (bn.lt(new BigNumber_js_1.default(0x100000000))) {
            const n = bn.toNumber();
            // Value fits in a uint32
            buf = [
                254,
                n & 0xff,
                (n >> 8) & 0xff,
                (n >> 16) & 0xff,
                (n >> 24) & 0xff
            ];
        }
        else {
            const bw = new Writer();
            bw.writeUInt8(255);
            bw.writeUInt64LEBn(bn);
            buf = bw.toArray();
        }
        return buf;
    }
}
exports.Writer = Writer;
class Reader {
    constructor(bin = [], pos = 0) {
        this.bin = bin;
        this.pos = pos;
        this.length = bin.length;
    }
    eof() {
        return this.pos >= this.length;
    }
    read(len = this.length) {
        const start = this.pos;
        const end = this.pos + len;
        this.pos = end;
        return this.bin.slice(start, end);
    }
    readReverse(len = this.length) {
        const buf2 = new Array(len);
        for (let i = 0; i < len; i++) {
            buf2[i] = this.bin[this.pos + len - 1 - i];
        }
        this.pos += len;
        return buf2;
    }
    readUInt8() {
        const val = this.bin[this.pos];
        this.pos += 1;
        return val;
    }
    readInt8() {
        const val = this.bin[this.pos];
        this.pos += 1;
        // If the sign bit is set, convert to negative value
        return (val & 0x80) === 0 ? val : val - 0x100;
    }
    readUInt16BE() {
        const val = (this.bin[this.pos] << 8) | this.bin[this.pos + 1];
        this.pos += 2;
        return val;
    }
    readInt16BE() {
        const val = this.readUInt16BE();
        // If the sign bit is set, convert to negative value
        return (val & 0x8000) === 0 ? val : val - 0x10000;
    }
    readUInt16LE() {
        const val = this.bin[this.pos] | (this.bin[this.pos + 1] << 8);
        this.pos += 2;
        return val;
    }
    readInt16LE() {
        const val = this.readUInt16LE();
        // If the sign bit is set, convert to negative value
        const x = (val & 0x8000) === 0 ? val : val - 0x10000;
        return x;
    }
    readUInt32BE() {
        const val = this.bin[this.pos] * 0x1000000 + // Shift the first byte by 24 bits
            ((this.bin[this.pos + 1] << 16) | // Shift the second byte by 16 bits
                (this.bin[this.pos + 2] << 8) | // Shift the third byte by 8 bits
                this.bin[this.pos + 3]); // The fourth byte
        this.pos += 4;
        return val;
    }
    readInt32BE() {
        const val = this.readUInt32BE();
        // If the sign bit is set, convert to negative value
        return (val & 0x80000000) === 0 ? val : val - 0x100000000;
    }
    readUInt32LE() {
        const val = (this.bin[this.pos] |
            (this.bin[this.pos + 1] << 8) |
            (this.bin[this.pos + 2] << 16) |
            (this.bin[this.pos + 3] << 24)) >>>
            0;
        this.pos += 4;
        return val;
    }
    readInt32LE() {
        const val = this.readUInt32LE();
        // Explicitly check if the sign bit is set and then convert to a negative value
        return (val & 0x80000000) === 0 ? val : val - 0x100000000;
    }
    readUInt64BEBn() {
        const bin = this.bin.slice(this.pos, this.pos + 8);
        const bn = new BigNumber_js_1.default(bin);
        this.pos = this.pos + 8;
        return bn;
    }
    readUInt64LEBn() {
        const bin = this.readReverse(8);
        const bn = new BigNumber_js_1.default(bin);
        return bn;
    }
    readInt64LEBn() {
        const bin = this.readReverse(8);
        let bn = new BigNumber_js_1.default(bin);
        if (bn.gte(OverflowInt64)) {
            bn = bn.sub(OverflowUint64); // Adjust for negative numbers
        }
        return bn;
    }
    readVarIntNum(signed = true) {
        const first = this.readUInt8();
        let bn;
        switch (first) {
            case 0xfd:
                return this.readUInt16LE();
            case 0xfe:
                return this.readUInt32LE();
            case 0xff:
                bn = signed ? this.readInt64LEBn() : this.readUInt64LEBn();
                if (bn.lte(new BigNumber_js_1.default(2).pow(new BigNumber_js_1.default(53)))) {
                    return bn.toNumber();
                }
                else {
                    throw new Error('number too large to retain precision - use readVarIntBn');
                }
            default:
                return first;
        }
    }
    readVarInt() {
        const first = this.bin[this.pos];
        switch (first) {
            case 0xfd:
                return this.read(1 + 2);
            case 0xfe:
                return this.read(1 + 4);
            case 0xff:
                return this.read(1 + 8);
            default:
                return this.read(1);
        }
    }
    readVarIntBn() {
        const first = this.readUInt8();
        switch (first) {
            case 0xfd:
                return new BigNumber_js_1.default(this.readUInt16LE());
            case 0xfe:
                return new BigNumber_js_1.default(this.readUInt32LE());
            case 0xff:
                return this.readUInt64LEBn();
            default:
                return new BigNumber_js_1.default(first);
        }
    }
}
exports.Reader = Reader;
const minimallyEncode = (buf) => {
    if (buf.length === 0) {
        return buf;
    }
    // If the last byte is not 0x00 or 0x80, we are minimally encoded.
    const last = buf.at(-1);
    if ((last & 0x7f) !== 0) {
        return buf;
    }
    // If the script is one byte long, then we have a zero, which encodes as an
    // empty array.
    if (buf.length === 1) {
        return [];
    }
    // If the next byte has it sign bit set, then we are minimaly encoded.
    if ((buf.at(-2) & 0x80) !== 0) {
        return buf;
    }
    // We are not minimally encoded, we need to figure out how much to trim.
    for (let i = buf.length - 1; i > 0; i--) {
        // We found a non zero byte, time to encode.
        if (buf[i - 1] !== 0) {
            if ((buf[i - 1] & 0x80) === 0) {
                // the sign bit is clear, we can use it.
                buf[i - 1] |= last;
                return buf.slice(0, i);
            }
            else {
                // We found a byte with it sign bit set so we need one more
                // byte.
                buf[i] = last;
                return buf.slice(0, i + 1);
            }
        }
    }
    // If we found the whole thing is zeros, then we have a zero.
    return [];
};
exports.minimallyEncode = minimallyEncode;
const OverflowInt64 = new BigNumber_js_1.default(2).pow(new BigNumber_js_1.default(63));
const OverflowUint64 = new BigNumber_js_1.default(2).pow(new BigNumber_js_1.default(64));
/**
 * Verifies that a value is not null or undefined, throwing an error if it is.
 *
 * @template T - The type of the value being verified
 * @param {T | undefined | null} value - The value to verify
 * @param {string} errorMessage - The error message to throw if the value is null or undefined
 * @returns {T} - The verified value
 * @throws {Error} - If the value is null or undefined
 *
 * @example
 * const myValue = verifyNotNull(someValue, 'someValue must be defined')
 */
function verifyNotNull(value, errorMessage = 'Expected a valid value, but got undefined or null.') {
    if (value == null)
        throw new Error(errorMessage);
    return value;
}
function constantTimeEquals(a, b) {
    if (a.length !== b.length)
        return false;
    let diff = 0;
    for (let i = 0; i < a.length; i++) {
        diff |= a[i] ^ b[i];
    }
    return diff === 0;
}
//# sourceMappingURL=utils.js.map