P√°gina Inicial
Artigos
Melhorando a transparência cripto com Zero-Knowledge Proof (ZKP)

Melhorando a transparência cripto com Zero-Knowledge Proof (ZKP)

Intermedi√°rio
Publicado em Feb 10, 2023Atualizado em Jan 5, 2024
10m

TL;DR

Uma zero-knowledge proof ou ZKP (prova de conhecimento zero) permite que uma parte (um verificador) determine a validade de uma declara√ß√£o dada por outra parte (o provador) sem qualquer conhecimento do conte√ļdo da declara√ß√£o. Por exemplo, a Binance pode querer provar que os fundos de seus usu√°rios est√£o totalmente garantidos em reservas sem revelar todos os saldos de usu√°rios individuais.

Uma Proof of Reserves ou ‚ÄúProva de Reservas‚ÄĚ (PoR) pode ser constru√≠da com uma Merkle Tree (√°rvore de Merkle) que oferece prote√ß√£o contra a falsifica√ß√£o de dados internos, neste caso, dos saldos l√≠quidos totais dos usu√°rios, que est√£o sob cust√≥dia da corretora. Isso pode ent√£o ser combinado com um zk-SNARK (um protocolo de prova de conhecimento zero) que garante que os usu√°rios possam verificar que seus saldos fazem parte do saldo total l√≠quido de ativos, sem ter conhecimento dos saldos individuais de cada usu√°rio.

Introdução

Diante dos eventos do mercado, a segurança dos criptoativos em custódia se tornou um tema muito importante. Os usuários da tecnologia Blockchain valorizam a transparência e a abertura, mas também defendem a privacidade e a confidencialidade. Isso cria um dilema no que diz respeito à comprovação das reservas de fundos mantidos pelos custodiantes. Muitas vezes, há um desequilíbrio entre transparência, confiança e confidencialidade dos dados.

No entanto, isso não é necessariamente o que ocorre. Ao combinar protocolos zero-knowledge proof como zk-SNARKs com Merkle Trees, é possível encontrar uma solução eficaz para todas as partes.

O que é zero-knowledge proof?

Uma zero-knowledge proof ou ZKP (prova de conhecimento zero) permite que uma parte (um verificador) determine a validade de uma declara√ß√£o dada por outra parte (o provador) sem qualquer conhecimento do conte√ļdo da declara√ß√£o. Vamos ver um exemplo simples.

Digamos que você tem um cofre trancado e que só você sabe a senha. Para o nosso exemplo, vamos considerar que esse cofre não pode ser arrombado, violado ou aberto de qualquer outra forma que não seja através da combinação correta. Este fato também é conhecido e verificado por seu amigo que está participando do experimento.

Voc√™ afirma ao seu amigo que sabe a combina√ß√£o, mas n√£o quer entreg√°-la ou abrir a caixa na frente dele. No topo da caixa h√° um buraco pelo qual seu amigo pode colocar uma nota. Para que isso seja uma prova de conhecimento zero, seu amigo n√£o deve ter nenhuma informa√ß√£o extra sobre o processo al√©m das informa√ß√Ķes fornecidas anteriormente.

Você pode provar ao seu amigo que sabe a combinação. Basta abrir a caixa, contar a ele o que estava escrito no bilhete e fechá-la novamente. Nesse processo, no entanto, você não revelou a combinação em nenhum momento.

Para um exemplo mais avançado, consulte o nosso artigo O que é zero-knowledge proof e como isso afeta a tecnologia blockchain?.

Por que usamos zero-knowledge proofs?

As provas de conhecimento zero s√£o adequadas para provar algo sem revelar informa√ß√Ķes ou detalhes confidenciais. Por exemplo, voc√™ pode n√£o querer compartilhar informa√ß√Ķes financeiras ou pessoais que possam ser usadas de forma inadequada.

Atrav√©s da criptografia, voc√™ pode provar que possui uma chave privada sem revel√°-la ou assinar algo digitalmente. Uma corretora de criptomoedas tamb√©m pode querer comprovar o status de suas reservas sem revelar informa√ß√Ķes confidenciais de seus usu√°rios, incluindo os saldos individuais de suas contas.¬†

Para esses exemplos (e muitos outros), uma zero-knowledge proof usaria algoritmos que recebem um input (entrada) de dados e retornam ‚Äúverdadeiro‚ÄĚ ou ‚Äúfalso‚ÄĚ como output (sa√≠da).¬†

Definindo zero-knowledge proofs em termos técnicos

Em termos t√©cnicos, uma prova de conhecimento zero segue uma estrutura espec√≠fica com determinados crit√©rios. J√° mencionamos as fun√ß√Ķes de provador e verificador, mas tamb√©m h√° tr√™s crit√©rios que uma ZKP deve cobrir:

  1. Integridade. Critério também referido como completude. Se a afirmação for verdadeira, o verificador será convencido pela prova fornecida, sem a necessidade de qualquer outra informação ou verificação.

  2. Solidez. Se a declaração for falsa, o verificador não será convencido da veracidade de uma declaração pela prova fornecida.

  3. Conhecimento zero. Se a afirmação for verdadeira, o verificador não terá conhecimento de nenhuma informação além do fato de que a afirmação é verdadeira.

O que é zk-SNARK?

Zk-SNARK (Zero-Knowledge Succinct Non-Interactive Argument of Knowledge) é um protocolo de prova que segue os princípios de conhecimento zero descritos anteriormente. Com um zk-SNARK, você pode provar que conhece o valor original submetido ao hashing (discutiremos mais adiante) sem revelar qual é esse valor. Você também pode provar a validade de uma transação sem revelar nenhuma informação sobre os valores, quantidade ou endereços específicos relativos a ela.

As discuss√Ķes e o uso de zk-SNARKs s√£o muito comuns no mundo da tecnologia blockchain e das criptomoedas. Voc√™ pode estar se perguntando por que algu√©m se incomodaria em usar um zk-SNARK quando poderia usar um m√©todo simples de par de chaves p√ļblica e privada para garantir a seguran√ßa das informa√ß√Ķes. No entanto, n√£o ser√≠amos capazes de implementar a prova matem√°tica para garantir que n√£o sejam inclu√≠dos saldos negativos e que a soma da Merkle Tree esteja correta.¬†

No caso das reservas de uma corretora, a intenção é comprovar a proporção direta de 1:1 dos saldos dos clientes, sem que os identificadores e saldos de cada conta sejam divulgados publicamente. Além disso, a tecnologia zk-SNARK torna a falsificação de dados ainda mais improvável.

O que é uma Merkle Tree?

Para apresentar a soma dos fundos das contas dos usu√°rios da Binance, √© preciso lidar com um grande volume de dados. Uma maneira de apresentar essa grande quantidade de dados criptograficamente √© usando uma Merkle Tree (√°rvore de Merkle). Uma quantidade enorme de informa√ß√Ķes pode ser armazenada de forma eficiente dentro dela, e sua natureza criptogr√°fica facilita a verifica√ß√£o de integridade.

Fun√ß√Ķes Hash

Para codificar sucintamente um input (entrada), uma Merkle Tree depende do uso de fun√ß√Ķes de hashing. Resumidamente, hashing refere-se ao processo de gera√ß√£o de um output (sa√≠da) de tamanho fixo a partir de um input (entrada) de tamanho vari√°vel. Em outras palavras, quando um input de qualquer comprimento √© submetido ao hashing por meio de um algoritmo, ele produzir√° um output criptografado de comprimento fixo.

Sendo assim, enquanto o input permanecer o mesmo, o output tamb√©m ser√° sempre o mesmo. Isso significa que podemos submeter grandes quantidades de dados de transa√ß√Ķes a fun√ß√Ķes de hashing e convert√™-los em um output gerenci√°vel. Se alguma informa√ß√£o do input for alterada, o output ser√° totalmente diferente.

Por exemplo, poder√≠amos submeter o conte√ļdo de 100 livros √† fun√ß√£o de hashing SHA-256. O resultado seria um output como o do exemplo abaixo:

801a9be154c78caa032a37b4a4f0747f1e1addb397b64fa8581d749d704c12ea

Se alter√°ssemos um √ļnico caractere do input (os 100 livros), o hash resultante seria completamente diferente, como por exemplo:

abc5d230121d93a93a25bf7cf54ab71e8617114ccb57385a87ff12872bfda410

Essa √© uma propriedade importante das fun√ß√Ķes de hashing, pois ela permite a f√°cil verifica√ß√£o da precis√£o dos dados. Se algu√©m replicar o processo de hashing desses mesmos 100 livros usando o algoritmo SHA-256, obter√° exatamente o mesmo hash de sa√≠da (output). Se o output for diferente, podemos afirmar com certeza que o input foi alterado. Isso significa que n√£o h√° necessidade de verificar individualmente ou manualmente as diferen√ßas entre os inputs, o que pode ser trabalhoso.

Merkle Trees no mundo das criptomoedas

Ao armazenar dados de transa√ß√£o em uma blockchain, cada nova transa√ß√£o √© enviada por meio de uma fun√ß√£o de hashing, que gera valores de hash exclusivos. Imagine que temos oito transa√ß√Ķes (A a H) e as submetemos ao hashing, individualmente, para obter seus hashes resultantes (hashed outputs). Estes s√£o o que chamamos de Merkle leaf nodes ("nodes de folhas" da Merkle Tree). Na imagem abaixo, podemos ver o valor de hash exclusivo de cada letra: hA para A, hB para B, hC para C, etc.

Podemos então combinar pares de hashed outputs para gerar uma novo hashed output. A combinação dos hashes hA e hB, por exemplo, nos dariam o novo hashed output hAB, conhecido como Merkle branch ("ramificação de Merkle"). Note que cada vez que um novo output é gerado, ele tem comprimento e tamanho fixos, de acordo com a função de hashing utilizada.

Agora, temos os dados de duas transa√ß√Ķes (por exemplo, A e B) combinadas em um hash (hAB). Observe que, se alterarmos qualquer informa√ß√£o de A ou B e repetirmos o processo, nosso hashed output hAB ser√° completamente diferente.

O processo continua enquanto combinamos novos pares de hashes para submet√™-los ao hashing novamente (veja a imagem abaixo). Fazemos o hashing de hAB com hCD para obter um √ļnico hash hABCD e fazemos o mesmo com hEF e hGH para obter hEFGH. No final, recebemos um √ļnico hash representando os hashed outputs de todos os hashes das transa√ß√Ķes anteriores. Em outras palavras, o hashed output hABCDEFGH representa todas as informa√ß√Ķes que vieram antes dele.

O gráfico exibido acima é chamado de Merkle Tree e o hashed output hABCDEFGH é a Merkle root ("raiz de Merkle"). Usamos Merkle roots em cabeçalhos de bloco, pois eles resumem criptograficamente todos os dados da transação em um bloco de maneira sucinta. Também é possível verificar rapidamente se algum dado foi adulterado ou alterado dentro do bloco.

Limita√ß√Ķes das Merkle Trees

Voltemos ao nosso exemplo de reservas de corretoras centralizadas (CEX). Uma CEX quer provar o valor atrelado em proporção de 1:1 de todos os ativos de seus clientes e cria uma Merkle Tree que agrupa (hashing) os UIDs dos clientes e seus holdings líquidos (considerando ativos e passivos) a nível de tokens. Após a liberação (e assinatura para provar a propriedade sobre a Merkle root fornecida), um usuário individual não teria como verificar se a Merkle Tree é válida sem ter acesso a todos os seus inputs.

Uma corretora pode ter deixado de incluir alguns inputs. Ela também poderia criar contas falsas com saldos negativos para alterar o passivo total. Por exemplo, embora os ativos dos clientes possam totalizar $1.000.000, uma conta falsa pode ser adicionada com um saldo de -$500.000. Isso resultaria em um valor de reservas de apenas $500.000.

O caso para a comprova√ß√£o de reservas √© diferente da Merkle root de um bloco, pois os usu√°rios podem ver todas as transa√ß√Ķes de um bloco em um blockchain explorer. No entanto, por motivos de seguran√ßa e privacidade de dados, uma CEX n√£o tem interesse em divulgar o saldo de cada conta. Os clientes tamb√©m n√£o ficariam satisfeitos com a divulga√ß√£o p√ļblica de seus saldos de conta. Nesse caso, a CEX n√£o pode provar que os saldos dos usu√°rios somam o total correto sem tornar vis√≠veis os outros saldos dos usu√°rios.

Uma solução que as corretoras podem considerar é o uso de um auditor terceirizado confiável. O auditor pode verificar as contas e reservas individuais antes de finalmente atestar a validade da Merkle root fornecida. No entanto, para os usuários, esse método exige confiança no auditor e nos dados usados para a auditoria. Você não precisa depender de terceiros quando pode confiar em dados.

Combinando zk-SNARKs com Merkle Trees

O problema acima é um caso de uso perfeito para zk-SNARKs. Queremos provar que as reservas cobrem totalmente o valor de passivos dos usuários e que não são falsificadas. No entanto, por motivos de privacidade e segurança, não queremos mostrar ao verificador a composição exata dos saldos e reservas dos usuários. 

Usando um zk-SNARK, uma corretora cripto pode provar que todos os conjuntos de saldos dos leaf nodes da Merkle Tree (ou seja, os saldos das contas dos usuários) contribuem para o saldo total de ativos de usuários, conforme alegação da corretora. Cada usuário pode acessar facilmente seu leaf node para verificar se o mesmo foi incluído no processo. O zk-SNARK também garante que qualquer Merkle Tree gerada não inclua usuários com um saldo negativo de ativos líquidos totais (o que implicaria falsificação de dados, pois todos os empréstimos são sobrecolateralizados). Também se utiliza um cálculo do estado global da Binance, ou seja, uma lista do saldo líquido total de cada ativo que cada cliente da Binance possui.

Vamos dar uma olhada na forma como a Binance aborda a situa√ß√£o. Para come√ßar, a Binance define as restri√ß√Ķes (constraints) computacionais que deseja provar e as define como um circuito program√°vel. Abaixo, temos o conjunto de tr√™s restri√ß√Ķes que a Binance usa em seu modelo.¬†

Para o conjunto de saldos de cada usu√°rio (Merkle tree leaf node), nosso circuito garante que:

  1. Os saldos de ativos de um usuário são incluídos no cálculo da soma dos saldos líquidos totais dos usuários da Binance.

  2. O saldo líquido total do usuário é maior ou igual a zero.

  3. A altera√ß√£o da Merkle root √© v√°lida (ou seja, n√£o usa informa√ß√Ķes falsificadas) ap√≥s atualizar as informa√ß√Ķes de um usu√°rio para o hash do leaf node.

A Binance pode ent√£o gerar uma prova zk-SNARK para a constru√ß√£o da Merkle Tree de acordo com esse circuito program√°vel. Isso significa que a corretora deve executar o pesado processo computacional que envolve o hashing dos IDs e saldos dos usu√°rios, ao mesmo tempo em que garante que a prova atenda √†s restri√ß√Ķes.

Um verificador examinar√° a prova (e o c√≥digo aberto divulgado publicamente) para se convencer de que o c√°lculo foi executado corretamente e que todas as restri√ß√Ķes foram respeitadas. A verifica√ß√£o computacional √© conclu√≠da em um tempo extremamente curto em compara√ß√£o ao tempo de prova.

A cada lançamento de provas (Proof of Reserves), a corretora publicará:

1. A prova da Merkle Tree para cada usu√°rio.

2. A prova zk-SNARK e o input p√ļblico (um hash da lista do saldo l√≠quido total de cada ativo e a Merkle root) do circuito para todos os usu√°rios.

Os interessados podem verificar a prova da Merkle Tree, garantindo que seus saldos individuais foram considerados para a Merkle root. Eles tamb√©m podem verificar a prova zk-SNARK para garantir que a constru√ß√£o da Merkle Tree atenda √†s restri√ß√Ķes definidas no circuito. Para uma explica√ß√£o mais detalhada da solu√ß√£o zk-SNARK e seu desempenho, consulte nosso blog Como zk-SNARKs melhoram o sistema de Proof of Reserves da Binance.

Considera√ß√Ķes finais

Os zk-SNARKs fornecem a tecnologia necess√°ria para garantir, simultaneamente, a integridade e a privacidade dos dados. Seu uso para a comprova√ß√£o de reservas e aumento da transpar√™ncia de CEXs deve ajudar a aumentar confian√ßa na ind√ļstria blockchain. Para muitos, um avan√ßo como este tem sido aguardado h√° muito tempo e chega em um momento crucial para as CEXs.

Esta é a primeira versão do nosso zk-SNARK e estamos ansiosos para receber o feedback da comunidade, para que possamos continuar aprimorando o sistema.

Leituras adicionais