Skip to content

crypto: add uuidv7 monotonic counter#62601

Open
araujogui wants to merge 1 commit intonodejs:mainfrom
araujogui:uuidv7-counter
Open

crypto: add uuidv7 monotonic counter#62601
araujogui wants to merge 1 commit intonodejs:mainfrom
araujogui:uuidv7-counter

Conversation

@araujogui
Copy link
Copy Markdown
Member

Follow up #62553

Copilot AI review requested due to automatic review settings April 5, 2026 16:15
@nodejs-github-bot
Copy link
Copy Markdown
Collaborator

Review requested:

  • @nodejs/crypto

@nodejs-github-bot nodejs-github-bot added crypto Issues and PRs related to the crypto subsystem. needs-ci PRs that need a full CI run. labels Apr 5, 2026
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a monotonic counter to crypto.randomUUIDv7() so UUIDv7 values are strictly increasing even when multiple UUIDs are generated within the same millisecond.

Changes:

  • Implement monotonic rand_a counter state for UUIDv7 generation (buffered + unbuffered paths).
  • Write timestamp + counter into UUIDv7 bytes before serialization.
  • Tighten/extend tests to assert strict ordering, including burst generation.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
test/parallel/test-crypto-randomuuidv7.js Updates ordering assertions to require strict monotonic UUID string ordering and adds a burst test.
lib/internal/crypto/random.js Adds UUIDv7-specific buffered state and monotonic timestamp/counter logic used by randomUUIDv7().

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 62 to +86
{
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]}`);
}
}
Copy link

Copilot AI Apr 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new monotonic-ordering assertions only exercise the default (buffered) code path. Since this PR changes both buffered and disableEntropyCache: true (unbuffered) implementations, it would be good to add at least one ordering check for randomUUIDv7({ disableEntropyCache: true }) as well, to ensure the unbuffered counter/timestamp logic stays monotonic too.

Copilot uses AI. Check for mistakes.
@harimm
Copy link
Copy Markdown

harimm commented Apr 5, 2026

Can you confirm that it’s intentional for advanceV7() to let the encoded timestamp move ahead of current clock time in order to preserve strict monotonic ordering once the 12-bit space is exhausted within a millisecond? Relatedly, under sustained high-throughput generation across multiple consecutive milliseconds, should we expect that drift from wall clock to continue accumulating until the burst subsides? Out of curiosity, is the 12-bit limit here driven strictly by any spec, or was there any consideration of alternative approaches once that per-millisecond space is exhausted?

@codecov
Copy link
Copy Markdown

codecov bot commented Apr 5, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 89.70%. Comparing base (dec5973) to head (5e312c1).
⚠️ Report is 2 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main   #62601      +/-   ##
==========================================
- Coverage   89.70%   89.70%   -0.01%     
==========================================
  Files         695      695              
  Lines      214524   214549      +25     
  Branches    41080    41082       +2     
==========================================
+ Hits       192443   192461      +18     
+ Misses      14121    14119       -2     
- Partials     7960     7969       +9     
Files with missing lines Coverage Δ
lib/internal/crypto/random.js 96.21% <100.00%> (+0.14%) ⬆️

... and 25 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

crypto Issues and PRs related to the crypto subsystem. needs-ci PRs that need a full CI run.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants