
Implementamos um protótipo de transações anônimas baseadas no zkSNARK para garantir transações confidenciais na blockchain Waves. Em nossa implementação, usamos o sistema de evidências Groth16 na curva BN254 e no DSC circom .
Nós explicamos como isso funciona.
zkSNARKs
O zkSNARK é uma primitiva criptográfica que confirma o conhecimento de um conjunto de dados especial (evidência) correspondente ao conjunto das seguintes equações (sistema de restrição):
⟨ai,w⟩⟨bi,w⟩+⟨ci,w⟩=0
parte da evidência é privada. Essa construção nos permite provar, por exemplo, o conhecimento da imagem inversa de hash sem divulgar a imagem inversa. Também pode ser usado no mecanismo de transação privada do modelo UTXO ( Saída não transacionada (TX)), onde apenas os hashes UTXO são publicados, e a validade da transação é comprovada no zkSNARK (prova de propriedade, prova de economia do valor).
O zkSNARK é uma tecnologia não interativa de divulgação zero, ou seja, não implica um protocolo de interação entre participantes que é implementado para provar o conhecimento. Na tecnologia zkSNARK, o fornecedor constrói a prova e a envia ao fornecedor - nenhuma interação adicional é necessária. O examinador pode verificar a exatidão e a exatidão do uso de dados de evidências sem recorrer a informações adicionais. Inicialmente, os zkSNARKs foram criados como um protocolo de “computação confidencial”: ao calcular o resultado, os dados envolvidos nos cálculos não são divulgados.
Usando a tecnologia zkSNARK, um esquema de divulgação de confirmação pode ser implementado: o provador calcula o hash, entrega ao provador e faz uma prova especial de que conhece a imagem inversa do hash x. Substituindo os valores de x e hash na fórmula e passando essa fórmula e a prova para o examinador, o examinador pode garantir que o provador conheça x. Essa é a base para transações anônimas: conhecemos a chave privada e alguma entrada específica (UTXO não gasto) com uma quantia específica que o usuário criou no contrato inteligente. Sem divulgar esses dados, o usuário pode confirmar com um contrato inteligente que essa é a sua entrada, que pode descartá-los e entregá-los a alguém para uso.
Agora a tecnologia não é usada em todos os lugares, porque a prova é gerada por vários minutos, o que não é muito conveniente para o usuário.
Saiba mais sobre a programação do zkSNARK no artigo de Vitalik Buterin "Programas aritméticos quadráticos: de zero a herói" e no artigo de Iden3 sobre design de circuitos circom.
Modelo de conta
Para transações no Waves, eles geralmente usam chaves e endereços com base na curve25519
. Essa curva não é compatível com o zkSNARK, portanto, para transações anônimas, usamos o subgrupo Edwards de curvas torcidas do BabyJubJub
. Além disso, usamos chaves públicas como endereços, pois ao enviar, você precisa criptografar os dados do destinatário.
Modelo UTXO
Em nosso modelo, o UTXO é representado por um conjunto de três parâmetros: saldo, chave pública do proprietário e segredo exclusivo. O blockchain contém apenas hashes sem criptografia adicional. O proprietário é representado por uma chave pública e, como observado anteriormente, usamos chaves públicas não na curva curve25519
, mas na curva BabyJubJub
compatível com BabyJubJub
. O ID do UTXO deve ser gerado aleatoriamente, porque se o usuário especificar dois IDs idênticos, ele poderá pegar (gastar) o UTXO apenas em um deles. Nesse caso, apenas o UTXO com o ID correspondente para o usuário atual será bloqueado, mas não para o restante. É do interesse do usuário escolher a identificação usando um gerador de números aleatórios (253 bits são alocados na identificação, por isso é difícil obter uma colisão).
Para gastar o UTXO, você deve publicar um nullifier, uma função determinística do UTXO, definida como hash (segredo, owner_privkey). Esse valor é determinístico e exclusivo para cada UTXO; somente o proprietário o conhece. Além do proprietário, ninguém pode associar o UTXO ao seu anulador correspondente.
Os UTXOs são armazenados dentro do mapa de hash do dApp, ou seja, no estilo do contrato. No blockchain, os UTXOs são criptografados. Para receber seu dinheiro, o usuário deve escanear o blockchain e tentar descriptografar cada UTXO.
Região dapp
O estilo do dApp contém mapas de hash representando dois conjuntos:
Assim, o dApp pode verificar a existência de um conjunto anônimo UTXO e a exclusividade de anuladores. Isso é suficiente para processar transferências anônimas com proteção contra falsificação de novos ativos e duplicação de gastos.
O DApp possui 3 métodos que correspondem aos tipos básicos de transações:
- Depositar
- Transferir
- Conclusão
Para transferir e retirar fundos, usamos nossos próprios verificadores que garantem a interação do dApp com contas anônimas especiais com base na curva BabyJubJub. Os depósitos são processados a partir de contas regulares do Waves.
Comissões
Para o reabastecimento da conta, é cobrada uma taxa da conta curve25519
. Para transferências e saques, a comissão é debitada da conta anônima. No nível do dApp, fica assim:
O dApp paga pela transação em si, ou seja, o token nativo gasto no pagamento da comissão é debitado do seu saldo
Entre entradas e saídas, parte da comissão é queimada para anular os ativos correspondentes aos ativos reais no contrato inteligente
No nível UTXO, queimamos uma certa quantia como comissão ao processar uma transação.
Transações
Um depósito é uma operação simples, cada depósito adiciona um novo elemento ao UTXO.

As transferências são baseadas na primitiva de conversão 2 para 2.

Algumas entradas e saídas podem ser zero. Como exemplo parcial dessa construção, qualquer tipo de tradução simples pode ser representada (junção, divisão e outras transferências, com exceção dos swaps atômicos).
As conclusões funcionam como outras transações, mas, em vez de criar um segundo UTXO, permitem que o usuário retire seu UTXO do dApp. Também pode haver dois UTXOs na entrada, UTXOs na saída com o restante dos fundos e saque, que são publicados na blockchain.

Ao retirar ou transferir, o dApp verifica se os anuladores correspondentes ainda não foram encontrados em sua pilha.
Usando zkSNARK, podemos calcular que a soma das entradas da transação é igual à soma das saídas. Ao executar uma transação, a gastamos no UTXO e em algum outro UTXO zero, que não está na árvore de merkle. Para gastar o UTXO, você precisa provar o conhecimento da chave privada de seu proprietário. Verifique se a chave privada, quando multiplicada pelo gerador do grupo, resulta em uma chave pública. Assim, sem conhecer a chave privada, uma transação não pode ser concluída.
Conjunto anônimo
Usamos um conjunto anônimo de 8 elementos. O elemento de destino é selecionado em particular do conjunto representado na entrada pública zkSNARK. Este método permite ofuscar o gráfico de transação (se for possível restaurar o gráfico de interação UTXO, existe a possibilidade de desanonizar transações).
Além disso, um coletor simples de 8 elementos pode ser substituído por um coletor de árvores Merkle. A abordagem oculta o gráfico da transação.
Para criar uma transação válida, provamos que gastamos um pouco de UTXO do conjunto de UTXO. Colocamos provas do zkSNARK merkle e dados UTXO em entradas privadas e hash raiz na entrada pública. Assim, usando SNARK, provamos que conhecemos o UTXO.

Proteção contra gastos duplos
Para proteger contra gastos duplos, usamos nullifiers - funções determinísticas que não dependem diretamente do hash UTXO. Para calcular o nulo, tomamos a função da chave privada, é comprovado que corresponde à chave pública, id e hash UTXO. Para cada UTXO, existe apenas um nulo.
Para cada transação, o anulador das saídas UTXO gastas deve ser apresentado como uma entrada pública para zkSNARK. Dentro do circuito zkSNARK, também deve ser confirmado que ele pertence ao UTXO gasto.
Se o contrato do dApp receber um valor nulo de nulificador, a transação será rejeitada. Assim, é garantido que cada UTXO seja gasto uma vez.
Depois que eles gastaram o UTXO, o anulador é publicado na lista de anuladores gastos no artigo do dApp. Ou seja, no mapa de hash, oposto a esse anulador, "true" está definido. Antes de publicar o nullifier no artigo, verificamos que esse nullifier ainda não foi usado, o que significa que UTXO com esse ID pode ser gasto.