Closed MrZoidberg closed 2 years ago
Not enough Coffee! I didn't merge anything for this issue. I was trying to merge changes for #8 sorry for the notifications.
I also see https://github.com/uuid6/uuid6-ietf-draft/issues/43
I am open to Test Vectors but I don't have the cycles at the moment to work through them. PRs are welcome on the Python implementation on this page.
import secrets
import time
def _subsec_decode(value: int, subsec_bits: int, subsec_decimal_digits: int) -> int:
return -(-value * 10 ** subsec_decimal_digits // 2 ** subsec_bits)
def _subsec_encode(value: int, subsec_bits: int, subsec_decimal_digits: int) -> int:
return value * 2 ** subsec_bits // 10 ** subsec_decimal_digits
def uuid7(
unixts: int = None,
subsec: int = None,
seq: int = None,
node: int = None,
subsec_bits: int = 30,
subsec_digits: int = 9,
seq_bits: int = 0,
) -> str:
"""UUIDv7 draft 02"""
node_bits = 86 - subsec_bits - seq_bits
# sanity checks
if subsec_bits < 0 or seq_bits < 0 or node_bits < 0:
raise ValueError("invalid bit value")
if unixts is None or subsec is None:
if unixts is not None or subsec is not None:
raise ValueError("both unixts and subsec need to be set or unset")
if subsec_digits != 9:
raise ValueError("invalid subsec_digits")
unixts, subsec = divmod(time.time_ns(), 10 ** 9)
if unixts < 0:
raise ValueError("unixts needs to be greater than or equal to 0")
if subsec < 0:
raise ValueError("subsec needs to be greater than or equal to 0")
if subsec >= 10 ** subsec_digits:
raise ValueError("subsec overflow")
if seq is not None:
if seq < 0:
raise ValueError("seq needs to be greater than or equal to 0")
if seq >= 2 ** seq_bits:
raise ValueError("seq overflow")
if node is not None:
if node <= 0:
raise ValueError("node needs to be greater than 0")
if node >= 2 ** node_bits:
raise ValueError("node overflow")
subsec_seq_node = _subsec_encode(subsec, subsec_bits, subsec_digits) << (
node_bits + seq_bits
)
if seq:
subsec_seq_node |= seq << node_bits
if node_bits:
while node is None or node == 0:
node = secrets.randbits(node_bits)
subsec_seq_node |= node
subsec_a = subsec_seq_node >> 74
subsec_b = (subsec_seq_node >> 62) & 0x0FFF
uuid_int = (unixts & 0x0FFFFFFFFF) << 92
uuid_int |= subsec_a << 80
uuid_int |= subsec_b << 64
uuid_int |= subsec_seq_node & 0x03FFFFFFFFFFFFFFF
# Set the variant to RFC 4122.
uuid_int |= 0x8000 << 48
# Set the version number.
uuid_int |= 7 << 76
uuid_hex = "%032x" % uuid_int
return "%s-%s-%s-%s-%s" % (
uuid_hex[:8],
uuid_hex[8:12],
uuid_hex[12:16],
uuid_hex[16:20],
uuid_hex[20:],
)
I haven't tested this thoroughly, but if there aren't any major bugs, you can pretty easily input whatever you want for unixts
, subsec
, and so on. Without any parameters the current time is used and a random node
is generated with secrets.randbits()
.
>>> uuid7(123, 456, 78, 9, seq_bits=8)
'00000007-b000-7007-a94e-000000000009'
>>> uuid7()
'061d1ff8-cd61-7a60-b546-3746d11b885d'
I've generated some test vectors with the following snippet. What do you guys think about it?
def generate_test_vectors():
for subsec_bits in (10, 12, 20, 24, 30, 40):
for subsec_digits in range(3, 13):
print(f"### {subsec_bits=}, {subsec_digits=}")
for unixts in (0, 1, 2, 2 ** 35, 2 ** 36 - 1):
for subsec in (
0,
1,
2,
10 ** subsec_digits // 2 - 1,
10 ** subsec_digits // 2,
10 ** subsec_digits - 2,
10 ** subsec_digits - 1,
):
for node in (
1,
2,
2 ** (86 - subsec_bits) - 2,
2 ** (86 - subsec_bits) - 1,
):
value = uuid7(
unixts,
subsec,
node=node,
subsec_bits=subsec_bits,
subsec_digits=subsec_digits,
)
print(f"{unixts=}, {subsec=}, {node=} = {value}")
Part of the output that covers the common(?) nanosecond case, which requires 30 bits to represent it.
### subsec_bits=30, subsec_digits=9
unixts=0, subsec=0, node=1 = 00000000-0000-7000-8000-000000000001
unixts=0, subsec=0, node=2 = 00000000-0000-7000-8000-000000000002
unixts=0, subsec=0, node=72057594037927934 = 00000000-0000-7000-80ff-fffffffffffe
unixts=0, subsec=0, node=72057594037927935 = 00000000-0000-7000-80ff-ffffffffffff
unixts=0, subsec=1, node=1 = 00000000-0000-7000-8100-000000000001
unixts=0, subsec=1, node=2 = 00000000-0000-7000-8100-000000000002
unixts=0, subsec=1, node=72057594037927934 = 00000000-0000-7000-81ff-fffffffffffe
unixts=0, subsec=1, node=72057594037927935 = 00000000-0000-7000-81ff-ffffffffffff
unixts=0, subsec=2, node=1 = 00000000-0000-7000-8200-000000000001
unixts=0, subsec=2, node=2 = 00000000-0000-7000-8200-000000000002
unixts=0, subsec=2, node=72057594037927934 = 00000000-0000-7000-82ff-fffffffffffe
unixts=0, subsec=2, node=72057594037927935 = 00000000-0000-7000-82ff-ffffffffffff
unixts=0, subsec=499999999, node=1 = 00000000-07ff-7fff-be00-000000000001
unixts=0, subsec=499999999, node=2 = 00000000-07ff-7fff-be00-000000000002
unixts=0, subsec=499999999, node=72057594037927934 = 00000000-07ff-7fff-beff-fffffffffffe
unixts=0, subsec=499999999, node=72057594037927935 = 00000000-07ff-7fff-beff-ffffffffffff
unixts=0, subsec=500000000, node=1 = 00000000-0800-7000-8000-000000000001
unixts=0, subsec=500000000, node=2 = 00000000-0800-7000-8000-000000000002
unixts=0, subsec=500000000, node=72057594037927934 = 00000000-0800-7000-80ff-fffffffffffe
unixts=0, subsec=500000000, node=72057594037927935 = 00000000-0800-7000-80ff-ffffffffffff
unixts=0, subsec=999999998, node=1 = 00000000-0fff-7fff-bd00-000000000001
unixts=0, subsec=999999998, node=2 = 00000000-0fff-7fff-bd00-000000000002
unixts=0, subsec=999999998, node=72057594037927934 = 00000000-0fff-7fff-bdff-fffffffffffe
unixts=0, subsec=999999998, node=72057594037927935 = 00000000-0fff-7fff-bdff-ffffffffffff
unixts=0, subsec=999999999, node=1 = 00000000-0fff-7fff-be00-000000000001
unixts=0, subsec=999999999, node=2 = 00000000-0fff-7fff-be00-000000000002
unixts=0, subsec=999999999, node=72057594037927934 = 00000000-0fff-7fff-beff-fffffffffffe
unixts=0, subsec=999999999, node=72057594037927935 = 00000000-0fff-7fff-beff-ffffffffffff
unixts=1, subsec=0, node=1 = 00000000-1000-7000-8000-000000000001
unixts=1, subsec=0, node=2 = 00000000-1000-7000-8000-000000000002
unixts=1, subsec=0, node=72057594037927934 = 00000000-1000-7000-80ff-fffffffffffe
unixts=1, subsec=0, node=72057594037927935 = 00000000-1000-7000-80ff-ffffffffffff
unixts=1, subsec=1, node=1 = 00000000-1000-7000-8100-000000000001
unixts=1, subsec=1, node=2 = 00000000-1000-7000-8100-000000000002
unixts=1, subsec=1, node=72057594037927934 = 00000000-1000-7000-81ff-fffffffffffe
unixts=1, subsec=1, node=72057594037927935 = 00000000-1000-7000-81ff-ffffffffffff
unixts=1, subsec=2, node=1 = 00000000-1000-7000-8200-000000000001
unixts=1, subsec=2, node=2 = 00000000-1000-7000-8200-000000000002
unixts=1, subsec=2, node=72057594037927934 = 00000000-1000-7000-82ff-fffffffffffe
unixts=1, subsec=2, node=72057594037927935 = 00000000-1000-7000-82ff-ffffffffffff
unixts=1, subsec=499999999, node=1 = 00000000-17ff-7fff-be00-000000000001
unixts=1, subsec=499999999, node=2 = 00000000-17ff-7fff-be00-000000000002
unixts=1, subsec=499999999, node=72057594037927934 = 00000000-17ff-7fff-beff-fffffffffffe
unixts=1, subsec=499999999, node=72057594037927935 = 00000000-17ff-7fff-beff-ffffffffffff
unixts=1, subsec=500000000, node=1 = 00000000-1800-7000-8000-000000000001
unixts=1, subsec=500000000, node=2 = 00000000-1800-7000-8000-000000000002
unixts=1, subsec=500000000, node=72057594037927934 = 00000000-1800-7000-80ff-fffffffffffe
unixts=1, subsec=500000000, node=72057594037927935 = 00000000-1800-7000-80ff-ffffffffffff
unixts=1, subsec=999999998, node=1 = 00000000-1fff-7fff-bd00-000000000001
unixts=1, subsec=999999998, node=2 = 00000000-1fff-7fff-bd00-000000000002
unixts=1, subsec=999999998, node=72057594037927934 = 00000000-1fff-7fff-bdff-fffffffffffe
unixts=1, subsec=999999998, node=72057594037927935 = 00000000-1fff-7fff-bdff-ffffffffffff
unixts=1, subsec=999999999, node=1 = 00000000-1fff-7fff-be00-000000000001
unixts=1, subsec=999999999, node=2 = 00000000-1fff-7fff-be00-000000000002
unixts=1, subsec=999999999, node=72057594037927934 = 00000000-1fff-7fff-beff-fffffffffffe
unixts=1, subsec=999999999, node=72057594037927935 = 00000000-1fff-7fff-beff-ffffffffffff
unixts=2, subsec=0, node=1 = 00000000-2000-7000-8000-000000000001
unixts=2, subsec=0, node=2 = 00000000-2000-7000-8000-000000000002
unixts=2, subsec=0, node=72057594037927934 = 00000000-2000-7000-80ff-fffffffffffe
unixts=2, subsec=0, node=72057594037927935 = 00000000-2000-7000-80ff-ffffffffffff
unixts=2, subsec=1, node=1 = 00000000-2000-7000-8100-000000000001
unixts=2, subsec=1, node=2 = 00000000-2000-7000-8100-000000000002
unixts=2, subsec=1, node=72057594037927934 = 00000000-2000-7000-81ff-fffffffffffe
unixts=2, subsec=1, node=72057594037927935 = 00000000-2000-7000-81ff-ffffffffffff
unixts=2, subsec=2, node=1 = 00000000-2000-7000-8200-000000000001
unixts=2, subsec=2, node=2 = 00000000-2000-7000-8200-000000000002
unixts=2, subsec=2, node=72057594037927934 = 00000000-2000-7000-82ff-fffffffffffe
unixts=2, subsec=2, node=72057594037927935 = 00000000-2000-7000-82ff-ffffffffffff
unixts=2, subsec=499999999, node=1 = 00000000-27ff-7fff-be00-000000000001
unixts=2, subsec=499999999, node=2 = 00000000-27ff-7fff-be00-000000000002
unixts=2, subsec=499999999, node=72057594037927934 = 00000000-27ff-7fff-beff-fffffffffffe
unixts=2, subsec=499999999, node=72057594037927935 = 00000000-27ff-7fff-beff-ffffffffffff
unixts=2, subsec=500000000, node=1 = 00000000-2800-7000-8000-000000000001
unixts=2, subsec=500000000, node=2 = 00000000-2800-7000-8000-000000000002
unixts=2, subsec=500000000, node=72057594037927934 = 00000000-2800-7000-80ff-fffffffffffe
unixts=2, subsec=500000000, node=72057594037927935 = 00000000-2800-7000-80ff-ffffffffffff
unixts=2, subsec=999999998, node=1 = 00000000-2fff-7fff-bd00-000000000001
unixts=2, subsec=999999998, node=2 = 00000000-2fff-7fff-bd00-000000000002
unixts=2, subsec=999999998, node=72057594037927934 = 00000000-2fff-7fff-bdff-fffffffffffe
unixts=2, subsec=999999998, node=72057594037927935 = 00000000-2fff-7fff-bdff-ffffffffffff
unixts=2, subsec=999999999, node=1 = 00000000-2fff-7fff-be00-000000000001
unixts=2, subsec=999999999, node=2 = 00000000-2fff-7fff-be00-000000000002
unixts=2, subsec=999999999, node=72057594037927934 = 00000000-2fff-7fff-beff-fffffffffffe
unixts=2, subsec=999999999, node=72057594037927935 = 00000000-2fff-7fff-beff-ffffffffffff
unixts=34359738368, subsec=0, node=1 = 80000000-0000-7000-8000-000000000001
unixts=34359738368, subsec=0, node=2 = 80000000-0000-7000-8000-000000000002
unixts=34359738368, subsec=0, node=72057594037927934 = 80000000-0000-7000-80ff-fffffffffffe
unixts=34359738368, subsec=0, node=72057594037927935 = 80000000-0000-7000-80ff-ffffffffffff
unixts=34359738368, subsec=1, node=1 = 80000000-0000-7000-8100-000000000001
unixts=34359738368, subsec=1, node=2 = 80000000-0000-7000-8100-000000000002
unixts=34359738368, subsec=1, node=72057594037927934 = 80000000-0000-7000-81ff-fffffffffffe
unixts=34359738368, subsec=1, node=72057594037927935 = 80000000-0000-7000-81ff-ffffffffffff
unixts=34359738368, subsec=2, node=1 = 80000000-0000-7000-8200-000000000001
unixts=34359738368, subsec=2, node=2 = 80000000-0000-7000-8200-000000000002
unixts=34359738368, subsec=2, node=72057594037927934 = 80000000-0000-7000-82ff-fffffffffffe
unixts=34359738368, subsec=2, node=72057594037927935 = 80000000-0000-7000-82ff-ffffffffffff
unixts=34359738368, subsec=499999999, node=1 = 80000000-07ff-7fff-be00-000000000001
unixts=34359738368, subsec=499999999, node=2 = 80000000-07ff-7fff-be00-000000000002
unixts=34359738368, subsec=499999999, node=72057594037927934 = 80000000-07ff-7fff-beff-fffffffffffe
unixts=34359738368, subsec=499999999, node=72057594037927935 = 80000000-07ff-7fff-beff-ffffffffffff
unixts=34359738368, subsec=500000000, node=1 = 80000000-0800-7000-8000-000000000001
unixts=34359738368, subsec=500000000, node=2 = 80000000-0800-7000-8000-000000000002
unixts=34359738368, subsec=500000000, node=72057594037927934 = 80000000-0800-7000-80ff-fffffffffffe
unixts=34359738368, subsec=500000000, node=72057594037927935 = 80000000-0800-7000-80ff-ffffffffffff
unixts=34359738368, subsec=999999998, node=1 = 80000000-0fff-7fff-bd00-000000000001
unixts=34359738368, subsec=999999998, node=2 = 80000000-0fff-7fff-bd00-000000000002
unixts=34359738368, subsec=999999998, node=72057594037927934 = 80000000-0fff-7fff-bdff-fffffffffffe
unixts=34359738368, subsec=999999998, node=72057594037927935 = 80000000-0fff-7fff-bdff-ffffffffffff
unixts=34359738368, subsec=999999999, node=1 = 80000000-0fff-7fff-be00-000000000001
unixts=34359738368, subsec=999999999, node=2 = 80000000-0fff-7fff-be00-000000000002
unixts=34359738368, subsec=999999999, node=72057594037927934 = 80000000-0fff-7fff-beff-fffffffffffe
unixts=34359738368, subsec=999999999, node=72057594037927935 = 80000000-0fff-7fff-beff-ffffffffffff
unixts=68719476735, subsec=0, node=1 = ffffffff-f000-7000-8000-000000000001
unixts=68719476735, subsec=0, node=2 = ffffffff-f000-7000-8000-000000000002
unixts=68719476735, subsec=0, node=72057594037927934 = ffffffff-f000-7000-80ff-fffffffffffe
unixts=68719476735, subsec=0, node=72057594037927935 = ffffffff-f000-7000-80ff-ffffffffffff
unixts=68719476735, subsec=1, node=1 = ffffffff-f000-7000-8100-000000000001
unixts=68719476735, subsec=1, node=2 = ffffffff-f000-7000-8100-000000000002
unixts=68719476735, subsec=1, node=72057594037927934 = ffffffff-f000-7000-81ff-fffffffffffe
unixts=68719476735, subsec=1, node=72057594037927935 = ffffffff-f000-7000-81ff-ffffffffffff
unixts=68719476735, subsec=2, node=1 = ffffffff-f000-7000-8200-000000000001
unixts=68719476735, subsec=2, node=2 = ffffffff-f000-7000-8200-000000000002
unixts=68719476735, subsec=2, node=72057594037927934 = ffffffff-f000-7000-82ff-fffffffffffe
unixts=68719476735, subsec=2, node=72057594037927935 = ffffffff-f000-7000-82ff-ffffffffffff
unixts=68719476735, subsec=499999999, node=1 = ffffffff-f7ff-7fff-be00-000000000001
unixts=68719476735, subsec=499999999, node=2 = ffffffff-f7ff-7fff-be00-000000000002
unixts=68719476735, subsec=499999999, node=72057594037927934 = ffffffff-f7ff-7fff-beff-fffffffffffe
unixts=68719476735, subsec=499999999, node=72057594037927935 = ffffffff-f7ff-7fff-beff-ffffffffffff
unixts=68719476735, subsec=500000000, node=1 = ffffffff-f800-7000-8000-000000000001
unixts=68719476735, subsec=500000000, node=2 = ffffffff-f800-7000-8000-000000000002
unixts=68719476735, subsec=500000000, node=72057594037927934 = ffffffff-f800-7000-80ff-fffffffffffe
unixts=68719476735, subsec=500000000, node=72057594037927935 = ffffffff-f800-7000-80ff-ffffffffffff
unixts=68719476735, subsec=999999998, node=1 = ffffffff-ffff-7fff-bd00-000000000001
unixts=68719476735, subsec=999999998, node=2 = ffffffff-ffff-7fff-bd00-000000000002
unixts=68719476735, subsec=999999998, node=72057594037927934 = ffffffff-ffff-7fff-bdff-fffffffffffe
unixts=68719476735, subsec=999999998, node=72057594037927935 = ffffffff-ffff-7fff-bdff-ffffffffffff
unixts=68719476735, subsec=999999999, node=1 = ffffffff-ffff-7fff-be00-000000000001
unixts=68719476735, subsec=999999999, node=2 = ffffffff-ffff-7fff-be00-000000000002
unixts=68719476735, subsec=999999999, node=72057594037927934 = ffffffff-ffff-7fff-beff-fffffffffffe
unixts=68719476735, subsec=999999999, node=72057594037927935 = ffffffff-ffff-7fff-beff-ffffffffffff
@oittaa, I put this on hold because of some changes in Draft 03. I also took your feedback and added an Appendix to the RFC Draft with a single test vector detailing UUIDv1 vs UUIDv6, UUIDv7 and a UUIDv8 sample.
If you could take a look at the latest Draft 03 PR that would be great!
I'm implementing a C# version of UUIDv7 and it looks like I have some problems with my implementation. It would be great to have a common list of tests to check the implementation.