Я опишу минимальную схему, которая, с моей точки зрения, обеспечивает тайность голосования и невозможность его подделки, в том смысле, что каждый проголосовавший сможет проверить свой голос. В конце я приведу некоторые дополнения, которые не сказываются на тайности голосования и невозможности его подделки, но делают схему более удобной в применении. Схема предполагает возможность делегировать свой голос делегату.
Предположения: у человека есть Логин (уникален в системе), секретный пароль (никогда не передается по телекоммуникационным сетям, знает его только пользователь, нужен для доступа к паре открытый-закрытый ключ), пара открытый-закрытый ключ (закрытый ключ используется для подписи, открытый ключ - для шифрования). Закрытый ключ известен только пользователю, открытый ключ - кому угодно. Открытые ключи передаются по каналам связи, закрытые ключи никогда не передаются по каналам связи. Пара открытый-закртый ключ выдается по паспорту, что обеспечивает однооднозначное (одно - 2 раза) соответствие между пользователями и парами ключей.
Голосование: вопрос, варианты ответов (конечное число, варианты определяются предварительно). Каждое голосование имеет Уникальный Серийный Номер Голосования. Уникальный Серийный Номер Голосования передается по каналам связи. Варианты ответов и их числовые представления известны всем. Они передаются по каналам связи.
Процесс голосования:
1. Пользователь решает принять участие в голосовании.
2. Голосующий подписывает Уникальный Серийный Номер Голосования своим закрытым ключом.
3. Голосующий выбирает вариант, за который он отдет свой голос.
4. Пользователь выбирает произвольное число, какое захочет, назовем его Секрет Пользователя в Голосовании. Секрет Пользователя в Голосовании НЕ передается по каналам связи в первозданном виде.
Составляем таблицу участвоваших в голосовании:
1. Логин (по нему мы можем выяснить все данные пользователя: ФИО, контакты, фото).
2. Подписанный закрытым ключом пользователя Уникальный Серийный Номер Голосования.
3. Число делегировавших пользователю с Логином пользвателей, которыми он проголосовал в этом голосовании плюс один (за себя самого), с подписью.
Эта таблица защищиает результаты голосования от изъятий и вложений. Если в этой таблице есть запись, что пользователь принял участие в голосовании, то и в следующей таблице должна быть запись, соответствующая пользователю, причем записей в таблице результатов голосования будет равно Числу в поле 3 из предыдущей таблице.
Составляем таблицу результатов голосования.
Структура записей в этой таблице:
1. Уникальный Серийный Номер Голосования.
2. Числовое Представление Варианта Ответа.
3. Секрет Пользователя в Голосовании, подписанный закрытым ключом пользвателя. Сам Секрет Пользователя в Голосовании в это поле не вносится.
4. Специальное Поле.
Столбцы 1,2 используются для подведения итогов голосования.
Столбецы 3,4 - используются для проверки пользователями (самим пользователем либо делегировавшим ему свои голоса) правильности стобцов 1,2.
Специальное Поле - некоторое зашифрованное поле.
В записи пользователя, который голосовал сам:
Секрет Пользователя в Голосовании - подписанное самим пользователем.
Специальное Поле - это подписанные закрытым ключом пользователя данные (Уникальный Серийный Номер Голосования, Числовое Представление Варианта Ответа, Логин, Секрет Пользователя в Голосовании) и эти же данные в открытом виде. Эти открытые данные и они же подписанные шифруются открытым ключом польвателя. Расшифровать его может только сам пользователь.
В записи пользователя, который делегировал свой голос:
Секрет ДЕЛЕГАТА в Голосовании - подписанное ДЕЛЕГАТОМ.
Специальное Поле - это подписанные закрытым ключом ДЕЛЕГАТА данные (Уникальный Серийный Номер Голосования, Числовое Представление Варианта Ответа, Логин Делегирующего, Секрет Делегата в Голосовании) и эти же данные в открытом виде. Эти открытые данные и они же подписанные шифруются открытым ключом ДЕЛЕГИРУЮЩЕГО. Расшифровать его может только сам делегирующий.
Зашифрованное Специальное Поле передается по каналам связи.
Никакаие другие данные по голосованию не сохраняются.
После проведения голосования, любой человек может скачать результаты и подвести итоги голосования.
Поиск своей записи в голосовании: перебираем все строки, пытаемся расшифровать Специальное Поле. Та строка, где Специальное Поле расшифровалось, и там есть логин пользователя, является записью пользователя.
Проверка правильности учета своего неделегированного голоса: ищем свою запись, проверяем свою подпись, сравниваем открытые результаты с тем, что расшифровали и проверили.
Проверка правильности учета своего делегированного голоса: ищем свою запись, проверяем подпись делегата, сравниваем открытые результаты с тем, что расшифровали и проверили.
Обеспечение тайны голосования - есть.
Расшифровать Специальное Поле можно только с помощью закрытого ключа пользователя.
Невозможность подделки голосования - есть.
Данные подписанны либо самим пользователеми, либо делегатом.
Проверяя свой голос, который сделан делегатом, пользователь узнает Секрет Делегата в Голосовании. По нему и открытому ключу делегата, пользователь может проверить количество голосов, которыми проголосовал делегат в данном голосовании. Это помогает удостовериться в том, что результаты голосования не подделаны.
Очень многие аспекты тайны голосования и невозможности его подделки обсуждены в теме
http://xn----7sbabbvhzqeqhjj5a7a4euhk.xn--p1ai/forum/viewtopic.php?f=5&t=48. Если вы ее не читали, очень прошу почитать. Не хочется отвечать на те же вопросы, на которые уже отвечал.
Ниже описана модификация для быстрого поиска записи пользователя голосования:
Выдаем пользователю Уникальный Одноразовый Идентификатор Пользователя в Голосовании. Добавляем Уникальный Одноразовый Идентификатор Пользователя в Голосовании в таблицу результатов голосования и в Специальное Поле. Теперь пользователь может искать свою запись по Уникальному Одноразовому Идентификатору Пользователя в Голосовании.
Невозможно выдать один и тот же Уникальный Одноразовый Идентификатор Пользователя в Голосовании нескольким пользователям, так как иначе будет несколько записей в базе данных с одинаковыми Уникальный Одноразовый Идентификатор Пользователя в Голосовании, что легко проверяется, либо одна запись, Специальное Поле которой сможет расшифровать только один из пользователей.
Описанная выше схема работает при следующих условиях:
1. Никто не запоминает соответсвия Уникальный Одноразовый Идентификатор Пользователя в Голосовании <--> Логин в открытом виде.
2. Уникальный Одноразовый Идентификатор Пользователя в Голосовании могут получить только пользователи, прошедшие аутентификацию, то есть не существует Уникальный Одноразовый Идентификатор Пользователя в Голосовании, которые бы не соответствовали реальному пользователю системы.
Для дополнительного удобства пользователя (чтобы ему не пришлось запоминать Уникальный Одноразовый Идентификатор Пользователя в Голосовании), создаем следующую таблицу.
Таблица поиска:
1. Логин пользователя
2. Уникальный Серийный Номер Голосования
3. Уникальный Одноразовый Идентификатор Пользователя в Голосовании, зашифрованный открытым ключом пользователя.