-
-
Notifications
You must be signed in to change notification settings - Fork 35.3k
crypto: add uuidv7 monotonic counter #62601
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 3 commits
5e312c1
19bb93c
a5f3be5
2f90718
c798973
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -56,24 +56,37 @@ const { | |
| const timestamp = parseInt(timestampHex, 16); | ||
|
|
||
| assert(timestamp >= before, `Timestamp ${timestamp} < before ${before}`); | ||
| assert(timestamp <= after, `Timestamp ${timestamp} > after ${after}`); | ||
| // The monotonic counter may have overflowed in a prior call and advanced | ||
| // v7LastTimestamp by 1 ms beyond wall-clock time (RFC 9562 §6.2 allows this). | ||
| assert(timestamp <= after + 1, `Timestamp ${timestamp} > after+1 ${after + 1}`); | ||
| } | ||
|
|
||
| { | ||
| let prev = randomUUIDv7(); | ||
| for (let i = 0; i < 100; i++) { | ||
| const curr = randomUUIDv7(); | ||
| // UUIDs with later timestamps must sort after earlier ones. | ||
| // Within the same millisecond, ordering depends on random bits, | ||
| // so we only assert >= on the timestamp portion. | ||
| const prevTs = parseInt(prev.replace(/-/g, '').slice(0, 12), 16); | ||
| const currTs = parseInt(curr.replace(/-/g, '').slice(0, 12), 16); | ||
| assert(currTs >= prevTs, | ||
| `Timestamp went backwards: ${currTs} < ${prevTs}`); | ||
| // With a monotonic counter in rand_a, each UUID must be strictly greater | ||
| // than the previous regardless of whether the timestamp changed. | ||
| assert(curr > prev, | ||
| `UUID ordering violated: ${curr} <= ${prev}`); | ||
| prev = curr; | ||
| } | ||
| } | ||
|
|
||
| // Sub-millisecond ordering: a tight synchronous burst exercises the counter | ||
| // increment path and must also produce strictly increasing UUIDs. | ||
| { | ||
| const burst = []; | ||
| for (let i = 0; i < 500; i++) { | ||
| burst.push(randomUUIDv7()); | ||
| } | ||
| for (let i = 1; i < burst.length; i++) { | ||
| assert(burst[i] > burst[i - 1], | ||
| `Sub-millisecond ordering violated at index ${i}: ` + | ||
| `${burst[i]} <= ${burst[i - 1]}`); | ||
| } | ||
| } | ||
|
Comment on lines
62
to
+88
|
||
|
|
||
| // Ensure randomUUIDv7 takes no arguments (or ignores them gracefully). | ||
| { | ||
| const uuid = randomUUIDv7(); | ||
|
|
@@ -92,13 +105,22 @@ const { | |
| assert.match(randomUUIDv7({ disableEntropyCache: true }), uuidv7Regex); | ||
| assert.match(randomUUIDv7({ disableEntropyCache: true }), uuidv7Regex); | ||
|
|
||
| // monotonic: false — rand_a is random; UUIDs must still be valid but are not | ||
| // guaranteed to be strictly ordered within the same millisecond. | ||
| assert.match(randomUUIDv7({ monotonic: false }), uuidv7Regex); | ||
| assert.match(randomUUIDv7({ monotonic: false, disableEntropyCache: true }), uuidv7Regex); | ||
|
|
||
| assert.throws(() => randomUUIDv7(1), { | ||
| code: 'ERR_INVALID_ARG_TYPE', | ||
| }); | ||
|
|
||
| assert.throws(() => randomUUIDv7({ disableEntropyCache: '' }), { | ||
| code: 'ERR_INVALID_ARG_TYPE', | ||
| }); | ||
|
|
||
| assert.throws(() => randomUUIDv7({ monotonic: 1 }), { | ||
| code: 'ERR_INVALID_ARG_TYPE', | ||
| }); | ||
| } | ||
|
|
||
| { | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.