
Neste tutorial, implementamos um sistema de votação privada baseado em ZK, o Privote, no qual ninguém pode ver as escolhas dos eleitores até o encerramento da votação

Imagine que você é um eleitor registrado votando em uma questão específica ou candidato. Uma parte externa quer que você venda seu voto, ou seja, quer que você vote na escolha dela, não na sua, em troca de alguns incentivos. Ela precisará de uma prova do seu voto caso você ceda à demanda — geralmente por meio de um recibo de transação na blockchain. Embora isso possa parecer uma ótima oportunidade se você estiver inclinado a vender seu voto, isso compromete a integridade de todo o processo eleitoral.
Como podemos permitir que os eleitores votem em seus candidatos ou questões preferidos enquanto ocultam suas escolhas para que ninguém mais possa vê-las? A resposta está em uma única palavra: Criptografia.
Neste tutorial, vamos explorar como desenvolver uma aplicação de votação simples — a Privote — que utiliza criptografia na blockchain. Quando chegar o momento, os votos são descriptografados e contabilizados, e os resultados são publicados de volta na blockchain, mantendo o anonimato dos eleitores. Os resultados são verificados por meio de uma prova de conhecimento zero (ZK). Embora não seja perfeita, este exemplo ilustra os conceitos subjacentes.
Consulte o post do blog de Vitalik Buterin para uma compreensão aprofundada sobre votação em blockchain.
Antes de prosseguirmos, aqui está um resumo dos principais componentes do dapp Privote:
Contrato Inteligente: Este sistema armazena múltiplos votos (cédulas) e dados relacionados, como títulos, opções disponíveis e dados criptografados.
Parte Confiável: Um servidor off-chain que descriptografa os votos, calcula os resultados e os publica na blockchain. Este servidor é chamado de "Parte Confiável" por uma razão: ele não pode publicar resultados incorretos, seja por cálculo impreciso ou por censura de mensagens.
Frontend: Uma plataforma onde os usuários conectam suas carteiras e enviam votos. Haverá também uma página separada para o "admin" visualizar o número de votos registrados e liberar os resultados manualmente.
Para construir a Privote com sucesso, precisamos resolver dois desafios:
Permitir que qualquer eleitor criptografe seu voto enquanto permite que a parte confiável o descriptografe?
Garantir que a parte confiável seja confiável e possa fornecer uma prova ZK do cálculo, mas o que exatamente estamos provando?
Para resolver isso, podemos adotar a criptografia assimétrica. Ao contrário da criptografia simétrica, que usa a mesma chave para criptografar e descriptografar dados, a criptografia assimétrica usa duas chaves diferentes: uma para criptografar e outra para descriptografar. Existem vários algoritmos de criptografia assimétrica, incluindo ElGamal, RSA, DSA e técnicas de curva elíptica. Para este tutorial, usaremos as técnicas de curva elíptica, especificamente o Diffie-Hellman key exchange(ECDH)](https://www.upguard.com/blog/diffie-hellman)(ECDH)).
No ECDH, tanto a parte confiável quanto cada eleitor possuem seus próprios pares de chaves (uma chave pública e uma chave privada), e a escolha da curva elíptica, como a curva Baby Jubjub usada aqui por sua adequação em provas de conhecimento zero, impacta a segurança e a eficiência das operações criptográficas; a curva Baby Jubjub é definida pela equação y^2 = x^3 + 168698 x 2 + x, e os pares de chaves são gerados como pares específicos de pontos nessa curva:
Na função generateKeyPair, primeiro crio uma chave privada aleatória segura e, em seguida, calculo a chave pública correspondente realizando uma operação matemática específica (multiplicação escalar) em um ponto predefinido na curva, frequentemente chamado de ponto base ou ponto gerador. No código, esse ponto é denominado Base8. O resultado dessa multiplicação é outro ponto na curva, denotado por suas coordenadas X e Y. Em seguida, o ponto é formatado em um bigint para uso conveniente com a função packPoint.
O eleitor cria uma cifra combinando sua chave privada com a chave pública da parte confiável. Essa cifra é usada para criptografar o voto. O contrato inteligente então salva o voto criptografado e a chave pública do eleitor juntos.
A parte confiável pode criar uma cifra usando sua chave privada e a chave pública de cada eleitor para descriptografar os dados.
Na função generateKeyPair, formatamos a chave pública para facilitar o uso com a função packPoint. No código acima, com unpackPoint, a convertemos de volta à sua forma original porque precisamos criar um segredo compartilhado combinando a chave privada e a chave pública do eleitor. O segredo compartilhado é usado para descriptografar o voto.
Após descriptografar cada voto, calcular os resultados é simples! Basta percorrer o array de votos e acumular os votos para uma determinada escolha.
Se você não está familiarizado com provas ZK, elas são uma tecnologia bastante complexa, porém fascinante. As provas ZK são um método pelo qual uma parte pode provar a outra que conhece um valor sem revelar nenhuma informação sobre o próprio valor. Essencialmente, é uma forma de validar a veracidade de algo sem compartilhar os detalhes. Além disso, qualquer pessoa pode verificar se essa prova está correta.
Para nossa aplicação, idealmente, a parte confiável deve provar que pode pegar os votos criptografados, descriptografá-los e calcular o número de votos que cada escolha recebeu. Neste caso, a chave "secreta" é a chave privada da parte confiável. Por questão de simplicidade, estamos apenas provando a posse de uma chave privada que corresponde à chave pública registrada no contrato inteligente. Como mencionado anteriormente, os votos usam essa chave para gerar uma cifra para criptografar o voto.
Para esse propósito, usaremos o ZoKrates, uma caixa de ferramentas para zkSNARKs no Ethereum. Ele ajuda você a utilizar computação verificável em seu dapp, desde a especificação do seu programa em uma linguagem de alto nível até a geração de provas de computação e a verificação dessas provas em Solidity.
Este é o programa ZK simples que utilizo:
Como você pode ver na lista de argumentos, pk é um argumento público e sk é um argumento privado. context também é público. Apenas o provador — a parte confiável — conhece o sk, mas o pk é conhecido por qualquer pessoa, pois está no contrato inteligente. context são os parâmetros relacionados à curva que escolhemos para gerar um par de chaves.
No trecho acima, estou usando o ZoKrates JS SDK para gerar uma prova. O fluxo é semelhante ao que está documentado na documentação do ZoKrates. Nosso objetivo é usar o programa ZoKrates para gerar uma prova, portanto estamos passando três argumentos para a função computeWitness: pk (um argumento público), sk (um argumento privado) e context. Eles são usados para criar uma witness, que é então usada para gerar a prova.
Você pode estar se perguntando sobre esta parte do argumento:
O context fornece os dados relacionados à curva Baby JubJub específica que usamos ao longo da aplicação, já que muitas variações de curva podem ser utilizadas. Arquivos como a chave de verificação, a chave de prova e o programa ZoKrates são mantidos em um diretório separado. Estou usando a função abaixo para obtê-los:
O trecho abaixo é do contrato no qual o contrato aceita os resultados calculados pela parte confiável. Somente se a verificação for bem-sucedida o contrato aceita o resultado. Partes externas podem verificar isso passando o pk (que é público e está no contrato) e a prova para a função verificadora:
Neste blog, desenvolvemos a Privote, um sistema de votação privada baseado em ZK que mantém as escolhas dos eleitores confidenciais até o término do período de votação. Usamos técnicas de curva elíptica para criptografar votos e demonstramos como descriptografá-los e contabilizá-los com segurança. Também implementamos provas de conhecimento zero usando ZoKrates para verificar a integridade do processo de votação sem revelar informações privadas.
Este tutorial fornece uma compreensão básica de como criar sistemas de votação seguros e privados na blockchain. Na segunda parte, construiremos o frontend e mostraremos como os usuários podem se conectar e votar usando o MetaMask SDK.
Traduzido por IA. Pode conter erros. Por favor, verifique sempre as informações.