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.

170 lines (161 loc) 21.1 kB
"use strict"; var _globals = require("@jest/globals"); var _registry = require("./curves/registry"); var _curve = require("./core/curve"); var _point = require("./core/point"); // --------------------------------------------------------------------------- // Curve registry // // Lookup functions for SEC 2 / NIST standard curves. // getCurve(name) → CurveParams { p, a, b, n, h, coord } // getGenerator(name) → Point(Gx, Gy, curve) // --------------------------------------------------------------------------- (0, _globals.describe)('Curve registry', function () { (0, _globals.test)('getCurve returns a valid CurveParams with all fields', function () { var curve = (0, _registry.getCurve)('secp256k1'); (0, _globals.expect)(curve.p).toBeDefined(); (0, _globals.expect)(curve.a).toBeDefined(); (0, _globals.expect)(curve.b).toBeDefined(); (0, _globals.expect)(curve.n).toBeDefined(); (0, _globals.expect)(curve.h).toBeDefined(); }); (0, _globals.test)('getGenerator returns a point that satisfies y² ≡ x³ + ax + b (mod p)', function () { var G = (0, _registry.getGenerator)('secp256k1'); (0, _globals.expect)(G.x).not.toBe(null); (0, _globals.expect)(G.y).not.toBe(null); (0, _globals.expect)(G.isOnCurve()).toBe(true); }); (0, _globals.test)('getCurve throws for unknown curve names', function () { (0, _globals.expect)(function () { return (0, _registry.getCurve)('invalidCurveName'); }).toThrow(); }); (0, _globals.test)('getGenerator throws for unknown curve names', function () { (0, _globals.expect)(function () { return (0, _registry.getGenerator)('invalidCurveName'); }).toThrow(); }); (0, _globals.test)('lookup is case-insensitive', function () { var c1 = (0, _registry.getCurve)('secp256k1'); var c2 = (0, _registry.getCurve)('SECP256K1'); (0, _globals.expect)(c1.p).toBe(c2.p); (0, _globals.expect)(c1.n).toBe(c2.n); }); (0, _globals.test)('all 8 standard curves are accessible and their generators are on-curve', function () { var names = ['secp192k1', 'secp192r1', 'secp224k1', 'secp224r1', 'secp256k1', 'secp256r1', 'secp384r1', 'secp521r1']; for (var _i = 0, _names = names; _i < _names.length; _i++) { var name = _names[_i]; var curve = (0, _registry.getCurve)(name); (0, _globals.expect)(curve.p > 0n).toBe(true); var G = (0, _registry.getGenerator)(name); (0, _globals.expect)(G.isOnCurve()).toBe(true); } }); }); // --------------------------------------------------------------------------- // Curve validation // // A valid (non-singular) elliptic curve y² = x³ + ax + b (mod p) requires: // Δ = -16(4a³ + 27b²) ≠ 0 (mod p) // // CurveParams validates this at construction time. // --------------------------------------------------------------------------- (0, _globals.describe)('Curve validation', function () { (0, _globals.test)('well-formed curve is created without errors', function () { var curve = new _curve.CurveParams({ p: 23n, a: 1n, b: 1n, n: 28n, h: 1n }); (0, _globals.expect)(curve.p).toBe(23n); (0, _globals.expect)(curve.a).toBe(1n); (0, _globals.expect)(curve.b).toBe(1n); }); // y² = x³ (a=0, b=0) → 4·0³ + 27·0² = 0 (0, _globals.test)('singular curve a=0, b=0 raises error', function () { (0, _globals.expect)(function () { return new _curve.CurveParams({ p: 23n, a: 0n, b: 0n, n: 1n }); }).toThrow('Singular curve'); }); // 4·(-3)³ + 27·(2)² = -108 + 108 = 0 (0, _globals.test)('singular curve a=-3, b=2, p=7 raises error', function () { (0, _globals.expect)(function () { return new _curve.CurveParams({ p: 7n, a: -3n, b: 2n, n: 1n }); }).toThrow(); }); (0, _globals.test)('all registry curves have non-zero discriminant', function () { var names = ['secp192k1', 'secp192r1', 'secp224k1', 'secp224r1', 'secp256k1', 'secp256r1', 'secp384r1', 'secp521r1']; var _loop = function _loop() { var name = _names2[_i2]; // If discriminant were zero, getCurve would throw (0, _globals.expect)(function () { return (0, _registry.getCurve)(name); }).not.toThrow(); }; for (var _i2 = 0, _names2 = names; _i2 < _names2.length; _i2++) { _loop(); } }); (0, _globals.test)('explicit AFFINE coordinate system is accepted', function () { var curve = new _curve.CurveParams({ p: 23n, a: 1n, b: 1n, n: 28n, coord: _curve.CoordinateSystem.AFFINE }); (0, _globals.expect)(curve.coord).toBe(_curve.CoordinateSystem.AFFINE); }); (0, _globals.test)('CurveParams is frozen (immutable)', function () { var curve = new _curve.CurveParams({ p: 23n, a: 1n, b: 1n, n: 28n }); (0, _globals.expect)(Object.isFrozen(curve)).toBe(true); }); }); // --------------------------------------------------------------------------- // Coordinate system settings // // The default coordinate system is JACOBIAN for performance (~3× faster // scalar multiplication). Both systems must produce identical results. // --------------------------------------------------------------------------- (0, _globals.describe)('Coordinate system settings', function () { (0, _globals.test)('default coordinate system is JACOBIAN', function () { var curve = (0, _registry.getCurve)('secp256r1'); (0, _globals.expect)(curve.coord).toBe(_curve.CoordinateSystem.JACOBIAN); }); // 42·G must be the same point regardless of coordinate system (0, _globals.test)('affine and Jacobian produce identical results for 42·G on secp192k1', function () { var curveJac = (0, _registry.getCurve)('secp192k1'); var curveAff = new _curve.CurveParams({ p: curveJac.p, a: curveJac.a, b: curveJac.b, n: curveJac.n, h: curveJac.h, coord: _curve.CoordinateSystem.AFFINE }); var Gjac = (0, _registry.getGenerator)('secp192k1'); var Gaff = new _point.Point(Gjac.x, Gjac.y, curveAff); var resultJac = Gjac.mul(42n); var resultAff = Gaff.mul(42n); (0, _globals.expect)(resultJac.x).toBe(resultAff.x); (0, _globals.expect)(resultJac.y).toBe(resultAff.y); }); }); //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfZ2xvYmFscyIsInJlcXVpcmUiLCJfcmVnaXN0cnkiLCJfY3VydmUiLCJfcG9pbnQiLCJkZXNjcmliZSIsInRlc3QiLCJjdXJ2ZSIsImdldEN1cnZlIiwiZXhwZWN0IiwicCIsInRvQmVEZWZpbmVkIiwiYSIsImIiLCJuIiwiaCIsIkciLCJnZXRHZW5lcmF0b3IiLCJ4Iiwibm90IiwidG9CZSIsInkiLCJpc09uQ3VydmUiLCJ0b1Rocm93IiwiYzEiLCJjMiIsIm5hbWVzIiwiX2kiLCJfbmFtZXMiLCJsZW5ndGgiLCJuYW1lIiwiQ3VydmVQYXJhbXMiLCJfbG9vcCIsIl9uYW1lczIiLCJfaTIiLCJjb29yZCIsIkNvb3JkaW5hdGVTeXN0ZW0iLCJBRkZJTkUiLCJPYmplY3QiLCJpc0Zyb3plbiIsIkpBQ09CSUFOIiwiY3VydmVKYWMiLCJjdXJ2ZUFmZiIsIkdqYWMiLCJHYWZmIiwiUG9pbnQiLCJyZXN1bHRKYWMiLCJtdWwiLCJyZXN1bHRBZmYiXSwic291cmNlcyI6WyIuLi8uLi9zcmMvY3VydmVzLnRlc3QuanMiXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgdGVzdCwgZXhwZWN0LCBkZXNjcmliZSB9IGZyb20gJ0BqZXN0L2dsb2JhbHMnXG5pbXBvcnQgeyBnZXRDdXJ2ZSwgZ2V0R2VuZXJhdG9yIH0gZnJvbSAnLi9jdXJ2ZXMvcmVnaXN0cnknXG5pbXBvcnQgeyBDb29yZGluYXRlU3lzdGVtLCBDdXJ2ZVBhcmFtcyB9IGZyb20gJy4vY29yZS9jdXJ2ZSdcbmltcG9ydCB7IFBvaW50IH0gZnJvbSAnLi9jb3JlL3BvaW50J1xuXG4vLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbi8vIEN1cnZlIHJlZ2lzdHJ5XG4vL1xuLy8gTG9va3VwIGZ1bmN0aW9ucyBmb3IgU0VDIDIgLyBOSVNUIHN0YW5kYXJkIGN1cnZlcy5cbi8vIGdldEN1cnZlKG5hbWUpICAgICDihpIgQ3VydmVQYXJhbXMgeyBwLCBhLCBiLCBuLCBoLCBjb29yZCB9XG4vLyBnZXRHZW5lcmF0b3IobmFtZSkg4oaSIFBvaW50KEd4LCBHeSwgY3VydmUpXG4vLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cblxuZGVzY3JpYmUoJ0N1cnZlIHJlZ2lzdHJ5JywgKCkgPT4ge1xuICB0ZXN0KCdnZXRDdXJ2ZSByZXR1cm5zIGEgdmFsaWQgQ3VydmVQYXJhbXMgd2l0aCBhbGwgZmllbGRzJywgKCkgPT4ge1xuICAgIGNvbnN0IGN1cnZlID0gZ2V0Q3VydmUoJ3NlY3AyNTZrMScpXG4gICAgZXhwZWN0KGN1cnZlLnApLnRvQmVEZWZpbmVkKClcbiAgICBleHBlY3QoY3VydmUuYSkudG9CZURlZmluZWQoKVxuICAgIGV4cGVjdChjdXJ2ZS5iKS50b0JlRGVmaW5lZCgpXG4gICAgZXhwZWN0KGN1cnZlLm4pLnRvQmVEZWZpbmVkKClcbiAgICBleHBlY3QoY3VydmUuaCkudG9CZURlZmluZWQoKVxuICB9KVxuXG4gIHRlc3QoJ2dldEdlbmVyYXRvciByZXR1cm5zIGEgcG9pbnQgdGhhdCBzYXRpc2ZpZXMgecKyIOKJoSB4wrMgKyBheCArIGIgKG1vZCBwKScsICgpID0+IHtcbiAgICBjb25zdCBHID0gZ2V0R2VuZXJhdG9yKCdzZWNwMjU2azEnKVxuICAgIGV4cGVjdChHLngpLm5vdC50b0JlKG51bGwpXG4gICAgZXhwZWN0KEcueSkubm90LnRvQmUobnVsbClcbiAgICBleHBlY3QoRy5pc09uQ3VydmUoKSkudG9CZSh0cnVlKVxuICB9KVxuXG4gIHRlc3QoJ2dldEN1cnZlIHRocm93cyBmb3IgdW5rbm93biBjdXJ2ZSBuYW1lcycsICgpID0+IHtcbiAgICBleHBlY3QoKCkgPT4gZ2V0Q3VydmUoJ2ludmFsaWRDdXJ2ZU5hbWUnKSkudG9UaHJvdygpXG4gIH0pXG5cbiAgdGVzdCgnZ2V0R2VuZXJhdG9yIHRocm93cyBmb3IgdW5rbm93biBjdXJ2ZSBuYW1lcycsICgpID0+IHtcbiAgICBleHBlY3QoKCkgPT4gZ2V0R2VuZXJhdG9yKCdpbnZhbGlkQ3VydmVOYW1lJykpLnRvVGhyb3coKVxuICB9KVxuXG4gIHRlc3QoJ2xvb2t1cCBpcyBjYXNlLWluc2Vuc2l0aXZlJywgKCkgPT4ge1xuICAgIGNvbnN0IGMxID0gZ2V0Q3VydmUoJ3NlY3AyNTZrMScpXG4gICAgY29uc3QgYzIgPSBnZXRDdXJ2ZSgnU0VDUDI1NksxJylcbiAgICBleHBlY3QoYzEucCkudG9CZShjMi5wKVxuICAgIGV4cGVjdChjMS5uKS50b0JlKGMyLm4pXG4gIH0pXG5cbiAgdGVzdCgnYWxsIDggc3RhbmRhcmQgY3VydmVzIGFyZSBhY2Nlc3NpYmxlIGFuZCB0aGVpciBnZW5lcmF0b3JzIGFyZSBvbi1jdXJ2ZScsICgpID0+IHtcbiAgICBjb25zdCBuYW1lcyA9IFtcbiAgICAgICdzZWNwMTkyazEnLFxuICAgICAgJ3NlY3AxOTJyMScsXG4gICAgICAnc2VjcDIyNGsxJyxcbiAgICAgICdzZWNwMjI0cjEnLFxuICAgICAgJ3NlY3AyNTZrMScsXG4gICAgICAnc2VjcDI1NnIxJyxcbiAgICAgICdzZWNwMzg0cjEnLFxuICAgICAgJ3NlY3A1MjFyMScsXG4gICAgXVxuICAgIGZvciAoY29uc3QgbmFtZSBvZiBuYW1lcykge1xuICAgICAgY29uc3QgY3VydmUgPSBnZXRDdXJ2ZShuYW1lKVxuICAgICAgZXhwZWN0KGN1cnZlLnAgPiAwbikudG9CZSh0cnVlKVxuICAgICAgY29uc3QgRyA9IGdldEdlbmVyYXRvcihuYW1lKVxuICAgICAgZXhwZWN0KEcuaXNPbkN1cnZlKCkpLnRvQmUodHJ1ZSlcbiAgICB9XG4gIH0pXG59KVxuXG4vLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbi8vIEN1cnZlIHZhbGlkYXRpb25cbi8vXG4vLyBBIHZhbGlkIChub24tc2luZ3VsYXIpIGVsbGlwdGljIGN1cnZlIHnCsiA9IHjCsyArIGF4ICsgYiAobW9kIHApIHJlcXVpcmVzOlxuLy8gICDOlCA9IC0xNig0YcKzICsgMjdiwrIpIOKJoCAwICAobW9kIHApXG4vL1xuLy8gQ3VydmVQYXJhbXMgdmFsaWRhdGVzIHRoaXMgYXQgY29uc3RydWN0aW9uIHRpbWUuXG4vLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cblxuZGVzY3JpYmUoJ0N1cnZlIHZhbGlkYXRpb24nLCAoKSA9PiB7XG4gIHRlc3QoJ3dlbGwtZm9ybWVkIGN1cnZlIGlzIGNyZWF0ZWQgd2l0aG91dCBlcnJvcnMnLCAoKSA9PiB7XG4gICAgY29uc3QgY3VydmUgPSBuZXcgQ3VydmVQYXJhbXMoeyBwOiAyM24sIGE6IDFuLCBiOiAxbiwgbjogMjhuLCBoOiAxbiB9KVxuICAgIGV4cGVjdChjdXJ2ZS5wKS50b0JlKDIzbilcbiAgICBleHBlY3QoY3VydmUuYSkudG9CZSgxbilcbiAgICBleHBlY3QoY3VydmUuYikudG9CZSgxbilcbiAgfSlcblxuICAvLyB5wrIgPSB4wrMgKGE9MCwgYj0wKSDihpIgNMK3MMKzICsgMjfCtzDCsiA9IDBcbiAgdGVzdCgnc2luZ3VsYXIgY3VydmUgYT0wLCBiPTAgcmFpc2VzIGVycm9yJywgKCkgPT4ge1xuICAgIGV4cGVjdCgoKSA9PiBuZXcgQ3VydmVQYXJhbXMoeyBwOiAyM24sIGE6IDBuLCBiOiAwbiwgbjogMW4gfSkpLnRvVGhyb3coXG4gICAgICAnU2luZ3VsYXIgY3VydmUnLFxuICAgIClcbiAgfSlcblxuICAvLyA0wrcoLTMpwrMgKyAyN8K3KDIpwrIgPSAtMTA4ICsgMTA4ID0gMFxuICB0ZXN0KCdzaW5ndWxhciBjdXJ2ZSBhPS0zLCBiPTIsIHA9NyByYWlzZXMgZXJyb3InLCAoKSA9PiB7XG4gICAgZXhwZWN0KCgpID0+IG5ldyBDdXJ2ZVBhcmFtcyh7IHA6IDduLCBhOiAtM24sIGI6IDJuLCBuOiAxbiB9KSkudG9UaHJvdygpXG4gIH0pXG5cbiAgdGVzdCgnYWxsIHJlZ2lzdHJ5IGN1cnZlcyBoYXZlIG5vbi16ZXJvIGRpc2NyaW1pbmFudCcsICgpID0+IHtcbiAgICBjb25zdCBuYW1lcyA9IFtcbiAgICAgICdzZWNwMTkyazEnLFxuICAgICAgJ3NlY3AxOTJyMScsXG4gICAgICAnc2VjcDIyNGsxJyxcbiAgICAgICdzZWNwMjI0cjEnLFxuICAgICAgJ3NlY3AyNTZrMScsXG4gICAgICAnc2VjcDI1NnIxJyxcbiAgICAgICdzZWNwMzg0cjEnLFxuICAgICAgJ3NlY3A1MjFyMScsXG4gICAgXVxuICAgIGZvciAoY29uc3QgbmFtZSBvZiBuYW1lcykge1xuICAgICAgLy8gSWYgZGlzY3JpbWluYW50IHdlcmUgemVybywgZ2V0Q3VydmUgd291bGQgdGhyb3dcbiAgICAgIGV4cGVjdCgoKSA9PiBnZXRDdXJ2ZShuYW1lKSkubm90LnRvVGhyb3coKVxuICAgIH1cbiAgfSlcblxuICB0ZXN0KCdleHBsaWNpdCBBRkZJTkUgY29vcmRpbmF0ZSBzeXN0ZW0gaXMgYWNjZXB0ZWQnLCAoKSA9PiB7XG4gICAgY29uc3QgY3VydmUgPSBuZXcgQ3VydmVQYXJhbXMoe1xuICAgICAgcDogMjNuLFxuICAgICAgYTogMW4sXG4gICAgICBiOiAxbixcbiAgICAgIG46IDI4bixcbiAgICAgIGNvb3JkOiBDb29yZGluYXRlU3lzdGVtLkFGRklORSxcbiAgICB9KVxuICAgIGV4cGVjdChjdXJ2ZS5jb29yZCkudG9CZShDb29yZGluYXRlU3lzdGVtLkFGRklORSlcbiAgfSlcblxuICB0ZXN0KCdDdXJ2ZVBhcmFtcyBpcyBmcm96ZW4gKGltbXV0YWJsZSknLCAoKSA9PiB7XG4gICAgY29uc3QgY3VydmUgPSBuZXcgQ3VydmVQYXJhbXMoeyBwOiAyM24sIGE6IDFuLCBiOiAxbiwgbjogMjhuIH0pXG4gICAgZXhwZWN0KE9iamVjdC5pc0Zyb3plbihjdXJ2ZSkpLnRvQmUodHJ1ZSlcbiAgfSlcbn0pXG5cbi8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuLy8gQ29vcmRpbmF0ZSBzeXN0ZW0gc2V0dGluZ3Ncbi8vXG4vLyBUaGUgZGVmYXVsdCBjb29yZGluYXRlIHN5c3RlbSBpcyBKQUNPQklBTiBmb3IgcGVyZm9ybWFuY2UgKH4zw5cgZmFzdGVyXG4vLyBzY2FsYXIgbXVsdGlwbGljYXRpb24pLiAgQm90aCBzeXN0ZW1zIG11c3QgcHJvZHVjZSBpZGVudGljYWwgcmVzdWx0cy5cbi8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuXG5kZXNjcmliZSgnQ29vcmRpbmF0ZSBzeXN0ZW0gc2V0dGluZ3MnLCAoKSA9PiB7XG4gIHRlc3QoJ2RlZmF1bHQgY29vcmRpbmF0ZSBzeXN0ZW0gaXMgSkFDT0JJQU4nLCAoKSA9PiB7XG4gICAgY29uc3QgY3VydmUgPSBnZXRDdXJ2ZSgnc2VjcDI1NnIxJylcbiAgICBleHBlY3QoY3VydmUuY29vcmQpLnRvQmUoQ29vcmRpbmF0ZVN5c3RlbS5KQUNPQklBTilcbiAgfSlcblxuICAvLyA0MsK3RyBtdXN0IGJlIHRoZSBzYW1lIHBvaW50IHJlZ2FyZGxlc3Mgb2YgY29vcmRpbmF0ZSBzeXN0ZW1cbiAgdGVzdCgnYWZmaW5lIGFuZCBKYWNvYmlhbiBwcm9kdWNlIGlkZW50aWNhbCByZXN1bHRzIGZvciA0MsK3RyBvbiBzZWNwMTkyazEnLCAoKSA9PiB7XG4gICAgY29uc3QgY3VydmVKYWMgPSBnZXRDdXJ2ZSgnc2VjcDE5MmsxJylcbiAgICBjb25zdCBjdXJ2ZUFmZiA9IG5ldyBDdXJ2ZVBhcmFtcyh7XG4gICAgICBwOiBjdXJ2ZUphYy5wLFxuICAgICAgYTogY3VydmVKYWMuYSxcbiAgICAgIGI6IGN1cnZlSmFjLmIsXG4gICAgICBuOiBjdXJ2ZUphYy5uLFxuICAgICAgaDogY3VydmVKYWMuaCxcbiAgICAgIGNvb3JkOiBDb29yZGluYXRlU3lzdGVtLkFGRklORSxcbiAgICB9KVxuXG4gICAgY29uc3QgR2phYyA9IGdldEdlbmVyYXRvcignc2VjcDE5MmsxJylcbiAgICBjb25zdCBHYWZmID0gbmV3IFBvaW50KEdqYWMueCwgR2phYy55LCBjdXJ2ZUFmZilcblxuICAgIGNvbnN0IHJlc3VsdEphYyA9IEdqYWMubXVsKDQybilcbiAgICBjb25zdCByZXN1bHRBZmYgPSBHYWZmLm11bCg0Mm4pXG5cbiAgICBleHBlY3QocmVzdWx0SmFjLngpLnRvQmUocmVzdWx0QWZmLngpXG4gICAgZXhwZWN0KHJlc3VsdEphYy55KS50b0JlKHJlc3VsdEFmZi55KVxuICB9KVxufSlcbiJdLCJtYXBwaW5ncyI6Ijs7QUFBQSxJQUFBQSxRQUFBLEdBQUFDLE9BQUE7QUFDQSxJQUFBQyxTQUFBLEdBQUFELE9BQUE7QUFDQSxJQUFBRSxNQUFBLEdBQUFGLE9BQUE7QUFDQSxJQUFBRyxNQUFBLEdBQUFILE9BQUE7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQSxJQUFBSSxpQkFBUSxFQUFDLGdCQUFnQixFQUFFLFlBQU07RUFDL0IsSUFBQUMsYUFBSSxFQUFDLHNEQUFzRCxFQUFFLFlBQU07SUFDakUsSUFBTUMsS0FBSyxHQUFHLElBQUFDLGtCQUFRLEVBQUMsV0FBVyxDQUFDO0lBQ25DLElBQUFDLGVBQU0sRUFBQ0YsS0FBSyxDQUFDRyxDQUFDLENBQUMsQ0FBQ0MsV0FBVyxDQUFDLENBQUM7SUFDN0IsSUFBQUYsZUFBTSxFQUFDRixLQUFLLENBQUNLLENBQUMsQ0FBQyxDQUFDRCxXQUFXLENBQUMsQ0FBQztJQUM3QixJQUFBRixlQUFNLEVBQUNGLEtBQUssQ0FBQ00sQ0FBQyxDQUFDLENBQUNGLFdBQVcsQ0FBQyxDQUFDO0lBQzdCLElBQUFGLGVBQU0sRUFBQ0YsS0FBSyxDQUFDTyxDQUFDLENBQUMsQ0FBQ0gsV0FBVyxDQUFDLENBQUM7SUFDN0IsSUFBQUYsZUFBTSxFQUFDRixLQUFLLENBQUNRLENBQUMsQ0FBQyxDQUFDSixXQUFXLENBQUMsQ0FBQztFQUMvQixDQUFDLENBQUM7RUFFRixJQUFBTCxhQUFJLEVBQUMsc0VBQXNFLEVBQUUsWUFBTTtJQUNqRixJQUFNVSxDQUFDLEdBQUcsSUFBQUMsc0JBQVksRUFBQyxXQUFXLENBQUM7SUFDbkMsSUFBQVIsZUFBTSxFQUFDTyxDQUFDLENBQUNFLENBQUMsQ0FBQyxDQUFDQyxHQUFHLENBQUNDLElBQUksQ0FBQyxJQUFJLENBQUM7SUFDMUIsSUFBQVgsZUFBTSxFQUFDTyxDQUFDLENBQUNLLENBQUMsQ0FBQyxDQUFDRixHQUFHLENBQUNDLElBQUksQ0FBQyxJQUFJLENBQUM7SUFDMUIsSUFBQVgsZUFBTSxFQUFDTyxDQUFDLENBQUNNLFNBQVMsQ0FBQyxDQUFDLENBQUMsQ0FBQ0YsSUFBSSxDQUFDLElBQUksQ0FBQztFQUNsQyxDQUFDLENBQUM7RUFFRixJQUFBZCxhQUFJLEVBQUMseUNBQXlDLEVBQUUsWUFBTTtJQUNwRCxJQUFBRyxlQUFNLEVBQUM7TUFBQSxPQUFNLElBQUFELGtCQUFRLEVBQUMsa0JBQWtCLENBQUM7SUFBQSxFQUFDLENBQUNlLE9BQU8sQ0FBQyxDQUFDO0VBQ3RELENBQUMsQ0FBQztFQUVGLElBQUFqQixhQUFJLEVBQUMsNkNBQTZDLEVBQUUsWUFBTTtJQUN4RCxJQUFBRyxlQUFNLEVBQUM7TUFBQSxPQUFNLElBQUFRLHNCQUFZLEVBQUMsa0JBQWtCLENBQUM7SUFBQSxFQUFDLENBQUNNLE9BQU8sQ0FBQyxDQUFDO0VBQzFELENBQUMsQ0FBQztFQUVGLElBQUFqQixhQUFJLEVBQUMsNEJBQTRCLEVBQUUsWUFBTTtJQUN2QyxJQUFNa0IsRUFBRSxHQUFHLElBQUFoQixrQkFBUSxFQUFDLFdBQVcsQ0FBQztJQUNoQyxJQUFNaUIsRUFBRSxHQUFHLElBQUFqQixrQkFBUSxFQUFDLFdBQVcsQ0FBQztJQUNoQyxJQUFBQyxlQUFNLEVBQUNlLEVBQUUsQ0FBQ2QsQ0FBQyxDQUFDLENBQUNVLElBQUksQ0FBQ0ssRUFBRSxDQUFDZixDQUFDLENBQUM7SUFDdkIsSUFBQUQsZUFBTSxFQUFDZSxFQUFFLENBQUNWLENBQUMsQ0FBQyxDQUFDTSxJQUFJLENBQUNLLEVBQUUsQ0FBQ1gsQ0FBQyxDQUFDO0VBQ3pCLENBQUMsQ0FBQztFQUVGLElBQUFSLGFBQUksRUFBQyx3RUFBd0UsRUFBRSxZQUFNO0lBQ25GLElBQU1vQixLQUFLLEdBQUcsQ0FDWixXQUFXLEVBQ1gsV0FBVyxFQUNYLFdBQVcsRUFDWCxXQUFXLEVBQ1gsV0FBVyxFQUNYLFdBQVcsRUFDWCxXQUFXLEVBQ1gsV0FBVyxDQUNaO0lBQ0QsU0FBQUMsRUFBQSxNQUFBQyxNQUFBLEdBQW1CRixLQUFLLEVBQUFDLEVBQUEsR0FBQUMsTUFBQSxDQUFBQyxNQUFBLEVBQUFGLEVBQUEsSUFBRTtNQUFyQixJQUFNRyxJQUFJLEdBQUFGLE1BQUEsQ0FBQUQsRUFBQTtNQUNiLElBQU1wQixLQUFLLEdBQUcsSUFBQUMsa0JBQVEsRUFBQ3NCLElBQUksQ0FBQztNQUM1QixJQUFBckIsZUFBTSxFQUFDRixLQUFLLENBQUNHLENBQUMsR0FBRyxFQUFFLENBQUMsQ0FBQ1UsSUFBSSxDQUFDLElBQUksQ0FBQztNQUMvQixJQUFNSixDQUFDLEdBQUcsSUFBQUMsc0JBQVksRUFBQ2EsSUFBSSxDQUFDO01BQzVCLElBQUFyQixlQUFNLEVBQUNPLENBQUMsQ0FBQ00sU0FBUyxDQUFDLENBQUMsQ0FBQyxDQUFDRixJQUFJLENBQUMsSUFBSSxDQUFDO0lBQ2xDO0VBQ0YsQ0FBQyxDQUFDO0FBQ0osQ0FBQyxDQUFDOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUEsSUFBQWYsaUJBQVEsRUFBQyxrQkFBa0IsRUFBRSxZQUFNO0VBQ2pDLElBQUFDLGFBQUksRUFBQyw2Q0FBNkMsRUFBRSxZQUFNO0lBQ3hELElBQU1DLEtBQUssR0FBRyxJQUFJd0Isa0JBQVcsQ0FBQztNQUFFckIsQ0FBQyxFQUFFLEdBQUc7TUFBRUUsQ0FBQyxFQUFFLEVBQUU7TUFBRUMsQ0FBQyxFQUFFLEVBQUU7TUFBRUMsQ0FBQyxFQUFFLEdBQUc7TUFBRUMsQ0FBQyxFQUFFO0lBQUcsQ0FBQyxDQUFDO0lBQ3RFLElBQUFOLGVBQU0sRUFBQ0YsS0FBSyxDQUFDRyxDQUFDLENBQUMsQ0FBQ1UsSUFBSSxDQUFDLEdBQUcsQ0FBQztJQUN6QixJQUFBWCxlQUFNLEVBQUNGLEtBQUssQ0FBQ0ssQ0FBQyxDQUFDLENBQUNRLElBQUksQ0FBQyxFQUFFLENBQUM7SUFDeEIsSUFBQVgsZUFBTSxFQUFDRixLQUFLLENBQUNNLENBQUMsQ0FBQyxDQUFDTyxJQUFJLENBQUMsRUFBRSxDQUFDO0VBQzFCLENBQUMsQ0FBQzs7RUFFRjtFQUNBLElBQUFkLGFBQUksRUFBQyxzQ0FBc0MsRUFBRSxZQUFNO0lBQ2pELElBQUFHLGVBQU0sRUFBQztNQUFBLE9BQU0sSUFBSXNCLGtCQUFXLENBQUM7UUFBRXJCLENBQUMsRUFBRSxHQUFHO1FBQUVFLENBQUMsRUFBRSxFQUFFO1FBQUVDLENBQUMsRUFBRSxFQUFFO1FBQUVDLENBQUMsRUFBRTtNQUFHLENBQUMsQ0FBQztJQUFBLEVBQUMsQ0FBQ1MsT0FBTyxDQUNwRSxnQkFDRixDQUFDO0VBQ0gsQ0FBQyxDQUFDOztFQUVGO0VBQ0EsSUFBQWpCLGFBQUksRUFBQyw0Q0FBNEMsRUFBRSxZQUFNO0lBQ3ZELElBQUFHLGVBQU0sRUFBQztNQUFBLE9BQU0sSUFBSXNCLGtCQUFXLENBQUM7UUFBRXJCLENBQUMsRUFBRSxFQUFFO1FBQUVFLENBQUMsRUFBRSxDQUFDLEVBQUU7UUFBRUMsQ0FBQyxFQUFFLEVBQUU7UUFBRUMsQ0FBQyxFQUFFO01BQUcsQ0FBQyxDQUFDO0lBQUEsRUFBQyxDQUFDUyxPQUFPLENBQUMsQ0FBQztFQUMxRSxDQUFDLENBQUM7RUFFRixJQUFBakIsYUFBSSxFQUFDLGdEQUFnRCxFQUFFLFlBQU07SUFDM0QsSUFBTW9CLEtBQUssR0FBRyxDQUNaLFdBQVcsRUFDWCxXQUFXLEVBQ1gsV0FBVyxFQUNYLFdBQVcsRUFDWCxXQUFXLEVBQ1gsV0FBVyxFQUNYLFdBQVcsRUFDWCxXQUFXLENBQ1o7SUFBQSxJQUFBTSxLQUFBLFlBQUFBLE1BQUEsRUFDeUI7TUFBckIsSUFBTUYsSUFBSSxHQUFBRyxPQUFBLENBQUFDLEdBQUE7TUFDYjtNQUNBLElBQUF6QixlQUFNLEVBQUM7UUFBQSxPQUFNLElBQUFELGtCQUFRLEVBQUNzQixJQUFJLENBQUM7TUFBQSxFQUFDLENBQUNYLEdBQUcsQ0FBQ0ksT0FBTyxDQUFDLENBQUM7SUFDNUMsQ0FBQztJQUhELFNBQUFXLEdBQUEsTUFBQUQsT0FBQSxHQUFtQlAsS0FBSyxFQUFBUSxHQUFBLEdBQUFELE9BQUEsQ0FBQUosTUFBQSxFQUFBSyxHQUFBO01BQUFGLEtBQUE7SUFBQTtFQUkxQixDQUFDLENBQUM7RUFFRixJQUFBMUIsYUFBSSxFQUFDLCtDQUErQyxFQUFFLFlBQU07SUFDMUQsSUFBTUMsS0FBSyxHQUFHLElBQUl3QixrQkFBVyxDQUFDO01BQzVCckIsQ0FBQyxFQUFFLEdBQUc7TUFDTkUsQ0FBQyxFQUFFLEVBQUU7TUFDTEMsQ0FBQyxFQUFFLEVBQUU7TUFDTEMsQ0FBQyxFQUFFLEdBQUc7TUFDTnFCLEtBQUssRUFBRUMsdUJBQWdCLENBQUNDO0lBQzFCLENBQUMsQ0FBQztJQUNGLElBQUE1QixlQUFNLEVBQUNGLEtBQUssQ0FBQzRCLEtBQUssQ0FBQyxDQUFDZixJQUFJLENBQUNnQix1QkFBZ0IsQ0FBQ0MsTUFBTSxDQUFDO0VBQ25ELENBQUMsQ0FBQztFQUVGLElBQUEvQixhQUFJLEVBQUMsbUNBQW1DLEVBQUUsWUFBTTtJQUM5QyxJQUFNQyxLQUFLLEdBQUcsSUFBSXdCLGtCQUFXLENBQUM7TUFBRXJCLENBQUMsRUFBRSxHQUFHO01BQUVFLENBQUMsRUFBRSxFQUFFO01BQUVDLENBQUMsRUFBRSxFQUFFO01BQUVDLENBQUMsRUFBRTtJQUFJLENBQUMsQ0FBQztJQUMvRCxJQUFBTCxlQUFNLEVBQUM2QixNQUFNLENBQUNDLFFBQVEsQ0FBQ2hDLEtBQUssQ0FBQyxDQUFDLENBQUNhLElBQUksQ0FBQyxJQUFJLENBQUM7RUFDM0MsQ0FBQyxDQUFDO0FBQ0osQ0FBQyxDQUFDOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQSxJQUFBZixpQkFBUSxFQUFDLDRCQUE0QixFQUFFLFlBQU07RUFDM0MsSUFBQUMsYUFBSSxFQUFDLHVDQUF1QyxFQUFFLFlBQU07SUFDbEQsSUFBTUMsS0FBSyxHQUFHLElBQUFDLGtCQUFRLEVBQUMsV0FBVyxDQUFDO0lBQ25DLElBQUFDLGVBQU0sRUFBQ0YsS0FBSyxDQUFDNEIsS0FBSyxDQUFDLENBQUNmLElBQUksQ0FBQ2dCLHVCQUFnQixDQUFDSSxRQUFRLENBQUM7RUFDckQsQ0FBQyxDQUFDOztFQUVGO0VBQ0EsSUFBQWxDLGFBQUksRUFBQyxxRUFBcUUsRUFBRSxZQUFNO0lBQ2hGLElBQU1tQyxRQUFRLEdBQUcsSUFBQWpDLGtCQUFRLEVBQUMsV0FBVyxDQUFDO0lBQ3RDLElBQU1rQyxRQUFRLEdBQUcsSUFBSVgsa0JBQVcsQ0FBQztNQUMvQnJCLENBQUMsRUFBRStCLFFBQVEsQ0FBQy9CLENBQUM7TUFDYkUsQ0FBQyxFQUFFNkIsUUFBUSxDQUFDN0IsQ0FBQztNQUNiQyxDQUFDLEVBQUU0QixRQUFRLENBQUM1QixDQUFDO01BQ2JDLENBQUMsRUFBRTJCLFFBQVEsQ0FBQzNCLENBQUM7TUFDYkMsQ0FBQyxFQUFFMEIsUUFBUSxDQUFDMUIsQ0FBQztNQUNib0IsS0FBSyxFQUFFQyx1QkFBZ0IsQ0FBQ0M7SUFDMUIsQ0FBQyxDQUFDO0lBRUYsSUFBTU0sSUFBSSxHQUFHLElBQUExQixzQkFBWSxFQUFDLFdBQVcsQ0FBQztJQUN0QyxJQUFNMkIsSUFBSSxHQUFHLElBQUlDLFlBQUssQ0FBQ0YsSUFBSSxDQUFDekIsQ0FBQyxFQUFFeUIsSUFBSSxDQUFDdEIsQ0FBQyxFQUFFcUIsUUFBUSxDQUFDO0lBRWhELElBQU1JLFNBQVMsR0FBR0gsSUFBSSxDQUFDSSxHQUFHLENBQUMsR0FBRyxDQUFDO0lBQy9CLElBQU1DLFNBQVMsR0FBR0osSUFBSSxDQUFDRyxHQUFHLENBQUMsR0FBRyxDQUFDO0lBRS9CLElBQUF0QyxlQUFNLEVBQUNxQyxTQUFTLENBQUM1QixDQUFDLENBQUMsQ0FBQ0UsSUFBSSxDQUFDNEIsU0FBUyxDQUFDOUIsQ0FBQyxDQUFDO0lBQ3JDLElBQUFULGVBQU0sRUFBQ3FDLFNBQVMsQ0FBQ3pCLENBQUMsQ0FBQyxDQUFDRCxJQUFJLENBQUM0QixTQUFTLENBQUMzQixDQUFDLENBQUM7RUFDdkMsQ0FBQyxDQUFDO0FBQ0osQ0FBQyxDQUFDIiwiaWdub3JlTGlzdCI6W119