uuid6 / prototypes

Draft Prototypes and Tests for UUIDv6 and beyond
46 stars 16 forks source link

Test suite #11

Closed MrZoidberg closed 2 years ago

MrZoidberg commented 3 years ago

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.

kyzer-davis commented 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.

oittaa commented 2 years ago
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'
oittaa commented 2 years ago

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
kyzer-davis commented 2 years ago

@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!