implement packet compression, implement player controller, implement join server authentication, add cobblestone, implement chunk provider, implement block position, implement session, implement movement, chunk, chat and block update packets, version 1.1.5
This commit is contained in:
+733
-697
File diff suppressed because it is too large
Load Diff
+135
-102
@@ -2,126 +2,159 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
// https://git.coolaj86.com/coolaj86/asn1-parser.js
|
||||
;(function (exports) {
|
||||
'use strict';
|
||||
|
||||
let ELOOPN = 102;
|
||||
let EDEEPN = 60;
|
||||
let CTYPES = [0x30, 0x31, 0xa0, 0xa1];
|
||||
let VTYPES = [0x01, 0x02, 0x05, 0x06, 0x0c, 0x82];
|
||||
if (!exports.ASN1) { exports.ASN1 = {}; }
|
||||
if (!exports.Enc) { exports.Enc = {}; }
|
||||
if (!exports.PEM) { exports.PEM = {}; }
|
||||
|
||||
function parseAsn1(buf) {
|
||||
//let ws = ' ';
|
||||
function parseAsn1(buf, depth, eager) {
|
||||
if (depth.length >= EDEEPN) {
|
||||
throw new Error("EDEEP");
|
||||
}
|
||||
var ASN1 = exports.ASN1;
|
||||
var Enc = exports.Enc;
|
||||
var PEM = exports.PEM;
|
||||
|
||||
let index = 2; // we know, at minimum, data starts after type (0) and lengthSize (1)
|
||||
let asn1 = {type: buf[0], lengthSize: 0, length: buf[1]};
|
||||
let child;
|
||||
let iters = 0;
|
||||
let adjust = 0;
|
||||
let adjustedLen;
|
||||
//
|
||||
// Parser
|
||||
//
|
||||
// Although I've only seen 9 max in https certificates themselves,
|
||||
// but each domain list could have up to 100
|
||||
ASN1.ELOOPN = 102;
|
||||
ASN1.ELOOP = "uASN1.js Error: iterated over " + ASN1.ELOOPN + "+ elements (probably a malformed file)";
|
||||
// I've seen https certificates go 29 deep
|
||||
ASN1.EDEEPN = 60;
|
||||
ASN1.EDEEP = "uASN1.js Error: element nested " + ASN1.EDEEPN + "+ layers deep (probably a malformed file)";
|
||||
// Container Types are Sequence 0x30, Container Array? (0xA0, 0xA1)
|
||||
// Value Types are Boolean 0x01, Integer 0x02, Null 0x05, Object ID 0x06, String 0x0C, 0x16, 0x13, 0x1e Value Array? (0x82)
|
||||
// Bit String (0x03) and Octet String (0x04) may be values or containers
|
||||
// Sometimes Bit String is used as a container (RSA Pub Spki)
|
||||
ASN1.CTYPES = [ 0x30, 0x31, 0xa0, 0xa1 ];
|
||||
ASN1.VTYPES = [ 0x01, 0x02, 0x05, 0x06, 0x0c, 0x82 ];
|
||||
ASN1.parse = function parseAsn1Helper(buf) {
|
||||
//var ws = ' ';
|
||||
function parseAsn1(buf, depth, eager) {
|
||||
if (depth.length >= ASN1.EDEEPN) { throw new Error(ASN1.EDEEP); }
|
||||
|
||||
// Determine how many bytes the length uses, and what it is
|
||||
if (0x80 & asn1.length) {
|
||||
asn1.lengthSize = 0x7f & asn1.length;
|
||||
// I think that buf->hex->int solves the problem of Endianness... not sure
|
||||
asn1.length = parseInt(bufToHex(buf.slice(index, index + asn1.lengthSize)), 16);
|
||||
index += asn1.lengthSize;
|
||||
}
|
||||
var index = 2; // we know, at minimum, data starts after type (0) and lengthSize (1)
|
||||
var asn1 = { type: buf[0], lengthSize: 0, length: buf[1] };
|
||||
var child;
|
||||
var iters = 0;
|
||||
var adjust = 0;
|
||||
var adjustedLen;
|
||||
|
||||
// High-order bit Integers have a leading 0x00 to signify that they are positive.
|
||||
// Bit Streams use the first byte to signify padding, which x.509 doesn't use.
|
||||
if (0x00 === buf[index] && (0x02 === asn1.type || 0x03 === asn1.type)) {
|
||||
// However, 0x00 on its own is a valid number
|
||||
if (asn1.length > 1) {
|
||||
index += 1;
|
||||
adjust = -1;
|
||||
// Determine how many bytes the length uses, and what it is
|
||||
if (0x80 & asn1.length) {
|
||||
asn1.lengthSize = 0x7f & asn1.length;
|
||||
// I think that buf->hex->int solves the problem of Endianness... not sure
|
||||
asn1.length = parseInt(Enc.bufToHex(buf.slice(index, index + asn1.lengthSize)), 16);
|
||||
index += asn1.lengthSize;
|
||||
}
|
||||
}
|
||||
adjustedLen = asn1.length + adjust;
|
||||
|
||||
function bufToHex(u8) {
|
||||
let hex = [];
|
||||
let i, h;
|
||||
let len = (u8.byteLength || u8.length);
|
||||
|
||||
for (i = 0; i < len; i += 1) {
|
||||
h = u8[i].toString(16);
|
||||
if (h.length % 2) {
|
||||
h = '0' + h;
|
||||
// High-order bit Integers have a leading 0x00 to signify that they are positive.
|
||||
// Bit Streams use the first byte to signify padding, which x.509 doesn't use.
|
||||
if (0x00 === buf[index] && (0x02 === asn1.type || 0x03 === asn1.type)) {
|
||||
// However, 0x00 on its own is a valid number
|
||||
if (asn1.length > 1) {
|
||||
index += 1;
|
||||
adjust = -1;
|
||||
}
|
||||
hex.push(h);
|
||||
}
|
||||
adjustedLen = asn1.length + adjust;
|
||||
|
||||
return hex.join('').toLowerCase();
|
||||
}
|
||||
|
||||
//console.warn(depth.join(ws) + '0x' + Enc.numToHex(asn1.type), index, 'len:', asn1.length, asn1);
|
||||
function parseChildren(eager) {
|
||||
asn1.children = [];
|
||||
//console.warn('1 len:', (2 + asn1.lengthSize + asn1.length), 'idx:', index, 'clen:', 0);
|
||||
while (iters < ELOOPN && index < (2 + asn1.length + asn1.lengthSize)) {
|
||||
iters += 1;
|
||||
depth.length += 1;
|
||||
child = parseAsn1(buf.slice(index, index + adjustedLen), depth, eager);
|
||||
depth.length -= 1;
|
||||
// The numbers don't match up exactly and I don't remember why...
|
||||
// probably something with adjustedLen or some such, but the tests pass
|
||||
index += (2 + child.lengthSize + child.length);
|
||||
//console.warn('2 len:', (2 + asn1.lengthSize + asn1.length), 'idx:', index, 'clen:', (2 + child.lengthSize + child.length));
|
||||
if (index > (2 + asn1.lengthSize + asn1.length)) {
|
||||
if (!eager) {
|
||||
console.error("error");
|
||||
//console.warn(depth.join(ws) + '0x' + Enc.numToHex(asn1.type), index, 'len:', asn1.length, asn1);
|
||||
function parseChildren(eager) {
|
||||
asn1.children = [];
|
||||
//console.warn('1 len:', (2 + asn1.lengthSize + asn1.length), 'idx:', index, 'clen:', 0);
|
||||
while (iters < ASN1.ELOOPN && index < (2 + asn1.length + asn1.lengthSize)) {
|
||||
iters += 1;
|
||||
depth.length += 1;
|
||||
child = parseAsn1(buf.slice(index, index + adjustedLen), depth, eager);
|
||||
depth.length -= 1;
|
||||
// The numbers don't match up exactly and I don't remember why...
|
||||
// probably something with adjustedLen or some such, but the tests pass
|
||||
index += (2 + child.lengthSize + child.length);
|
||||
//console.warn('2 len:', (2 + asn1.lengthSize + asn1.length), 'idx:', index, 'clen:', (2 + child.lengthSize + child.length));
|
||||
if (index > (2 + asn1.lengthSize + asn1.length)) {
|
||||
if (!eager) { console.error(JSON.stringify(asn1, ASN1._replacer, 2)); }
|
||||
throw new Error("Parse error: child value length (" + child.length
|
||||
+ ") is greater than remaining parent length (" + (asn1.length - index)
|
||||
+ " = " + asn1.length + " - " + index + ")");
|
||||
}
|
||||
throw new Error("Parse error: child value length (" + child.length
|
||||
+ ") is greater than remaining parent length (" + (asn1.length - index)
|
||||
+ " = " + asn1.length + " - " + index + ")");
|
||||
asn1.children.push(child);
|
||||
//console.warn(depth.join(ws) + '0x' + Enc.numToHex(asn1.type), index, 'len:', asn1.length, asn1);
|
||||
}
|
||||
asn1.children.push(child);
|
||||
//console.warn(depth.join(ws) + '0x' + Enc.numToHex(asn1.type), index, 'len:', asn1.length, asn1);
|
||||
}
|
||||
if (index !== (2 + asn1.lengthSize + asn1.length)) {
|
||||
//console.warn('index:', index, 'length:', (2 + asn1.lengthSize + asn1.length));
|
||||
throw new Error("premature end-of-file");
|
||||
}
|
||||
if (iters >= ELOOPN) {
|
||||
throw new Error("ELOOP");
|
||||
if (index !== (2 + asn1.lengthSize + asn1.length)) {
|
||||
//console.warn('index:', index, 'length:', (2 + asn1.lengthSize + asn1.length));
|
||||
throw new Error("premature end-of-file");
|
||||
}
|
||||
if (iters >= ASN1.ELOOPN) { throw new Error(ASN1.ELOOP); }
|
||||
|
||||
delete asn1.value;
|
||||
return asn1;
|
||||
}
|
||||
|
||||
delete asn1.value;
|
||||
return asn1;
|
||||
// Recurse into types that are _always_ containers
|
||||
if (-1 !== ASN1.CTYPES.indexOf(asn1.type)) { return parseChildren(eager); }
|
||||
|
||||
// Return types that are _always_ values
|
||||
asn1.value = buf.slice(index, index + adjustedLen);
|
||||
if (-1 !== ASN1.VTYPES.indexOf(asn1.type)) { return asn1; }
|
||||
|
||||
// For ambigious / unknown types, recurse and return on failure
|
||||
// (and return child array size to zero)
|
||||
try { return parseChildren(true); }
|
||||
catch(e) { asn1.children.length = 0; return asn1; }
|
||||
}
|
||||
|
||||
// Recurse into types that are _always_ containers
|
||||
if (-1 !== CTYPES.indexOf(asn1.type)) {
|
||||
return parseChildren(eager);
|
||||
var asn1 = parseAsn1(buf, []);
|
||||
var len = buf.byteLength || buf.length;
|
||||
if (len !== 2 + asn1.lengthSize + asn1.length) {
|
||||
throw new Error("Length of buffer does not match length of ASN.1 sequence.");
|
||||
}
|
||||
return asn1;
|
||||
};
|
||||
ASN1._replacer = function (k, v) {
|
||||
if ('type' === k) { return '0x' + Enc.numToHex(v); }
|
||||
if (v && 'value' === k) { return '0x' + Enc.bufToHex(v.data || v); }
|
||||
return v;
|
||||
};
|
||||
|
||||
// don't replace the full parseBlock, if it exists
|
||||
PEM.parseBlock = PEM.parseBlock || function (str) {
|
||||
var der = str.split(/\n/).filter(function (line) {
|
||||
return !/-----/.test(line);
|
||||
}).join('');
|
||||
return { der: Enc.base64ToBuf(der) };
|
||||
};
|
||||
|
||||
Enc.base64ToBuf = function (b64) {
|
||||
return Enc.binToBuf(atob(b64));
|
||||
};
|
||||
Enc.binToBuf = function (bin) {
|
||||
var arr = bin.split('').map(function (ch) {
|
||||
return ch.charCodeAt(0);
|
||||
});
|
||||
return 'undefined' !== typeof Uint8Array ? new Uint8Array(arr) : arr;
|
||||
};
|
||||
Enc.bufToHex = function (u8) {
|
||||
var hex = [];
|
||||
var i, h;
|
||||
var len = (u8.byteLength || u8.length);
|
||||
|
||||
for (i = 0; i < len; i += 1) {
|
||||
h = u8[i].toString(16);
|
||||
if (h.length % 2) { h = '0' + h; }
|
||||
hex.push(h);
|
||||
}
|
||||
|
||||
// Return types that are _always_ values
|
||||
asn1.value = buf.slice(index, index + adjustedLen);
|
||||
if (-1 !== VTYPES.indexOf(asn1.type)) {
|
||||
return asn1;
|
||||
return hex.join('').toLowerCase();
|
||||
};
|
||||
Enc.numToHex = function (d) {
|
||||
d = d.toString(16);
|
||||
if (d.length % 2) {
|
||||
return '0' + d;
|
||||
}
|
||||
return d;
|
||||
};
|
||||
|
||||
// For ambigious / unknown types, recurse and return on failure
|
||||
// (and return child array size to zero)
|
||||
try {
|
||||
return parseChildren(true);
|
||||
} catch (e) {
|
||||
asn1.children.length = 0;
|
||||
return asn1;
|
||||
}
|
||||
}
|
||||
|
||||
let asn1 = parseAsn1(buf, []);
|
||||
let len = buf.byteLength || buf.length;
|
||||
if (len !== 2 + asn1.lengthSize + asn1.length) {
|
||||
throw new Error("Length of buffer does not match length of ASN.1 sequence.");
|
||||
}
|
||||
return asn1;
|
||||
}
|
||||
|
||||
export {parseAsn1};
|
||||
}('undefined' !== typeof window ? window : module.exports));
|
||||
@@ -0,0 +1,160 @@
|
||||
// https://github.com/juanelas/bigint-mod-arith
|
||||
|
||||
window["bigint-mod-arith"] = function () {
|
||||
/**
|
||||
* Absolute value. abs(a)==a if a>=0. abs(a)==-a if a<0
|
||||
*
|
||||
* @param a
|
||||
*
|
||||
* @returns The absolute value of a
|
||||
*/
|
||||
function abs(a) {
|
||||
return (a >= 0) ? a : -a;
|
||||
}
|
||||
|
||||
/**
|
||||
* An iterative implementation of the extended euclidean algorithm or extended greatest common divisor algorithm.
|
||||
* Take positive integers a, b as input, and return a triple (g, x, y), such that ax + by = g = gcd(a, b).
|
||||
*
|
||||
* @param a
|
||||
* @param b
|
||||
*
|
||||
* @throws {RangeError}
|
||||
* This excepction is thrown if a or b are less than 0
|
||||
*
|
||||
* @returns A triple (g, x, y), such that ax + by = g = gcd(a, b).
|
||||
*/
|
||||
function eGcd(a, b) {
|
||||
if (typeof a === 'number')
|
||||
a = BigInt(a);
|
||||
if (typeof b === 'number')
|
||||
b = BigInt(b);
|
||||
if (a <= 0n || b <= 0n)
|
||||
throw new RangeError('a and b MUST be > 0'); // a and b MUST be positive
|
||||
let x = 0n;
|
||||
let y = 1n;
|
||||
let u = 1n;
|
||||
let v = 0n;
|
||||
while (a !== 0n) {
|
||||
const q = b / a;
|
||||
const r = b % a;
|
||||
const m = x - (u * q);
|
||||
const n = y - (v * q);
|
||||
b = a;
|
||||
a = r;
|
||||
x = u;
|
||||
y = v;
|
||||
u = m;
|
||||
v = n;
|
||||
}
|
||||
return {
|
||||
g: b,
|
||||
x: x,
|
||||
y: y
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the smallest positive element that is congruent to a in modulo n
|
||||
*
|
||||
* @remarks
|
||||
* a and b must be the same type, either number or bigint
|
||||
*
|
||||
* @param a - An integer
|
||||
* @param n - The modulo
|
||||
*
|
||||
* @throws {RangeError}
|
||||
* Excpeption thrown when n is not > 0
|
||||
*
|
||||
* @returns A bigint with the smallest positive representation of a modulo n
|
||||
*/
|
||||
function toZn(a, n) {
|
||||
if (typeof a === 'number')
|
||||
a = BigInt(a);
|
||||
if (typeof n === 'number')
|
||||
n = BigInt(n);
|
||||
if (n <= 0n) {
|
||||
throw new RangeError('n must be > 0');
|
||||
}
|
||||
const aZn = a % n;
|
||||
return (aZn < 0n) ? aZn + n : aZn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Modular inverse.
|
||||
*
|
||||
* @param a The number to find an inverse for
|
||||
* @param n The modulo
|
||||
*
|
||||
* @throws {RangeError}
|
||||
* Excpeption thorwn when a does not have inverse modulo n
|
||||
*
|
||||
* @returns The inverse modulo n
|
||||
*/
|
||||
function modInv(a, n) {
|
||||
const egcd = eGcd(toZn(a, n), n);
|
||||
if (egcd.g !== 1n) {
|
||||
throw new RangeError(`${a.toString()} does not have inverse modulo ${n.toString()}`); // modular inverse does not exist
|
||||
} else {
|
||||
return toZn(egcd.x, n);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Modular exponentiation b**e mod n. Currently using the right-to-left binary method
|
||||
*
|
||||
* @param b base
|
||||
* @param e exponent
|
||||
* @param n modulo
|
||||
*
|
||||
* @throws {RangeError}
|
||||
* Excpeption thrown when n is not > 0
|
||||
*
|
||||
* @returns b**e mod n
|
||||
*/
|
||||
function modPow(b, e, n) {
|
||||
if (typeof b === 'number')
|
||||
b = BigInt(b);
|
||||
if (typeof e === 'number')
|
||||
e = BigInt(e);
|
||||
if (typeof n === 'number')
|
||||
n = BigInt(n);
|
||||
if (n <= 0n) {
|
||||
throw new RangeError('n must be > 0');
|
||||
} else if (n === 1n) {
|
||||
return 0n;
|
||||
}
|
||||
b = toZn(b, n);
|
||||
if (e < 0n) {
|
||||
return modInv(modPow(b, abs(e), n), n);
|
||||
}
|
||||
let r = 1n;
|
||||
while (e > 0) {
|
||||
if ((e % 2n) === 1n) {
|
||||
r = r * b % n;
|
||||
}
|
||||
e = e / 2n;
|
||||
b = b ** 2n % n;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
function bytesToBigInt(bytes) {
|
||||
return BigInt("0x" + Array.from(bytes, byte => {
|
||||
return ('0' + (byte & 0xFF).toString(16)).slice(-2);
|
||||
}).join(''));
|
||||
}
|
||||
|
||||
function bigIntToBytes(bigInt) {
|
||||
let hex = bigInt.toString(16);
|
||||
|
||||
// Convert hex to bytes
|
||||
let bytes = [];
|
||||
for (let c = 0; c < hex.length; c += 2) {
|
||||
bytes.push(parseInt(hex.substr(c, 2), 16));
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
|
||||
return {bigIntToBytes, bytesToBigInt, modPow};
|
||||
}();
|
||||
+24
-108
@@ -157,158 +157,74 @@ export function flatten(component) {
|
||||
}
|
||||
|
||||
/** Converts a `StringComponent` to plain text and can format it using ANSI codes. */
|
||||
export function formatString(component, useAnsiCodes = false) {
|
||||
let text = flatten(component).map((c) => {
|
||||
if (!useAnsiCodes)
|
||||
return c.text;
|
||||
export function formatString(component) {
|
||||
return flatten(component).map((c) => {
|
||||
let codes = colorToAnsiCode(c.color);
|
||||
if (c.bold)
|
||||
codes += "\x1b[1m";
|
||||
codes += "\u00a7l";
|
||||
if (c.italic)
|
||||
codes += "\x1b[3m";
|
||||
codes += "\u00a7o";
|
||||
if (c.underlined)
|
||||
codes += "\x1b[4m";
|
||||
codes += "\u00a7n";
|
||||
if (c.strikethrough)
|
||||
codes += "\x1b[9m";
|
||||
return codes ? codes + c.text + "\x1b[0m" : c.text;
|
||||
codes += "\u00a7m";
|
||||
return codes ? codes + c.text + "\u00a7r" : c.text;
|
||||
}).join("");
|
||||
if (!useAnsiCodes)
|
||||
return text;
|
||||
const resetCodes = new Set();
|
||||
text = text.split(/ยง(.)/).map((t, i) => {
|
||||
if (i % 2 === 0)
|
||||
return t;
|
||||
else
|
||||
switch (t) {
|
||||
case "l":
|
||||
resetCodes.add("\x1b[22m");
|
||||
return "\x1b[1m";
|
||||
case "m":
|
||||
resetCodes.add("\x1b[29m");
|
||||
return "\x1b[9m";
|
||||
case "n":
|
||||
resetCodes.add("\x1b[24m");
|
||||
return "\x1b[4m";
|
||||
case "o":
|
||||
resetCodes.add("\x1b[23m");
|
||||
return "\x1b[3m";
|
||||
case "r":
|
||||
resetCodes.clear();
|
||||
return "\x1b[0m";
|
||||
case "k":
|
||||
t = "";
|
||||
break;
|
||||
case "0":
|
||||
t = "\x1b[38;2;0;0;0m";
|
||||
break;
|
||||
case "1":
|
||||
t = "\x1b[38;2;0;0;170m";
|
||||
break;
|
||||
case "2":
|
||||
t = "\x1b[38;2;0;170;0m";
|
||||
break;
|
||||
case "3":
|
||||
t = "\x1b[38;2;0;170;170m";
|
||||
break;
|
||||
case "4":
|
||||
t = "\x1b[38;2;170;0;0m";
|
||||
break;
|
||||
case "5":
|
||||
t = "\x1b[38;2;170;0;170m";
|
||||
break;
|
||||
case "6":
|
||||
t = "\x1b[38;2;255;170;0m";
|
||||
break;
|
||||
case "7":
|
||||
t = "\x1b[38;2;170;170;170m";
|
||||
break;
|
||||
case "8":
|
||||
t = "\x1b[38;2;85;85;85m";
|
||||
break;
|
||||
case "9":
|
||||
t = "\x1b[38;2;85;85;255m";
|
||||
break;
|
||||
case "a":
|
||||
t = "\x1b[38;2;85;255;85m";
|
||||
break;
|
||||
case "b":
|
||||
t = "\x1b[38;2;85;255;255m";
|
||||
break;
|
||||
case "c":
|
||||
t = "\x1b[38;2;255;85;85m";
|
||||
break;
|
||||
case "d":
|
||||
t = "\x1b[38;2;255;85;255m";
|
||||
break;
|
||||
case "e":
|
||||
t = "\x1b[38;2;255;255;85m";
|
||||
break;
|
||||
case "f":
|
||||
t = "\x1b[38;2;255;255;255m";
|
||||
break;
|
||||
}
|
||||
return t + [...resetCodes.values()].join("");
|
||||
}).join("");
|
||||
const index = text.lastIndexOf("\x1b[");
|
||||
if (index === -1)
|
||||
return text;
|
||||
const code = text.slice(index + 2).match(/(.+)m/)[1];
|
||||
return code === "0" ? text : text + "\x1b[0m";
|
||||
}
|
||||
|
||||
function colorToAnsiCode(color) {
|
||||
let code = "";
|
||||
switch (color) {
|
||||
case "black":
|
||||
code += "0;0;0";
|
||||
code += "0";
|
||||
break;
|
||||
case "dark_blue":
|
||||
code += "0;0;170";
|
||||
code += "1";
|
||||
break;
|
||||
case "dark_green":
|
||||
code += "0;170;0";
|
||||
code += "2";
|
||||
break;
|
||||
case "dark_aqua":
|
||||
code += "0;170;170";
|
||||
code += "3";
|
||||
break;
|
||||
case "dark_red":
|
||||
code += "170;0;0";
|
||||
code += "4";
|
||||
break;
|
||||
case "dark_purple":
|
||||
code += "170;0;170";
|
||||
code += "5";
|
||||
break;
|
||||
case "gold":
|
||||
code += "255;170;0";
|
||||
code += "6";
|
||||
break;
|
||||
case "gray":
|
||||
code += "170;170;170";
|
||||
code += "7";
|
||||
break;
|
||||
case "dark_gray":
|
||||
code += "85;85;85";
|
||||
code += "8";
|
||||
break;
|
||||
case "blue":
|
||||
code += "85;85;255";
|
||||
code += "9";
|
||||
break;
|
||||
case "green":
|
||||
code += "85;255;85";
|
||||
code += "a";
|
||||
break;
|
||||
case "aqua":
|
||||
code += "85;255;255";
|
||||
code += "b";
|
||||
break;
|
||||
case "red":
|
||||
code += "255;85;85";
|
||||
code += "c";
|
||||
break;
|
||||
case "light_purple":
|
||||
code += "255;85;255";
|
||||
code += "d";
|
||||
break;
|
||||
case "yellow":
|
||||
code += "255;255;85";
|
||||
code += "e";
|
||||
break;
|
||||
case "white":
|
||||
code += "255;255;255";
|
||||
code += "f";
|
||||
break;
|
||||
}
|
||||
return code && "\x1b[38;2;" + code + "m";
|
||||
return code && "\u00a7" + code;
|
||||
}
|
||||
|
||||
function flattenArray(array) {
|
||||
|
||||
+1371
-1364
File diff suppressed because it is too large
Load Diff
@@ -1,257 +0,0 @@
|
||||
// https://github.com/juanelas/bigint-mod-arith
|
||||
|
||||
/**
|
||||
* Absolute value. abs(a)==a if a>=0. abs(a)==-a if a<0
|
||||
*
|
||||
* @param a
|
||||
*
|
||||
* @returns The absolute value of a
|
||||
*/
|
||||
function abs(a) {
|
||||
return (a >= 0) ? a : -a;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the bitlength of a number
|
||||
*
|
||||
* @param a
|
||||
* @returns The bit length
|
||||
*/
|
||||
function bitLength(a) {
|
||||
if (typeof a === 'number')
|
||||
a = BigInt(a);
|
||||
if (a === 1n) {
|
||||
return 1;
|
||||
}
|
||||
let bits = 1;
|
||||
do {
|
||||
bits++;
|
||||
} while ((a >>= 1n) > 1n);
|
||||
return bits;
|
||||
}
|
||||
|
||||
/**
|
||||
* An iterative implementation of the extended euclidean algorithm or extended greatest common divisor algorithm.
|
||||
* Take positive integers a, b as input, and return a triple (g, x, y), such that ax + by = g = gcd(a, b).
|
||||
*
|
||||
* @param a
|
||||
* @param b
|
||||
*
|
||||
* @throws {RangeError}
|
||||
* This excepction is thrown if a or b are less than 0
|
||||
*
|
||||
* @returns A triple (g, x, y), such that ax + by = g = gcd(a, b).
|
||||
*/
|
||||
function eGcd(a, b) {
|
||||
if (typeof a === 'number')
|
||||
a = BigInt(a);
|
||||
if (typeof b === 'number')
|
||||
b = BigInt(b);
|
||||
if (a <= 0n || b <= 0n)
|
||||
throw new RangeError('a and b MUST be > 0'); // a and b MUST be positive
|
||||
let x = 0n;
|
||||
let y = 1n;
|
||||
let u = 1n;
|
||||
let v = 0n;
|
||||
while (a !== 0n) {
|
||||
const q = b / a;
|
||||
const r = b % a;
|
||||
const m = x - (u * q);
|
||||
const n = y - (v * q);
|
||||
b = a;
|
||||
a = r;
|
||||
x = u;
|
||||
y = v;
|
||||
u = m;
|
||||
v = n;
|
||||
}
|
||||
return {
|
||||
g: b,
|
||||
x: x,
|
||||
y: y
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Greatest-common divisor of two integers based on the iterative binary algorithm.
|
||||
*
|
||||
* @param a
|
||||
* @param b
|
||||
*
|
||||
* @returns The greatest common divisor of a and b
|
||||
*/
|
||||
function gcd(a, b) {
|
||||
let aAbs = (typeof a === 'number') ? BigInt(abs(a)) : abs(a);
|
||||
let bAbs = (typeof b === 'number') ? BigInt(abs(b)) : abs(b);
|
||||
if (aAbs === 0n) {
|
||||
return bAbs;
|
||||
} else if (bAbs === 0n) {
|
||||
return aAbs;
|
||||
}
|
||||
let shift = 0n;
|
||||
while (((aAbs | bAbs) & 1n) === 0n) {
|
||||
aAbs >>= 1n;
|
||||
bAbs >>= 1n;
|
||||
shift++;
|
||||
}
|
||||
while ((aAbs & 1n) === 0n)
|
||||
aAbs >>= 1n;
|
||||
do {
|
||||
while ((bAbs & 1n) === 0n)
|
||||
bAbs >>= 1n;
|
||||
if (aAbs > bAbs) {
|
||||
const x = aAbs;
|
||||
aAbs = bAbs;
|
||||
bAbs = x;
|
||||
}
|
||||
bAbs -= aAbs;
|
||||
} while (bAbs !== 0n);
|
||||
// rescale
|
||||
return aAbs << shift;
|
||||
}
|
||||
|
||||
/**
|
||||
* The least common multiple computed as abs(a*b)/gcd(a,b)
|
||||
* @param a
|
||||
* @param b
|
||||
*
|
||||
* @returns The least common multiple of a and b
|
||||
*/
|
||||
function lcm(a, b) {
|
||||
if (typeof a === 'number')
|
||||
a = BigInt(a);
|
||||
if (typeof b === 'number')
|
||||
b = BigInt(b);
|
||||
if (a === 0n && b === 0n)
|
||||
return BigInt(0);
|
||||
// return abs(a * b) as bigint / gcd(a, b)
|
||||
return abs((a / gcd(a, b)) * b);
|
||||
}
|
||||
|
||||
/**
|
||||
* Maximum. max(a,b)==a if a>=b. max(a,b)==b if a<=b
|
||||
*
|
||||
* @param a
|
||||
* @param b
|
||||
*
|
||||
* @returns Maximum of numbers a and b
|
||||
*/
|
||||
function max(a, b) {
|
||||
return (a >= b) ? a : b;
|
||||
}
|
||||
|
||||
/**
|
||||
* Minimum. min(a,b)==b if a>=b. min(a,b)==a if a<=b
|
||||
*
|
||||
* @param a
|
||||
* @param b
|
||||
*
|
||||
* @returns Minimum of numbers a and b
|
||||
*/
|
||||
function min(a, b) {
|
||||
return (a >= b) ? b : a;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the smallest positive element that is congruent to a in modulo n
|
||||
*
|
||||
* @remarks
|
||||
* a and b must be the same type, either number or bigint
|
||||
*
|
||||
* @param a - An integer
|
||||
* @param n - The modulo
|
||||
*
|
||||
* @throws {RangeError}
|
||||
* Excpeption thrown when n is not > 0
|
||||
*
|
||||
* @returns A bigint with the smallest positive representation of a modulo n
|
||||
*/
|
||||
function toZn(a, n) {
|
||||
if (typeof a === 'number')
|
||||
a = BigInt(a);
|
||||
if (typeof n === 'number')
|
||||
n = BigInt(n);
|
||||
if (n <= 0n) {
|
||||
throw new RangeError('n must be > 0');
|
||||
}
|
||||
const aZn = a % n;
|
||||
return (aZn < 0n) ? aZn + n : aZn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Modular inverse.
|
||||
*
|
||||
* @param a The number to find an inverse for
|
||||
* @param n The modulo
|
||||
*
|
||||
* @throws {RangeError}
|
||||
* Excpeption thorwn when a does not have inverse modulo n
|
||||
*
|
||||
* @returns The inverse modulo n
|
||||
*/
|
||||
function modInv(a, n) {
|
||||
const egcd = eGcd(toZn(a, n), n);
|
||||
if (egcd.g !== 1n) {
|
||||
throw new RangeError(`${a.toString()} does not have inverse modulo ${n.toString()}`); // modular inverse does not exist
|
||||
} else {
|
||||
return toZn(egcd.x, n);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Modular exponentiation b**e mod n. Currently using the right-to-left binary method
|
||||
*
|
||||
* @param b base
|
||||
* @param e exponent
|
||||
* @param n modulo
|
||||
*
|
||||
* @throws {RangeError}
|
||||
* Excpeption thrown when n is not > 0
|
||||
*
|
||||
* @returns b**e mod n
|
||||
*/
|
||||
function modPow(b, e, n) {
|
||||
if (typeof b === 'number')
|
||||
b = BigInt(b);
|
||||
if (typeof e === 'number')
|
||||
e = BigInt(e);
|
||||
if (typeof n === 'number')
|
||||
n = BigInt(n);
|
||||
if (n <= 0n) {
|
||||
throw new RangeError('n must be > 0');
|
||||
} else if (n === 1n) {
|
||||
return 0n;
|
||||
}
|
||||
b = toZn(b, n);
|
||||
if (e < 0n) {
|
||||
return modInv(modPow(b, abs(e), n), n);
|
||||
}
|
||||
let r = 1n;
|
||||
while (e > 0) {
|
||||
if ((e % 2n) === 1n) {
|
||||
r = r * b % n;
|
||||
}
|
||||
e = e / 2n;
|
||||
b = b ** 2n % n;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
function bytesToBigInt(bytes) {
|
||||
return BigInt("0x" + Array.from(bytes, byte => {
|
||||
return ('0' + (byte & 0xFF).toString(16)).slice(-2);
|
||||
}).join(''));
|
||||
}
|
||||
|
||||
function bigIntToBytes(bigInt) {
|
||||
let hex = bigInt.toString(16);
|
||||
|
||||
// Convert hex to bytes
|
||||
let bytes = [];
|
||||
for (let c = 0; c < hex.length; c += 2) {
|
||||
bytes.push(parseInt(hex.substr(c, 2), 16));
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
|
||||
export {abs, bitLength, eGcd, gcd, lcm, max, min, modInv, modPow, toZn, bytesToBigInt, bigIntToBytes};
|
||||
Vendored
+8027
File diff suppressed because it is too large
Load Diff
Vendored
+9
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user