11cb0ef41Sopenharmony_ci'use strict';
21cb0ef41Sopenharmony_ci
31cb0ef41Sopenharmony_ciconst {
41cb0ef41Sopenharmony_ci  Array,
51cb0ef41Sopenharmony_ci  ArrayBufferPrototypeGetByteLength,
61cb0ef41Sopenharmony_ci  ArrayPrototypeForEach,
71cb0ef41Sopenharmony_ci  ArrayPrototypePush,
81cb0ef41Sopenharmony_ci  ArrayPrototypeShift,
91cb0ef41Sopenharmony_ci  ArrayPrototypeSplice,
101cb0ef41Sopenharmony_ci  BigInt,
111cb0ef41Sopenharmony_ci  BigIntPrototypeToString,
121cb0ef41Sopenharmony_ci  DataView,
131cb0ef41Sopenharmony_ci  DataViewPrototypeGetUint8,
141cb0ef41Sopenharmony_ci  FunctionPrototypeBind,
151cb0ef41Sopenharmony_ci  FunctionPrototypeCall,
161cb0ef41Sopenharmony_ci  MathMin,
171cb0ef41Sopenharmony_ci  NumberIsNaN,
181cb0ef41Sopenharmony_ci  NumberIsSafeInteger,
191cb0ef41Sopenharmony_ci  NumberPrototypeToString,
201cb0ef41Sopenharmony_ci  StringFromCharCodeApply,
211cb0ef41Sopenharmony_ci  StringPrototypePadStart,
221cb0ef41Sopenharmony_ci} = primordials;
231cb0ef41Sopenharmony_ci
241cb0ef41Sopenharmony_ciconst {
251cb0ef41Sopenharmony_ci  RandomBytesJob,
261cb0ef41Sopenharmony_ci  RandomPrimeJob,
271cb0ef41Sopenharmony_ci  CheckPrimeJob,
281cb0ef41Sopenharmony_ci  kCryptoJobAsync,
291cb0ef41Sopenharmony_ci  kCryptoJobSync,
301cb0ef41Sopenharmony_ci  secureBuffer,
311cb0ef41Sopenharmony_ci} = internalBinding('crypto');
321cb0ef41Sopenharmony_ci
331cb0ef41Sopenharmony_ciconst {
341cb0ef41Sopenharmony_ci  kEmptyObject,
351cb0ef41Sopenharmony_ci  lazyDOMException,
361cb0ef41Sopenharmony_ci} = require('internal/util');
371cb0ef41Sopenharmony_ci
381cb0ef41Sopenharmony_ciconst { Buffer, kMaxLength } = require('buffer');
391cb0ef41Sopenharmony_ci
401cb0ef41Sopenharmony_ciconst {
411cb0ef41Sopenharmony_ci  codes: {
421cb0ef41Sopenharmony_ci    ERR_INVALID_ARG_TYPE,
431cb0ef41Sopenharmony_ci    ERR_MISSING_ARGS,
441cb0ef41Sopenharmony_ci    ERR_OUT_OF_RANGE,
451cb0ef41Sopenharmony_ci    ERR_OPERATION_FAILED,
461cb0ef41Sopenharmony_ci  },
471cb0ef41Sopenharmony_ci} = require('internal/errors');
481cb0ef41Sopenharmony_ci
491cb0ef41Sopenharmony_ciconst {
501cb0ef41Sopenharmony_ci  validateNumber,
511cb0ef41Sopenharmony_ci  validateBoolean,
521cb0ef41Sopenharmony_ci  validateFunction,
531cb0ef41Sopenharmony_ci  validateInt32,
541cb0ef41Sopenharmony_ci  validateObject,
551cb0ef41Sopenharmony_ci} = require('internal/validators');
561cb0ef41Sopenharmony_ci
571cb0ef41Sopenharmony_ciconst {
581cb0ef41Sopenharmony_ci  isArrayBufferView,
591cb0ef41Sopenharmony_ci  isAnyArrayBuffer,
601cb0ef41Sopenharmony_ci  isTypedArray,
611cb0ef41Sopenharmony_ci  isFloat32Array,
621cb0ef41Sopenharmony_ci  isFloat64Array,
631cb0ef41Sopenharmony_ci} = require('internal/util/types');
641cb0ef41Sopenharmony_ci
651cb0ef41Sopenharmony_ciconst { FastBuffer } = require('internal/buffer');
661cb0ef41Sopenharmony_ci
671cb0ef41Sopenharmony_ciconst kMaxInt32 = 2 ** 31 - 1;
681cb0ef41Sopenharmony_ciconst kMaxPossibleLength = MathMin(kMaxLength, kMaxInt32);
691cb0ef41Sopenharmony_ci
701cb0ef41Sopenharmony_cifunction assertOffset(offset, elementSize, length) {
711cb0ef41Sopenharmony_ci  validateNumber(offset, 'offset');
721cb0ef41Sopenharmony_ci  offset *= elementSize;
731cb0ef41Sopenharmony_ci
741cb0ef41Sopenharmony_ci  const maxLength = MathMin(length, kMaxPossibleLength);
751cb0ef41Sopenharmony_ci  if (NumberIsNaN(offset) || offset > maxLength || offset < 0) {
761cb0ef41Sopenharmony_ci    throw new ERR_OUT_OF_RANGE('offset', `>= 0 && <= ${maxLength}`, offset);
771cb0ef41Sopenharmony_ci  }
781cb0ef41Sopenharmony_ci
791cb0ef41Sopenharmony_ci  return offset >>> 0;  // Convert to uint32.
801cb0ef41Sopenharmony_ci}
811cb0ef41Sopenharmony_ci
821cb0ef41Sopenharmony_cifunction assertSize(size, elementSize, offset, length) {
831cb0ef41Sopenharmony_ci  validateNumber(size, 'size');
841cb0ef41Sopenharmony_ci  size *= elementSize;
851cb0ef41Sopenharmony_ci
861cb0ef41Sopenharmony_ci  if (NumberIsNaN(size) || size > kMaxPossibleLength || size < 0) {
871cb0ef41Sopenharmony_ci    throw new ERR_OUT_OF_RANGE('size',
881cb0ef41Sopenharmony_ci                               `>= 0 && <= ${kMaxPossibleLength}`, size);
891cb0ef41Sopenharmony_ci  }
901cb0ef41Sopenharmony_ci
911cb0ef41Sopenharmony_ci  if (size + offset > length) {
921cb0ef41Sopenharmony_ci    throw new ERR_OUT_OF_RANGE('size + offset', `<= ${length}`, size + offset);
931cb0ef41Sopenharmony_ci  }
941cb0ef41Sopenharmony_ci
951cb0ef41Sopenharmony_ci  return size >>> 0;  // Convert to uint32.
961cb0ef41Sopenharmony_ci}
971cb0ef41Sopenharmony_ci
981cb0ef41Sopenharmony_cifunction randomBytes(size, callback) {
991cb0ef41Sopenharmony_ci  size = assertSize(size, 1, 0, Infinity);
1001cb0ef41Sopenharmony_ci  if (callback !== undefined) {
1011cb0ef41Sopenharmony_ci    validateFunction(callback, 'callback');
1021cb0ef41Sopenharmony_ci  }
1031cb0ef41Sopenharmony_ci
1041cb0ef41Sopenharmony_ci  const buf = new FastBuffer(size);
1051cb0ef41Sopenharmony_ci
1061cb0ef41Sopenharmony_ci  if (callback === undefined) {
1071cb0ef41Sopenharmony_ci    randomFillSync(buf.buffer, 0, size);
1081cb0ef41Sopenharmony_ci    return buf;
1091cb0ef41Sopenharmony_ci  }
1101cb0ef41Sopenharmony_ci
1111cb0ef41Sopenharmony_ci  // Keep the callback as a regular function so this is propagated.
1121cb0ef41Sopenharmony_ci  randomFill(buf.buffer, 0, size, function(error) {
1131cb0ef41Sopenharmony_ci    if (error) return FunctionPrototypeCall(callback, this, error);
1141cb0ef41Sopenharmony_ci    FunctionPrototypeCall(callback, this, null, buf);
1151cb0ef41Sopenharmony_ci  });
1161cb0ef41Sopenharmony_ci}
1171cb0ef41Sopenharmony_ci
1181cb0ef41Sopenharmony_cifunction randomFillSync(buf, offset = 0, size) {
1191cb0ef41Sopenharmony_ci  if (!isAnyArrayBuffer(buf) && !isArrayBufferView(buf)) {
1201cb0ef41Sopenharmony_ci    throw new ERR_INVALID_ARG_TYPE(
1211cb0ef41Sopenharmony_ci      'buf',
1221cb0ef41Sopenharmony_ci      ['ArrayBuffer', 'ArrayBufferView'],
1231cb0ef41Sopenharmony_ci      buf);
1241cb0ef41Sopenharmony_ci  }
1251cb0ef41Sopenharmony_ci
1261cb0ef41Sopenharmony_ci  const elementSize = buf.BYTES_PER_ELEMENT || 1;
1271cb0ef41Sopenharmony_ci
1281cb0ef41Sopenharmony_ci  offset = assertOffset(offset, elementSize, buf.byteLength);
1291cb0ef41Sopenharmony_ci
1301cb0ef41Sopenharmony_ci  if (size === undefined) {
1311cb0ef41Sopenharmony_ci    size = buf.byteLength - offset;
1321cb0ef41Sopenharmony_ci  } else {
1331cb0ef41Sopenharmony_ci    size = assertSize(size, elementSize, offset, buf.byteLength);
1341cb0ef41Sopenharmony_ci  }
1351cb0ef41Sopenharmony_ci
1361cb0ef41Sopenharmony_ci  if (size === 0)
1371cb0ef41Sopenharmony_ci    return buf;
1381cb0ef41Sopenharmony_ci
1391cb0ef41Sopenharmony_ci  const job = new RandomBytesJob(
1401cb0ef41Sopenharmony_ci    kCryptoJobSync,
1411cb0ef41Sopenharmony_ci    buf,
1421cb0ef41Sopenharmony_ci    offset,
1431cb0ef41Sopenharmony_ci    size);
1441cb0ef41Sopenharmony_ci
1451cb0ef41Sopenharmony_ci  const err = job.run()[0];
1461cb0ef41Sopenharmony_ci  if (err)
1471cb0ef41Sopenharmony_ci    throw err;
1481cb0ef41Sopenharmony_ci
1491cb0ef41Sopenharmony_ci  return buf;
1501cb0ef41Sopenharmony_ci}
1511cb0ef41Sopenharmony_ci
1521cb0ef41Sopenharmony_cifunction randomFill(buf, offset, size, callback) {
1531cb0ef41Sopenharmony_ci  if (!isAnyArrayBuffer(buf) && !isArrayBufferView(buf)) {
1541cb0ef41Sopenharmony_ci    throw new ERR_INVALID_ARG_TYPE(
1551cb0ef41Sopenharmony_ci      'buf',
1561cb0ef41Sopenharmony_ci      ['ArrayBuffer', 'ArrayBufferView'],
1571cb0ef41Sopenharmony_ci      buf);
1581cb0ef41Sopenharmony_ci  }
1591cb0ef41Sopenharmony_ci
1601cb0ef41Sopenharmony_ci  const elementSize = buf.BYTES_PER_ELEMENT || 1;
1611cb0ef41Sopenharmony_ci
1621cb0ef41Sopenharmony_ci  if (typeof offset === 'function') {
1631cb0ef41Sopenharmony_ci    callback = offset;
1641cb0ef41Sopenharmony_ci    offset = 0;
1651cb0ef41Sopenharmony_ci    // Size is a length here, assertSize() call turns it into a number of bytes
1661cb0ef41Sopenharmony_ci    size = buf.length;
1671cb0ef41Sopenharmony_ci  } else if (typeof size === 'function') {
1681cb0ef41Sopenharmony_ci    callback = size;
1691cb0ef41Sopenharmony_ci    size = buf.length - offset;
1701cb0ef41Sopenharmony_ci  } else {
1711cb0ef41Sopenharmony_ci    validateFunction(callback, 'callback');
1721cb0ef41Sopenharmony_ci  }
1731cb0ef41Sopenharmony_ci
1741cb0ef41Sopenharmony_ci  offset = assertOffset(offset, elementSize, buf.byteLength);
1751cb0ef41Sopenharmony_ci
1761cb0ef41Sopenharmony_ci  if (size === undefined) {
1771cb0ef41Sopenharmony_ci    size = buf.byteLength - offset;
1781cb0ef41Sopenharmony_ci  } else {
1791cb0ef41Sopenharmony_ci    size = assertSize(size, elementSize, offset, buf.byteLength);
1801cb0ef41Sopenharmony_ci  }
1811cb0ef41Sopenharmony_ci
1821cb0ef41Sopenharmony_ci  if (size === 0) {
1831cb0ef41Sopenharmony_ci    callback(null, buf);
1841cb0ef41Sopenharmony_ci    return;
1851cb0ef41Sopenharmony_ci  }
1861cb0ef41Sopenharmony_ci
1871cb0ef41Sopenharmony_ci  const job = new RandomBytesJob(
1881cb0ef41Sopenharmony_ci    kCryptoJobAsync,
1891cb0ef41Sopenharmony_ci    buf,
1901cb0ef41Sopenharmony_ci    offset,
1911cb0ef41Sopenharmony_ci    size);
1921cb0ef41Sopenharmony_ci  job.ondone = FunctionPrototypeBind(onJobDone, job, buf, callback);
1931cb0ef41Sopenharmony_ci  job.run();
1941cb0ef41Sopenharmony_ci}
1951cb0ef41Sopenharmony_ci
1961cb0ef41Sopenharmony_ci// Largest integer we can read from a buffer.
1971cb0ef41Sopenharmony_ci// e.g.: Buffer.from("ff".repeat(6), "hex").readUIntBE(0, 6);
1981cb0ef41Sopenharmony_ciconst RAND_MAX = 0xFFFF_FFFF_FFFF;
1991cb0ef41Sopenharmony_ci
2001cb0ef41Sopenharmony_ci// Cache random data to use in randomInt. The cache size must be evenly
2011cb0ef41Sopenharmony_ci// divisible by 6 because each attempt to obtain a random int uses 6 bytes.
2021cb0ef41Sopenharmony_ciconst randomCache = new FastBuffer(6 * 1024);
2031cb0ef41Sopenharmony_cilet randomCacheOffset = randomCache.length;
2041cb0ef41Sopenharmony_cilet asyncCacheFillInProgress = false;
2051cb0ef41Sopenharmony_ciconst asyncCachePendingTasks = [];
2061cb0ef41Sopenharmony_ci
2071cb0ef41Sopenharmony_ci// Generates an integer in [min, max) range where min is inclusive and max is
2081cb0ef41Sopenharmony_ci// exclusive.
2091cb0ef41Sopenharmony_cifunction randomInt(min, max, callback) {
2101cb0ef41Sopenharmony_ci  // Detect optional min syntax
2111cb0ef41Sopenharmony_ci  // randomInt(max)
2121cb0ef41Sopenharmony_ci  // randomInt(max, callback)
2131cb0ef41Sopenharmony_ci  const minNotSpecified = typeof max === 'undefined' ||
2141cb0ef41Sopenharmony_ci    typeof max === 'function';
2151cb0ef41Sopenharmony_ci
2161cb0ef41Sopenharmony_ci  if (minNotSpecified) {
2171cb0ef41Sopenharmony_ci    callback = max;
2181cb0ef41Sopenharmony_ci    max = min;
2191cb0ef41Sopenharmony_ci    min = 0;
2201cb0ef41Sopenharmony_ci  }
2211cb0ef41Sopenharmony_ci
2221cb0ef41Sopenharmony_ci  const isSync = typeof callback === 'undefined';
2231cb0ef41Sopenharmony_ci  if (!isSync) {
2241cb0ef41Sopenharmony_ci    validateFunction(callback, 'callback');
2251cb0ef41Sopenharmony_ci  }
2261cb0ef41Sopenharmony_ci  if (!NumberIsSafeInteger(min)) {
2271cb0ef41Sopenharmony_ci    throw new ERR_INVALID_ARG_TYPE('min', 'a safe integer', min);
2281cb0ef41Sopenharmony_ci  }
2291cb0ef41Sopenharmony_ci  if (!NumberIsSafeInteger(max)) {
2301cb0ef41Sopenharmony_ci    throw new ERR_INVALID_ARG_TYPE('max', 'a safe integer', max);
2311cb0ef41Sopenharmony_ci  }
2321cb0ef41Sopenharmony_ci  if (max <= min) {
2331cb0ef41Sopenharmony_ci    throw new ERR_OUT_OF_RANGE(
2341cb0ef41Sopenharmony_ci      'max', `greater than the value of "min" (${min})`, max,
2351cb0ef41Sopenharmony_ci    );
2361cb0ef41Sopenharmony_ci  }
2371cb0ef41Sopenharmony_ci
2381cb0ef41Sopenharmony_ci  // First we generate a random int between [0..range)
2391cb0ef41Sopenharmony_ci  const range = max - min;
2401cb0ef41Sopenharmony_ci
2411cb0ef41Sopenharmony_ci  if (!(range <= RAND_MAX)) {
2421cb0ef41Sopenharmony_ci    throw new ERR_OUT_OF_RANGE(`max${minNotSpecified ? '' : ' - min'}`,
2431cb0ef41Sopenharmony_ci                               `<= ${RAND_MAX}`, range);
2441cb0ef41Sopenharmony_ci  }
2451cb0ef41Sopenharmony_ci
2461cb0ef41Sopenharmony_ci  // For (x % range) to produce an unbiased value greater than or equal to 0 and
2471cb0ef41Sopenharmony_ci  // less than range, x must be drawn randomly from the set of integers greater
2481cb0ef41Sopenharmony_ci  // than or equal to 0 and less than randLimit.
2491cb0ef41Sopenharmony_ci  const randLimit = RAND_MAX - (RAND_MAX % range);
2501cb0ef41Sopenharmony_ci
2511cb0ef41Sopenharmony_ci  // If we don't have a callback, or if there is still data in the cache, we can
2521cb0ef41Sopenharmony_ci  // do this synchronously, which is super fast.
2531cb0ef41Sopenharmony_ci  while (isSync || (randomCacheOffset < randomCache.length)) {
2541cb0ef41Sopenharmony_ci    if (randomCacheOffset === randomCache.length) {
2551cb0ef41Sopenharmony_ci      // This might block the thread for a bit, but we are in sync mode.
2561cb0ef41Sopenharmony_ci      randomFillSync(randomCache);
2571cb0ef41Sopenharmony_ci      randomCacheOffset = 0;
2581cb0ef41Sopenharmony_ci    }
2591cb0ef41Sopenharmony_ci
2601cb0ef41Sopenharmony_ci    const x = randomCache.readUIntBE(randomCacheOffset, 6);
2611cb0ef41Sopenharmony_ci    randomCacheOffset += 6;
2621cb0ef41Sopenharmony_ci
2631cb0ef41Sopenharmony_ci    if (x < randLimit) {
2641cb0ef41Sopenharmony_ci      const n = (x % range) + min;
2651cb0ef41Sopenharmony_ci      if (isSync) return n;
2661cb0ef41Sopenharmony_ci      process.nextTick(callback, undefined, n);
2671cb0ef41Sopenharmony_ci      return;
2681cb0ef41Sopenharmony_ci    }
2691cb0ef41Sopenharmony_ci  }
2701cb0ef41Sopenharmony_ci
2711cb0ef41Sopenharmony_ci  // At this point, we are in async mode with no data in the cache. We cannot
2721cb0ef41Sopenharmony_ci  // simply refill the cache, because another async call to randomInt might
2731cb0ef41Sopenharmony_ci  // already be doing that. Instead, queue this call for when the cache has
2741cb0ef41Sopenharmony_ci  // been refilled.
2751cb0ef41Sopenharmony_ci  ArrayPrototypePush(asyncCachePendingTasks, { min, max, callback });
2761cb0ef41Sopenharmony_ci  asyncRefillRandomIntCache();
2771cb0ef41Sopenharmony_ci}
2781cb0ef41Sopenharmony_ci
2791cb0ef41Sopenharmony_cifunction asyncRefillRandomIntCache() {
2801cb0ef41Sopenharmony_ci  if (asyncCacheFillInProgress)
2811cb0ef41Sopenharmony_ci    return;
2821cb0ef41Sopenharmony_ci
2831cb0ef41Sopenharmony_ci  asyncCacheFillInProgress = true;
2841cb0ef41Sopenharmony_ci  randomFill(randomCache, (err) => {
2851cb0ef41Sopenharmony_ci    asyncCacheFillInProgress = false;
2861cb0ef41Sopenharmony_ci
2871cb0ef41Sopenharmony_ci    const tasks = asyncCachePendingTasks;
2881cb0ef41Sopenharmony_ci    const errorReceiver = err && ArrayPrototypeShift(tasks);
2891cb0ef41Sopenharmony_ci    if (!err)
2901cb0ef41Sopenharmony_ci      randomCacheOffset = 0;
2911cb0ef41Sopenharmony_ci
2921cb0ef41Sopenharmony_ci    // Restart all pending tasks. If an error occurred, we only notify a single
2931cb0ef41Sopenharmony_ci    // callback (errorReceiver) about it. This way, every async call to
2941cb0ef41Sopenharmony_ci    // randomInt has a chance of being successful, and it avoids complex
2951cb0ef41Sopenharmony_ci    // exception handling here.
2961cb0ef41Sopenharmony_ci    ArrayPrototypeForEach(ArrayPrototypeSplice(tasks, 0), (task) => {
2971cb0ef41Sopenharmony_ci      randomInt(task.min, task.max, task.callback);
2981cb0ef41Sopenharmony_ci    });
2991cb0ef41Sopenharmony_ci
3001cb0ef41Sopenharmony_ci    // This is the only call that might throw, and is therefore done at the end.
3011cb0ef41Sopenharmony_ci    if (errorReceiver)
3021cb0ef41Sopenharmony_ci      errorReceiver.callback(err);
3031cb0ef41Sopenharmony_ci  });
3041cb0ef41Sopenharmony_ci}
3051cb0ef41Sopenharmony_ci
3061cb0ef41Sopenharmony_ci
3071cb0ef41Sopenharmony_cifunction onJobDone(buf, callback, error) {
3081cb0ef41Sopenharmony_ci  if (error) return FunctionPrototypeCall(callback, this, error);
3091cb0ef41Sopenharmony_ci  FunctionPrototypeCall(callback, this, null, buf);
3101cb0ef41Sopenharmony_ci}
3111cb0ef41Sopenharmony_ci
3121cb0ef41Sopenharmony_ci// Really just the Web Crypto API alternative
3131cb0ef41Sopenharmony_ci// to require('crypto').randomFillSync() with an
3141cb0ef41Sopenharmony_ci// additional limitation that the input buffer is
3151cb0ef41Sopenharmony_ci// not allowed to exceed 65536 bytes, and can only
3161cb0ef41Sopenharmony_ci// be an integer-type TypedArray.
3171cb0ef41Sopenharmony_cifunction getRandomValues(data) {
3181cb0ef41Sopenharmony_ci  if (arguments.length < 1)
3191cb0ef41Sopenharmony_ci    throw new ERR_MISSING_ARGS('typedArray');
3201cb0ef41Sopenharmony_ci  if (!isTypedArray(data) ||
3211cb0ef41Sopenharmony_ci      isFloat32Array(data) ||
3221cb0ef41Sopenharmony_ci      isFloat64Array(data)) {
3231cb0ef41Sopenharmony_ci    // Ordinarily this would be an ERR_INVALID_ARG_TYPE. However,
3241cb0ef41Sopenharmony_ci    // the Web Crypto API and web platform tests expect this to
3251cb0ef41Sopenharmony_ci    // be a DOMException with type TypeMismatchError.
3261cb0ef41Sopenharmony_ci    throw lazyDOMException(
3271cb0ef41Sopenharmony_ci      'The data argument must be an integer-type TypedArray',
3281cb0ef41Sopenharmony_ci      'TypeMismatchError');
3291cb0ef41Sopenharmony_ci  }
3301cb0ef41Sopenharmony_ci  if (data.byteLength > 65536) {
3311cb0ef41Sopenharmony_ci    throw lazyDOMException(
3321cb0ef41Sopenharmony_ci      'The requested length exceeds 65,536 bytes',
3331cb0ef41Sopenharmony_ci      'QuotaExceededError');
3341cb0ef41Sopenharmony_ci  }
3351cb0ef41Sopenharmony_ci  randomFillSync(data, 0);
3361cb0ef41Sopenharmony_ci  return data;
3371cb0ef41Sopenharmony_ci}
3381cb0ef41Sopenharmony_ci
3391cb0ef41Sopenharmony_ci// Implements an RFC 4122 version 4 random UUID.
3401cb0ef41Sopenharmony_ci// To improve performance, random data is generated in batches
3411cb0ef41Sopenharmony_ci// large enough to cover kBatchSize UUID's at a time. The uuidData
3421cb0ef41Sopenharmony_ci// buffer is reused. Each call to randomUUID() consumes 16 bytes
3431cb0ef41Sopenharmony_ci// from the buffer.
3441cb0ef41Sopenharmony_ci
3451cb0ef41Sopenharmony_ciconst kBatchSize = 128;
3461cb0ef41Sopenharmony_cilet uuidData;
3471cb0ef41Sopenharmony_cilet uuidNotBuffered;
3481cb0ef41Sopenharmony_cilet uuidBatch = 0;
3491cb0ef41Sopenharmony_ci
3501cb0ef41Sopenharmony_cilet hexBytesCache;
3511cb0ef41Sopenharmony_cifunction getHexBytes() {
3521cb0ef41Sopenharmony_ci  if (hexBytesCache === undefined) {
3531cb0ef41Sopenharmony_ci    hexBytesCache = new Array(256);
3541cb0ef41Sopenharmony_ci    for (let i = 0; i < hexBytesCache.length; i++) {
3551cb0ef41Sopenharmony_ci      const hex = NumberPrototypeToString(i, 16);
3561cb0ef41Sopenharmony_ci      hexBytesCache[i] = StringPrototypePadStart(hex, 2, '0');
3571cb0ef41Sopenharmony_ci    }
3581cb0ef41Sopenharmony_ci  }
3591cb0ef41Sopenharmony_ci  return hexBytesCache;
3601cb0ef41Sopenharmony_ci}
3611cb0ef41Sopenharmony_ci
3621cb0ef41Sopenharmony_cifunction serializeUUID(buf, offset = 0) {
3631cb0ef41Sopenharmony_ci  const kHexBytes = getHexBytes();
3641cb0ef41Sopenharmony_ci  // xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
3651cb0ef41Sopenharmony_ci  return kHexBytes[buf[offset]] +
3661cb0ef41Sopenharmony_ci    kHexBytes[buf[offset + 1]] +
3671cb0ef41Sopenharmony_ci    kHexBytes[buf[offset + 2]] +
3681cb0ef41Sopenharmony_ci    kHexBytes[buf[offset + 3]] +
3691cb0ef41Sopenharmony_ci    '-' +
3701cb0ef41Sopenharmony_ci    kHexBytes[buf[offset + 4]] +
3711cb0ef41Sopenharmony_ci    kHexBytes[buf[offset + 5]] +
3721cb0ef41Sopenharmony_ci    '-' +
3731cb0ef41Sopenharmony_ci    kHexBytes[(buf[offset + 6] & 0x0f) | 0x40] +
3741cb0ef41Sopenharmony_ci    kHexBytes[buf[offset + 7]] +
3751cb0ef41Sopenharmony_ci    '-' +
3761cb0ef41Sopenharmony_ci    kHexBytes[(buf[offset + 8] & 0x3f) | 0x80] +
3771cb0ef41Sopenharmony_ci    kHexBytes[buf[offset + 9]] +
3781cb0ef41Sopenharmony_ci    '-' +
3791cb0ef41Sopenharmony_ci    kHexBytes[buf[offset + 10]] +
3801cb0ef41Sopenharmony_ci    kHexBytes[buf[offset + 11]] +
3811cb0ef41Sopenharmony_ci    kHexBytes[buf[offset + 12]] +
3821cb0ef41Sopenharmony_ci    kHexBytes[buf[offset + 13]] +
3831cb0ef41Sopenharmony_ci    kHexBytes[buf[offset + 14]] +
3841cb0ef41Sopenharmony_ci    kHexBytes[buf[offset + 15]];
3851cb0ef41Sopenharmony_ci}
3861cb0ef41Sopenharmony_ci
3871cb0ef41Sopenharmony_cifunction getBufferedUUID() {
3881cb0ef41Sopenharmony_ci  uuidData ??= secureBuffer(16 * kBatchSize);
3891cb0ef41Sopenharmony_ci  if (uuidData === undefined)
3901cb0ef41Sopenharmony_ci    throw new ERR_OPERATION_FAILED('Out of memory');
3911cb0ef41Sopenharmony_ci
3921cb0ef41Sopenharmony_ci  if (uuidBatch === 0) randomFillSync(uuidData);
3931cb0ef41Sopenharmony_ci  uuidBatch = (uuidBatch + 1) % kBatchSize;
3941cb0ef41Sopenharmony_ci  return serializeUUID(uuidData, uuidBatch * 16);
3951cb0ef41Sopenharmony_ci}
3961cb0ef41Sopenharmony_ci
3971cb0ef41Sopenharmony_cifunction getUnbufferedUUID() {
3981cb0ef41Sopenharmony_ci  uuidNotBuffered ??= secureBuffer(16);
3991cb0ef41Sopenharmony_ci  if (uuidNotBuffered === undefined)
4001cb0ef41Sopenharmony_ci    throw new ERR_OPERATION_FAILED('Out of memory');
4011cb0ef41Sopenharmony_ci  randomFillSync(uuidNotBuffered);
4021cb0ef41Sopenharmony_ci  return serializeUUID(uuidNotBuffered);
4031cb0ef41Sopenharmony_ci}
4041cb0ef41Sopenharmony_ci
4051cb0ef41Sopenharmony_cifunction randomUUID(options) {
4061cb0ef41Sopenharmony_ci  if (options !== undefined)
4071cb0ef41Sopenharmony_ci    validateObject(options, 'options');
4081cb0ef41Sopenharmony_ci  const {
4091cb0ef41Sopenharmony_ci    disableEntropyCache = false,
4101cb0ef41Sopenharmony_ci  } = options || kEmptyObject;
4111cb0ef41Sopenharmony_ci
4121cb0ef41Sopenharmony_ci  validateBoolean(disableEntropyCache, 'options.disableEntropyCache');
4131cb0ef41Sopenharmony_ci
4141cb0ef41Sopenharmony_ci  return disableEntropyCache ? getUnbufferedUUID() : getBufferedUUID();
4151cb0ef41Sopenharmony_ci}
4161cb0ef41Sopenharmony_ci
4171cb0ef41Sopenharmony_cifunction createRandomPrimeJob(type, size, options) {
4181cb0ef41Sopenharmony_ci  validateObject(options, 'options');
4191cb0ef41Sopenharmony_ci
4201cb0ef41Sopenharmony_ci  const {
4211cb0ef41Sopenharmony_ci    safe = false,
4221cb0ef41Sopenharmony_ci    bigint = false,
4231cb0ef41Sopenharmony_ci  } = options;
4241cb0ef41Sopenharmony_ci  let {
4251cb0ef41Sopenharmony_ci    add,
4261cb0ef41Sopenharmony_ci    rem,
4271cb0ef41Sopenharmony_ci  } = options;
4281cb0ef41Sopenharmony_ci
4291cb0ef41Sopenharmony_ci  validateBoolean(safe, 'options.safe');
4301cb0ef41Sopenharmony_ci  validateBoolean(bigint, 'options.bigint');
4311cb0ef41Sopenharmony_ci
4321cb0ef41Sopenharmony_ci  if (add !== undefined) {
4331cb0ef41Sopenharmony_ci    if (typeof add === 'bigint') {
4341cb0ef41Sopenharmony_ci      add = unsignedBigIntToBuffer(add, 'options.add');
4351cb0ef41Sopenharmony_ci    } else if (!isAnyArrayBuffer(add) && !isArrayBufferView(add)) {
4361cb0ef41Sopenharmony_ci      throw new ERR_INVALID_ARG_TYPE(
4371cb0ef41Sopenharmony_ci        'options.add',
4381cb0ef41Sopenharmony_ci        [
4391cb0ef41Sopenharmony_ci          'ArrayBuffer',
4401cb0ef41Sopenharmony_ci          'TypedArray',
4411cb0ef41Sopenharmony_ci          'Buffer',
4421cb0ef41Sopenharmony_ci          'DataView',
4431cb0ef41Sopenharmony_ci          'bigint',
4441cb0ef41Sopenharmony_ci        ],
4451cb0ef41Sopenharmony_ci        add);
4461cb0ef41Sopenharmony_ci    }
4471cb0ef41Sopenharmony_ci  }
4481cb0ef41Sopenharmony_ci
4491cb0ef41Sopenharmony_ci  if (rem !== undefined) {
4501cb0ef41Sopenharmony_ci    if (typeof rem === 'bigint') {
4511cb0ef41Sopenharmony_ci      rem = unsignedBigIntToBuffer(rem, 'options.rem');
4521cb0ef41Sopenharmony_ci    } else if (!isAnyArrayBuffer(rem) && !isArrayBufferView(rem)) {
4531cb0ef41Sopenharmony_ci      throw new ERR_INVALID_ARG_TYPE(
4541cb0ef41Sopenharmony_ci        'options.rem',
4551cb0ef41Sopenharmony_ci        [
4561cb0ef41Sopenharmony_ci          'ArrayBuffer',
4571cb0ef41Sopenharmony_ci          'TypedArray',
4581cb0ef41Sopenharmony_ci          'Buffer',
4591cb0ef41Sopenharmony_ci          'DataView',
4601cb0ef41Sopenharmony_ci          'bigint',
4611cb0ef41Sopenharmony_ci        ],
4621cb0ef41Sopenharmony_ci        rem);
4631cb0ef41Sopenharmony_ci    }
4641cb0ef41Sopenharmony_ci  }
4651cb0ef41Sopenharmony_ci
4661cb0ef41Sopenharmony_ci  const job = new RandomPrimeJob(type, size, safe, add, rem);
4671cb0ef41Sopenharmony_ci  job.result = bigint ? arrayBufferToUnsignedBigInt : (p) => p;
4681cb0ef41Sopenharmony_ci  return job;
4691cb0ef41Sopenharmony_ci}
4701cb0ef41Sopenharmony_ci
4711cb0ef41Sopenharmony_cifunction generatePrime(size, options, callback) {
4721cb0ef41Sopenharmony_ci  validateInt32(size, 'size', 1);
4731cb0ef41Sopenharmony_ci  if (typeof options === 'function') {
4741cb0ef41Sopenharmony_ci    callback = options;
4751cb0ef41Sopenharmony_ci    options = kEmptyObject;
4761cb0ef41Sopenharmony_ci  }
4771cb0ef41Sopenharmony_ci  validateFunction(callback, 'callback');
4781cb0ef41Sopenharmony_ci
4791cb0ef41Sopenharmony_ci  const job = createRandomPrimeJob(kCryptoJobAsync, size, options);
4801cb0ef41Sopenharmony_ci  job.ondone = (err, prime) => {
4811cb0ef41Sopenharmony_ci    if (err) {
4821cb0ef41Sopenharmony_ci      callback(err);
4831cb0ef41Sopenharmony_ci      return;
4841cb0ef41Sopenharmony_ci    }
4851cb0ef41Sopenharmony_ci
4861cb0ef41Sopenharmony_ci    callback(
4871cb0ef41Sopenharmony_ci      undefined,
4881cb0ef41Sopenharmony_ci      job.result(prime));
4891cb0ef41Sopenharmony_ci  };
4901cb0ef41Sopenharmony_ci  job.run();
4911cb0ef41Sopenharmony_ci}
4921cb0ef41Sopenharmony_ci
4931cb0ef41Sopenharmony_cifunction generatePrimeSync(size, options = kEmptyObject) {
4941cb0ef41Sopenharmony_ci  validateInt32(size, 'size', 1);
4951cb0ef41Sopenharmony_ci
4961cb0ef41Sopenharmony_ci  const job = createRandomPrimeJob(kCryptoJobSync, size, options);
4971cb0ef41Sopenharmony_ci  const { 0: err, 1: prime } = job.run();
4981cb0ef41Sopenharmony_ci  if (err)
4991cb0ef41Sopenharmony_ci    throw err;
5001cb0ef41Sopenharmony_ci  return job.result(prime);
5011cb0ef41Sopenharmony_ci}
5021cb0ef41Sopenharmony_ci
5031cb0ef41Sopenharmony_ci/**
5041cb0ef41Sopenharmony_ci * 48 is the ASCII code for '0', 97 is the ASCII code for 'a'.
5051cb0ef41Sopenharmony_ci * @param {number} number An integer between 0 and 15.
5061cb0ef41Sopenharmony_ci * @returns {number} corresponding to the ASCII code of the hex representation
5071cb0ef41Sopenharmony_ci *                   of the parameter.
5081cb0ef41Sopenharmony_ci */
5091cb0ef41Sopenharmony_ciconst numberToHexCharCode = (number) => (number < 10 ? 48 : 87) + number;
5101cb0ef41Sopenharmony_ci
5111cb0ef41Sopenharmony_ci/**
5121cb0ef41Sopenharmony_ci * @param {ArrayBuffer} buf An ArrayBuffer.
5131cb0ef41Sopenharmony_ci * @return {bigint}
5141cb0ef41Sopenharmony_ci */
5151cb0ef41Sopenharmony_cifunction arrayBufferToUnsignedBigInt(buf) {
5161cb0ef41Sopenharmony_ci  const length = ArrayBufferPrototypeGetByteLength(buf);
5171cb0ef41Sopenharmony_ci  const chars = Array(length * 2);
5181cb0ef41Sopenharmony_ci  const view = new DataView(buf);
5191cb0ef41Sopenharmony_ci
5201cb0ef41Sopenharmony_ci  for (let i = 0; i < length; i++) {
5211cb0ef41Sopenharmony_ci    const val = DataViewPrototypeGetUint8(view, i);
5221cb0ef41Sopenharmony_ci    chars[2 * i] = numberToHexCharCode(val >> 4);
5231cb0ef41Sopenharmony_ci    chars[2 * i + 1] = numberToHexCharCode(val & 0xf);
5241cb0ef41Sopenharmony_ci  }
5251cb0ef41Sopenharmony_ci
5261cb0ef41Sopenharmony_ci  return BigInt(`0x${StringFromCharCodeApply(chars)}`);
5271cb0ef41Sopenharmony_ci}
5281cb0ef41Sopenharmony_ci
5291cb0ef41Sopenharmony_cifunction unsignedBigIntToBuffer(bigint, name) {
5301cb0ef41Sopenharmony_ci  if (bigint < 0) {
5311cb0ef41Sopenharmony_ci    throw new ERR_OUT_OF_RANGE(name, '>= 0', bigint);
5321cb0ef41Sopenharmony_ci  }
5331cb0ef41Sopenharmony_ci
5341cb0ef41Sopenharmony_ci  const hex = BigIntPrototypeToString(bigint, 16);
5351cb0ef41Sopenharmony_ci  const padded = StringPrototypePadStart(hex, hex.length + (hex.length % 2), 0);
5361cb0ef41Sopenharmony_ci  return Buffer.from(padded, 'hex');
5371cb0ef41Sopenharmony_ci}
5381cb0ef41Sopenharmony_ci
5391cb0ef41Sopenharmony_cifunction checkPrime(candidate, options = kEmptyObject, callback) {
5401cb0ef41Sopenharmony_ci  if (typeof candidate === 'bigint')
5411cb0ef41Sopenharmony_ci    candidate = unsignedBigIntToBuffer(candidate, 'candidate');
5421cb0ef41Sopenharmony_ci  if (!isAnyArrayBuffer(candidate) && !isArrayBufferView(candidate)) {
5431cb0ef41Sopenharmony_ci    throw new ERR_INVALID_ARG_TYPE(
5441cb0ef41Sopenharmony_ci      'candidate',
5451cb0ef41Sopenharmony_ci      [
5461cb0ef41Sopenharmony_ci        'ArrayBuffer',
5471cb0ef41Sopenharmony_ci        'TypedArray',
5481cb0ef41Sopenharmony_ci        'Buffer',
5491cb0ef41Sopenharmony_ci        'DataView',
5501cb0ef41Sopenharmony_ci        'bigint',
5511cb0ef41Sopenharmony_ci      ],
5521cb0ef41Sopenharmony_ci      candidate,
5531cb0ef41Sopenharmony_ci    );
5541cb0ef41Sopenharmony_ci  }
5551cb0ef41Sopenharmony_ci  if (typeof options === 'function') {
5561cb0ef41Sopenharmony_ci    callback = options;
5571cb0ef41Sopenharmony_ci    options = kEmptyObject;
5581cb0ef41Sopenharmony_ci  }
5591cb0ef41Sopenharmony_ci  validateFunction(callback, 'callback');
5601cb0ef41Sopenharmony_ci  validateObject(options, 'options');
5611cb0ef41Sopenharmony_ci  const {
5621cb0ef41Sopenharmony_ci    checks = 0,
5631cb0ef41Sopenharmony_ci  } = options;
5641cb0ef41Sopenharmony_ci
5651cb0ef41Sopenharmony_ci  // The checks option is unsigned but must fit into a signed C int for OpenSSL.
5661cb0ef41Sopenharmony_ci  validateInt32(checks, 'options.checks', 0);
5671cb0ef41Sopenharmony_ci
5681cb0ef41Sopenharmony_ci  const job = new CheckPrimeJob(kCryptoJobAsync, candidate, checks);
5691cb0ef41Sopenharmony_ci  job.ondone = callback;
5701cb0ef41Sopenharmony_ci  job.run();
5711cb0ef41Sopenharmony_ci}
5721cb0ef41Sopenharmony_ci
5731cb0ef41Sopenharmony_cifunction checkPrimeSync(candidate, options = kEmptyObject) {
5741cb0ef41Sopenharmony_ci  if (typeof candidate === 'bigint')
5751cb0ef41Sopenharmony_ci    candidate = unsignedBigIntToBuffer(candidate, 'candidate');
5761cb0ef41Sopenharmony_ci  if (!isAnyArrayBuffer(candidate) && !isArrayBufferView(candidate)) {
5771cb0ef41Sopenharmony_ci    throw new ERR_INVALID_ARG_TYPE(
5781cb0ef41Sopenharmony_ci      'candidate',
5791cb0ef41Sopenharmony_ci      [
5801cb0ef41Sopenharmony_ci        'ArrayBuffer',
5811cb0ef41Sopenharmony_ci        'TypedArray',
5821cb0ef41Sopenharmony_ci        'Buffer',
5831cb0ef41Sopenharmony_ci        'DataView',
5841cb0ef41Sopenharmony_ci        'bigint',
5851cb0ef41Sopenharmony_ci      ],
5861cb0ef41Sopenharmony_ci      candidate,
5871cb0ef41Sopenharmony_ci    );
5881cb0ef41Sopenharmony_ci  }
5891cb0ef41Sopenharmony_ci  validateObject(options, 'options');
5901cb0ef41Sopenharmony_ci  const {
5911cb0ef41Sopenharmony_ci    checks = 0,
5921cb0ef41Sopenharmony_ci  } = options;
5931cb0ef41Sopenharmony_ci
5941cb0ef41Sopenharmony_ci  // The checks option is unsigned but must fit into a signed C int for OpenSSL.
5951cb0ef41Sopenharmony_ci  validateInt32(checks, 'options.checks', 0);
5961cb0ef41Sopenharmony_ci
5971cb0ef41Sopenharmony_ci  const job = new CheckPrimeJob(kCryptoJobSync, candidate, checks);
5981cb0ef41Sopenharmony_ci  const { 0: err, 1: result } = job.run();
5991cb0ef41Sopenharmony_ci  if (err)
6001cb0ef41Sopenharmony_ci    throw err;
6011cb0ef41Sopenharmony_ci
6021cb0ef41Sopenharmony_ci  return result;
6031cb0ef41Sopenharmony_ci}
6041cb0ef41Sopenharmony_ci
6051cb0ef41Sopenharmony_cimodule.exports = {
6061cb0ef41Sopenharmony_ci  checkPrime,
6071cb0ef41Sopenharmony_ci  checkPrimeSync,
6081cb0ef41Sopenharmony_ci  randomBytes,
6091cb0ef41Sopenharmony_ci  randomFill,
6101cb0ef41Sopenharmony_ci  randomFillSync,
6111cb0ef41Sopenharmony_ci  randomInt,
6121cb0ef41Sopenharmony_ci  getRandomValues,
6131cb0ef41Sopenharmony_ci  randomUUID,
6141cb0ef41Sopenharmony_ci  generatePrime,
6151cb0ef41Sopenharmony_ci  generatePrimeSync,
6161cb0ef41Sopenharmony_ci};
617