├── .github └── workflows │ └── ci.yml ├── .gitignore ├── README.md ├── index.ts ├── lib ├── bignum.ts ├── compare.ts ├── equals.ts ├── int32.ts ├── intdiv.ts ├── resize.ts ├── select.ts └── trim.ts ├── package-lock.json ├── package.json ├── tests ├── bignum.test.ts ├── compare.test.ts ├── equals.test.ts ├── int32.test.ts ├── intdiv.test.ts ├── resize.test.ts ├── select.test.ts ├── test-helper.ts └── trim.test.ts └── tsconfig.json /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: Unit Tests 2 | 3 | on: 4 | push: 5 | branches: [ main, master ] 6 | pull_request: 7 | branches: [ main, master ] 8 | 9 | jobs: 10 | build: 11 | 12 | runs-on: ubuntu-latest 13 | 14 | strategy: 15 | matrix: 16 | node-version: [14.x, 15.x, 16.x, 17.x, 18.x] 17 | 18 | steps: 19 | - uses: actions/checkout@v2 20 | - name: Use Node.js ${{ matrix.node-version }} 21 | uses: actions/setup-node@v1 22 | with: 23 | node-version: ${{ matrix.node-version }} 24 | - run: npm ci 25 | - run: npm run build --if-present 26 | - run: npm run test 27 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /.idea 2 | /node_modules 3 | /*.js 4 | /lib/*.js 5 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Constant-Time JavaScript 2 | 3 | Constant-time algorithms written in TypeScript. 4 | 5 | [![Build Status](https://github.com/soatok/constant-time-js/actions/workflows/ci.yml/badge.svg)](https://github.com/soatok/soatok/constant-time-js/actions) 6 | [![npm version](https://img.shields.io/npm/v/constant-time-js.svg)](https://npm.im/constant-time-js) 7 | 8 | **Important**: This Github repository is the companion to [Soatok's Guide to Side-Channel Attacks](https://soatok.blog/2020/08/27/soatoks-guide-to-side-channel-attacks/). 9 | Do not use this in production, especially if you don't have the budget for a cryptography audit. 10 | 11 | ![Mind Blowing, right?](https://soatok.files.wordpress.com/2020/08/soatoktelegrams2020-01.png) 12 | 13 | ## Installing and Usage 14 | 15 | Simply add `constant-time-js` to your dependencies section. One way to do this is with `npm`: 16 | 17 | ```terminal 18 | npm install --save constant-time-js 19 | ``` 20 | 21 | Next, you can import the modules you need. 22 | 23 | For JavaScript users: 24 | 25 | ```js 26 | const { compare, bignum } = require('constant-time-js'); 27 | ``` 28 | 29 | Tor TypeScript users: 30 | 31 | ```typescript 32 | import { compare, bignum } from 'constant-time-js'; 33 | ``` 34 | 35 | Please refer to the documentation below for what each function/class does. 36 | 37 | ## Documentation 38 | 39 | This is just a quick outline of what each function does. 40 | 41 | * `compare(a, b)` - Compare two `Uint8Array` objects. 42 | * [Explanation](https://soatok.blog/2020/08/27/soatoks-guide-to-side-channel-attacks/#string-inequality) 43 | * Returns `-1` if `a < b` 44 | * Returns `1` if `a > b` 45 | * Returns `0` if `a === b` 46 | * Throws an `Error` if `a.length !== b.length` 47 | * `compare_ints(a, b)` - Compare two integers. 48 | * [Explanation](https://soatok.blog/2020/08/27/soatoks-guide-to-side-channel-attacks/#string-inequality) 49 | * Returns `-1` if `a < b` 50 | * Returns `1` if `a > b` 51 | * Returns `0` if `a === b` 52 | * `equals(a, b)` - Are these `Uint8Array` objects equal? 53 | * [Explanation](https://soatok.blog/2020/08/27/soatoks-guide-to-side-channel-attacks/#string-comparison) 54 | * Returns `true` if they are equal. 55 | * Returns `false` if they are not equal. 56 | * Throws an `Error` if `a.length !== b.length` 57 | * `hmac_equals(a, b)` - Are these `Uint8Array` objects equal? (Using HMAC to compare.) 58 | * [Explanation](https://soatok.blog/2020/08/27/soatoks-guide-to-side-channel-attacks/#double-hmac) 59 | * Returns `true` if they are equal. 60 | * Returns `false` if they are not equal. 61 | * Throws an `Error` if `a.length !== b.length` 62 | * `intdiv(N, D)` - Divide `N` into `D`, discarding remainder. 63 | * [Explanation](https://soatok.blog/2020/08/27/soatoks-guide-to-side-channel-attacks/#integer-division) 64 | * Returns an integer. 65 | * `modulo(N, D)` - Divide `N` into `D`, return the remainder. 66 | * [Explanation](https://soatok.blog/2020/08/27/soatoks-guide-to-side-channel-attacks/#integer-division) 67 | * Returns an integer. 68 | * `resize(buf, size)` - Return a resized `Uint8Array` object (to side-step memory access leakage) 69 | * `select(x, a, b)` - Read it as a ternary. If `x` is true, returns `a`. Otherwise, returns `b`. 70 | * [Explanation](https://soatok.blog/2020/08/27/soatoks-guide-to-side-channel-attacks/#conditional-select) 71 | * `x` must be a `boolean` 72 | * `a` must be a `Uint8Array` 73 | * `b` must be a `Uint8Array` 74 | * Throws an `Error` if `a.length !== b.length` 75 | * `select_ints(x, a, b)` - Read it as a ternary. If `x` is even, returns `a`. Otherwise, returns `b`. 76 | (You should pass `1` or `0` for `x`). 77 | * [Explanation](https://soatok.blog/2020/08/27/soatoks-guide-to-side-channel-attacks/#conditional-select) 78 | * `x` must be a `boolean` 79 | * `a` must be a `number` 80 | * `b` must be a `number` 81 | * `trim_zeroes_left(buf)` 82 | * [Explanation](https://soatok.blog/2020/08/27/soatoks-guide-to-side-channel-attacks/#null-byte-trimming) 83 | * `buf` must be a `Uint8Array` 84 | * Returns a `Uint8Array` 85 | * `trim_zeroes_right(buf)` 86 | * [Explanation](https://soatok.blog/2020/08/27/soatoks-guide-to-side-channel-attacks/#null-byte-trimming) 87 | * `buf` must be a `Uint8Array` 88 | * Returns a `Uint8Array` 89 | 90 | ### BigNumber 91 | 92 | Our BigNumber implementation aims to be constant-time for the magnitude of the numbers 93 | (i.e. number of limbs or bytes, regardless of how many bits are significant). 94 | 95 | Unless otherwise stated, all of our APIs expect `Uint8Array` objects (`Buffer` extends 96 | from `Uint8Array` and should work too, but we return `Uint8Array` objects, not `Buffer` 97 | objects). 98 | 99 | Unless otherwise stated, all `Uint8Array` objects are **big-endian byte order**. 100 | 101 | Unless otherwise stated, all `Uint8Array` objects assume **unsigned integer** behavior. 102 | 103 | Unless otherwise stated, all of the `bignum` methods are immutable (meaning: they return 104 | a new `Uint8Array` object rather than mutating the input arrays). 105 | 106 | #### bignum.add() 107 | 108 | Returns `a + b`. Overflow is discarded. 109 | 110 | ```typescript 111 | /** 112 | * @var {Uint8Array} a 113 | * @var {Uint8Array} b 114 | */ 115 | const c: Uint8Array = bignum.add(a, b); 116 | ``` 117 | #### bignum.and() 118 | 119 | Returns `a & b` (bitwise AND). 120 | 121 | ```typescript 122 | /** 123 | * @var {Uint8Array} a 124 | * @var {Uint8Array} b 125 | */ 126 | const c: Uint8Array = bignum.and(a, b); 127 | ``` 128 | 129 | #### bignum.count_trailing_zero_bits() 130 | 131 | Counts the number of `0` bits beneath the most significant `1` bit. 132 | 133 | Returns a **BigInt** (the native JS type), since the number of bits may 134 | exceed 2^32 for an array that is less than 2^32 elements long. 135 | 136 | ```typescript 137 | /** 138 | * @var {Uint8Array} a 139 | */ 140 | const c: bigint = bignum.count_trailing_zero_bits(a, b); 141 | ``` 142 | 143 | #### bignum.divide() 144 | 145 | Calculate `a / b`, discarding the remainder. 146 | 147 | ```typescript 148 | /** 149 | * @var {Uint8Array} a 150 | * @var {Uint8Array} b 151 | */ 152 | const c: Uint8Array = bignum.divide(a, b); 153 | ``` 154 | 155 | #### bignum.gcd() 156 | 157 | Calculate the Greatest Common Denominator of two integers. 158 | 159 | ```typescript 160 | /** 161 | * @var {Uint8Array} a 162 | * @var {Uint8Array} b 163 | */ 164 | const c: Uint8Array = bignum.gcd(a, b); 165 | ``` 166 | 167 | #### bignum.is_nonzero() 168 | 169 | Returns true if this number is not equal to zero? 170 | 171 | ```typescript 172 | /** 173 | * @var {Uint8Array} x 174 | */ 175 | const check: boolean = bignum.is_nonzero(x); 176 | ``` 177 | 178 | #### bignum.lsb() 179 | 180 | Returns the least significant bit of a big number. 181 | (If `0`, this is a multiple of two.) 182 | 183 | ```typescript 184 | /** 185 | * @var {Uint8Array} x 186 | */ 187 | const least: number = bignum.lsb(x); 188 | ``` 189 | 190 | #### bignum.lshift1() 191 | 192 | **Mutates the input array.** 193 | 194 | Left-shift by 1. This is used internally in some algorithms. 195 | 196 | ```typescript 197 | /** 198 | * @var {Uint8Array} a 199 | */ 200 | lshift1(a); 201 | // `a` is now double its previous value 202 | ``` 203 | 204 | #### bignum.modulo() 205 | 206 | Calculate `a mod b`. 207 | 208 | ```typescript 209 | /** 210 | * @var {Uint8Array} a 211 | * @var {Uint8Array} b 212 | */ 213 | const c: Uint8Array = bignum.modulo(a, b); 214 | ``` 215 | 216 | #### bignum.modInverse() 217 | 218 | Calculate the modular inverse of two integers. 219 | 220 | **Throws if `gcd(a, b)` is not equal to `1`.** 221 | 222 | ```typescript 223 | /** 224 | * @var {Uint8Array} a 225 | * @var {Uint8Array} b 226 | */ 227 | let one_over_a: Uint8Array; 228 | try { 229 | one_over_a = bignum.modInverse(a, b); 230 | } catch (e) { 231 | // Handle exception when 1/a is not defined (mod b). 232 | } 233 | ``` 234 | 235 | #### bignum.modPow() 236 | 237 | Modular exponentiation. 238 | 239 | ```typescript 240 | /** 241 | * @var {Uint8Array} base 242 | * @var {Uint8Array} exp 243 | * @var {Uint8Array} mod 244 | */ 245 | const out: Uint8Array = bignum.modPow(base, exp, mod); 246 | ``` 247 | 248 | #### bignum.msb() 249 | 250 | Returns the most significant bit of a big number. 251 | 252 | ```typescript 253 | /** 254 | * @var {Uint8Array} x 255 | */ 256 | const most: number = bignum.msb(x); 257 | ``` 258 | 259 | #### bignum.multiply() 260 | 261 | Multiply two big numbers, return the product. 262 | 263 | The output size will be larger than the inputs. 264 | 265 | ```typescript 266 | /** 267 | * @var {Uint8Array} x 268 | * @var {Uint8Array} y 269 | */ 270 | const z: Uint8Array = bignum.multiply(x, y); 271 | ``` 272 | 273 | #### bignum.normalize() 274 | 275 | Resize an Uint8Array to the desired length. 276 | 277 | The default behavior is to treat the number as signed (thereby filling in the 278 | left with 0xFF bytes if the most significant bit of the input Uint8Array is set). 279 | 280 | Pass `true` to the optional third argument to always zero-fill this padding value. 281 | 282 | ```typescript 283 | /** 284 | * @var {Uint8Array} a 285 | * @var {number} len 286 | */ 287 | const c: Uint8Array = bignum.normalize(a, len); 288 | ``` 289 | 290 | #### bignum.or() 291 | 292 | Returns `a | b` (bitwise OR). 293 | 294 | ```typescript 295 | /** 296 | * @var {Uint8Array} a 297 | * @var {Uint8Array} b 298 | */ 299 | const c: Uint8Array = bignum.or(a, b); 300 | ``` 301 | 302 | 303 | #### bignum.pow() 304 | 305 | Exponentiation. 306 | 307 | ```typescript 308 | /** 309 | * @var {Uint8Array} a 310 | * @var {Uint8Array} n 311 | */ 312 | const c: Uint8Array = bignum.pow(a, n); 313 | ``` 314 | 315 | #### bignum.rshift1() 316 | 317 | **Mutates the input array.** 318 | 319 | Right-shift by 1. This is used internally in some algorithms. 320 | 321 | ```typescript 322 | /** 323 | * @var {Uint8Array} a 324 | */ 325 | rshift1(a); 326 | // `a` is half double its previous value 327 | ``` 328 | 329 | The default behavior is congruent to JavaScript's `>>` operator. 330 | For an unsigned right shift (`>>>`), pass `true` as the second argument: 331 | 332 | ``` 333 | rshift1(a, true); 334 | ``` 335 | 336 | #### bignum.shift_left() 337 | 338 | Shift left by an arbitrary amount. 339 | 340 | ```typescript 341 | /** 342 | * @var {Uint8Array} x 343 | */ 344 | const y: Uint8Array = bignum.shift_left(x, 3n); 345 | // y := 8 * x 346 | ``` 347 | 348 | #### bignum.shift_right() 349 | 350 | Shift right by an arbitrary amount. 351 | 352 | ```typescript 353 | /** 354 | * @var {Uint8Array} x 355 | */ 356 | const y: Uint8Array = bignum.shift_right(x, 3n); 357 | // y := x / 8 358 | ``` 359 | 360 | #### bignum.sub() 361 | 362 | Returns `a - b`. Use `msb()` to check if the output is negative. 363 | 364 | ```typescript 365 | /** 366 | * @var {Uint8Array} a 367 | * @var {Uint8Array} b 368 | */ 369 | const c: Uint8Array = bignum.sub(a, b); 370 | ``` 371 | 372 | #### bignum.xor() 373 | 374 | Returns `a ^ b` (bitwise XOR). 375 | 376 | ```typescript 377 | /** 378 | * @var {Uint8Array} a 379 | * @var {Uint8Array} b 380 | */ 381 | const c: Uint8Array = bignum.xor(a, b); 382 | ``` 383 | 384 | ## Limitations 385 | 386 | ### Potentially Dangerous on 32-bit Applications 387 | 388 | 32-bit v8 (and, presumably, a lot of other 32-bit implementations) do things wrong, 389 | and our implementation might be variable-time on it. 390 | 391 | Specifically, the most significant bit of a 32-bit integer distinguishes values from pointers. 392 | As a result, accessing the highest bit of a 32-bit number in 32-bit JavaScript engines (such as v8) 393 | is potentially variable-time. 394 | 395 | To mitigate this risk, the [`int32` class was created](https://github.com/soatok/constant-time-js/blob/master/lib/int32.ts) 396 | which wraps operates on 16-bit limbs (wrapping `Uint16Array`). 397 | 398 | ## Frequently Asked Questions 399 | 400 | ### But Why Though? 401 | 402 | ![Mwahahahahahaha!](https://soatok.files.wordpress.com/2020/04/soatok_stickerpack-evil-laughter.png) 403 | 404 | **For science!** 405 | 406 | This is a proof-of-concept library, that will eventually implement 407 | all of the algorithms described in [the accompanying blog post](https://soatok.blog/2020/08/27/soatoks-guide-to-side-channel-attacks/). 408 | 409 | The main purpose of this library is to demonstrate the concepts in a programming 410 | language widely accessible outside of the cryptography orthodoxy (which today is 411 | largely C and sometimes Python, and hopefully soon Rust). 412 | 413 | ### Can I use this in a project? 414 | 415 | Hold off until v1.0.0 is tagged before you even *think* about relying on it for 416 | anything. APIs might break until then. 417 | 418 | ### What's with the blue {fox, wolf}? 419 | 420 | My fursona is a [dhole](https://soatok.blog/2020/08/10/all-about-dholes-and-dhole-fursonas/), not a wolf. 421 | 422 | ### You should remove your fursona from this so my manager might take it seriously. 423 | 424 | I don't owe you anything. I don't owe your manager anything. 425 | 426 | Besides, if anyone is bigoted against a [predominantly LGBTQIA+ community](https://furscience.com/research-findings/sex-relationships-pornography/5-1-orientation/), 427 | they're precisely the sort of person whose career I don't want to help. 428 | 429 | In sum: 430 | 431 | [![I will increase the thing](https://soatok.files.wordpress.com/2020/07/increase-the-thing.png)](https://soatok.blog/2020/07/09/a-word-on-anti-furry-sentiments-in-the-tech-community/) 432 | -------------------------------------------------------------------------------- /index.ts: -------------------------------------------------------------------------------- 1 | export { compare, compare_ints, compare_alt, compare_ints_alt } from './lib/compare'; 2 | export * as bignum from './lib/bignum'; 3 | export { equals, hmac_equals } from './lib/equals'; 4 | export { intdiv, modulo } from './lib/intdiv'; 5 | export { resize } from './lib/resize'; 6 | export { select_alt, select_int32, select_ints, select } from './lib/select'; 7 | export { trim_zeroes_left, trim_zeroes_right } from './lib/trim'; 8 | -------------------------------------------------------------------------------- /lib/bignum.ts: -------------------------------------------------------------------------------- 1 | import {compare_alt} from './compare'; 2 | import {equals} from './equals'; 3 | import {modulo as mod} from './intdiv'; 4 | import {select, select_alt} from './select'; 5 | import {trim_zeroes_left} from './trim'; 6 | 7 | /** 8 | * Add two big numbers. Does not support overflow. 9 | * 10 | * @param {Uint8Array} a 11 | * @param {Uint8Array} b 12 | * @returns {Uint8Array} 13 | */ 14 | export function add(a: Uint8Array, b: Uint8Array): Uint8Array { 15 | const out: Uint8Array = new Uint8Array(Math.max(a.length, b.length)); 16 | let c: number = 0; 17 | for (let i: number = out.length - 1; i >= 0; i--) { 18 | c += a[i] + b[i]; 19 | out[i] = c & 0xff; 20 | c >>>= 8; 21 | } 22 | return out; 23 | } 24 | 25 | /** 26 | * Bitwise AND two big numbers. 27 | * 28 | * @param {Uint8Array} a 29 | * @param {Uint8Array} b 30 | * @returns {Uint8Array} 31 | */ 32 | export function and(a: Uint8Array, b: Uint8Array): Uint8Array { 33 | if (a.length !== b.length) { 34 | throw new Error('Both arrays must be of equal length'); 35 | } 36 | const c: Uint8Array = new Uint8Array(a.length); 37 | for (let i: number = 0; i < c.length; i++) { 38 | c[i] = a[i] & b[i]; 39 | } 40 | return c; 41 | } 42 | 43 | /** 44 | * Returns the number of trailing 0 bits (least significant, big endian) 45 | * in a big number. 46 | * 47 | * This returns a native bigint type because the number of zero bits might be 48 | * >= 2^32 for large data buffers (e.g. 2^30 bytes -> 2^33 bits). 49 | * 50 | * @param {Uint8Array} a 51 | * @returns {bigint} 52 | */ 53 | export function count_trailing_zero_bits(a: Uint8Array): bigint { 54 | let b: bigint = 0n; 55 | let num: bigint = 0n; 56 | let found: bigint = 0n; 57 | let bit: number = 0; 58 | for (let i: number = a.length - 1; i >= 0; i--) { 59 | for (let j: number = 0; j < 8; j++) { 60 | bit = (a[i] >>> j) & 1; // 1 if non-zero 61 | num = ((BigInt(-bit) & b) & ~found) ^ (num & found); 62 | found |= BigInt(-bit); // -1 if found, 0 if not 63 | b++; 64 | } 65 | } 66 | return num; 67 | } 68 | 69 | /** 70 | * Divide a / b. Returns only the quotient (no remainder). 71 | * 72 | * @param {Uint8Array} a 73 | * @param {Uint8Array} b 74 | * @returns {Uint8Array} 75 | */ 76 | export function divide(a: Uint8Array, b: Uint8Array): Uint8Array { 77 | return division(a, b)[0]; 78 | } 79 | 80 | /** 81 | * Calculate the greatest common denominator of two big numbers. 82 | * 83 | * @param {Uint8Array} a 84 | * @param {Uint8Array} b 85 | * @returns {Uint8Array} 86 | */ 87 | export function gcd(a: Uint8Array, b: Uint8Array): Uint8Array { 88 | return xgcd(a, b)[1]; 89 | } 90 | 91 | /** 92 | * Is this number anything except zero? 93 | * 94 | * @param {Uint8Array} num 95 | * @returns {boolean} 96 | */ 97 | export function is_nonzero(num: Uint8Array): boolean { 98 | let d: number = 0; 99 | for (let i: number = num.length - 1; i >= 0; i--) { 100 | d |= num[i]; 101 | } 102 | return d !== 0; 103 | } 104 | 105 | /** 106 | * Return the least significant bit (big endian). 107 | * 108 | * @param {Uint8Array} y 109 | * @returns {number} (0 or 1) 110 | */ 111 | export function lsb(y: Uint8Array): number { 112 | return y[y.length - 1] & 1; 113 | } 114 | 115 | /** 116 | * Left-shift this big number in-place by 1. 117 | * 118 | * @param {Uint8Array} x 119 | */ 120 | export function lshift1(x: Uint8Array): void { 121 | let carry: number = 0; 122 | let tmp: number = 0; 123 | for (let i: number = x.length - 1; i >= 0; i--) { 124 | tmp = x[i]; 125 | x[i] = (tmp << 1) | carry; 126 | carry = (tmp >>> 7) & 1; 127 | } 128 | } 129 | 130 | /** 131 | * Divide a / b. Returns the remainder. 132 | * 133 | * @param {Uint8Array} a 134 | * @param {Uint8Array} b 135 | * @returns {Uint8Array} 136 | */ 137 | export function modulo(a: Uint8Array, b: Uint8Array): Uint8Array { 138 | return division(a, b)[1]; 139 | } 140 | 141 | /** 142 | * Calculate a^x (mod m). 143 | * 144 | * @param {Uint8Array} a 145 | * @param {Uint8Array} x 146 | * @param {Uint8Array} m 147 | */ 148 | export function modPow(a: Uint8Array, x: Uint8Array, m: Uint8Array): Uint8Array { 149 | const zero: Uint8Array = new Uint8Array(m.length + 1); 150 | const one: Uint8Array = zero.slice(); 151 | one[one.length - 1] = 1; 152 | const two: Uint8Array = zero.slice(); 153 | two[two.length - 1] = 2; 154 | 155 | let length: number = zero.length << 1; 156 | const mod: Uint8Array = normalize(m, length); 157 | let result: Uint8Array = normalize(one, length); 158 | let base: Uint8Array = normalize(a, length); 159 | let e: Uint8Array = normalize(x, length); 160 | let p: Uint8Array; 161 | 162 | while (is_nonzero(e)) { 163 | /* 164 | if (exponent & 1) equals 1: 165 | result = (result * base) mod modulus 166 | */ 167 | p = multiply(result, base); 168 | p = normalize(modulo(p, mod), length, true); 169 | result = select_alt(lsb(e), p, result); 170 | 171 | /* 172 | exponent := exponent >> 1 173 | */ 174 | rshift1(e, true); 175 | 176 | /* 177 | base = (base * base) mod modulus 178 | */ 179 | p = multiply(base, base); 180 | p = normalize(modulo(p, mod), length, true); 181 | base = p; 182 | } 183 | return normalize(result, zero.length - 1); 184 | } 185 | 186 | /** 187 | * Calculate the modular inverse (1/x mod m). 188 | * 189 | * @param {Uint8Array} x 190 | * @param {Uint8Array} m 191 | */ 192 | export function modInverse(x: Uint8Array, m: Uint8Array): Uint8Array { 193 | const [a, y] = xgcd(x, m); 194 | 195 | /* if (y != 1) throw */ 196 | const one: Uint8Array = new Uint8Array(x.length); 197 | one[one.length - 1] = 1; 198 | if (!equals(one, y)) { 199 | throw new Error('inverse does not exist'); 200 | } 201 | /* if (gcd(x, m) == 1), a is the modular inverse */ 202 | return a; 203 | } 204 | 205 | /** 206 | * Return the most significant bit (big endian). 207 | * 208 | * @param {Uint8Array} x 209 | * @returns {number} (0 or 1) 210 | */ 211 | export function msb(x: Uint8Array): number { 212 | return (x[0] >>> 7) & 1; 213 | } 214 | 215 | /** 216 | * Multiply two big numbers. Output is twice the length of the input. 217 | * 218 | * @param {Uint8Array} a 219 | * @param {Uint8Array} b 220 | * @param {Number?} ops 221 | * @returns {Uint8Array} 222 | */ 223 | export function multiply(a: Uint8Array, b: Uint8Array, ops?: number): Uint8Array { 224 | let z = new Uint8Array(a.length + b.length); 225 | let x = new Uint8Array(z.length); 226 | let y = new Uint8Array(z.length); 227 | x.set(a, z.length - a.length); 228 | y.set(b, z.length - b.length); 229 | if (!ops) { 230 | ops = Math.max(x.length, y.length) << 3; 231 | } 232 | 233 | while (ops > 0) { 234 | z = select_alt(lsb(y), add(z, x), z); 235 | lshift1(x); 236 | rshift1(y); 237 | ops--; 238 | } 239 | return z; 240 | } 241 | 242 | /** 243 | * Normalize this output to the desired length. 244 | * 245 | * @param {Uint8Array} a 246 | * @param {number} l 247 | * @param {boolean} unsigned 248 | */ 249 | export function normalize(a: Uint8Array, l: number, unsigned?: boolean): Uint8Array { 250 | const out = new Uint8Array(l); 251 | const neg: number = unsigned 252 | ? 0x00 253 | : ((-msb(a)) & 0xff); 254 | let j: number = a.length - 1; 255 | const tmp: Int32Array = new Int32Array(1); 256 | for (let i: number = l - 1; i >= 0; i--, j--) { 257 | /* if j >= 0: 258 | fill = 0xff 259 | else: 260 | fill = 0x00 261 | */ 262 | tmp[0] = j >>> 31; 263 | tmp[0] *= -1; 264 | const fill: number = ~tmp[0] & 0xff; 265 | const index: number = mod(j, a.length) & fill; 266 | /* if j < 0, neg; else, a[j] */ 267 | out[i] = (a[index] & fill) ^ (neg & ~fill); 268 | } 269 | return out; 270 | } 271 | 272 | /** 273 | * Bitwise OR two big numbers. 274 | * 275 | * @param {Uint8Array} a 276 | * @param {Uint8Array} b 277 | * @returns {Uint8Array} 278 | */ 279 | export function or(a: Uint8Array, b: Uint8Array): Uint8Array { 280 | if (a.length !== b.length) { 281 | throw new Error('Both arrays must be of equal length'); 282 | } 283 | const c: Uint8Array = new Uint8Array(a.length); 284 | for (let i: number = 0; i < c.length; i++) { 285 | c[i] = a[i] | b[i]; 286 | } 287 | return c; 288 | } 289 | 290 | /** 291 | * Calculate a to the nth power. 292 | * 293 | * Based off algorithm 14.76 from the Handbook of Applied Cryptography 294 | * 295 | * @param {Uint8Array} a 296 | * @param {Uint8Array} n 297 | * @returns {Uint8Array} 298 | */ 299 | export function pow(a: Uint8Array, n: Uint8Array): Uint8Array { 300 | const one: Uint8Array = new Uint8Array(a.length); 301 | one[one.length - 1] = 1; 302 | 303 | let A: Uint8Array = one.slice(); 304 | let S: Uint8Array = a.slice(); 305 | let e: Uint8Array = n.slice(); 306 | let Aprime: Uint8Array; 307 | let Sprime: Uint8Array; 308 | do { 309 | Aprime = multiply(A, S); 310 | A = select_alt( 311 | lsb(e), 312 | Aprime, 313 | normalize(A, Aprime.length) 314 | ); 315 | rshift1(e, true); 316 | Sprime = multiply(S, S); 317 | S = select( 318 | is_nonzero(e), 319 | Sprime, 320 | normalize(S, Sprime.length) 321 | ); 322 | } while (is_nonzero(e)); 323 | return trim_zeroes_left(A); 324 | } 325 | 326 | /** 327 | * Right-shift a big number in-place. 328 | * 329 | * Defaults to a signed right shift (JS >> operator). 330 | * 331 | * Pass {true} to the second argument to make it behave like an 332 | * unsigned right shift (JS >>> operator). 333 | * 334 | * @param {Uint8Array} y 335 | * @param {boolean?} unsigned 336 | */ 337 | export function rshift1(y: Uint8Array, unsigned?: boolean): void { 338 | let carry: number = unsigned ? 0 : msb(y); 339 | let tmp: number = 0; 340 | for (let i: number = 0; i < y.length; i++) { 341 | // Get LSB 342 | tmp = y[i] & 1; 343 | // Right shift, restoring previous LSB to the MSB 344 | y[i] = (y[i] >>> 1) | (carry << 7); 345 | // Store LSB in carry 346 | carry = tmp; 347 | } 348 | } 349 | 350 | /** 351 | * Shift left by an arbitrary number of bits. 352 | * 353 | * @param {Uint8Array} a 354 | * @param {bigint} e 355 | */ 356 | export function shift_left(a: Uint8Array, e: bigint): Uint8Array { 357 | const out = new Uint8Array(a.length); 358 | let index: number = a.length - 1 - (Number(e >> 3n) & 0x7fffffff); 359 | const s: number = Number(e & 7n); 360 | const m: number = (1 << s) - 1; 361 | /* index <= i, 0 <= s <= 7, 0 <= m <= 127 */ 362 | let x: number = 0; 363 | let y: number = 0; 364 | let tmp: number = 0; 365 | let carry: number = 0; 366 | for (let i: number = a.length - 1; i >= 0; index--, i--) { 367 | x = ~(index >> 31); 368 | y = (mod(index, a.length) & x); 369 | tmp = (a[i] >>> (8 - s)) & m; 370 | out[y] = ((((a[i] << s) & 0xff) | carry) & x) ^ (out[y] & ~x); 371 | carry = tmp; 372 | } 373 | return out; 374 | } 375 | 376 | /** 377 | * Shift right by an arbitrary number of bits. 378 | * 379 | * @param {Uint8Array} a 380 | * @param {bigint} e 381 | */ 382 | export function shift_right(a: Uint8Array, e: bigint): Uint8Array { 383 | const out = new Uint8Array(a.length); 384 | let index: number = (Number(e >> 3n) & 0x7fffffff); 385 | const s: number = Number(e & 7n); 386 | const m: number = ~((1 << s) - 1); 387 | /* index <= i, 0 <= s <= 7, 0 <= m <= 255 */ 388 | let x: number = 0; 389 | let y: number = 0; 390 | let tmp: number = 0; 391 | let carry: number = 0; 392 | for (let i: number = 0; i < a.length; i++, index++) { 393 | x = ~((a.length - index - 1) >> 31); 394 | y = (mod(index, a.length) & x); 395 | tmp = (a[i] << (8 - s)) & m; 396 | out[y] = ((((a[i] >>> s) & 0xff) | carry) & x) ^ (out[y] & ~x); 397 | carry = tmp; 398 | } 399 | return out; 400 | } 401 | 402 | /** 403 | * Subtract two big numbers. 404 | * 405 | * @param {Uint8Array} a 406 | * @param {Uint8Array} b 407 | * @returns {Uint8Array} 408 | */ 409 | export function sub(a: Uint8Array, b: Uint8Array): Uint8Array { 410 | const out: Uint8Array = new Uint8Array(Math.max(a.length, b.length)); 411 | const c: Int16Array = new Int16Array(1); 412 | for (let i: number = out.length - 1; i >= 0; i--) { 413 | c[0] += a[i] - b[i]; 414 | out[i] = c[0] & 0xff; 415 | c[0] >>= 8; 416 | } 417 | return out; 418 | } 419 | 420 | /** 421 | * Bitwise XOR two big numbers. 422 | * 423 | * @param {Uint8Array} a 424 | * @param {Uint8Array} b 425 | * @returns {Uint8Array} 426 | */ 427 | export function xor(a: Uint8Array, b: Uint8Array): Uint8Array { 428 | if (a.length !== b.length) { 429 | throw new Error('Both arrays must be of equal length'); 430 | } 431 | const c: Uint8Array = new Uint8Array(a.length); 432 | for (let i: number = 0; i < c.length; i++) { 433 | c[i] = a[i] ^ b[i]; 434 | } 435 | return c; 436 | } 437 | 438 | /** 439 | * Return the minimum of two native bigints. 440 | * 441 | * @param {bigint} a 442 | * @param {bigint} b 443 | * @returns {bigint} 444 | */ 445 | function minBigInt(a: bigint, b: bigint): bigint { 446 | let d: bigint = b - a; 447 | d = (d >> 63n) & d; 448 | a += d; 449 | return a; 450 | } 451 | 452 | /** 453 | * Based on algorithm 14.61 from the Handbook of Applied Cryptography 454 | * 455 | * @param {Uint8Array} x 456 | * @param {Uint8Array} y 457 | * @returns {Uint8Array[]} 458 | */ 459 | function xgcd(x: Uint8Array, y: Uint8Array): Uint8Array[] { 460 | if (x.length !== y.length) { 461 | throw new Error('Normalize your Uint8Array lengths first'); 462 | } 463 | const zero: Uint8Array = new Uint8Array(y.length); 464 | const one: Uint8Array = zero.slice(); 465 | one[one.length - 1] = 1; 466 | 467 | const g: bigint = minBigInt( 468 | count_trailing_zero_bits(x), 469 | count_trailing_zero_bits(y), 470 | ); 471 | shift_right(x, g); 472 | shift_right(y, g); 473 | let u: Uint8Array = x.slice(); 474 | let v: Uint8Array = y.slice(); 475 | let A: Uint8Array = one.slice(); 476 | let B: Uint8Array = zero.slice(); 477 | let C: Uint8Array = zero.slice(); 478 | let D: Uint8Array = one.slice(); 479 | let bits: bigint; 480 | let swap: number; 481 | do { 482 | for (bits = count_trailing_zero_bits(u); bits > 0n; bits--) { 483 | rshift1(u); 484 | swap = (~lsb(A) & ~lsb(B)) & 1; 485 | A = select_alt(swap, A, add(A, y)); 486 | rshift1(A); 487 | B = select_alt(swap, B, sub(B, x)); 488 | rshift1(B); 489 | } 490 | for (bits = count_trailing_zero_bits(v); bits > 0n; bits--) { 491 | rshift1(v); 492 | swap = (~lsb(C) & ~lsb(D)) & 1; 493 | C = select_alt(swap, C, add(C, y)); 494 | rshift1(C); 495 | D = select_alt(swap, D, sub(D, x)); 496 | rshift1(D); 497 | } 498 | 499 | /* 500 | | compare(u, v) | swap | 501 | +---------------+------+ 502 | | -1 | 0 | 503 | | 0 | 1 | 504 | | 1 | 1 | 505 | */ 506 | 507 | // if (u >= v): 508 | swap = (1 - (compare_alt(u, v)[0] >>> 31)); 509 | u = select_alt(swap, sub(u, v), u); 510 | A = select_alt(swap, sub(A, C), A); 511 | B = select_alt(swap, sub(B, D), B); 512 | 513 | swap = 1 - swap; 514 | // else: 515 | v = select_alt(swap, sub(v, u), v); 516 | C = select_alt(swap, sub(C, A), C); 517 | D = select_alt(swap, sub(D, B), D); 518 | } while (is_nonzero(u)); 519 | return [C, shift_left(v, g)]; 520 | } 521 | 522 | /** 523 | * Big number division. 524 | * 525 | * @param {Uint8Array} num 526 | * @param {Uint8Array} denom 527 | * @returns {Uint8Array} 528 | */ 529 | function division(num: Uint8Array, denom: Uint8Array): Uint8Array[] { 530 | if (!is_nonzero(denom)) { 531 | throw new Error('Division by zero'); 532 | } 533 | const length: number = Math.max(num.length, denom.length); 534 | const zero: Uint8Array = new Uint8Array(length); 535 | let bits: number = (length << 3) - 1; 536 | let N: Uint8Array = normalize(num, length, true); 537 | let D: Uint8Array = normalize(denom, length, true); 538 | let Q: Uint8Array = zero.slice(); 539 | let R: Uint8Array = zero.slice(); 540 | let Qprime: Uint8Array; 541 | let Rprime: Uint8Array; 542 | let compared: Uint32Array; 543 | let swap: number; 544 | let byte: number; 545 | let b: number; 546 | let i: number; 547 | for (i = 0; i <= bits; i++) { 548 | byte = i >>> 3; 549 | b = ((bits - i) & 7); 550 | lshift1(R); 551 | 552 | // R(0) := N(i) 553 | R[R.length - 1] |= (N[byte] >>> b) & 1; 554 | 555 | /* 556 | -- if R > D then compared == 1, swap = 1 557 | -- if R == D then compared == 0, swap = 1 558 | -- if R < D then compared == -1, swap = 0 559 | */ 560 | compared = compare_alt(R, D); 561 | swap = (1 - (compared[0] >>> 31)); 562 | 563 | /* 564 | Rprime := R - D 565 | Qprime := Q 566 | Qprime(i) := 1 567 | */ 568 | Rprime = sub(R, D); 569 | Qprime = Q.slice(); 570 | Qprime[byte] |= (1 << b); 571 | 572 | R = select_alt(swap, Rprime, R); 573 | Q = select_alt(swap, Qprime, Q); 574 | } 575 | return [Q, R]; 576 | } 577 | -------------------------------------------------------------------------------- /lib/compare.ts: -------------------------------------------------------------------------------- 1 | import { int32 } from './int32'; 2 | 3 | /** 4 | * Compare {left} with {right}. 5 | * 6 | * @param {Uint8Array} left 7 | * @param {Uint8Array} right 8 | * @returns {number} -1 if left < right, 0 if left == right, 1 if left > right 9 | */ 10 | export function compare(left: Uint8Array, right: Uint8Array): number { 11 | if (left.length !== right.length) { 12 | throw new Error('Both arrays must be of equal length'); 13 | } 14 | let gt: number = 0; 15 | let eq: number = 1; 16 | let l: int32 = int32.zero(); 17 | let r: int32 = int32.zero(); 18 | for (let i: number = 0; i < left.length; i++) { 19 | r = int32.fromInt(right[i]); 20 | l = int32.fromInt(left[i]); 21 | const d: int32 = r.sub(l); 22 | gt |= d.xor(l.xor(r).and(l.xor(d))).msb() & eq; 23 | eq &= r.xor(l).isZero(); 24 | } 25 | l.wipe(); 26 | r.wipe(); 27 | return (gt + gt + eq) - 1; 28 | } 29 | 30 | /** 31 | * Compare {left} with {right}. Avoids the Number type. 32 | * 33 | * @param {Uint8Array} left 34 | * @param {Uint8Array} right 35 | * @returns {Uint32Array} -1 if left < right, 0 if left == right, 1 if left > right 36 | */ 37 | export function compare_alt(left: Uint8Array, right: Uint8Array): Uint32Array { 38 | const ret: Uint32Array = new Uint32Array(1); 39 | if (left.length !== right.length) { 40 | throw new Error('Both arrays must be of equal length'); 41 | } 42 | let gt: number = 0; 43 | let eq: number = 1; 44 | let l: int32; 45 | let r: int32; 46 | for (let i: number = 0; i < left.length; i++) { 47 | r = int32.fromInt(right[i]); 48 | l = int32.fromInt(left[i]); 49 | const d: int32 = r.sub(l); 50 | gt |= d.xor(l.xor(r).and(l.xor(d))).msb() & eq; 51 | eq &= r.xor(l).isZero(); 52 | } 53 | l.wipe(); 54 | r.wipe(); 55 | ret[0] = (gt + gt + eq); 56 | ret[0]--; 57 | return ret; 58 | } 59 | 60 | /** 61 | * Compare {left} with {right} 62 | * 63 | * @param {number} left 64 | * @param {number} right 65 | * @returns {number} -1 if left < right, 0 if left == right, 1 if left > right 66 | */ 67 | export function compare_ints(left: number, right: number): number { 68 | /* 69 | let gt: number = (right - left) >>> 31; 70 | let eq: number = ((right ^ left) - 1) >>> 31; 71 | */ 72 | const L: int32 = int32.fromInt(left); 73 | const R: int32 = int32.fromInt(right); 74 | /* 75 | This borrows a trick from Thomas Pornin's CTTK library: 76 | 77 | https://github.com/pornin/CTTK/blob/1d592024398f06c8eda1d325bdbd105ac32d92b3/inc/cttk.h#L552-L581 78 | 79 | > If both x >= 2^31 and y >= 2^31, then we can virtually 80 | > subtract 2^31 from both, and we are back to the first 81 | > case. Since (y-2^31)-(x-2^31) = y-x, the direct subtraction 82 | > is already fine. 83 | 84 | Except (L, R, diff) := (x, y, z), respectively 85 | */ 86 | const diff: int32 = R.sub(L); 87 | const gt: number = diff.xor(L.xor(R).and(L.xor(diff))).msb(); 88 | const eq: number = R.xor(L).isZero(); 89 | L.wipe(); 90 | R.wipe(); 91 | return (gt + gt + eq) - 1; 92 | } 93 | 94 | /** 95 | * Compare {left} with {right}. Avoids the Number type. 96 | * 97 | * @param {number} left 98 | * @param {number} right 99 | * @returns {Uint32Array} -1 if left < right, 0 if left == right, 1 if left > right 100 | */ 101 | export function compare_ints_alt(left: number, right: number): Uint32Array { 102 | const ret: Uint32Array = new Uint32Array(1); 103 | const R: int32 = int32.fromInt(right); 104 | const L: int32 = int32.fromInt(left); 105 | const diff: int32 = R.sub(L); 106 | const gt: number = diff.xor(L.xor(R).and(L.xor(diff))).msb(); 107 | const eq: number = R.xor(L).isZero(); 108 | L.wipe(); 109 | R.wipe(); 110 | ret[0] = (gt + gt + eq); 111 | ret[0]--; 112 | return ret; 113 | } 114 | -------------------------------------------------------------------------------- /lib/equals.ts: -------------------------------------------------------------------------------- 1 | import * as crypto from 'crypto'; 2 | 3 | /** 4 | * Constant-time buffer comparison 5 | * 6 | * @param {Uint8Array} left 7 | * @param {Uint8Array} right 8 | * @returns {boolean} 9 | */ 10 | export function equals(left: Uint8Array, right: Uint8Array): boolean { 11 | if (left.length !== right.length) { 12 | return false; 13 | } 14 | let d: number = 0; 15 | let i: number; 16 | for (i = 0; i < left.length; i++) { 17 | d |= left[i] ^ right[i]; 18 | } 19 | return d === 0; 20 | } 21 | 22 | /** 23 | * Constant-time equality even with an adversarial JIT compiler. 24 | * 25 | * @param {Uint8Array} left 26 | * @param {Uint8Array} right 27 | * @returns {boolean} 28 | */ 29 | export function hmac_equals(left: Uint8Array, right: Uint8Array): boolean { 30 | return equals( 31 | crypto.createHmac('sha256', hmacKey).update(left).digest(), 32 | crypto.createHmac('sha256', hmacKey).update(right).digest() 33 | ); 34 | } 35 | 36 | const hmacKey = crypto.randomBytes(32); 37 | -------------------------------------------------------------------------------- /lib/int32.ts: -------------------------------------------------------------------------------- 1 | export class int32 { 2 | private limbs: Uint16Array; 3 | 4 | constructor(low: number, high: number) { 5 | this.limbs = new Uint16Array([low, high]); 6 | } 7 | 8 | /** 9 | * Returns an int32 with value 0 10 | * 11 | * @returns {int32} 12 | */ 13 | static zero(): int32 { 14 | return new int32(0, 0); 15 | } 16 | 17 | /** 18 | * Returns an int32 with value 1 19 | * 20 | * @returns {int32} 21 | */ 22 | static one(): int32 { 23 | return new int32(1, 0); 24 | } 25 | 26 | /** 27 | * Returns an int32 with the value of {int} 28 | * 29 | * @returns {int32} 30 | */ 31 | static fromInt(int: number): int32 { 32 | return new int32(int & 0xffff, int >>> 16); 33 | } 34 | /** 35 | * Returns an int32 with the value of {int} 36 | * 37 | * @param {number} flag 38 | * @returns {int32} 39 | */ 40 | static fromFlag(flag: number): int32 { 41 | const tmp: Int32Array = new Int32Array(1); 42 | tmp[0] = flag; 43 | tmp[0] *= -1; 44 | return new int32(tmp[0] & 0xffff, tmp[0] >>> 16); 45 | } 46 | 47 | /** 48 | * @returns {number} 49 | */ 50 | low() { 51 | return this.limbs[0]; 52 | } 53 | 54 | /** 55 | * @returns {number} 56 | */ 57 | high() { 58 | return this.limbs[1]; 59 | } 60 | 61 | /** 62 | * @returns {number} 63 | */ 64 | lsb() { 65 | return this.limbs[0] & 1; 66 | } 67 | 68 | /** 69 | * @returns {number} 70 | */ 71 | msb() { 72 | return (this.limbs[1] >>> 15) & 1; 73 | } 74 | 75 | /** 76 | * Returns the sum of {this} and {arg}. 77 | * 78 | * @param {number|int32} arg 79 | * @returns {number} 80 | */ 81 | add(arg: number|int32): int32 { 82 | if (arg instanceof int32) { 83 | return int32_add_int32(this, arg); 84 | } 85 | return int32_add_number(this, arg); 86 | } 87 | 88 | /** 89 | * Returns the result of {this & arg}. 90 | * 91 | * @param {number|int32} arg 92 | * @returns {number} 93 | */ 94 | and(arg: number|int32): int32 { 95 | if (arg instanceof int32) { 96 | return int32_and_int32(this, arg); 97 | } 98 | return int32_and_number(this, arg); 99 | } 100 | 101 | /** 102 | * Returns -1 if {this < arg} 103 | * Returns 0 if {this == arg} 104 | * Returns 1 if {this > arg} 105 | * 106 | * @param {number|int32} arg 107 | * @returns {number} 108 | */ 109 | compare(arg: number|int32): int32 { 110 | if (typeof arg === 'number') { 111 | arg = int32.fromInt(arg); 112 | } 113 | return int32_compare(this, arg); 114 | } 115 | 116 | /** 117 | * Is this number zero? 118 | * 119 | * @returns {number} 1 if true, 0 if false 120 | */ 121 | isZero(): number { 122 | return int32_is_zero(this); 123 | } 124 | 125 | /** 126 | * Return {this} left-shifted by {amount}. 127 | * 128 | * @param {number} amount 129 | * @returns {number} 130 | */ 131 | lshift(amount: number): int32 { 132 | if (amount > 31) { 133 | return int32.zero(); 134 | } 135 | return int32_lshift(this, amount); 136 | } 137 | 138 | /** 139 | * Returns a bitwise NOT of {this} 140 | * 141 | * @returns {number} 142 | */ 143 | not(): int32 { 144 | return int32_not(this); 145 | } 146 | 147 | /** 148 | * Returns the result of {this | arg}. 149 | * 150 | * @param {number|int32} arg 151 | * @returns {number} 152 | */ 153 | or(arg: number|int32): int32 { 154 | if (arg instanceof int32) { 155 | return int32_or_int32(this, arg); 156 | } 157 | return int32_or_number(this, arg); 158 | } 159 | 160 | /** 161 | * Return {this} right-shifted by {amount}. 162 | * 163 | * @param {number} amount 164 | * @returns {int32} 165 | */ 166 | rshift(amount: number): int32 { 167 | if (amount > 31) { 168 | return int32.zero(); 169 | } 170 | return int32_rshift(this, amount); 171 | } 172 | 173 | /** 174 | * Returns {this - arg}. 175 | * 176 | * @param {number|int32} arg 177 | * @returns {number} 178 | */ 179 | sub(arg: number|int32): int32 { 180 | if (arg instanceof int32) { 181 | return int32_sub_int32(this, arg); 182 | } 183 | return int32_sub_number(this, arg); 184 | } 185 | 186 | /** 187 | * Returns {this ^ arg} 188 | * 189 | * @param {number|int32} arg 190 | * @returns {number} 191 | */ 192 | xor(arg: number|int32): int32 { 193 | if (arg instanceof int32) { 194 | return int32_xor_int32(this, arg); 195 | } 196 | return int32_xor_number(this, arg); 197 | } 198 | 199 | /** 200 | * Returns the hexadecimal representation of this integer. 201 | * 202 | * @returns {string} 203 | */ 204 | toHex(): string { 205 | const l: string = (this.low() & 0xffff) 206 | .toString(16) 207 | .padStart(4, '0'); 208 | const h: string = (this.high() & 0xffff) 209 | .toString(16) 210 | .padStart(4, '0'); 211 | return h.concat(l); 212 | } 213 | 214 | /** 215 | * Subtract 1, return a new int32 216 | * 217 | * @returns {int32} 218 | */ 219 | decrement(): int32 { 220 | const out: int32 = new int32(this.low(), this.high()); 221 | const carry: Uint32Array = new Uint32Array(1); 222 | carry[0] = out.limbs[0] - 1; 223 | out.limbs[0] = carry[0] & 0xffff; 224 | out.limbs[1] = out.limbs[1] + (carry[0] >>> 16); 225 | return out; 226 | } 227 | 228 | /** 229 | * Convert to a JavaScript Number. 230 | * 231 | * @returns {number} 232 | */ 233 | toNumber(): number { 234 | return (this.low() | (this.high() << 16)); 235 | } 236 | 237 | /** 238 | * MUTATES the obejct! 239 | * 240 | * Set both limbs to 0 in-place. 241 | */ 242 | wipe(): void { 243 | this.limbs[0] ^= this.limbs[0]; 244 | this.limbs[1] ^= this.limbs[1]; 245 | } 246 | } 247 | 248 | function int32_add_int32(a: int32, b: int32): int32 { 249 | let l: number = a.low() + b.low(); 250 | let h: number = a.high() + b.high() + (l >>> 16); 251 | return new int32(l & 0xffff, h & 0xffff); 252 | } 253 | 254 | function int32_add_number(a: int32, b: number): int32 { 255 | let l: number = a.low() + (b & 0xffff); 256 | let h: number = a.high() + (b >>> 16) + (l >>> 16); 257 | return new int32(l & 0xffff, h & 0xffff); 258 | } 259 | 260 | function int32_and_int32(a: int32, b: int32): int32 { 261 | let l: number = a.low() & b.low(); 262 | let h: number = a.high() & b.high(); 263 | return new int32(l & 0xffff, h & 0xffff); 264 | } 265 | 266 | function int32_and_number(a: int32, b: number): int32 { 267 | let l: number = a.low() & (b & 0xffff); 268 | let h: number = a.high() & (b >>> 16); 269 | return new int32(l & 0xffff, h & 0xffff); 270 | } 271 | 272 | function int32_compare(left, right): int32 { 273 | const diff: int32 = right.sub(left); 274 | /* 275 | This borrows a trick from Thomas Pornin's CTTK library: 276 | 277 | https://github.com/pornin/CTTK/blob/1d592024398f06c8eda1d325bdbd105ac32d92b3/inc/cttk.h#L552-L581 278 | 279 | > If both x >= 2^31 and y >= 2^31, then we can virtually 280 | > subtract 2^31 from both, and we are back to the first 281 | > case. Since (y-2^31)-(x-2^31) = y-x, the direct subtraction 282 | > is already fine. 283 | 284 | Except (left, right, diff) := (x, y, z), respectively 285 | */ 286 | let gt: number = diff.xor(left.xor(right).and(left.xor(diff))).msb(); 287 | let eq: number = right.xor(left).isZero(); 288 | return int32.fromInt((gt + gt + eq)).decrement(); 289 | } 290 | 291 | function int32_is_zero(a: int32): number { 292 | /* 293 | Bitiwse OR the bits of the limbs together 294 | then subtract 1 and grab the most significant bit. 295 | 296 | [0] - 1 >>> 31 297 | -> 1 298 | [1..0xffff] - 1 >>> 31 299 | -> 0 300 | */ 301 | const tmp = new Uint32Array(1); 302 | tmp[0] = (a.low() | a.high()); 303 | tmp[0]--; 304 | return tmp[0] >>> 31; 305 | } 306 | 307 | function int32_lshift(a: int32, x: number) { 308 | let l: number = (a.low() << x); 309 | let h: number = (l >>> 16) | (a.high() << x); 310 | return new int32(l & 0xffff, h & 0xffff); 311 | } 312 | 313 | function int32_not(a: int32): int32 { 314 | let l: number = a.low() ^ 0xffff; 315 | let h: number = a.high() ^ 0xffff; 316 | return new int32(l & 0xffff, h & 0xffff); 317 | } 318 | 319 | function int32_or_int32(a: int32, b: int32): int32 { 320 | let l: number = a.low() | b.low(); 321 | let h: number = a.high() | b.high(); 322 | return new int32(l & 0xffff, h & 0xffff); 323 | } 324 | 325 | function int32_or_number(a: int32, b: number): int32 { 326 | let l: number = a.low() | (b & 0xffff); 327 | let h: number = a.high() | (b >>> 16); 328 | return new int32(l & 0xffff, h & 0xffff); 329 | } 330 | 331 | function int32_rshift(a: int32, amount: number) { 332 | let m: number = (1 << (amount + 1)) - 1; 333 | let h: number = (a.high() >>> amount); 334 | let l: number = (a.low() >>> amount) | (((a.high() & m) << 16) >>> amount); 335 | return new int32(l & 0xffff, h & 0xffff); 336 | } 337 | 338 | function int32_sub_int32(a: int32, b: int32): int32 { 339 | let l: number = a.low() - b.low(); 340 | let h: number = a.high() - b.high() + (l >>> 16); 341 | return new int32(l & 0xffff, h & 0xffff); 342 | } 343 | function int32_sub_number(a: int32, b: number): int32 { 344 | let l: number = a.low() - (b & 0xffff); 345 | let h: number = a.high() - (b >>> 16) + (l >>> 16); 346 | return new int32(l & 0xffff, h & 0xffff); 347 | } 348 | 349 | function int32_xor_int32(a: int32, b: int32): int32 { 350 | let l: number = a.low() ^ b.low(); 351 | let h: number = a.high() ^ b.high(); 352 | return new int32(l & 0xffff, h & 0xffff); 353 | } 354 | 355 | function int32_xor_number(a: int32, b: number): int32 { 356 | let l: number = a.low() ^ (b & 0xffff); 357 | let h: number = a.high() ^ (b >>> 16); 358 | return new int32(l & 0xffff, h & 0xffff); 359 | } 360 | -------------------------------------------------------------------------------- /lib/intdiv.ts: -------------------------------------------------------------------------------- 1 | import { int32 } from './int32'; 2 | import { select_int32 } from './select'; 3 | 4 | /** 5 | * Returns {num / denom} rounded down. 6 | * 7 | * @param {number} numerator 8 | * @param {number} denominator 9 | * @returns {number} 10 | */ 11 | export function intdiv(numerator: number, denominator: number): number { 12 | return divide(numerator, denominator)[0]; 13 | } 14 | 15 | /** 16 | * Returns {num % denom}. 17 | * 18 | * @param {number} numerator 19 | * @param {number} denominator 20 | * @returns {number} 21 | */ 22 | export function modulo(numerator: number, denominator: number): number { 23 | return divide(numerator, denominator)[1]; 24 | } 25 | 26 | function divide(num: number, denom: number): number[] { 27 | if (denom === 0) { 28 | throw new Error('Division by zero'); 29 | } 30 | let bits: number = Math.ceil(Math.log2(num)) | 0; 31 | let N: int32 = int32.fromInt(num); 32 | let D: int32 = int32.fromInt(denom); 33 | let Q: int32 = int32.zero(); 34 | let R: int32 = int32.zero(); 35 | let Qprime: int32 = int32.zero(); 36 | let Rprime: int32 = int32.zero(); 37 | let i: number; 38 | let compared: int32 = int32.zero(); 39 | let swap: number; 40 | for (i = 0; i <= bits; i++) { 41 | // R := R << 1 42 | // R(0) := N(i) 43 | R = R.lshift(1).or( 44 | N.rshift(bits - i).lsb() 45 | ); 46 | 47 | /* 48 | -- if R > D then compared == 1, swap = 1 49 | -- if R == D then compared == 0, swap = 1 50 | -- if R < D then compared == -1, swap = 0 51 | */ 52 | compared = R.compare(D); 53 | swap = (1 - compared.msb()); 54 | 55 | /* 56 | Rprime := R - D 57 | Qprime := Q 58 | Qprime(i) := 1 59 | */ 60 | Rprime = R.sub(D); 61 | Qprime = Q.or(1 << (bits - i)); 62 | 63 | R = select_int32(swap, Rprime, R); 64 | Q = select_int32(swap, Qprime, Q); 65 | } 66 | // Wipe intermediary values 67 | const ret: number[] = [Q.toNumber(), R.toNumber()]; 68 | compared.wipe(); 69 | Qprime.wipe(); 70 | Rprime.wipe(); 71 | N.wipe(); 72 | D.wipe(); 73 | Q.wipe(); 74 | R.wipe(); 75 | return ret; 76 | } 77 | -------------------------------------------------------------------------------- /lib/resize.ts: -------------------------------------------------------------------------------- 1 | import { int32 } from './int32'; 2 | import { modulo } from './intdiv'; 3 | import { select_ints } from './select'; 4 | 5 | /** 6 | * Iterate over every byte of the input array, returning a new object 7 | * (so as to minimize memory access leakage outside). 8 | * 9 | * This is useful for building functions to trim trailing or leading zero 10 | * bytes without leakage. 11 | * 12 | * @param {Uint8Array} input 13 | * @param {number} desired 14 | */ 15 | export function resize(input: Uint8Array, desired: number): Uint8Array { 16 | if (desired === 0) { 17 | return new Uint8Array(0); 18 | } 19 | const output: Uint8Array = new Uint8Array(desired); 20 | let x: number; 21 | let y: number; 22 | let z: number; 23 | const desired32: int32 = int32.fromInt(desired); 24 | for (x = 0; x < input.length; x++) { 25 | /* 26 | if (x <= desired) y = 0; 27 | else y = 1; 28 | */ 29 | y = int32.fromInt(x).sub(desired32).msb(); 30 | z = modulo(x, desired); 31 | output[z] = select_ints(y|0, input[x], output[z]); 32 | } 33 | desired32.wipe(); 34 | 35 | return output; 36 | } 37 | -------------------------------------------------------------------------------- /lib/select.ts: -------------------------------------------------------------------------------- 1 | import { int32 } from './int32'; 2 | 3 | /** 4 | * If TRUE, return left; else, return right. 5 | * 6 | * @param {boolean} returnLeft 7 | * @param {Uint8Array} left 8 | * @param {Uint8Array} right 9 | * @returns {Uint8Array} 10 | */ 11 | export function select(returnLeft: boolean, left: Uint8Array, right: Uint8Array): Uint8Array { 12 | if (left.length !== right.length) { 13 | throw new Error('select() expects two Uint8Array objects of equal length'); 14 | } 15 | /* 16 | If returnLeft, mask = 0xFF; else, mask = 0x00; 17 | */ 18 | const mask: number = (-!!returnLeft) & 0xff; 19 | const out: Uint8Array = new Uint8Array(left.length); 20 | for (let i: number = 0; i < left.length; i++) { 21 | out[i] = right[i] ^ ((left[i] ^ right[i]) & mask); 22 | } 23 | return out; 24 | } 25 | 26 | /** 27 | * Returns (choice ? m : n) without branches indexed by secret data. 28 | * 29 | * @param {number} choice (0 or 1) 30 | * @param {Uint8Array} m 31 | * @param {Uint8Array} n 32 | * @returns {Uint8Array} 33 | */ 34 | export function select_alt(choice: number, m: Uint8Array, n: Uint8Array): Uint8Array { 35 | if (m.length !== n.length) { 36 | throw new Error('Both Uint8Arrays must be the same length'); 37 | } 38 | const mask = (-choice) & 0xff; 39 | const out = new Uint8Array(m.length); 40 | for (let i: number = 0; i < out.length; i++) { 41 | out[i] = n[i] ^ ((m[i] ^ n[i]) & mask); 42 | } 43 | return out; 44 | } 45 | 46 | /** 47 | * If TRUE, return left; else, return right. 48 | * 49 | * @param {number} returnLeft 50 | * @param {number} left 51 | * @param {number} right 52 | * @returns {number} 53 | */ 54 | export function select_ints(returnLeft: number, left: number, right: number): number { 55 | /* 56 | If returnLeft, mask = 0xFFFFFFFF; else, mask = 0x00000000; 57 | */ 58 | const mask: number = (-(returnLeft & 1)) & 0xfffffffff; 59 | return right ^ ((left ^ right) & mask); 60 | } 61 | 62 | /** 63 | * If TRUE, return left; else, return right. 64 | * 65 | * @param {number} returnLeft 66 | * @param {number} left 67 | * @param {number} right 68 | * @returns {number} 69 | */ 70 | export function select_int32(returnLeft: number, left: int32, right: int32): int32 { 71 | return right.xor(left.xor(right).and( 72 | int32.fromFlag(returnLeft & 1) 73 | )); 74 | } 75 | -------------------------------------------------------------------------------- /lib/trim.ts: -------------------------------------------------------------------------------- 1 | import { int32 } from './int32'; 2 | import { resize } from './resize'; 3 | 4 | /** 5 | * @param {Uint8Array} buf 6 | * @returns {Uint8Array} 7 | */ 8 | export function trim_zeroes_right(buf: Uint8Array): Uint8Array { 9 | let foundNonZero: int32 = int32.zero(); 10 | let i: number; 11 | let index: number = -1; 12 | let isNonZero: int32 = int32.zero(); 13 | const m: int32 = int32.fromInt(0xff); 14 | for (i = buf.length - 1; i >= 0; i--) { 15 | /* if foundNonZero === 0 && buf[i] !== 0, index := i */ 16 | isNonZero = int32.fromInt(buf[i]).sub(1).rshift(8).and(m); 17 | index = (foundNonZero.not().and(i)) 18 | .xor(foundNonZero.and(index)) 19 | .toNumber(); 20 | foundNonZero = foundNonZero.or(isNonZero.not()).and(m); 21 | } 22 | foundNonZero.wipe(); 23 | isNonZero.wipe(); 24 | return resize(buf, index + 1); 25 | } 26 | 27 | /** 28 | * @param {Uint8Array} buf 29 | * @returns {Uint8Array} 30 | */ 31 | export function trim_zeroes_left(buf: Uint8Array): Uint8Array { 32 | const ret = buf.slice(); 33 | ret.reverse(); 34 | return trim_zeroes_right(ret).reverse(); 35 | } 36 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "constant-time-js", 3 | "version": "0.4.0", 4 | "lockfileVersion": 2, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "constant-time-js", 9 | "version": "0.4.0", 10 | "license": "ISC", 11 | "dependencies": { 12 | "@types/node": "^18.8.0", 13 | "tslib": "^2.4.0" 14 | }, 15 | "devDependencies": { 16 | "@types/chai": "^4.3.3", 17 | "@types/mocha": "^8.2.3", 18 | "chai": "^4.3.6", 19 | "chai-as-promised": "^7.1.1", 20 | "mocha": "^10.0.0", 21 | "ts-node": "^10.9.1", 22 | "typescript": "^4.8.4" 23 | } 24 | }, 25 | "node_modules/@cspotcode/source-map-support": { 26 | "version": "0.8.1", 27 | "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", 28 | "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", 29 | "dev": true, 30 | "dependencies": { 31 | "@jridgewell/trace-mapping": "0.3.9" 32 | }, 33 | "engines": { 34 | "node": ">=12" 35 | } 36 | }, 37 | "node_modules/@jridgewell/resolve-uri": { 38 | "version": "3.1.0", 39 | "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", 40 | "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", 41 | "dev": true, 42 | "engines": { 43 | "node": ">=6.0.0" 44 | } 45 | }, 46 | "node_modules/@jridgewell/sourcemap-codec": { 47 | "version": "1.4.14", 48 | "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", 49 | "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", 50 | "dev": true 51 | }, 52 | "node_modules/@jridgewell/trace-mapping": { 53 | "version": "0.3.9", 54 | "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", 55 | "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", 56 | "dev": true, 57 | "dependencies": { 58 | "@jridgewell/resolve-uri": "^3.0.3", 59 | "@jridgewell/sourcemap-codec": "^1.4.10" 60 | } 61 | }, 62 | "node_modules/@tsconfig/node10": { 63 | "version": "1.0.9", 64 | "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", 65 | "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==", 66 | "dev": true 67 | }, 68 | "node_modules/@tsconfig/node12": { 69 | "version": "1.0.11", 70 | "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", 71 | "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", 72 | "dev": true 73 | }, 74 | "node_modules/@tsconfig/node14": { 75 | "version": "1.0.3", 76 | "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", 77 | "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", 78 | "dev": true 79 | }, 80 | "node_modules/@tsconfig/node16": { 81 | "version": "1.0.3", 82 | "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.3.tgz", 83 | "integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==", 84 | "dev": true 85 | }, 86 | "node_modules/@types/chai": { 87 | "version": "4.3.3", 88 | "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.3.tgz", 89 | "integrity": "sha512-hC7OMnszpxhZPduX+m+nrx+uFoLkWOMiR4oa/AZF3MuSETYTZmFfJAHqZEM8MVlvfG7BEUcgvtwoCTxBp6hm3g==", 90 | "dev": true 91 | }, 92 | "node_modules/@types/mocha": { 93 | "version": "8.2.3", 94 | "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-8.2.3.tgz", 95 | "integrity": "sha512-ekGvFhFgrc2zYQoX4JeZPmVzZxw6Dtllga7iGHzfbYIYkAMUx/sAFP2GdFpLff+vdHXu5fl7WX9AT+TtqYcsyw==", 96 | "dev": true 97 | }, 98 | "node_modules/@types/node": { 99 | "version": "18.8.0", 100 | "resolved": "https://registry.npmjs.org/@types/node/-/node-18.8.0.tgz", 101 | "integrity": "sha512-u+h43R6U8xXDt2vzUaVP3VwjjLyOJk6uEciZS8OSyziUQGOwmk+l+4drxcsDboHXwyTaqS1INebghmWMRxq3LA==" 102 | }, 103 | "node_modules/@ungap/promise-all-settled": { 104 | "version": "1.1.2", 105 | "resolved": "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz", 106 | "integrity": "sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==", 107 | "dev": true 108 | }, 109 | "node_modules/acorn": { 110 | "version": "8.8.0", 111 | "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.0.tgz", 112 | "integrity": "sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==", 113 | "dev": true, 114 | "bin": { 115 | "acorn": "bin/acorn" 116 | }, 117 | "engines": { 118 | "node": ">=0.4.0" 119 | } 120 | }, 121 | "node_modules/acorn-walk": { 122 | "version": "8.2.0", 123 | "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", 124 | "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", 125 | "dev": true, 126 | "engines": { 127 | "node": ">=0.4.0" 128 | } 129 | }, 130 | "node_modules/ansi-colors": { 131 | "version": "4.1.1", 132 | "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", 133 | "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", 134 | "dev": true, 135 | "engines": { 136 | "node": ">=6" 137 | } 138 | }, 139 | "node_modules/ansi-styles": { 140 | "version": "4.3.0", 141 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", 142 | "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", 143 | "dev": true, 144 | "dependencies": { 145 | "color-convert": "^2.0.1" 146 | }, 147 | "engines": { 148 | "node": ">=8" 149 | }, 150 | "funding": { 151 | "url": "https://github.com/chalk/ansi-styles?sponsor=1" 152 | } 153 | }, 154 | "node_modules/anymatch": { 155 | "version": "3.1.2", 156 | "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", 157 | "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", 158 | "dev": true, 159 | "dependencies": { 160 | "normalize-path": "^3.0.0", 161 | "picomatch": "^2.0.4" 162 | }, 163 | "engines": { 164 | "node": ">= 8" 165 | } 166 | }, 167 | "node_modules/arg": { 168 | "version": "4.1.3", 169 | "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", 170 | "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", 171 | "dev": true 172 | }, 173 | "node_modules/argparse": { 174 | "version": "2.0.1", 175 | "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", 176 | "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", 177 | "dev": true 178 | }, 179 | "node_modules/assertion-error": { 180 | "version": "1.1.0", 181 | "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", 182 | "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", 183 | "dev": true, 184 | "engines": { 185 | "node": "*" 186 | } 187 | }, 188 | "node_modules/balanced-match": { 189 | "version": "1.0.2", 190 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", 191 | "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", 192 | "dev": true 193 | }, 194 | "node_modules/binary-extensions": { 195 | "version": "2.2.0", 196 | "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", 197 | "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", 198 | "dev": true, 199 | "engines": { 200 | "node": ">=8" 201 | } 202 | }, 203 | "node_modules/brace-expansion": { 204 | "version": "2.0.1", 205 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", 206 | "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", 207 | "dev": true, 208 | "dependencies": { 209 | "balanced-match": "^1.0.0" 210 | } 211 | }, 212 | "node_modules/braces": { 213 | "version": "3.0.2", 214 | "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", 215 | "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", 216 | "dev": true, 217 | "dependencies": { 218 | "fill-range": "^7.0.1" 219 | }, 220 | "engines": { 221 | "node": ">=8" 222 | } 223 | }, 224 | "node_modules/browser-stdout": { 225 | "version": "1.3.1", 226 | "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", 227 | "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", 228 | "dev": true 229 | }, 230 | "node_modules/camelcase": { 231 | "version": "6.2.0", 232 | "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.2.0.tgz", 233 | "integrity": "sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg==", 234 | "dev": true, 235 | "engines": { 236 | "node": ">=10" 237 | }, 238 | "funding": { 239 | "url": "https://github.com/sponsors/sindresorhus" 240 | } 241 | }, 242 | "node_modules/chai": { 243 | "version": "4.3.6", 244 | "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.6.tgz", 245 | "integrity": "sha512-bbcp3YfHCUzMOvKqsztczerVgBKSsEijCySNlHHbX3VG1nskvqjz5Rfso1gGwD6w6oOV3eI60pKuMOV5MV7p3Q==", 246 | "dev": true, 247 | "dependencies": { 248 | "assertion-error": "^1.1.0", 249 | "check-error": "^1.0.2", 250 | "deep-eql": "^3.0.1", 251 | "get-func-name": "^2.0.0", 252 | "loupe": "^2.3.1", 253 | "pathval": "^1.1.1", 254 | "type-detect": "^4.0.5" 255 | }, 256 | "engines": { 257 | "node": ">=4" 258 | } 259 | }, 260 | "node_modules/chai-as-promised": { 261 | "version": "7.1.1", 262 | "resolved": "https://registry.npmjs.org/chai-as-promised/-/chai-as-promised-7.1.1.tgz", 263 | "integrity": "sha512-azL6xMoi+uxu6z4rhWQ1jbdUhOMhis2PvscD/xjLqNMkv3BPPp2JyyuTHOrf9BOosGpNQ11v6BKv/g57RXbiaA==", 264 | "dev": true, 265 | "dependencies": { 266 | "check-error": "^1.0.2" 267 | }, 268 | "peerDependencies": { 269 | "chai": ">= 2.1.2 < 5" 270 | } 271 | }, 272 | "node_modules/chalk": { 273 | "version": "4.1.2", 274 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", 275 | "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", 276 | "dev": true, 277 | "dependencies": { 278 | "ansi-styles": "^4.1.0", 279 | "supports-color": "^7.1.0" 280 | }, 281 | "engines": { 282 | "node": ">=10" 283 | }, 284 | "funding": { 285 | "url": "https://github.com/chalk/chalk?sponsor=1" 286 | } 287 | }, 288 | "node_modules/chalk/node_modules/supports-color": { 289 | "version": "7.2.0", 290 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", 291 | "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", 292 | "dev": true, 293 | "dependencies": { 294 | "has-flag": "^4.0.0" 295 | }, 296 | "engines": { 297 | "node": ">=8" 298 | } 299 | }, 300 | "node_modules/check-error": { 301 | "version": "1.0.2", 302 | "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", 303 | "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=", 304 | "dev": true, 305 | "engines": { 306 | "node": "*" 307 | } 308 | }, 309 | "node_modules/chokidar": { 310 | "version": "3.5.3", 311 | "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", 312 | "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", 313 | "dev": true, 314 | "funding": [ 315 | { 316 | "type": "individual", 317 | "url": "https://paulmillr.com/funding/" 318 | } 319 | ], 320 | "dependencies": { 321 | "anymatch": "~3.1.2", 322 | "braces": "~3.0.2", 323 | "glob-parent": "~5.1.2", 324 | "is-binary-path": "~2.1.0", 325 | "is-glob": "~4.0.1", 326 | "normalize-path": "~3.0.0", 327 | "readdirp": "~3.6.0" 328 | }, 329 | "engines": { 330 | "node": ">= 8.10.0" 331 | }, 332 | "optionalDependencies": { 333 | "fsevents": "~2.3.2" 334 | } 335 | }, 336 | "node_modules/cliui": { 337 | "version": "7.0.4", 338 | "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", 339 | "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", 340 | "dev": true, 341 | "dependencies": { 342 | "string-width": "^4.2.0", 343 | "strip-ansi": "^6.0.0", 344 | "wrap-ansi": "^7.0.0" 345 | } 346 | }, 347 | "node_modules/cliui/node_modules/ansi-regex": { 348 | "version": "5.0.1", 349 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", 350 | "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", 351 | "dev": true, 352 | "engines": { 353 | "node": ">=8" 354 | } 355 | }, 356 | "node_modules/cliui/node_modules/is-fullwidth-code-point": { 357 | "version": "3.0.0", 358 | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", 359 | "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", 360 | "dev": true, 361 | "engines": { 362 | "node": ">=8" 363 | } 364 | }, 365 | "node_modules/cliui/node_modules/string-width": { 366 | "version": "4.2.0", 367 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", 368 | "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", 369 | "dev": true, 370 | "dependencies": { 371 | "emoji-regex": "^8.0.0", 372 | "is-fullwidth-code-point": "^3.0.0", 373 | "strip-ansi": "^6.0.0" 374 | }, 375 | "engines": { 376 | "node": ">=8" 377 | } 378 | }, 379 | "node_modules/cliui/node_modules/strip-ansi": { 380 | "version": "6.0.0", 381 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", 382 | "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", 383 | "dev": true, 384 | "dependencies": { 385 | "ansi-regex": "^5.0.0" 386 | }, 387 | "engines": { 388 | "node": ">=8" 389 | } 390 | }, 391 | "node_modules/color-convert": { 392 | "version": "2.0.1", 393 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", 394 | "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", 395 | "dev": true, 396 | "dependencies": { 397 | "color-name": "~1.1.4" 398 | }, 399 | "engines": { 400 | "node": ">=7.0.0" 401 | } 402 | }, 403 | "node_modules/color-name": { 404 | "version": "1.1.4", 405 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", 406 | "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", 407 | "dev": true 408 | }, 409 | "node_modules/concat-map": { 410 | "version": "0.0.1", 411 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", 412 | "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", 413 | "dev": true 414 | }, 415 | "node_modules/create-require": { 416 | "version": "1.1.1", 417 | "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", 418 | "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", 419 | "dev": true 420 | }, 421 | "node_modules/debug": { 422 | "version": "4.3.4", 423 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", 424 | "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", 425 | "dev": true, 426 | "dependencies": { 427 | "ms": "2.1.2" 428 | }, 429 | "engines": { 430 | "node": ">=6.0" 431 | }, 432 | "peerDependenciesMeta": { 433 | "supports-color": { 434 | "optional": true 435 | } 436 | } 437 | }, 438 | "node_modules/debug/node_modules/ms": { 439 | "version": "2.1.2", 440 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", 441 | "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", 442 | "dev": true 443 | }, 444 | "node_modules/decamelize": { 445 | "version": "4.0.0", 446 | "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", 447 | "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", 448 | "dev": true, 449 | "engines": { 450 | "node": ">=10" 451 | }, 452 | "funding": { 453 | "url": "https://github.com/sponsors/sindresorhus" 454 | } 455 | }, 456 | "node_modules/deep-eql": { 457 | "version": "3.0.1", 458 | "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz", 459 | "integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==", 460 | "dev": true, 461 | "dependencies": { 462 | "type-detect": "^4.0.0" 463 | }, 464 | "engines": { 465 | "node": ">=0.12" 466 | } 467 | }, 468 | "node_modules/diff": { 469 | "version": "5.0.0", 470 | "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", 471 | "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", 472 | "dev": true, 473 | "engines": { 474 | "node": ">=0.3.1" 475 | } 476 | }, 477 | "node_modules/emoji-regex": { 478 | "version": "8.0.0", 479 | "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", 480 | "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", 481 | "dev": true 482 | }, 483 | "node_modules/escalade": { 484 | "version": "3.1.1", 485 | "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", 486 | "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", 487 | "dev": true, 488 | "engines": { 489 | "node": ">=6" 490 | } 491 | }, 492 | "node_modules/escape-string-regexp": { 493 | "version": "4.0.0", 494 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", 495 | "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", 496 | "dev": true, 497 | "engines": { 498 | "node": ">=10" 499 | }, 500 | "funding": { 501 | "url": "https://github.com/sponsors/sindresorhus" 502 | } 503 | }, 504 | "node_modules/fill-range": { 505 | "version": "7.0.1", 506 | "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", 507 | "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", 508 | "dev": true, 509 | "dependencies": { 510 | "to-regex-range": "^5.0.1" 511 | }, 512 | "engines": { 513 | "node": ">=8" 514 | } 515 | }, 516 | "node_modules/find-up": { 517 | "version": "5.0.0", 518 | "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", 519 | "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", 520 | "dev": true, 521 | "dependencies": { 522 | "locate-path": "^6.0.0", 523 | "path-exists": "^4.0.0" 524 | }, 525 | "engines": { 526 | "node": ">=10" 527 | }, 528 | "funding": { 529 | "url": "https://github.com/sponsors/sindresorhus" 530 | } 531 | }, 532 | "node_modules/flat": { 533 | "version": "5.0.2", 534 | "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", 535 | "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", 536 | "dev": true, 537 | "bin": { 538 | "flat": "cli.js" 539 | } 540 | }, 541 | "node_modules/fs.realpath": { 542 | "version": "1.0.0", 543 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", 544 | "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", 545 | "dev": true 546 | }, 547 | "node_modules/fsevents": { 548 | "version": "2.3.2", 549 | "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", 550 | "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", 551 | "dev": true, 552 | "hasInstallScript": true, 553 | "optional": true, 554 | "os": [ 555 | "darwin" 556 | ], 557 | "engines": { 558 | "node": "^8.16.0 || ^10.6.0 || >=11.0.0" 559 | } 560 | }, 561 | "node_modules/get-caller-file": { 562 | "version": "2.0.5", 563 | "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", 564 | "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", 565 | "dev": true, 566 | "engines": { 567 | "node": "6.* || 8.* || >= 10.*" 568 | } 569 | }, 570 | "node_modules/get-func-name": { 571 | "version": "2.0.0", 572 | "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", 573 | "integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=", 574 | "dev": true, 575 | "engines": { 576 | "node": "*" 577 | } 578 | }, 579 | "node_modules/glob": { 580 | "version": "7.2.0", 581 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", 582 | "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", 583 | "dev": true, 584 | "dependencies": { 585 | "fs.realpath": "^1.0.0", 586 | "inflight": "^1.0.4", 587 | "inherits": "2", 588 | "minimatch": "^3.0.4", 589 | "once": "^1.3.0", 590 | "path-is-absolute": "^1.0.0" 591 | }, 592 | "engines": { 593 | "node": "*" 594 | }, 595 | "funding": { 596 | "url": "https://github.com/sponsors/isaacs" 597 | } 598 | }, 599 | "node_modules/glob-parent": { 600 | "version": "5.1.2", 601 | "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", 602 | "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", 603 | "dev": true, 604 | "dependencies": { 605 | "is-glob": "^4.0.1" 606 | }, 607 | "engines": { 608 | "node": ">= 6" 609 | } 610 | }, 611 | "node_modules/glob/node_modules/brace-expansion": { 612 | "version": "1.1.11", 613 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", 614 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", 615 | "dev": true, 616 | "dependencies": { 617 | "balanced-match": "^1.0.0", 618 | "concat-map": "0.0.1" 619 | } 620 | }, 621 | "node_modules/glob/node_modules/minimatch": { 622 | "version": "3.1.2", 623 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", 624 | "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", 625 | "dev": true, 626 | "dependencies": { 627 | "brace-expansion": "^1.1.7" 628 | }, 629 | "engines": { 630 | "node": "*" 631 | } 632 | }, 633 | "node_modules/has-flag": { 634 | "version": "4.0.0", 635 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", 636 | "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", 637 | "dev": true, 638 | "engines": { 639 | "node": ">=8" 640 | } 641 | }, 642 | "node_modules/he": { 643 | "version": "1.2.0", 644 | "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", 645 | "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", 646 | "dev": true, 647 | "bin": { 648 | "he": "bin/he" 649 | } 650 | }, 651 | "node_modules/inflight": { 652 | "version": "1.0.6", 653 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", 654 | "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", 655 | "dev": true, 656 | "dependencies": { 657 | "once": "^1.3.0", 658 | "wrappy": "1" 659 | } 660 | }, 661 | "node_modules/inherits": { 662 | "version": "2.0.4", 663 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", 664 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", 665 | "dev": true 666 | }, 667 | "node_modules/is-binary-path": { 668 | "version": "2.1.0", 669 | "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", 670 | "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", 671 | "dev": true, 672 | "dependencies": { 673 | "binary-extensions": "^2.0.0" 674 | }, 675 | "engines": { 676 | "node": ">=8" 677 | } 678 | }, 679 | "node_modules/is-extglob": { 680 | "version": "2.1.1", 681 | "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", 682 | "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", 683 | "dev": true, 684 | "engines": { 685 | "node": ">=0.10.0" 686 | } 687 | }, 688 | "node_modules/is-glob": { 689 | "version": "4.0.3", 690 | "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", 691 | "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", 692 | "dev": true, 693 | "dependencies": { 694 | "is-extglob": "^2.1.1" 695 | }, 696 | "engines": { 697 | "node": ">=0.10.0" 698 | } 699 | }, 700 | "node_modules/is-number": { 701 | "version": "7.0.0", 702 | "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", 703 | "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", 704 | "dev": true, 705 | "engines": { 706 | "node": ">=0.12.0" 707 | } 708 | }, 709 | "node_modules/is-plain-obj": { 710 | "version": "2.1.0", 711 | "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", 712 | "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", 713 | "dev": true, 714 | "engines": { 715 | "node": ">=8" 716 | } 717 | }, 718 | "node_modules/is-unicode-supported": { 719 | "version": "0.1.0", 720 | "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", 721 | "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", 722 | "dev": true, 723 | "engines": { 724 | "node": ">=10" 725 | }, 726 | "funding": { 727 | "url": "https://github.com/sponsors/sindresorhus" 728 | } 729 | }, 730 | "node_modules/js-yaml": { 731 | "version": "4.1.0", 732 | "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", 733 | "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", 734 | "dev": true, 735 | "dependencies": { 736 | "argparse": "^2.0.1" 737 | }, 738 | "bin": { 739 | "js-yaml": "bin/js-yaml.js" 740 | } 741 | }, 742 | "node_modules/locate-path": { 743 | "version": "6.0.0", 744 | "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", 745 | "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", 746 | "dev": true, 747 | "dependencies": { 748 | "p-locate": "^5.0.0" 749 | }, 750 | "engines": { 751 | "node": ">=10" 752 | }, 753 | "funding": { 754 | "url": "https://github.com/sponsors/sindresorhus" 755 | } 756 | }, 757 | "node_modules/log-symbols": { 758 | "version": "4.1.0", 759 | "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", 760 | "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", 761 | "dev": true, 762 | "dependencies": { 763 | "chalk": "^4.1.0", 764 | "is-unicode-supported": "^0.1.0" 765 | }, 766 | "engines": { 767 | "node": ">=10" 768 | }, 769 | "funding": { 770 | "url": "https://github.com/sponsors/sindresorhus" 771 | } 772 | }, 773 | "node_modules/loupe": { 774 | "version": "2.3.4", 775 | "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.4.tgz", 776 | "integrity": "sha512-OvKfgCC2Ndby6aSTREl5aCCPTNIzlDfQZvZxNUrBrihDhL3xcrYegTblhmEiCrg2kKQz4XsFIaemE5BF4ybSaQ==", 777 | "dev": true, 778 | "dependencies": { 779 | "get-func-name": "^2.0.0" 780 | } 781 | }, 782 | "node_modules/make-error": { 783 | "version": "1.3.6", 784 | "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", 785 | "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", 786 | "dev": true 787 | }, 788 | "node_modules/minimatch": { 789 | "version": "5.0.1", 790 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz", 791 | "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==", 792 | "dev": true, 793 | "dependencies": { 794 | "brace-expansion": "^2.0.1" 795 | }, 796 | "engines": { 797 | "node": ">=10" 798 | } 799 | }, 800 | "node_modules/mocha": { 801 | "version": "10.0.0", 802 | "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.0.0.tgz", 803 | "integrity": "sha512-0Wl+elVUD43Y0BqPZBzZt8Tnkw9CMUdNYnUsTfOM1vuhJVZL+kiesFYsqwBkEEuEixaiPe5ZQdqDgX2jddhmoA==", 804 | "dev": true, 805 | "dependencies": { 806 | "@ungap/promise-all-settled": "1.1.2", 807 | "ansi-colors": "4.1.1", 808 | "browser-stdout": "1.3.1", 809 | "chokidar": "3.5.3", 810 | "debug": "4.3.4", 811 | "diff": "5.0.0", 812 | "escape-string-regexp": "4.0.0", 813 | "find-up": "5.0.0", 814 | "glob": "7.2.0", 815 | "he": "1.2.0", 816 | "js-yaml": "4.1.0", 817 | "log-symbols": "4.1.0", 818 | "minimatch": "5.0.1", 819 | "ms": "2.1.3", 820 | "nanoid": "3.3.3", 821 | "serialize-javascript": "6.0.0", 822 | "strip-json-comments": "3.1.1", 823 | "supports-color": "8.1.1", 824 | "workerpool": "6.2.1", 825 | "yargs": "16.2.0", 826 | "yargs-parser": "20.2.4", 827 | "yargs-unparser": "2.0.0" 828 | }, 829 | "bin": { 830 | "_mocha": "bin/_mocha", 831 | "mocha": "bin/mocha.js" 832 | }, 833 | "engines": { 834 | "node": ">= 14.0.0" 835 | }, 836 | "funding": { 837 | "type": "opencollective", 838 | "url": "https://opencollective.com/mochajs" 839 | } 840 | }, 841 | "node_modules/ms": { 842 | "version": "2.1.3", 843 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", 844 | "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", 845 | "dev": true 846 | }, 847 | "node_modules/nanoid": { 848 | "version": "3.3.3", 849 | "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz", 850 | "integrity": "sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==", 851 | "dev": true, 852 | "bin": { 853 | "nanoid": "bin/nanoid.cjs" 854 | }, 855 | "engines": { 856 | "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" 857 | } 858 | }, 859 | "node_modules/normalize-path": { 860 | "version": "3.0.0", 861 | "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", 862 | "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", 863 | "dev": true, 864 | "engines": { 865 | "node": ">=0.10.0" 866 | } 867 | }, 868 | "node_modules/once": { 869 | "version": "1.4.0", 870 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 871 | "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", 872 | "dev": true, 873 | "dependencies": { 874 | "wrappy": "1" 875 | } 876 | }, 877 | "node_modules/p-limit": { 878 | "version": "3.1.0", 879 | "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", 880 | "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", 881 | "dev": true, 882 | "dependencies": { 883 | "yocto-queue": "^0.1.0" 884 | }, 885 | "engines": { 886 | "node": ">=10" 887 | }, 888 | "funding": { 889 | "url": "https://github.com/sponsors/sindresorhus" 890 | } 891 | }, 892 | "node_modules/p-locate": { 893 | "version": "5.0.0", 894 | "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", 895 | "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", 896 | "dev": true, 897 | "dependencies": { 898 | "p-limit": "^3.0.2" 899 | }, 900 | "engines": { 901 | "node": ">=10" 902 | }, 903 | "funding": { 904 | "url": "https://github.com/sponsors/sindresorhus" 905 | } 906 | }, 907 | "node_modules/path-exists": { 908 | "version": "4.0.0", 909 | "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", 910 | "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", 911 | "dev": true, 912 | "engines": { 913 | "node": ">=8" 914 | } 915 | }, 916 | "node_modules/path-is-absolute": { 917 | "version": "1.0.1", 918 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", 919 | "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", 920 | "dev": true, 921 | "engines": { 922 | "node": ">=0.10.0" 923 | } 924 | }, 925 | "node_modules/pathval": { 926 | "version": "1.1.1", 927 | "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", 928 | "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", 929 | "dev": true, 930 | "engines": { 931 | "node": "*" 932 | } 933 | }, 934 | "node_modules/picomatch": { 935 | "version": "2.3.1", 936 | "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", 937 | "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", 938 | "dev": true, 939 | "engines": { 940 | "node": ">=8.6" 941 | }, 942 | "funding": { 943 | "url": "https://github.com/sponsors/jonschlinkert" 944 | } 945 | }, 946 | "node_modules/randombytes": { 947 | "version": "2.1.0", 948 | "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", 949 | "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", 950 | "dev": true, 951 | "dependencies": { 952 | "safe-buffer": "^5.1.0" 953 | } 954 | }, 955 | "node_modules/readdirp": { 956 | "version": "3.6.0", 957 | "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", 958 | "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", 959 | "dev": true, 960 | "dependencies": { 961 | "picomatch": "^2.2.1" 962 | }, 963 | "engines": { 964 | "node": ">=8.10.0" 965 | } 966 | }, 967 | "node_modules/require-directory": { 968 | "version": "2.1.1", 969 | "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", 970 | "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", 971 | "dev": true, 972 | "engines": { 973 | "node": ">=0.10.0" 974 | } 975 | }, 976 | "node_modules/safe-buffer": { 977 | "version": "5.2.1", 978 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", 979 | "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", 980 | "dev": true, 981 | "funding": [ 982 | { 983 | "type": "github", 984 | "url": "https://github.com/sponsors/feross" 985 | }, 986 | { 987 | "type": "patreon", 988 | "url": "https://www.patreon.com/feross" 989 | }, 990 | { 991 | "type": "consulting", 992 | "url": "https://feross.org/support" 993 | } 994 | ] 995 | }, 996 | "node_modules/serialize-javascript": { 997 | "version": "6.0.0", 998 | "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", 999 | "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", 1000 | "dev": true, 1001 | "dependencies": { 1002 | "randombytes": "^2.1.0" 1003 | } 1004 | }, 1005 | "node_modules/strip-json-comments": { 1006 | "version": "3.1.1", 1007 | "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", 1008 | "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", 1009 | "dev": true, 1010 | "engines": { 1011 | "node": ">=8" 1012 | }, 1013 | "funding": { 1014 | "url": "https://github.com/sponsors/sindresorhus" 1015 | } 1016 | }, 1017 | "node_modules/supports-color": { 1018 | "version": "8.1.1", 1019 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", 1020 | "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", 1021 | "dev": true, 1022 | "dependencies": { 1023 | "has-flag": "^4.0.0" 1024 | }, 1025 | "engines": { 1026 | "node": ">=10" 1027 | }, 1028 | "funding": { 1029 | "url": "https://github.com/chalk/supports-color?sponsor=1" 1030 | } 1031 | }, 1032 | "node_modules/to-regex-range": { 1033 | "version": "5.0.1", 1034 | "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", 1035 | "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", 1036 | "dev": true, 1037 | "dependencies": { 1038 | "is-number": "^7.0.0" 1039 | }, 1040 | "engines": { 1041 | "node": ">=8.0" 1042 | } 1043 | }, 1044 | "node_modules/ts-node": { 1045 | "version": "10.9.1", 1046 | "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", 1047 | "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==", 1048 | "dev": true, 1049 | "dependencies": { 1050 | "@cspotcode/source-map-support": "^0.8.0", 1051 | "@tsconfig/node10": "^1.0.7", 1052 | "@tsconfig/node12": "^1.0.7", 1053 | "@tsconfig/node14": "^1.0.0", 1054 | "@tsconfig/node16": "^1.0.2", 1055 | "acorn": "^8.4.1", 1056 | "acorn-walk": "^8.1.1", 1057 | "arg": "^4.1.0", 1058 | "create-require": "^1.1.0", 1059 | "diff": "^4.0.1", 1060 | "make-error": "^1.1.1", 1061 | "v8-compile-cache-lib": "^3.0.1", 1062 | "yn": "3.1.1" 1063 | }, 1064 | "bin": { 1065 | "ts-node": "dist/bin.js", 1066 | "ts-node-cwd": "dist/bin-cwd.js", 1067 | "ts-node-esm": "dist/bin-esm.js", 1068 | "ts-node-script": "dist/bin-script.js", 1069 | "ts-node-transpile-only": "dist/bin-transpile.js", 1070 | "ts-script": "dist/bin-script-deprecated.js" 1071 | }, 1072 | "peerDependencies": { 1073 | "@swc/core": ">=1.2.50", 1074 | "@swc/wasm": ">=1.2.50", 1075 | "@types/node": "*", 1076 | "typescript": ">=2.7" 1077 | }, 1078 | "peerDependenciesMeta": { 1079 | "@swc/core": { 1080 | "optional": true 1081 | }, 1082 | "@swc/wasm": { 1083 | "optional": true 1084 | } 1085 | } 1086 | }, 1087 | "node_modules/ts-node/node_modules/diff": { 1088 | "version": "4.0.2", 1089 | "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", 1090 | "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", 1091 | "dev": true, 1092 | "engines": { 1093 | "node": ">=0.3.1" 1094 | } 1095 | }, 1096 | "node_modules/tslib": { 1097 | "version": "2.4.0", 1098 | "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", 1099 | "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" 1100 | }, 1101 | "node_modules/type-detect": { 1102 | "version": "4.0.8", 1103 | "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", 1104 | "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", 1105 | "dev": true, 1106 | "engines": { 1107 | "node": ">=4" 1108 | } 1109 | }, 1110 | "node_modules/typescript": { 1111 | "version": "4.8.4", 1112 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.4.tgz", 1113 | "integrity": "sha512-QCh+85mCy+h0IGff8r5XWzOVSbBO+KfeYrMQh7NJ58QujwcE22u+NUSmUxqF+un70P9GXKxa2HCNiTTMJknyjQ==", 1114 | "dev": true, 1115 | "bin": { 1116 | "tsc": "bin/tsc", 1117 | "tsserver": "bin/tsserver" 1118 | }, 1119 | "engines": { 1120 | "node": ">=4.2.0" 1121 | } 1122 | }, 1123 | "node_modules/v8-compile-cache-lib": { 1124 | "version": "3.0.1", 1125 | "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", 1126 | "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", 1127 | "dev": true 1128 | }, 1129 | "node_modules/workerpool": { 1130 | "version": "6.2.1", 1131 | "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz", 1132 | "integrity": "sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==", 1133 | "dev": true 1134 | }, 1135 | "node_modules/wrap-ansi": { 1136 | "version": "7.0.0", 1137 | "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", 1138 | "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", 1139 | "dev": true, 1140 | "dependencies": { 1141 | "ansi-styles": "^4.0.0", 1142 | "string-width": "^4.1.0", 1143 | "strip-ansi": "^6.0.0" 1144 | }, 1145 | "engines": { 1146 | "node": ">=10" 1147 | }, 1148 | "funding": { 1149 | "url": "https://github.com/chalk/wrap-ansi?sponsor=1" 1150 | } 1151 | }, 1152 | "node_modules/wrap-ansi/node_modules/ansi-regex": { 1153 | "version": "5.0.1", 1154 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", 1155 | "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", 1156 | "dev": true, 1157 | "engines": { 1158 | "node": ">=8" 1159 | } 1160 | }, 1161 | "node_modules/wrap-ansi/node_modules/is-fullwidth-code-point": { 1162 | "version": "3.0.0", 1163 | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", 1164 | "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", 1165 | "dev": true, 1166 | "engines": { 1167 | "node": ">=8" 1168 | } 1169 | }, 1170 | "node_modules/wrap-ansi/node_modules/string-width": { 1171 | "version": "4.2.0", 1172 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", 1173 | "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", 1174 | "dev": true, 1175 | "dependencies": { 1176 | "emoji-regex": "^8.0.0", 1177 | "is-fullwidth-code-point": "^3.0.0", 1178 | "strip-ansi": "^6.0.0" 1179 | }, 1180 | "engines": { 1181 | "node": ">=8" 1182 | } 1183 | }, 1184 | "node_modules/wrap-ansi/node_modules/strip-ansi": { 1185 | "version": "6.0.0", 1186 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", 1187 | "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", 1188 | "dev": true, 1189 | "dependencies": { 1190 | "ansi-regex": "^5.0.0" 1191 | }, 1192 | "engines": { 1193 | "node": ">=8" 1194 | } 1195 | }, 1196 | "node_modules/wrappy": { 1197 | "version": "1.0.2", 1198 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 1199 | "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", 1200 | "dev": true 1201 | }, 1202 | "node_modules/y18n": { 1203 | "version": "5.0.5", 1204 | "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.5.tgz", 1205 | "integrity": "sha512-hsRUr4FFrvhhRH12wOdfs38Gy7k2FFzB9qgN9v3aLykRq0dRcdcpz5C9FxdS2NuhOrI/628b/KSTJ3rwHysYSg==", 1206 | "dev": true, 1207 | "engines": { 1208 | "node": ">=10" 1209 | } 1210 | }, 1211 | "node_modules/yargs": { 1212 | "version": "16.2.0", 1213 | "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", 1214 | "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", 1215 | "dev": true, 1216 | "dependencies": { 1217 | "cliui": "^7.0.2", 1218 | "escalade": "^3.1.1", 1219 | "get-caller-file": "^2.0.5", 1220 | "require-directory": "^2.1.1", 1221 | "string-width": "^4.2.0", 1222 | "y18n": "^5.0.5", 1223 | "yargs-parser": "^20.2.2" 1224 | }, 1225 | "engines": { 1226 | "node": ">=10" 1227 | } 1228 | }, 1229 | "node_modules/yargs-parser": { 1230 | "version": "20.2.4", 1231 | "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", 1232 | "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", 1233 | "dev": true, 1234 | "engines": { 1235 | "node": ">=10" 1236 | } 1237 | }, 1238 | "node_modules/yargs-unparser": { 1239 | "version": "2.0.0", 1240 | "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", 1241 | "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", 1242 | "dev": true, 1243 | "dependencies": { 1244 | "camelcase": "^6.0.0", 1245 | "decamelize": "^4.0.0", 1246 | "flat": "^5.0.2", 1247 | "is-plain-obj": "^2.1.0" 1248 | }, 1249 | "engines": { 1250 | "node": ">=10" 1251 | } 1252 | }, 1253 | "node_modules/yargs/node_modules/ansi-regex": { 1254 | "version": "5.0.1", 1255 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", 1256 | "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", 1257 | "dev": true, 1258 | "engines": { 1259 | "node": ">=8" 1260 | } 1261 | }, 1262 | "node_modules/yargs/node_modules/is-fullwidth-code-point": { 1263 | "version": "3.0.0", 1264 | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", 1265 | "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", 1266 | "dev": true, 1267 | "engines": { 1268 | "node": ">=8" 1269 | } 1270 | }, 1271 | "node_modules/yargs/node_modules/string-width": { 1272 | "version": "4.2.0", 1273 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", 1274 | "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", 1275 | "dev": true, 1276 | "dependencies": { 1277 | "emoji-regex": "^8.0.0", 1278 | "is-fullwidth-code-point": "^3.0.0", 1279 | "strip-ansi": "^6.0.0" 1280 | }, 1281 | "engines": { 1282 | "node": ">=8" 1283 | } 1284 | }, 1285 | "node_modules/yargs/node_modules/strip-ansi": { 1286 | "version": "6.0.0", 1287 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", 1288 | "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", 1289 | "dev": true, 1290 | "dependencies": { 1291 | "ansi-regex": "^5.0.0" 1292 | }, 1293 | "engines": { 1294 | "node": ">=8" 1295 | } 1296 | }, 1297 | "node_modules/yn": { 1298 | "version": "3.1.1", 1299 | "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", 1300 | "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", 1301 | "dev": true, 1302 | "engines": { 1303 | "node": ">=6" 1304 | } 1305 | }, 1306 | "node_modules/yocto-queue": { 1307 | "version": "0.1.0", 1308 | "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", 1309 | "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", 1310 | "dev": true, 1311 | "engines": { 1312 | "node": ">=10" 1313 | }, 1314 | "funding": { 1315 | "url": "https://github.com/sponsors/sindresorhus" 1316 | } 1317 | } 1318 | }, 1319 | "dependencies": { 1320 | "@cspotcode/source-map-support": { 1321 | "version": "0.8.1", 1322 | "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", 1323 | "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", 1324 | "dev": true, 1325 | "requires": { 1326 | "@jridgewell/trace-mapping": "0.3.9" 1327 | } 1328 | }, 1329 | "@jridgewell/resolve-uri": { 1330 | "version": "3.1.0", 1331 | "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", 1332 | "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", 1333 | "dev": true 1334 | }, 1335 | "@jridgewell/sourcemap-codec": { 1336 | "version": "1.4.14", 1337 | "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", 1338 | "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", 1339 | "dev": true 1340 | }, 1341 | "@jridgewell/trace-mapping": { 1342 | "version": "0.3.9", 1343 | "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", 1344 | "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", 1345 | "dev": true, 1346 | "requires": { 1347 | "@jridgewell/resolve-uri": "^3.0.3", 1348 | "@jridgewell/sourcemap-codec": "^1.4.10" 1349 | } 1350 | }, 1351 | "@tsconfig/node10": { 1352 | "version": "1.0.9", 1353 | "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", 1354 | "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==", 1355 | "dev": true 1356 | }, 1357 | "@tsconfig/node12": { 1358 | "version": "1.0.11", 1359 | "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", 1360 | "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", 1361 | "dev": true 1362 | }, 1363 | "@tsconfig/node14": { 1364 | "version": "1.0.3", 1365 | "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", 1366 | "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", 1367 | "dev": true 1368 | }, 1369 | "@tsconfig/node16": { 1370 | "version": "1.0.3", 1371 | "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.3.tgz", 1372 | "integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==", 1373 | "dev": true 1374 | }, 1375 | "@types/chai": { 1376 | "version": "4.3.3", 1377 | "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.3.tgz", 1378 | "integrity": "sha512-hC7OMnszpxhZPduX+m+nrx+uFoLkWOMiR4oa/AZF3MuSETYTZmFfJAHqZEM8MVlvfG7BEUcgvtwoCTxBp6hm3g==", 1379 | "dev": true 1380 | }, 1381 | "@types/mocha": { 1382 | "version": "8.2.3", 1383 | "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-8.2.3.tgz", 1384 | "integrity": "sha512-ekGvFhFgrc2zYQoX4JeZPmVzZxw6Dtllga7iGHzfbYIYkAMUx/sAFP2GdFpLff+vdHXu5fl7WX9AT+TtqYcsyw==", 1385 | "dev": true 1386 | }, 1387 | "@types/node": { 1388 | "version": "18.8.0", 1389 | "resolved": "https://registry.npmjs.org/@types/node/-/node-18.8.0.tgz", 1390 | "integrity": "sha512-u+h43R6U8xXDt2vzUaVP3VwjjLyOJk6uEciZS8OSyziUQGOwmk+l+4drxcsDboHXwyTaqS1INebghmWMRxq3LA==" 1391 | }, 1392 | "@ungap/promise-all-settled": { 1393 | "version": "1.1.2", 1394 | "resolved": "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz", 1395 | "integrity": "sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==", 1396 | "dev": true 1397 | }, 1398 | "acorn": { 1399 | "version": "8.8.0", 1400 | "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.0.tgz", 1401 | "integrity": "sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==", 1402 | "dev": true 1403 | }, 1404 | "acorn-walk": { 1405 | "version": "8.2.0", 1406 | "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", 1407 | "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", 1408 | "dev": true 1409 | }, 1410 | "ansi-colors": { 1411 | "version": "4.1.1", 1412 | "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", 1413 | "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", 1414 | "dev": true 1415 | }, 1416 | "ansi-styles": { 1417 | "version": "4.3.0", 1418 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", 1419 | "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", 1420 | "dev": true, 1421 | "requires": { 1422 | "color-convert": "^2.0.1" 1423 | } 1424 | }, 1425 | "anymatch": { 1426 | "version": "3.1.2", 1427 | "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", 1428 | "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", 1429 | "dev": true, 1430 | "requires": { 1431 | "normalize-path": "^3.0.0", 1432 | "picomatch": "^2.0.4" 1433 | } 1434 | }, 1435 | "arg": { 1436 | "version": "4.1.3", 1437 | "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", 1438 | "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", 1439 | "dev": true 1440 | }, 1441 | "argparse": { 1442 | "version": "2.0.1", 1443 | "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", 1444 | "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", 1445 | "dev": true 1446 | }, 1447 | "assertion-error": { 1448 | "version": "1.1.0", 1449 | "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", 1450 | "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", 1451 | "dev": true 1452 | }, 1453 | "balanced-match": { 1454 | "version": "1.0.2", 1455 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", 1456 | "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", 1457 | "dev": true 1458 | }, 1459 | "binary-extensions": { 1460 | "version": "2.2.0", 1461 | "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", 1462 | "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", 1463 | "dev": true 1464 | }, 1465 | "brace-expansion": { 1466 | "version": "2.0.1", 1467 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", 1468 | "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", 1469 | "dev": true, 1470 | "requires": { 1471 | "balanced-match": "^1.0.0" 1472 | } 1473 | }, 1474 | "braces": { 1475 | "version": "3.0.2", 1476 | "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", 1477 | "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", 1478 | "dev": true, 1479 | "requires": { 1480 | "fill-range": "^7.0.1" 1481 | } 1482 | }, 1483 | "browser-stdout": { 1484 | "version": "1.3.1", 1485 | "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", 1486 | "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", 1487 | "dev": true 1488 | }, 1489 | "camelcase": { 1490 | "version": "6.2.0", 1491 | "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.2.0.tgz", 1492 | "integrity": "sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg==", 1493 | "dev": true 1494 | }, 1495 | "chai": { 1496 | "version": "4.3.6", 1497 | "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.6.tgz", 1498 | "integrity": "sha512-bbcp3YfHCUzMOvKqsztczerVgBKSsEijCySNlHHbX3VG1nskvqjz5Rfso1gGwD6w6oOV3eI60pKuMOV5MV7p3Q==", 1499 | "dev": true, 1500 | "requires": { 1501 | "assertion-error": "^1.1.0", 1502 | "check-error": "^1.0.2", 1503 | "deep-eql": "^3.0.1", 1504 | "get-func-name": "^2.0.0", 1505 | "loupe": "^2.3.1", 1506 | "pathval": "^1.1.1", 1507 | "type-detect": "^4.0.5" 1508 | } 1509 | }, 1510 | "chai-as-promised": { 1511 | "version": "7.1.1", 1512 | "resolved": "https://registry.npmjs.org/chai-as-promised/-/chai-as-promised-7.1.1.tgz", 1513 | "integrity": "sha512-azL6xMoi+uxu6z4rhWQ1jbdUhOMhis2PvscD/xjLqNMkv3BPPp2JyyuTHOrf9BOosGpNQ11v6BKv/g57RXbiaA==", 1514 | "dev": true, 1515 | "requires": { 1516 | "check-error": "^1.0.2" 1517 | } 1518 | }, 1519 | "chalk": { 1520 | "version": "4.1.2", 1521 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", 1522 | "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", 1523 | "dev": true, 1524 | "requires": { 1525 | "ansi-styles": "^4.1.0", 1526 | "supports-color": "^7.1.0" 1527 | }, 1528 | "dependencies": { 1529 | "supports-color": { 1530 | "version": "7.2.0", 1531 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", 1532 | "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", 1533 | "dev": true, 1534 | "requires": { 1535 | "has-flag": "^4.0.0" 1536 | } 1537 | } 1538 | } 1539 | }, 1540 | "check-error": { 1541 | "version": "1.0.2", 1542 | "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", 1543 | "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=", 1544 | "dev": true 1545 | }, 1546 | "chokidar": { 1547 | "version": "3.5.3", 1548 | "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", 1549 | "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", 1550 | "dev": true, 1551 | "requires": { 1552 | "anymatch": "~3.1.2", 1553 | "braces": "~3.0.2", 1554 | "fsevents": "~2.3.2", 1555 | "glob-parent": "~5.1.2", 1556 | "is-binary-path": "~2.1.0", 1557 | "is-glob": "~4.0.1", 1558 | "normalize-path": "~3.0.0", 1559 | "readdirp": "~3.6.0" 1560 | } 1561 | }, 1562 | "cliui": { 1563 | "version": "7.0.4", 1564 | "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", 1565 | "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", 1566 | "dev": true, 1567 | "requires": { 1568 | "string-width": "^4.2.0", 1569 | "strip-ansi": "^6.0.0", 1570 | "wrap-ansi": "^7.0.0" 1571 | }, 1572 | "dependencies": { 1573 | "ansi-regex": { 1574 | "version": "5.0.1", 1575 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", 1576 | "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", 1577 | "dev": true 1578 | }, 1579 | "is-fullwidth-code-point": { 1580 | "version": "3.0.0", 1581 | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", 1582 | "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", 1583 | "dev": true 1584 | }, 1585 | "string-width": { 1586 | "version": "4.2.0", 1587 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", 1588 | "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", 1589 | "dev": true, 1590 | "requires": { 1591 | "emoji-regex": "^8.0.0", 1592 | "is-fullwidth-code-point": "^3.0.0", 1593 | "strip-ansi": "^6.0.0" 1594 | } 1595 | }, 1596 | "strip-ansi": { 1597 | "version": "6.0.0", 1598 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", 1599 | "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", 1600 | "dev": true, 1601 | "requires": { 1602 | "ansi-regex": "^5.0.0" 1603 | } 1604 | } 1605 | } 1606 | }, 1607 | "color-convert": { 1608 | "version": "2.0.1", 1609 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", 1610 | "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", 1611 | "dev": true, 1612 | "requires": { 1613 | "color-name": "~1.1.4" 1614 | } 1615 | }, 1616 | "color-name": { 1617 | "version": "1.1.4", 1618 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", 1619 | "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", 1620 | "dev": true 1621 | }, 1622 | "concat-map": { 1623 | "version": "0.0.1", 1624 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", 1625 | "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", 1626 | "dev": true 1627 | }, 1628 | "create-require": { 1629 | "version": "1.1.1", 1630 | "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", 1631 | "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", 1632 | "dev": true 1633 | }, 1634 | "debug": { 1635 | "version": "4.3.4", 1636 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", 1637 | "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", 1638 | "dev": true, 1639 | "requires": { 1640 | "ms": "2.1.2" 1641 | }, 1642 | "dependencies": { 1643 | "ms": { 1644 | "version": "2.1.2", 1645 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", 1646 | "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", 1647 | "dev": true 1648 | } 1649 | } 1650 | }, 1651 | "decamelize": { 1652 | "version": "4.0.0", 1653 | "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", 1654 | "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", 1655 | "dev": true 1656 | }, 1657 | "deep-eql": { 1658 | "version": "3.0.1", 1659 | "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz", 1660 | "integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==", 1661 | "dev": true, 1662 | "requires": { 1663 | "type-detect": "^4.0.0" 1664 | } 1665 | }, 1666 | "diff": { 1667 | "version": "5.0.0", 1668 | "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", 1669 | "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", 1670 | "dev": true 1671 | }, 1672 | "emoji-regex": { 1673 | "version": "8.0.0", 1674 | "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", 1675 | "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", 1676 | "dev": true 1677 | }, 1678 | "escalade": { 1679 | "version": "3.1.1", 1680 | "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", 1681 | "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", 1682 | "dev": true 1683 | }, 1684 | "escape-string-regexp": { 1685 | "version": "4.0.0", 1686 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", 1687 | "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", 1688 | "dev": true 1689 | }, 1690 | "fill-range": { 1691 | "version": "7.0.1", 1692 | "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", 1693 | "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", 1694 | "dev": true, 1695 | "requires": { 1696 | "to-regex-range": "^5.0.1" 1697 | } 1698 | }, 1699 | "find-up": { 1700 | "version": "5.0.0", 1701 | "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", 1702 | "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", 1703 | "dev": true, 1704 | "requires": { 1705 | "locate-path": "^6.0.0", 1706 | "path-exists": "^4.0.0" 1707 | } 1708 | }, 1709 | "flat": { 1710 | "version": "5.0.2", 1711 | "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", 1712 | "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", 1713 | "dev": true 1714 | }, 1715 | "fs.realpath": { 1716 | "version": "1.0.0", 1717 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", 1718 | "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", 1719 | "dev": true 1720 | }, 1721 | "fsevents": { 1722 | "version": "2.3.2", 1723 | "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", 1724 | "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", 1725 | "dev": true, 1726 | "optional": true 1727 | }, 1728 | "get-caller-file": { 1729 | "version": "2.0.5", 1730 | "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", 1731 | "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", 1732 | "dev": true 1733 | }, 1734 | "get-func-name": { 1735 | "version": "2.0.0", 1736 | "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", 1737 | "integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=", 1738 | "dev": true 1739 | }, 1740 | "glob": { 1741 | "version": "7.2.0", 1742 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", 1743 | "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", 1744 | "dev": true, 1745 | "requires": { 1746 | "fs.realpath": "^1.0.0", 1747 | "inflight": "^1.0.4", 1748 | "inherits": "2", 1749 | "minimatch": "^3.0.4", 1750 | "once": "^1.3.0", 1751 | "path-is-absolute": "^1.0.0" 1752 | }, 1753 | "dependencies": { 1754 | "brace-expansion": { 1755 | "version": "1.1.11", 1756 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", 1757 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", 1758 | "dev": true, 1759 | "requires": { 1760 | "balanced-match": "^1.0.0", 1761 | "concat-map": "0.0.1" 1762 | } 1763 | }, 1764 | "minimatch": { 1765 | "version": "3.1.2", 1766 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", 1767 | "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", 1768 | "dev": true, 1769 | "requires": { 1770 | "brace-expansion": "^1.1.7" 1771 | } 1772 | } 1773 | } 1774 | }, 1775 | "glob-parent": { 1776 | "version": "5.1.2", 1777 | "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", 1778 | "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", 1779 | "dev": true, 1780 | "requires": { 1781 | "is-glob": "^4.0.1" 1782 | } 1783 | }, 1784 | "has-flag": { 1785 | "version": "4.0.0", 1786 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", 1787 | "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", 1788 | "dev": true 1789 | }, 1790 | "he": { 1791 | "version": "1.2.0", 1792 | "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", 1793 | "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", 1794 | "dev": true 1795 | }, 1796 | "inflight": { 1797 | "version": "1.0.6", 1798 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", 1799 | "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", 1800 | "dev": true, 1801 | "requires": { 1802 | "once": "^1.3.0", 1803 | "wrappy": "1" 1804 | } 1805 | }, 1806 | "inherits": { 1807 | "version": "2.0.4", 1808 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", 1809 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", 1810 | "dev": true 1811 | }, 1812 | "is-binary-path": { 1813 | "version": "2.1.0", 1814 | "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", 1815 | "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", 1816 | "dev": true, 1817 | "requires": { 1818 | "binary-extensions": "^2.0.0" 1819 | } 1820 | }, 1821 | "is-extglob": { 1822 | "version": "2.1.1", 1823 | "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", 1824 | "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", 1825 | "dev": true 1826 | }, 1827 | "is-glob": { 1828 | "version": "4.0.3", 1829 | "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", 1830 | "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", 1831 | "dev": true, 1832 | "requires": { 1833 | "is-extglob": "^2.1.1" 1834 | } 1835 | }, 1836 | "is-number": { 1837 | "version": "7.0.0", 1838 | "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", 1839 | "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", 1840 | "dev": true 1841 | }, 1842 | "is-plain-obj": { 1843 | "version": "2.1.0", 1844 | "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", 1845 | "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", 1846 | "dev": true 1847 | }, 1848 | "is-unicode-supported": { 1849 | "version": "0.1.0", 1850 | "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", 1851 | "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", 1852 | "dev": true 1853 | }, 1854 | "js-yaml": { 1855 | "version": "4.1.0", 1856 | "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", 1857 | "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", 1858 | "dev": true, 1859 | "requires": { 1860 | "argparse": "^2.0.1" 1861 | } 1862 | }, 1863 | "locate-path": { 1864 | "version": "6.0.0", 1865 | "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", 1866 | "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", 1867 | "dev": true, 1868 | "requires": { 1869 | "p-locate": "^5.0.0" 1870 | } 1871 | }, 1872 | "log-symbols": { 1873 | "version": "4.1.0", 1874 | "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", 1875 | "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", 1876 | "dev": true, 1877 | "requires": { 1878 | "chalk": "^4.1.0", 1879 | "is-unicode-supported": "^0.1.0" 1880 | } 1881 | }, 1882 | "loupe": { 1883 | "version": "2.3.4", 1884 | "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.4.tgz", 1885 | "integrity": "sha512-OvKfgCC2Ndby6aSTREl5aCCPTNIzlDfQZvZxNUrBrihDhL3xcrYegTblhmEiCrg2kKQz4XsFIaemE5BF4ybSaQ==", 1886 | "dev": true, 1887 | "requires": { 1888 | "get-func-name": "^2.0.0" 1889 | } 1890 | }, 1891 | "make-error": { 1892 | "version": "1.3.6", 1893 | "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", 1894 | "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", 1895 | "dev": true 1896 | }, 1897 | "minimatch": { 1898 | "version": "5.0.1", 1899 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz", 1900 | "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==", 1901 | "dev": true, 1902 | "requires": { 1903 | "brace-expansion": "^2.0.1" 1904 | } 1905 | }, 1906 | "mocha": { 1907 | "version": "10.0.0", 1908 | "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.0.0.tgz", 1909 | "integrity": "sha512-0Wl+elVUD43Y0BqPZBzZt8Tnkw9CMUdNYnUsTfOM1vuhJVZL+kiesFYsqwBkEEuEixaiPe5ZQdqDgX2jddhmoA==", 1910 | "dev": true, 1911 | "requires": { 1912 | "@ungap/promise-all-settled": "1.1.2", 1913 | "ansi-colors": "4.1.1", 1914 | "browser-stdout": "1.3.1", 1915 | "chokidar": "3.5.3", 1916 | "debug": "4.3.4", 1917 | "diff": "5.0.0", 1918 | "escape-string-regexp": "4.0.0", 1919 | "find-up": "5.0.0", 1920 | "glob": "7.2.0", 1921 | "he": "1.2.0", 1922 | "js-yaml": "4.1.0", 1923 | "log-symbols": "4.1.0", 1924 | "minimatch": "5.0.1", 1925 | "ms": "2.1.3", 1926 | "nanoid": "3.3.3", 1927 | "serialize-javascript": "6.0.0", 1928 | "strip-json-comments": "3.1.1", 1929 | "supports-color": "8.1.1", 1930 | "workerpool": "6.2.1", 1931 | "yargs": "16.2.0", 1932 | "yargs-parser": "20.2.4", 1933 | "yargs-unparser": "2.0.0" 1934 | } 1935 | }, 1936 | "ms": { 1937 | "version": "2.1.3", 1938 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", 1939 | "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", 1940 | "dev": true 1941 | }, 1942 | "nanoid": { 1943 | "version": "3.3.3", 1944 | "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz", 1945 | "integrity": "sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==", 1946 | "dev": true 1947 | }, 1948 | "normalize-path": { 1949 | "version": "3.0.0", 1950 | "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", 1951 | "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", 1952 | "dev": true 1953 | }, 1954 | "once": { 1955 | "version": "1.4.0", 1956 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 1957 | "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", 1958 | "dev": true, 1959 | "requires": { 1960 | "wrappy": "1" 1961 | } 1962 | }, 1963 | "p-limit": { 1964 | "version": "3.1.0", 1965 | "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", 1966 | "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", 1967 | "dev": true, 1968 | "requires": { 1969 | "yocto-queue": "^0.1.0" 1970 | } 1971 | }, 1972 | "p-locate": { 1973 | "version": "5.0.0", 1974 | "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", 1975 | "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", 1976 | "dev": true, 1977 | "requires": { 1978 | "p-limit": "^3.0.2" 1979 | } 1980 | }, 1981 | "path-exists": { 1982 | "version": "4.0.0", 1983 | "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", 1984 | "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", 1985 | "dev": true 1986 | }, 1987 | "path-is-absolute": { 1988 | "version": "1.0.1", 1989 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", 1990 | "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", 1991 | "dev": true 1992 | }, 1993 | "pathval": { 1994 | "version": "1.1.1", 1995 | "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", 1996 | "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", 1997 | "dev": true 1998 | }, 1999 | "picomatch": { 2000 | "version": "2.3.1", 2001 | "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", 2002 | "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", 2003 | "dev": true 2004 | }, 2005 | "randombytes": { 2006 | "version": "2.1.0", 2007 | "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", 2008 | "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", 2009 | "dev": true, 2010 | "requires": { 2011 | "safe-buffer": "^5.1.0" 2012 | } 2013 | }, 2014 | "readdirp": { 2015 | "version": "3.6.0", 2016 | "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", 2017 | "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", 2018 | "dev": true, 2019 | "requires": { 2020 | "picomatch": "^2.2.1" 2021 | } 2022 | }, 2023 | "require-directory": { 2024 | "version": "2.1.1", 2025 | "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", 2026 | "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", 2027 | "dev": true 2028 | }, 2029 | "safe-buffer": { 2030 | "version": "5.2.1", 2031 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", 2032 | "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", 2033 | "dev": true 2034 | }, 2035 | "serialize-javascript": { 2036 | "version": "6.0.0", 2037 | "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", 2038 | "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", 2039 | "dev": true, 2040 | "requires": { 2041 | "randombytes": "^2.1.0" 2042 | } 2043 | }, 2044 | "strip-json-comments": { 2045 | "version": "3.1.1", 2046 | "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", 2047 | "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", 2048 | "dev": true 2049 | }, 2050 | "supports-color": { 2051 | "version": "8.1.1", 2052 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", 2053 | "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", 2054 | "dev": true, 2055 | "requires": { 2056 | "has-flag": "^4.0.0" 2057 | } 2058 | }, 2059 | "to-regex-range": { 2060 | "version": "5.0.1", 2061 | "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", 2062 | "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", 2063 | "dev": true, 2064 | "requires": { 2065 | "is-number": "^7.0.0" 2066 | } 2067 | }, 2068 | "ts-node": { 2069 | "version": "10.9.1", 2070 | "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", 2071 | "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==", 2072 | "dev": true, 2073 | "requires": { 2074 | "@cspotcode/source-map-support": "^0.8.0", 2075 | "@tsconfig/node10": "^1.0.7", 2076 | "@tsconfig/node12": "^1.0.7", 2077 | "@tsconfig/node14": "^1.0.0", 2078 | "@tsconfig/node16": "^1.0.2", 2079 | "acorn": "^8.4.1", 2080 | "acorn-walk": "^8.1.1", 2081 | "arg": "^4.1.0", 2082 | "create-require": "^1.1.0", 2083 | "diff": "^4.0.1", 2084 | "make-error": "^1.1.1", 2085 | "v8-compile-cache-lib": "^3.0.1", 2086 | "yn": "3.1.1" 2087 | }, 2088 | "dependencies": { 2089 | "diff": { 2090 | "version": "4.0.2", 2091 | "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", 2092 | "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", 2093 | "dev": true 2094 | } 2095 | } 2096 | }, 2097 | "tslib": { 2098 | "version": "2.4.0", 2099 | "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", 2100 | "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" 2101 | }, 2102 | "type-detect": { 2103 | "version": "4.0.8", 2104 | "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", 2105 | "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", 2106 | "dev": true 2107 | }, 2108 | "typescript": { 2109 | "version": "4.8.4", 2110 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.4.tgz", 2111 | "integrity": "sha512-QCh+85mCy+h0IGff8r5XWzOVSbBO+KfeYrMQh7NJ58QujwcE22u+NUSmUxqF+un70P9GXKxa2HCNiTTMJknyjQ==", 2112 | "dev": true 2113 | }, 2114 | "v8-compile-cache-lib": { 2115 | "version": "3.0.1", 2116 | "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", 2117 | "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", 2118 | "dev": true 2119 | }, 2120 | "workerpool": { 2121 | "version": "6.2.1", 2122 | "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz", 2123 | "integrity": "sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==", 2124 | "dev": true 2125 | }, 2126 | "wrap-ansi": { 2127 | "version": "7.0.0", 2128 | "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", 2129 | "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", 2130 | "dev": true, 2131 | "requires": { 2132 | "ansi-styles": "^4.0.0", 2133 | "string-width": "^4.1.0", 2134 | "strip-ansi": "^6.0.0" 2135 | }, 2136 | "dependencies": { 2137 | "ansi-regex": { 2138 | "version": "5.0.1", 2139 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", 2140 | "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", 2141 | "dev": true 2142 | }, 2143 | "is-fullwidth-code-point": { 2144 | "version": "3.0.0", 2145 | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", 2146 | "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", 2147 | "dev": true 2148 | }, 2149 | "string-width": { 2150 | "version": "4.2.0", 2151 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", 2152 | "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", 2153 | "dev": true, 2154 | "requires": { 2155 | "emoji-regex": "^8.0.0", 2156 | "is-fullwidth-code-point": "^3.0.0", 2157 | "strip-ansi": "^6.0.0" 2158 | } 2159 | }, 2160 | "strip-ansi": { 2161 | "version": "6.0.0", 2162 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", 2163 | "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", 2164 | "dev": true, 2165 | "requires": { 2166 | "ansi-regex": "^5.0.0" 2167 | } 2168 | } 2169 | } 2170 | }, 2171 | "wrappy": { 2172 | "version": "1.0.2", 2173 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 2174 | "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", 2175 | "dev": true 2176 | }, 2177 | "y18n": { 2178 | "version": "5.0.5", 2179 | "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.5.tgz", 2180 | "integrity": "sha512-hsRUr4FFrvhhRH12wOdfs38Gy7k2FFzB9qgN9v3aLykRq0dRcdcpz5C9FxdS2NuhOrI/628b/KSTJ3rwHysYSg==", 2181 | "dev": true 2182 | }, 2183 | "yargs": { 2184 | "version": "16.2.0", 2185 | "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", 2186 | "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", 2187 | "dev": true, 2188 | "requires": { 2189 | "cliui": "^7.0.2", 2190 | "escalade": "^3.1.1", 2191 | "get-caller-file": "^2.0.5", 2192 | "require-directory": "^2.1.1", 2193 | "string-width": "^4.2.0", 2194 | "y18n": "^5.0.5", 2195 | "yargs-parser": "^20.2.2" 2196 | }, 2197 | "dependencies": { 2198 | "ansi-regex": { 2199 | "version": "5.0.1", 2200 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", 2201 | "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", 2202 | "dev": true 2203 | }, 2204 | "is-fullwidth-code-point": { 2205 | "version": "3.0.0", 2206 | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", 2207 | "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", 2208 | "dev": true 2209 | }, 2210 | "string-width": { 2211 | "version": "4.2.0", 2212 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", 2213 | "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", 2214 | "dev": true, 2215 | "requires": { 2216 | "emoji-regex": "^8.0.0", 2217 | "is-fullwidth-code-point": "^3.0.0", 2218 | "strip-ansi": "^6.0.0" 2219 | } 2220 | }, 2221 | "strip-ansi": { 2222 | "version": "6.0.0", 2223 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", 2224 | "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", 2225 | "dev": true, 2226 | "requires": { 2227 | "ansi-regex": "^5.0.0" 2228 | } 2229 | } 2230 | } 2231 | }, 2232 | "yargs-parser": { 2233 | "version": "20.2.4", 2234 | "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", 2235 | "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", 2236 | "dev": true 2237 | }, 2238 | "yargs-unparser": { 2239 | "version": "2.0.0", 2240 | "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", 2241 | "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", 2242 | "dev": true, 2243 | "requires": { 2244 | "camelcase": "^6.0.0", 2245 | "decamelize": "^4.0.0", 2246 | "flat": "^5.0.2", 2247 | "is-plain-obj": "^2.1.0" 2248 | } 2249 | }, 2250 | "yn": { 2251 | "version": "3.1.1", 2252 | "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", 2253 | "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", 2254 | "dev": true 2255 | }, 2256 | "yocto-queue": { 2257 | "version": "0.1.0", 2258 | "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", 2259 | "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", 2260 | "dev": true 2261 | } 2262 | } 2263 | } 2264 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "constant-time-js", 3 | "version": "0.4.0", 4 | "description": "Constant-time algorithms in JavaScript", 5 | "main": "index.ts", 6 | "scripts": { 7 | "test": "mocha -r ts-node/register ./tests/*.ts" 8 | }, 9 | "type": "module", 10 | "keywords": [ 11 | "crypto", 12 | "constant-time", 13 | "cryptography" 14 | ], 15 | "dependencies": { 16 | "@types/node": "^18.8.0", 17 | "tslib": "^2.4.0" 18 | }, 19 | "devDependencies": { 20 | "@types/chai": "^4.3.3", 21 | "@types/mocha": "^8.2.3", 22 | "chai": "^4.3.6", 23 | "chai-as-promised": "^7.1.1", 24 | "mocha": "^10.0.0", 25 | "ts-node": "^10.9.1", 26 | "typescript": "^4.8.4" 27 | }, 28 | "author": "Soatok Dreamseeker", 29 | "license": "ISC" 30 | } 31 | -------------------------------------------------------------------------------- /tests/bignum.test.ts: -------------------------------------------------------------------------------- 1 | import { 2 | add, 3 | and, 4 | count_trailing_zero_bits, 5 | divide, 6 | gcd, 7 | lshift1, 8 | modInverse, 9 | modPow, 10 | modulo, 11 | multiply, 12 | normalize, 13 | or, 14 | pow, 15 | rshift1, 16 | shift_left, 17 | shift_right, 18 | sub, 19 | xor, 20 | } from '../lib/bignum'; 21 | import { expect } from 'chai'; 22 | import 'mocha'; 23 | import { uint8array_to_hex } from './test-helper'; 24 | import {trim_zeroes_left} from "../lib/trim"; 25 | import {intdiv} from "../lib/intdiv"; 26 | 27 | describe('Constant-Time BigNumber Arithmetic', () => { 28 | it('add()', () => { 29 | const a = new Uint8Array([0x31, 0x41]); 30 | const b = new Uint8Array([0x59, 0x65]); 31 | expect(uint8array_to_hex(add(a, b))) 32 | .to.be.equal('8aa6'); 33 | }); 34 | 35 | it('and()', () => { 36 | const a = new Uint8Array([0x31, 0x41]); 37 | const b = new Uint8Array([0x59, 0x65]); 38 | expect(uint8array_to_hex(and(a, b))) 39 | .to.be.equal('1141'); 40 | }); 41 | 42 | it('count_trailing_zero_bits()', () => { 43 | const a = new Uint8Array([0x31, 0x41, 0x59, 0xff]); 44 | let count: number; 45 | count = Number(count_trailing_zero_bits(a)); 46 | expect(count).to.be.equal(0); 47 | 48 | a[3] = 0xfe; 49 | count = Number(count_trailing_zero_bits(a)); 50 | expect(count).to.be.equal(1); 51 | 52 | a[3] = 0xfc; 53 | count = Number(count_trailing_zero_bits(a)); 54 | expect(count).to.be.equal(2); 55 | 56 | a[3] = 0xf8; 57 | count = Number(count_trailing_zero_bits(a)); 58 | expect(count).to.be.equal(3); 59 | 60 | a[3] = 0xf0; 61 | count = Number(count_trailing_zero_bits(a)); 62 | expect(count).to.be.equal(4); 63 | 64 | a[3] = 0x00; 65 | count = Number(count_trailing_zero_bits(a)); 66 | expect(count).to.be.equal(8); 67 | }); 68 | 69 | it('divide() and modulo()', () => { 70 | const testCases = [ 71 | {N: 3628800, D: 11, Q: 329890, R: 10}, 72 | {N: 3628800, D: 10, Q: 362880, R: 0}, 73 | {N: 3628800, D: 9, Q: 403200, R: 0}, 74 | {N: 3628800, D: 13, Q: 279138, R: 6}, 75 | ]; 76 | for (const test of testCases) { 77 | const testN = new Uint8Array([ 78 | (test.N >>> 24) & 0xff, 79 | (test.N >>> 16) & 0xff, 80 | (test.N >>> 8) & 0xff, 81 | test.N & 0xff, 82 | ]); 83 | const testD = new Uint8Array([ 84 | (test.D >>> 24) & 0xff, 85 | (test.D >>> 16) & 0xff, 86 | (test.D >>> 8) & 0xff, 87 | test.D & 0xff, 88 | ]); 89 | const testQ = new Uint8Array([ 90 | (test.Q >>> 24) & 0xff, 91 | (test.Q >>> 16) & 0xff, 92 | (test.Q >>> 8) & 0xff, 93 | test.Q & 0xff, 94 | ]); 95 | const testR = new Uint8Array([ 96 | (test.R >>> 24) & 0xff, 97 | (test.R >>> 16) & 0xff, 98 | (test.R >>> 8) & 0xff, 99 | test.R & 0xff, 100 | ]); 101 | expect(uint8array_to_hex(testQ)) 102 | .to.be.equal(uint8array_to_hex(divide(testN, testD))); 103 | expect(uint8array_to_hex(testR)) 104 | .to.be.equal(uint8array_to_hex(modulo(testN, testD))); 105 | } 106 | 107 | const a = new Uint8Array([0x0e]) 108 | const b = new Uint8Array([0x07]); 109 | expect('02').to.be.equal( 110 | uint8array_to_hex(divide(a, b)) 111 | ); 112 | 113 | const c = new Uint8Array([0x00, 0x00, 0xff, 0xff]) 114 | const d = new Uint8Array([0x00, 0x00, 0x00, 0xff]); 115 | expect('00000101').to.be.equal( 116 | uint8array_to_hex(divide(c, d)) 117 | ); 118 | const e = new Uint8Array([0x00, 0x00, 0x01, 0x01]); 119 | expect('000000ff').to.be.equal( 120 | uint8array_to_hex(divide(c, e)) 121 | ); 122 | }); 123 | 124 | it('gcd()', () => { 125 | const a = new Uint8Array([0x00, 0x00, 0xff, 0xff]) 126 | const b = new Uint8Array([0x00, 0x00, 0x01, 0x01]); 127 | expect(uint8array_to_hex(gcd(a, b))) 128 | .to.be.equal('00000101'); 129 | 130 | const c = new Uint8Array([0x00, 0x00, 0x02, 0xb5]) 131 | const d = new Uint8Array([0x00, 0x00, 0x02, 0x61]); 132 | expect(uint8array_to_hex(gcd(c, d))) 133 | .to.be.equal('00000015'); 134 | }); 135 | 136 | it('lshift1()', () => { 137 | const a = new Uint8Array([0x31, 0x41, 0x59, 0x65]); 138 | lshift1(a); 139 | expect(uint8array_to_hex(a)).to.be.equal('6282b2ca'); 140 | lshift1(a); 141 | expect(uint8array_to_hex(a)).to.be.equal('c5056594'); 142 | lshift1(a); 143 | expect(uint8array_to_hex(a)).to.be.equal('8a0acb28'); 144 | lshift1(a); 145 | expect(uint8array_to_hex(a)).to.be.equal('14159650'); 146 | }); 147 | 148 | it('modInverse()', () => { 149 | const prime = new Uint8Array([0x00, 0x01, 0x00, 0x01]); // 65537 150 | const three = new Uint8Array([0x00, 0x00, 0x00, 0x03]); 151 | expect(uint8array_to_hex(modInverse(three, prime))) 152 | .to.be.equal('00005556'); 153 | 154 | const five = new Uint8Array([0x00, 0x00, 0x00, 0x05]); 155 | expect(uint8array_to_hex(modInverse(five, prime))) 156 | .to.be.equal('00006667'); 157 | 158 | const half = new Uint8Array([0x00, 0x00, 0x7f, 0xff]); 159 | expect(uint8array_to_hex(modInverse(half, prime))) 160 | .to.be.equal('00005555'); 161 | 162 | const halfUpper = new Uint8Array([0x00, 0x00, 0x80, 0x00]); 163 | expect(uint8array_to_hex(modInverse(halfUpper, prime))) 164 | .to.be.equal('0000ffff'); 165 | }); 166 | 167 | it('modInverse() - expected failure cases', () => { 168 | expect( 169 | () => modInverse(new Uint8Array([4]), new Uint8Array([12])) 170 | ).to.throw('inverse does not exist'); 171 | expect( 172 | () => modInverse(new Uint8Array([127]), new Uint8Array([127])) 173 | ).to.throw('inverse does not exist'); 174 | }); 175 | 176 | it('modPow()', () => { 177 | const base = new Uint8Array([0x00, 0x04]); // 4 178 | const exponent = new Uint8Array([0x00, 0x0d]); // 13 179 | const modulus = new Uint8Array([0x01, 0xf1]); // 497 180 | expect('01bd').to.be.equal( 181 | uint8array_to_hex(modPow(base, exponent, modulus)) 182 | ); 183 | }); 184 | 185 | it('modPow() - Fermat - 3 ^ 65535 mod 65537', () => { 186 | const prime = new Uint8Array([0x00, 0x01, 0x00, 0x01]); // 65537 187 | const pMinus2 = new Uint8Array([0x00, 0x00, 0xff, 0xff]); // 65535 188 | const three = new Uint8Array([0x00, 0x00, 0x00, 0x03]); 189 | expect(uint8array_to_hex(modPow(three, pMinus2, prime))) 190 | .to.be.equal('00005556'); 191 | }); 192 | it('modPow() - Fermat - 5 ^ 65535 mod 65537', () => { 193 | const prime = new Uint8Array([0x00, 0x01, 0x00, 0x01]); // 65537 194 | const pMinus2 = new Uint8Array([0x00, 0x00, 0xff, 0xff]); // 65535 195 | const five = new Uint8Array([0x00, 0x00, 0x00, 0x05]); 196 | 197 | expect(uint8array_to_hex(modPow(five, pMinus2, prime))) 198 | .to.be.equal('00006667'); 199 | }); 200 | 201 | it('modPow() - Fermat - 32767 ^ 65535 mod 65537', () => { 202 | const prime = new Uint8Array([0x00, 0x01, 0x00, 0x01]); // 65537 203 | const pMinus2 = new Uint8Array([0x00, 0x00, 0xff, 0xff]); // 65535 204 | const half = new Uint8Array([0x00, 0x00, 0x7f, 0xff]); 205 | 206 | expect(uint8array_to_hex(modPow(half, pMinus2, prime))) 207 | .to.be.equal('00005555'); 208 | }); 209 | it('modPow() - Fermat - 32768 ^ 65535 mod 65537', () => { 210 | const prime = new Uint8Array([0x00, 0x01, 0x00, 0x01]); // 65537 211 | const pMinus2 = new Uint8Array([0x00, 0x00, 0xff, 0xff]); // 65535 212 | const halfUpper = new Uint8Array([0x00, 0x00, 0x80, 0x00]); 213 | expect(uint8array_to_hex(modPow(halfUpper, pMinus2, prime))) 214 | .to.be.equal('0000ffff'); 215 | }); 216 | 217 | it('modulo()', () => { 218 | expect('00000000001e').to.be.equal( 219 | uint8array_to_hex( 220 | modulo( 221 | new Uint8Array([0, 0, 0, 0, 4, 0]), 222 | new Uint8Array([0, 0, 0, 0, 1, 241]) 223 | ) 224 | ) 225 | ); 226 | expect('00000001').to.be.equal( 227 | uint8array_to_hex( 228 | modulo( 229 | new Uint8Array([0xFF, 0xFF, 0xFF, 0xFF]), 230 | new Uint8Array([0x00, 0x00, 0x00, 0x02]) 231 | ) 232 | ) 233 | ); 234 | expect('00000003').to.be.equal( 235 | uint8array_to_hex( 236 | modulo( 237 | new Uint8Array([0xFF, 0xFF, 0xFF, 0xFF]), 238 | new Uint8Array([0x00, 0x00, 0x00, 0x04]) 239 | ) 240 | ) 241 | ); 242 | expect('0000fff9').to.be.equal( 243 | uint8array_to_hex( 244 | modulo( 245 | new Uint8Array([0x04, 0x08, 0x04, 0x00]), 246 | new Uint8Array([0x00, 0x01, 0x00, 0x01]) 247 | ) 248 | ) 249 | ); 250 | expect('00000000001e').to.be.equal( 251 | uint8array_to_hex( 252 | modulo( 253 | new Uint8Array([0, 0, 0, 0, 4, 0]), 254 | new Uint8Array([0, 0, 0, 0, 1, 241]) 255 | ) 256 | ) 257 | ); 258 | 259 | }); 260 | 261 | it('multiply()', () => { 262 | const a = new Uint8Array([0x31, 0x41]); 263 | const b = new Uint8Array([0x59, 0x65]); 264 | const one = new Uint8Array([0x00, 0x01]); 265 | const two = new Uint8Array([0x00, 0x02]); 266 | expect(uint8array_to_hex(multiply(a, one))) 267 | .to.be.equal('00003141'); 268 | expect(uint8array_to_hex(multiply(a, two))) 269 | .to.be.equal('00006282'); 270 | expect(uint8array_to_hex(multiply(a, b))) 271 | .to.be.equal('113307a5'); 272 | expect(uint8array_to_hex(multiply(b, a))) 273 | .to.be.equal('113307a5'); 274 | expect(uint8array_to_hex(multiply(a, a))) 275 | .to.be.equal('0979f281'); 276 | }); 277 | 278 | it('or()', () => { 279 | const a = new Uint8Array([0x00, 0x31, 0x41]); 280 | expect(uint8array_to_hex(normalize(a, 8))) 281 | .to.be.equal('0000000000003141'); 282 | expect(uint8array_to_hex(normalize(a, 3))) 283 | .to.be.equal('003141'); 284 | expect(uint8array_to_hex(normalize(a, 2))) 285 | .to.be.equal('3141'); 286 | 287 | const b = new Uint8Array([0xff, 0xff, 0x3e]); 288 | expect(uint8array_to_hex(normalize(b, 8))) 289 | .to.be.equal('ffffffffffffff3e'); 290 | }); 291 | 292 | it('or()', () => { 293 | const a = new Uint8Array([0x31, 0x41]); 294 | const b = new Uint8Array([0x59, 0x65]); 295 | expect(uint8array_to_hex(or(a, b))) 296 | .to.be.equal('7965'); 297 | }); 298 | 299 | it('pow()', () => { 300 | const a = new Uint8Array([0x00, 0x00, 0x00, 0x07]); 301 | const n = new Uint8Array([0x00, 0x00, 0x00, 0x03]); 302 | expect(uint8array_to_hex(pow(a, n))) 303 | .to.be.equal('0157'); 304 | }); 305 | 306 | it('rshift1()', () => { 307 | const a = new Uint8Array([0x62, 0x82, 0xb2, 0xca]); 308 | rshift1(a); 309 | expect(uint8array_to_hex(a)).to.be.equal('31415965'); 310 | rshift1(a); 311 | expect(uint8array_to_hex(a)).to.be.equal('18a0acb2'); 312 | rshift1(a); 313 | expect(uint8array_to_hex(a)).to.be.equal('0c505659'); 314 | rshift1(a); 315 | expect(uint8array_to_hex(a)).to.be.equal('06282b2c'); 316 | rshift1(a); 317 | expect(uint8array_to_hex(a)).to.be.equal('03141596'); 318 | 319 | const b = new Uint8Array([0x00, 0xff, 0xff, 0x00]); 320 | rshift1(b); 321 | expect(uint8array_to_hex(b)).to.be.equal('007fff80'); 322 | }); 323 | 324 | it('shift_left()', () => { 325 | const a = new Uint8Array([0x31, 0x41, 0x59, 0x65]); 326 | expect(uint8array_to_hex(shift_left(a, 1n))) 327 | .to.be.equal('6282b2ca'); 328 | expect(uint8array_to_hex(shift_left(a, 2n))) 329 | .to.be.equal('c5056594'); 330 | expect(uint8array_to_hex(shift_left(a, 3n))) 331 | .to.be.equal('8a0acb28'); 332 | expect(uint8array_to_hex(shift_left(a, 4n))) 333 | .to.be.equal('14159650'); 334 | expect(uint8array_to_hex(shift_left(a, 8n))) 335 | .to.be.equal('41596500'); 336 | expect(uint8array_to_hex(shift_left(a, 9n))) 337 | .to.be.equal('82b2ca00'); 338 | expect(uint8array_to_hex(shift_left(a, 16n))) 339 | .to.be.equal('59650000'); 340 | expect(uint8array_to_hex(shift_left(a, 24n))) 341 | .to.be.equal('65000000'); 342 | const b = new Uint8Array([0x00, 0x00, 0x31, 0x41, 0x59, 0x65, 0x00, 0x00]); 343 | expect(uint8array_to_hex(shift_left(b, 1n))) 344 | .to.be.equal('00006282b2ca0000'); 345 | expect(uint8array_to_hex(shift_left(b, 2n))) 346 | .to.be.equal('0000c50565940000'); 347 | expect(uint8array_to_hex(shift_left(b, 3n))) 348 | .to.be.equal('00018a0acb280000'); 349 | expect(uint8array_to_hex(shift_left(b, 4n))) 350 | .to.be.equal('0003141596500000'); 351 | expect(uint8array_to_hex(shift_left(b, 8n))) 352 | .to.be.equal('0031415965000000'); 353 | expect(uint8array_to_hex(shift_left(b, 9n))) 354 | .to.be.equal('006282b2ca000000'); 355 | expect(uint8array_to_hex(shift_left(b, 16n))) 356 | .to.be.equal('3141596500000000'); 357 | expect(uint8array_to_hex(shift_left(b, 24n))) 358 | .to.be.equal('4159650000000000'); 359 | }); 360 | 361 | it('shift_right()', () => { 362 | const a = new Uint8Array([0x31, 0x41, 0x59, 0x65]); 363 | expect(uint8array_to_hex(shift_right(a, 1n))) 364 | .to.be.equal('18a0acb2'); 365 | const b = new Uint8Array([0x00, 0x00, 0x31, 0x41, 0x59, 0x65, 0x00, 0x00]); 366 | expect(uint8array_to_hex(shift_right(b, 1n))) 367 | .to.be.equal('000018a0acb28000'); 368 | expect(uint8array_to_hex(shift_right(b, 2n))) 369 | .to.be.equal('00000c5056594000'); 370 | expect(uint8array_to_hex(shift_right(b, 3n))) 371 | .to.be.equal('000006282b2ca000'); 372 | expect(uint8array_to_hex(shift_right(b, 4n))) 373 | .to.be.equal('0000031415965000'); 374 | }); 375 | 376 | it('sub()', () => { 377 | const a = new Uint8Array([0x8a, 0xa6]); 378 | const b = new Uint8Array([0x59, 0x65]); 379 | expect(uint8array_to_hex(sub(a, b))) 380 | .to.be.equal('3141'); 381 | 382 | const c = new Uint8Array([0x01, 0x02, 0x03, 0x04]); 383 | const d = new Uint8Array([0x7f, 0xff, 0xff, 0xff]); 384 | expect(uint8array_to_hex(sub(c, d))) 385 | .to.be.equal('81020305'); 386 | }); 387 | 388 | it('xor()', () => { 389 | const a = new Uint8Array([0x31, 0x41]); 390 | const b = new Uint8Array([0x59, 0x65]); 391 | expect(uint8array_to_hex(xor(a, b))) 392 | .to.be.equal('6824'); 393 | }); 394 | }); 395 | -------------------------------------------------------------------------------- /tests/compare.test.ts: -------------------------------------------------------------------------------- 1 | import { compare, compare_ints } from '../lib/compare'; 2 | import { expect } from 'chai'; 3 | import 'mocha'; 4 | 5 | describe('Constant-Time Comparison', () => { 6 | it('compare()', () => { 7 | const A = new Uint8Array([0x12, 0x34, 0x56, 0x78]); 8 | const B = new Uint8Array([0x12, 0x34, 0x56, 0x79]); 9 | const C = new Uint8Array([0x12, 0x34, 0x56, 0x7A]); 10 | 11 | expect(compare(A, A)).to.be.equal(0); 12 | expect(compare(B, A)).to.be.equal(1); 13 | expect(compare(C, A)).to.be.equal(1); 14 | 15 | expect(compare(A, B)).to.be.equal(-1); 16 | expect(compare(B, B)).to.be.equal(0); 17 | expect(compare(C, B)).to.be.equal(1); 18 | 19 | expect(compare(A, C)).to.be.equal(-1); 20 | expect(compare(B, C)).to.be.equal(-1); 21 | expect(compare(C, C)).to.be.equal(0); 22 | 23 | const D = new Uint8Array([0x00, 0x00, 0x00, 0x03]); 24 | const E = new Uint8Array([0x00, 0x01, 0x00, 0x01]); 25 | expect(compare(D, E)).to.be.equal(-1); 26 | expect(compare(D, D)).to.be.equal(0); 27 | expect(compare(E, E)).to.be.equal(0); 28 | expect(compare(E, D)).to.be.equal(1); 29 | }); 30 | 31 | it('compare_ints()', () => { 32 | const A = 0x1234; 33 | const B = 0x1235; 34 | const C = 0x1236; 35 | 36 | expect(compare_ints(A, A)).to.be.equal(0); 37 | expect(compare_ints(B, A)).to.be.equal(1); 38 | expect(compare_ints(C, A)).to.be.equal(1); 39 | 40 | expect(compare_ints(A, B)).to.be.equal(-1); 41 | expect(compare_ints(B, B)).to.be.equal(0); 42 | expect(compare_ints(C, B)).to.be.equal(1); 43 | 44 | expect(compare_ints(A, C)).to.be.equal(-1); 45 | expect(compare_ints(B, C)).to.be.equal(-1); 46 | expect(compare_ints(C, C)).to.be.equal(0); 47 | }); 48 | 49 | it('compare_ints() big', () => { 50 | const SMOL = 0x12345678; 51 | const CHUNGUS = 0x7fffffff; 52 | const MAX = 0xffffffff; 53 | 54 | expect(compare_ints(MAX, MAX)).to.be.equal(0); 55 | expect(compare_ints(CHUNGUS, MAX)).to.be.equal(-1); 56 | expect(compare_ints(SMOL, MAX)).to.be.equal(-1); 57 | 58 | expect(compare_ints(MAX, CHUNGUS)).to.be.equal(1); 59 | expect(compare_ints(CHUNGUS, CHUNGUS)).to.be.equal(0); 60 | expect(compare_ints(SMOL, CHUNGUS)).to.be.equal(-1); 61 | 62 | expect(compare_ints(MAX, SMOL)).to.be.equal(1); 63 | expect(compare_ints(CHUNGUS, SMOL)).to.be.equal(1); 64 | expect(compare_ints(SMOL, SMOL)).to.be.equal(0); 65 | }) 66 | }); 67 | -------------------------------------------------------------------------------- /tests/equals.test.ts: -------------------------------------------------------------------------------- 1 | import { equals, hmac_equals } from '../lib/equals'; 2 | import { expect } from 'chai'; 3 | import 'mocha'; 4 | import * as crypto from 'crypto'; 5 | 6 | describe('Constant-Time Equality', () => { 7 | it('equals()', () => { 8 | const buf1 = crypto.randomBytes(32); 9 | const buf2 = crypto.randomBytes(32); 10 | expect(equals(buf1, buf1)).to.be.equals(true); 11 | expect(equals(buf1, buf2)).to.be.equals(false); 12 | expect(equals(buf2, buf1)).to.be.equals(false); 13 | expect(equals(buf2, buf2)).to.be.equals(true); 14 | }); 15 | 16 | it('hmac_equals()', () => { 17 | const buf1 = crypto.randomBytes(32); 18 | const buf2 = crypto.randomBytes(32); 19 | expect(hmac_equals(buf1, buf1)).to.be.equals(true); 20 | expect(hmac_equals(buf1, buf2)).to.be.equals(false); 21 | expect(hmac_equals(buf2, buf1)).to.be.equals(false); 22 | expect(hmac_equals(buf2, buf2)).to.be.equals(true); 23 | }); 24 | }); 25 | -------------------------------------------------------------------------------- /tests/int32.test.ts: -------------------------------------------------------------------------------- 1 | import { int32 } from '../lib/int32'; 2 | import { expect } from 'chai'; 3 | import 'mocha'; 4 | 5 | describe('Int32', () => { 6 | it('add()', () => { 7 | expect(int32.fromInt(0xffffffff).add(1).toHex()) 8 | .to.be.equal('00000000'); 9 | expect(int32.fromInt(0x7fffffff).add(1).toHex()) 10 | .to.be.equal('80000000'); 11 | const x: int32 = int32.fromInt(0x7fff); 12 | expect(x.add(2).toHex()) 13 | .to.be.equal('00008001'); 14 | expect(x.add(x).toHex()) 15 | .to.be.equal('0000fffe'); 16 | }); 17 | 18 | it('and()', () => { 19 | expect(int32.fromInt(0xffff).and(1 << 16).toHex()) 20 | .to.be.equal('00000000'); 21 | expect(int32.fromInt(0xffff).and(1 << 15).toHex()) 22 | .to.be.equal('00008000'); 23 | const y: int32 = new int32(0xffff, 0xffff); 24 | const z: int32 = int32.fromInt(0x12345678); 25 | expect(z.and(y).toHex()).to.be.equal('12345678') 26 | }); 27 | 28 | it('compare()', () => { 29 | const x: int32 = new int32(0x5678, 0x1234); 30 | const y: int32 = new int32(0x5679, 0x1234); 31 | const z: int32 = new int32(0xffff, 0x7fff); 32 | 33 | expect(x.compare(x).toNumber()).to.be.equal(0); 34 | expect(y.compare(x).toNumber()).to.be.equal(1); 35 | expect(z.compare(x).toNumber()).to.be.equal(1); 36 | expect(x.compare(y).toNumber()).to.be.equal(-1); 37 | expect(y.compare(y).toNumber()).to.be.equal(0); 38 | expect(z.compare(y).toNumber()).to.be.equal(1); 39 | expect(x.compare(z).toNumber()).to.be.equal(-1); 40 | expect(y.compare(z).toNumber()).to.be.equal(-1); 41 | expect(z.compare(z).toNumber()).to.be.equal(0); 42 | }); 43 | 44 | it('msb()', () => { 45 | expect(int32.fromInt(0x7fffffff).msb()) 46 | .to.be.equal(0); 47 | expect(int32.fromInt(0x8fffffff).msb()) 48 | .to.be.equal(1); 49 | expect(int32.fromInt(0xffffffff).msb()) 50 | .to.be.equal(1); 51 | expect(int32.fromInt(-1).msb()) 52 | .to.be.equal(1); 53 | }); 54 | 55 | it('lshift()', () => { 56 | let a: int32 = int32.fromInt(0x12345678); 57 | expect(a.lshift(4).toNumber()) 58 | .to.be.equal(0x23456780); 59 | expect(a.lshift(8).toNumber()) 60 | .to.be.equal(0x34567800); 61 | expect(a.lshift(16).toNumber()) 62 | .to.be.equal(0x56780000); 63 | expect(a.lshift(24).toNumber()) 64 | .to.be.equal(0x78000000); 65 | expect(a.lshift(28).toNumber()) 66 | .to.be.equal(0x80000000|0); 67 | expect(a.lshift(32).toNumber()) 68 | .to.be.equal(0); 69 | }); 70 | 71 | it('not()', () => { 72 | const z: int32 = int32.fromInt(0x12345678); 73 | expect(z.not().toHex()).to.be.equal('edcba987'); 74 | expect(z.toHex()).to.be.equal('12345678'); 75 | }); 76 | 77 | it('or()', () => { 78 | expect(int32.fromInt(0xffff).or(1 << 16).toHex()) 79 | .to.be.equal('0001ffff'); 80 | const y: int32 = new int32(0xffff, 0xffff); 81 | const z: int32 = int32.fromInt(0x12345678); 82 | expect(z.or(y).toHex()).to.be.equal('ffffffff') 83 | }); 84 | 85 | it('rshift()', () => { 86 | let a: int32 = int32.fromInt(0x12345678); 87 | expect(a.rshift(4).toNumber()) 88 | .to.be.equal(0x01234567); 89 | expect(a.rshift(8).toNumber()) 90 | .to.be.equal(0x00123456); 91 | expect(a.rshift(16).toNumber()) 92 | .to.be.equal(0x00001234); 93 | expect(a.rshift(24).toNumber()) 94 | .to.be.equal(0x00000012); 95 | expect(a.rshift(28).toNumber()) 96 | .to.be.equal(0x00000001); 97 | expect(a.rshift(32).toNumber()) 98 | .to.be.equal(0); 99 | }); 100 | 101 | it('sub()', () => { 102 | const x: int32 = int32.fromInt(0x7fff); 103 | const y: int32 = int32.fromInt(0x1234); 104 | const z: int32 = int32.fromInt(0x12345678); 105 | 106 | expect(x.sub(y).toHex()).to.be.equal('00006dcb'); 107 | expect(y.sub(x).toHex()).to.be.equal('ffff9235'); 108 | expect(z.sub(y).toHex()).to.be.equal('12344444'); 109 | expect(y.sub(z).toHex()).to.be.equal('edcbbbbc'); 110 | }); 111 | 112 | it('xor()', () => { 113 | expect(int32.fromInt(0x7fff).xor(0x1234).toHex()) 114 | .to.be.equal('00006dcb'); 115 | expect(int32.fromInt(0xffff).xor(1 << 16).toHex()) 116 | .to.be.equal('0001ffff'); 117 | 118 | const y: int32 = new int32(0xffff, 0xffff); 119 | const z: int32 = int32.fromInt(0x12345678); 120 | expect(z.xor(y).toHex()).to.be.equal('edcba987') 121 | }); 122 | }); 123 | -------------------------------------------------------------------------------- /tests/intdiv.test.ts: -------------------------------------------------------------------------------- 1 | import { intdiv, modulo } from '../lib/intdiv'; 2 | import { expect } from 'chai'; 3 | import 'mocha'; 4 | 5 | describe('Constant-Time Integer Division', () => { 6 | it('intdiv() and modulo()', () => { 7 | const testCases = [ 8 | {N: 3628800, D: 11, Q: 329890, R: 10}, 9 | {N: 3628800, D: 10, Q: 362880, R: 0}, 10 | {N: 3628800, D: 9, Q: 403200, R: 0}, 11 | {N: 3628800, D: 13, Q: 279138, R: 6}, 12 | ]; 13 | for (const test of testCases) { 14 | expect(test.Q * test.D + test.R).to.be.equal(test.N); 15 | expect(intdiv(test.N, test.D)).to.be.equal(test.Q); 16 | expect(modulo(test.N, test.D)).to.be.equal(test.R); 17 | } 18 | }); 19 | }); 20 | -------------------------------------------------------------------------------- /tests/resize.test.ts: -------------------------------------------------------------------------------- 1 | import { resize } from '../lib/resize'; 2 | import { expect } from 'chai'; 3 | import 'mocha'; 4 | import * as crypto from 'crypto'; 5 | import { uint8array_to_hex } from './test-helper'; 6 | 7 | describe('Constant-Time Buffer Resizing', () => { 8 | it('resize()', () => { 9 | const inBuf = crypto.randomBytes(32); 10 | for (let i = 1; i < 32; i++) { 11 | const left = resize(inBuf, i); 12 | const right = inBuf.slice(0, i); 13 | expect(uint8array_to_hex(left)) 14 | .to.be.equal(uint8array_to_hex(right), `i = ${i}`); 15 | } 16 | }); 17 | }); 18 | -------------------------------------------------------------------------------- /tests/select.test.ts: -------------------------------------------------------------------------------- 1 | import { select, select_ints } from '../lib/select'; 2 | import { expect } from 'chai'; 3 | import 'mocha'; 4 | import { uint8array_to_hex } from './test-helper'; 5 | 6 | describe('Constant-Time Selection', () => { 7 | it('select()', () => { 8 | const left = new Uint8Array([0x31, 0x32, 0x33, 0x34]); 9 | const right = new Uint8Array([0x35, 0x36, 0x37, 0x38]); 10 | expect(uint8array_to_hex(select(true, left, right))) 11 | .to.be.equal(uint8array_to_hex(left)); 12 | expect(uint8array_to_hex(select(false, left, right))) 13 | .to.be.equal(uint8array_to_hex(right)); 14 | expect(uint8array_to_hex(select(false, right, left))) 15 | .to.be.equal(uint8array_to_hex(left)); 16 | expect(uint8array_to_hex(select(true, right, left))) 17 | .to.be.equal(uint8array_to_hex(right)); 18 | }) 19 | 20 | it('select_ints()', () => { 21 | expect(select_ints(0, 0xBEEF, 0xCAFE)) 22 | .to.be.equal(0xCAFE); 23 | expect(select_ints(1, 0xBEEF, 0xCAFE)) 24 | .to.be.equal(0xBEEF); 25 | expect(select_ints(1, 0xBEEFCAFE, 0)) 26 | .to.be.equal(0xBEEFCAFE | 0); 27 | expect(select_ints(0, 0xBEEFCAFE, 0)) 28 | .to.be.equal(0); 29 | }) 30 | }); 31 | -------------------------------------------------------------------------------- /tests/test-helper.ts: -------------------------------------------------------------------------------- 1 | export function uint8array_to_hex(input: Uint8Array): string { 2 | return Buffer.from(input).toString('hex'); 3 | } 4 | -------------------------------------------------------------------------------- /tests/trim.test.ts: -------------------------------------------------------------------------------- 1 | import { trim_zeroes_left, trim_zeroes_right } from '../lib/trim'; 2 | import { expect } from 'chai'; 3 | import 'mocha'; 4 | import { uint8array_to_hex } from './test-helper'; 5 | 6 | describe('Constant-Time Trim', () => { 7 | it('trim_zeroes_left()', () => { 8 | const before = new Uint8Array([ 9 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0xEC, 0xAF, 0xC0, 0xFF, 0xEE 10 | ]); 11 | const after = new Uint8Array([ 12 | 0x0D, 0xEC, 0xAF, 0xC0, 0xFF, 0xEE 13 | ]); 14 | expect(uint8array_to_hex(trim_zeroes_left(before))) 15 | .to.be.equal(uint8array_to_hex(after)); 16 | }); 17 | it('trim_zeroes_right()', () => { 18 | const before = new Uint8Array([ 19 | 0x0D, 0xEC, 0xAF, 0xC0, 0xFF, 0xEE, 0x00, 0x00, 0x00, 0x00, 0x00 20 | ]); 21 | const after = new Uint8Array([ 22 | 0x0D, 0xEC, 0xAF, 0xC0, 0xFF, 0xEE 23 | ]); 24 | expect(uint8array_to_hex(trim_zeroes_right(before))) 25 | .to.be.equal(uint8array_to_hex(after)); 26 | }); 27 | }); 28 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "allowSyntheticDefaultImports": true, 4 | "lib": ["ES2020"], 5 | "target": "ES2020", 6 | "baseUrl": ".", 7 | "paths": { 8 | "*": ["*", "generated/*"] 9 | } 10 | } 11 | } 12 | --------------------------------------------------------------------------------