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.

143 lines (136 loc) 17.5 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Koblitz = void 0; var _point = require("../core/point.js"); var _registry = require("../curves/registry.js"); var _math = require("../utils/math.js"); 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); } function _classCallCheck(a, n) { if (!(a instanceof n)) throw new TypeError("Cannot call a class as a function"); } 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); } /** * Koblitz method for encoding/decoding messages as elliptic curve points. * * Encoding algorithm: * 1. Convert the message string to an integer m using base-α * positional encoding (α = alphabetSize). * 2. For j = 1, 2, ..., d-1: * x = (d·m + j) mod p * 3. Test if x³ + ax + b is a quadratic residue mod p. * 4. If yes, compute y = √(x³ + ax + b) mod p and return * (Point(x, y), j). * * With d = 100 the probability of failure per attempt is ≈ 1/2, so the * overall failure probability after 99 attempts is ≈ 2⁻⁹⁹. * * Usage: * * const kob = new Koblitz('secp521r1') * const [point, j] = kob.encode('Hello, world!') * const text = kob.decode(point, j) * // text === 'Hello, world!' */ /** * Koblitz message encoding/decoding on an elliptic curve. */ var Koblitz = exports.Koblitz = /*#__PURE__*/function () { /** * @param {string} [curveName='secp521r1'] - Name of the curve. * Larger curves can encode longer messages in a single point. * @param {BigInt} [alphabetSize=256n] - Character set size. * 256 for ASCII, 65536 for Unicode. */ function Koblitz() { var curveName = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'secp521r1'; var alphabetSize = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 256n; _classCallCheck(this, Koblitz); this.curveName = curveName; this.alphabetSize = alphabetSize; Object.freeze(this); } return _createClass(Koblitz, [{ key: "_curve", get: function get() { return (0, _registry.getCurve)(this.curveName); } /** * Encode a text message into a point on the curve. * * The message is first converted to an integer m via base-α encoding: * * m = Σ char_code(ch_i) · α^i * * Then Koblitz's method searches for a valid curve point: * * for j = 1, 2, ..., 99: * x = (100·m + j) mod p * s = x³ + ax + b (mod p) * if s is a quadratic residue: * y = √s mod p * return (Point(x, y), j) * * @param {string} message - The text to encode (limited by curve size). * @returns {[Point, number]} [point, j] where j is needed for decoding. * @throws {Error} If no valid point is found (probability ≈ 2⁻⁹⁹). */ }, { key: "encode", value: function encode(message) { var curve = this._curve; var alpha = this.alphabetSize; // Convert string → integer (base-alpha encoding) var m = 0n; for (var i = 0; i < message.length; i++) { m += BigInt(message.charCodeAt(i)) * alpha ** BigInt(i); } // Koblitz: try x = d·m + j until y² = x³ + ax + b has a root var d = 100n; for (var j = 1; j < 100; j++) { var x = (0, _math.modulus)(d * m + BigInt(j), curve.p); var s = (0, _math.modulus)((0, _math.modPow)(x, 3n, curve.p) + curve.a * x + curve.b, curve.p); // Euler criterion + shortcut for p ≡ 3 (mod 4): // s is a QR iff s ≡ s^((p+1)/2) (mod p) // y = s^((p+1)/4) mod p if (s === (0, _math.modPow)(s, (curve.p + 1n) / 2n, curve.p)) { var y = (0, _math.modPow)(s, (curve.p + 1n) / 4n, curve.p); var pt = new _point.Point(x, y, curve); if (pt.isOnCurve()) { return [pt, j]; } } } /* istanbul ignore next -- failure probability ≈ 2⁻⁹⁹ */ throw new Error('Failed to encode message to a valid point on the curve.'); } /** * Decode a curve point back into the original text message. * * Reverses the encoding: * * m = (x - j) / 100 * * Then converts integer m back to a string via base-α decomposition. * * @param {Point} point - The encoded point (as returned by encode). * @param {number} j - The auxiliary value returned alongside the point. * @returns {string} The original text message. */ }, { key: "decode", value: function decode(point, j) { var alpha = this.alphabetSize; var d = 100n; var m = (point.x - BigInt(j)) / d; var chars = []; while (m > 0n) { chars.push(String.fromCharCode(Number(m % alpha))); m /= alpha; } return chars.join(''); } }]); }(); //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfcG9pbnQiLCJyZXF1aXJlIiwiX3JlZ2lzdHJ5IiwiX21hdGgiLCJfdHlwZW9mIiwibyIsIlN5bWJvbCIsIml0ZXJhdG9yIiwiY29uc3RydWN0b3IiLCJwcm90b3R5cGUiLCJfY2xhc3NDYWxsQ2hlY2siLCJhIiwibiIsIlR5cGVFcnJvciIsIl9kZWZpbmVQcm9wZXJ0aWVzIiwiZSIsInIiLCJ0IiwibGVuZ3RoIiwiZW51bWVyYWJsZSIsImNvbmZpZ3VyYWJsZSIsIndyaXRhYmxlIiwiT2JqZWN0IiwiZGVmaW5lUHJvcGVydHkiLCJfdG9Qcm9wZXJ0eUtleSIsImtleSIsIl9jcmVhdGVDbGFzcyIsImkiLCJfdG9QcmltaXRpdmUiLCJ0b1ByaW1pdGl2ZSIsImNhbGwiLCJTdHJpbmciLCJOdW1iZXIiLCJLb2JsaXR6IiwiZXhwb3J0cyIsImN1cnZlTmFtZSIsImFyZ3VtZW50cyIsInVuZGVmaW5lZCIsImFscGhhYmV0U2l6ZSIsImZyZWV6ZSIsImdldCIsImdldEN1cnZlIiwidmFsdWUiLCJlbmNvZGUiLCJtZXNzYWdlIiwiY3VydmUiLCJfY3VydmUiLCJhbHBoYSIsIm0iLCJCaWdJbnQiLCJjaGFyQ29kZUF0IiwiZCIsImoiLCJ4IiwibW9kdWx1cyIsInAiLCJzIiwibW9kUG93IiwiYiIsInkiLCJwdCIsIlBvaW50IiwiaXNPbkN1cnZlIiwiRXJyb3IiLCJkZWNvZGUiLCJwb2ludCIsImNoYXJzIiwicHVzaCIsImZyb21DaGFyQ29kZSIsImpvaW4iXSwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvYWxnb3JpdGhtcy9rb2JsaXR6LmpzIl0sInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogS29ibGl0eiBtZXRob2QgZm9yIGVuY29kaW5nL2RlY29kaW5nIG1lc3NhZ2VzIGFzIGVsbGlwdGljIGN1cnZlIHBvaW50cy5cbiAqXG4gKiBFbmNvZGluZyBhbGdvcml0aG06XG4gKiAgICAgMS4gQ29udmVydCB0aGUgbWVzc2FnZSBzdHJpbmcgdG8gYW4gaW50ZWdlciBtIHVzaW5nIGJhc2UtzrFcbiAqICAgICAgICBwb3NpdGlvbmFsIGVuY29kaW5nICjOsSA9IGFscGhhYmV0U2l6ZSkuXG4gKiAgICAgMi4gRm9yIGogPSAxLCAyLCAuLi4sIGQtMTpcbiAqICAgICAgICAgIHggPSAoZMK3bSArIGopIG1vZCBwXG4gKiAgICAgMy4gVGVzdCBpZiB4wrMgKyBheCArIGIgaXMgYSBxdWFkcmF0aWMgcmVzaWR1ZSBtb2QgcC5cbiAqICAgICA0LiBJZiB5ZXMsIGNvbXB1dGUgeSA9IOKImih4wrMgKyBheCArIGIpIG1vZCBwIGFuZCByZXR1cm5cbiAqICAgICAgICAoUG9pbnQoeCwgeSksIGopLlxuICpcbiAqIFdpdGggZCA9IDEwMCB0aGUgcHJvYmFiaWxpdHkgb2YgZmFpbHVyZSBwZXIgYXR0ZW1wdCBpcyDiiYggMS8yLCBzbyB0aGVcbiAqIG92ZXJhbGwgZmFpbHVyZSBwcm9iYWJpbGl0eSBhZnRlciA5OSBhdHRlbXB0cyBpcyDiiYggMuKBu+KBueKBuS5cbiAqXG4gKiBVc2FnZTpcbiAqXG4gKiAgICAgY29uc3Qga29iID0gbmV3IEtvYmxpdHooJ3NlY3A1MjFyMScpXG4gKiAgICAgY29uc3QgW3BvaW50LCBqXSA9IGtvYi5lbmNvZGUoJ0hlbGxvLCB3b3JsZCEnKVxuICogICAgIGNvbnN0IHRleHQgPSBrb2IuZGVjb2RlKHBvaW50LCBqKVxuICogICAgIC8vIHRleHQgPT09ICdIZWxsbywgd29ybGQhJ1xuICovXG5cbmltcG9ydCB7IFBvaW50IH0gZnJvbSAnLi4vY29yZS9wb2ludC5qcydcbmltcG9ydCB7IGdldEN1cnZlIH0gZnJvbSAnLi4vY3VydmVzL3JlZ2lzdHJ5LmpzJ1xuaW1wb3J0IHsgbW9kUG93LCBtb2R1bHVzIH0gZnJvbSAnLi4vdXRpbHMvbWF0aC5qcydcblxuLyoqXG4gKiBLb2JsaXR6IG1lc3NhZ2UgZW5jb2RpbmcvZGVjb2Rpbmcgb24gYW4gZWxsaXB0aWMgY3VydmUuXG4gKi9cbmV4cG9ydCBjbGFzcyBLb2JsaXR6IHtcbiAgLyoqXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBbY3VydmVOYW1lPSdzZWNwNTIxcjEnXSAtIE5hbWUgb2YgdGhlIGN1cnZlLlxuICAgKiAgIExhcmdlciBjdXJ2ZXMgY2FuIGVuY29kZSBsb25nZXIgbWVzc2FnZXMgaW4gYSBzaW5nbGUgcG9pbnQuXG4gICAqIEBwYXJhbSB7QmlnSW50fSBbYWxwaGFiZXRTaXplPTI1Nm5dICAgICAtIENoYXJhY3RlciBzZXQgc2l6ZS5cbiAgICogICAyNTYgZm9yIEFTQ0lJLCA2NTUzNiBmb3IgVW5pY29kZS5cbiAgICovXG4gIGNvbnN0cnVjdG9yKGN1cnZlTmFtZSA9ICdzZWNwNTIxcjEnLCBhbHBoYWJldFNpemUgPSAyNTZuKSB7XG4gICAgdGhpcy5jdXJ2ZU5hbWUgPSBjdXJ2ZU5hbWVcbiAgICB0aGlzLmFscGhhYmV0U2l6ZSA9IGFscGhhYmV0U2l6ZVxuICAgIE9iamVjdC5mcmVlemUodGhpcylcbiAgfVxuXG4gIGdldCBfY3VydmUoKSB7XG4gICAgcmV0dXJuIGdldEN1cnZlKHRoaXMuY3VydmVOYW1lKVxuICB9XG5cbiAgLyoqXG4gICAqIEVuY29kZSBhIHRleHQgbWVzc2FnZSBpbnRvIGEgcG9pbnQgb24gdGhlIGN1cnZlLlxuICAgKlxuICAgKiBUaGUgbWVzc2FnZSBpcyBmaXJzdCBjb252ZXJ0ZWQgdG8gYW4gaW50ZWdlciBtIHZpYSBiYXNlLc6xIGVuY29kaW5nOlxuICAgKlxuICAgKiAgICAgbSA9IM6jICBjaGFyX2NvZGUoY2hfaSkgwrcgzrFeaVxuICAgKlxuICAgKiBUaGVuIEtvYmxpdHoncyBtZXRob2Qgc2VhcmNoZXMgZm9yIGEgdmFsaWQgY3VydmUgcG9pbnQ6XG4gICAqXG4gICAqICAgICBmb3IgaiA9IDEsIDIsIC4uLiwgOTk6XG4gICAqICAgICAgIHggPSAoMTAwwrdtICsgaikgbW9kIHBcbiAgICogICAgICAgcyA9IHjCsyArIGF4ICsgYiAgKG1vZCBwKVxuICAgKiAgICAgICBpZiBzIGlzIGEgcXVhZHJhdGljIHJlc2lkdWU6XG4gICAqICAgICAgICAgeSA9IOKImnMgbW9kIHBcbiAgICogICAgICAgICByZXR1cm4gKFBvaW50KHgsIHkpLCBqKVxuICAgKlxuICAgKiBAcGFyYW0ge3N0cmluZ30gbWVzc2FnZSAtIFRoZSB0ZXh0IHRvIGVuY29kZSAobGltaXRlZCBieSBjdXJ2ZSBzaXplKS5cbiAgICogQHJldHVybnMge1tQb2ludCwgbnVtYmVyXX0gW3BvaW50LCBqXSB3aGVyZSBqIGlzIG5lZWRlZCBmb3IgZGVjb2RpbmcuXG4gICAqIEB0aHJvd3Mge0Vycm9yfSBJZiBubyB2YWxpZCBwb2ludCBpcyBmb3VuZCAocHJvYmFiaWxpdHkg4omIIDLigbvigbnigbkpLlxuICAgKi9cbiAgZW5jb2RlKG1lc3NhZ2UpIHtcbiAgICBjb25zdCBjdXJ2ZSA9IHRoaXMuX2N1cnZlXG4gICAgY29uc3QgYWxwaGEgPSB0aGlzLmFscGhhYmV0U2l6ZVxuXG4gICAgLy8gQ29udmVydCBzdHJpbmcg4oaSIGludGVnZXIgIChiYXNlLWFscGhhIGVuY29kaW5nKVxuICAgIGxldCBtID0gMG5cbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IG1lc3NhZ2UubGVuZ3RoOyBpKyspIHtcbiAgICAgIG0gKz0gQmlnSW50KG1lc3NhZ2UuY2hhckNvZGVBdChpKSkgKiBhbHBoYSAqKiBCaWdJbnQoaSlcbiAgICB9XG5cbiAgICAvLyBLb2JsaXR6OiB0cnkgeCA9IGTCt20gKyBqIHVudGlsIHnCsiA9IHjCsyArIGF4ICsgYiBoYXMgYSByb290XG4gICAgY29uc3QgZCA9IDEwMG5cbiAgICBmb3IgKGxldCBqID0gMTsgaiA8IDEwMDsgaisrKSB7XG4gICAgICBjb25zdCB4ID0gbW9kdWx1cyhkICogbSArIEJpZ0ludChqKSwgY3VydmUucClcbiAgICAgIGNvbnN0IHMgPSBtb2R1bHVzKG1vZFBvdyh4LCAzbiwgY3VydmUucCkgKyBjdXJ2ZS5hICogeCArIGN1cnZlLmIsIGN1cnZlLnApXG5cbiAgICAgIC8vIEV1bGVyIGNyaXRlcmlvbiArIHNob3J0Y3V0IGZvciBwIOKJoSAzIChtb2QgNCk6XG4gICAgICAvLyAgIHMgaXMgYSBRUiBpZmYgcyDiiaEgc14oKHArMSkvMikgKG1vZCBwKVxuICAgICAgLy8gICB5ID0gc14oKHArMSkvNCkgbW9kIHBcbiAgICAgIGlmIChzID09PSBtb2RQb3cocywgKGN1cnZlLnAgKyAxbikgLyAybiwgY3VydmUucCkpIHtcbiAgICAgICAgY29uc3QgeSA9IG1vZFBvdyhzLCAoY3VydmUucCArIDFuKSAvIDRuLCBjdXJ2ZS5wKVxuICAgICAgICBjb25zdCBwdCA9IG5ldyBQb2ludCh4LCB5LCBjdXJ2ZSlcbiAgICAgICAgaWYgKHB0LmlzT25DdXJ2ZSgpKSB7XG4gICAgICAgICAgcmV0dXJuIFtwdCwgal1cbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cblxuICAgIC8qIGlzdGFuYnVsIGlnbm9yZSBuZXh0IC0tIGZhaWx1cmUgcHJvYmFiaWxpdHkg4omIIDLigbvigbnigbkgKi9cbiAgICB0aHJvdyBuZXcgRXJyb3IoJ0ZhaWxlZCB0byBlbmNvZGUgbWVzc2FnZSB0byBhIHZhbGlkIHBvaW50IG9uIHRoZSBjdXJ2ZS4nKVxuICB9XG5cbiAgLyoqXG4gICAqIERlY29kZSBhIGN1cnZlIHBvaW50IGJhY2sgaW50byB0aGUgb3JpZ2luYWwgdGV4dCBtZXNzYWdlLlxuICAgKlxuICAgKiBSZXZlcnNlcyB0aGUgZW5jb2Rpbmc6XG4gICAqXG4gICAqICAgICBtID0gKHggLSBqKSAvIDEwMFxuICAgKlxuICAgKiBUaGVuIGNvbnZlcnRzIGludGVnZXIgbSBiYWNrIHRvIGEgc3RyaW5nIHZpYSBiYXNlLc6xIGRlY29tcG9zaXRpb24uXG4gICAqXG4gICAqIEBwYXJhbSB7UG9pbnR9IHBvaW50IC0gVGhlIGVuY29kZWQgcG9pbnQgKGFzIHJldHVybmVkIGJ5IGVuY29kZSkuXG4gICAqIEBwYXJhbSB7bnVtYmVyfSBqICAgIC0gVGhlIGF1eGlsaWFyeSB2YWx1ZSByZXR1cm5lZCBhbG9uZ3NpZGUgdGhlIHBvaW50LlxuICAgKiBAcmV0dXJucyB7c3RyaW5nfSBUaGUgb3JpZ2luYWwgdGV4dCBtZXNzYWdlLlxuICAgKi9cbiAgZGVjb2RlKHBvaW50LCBqKSB7XG4gICAgY29uc3QgYWxwaGEgPSB0aGlzLmFscGhhYmV0U2l6ZVxuICAgIGNvbnN0IGQgPSAxMDBuXG4gICAgbGV0IG0gPSAocG9pbnQueCAtIEJpZ0ludChqKSkgLyBkXG5cbiAgICBjb25zdCBjaGFycyA9IFtdXG4gICAgd2hpbGUgKG0gPiAwbikge1xuICAgICAgY2hhcnMucHVzaChTdHJpbmcuZnJvbUNoYXJDb2RlKE51bWJlcihtICUgYWxwaGEpKSlcbiAgICAgIG0gLz0gYWxwaGFcbiAgICB9XG4gICAgcmV0dXJuIGNoYXJzLmpvaW4oJycpXG4gIH1cbn1cbiJdLCJtYXBwaW5ncyI6Ijs7Ozs7O0FBdUJBLElBQUFBLE1BQUEsR0FBQUMsT0FBQTtBQUNBLElBQUFDLFNBQUEsR0FBQUQsT0FBQTtBQUNBLElBQUFFLEtBQUEsR0FBQUYsT0FBQTtBQUFrRCxTQUFBRyxRQUFBQyxDQUFBLHNDQUFBRCxPQUFBLHdCQUFBRSxNQUFBLHVCQUFBQSxNQUFBLENBQUFDLFFBQUEsYUFBQUYsQ0FBQSxrQkFBQUEsQ0FBQSxnQkFBQUEsQ0FBQSxXQUFBQSxDQUFBLHlCQUFBQyxNQUFBLElBQUFELENBQUEsQ0FBQUcsV0FBQSxLQUFBRixNQUFBLElBQUFELENBQUEsS0FBQUMsTUFBQSxDQUFBRyxTQUFBLHFCQUFBSixDQUFBLEtBQUFELE9BQUEsQ0FBQUMsQ0FBQTtBQUFBLFNBQUFLLGdCQUFBQyxDQUFBLEVBQUFDLENBQUEsVUFBQUQsQ0FBQSxZQUFBQyxDQUFBLGFBQUFDLFNBQUE7QUFBQSxTQUFBQyxrQkFBQUMsQ0FBQSxFQUFBQyxDQUFBLGFBQUFDLENBQUEsTUFBQUEsQ0FBQSxHQUFBRCxDQUFBLENBQUFFLE1BQUEsRUFBQUQsQ0FBQSxVQUFBWixDQUFBLEdBQUFXLENBQUEsQ0FBQUMsQ0FBQSxHQUFBWixDQUFBLENBQUFjLFVBQUEsR0FBQWQsQ0FBQSxDQUFBYyxVQUFBLFFBQUFkLENBQUEsQ0FBQWUsWUFBQSxrQkFBQWYsQ0FBQSxLQUFBQSxDQUFBLENBQUFnQixRQUFBLFFBQUFDLE1BQUEsQ0FBQUMsY0FBQSxDQUFBUixDQUFBLEVBQUFTLGNBQUEsQ0FBQW5CLENBQUEsQ0FBQW9CLEdBQUEsR0FBQXBCLENBQUE7QUFBQSxTQUFBcUIsYUFBQVgsQ0FBQSxFQUFBQyxDQUFBLEVBQUFDLENBQUEsV0FBQUQsQ0FBQSxJQUFBRixpQkFBQSxDQUFBQyxDQUFBLENBQUFOLFNBQUEsRUFBQU8sQ0FBQSxHQUFBQyxDQUFBLElBQUFILGlCQUFBLENBQUFDLENBQUEsRUFBQUUsQ0FBQSxHQUFBSyxNQUFBLENBQUFDLGNBQUEsQ0FBQVIsQ0FBQSxpQkFBQU0sUUFBQSxTQUFBTixDQUFBO0FBQUEsU0FBQVMsZUFBQVAsQ0FBQSxRQUFBVSxDQUFBLEdBQUFDLFlBQUEsQ0FBQVgsQ0FBQSxnQ0FBQWIsT0FBQSxDQUFBdUIsQ0FBQSxJQUFBQSxDQUFBLEdBQUFBLENBQUE7QUFBQSxTQUFBQyxhQUFBWCxDQUFBLEVBQUFELENBQUEsb0JBQUFaLE9BQUEsQ0FBQWEsQ0FBQSxNQUFBQSxDQUFBLFNBQUFBLENBQUEsTUFBQUYsQ0FBQSxHQUFBRSxDQUFBLENBQUFYLE1BQUEsQ0FBQXVCLFdBQUEsa0JBQUFkLENBQUEsUUFBQVksQ0FBQSxHQUFBWixDQUFBLENBQUFlLElBQUEsQ0FBQWIsQ0FBQSxFQUFBRCxDQUFBLGdDQUFBWixPQUFBLENBQUF1QixDQUFBLFVBQUFBLENBQUEsWUFBQWQsU0FBQSx5RUFBQUcsQ0FBQSxHQUFBZSxNQUFBLEdBQUFDLE1BQUEsRUFBQWYsQ0FBQSxLQXpCbEQ7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFNQTtBQUNBO0FBQ0E7QUFGQSxJQUdhZ0IsT0FBTyxHQUFBQyxPQUFBLENBQUFELE9BQUE7RUFDbEI7QUFDRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0VBQ0UsU0FBQUEsUUFBQSxFQUEwRDtJQUFBLElBQTlDRSxTQUFTLEdBQUFDLFNBQUEsQ0FBQWxCLE1BQUEsUUFBQWtCLFNBQUEsUUFBQUMsU0FBQSxHQUFBRCxTQUFBLE1BQUcsV0FBVztJQUFBLElBQUVFLFlBQVksR0FBQUYsU0FBQSxDQUFBbEIsTUFBQSxRQUFBa0IsU0FBQSxRQUFBQyxTQUFBLEdBQUFELFNBQUEsTUFBRyxJQUFJO0lBQUExQixlQUFBLE9BQUF1QixPQUFBO0lBQ3RELElBQUksQ0FBQ0UsU0FBUyxHQUFHQSxTQUFTO0lBQzFCLElBQUksQ0FBQ0csWUFBWSxHQUFHQSxZQUFZO0lBQ2hDaEIsTUFBTSxDQUFDaUIsTUFBTSxDQUFDLElBQUksQ0FBQztFQUNyQjtFQUFDLE9BQUFiLFlBQUEsQ0FBQU8sT0FBQTtJQUFBUixHQUFBO0lBQUFlLEdBQUEsRUFFRCxTQUFBQSxJQUFBLEVBQWE7TUFDWCxPQUFPLElBQUFDLGtCQUFRLEVBQUMsSUFBSSxDQUFDTixTQUFTLENBQUM7SUFDakM7O0lBRUE7QUFDRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtFQW5CRTtJQUFBVixHQUFBO0lBQUFpQixLQUFBLEVBb0JBLFNBQUFDLE9BQU9DLE9BQU8sRUFBRTtNQUNkLElBQU1DLEtBQUssR0FBRyxJQUFJLENBQUNDLE1BQU07TUFDekIsSUFBTUMsS0FBSyxHQUFHLElBQUksQ0FBQ1QsWUFBWTs7TUFFL0I7TUFDQSxJQUFJVSxDQUFDLEdBQUcsRUFBRTtNQUNWLEtBQUssSUFBSXJCLENBQUMsR0FBRyxDQUFDLEVBQUVBLENBQUMsR0FBR2lCLE9BQU8sQ0FBQzFCLE1BQU0sRUFBRVMsQ0FBQyxFQUFFLEVBQUU7UUFDdkNxQixDQUFDLElBQUlDLE1BQU0sQ0FBQ0wsT0FBTyxDQUFDTSxVQUFVLENBQUN2QixDQUFDLENBQUMsQ0FBQyxHQUFHb0IsS0FBSyxJQUFJRSxNQUFNLENBQUN0QixDQUFDLENBQUM7TUFDekQ7O01BRUE7TUFDQSxJQUFNd0IsQ0FBQyxHQUFHLElBQUk7TUFDZCxLQUFLLElBQUlDLENBQUMsR0FBRyxDQUFDLEVBQUVBLENBQUMsR0FBRyxHQUFHLEVBQUVBLENBQUMsRUFBRSxFQUFFO1FBQzVCLElBQU1DLENBQUMsR0FBRyxJQUFBQyxhQUFPLEVBQUNILENBQUMsR0FBR0gsQ0FBQyxHQUFHQyxNQUFNLENBQUNHLENBQUMsQ0FBQyxFQUFFUCxLQUFLLENBQUNVLENBQUMsQ0FBQztRQUM3QyxJQUFNQyxDQUFDLEdBQUcsSUFBQUYsYUFBTyxFQUFDLElBQUFHLFlBQU0sRUFBQ0osQ0FBQyxFQUFFLEVBQUUsRUFBRVIsS0FBSyxDQUFDVSxDQUFDLENBQUMsR0FBR1YsS0FBSyxDQUFDbEMsQ0FBQyxHQUFHMEMsQ0FBQyxHQUFHUixLQUFLLENBQUNhLENBQUMsRUFBRWIsS0FBSyxDQUFDVSxDQUFDLENBQUM7O1FBRTFFO1FBQ0E7UUFDQTtRQUNBLElBQUlDLENBQUMsS0FBSyxJQUFBQyxZQUFNLEVBQUNELENBQUMsRUFBRSxDQUFDWCxLQUFLLENBQUNVLENBQUMsR0FBRyxFQUFFLElBQUksRUFBRSxFQUFFVixLQUFLLENBQUNVLENBQUMsQ0FBQyxFQUFFO1VBQ2pELElBQU1JLENBQUMsR0FBRyxJQUFBRixZQUFNLEVBQUNELENBQUMsRUFBRSxDQUFDWCxLQUFLLENBQUNVLENBQUMsR0FBRyxFQUFFLElBQUksRUFBRSxFQUFFVixLQUFLLENBQUNVLENBQUMsQ0FBQztVQUNqRCxJQUFNSyxFQUFFLEdBQUcsSUFBSUMsWUFBSyxDQUFDUixDQUFDLEVBQUVNLENBQUMsRUFBRWQsS0FBSyxDQUFDO1VBQ2pDLElBQUllLEVBQUUsQ0FBQ0UsU0FBUyxDQUFDLENBQUMsRUFBRTtZQUNsQixPQUFPLENBQUNGLEVBQUUsRUFBRVIsQ0FBQyxDQUFDO1VBQ2hCO1FBQ0Y7TUFDRjs7TUFFQTtNQUNBLE1BQU0sSUFBSVcsS0FBSyxDQUFDLHlEQUF5RCxDQUFDO0lBQzVFOztJQUVBO0FBQ0Y7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0VBWkU7SUFBQXRDLEdBQUE7SUFBQWlCLEtBQUEsRUFhQSxTQUFBc0IsT0FBT0MsS0FBSyxFQUFFYixDQUFDLEVBQUU7TUFDZixJQUFNTCxLQUFLLEdBQUcsSUFBSSxDQUFDVCxZQUFZO01BQy9CLElBQU1hLENBQUMsR0FBRyxJQUFJO01BQ2QsSUFBSUgsQ0FBQyxHQUFHLENBQUNpQixLQUFLLENBQUNaLENBQUMsR0FBR0osTUFBTSxDQUFDRyxDQUFDLENBQUMsSUFBSUQsQ0FBQztNQUVqQyxJQUFNZSxLQUFLLEdBQUcsRUFBRTtNQUNoQixPQUFPbEIsQ0FBQyxHQUFHLEVBQUUsRUFBRTtRQUNia0IsS0FBSyxDQUFDQyxJQUFJLENBQUNwQyxNQUFNLENBQUNxQyxZQUFZLENBQUNwQyxNQUFNLENBQUNnQixDQUFDLEdBQUdELEtBQUssQ0FBQyxDQUFDLENBQUM7UUFDbERDLENBQUMsSUFBSUQsS0FBSztNQUNaO01BQ0EsT0FBT21CLEtBQUssQ0FBQ0csSUFBSSxDQUFDLEVBQUUsQ0FBQztJQUN2QjtFQUFDO0FBQUEiLCJpZ25vcmVMaXN0IjpbXX0=