jobsys-explore
Version:
Enhanced component based on vant
1 lines • 211 kB
Source Map (JSON)
{"version":3,"file":"cipher-98df1050.cjs","sources":["../hooks/network.js","../hooks/utils.js","../hooks/form.js","../../../node_modules/.pnpm/@noble+curves@1.1.0/node_modules/@noble/curves/esm/abstract/utils.js","../../../node_modules/.pnpm/@noble+curves@1.1.0/node_modules/@noble/curves/esm/abstract/modular.js","../../../node_modules/.pnpm/@noble+curves@1.1.0/node_modules/@noble/curves/esm/abstract/curve.js","../../../node_modules/.pnpm/@noble+curves@1.1.0/node_modules/@noble/curves/esm/abstract/weierstrass.js","../../../node_modules/.pnpm/sm-crypto-v2@1.7.0/node_modules/sm-crypto-v2/dist/index.mjs","../hooks/cipher.js"],"sourcesContent":["import axios from \"axios\"\nimport { allowMultipleToast, closeToast, showLoadingToast } from \"vant\"\nimport { isObject, isString } from \"lodash-es\"\n\n/**\n * 请求返回状态码\n * @type {{STATE_CODE_NOT_FOUND: string, STATE_CODE_SUCCESS: string, STATE_CODE_FAIL: string, STATE_CODE_INFO_NOT_COMPLETE: string, STATE_CODE_NOT_ALLOWED: string}}\n */\nexport const STATUS = {\n\tSTATE_CODE_SUCCESS: \"SUCCESS\", // 成功\n\tSTATE_CODE_FAIL: \"FAIL\", // 失败\n\tSTATE_CODE_NOT_FOUND: \"NOT_FOUND\", // 找不到资源\n\tSTATE_CODE_INFO_NOT_COMPLETE: \"INCOMPLETE\", // 信息不完整\n\tSTATE_CODE_NOT_ALLOWED: \"NOT_ALLOWED\", //没有权限\n}\n\n/**\n * STATUS 适配器,内部使用\n * @param status\n * @private\n */\nexport function _configStatus(status) {\n\tObject.keys(status).forEach((key) => {\n\t\tSTATUS[key] = status[key]\n\t})\n}\n\n/**\n * 通用 AJAX 请求\n * @param {Object} [fetcher] - 用于存储请求状态的对象\n * @returns {{post(*=, *=, *=): Promise<unknown>, get(*=, *=): Promise<unknown>}}\n */\nexport function useFetch(fetcher) {\n\t// 记录当前 Fetcher 是否处于 Loading 状态\n\tlet globalLoading = null\n\n\tif (!fetcher) {\n\t\tfetcher = {}\n\t}\n\tfetcher.loading = true\n\n\treturn {\n\t\t/**\n\t\t * get请求\n\t\t * @param url\n\t\t * @param {Object} [config] - axios config\n\t\t * @returns {Promise<unknown>}\n\t\t */\n\t\tget(url, config) {\n\t\t\treturn new Promise((resolve, reject) => {\n\t\t\t\taxios\n\t\t\t\t\t.get(url, config)\n\t\t\t\t\t.then((res) => {\n\t\t\t\t\t\tresolve(res)\n\t\t\t\t\t})\n\t\t\t\t\t.catch((err) => {\n\t\t\t\t\t\treject(err)\n\t\t\t\t\t})\n\t\t\t\t\t.finally(() => {\n\t\t\t\t\t\tif (globalLoading) {\n\t\t\t\t\t\t\tallowMultipleToast(false)\n\t\t\t\t\t\t\tglobalLoading.close()\n\t\t\t\t\t\t}\n\t\t\t\t\t\tfetcher.loading = false\n\t\t\t\t\t})\n\t\t\t})\n\t\t},\n\t\t/**\n\t\t * post请求\n\t\t * @param {string} url\n\t\t * @param {Object} data\n\t\t * @param {Object} [config] - axios config\n\t\t * @returns {Promise<unknown>}\n\t\t */\n\t\tpost(url, data, config) {\n\t\t\treturn new Promise((resolve, reject) => {\n\t\t\t\taxios\n\t\t\t\t\t.post(url, data, config)\n\t\t\t\t\t.then((res) => {\n\t\t\t\t\t\tresolve(res)\n\t\t\t\t\t})\n\t\t\t\t\t.catch((err) => {\n\t\t\t\t\t\treject(err)\n\t\t\t\t\t})\n\t\t\t\t\t.finally(() => {\n\t\t\t\t\t\tif (globalLoading) {\n\t\t\t\t\t\t\tallowMultipleToast(false)\n\t\t\t\t\t\t\tglobalLoading.close()\n\t\t\t\t\t\t}\n\t\t\t\t\t\tfetcher.loading = false\n\t\t\t\t\t})\n\t\t\t})\n\t\t},\n\n\t\t/**\n\t\t * 参数为\n\t\t * @param {String|Object} [message] Toast 的 Message 或者是 Toast 的配置\n\t\t * @return {*}\n\t\t */\n\t\tloading(message) {\n\t\t\tcloseToast(true)\n\t\t\tallowMultipleToast()\n\t\t\tif (isString(message)) {\n\t\t\t\tglobalLoading = showLoadingToast({\n\t\t\t\t\tmessage: message || \"加载中...\",\n\t\t\t\t\tduration: 0,\n\t\t\t\t\tforbidClick: true,\n\t\t\t\t})\n\t\t\t} else if (isObject(message)) {\n\t\t\t\tglobalLoading = showLoadingToast({ duration: 0, ...message })\n\t\t\t} else {\n\t\t\t\tglobalLoading = showLoadingToast({\n\t\t\t\t\tmessage: \"加载中...\",\n\t\t\t\t\tduration: 0,\n\t\t\t\t\tforbidClick: true,\n\t\t\t\t})\n\t\t\t}\n\n\t\t\treturn this\n\t\t},\n\t}\n}\n","import { find, flatMapDeep, isNull, isUndefined, reduce } from \"lodash-es\"\n\n/**\n * 从 options 中根据 value 获取 text\n * @param value\n * @param options\n * * @param {Object} [adapter={value: \"value\",label: \"label\",children: \"children\"}] - 选项适配器\n * @param adapter\n * @return {*|string|string}\n */\nexport function useTextFromOptionsValue(value, options, adapter) {\n\tif (!options) {\n\t\treturn \"\"\n\t}\n\tadapter = adapter || {\n\t\tvalue: \"value\",\n\t\tlabel: \"text\",\n\t}\n\tconst option = options.find((option) => option[adapter.value] === value)\n\treturn option ? option[adapter.label] : \"\"\n}\n\n/**\n * 从嵌套的 options 中根据 value 获取 text, 如 [1, 3] => [\"东\", \"南\"]\n *\n * @param {Array} options - 嵌套的选项\n * @param {Array} values - 需要查找的值\n * @param {Object} [adapter={value: \"value\",label: \"label\",children: \"children\"}] - 选项适配器\n * @return Array\n */\nexport function useFindTextsInValues(options, values, adapter) {\n\tadapter = adapter || {\n\t\tvalue: \"value\",\n\t\tlabel: \"text\",\n\t\tchildren: \"children\",\n\t}\n\n\tconst labels = []\n\n\tfunction recursiveSearch(node) {\n\t\tif (values.includes(node[adapter.value])) {\n\t\t\tlabels.push(node[adapter.label])\n\t\t}\n\n\t\tif (node[adapter.children]?.length) {\n\t\t\tnode[adapter.children].forEach((child) => {\n\t\t\t\trecursiveSearch(child)\n\t\t\t})\n\t\t}\n\t}\n\n\toptions.forEach((item) => {\n\t\trecursiveSearch(item)\n\t})\n\n\treturn labels\n}\n\n/**\n * 从嵌套的 options 中根据 value 获取 label, 如地区路径: [440000, 440100, 440113] => ['广东省', '广州市', '番禺区']\n * @param {Array} options\n * @param {Array} path\n * @param {Object} [adapter]\n * @return Array\n */\nexport function useFindLabelsFromPath(options, path, adapter) {\n\tadapter = adapter || {\n\t\tvalue: \"value\",\n\t\tlabel: \"text\",\n\t\tchildren: \"children\",\n\t}\n\n\tlet labels = []\n\treduce(\n\t\tpath,\n\t\t(acc, value) => {\n\t\t\tconst item = find(acc, { [adapter.value]: value })\n\t\t\tif (item) {\n\t\t\t\tlabels.push(item[adapter.label])\n\t\t\t\treturn item[adapter.children]\n\t\t\t}\n\t\t},\n\t\toptions,\n\t)\n\treturn labels\n}\n\n/**\n * 从 options 为 [{text: \"\", value: \"\", children: []] 样式的多层数组中,根据所给的 value 递归找出该 option\n * @param {Array} options\n * @param {Number|String} value\n * @param {Object} [adapter]\n * @return {Object|null}\n */\nexport function useFindOptionByValue(options, value, adapter) {\n\tadapter = adapter || {\n\t\tvalue: \"value\",\n\t\tlabel: \"text\",\n\t\tchildren: \"children\",\n\t}\n\n\t// 遍历 options 数组\n\tfor (let option of options) {\n\t\t// 如果当前 option 的 value 匹配目标值,则返回当前 option\n\t\tif (option[adapter.value] === value) {\n\t\t\treturn option\n\t\t}\n\t\t// 如果当前 option 有子选项\n\t\tif (option[adapter.children] && option[adapter.children].length) {\n\t\t\t// 递归搜索子选项数组\n\t\t\tconst foundOption = useFindOptionByValue(option[adapter.children], value, adapter)\n\t\t\t// 如果找到了匹配的子选项,则返回\n\t\t\tif (foundOption) {\n\t\t\t\treturn foundOption\n\t\t\t}\n\t\t}\n\t}\n\t// 如果未找到匹配的选项,则返回 null\n\treturn null\n}\n\n/**\n * [移动端适配]\n * 从嵌套的 options 中根据 value 获取 text\n * @param {Array} options\n * @param {Array} path\n * @param {Object} [adapter]\n * @return Array\n */\nexport function useFindTextsFromPath(options, path, adapter) {\n\tadapter = adapter || {\n\t\tvalue: \"value\",\n\t\tlabel: \"text\",\n\t\tchildren: \"children\",\n\t}\n\treturn useFindLabelsFromPath(options, path, adapter)\n}\n\n/**\n * let obj = {\n * \"name\": \"西学楼1号\",\n * \"parent\": {\n * \"name\": \"学生宿舍\",\n * \"parent\": {\n * \"name\": \"宿舍区域\",\n * }\n * }\n * }\n * useFindPropertyRecursive(obj, 'name', 'parent') // [\"西学楼1号\", \"学生宿舍\", \"宿舍区域\"]\n *\n * 从嵌套的对象中递归获取某个属性\n * @param {Object} item 获取对象\n * @param {String} propertyKey 想获取的属性名称\n * @param {String} nestedKey 嵌套的属性\n * @return Array\n */\nexport function useFindPropertyRecursive(item, propertyKey, nestedKey) {\n\treturn flatMapDeep(item, (value, key) => {\n\t\tif (key === propertyKey) {\n\t\t\treturn value\n\t\t}\n\t\tif (key === nestedKey) {\n\t\t\treturn useFindPropertyRecursive(value, propertyKey, nestedKey)\n\t\t}\n\t\treturn []\n\t})\n}\n\n/**\n * 从嵌套的 options 中根据 value 获取 text 路径, 如地区路径: 440113 => [\"广东省\", \"广州市\", \" 番禺区\"]\n * @param options\n * @param value\n * @param adapter\n * @return {*}\n */\nexport function useFindParentLabels(options, value, adapter) {\n\tadapter = adapter || {\n\t\tvalue: \"value\",\n\t\tlabel: \"text\",\n\t\tchildren: \"children\",\n\t}\n\n\tconst labels = []\n\n\tfunction findParentLabels(options, value, labels) {\n\t\tfor (const option of options) {\n\t\t\tif (option[adapter.value] === value) {\n\t\t\t\tlabels.unshift(option[adapter.label])\n\t\t\t\tbreak\n\t\t\t} else if (option[adapter.children]) {\n\t\t\t\tconst childResult = findParentLabels(option[adapter.children], value, labels)\n\t\t\t\tif (childResult.length > 0) {\n\t\t\t\t\tlabels.unshift(option[adapter.label])\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn labels\n\t}\n\n\treturn findParentLabels(options, value, labels)\n}\n\n/**\n * 从嵌套的 options 中根据 value 获取整个 values 路径, 如地区路径: 440113 => [440000, 440100, 440113]\n * @param options\n * @param value\n * @param adapter\n * @return Array\n */\nexport function useFindParentValues(options, value, adapter) {\n\tadapter = adapter || {\n\t\tvalue: \"value\",\n\t\tlabel: \"text\",\n\t\tchildren: \"children\",\n\t}\n\n\tconst values = []\n\n\tfunction findParentValues(options, value, values) {\n\t\tfor (const option of options) {\n\t\t\tif (option[adapter.value] === value) {\n\t\t\t\tvalues.unshift(option[adapter.value])\n\t\t\t\tbreak\n\t\t\t} else if (option[adapter.children]) {\n\t\t\t\tconst childResult = findParentValues(option[adapter.children], value, values)\n\t\t\t\tif (childResult.length > 0) {\n\t\t\t\t\tvalues.unshift(option[adapter.value])\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn values\n\t}\n\n\treturn findParentValues(options, value, values)\n}\n\nconst localCacheSession = {}\nconst localSession = {\n\tsetItem(key, value) {\n\t\tlocalCacheSession[key] = value\n\t},\n\tgetItem(key) {\n\t\treturn localCacheSession[key]\n\t},\n\tremoveItem(key) {\n\t\tdelete localCacheSession[key]\n\t},\n}\n\nwindow._printCache = () => {\n\tconsole.log(JSON.parse(JSON.stringify(localCacheSession, null, 2)))\n}\n\n/**\n * 用于储存缓存的值\n * @param {*} key 缓存的 key\n * @param {*} [sessionType] 缓存的类型,默认为内存缓存\n * @returns get(默认值) 获取缓存的值,set(键, 值) 设置缓存的值\n */\nexport function useCache(key, sessionType) {\n\tconst cacheSession = sessionType || localSession\n\tconst shouldTransform = !!sessionType // 如果是 localStorage 之类的,则需要转换一下\n\treturn {\n\t\tget(defaultValue) {\n\t\t\tconst value = cacheSession.getItem(key)\n\t\t\tif (isNull(value) || isUndefined(value)) {\n\t\t\t\treturn defaultValue\n\t\t\t}\n\t\t\treturn shouldTransform ? JSON.parse(value) : value\n\t\t},\n\t\tset(value) {\n\t\t\tcacheSession.setItem(key, shouldTransform ? JSON.stringify(value) : value)\n\t\t},\n\t\tremove() {\n\t\t\tcacheSession.removeItem(key)\n\t\t},\n\t}\n}\n","import { cloneDeep, isArray, isBoolean, isDate, isFunction, isObject, isString, isUndefined } from \"lodash-es\"\nimport { STATUS } from \"./network\"\nimport { showFailToast, showSuccessToast } from \"vant\"\nimport dayjs from \"dayjs\"\n\n/**\n * 创建一个隐藏的表单\n *\n * @param {Object} options\n * @param {string} options.url\n * @param {Object} options.data\n * @param {string} [options.method]\n * @param {string} options.csrfToken\n * @returns {HTMLFormElement}\n */\nexport function useHiddenForm(options) {\n\tconst { url, data, csrfToken } = options\n\tlet { method } = options\n\n\tmethod = method || \"post\"\n\n\tconst form = document.createElement(\"form\")\n\tform.action = url\n\tform.method = method\n\tform.target = \"_blank\"\n\tform.style.display = \"none\"\n\n\tObject.keys(data).forEach((key) => {\n\t\tconst input = document.createElement(\"input\")\n\t\tinput.type = \"hidden\"\n\t\tinput.name = key\n\t\tinput.value = data[key]\n\t\tform.appendChild(input)\n\t})\n\n\tif (!csrfToken) {\n\t\tconst input = document.createElement(\"input\")\n\t\tinput.type = \"hidden\"\n\t\tinput.name = \"_token\"\n\t\tinput.value = document.querySelector('meta[name=\"csrf-token\"]').getAttribute(\"content\")\n\t\tform.appendChild(input)\n\t}\n\n\tdocument.body.appendChild(form)\n\n\treturn form\n}\n\n/**\n * 处理请求结果\n *\n * @param {object} res 请求结果\n * @param {string|number} res.status 请求结果状态\n * @param {*} res.result 请求结果信息\n * @param {Object.<string, string|function>} ops 状态的处理对象\n */\nexport function useProcessStatus(res, ops) {\n\tconst { status } = res\n\tconst msg = res.result\n\tconst predefined = {}\n\tpredefined.default = \"请求失败, 请检查数据并重试\"\n\tpredefined[STATUS.STATE_CODE_FAIL] = \"系统错误,请稍候再试\"\n\tpredefined[STATUS.STATE_CODE_NOT_FOUND] = \"请求的内容不存在\"\n\tpredefined[STATUS.STATE_CODE_INFO_NOT_COMPLETE] = \"信息不完整\"\n\tpredefined[STATUS.STATE_CODE_NOT_ALLOWED] = \"没有权限\"\n\n\t// 有几个常用的自定义名称\n\tconst special = {\n\t\t[STATUS.STATE_CODE_SUCCESS]: \"success\",\n\t}\n\n\tconst op = ops[status] || ops[special[status]] || predefined[status] || predefined.default\n\n\tif (isString(op)) {\n\t\tif (status === STATUS.STATE_CODE_SUCCESS) {\n\t\t\tshowSuccessToast(op)\n\t\t} else {\n\t\t\tshowFailToast(msg || op)\n\t\t}\n\t} else if (isFunction(op)) {\n\t\top()\n\t}\n}\n\n/**\n * 处理正确请求结果\n *\n * @param {object} res 请求结果\n * @param {string} res.status 请求结果状态\n * @param {*} res.result 请求结果信息\n * @param {string|function} success 状态的处理对象\n */\nexport function useProcessStatusSuccess(res, success) {\n\tuseProcessStatus(res, { success })\n}\n\n/**\n * 处理表单提交失败\n * @param {*} e\n */\nexport function useFormFail(e) {\n\tif (e && e.errorFields) {\n\t\te.errorFields.forEach((item) => {\n\t\t\tshowFailToast(item.errors.join(\" \"))\n\t\t})\n\t} else if (!(e && e.response)) {\n\t\tshowFailToast(\"请检查填写项\")\n\t} else {\n\t\tshowFailToast(\"网络异常\")\n\t}\n}\n\n/**\n * 处理表单数据\n * @param {Object} form\n * @param {Object} [format] 需要处理的类型\n * @param {boolean|string|Function} [format.date] `true`: 转成时间戳,`string`: 为 Format 格式, 如 `\"YYYY-MM-DD\"`, `function`: 自定义处理函数, 参数为 dayjs 对象\n * @param {boolean} [format.boolean] 布尔值处理, 如果开启则 `true` 转成 1, `false` 转成 0\n * @param {string|Function} [format.attachment] `string`: 附件字段名, `function`: 自定义处理函数, 参数为附件对象\n * @return {Object}\n */\nexport function useFormFormat(form, format) {\n\t//必须先 Copy form, 否则会改变 vm model 里的引用值而导致出错\n\tconst newForm = cloneDeep(form)\n\tformat = format || {}\n\tconst formatter = (obj) => {\n\t\tfor (let key in obj) {\n\t\t\t//日期处理\n\n\t\t\tlet date\n\t\t\tif (dayjs.isDayjs(obj[key])) {\n\t\t\t\tdate = obj[key]\n\t\t\t} else if (isDate(obj[key])) {\n\t\t\t\tdate = dayjs(obj[key])\n\t\t\t}\n\n\t\t\tif (date && format.date) {\n\t\t\t\tif (isString(format.date)) {\n\t\t\t\t\tobj[key] = date.format(format.date)\n\t\t\t\t} else if (isFunction(format.date)) {\n\t\t\t\t\tobj[key] = format.date(date)\n\t\t\t\t} else {\n\t\t\t\t\tobj[key] = date.unix()\n\t\t\t\t}\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\t//布尔值处理\n\t\t\tif (isBoolean(obj[key]) && format.boolean) {\n\t\t\t\tif (format.boolean === true) {\n\t\t\t\t\tobj[key] = obj[key] ? 1 : 0\n\t\t\t\t} else if (Array.isArray(format.boolean)) {\n\t\t\t\t\tobj[key] = obj[key] ? format.boolean?.[0] || 1 : format.boolean?.[1] || 0\n\t\t\t\t}\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\t//附件处理\n\t\t\tif (format.attachment) {\n\t\t\t\tconst checker = format.attachment\n\t\t\t\tif (isObject(obj[key]) && obj[key]._type === \"file\" && isString(checker) && !isUndefined(obj[key][checker])) {\n\t\t\t\t\tobj[key] = obj[key][checker]\n\t\t\t\t\tcontinue\n\t\t\t\t} else if (isObject(obj[key]) && isFunction(checker) && obj[key]._type === \"file\") {\n\t\t\t\t\tobj[key] = checker(obj[key])\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t//数组处理\n\t\t\tif (isArray(obj[key])) {\n\t\t\t\tobj[key] = formatter(obj[key])\n\t\t\t}\n\t\t}\n\n\t\treturn obj\n\t}\n\n\treturn formatter(newForm)\n}\n\nexport default {\n\tuseHiddenForm,\n\tuseProcessStatus,\n\tuseProcessStatusSuccess,\n\tuseFormFail,\n\tuseFormFormat,\n}\n","/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */\n// 100 lines of code in the file are duplicated from noble-hashes (utils).\n// This is OK: `abstract` directory does not use noble-hashes.\n// User may opt-in into using different hashing library. This way, noble-hashes\n// won't be included into their bundle.\nconst _0n = BigInt(0);\nconst _1n = BigInt(1);\nconst _2n = BigInt(2);\nconst u8a = (a) => a instanceof Uint8Array;\nconst hexes = Array.from({ length: 256 }, (v, i) => i.toString(16).padStart(2, '0'));\n/**\n * @example bytesToHex(Uint8Array.from([0xca, 0xfe, 0x01, 0x23])) // 'cafe0123'\n */\nexport function bytesToHex(bytes) {\n if (!u8a(bytes))\n throw new Error('Uint8Array expected');\n // pre-caching improves the speed 6x\n let hex = '';\n for (let i = 0; i < bytes.length; i++) {\n hex += hexes[bytes[i]];\n }\n return hex;\n}\nexport function numberToHexUnpadded(num) {\n const hex = num.toString(16);\n return hex.length & 1 ? `0${hex}` : hex;\n}\nexport function hexToNumber(hex) {\n if (typeof hex !== 'string')\n throw new Error('hex string expected, got ' + typeof hex);\n // Big Endian\n return BigInt(hex === '' ? '0' : `0x${hex}`);\n}\n/**\n * @example hexToBytes('cafe0123') // Uint8Array.from([0xca, 0xfe, 0x01, 0x23])\n */\nexport function hexToBytes(hex) {\n if (typeof hex !== 'string')\n throw new Error('hex string expected, got ' + typeof hex);\n const len = hex.length;\n if (len % 2)\n throw new Error('padded hex string expected, got unpadded hex of length ' + len);\n const array = new Uint8Array(len / 2);\n for (let i = 0; i < array.length; i++) {\n const j = i * 2;\n const hexByte = hex.slice(j, j + 2);\n const byte = Number.parseInt(hexByte, 16);\n if (Number.isNaN(byte) || byte < 0)\n throw new Error('Invalid byte sequence');\n array[i] = byte;\n }\n return array;\n}\n// BE: Big Endian, LE: Little Endian\nexport function bytesToNumberBE(bytes) {\n return hexToNumber(bytesToHex(bytes));\n}\nexport function bytesToNumberLE(bytes) {\n if (!u8a(bytes))\n throw new Error('Uint8Array expected');\n return hexToNumber(bytesToHex(Uint8Array.from(bytes).reverse()));\n}\nexport function numberToBytesBE(n, len) {\n return hexToBytes(n.toString(16).padStart(len * 2, '0'));\n}\nexport function numberToBytesLE(n, len) {\n return numberToBytesBE(n, len).reverse();\n}\n// Unpadded, rarely used\nexport function numberToVarBytesBE(n) {\n return hexToBytes(numberToHexUnpadded(n));\n}\n/**\n * Takes hex string or Uint8Array, converts to Uint8Array.\n * Validates output length.\n * Will throw error for other types.\n * @param title descriptive title for an error e.g. 'private key'\n * @param hex hex string or Uint8Array\n * @param expectedLength optional, will compare to result array's length\n * @returns\n */\nexport function ensureBytes(title, hex, expectedLength) {\n let res;\n if (typeof hex === 'string') {\n try {\n res = hexToBytes(hex);\n }\n catch (e) {\n throw new Error(`${title} must be valid hex string, got \"${hex}\". Cause: ${e}`);\n }\n }\n else if (u8a(hex)) {\n // Uint8Array.from() instead of hash.slice() because node.js Buffer\n // is instance of Uint8Array, and its slice() creates **mutable** copy\n res = Uint8Array.from(hex);\n }\n else {\n throw new Error(`${title} must be hex string or Uint8Array`);\n }\n const len = res.length;\n if (typeof expectedLength === 'number' && len !== expectedLength)\n throw new Error(`${title} expected ${expectedLength} bytes, got ${len}`);\n return res;\n}\n/**\n * Copies several Uint8Arrays into one.\n */\nexport function concatBytes(...arrays) {\n const r = new Uint8Array(arrays.reduce((sum, a) => sum + a.length, 0));\n let pad = 0; // walk through each item, ensure they have proper type\n arrays.forEach((a) => {\n if (!u8a(a))\n throw new Error('Uint8Array expected');\n r.set(a, pad);\n pad += a.length;\n });\n return r;\n}\nexport function equalBytes(b1, b2) {\n // We don't care about timing attacks here\n if (b1.length !== b2.length)\n return false;\n for (let i = 0; i < b1.length; i++)\n if (b1[i] !== b2[i])\n return false;\n return true;\n}\n/**\n * @example utf8ToBytes('abc') // new Uint8Array([97, 98, 99])\n */\nexport function utf8ToBytes(str) {\n if (typeof str !== 'string')\n throw new Error(`utf8ToBytes expected string, got ${typeof str}`);\n return new Uint8Array(new TextEncoder().encode(str)); // https://bugzil.la/1681809\n}\n// Bit operations\n/**\n * Calculates amount of bits in a bigint.\n * Same as `n.toString(2).length`\n */\nexport function bitLen(n) {\n let len;\n for (len = 0; n > _0n; n >>= _1n, len += 1)\n ;\n return len;\n}\n/**\n * Gets single bit at position.\n * NOTE: first bit position is 0 (same as arrays)\n * Same as `!!+Array.from(n.toString(2)).reverse()[pos]`\n */\nexport function bitGet(n, pos) {\n return (n >> BigInt(pos)) & _1n;\n}\n/**\n * Sets single bit at position.\n */\nexport const bitSet = (n, pos, value) => {\n return n | ((value ? _1n : _0n) << BigInt(pos));\n};\n/**\n * Calculate mask for N bits. Not using ** operator with bigints because of old engines.\n * Same as BigInt(`0b${Array(i).fill('1').join('')}`)\n */\nexport const bitMask = (n) => (_2n << BigInt(n - 1)) - _1n;\n// DRBG\nconst u8n = (data) => new Uint8Array(data); // creates Uint8Array\nconst u8fr = (arr) => Uint8Array.from(arr); // another shortcut\n/**\n * Minimal HMAC-DRBG from NIST 800-90 for RFC6979 sigs.\n * @returns function that will call DRBG until 2nd arg returns something meaningful\n * @example\n * const drbg = createHmacDRBG<Key>(32, 32, hmac);\n * drbg(seed, bytesToKey); // bytesToKey must return Key or undefined\n */\nexport function createHmacDrbg(hashLen, qByteLen, hmacFn) {\n if (typeof hashLen !== 'number' || hashLen < 2)\n throw new Error('hashLen must be a number');\n if (typeof qByteLen !== 'number' || qByteLen < 2)\n throw new Error('qByteLen must be a number');\n if (typeof hmacFn !== 'function')\n throw new Error('hmacFn must be a function');\n // Step B, Step C: set hashLen to 8*ceil(hlen/8)\n let v = u8n(hashLen); // Minimal non-full-spec HMAC-DRBG from NIST 800-90 for RFC6979 sigs.\n let k = u8n(hashLen); // Steps B and C of RFC6979 3.2: set hashLen, in our case always same\n let i = 0; // Iterations counter, will throw when over 1000\n const reset = () => {\n v.fill(1);\n k.fill(0);\n i = 0;\n };\n const h = (...b) => hmacFn(k, v, ...b); // hmac(k)(v, ...values)\n const reseed = (seed = u8n()) => {\n // HMAC-DRBG reseed() function. Steps D-G\n k = h(u8fr([0x00]), seed); // k = hmac(k || v || 0x00 || seed)\n v = h(); // v = hmac(k || v)\n if (seed.length === 0)\n return;\n k = h(u8fr([0x01]), seed); // k = hmac(k || v || 0x01 || seed)\n v = h(); // v = hmac(k || v)\n };\n const gen = () => {\n // HMAC-DRBG generate() function\n if (i++ >= 1000)\n throw new Error('drbg: tried 1000 values');\n let len = 0;\n const out = [];\n while (len < qByteLen) {\n v = h();\n const sl = v.slice();\n out.push(sl);\n len += v.length;\n }\n return concatBytes(...out);\n };\n const genUntil = (seed, pred) => {\n reset();\n reseed(seed); // Steps D-G\n let res = undefined; // Step H: grind until k is in [1..n-1]\n while (!(res = pred(gen())))\n reseed();\n reset();\n return res;\n };\n return genUntil;\n}\n// Validating curves and fields\nconst validatorFns = {\n bigint: (val) => typeof val === 'bigint',\n function: (val) => typeof val === 'function',\n boolean: (val) => typeof val === 'boolean',\n string: (val) => typeof val === 'string',\n isSafeInteger: (val) => Number.isSafeInteger(val),\n array: (val) => Array.isArray(val),\n field: (val, object) => object.Fp.isValid(val),\n hash: (val) => typeof val === 'function' && Number.isSafeInteger(val.outputLen),\n};\n// type Record<K extends string | number | symbol, T> = { [P in K]: T; }\nexport function validateObject(object, validators, optValidators = {}) {\n const checkField = (fieldName, type, isOptional) => {\n const checkVal = validatorFns[type];\n if (typeof checkVal !== 'function')\n throw new Error(`Invalid validator \"${type}\", expected function`);\n const val = object[fieldName];\n if (isOptional && val === undefined)\n return;\n if (!checkVal(val, object)) {\n throw new Error(`Invalid param ${String(fieldName)}=${val} (${typeof val}), expected ${type}`);\n }\n };\n for (const [fieldName, type] of Object.entries(validators))\n checkField(fieldName, type, false);\n for (const [fieldName, type] of Object.entries(optValidators))\n checkField(fieldName, type, true);\n return object;\n}\n// validate type tests\n// const o: { a: number; b: number; c: number } = { a: 1, b: 5, c: 6 };\n// const z0 = validateObject(o, { a: 'isSafeInteger' }, { c: 'bigint' }); // Ok!\n// // Should fail type-check\n// const z1 = validateObject(o, { a: 'tmp' }, { c: 'zz' });\n// const z2 = validateObject(o, { a: 'isSafeInteger' }, { c: 'zz' });\n// const z3 = validateObject(o, { test: 'boolean', z: 'bug' });\n// const z4 = validateObject(o, { a: 'boolean', z: 'bug' });\n//# sourceMappingURL=utils.js.map","/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */\n// Utilities for modular arithmetics and finite fields\nimport { bitMask, numberToBytesBE, numberToBytesLE, bytesToNumberBE, bytesToNumberLE, ensureBytes, validateObject, } from './utils.js';\n// prettier-ignore\nconst _0n = BigInt(0), _1n = BigInt(1), _2n = BigInt(2), _3n = BigInt(3);\n// prettier-ignore\nconst _4n = BigInt(4), _5n = BigInt(5), _8n = BigInt(8);\n// prettier-ignore\nconst _9n = BigInt(9), _16n = BigInt(16);\n// Calculates a modulo b\nexport function mod(a, b) {\n const result = a % b;\n return result >= _0n ? result : b + result;\n}\n/**\n * Efficiently raise num to power and do modular division.\n * Unsafe in some contexts: uses ladder, so can expose bigint bits.\n * @example\n * pow(2n, 6n, 11n) // 64n % 11n == 9n\n */\n// TODO: use field version && remove\nexport function pow(num, power, modulo) {\n if (modulo <= _0n || power < _0n)\n throw new Error('Expected power/modulo > 0');\n if (modulo === _1n)\n return _0n;\n let res = _1n;\n while (power > _0n) {\n if (power & _1n)\n res = (res * num) % modulo;\n num = (num * num) % modulo;\n power >>= _1n;\n }\n return res;\n}\n// Does x ^ (2 ^ power) mod p. pow2(30, 4) == 30 ^ (2 ^ 4)\nexport function pow2(x, power, modulo) {\n let res = x;\n while (power-- > _0n) {\n res *= res;\n res %= modulo;\n }\n return res;\n}\n// Inverses number over modulo\nexport function invert(number, modulo) {\n if (number === _0n || modulo <= _0n) {\n throw new Error(`invert: expected positive integers, got n=${number} mod=${modulo}`);\n }\n // Euclidean GCD https://brilliant.org/wiki/extended-euclidean-algorithm/\n // Fermat's little theorem \"CT-like\" version inv(n) = n^(m-2) mod m is 30x slower.\n let a = mod(number, modulo);\n let b = modulo;\n // prettier-ignore\n let x = _0n, y = _1n, u = _1n, v = _0n;\n while (a !== _0n) {\n // JIT applies optimization if those two lines follow each other\n const q = b / a;\n const r = b % a;\n const m = x - u * q;\n const n = y - v * q;\n // prettier-ignore\n b = a, a = r, x = u, y = v, u = m, v = n;\n }\n const gcd = b;\n if (gcd !== _1n)\n throw new Error('invert: does not exist');\n return mod(x, modulo);\n}\n// Tonelli-Shanks algorithm\n// Paper 1: https://eprint.iacr.org/2012/685.pdf (page 12)\n// Paper 2: Square Roots from 1; 24, 51, 10 to Dan Shanks\nexport function tonelliShanks(P) {\n // Legendre constant: used to calculate Legendre symbol (a | p),\n // which denotes the value of a^((p-1)/2) (mod p).\n // (a | p) ≡ 1 if a is a square (mod p)\n // (a | p) ≡ -1 if a is not a square (mod p)\n // (a | p) ≡ 0 if a ≡ 0 (mod p)\n const legendreC = (P - _1n) / _2n;\n let Q, S, Z;\n // Step 1: By factoring out powers of 2 from p - 1,\n // find q and s such that p - 1 = q*(2^s) with q odd\n for (Q = P - _1n, S = 0; Q % _2n === _0n; Q /= _2n, S++)\n ;\n // Step 2: Select a non-square z such that (z | p) ≡ -1 and set c ≡ zq\n for (Z = _2n; Z < P && pow(Z, legendreC, P) !== P - _1n; Z++)\n ;\n // Fast-path\n if (S === 1) {\n const p1div4 = (P + _1n) / _4n;\n return function tonelliFast(Fp, n) {\n const root = Fp.pow(n, p1div4);\n if (!Fp.eql(Fp.sqr(root), n))\n throw new Error('Cannot find square root');\n return root;\n };\n }\n // Slow-path\n const Q1div2 = (Q + _1n) / _2n;\n return function tonelliSlow(Fp, n) {\n // Step 0: Check that n is indeed a square: (n | p) should not be ≡ -1\n if (Fp.pow(n, legendreC) === Fp.neg(Fp.ONE))\n throw new Error('Cannot find square root');\n let r = S;\n // TODO: will fail at Fp2/etc\n let g = Fp.pow(Fp.mul(Fp.ONE, Z), Q); // will update both x and b\n let x = Fp.pow(n, Q1div2); // first guess at the square root\n let b = Fp.pow(n, Q); // first guess at the fudge factor\n while (!Fp.eql(b, Fp.ONE)) {\n if (Fp.eql(b, Fp.ZERO))\n return Fp.ZERO; // https://en.wikipedia.org/wiki/Tonelli%E2%80%93Shanks_algorithm (4. If t = 0, return r = 0)\n // Find m such b^(2^m)==1\n let m = 1;\n for (let t2 = Fp.sqr(b); m < r; m++) {\n if (Fp.eql(t2, Fp.ONE))\n break;\n t2 = Fp.sqr(t2); // t2 *= t2\n }\n // NOTE: r-m-1 can be bigger than 32, need to convert to bigint before shift, otherwise there will be overflow\n const ge = Fp.pow(g, _1n << BigInt(r - m - 1)); // ge = 2^(r-m-1)\n g = Fp.sqr(ge); // g = ge * ge\n x = Fp.mul(x, ge); // x *= ge\n b = Fp.mul(b, g); // b *= g\n r = m;\n }\n return x;\n };\n}\nexport function FpSqrt(P) {\n // NOTE: different algorithms can give different roots, it is up to user to decide which one they want.\n // For example there is FpSqrtOdd/FpSqrtEven to choice root based on oddness (used for hash-to-curve).\n // P ≡ 3 (mod 4)\n // √n = n^((P+1)/4)\n if (P % _4n === _3n) {\n // Not all roots possible!\n // const ORDER =\n // 0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaabn;\n // const NUM = 72057594037927816n;\n const p1div4 = (P + _1n) / _4n;\n return function sqrt3mod4(Fp, n) {\n const root = Fp.pow(n, p1div4);\n // Throw if root**2 != n\n if (!Fp.eql(Fp.sqr(root), n))\n throw new Error('Cannot find square root');\n return root;\n };\n }\n // Atkin algorithm for q ≡ 5 (mod 8), https://eprint.iacr.org/2012/685.pdf (page 10)\n if (P % _8n === _5n) {\n const c1 = (P - _5n) / _8n;\n return function sqrt5mod8(Fp, n) {\n const n2 = Fp.mul(n, _2n);\n const v = Fp.pow(n2, c1);\n const nv = Fp.mul(n, v);\n const i = Fp.mul(Fp.mul(nv, _2n), v);\n const root = Fp.mul(nv, Fp.sub(i, Fp.ONE));\n if (!Fp.eql(Fp.sqr(root), n))\n throw new Error('Cannot find square root');\n return root;\n };\n }\n // P ≡ 9 (mod 16)\n if (P % _16n === _9n) {\n // NOTE: tonelli is too slow for bls-Fp2 calculations even on start\n // Means we cannot use sqrt for constants at all!\n //\n // const c1 = Fp.sqrt(Fp.negate(Fp.ONE)); // 1. c1 = sqrt(-1) in F, i.e., (c1^2) == -1 in F\n // const c2 = Fp.sqrt(c1); // 2. c2 = sqrt(c1) in F, i.e., (c2^2) == c1 in F\n // const c3 = Fp.sqrt(Fp.negate(c1)); // 3. c3 = sqrt(-c1) in F, i.e., (c3^2) == -c1 in F\n // const c4 = (P + _7n) / _16n; // 4. c4 = (q + 7) / 16 # Integer arithmetic\n // sqrt = (x) => {\n // let tv1 = Fp.pow(x, c4); // 1. tv1 = x^c4\n // let tv2 = Fp.mul(c1, tv1); // 2. tv2 = c1 * tv1\n // const tv3 = Fp.mul(c2, tv1); // 3. tv3 = c2 * tv1\n // let tv4 = Fp.mul(c3, tv1); // 4. tv4 = c3 * tv1\n // const e1 = Fp.equals(Fp.square(tv2), x); // 5. e1 = (tv2^2) == x\n // const e2 = Fp.equals(Fp.square(tv3), x); // 6. e2 = (tv3^2) == x\n // tv1 = Fp.cmov(tv1, tv2, e1); // 7. tv1 = CMOV(tv1, tv2, e1) # Select tv2 if (tv2^2) == x\n // tv2 = Fp.cmov(tv4, tv3, e2); // 8. tv2 = CMOV(tv4, tv3, e2) # Select tv3 if (tv3^2) == x\n // const e3 = Fp.equals(Fp.square(tv2), x); // 9. e3 = (tv2^2) == x\n // return Fp.cmov(tv1, tv2, e3); // 10. z = CMOV(tv1, tv2, e3) # Select the sqrt from tv1 and tv2\n // }\n }\n // Other cases: Tonelli-Shanks algorithm\n return tonelliShanks(P);\n}\n// Little-endian check for first LE bit (last BE bit);\nexport const isNegativeLE = (num, modulo) => (mod(num, modulo) & _1n) === _1n;\n// prettier-ignore\nconst FIELD_FIELDS = [\n 'create', 'isValid', 'is0', 'neg', 'inv', 'sqrt', 'sqr',\n 'eql', 'add', 'sub', 'mul', 'pow', 'div',\n 'addN', 'subN', 'mulN', 'sqrN'\n];\nexport function validateField(field) {\n const initial = {\n ORDER: 'bigint',\n MASK: 'bigint',\n BYTES: 'isSafeInteger',\n BITS: 'isSafeInteger',\n };\n const opts = FIELD_FIELDS.reduce((map, val) => {\n map[val] = 'function';\n return map;\n }, initial);\n return validateObject(field, opts);\n}\n// Generic field functions\nexport function FpPow(f, num, power) {\n // Should have same speed as pow for bigints\n // TODO: benchmark!\n if (power < _0n)\n throw new Error('Expected power > 0');\n if (power === _0n)\n return f.ONE;\n if (power === _1n)\n return num;\n let p = f.ONE;\n let d = num;\n while (power > _0n) {\n if (power & _1n)\n p = f.mul(p, d);\n d = f.sqr(d);\n power >>= _1n;\n }\n return p;\n}\n// 0 is non-invertible: non-batched version will throw on 0\nexport function FpInvertBatch(f, nums) {\n const tmp = new Array(nums.length);\n // Walk from first to last, multiply them by each other MOD p\n const lastMultiplied = nums.reduce((acc, num, i) => {\n if (f.is0(num))\n return acc;\n tmp[i] = acc;\n return f.mul(acc, num);\n }, f.ONE);\n // Invert last element\n const inverted = f.inv(lastMultiplied);\n // Walk from last to first, multiply them by inverted each other MOD p\n nums.reduceRight((acc, num, i) => {\n if (f.is0(num))\n return acc;\n tmp[i] = f.mul(acc, tmp[i]);\n return f.mul(acc, num);\n }, inverted);\n return tmp;\n}\nexport function FpDiv(f, lhs, rhs) {\n return f.mul(lhs, typeof rhs === 'bigint' ? invert(rhs, f.ORDER) : f.inv(rhs));\n}\n// This function returns True whenever the value x is a square in the field F.\nexport function FpIsSquare(f) {\n const legendreConst = (f.ORDER - _1n) / _2n; // Integer arithmetic\n return (x) => {\n const p = f.pow(x, legendreConst);\n return f.eql(p, f.ZERO) || f.eql(p, f.ONE);\n };\n}\n// CURVE.n lengths\nexport function nLength(n, nBitLength) {\n // Bit size, byte size of CURVE.n\n const _nBitLength = nBitLength !== undefined ? nBitLength : n.toString(2).length;\n const nByteLength = Math.ceil(_nBitLength / 8);\n return { nBitLength: _nBitLength, nByteLength };\n}\n/**\n * Initializes a galois field over prime. Non-primes are not supported for now.\n * Do not init in loop: slow. Very fragile: always run a benchmark on change.\n * Major performance gains:\n * a) non-normalized operations like mulN instead of mul\n * b) `Object.freeze`\n * c) Same object shape: never add or remove keys\n * @param ORDER prime positive bigint\n * @param bitLen how many bits the field consumes\n * @param isLE (def: false) if encoding / decoding should be in little-endian\n * @param redef optional faster redefinitions of sqrt and other methods\n */\nexport function Field(ORDER, bitLen, isLE = false, redef = {}) {\n if (ORDER <= _0n)\n throw new Error(`Expected Fp ORDER > 0, got ${ORDER}`);\n const { nBitLength: BITS, nByteLength: BYTES } = nLength(ORDER, bitLen);\n if (BYTES > 2048)\n throw new Error('Field lengths over 2048 bytes are not supported');\n const sqrtP = FpSqrt(ORDER);\n const f = Object.freeze({\n ORDER,\n BITS,\n BYTES,\n MASK: bitMask(BITS),\n ZERO: _0n,\n ONE: _1n,\n create: (num) => mod(num, ORDER),\n isValid: (num) => {\n if (typeof num !== 'bigint')\n throw new Error(`Invalid field element: expected bigint, got ${typeof num}`);\n return _0n <= num && num < ORDER; // 0 is valid element, but it's not invertible\n },\n is0: (num) => num === _0n,\n isOdd: (num) => (num & _1n) === _1n,\n neg: (num) => mod(-num, ORDER),\n eql: (lhs, rhs) => lhs === rhs,\n sqr: (num) => mod(num * num, ORDER),\n add: (lhs, rhs) => mod(lhs + rhs, ORDER),\n sub: (lhs, rhs) => mod(lhs - rhs, ORDER),\n mul: (lhs, rhs) => mod(lhs * rhs, ORDER),\n pow: (num, power) => FpPow(f, num, power),\n div: (lhs, rhs) => mod(lhs * invert(rhs, ORDER), ORDER),\n // Same as above, but doesn't normalize\n sqrN: (num) => num * num,\n addN: (lhs, rhs) => lhs + rhs,\n subN: (lhs, rhs) => lhs - rhs,\n mulN: (lhs, rhs) => lhs * rhs,\n inv: (num) => invert(num, ORDER),\n sqrt: redef.sqrt || ((n) => sqrtP(f, n)),\n invertBatch: (lst) => FpInvertBatch(f, lst),\n // TODO: do we really need constant cmov?\n // We don't have const-time bigints anyway, so probably will be not very useful\n cmov: (a, b, c) => (c ? b : a),\n toBytes: (num) => (isLE ? numberToBytesLE(num, BYTES) : numberToBytesBE(num, BYTES)),\n fromBytes: (bytes) => {\n if (bytes.length !== BYTES)\n throw new Error(`Fp.fromBytes: expected ${BYTES}, got ${bytes.length}`);\n return isLE ? bytesToNumberLE(bytes) : bytesToNumberBE(bytes);\n },\n });\n return Object.freeze(f);\n}\nexport function FpSqrtOdd(Fp, elm) {\n if (!Fp.isOdd)\n throw new Error(`Field doesn't have isOdd`);\n const root = Fp.sqrt(elm);\n return Fp.isOdd(root) ? root : Fp.neg(root);\n}\nexport function FpSqrtEven(Fp, elm) {\n if (!Fp.isOdd)\n throw new Error(`Field doesn't have isOdd`);\n const root = Fp.sqrt(elm);\n return Fp.isOdd(root) ? Fp.neg(root) : root;\n}\n/**\n * FIPS 186 B.4.1-compliant \"constant-time\" private key generation utility.\n * Can take (n+8) or more bytes of uniform input e.g. from CSPRNG or KDF\n * and convert them into private scalar, with the modulo bias being negligible.\n * Needs at least 40 bytes of input for 32-byte private key.\n * https://research.kudelskisecurity.com/2020/07/28/the-definitive-guide-to-modulo-bias-and-how-to-avoid-it/\n * @param hash hash output from SHA3 or a similar function\n * @param groupOrder size of subgroup - (e.g. curveFn.CURVE.n)\n * @param isLE interpret hash bytes as LE num\n * @returns valid private scalar\n */\nexport function hashToPrivateScalar(hash, groupOrder, isLE = false) {\n hash = ensureBytes('privateHash', hash);\n const hashLen = hash.length;\n const minLen = nLength(groupOrder).nByteLength + 8;\n if (minLen < 24 || hashLen < minLen || hashLen > 1024)\n throw new Error(`hashToPrivateScalar: expected ${minLen}-1024 bytes of input, got ${hashLen}`);\n const num = isLE ? bytesToNumberLE(hash) : bytesToNumberBE(hash);\n return mod(num, groupOrder - _1n) + _1n;\n}\n//# sourceMappingURL=modular.js.map","/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */\n// Abelian group utilities\nimport { validateField, nLength } from './modular.js';\nimport { validateObject } from './utils.js';\nconst _0n = BigInt(0);\nconst _1n = BigInt(1);\n// Elliptic curve multiplication of Point by scalar. Fragile.\n// Scalars should always be less than curve order: this should be checked inside of a curve itself.\n// Creates precomputation tables for fast multiplication:\n// - private scalar is split by fixed size windows of W bits\n// - every window point is collected from window's table & added to accumulator\n// - since windows are different, same point inside tables won't be accessed more than once per calc\n// - each multiplication is 'Math.ceil(CURVE_ORDER / 𝑊) + 1' point additions (fixed for any scalar)\n// - +1 window is neccessary for wNAF\n// - wNAF reduces table size: 2x less memory + 2x faster generation, but 10% slower multiplication\n// TODO: Research returning 2d JS array of windows, instead of a single window. This would allow\n// windows to be in different memory locations\nexport function wNAF(c, bits) {\n const constTimeNegate = (condition, item) => {\n const neg = item.negate();\n return condition ? neg : item;\n };\n const opts = (W) => {\n const windows = Math.ceil(bits / W) + 1; // +1, because\n const windowSize = 2 ** (W - 1); // -1 because we skip zero\n return { windows, windowSize };\n };\n return {\n constTimeNegate,\n // non-const time multiplication ladder\n unsafeLadder(elm, n) {\n let p = c.ZERO;\n let d = elm;\n while (n > _0n) {\n if (n & _1n)\n p = p.add(d);\n d = d.double();\n n >>= _1n;\n }\n return p;\n },\n /**\n * Creates a wNAF precomputation window. Used for caching.\n * Default window size is set by `utils.precompute()` and is equal to 8.\n * Number of precomputed points depends on the curve size:\n * 2^(𝑊−1) * (Math.ceil(𝑛 / 𝑊) + 1), where:\n * - 𝑊 is the window size\n * - 𝑛 is the bitlength of the curve order.\n * For a 256-bit curve and window size 8, the number of precomputed points is 128 * 33 = 4224.\n * @returns precomputed point tables flattened to a single array\n */\n precomputeWindow(elm, W) {\n const { windows, windowSize } = opts(W);\n const points = [];\n let p = elm;\n let base = p;\n for (let window = 0; window < windows; window++) {\n base = p;\n points.push(base);\n // =1, because we skip zero\n for (let i = 1; i < windowSize; i++) {\n base = base.add(p);\n points.push(base);\n }\n p = base.double();\n }\n return points;\n },\n /**\n * Implements ec multiplication using precomputed tables and w-ary non-adjacent form.\n * @param W window size\n * @param precomputes precomputed tables\n * @param n scalar (we don't check here, but should be less than curve order)\n * @returns real and fake (for const-time) points\n */\n wNAF(W, precomputes, n) {\n // TODO: maybe check that scalar is less than group order? wNAF behavious is undefined otherwise\n // But need to carefully remove other checks before wNAF. ORDER == bits here\n const { windows, windowSize } = opts(W);\n let p = c.ZERO;\n let f = c.BASE;\n const mask = BigInt(2 ** W - 1); // Create mask with W ones: 0b1111 for W=4 etc.\n const maxNumber = 2 ** W;\n const shiftBy = BigInt(W);\n for (let window = 0; window < windows; window++) {\n const offset = window * windowSize;\n // Extract W bits.\n let wbits = Number(n & mask);\n // Shift number by W bits.\n n >>= shiftBy;\n // If the bits are bigger than max size, we'll split those.\n // +224 => 256 - 32\n if (wbits > windowSize) {\n wbits -= maxNumber;\n n += _1n;\n }\n // This code was first written with assumption that 'f' and 'p' will never be infinity point:\n // since each addition is multiplied by 2 ** W, it cannot cancel each other. However,\n // there is negate now: it is possible that negated element from low value\n // would be the same as high element, which will create carry into next window.\n // It's not obvious how this can fail, but still worth investigating later.\n // Check if we're onto Zero point.\n // Add random point inside current window to f.\n const offset1 = offset;\n const offset2 = offset + Math.abs(wbits) - 1; // -1 because we skip zero\n const cond1 = window % 2 !== 0;\n const cond2 = wbits < 0;\n if (wbits === 0) {\n // The most important part for const-time getPublicKey\n f = f.add(constTimeNegate(cond1, precomputes[offset1]));\n }\n else {\n p = p.add(constTimeNegate(cond2, precomputes[offset2]));\n }\n }\n // JIT-compiler should not eliminate f here, since it will later be used in normalizeZ()\n // Even if the variable is still unused, there are some checks which will\n // throw an exception, so compiler needs to prove they won't happen, which is hard.\n // At this point there is a way to F be infinity-point even if p is not,\n // which makes it less const-time: around 1 bigint multiply.\n return { p, f };\n },\n wNAFCached(P, precomputesMap, n, transform) {\n // @ts-ignore\n const W = P._WINDOW_SIZE || 1;\n // Calculate precomputes on a first run, reuse them after\n let comp = precomputesMap.get(P);\n if (!comp) {\n comp = this.precomputeWindow(P, W);\n if (W !== 1) {\n precomputesMap.set(P, transform(comp));\n }\n }\n return this.wNAF(W, comp, n);\n },\n };\n}\nexport function validateBasic(curve) {\n validateField(curve.Fp);\n validateObject(curve, {\n n: 'bigint',\n h: 'bigint',\n Gx: 'field',\n Gy: 'field',\n }, {\n nBitLength: 'isSafeInteger',\n nByteLength: 'isSafeInteger',\n });\n // Set defaults\n return Object.freeze({\n ...nLength(curve.n, curve.nBitLength),\n ...curve,\n ...{ p: curve.Fp.ORDER },\n });\n}\n//# sourceMappingURL=curve.js.map","/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */\n// Short Weierstrass curve. The formula is: y² = x³ + ax + b\nimport * as mod from './modular.js';\nimport * as ut from './utils.js';\nimport { ensureBytes } from './utils.js';\nimport { wNAF, validateBasic } from './curve.js';\nfunction validatePointOpts(curve) {\n const opts = validateBasic(curve);\n ut.validateObject(opts, {\n a: 'field',\n b: 'field',\n }, {\n allowedPrivateKeyLengths: 'array',\n wrapPrivateKey: 'boolean',\n isTorsionFree: 'function',\n clearCofactor: 'function',\n allowInfinityPoint: 'boolean',\n fromBytes: 'function',\n toBytes: 'function',\n });\n const { endo, Fp, a } = opts;\n if (endo) {\n if (!Fp.eql(a, Fp.ZERO)) {\n throw new Error('Endomorphism can only be defined for Koblitz curves that have a=0');\n }\n if (typeof endo !== 'object' ||\n typeof endo.beta !== 'bigint' ||\n typeof endo.splitScalar !== 'function') {\n throw new Error('Expected endomorphism with beta: bigint and splitScalar: function');\n }\n }\n return Object.freeze({ ...opts });\n}\n// ASN.1 DER encoding utilities\nconst { bytesToNumberBE: b2n, hexToBytes: h2b } = ut;\nexport const DER = {\n // asn.1 DER encoding utils\n Err: class DERErr extends Error {\n constructor(m = '') {\n super(m);\n }\n },\n _parseInt(data) {\n const { Err: E } = DER;\n if (data.length < 2 || data[0] !== 0x02)\n throw new E('Invalid signature integer tag');\n const len = data[1];\n const res = data.subarray(2, len + 2);\n if (!len || res.length !== len)\n throw new E('Invalid signature integer: wrong length');\n // https://crypto.stackexchange.com/a/57734 Leftmost bit of first byte is 'negative' flag,\n // since we always use positive integers here. It must always be empty:\n // - add zero byte if exists\n // - if next byte doesn't have a flag, leading zero is not allowed (minimal encoding)\n if (res[0] & 0b10000000)\n throw new E('Invalid sign