secp256k1-compat.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. exports.createPrivateKeySync = createPrivateKeySync;
  4. exports.createPrivateKey = createPrivateKey;
  5. exports.privateKeyVerify = privateKeyVerify;
  6. exports.publicKeyCreate = publicKeyCreate;
  7. exports.publicKeyVerify = publicKeyVerify;
  8. exports.publicKeyConvert = publicKeyConvert;
  9. exports.ecdsaSign = ecdsaSign;
  10. exports.ecdsaRecover = ecdsaRecover;
  11. exports.ecdsaVerify = ecdsaVerify;
  12. exports.privateKeyTweakAdd = privateKeyTweakAdd;
  13. exports.privateKeyNegate = privateKeyNegate;
  14. exports.publicKeyNegate = publicKeyNegate;
  15. exports.publicKeyCombine = publicKeyCombine;
  16. exports.publicKeyTweakAdd = publicKeyTweakAdd;
  17. exports.publicKeyTweakMul = publicKeyTweakMul;
  18. exports.privateKeyTweakMul = privateKeyTweakMul;
  19. exports.signatureExport = signatureExport;
  20. exports.signatureImport = signatureImport;
  21. exports.signatureNormalize = signatureNormalize;
  22. exports.ecdh = ecdh;
  23. exports.contextRandomize = contextRandomize;
  24. const sha256_1 = require("@noble/hashes/sha256");
  25. const modular_1 = require("@noble/curves/abstract/modular");
  26. const secp256k1_js_1 = require("./secp256k1.js");
  27. const utils_js_1 = require("./utils.js");
  28. // Use `secp256k1` module directly.
  29. // This is a legacy compatibility layer for the npm package `secp256k1` via noble-secp256k1
  30. const Point = secp256k1_js_1.secp256k1.ProjectivePoint;
  31. function hexToNumber(hex) {
  32. if (typeof hex !== "string") {
  33. throw new TypeError("hexToNumber: expected string, got " + typeof hex);
  34. }
  35. return BigInt(`0x${hex}`);
  36. }
  37. // Copy-paste from secp256k1, maybe export it?
  38. const bytesToNumber = (bytes) => hexToNumber((0, utils_js_1.toHex)(bytes));
  39. const numberToHex = (num) => num.toString(16).padStart(64, "0");
  40. const numberToBytes = (num) => (0, utils_js_1.hexToBytes)(numberToHex(num));
  41. const ORDER = secp256k1_js_1.secp256k1.CURVE.n;
  42. function output(out = (len) => new Uint8Array(len), length, value) {
  43. if (typeof out === "function") {
  44. out = out(length);
  45. }
  46. (0, utils_js_1.assertBytes)(out, length);
  47. if (value) {
  48. out.set(value);
  49. }
  50. return out;
  51. }
  52. function getSignature(signature) {
  53. (0, utils_js_1.assertBytes)(signature, 64);
  54. return secp256k1_js_1.secp256k1.Signature.fromCompact(signature);
  55. }
  56. function createPrivateKeySync() {
  57. return secp256k1_js_1.secp256k1.utils.randomPrivateKey();
  58. }
  59. async function createPrivateKey() {
  60. return createPrivateKeySync();
  61. }
  62. function privateKeyVerify(privateKey) {
  63. (0, utils_js_1.assertBytes)(privateKey, 32);
  64. return secp256k1_js_1.secp256k1.utils.isValidPrivateKey(privateKey);
  65. }
  66. function publicKeyCreate(privateKey, compressed = true, out) {
  67. (0, utils_js_1.assertBytes)(privateKey, 32);
  68. (0, utils_js_1.assertBool)(compressed);
  69. const res = secp256k1_js_1.secp256k1.getPublicKey(privateKey, compressed);
  70. return output(out, compressed ? 33 : 65, res);
  71. }
  72. function publicKeyVerify(publicKey) {
  73. (0, utils_js_1.assertBytes)(publicKey, 33, 65);
  74. try {
  75. Point.fromHex(publicKey);
  76. return true;
  77. }
  78. catch (e) {
  79. return false;
  80. }
  81. }
  82. function publicKeyConvert(publicKey, compressed = true, out) {
  83. (0, utils_js_1.assertBytes)(publicKey, 33, 65);
  84. (0, utils_js_1.assertBool)(compressed);
  85. const res = Point.fromHex(publicKey).toRawBytes(compressed);
  86. return output(out, compressed ? 33 : 65, res);
  87. }
  88. function ecdsaSign(msgHash, privateKey, options = { noncefn: undefined, data: undefined }, out) {
  89. (0, utils_js_1.assertBytes)(msgHash, 32);
  90. (0, utils_js_1.assertBytes)(privateKey, 32);
  91. if (typeof options !== "object" || options === null) {
  92. throw new TypeError("secp256k1.ecdsaSign: options should be object");
  93. }
  94. // noble-secp256k1 uses hmac instead of hmac-drbg here
  95. if (options &&
  96. (options.noncefn !== undefined || options.data !== undefined)) {
  97. throw new Error("Secp256k1: noncefn && data is unsupported");
  98. }
  99. const sig = secp256k1_js_1.secp256k1.sign(msgHash, privateKey);
  100. const recid = sig.recovery;
  101. return { signature: output(out, 64, sig.toCompactRawBytes()), recid };
  102. }
  103. function ecdsaRecover(signature, recid, msgHash, compressed = true, out) {
  104. (0, utils_js_1.assertBytes)(msgHash, 32);
  105. (0, utils_js_1.assertBool)(compressed);
  106. const sign = getSignature(signature);
  107. const point = sign.addRecoveryBit(recid).recoverPublicKey(msgHash);
  108. return output(out, compressed ? 33 : 65, point.toRawBytes(compressed));
  109. }
  110. function ecdsaVerify(signature, msgHash, publicKey) {
  111. (0, utils_js_1.assertBytes)(signature, 64);
  112. (0, utils_js_1.assertBytes)(msgHash, 32);
  113. (0, utils_js_1.assertBytes)(publicKey, 33, 65);
  114. (0, utils_js_1.assertBytes)(signature, 64);
  115. const r = bytesToNumber(signature.slice(0, 32));
  116. const s = bytesToNumber(signature.slice(32, 64));
  117. if (r >= ORDER || s >= ORDER) {
  118. throw new Error("Cannot parse signature");
  119. }
  120. const pub = Point.fromHex(publicKey); // can throw error
  121. pub; // typescript
  122. let sig;
  123. try {
  124. sig = getSignature(signature);
  125. }
  126. catch (error) {
  127. return false;
  128. }
  129. return secp256k1_js_1.secp256k1.verify(sig, msgHash, publicKey);
  130. }
  131. function privateKeyTweakAdd(privateKey, tweak) {
  132. (0, utils_js_1.assertBytes)(privateKey, 32);
  133. (0, utils_js_1.assertBytes)(tweak, 32);
  134. let t = bytesToNumber(tweak);
  135. if (t === 0n) {
  136. throw new Error("Tweak must not be zero");
  137. }
  138. if (t >= ORDER) {
  139. throw new Error("Tweak bigger than curve order");
  140. }
  141. t += bytesToNumber(privateKey);
  142. if (t >= ORDER) {
  143. t -= ORDER;
  144. }
  145. if (t === 0n) {
  146. throw new Error("The tweak was out of range or the resulted private key is invalid");
  147. }
  148. privateKey.set((0, utils_js_1.hexToBytes)(numberToHex(t)));
  149. return privateKey;
  150. }
  151. function privateKeyNegate(privateKey) {
  152. (0, utils_js_1.assertBytes)(privateKey, 32);
  153. const bn = (0, modular_1.mod)(-bytesToNumber(privateKey), ORDER);
  154. privateKey.set((0, utils_js_1.hexToBytes)(numberToHex(bn)));
  155. return privateKey;
  156. }
  157. function publicKeyNegate(publicKey, compressed = true, out) {
  158. (0, utils_js_1.assertBytes)(publicKey, 33, 65);
  159. (0, utils_js_1.assertBool)(compressed);
  160. const point = Point.fromHex(publicKey).negate();
  161. return output(out, compressed ? 33 : 65, point.toRawBytes(compressed));
  162. }
  163. function publicKeyCombine(publicKeys, compressed = true, out) {
  164. if (!Array.isArray(publicKeys) || !publicKeys.length) {
  165. throw new TypeError(`Expected array with one or more items, not ${publicKeys}`);
  166. }
  167. for (const publicKey of publicKeys) {
  168. (0, utils_js_1.assertBytes)(publicKey, 33, 65);
  169. }
  170. (0, utils_js_1.assertBool)(compressed);
  171. const combined = publicKeys
  172. .map((pub) => Point.fromHex(pub))
  173. .reduce((res, curr) => res.add(curr), Point.ZERO);
  174. // Prohibit returning ZERO point
  175. if (combined.equals(Point.ZERO)) {
  176. throw new Error("Combined result must not be zero");
  177. }
  178. return output(out, compressed ? 33 : 65, combined.toRawBytes(compressed));
  179. }
  180. function publicKeyTweakAdd(publicKey, tweak, compressed = true, out) {
  181. (0, utils_js_1.assertBytes)(publicKey, 33, 65);
  182. (0, utils_js_1.assertBytes)(tweak, 32);
  183. (0, utils_js_1.assertBool)(compressed);
  184. const p1 = Point.fromHex(publicKey);
  185. const p2 = Point.fromPrivateKey(tweak);
  186. const point = p1.add(p2);
  187. if (p2.equals(Point.ZERO) || point.equals(Point.ZERO)) {
  188. throw new Error("Tweak must not be zero");
  189. }
  190. return output(out, compressed ? 33 : 65, point.toRawBytes(compressed));
  191. }
  192. function publicKeyTweakMul(publicKey, tweak, compressed = true, out) {
  193. (0, utils_js_1.assertBytes)(publicKey, 33, 65);
  194. (0, utils_js_1.assertBytes)(tweak, 32);
  195. (0, utils_js_1.assertBool)(compressed);
  196. const bn = bytesToNumber(tweak);
  197. if (bn === 0n) {
  198. throw new Error("Tweak must not be zero");
  199. }
  200. if (bn <= 1 || bn >= ORDER) {
  201. throw new Error("Tweak is zero or bigger than curve order");
  202. }
  203. const point = Point.fromHex(publicKey).multiply(bn);
  204. return output(out, compressed ? 33 : 65, point.toRawBytes(compressed));
  205. }
  206. function privateKeyTweakMul(privateKey, tweak) {
  207. (0, utils_js_1.assertBytes)(privateKey, 32);
  208. (0, utils_js_1.assertBytes)(tweak, 32);
  209. const bn = bytesToNumber(tweak);
  210. if (bn <= 1 || bn >= ORDER) {
  211. throw new Error("Tweak is zero or bigger than curve order");
  212. }
  213. const res = (0, modular_1.mod)(bn * bytesToNumber(privateKey), ORDER);
  214. if (res === 0n) {
  215. throw new Error("The tweak was out of range or the resulted private key is invalid");
  216. }
  217. privateKey.set((0, utils_js_1.hexToBytes)(numberToHex(res)));
  218. return privateKey;
  219. }
  220. // internal -> DER
  221. function signatureExport(signature, out) {
  222. const res = getSignature(signature).toDERRawBytes();
  223. return output(out, 72, res.slice()).slice(0, res.length);
  224. }
  225. // DER -> internal
  226. function signatureImport(signature, out) {
  227. (0, utils_js_1.assertBytes)(signature);
  228. const sig = secp256k1_js_1.secp256k1.Signature.fromDER(signature);
  229. return output(out, 64, (0, utils_js_1.hexToBytes)(sig.toCompactHex()));
  230. }
  231. function signatureNormalize(signature) {
  232. const res = getSignature(signature);
  233. if (res.s > ORDER / 2n) {
  234. signature.set(numberToBytes(ORDER - res.s), 32);
  235. }
  236. return signature;
  237. }
  238. function ecdh(publicKey, privateKey, options = {}, out) {
  239. (0, utils_js_1.assertBytes)(publicKey, 33, 65);
  240. (0, utils_js_1.assertBytes)(privateKey, 32);
  241. if (typeof options !== "object" || options === null) {
  242. throw new TypeError("secp256k1.ecdh: options should be object");
  243. }
  244. if (options.data !== undefined) {
  245. (0, utils_js_1.assertBytes)(options.data);
  246. }
  247. const point = Point.fromHex(secp256k1_js_1.secp256k1.getSharedSecret(privateKey, publicKey));
  248. if (options.hashfn === undefined) {
  249. return output(out, 32, (0, sha256_1.sha256)(point.toRawBytes(true)));
  250. }
  251. if (typeof options.hashfn !== "function") {
  252. throw new TypeError("secp256k1.ecdh: options.hashfn should be function");
  253. }
  254. if (options.xbuf !== undefined) {
  255. (0, utils_js_1.assertBytes)(options.xbuf, 32);
  256. }
  257. if (options.ybuf !== undefined) {
  258. (0, utils_js_1.assertBytes)(options.ybuf, 32);
  259. }
  260. (0, utils_js_1.assertBytes)(out, 32);
  261. const { x, y } = point.toAffine();
  262. const xbuf = options.xbuf || new Uint8Array(32);
  263. xbuf.set(numberToBytes(x));
  264. const ybuf = options.ybuf || new Uint8Array(32);
  265. ybuf.set(numberToBytes(y));
  266. const hash = options.hashfn(xbuf, ybuf, options.data);
  267. if (!(hash instanceof Uint8Array) || hash.length !== 32) {
  268. throw new Error("secp256k1.ecdh: invalid options.hashfn output");
  269. }
  270. return output(out, 32, hash);
  271. }
  272. function contextRandomize(seed) {
  273. if (seed !== null) {
  274. (0, utils_js_1.assertBytes)(seed, 32);
  275. }
  276. // There is no context to randomize
  277. }