v5 UUIDを生成しています。名前と名前空間とは何ですか?


125

私が読んだmanページを、私はしませundestand何namenamespaceするためのものです。

バージョン3およびバージョン5のUUIDの場合、追加のコマンドライン引数の名前空間と名前を指定する必要があります。名前空間は、文字列表現のUUIDまたは内部的に事前定義された名前空間UUIDの識別子です(現在、「ns:DNS」、「ns:URL」、「ns:OID」、および「ns:X500」と呼ばれます)。名前は任意の長さの文字列です。

名前空間:

名前空間は、文字列表現のUUIDまたは

生成されたUUID v5のどこかにそれ(UUID v4)を保存する必要があるということですか?どちらの場合でも、なぜこれが自動的に行われないのですか?

名前は任意の長さの文字列です。

name完全にランダムな文字列?それの目的は何ですか?UUID v5からデコードできますか?

回答:


106

名前と名前空間を使用して、(おそらく)一意のUUIDの階層を作成できます。

大まかに言えば、タイプ3またはタイプ5のUUIDは、名前空間識別子と名前を一緒にハッシュすることによって生成されます。タイプ3 UUIDはMD5を使用し、タイプ5 UUIDはSHA1を使用します。128ビットのみが使用可能で、5ビットがタイプの指定に使用されるため、すべてのハッシュビットがUUIDに含まれるわけではありません。(また、MD5は暗号的に破損していると見なされ、SHA1は最後のレッグにあるため、「非常に安全」である必要があるデータを検証するためにこれを使用しないでください)。つまり、階層名を確率的に一意の128ビット値にマッピングし、潜在的に階層ハッシュまたはMACのように機能する、再現可能/検証可能な「ハッシュ」関数を作成する方法を提供します。

(key、value)ストアがあるが、それがサポートする名前空間は1つだけだとします。タイプ3またはタイプ5のUUIDを使用して、多数の異なる論理名前空間を生成できます。まず、名前空間ごとにルートUUIDを作成します。どこかに隠しておく限り、これはタイプ1(ホスト+タイムスタンプ)またはタイプ4(ランダム)UUIDになる可能性があります。または、ルート用にランダムなUUIDを1つ作成(またはnullUUID:00000000-0000-0000-0000-000000000000をルートとして使用)し、 " uuid -v5 $ROOTUUID $NAMESPACENAME" を使用して各名前空間に再現可能なUUIDを作成することもできます。これで、名前空間内のキーに一意のUUIDを作成できます。uuid -v5 $NAMESPACEUUID $KEYこれらのUUIDは、衝突を回避する可能性が高い単一のKey-Valueストアにスローできます。このプロセスを再帰的に繰り返すことができるため、たとえば、UUIDキーに関連付けられた「値」が、ある種の論理的な「名前空間」を表す場合"バケット、コンテナ、ディレクトリのように、そのUUIDを使用してさらに階層的なUUIDを生成できます。

生成されたタイプ3またはタイプ5のUUIDは、名前空間ID(名前空間内の名前(キー))の(部分的な)ハッシュを保持します。ネームスペースUUIDを保持するのは、メッセージMACがエンコード元のメッセージのコンテンツを保持することだけです。名前は、uuidアルゴリズムの観点から見た「任意」の(オクテット)文字列です。ただし、その意味はアプリケーションによって異なります。論理ディレクトリ内のファイル名、オブジェクトストア内のオブジェクトIDなどです。

これは、適度に多数の名前空間とキーでうまく機能しますが、非常に高い確率で一意である非常に多数のキーを対象とする場合、最終的には使い果たされます。誕生日問題(別名誕生日パラドックス)のWikipediaエントリには、さまざまな数のキーとテーブルサイズの少なくとも1つの衝突の確率を示すテーブルが含まれています。128ビットの場合、この方法で260億のキーをハッシュすると、p=10^-18(無視できる)の衝突の確率がありますが、26兆のキーは、少なくとも1つの衝突の確率をp=10^-12(1兆分の1)26*10^15に増やし、キーのハッシュは、少なくとも1つの衝突p=10^-6(100万人に一人)。UUIDタイプをエンコードする5ビットに合わせて調整すると、少し速く実行されます。そのため、1兆のキーには、1コリジョンが発生する可能性が約1兆分の1になります。

確率表については、http://en.wikipedia.org/wiki/Birthday_problem#Probability_tableを参照してください

UUIDエンコーディングの詳細については、http://www.ietf.org/rfc/rfc4122.txtを参照してください


2
階層の特定のレベルで、名前空間としてUUIDv5を使用し、ランダムキーとしてUUIDv4を使用して、(このGUIDによって識別される)データ自体の衝突がUUIDの衝突の可能性を高めないようにすることができますか?知っておくべきパフォーマンスの問題はありますか?
ermik

私はその概念に不慣れで、あなたが話しているその階層が何であるかに戸惑いました。どこで確認できますか...説明に行き詰まると、名前空間の再現可能なUUIDを作成するためにこれが使用される可能性があるため、ある程度の明確さが得られました。特定の名前空間(そのUUID)を使用して、特定のUUID(タイプ3または5)が生成されたことを確認する方法はあるのでしょうか。
msciwoj 2018年

213

タイプ3およびタイプ5のUUIDは、ハッシュをUUID に詰め込む手法にすぎません。

  • タイプ1:MACアドレス+日時を128ビットに詰める
  • タイプ3:MD5ハッシュを128ビットに詰め込む
  • タイプ4:ランダムデータを128ビットに詰める
  • タイプ5:SHA1ハッシュを128ビットに詰める
  • タイプ6:順次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」の最初の2ビットはすでにそれぞれ1と0であるため、これは効果がないことに注意してください)。

何をハッシュしますか?

あなたはおそらく私がハッシュすることになっているのは何だろうと思っているでしょう。基本的には、次の連結をハッシュします。

sha1([NamespaceUUID]+[AnyString]);

名前の競合を防ぐために、いわゆる名前空間を文字列の前に付けます。

UUID RFCはあなたのための4つの名前空間を定義して、事前:

  • 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は次の方法を定義します。

  • SHA1から160ビットを取る
  • そしてそれをUUIDの128ビットに変換します

基本的な要点は、最初の128ビットのみを取得5し、レコードにa を詰め込み、clock_seq_hi_and_reservedセクションの最初の2ビットをそれぞれ1および0に設定することです。

その他の例

いわゆるNameを生成する関数ができたので、関数を(疑似コードで)持つことができます。

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 = '8e884ace-bee4-11e4-8dfc-aa07a5b093db'

名前は任意の長さの文字列です。

名前は、名前空間に追加し、ハッシュして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');

:パブリックドメインにリリースされたコード。帰属は必要ありません。


45
徹底的な説明ありがとうございます。ボーナスポイントをNamespace_RectalForeignExtractedObjectあげられたら。
boodle 2016年

UUIDからデコードされた名前または名前空間をデコードすることは可能ですか?
Sathesh

3
@Satheshいいえ、ハッシュをデコードすることはできません。ハッシュは一方向の関数です。たとえば、Star Trek TNG Blu-Rayコレクション全体は81 GBで、ハッシュはC5740BBBF2429115276D4AB60A020ED3ADE01192です。この20バイトのハッシュをデコードして81 GBに戻す方法はありません。本当に必要な場合は、同じ結果が得られる組み合わせが見つかるまで、可能なすべてのGUIDと可能な文字列をハッシュしてみてください。どのようなランチでも、永遠と永遠の間のどこかにそれを見つけるでしょう。
Ian Boyd

22

名前は、名前空間内で一意の識別子にすぎません。問題は、名前空間がしばしば非常に小さく、1つの名前が他の名前と衝突することが多いことです。たとえば、私の車のナンバープレート番号(名前)は私の州のDMVの名前空間内で一意ですが、おそらく世界で一意ではありません。他の状態のDMVは、独自の名前空間で同じ名前を使用している可能性があります。一体、他の誰かが電話番号(名前)を持っているかもしれません。これもまた別の名前空間だからです。

UUIDは単一の名前空間に存在するものと見なすことができるため、すべてに一意の名前を付けることができます。それが「ユニバーサル」の意味です。しかし、他の名前空間の既存の名前をUUIDにどのようにマッピングしますか?

明白な解決策の1つは、すべてのアイテムのUUID(V1またはV4)を生成して、互いに結合していない名前空間の古い名前を置き換えることです。欠点は、それらがはるかに大きいことです。データセットのコピーを持っているすべての人にすべての新しい名前を伝え、すべてのAPIを更新する必要があります。実際には、古い名前を完全に取り除くことはできません。とにかく、これはすべてのアイテムが2つの名前を持つようになったことを意味します。

これがV3 / V5の出番です。UUID はV4と同じようにランダムに見えますが、実際には確定的です。名前空間に適切なUUIDを持っている人は誰でも、その名前空間内の任意の名前に対して同じUUIDを個別に生成できます。誰でも必要に応じてその場で作成できるため、公開する必要も、事前に生成する必要もありません。

DNS名とURLは非常に一般的に使用される名前空間であるため、標準のUUIDが公開されています。ASN.1 OIDとX.500の名前はそれほど一般的ではありませんが、標準化団体はそれらを愛しており、標準の名前空間UUIDも公開しています。

他のすべての名前空間については、独自の名前空間UUID(V1またはV4)を生成し、それを必要とするすべての人に伝達する必要があります。複数の名前空間がある場合、それぞれにUUIDを公開することは明らかに理想的ではありません。

これが階層の出番です。1つの「ベース」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。


そのAPIが明らかにビッグ整数のみを文字列として返す場合、stackoverflowが一意に生成されたビッグ整数をUUIDにマップする必要があるのはなぜですか。APIにない場合、UUIDはどこで使用されますか。UUIDまたはBIGINTを選択する必要があるようです。なぜこのハイブリッド戦略を行うのか。しかし、あなたの答えの明確な説明のために+1。
nishant 2018

4
UUID V3 / V5は、既存の(衝突する可能性が高い)名前空間を1つのUUID名前空間に決定論的に変換する必要がある場合のために設計されました。これは、データセットをマージするときに役立つことがよくあります。それがあなたのしていることに当てはまらない場合は、V1 / V4を使用してください。
StephenS 2018
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.