UNPKG

@isdk/bigint

Version:

The BigInteger class wrapped bn.js and native BitInt

423 lines (421 loc) 9.91 kB
"use strict"; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // src/native.ts var native_exports = {}; __export(native_exports, { BigIntNative: () => BigIntNative }); module.exports = __toCommonJS(native_exports); var BigIntNative = class { /** * Get a BigInteger (input must be big endian for strings and arrays) * @param {Number|String|Uint8Array} n - Value to convert * @throws {Error} on null or undefined input */ constructor(n) { if (n === void 0) { throw new Error("Invalid BigInteger input"); } if (n instanceof Uint8Array) { const bytes = n; const hex = new Array(bytes.length); for (let i = 0; i < bytes.length; i++) { const hexByte = bytes[i].toString(16); hex[i] = bytes[i] <= 15 ? `0${hexByte}` : hexByte; } this.value = BigInt(`0x0${hex.join("")}`); } else { this.value = BigInt(n); } } clone() { return new BigIntNative(this.value); } iinc(n = 1) { if (n === 1) { this.value++; } else { this.value += BigInt(n); } return this; } inc(n) { return this.clone().iinc(n); } idec(n = 1) { if (n === 1) { this.value--; } else { this.value -= BigInt(n); } return this; } dec(n) { return this.clone().idec(n); } /** * BigInteger addition in place * @param {BigIntNative} x - Value to add */ iadd(x) { this.value += x.value; return this; } /** * BigInteger addition * @param {BigIntNative} x - Value to add * @returns {BigIntNative} this + x. */ add(x) { return this.clone().iadd(x); } /** * BigInteger subtraction in place * @param {BigIntNative} x - Value to subtract */ isub(x) { this.value -= x.value; return this; } /** * BigInteger subtraction * @param {BigIntNative} x - Value to subtract * @returns {BigIntNative} this - x. */ sub(x) { return this.clone().isub(x); } /** * BigInteger multiplication in place * @param {BigIntNative} x - Value to multiply */ imul(x) { this.value *= x.value; return this; } /** * BigInteger multiplication * @param {BigIntNative} x - Value to multiply * @returns {BigIntNative} this * x. */ mul(x) { return this.clone().imul(x); } imod(m) { this.value %= m.value; return this; } /** * Compute value modulo m, in place * @param {BigIntNative} m - Modulo */ iumod(m) { this.value %= m.value; if (this.isNegative()) { this.iadd(m); } return this; } /** * Compute value modulo m * @param {BigIntNative} m - Modulo * @returns {BigIntNative} this mod m. */ umod(m) { return this.clone().iumod(m); } /** * Compute value modulo m * @param {BigIntNative} m - Modulo * @returns {BigIntNative} this mod m. */ mod(m) { return this.clone().imod(m); } modExp(e, n) { if (n.isZero()) { throw new Error("Modulo cannot be zero"); } if (n.isOne()) { return new BigIntNative(0); } if (e.isNegative()) { throw new Error("Unsupported negative exponent"); } let exp = e.value; let x = this.value; x %= n.value; let r = BigInt(1); while (exp > BigInt(0)) { const lsb = exp & BigInt(1); exp >>= BigInt(1); const rx = r * x % n.value; r = lsb ? rx : r; x = x * x % n.value; } return new BigIntNative(r); } /** * Compute the inverse of this value modulo n * Note: this and and n must be relatively prime * @param {BigIntNative} n - Modulo * @returns {BigIntNative} x such that this*x = 1 mod n * @throws {Error} if the inverse does not exist */ modInv(n) { const _n = n.value; const { gcd, x } = this.__egcd(_n); if (gcd !== BigInt(1)) { throw new Error("Inverse does not exist"); } return new BigIntNative((x + _n) % _n); } __egcd(b) { let x = BigInt(0); let y = BigInt(1); let xPrev = BigInt(1); let yPrev = BigInt(0); let a = this.value; while (b !== BigInt(0)) { const q = a / b; let tmp = x; x = xPrev - q * x; xPrev = tmp; tmp = y; y = yPrev - q * y; yPrev = tmp; tmp = b; b = a % b; a = tmp; } return { x: xPrev, y: yPrev, gcd: a }; } /** * Extended Eucleadian algorithm (http://anh.cs.luc.edu/331/notes/xgcd.pdf) * Given a = this and b, compute (x, y) such that ax + by = gdc(a, b) * @param {BigIntNative} b - Second operand * @returns {{ gcd, x, y: BigIntNative }} */ _egcd(b) { const { x, y, gcd } = this.__egcd(b.value); return { x: new BigIntNative(x), y: new BigIntNative(y), gcd: new BigIntNative(gcd) }; } /** * Compute greatest common divisor between this and n * @param {BigIntNative} b - Operand * @returns {BigIntNative} gcd */ gcd(b) { let a = this.value; b = b.value; while (b !== BigInt(0)) { const tmp = b; b = a % b; a = tmp; } return new BigIntNative(a); } /** * Shift this to the left by x, in place * @param {BigIntNative} x - Shift value */ ileftShift(x) { this.value <<= x.value; return this; } /** * Shift this to the left by x * @param {BigIntNative} x - Shift value * @returns {BigIntNative} this << x. */ leftShift(x) { return this.clone().ileftShift(x); } /** * Shift this to the right by x, in place * @param {BigIntNative} x - Shift value */ irightShift(x) { this.value >>= x.value; return this; } /** * Shift this to the right by x * @param {BigIntNative} x - Shift value * @returns {BigIntNative} this >> x. */ rightShift(x) { return this.clone().irightShift(x); } /** * Whether this value is equal to x * @param {BigIntNative} x * @returns {Boolean} */ equal(x) { return this.value === x.value; } /** * Whether this value is less than x * @param {BigIntNative} x * @returns {Boolean} */ lt(x) { return this.value < x.value; } /** * Whether this value is less than or equal to x * @param {BigIntNative} x * @returns {Boolean} */ lte(x) { return this.value <= x.value; } /** * Whether this value is greater than x * @param {BigIntNative} x * @returns {Boolean} */ gt(x) { return this.value > x.value; } /** * Whether this value is greater than or equal to x * @param {BigIntNative} x * @returns {Boolean} */ gte(x) { return this.value >= x.value; } isZero() { return this.value === BigInt(0); } isOne() { return this.value === BigInt(1); } isNegative() { return this.value < BigInt(0); } isEven() { return !(this.value & BigInt(1)); } abs() { const res = this.clone(); if (this.isNegative()) { res.value = -res.value; } return res; } /** * Get this value as a string * @returns {String} this value. */ toString() { return this.value.toString(); } /** * Get this value as an exact Number (max 53 bits) * Fails if this value is too large * @returns {Number} */ toNumber() { const number = Number(this.value); if (number > Number.MAX_SAFE_INTEGER) { throw new Error("Number can only safely store up to 53 bits"); } return number; } /** * Get value of i-th bit * @param {Number} i - Bit index * @returns {Number} Bit value. */ getBit(i) { const bit = this.value >> BigInt(i) & BigInt(1); return bit === BigInt(0) ? 0 : 1; } /** * Compute bit length * @returns {Number} Bit length. */ bitLength() { const zero = BigInt(0); const one = BigInt(1); const negOne = BigInt(-1); const target = this.value < 0 ? negOne : zero; let result = 1; let tmp = this.value; while ((tmp >>= one) !== target) { result++; } return result; } /** * Compute byte length * @returns {Number} Byte length. */ byteLength() { const zero = new BigIntNative(0); const negOne = new BigIntNative(-1); const target = this.isNegative() ? negOne : zero; const eight = new BigIntNative(8); let len = 1; const tmp = this.clone(); while (!tmp.irightShift(eight).equal(target)) { len++; } return len; } /** * Get Uint8Array representation of this number * @param {String} endian - Endianess of output array (defaults to 'be') * @param {Number} length - Of output array * @returns {Uint8Array} */ toUint8Array(endian = "be", length) { let hex = this.value.toString(16); if (hex.length % 2 === 1) { hex = `0${hex}`; } const rawLength = hex.length / 2; const bytes = new Uint8Array(length || rawLength); const offset = length ? length - rawLength : 0; let i = 0; while (i < rawLength) { bytes[i + offset] = parseInt(hex.slice(2 * i, 2 * i + 2), 16); i++; } if (endian !== "be") { bytes.reverse(); } return bytes; } }; // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { BigIntNative });