utils.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. exports.bitMask = void 0;
  4. exports.isBytes = isBytes;
  5. exports.abytes = abytes;
  6. exports.bytesToHex = bytesToHex;
  7. exports.numberToHexUnpadded = numberToHexUnpadded;
  8. exports.hexToNumber = hexToNumber;
  9. exports.hexToBytes = hexToBytes;
  10. exports.bytesToNumberBE = bytesToNumberBE;
  11. exports.bytesToNumberLE = bytesToNumberLE;
  12. exports.numberToBytesBE = numberToBytesBE;
  13. exports.numberToBytesLE = numberToBytesLE;
  14. exports.numberToVarBytesBE = numberToVarBytesBE;
  15. exports.ensureBytes = ensureBytes;
  16. exports.concatBytes = concatBytes;
  17. exports.equalBytes = equalBytes;
  18. exports.utf8ToBytes = utf8ToBytes;
  19. exports.bitLen = bitLen;
  20. exports.bitGet = bitGet;
  21. exports.bitSet = bitSet;
  22. exports.createHmacDrbg = createHmacDrbg;
  23. exports.validateObject = validateObject;
  24. /*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
  25. // 100 lines of code in the file are duplicated from noble-hashes (utils).
  26. // This is OK: `abstract` directory does not use noble-hashes.
  27. // User may opt-in into using different hashing library. This way, noble-hashes
  28. // won't be included into their bundle.
  29. const _0n = /* @__PURE__ */ BigInt(0);
  30. const _1n = /* @__PURE__ */ BigInt(1);
  31. const _2n = /* @__PURE__ */ BigInt(2);
  32. function isBytes(a) {
  33. return (a instanceof Uint8Array ||
  34. (a != null && typeof a === 'object' && a.constructor.name === 'Uint8Array'));
  35. }
  36. function abytes(item) {
  37. if (!isBytes(item))
  38. throw new Error('Uint8Array expected');
  39. }
  40. // Array where index 0xf0 (240) is mapped to string 'f0'
  41. const hexes = /* @__PURE__ */ Array.from({ length: 256 }, (_, i) => i.toString(16).padStart(2, '0'));
  42. /**
  43. * @example bytesToHex(Uint8Array.from([0xca, 0xfe, 0x01, 0x23])) // 'cafe0123'
  44. */
  45. function bytesToHex(bytes) {
  46. abytes(bytes);
  47. // pre-caching improves the speed 6x
  48. let hex = '';
  49. for (let i = 0; i < bytes.length; i++) {
  50. hex += hexes[bytes[i]];
  51. }
  52. return hex;
  53. }
  54. function numberToHexUnpadded(num) {
  55. const hex = num.toString(16);
  56. return hex.length & 1 ? `0${hex}` : hex;
  57. }
  58. function hexToNumber(hex) {
  59. if (typeof hex !== 'string')
  60. throw new Error('hex string expected, got ' + typeof hex);
  61. // Big Endian
  62. return BigInt(hex === '' ? '0' : `0x${hex}`);
  63. }
  64. // We use optimized technique to convert hex string to byte array
  65. const asciis = { _0: 48, _9: 57, _A: 65, _F: 70, _a: 97, _f: 102 };
  66. function asciiToBase16(char) {
  67. if (char >= asciis._0 && char <= asciis._9)
  68. return char - asciis._0;
  69. if (char >= asciis._A && char <= asciis._F)
  70. return char - (asciis._A - 10);
  71. if (char >= asciis._a && char <= asciis._f)
  72. return char - (asciis._a - 10);
  73. return;
  74. }
  75. /**
  76. * @example hexToBytes('cafe0123') // Uint8Array.from([0xca, 0xfe, 0x01, 0x23])
  77. */
  78. function hexToBytes(hex) {
  79. if (typeof hex !== 'string')
  80. throw new Error('hex string expected, got ' + typeof hex);
  81. const hl = hex.length;
  82. const al = hl / 2;
  83. if (hl % 2)
  84. throw new Error('padded hex string expected, got unpadded hex of length ' + hl);
  85. const array = new Uint8Array(al);
  86. for (let ai = 0, hi = 0; ai < al; ai++, hi += 2) {
  87. const n1 = asciiToBase16(hex.charCodeAt(hi));
  88. const n2 = asciiToBase16(hex.charCodeAt(hi + 1));
  89. if (n1 === undefined || n2 === undefined) {
  90. const char = hex[hi] + hex[hi + 1];
  91. throw new Error('hex string expected, got non-hex character "' + char + '" at index ' + hi);
  92. }
  93. array[ai] = n1 * 16 + n2;
  94. }
  95. return array;
  96. }
  97. // BE: Big Endian, LE: Little Endian
  98. function bytesToNumberBE(bytes) {
  99. return hexToNumber(bytesToHex(bytes));
  100. }
  101. function bytesToNumberLE(bytes) {
  102. abytes(bytes);
  103. return hexToNumber(bytesToHex(Uint8Array.from(bytes).reverse()));
  104. }
  105. function numberToBytesBE(n, len) {
  106. return hexToBytes(n.toString(16).padStart(len * 2, '0'));
  107. }
  108. function numberToBytesLE(n, len) {
  109. return numberToBytesBE(n, len).reverse();
  110. }
  111. // Unpadded, rarely used
  112. function numberToVarBytesBE(n) {
  113. return hexToBytes(numberToHexUnpadded(n));
  114. }
  115. /**
  116. * Takes hex string or Uint8Array, converts to Uint8Array.
  117. * Validates output length.
  118. * Will throw error for other types.
  119. * @param title descriptive title for an error e.g. 'private key'
  120. * @param hex hex string or Uint8Array
  121. * @param expectedLength optional, will compare to result array's length
  122. * @returns
  123. */
  124. function ensureBytes(title, hex, expectedLength) {
  125. let res;
  126. if (typeof hex === 'string') {
  127. try {
  128. res = hexToBytes(hex);
  129. }
  130. catch (e) {
  131. throw new Error(`${title} must be valid hex string, got "${hex}". Cause: ${e}`);
  132. }
  133. }
  134. else if (isBytes(hex)) {
  135. // Uint8Array.from() instead of hash.slice() because node.js Buffer
  136. // is instance of Uint8Array, and its slice() creates **mutable** copy
  137. res = Uint8Array.from(hex);
  138. }
  139. else {
  140. throw new Error(`${title} must be hex string or Uint8Array`);
  141. }
  142. const len = res.length;
  143. if (typeof expectedLength === 'number' && len !== expectedLength)
  144. throw new Error(`${title} expected ${expectedLength} bytes, got ${len}`);
  145. return res;
  146. }
  147. /**
  148. * Copies several Uint8Arrays into one.
  149. */
  150. function concatBytes(...arrays) {
  151. let sum = 0;
  152. for (let i = 0; i < arrays.length; i++) {
  153. const a = arrays[i];
  154. abytes(a);
  155. sum += a.length;
  156. }
  157. const res = new Uint8Array(sum);
  158. for (let i = 0, pad = 0; i < arrays.length; i++) {
  159. const a = arrays[i];
  160. res.set(a, pad);
  161. pad += a.length;
  162. }
  163. return res;
  164. }
  165. // Compares 2 u8a-s in kinda constant time
  166. function equalBytes(a, b) {
  167. if (a.length !== b.length)
  168. return false;
  169. let diff = 0;
  170. for (let i = 0; i < a.length; i++)
  171. diff |= a[i] ^ b[i];
  172. return diff === 0;
  173. }
  174. /**
  175. * @example utf8ToBytes('abc') // new Uint8Array([97, 98, 99])
  176. */
  177. function utf8ToBytes(str) {
  178. if (typeof str !== 'string')
  179. throw new Error(`utf8ToBytes expected string, got ${typeof str}`);
  180. return new Uint8Array(new TextEncoder().encode(str)); // https://bugzil.la/1681809
  181. }
  182. // Bit operations
  183. /**
  184. * Calculates amount of bits in a bigint.
  185. * Same as `n.toString(2).length`
  186. */
  187. function bitLen(n) {
  188. let len;
  189. for (len = 0; n > _0n; n >>= _1n, len += 1)
  190. ;
  191. return len;
  192. }
  193. /**
  194. * Gets single bit at position.
  195. * NOTE: first bit position is 0 (same as arrays)
  196. * Same as `!!+Array.from(n.toString(2)).reverse()[pos]`
  197. */
  198. function bitGet(n, pos) {
  199. return (n >> BigInt(pos)) & _1n;
  200. }
  201. /**
  202. * Sets single bit at position.
  203. */
  204. function bitSet(n, pos, value) {
  205. return n | ((value ? _1n : _0n) << BigInt(pos));
  206. }
  207. /**
  208. * Calculate mask for N bits. Not using ** operator with bigints because of old engines.
  209. * Same as BigInt(`0b${Array(i).fill('1').join('')}`)
  210. */
  211. const bitMask = (n) => (_2n << BigInt(n - 1)) - _1n;
  212. exports.bitMask = bitMask;
  213. // DRBG
  214. const u8n = (data) => new Uint8Array(data); // creates Uint8Array
  215. const u8fr = (arr) => Uint8Array.from(arr); // another shortcut
  216. /**
  217. * Minimal HMAC-DRBG from NIST 800-90 for RFC6979 sigs.
  218. * @returns function that will call DRBG until 2nd arg returns something meaningful
  219. * @example
  220. * const drbg = createHmacDRBG<Key>(32, 32, hmac);
  221. * drbg(seed, bytesToKey); // bytesToKey must return Key or undefined
  222. */
  223. function createHmacDrbg(hashLen, qByteLen, hmacFn) {
  224. if (typeof hashLen !== 'number' || hashLen < 2)
  225. throw new Error('hashLen must be a number');
  226. if (typeof qByteLen !== 'number' || qByteLen < 2)
  227. throw new Error('qByteLen must be a number');
  228. if (typeof hmacFn !== 'function')
  229. throw new Error('hmacFn must be a function');
  230. // Step B, Step C: set hashLen to 8*ceil(hlen/8)
  231. let v = u8n(hashLen); // Minimal non-full-spec HMAC-DRBG from NIST 800-90 for RFC6979 sigs.
  232. let k = u8n(hashLen); // Steps B and C of RFC6979 3.2: set hashLen, in our case always same
  233. let i = 0; // Iterations counter, will throw when over 1000
  234. const reset = () => {
  235. v.fill(1);
  236. k.fill(0);
  237. i = 0;
  238. };
  239. const h = (...b) => hmacFn(k, v, ...b); // hmac(k)(v, ...values)
  240. const reseed = (seed = u8n()) => {
  241. // HMAC-DRBG reseed() function. Steps D-G
  242. k = h(u8fr([0x00]), seed); // k = hmac(k || v || 0x00 || seed)
  243. v = h(); // v = hmac(k || v)
  244. if (seed.length === 0)
  245. return;
  246. k = h(u8fr([0x01]), seed); // k = hmac(k || v || 0x01 || seed)
  247. v = h(); // v = hmac(k || v)
  248. };
  249. const gen = () => {
  250. // HMAC-DRBG generate() function
  251. if (i++ >= 1000)
  252. throw new Error('drbg: tried 1000 values');
  253. let len = 0;
  254. const out = [];
  255. while (len < qByteLen) {
  256. v = h();
  257. const sl = v.slice();
  258. out.push(sl);
  259. len += v.length;
  260. }
  261. return concatBytes(...out);
  262. };
  263. const genUntil = (seed, pred) => {
  264. reset();
  265. reseed(seed); // Steps D-G
  266. let res = undefined; // Step H: grind until k is in [1..n-1]
  267. while (!(res = pred(gen())))
  268. reseed();
  269. reset();
  270. return res;
  271. };
  272. return genUntil;
  273. }
  274. // Validating curves and fields
  275. const validatorFns = {
  276. bigint: (val) => typeof val === 'bigint',
  277. function: (val) => typeof val === 'function',
  278. boolean: (val) => typeof val === 'boolean',
  279. string: (val) => typeof val === 'string',
  280. stringOrUint8Array: (val) => typeof val === 'string' || isBytes(val),
  281. isSafeInteger: (val) => Number.isSafeInteger(val),
  282. array: (val) => Array.isArray(val),
  283. field: (val, object) => object.Fp.isValid(val),
  284. hash: (val) => typeof val === 'function' && Number.isSafeInteger(val.outputLen),
  285. };
  286. // type Record<K extends string | number | symbol, T> = { [P in K]: T; }
  287. function validateObject(object, validators, optValidators = {}) {
  288. const checkField = (fieldName, type, isOptional) => {
  289. const checkVal = validatorFns[type];
  290. if (typeof checkVal !== 'function')
  291. throw new Error(`Invalid validator "${type}", expected function`);
  292. const val = object[fieldName];
  293. if (isOptional && val === undefined)
  294. return;
  295. if (!checkVal(val, object)) {
  296. throw new Error(`Invalid param ${String(fieldName)}=${val} (${typeof val}), expected ${type}`);
  297. }
  298. };
  299. for (const [fieldName, type] of Object.entries(validators))
  300. checkField(fieldName, type, false);
  301. for (const [fieldName, type] of Object.entries(optValidators))
  302. checkField(fieldName, type, true);
  303. return object;
  304. }
  305. // validate type tests
  306. // const o: { a: number; b: number; c: number } = { a: 1, b: 5, c: 6 };
  307. // const z0 = validateObject(o, { a: 'isSafeInteger' }, { c: 'bigint' }); // Ok!
  308. // // Should fail type-check
  309. // const z1 = validateObject(o, { a: 'tmp' }, { c: 'zz' });
  310. // const z2 = validateObject(o, { a: 'isSafeInteger' }, { c: 'zz' });
  311. // const z3 = validateObject(o, { test: 'boolean', z: 'bug' });
  312. // const z4 = validateObject(o, { a: 'boolean', z: 'bug' });
  313. //# sourceMappingURL=utils.js.map