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
JavaScript
"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+IHtcbiAgICBjb25zdCBuYW1lcyA9IFtcbiAgICAgICdzZWNwMTkyazEnLFxuICAgICAgJ3NlY3AxOTJyMScsXG4gICAgICAnc2VjcDIyNGsxJyxcbiAgICAgICdzZWNwMjI0cjEnLFxuICAgICAgJ3NlY3AyNTZrMScsXG4gICAgICAnc2VjcDI1NnIxJyxcbiAgICAgICdzZWNwMzg0cjEnLFxuICAgICAgJ3NlY3A1MjFyMScsXG4gICAgXVxuICAgIGZvciAoY29uc3QgbmFtZSBvZiBuYW1lcykge1xuICAgICAgLy8gSWYgZGlzY3JpbWluYW50IHdlcmUgemVybywgZ2V0Q3VydmUgd291bGQgdGhyb3dcbiAgICAgIGV4cGVjdCgoKSA9PiBnZXRDdXJ2ZShuYW1lKSkubm90LnRvVGhyb3coKVxuICAgIH1cbiAgfSlcblxuICB0ZXN0KCdleHBsaWNpdCBBRkZJTkUgY29vcmRpbmF0ZSBzeXN0ZW0gaXMgYWNjZXB0ZWQnLCAoKSA9PiB7XG4gICAgY29uc3QgY3VydmUgPSBuZXcgQ3VydmVQYXJhbXMoe1xuICAgICAgcDogMjNuLFxuICAgICAgYTogMW4sXG4gICAgICBiOiAxbixcbiAgICAgIG46IDI4bixcbiAgICAgIGNvb3JkOiBDb29yZGluYXRlU3lzdGVtLkFGRklORSxcbiAgICB9KVxuICAgIGV4cGVjdChjdXJ2ZS5jb29yZCkudG9CZShDb29yZGluYXRlU3lzdGVtLkFGRklORSlcbiAgfSlcblxuICB0ZXN0KCdDdXJ2ZVBhcmFtcyBpcyBmcm96ZW4gKGltbXV0YWJsZSknLCAoKSA9PiB7XG4gICAgY29uc3QgY3VydmUgPSBuZXcgQ3VydmVQYXJhbXMoeyBwOiAyM24sIGE6IDFuLCBiOiAxbiwgbjogMjhuIH0pXG4gICAgZXhwZWN0KE9iamVjdC5pc0Zyb3plbihjdXJ2ZSkpLnRvQmUodHJ1ZSlcbiAgfSlcbn0pXG5cbi8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuLy8gQ29vcmRpbmF0ZSBzeXN0ZW0gc2V0dGluZ3Ncbi8vXG4vLyBUaGUgZGVmYXVsdCBjb29yZGluYXRlIHN5c3RlbSBpcyBKQUNPQklBTiBmb3IgcGVyZm9ybWFuY2UgKH4zw5cgZmFzdGVyXG4vLyBzY2FsYXIgbXVsdGlwbGljYXRpb24pLiAgQm90aCBzeXN0ZW1zIG11c3QgcHJvZHVjZSBpZGVudGljYWwgcmVzdWx0cy5cbi8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuXG5kZXNjcmliZSgnQ29vcmRpbmF0ZSBzeXN0ZW0gc2V0dGluZ3MnLCAoKSA9PiB7XG4gIHRlc3QoJ2RlZmF1bHQgY29vcmRpbmF0ZSBzeXN0ZW0gaXMgSkFDT0JJQU4nLCAoKSA9PiB7XG4gICAgY29uc3QgY3VydmUgPSBnZXRDdXJ2ZSgnc2VjcDI1NnIxJylcbiAgICBleHBlY3QoY3VydmUuY29vcmQpLnRvQmUoQ29vcmRpbmF0ZVN5c3RlbS5KQUNPQklBTilcbiAgfSlcblxuICAvLyA0MsK3RyBtdXN0IGJlIHRoZSBzYW1lIHBvaW50IHJlZ2FyZGxlc3Mgb2YgY29vcmRpbmF0ZSBzeXN0ZW1cbiAgdGVzdCgnYWZmaW5lIGFuZCBKYWNvYmlhbiBwcm9kdWNlIGlkZW50aWNhbCByZXN1bHRzIGZvciA0MsK3RyBvbiBzZWNwMTkyazEnLCAoKSA9PiB7XG4gICAgY29uc3QgY3VydmVKYWMgPSBnZXRDdXJ2ZSgnc2VjcDE5MmsxJylcbiAgICBjb25zdCBjdXJ2ZUFmZiA9IG5ldyBDdXJ2ZVBhcmFtcyh7XG4gICAgICBwOiBjdXJ2ZUphYy5wLFxuICAgICAgYTogY3VydmVKYWMuYSxcbiAgICAgIGI6IGN1cnZlSmFjLmIsXG4gICAgICBuOiBjdXJ2ZUphYy5uLFxuICAgICAgaDogY3VydmVKYWMuaCxcbiAgICAgIGNvb3JkOiBDb29yZGluYXRlU3lzdGVtLkFGRklORSxcbiAgICB9KVxuXG4gICAgY29uc3QgR2phYyA9IGdldEdlbmVyYXRvcignc2VjcDE5MmsxJylcbiAgICBjb25zdCBHYWZmID0gbmV3IFBvaW50KEdqYWMueCwgR2phYy55LCBjdXJ2ZUFmZilcblxuICAgIGNvbnN0IHJlc3VsdEphYyA9IEdqYWMubXVsKDQybilcbiAgICBjb25zdCByZXN1bHRBZmYgPSBHYWZmLm11bCg0Mm4pXG5cbiAgICBleHBlY3QocmVzdWx0SmFjLngpLnRvQmUocmVzdWx0QWZmLngpXG4gICAgZXhwZWN0KHJlc3VsdEphYy55KS50b0JlKHJlc3VsdEFmZi55KVxuICB9KVxufSlcbiJdLCJtYXBwaW5ncyI6Ijs7QUFBQSxJQUFBQSxRQUFBLEdBQUFDLE9BQUE7QUFDQSxJQUFBQyxTQUFBLEdBQUFELE9BQUE7QUFDQSxJQUFBRSxNQUFBLEdBQUFGLE9BQUE7QUFDQSxJQUFBRyxNQUFBLEdBQUFILE9BQUE7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQSxJQUFBSSxpQkFBUSxFQUFDLGdCQUFnQixFQUFFLFlBQU07RUFDL0IsSUFBQUMsYUFBSSxFQUFDLHNEQUFzRCxFQUFFLFlBQU07SUFDakUsSUFBTUMsS0FBSyxHQUFHLElBQUFDLGtCQUFRLEVBQUMsV0FBVyxDQUFDO0lBQ25DLElBQUFDLGVBQU0sRUFBQ0YsS0FBSyxDQUFDRyxDQUFDLENBQUMsQ0FBQ0MsV0FBVyxDQUFDLENBQUM7SUFDN0IsSUFBQUYsZUFBTSxFQUFDRixLQUFLLENBQUNLLENBQUMsQ0FBQyxDQUFDRCxXQUFXLENBQUMsQ0FBQztJQUM3QixJQUFBRixlQUFNLEVBQUNGLEtBQUssQ0FBQ00sQ0FBQyxDQUFDLENBQUNGLFdBQVcsQ0FBQyxDQUFDO0lBQzdCLElBQUFGLGVBQU0sRUFBQ0YsS0FBSyxDQUFDTyxDQUFDLENBQUMsQ0FBQ0gsV0FBVyxDQUFDLENBQUM7SUFDN0IsSUFBQUYsZUFBTSxFQUFDRixLQUFLLENB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M0MsQ0FBQyxDQUFDO0FBQ0osQ0FBQyxDQUFDOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQSxJQUFBZixpQkFBUSxFQUFDLDRCQUE0QixFQUFFLFlBQU07RUFDM0MsSUFBQUMsYUFBSSxFQUFDLHVDQUF1QyxFQUFFLFlBQU07SUFDbEQsSUFBTUMsS0FBSyxHQUFHLElBQUFDLGtCQUFRLEVBQUMsV0FBVyxDQUFDO0lBQ25DLElBQUFDLGVBQU0sRUFBQ0YsS0FBSyxDQUFDNEIsS0FBSyxDQUFDLENBQUNmLElBQUksQ0FBQ2dCLHVCQUFnQixDQUFDSSxRQUFRLENBQUM7RUFDckQsQ0FBQyxDQUFDOztFQUVGO0VBQ0EsSUFBQWxDLGFBQUksRUFBQyxxRUFBcUUsRUFBRSxZQUFNO0lBQ2hGLElBQU1tQyxRQUFRLEdBQUcsSUFBQWpDLGtCQUFRLEVBQUMsV0FBVyxDQUFDO0lBQ3RDLElBQU1rQyxRQUFRLEdBQUcsSUFBSVgsa0JBQVcsQ0FBQztNQUMvQnJCLENBQUMsRUFBRStCLFFBQVEsQ0FBQy9CLENBQUM7TUFDYkUsQ0FBQyxFQUFFNkIsUUFBUSxDQUFDN0IsQ0FBQztNQUNiQyxDQUFDLEVBQUU0QixRQUFRLENBQUM1QixDQUFDO01BQ2JDLENBQUMsRUFBRTJCLFFBQVEsQ0FBQzNCLENBQUM7TUFDYkMsQ0FBQyxFQUFFMEIsUUFBUSxDQUFDMUIsQ0FBQztNQUNib0IsS0FBSyxFQUFFQyx1QkFBZ0IsQ0FBQ0M7SUFDMUIsQ0FBQyxDQUFDO0lBRUYsSUFBTU0sSUFBSSxHQUFHLElBQUExQixzQkFBWSxFQUFDLFdBQVcsQ0FBQztJQUN0QyxJQUFNMkIsSUFBSSxHQUFHLElBQUlDLFlBQUssQ0FBQ0YsSUFBSSxDQUFDekIsQ0FBQyxFQUFFeUIsSUFBSSxDQUFDdEIsQ0FBQyxFQUFFcUIsUUFBUSxDQUFDO0lBRWhELElBQU1JLFNBQVMsR0FBR0gsSUFBSSxDQUFDSSxHQUFHLENBQUMsR0FBRyxDQUFDO0lBQy9CLElBQU1DLFNBQVMsR0FBR0osSUFBSSxDQUFDRyxHQUFHLENBQUMsR0FBRyxDQUFDO0lBRS9CLElBQUF0QyxlQUFNLEVBQUNxQyxTQUFTLENBQUM1QixDQUFDLENBQUMsQ0FBQ0UsSUFBSSxDQUFDNEIsU0FBUyxDQUFDOUIsQ0FBQyxDQUFDO0lBQ3JDLElBQUFULGVBQU0sRUFBQ3FDLFNBQVMsQ0FBQ3pCLENBQUMsQ0FBQyxDQUFDRCxJQUFJLENBQUM0QixTQUFTLENBQUMzQixDQUFDLENBQUM7RUFDdkMsQ0FBQyxDQUFDO0FBQ0osQ0FBQyxDQUFDIiwiaWdub3JlTGlzdCI6W119