Skip to content
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

Wrapping behavior of impl ClockSequence for Context #702

Closed
fef1312 opened this issue Aug 7, 2023 · 4 comments · Fixed by #705
Closed

Wrapping behavior of impl ClockSequence for Context #702

fef1312 opened this issue Aug 7, 2023 · 4 comments · Fixed by #705

Comments

@fef1312
Copy link
Contributor

fef1312 commented Aug 7, 2023

Hi there! First of all, sorry for not using the bug report template; the link in the contribution guide seems broken.

Anyway, I was just browsing your code and noticed a minor oddity in the implementation of ClockSequence for Context, in timestamp.rs:441. Based on what the comment there states, generate_sequence() is supposed to just truncate the counter to 14 bits before returning it. However, it actually takes the modulus with 0x1fff instead of 0x2000, which decreases entropy by one and compiles to a division instead of a simple bitwise AND.

Is this intentional? I realize I'm being a bit pedantic here, but it can't hurt to point out.

@KodrAus
Copy link
Member

KodrAus commented Aug 11, 2023

Hi @fef1312 👋

Hmm, the result of u16::MAX >> 2 should be 0x3fff rather than 0x1fff right? 🤔 Would a method using a bitwise AND actually have lower entropy than the current method that wraps? Or would they be the same? In the end we're mapping 16 bits down to 14, so if they're the same then an AND definitely sounds preferable to a division.

@fef1312
Copy link
Contributor Author

fef1312 commented Aug 11, 2023

Oops, you're right about the 0x3fff. My bad!

What I mean by "lower entropy" is that anything modulo N is always less than N, so the largest value this method will ever return in its current implementation is actually 0x3ffe. In other words, the counter has "only" 16383 rather than 16384 possible states. To wrap at exactly 14 bits, you have two options:

self.count.fetch_add(1, Ordering::AcqRel) % (1 << 14)
self.count.fetch_add(1, Ordering::AcqRel) & (u16::MAX >> 2)

These are mathematically equivalent because it's a power of two, so rustc will pick the AND version either way. But again, this is merely a technicality and a single division here won't make an observable difference in the grand scheme of things. The main reason I brought it up was because it's technically not compliant with the RFC.

@KodrAus
Copy link
Member

KodrAus commented Aug 11, 2023

Aha, thanks for the explanation. It was simply my ignorance that lead to the original implementation and I think your suggested alternative:

self.count.fetch_add(1, Ordering::AcqRel) & (u16::MAX >> 2)

would be a great fix.

Would you like to submit a PR for it?

@fef1312
Copy link
Contributor Author

fef1312 commented Aug 11, 2023

Alright, sure!

fef1312 added a commit to fef1312/uuid-rs that referenced this issue Aug 11, 2023
fef1312 added a commit to fef1312/uuid-rs that referenced this issue Aug 14, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants