为什么第 4 版 GUID 的第 17 位仅限于 4 种可能性?

Why is the 17th digit of version 4 GUIDs limited to only 4 possibilities?

我知道这并没有减少所涉及的熵的很大一部分,即使保留了 GUID 的整个其他字符(出于任何目的),我们仍然可以为每个昆虫有一个,所以我不担心,只是好奇。

因为 this great answer shows, the Version 4 生成 GUID 的算法具有以下格式:

xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx
  1. x 是随机的
  2. 4是常量,代表版本号
  3. y 是以下之一:8、9、A 或 B

RFC spec for UUIDs 说这些位必须这样设置,但我看不出有任何理由。

为什么第三个项目符号(第 17 个数字)仅限于这四个数字?

引用可贵的利珀特先生的话

First off, what bits are we talking about when we say “the bits”? We already know that in a “random” GUID the first hex digit of the third section is always 4....there is additional version information stored in the GUID in the bits in the fourth section as well; you’ll note that a GUID almost always has 8, 9, a or b as the first hex digit of the fourth section. So in total we have six bits reserved for version information, leaving 122 bits that can be chosen at random.

(来自https://ericlippert.com/2012/05/07/guid-guide-part-three/

tl;dr - 这是更多版本信息。要获得比这更具体的信息,我怀疑您将不得不追踪规范的作者。

位,不是十六进制

关注 hexadecimal digits 会让您感到困惑。

UUID 不是十六进制的。一个UUID由128位组成。

人类会反感阅读一系列 128 bits 呈现为一长串 10 字符。所以为了人类读写的方便,我们把128位以16进制表示。

永远记住,当您看到带有连字符的 36 个十六进制字符系列时,您不是正在查看 UUID。您正在查看一些生成的文本,以表示 UUID 中实际存在的 128 位。

版本和变体

您提到的第一个特殊含义,链接规范的“version” of UUID, is recorded using 4 bits. See section 4.1.3

您指出的第二个特殊含义是链接规范的 “variant”. This value takes 1-3 bits. This See section 4.1.1

一个十六进制字符代表 4 位(octet 的一半)。

  • 版本 数字是 4 位,它本身就是一个完整的十六进制字符。
  • 版本 4 特别使用位 01 00,十六进制为 4,十进制(基数 10)也是如此。
  • 变体,是 1-3 位, 占用整个十六进制字符.
  • 在 Microsoft 的 GUID 世界之外,当今的其他行业使用两个位:10,十进制值为 2,作为变体。这对位落在八位组 #8 的最高有效位中。该八位组看起来像这样,其中“n”表示 0 或 1:10 nn nn nn。一对十六进制字符代表该八位组的每一半。所以你的第 17 个十六进制数字,即第 8 个八位字节的前半部分,10 nn,只能有四个可能的值:
    • 10 00(十六进制 8)
    • 10 01(十六进制 9)
    • 10 10(十六进制 A)
    • 10 11(十六进制 B)

根据我今天尝试学习的内容,我尝试将 C#/.NET 'LINQPad' snippet/script 放在一起,以(对于一小部分)分解 GUID/UUID(- 以防万一):

void Main()
{
    var guid =
        Guid.Parse(
                //@"08c8fbdc-ff38-402e-b0fd-353392a407af"  // v4 - Microsoft/.NET
                @"7c2a81c7-37ce-4bae-ba7d-11123200d59a"  // v4
                //@"493f6528-d76a-11ec-9d64-0242ac120002"  // v1
                //@"5f0ad0df-99d4-5b63-a267-f0f32cf4c2a2"  // v5
            );

    Console.WriteLine(
        $"UUID = '{guid}' :");

    Console.WriteLine();

    var guidBytes =
        guid.ToByteArray();

    // Version # - 8th octet

    const int timeHiAndVersionOctetIdx = 7;

    var timeHiAndVersionOctet =
        guidBytes[timeHiAndVersionOctetIdx];

    var versionNum =
        (timeHiAndVersionOctet & 0b11110000) >> 4;  // 0xF0

    // Variant # - 9th octet

    const int clkSeqHiResOctetIdx = 8;

    var clkSeqHiResOctet =
        guidBytes[clkSeqHiResOctetIdx];

    var msVariantNum =
        (clkSeqHiResOctet & 0b11100000) >> 5;  // 0xE0/3 bits

    var variantNum =
        (clkSeqHiResOctet & 0b11000000) >> 5;  // 0xC0/2bits - 0x8/0x9/0xA/0xB

    //

    Console.WriteLine(
        $"\tVariant # = '{variantNum}' ('0x{variantNum:X}') - '0b{((variantNum & 0b00000100) > 0 ? '1' : '0')}{((variantNum & 0b00000010) > 0 ? '1' : '0')}{((variantNum & 0b00000001) > 0 ? '1' : '0')}'");
    Console.WriteLine();

    if (variantNum < 4)
    {
        Console.WriteLine(
            $"\t\t'0 x x' - \"Reserved, NCS backward compatibility\"");
    }
    else
    {
        if (variantNum == 4 ||
            variantNum == 5)
        {
            Console.WriteLine(
                $"\t\t'1 0 x' - \"The variant specified in this {{RFC4122}} document\"");
        }
        else
        {
            if (variantNum == 6)
            {
                Console.WriteLine(
                    $"\t\t'1 1 0' - \"Reserved, Microsoft Corporation backward compatibility\"");
            }
            else
            {
                if (variantNum == 7)
                {
                    Console.WriteLine(
                        $"\t\t'1 1 1' - \"Reserved for future definition\"");
                }
            }
        }
    }

    Console.WriteLine();

    Console.WriteLine(
        $"\tVersion # = '{versionNum}' ('0x{versionNum:X}') - '0b{((versionNum & 0b00001000) > 0 ? '1' : '0')}{((versionNum & 0b00000100) > 0 ? '1' : '0')}{((versionNum & 0b00000010) > 0 ? '1' : '0')}{((versionNum & 0b00000001) > 0 ? '1' : '0')}'");
    Console.WriteLine();

    string[] versionDescriptions =
        new[]
        {
            @"The time-based version specified in this {{RFC4122}} document",
            @"DCE Security version, with embedded POSIX UIDs",
            @"The name-based version specified in this {{RFC4122}} document that uses MD5 hashing",
            @"The randomly or pseudo-randomly generated version specified in this {{RFC4122}} document",
            @"The name-based version specified in this {{RFC4122}} document that uses SHA-1 hashing"
        };

    Console.WriteLine(
        $"\t\t'{versionNum}' = \"{versionDescriptions[versionNum - 1]}\"");
    Console.WriteLine();

    Console.WriteLine(
        $"'RFC4122' document - <https://datatracker.ietf.org/doc/html/rfc4122#section-4.1.1>");
    Console.WriteLine();
}