Доказуемо честно

Кости, в которых не нужно верить нам на слово

До начала игры мы фиксируем секретное число и публикуем его отпечаток. По окончании публикуем само число. Между этими двумя моментами каждый бросок уже предопределён — а после любой может пересчитать их все и убедиться, что ничего не сдвинулось.

Открыть журнал

То, что не исправит даже хороший генератор случайных чисел

Наши кости берутся из криптографического генератора операционной системы — того же источника, что защищает вход в банк, а не из ярлыка, которым пользуется большинство игр. Это решает вопрос о качестве случайности. И ничего не решает в том вопросе, который на самом деле задают игроки.

Честно выпавшая кость и намеренно выбранная выглядят потом одинаково. И то и другое — просто число в журнале.

Значит, полезный вопрос не «хорош ли ваш генератор?», а «могу ли я проверить?». Всё, что ниже, существует ради того, чтобы ответ был «да» — без просьбы поверить нам хоть в чём-то.

Запечатано до, вскрыто после

Четыре шага. Два из них вы можете выполнить сами — и именно эти два поймали бы нас.

  1. 1

    Запечатать

    До первого броска сервер берёт секретное 32-байтовое число — серверное зерно — и публикует его отпечаток SHA-256 обоим игрокам. Отпечаток не выдаёт ничего, но зерно уже зафиксировано: любое другое дало бы другой отпечаток.

    commit0df0916cb0…2904e706
  2. 2

    Смешать

    Ваше приложение генерирует собственное случайное зерно и отправляет его, когда вы садитесь за стол. Зёрна обоих игроков входят в каждый бросок, поэтому мы не можем заранее подобрать зерно с удобными нам бросками — в момент фиксации мы не знаем, что вы добавите.

    clientSeeda26460084a0ef89b:d4f28bac6efd1b6e
  3. 3

    Вывести

    Каждая кость считывается из HMAC-SHA256 от зёрен и номера броска. Ничего не хранится и ничего не выбирается: одни и те же три входа всегда дают одну и ту же кость, и никакие другие её не дают.

    die(n) = (HMAC-SHA256(serverSeed, "clientSeed:n:round")[0] < 252) % 6 + 1
  4. 4

    Вскрыть

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

    serverSeed5cde3365be…7b6b2bd5

Значения выше — настоящее доказательство игры №148, завершённой игры, которую может посмотреть любой. Введите этот номер в поле ниже и убедитесь сами.

Проверить игру — здесь и сейчас

Введите номер игры. Страница получит её доказательство, затем заново возьмёт хеш зерна и пересчитает каждую кость средствами криптографии вашего собственного браузера.

Вычисления идут на вашем устройстве. Ничего из введённого нам не отправляется, и ни одна галочка на этой странице не является значением, которое передали мы, — иначе мы просили бы поверить нам в вопросе о том, можно ли нам верить.
Или вставьте три значения сами

Почему ни одна грань не вероятнее даже чуть-чуть

Байт — число от 0 до 255, то есть 256 вариантов. 256 не кратно шести: это 6 × 42 и ещё 4 в остатке. Возьмите остаток от деления байта на шесть — и четыре грани тихо получат 43 шанса из 256, а две другие 42. Смещение крошечное, но на миллионе бросков это уже настоящее преимущество. Поэтому эти четыре значения отбрасываются.

252 = 6 × 42. Каждой грани достаётся ровно одинаковое число байтов, значит каждая — ровно одна шестая.

Где доказательство заканчивается

Два вида костей на этом сайте цепочкой не покрыты. Они названы здесь, а не опущены: утверждение о честности с тихой дырой стоит меньше, чем отсутствие утверждения.

  • TelegramКости, брошенные в чате ботаЕсли бросить собственной анимацией костей Telegram, это число приходит от Telegram, а не от нас; никакое наше зерно его не воспроизводит. Опубликованное доказательство перечисляет ровно эти позиции, а журнал ставит там знак Telegram вместо грани. Для полностью проверяемой игры бросайте в приложении.
  • ТренировкаИгры против компьютераОфлайновая тренировочная игра бросает кости на вашем устройстве, без зерна и без доказательства. Нет соперника и нет ставки — нечего доказывать и нечем рисковать.

Всё остальное — онлайн 1v1, комнаты с друзьями и турниры, бесплатные или на ставку — работает на описанной выше цепочке.

Та же проверка, без этой страницы

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

JavaScript
const enc = new TextEncoder();
const hex = (b) => [...new Uint8Array(b)].map((x) => x.toString(16).padStart(2, '0')).join('');

// 1. the seed we revealed must hash to the commitment you were given first
const commitOk = hex(await crypto.subtle.digest('SHA-256', enc.encode(serverSeed))) === commit;

// 2. every die, re-derived from that seed
const key = await crypto.subtle.importKey(
  'raw', enc.encode(serverSeed), { name: 'HMAC', hash: 'SHA-256' }, false, ['sign']);

async function die(n) {
  for (let round = 0; round < 16; round++) {
    const mac = new Uint8Array(
      await crypto.subtle.sign('HMAC', key, enc.encode(`${clientSeed}:${n}:${round}`)));
    for (const b of mac) if (b < 252) return (b % 6) + 1;
  }
}

Каждое доказательство открыто по адресу /fair/<id> — без ключа, без аккаунта, без имён игроков и без сумм. Только кости.

Вопросы, которые задают на самом деле

Я проиграл четыре игры подряд. Кости против меня?

Не могут быть. Каждая кость завершённой игры была предопределена до её начала зерном, зафиксированным заранее, и все их можно пересчитать выше. Серии кажутся адресными, но таковыми не являются: с двумя костями соперник обыгрывает вас четыре игры подряд куда чаще, чем принято думать.

Может ли сервер выбрать бросок в решающий момент?

Ему пришлось бы сломать одну из двух проверок. Либо он публикует зерно, хеш которого не совпадает с отпечатком, выданным до игры, — это видно каждому, — либо публикует настоящее, и тогда кости, которые оно порождает, и есть те, которыми вы играли.

А если моё приложение не отправило своё зерно?

Вместо него генерируется случайное, чтобы цепочка всегда была корректной. Это ослабляет только ваш собственный вклад; фиксация и все проверки выше остаются в силе.

Влияет ли раскрытое зерно на мою следующую игру?

Нет. Для каждой игры, включая матч-реванш, берётся новое зерно и публикуется новый отпечаток. Опубликованное зерно больше никогда не определяет броски.

Почему на некоторых костях знак Telegram?

Они брошены анимацией костей Telegram в чате бота, то есть пришли от Telegram, и никакое наше зерно их не воспроизводит. Они помечены, а не скрыты, и число, которое наша цепочка дала бы на этой позиции, намеренно не показано — это не та кость, которую кто-то бросал.

Откроется Telegram, чтобы подтвердить, что это вы. Мы никогда не видим ваш пароль.

Играть гостем

Продолжая, вы принимаете Условия и подтверждаете, что вам 18 лет или больше.
УсловияКонфиденциальностьОтветственная игра