secp256k1.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. exports.encodeToCurve = exports.hashToCurve = exports.schnorr = exports.secp256k1 = void 0;
  4. /*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
  5. const sha256_1 = require("@noble/hashes/sha256");
  6. const utils_1 = require("@noble/hashes/utils");
  7. const _shortw_utils_js_1 = require("./_shortw_utils.js");
  8. const hash_to_curve_js_1 = require("./abstract/hash-to-curve.js");
  9. const modular_js_1 = require("./abstract/modular.js");
  10. const utils_js_1 = require("./abstract/utils.js");
  11. const weierstrass_js_1 = require("./abstract/weierstrass.js");
  12. const secp256k1P = BigInt('0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f');
  13. const secp256k1N = BigInt('0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141');
  14. const _1n = BigInt(1);
  15. const _2n = BigInt(2);
  16. const divNearest = (a, b) => (a + b / _2n) / b;
  17. /**
  18. * √n = n^((p+1)/4) for fields p = 3 mod 4. We unwrap the loop and multiply bit-by-bit.
  19. * (P+1n/4n).toString(2) would produce bits [223x 1, 0, 22x 1, 4x 0, 11, 00]
  20. */
  21. function sqrtMod(y) {
  22. const P = secp256k1P;
  23. // prettier-ignore
  24. const _3n = BigInt(3), _6n = BigInt(6), _11n = BigInt(11), _22n = BigInt(22);
  25. // prettier-ignore
  26. const _23n = BigInt(23), _44n = BigInt(44), _88n = BigInt(88);
  27. const b2 = (y * y * y) % P; // x^3, 11
  28. const b3 = (b2 * b2 * y) % P; // x^7
  29. const b6 = ((0, modular_js_1.pow2)(b3, _3n, P) * b3) % P;
  30. const b9 = ((0, modular_js_1.pow2)(b6, _3n, P) * b3) % P;
  31. const b11 = ((0, modular_js_1.pow2)(b9, _2n, P) * b2) % P;
  32. const b22 = ((0, modular_js_1.pow2)(b11, _11n, P) * b11) % P;
  33. const b44 = ((0, modular_js_1.pow2)(b22, _22n, P) * b22) % P;
  34. const b88 = ((0, modular_js_1.pow2)(b44, _44n, P) * b44) % P;
  35. const b176 = ((0, modular_js_1.pow2)(b88, _88n, P) * b88) % P;
  36. const b220 = ((0, modular_js_1.pow2)(b176, _44n, P) * b44) % P;
  37. const b223 = ((0, modular_js_1.pow2)(b220, _3n, P) * b3) % P;
  38. const t1 = ((0, modular_js_1.pow2)(b223, _23n, P) * b22) % P;
  39. const t2 = ((0, modular_js_1.pow2)(t1, _6n, P) * b2) % P;
  40. const root = (0, modular_js_1.pow2)(t2, _2n, P);
  41. if (!Fp.eql(Fp.sqr(root), y))
  42. throw new Error('Cannot find square root');
  43. return root;
  44. }
  45. const Fp = (0, modular_js_1.Field)(secp256k1P, undefined, undefined, { sqrt: sqrtMod });
  46. exports.secp256k1 = (0, _shortw_utils_js_1.createCurve)({
  47. a: BigInt(0), // equation params: a, b
  48. b: BigInt(7), // Seem to be rigid: bitcointalk.org/index.php?topic=289795.msg3183975#msg3183975
  49. Fp, // Field's prime: 2n**256n - 2n**32n - 2n**9n - 2n**8n - 2n**7n - 2n**6n - 2n**4n - 1n
  50. n: secp256k1N, // Curve order, total count of valid points in the field
  51. // Base point (x, y) aka generator point
  52. Gx: BigInt('55066263022277343669578718895168534326250603453777594175500187360389116729240'),
  53. Gy: BigInt('32670510020758816978083085130507043184471273380659243275938904335757337482424'),
  54. h: BigInt(1), // Cofactor
  55. lowS: true, // Allow only low-S signatures by default in sign() and verify()
  56. /**
  57. * secp256k1 belongs to Koblitz curves: it has efficiently computable endomorphism.
  58. * Endomorphism uses 2x less RAM, speeds up precomputation by 2x and ECDH / key recovery by 20%.
  59. * For precomputed wNAF it trades off 1/2 init time & 1/3 ram for 20% perf hit.
  60. * Explanation: https://gist.github.com/paulmillr/eb670806793e84df628a7c434a873066
  61. */
  62. endo: {
  63. beta: BigInt('0x7ae96a2b657c07106e64479eac3434e99cf0497512f58995c1396c28719501ee'),
  64. splitScalar: (k) => {
  65. const n = secp256k1N;
  66. const a1 = BigInt('0x3086d221a7d46bcde86c90e49284eb15');
  67. const b1 = -_1n * BigInt('0xe4437ed6010e88286f547fa90abfe4c3');
  68. const a2 = BigInt('0x114ca50f7a8e2f3f657c1108d9d44cfd8');
  69. const b2 = a1;
  70. const POW_2_128 = BigInt('0x100000000000000000000000000000000'); // (2n**128n).toString(16)
  71. const c1 = divNearest(b2 * k, n);
  72. const c2 = divNearest(-b1 * k, n);
  73. let k1 = (0, modular_js_1.mod)(k - c1 * a1 - c2 * a2, n);
  74. let k2 = (0, modular_js_1.mod)(-c1 * b1 - c2 * b2, n);
  75. const k1neg = k1 > POW_2_128;
  76. const k2neg = k2 > POW_2_128;
  77. if (k1neg)
  78. k1 = n - k1;
  79. if (k2neg)
  80. k2 = n - k2;
  81. if (k1 > POW_2_128 || k2 > POW_2_128) {
  82. throw new Error('splitScalar: Endomorphism failed, k=' + k);
  83. }
  84. return { k1neg, k1, k2neg, k2 };
  85. },
  86. },
  87. }, sha256_1.sha256);
  88. // Schnorr signatures are superior to ECDSA from above. Below is Schnorr-specific BIP0340 code.
  89. // https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki
  90. const _0n = BigInt(0);
  91. const fe = (x) => typeof x === 'bigint' && _0n < x && x < secp256k1P;
  92. const ge = (x) => typeof x === 'bigint' && _0n < x && x < secp256k1N;
  93. /** An object mapping tags to their tagged hash prefix of [SHA256(tag) | SHA256(tag)] */
  94. const TAGGED_HASH_PREFIXES = {};
  95. function taggedHash(tag, ...messages) {
  96. let tagP = TAGGED_HASH_PREFIXES[tag];
  97. if (tagP === undefined) {
  98. const tagH = (0, sha256_1.sha256)(Uint8Array.from(tag, (c) => c.charCodeAt(0)));
  99. tagP = (0, utils_js_1.concatBytes)(tagH, tagH);
  100. TAGGED_HASH_PREFIXES[tag] = tagP;
  101. }
  102. return (0, sha256_1.sha256)((0, utils_js_1.concatBytes)(tagP, ...messages));
  103. }
  104. // ECDSA compact points are 33-byte. Schnorr is 32: we strip first byte 0x02 or 0x03
  105. const pointToBytes = (point) => point.toRawBytes(true).slice(1);
  106. const numTo32b = (n) => (0, utils_js_1.numberToBytesBE)(n, 32);
  107. const modP = (x) => (0, modular_js_1.mod)(x, secp256k1P);
  108. const modN = (x) => (0, modular_js_1.mod)(x, secp256k1N);
  109. const Point = exports.secp256k1.ProjectivePoint;
  110. const GmulAdd = (Q, a, b) => Point.BASE.multiplyAndAddUnsafe(Q, a, b);
  111. // Calculate point, scalar and bytes
  112. function schnorrGetExtPubKey(priv) {
  113. let d_ = exports.secp256k1.utils.normPrivateKeyToScalar(priv); // same method executed in fromPrivateKey
  114. let p = Point.fromPrivateKey(d_); // P = d'⋅G; 0 < d' < n check is done inside
  115. const scalar = p.hasEvenY() ? d_ : modN(-d_);
  116. return { scalar: scalar, bytes: pointToBytes(p) };
  117. }
  118. /**
  119. * lift_x from BIP340. Convert 32-byte x coordinate to elliptic curve point.
  120. * @returns valid point checked for being on-curve
  121. */
  122. function lift_x(x) {
  123. if (!fe(x))
  124. throw new Error('bad x: need 0 < x < p'); // Fail if x ≥ p.
  125. const xx = modP(x * x);
  126. const c = modP(xx * x + BigInt(7)); // Let c = x³ + 7 mod p.
  127. let y = sqrtMod(c); // Let y = c^(p+1)/4 mod p.
  128. if (y % _2n !== _0n)
  129. y = modP(-y); // Return the unique point P such that x(P) = x and
  130. const p = new Point(x, y, _1n); // y(P) = y if y mod 2 = 0 or y(P) = p-y otherwise.
  131. p.assertValidity();
  132. return p;
  133. }
  134. /**
  135. * Create tagged hash, convert it to bigint, reduce modulo-n.
  136. */
  137. function challenge(...args) {
  138. return modN((0, utils_js_1.bytesToNumberBE)(taggedHash('BIP0340/challenge', ...args)));
  139. }
  140. /**
  141. * Schnorr public key is just `x` coordinate of Point as per BIP340.
  142. */
  143. function schnorrGetPublicKey(privateKey) {
  144. return schnorrGetExtPubKey(privateKey).bytes; // d'=int(sk). Fail if d'=0 or d'≥n. Ret bytes(d'⋅G)
  145. }
  146. /**
  147. * Creates Schnorr signature as per BIP340. Verifies itself before returning anything.
  148. * auxRand is optional and is not the sole source of k generation: bad CSPRNG won't be dangerous.
  149. */
  150. function schnorrSign(message, privateKey, auxRand = (0, utils_1.randomBytes)(32)) {
  151. const m = (0, utils_js_1.ensureBytes)('message', message);
  152. const { bytes: px, scalar: d } = schnorrGetExtPubKey(privateKey); // checks for isWithinCurveOrder
  153. const a = (0, utils_js_1.ensureBytes)('auxRand', auxRand, 32); // Auxiliary random data a: a 32-byte array
  154. const t = numTo32b(d ^ (0, utils_js_1.bytesToNumberBE)(taggedHash('BIP0340/aux', a))); // Let t be the byte-wise xor of bytes(d) and hash/aux(a)
  155. const rand = taggedHash('BIP0340/nonce', t, px, m); // Let rand = hash/nonce(t || bytes(P) || m)
  156. const k_ = modN((0, utils_js_1.bytesToNumberBE)(rand)); // Let k' = int(rand) mod n
  157. if (k_ === _0n)
  158. throw new Error('sign failed: k is zero'); // Fail if k' = 0.
  159. const { bytes: rx, scalar: k } = schnorrGetExtPubKey(k_); // Let R = k'⋅G.
  160. const e = challenge(rx, px, m); // Let e = int(hash/challenge(bytes(R) || bytes(P) || m)) mod n.
  161. const sig = new Uint8Array(64); // Let sig = bytes(R) || bytes((k + ed) mod n).
  162. sig.set(rx, 0);
  163. sig.set(numTo32b(modN(k + e * d)), 32);
  164. // If Verify(bytes(P), m, sig) (see below) returns failure, abort
  165. if (!schnorrVerify(sig, m, px))
  166. throw new Error('sign: Invalid signature produced');
  167. return sig;
  168. }
  169. /**
  170. * Verifies Schnorr signature.
  171. * Will swallow errors & return false except for initial type validation of arguments.
  172. */
  173. function schnorrVerify(signature, message, publicKey) {
  174. const sig = (0, utils_js_1.ensureBytes)('signature', signature, 64);
  175. const m = (0, utils_js_1.ensureBytes)('message', message);
  176. const pub = (0, utils_js_1.ensureBytes)('publicKey', publicKey, 32);
  177. try {
  178. const P = lift_x((0, utils_js_1.bytesToNumberBE)(pub)); // P = lift_x(int(pk)); fail if that fails
  179. const r = (0, utils_js_1.bytesToNumberBE)(sig.subarray(0, 32)); // Let r = int(sig[0:32]); fail if r ≥ p.
  180. if (!fe(r))
  181. return false;
  182. const s = (0, utils_js_1.bytesToNumberBE)(sig.subarray(32, 64)); // Let s = int(sig[32:64]); fail if s ≥ n.
  183. if (!ge(s))
  184. return false;
  185. const e = challenge(numTo32b(r), pointToBytes(P), m); // int(challenge(bytes(r)||bytes(P)||m))%n
  186. const R = GmulAdd(P, s, modN(-e)); // R = s⋅G - e⋅P
  187. if (!R || !R.hasEvenY() || R.toAffine().x !== r)
  188. return false; // -eP == (n-e)P
  189. return true; // Fail if is_infinite(R) / not has_even_y(R) / x(R) ≠ r.
  190. }
  191. catch (error) {
  192. return false;
  193. }
  194. }
  195. exports.schnorr = (() => ({
  196. getPublicKey: schnorrGetPublicKey,
  197. sign: schnorrSign,
  198. verify: schnorrVerify,
  199. utils: {
  200. randomPrivateKey: exports.secp256k1.utils.randomPrivateKey,
  201. lift_x,
  202. pointToBytes,
  203. numberToBytesBE: utils_js_1.numberToBytesBE,
  204. bytesToNumberBE: utils_js_1.bytesToNumberBE,
  205. taggedHash,
  206. mod: modular_js_1.mod,
  207. },
  208. }))();
  209. const isoMap = /* @__PURE__ */ (() => (0, hash_to_curve_js_1.isogenyMap)(Fp, [
  210. // xNum
  211. [
  212. '0x8e38e38e38e38e38e38e38e38e38e38e38e38e38e38e38e38e38e38daaaaa8c7',
  213. '0x7d3d4c80bc321d5b9f315cea7fd44c5d595d2fc0bf63b92dfff1044f17c6581',
  214. '0x534c328d23f234e6e2a413deca25caece4506144037c40314ecbd0b53d9dd262',
  215. '0x8e38e38e38e38e38e38e38e38e38e38e38e38e38e38e38e38e38e38daaaaa88c',
  216. ],
  217. // xDen
  218. [
  219. '0xd35771193d94918a9ca34ccbb7b640dd86cd409542f8487d9fe6b745781eb49b',
  220. '0xedadc6f64383dc1df7c4b2d51b54225406d36b641f5e41bbc52a56612a8c6d14',
  221. '0x0000000000000000000000000000000000000000000000000000000000000001', // LAST 1
  222. ],
  223. // yNum
  224. [
  225. '0x4bda12f684bda12f684bda12f684bda12f684bda12f684bda12f684b8e38e23c',
  226. '0xc75e0c32d5cb7c0fa9d0a54b12a0a6d5647ab046d686da6fdffc90fc201d71a3',
  227. '0x29a6194691f91a73715209ef6512e576722830a201be2018a765e85a9ecee931',
  228. '0x2f684bda12f684bda12f684bda12f684bda12f684bda12f684bda12f38e38d84',
  229. ],
  230. // yDen
  231. [
  232. '0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffff93b',
  233. '0x7a06534bb8bdb49fd5e9e6632722c2989467c1bfc8e8d978dfb425d2685c2573',
  234. '0x6484aa716545ca2cf3a70c3fa8fe337e0a3d21162f0d6299a7bf8192bfd2a76f',
  235. '0x0000000000000000000000000000000000000000000000000000000000000001', // LAST 1
  236. ],
  237. ].map((i) => i.map((j) => BigInt(j)))))();
  238. const mapSWU = /* @__PURE__ */ (() => (0, weierstrass_js_1.mapToCurveSimpleSWU)(Fp, {
  239. A: BigInt('0x3f8731abdd661adca08a5558f0f5d272e953d363cb6f0e5d405447c01a444533'),
  240. B: BigInt('1771'),
  241. Z: Fp.create(BigInt('-11')),
  242. }))();
  243. const htf = /* @__PURE__ */ (() => (0, hash_to_curve_js_1.createHasher)(exports.secp256k1.ProjectivePoint, (scalars) => {
  244. const { x, y } = mapSWU(Fp.create(scalars[0]));
  245. return isoMap(x, y);
  246. }, {
  247. DST: 'secp256k1_XMD:SHA-256_SSWU_RO_',
  248. encodeDST: 'secp256k1_XMD:SHA-256_SSWU_NU_',
  249. p: Fp.ORDER,
  250. m: 1,
  251. k: 128,
  252. expand: 'xmd',
  253. hash: sha256_1.sha256,
  254. }))();
  255. exports.hashToCurve = (() => htf.hashToCurve)();
  256. exports.encodeToCurve = (() => htf.encodeToCurve)();
  257. //# sourceMappingURL=secp256k1.js.map