◐ Shell
clean mode source ↗

crypto: implement randomUUIDv7() · nodejs/node@b267f6b

@@ -11,6 +11,7 @@ const {

1111

BigIntPrototypeToString,

1212

DataView,

1313

DataViewPrototypeGetUint8,

14+

DateNow,

1415

FunctionPrototypeBind,

1516

FunctionPrototypeCall,

1617

MathMin,

@@ -359,7 +360,7 @@ function getHexBytes() {

359360

return hexBytesCache;

360361

}

361362362-

function serializeUUID(buf, offset = 0) {

363+

function serializeUUID(buf, version, variant, offset = 0) {

363364

const kHexBytes = getHexBytes();

364365

// xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx

365366

return kHexBytes[buf[offset]] +

@@ -370,10 +371,10 @@ function serializeUUID(buf, offset = 0) {

370371

kHexBytes[buf[offset + 4]] +

371372

kHexBytes[buf[offset + 5]] +

372373

'-' +

373-

kHexBytes[(buf[offset + 6] & 0x0f) | 0x40] +

374+

kHexBytes[(buf[offset + 6] & 0x0f) | version] +

374375

kHexBytes[buf[offset + 7]] +

375376

'-' +

376-

kHexBytes[(buf[offset + 8] & 0x3f) | 0x80] +

377+

kHexBytes[(buf[offset + 8] & 0x3f) | variant] +

377378

kHexBytes[buf[offset + 9]] +

378379

'-' +

379380

kHexBytes[buf[offset + 10]] +

@@ -391,15 +392,15 @@ function getBufferedUUID() {

391392392393

if (uuidBatch === 0) randomFillSync(uuidData);

393394

uuidBatch = (uuidBatch + 1) % kBatchSize;

394-

return serializeUUID(uuidData, uuidBatch * 16);

395+

return serializeUUID(uuidData, 0x40, 0x80, uuidBatch * 16);

395396

}

396397397398

function getUnbufferedUUID() {

398399

uuidNotBuffered ??= secureBuffer(16);

399400

if (uuidNotBuffered === undefined)

400401

throw new ERR_OPERATION_FAILED('Out of memory');

401402

randomFillSync(uuidNotBuffered);

402-

return serializeUUID(uuidNotBuffered);

403+

return serializeUUID(uuidNotBuffered, 0x40, 0x80);

403404

}

404405405406

function randomUUID(options) {

@@ -414,6 +415,50 @@ function randomUUID(options) {

414415

return disableEntropyCache ? getUnbufferedUUID() : getBufferedUUID();

415416

}

416417418+

function writeTimestamp(buf, offset) {

419+

const now = DateNow();

420+

const msb = now / (2 ** 32);

421+

buf[offset] = msb >>> 8;

422+

buf[offset + 1] = msb;

423+

buf[offset + 2] = now >>> 24;

424+

buf[offset + 3] = now >>> 16;

425+

buf[offset + 4] = now >>> 8;

426+

buf[offset + 5] = now;

427+

}

428+429+

function getBufferedUUIDv7() {

430+

uuidData ??= secureBuffer(16 * kBatchSize);

431+

if (uuidData === undefined)

432+

throw new ERR_OPERATION_FAILED('Out of memory');

433+434+

if (uuidBatch === 0) randomFillSync(uuidData);

435+

uuidBatch = (uuidBatch + 1) % kBatchSize;

436+

const offset = uuidBatch * 16;

437+

writeTimestamp(uuidData, offset);

438+

return serializeUUID(uuidData, 0x70, 0x80, offset);

439+

}

440+441+

function getUnbufferedUUIDv7() {

442+

uuidNotBuffered ??= secureBuffer(16);

443+

if (uuidNotBuffered === undefined)

444+

throw new ERR_OPERATION_FAILED('Out of memory');

445+

randomFillSync(uuidNotBuffered, 6);

446+

writeTimestamp(uuidNotBuffered, 0);

447+

return serializeUUID(uuidNotBuffered, 0x70, 0x80);

448+

}

449+450+

function randomUUIDv7(options) {

451+

if (options !== undefined)

452+

validateObject(options, 'options');

453+

const {

454+

disableEntropyCache = false,

455+

} = options || kEmptyObject;

456+457+

validateBoolean(disableEntropyCache, 'options.disableEntropyCache');

458+459+

return disableEntropyCache ? getUnbufferedUUIDv7() : getBufferedUUIDv7();

460+

}

461+417462

function createRandomPrimeJob(type, size, options) {

418463

validateObject(options, 'options');

419464

@@ -611,6 +656,7 @@ module.exports = {

611656

randomInt,

612657

getRandomValues,

613658

randomUUID,

659+

randomUUIDv7,

614660

generatePrime,

615661

generatePrimeSync,

616662

};