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.

112 lines (103 loc) 18.8 kB
"use strict"; var _globals = require("@jest/globals"); var _diffie_hellman = require("./protocols/diffie_hellman"); var _massey_omura = require("./protocols/massey_omura"); var _koblitz = require("./algorithms/koblitz"); var _registry = require("./curves/registry"); function _slicedToArray(r, e) { return _arrayWithHoles(r) || _iterableToArrayLimit(r, e) || _unsupportedIterableToArray(r, e) || _nonIterableRest(); } function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } } function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; } function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (null != t) { var e, n, i, u, a = [], f = !0, o = !1; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) return; f = !1; } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); } catch (r) { o = !0, n = r; } finally { try { if (!f && null != t["return"] && (u = t["return"](), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } } function _arrayWithHoles(r) { if (Array.isArray(r)) return r; } // --------------------------------------------------------------------------- // Elliptic Curve Diffie-Hellman (ECDH) // // Protocol: // 1. Alice: H_A = d_A · G // 2. Bob: H_B = d_B · G // 3. Shared secret: S = d_A · H_B = d_B · H_A = d_A · d_B · G // // Security: relies on the Elliptic Curve Discrete Logarithm Problem (ECDLP). // Given G and Q = d·G, recovering d is computationally infeasible. // --------------------------------------------------------------------------- (0, _globals.describe)('Diffie-Hellman key exchange', function () { (0, _globals.test)('both parties compute the same shared secret', function () { var alice = new _diffie_hellman.DiffieHellman(12345n); var bob = new _diffie_hellman.DiffieHellman(67890n); // S_A = d_A · H_B = d_A · d_B · G var secretAlice = alice.computeSharedSecret(bob.publicKey); // S_B = d_B · H_A = d_B · d_A · G var secretBob = bob.computeSharedSecret(alice.publicKey); (0, _globals.expect)(secretAlice.x).toBe(secretBob.x); (0, _globals.expect)(secretAlice.y).toBe(secretBob.y); }); (0, _globals.test)('default curve is secp256k1', function () { (0, _globals.expect)(new _diffie_hellman.DiffieHellman(1n).curveName).toBe('secp256k1'); }); // H = d·G must satisfy y² ≡ x³ + ax + b (mod p) (0, _globals.test)('public key lies on the curve', function () { (0, _globals.expect)(new _diffie_hellman.DiffieHellman(42n).publicKey.isOnCurve()).toBe(true); }); }); // --------------------------------------------------------------------------- // Massey-Omura three-pass protocol // // Allows two parties to exchange a secret point M without sharing keys // beforehand. Each party uses only their own private key. // // Three-pass flow: // 1. Alice encrypts: C₁ = e_A · M // 2. Bob encrypts: C₂ = e_B · C₁ // 3. Alice decrypts: C₃ = e_A⁻¹ · C₂ // 4. Bob decrypts: M = e_B⁻¹ · C₃ // // Works because scalar multiplication is commutative: // e_A · (e_B · M) = e_B · (e_A · M) // // Requirement: gcd(private_key, n) = 1 (so that e⁻¹ mod n exists) // --------------------------------------------------------------------------- (0, _globals.describe)('Massey-Omura three-pass protocol', function () { (0, _globals.test)('complete encryption/decryption cycle recovers original message', function () { var sender = new _massey_omura.MasseyOmura(123456n); var receiver = new _massey_omura.MasseyOmura(654321n); var message = (0, _registry.getGenerator)(sender.curveName); // C₁ = e_sender · M var c1 = sender.encrypt(message); // C₂ = e_receiver · C₁ var c2 = receiver.encrypt(c1); // C₃ = e_sender⁻¹ · C₂ (removes sender's encryption) var c3 = sender.decrypt(c2); // M = e_receiver⁻¹ · C₃ (removes receiver's encryption) var recovered = receiver.decrypt(c3); (0, _globals.expect)(recovered.x).toBe(message.x); (0, _globals.expect)(recovered.y).toBe(message.y); }); // d·G must lie on the curve (0, _globals.test)('point multiplication with private key produces on-curve point', function () { var mo = new _massey_omura.MasseyOmura(123456n); var G = (0, _registry.getGenerator)(mo.curveName); (0, _globals.expect)(G.mul(123456n).isOnCurve()).toBe(true); }); (0, _globals.test)('default curve is secp521r1', function () { (0, _globals.expect)(new _massey_omura.MasseyOmura(1n).curveName).toBe('secp521r1'); }); // Full end-to-end with Koblitz encoding (0, _globals.test)('three-pass exchange with Koblitz-encoded message', function () { var koblitz = new _koblitz.Koblitz('secp521r1'); var _koblitz$encode = koblitz.encode('Hello!'), _koblitz$encode2 = _slicedToArray(_koblitz$encode, 2), message = _koblitz$encode2[0], j = _koblitz$encode2[1]; var alice = new _massey_omura.MasseyOmura(0xa1n, 'secp521r1'); var bob = new _massey_omura.MasseyOmura(0xb2n, 'secp521r1'); var c1 = alice.encrypt(message); var c2 = bob.encrypt(c1); var c3 = alice.decrypt(c2); var plaintext = bob.decrypt(c3); (0, _globals.expect)(plaintext.x).toBe(message.x); (0, _globals.expect)(plaintext.y).toBe(message.y); (0, _globals.expect)(koblitz.decode(plaintext, j)).toBe('Hello!'); }); }); //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfZ2xvYmFscyIsInJlcXVpcmUiLCJfZGlmZmllX2hlbGxtYW4iLCJfbWFzc2V5X29tdXJhIiwiX2tvYmxpdHoiLCJfcmVnaXN0cnkiLCJfc2xpY2VkVG9BcnJheSIsInIiLCJlIiwiX2FycmF5V2l0aEhvbGVzIiwiX2l0ZXJhYmxlVG9BcnJheUxpbWl0IiwiX3Vuc3VwcG9ydGVkSXRlcmFibGVUb0FycmF5IiwiX25vbkl0ZXJhYmxlUmVzdCIsIlR5cGVFcnJvciIsImEiLCJfYXJyYXlMaWtlVG9BcnJheSIsInQiLCJ0b1N0cmluZyIsImNhbGwiLCJzbGljZSIsImNvbnN0cnVjdG9yIiwibmFtZSIsIkFycmF5IiwiZnJvbSIsInRlc3QiLCJsZW5ndGgiLCJuIiwibCIsIlN5bWJvbCIsIml0ZXJhdG9yIiwiaSIsInUiLCJmIiwibyIsIm5leHQiLCJPYmplY3QiLCJkb25lIiwicHVzaCIsInZhbHVlIiwiaXNBcnJheSIsImRlc2NyaWJlIiwiYWxpY2UiLCJEaWZmaWVIZWxsbWFuIiwiYm9iIiwic2VjcmV0QWxpY2UiLCJjb21wdXRlU2hhcmVkU2VjcmV0IiwicHVibGljS2V5Iiwic2VjcmV0Qm9iIiwiZXhwZWN0IiwieCIsInRvQmUiLCJ5IiwiY3VydmVOYW1lIiwiaXNPbkN1cnZlIiwic2VuZGVyIiwiTWFzc2V5T211cmEiLCJyZWNlaXZlciIsIm1lc3NhZ2UiLCJnZXRHZW5lcmF0b3IiLCJjMSIsImVuY3J5cHQiLCJjMiIsImMzIiwiZGVjcnlwdCIsInJlY292ZXJlZCIsIm1vIiwiRyIsIm11bCIsImtvYmxpdHoiLCJLb2JsaXR6IiwiX2tvYmxpdHokZW5jb2RlIiwiZW5jb2RlIiwiX2tvYmxpdHokZW5jb2RlMiIsImoiLCJwbGFpbnRleHQiLCJkZWNvZGUiXSwic291cmNlcyI6WyIuLi8uLi9zcmMvcHJvdG9jb2xzLnRlc3QuanMiXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgdGVzdCwgZXhwZWN0LCBkZXNjcmliZSB9IGZyb20gJ0BqZXN0L2dsb2JhbHMnXG5pbXBvcnQgeyBEaWZmaWVIZWxsbWFuIH0gZnJvbSAnLi9wcm90b2NvbHMvZGlmZmllX2hlbGxtYW4nXG5pbXBvcnQgeyBNYXNzZXlPbXVyYSB9IGZyb20gJy4vcHJvdG9jb2xzL21hc3NleV9vbXVyYSdcbmltcG9ydCB7IEtvYmxpdHogfSBmcm9tICcuL2FsZ29yaXRobXMva29ibGl0eidcbmltcG9ydCB7IGdldEdlbmVyYXRvciB9IGZyb20gJy4vY3VydmVzL3JlZ2lzdHJ5J1xuXG4vLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbi8vIEVsbGlwdGljIEN1cnZlIERpZmZpZS1IZWxsbWFuIChFQ0RIKVxuLy9cbi8vIFByb3RvY29sOlxuLy8gICAxLiBBbGljZTogIEhfQSA9IGRfQSDCtyBHXG4vLyAgIDIuIEJvYjogICAgSF9CID0gZF9CIMK3IEdcbi8vICAgMy4gU2hhcmVkIHNlY3JldDogIFMgPSBkX0EgwrcgSF9CID0gZF9CIMK3IEhfQSA9IGRfQSDCtyBkX0IgwrcgR1xuLy9cbi8vIFNlY3VyaXR5OiByZWxpZXMgb24gdGhlIEVsbGlwdGljIEN1cnZlIERpc2NyZXRlIExvZ2FyaXRobSBQcm9ibGVtIChFQ0RMUCkuXG4vLyBHaXZlbiBHIGFuZCBRID0gZMK3RywgcmVjb3ZlcmluZyBkIGlzIGNvbXB1dGF0aW9uYWxseSBpbmZlYXNpYmxlLlxuLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5cbmRlc2NyaWJlKCdEaWZmaWUtSGVsbG1hbiBrZXkgZXhjaGFuZ2UnLCAoKSA9PiB7XG4gIHRlc3QoJ2JvdGggcGFydGllcyBjb21wdXRlIHRoZSBzYW1lIHNoYXJlZCBzZWNyZXQnLCAoKSA9PiB7XG4gICAgY29uc3QgYWxpY2UgPSBuZXcgRGlmZmllSGVsbG1hbigxMjM0NW4pXG4gICAgY29uc3QgYm9iID0gbmV3IERpZmZpZUhlbGxtYW4oNjc4OTBuKVxuXG4gICAgLy8gU19BID0gZF9BIMK3IEhfQiA9IGRfQSDCtyBkX0IgwrcgR1xuICAgIGNvbnN0IHNlY3JldEFsaWNlID0gYWxpY2UuY29tcHV0ZVNoYXJlZFNlY3JldChib2IucHVibGljS2V5KVxuICAgIC8vIFNfQiA9IGRfQiDCtyBIX0EgPSBkX0IgwrcgZF9BIMK3IEdcbiAgICBjb25zdCBzZWNyZXRCb2IgPSBib2IuY29tcHV0ZVNoYXJlZFNlY3JldChhbGljZS5wdWJsaWNLZXkpXG5cbiAgICBleHBlY3Qoc2VjcmV0QWxpY2UueCkudG9CZShzZWNyZXRCb2IueClcbiAgICBleHBlY3Qoc2VjcmV0QWxpY2UueSkudG9CZShzZWNyZXRCb2IueSlcbiAgfSlcblxuICB0ZXN0KCdkZWZhdWx0IGN1cnZlIGlzIHNlY3AyNTZrMScsICgpID0+IHtcbiAgICBleHBlY3QobmV3IERpZmZpZUhlbGxtYW4oMW4pLmN1cnZlTmFtZSkudG9CZSgnc2VjcDI1NmsxJylcbiAgfSlcblxuICAvLyBIID0gZMK3RyBtdXN0IHNhdGlzZnkgecKyIOKJoSB4wrMgKyBheCArIGIgKG1vZCBwKVxuICB0ZXN0KCdwdWJsaWMga2V5IGxpZXMgb24gdGhlIGN1cnZlJywgKCkgPT4ge1xuICAgIGV4cGVjdChuZXcgRGlmZmllSGVsbG1hbig0Mm4pLnB1YmxpY0tleS5pc09uQ3VydmUoKSkudG9CZSh0cnVlKVxuICB9KVxufSlcblxuLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4vLyBNYXNzZXktT211cmEgdGhyZWUtcGFzcyBwcm90b2NvbFxuLy9cbi8vIEFsbG93cyB0d28gcGFydGllcyB0byBleGNoYW5nZSBhIHNlY3JldCBwb2ludCBNIHdpdGhvdXQgc2hhcmluZyBrZXlzXG4vLyBiZWZvcmVoYW5kLiAgRWFjaCBwYXJ0eSB1c2VzIG9ubHkgdGhlaXIgb3duIHByaXZhdGUga2V5LlxuLy9cbi8vIFRocmVlLXBhc3MgZmxvdzpcbi8vICAgMS4gQWxpY2UgZW5jcnlwdHM6ICAgQ+KCgSA9IGVfQSDCtyBNXG4vLyAgIDIuIEJvYiBlbmNyeXB0czogICAgIEPigoIgPSBlX0IgwrcgQ+KCgVxuLy8gICAzLiBBbGljZSBkZWNyeXB0czogICBD4oKDID0gZV9B4oG7wrkgwrcgQ+KCglxuLy8gICA0LiBCb2IgZGVjcnlwdHM6ICAgICBNICA9IGVfQuKBu8K5IMK3IEPigoNcbi8vXG4vLyBXb3JrcyBiZWNhdXNlIHNjYWxhciBtdWx0aXBsaWNhdGlvbiBpcyBjb21tdXRhdGl2ZTpcbi8vICAgZV9BIMK3IChlX0IgwrcgTSkgPSBlX0IgwrcgKGVfQSDCtyBNKVxuLy9cbi8vIFJlcXVpcmVtZW50OiBnY2QocHJpdmF0ZV9rZXksIG4pID0gMSAgKHNvIHRoYXQgZeKBu8K5IG1vZCBuIGV4aXN0cylcbi8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuXG5kZXNjcmliZSgnTWFzc2V5LU9tdXJhIHRocmVlLXBhc3MgcHJvdG9jb2wnLCAoKSA9PiB7XG4gIHRlc3QoJ2NvbXBsZXRlIGVuY3J5cHRpb24vZGVjcnlwdGlvbiBjeWNsZSByZWNvdmVycyBvcmlnaW5hbCBtZXNzYWdlJywgKCkgPT4ge1xuICAgIGNvbnN0IHNlbmRlciA9IG5ldyBNYXNzZXlPbXVyYSgxMjM0NTZuKVxuICAgIGNvbnN0IHJlY2VpdmVyID0gbmV3IE1hc3NleU9tdXJhKDY1NDMyMW4pXG5cbiAgICBjb25zdCBtZXNzYWdlID0gZ2V0R2VuZXJhdG9yKHNlbmRlci5jdXJ2ZU5hbWUpXG5cbiAgICAvLyBD4oKBID0gZV9zZW5kZXIgwrcgTVxuICAgIGNvbnN0IGMxID0gc2VuZGVyLmVuY3J5cHQobWVzc2FnZSlcbiAgICAvLyBD4oKCID0gZV9yZWNlaXZlciDCtyBD4oKBXG4gICAgY29uc3QgYzIgPSByZWNlaXZlci5lbmNyeXB0KGMxKVxuICAgIC8vIEPigoMgPSBlX3NlbmRlcuKBu8K5IMK3IEPigoIgIChyZW1vdmVzIHNlbmRlcidzIGVuY3J5cHRpb24pXG4gICAgY29uc3QgYzMgPSBzZW5kZXIuZGVjcnlwdChjMilcbiAgICAvLyBNICA9IGVfcmVjZWl2ZXLigbvCuSDCtyBD4oKDICAocmVtb3ZlcyByZWNlaXZlcidzIGVuY3J5cHRpb24pXG4gICAgY29uc3QgcmVjb3ZlcmVkID0gcmVjZWl2ZXIuZGVjcnlwdChjMylcblxuICAgIGV4cGVjdChyZWNvdmVyZWQueCkudG9CZShtZXNzYWdlLngpXG4gICAgZXhwZWN0KHJlY292ZXJlZC55KS50b0JlKG1lc3NhZ2UueSlcbiAgfSlcblxuICAvLyBkwrdHIG11c3QgbGllIG9uIHRoZSBjdXJ2ZVxuICB0ZXN0KCdwb2ludCBtdWx0aXBsaWNhdGlvbiB3aXRoIHByaXZhdGUga2V5IHByb2R1Y2VzIG9uLWN1cnZlIHBvaW50JywgKCkgPT4ge1xuICAgIGNvbnN0IG1vID0gbmV3IE1hc3NleU9tdXJhKDEyMzQ1Nm4pXG4gICAgY29uc3QgRyA9IGdldEdlbmVyYXRvcihtby5jdXJ2ZU5hbWUpXG4gICAgZXhwZWN0KEcubXVsKDEyMzQ1Nm4pLmlzT25DdXJ2ZSgpKS50b0JlKHRydWUpXG4gIH0pXG5cbiAgdGVzdCgnZGVmYXVsdCBjdXJ2ZSBpcyBzZWNwNTIxcjEnLCAoKSA9PiB7XG4gICAgZXhwZWN0KG5ldyBNYXNzZXlPbXVyYSgxbikuY3VydmVOYW1lKS50b0JlKCdzZWNwNTIxcjEnKVxuICB9KVxuXG4gIC8vIEZ1bGwgZW5kLXRvLWVuZCB3aXRoIEtvYmxpdHogZW5jb2RpbmdcbiAgdGVzdCgndGhyZWUtcGFzcyBleGNoYW5nZSB3aXRoIEtvYmxpdHotZW5jb2RlZCBtZXNzYWdlJywgKCkgPT4ge1xuICAgIGNvbnN0IGtvYmxpdHogPSBuZXcgS29ibGl0eignc2VjcDUyMXIxJylcbiAgICBjb25zdCBbbWVzc2FnZSwgal0gPSBrb2JsaXR6LmVuY29kZSgnSGVsbG8hJylcblxuICAgIGNvbnN0IGFsaWNlID0gbmV3IE1hc3NleU9tdXJhKDB4YTFuLCAnc2VjcDUyMXIxJylcbiAgICBjb25zdCBib2IgPSBuZXcgTWFzc2V5T211cmEoMHhiMm4sICdzZWNwNTIxcjEnKVxuXG4gICAgY29uc3QgYzEgPSBhbGljZS5lbmNyeXB0KG1lc3NhZ2UpXG4gICAgY29uc3QgYzIgPSBib2IuZW5jcnlwdChjMSlcbiAgICBjb25zdCBjMyA9IGFsaWNlLmRlY3J5cHQoYzIpXG4gICAgY29uc3QgcGxhaW50ZXh0ID0gYm9iLmRlY3J5cHQoYzMpXG5cbiAgICBleHBlY3QocGxhaW50ZXh0LngpLnRvQmUobWVzc2FnZS54KVxuICAgIGV4cGVjdChwbGFpbnRleHQueSkudG9CZShtZXNzYWdlLnkpXG4gICAgZXhwZWN0KGtvYmxpdHouZGVjb2RlKHBsYWludGV4dCwgaikpLnRvQmUoJ0hlbGxvIScpXG4gIH0pXG59KVxuIl0sIm1hcHBpbmdzIjoiOztBQUFBLElBQUFBLFFBQUEsR0FBQUMsT0FBQTtBQUNBLElBQUFDLGVBQUEsR0FBQUQsT0FBQTtBQUNBLElBQUFFLGFBQUEsR0FBQUYsT0FBQTtBQUNBLElBQUFHLFFBQUEsR0FBQUgsT0FBQTtBQUNBLElBQUFJLFNBQUEsR0FBQUosT0FBQTtBQUFnRCxTQUFBSyxlQUFBQyxDQUFBLEVBQUFDLENBQUEsV0FBQUMsZUFBQSxDQUFBRixDQUFBLEtBQUFHLHFCQUFBLENBQUFILENBQUEsRUFBQUMsQ0FBQSxLQUFBRywyQkFBQSxDQUFBSixDQUFBLEVBQUFDLENBQUEsS0FBQUksZ0JBQUE7QUFBQSxTQUFBQSxpQkFBQSxjQUFBQyxTQUFBO0FBQUEsU0FBQUYsNEJBQUFKLENBQUEsRUFBQU8sQ0FBQSxRQUFBUCxDQUFBLDJCQUFBQSxDQUFBLFNBQUFRLGlCQUFBLENBQUFSLENBQUEsRUFBQU8sQ0FBQSxPQUFBRSxDQUFBLE1BQUFDLFFBQUEsQ0FBQUMsSUFBQSxDQUFBWCxDQUFBLEVBQUFZLEtBQUEsNkJBQUFILENBQUEsSUFBQVQsQ0FBQSxDQUFBYSxXQUFBLEtB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