UNPKG

@jsonjoy.com/json-pack

Version:

High-performance JSON serialization library

104 lines 3.85 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.JsonPackMpint = void 0; /** * Represents an SSH multiprecision integer (mpint). * * An mpint is stored in two's complement format, 8 bits per byte, MSB first. * According to RFC 4251: * - Negative numbers have the value 1 as the most significant bit of the first byte * - If the most significant bit would be set for a positive number, the number MUST be preceded by a zero byte * - Unnecessary leading bytes with the value 0 or 255 MUST NOT be included * - The value zero MUST be stored as a string with zero bytes of data */ class JsonPackMpint { constructor(data) { this.data = data; } /** * Create an mpint from a BigInt value. */ static fromBigInt(value) { if (value === BigInt(0)) { return new JsonPackMpint(new Uint8Array(0)); } const negative = value < BigInt(0); const bytes = []; if (negative) { // For negative numbers, work with two's complement const absValue = -value; const bitLength = absValue.toString(2).length; const byteLength = Math.ceil((bitLength + 1) / 8); // +1 for sign bit // Calculate two's complement const twoComplement = (BigInt(1) << BigInt(byteLength * 8)) + value; for (let i = byteLength - 1; i >= 0; i--) { bytes.push(Number((twoComplement >> BigInt(i * 8)) & BigInt(0xff))); } // Ensure MSB is 1 for negative numbers while (bytes.length > 0 && bytes[0] === 0xff && bytes.length > 1 && (bytes[1] & 0x80) !== 0) { bytes.shift(); } } else { // For positive numbers let tempValue = value; while (tempValue > BigInt(0)) { bytes.unshift(Number(tempValue & BigInt(0xff))); tempValue >>= BigInt(8); } // Add leading zero if MSB is set (to indicate positive number) if (bytes[0] & 0x80) { bytes.unshift(0); } } return new JsonPackMpint(new Uint8Array(bytes)); } /** * Convert the mpint to a BigInt value. */ toBigInt() { if (this.data.length === 0) { return BigInt(0); } const negative = (this.data[0] & 0x80) !== 0; if (negative) { // Two's complement for negative numbers let value = BigInt(0); for (let i = 0; i < this.data.length; i++) { value = (value << BigInt(8)) | BigInt(this.data[i]); } // Convert from two's complement const bitLength = this.data.length * 8; return value - (BigInt(1) << BigInt(bitLength)); } else { // Positive number let value = BigInt(0); for (let i = 0; i < this.data.length; i++) { value = (value << BigInt(8)) | BigInt(this.data[i]); } return value; } } /** * Create an mpint from a number (limited to safe integer range). */ static fromNumber(value) { if (!Number.isInteger(value)) { throw new Error('Value must be an integer'); } return JsonPackMpint.fromBigInt(BigInt(value)); } /** * Convert the mpint to a number (throws if out of safe integer range). */ toNumber() { const bigIntValue = this.toBigInt(); if (bigIntValue > BigInt(Number.MAX_SAFE_INTEGER) || bigIntValue < BigInt(Number.MIN_SAFE_INTEGER)) { throw new Error('Value is outside safe integer range'); } return Number(bigIntValue); } } exports.JsonPackMpint = JsonPackMpint; //# sourceMappingURL=JsonPackMpint.js.map