Перейти к основному содержимому

Проверка честности

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

Как это устроено

  1. Сервер фиксирует секрет

    Сервер генерирует случайный серверный сид (32 байта) и публикует только его SHA-256 хеш. Сам сид остаётся скрытым — это обязательство, которое нельзя изменить задним числом.

  2. Вы задаёте свой сид

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

  3. Раунд вычисляется формулой

    Для каждого раунда берётся HMAC-SHA256 от строки «клиентский сид : номер раунда» на ключе серверного сида. Первые 13 шестнадцатеричных символов дают число от 0 до 1.

  4. Сид раскрывается

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

Формула

hmac  = HMAC_SHA256(key = serverSeed, message = clientSeed + ":" + nonce)
roll  = parseInt(hmac.slice(0, 13), 16) / 2^52     // число в [0, 1)

// Кейс: предметы отсортированы, веса суммируются
target = roll × Σweights
выпадает первый предмет, у которого накопленная сумма весов > target

Берутся 52 бита, а не 32: при 32 битах возможных значений всего ~4,3 млрд, и на дистанции это заметно искажает шансы предметов с вероятностью 0,01%.

Колесо: сектор картинки

Раунд колеса общий и идёт по таймеру, поэтому пара сидов у него своя: серверный создаётся при открытии раунда — до первой ставки, — а клиентский собирается из ставок раунда. Результат — не множитель, а номер сектора на картинке, и колесо на экране докручивается именно до него. Поэтому стрелка не может остановиться на одном цвете, пока в базе записан другой.

clientSeed = SHA256("<id игрока>:<множитель>:<сумма>|…")  // в порядке ставок
nonce      = номер раунда
roll       = parseInt(HMAC_SHA256(serverSeed, clientSeed + ":" + nonce).slice(0, 13), 16) / 2^52

сектор     = floor(roll × 25)        // 25 секторов, все одинакового размера
множитель  = раскладка[сектор]       // та же, по которой нарисовано колесо

Секторы равны по размеру, поэтому шанс цвета — это просто его доля на колесе: ×2 занимает 12 секторов из 25, ×21 — один. Отдельного числа вероятности, которое можно было бы поменять, в коде нет; таблица на странице игры считается из той же раскладки.

Джекпот: общий раунд

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

clientSeed = SHA256("<id игрока>:<сумма>|<id игрока>:<сумма>|…")  // в порядке ставок
nonce      = номер раунда
roll       = parseInt(HMAC_SHA256(serverSeed, clientSeed + ":" + nonce).slice(0, 13), 16) / 2^52

// Победитель: ставки в том же порядке, вес ставки = её сумма
target = roll × банк
выигрывает первая ставка, у которой накопленная сумма > target

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

Список ставок, по которому считался клиентский сид, раунд отдаёт вместе с результатом: GET /api/games/jackpot возвращает последние разыгранные раунды с полями entries, serverSeed, clientSeed и rollValue. Формула публичная, значит и её входные данные должны быть публичными.

Ваши сиды

Войдите, чтобы увидеть свою пару сидов и управлять ею.

Калькулятор проверки

Введите раскрытый серверный сид, клиентский сид и номер раунда. Расчёт выполняется прямо в браузере — данные никуда не отправляются.

Необязательно. Если указать — проверим, что сид соответствует обязательству.