为什么第 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
- x 是随机的
- 4是常量,代表版本号
- 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 呈现为一长串 1
和 0
字符。所以为了人类读写的方便,我们把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();
}
我知道这并没有减少所涉及的熵的很大一部分,即使保留了 GUID 的整个其他字符(出于任何目的),我们仍然可以为每个昆虫有一个,所以我不担心,只是好奇。
因为 this great answer shows, the Version 4 生成 GUID 的算法具有以下格式:
xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx
- x 是随机的
- 4是常量,代表版本号
- 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 呈现为一长串 1
和 0
字符。所以为了人类读写的方便,我们把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();
}