Comments 46
Выпавшее число вычисляется путём взятия остатка от деления результата SHA-3 на 37.
Это не самый правильный способ. Во-первых, множество возможных значений хэша обычно является степенью двойки, что не может делиться на 37. Так что некоторые остатки будут выпадать чуть-чуть чаще других. Разница совсем ничтожна, но как-то неэстетично. Во-вторых, доказать, что значения данного хэша перемешаны равномерно — очень нетривиальная задача. Хотя обычно по построению хэш-функции «хорошо» перемешивают.
Предлагаю универсальный способ генерации случайного результата. Пусть каждый заинтересованный участник (в данном случае это игрок и казино) сгенерируют любым способом число от 0 до 36 (рекомендуемый способ — посредством своего автономного ГСЧ, хотя это не обязательно), затем вычислит от него хэш заданной хэш-функцией и вышлет его организатору. Собранные хэши должны быть помещены в блокчейн, чтобы все их видели. Затем каждый участник высылает свое сгенерированное число, что тоже помещается в блокчейн, чтобы все могли проверить, что хеши были получены именно из этих чисел. Результатом объявляется сумма этих чисел по модулю 37. Нужно только немного побороться с теми, кто вышлет хэш, но зажмет свое исходное число, заблокировав тем самым всю процедуру. Но лекарство довольно очевидно.
Если я правильно понял описанный вами алгоритм, на каждое пари придётся совершить две транзакции: одна для хэшей, другая для сгенерированных чисел. Это, во первых, увеличит стоимость ставки (которая = стоимости жетонов + плата за транзакцию). А во вторых, из-за того что время генерации блока в хотя и бывает, в среднем 15 секунд, зачастую доходит полуминуты. А одна из самых частых жалоб на рассмотренную реализацию, как я понимаю — именно низкая скорость. Обычно ставка проходит за 30-60 секунд. Если ждать лишний блок — станет до 90 секунд, это многих раздражает.
Разумеется, там и близко нет 2.7%. Например, для 256-битного хэша нетрудно посчитать. Применяя теорему Ферма, имеем: 2^256 = 16 (mod 37). То есть каждый из остатков с 0 по 16 будет попадаться с вероятностью (x+1)/2^256, а каждый из оставшихся остатков — с вероятностью x/2^256, где x = ⌊2^256/37⌋. Итоговый дисбаланс (отношение вероятностей) составляет порядка 2^{-251}.
Да, действительно, нужно ждать две транзакции. Впрочем, вместо блокчейна можно использовать более слабые механизмы для публикации. Но, с другой стороны, в изначальном алгоритме зачем-то нужно ждать BlockDelay блоков, в то время как предлагаемые мной две транзакции вполне могут попасть в соседние блоки, то есть ждать даже меньше.
BlockDelay в настоящее время равен 1. Если бы он был равен нулю, то майнер мог бы вместо изменения nonce блока менять свою ставку, и с определённой долей вероятности мог бы не только получить вознаграждение за блок, но и выиграть в рулетку.
При этом ставка гарантированно будет рассчитана в BlockDelay блоке после её принятия.
С вашем-же предложением — как сервер, так и игрок могут не присылать свои числа довольно долго.
Кстати, если игрок не прислал число — ок, его ставка проигрывает. А если число не прислал сервер? А если он его не прислал не потому, что увидел ставку игрока и понял что проиграл, а потому что DDoS?
Попытался найти информацию о пригодности SHA-3 в качестве ГСЧ, её на удивление очень мало.
Из самого полезного: Statistical Analysis of Reduced Round Compression Functions of SHA-3 Second Round Candidates, Why not SHA-3?, Sponge-based pseudo-random number generators.
Насколько я понял, она считается вполне подходящей, а код типа r = sha3(blockash, nonce) % max — общепринятая практика.
Во-первых, есть общие соображения (по фон Нейману):
Кто пытается арифметическими методами генерировать случайные числа, тот, конечно, живет во грехе.
Во-вторых, даже хорошие криптографические решения опираются на сложную математику, убедиться в практической применимости данных методов весьма непросто.
А для данной реализации рулетки я даже придумал атаку. Нужно быть майнером и пытаться сгенерировать несколько валидных блоков, которые будут служить в качестве источника результата. Должно повезти дважды: (1) просто сгенерировать валидный блок, (2) найденный блок должен быть «хорошим», то есть дающим выигрыш ставке атакующего. Тогда остается только впихивать в сеть найденный хороший блок, и если повезет, (3) сеть выберет именно этот блок, и выигрыш будет в кармане. Если найдется «плохой» блок, то в сеть его вбрасывать не надо. Поскольку деятельность обычных майнеров — результат везения (1) и (3), то по затратам здесь атакующий выходит в ноль (считаем, что комиссии майнеров примерно равны затратам на вычисления). Нужно лишь, чтобы ставка была достаточно высока, чтобы покрыть риски нахождения «плохих» блоков.
Согласен, анализ таких решений — задача непростая. Кстати, спасибо за пояснение про вероятности веткой выше.
Про атаку на данный алгоритм вы не совсем правы. Надо сгенерировать BlockDelay + 1 связанных блоков, таких что в первом — выигрышная ставка, которая рассчитывается на основе хэша последнего. При этом изменение ставки требует пересчета всей цепочки.
Пусть t — среднее время поиска блока в сети.
Пусть p — вероятность, что наш конкретный майнер найдет блок за время t.
Если я правильно понимаю, то вероятность того, что майнер за время t успеет найти BlockDelay + 1 взаимосвязанных блоков равняется p ^ (BlockDelay + 1).
И это ещё если он найдет способ одновременно создавать ставку и blockhash последнего блока… Не представляю как это сделать.
Нет, идея атаки не в том, чтобы менять ставку, а в том, чтобы попытаться найти тот блок, который определяет выигрыш. Нужно действовать в точности как настоящий майнер, но выбрасывать найденные блоки, если они проигрышные. Таким образом можно лишь немного сместить шансы на выигрыш в свою пользу. А расплачиваться нужно валидными найденными блоками, которые в нормальной ситуации принесли бы законную комиссию.
Допустим, майнер делает одну из ставку, с наибольшей вероятностью выигрыша. Для примера «на красное». Надо, чтобы выигрыш принёс больше тех 5 ETH, которые он получит за найденный блок.
При ставке «на красное» сумма ставки должна быть не менее 2.5 ETH.
С другими типами ставок будет та же история — сумма меньше, но и вероятность что другой блок окажется «хорошим» тоже меньше.
Правда из-за Uncle-блоков майнер всё-таки может получить часть награды за неопубликованный блок. Так что действительно, его шанс выиграть окажется немного больше, чем у обычного игрока.
Но мне, всё же, кажется это весьма извращённый метод играть в казино…
Из этих выкладок можно сделать оценку снизу на то, какой должна быть ставка в казино, чтобы такая атака была оправданной. Правда, из-за того, что, во-первых, казино берет себе 1/37, и, во-вторых, невелики вероятности нахождения блока и включения его в цепочку, эта стратегия может потребовать очень много ресурсов: огромная ставка плюс огромные мощности.
Если же вопрос о том, почему в блокчейне нельзя такой подход организовать — тут всё просто: смарт-контракты Ethereum ничего не знают о мире вне блокчейна.
А ещё вычисления в блокчейне довольно дорогие, разархивировать архив на каждую ставку — так и разориться можно.
Такое очень много где есть. Например в казино Bitsler сервер генерирует случайное число (Seed server) и заранее показывает эго хэш. Так же клиент видит свой Client seed и может его перегенерировать. Плюс используется nonce — порядковый номер ставки игрока.
И далее, для игры в Multicolor рулетку:
$seed = $serverSeed.'-'.$clientSeed.'-'.$nonce;
do {
$seed = sha1($seed);
$lucky = hexdec(substr($seed,0,8));
} while ($lucky > 4294960000);
$luckyNumber = ($lucky % 100000) / 1000;
if ($luckyNumber < 0)
$luckyNumber = -$luckyNumber;
echo $luckyNumber;
Если же казино будет подсовывать неслучайные результаты и делать это честным образом (т.е. 'манипулировать со случайностью' ДО сделанных ставок), то обманет казино в первую очередь само себя, т.к. те, чье поведение подвержено манипуляциям может быть и будут чаще проигрывать, но те, кто способен если не отгадать эти манипуляции, то хотя бы провести статистический анализ эн предыдущих игр, наверняка будут чаще выигрывать.
Вместе с тем, может так случиться что владелец решит увеличить свою прибыль сверх этих 2.7% за счёт своего понимания человеческой психологии. Разумеется, это риск. Но кто сказал, что владелец казино — не азартный человек?
Допустим, казино формирует серии псевдо-случайных результатов персонально для каждого игрока по 100 штук за раз. Изначально результаты формируются полностью случайно. Однако по мере того, как игрок делает ставки некий чёрный ящик в казино анализирует поведение игрока и, в случае если понимает что игрок следует определённой стратегии, следующую серию результатов может сформировать спецальным образом.
Конечно, игрок тоже может анализировать результаты и в случае неравномерного их распределения — воспользоваться этим. Но не все сообразят так сделать. А «черный ящик» может выдавать сдвинутые результаты только тем, кто своим поведением показал, что не занимается анализом. Не забывайте, казино знает про игрока всё — вплоть до того, как он двигает мышкой.
Первый загадывает (пишет на бумажке) число от 0 до 36
Второй делает ставку
Первый называет загаданное число
Ставки и выигрыши — по рулеточным правилам.
При загадывании числа первый может пользоваться чем угодно, от TRNG, до учебника психологии.
В каком случае вы бы предпочли сесть за игровой стол вторым номером? (варианта 'не садиться за стол' нет)
А на месте первого игрока я бы сначала использовал TRNG и запустил бы нейронную сеть, тренируя её на ставках соперника в зависимости от N предыдущих чисел, чтобы она пыталась их предсказывать. И когда счёл бы, что сеть достаточно натренирована, попробовал бы с её помощью исключать числа которые, предположительно, дадут второму выигрыш.
Играя вторым номером вы всегда сможете свести преимущество первого игрока к 2,7%. Просто сами используйте TRNG для ставок.
И можете точно так же, как первый номер анализирует ваши ставки, анализировать его 'результаты'. Если на каком-то этапе анализа захотите — перейдете к активным действиям. При этом у вас есть важное преимущество — размер ставки выбираете вы.
И я думаю, большая часть игроков именно так и поступает: им интересно проверить свою интуицию и везение, а не работать роботом. Особенно зная, что робот всегда проигрывает.
Впрочем, лично мне интересно роботов писать… А в случае этой рулетки — оно ещё и разрешено организаторами.
интересно проверить свою интуицию и везениеВы всерьез собрались противопоставлять интуицию и везение TRNG?
Интуицию, везение и интеллект имеет смысл противопоставлять другому интеллекту (что есть вариант 2).
А в случае этой рулетки — оно ещё и разрешено организаторами.Разговор-то не за эту рулетку, а за то, что самое глупое, что может сделать казино — вносить априорную неслучайность в результаты.
Разговор начался с вопроса о том, имеет ли смысл владельцу казино заменять TRNG на что-то другое. И моя позиция заключается в том, что если игрок — человек, то такая замена может быть выгодна.
Лично для меня анализ этого смарт-контракта был ещё и способом разобраться в Solidity.
Столбики и по 95% выигрыша выдавали, куда выше, чем в рулетке.Незаряженная 'европейская' (с одним zero) рулетка возвращает 36/37, т.е. ~97,3%
p.s. как можно потестировать игру, не загружая блокчейн ethereum (под текущим его ддос это проблематично) или где его можно загрузить в виде архива?
После установки MetaMask он предложит создать кошелёк и выдаст на этот кошелёк 1 ETH в тестовой сети Ropsten. Вот на этот тестовый эфир и можно попробовать игру. Разумеется, это будут «фантики», т.к. ETH в тестовой сети никакой ценности не имеют.
Но конкретный сайт игры работает с конкретным экземпляром контракта. Сам контракт и входящие транзакции (ставки) исполняются майнерами последовательно во время формирования нового блока. Разумеется значение имеет только тот блок, который попадёт в блокчейн.
Я ожидал что я запущу клиент, во встроенном в нем браузере открою 'страницу' по некому стартовому адресу контракта и смогу там играть. Без необходимости в существовании какого то стороннего сервиса.
Это все еще недостижимо?
Когда вы делаете ставку скрипт на странице рулетки через web3 просить кошелёк выполнить транзакцию. Тот через JSON-RPC обращается к какой-нибудь (прописанной авторами MetaMask или настроенной вами самостоятельно) Ethereum-node, которая публикует транзакцию в сети.
Дальше майнер, пожелав включить эту транзакцию в блок, исполняет её код. А в коде — обращения к методу placeBet() смарт-контракта рулетки.
Если вы принципиально нехотите никаких сторонних сервисов — только вы и сеть Ethereum, вам потребуется Mist в режиме полной ноды. В его встроенном броузере открываете сайт рулетки и всё то же самое, только нода — сразу ваша, а не какая-то сторонняя.
Или даже не открываете сайт рулетки, а просто в консоле вызываете нужные методы смарт-контракта.
Я говорю о том что разработчики контракта не предоставляют всего этого в готовом виде, хотя у них этот функционал уже есть, у них же это как то работает? или я опять что то не понимаю.
В блокчейне ethereum не хранится код с интерфейсам пользователя для контрактов принципиально? или это техническое ограничение? Почему нужно открывать какой то вебсайт?
С другой стороны, кто угодно может сделать UI к этому контракту. Вам не нравится их сайт — делайте свой.
Почему UI не хранится непосредственно в блокчейне — хороший вопрос. Интересно узнать, как вы себе это представляете. Например, в каком виде его хранить? И, главное, зачем это делать — какая могла бы быть от такого хранения польза?
Теоретически, вы можете взять, например, весь код HTML+CSS+JS своего приложения и записать вместе с контрактом в блокчейн. Это будет довольно дорого: если я правильно понял спецификацию, за a байт придется заплатить Cmem(a) = Gmemory*a + (a^2/512) единиц газа, где Gmemory = 3. А обычная цена газа сегодня 0.00000002 ETH. Таким образом, 1Мб обойдется ~ 0.1049 ETH. Но вы можете это сделать.
Только просматривать такой UI на сегодня момент будет нечем.
Там плюшки всякие, маяки, проверяемость…
Это чтобы с ГПСЧ не морочиться и предотвратить возможность описанной потенциальной атаки?
Ну, и по-настоящему случайные числа.
В этом ключе интересен проект Aeternity, они собираются сделать блокчейн со встроенными оракулами. Идея в том, что автор контракта может сформулировать вопрос (человеческим языком) а пользователи сети будут, при желании, на него отвечать. Далее, методом консенсуса, схожим с PoS, будет определён верный ответ.
Дальнейшая жизнь пари начинается с вызова функции ProcessGames(), который, после появления новой ставки, выполняется, в настоящее время, с адреса ...Как этот адрес узнаёт о появлении новой ставки? И немного расширю вопрос (думаю, не одному мне нужно это понять). Контракт, при выполнении потребляет газ. Этот газ списывается с адреса отправителя, активировавшего контракт. Количество газа зависит от, грубо говоря, количества выполненного кода. Например:
Простой контракт лотереи. 10 игроков присылают по 1 ETH и происходит розыгрыш. Для девяти из них количество газа будет, например 0,002 (т.к. контракт только принимает платёж), а для последнего, который активировал розыгрыш, количество газа будет больше, ибо выполнится весь остальной код контракта.
Т.е. чтобы всё было честно, активироваться розыгрыш должен снаружи. Вот тут мы и возвращаемся к основному вопросу. Как 0xa92d36dc1ca4f505f1886503a0626c4aa8106497 узнал о появлении ставки и как он послал вызов функции ProcessGames()?
Проверяем честность игры в рулетку на смарт-контракте Ethereum