我已阅读man
页面,但我并未指出name
和namespace
的用途。
对于版本3和版本5,UUID是附加命令行 必须给出参数名称空间和名称。命名空间也是 字符串表示中的UUID或 内部预定义命名空间UUID的标识符(当前已知为“ns:DNS”,“ns:URL”,“ns:OID”和“ns:X500”)。该 name是一个任意长度的字符串。
命名空间:
命名空间是字符串表示形式的UUID或
这是否意味着我需要将它(UUID v4)存储在与生成的UUID v5相关的某个地方?在任何一种情况下,为什么不自动完成?
名称是一个任意长度的字符串。
name
一个完全随机的字符串?它的目的是什么呢?可以从UUID v5解码吗?
答案 0 :(得分:168)
类型3和类型5 UUID只是将哈希填充到UUID中的一种技术。
SHA1哈希输出160位(20字节)。哈希的结果被转换为UUID。来自SHA1的20字节:
SHA1 Digest: 74738ff5 5367 e958 9aee 98fffdcd1876 94028007
UUID (v5): 74738ff5-5367-5958-9aee-98fffdcd1876
^_low nibble is set to 5 to indicate type 5
^_first two bits set to 1 and 0, respectively
(请注意,' 9'的前两位分别为1和0,所以这没有效果。)
你可能想知道我应该散列什么。基本上你哈希连接:
sha1([NamespaceUUID]+[AnyString]);
您在字符串前加上一个所谓的命名空间,以防止名称冲突。
UUID RFC为您预先定义了四个名称空间:
NameSpace_DNS
:{6ba7b810-9dad-11d1-80b4-00c04fd430c8} NameSpace_URL
:{6ba7b811-9dad-11d1-80b4-00c04fd430c8} NameSpace_OID
:{6ba7b812-9dad-11d1-80b4-00c04fd430c8} NameSpace_X500
:{6ba7b814-9dad-11d1-80b4-00c04fd430c8} 所以,你可以一起散列:
StackOverflowDnsUUID = sha1(Namespace_DNS + "stackoverflow.com");
StackOverflowUrlUUID = sha1(Namespace_URL + "stackoverflow.com");
RFC然后定义如何:
基本要点是只取前128位,在类型记录中输入 5
,然后设置前两位clock_seq_hi_and_reserved
部分分别为1和0。
既然您有一个生成所谓的名称的函数,您可以使用该函数(伪代码):
UUID NameToUUID(UUID NamespaceUUID, String Name)
{
byte[] hash = sha1(NamespaceUUID.ToBytes() + Name.ToBytes());
UUID result;
Copy(hash, result, 16);
result[6] &= 0x0F;
result[6] |= 0x50;
result[8] &= 0x3F;
result[8] |= 0x80;
return result;
}
(注意,系统的字节序可以影响上述字节的索引)
你可以打电话:
uuid = NameToUUID(Namespace_DNS, 'www.stackoverflow.com');
uuid = NameToUUID(Namespace_DNS, 'www.google.com');
uuid = NameToUUID(Namespace_URL, 'http://www.stackoverflow.com');
uuid = NameToUUID(Namespace_URL, 'http://www.google.com/search&q=rfc+4112');
uuid = NameToUUID(Namespace_URL, 'http://stackoverflow.com/questions/5515880/test-vectors-for-uuid-version-5-converting-hash-into-guid-algorithm');
对于版本3和版本5 UUID,必须提供附加的命令行参数名称空间和名称。命名空间是字符串表示形式的UUID或内部预定义命名空间UUID的标识符(当前已知为" ns:DNS"," ns:URL"," ns :OID"和" ns:X500")。名称是一个任意长度的字符串。
名称空间是您喜欢的任何UUID。它可以是预定义的一个,也可以自己构成,例如:
UUID Namespace_RectalForeignExtractedObject = '4d79546f-6e67-7565-496e-486572417373'
名称是一个任意长度的字符串。
名称只是您要附加到命名空间的文本,然后进行散列,并填充到UUID中:
uuid = NameToUUID('8e884ace-bee4-11e4-8dfc-aa07a5b093db', 'screwdriver');
uuid = NameToUUID('8e884ace-bee4-11e4-8dfc-aa07a5b093db', 'toothbrush');
uuid = NameToUUID('8e884ace-bee4-11e4-8dfc-aa07a5b093db', 'broomstick');
uuid = NameToUUID('8e884ace-bee4-11e4-8dfc-aa07a5b093db', 'orange');
uuid = NameToUUID('8e884ace-bee4-11e4-8dfc-aa07a5b093db', 'axe handle');
uuid = NameToUUID('8e884ace-bee4-11e4-8dfc-aa07a5b093db', 'impulse body spray');
uuid = NameToUUID('8e884ace-bee4-11e4-8dfc-aa07a5b093db', 'iPod Touch');
注意:任何已发布到公共领域的代码。无需归属。
答案 1 :(得分:77)
名称和命名空间可用于创建(非常可能)唯一UUID的层次结构。
粗略地说,通过将命名空间标识符与名称一起散列来生成类型3或类型5 UUID。类型3 UUID使用MD5,类型5 UUID使用SHA1。只有128位可用,5位用于指定类型,因此所有散列位都不会进入UUID。 (此外,MD5被认为是加密断开的,并且SHA1处于最后阶段,所以不要使用它来验证需要非常安全的数据")。也就是说,它为您提供了一种创建可重复/可验证的#hash;#34;函数将可能的分层名称映射到概率上唯一的128位值,可能像分层哈希或MAC一样。
假设您有一个(key,value)存储,但它只支持一个命名空间。您可以使用类型3或类型5 UUID生成大量不同的逻辑名称空间。首先,为每个命名空间创建一个根UUID。这可以是类型1(主机+时间戳)或类型4(随机)UUID,只要您将其存放在某处。或者,您可以为根创建一个随机UUID(或以root身份使用null
UUID:00000000-0000-0000-0000-000000000000
,然后使用"为每个命名空间创建可重现的UUID。 uuid -v5 $ROOTUUID $NAMESPACENAME
&#34 ;.现在,您可以使用" uuid -v5 $NAMESPACEUUID $KEY
"为命名空间内的键创建唯一的UUID。这些UUID可以被抛入单个键值存储中,很可能避免冲突。这个过程可以递归地重复,以便如果例如"值"与UUID密钥相关联又代表某种逻辑"命名空间"像桶,容器或目录一样,它的UUID可以依次用于生成更多的分层UUID。
生成的类型3或类型5 UUID包含名称空间标识和名称空间名称(密钥)的(部分)哈希。它不再保留命名空间UUID,而不是消息MAC保存它所编码的消息的内容。这个名字是"任意的" (octet)字符串从uuid算法的角度来看。但其含义取决于您的应用。它可以是逻辑目录中的文件名,对象存储中的object-id等等。
虽然这适用于大量的名称空间和密钥,但如果你的目标是非常大的密钥是非常高概率的,那么它最终会失去动力。生日问题(又名生日悖论)的维基百科条目包括一个表格,该表格给出了针对不同数量的键和表格大小的至少一次碰撞的概率。对于128位,以这种方式散列260亿个密钥的碰撞概率为p=10^-18
(可忽略不计),但是26万亿个密钥,将至少一次碰撞的概率增加到p=10^-12
(万亿分之一) )和散列26*10^15
密钥,将至少一次冲突的概率增加到p=10^-6
(百万分之一)。对UUID类型进行5位编码调整时,它的运行速度会快一些,因此万亿次密钥的碰撞几率大约为1万亿次。
有关概率表,请参阅http://en.wikipedia.org/wiki/Birthday_problem#Probability_table。
有关UUID编码的详细信息,请参阅http://www.ietf.org/rfc/rfc4122.txt。
答案 2 :(得分:9)
名称不过是在某些名称空间中唯一的标识符。问题在于名称空间通常很小,一个名称空间经常与其他名称空间冲突。例如,在我的州DMV的命名空间中,我的车牌号(名称)是唯一的,但在世界范围内可能不是唯一的。其他状态DMV可能在其自己的名称空间中使用了相同的名称。哎呀,其他人的电话号码(名称)可能也匹配,因为那是另一个名称空间,等等。
UUID可以看作是一个单一的命名空间,其规模如此之大,以至于它可以为一切提供唯一的名称。这就是“通用”的意思。但是如何将其他命名空间中的现有名称映射到UUID?
一个明显的解决方案是为每个项目生成一个UUID(V1或V4),以替换其不相交的命名空间中的旧名称。缺点是它们更大,您必须将所有新名称传达给拥有数据集副本,更新所有API等的每个人。奇怪的是,您实际上无法完全摆脱旧名称无论如何,这意味着现在每个项目都有两个名称,那么您使事情变得更好还是更糟?
这是V3 / V5出现的地方。UUID外观与V4一样随机,但实际上是确定性的。任何对名称空间具有正确UUID的人都可以针对该名称空间中的任何给定名称独立地 生成相同的UUID。您根本不需要发布它们,甚至不需要预先生成它们,因为任何人都可以根据需要即时创建它们!
DNS名称和URL是非常常用的名称空间,因此为它们发布了标准UUID。 ASN.1 OID和X.500名称并不常见,但是标准机构喜欢它们,因此他们也为它们发布了标准名称空间UUID。
对于所有其他名称空间,您必须生成自己的名称空间UUID(V1或V4)并将其传达给需要它的任何人。如果您有多个命名空间,则必须为每个命名空间发布UUID显然是不理想的。
这是层次结构的来源:您创建一个“基本” UUID(任何类型),然后将其用作命名其他命名空间的命名空间!这样,您只需发布基本的UUID(或使用明显的UUID),每个人都可以计算出其余的UUID。
例如,让我们继续,我们想为StackOverflow创建一些UUID;该名称在DNS名称空间中具有明显的名称,因此基数很明显:
uuid ns_dns = '6ba7b810-9dad-11d1-80b4-00c04fd430c8';
uuid ns_base = uuidv5(ns_dns, 'stackoverflow.com');
StackOverflow本身具有用于用户,问题,答案,评论等的独立命名空间,但这些命名空间也很明显:
uuid ns_user = uuidv5(ns_base, 'user');
uuid ns_question = uuidv5(ns_base, 'question');
uuid ns_answer = uuidv5(ns_base, 'answer');
uuid ns_comment = uuidv5(ns_base, 'comment');
这个特定的问题是#10867405,因此它的UUID为:
uuid here = uuidv5(ns_question, '10867405');
请注意,此过程中没有 随机操作,因此,遵循相同逻辑的任何人都将得到相同的答案,但是UUID名称空间是如此之大,以至于(有效地,由于122位加密哈希)永远不会与从任何其他名称空间/名称对生成的UUID冲突。