Как Random является System.Guid.NewGuid()? (Возьми два)

Прежде чем вы начнете отмечать это как дубликат, прочитайте меня. Другой вопрос имеет (скорее всего) неверный принятый ответ.

Я не знаю, как .NET генерирует свои GUID, возможно, только Microsoft, но есть высокая вероятность, что он просто вызывает CoCreateGuid(), Однако эта функция документирована как вызов UuidCreate(). И алгоритмы для создания UUID довольно хорошо документированы.

Короче говоря, как бы то ни было, кажется, что System.Guid.NewGuid() действительно использует версию 4 алгоритм генерации UUID, потому что все GUID он генерирует соответствие критериям (см. сами, я попробовал пару миллионов GUID, все они совпали).

Другими словами, эти GUID являются почти случайными, за исключением нескольких известных бит.

Это снова вызывает вопрос - как случайный IS этот случайный? Как знает каждый хороший маленький программист, алгоритм псевдослучайного числа является столь же случайным, как и его семя (он же энтропия). Итак, каково семя для UuidCreate()? Как переназначается PRNG? Является ли это криптографически сильным, или я могу ожидать, что те же самые GUID начнут выливаться, если два компьютера случайно вызовут System.Guid.NewGuid() в одно и то же время? И можно ли предположить состояние PRNG, если собрано достаточно много последовательно сформированных GUID?

Добавлено: Чтобы уточнить, я хотел бы узнать, насколько случайным я могу доверять ему и тем самым - где я могу его использовать. Итак, позвольте установить грубую шкалу "случайности":

  • Базовая случайность, принимая текущее время в качестве семени. Используется для перетасовки карт в Solitaire, но еще немного, поскольку столкновения слишком легко прийти даже без попытки.
  • Более продвинутая случайность, использующая не только время, но и другие специфические для машины факторы для семян. Возможно, также высевается только один раз при запуске системы. Это можно использовать для генерации идентификаторов в БД, поскольку дубликаты маловероятны. Тем не менее, это не хорошо для безопасности, потому что результаты можно предсказать с достаточными усилиями.
  • Cryptograhpically random, используя шум устройства или другие продвинутые источники случайности для семян. Повторно посеяны при каждом вызове или, по крайней мере, довольно часто. Может использоваться для идентификаторов сеансов, переданных неназванным сторонам и т.д.

Я пришел к этому вопросу, думая, что было бы хорошо использовать их в качестве идентификаторов БД, и была ли реализована реализация алгоритма Guid.comb вместе с System.Guid.NewGuid() (например, NHibernate) будет ошибочным или нет.

Ответ 1

В принятом ответе на вопрос говорится:

GUID не гарантирует гарантии случайности, он делает гарантии по уникальности. Если вы хотите случайности, используйте Random для генерации строки.

Все остальное представляет собой деталь реализации (и может измениться).

Обновление. Чтобы сделать мою точку более четкой: даже если текущая реализация .NET 3.5 создала действительно случайное руководство (это не так), нет никакой гарантии, что это будет иметь место в будущем или верно для других реализаций BCL (например, Mono, Silverlight, CF и т.д.)

Обновление 2: Формат UUID указан RFC4122. Раздел 6 содержит явное выражение о безопасности:

Не предполагайте, что UUID трудно угадать; они не должны использоваться    как средства обеспечения безопасности (идентификаторы, чьи простые владения предоставляются    доступ), например. Предполагаемый источник случайных чисел будет    усугубляют ситуацию.

Ответ 2

Некоторые люди уже намекнули на это, но я хочу повторить его, поскольку там, похоже, есть неправильное представление:

Случайность и единственность - это ортогональные понятия.

Случайные данные могут быть уникальными или избыточными, а также уникальные данные могут использовать случайный источник или детерминированный источник (подумайте о глобальном счетчике, который заблокирован и увеличивается для каждого GUID, когда-либо созданного).

GUID были разработаны как уникальные, а не случайные. Если генератор .NET, похоже, использует случайный ввод, отлично. Но не полагайтесь на него как на источник случайности, ни на криптографические, ни на какие-либо другие цели (в частности, какую функцию распределения вы ожидаете получить?). С другой стороны, вы можете быть достаточно уверены, что GUID, созданные .NET, даже в больших томах, будут уникальными.

Ответ 3

API, которые производят случайные байты, но которые явно не документированы для получения криптографически сильных случайных байтов, не могут быть доверены для получения криптографически сильных случайных байтов.

Если вам нужны криптографически сильные случайные байты, тогда вы должны использовать API, который явно документирован для их создания.

public Guid CreateCryptographicallyStrongGuid() {
    var rng = new System.Security.Cryptography.RNGCryptoServiceProvider();
    var data = new byte[16];
    rng.GetBytes(data);
    return new Guid(data);
}

Эти идентификаторы GUID - это всего лишь 128 бит криптографической случайности. Они не структурированы, и они не будут сталкиваться.

См. эту статью для некоторых из математики. Используя "Формулу генерала рождения", перестановка дает

n = sqrt (-2T * ln (p))

где n - количество выбранных элементов, T - общее число элементов (2 ^ 128), а p - целевая вероятность того, что все n выбранных элементов будут разными. При p = 0,99 это дает * n = 2.61532104 * 10 ^ 18 *. Это означает, что мы можем генерировать миллиард поистине случайных GUID в секунду в системе на миллиард секунд (32 года) и иметь более 99% вероятности в конце, что каждый из них уникален в системе.

Ответ 4

Определение Random никоим образом не относится к определению глобально уникального.

Сбрасывая монету дважды и получая HH, HT, TH, TT, все случайны. HH так же случайен, как и HT.

Повторяя "специальную" монету дважды и гарантируя, что вы получите только HT или TH, это уникальность.

Ответ 5

Они являются случайными, так что это математически доказуемо, что столкновения не должны происходить в течение очень долгого времени, так что вы можете предположить, что они уникальны во всем мире. Тем не менее, они не криптографически сильны, поскольку для этого потребуется истинная случайность, что на самом деле невозможно на компьютерах без специального оборудования.

Ответ 6

GUID предназначены для числа 2 на вашем шкале, то есть "могут использоваться для генерации идентификаторов в БД, поскольку дубликаты маловероятны".

Что касается безопасности, проблема не в том, что "это не хорошо для безопасности, потому что результаты можно предсказать с достаточными усилиями". Проблема в том, что никто не дает вам документально подтвержденную гарантию безопасности.

На практике, согласно этот комментарий и этот, генерация GUID реализована с точки зрения криптографически безопасного RNG (CryptGenRandom). Но это, как представляется, недокументированная деталь реализации. (И я не проверил это - это случайные комментарии в Интернете, возьмите с грузовиком соли).

(* Где "маловероятно" означает что-то вроде "шансы любого, кто находит дублирующий GUID до конца юниверса, меньше шансов на то, что вы лично выиграете в лотерею". Исправленные ошибки реализации, конечно.)

Ответ 7

Сфокусировавшись на вопросе использования GUID в качестве идентификаторов строк:

GUID предназначены для баз данных, ориентированных на репликацию, или генерируют строки раньше времени, прежде чем добавлять их в БД. Если вам не нужен GUID для решения какой-либо конкретной проблемы, попробуйте придерживаться инкрементной нумерации. GUID затрудняет отладку и тестирование.

Метод COMB в статье, которую вы упоминаете, на самом деле выглядит довольно неплохо. Я так и не понял, спасибо за это! (стр. версия для печати этой статьи читается намного лучше)

Итак, если вам не нужно генерировать GUID раньше времени, вы можете позволить базе данных обрабатывать генерацию GUID для вас. Различия в скорости вы заметите только в том случае, если вы начнете добавлять 10 000 записей за один раз, чего не следует делать в любом случае, что для массового импорта.

Также посмотрите Jeff on ID vs GUID

create table #temp ([id] uniqueidentifier primary key default(newid()), [name] varchar(20))
insert into #temp (name) values ('apple')
insert into #temp (name) values ('orange')
insert into #temp (name) values ('banana')
select * from #temp
drop table #temp

id                                   name
------------------------------------ --------------------
911B0CBD-4EED-4EB0-8488-1B2CDD915C02 banana
56CF3A80-A2DE-4949-9C9B-5F890824EA9C orange
5990B9FD-143D-41B0-89D1-957B2C57AB94 apple

Ответ 8

Я где-то читал, что шансы выиграть в лотерею будут эквивалентны 2 4-байтным "GUID". Стандартные 16-байтные идентификаторы GUID будут иметь гораздо меньший шанс столкновения.