UNPKG

peerpigeon

Version:

WebRTC-based peer-to-peer mesh networking library with intelligent routing and signaling server

1,476 lines (1,474 loc) 530 kB
// PeerPigeon Browser Bundle - includes UnSEA crypto library // Generated automatically - do not edit directly var PeerPigeon = (() => { var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, { get: (a, b) => (typeof require !== "undefined" ? require : a)[b] }) : x)(function(x) { if (typeof require !== "undefined") return require.apply(this, arguments); throw Error('Dynamic require of "' + x + '" is not supported'); }); var __esm = (fn, res) => function __init() { return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res; }; var __commonJS = (cb, mod2) => function __require2() { return mod2 || (0, cb[__getOwnPropNames(cb)[0]])((mod2 = { exports: {} }).exports, mod2), mod2.exports; }; 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 __toESM = (mod2, isNodeMode, target) => (target = mod2 != null ? __create(__getProtoOf(mod2)) : {}, __copyProps( // If the importer is in node compatibility mode or this is not an ESM // file that has been converted to a CommonJS file using a Babel- // compatible transform (i.e. "__esModule" has not been set), then set // "default" to the CommonJS "module.exports" for node compatibility. isNodeMode || !mod2 || !mod2.__esModule ? __defProp(target, "default", { value: mod2, enumerable: true }) : target, mod2 )); var __toCommonJS = (mod2) => __copyProps(__defProp({}, "__esModule", { value: true }), mod2); var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value); // node_modules/unsea/dist/unsea.mjs var unsea_exports = {}; __export(unsea_exports, { SECURITY_CONFIG: () => SECURITY_CONFIG, clearKeys: () => clearKeys, decryptMessageWithMeta: () => decryptMessageWithMeta, encryptMessageWithMeta: () => encryptMessageWithMeta, exportToJWK: () => exportToJWK, exportToPEM: () => exportToPEM, generateRandomPair: () => generateRandomPair, generateSignedWork: () => generateSignedWork, generateWork: () => generateWork, getSecurityInfo: () => getSecurityInfo, importFromJWK: () => importFromJWK, importFromPEM: () => importFromPEM, loadKeys: () => loadKeys, saveKeys: () => saveKeys, signMessage: () => signMessage, verifyMessage: () => verifyMessage, verifySignedWork: () => verifySignedWork, verifyWork: () => verifyWork }); function isBytes(a) { return a instanceof Uint8Array || ArrayBuffer.isView(a) && a.constructor.name === "Uint8Array"; } function anumber(n) { if (!Number.isSafeInteger(n) || n < 0) throw new Error("positive integer expected, got " + n); } function abytes(b, ...lengths) { if (!isBytes(b)) throw new Error("Uint8Array expected"); if (lengths.length > 0 && !lengths.includes(b.length)) throw new Error("Uint8Array expected of length " + lengths + ", got length=" + b.length); } function ahash(h) { if (typeof h !== "function" || typeof h.create !== "function") throw new Error("Hash should be wrapped by utils.createHasher"); anumber(h.outputLen); anumber(h.blockLen); } function aexists(instance, checkFinished = true) { if (instance.destroyed) throw new Error("Hash instance has been destroyed"); if (checkFinished && instance.finished) throw new Error("Hash#digest() has already been called"); } function aoutput(out, instance) { abytes(out); const min = instance.outputLen; if (out.length < min) { throw new Error("digestInto() expects output buffer of length at least " + min); } } function clean(...arrays) { for (let i = 0; i < arrays.length; i++) { arrays[i].fill(0); } } function createView(arr) { return new DataView(arr.buffer, arr.byteOffset, arr.byteLength); } function rotr(word, shift) { return word << 32 - shift | word >>> shift; } function bytesToHex(bytes) { abytes(bytes); if (hasHexBuiltin) return bytes.toHex(); let hex = ""; for (let i = 0; i < bytes.length; i++) { hex += hexes[bytes[i]]; } return hex; } function asciiToBase16(ch) { if (ch >= asciis._0 && ch <= asciis._9) return ch - asciis._0; if (ch >= asciis.A && ch <= asciis.F) return ch - (asciis.A - 10); if (ch >= asciis.a && ch <= asciis.f) return ch - (asciis.a - 10); return; } function hexToBytes(hex) { if (typeof hex !== "string") throw new Error("hex string expected, got " + typeof hex); if (hasHexBuiltin) return Uint8Array.fromHex(hex); const hl = hex.length; const al = hl / 2; if (hl % 2) throw new Error("hex string expected, got unpadded hex of length " + hl); const array = new Uint8Array(al); for (let ai = 0, hi = 0; ai < al; ai++, hi += 2) { const n1 = asciiToBase16(hex.charCodeAt(hi)); const n2 = asciiToBase16(hex.charCodeAt(hi + 1)); if (n1 === void 0 || n2 === void 0) { const char = hex[hi] + hex[hi + 1]; throw new Error('hex string expected, got non-hex character "' + char + '" at index ' + hi); } array[ai] = n1 * 16 + n2; } return array; } function utf8ToBytes(str) { if (typeof str !== "string") throw new Error("string expected"); return new Uint8Array(new TextEncoder().encode(str)); } function toBytes(data) { if (typeof data === "string") data = utf8ToBytes(data); abytes(data); return data; } function concatBytes(...arrays) { let sum = 0; for (let i = 0; i < arrays.length; i++) { const a = arrays[i]; abytes(a); sum += a.length; } const res = new Uint8Array(sum); for (let i = 0, pad = 0; i < arrays.length; i++) { const a = arrays[i]; res.set(a, pad); pad += a.length; } return res; } function createHasher(hashCons) { const hashC = (msg) => hashCons().update(toBytes(msg)).digest(); const tmp = hashCons(); hashC.outputLen = tmp.outputLen; hashC.blockLen = tmp.blockLen; hashC.create = () => hashCons(); return hashC; } function randomBytes(bytesLength = 32) { if (crypto2 && typeof crypto2.getRandomValues === "function") { return crypto2.getRandomValues(new Uint8Array(bytesLength)); } if (crypto2 && typeof crypto2.randomBytes === "function") { return Uint8Array.from(crypto2.randomBytes(bytesLength)); } throw new Error("crypto.getRandomValues must be defined"); } function abool(title, value) { if (typeof value !== "boolean") throw new Error(title + " boolean expected, got " + value); } function numberToHexUnpadded(num) { const hex = num.toString(16); return hex.length & 1 ? "0" + hex : hex; } function hexToNumber(hex) { if (typeof hex !== "string") throw new Error("hex string expected, got " + typeof hex); return hex === "" ? _0n$3 : BigInt("0x" + hex); } function bytesToNumberBE(bytes) { return hexToNumber(bytesToHex(bytes)); } function bytesToNumberLE(bytes) { abytes(bytes); return hexToNumber(bytesToHex(Uint8Array.from(bytes).reverse())); } function numberToBytesBE(n, len) { return hexToBytes(n.toString(16).padStart(len * 2, "0")); } function numberToBytesLE(n, len) { return numberToBytesBE(n, len).reverse(); } function ensureBytes(title, hex, expectedLength) { let res; if (typeof hex === "string") { try { res = hexToBytes(hex); } catch (e) { throw new Error(title + " must be hex string or Uint8Array, cause: " + e); } } else if (isBytes(hex)) { res = Uint8Array.from(hex); } else { throw new Error(title + " must be hex string or Uint8Array"); } res.length; return res; } function inRange(n, min, max) { return isPosBig(n) && isPosBig(min) && isPosBig(max) && min <= n && n < max; } function aInRange(title, n, min, max) { if (!inRange(n, min, max)) throw new Error("expected valid " + title + ": " + min + " <= n < " + max + ", got " + n); } function bitLen(n) { let len; for (len = 0; n > _0n$3; n >>= _1n$3, len += 1) ; return len; } function createHmacDrbg(hashLen, qByteLen, hmacFn) { if (typeof hashLen !== "number" || hashLen < 2) throw new Error("hashLen must be a number"); if (typeof qByteLen !== "number" || qByteLen < 2) throw new Error("qByteLen must be a number"); if (typeof hmacFn !== "function") throw new Error("hmacFn must be a function"); const u8n = (len) => new Uint8Array(len); const u8of = (byte) => Uint8Array.of(byte); let v = u8n(hashLen); let k = u8n(hashLen); let i = 0; const reset = () => { v.fill(1); k.fill(0); i = 0; }; const h = (...b) => hmacFn(k, v, ...b); const reseed = (seed = u8n(0)) => { k = h(u8of(0), seed); v = h(); if (seed.length === 0) return; k = h(u8of(1), seed); v = h(); }; const gen = () => { if (i++ >= 1e3) throw new Error("drbg: tried 1000 values"); let len = 0; const out = []; while (len < qByteLen) { v = h(); const sl = v.slice(); out.push(sl); len += v.length; } return concatBytes(...out); }; const genUntil = (seed, pred) => { reset(); reseed(seed); let res = void 0; while (!(res = pred(gen()))) reseed(); reset(); return res; }; return genUntil; } function _validateObject(object, fields, optFields = {}) { if (!object || typeof object !== "object") throw new Error("expected valid options object"); function checkField(fieldName, expectedType, isOpt) { const val = object[fieldName]; if (isOpt && val === void 0) return; const current = typeof val; if (current !== expectedType || val === null) throw new Error(`param "${fieldName}" is invalid: expected ${expectedType}, got ${current}`); } Object.entries(fields).forEach(([k, v]) => checkField(k, v, false)); Object.entries(optFields).forEach(([k, v]) => checkField(k, v, true)); } function memoized(fn) { const map = /* @__PURE__ */ new WeakMap(); return (arg, ...args) => { const val = map.get(arg); if (val !== void 0) return val; const computed = fn(arg, ...args); map.set(arg, computed); return computed; }; } function mod(a, b) { const result = a % b; return result >= _0n$2 ? result : b + result; } function invert(number, modulo) { if (number === _0n$2) throw new Error("invert: expected non-zero number"); if (modulo <= _0n$2) throw new Error("invert: expected positive modulus, got " + modulo); let a = mod(number, modulo); let b = modulo; let x = _0n$2, u = _1n$2; while (a !== _0n$2) { const q = b / a; const r = b % a; const m = x - u * q; b = a, a = r, x = u, u = m; } const gcd = b; if (gcd !== _1n$2) throw new Error("invert: does not exist"); return mod(x, modulo); } function assertIsSquare(Fp, root, n) { if (!Fp.eql(Fp.sqr(root), n)) throw new Error("Cannot find square root"); } function sqrt3mod4(Fp, n) { const p1div4 = (Fp.ORDER + _1n$2) / _4n$1; const root = Fp.pow(n, p1div4); assertIsSquare(Fp, root, n); return root; } function sqrt5mod8(Fp, n) { const p5div8 = (Fp.ORDER - _5n) / _8n; const n2 = Fp.mul(n, _2n$1); const v = Fp.pow(n2, p5div8); const nv = Fp.mul(n, v); const i = Fp.mul(Fp.mul(nv, _2n$1), v); const root = Fp.mul(nv, Fp.sub(i, Fp.ONE)); assertIsSquare(Fp, root, n); return root; } function sqrt9mod16(P) { const Fp_ = Field(P); const tn = tonelliShanks(P); const c1 = tn(Fp_, Fp_.neg(Fp_.ONE)); const c2 = tn(Fp_, c1); const c3 = tn(Fp_, Fp_.neg(c1)); const c4 = (P + _7n) / _16n; return (Fp, n) => { let tv1 = Fp.pow(n, c4); let tv2 = Fp.mul(tv1, c1); const tv3 = Fp.mul(tv1, c2); const tv4 = Fp.mul(tv1, c3); const e1 = Fp.eql(Fp.sqr(tv2), n); const e2 = Fp.eql(Fp.sqr(tv3), n); tv1 = Fp.cmov(tv1, tv2, e1); tv2 = Fp.cmov(tv4, tv3, e2); const e3 = Fp.eql(Fp.sqr(tv2), n); const root = Fp.cmov(tv1, tv2, e3); assertIsSquare(Fp, root, n); return root; }; } function tonelliShanks(P) { if (P < _3n$1) throw new Error("sqrt is not defined for small field"); let Q = P - _1n$2; let S = 0; while (Q % _2n$1 === _0n$2) { Q /= _2n$1; S++; } let Z = _2n$1; const _Fp = Field(P); while (FpLegendre(_Fp, Z) === 1) { if (Z++ > 1e3) throw new Error("Cannot find square root: probably non-prime P"); } if (S === 1) return sqrt3mod4; let cc = _Fp.pow(Z, Q); const Q1div2 = (Q + _1n$2) / _2n$1; return function tonelliSlow(Fp, n) { if (Fp.is0(n)) return n; if (FpLegendre(Fp, n) !== 1) throw new Error("Cannot find square root"); let M = S; let c = Fp.mul(Fp.ONE, cc); let t = Fp.pow(n, Q); let R = Fp.pow(n, Q1div2); while (!Fp.eql(t, Fp.ONE)) { if (Fp.is0(t)) return Fp.ZERO; let i = 1; let t_tmp = Fp.sqr(t); while (!Fp.eql(t_tmp, Fp.ONE)) { i++; t_tmp = Fp.sqr(t_tmp); if (i === M) throw new Error("Cannot find square root"); } const exponent = _1n$2 << BigInt(M - i - 1); const b = Fp.pow(c, exponent); M = i; c = Fp.sqr(b); t = Fp.mul(t, c); R = Fp.mul(R, b); } return R; }; } function FpSqrt(P) { if (P % _4n$1 === _3n$1) return sqrt3mod4; if (P % _8n === _5n) return sqrt5mod8; if (P % _16n === _9n) return sqrt9mod16(P); return tonelliShanks(P); } function validateField(field) { const initial = { ORDER: "bigint", MASK: "bigint", BYTES: "number", BITS: "number" }; const opts = FIELD_FIELDS.reduce((map, val) => { map[val] = "function"; return map; }, initial); _validateObject(field, opts); return field; } function FpPow(Fp, num, power) { if (power < _0n$2) throw new Error("invalid exponent, negatives unsupported"); if (power === _0n$2) return Fp.ONE; if (power === _1n$2) return num; let p = Fp.ONE; let d = num; while (power > _0n$2) { if (power & _1n$2) p = Fp.mul(p, d); d = Fp.sqr(d); power >>= _1n$2; } return p; } function FpInvertBatch(Fp, nums, passZero = false) { const inverted = new Array(nums.length).fill(passZero ? Fp.ZERO : void 0); const multipliedAcc = nums.reduce((acc, num, i) => { if (Fp.is0(num)) return acc; inverted[i] = acc; return Fp.mul(acc, num); }, Fp.ONE); const invertedAcc = Fp.inv(multipliedAcc); nums.reduceRight((acc, num, i) => { if (Fp.is0(num)) return acc; inverted[i] = Fp.mul(acc, inverted[i]); return Fp.mul(acc, num); }, invertedAcc); return inverted; } function FpLegendre(Fp, n) { const p1mod2 = (Fp.ORDER - _1n$2) / _2n$1; const powered = Fp.pow(n, p1mod2); const yes = Fp.eql(powered, Fp.ONE); const zero = Fp.eql(powered, Fp.ZERO); const no = Fp.eql(powered, Fp.neg(Fp.ONE)); if (!yes && !zero && !no) throw new Error("invalid Legendre symbol result"); return yes ? 1 : zero ? 0 : -1; } function nLength(n, nBitLength) { if (nBitLength !== void 0) anumber(nBitLength); const _nBitLength = nBitLength !== void 0 ? nBitLength : n.toString(2).length; const nByteLength = Math.ceil(_nBitLength / 8); return { nBitLength: _nBitLength, nByteLength }; } function Field(ORDER, bitLenOrOpts, isLE = false, opts = {}) { if (ORDER <= _0n$2) throw new Error("invalid field: expected ORDER > 0, got " + ORDER); let _nbitLength = void 0; let _sqrt = void 0; let modOnDecode = false; let allowedLengths = void 0; if (typeof bitLenOrOpts === "object" && bitLenOrOpts != null) { if (opts.sqrt || isLE) throw new Error("cannot specify opts in two arguments"); const _opts = bitLenOrOpts; if (_opts.BITS) _nbitLength = _opts.BITS; if (_opts.sqrt) _sqrt = _opts.sqrt; if (typeof _opts.isLE === "boolean") isLE = _opts.isLE; if (typeof _opts.modOnDecode === "boolean") modOnDecode = _opts.modOnDecode; allowedLengths = _opts.allowedLengths; } else { if (typeof bitLenOrOpts === "number") _nbitLength = bitLenOrOpts; if (opts.sqrt) _sqrt = opts.sqrt; } const { nBitLength: BITS, nByteLength: BYTES } = nLength(ORDER, _nbitLength); if (BYTES > 2048) throw new Error("invalid field: expected ORDER of <= 2048 bytes"); let sqrtP; const f = Object.freeze({ ORDER, isLE, BITS, BYTES, MASK: bitMask(BITS), ZERO: _0n$2, ONE: _1n$2, allowedLengths, create: (num) => mod(num, ORDER), isValid: (num) => { if (typeof num !== "bigint") throw new Error("invalid field element: expected bigint, got " + typeof num); return _0n$2 <= num && num < ORDER; }, is0: (num) => num === _0n$2, // is valid and invertible isValidNot0: (num) => !f.is0(num) && f.isValid(num), isOdd: (num) => (num & _1n$2) === _1n$2, neg: (num) => mod(-num, ORDER), eql: (lhs, rhs) => lhs === rhs, sqr: (num) => mod(num * num, ORDER), add: (lhs, rhs) => mod(lhs + rhs, ORDER), sub: (lhs, rhs) => mod(lhs - rhs, ORDER), mul: (lhs, rhs) => mod(lhs * rhs, ORDER), pow: (num, power) => FpPow(f, num, power), div: (lhs, rhs) => mod(lhs * invert(rhs, ORDER), ORDER), // Same as above, but doesn't normalize sqrN: (num) => num * num, addN: (lhs, rhs) => lhs + rhs, subN: (lhs, rhs) => lhs - rhs, mulN: (lhs, rhs) => lhs * rhs, inv: (num) => invert(num, ORDER), sqrt: _sqrt || ((n) => { if (!sqrtP) sqrtP = FpSqrt(ORDER); return sqrtP(f, n); }), toBytes: (num) => isLE ? numberToBytesLE(num, BYTES) : numberToBytesBE(num, BYTES), fromBytes: (bytes, skipValidation = true) => { if (allowedLengths) { if (!allowedLengths.includes(bytes.length) || bytes.length > BYTES) { throw new Error("Field.fromBytes: expected " + allowedLengths + " bytes, got " + bytes.length); } const padded = new Uint8Array(BYTES); padded.set(bytes, isLE ? 0 : padded.length - bytes.length); bytes = padded; } if (bytes.length !== BYTES) throw new Error("Field.fromBytes: expected " + BYTES + " bytes, got " + bytes.length); let scalar = isLE ? bytesToNumberLE(bytes) : bytesToNumberBE(bytes); if (modOnDecode) scalar = mod(scalar, ORDER); if (!skipValidation) { if (!f.isValid(scalar)) throw new Error("invalid field element: outside of range 0..ORDER"); } return scalar; }, // TODO: we don't need it here, move out to separate fn invertBatch: (lst) => FpInvertBatch(f, lst), // We can't move this out because Fp6, Fp12 implement it // and it's unclear what to return in there. cmov: (a, b, c) => c ? b : a }); return Object.freeze(f); } function getFieldBytesLength(fieldOrder) { if (typeof fieldOrder !== "bigint") throw new Error("field order must be bigint"); const bitLength = fieldOrder.toString(2).length; return Math.ceil(bitLength / 8); } function getMinHashLength(fieldOrder) { const length = getFieldBytesLength(fieldOrder); return length + Math.ceil(length / 2); } function mapHashToField(key, fieldOrder, isLE = false) { const len = key.length; const fieldLen = getFieldBytesLength(fieldOrder); const minLen = getMinHashLength(fieldOrder); if (len < 16 || len < minLen || len > 1024) throw new Error("expected " + minLen + "-1024 bytes of input, got " + len); const num = isLE ? bytesToNumberLE(key) : bytesToNumberBE(key); const reduced = mod(num, fieldOrder - _1n$2) + _1n$2; return isLE ? numberToBytesLE(reduced, fieldLen) : numberToBytesBE(reduced, fieldLen); } function setBigUint64(view, byteOffset, value, isLE) { if (typeof view.setBigUint64 === "function") return view.setBigUint64(byteOffset, value, isLE); const _32n2 = BigInt(32); const _u32_max = BigInt(4294967295); const wh = Number(value >> _32n2 & _u32_max); const wl = Number(value & _u32_max); const h = isLE ? 4 : 0; const l = isLE ? 0 : 4; view.setUint32(byteOffset + h, wh, isLE); view.setUint32(byteOffset + l, wl, isLE); } function Chi(a, b, c) { return a & b ^ ~a & c; } function Maj(a, b, c) { return a & b ^ a & c ^ b & c; } function fromBig(n, le = false) { if (le) return { h: Number(n & U32_MASK64), l: Number(n >> _32n & U32_MASK64) }; return { h: Number(n >> _32n & U32_MASK64) | 0, l: Number(n & U32_MASK64) | 0 }; } function split(lst, le = false) { const len = lst.length; let Ah = new Uint32Array(len); let Al = new Uint32Array(len); for (let i = 0; i < len; i++) { const { h, l } = fromBig(lst[i], le); [Ah[i], Al[i]] = [h, l]; } return [Ah, Al]; } function add(Ah, Al, Bh, Bl) { const l = (Al >>> 0) + (Bl >>> 0); return { h: Ah + Bh + (l / 2 ** 32 | 0) | 0, l: l | 0 }; } function negateCt(condition, item) { const neg = item.negate(); return condition ? neg : item; } function normalizeZ(c, points) { const invertedZs = FpInvertBatch(c.Fp, points.map((p) => p.Z)); return points.map((p, i) => c.fromAffine(p.toAffine(invertedZs[i]))); } function validateW(W, bits) { if (!Number.isSafeInteger(W) || W <= 0 || W > bits) throw new Error("invalid window size, expected [1.." + bits + "], got W=" + W); } function calcWOpts(W, scalarBits) { validateW(W, scalarBits); const windows = Math.ceil(scalarBits / W) + 1; const windowSize = 2 ** (W - 1); const maxNumber = 2 ** W; const mask = bitMask(W); const shiftBy = BigInt(W); return { windows, windowSize, mask, maxNumber, shiftBy }; } function calcOffsets(n, window2, wOpts) { const { windowSize, mask, maxNumber, shiftBy } = wOpts; let wbits = Number(n & mask); let nextN = n >> shiftBy; if (wbits > windowSize) { wbits -= maxNumber; nextN += _1n$1; } const offsetStart = window2 * windowSize; const offset = offsetStart + Math.abs(wbits) - 1; const isZero = wbits === 0; const isNeg = wbits < 0; const isNegF = window2 % 2 !== 0; const offsetF = offsetStart; return { nextN, offset, isZero, isNeg, isNegF, offsetF }; } function validateMSMPoints(points, c) { if (!Array.isArray(points)) throw new Error("array expected"); points.forEach((p, i) => { if (!(p instanceof c)) throw new Error("invalid point at index " + i); }); } function validateMSMScalars(scalars, field) { if (!Array.isArray(scalars)) throw new Error("array of scalars expected"); scalars.forEach((s, i) => { if (!field.isValid(s)) throw new Error("invalid scalar at index " + i); }); } function getW(P) { return pointWindowSizes.get(P) || 1; } function assert0(n) { if (n !== _0n$1) throw new Error("invalid wNAF"); } function mulEndoUnsafe(Point, point, k1, k2) { let acc = point; let p1 = Point.ZERO; let p2 = Point.ZERO; while (k1 > _0n$1 || k2 > _0n$1) { if (k1 & _1n$1) p1 = p1.add(acc); if (k2 & _1n$1) p2 = p2.add(acc); acc = acc.double(); k1 >>= _1n$1; k2 >>= _1n$1; } return { p1, p2 }; } function pippenger(c, fieldN, points, scalars) { validateMSMPoints(points, c); validateMSMScalars(scalars, fieldN); const plength = points.length; const slength = scalars.length; if (plength !== slength) throw new Error("arrays of points and scalars must have equal length"); const zero = c.ZERO; const wbits = bitLen(BigInt(plength)); let windowSize = 1; if (wbits > 12) windowSize = wbits - 3; else if (wbits > 4) windowSize = wbits - 2; else if (wbits > 0) windowSize = 2; const MASK = bitMask(windowSize); const buckets = new Array(Number(MASK) + 1).fill(zero); const lastBits = Math.floor((fieldN.BITS - 1) / windowSize) * windowSize; let sum = zero; for (let i = lastBits; i >= 0; i -= windowSize) { buckets.fill(zero); for (let j = 0; j < slength; j++) { const scalar = scalars[j]; const wbits2 = Number(scalar >> BigInt(i) & MASK); buckets[wbits2] = buckets[wbits2].add(points[j]); } let resI = zero; for (let j = buckets.length - 1, sumI = zero; j > 0; j--) { sumI = sumI.add(buckets[j]); resI = resI.add(sumI); } sum = sum.add(resI); if (i !== 0) for (let j = 0; j < windowSize; j++) sum = sum.double(); } return sum; } function createField(order, field) { if (field) { if (field.ORDER !== order) throw new Error("Field.ORDER must match order: Fp == p, Fn == n"); validateField(field); return field; } else { return Field(order); } } function _createCurveFields(type, CURVE, curveOpts = {}) { if (!CURVE || typeof CURVE !== "object") throw new Error(`expected valid ${type} CURVE object`); for (const p of ["p", "n", "h"]) { const val = CURVE[p]; if (!(typeof val === "bigint" && val > _0n$1)) throw new Error(`CURVE.${p} must be positive bigint`); } const Fp = createField(CURVE.p, curveOpts.Fp); const Fn = createField(CURVE.n, curveOpts.Fn); const _b = "b"; const params = ["Gx", "Gy", "a", _b]; for (const p of params) { if (!Fp.isValid(CURVE[p])) throw new Error(`CURVE.${p} must be valid field element of CURVE.Fp`); } return { Fp, Fn }; } function _splitEndoScalar(k, basis, n) { const [[a1, b1], [a2, b2]] = basis; const c1 = divNearest(b2 * k, n); const c2 = divNearest(-b1 * k, n); let k1 = k - c1 * a1 - c2 * a2; let k2 = -c1 * b1 - c2 * b2; const k1neg = k1 < _0n; const k2neg = k2 < _0n; if (k1neg) k1 = -k1; if (k2neg) k2 = -k2; const MAX_NUM = bitMask(Math.ceil(bitLen(n) / 2)) + _1n; if (k1 < _0n || k1 >= MAX_NUM || k2 < _0n || k2 >= MAX_NUM) { throw new Error("splitScalar (endomorphism): failed, k=" + k); } return { k1neg, k1, k2neg, k2 }; } function validateSigVerOpts(opts) { if (opts.lowS !== void 0) abool("lowS", opts.lowS); if (opts.prehash !== void 0) abool("prehash", opts.prehash); } function _legacyHelperEquat(Fp, a, b) { function weierstrassEquation(x) { const x2 = Fp.sqr(x); const x3 = Fp.mul(x2, x); return Fp.add(Fp.add(x3, Fp.mul(x, a)), b); } return weierstrassEquation; } function _normFnElement(Fn, key) { const { BYTES: expected } = Fn; let num; if (typeof key === "bigint") { num = key; } else { let bytes = ensureBytes("private key", key); try { num = Fn.fromBytes(bytes); } catch (error) { throw new Error(`invalid private key: expected ui8a of size ${expected}, got ${typeof key}`); } } if (!Fn.isValidNot0(num)) throw new Error("invalid private key: out of range [1..N-1]"); return num; } function weierstrassN(CURVE, curveOpts = {}) { const { Fp, Fn } = _createCurveFields("weierstrass", CURVE, curveOpts); const { h: cofactor, n: CURVE_ORDER } = CURVE; _validateObject(curveOpts, {}, { allowInfinityPoint: "boolean", clearCofactor: "function", isTorsionFree: "function", fromBytes: "function", toBytes: "function", endo: "object", wrapPrivateKey: "boolean" }); const { endo } = curveOpts; if (endo) { if (!Fp.is0(CURVE.a) || typeof endo.beta !== "bigint" || !Array.isArray(endo.basises)) { throw new Error('invalid endo: expected "beta": bigint and "basises": array'); } } function assertCompressionIsSupported() { if (!Fp.isOdd) throw new Error("compression is not supported: Field does not have .isOdd()"); } function pointToBytes(_c, point, isCompressed) { const { x, y } = point.toAffine(); const bx = Fp.toBytes(x); abool("isCompressed", isCompressed); if (isCompressed) { assertCompressionIsSupported(); const hasEvenY = !Fp.isOdd(y); return concatBytes(pprefix(hasEvenY), bx); } else { return concatBytes(Uint8Array.of(4), bx, Fp.toBytes(y)); } } function pointFromBytes(bytes) { abytes(bytes); const L = Fp.BYTES; const LC = L + 1; const LU = 2 * L + 1; const length = bytes.length; const head = bytes[0]; const tail = bytes.subarray(1); if (length === LC && (head === 2 || head === 3)) { const x = Fp.fromBytes(tail); if (!Fp.isValid(x)) throw new Error("bad point: is not on curve, wrong x"); const y2 = weierstrassEquation(x); let y; try { y = Fp.sqrt(y2); } catch (sqrtError) { const err = sqrtError instanceof Error ? ": " + sqrtError.message : ""; throw new Error("bad point: is not on curve, sqrt error" + err); } assertCompressionIsSupported(); const isYOdd = Fp.isOdd(y); const isHeadOdd = (head & 1) === 1; if (isHeadOdd !== isYOdd) y = Fp.neg(y); return { x, y }; } else if (length === LU && head === 4) { const x = Fp.fromBytes(tail.subarray(L * 0, L * 1)); const y = Fp.fromBytes(tail.subarray(L * 1, L * 2)); if (!isValidXY(x, y)) throw new Error("bad point: is not on curve"); return { x, y }; } else { throw new Error(`bad point: got length ${length}, expected compressed=${LC} or uncompressed=${LU}`); } } const toBytes2 = curveOpts.toBytes || pointToBytes; const fromBytes = curveOpts.fromBytes || pointFromBytes; const weierstrassEquation = _legacyHelperEquat(Fp, CURVE.a, CURVE.b); function isValidXY(x, y) { const left = Fp.sqr(y); const right = weierstrassEquation(x); return Fp.eql(left, right); } if (!isValidXY(CURVE.Gx, CURVE.Gy)) throw new Error("bad curve params: generator point"); const _4a3 = Fp.mul(Fp.pow(CURVE.a, _3n), _4n); const _27b2 = Fp.mul(Fp.sqr(CURVE.b), BigInt(27)); if (Fp.is0(Fp.add(_4a3, _27b2))) throw new Error("bad curve params: a or b"); function acoord(title, n, banZero = false) { if (!Fp.isValid(n) || banZero && Fp.is0(n)) throw new Error(`bad point coordinate ${title}`); return n; } function aprjpoint(other) { if (!(other instanceof Point)) throw new Error("ProjectivePoint expected"); } function splitEndoScalarN(k) { if (!endo || !endo.basises) throw new Error("no endo"); return _splitEndoScalar(k, endo.basises, Fn.ORDER); } const toAffineMemo = memoized((p, iz) => { const { X, Y, Z } = p; if (Fp.eql(Z, Fp.ONE)) return { x: X, y: Y }; const is0 = p.is0(); if (iz == null) iz = is0 ? Fp.ONE : Fp.inv(Z); const x = Fp.mul(X, iz); const y = Fp.mul(Y, iz); const zz = Fp.mul(Z, iz); if (is0) return { x: Fp.ZERO, y: Fp.ZERO }; if (!Fp.eql(zz, Fp.ONE)) throw new Error("invZ was invalid"); return { x, y }; }); const assertValidMemo = memoized((p) => { if (p.is0()) { if (curveOpts.allowInfinityPoint && !Fp.is0(p.Y)) return; throw new Error("bad point: ZERO"); } const { x, y } = p.toAffine(); if (!Fp.isValid(x) || !Fp.isValid(y)) throw new Error("bad point: x or y not field elements"); if (!isValidXY(x, y)) throw new Error("bad point: equation left != right"); if (!p.isTorsionFree()) throw new Error("bad point: not in prime-order subgroup"); return true; }); function finishEndo(endoBeta, k1p, k2p, k1neg, k2neg) { k2p = new Point(Fp.mul(k2p.X, endoBeta), k2p.Y, k2p.Z); k1p = negateCt(k1neg, k1p); k2p = negateCt(k2neg, k2p); return k1p.add(k2p); } class Point { /** Does NOT validate if the point is valid. Use `.assertValidity()`. */ constructor(X, Y, Z) { this.X = acoord("x", X); this.Y = acoord("y", Y, true); this.Z = acoord("z", Z); Object.freeze(this); } /** Does NOT validate if the point is valid. Use `.assertValidity()`. */ static fromAffine(p) { const { x, y } = p || {}; if (!p || !Fp.isValid(x) || !Fp.isValid(y)) throw new Error("invalid affine point"); if (p instanceof Point) throw new Error("projective point not allowed"); if (Fp.is0(x) && Fp.is0(y)) return Point.ZERO; return new Point(x, y, Fp.ONE); } get x() { return this.toAffine().x; } get y() { return this.toAffine().y; } // TODO: remove get px() { return this.X; } get py() { return this.X; } get pz() { return this.Z; } static normalizeZ(points) { return normalizeZ(Point, points); } static fromBytes(bytes) { abytes(bytes); return Point.fromHex(bytes); } /** Converts hash string or Uint8Array to Point. */ static fromHex(hex) { const P = Point.fromAffine(fromBytes(ensureBytes("pointHex", hex))); P.assertValidity(); return P; } /** Multiplies generator point by privateKey. */ static fromPrivateKey(privateKey) { return Point.BASE.multiply(_normFnElement(Fn, privateKey)); } // TODO: remove static msm(points, scalars) { return pippenger(Point, Fn, points, scalars); } _setWindowSize(windowSize) { this.precompute(windowSize); } /** * * @param windowSize * @param isLazy true will defer table computation until the first multiplication * @returns */ precompute(windowSize = 8, isLazy = true) { wnaf.createCache(this, windowSize); if (!isLazy) this.multiply(_3n); return this; } // TODO: return `this` /** A point on curve is valid if it conforms to equation. */ assertValidity() { assertValidMemo(this); } hasEvenY() { const { y } = this.toAffine(); if (!Fp.isOdd) throw new Error("Field doesn't support isOdd"); return !Fp.isOdd(y); } /** Compare one point to another. */ equals(other) { aprjpoint(other); const { X: X1, Y: Y1, Z: Z1 } = this; const { X: X2, Y: Y2, Z: Z2 } = other; const U1 = Fp.eql(Fp.mul(X1, Z2), Fp.mul(X2, Z1)); const U2 = Fp.eql(Fp.mul(Y1, Z2), Fp.mul(Y2, Z1)); return U1 && U2; } /** Flips point to one corresponding to (x, -y) in Affine coordinates. */ negate() { return new Point(this.X, Fp.neg(this.Y), this.Z); } // Renes-Costello-Batina exception-free doubling formula. // There is 30% faster Jacobian formula, but it is not complete. // https://eprint.iacr.org/2015/1060, algorithm 3 // Cost: 8M + 3S + 3*a + 2*b3 + 15add. double() { const { a, b } = CURVE; const b3 = Fp.mul(b, _3n); const { X: X1, Y: Y1, Z: Z1 } = this; let X3 = Fp.ZERO, Y3 = Fp.ZERO, Z3 = Fp.ZERO; let t0 = Fp.mul(X1, X1); let t1 = Fp.mul(Y1, Y1); let t2 = Fp.mul(Z1, Z1); let t3 = Fp.mul(X1, Y1); t3 = Fp.add(t3, t3); Z3 = Fp.mul(X1, Z1); Z3 = Fp.add(Z3, Z3); X3 = Fp.mul(a, Z3); Y3 = Fp.mul(b3, t2); Y3 = Fp.add(X3, Y3); X3 = Fp.sub(t1, Y3); Y3 = Fp.add(t1, Y3); Y3 = Fp.mul(X3, Y3); X3 = Fp.mul(t3, X3); Z3 = Fp.mul(b3, Z3); t2 = Fp.mul(a, t2); t3 = Fp.sub(t0, t2); t3 = Fp.mul(a, t3); t3 = Fp.add(t3, Z3); Z3 = Fp.add(t0, t0); t0 = Fp.add(Z3, t0); t0 = Fp.add(t0, t2); t0 = Fp.mul(t0, t3); Y3 = Fp.add(Y3, t0); t2 = Fp.mul(Y1, Z1); t2 = Fp.add(t2, t2); t0 = Fp.mul(t2, t3); X3 = Fp.sub(X3, t0); Z3 = Fp.mul(t2, t1); Z3 = Fp.add(Z3, Z3); Z3 = Fp.add(Z3, Z3); return new Point(X3, Y3, Z3); } // Renes-Costello-Batina exception-free addition formula. // There is 30% faster Jacobian formula, but it is not complete. // https://eprint.iacr.org/2015/1060, algorithm 1 // Cost: 12M + 0S + 3*a + 3*b3 + 23add. add(other) { aprjpoint(other); const { X: X1, Y: Y1, Z: Z1 } = this; const { X: X2, Y: Y2, Z: Z2 } = other; let X3 = Fp.ZERO, Y3 = Fp.ZERO, Z3 = Fp.ZERO; const a = CURVE.a; const b3 = Fp.mul(CURVE.b, _3n); let t0 = Fp.mul(X1, X2); let t1 = Fp.mul(Y1, Y2); let t2 = Fp.mul(Z1, Z2); let t3 = Fp.add(X1, Y1); let t4 = Fp.add(X2, Y2); t3 = Fp.mul(t3, t4); t4 = Fp.add(t0, t1); t3 = Fp.sub(t3, t4); t4 = Fp.add(X1, Z1); let t5 = Fp.add(X2, Z2); t4 = Fp.mul(t4, t5); t5 = Fp.add(t0, t2); t4 = Fp.sub(t4, t5); t5 = Fp.add(Y1, Z1); X3 = Fp.add(Y2, Z2); t5 = Fp.mul(t5, X3); X3 = Fp.add(t1, t2); t5 = Fp.sub(t5, X3); Z3 = Fp.mul(a, t4); X3 = Fp.mul(b3, t2); Z3 = Fp.add(X3, Z3); X3 = Fp.sub(t1, Z3); Z3 = Fp.add(t1, Z3); Y3 = Fp.mul(X3, Z3); t1 = Fp.add(t0, t0); t1 = Fp.add(t1, t0); t2 = Fp.mul(a, t2); t4 = Fp.mul(b3, t4); t1 = Fp.add(t1, t2); t2 = Fp.sub(t0, t2); t2 = Fp.mul(a, t2); t4 = Fp.add(t4, t2); t0 = Fp.mul(t1, t4); Y3 = Fp.add(Y3, t0); t0 = Fp.mul(t5, t4); X3 = Fp.mul(t3, X3); X3 = Fp.sub(X3, t0); t0 = Fp.mul(t3, t1); Z3 = Fp.mul(t5, Z3); Z3 = Fp.add(Z3, t0); return new Point(X3, Y3, Z3); } subtract(other) { return this.add(other.negate()); } is0() { return this.equals(Point.ZERO); } /** * Constant time multiplication. * Uses wNAF method. Windowed method may be 10% faster, * but takes 2x longer to generate and consumes 2x memory. * Uses precomputes when available. * Uses endomorphism for Koblitz curves. * @param scalar by which the point would be multiplied * @returns New point */ multiply(scalar) { const { endo: endo2 } = curveOpts; if (!Fn.isValidNot0(scalar)) throw new Error("invalid scalar: out of range"); let point, fake; const mul = (n) => wnaf.cached(this, n, (p) => normalizeZ(Point, p)); if (endo2) { const { k1neg, k1, k2neg, k2 } = splitEndoScalarN(scalar); const { p: k1p, f: k1f } = mul(k1); const { p: k2p, f: k2f } = mul(k2); fake = k1f.add(k2f); point = finishEndo(endo2.beta, k1p, k2p, k1neg, k2neg); } else { const { p, f } = mul(scalar); point = p; fake = f; } return normalizeZ(Point, [point, fake])[0]; } /** * Non-constant-time multiplication. Uses double-and-add algorithm. * It's faster, but should only be used when you don't care about * an exposed secret key e.g. sig verification, which works over *public* keys. */ multiplyUnsafe(sc) { const { endo: endo2 } = curveOpts; const p = this; if (!Fn.isValid(sc)) throw new Error("invalid scalar: out of range"); if (sc === _0n || p.is0()) return Point.ZERO; if (sc === _1n) return p; if (wnaf.hasCache(this)) return this.multiply(sc); if (endo2) { const { k1neg, k1, k2neg, k2 } = splitEndoScalarN(sc); const { p1, p2 } = mulEndoUnsafe(Point, p, k1, k2); return finishEndo(endo2.beta, p1, p2, k1neg, k2neg); } else { return wnaf.unsafe(p, sc); } } multiplyAndAddUnsafe(Q, a, b) { const sum = this.multiplyUnsafe(a).add(Q.multiplyUnsafe(b)); return sum.is0() ? void 0 : sum; } /** * Converts Projective point to affine (x, y) coordinates. * @param invertedZ Z^-1 (inverted zero) - optional, precomputation is useful for invertBatch */ toAffine(invertedZ) { return toAffineMemo(this, invertedZ); } /** * Checks whether Point is free of torsion elements (is in prime subgroup). * Always torsion-free for cofactor=1 curves. */ isTorsionFree() { const { isTorsionFree } = curveOpts; if (cofactor === _1n) return true; if (isTorsionFree) return isTorsionFree(Point, this); return wnaf.unsafe(this, CURVE_ORDER).is0(); } clearCofactor() { const { clearCofactor } = curveOpts; if (cofactor === _1n) return this; if (clearCofactor) return clearCofactor(Point, this); return this.multiplyUnsafe(cofactor); } isSmallOrder() { return this.multiplyUnsafe(cofactor).is0(); } toBytes(isCompressed = true) { abool("isCompressed", isCompressed); this.assertValidity(); return toBytes2(Point, this, isCompressed); } /** @deprecated use `toBytes` */ toRawBytes(isCompressed = true) { return this.toBytes(isCompressed); } toHex(isCompressed = true) { return bytesToHex(this.toBytes(isCompressed)); } toString() { return `<Point ${this.is0() ? "ZERO" : this.toHex()}>`; } } Point.BASE = new Point(CURVE.Gx, CURVE.Gy, Fp.ONE); Point.ZERO = new Point(Fp.ZERO, Fp.ONE, Fp.ZERO); Point.Fp = Fp; Point.Fn = Fn; const bits = Fn.BITS; const wnaf = new wNAF(Point, curveOpts.endo ? Math.ceil(bits / 2) : bits); return Point; } function pprefix(hasEvenY) { return Uint8Array.of(hasEvenY ? 2 : 3); } function ecdsa(Point, hash, ecdsaOpts = {}) { ahash(hash); _validateObject(ecdsaOpts, {}, { hmac: "function", lowS: "boolean", randomBytes: "function", bits2int: "function", bits2int_modN: "function" }); const randomBytes_ = ecdsaOpts.randomBytes || randomBytes; const hmac_ = ecdsaOpts.hmac || ((key, ...msgs) => hmac(hash, key, concatBytes(...msgs))); const { Fp, Fn } = Point; const { ORDER: CURVE_ORDER, BITS: fnBits } = Fn; const seedLen = getMinHashLength(CURVE_ORDER); const lengths = { secret: Fn.BYTES, public: 1 + Fp.BYTES, publicUncompressed: 1 + 2 * Fp.BYTES, signature: 2 * Fn.BYTES, seed: seedLen }; function isBiggerThanHalfOrder(number) { const HALF = CURVE_ORDER >> _1n; return number > HALF; } function normalizeS(s) { return isBiggerThanHalfOrder(s) ? Fn.neg(s) : s; } function aValidRS(title, num) { if (!Fn.isValidNot0(num)) throw new Error(`invalid signature ${title}: out of range 1..CURVE.n`); } class Signature { constructor(r, s, recovery) { aValidRS("r", r); aValidRS("s", s); this.r = r; this.s = s; if (recovery != null) this.recovery = recovery; Object.freeze(this); } static fromBytes(bytes, format = "compact") { if (format === "compact") { const L = Fn.BYTES; abytes(bytes, L * 2); const r = bytes.subarray(0, L); const s = bytes.subarray(L, L * 2); return new Signature(Fn.fromBytes(r), Fn.fromBytes(s)); } if (format === "der") { abytes(bytes); const { r, s } = DER.toSig(bytes); return new Signature(r, s); } throw new Error("invalid format"); } static fromHex(hex, format) { return this.fromBytes(hexToBytes(hex), format); } addRecoveryBit(recovery) { return new Signature(this.r, this.s, recovery); } // ProjPointType<bigint> recoverPublicKey(msgHash) { const FIELD_ORDER = Fp.ORDER; const { r, s, recovery: rec } = this; if (rec == null || ![0, 1, 2, 3].includes(rec)) throw new Error("recovery id invalid"); const hasCofactor = CURVE_ORDER * _2n < FIELD_ORDER; if (hasCofactor && rec > 1) throw new Error("recovery id is ambiguous for h>1 curve"); const radj = rec === 2 || rec === 3 ? r + CURVE_ORDER : r; if (!Fp.isValid(radj)) throw new Error("recovery id 2 or 3 invalid"); const x = Fp.toBytes(radj); const R = Point.fromHex(concatBytes(pprefix((rec & 1) === 0), x)); const ir = Fn.inv(radj); const h = bits2int_modN(ensureBytes("msgHash", msgHash)); const u1 = Fn.create(-h * ir); const u2 = Fn.create(s * ir); const Q = Point.BASE.multiplyUnsafe(u1).add(R.multiplyUnsafe(u2)); if (Q.is0()) throw new Error("point at infinify"); Q.assertValidity(); return Q; } // Signatures should be low-s, to prevent malleability. hasHighS() { return isBiggerThanHalfOrder(this.s); } normalizeS() { return this.hasHighS() ? new Signature(this.r, Fn.neg(this.s), this.recovery) : this; } toBytes(format = "compact") { if (format === "compact") return concatBytes(Fn.toBytes(this.r), Fn.toBytes(this.s)); if (format === "der") return hexToBytes(DER.hexFromSig(this)); throw new Error("invalid format"); } toHex(format) { return bytesToHex(this.toBytes(format)); } // TODO: remove assertValidity() { } static fromCompact(hex) { return Signature.fromBytes(ensureBytes("sig", hex), "compact"); } static fromDER(hex) { return Signature.fromBytes(ensureBytes("sig", hex), "der"); } toDERRawBytes() { return this.toBytes("der"); } toDERHex() { return bytesToHex(this.toBytes("der")); } toCompactRawBytes() { return this.toBytes("compact"); } toCompactHex() { return bytesToHex(this.toBytes("compact")); } } function isValidSecretKey(privateKey) { try { return !!_normFnElement(Fn, privateKey); } catch (error) { return false; } } function isValidPublicKey(publicKey, isCompressed) { try { const l = publicKey.length; if (isCompressed === true && l !== lengths.public) return false; if (isCompressed === false && l !== lengths.publicUncompressed) return false; return !!Point.fromBytes(publicKey); } catch (error) { return false; } } function randomSecretKey(seed = randomBytes_(seedLen)) { return mapHashToField(seed, CURVE_ORDER); } const utils = { isValidSecretKey, isValidPublicKey, randomSecretKey, // TODO: remove isValidPrivateKey: isValidSecretKey, randomPrivateKey: randomSecretKey, normPrivateKeyToScalar: (key) => _normFnElement(Fn, key), precompute(windowSize = 8, point = Point.BASE) { return point.precompute(windowSize, false); } }; function getPublicKey(secretKey, isCompressed = true) { return Point.BASE.multiply(_normFnElement(Fn, secretKey)).toBytes(isCompressed); } function isProbPub(item) { if (typeof item === "bigint") return false; if (item instanceof Point) return true; if (Fn.allowedLengths || lengths.secret === lengths.public) return void 0; const l = ensureBytes("key", item).length; return l === lengths.public || l === lengths.publicUncompressed; } function getSharedSecret(secretKeyA, publicKeyB, isCompressed = true) { if (isProbPub(sec