Генерування v5 UUID. Що таке ім’я та простір імен?


125

Я прочитав manсторінку, але не відмовляю, для чого nameі namespaceдля чого.

Для версій 3 та версії 5 UUID повинні бути вказані додаткові простори імен аргументів командного рядка. Простір імен є або UUID у поданні рядків, або ідентифікатор внутрішньо заздалегідь визначених UUID просторів імен (відомі в даний час "ns: DNS", "ns: URL", "ns: OID" та "ns: X500"). Назва - рядок довільної довжини.

Простір імен:

Простір імен є або UUID у поданні рядків, або an

Чи означає це, що мені потрібно зберігати його (UUID v4) десь відносно згенерованого UUID v5? В будь-якому випадку, чому це не робиться автоматично?

Назва - рядок довільної довжини.

nameабсолютно випадковий рядок? Яка мета цього тоді? Чи можна його розшифрувати з UUID v5?

Відповіді:


106

Ім’я та простір імен можна використовувати для створення ієрархії (дуже ймовірно) унікальних UUID.

Грубо кажучи, UUID типу 3 або 5 генерується шляхом об'єднання ідентифікатора простору імен з іменем. UUID типу 3 використовують MD5, а UUID типу 5 використовують SHA1. Доступні лише 128 біти, а 5 біт використовується для вказівки типу, тому всі біти хешу не перетворюються на UUID. (Також MD5 вважається криптографічно зламаним, і SHA1 знаходиться на останніх ногах, тому не використовуйте це для перевірки даних, які потребують "дуже безпечного"). Однак, це дає вам змогу створити повторювану / перевірену "хеш-функцію", яка відображає можливо ієрархічне ім'я на ймовірнісно унікальне 128-бітове значення, потенційно діє як ієрархічний хеш або MAC.

Припустимо, у вас є (ключ, значення) магазин, але він підтримує лише одне простір імен. Можна створити велику кількість різних логічних просторів імен, використовуючи UUID типу 3 або типу 5. Спочатку створіть кореневий UUID для кожного простору імен. Це може бути тип 1 (хост + часова марка) або тип 4 (випадковий) UUID до тих пір, поки ви його десь сховали. Крім того, ви можете створити один випадковий UUID для свого кореня (або використовувати nullUUID: 00000000-0000-0000-0000-000000000000як корінь), а потім створити відтворюваний UUID для кожного простору імен, використовуючи " uuid -v5 $ROOTUUID $NAMESPACENAME". Тепер ви можете створити унікальні UUID для ключів у просторі імен, використовуючи "uuid -v5 $NAMESPACEUUID $KEYЦі UUID можуть бути перекинуті в єдиний сховище ключів-значень з високою ймовірністю уникнення зіткнення. Цей процес може повторюватися рекурсивно, так що, наприклад, "значення", пов'язане з ключем UUID, в свою чергу являє собою певний логічний "простір імен "як відро, контейнер або каталог, тоді його UUID можна використовувати по черзі для створення більшої кількості ієрархічних UUID.

Створений UUID типу 3 або типу 5 містить (частковий) хеш ідентифікатора простору імен та імені в межах імен (ключа). Він більше не містить UUID простору імен, ніж повідомлення MAC містить вміст повідомлення, з якого він закодований. Назва - "довільна" (октетна) рядок з точки зору алгоритму uuid. Однак його значення залежить від вашої заявки. Це може бути ім'я файлу в логічному каталозі, ідентифікатор об'єкта в магазині об'єктів і т.д.

Хоча це добре працює для помірно великої кількості просторів імен та клавіш, але з часом вичерпається пара, якщо ви прагнете до дуже великої кількості клавіш, унікальних з дуже високою ймовірністю. Запис у Вікіпедії для проблеми з днем ​​народження (він же парадокс від дня народження) включає таблицю, яка дає ймовірність принаймні одного зіткнення для різних номерів ключів та розмірів таблиці. Для 128-бітних хешування 26 мільярдів ключів таким чином є ймовірність зіткнення p=10^-18(мізерно мала), але 26 трлн ключів, збільшує ймовірність принаймні одного зіткнення p=10^-12(один на трильйон) та хешування 26*10^15ключів, збільшує ймовірність принаймні одне зіткненняp=10^-6(один на мільйон). Регулюючи 5 біт, що кодують тип UUID, він закінчиться дещо швидше, тому трильйон ключів має приблизно 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 (типу 3 або 5) був створений за допомогою певного простору імен (його UUID)?
msciwoj

213

UUID типу 3 і 5 - це лише техніка заповнення хешу в UUID.

SHA1 хеш виводить 160 біт (20 байт); результат хешу перетворюється на UUID.

З 20-байтовим хешем від SHA1:

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 визначає, як:

  • візьміть 160 біт від SHA1
  • і перетворити його на 128 біт UUID

Основна суть полягає в тому, щоб взяти лише перші 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 = '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

Чи можливо розшифрувати ім'я або простір імен, декодованих з UUID?
Sathesh

3
@Sathesh Ні, розшифрувати хеш неможливо; хеші - це односторонні функції. Наприклад, вся колекція Blu-Ray Star Trek TNG Blu-Ray становить 81 Гб, а хеш - C5740BBBFF2429115276D4AB60A020ED3ADE01192 . Немає можливості розшифрувати цей 20-байтний хеш в 81 ГБ. Якщо вам дійсно потрібно було, ви можете спробувати хешировать усі можливі GUID та можливі рядки, поки не знайдете комбінацію, яка дасть той самий результат. З будь-якою популярністю ви знайдете його десь між віком і вічністю.
Ян Бойд

22

Ім'я - це не що інше, як ідентифікатор, унікальний у певній області імен. Проблема полягає в тому, що простори імен часто досить малі, а імена в одних часто стикаються з іменами в інших. Наприклад, номер (найменування) мого автомобіля є унікальним у просторі імен мого штату DMV, але він, мабуть, не є унікальним у світі; інші державні DMV можуть використовувати те саме ім’я у власних просторах імен. Хрен, у когось іншого може бути номер телефону (ім'я), який також відповідає тому, що це ще одне простір імен тощо.

UUID можна розглядати як такі, що займають єдиний простір імен настільки величезний, що він може надати унікальну назву для всього ; ось що означає "універсальний". Але як відобразити наявні імена в інших просторах імен на UUID?

Одне очевидне рішення - створити UUID (V1 або V4) для кожного елемента, щоб замінити старі імена в їхніх неперервних просторах імен. Мінус полягає в тому, що вони набагато більше, ви повинні повідомити всі нові імена всім, хто має копію вашого набору даних, оновити всі свої API та ін. Швидше за все, ви насправді не зможете повністю позбутися старих імен. у будь-якому випадку, це означає, що зараз кожен предмет має два назви, тож ви зробили щось краще чи гірше?

Тут входять V3 / V5. UUID виглядають так само випадково, як V4, але насправді детерміновані; кожен, хто має право UUID для простору імен, може самостійно генерувати той самий UUID для будь-якого даного імені в цьому просторі імен. Вам взагалі не потрібно публікувати їх, а також попередньо створювати їх, оскільки кожен може створювати їх на ходу за потребою!

Імена та URL-адреси DNS дуже часто використовуються просторами імен, тому для них були опубліковані стандартні UUID; ASN.1 імена OID та X.500 не такі поширені, але органи стандартів їх люблять, тому вони публікували і стандартні UUID-адреси простору імен.

Для всіх інших просторів імен вам потрібно створити власний UUID простору імен (V1 або V4) та повідомити його будь-кому, хто потребує цього. Якщо у вас є кілька просторів імен, публікація UUID для кожного очевидно не є ідеальною.

Ось тут і входить ієрархія: ви створюєте один "базовий" UUID (будь-якого типу), а потім використовуєте це як простір імен для імен інших ваших просторів імен! Таким чином, вам залишається лише опублікувати базовий UUID (або використовувати очевидний), і кожен може розрахувати решту.

Наприклад, давайте залишимось, що ми хотіли створити кілька UUID для StackOverflow; що має очевидне ім’я в просторі імен 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, створений з будь-якого іншого простору імен / пари імен.


Мені цікаво, чому stackoverflow повинен зіставити однозначно сформоване велике ціле число на UUID, враховуючи, що його API, очевидно, повертають лише велике ціле число у вигляді рядка. Де б UUID використовувався, якби не в API. Здається, нам слід вибрати або UUID, або BIGINT? Навіщо така гібридна стратегія. І все ж +1 для чіткого пояснення вашої відповіді.
нішант

4
UUID V3 / V5 розроблений для того, коли потрібно детерміновано перетворити існуючі (і, ймовірно, зіткнення) простори імен в один простір імен UUID, що часто корисно при об'єднанні наборів даних. Якщо це не стосується того, що ви робите, тоді перейдіть з V1 / V4.
StephenS
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.