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.

1 lines 13.7 kB
(()=>{var f={246(f){function e(f){var e=new Error("Cannot find module '"+f+"'");throw e.code="MODULE_NOT_FOUND",e}e.keys=()=>[],e.resolve=e,e.id=246,f.exports=e}},e={};function n(t){var r=e[t];if(void 0!==r)return r.exports;var i=e[t]={exports:{}};return f[t](i,i.exports,n),i.exports}n.d=(f,e)=>{for(var t in e)n.o(e,t)&&!n.o(f,t)&&Object.defineProperty(f,t,{enumerable:!0,get:e[t]})},n.o=(f,e)=>Object.prototype.hasOwnProperty.call(f,e),n.r=f=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(f,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(f,"__esModule",{value:!0})};var t={};(()=>{"use strict";function f(f,e){return(f%e+e)%e}function e(e,n){e=f(e,n);const[t,r]=function(f,e){let n=f,t=e,r=1n,i=0n,c=0n,s=1n;for(;0n!==t;){const f=n/t;[n,t]=[t,n-f*t],[r,i]=[i,r-f*i],[c,s]=[s,c-f*s]}return[n,r,c]}(e,n);if(1n!==t)throw new Error("Modular inverse does not exist.");return f(r,n)}function r(e,n,t){if(1n===t)return 0n;e=f(e,t);let r=1n;for(;n>0n;)1n&n&&(r=r*e%t),n>>=1n,e=e*e%t;return r}function i(e,n){return 0n!==(e=f(e,n))&&1n===r(e,(n-1n)/2n,n)}function c(e,n){if(0n===(e=f(e,n)))return 0n;if(!i(e,n))return null;if(n%4n==3n)return r(e,(n+1n)/4n,n);let t=0n,c=n-1n;for(;c%2n==0n;)c/=2n,t+=1n;let s=2n;for(;i(s,n);)s+=1n;let o=t,a=r(s,c,n),u=r(e,c,n),l=r(e,(c+1n)/2n,n);for(;;){if(1n===u)return l;let f=1n,e=u*u%n;for(;1n!==e;)e=e*e%n,f+=1n;const t=r(a,1n<<o-f-1n,n);o=f,a=t*t%n,u=u*a%n,l=l*t%n}}function s(n,t,r){if(null===n||null===t)return[null,null];const i=r.p,c=f(3n*n*n+r.a,i),s=f(2n*t,i);if(0n===s)return[null,null];const o=c*e(s,i)%i,a=f(o*o-2n*n,i);return[a,f(o*(n-a)-t,i)]}function o(n,t,r,i,c){if(null===n||null===t)return[r,i];if(null===r||null===i)return[n,t];if(n===r&&t===i)return s(n,t,c);const o=c.p,a=f(i-t,o),u=f(r-n,o);if(0n===u)return[null,null];const l=a*e(u,o)%o,b=f(l*l-n-r,o);return[b,f(l*(n-b)-t,o)]}n.r(t),n.d(t,{CoordinateSystem:()=>h,CurveParams:()=>p,DiffieHellman:()=>E,DigitalSignature:()=>_,Koblitz:()=>I,MasseyOmura:()=>O,Point:()=>x,getCurve:()=>w,getGenerator:()=>m,isQuadraticResidue:()=>i,modularSqrt:()=>c});class a{constructor(f=null,e=null,n=1n){this.x=f,this.y=e,this.z=n,Object.freeze(this)}}function u(f){return f.isIdentity?new a:new a(f.x,f.y,1n)}function l(n,t){if(null===n.x||null===n.y||0n===n.z)return[null,null];const r=e(n.z,t.p),i=r*r%t.p,c=i*r%t.p;return[f(n.x*i,t.p),f(n.y*c,t.p)]}function b(e,n){if(null===e.x||null===e.y||0n===e.y)return new a;const t=n.p,r=f(e.y*e.y,t),i=f(e.z*e.z,t),c=f(4n*e.x*r,t),s=f(3n*e.x*e.x+n.a*i*i,t),o=f(s*s-2n*c,t),u=f(s*(c-o)-8n*r*r,t),l=f(2n*e.y*e.z,t);return new a(o,u,l)}function d(e,n,t){if(null===e.x||null===e.y)return n;if(null===n.x||null===n.y)return e;const r=t.p,i=f(e.z*e.z,r),c=f(n.z*n.z,r),s=f(e.x*c,r),o=f(n.x*i,r),u=f(e.y*n.z*c,r),l=f(n.y*e.z*i,r);if(s===o)return u!==l?new a:b(e,t);const d=o-s,h=f(2n*d*(2n*d),r),p=f(d*h,r),x=f(2n*(l-u),r),y=f(s*h,r),v=f(x*x-p-2n*y,r),g=f(x*(y-v)-2n*u*p,r),w=f(((e.z+n.z)*(e.z+n.z)-i-c)*d,r);return new a(v,g,w)}const h=Object.freeze({AFFINE:"AFFINE",JACOBIAN:"JACOBIAN"});class p{constructor({p:f,a:e,b:n,n:t,h:i=1n,coord:c=h.JACOBIAN}){if(this.p=f,this.a=e,this.b=n,this.n=t,this.h=i,this.coord=c,0n==(4n*r(e,3n,f)+27n*r(n,2n,f))%f)throw new Error(`Singular curve: 4a³ + 27b² ≡ 0 (mod p) for a=${e}, b=${n}, p=${f}. The discriminant must be non-zero for a valid elliptic curve.`);Object.freeze(this)}}class x{constructor(e=null,n=null,t=null,i=!1){if(this.x=e,this.y=n,this.curve=t,!i&&null!==e&&null!==n&&null!==t&&r(n,2n,t.p)!==f(r(e,3n,t.p)+t.a*e+t.b,t.p))throw new Error(`Point(${e}, ${n}) is not on the curve y² = x³ + ${t.a}x + ${t.b} (mod ${t.p}).`);Object.freeze(this)}get isIdentity(){return null===this.x||null===this.y}isOnCurve(){return!this.isIdentity&&null!==this.curve&&r(this.y,2n,this.curve.p)===f(r(this.x,3n,this.curve.p)+this.curve.a*this.x+this.curve.b,this.curve.p)}_requireCurve(){if(null===this.curve)throw new Error("Cannot perform arithmetic on a Point without curve parameters. Pass a CurveParams instance via the 'curve' argument.");return this.curve}_coerce(f){return null===f.curve&&null!==this.curve?new x(f.x,f.y,this.curve,!0):f}_wrap(f,e){return new x(f,e,this.curve,!0)}compress(){if(this.isIdentity)throw new Error("Cannot compress the identity point (point at infinity).");return[this.x,this.y%2n]}static decompress(e,n,t){let i=c(f(r(e,3n,t.p)+t.a*e+t.b,t.p),t.p);if(null===i)throw new Error(`x=${e} does not correspond to a valid point on the curve y² = x³ + ${t.a}x + ${t.b} (mod ${t.p}).`);return i%2n!==n&&(i=t.p-i),new x(e,i,t)}compressSec1(){if(this.isIdentity)throw new Error("Cannot compress the identity point (point at infinity).");const f=this._requireCurve(),e=Number((BigInt(f.p.toString(2).length)+7n)/8n),n=this.y%2n?3:2,t=y(this.x,e),r=new Uint8Array(1+e);return r[0]=n,r.set(t,1),r}toUncompressedSec1(){if(this.isIdentity)throw new Error("Cannot serialize the identity point (point at infinity).");const f=this._requireCurve(),e=Number((BigInt(f.p.toString(2).length)+7n)/8n),n=y(this.x,e),t=y(this.y,e),r=new Uint8Array(1+2*e);return r[0]=4,r.set(n,1),r.set(t,1+e),r}static fromSec1(f,e){if(f.length<2)throw new Error("SEC 1 data too short.");const n=Number((BigInt(e.p.toString(2).length)+7n)/8n),t=f[0];if(2===t||3===t){if(f.length!==1+n)throw new Error(`Compressed SEC 1 data must be ${1+n} bytes, got ${f.length}.`);const r=v(f.slice(1)),i=BigInt(t-2);return x.decompress(r,i,e)}if(4===t){if(f.length!==1+2*n)throw new Error(`Uncompressed SEC 1 data must be ${1+2*n} bytes, got ${f.length}.`);const t=v(f.slice(1,1+n)),r=v(f.slice(1+n));return new x(t,r,e)}throw new Error(`Unknown SEC 1 prefix: 0x${t.toString(16).padStart(2,"0")}. Expected 0x02, 0x03, or 0x04.`)}neg(){if(this.isIdentity)return this;const e=this._requireCurve();return new x(this.x,f(-this.y,e.p),e,!0)}add(f){const e=this._requireCurve();if(f=this._coerce(f),e.coord===h.JACOBIAN){const n=d(u(this),u(f),e);return this._wrap(...l(n,e))}return this._wrap(...o(this.x,this.y,f.x,f.y,e))}sub(e){return this.add(e.neg?e.neg():new x(e.x,f(-e.y,this._requireCurve().p),e.curve||this.curve,!0))}mul(e){const n=this._requireCurve();if(e=f(e,n.n),n.coord===h.JACOBIAN){const f=function(f,e,n){if(0n===f||null===e.x||null===e.y)return new a;let t=new a;const r=f.toString(2);for(let f=0;f<r.length;f++)"1"===r[r.length-f-1]&&(t=d(t,e,n)),e=b(e,n);return t}(e,u(this),n);return this._wrap(...l(f,n))}return this._wrap(...function(f,e,n,t){if(null===e||null===n||0n===f)return[null,null];let r=null,i=null;for(;f>0n;)1n&f&&([r,i]=o(r,i,e,n,t)),[e,n]=s(e,n,t),f>>=1n;return[r,i]}(e,this.x,this.y,n))}toString(){return this.isIdentity?"Point(∞)":`Point(x=${this.x}, y=${this.y})`}}function y(f,e){const n=f.toString(16).padStart(2*e,"0"),t=new Uint8Array(e);for(let f=0;f<e;f++)t[f]=parseInt(n.slice(2*f,2*f+2),16);return t}function v(f){let e="";for(let n=0;n<f.length;n++)e+=f[n].toString(16).padStart(2,"0");return BigInt("0x"+e)}const g={secp192k1:{p:0xfffffffffffffffffffffffffffffffffffffffeffffee37n,a:0x0n,b:0x3n,Gx:0xdb4ff10ec057e9ae26b07d0280b7f4341da5d1b1eae06c7dn,Gy:0x9b2f2f6d9c5628a7844163d015be86344082aa88d95e2f9dn,n:0xfffffffffffffffffffffffe26f2fc170f69466a74defd8dn,h:1n},secp192r1:{p:0xfffffffffffffffffffffffffffffffeffffffffffffffffn,a:0xfffffffffffffffffffffffffffffffefffffffffffffffcn,b:0x64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1n,Gx:0x188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012n,Gy:0x07192b95ffc8da78631011ed6b24cdd573f977a11e794811n,n:0xffffffffffffffffffffffff99def836146bc9b1b4d22831n,h:1n},secp224k1:{p:0xfffffffffffffffffffffffffffffffffffffffffffffffeffffe56dn,a:0x0n,b:0x5n,Gx:0xa1455b334df099df30fc28a169a467e9e47075a90f7e650eb6b7a45cn,Gy:0x7e089fed7fba344282cafbd6f7e319f7c0b0bd59e2ca4bdb556d61a5n,n:0x10000000000000000000000000001dce8d2ec6184caf0a971769fb1f7n,h:1n},secp224r1:{p:0xffffffffffffffffffffffffffffffff000000000000000000000001n,a:0xfffffffffffffffffffffffffffffffefffffffffffffffffffffffen,b:0xb4050a850c04b3abf54132565044b0b7d7bfd8ba270b39432355ffb4n,Gx:0xb70e0cbd6bb4bf7f321390b94a03c1d356c21122343280d6115c1d21n,Gy:0xbd376388b5f723fb4c22dfe6cd4375a05a07476444d5819985007e34n,n:0xffffffffffffffffffffffffffff16a2e0b8f03e13dd29455c5c2a3dn,h:1n},secp256k1:{p:0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2fn,a:0x0n,b:0x7n,Gx:0x79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798n,Gy:0x483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8n,n:0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141n,h:1n},secp256r1:{p:0xffffffff00000001000000000000000000000000ffffffffffffffffffffffffn,a:0xffffffff00000001000000000000000000000000fffffffffffffffffffffffcn,b:0x5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604bn,Gx:0x6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296n,Gy:0x4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5n,n:0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551n,h:1n},secp384r1:{p:0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000ffffffffn,a:0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000fffffffcn,b:0xb3312fa7e23ee7e4988e056be3f82d19181d9c6efe8141120314088f5013875ac656398d8a2ed19d2a85c8edd3ec2aefn,Gx:0xaa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a385502f25dbf55296c3a545e3872760ab7n,Gy:0x3617de4a96262c6f5d9e98bf9292dc29f8f41dbd289a147ce9da3113b5f0b8c00a60b1ce1d7e819d7a431d7c90ea0e5fn,n:0xffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf581a0db248b0a77aecec196accc52973n,h:1n},secp521r1:{p:0x1ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffn,a:0x1fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcn,b:0x051953eb9618e1c9a1f929a21a0b68540eea2da725b99b315f3b8b489918ef109e156193951ec7e937b1652c0bd3bb1bf073573df883d2c34f1ef451fd46b503f00n,Gx:0x0c6858e06b70404e9cd9e3ecb662395b4429c648139053fb521f828af606b4d3dbaa14b5e77efe75928fe1dc127a2ffa8de3348b3c1856a429bf97e7e31c2e5bd66n,Gy:0x11839296a789a3bc0045c8a5fb42c7d1bd998f54449579b446817afbd17273e662c97ee72995ef42640c550b9013fad0761353c7086a272c24088be94769fd16650n,n:0x1fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa51868783bf2f966b7fcc0148f709a5d03bb5c9b8899c47aebb6fb71e91386409n,h:1n}};function w(f){const e=f.toLowerCase().trim();if(!(e in g)){const e=Object.keys(g).sort().join(", ");throw new Error(`Unknown curve '${f}'. Available: ${e}`)}const n=g[e];return new p({p:n.p,a:n.a,b:n.b,n:n.n,h:n.h})}function m(f){const e=f.toLowerCase().trim();if(!(e in g)){const e=Object.keys(g).sort().join(", ");throw new Error(`Unknown curve '${f}'. Available: ${e}`)}const n=g[e],t=w(f);return new x(n.Gx,n.Gy,t)}function S(){return void 0!==globalThis.crypto?globalThis.crypto:n(246)("crypto")}function C(f){if(f<=1n)return 1n;const e=f.toString(16).length+1>>1,n=new Uint8Array(e);let t;do{const r=S();if(r&&r.getRandomValues)r.getRandomValues(n);else{if(!r||!r.randomBytes)throw new Error("No secure random number generator available.");{const f=r.randomBytes(e);n.set(f)}}let i="";for(let f=0;f<n.length;f++)i+=n[f].toString(16).padStart(2,"0");t=BigInt("0x"+i)%f}while(0n===t);return t}class _{constructor(f,e="secp256k1"){this.privateKey=f,this.curveName=e,Object.freeze(this)}get _curve(){return w(this.curveName)}get _G(){return m(this.curveName)}get publicKey(){return this._G.mul(this.privateKey)}sign(n){const t=this._curve.n,r=this._G;let i=0n,c=0n;for(;0n===i||0n===c;){const s=C(t);i=f(r.mul(s).x,t),c=f((n+i*this.privateKey)*e(s,t),t)}return[i,c]}verify(n,t,r,i){const c=this._curve.n;if(!(1n<=r&&r<c&&1n<=i&&i<c))throw new Error("r or s are not in the valid range [1, n-1].");const s=this._G,o=e(i,c),a=f(t*o,c),u=f(r*o,c);return f(s.mul(a).add(n.mul(u)).x,c)===r}async signMessage(f,e){const n=await z(f,e);return this.sign(n)}async verifyMessage(f,e,n,t,r){const i=await z(e,r);return this.verify(f,i,n,t)}}async function z(f,e){if(e){const n=await e(f);return BigInt("0x"+n)}let n;n="string"==typeof f?(new TextEncoder).encode(f):f;const t=S();if(t&&t.subtle){const f=await t.subtle.digest("SHA-256",n),e=new Uint8Array(f);let r="";for(let f=0;f<e.length;f++)r+=e[f].toString(16).padStart(2,"0");return BigInt("0x"+r)}if(t&&t.createHash){const f=t.createHash("sha256").update(n).digest("hex");return BigInt("0x"+f)}throw new Error("No hash function available.")}class I{constructor(f="secp521r1",e=256n){this.curveName=f,this.alphabetSize=e,Object.freeze(this)}get _curve(){return w(this.curveName)}encode(e){const n=this._curve,t=this.alphabetSize;let i=0n;for(let f=0;f<e.length;f++)i+=BigInt(e.charCodeAt(f))*t**BigInt(f);for(let e=1;e<100;e++){const t=f(100n*i+BigInt(e),n.p),c=f(r(t,3n,n.p)+n.a*t+n.b,n.p);if(c===r(c,(n.p+1n)/2n,n.p)){const f=r(c,(n.p+1n)/4n,n.p),i=new x(t,f,n);if(i.isOnCurve())return[i,e]}}throw new Error("Failed to encode message to a valid point on the curve.")}decode(f,e){const n=this.alphabetSize;let t=(f.x-BigInt(e))/100n;const r=[];for(;t>0n;)r.push(String.fromCharCode(Number(t%n))),t/=n;return r.join("")}}class E{constructor(f,e="secp256k1"){this.privateKey=f,this.curveName=e,Object.freeze(this)}get _G(){return m(this.curveName)}get publicKey(){return this._G.mul(this.privateKey)}computeSharedSecret(f){return f.mul(this.privateKey)}}class O{constructor(f,e="secp521r1"){this.privateKey=f,this.curveName=e,Object.freeze(this)}get _curve(){return w(this.curveName)}get _inverseKey(){return e(this.privateKey,this._curve.n)}encrypt(f){return f.mul(this.privateKey)}decrypt(f){return f.mul(this._inverseKey)}}})(),window.ecutils=t})();