@@ -7,14 +7,27 @@ const {
77} = primordials ;
88
99const { AsyncWrap, Providers } = internalBinding ( 'async_wrap' ) ;
10- const { kMaxLength } = require ( 'buffer' ) ;
11- const { randomBytes : _randomBytes } = internalBinding ( 'crypto' ) ;
1210const {
13- ERR_INVALID_ARG_TYPE ,
14- ERR_INVALID_CALLBACK ,
15- ERR_OUT_OF_RANGE
16- } = require ( 'internal/errors' ) . codes ;
17- const { validateNumber } = require ( 'internal/validators' ) ;
11+ Buffer,
12+ kMaxLength,
13+ } = require ( 'buffer' ) ;
14+ const {
15+ randomBytes : _randomBytes ,
16+ secureBuffer,
17+ } = internalBinding ( 'crypto' ) ;
18+ const {
19+ codes : {
20+ ERR_INVALID_ARG_TYPE ,
21+ ERR_INVALID_CALLBACK ,
22+ ERR_OUT_OF_RANGE ,
23+ ERR_OPERATION_FAILED ,
24+ }
25+ } = require ( 'internal/errors' ) ;
26+ const {
27+ validateBoolean,
28+ validateNumber,
29+ validateObject,
30+ } = require ( 'internal/validators' ) ;
1831const { isArrayBufferView } = require ( 'internal/util/types' ) ;
1932const { FastBuffer } = require ( 'internal/buffer' ) ;
2033
@@ -203,9 +216,113 @@ function handleError(ex, buf) {
203216 return buf ;
204217}
205218
219+ // Implements an RFC 4122 version 4 random UUID.
220+ // To improve performance, random data is generated in batches
221+ // large enough to cover kBatchSize UUID's at a time. The uuidData
222+ // and uuid buffers are reused. Each call to randomUUID() consumes
223+ // 16 bytes from the buffer.
224+
225+ const kHexDigits = [
226+ 48 , 49 , 50 , 51 , 52 , 53 , 54 , 55 ,
227+ 56 , 57 , 97 , 98 , 99 , 100 , 101 , 102
228+ ] ;
229+
230+ const kBatchSize = 128 ;
231+ let uuidData ;
232+ let uuidNotBuffered ;
233+ let uuid ;
234+ let uuidBatch = 0 ;
235+
236+ function getBufferedUUID ( ) {
237+ if ( uuidData === undefined ) {
238+ uuidData = secureBuffer ( 16 * kBatchSize ) ;
239+ if ( uuidData === undefined )
240+ throw new ERR_OPERATION_FAILED ( 'Out of memory' ) ;
241+ }
242+
243+ if ( uuidBatch === 0 ) randomFillSync ( uuidData ) ;
244+ uuidBatch = ( uuidBatch + 1 ) % kBatchSize ;
245+ return uuidData . slice ( uuidBatch * 16 , ( uuidBatch * 16 ) + 16 ) ;
246+ }
247+
248+ function randomUUID ( options ) {
249+ if ( options !== undefined )
250+ validateObject ( options , 'options' ) ;
251+ const {
252+ disableEntropyCache = false ,
253+ } = { ...options } ;
254+
255+ validateBoolean ( disableEntropyCache , 'options.disableEntropyCache' ) ;
256+
257+ if ( uuid === undefined ) {
258+ uuid = Buffer . alloc ( 36 , '-' ) ;
259+ uuid [ 14 ] = 52 ; // '4', identifies the UUID version
260+ }
261+
262+ let uuidBuf ;
263+ if ( ! disableEntropyCache ) {
264+ uuidBuf = getBufferedUUID ( ) ;
265+ } else {
266+ uuidBuf = uuidNotBuffered ;
267+ if ( uuidBuf === undefined )
268+ uuidBuf = uuidNotBuffered = secureBuffer ( 16 ) ;
269+ if ( uuidBuf === undefined )
270+ throw new ERR_OPERATION_FAILED ( 'Out of memory' ) ;
271+ randomFillSync ( uuidBuf ) ;
272+ }
273+
274+ // Variant byte: 10xxxxxx (variant 1)
275+ uuidBuf [ 8 ] = ( uuidBuf [ 8 ] & 0x3f ) | 0x80 ;
276+
277+ // This function is structured the way it is for performance.
278+ // The uuid buffer stores the serialization of the random
279+ // bytes from uuidData.
280+ // xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
281+ let n = 0 ;
282+ uuid [ 0 ] = kHexDigits [ uuidBuf [ n ] >> 4 ] ;
283+ uuid [ 1 ] = kHexDigits [ uuidBuf [ n ++ ] & 0xf ] ;
284+ uuid [ 2 ] = kHexDigits [ uuidBuf [ n ] >> 4 ] ;
285+ uuid [ 3 ] = kHexDigits [ uuidBuf [ n ++ ] & 0xf ] ;
286+ uuid [ 4 ] = kHexDigits [ uuidBuf [ n ] >> 4 ] ;
287+ uuid [ 5 ] = kHexDigits [ uuidBuf [ n ++ ] & 0xf ] ;
288+ uuid [ 6 ] = kHexDigits [ uuidBuf [ n ] >> 4 ] ;
289+ uuid [ 7 ] = kHexDigits [ uuidBuf [ n ++ ] & 0xf ] ;
290+ // -
291+ uuid [ 9 ] = kHexDigits [ uuidBuf [ n ] >> 4 ] ;
292+ uuid [ 10 ] = kHexDigits [ uuidBuf [ n ++ ] & 0xf ] ;
293+ uuid [ 11 ] = kHexDigits [ uuidBuf [ n ] >> 4 ] ;
294+ uuid [ 12 ] = kHexDigits [ uuidBuf [ n ++ ] & 0xf ] ;
295+ // -
296+ // 4, uuid[14] is set already...
297+ uuid [ 15 ] = kHexDigits [ uuidBuf [ n ++ ] & 0xf ] ;
298+ uuid [ 16 ] = kHexDigits [ uuidBuf [ n ] >> 4 ] ;
299+ uuid [ 17 ] = kHexDigits [ uuidBuf [ n ++ ] & 0xf ] ;
300+ // -
301+ uuid [ 19 ] = kHexDigits [ uuidBuf [ n ] >> 4 ] ;
302+ uuid [ 20 ] = kHexDigits [ uuidBuf [ n ++ ] & 0xf ] ;
303+ uuid [ 21 ] = kHexDigits [ uuidBuf [ n ] >> 4 ] ;
304+ uuid [ 22 ] = kHexDigits [ uuidBuf [ n ++ ] & 0xf ] ;
305+ // -
306+ uuid [ 24 ] = kHexDigits [ uuidBuf [ n ] >> 4 ] ;
307+ uuid [ 25 ] = kHexDigits [ uuidBuf [ n ++ ] & 0xf ] ;
308+ uuid [ 26 ] = kHexDigits [ uuidBuf [ n ] >> 4 ] ;
309+ uuid [ 27 ] = kHexDigits [ uuidBuf [ n ++ ] & 0xf ] ;
310+ uuid [ 28 ] = kHexDigits [ uuidBuf [ n ] >> 4 ] ;
311+ uuid [ 29 ] = kHexDigits [ uuidBuf [ n ++ ] & 0xf ] ;
312+ uuid [ 30 ] = kHexDigits [ uuidBuf [ n ] >> 4 ] ;
313+ uuid [ 31 ] = kHexDigits [ uuidBuf [ n ++ ] & 0xf ] ;
314+ uuid [ 32 ] = kHexDigits [ uuidBuf [ n ] >> 4 ] ;
315+ uuid [ 33 ] = kHexDigits [ uuidBuf [ n ++ ] & 0xf ] ;
316+ uuid [ 34 ] = kHexDigits [ uuidBuf [ n ] >> 4 ] ;
317+ uuid [ 35 ] = kHexDigits [ uuidBuf [ n ] & 0xf ] ;
318+
319+ return uuid . latin1Slice ( 0 , 36 ) ;
320+ }
321+
206322module . exports = {
207323 randomBytes,
208324 randomFill,
209325 randomFillSync,
210- randomInt
326+ randomInt,
327+ randomUUID,
211328} ;
0 commit comments