Мэрия (случайно?) позволила расшифровать голоса на выборах в Мосгордуму. Мы это сделали и нашли кое-что странное Вы тоже можете попробовать
8 сентября 2019 года в трех округах Москвы прошел эксперимент по интернет-голосованию на выборах депутатов Мосгордумы. В одном случае его результаты оказались определяющими: в 30-м округе Роман Юнеман выиграл очное голосование, но уступил Маргарите Русецкой в дистанционном. Теперь он требует пересмотреть результаты. Организаторы эксперимента опубликовали результаты выборов, но не предоставили доступ к исходным данным. «Медуза» добыла секретный ключ, расшифровала все голоса избирателей и восстановила ход голосования.
Мэрия опубликовала зашифрованные голоса избирателей
Во время голосования департамент информационных технологий мэрии Москвы каждые полчаса выкладывал на специальном сайте сводные анонимные данные с зашифрованными голосами избирателей. Для каждого голоса там были указаны:
- номер избирательного округа (1, 10 или 30);
- номер блока в блокчейне, куда была записана транзакция с голосом;
- время формирования этого блока;
- зашифрованный выбор избирателя.
И (случайно?) оставила доступ к секретному ключу, который нужен для расшифровки голосов
После окончания голосования и публикации итогового CSV-файла с 9810 голосами избирателей приватный ключ был восстановлен из нескольких частей, заранее переданных доверенным лицам. Этот приватный ключ был записан в блокчейн. «Медуза» сумела найти нужный блок и транзакцию с приватным ключом через веб-интерфейс и скопировать данные до тех пор, пока доступ к блокчейну не был закрыт.
Обновление. В мэрии утверждают, что специально опубликовали приватный ключ. Но, если они намеренно предоставили наблюдателям доступ к приватному ключу, непонятно зачем через несколько часов нужно было закрывать доступ к веб-интерфейсу блокчейна.
Мы смогли расшифровать голоса избирателей
Для успешной расшифровки сообщений, зашифрованных по схеме Эль-Гамаля, кроме секретного ключа нам нужно было узнать один из компонентов открытого ключа — его модуль.
Чтобы его узнать, мы попросили научного редактора «Медузы» Александра Ершова, который голосовал через интернет, предоставить HTML-страницу своего бюллетеня. Там прописан публичный ключ, с помощью которого шифровался голос избирателя (в том числе необходимый нам модуль).
Если вы попытаетесь самостоятельно расшифровать голоса, учтите, что каждому кандидату на выборах был присвоен свой номер. Перед шифрованием в браузере пользователя этот номер возводился в квадрат. Поэтому, чтобы получить оригинальное значение, надо извлечь из расшифрованного числа квадратный корень.
Вот зачем нужны эти дополнительные вычисления
И выяснили, за кого голосовал наш коллега
Александр Ершов записал процесс интернет-голосования в HAR-файл. Он позволяет сохранить весь входящий и исходящий трафик при посещении веб-сайта или взаимодействии пользователя с веб-приложением. Мы нашли в этом архиве зашифрованный голос — дальше все было просто.
Записать процесс своего интернет-голосования совсем не сложно — не нужно даже ставить специальные программы. Встроенные инструменты для записи веб-трафика в HAR-файлы есть в браузерах Google Chrome, Mozilla Firefox, Safari и даже Microsoft Edge.
Если временная публикация приватного ключа была организована преднамеренно, то теоретически руководители, заставлявшие своих работников проголосовать определенным образом, могли выяснить, как распорядились своим голосом их сотрудники.
Подробнее про принуждение к голосованию
Данные интернет-голосования выглядят странно
Официальные результаты эксперимента, подведенные участковыми избирательными комиссиями № 5001, № 5002 и № 5003, полностью совпадают с расшифрованными нами голосами избирателей. Без доступа к блокчейну мы, правда, не можем проверить число выданных избирателям бюллетеней.
Но чтобы заметить странности, можно даже ничего не расшифровывать. Достаточно разбить весь день голосования на отрезки по 5 минут и сгруппировать попавшие туда блоки с голосами избирателей.
Двенадцать часов, отведенные на интернет-голосование, оказались разбиты на неравные диапазоны. Там были и три часа, в течение которых голоса избирателей вообще не записывались в блокчейн, и час, когда была сгенерирована половина всех блоков с голосами (правда очень мелких — в 1-3 транзакции), и 5 минут, за которые в блокчейне оказались почти 1400 голосов (14% от общего числа).
- С 08:02:58 до 09:26:04 были сформированы 53 блока (#668—#2046) с 3308 голосами избирателей; шаг между блоками (группами блоков) составлял около 2 минут.
- Произошел первый сбой продолжительностью 54 минуты.
- В 10:20:12 был сформирован один (#2525) с 35 голосами.
- Произошел второй сбой продолжительностью 48 минут.
- С 11:08:22 по 11:19:08 в блокчейн были записаны 7 блоков (#2651—#2818) с 92 голосами; шаг составлял 2 минуты.
- Был объявлен перерыв, длившийся 1 час 10 минут.
- С 12:29:18 до 13:08:18 были записаны 25 блоков (#2956—#3516) с 1189 голосами; шаг составлял 2 минуты.
- С 13:10:28 до 14:13:46 были сформированы 328 блоков (#3541—#4686) с 612 голосами; шаг между блоками составлял несколько секунд, а между группами блоков — от 2 до 11 минут.
- С 14:16:20 до 14:20:44 был записан 31 блок (#4731—#4804) с 1362 голосами; шаг составлял десятки секунд.
- С 14:21:02 до 15:22:48 было сформирован 76 блоков (#4809—#5530) с голосами 1092 избирателей; шаг составлял окого 1 минуты.
- С 15:24:48 до 20:00:44 были записаны 142 блока (#5544—#7168) с 2119 голосами избирателей; шаг вновь составлял около 2 минут.
- В 20:15:28 был записан последний блок (#7190) с одним голосом.
Но, кажется, это следы технических проблем, а не вбросов
А вот это мы можем показать только благодаря расшифрованным голосам. Продемонстрируем распределение голосов у трех принципиальных соперников — независимого кандидата Романа Юнемана, провластного кандидата Маргариты Русецкой, а также кандидата от «Умного голосования» и КПРФ Владислава Жуковского.
Хотя есть и странность: распределение голосов за провластных и независимых кандидатов
Избиратели, выбиравшие провластных кандидатов, во всех трех округах заметно чаще голосовали утром (в первые полтора часа, до первого сбоя), чем избиратели независимых кандидатов.
Мы не знаем, можно ли с помощью этих данных зафиксировать принудительное голосование и определить его вклад.
Мы поминутно восстановили ход интернет-голосования
Это оказалось возможным благодаря использованию блокчейна. Мы точно знаем, что каждый голос, оказавшийся в определенном блоке не мог быть отдан позже времени записи этого блока в блокчейн. Разработчики московской системы интернет-выборов обещали случайным образом генерировать задержку для каждого бюллетеня перед записью в блокчейн. Возможно, она помогает только перемешивать голоса внутри блоков: голос Александра Ершова оказался в первом же блоке, сформированном после заполнения бюллетеня.
Посмотрите на реконструкцию противостояния Романа Юнемана и Маргариты Русецкой. Если допустить, что нам заранее известны результаты обычного «бумажного» голосования, то можно пошагово увидеть, как постепенно тает преимущество Юнемана в 581 голос.
А теперь делимся данными для исследователей
Вы можете скачать:
- публичный и приватный ключи, использовавшиеся на выборах 8 сентября 2019 года
- зашифрованные бюллетени
- расшифрованные бюллетени
Не забудьте написать нам, если вы найдете в этих данных что-нибудь интересное.