@@ -12,24 +12,28 @@ const {
1212 RandomBytesJob,
1313 kCryptoJobAsync,
1414 kCryptoJobSync,
15+ secureBuffer,
1516} = internalBinding ( 'crypto' ) ;
1617
1718const {
1819 lazyDOMException,
1920} = require ( 'internal/crypto/util' ) ;
2021
21- const { kMaxLength } = require ( 'buffer' ) ;
22+ const { Buffer , kMaxLength } = require ( 'buffer' ) ;
2223
2324const {
2425 codes : {
2526 ERR_INVALID_ARG_TYPE ,
2627 ERR_OUT_OF_RANGE ,
28+ ERR_OPERATION_FAILED ,
2729 }
2830} = require ( 'internal/errors' ) ;
2931
3032const {
3133 validateNumber,
34+ validateBoolean,
3235 validateCallback,
36+ validateObject,
3337} = require ( 'internal/validators' ) ;
3438
3539const {
@@ -281,10 +285,114 @@ function getRandomValues(data) {
281285 return data ;
282286}
283287
288+ // Implements an RFC 4122 version 4 random UUID.
289+ // To improve performance, random data is generated in batches
290+ // large enough to cover kBatchSize UUID's at a time. The uuidData
291+ // and uuid buffers are reused. Each call to randomUUID() consumes
292+ // 16 bytes from the buffer.
293+
294+ const kHexDigits = [
295+ 48 , 49 , 50 , 51 , 52 , 53 , 54 , 55 ,
296+ 56 , 57 , 97 , 98 , 99 , 100 , 101 , 102
297+ ] ;
298+
299+ const kBatchSize = 128 ;
300+ let uuidData ;
301+ let uuidNotBuffered ;
302+ let uuid ;
303+ let uuidBatch = 0 ;
304+
305+ function getBufferedUUID ( ) {
306+ if ( uuidData === undefined ) {
307+ uuidData = secureBuffer ( 16 * kBatchSize ) ;
308+ if ( uuidData === undefined )
309+ throw new ERR_OPERATION_FAILED ( 'Out of memory' ) ;
310+ }
311+
312+ if ( uuidBatch === 0 ) randomFillSync ( uuidData ) ;
313+ uuidBatch = ( uuidBatch + 1 ) % kBatchSize ;
314+ return uuidData . slice ( uuidBatch * 16 , ( uuidBatch * 16 ) + 16 ) ;
315+ }
316+
317+ function randomUUID ( options ) {
318+ if ( options !== undefined )
319+ validateObject ( options , 'options' ) ;
320+ const {
321+ disableEntropyCache = false ,
322+ } = { ...options } ;
323+
324+ validateBoolean ( disableEntropyCache , 'options.disableEntropyCache' ) ;
325+
326+ if ( uuid === undefined ) {
327+ uuid = Buffer . alloc ( 36 , '-' ) ;
328+ uuid [ 14 ] = 52 ; // '4', identifies the UUID version
329+ }
330+
331+ let uuidBuf ;
332+ if ( ! disableEntropyCache ) {
333+ uuidBuf = getBufferedUUID ( ) ;
334+ } else {
335+ uuidBuf = uuidNotBuffered ;
336+ if ( uuidBuf === undefined )
337+ uuidBuf = uuidNotBuffered = secureBuffer ( 16 ) ;
338+ if ( uuidBuf === undefined )
339+ throw new ERR_OPERATION_FAILED ( 'Out of memory' ) ;
340+ randomFillSync ( uuidBuf ) ;
341+ }
342+
343+ // Variant byte: 10xxxxxx (variant 1)
344+ uuidBuf [ 8 ] = ( uuidBuf [ 8 ] & 0x3f ) | 0x80 ;
345+
346+ // This function is structured the way it is for performance.
347+ // The uuid buffer stores the serialization of the random
348+ // bytes from uuidData.
349+ // xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
350+ let n = 0 ;
351+ uuid [ 0 ] = kHexDigits [ uuidBuf [ n ] >> 4 ] ;
352+ uuid [ 1 ] = kHexDigits [ uuidBuf [ n ++ ] & 0xf ] ;
353+ uuid [ 2 ] = kHexDigits [ uuidBuf [ n ] >> 4 ] ;
354+ uuid [ 3 ] = kHexDigits [ uuidBuf [ n ++ ] & 0xf ] ;
355+ uuid [ 4 ] = kHexDigits [ uuidBuf [ n ] >> 4 ] ;
356+ uuid [ 5 ] = kHexDigits [ uuidBuf [ n ++ ] & 0xf ] ;
357+ uuid [ 6 ] = kHexDigits [ uuidBuf [ n ] >> 4 ] ;
358+ uuid [ 7 ] = kHexDigits [ uuidBuf [ n ++ ] & 0xf ] ;
359+ // -
360+ uuid [ 9 ] = kHexDigits [ uuidBuf [ n ] >> 4 ] ;
361+ uuid [ 10 ] = kHexDigits [ uuidBuf [ n ++ ] & 0xf ] ;
362+ uuid [ 11 ] = kHexDigits [ uuidBuf [ n ] >> 4 ] ;
363+ uuid [ 12 ] = kHexDigits [ uuidBuf [ n ++ ] & 0xf ] ;
364+ // -
365+ // 4, uuid[14] is set already...
366+ uuid [ 15 ] = kHexDigits [ uuidBuf [ n ++ ] & 0xf ] ;
367+ uuid [ 16 ] = kHexDigits [ uuidBuf [ n ] >> 4 ] ;
368+ uuid [ 17 ] = kHexDigits [ uuidBuf [ n ++ ] & 0xf ] ;
369+ // -
370+ uuid [ 19 ] = kHexDigits [ uuidBuf [ n ] >> 4 ] ;
371+ uuid [ 20 ] = kHexDigits [ uuidBuf [ n ++ ] & 0xf ] ;
372+ uuid [ 21 ] = kHexDigits [ uuidBuf [ n ] >> 4 ] ;
373+ uuid [ 22 ] = kHexDigits [ uuidBuf [ n ++ ] & 0xf ] ;
374+ // -
375+ uuid [ 24 ] = kHexDigits [ uuidBuf [ n ] >> 4 ] ;
376+ uuid [ 25 ] = kHexDigits [ uuidBuf [ n ++ ] & 0xf ] ;
377+ uuid [ 26 ] = kHexDigits [ uuidBuf [ n ] >> 4 ] ;
378+ uuid [ 27 ] = kHexDigits [ uuidBuf [ n ++ ] & 0xf ] ;
379+ uuid [ 28 ] = kHexDigits [ uuidBuf [ n ] >> 4 ] ;
380+ uuid [ 29 ] = kHexDigits [ uuidBuf [ n ++ ] & 0xf ] ;
381+ uuid [ 30 ] = kHexDigits [ uuidBuf [ n ] >> 4 ] ;
382+ uuid [ 31 ] = kHexDigits [ uuidBuf [ n ++ ] & 0xf ] ;
383+ uuid [ 32 ] = kHexDigits [ uuidBuf [ n ] >> 4 ] ;
384+ uuid [ 33 ] = kHexDigits [ uuidBuf [ n ++ ] & 0xf ] ;
385+ uuid [ 34 ] = kHexDigits [ uuidBuf [ n ] >> 4 ] ;
386+ uuid [ 35 ] = kHexDigits [ uuidBuf [ n ] & 0xf ] ;
387+
388+ return uuid . latin1Slice ( 0 , 36 ) ;
389+ }
390+
284391module . exports = {
285392 randomBytes,
286393 randomFill,
287394 randomFillSync,
288395 randomInt,
289396 getRandomValues,
397+ randomUUID,
290398} ;
0 commit comments