UNPKG

js-ecutils

Version:

JavaScript Library for Elliptic Curve Cryptography: key exchanges (Diffie-Hellman, Massey-Omura), ECDSA signatures, and Koblitz encoding. Suitable for crypto education and secure systems.

191 lines (186 loc) 24.5 kB
"use strict"; function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); } Object.defineProperty(exports, "__esModule", { value: true }); exports.JacobianPoint = void 0; exports.jacAdd = jacAdd; exports.jacDouble = jacDouble; exports.jacMul = jacMul; exports.toAffine = toAffine; exports.toJacobian = toJacobian; var _math = require("../../utils/math.js"); function _defineProperties(e, r) { for (var t = 0; t < r.length; t++) { var o = r[t]; o.enumerable = o.enumerable || !1, o.configurable = !0, "value" in o && (o.writable = !0), Object.defineProperty(e, _toPropertyKey(o.key), o); } } function _createClass(e, r, t) { return r && _defineProperties(e.prototype, r), t && _defineProperties(e, t), Object.defineProperty(e, "prototype", { writable: !1 }), e; } function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : i + ""; } function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); } function _classCallCheck(a, n) { if (!(a instanceof n)) throw new TypeError("Cannot call a class as a function"); } /** * Elliptic curve arithmetic in Jacobian (projective) coordinates. * * In Jacobian coordinates a point is represented as (X, Y, Z) where the * affine equivalents are x = X/Z² and y = Y/Z³. The identity (point at * infinity) is represented by x = null, y = null. * * The key advantage over affine arithmetic is that point addition and * doubling can be performed WITHOUT modular inversions (only * multiplications and squarings), making scalar multiplication roughly * 3x faster for large scalars. * * Trade-off: each point uses three coordinates instead of two, and a * single inversion is needed at the end to convert back to affine form. * * See RFC 6090, Section 4 for a detailed treatment of projective * coordinate systems and their security considerations. */ /** * A point in Jacobian projective coordinates (X, Y, Z). * * The affine point (x, y) corresponds to (X/Z², Y/Z³). * The identity element is represented by x = null, y = null. */ var JacobianPoint = exports.JacobianPoint = /*#__PURE__*/_createClass(function JacobianPoint() { var x = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null; var y = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null; var z = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 1n; _classCallCheck(this, JacobianPoint); this.x = x; this.y = y; this.z = z; Object.freeze(this); }); /** * Convert an affine Point to Jacobian coordinates. * * The affine point (x, y) maps to (x, y, 1) in Jacobian form. * The identity point maps to JacobianPoint(null, null, 1). * * @param {Point} point - An affine Point. * @returns {JacobianPoint} */ function toJacobian(point) { if (point.isIdentity) { return new JacobianPoint(); } return new JacobianPoint(point.x, point.y, 1n); } /** * Convert a JacobianPoint back to affine (x, y) coordinates. * * x = X · Z⁻² (mod p) * y = Y · Z⁻³ (mod p) * * @param {JacobianPoint} jp * @param {CurveParams} curve * @returns {[BigInt|null, BigInt|null]} */ function toAffine(jp, curve) { if (jp.x === null || jp.y === null || jp.z === 0n) { return [null, null]; } var invZ = (0, _math.modInverse)(jp.z, curve.p); var invZ2 = invZ * invZ % curve.p; var invZ3 = invZ2 * invZ % curve.p; return [(0, _math.modulus)(jp.x * invZ2, curve.p), (0, _math.modulus)(jp.y * invZ3, curve.p)]; } /** * Double a point in Jacobian coordinates. * * Uses the standard Jacobian doubling formulas (see RFC 6090 Section 4): * * S = 4 · X · Y² * M = 3 · X² + a · Z⁴ * X' = M² - 2·S * Y' = M · (S - X') - 8·Y⁴ * Z' = 2 · Y · Z * * Cost: 1S + 4M (no field inversions). * * @param {JacobianPoint} jp * @param {CurveParams} curve * @returns {JacobianPoint} */ function jacDouble(jp, curve) { if (jp.x === null || jp.y === null || jp.y === 0n) { return new JacobianPoint(); } var p = curve.p; var ysq = (0, _math.modulus)(jp.y * jp.y, p); var zsqr = (0, _math.modulus)(jp.z * jp.z, p); var s = (0, _math.modulus)(4n * jp.x * ysq, p); var m = (0, _math.modulus)(3n * jp.x * jp.x + curve.a * zsqr * zsqr, p); var nx = (0, _math.modulus)(m * m - 2n * s, p); var ny = (0, _math.modulus)(m * (s - nx) - 8n * ysq * ysq, p); var nz = (0, _math.modulus)(2n * jp.y * jp.z, p); return new JacobianPoint(nx, ny, nz); } /** * Add two points in Jacobian coordinates. * * Uses the standard Jacobian addition formulas (see RFC 6090 Section 4): * * U₁ = X₁ · Z₂², U₂ = X₂ · Z₁² * S₁ = Y₁ · Z₂³, S₂ = Y₂ · Z₁³ * H = U₂ - U₁, R = 2 · (S₂ - S₁) * X' = R² - H³ - 2 · U₁ · H² * Y' = R · (U₁ · H² - X') - 2 · S₁ · H³ * Z' = ((Z₁ + Z₂)² - Z₁² - Z₂²) · H * * If U₁ = U₂ and S₁ ≠ S₂ the points are inverses → identity. * If U₁ = U₂ and S₁ = S₂ the points are equal → delegates to jacDouble. * * @param {JacobianPoint} jp1 * @param {JacobianPoint} jp2 * @param {CurveParams} curve * @returns {JacobianPoint} */ function jacAdd(jp1, jp2, curve) { if (jp1.x === null || jp1.y === null) return jp2; if (jp2.x === null || jp2.y === null) return jp1; var p = curve.p; var z1z1 = (0, _math.modulus)(jp1.z * jp1.z, p); var z2z2 = (0, _math.modulus)(jp2.z * jp2.z, p); var u1 = (0, _math.modulus)(jp1.x * z2z2, p); var u2 = (0, _math.modulus)(jp2.x * z1z1, p); var s1 = (0, _math.modulus)(jp1.y * jp2.z * z2z2, p); var s2 = (0, _math.modulus)(jp2.y * jp1.z * z1z1, p); if (u1 === u2) { if (s1 !== s2) return new JacobianPoint(); return jacDouble(jp1, curve); } var h = u2 - u1; var i = (0, _math.modulus)(2n * h * (2n * h), p); var j = (0, _math.modulus)(h * i, p); var r = (0, _math.modulus)(2n * (s2 - s1), p); var v = (0, _math.modulus)(u1 * i, p); var x = (0, _math.modulus)(r * r - j - 2n * v, p); var y = (0, _math.modulus)(r * (v - x) - 2n * s1 * j, p); var z = (0, _math.modulus)(((jp1.z + jp2.z) * (jp1.z + jp2.z) - z1z1 - z2z2) * h, p); return new JacobianPoint(x, y, z); } /** * Scalar multiplication in Jacobian coordinates (double-and-add). * * Computes k·P using the binary expansion of k. Runs in O(log k) * doublings and at most O(log k) additions, all without field inversions * until the final conversion back to affine. * * @param {BigInt} k - Scalar multiplier. * @param {JacobianPoint} jp - Base point in Jacobian coordinates. * @param {CurveParams} curve * @returns {JacobianPoint} */ function jacMul(k, jp, curve) { if (k === 0n || jp.x === null || jp.y === null) { return new JacobianPoint(); } var result = new JacobianPoint(); var bits = k.toString(2); for (var idx = 0; idx < bits.length; idx++) { if (bits[bits.length - idx - 1] === '1') { result = jacAdd(result, jp, curve); } jp = jacDouble(jp, curve); } return result; } //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfbWF0aCIsInJlcXVpcmUiLCJfZGVmaW5lUHJvcGVydGllcyIsImUiLCJyIiwidCIsImxlbmd0aCIsIm8iLCJlbnVtZXJhYmxlIiwiY29uZmlndXJhYmxlIiwid3JpdGFibGUiLCJPYmplY3QiLCJkZWZpbmVQcm9wZXJ0eSIsIl90b1Byb3BlcnR5S2V5Iiwia2V5IiwiX2NyZWF0ZUNsYXNzIiwicHJvdG90eXBlIiwiaSIsIl90b1ByaW1pdGl2ZSIsIl90eXBlb2YiLCJTeW1ib2wiLCJ0b1ByaW1pdGl2ZSIsImNhbGwiLCJUeXBlRXJyb3IiLCJTdHJpbmciLCJOdW1iZXIiLCJfY2xhc3NDYWxsQ2hlY2siLCJhIiwibiIsIkphY29iaWFuUG9pbnQiLCJleHBvcnRzIiwieCIsImFyZ3VtZW50cyIsInVuZGVmaW5lZCIsInkiLCJ6IiwiZnJlZXplIiwidG9KYWNvYmlhbiIsInBvaW50IiwiaXNJZGVudGl0eSIsInRvQWZmaW5lIiwianAiLCJjdXJ2ZSIsImludloiLCJtb2RJbnZlcnNlIiwicCIsImludloyIiwiaW52WjMiLCJtb2R1bHVzIiwiamFjRG91YmxlIiwieXNxIiwienNxciIsInMiLCJtIiwibngiLCJueSIsIm56IiwiamFjQWRkIiwianAxIiwianAyIiwiejF6MSIsInoyejIiLCJ1MSIsInUyIiwiczEiLCJzMiIsImgiLCJqIiwidiIsImphY011bCIsImsiLCJyZXN1bHQiLCJiaXRzIiwidG9TdHJpbmciLCJpZHgiXSwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvY29yZS9hcml0aG1ldGljL2phY29iaWFuLmpzIl0sInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogRWxsaXB0aWMgY3VydmUgYXJpdGhtZXRpYyBpbiBKYWNvYmlhbiAocHJvamVjdGl2ZSkgY29vcmRpbmF0ZXMuXG4gKlxuICogSW4gSmFjb2JpYW4gY29vcmRpbmF0ZXMgYSBwb2ludCBpcyByZXByZXNlbnRlZCBhcyAoWCwgWSwgWikgd2hlcmUgdGhlXG4gKiBhZmZpbmUgZXF1aXZhbGVudHMgYXJlIHggPSBYL1rCsiBhbmQgeSA9IFkvWsKzLiAgVGhlIGlkZW50aXR5IChwb2ludCBhdFxuICogaW5maW5pdHkpIGlzIHJlcHJlc2VudGVkIGJ5IHggPSBudWxsLCB5ID0gbnVsbC5cbiAqXG4gKiBUaGUga2V5IGFkdmFudGFnZSBvdmVyIGFmZmluZSBhcml0aG1ldGljIGlzIHRoYXQgcG9pbnQgYWRkaXRpb24gYW5kXG4gKiBkb3VibGluZyBjYW4gYmUgcGVyZm9ybWVkIFdJVEhPVVQgbW9kdWxhciBpbnZlcnNpb25zIChvbmx5XG4gKiBtdWx0aXBsaWNhdGlvbnMgYW5kIHNxdWFyaW5ncyksIG1ha2luZyBzY2FsYXIgbXVsdGlwbGljYXRpb24gcm91Z2hseVxuICogM3ggZmFzdGVyIGZvciBsYXJnZSBzY2FsYXJzLlxuICpcbiAqIFRyYWRlLW9mZjogZWFjaCBwb2ludCB1c2VzIHRocmVlIGNvb3JkaW5hdGVzIGluc3RlYWQgb2YgdHdvLCBhbmQgYVxuICogc2luZ2xlIGludmVyc2lvbiBpcyBuZWVkZWQgYXQgdGhlIGVuZCB0byBjb252ZXJ0IGJhY2sgdG8gYWZmaW5lIGZvcm0uXG4gKlxuICogU2VlIFJGQyA2MDkwLCBTZWN0aW9uIDQgZm9yIGEgZGV0YWlsZWQgdHJlYXRtZW50IG9mIHByb2plY3RpdmVcbiAqIGNvb3JkaW5hdGUgc3lzdGVtcyBhbmQgdGhlaXIgc2VjdXJpdHkgY29uc2lkZXJhdGlvbnMuXG4gKi9cblxuaW1wb3J0IHsgbW9kdWx1cywgbW9kSW52ZXJzZSB9IGZyb20gJy4uLy4uL3V0aWxzL21hdGguanMnXG5cbi8qKlxuICogQSBwb2ludCBpbiBKYWNvYmlhbiBwcm9qZWN0aXZlIGNvb3JkaW5hdGVzIChYLCBZLCBaKS5cbiAqXG4gKiBUaGUgYWZmaW5lIHBvaW50ICh4LCB5KSBjb3JyZXNwb25kcyB0byAoWC9awrIsIFkvWsKzKS5cbiAqIFRoZSBpZGVudGl0eSBlbGVtZW50IGlzIHJlcHJlc2VudGVkIGJ5IHggPSBudWxsLCB5ID0gbnVsbC5cbiAqL1xuZXhwb3J0IGNsYXNzIEphY29iaWFuUG9pbnQge1xuICBjb25zdHJ1Y3Rvcih4ID0gbnVsbCwgeSA9IG51bGwsIHogPSAxbikge1xuICAgIHRoaXMueCA9IHhcbiAgICB0aGlzLnkgPSB5XG4gICAgdGhpcy56ID0gelxuICAgIE9iamVjdC5mcmVlemUodGhpcylcbiAgfVxufVxuXG4vKipcbiAqIENvbnZlcnQgYW4gYWZmaW5lIFBvaW50IHRvIEphY29iaWFuIGNvb3JkaW5hdGVzLlxuICpcbiAqIFRoZSBhZmZpbmUgcG9pbnQgKHgsIHkpIG1hcHMgdG8gKHgsIHksIDEpIGluIEphY29iaWFuIGZvcm0uXG4gKiBUaGUgaWRlbnRpdHkgcG9pbnQgbWFwcyB0byBKYWNvYmlhblBvaW50KG51bGwsIG51bGwsIDEpLlxuICpcbiAqIEBwYXJhbSB7UG9pbnR9IHBvaW50IC0gQW4gYWZmaW5lIFBvaW50LlxuICogQHJldHVybnMge0phY29iaWFuUG9pbnR9XG4gKi9cbmV4cG9ydCBmdW5jdGlvbiB0b0phY29iaWFuKHBvaW50KSB7XG4gIGlmIChwb2ludC5pc0lkZW50aXR5KSB7XG4gICAgcmV0dXJuIG5ldyBKYWNvYmlhblBvaW50KClcbiAgfVxuICByZXR1cm4gbmV3IEphY29iaWFuUG9pbnQocG9pbnQueCwgcG9pbnQueSwgMW4pXG59XG5cbi8qKlxuICogQ29udmVydCBhIEphY29iaWFuUG9pbnQgYmFjayB0byBhZmZpbmUgKHgsIHkpIGNvb3JkaW5hdGVzLlxuICpcbiAqICAgICB4ID0gWCDCtyBa4oG7wrIgIChtb2QgcClcbiAqICAgICB5ID0gWSDCtyBa4oG7wrMgIChtb2QgcClcbiAqXG4gKiBAcGFyYW0ge0phY29iaWFuUG9pbnR9IGpwXG4gKiBAcGFyYW0ge0N1cnZlUGFyYW1zfSBjdXJ2ZVxuICogQHJldHVybnMge1tCaWdJbnR8bnVsbCwgQmlnSW50fG51bGxdfVxuICovXG5leHBvcnQgZnVuY3Rpb24gdG9BZmZpbmUoanAsIGN1cnZlKSB7XG4gIGlmIChqcC54ID09PSBudWxsIHx8IGpwLnkgPT09IG51bGwgfHwganAueiA9PT0gMG4pIHtcbiAgICByZXR1cm4gW251bGwsIG51bGxdXG4gIH1cbiAgY29uc3QgaW52WiA9IG1vZEludmVyc2UoanAueiwgY3VydmUucClcbiAgY29uc3QgaW52WjIgPSAoaW52WiAqIGludlopICUgY3VydmUucFxuICBjb25zdCBpbnZaMyA9IChpbnZaMiAqIGludlopICUgY3VydmUucFxuICByZXR1cm4gW21vZHVsdXMoanAueCAqIGludloyLCBjdXJ2ZS5wKSwgbW9kdWx1cyhqcC55ICogaW52WjMsIGN1cnZlLnApXVxufVxuXG4vKipcbiAqIERvdWJsZSBhIHBvaW50IGluIEphY29iaWFuIGNvb3JkaW5hdGVzLlxuICpcbiAqIFVzZXMgdGhlIHN0YW5kYXJkIEphY29iaWFuIGRvdWJsaW5nIGZvcm11bGFzIChzZWUgUkZDIDYwOTAgU2VjdGlvbiA0KTpcbiAqXG4gKiAgICAgUyAgPSA0IMK3IFggwrcgWcKyXG4gKiAgICAgTSAgPSAzIMK3IFjCsiArIGEgwrcgWuKBtFxuICogICAgIFgnID0gTcKyIC0gMsK3U1xuICogICAgIFknID0gTSDCtyAoUyAtIFgnKSAtIDjCt1nigbRcbiAqICAgICBaJyA9IDIgwrcgWSDCtyBaXG4gKlxuICogQ29zdDogMVMgKyA0TSAobm8gZmllbGQgaW52ZXJzaW9ucykuXG4gKlxuICogQHBhcmFtIHtKYWNvYmlhblBvaW50fSBqcFxuICogQHBhcmFtIHtDdXJ2ZVBhcmFtc30gY3VydmVcbiAqIEByZXR1cm5zIHtKYWNvYmlhblBvaW50fVxuICovXG5leHBvcnQgZnVuY3Rpb24gamFjRG91YmxlKGpwLCBjdXJ2ZSkge1xuICBpZiAoanAueCA9PT0gbnVsbCB8fCBqcC55ID09PSBudWxsIHx8IGpwLnkgPT09IDBuKSB7XG4gICAgcmV0dXJuIG5ldyBKYWNvYmlhblBvaW50KClcbiAgfVxuICBjb25zdCBwID0gY3VydmUucFxuICBjb25zdCB5c3EgPSBtb2R1bHVzKGpwLnkgKiBqcC55LCBwKVxuICBjb25zdCB6c3FyID0gbW9kdWx1cyhqcC56ICoganAueiwgcClcbiAgY29uc3QgcyA9IG1vZHVsdXMoNG4gKiBqcC54ICogeXNxLCBwKVxuICBjb25zdCBtID0gbW9kdWx1cygzbiAqIGpwLnggKiBqcC54ICsgY3VydmUuYSAqIHpzcXIgKiB6c3FyLCBwKVxuICBjb25zdCBueCA9IG1vZHVsdXMobSAqIG0gLSAybiAqIHMsIHApXG4gIGNvbnN0IG55ID0gbW9kdWx1cyhtICogKHMgLSBueCkgLSA4biAqIHlzcSAqIHlzcSwgcClcbiAgY29uc3QgbnogPSBtb2R1bHVzKDJuICoganAueSAqIGpwLnosIHApXG4gIHJldHVybiBuZXcgSmFjb2JpYW5Qb2ludChueCwgbnksIG56KVxufVxuXG4vKipcbiAqIEFkZCB0d28gcG9pbnRzIGluIEphY29iaWFuIGNvb3JkaW5hdGVzLlxuICpcbiAqIFVzZXMgdGhlIHN0YW5kYXJkIEphY29iaWFuIGFkZGl0aW9uIGZvcm11bGFzIChzZWUgUkZDIDYwOTAgU2VjdGlvbiA0KTpcbiAqXG4gKiAgICAgVeKCgSA9IFjigoEgwrcgWuKCgsKyLCAgIFXigoIgPSBY4oKCIMK3IFrigoHCslxuICogICAgIFPigoEgPSBZ4oKBIMK3IFrigoLCsywgICBT4oKCID0gWeKCgiDCtyBa4oKBwrNcbiAqICAgICBIICA9IFXigoIgLSBV4oKBLCAgICAgUiAgPSAyIMK3IChT4oKCIC0gU+KCgSlcbiAqICAgICBYJyA9IFLCsiAtIEjCsyAtIDIgwrcgVeKCgSDCtyBIwrJcbiAqICAgICBZJyA9IFIgwrcgKFXigoEgwrcgSMKyIC0gWCcpIC0gMiDCtyBT4oKBIMK3IEjCs1xuICogICAgIFonID0gKCha4oKBICsgWuKCginCsiAtIFrigoHCsiAtIFrigoLCsikgwrcgSFxuICpcbiAqIElmIFXigoEgPSBV4oKCIGFuZCBT4oKBIOKJoCBT4oKCIHRoZSBwb2ludHMgYXJlIGludmVyc2VzIOKGkiBpZGVudGl0eS5cbiAqIElmIFXigoEgPSBV4oKCIGFuZCBT4oKBID0gU+KCgiB0aGUgcG9pbnRzIGFyZSBlcXVhbCDihpIgZGVsZWdhdGVzIHRvIGphY0RvdWJsZS5cbiAqXG4gKiBAcGFyYW0ge0phY29iaWFuUG9pbnR9IGpwMVxuICogQHBhcmFtIHtKYWNvYmlhblBvaW50fSBqcDJcbiAqIEBwYXJhbSB7Q3VydmVQYXJhbXN9IGN1cnZlXG4gKiBAcmV0dXJucyB7SmFjb2JpYW5Qb2ludH1cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGphY0FkZChqcDEsIGpwMiwgY3VydmUpIHtcbiAgaWYgKGpwMS54ID09PSBudWxsIHx8IGpwMS55ID09PSBudWxsKSByZXR1cm4ganAyXG4gIGlmIChqcDIueCA9PT0gbnVsbCB8fCBqcDIueSA9PT0gbnVsbCkgcmV0dXJuIGpwMVxuICBjb25zdCBwID0gY3VydmUucFxuICBjb25zdCB6MXoxID0gbW9kdWx1cyhqcDEueiAqIGpwMS56LCBwKVxuICBjb25zdCB6MnoyID0gbW9kdWx1cyhqcDIueiAqIGpwMi56LCBwKVxuICBjb25zdCB1MSA9IG1vZHVsdXMoanAxLnggKiB6MnoyLCBwKVxuICBjb25zdCB1MiA9IG1vZHVsdXMoanAyLnggKiB6MXoxLCBwKVxuICBjb25zdCBzMSA9IG1vZHVsdXMoanAxLnkgKiBqcDIueiAqIHoyejIsIHApXG4gIGNvbnN0IHMyID0gbW9kdWx1cyhqcDIueSAqIGpwMS56ICogejF6MSwgcClcbiAgaWYgKHUxID09PSB1Mikge1xuICAgIGlmIChzMSAhPT0gczIpIHJldHVybiBuZXcgSmFjb2JpYW5Qb2ludCgpXG4gICAgcmV0dXJuIGphY0RvdWJsZShqcDEsIGN1cnZlKVxuICB9XG4gIGNvbnN0IGggPSB1MiAtIHUxXG4gIGNvbnN0IGkgPSBtb2R1bHVzKDJuICogaCAqICgybiAqIGgpLCBwKVxuICBjb25zdCBqID0gbW9kdWx1cyhoICogaSwgcClcbiAgY29uc3QgciA9IG1vZHVsdXMoMm4gKiAoczIgLSBzMSksIHApXG4gIGNvbnN0IHYgPSBtb2R1bHVzKHUxICogaSwgcClcbiAgY29uc3QgeCA9IG1vZHVsdXMociAqIHIgLSBqIC0gMm4gKiB2LCBwKVxuICBjb25zdCB5ID0gbW9kdWx1cyhyICogKHYgLSB4KSAtIDJuICogczEgKiBqLCBwKVxuICBjb25zdCB6ID0gbW9kdWx1cygoKGpwMS56ICsganAyLnopICogKGpwMS56ICsganAyLnopIC0gejF6MSAtIHoyejIpICogaCwgcClcbiAgcmV0dXJuIG5ldyBKYWNvYmlhblBvaW50KHgsIHksIHopXG59XG5cbi8qKlxuICogU2NhbGFyIG11bHRpcGxpY2F0aW9uIGluIEphY29iaWFuIGNvb3JkaW5hdGVzIChkb3VibGUtYW5kLWFkZCkuXG4gKlxuICogQ29tcHV0ZXMga8K3UCB1c2luZyB0aGUgYmluYXJ5IGV4cGFuc2lvbiBvZiBrLiAgUnVucyBpbiBPKGxvZyBrKVxuICogZG91YmxpbmdzIGFuZCBhdCBtb3N0IE8obG9nIGspIGFkZGl0aW9ucywgYWxsIHdpdGhvdXQgZmllbGQgaW52ZXJzaW9uc1xuICogdW50aWwgdGhlIGZpbmFsIGNvbnZlcnNpb24gYmFjayB0byBhZmZpbmUuXG4gKlxuICogQHBhcmFtIHtCaWdJbnR9IGsgICAtIFNjYWxhciBtdWx0aXBsaWVyLlxuICogQHBhcmFtIHtKYWNvYmlhblBvaW50fSBqcCAtIEJhc2UgcG9pbnQgaW4gSmFjb2JpYW4gY29vcmRpbmF0ZXMuXG4gKiBAcGFyYW0ge0N1cnZlUGFyYW1zfSBjdXJ2ZVxuICogQHJldHVybnMge0phY29iaWFuUG9pbnR9XG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBqYWNNdWwoaywganAsIGN1cnZlKSB7XG4gIGlmIChrID09PSAwbiB8fCBqcC54ID09PSBudWxsIHx8IGpwLnkgPT09IG51bGwpIHtcbiAgICByZXR1cm4gbmV3IEphY29iaWFuUG9pbnQoKVxuICB9XG4gIGxldCByZXN1bHQgPSBuZXcgSmFjb2JpYW5Qb2ludCgpXG4gIGNvbnN0IGJpdHMgPSBrLnRvU3RyaW5nKDIpXG4gIGZvciAobGV0IGlkeCA9IDA7IGlkeCA8IGJpdHMubGVuZ3RoOyBpZHgrKykge1xuICAgIGlmIChiaXRzW2JpdHMubGVuZ3RoIC0gaWR4IC0gMV0gPT09ICcxJykge1xuICAgICAgcmVzdWx0ID0gamFjQWRkKHJlc3VsdCwganAsIGN1cnZlKVxuICAgIH1cbiAgICBqcCA9IGphY0RvdWJsZShqcCwgY3VydmUpXG4gIH1cbiAgcmV0dXJuIHJlc3VsdFxufVxuIl0sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7QUFtQkEsSUFBQUEsS0FBQSxHQUFBQyxPQUFBO0FBQXlELFNBQUFDLGtCQUFBQyxDQUFBLEVBQUFDLENBQUEsYUFBQUMsQ0FBQSxNQUFBQSxDQUFBLEdBQUFELENBQUEsQ0FBQUUsTUFBQSxFQUFBRCxDQUFBLFVBQUFFLENBQUEsR0FBQUgsQ0FBQSxDQUFBQyxDQUFBLEdBQUFFLENBQUEsQ0FBQUMsVUFBQSxHQUFBRCxDQUFBLENBQUFDLFVBQUEsUUFBQUQsQ0FBQSxDQUFBRSxZQUFBLGtCQUFBRixDQUFBLEtBQUFBLENBQUEsQ0FBQUcsUUFBQSxRQUFBQyxNQUFBLENBQUFDLGNBQUEsQ0FBQVQsQ0FBQSxFQUFBVSxjQUFBLENBQUFOLENBQUEsQ0FBQU8sR0FBQSxHQUFBUCxDQUFBO0FBQUEsU0FBQVEsYUFBQVosQ0FBQSxFQUFBQyxDQUFBLEVBQUFDLENBQUEsV0FBQUQsQ0FBQSxJQUFBRixpQkFBQSxDQUFBQyxDQUFBLENBQUFhLFNBQUEsRUFBQVosQ0FBQSxHQUFBQyxDQUFBLElBQUFILGlCQUFBLENBQUFDLENBQUEsRUFBQUUsQ0FBQSxHQUFBTSxNQUFBLENBQUFDLGNBQUEsQ0FBQVQsQ0FBQSxpQkFBQU8sUUFBQSxTQUFBUCxDQUFBO0FBQUEsU0FBQVUsZUFBQVIsQ0FBQSxRQUFBWSxDQUFBLEdBQUFDLFlBQUEsQ0FBQWIsQ0FBQSxnQ0FBQWMsT0FBQSxDQUFBRixDQUFBLElBQUFBLENBQUEsR0FBQUEsQ0FBQTtBQUFBLFNBQUFDLGFBQUFiLENBQUEsRUFBQUQsQ0FBQSxvQkFBQWUsT0FBQSxDQUFBZCxDQUFBLE1BQUFBLENBQUEsU0FBQUEsQ0FBQSxNQUFBRixDQUFBLEdBQUFFLENBQUEsQ0FBQWUsTUFBQSxDQUFBQyxXQUFBLGtCQUFBbEIsQ0FB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