Vitalik Buterin, fundador da Ethereum, dá uma aula de prova de reservas e insolvência

Vitalik Buterin

Empresas que possuem duas stablecoins estão quebrando o mercado cripto, Vitalik fala e explica todo um fator que envolve a prova de reserva e insolvência

Toda vez que uma grande exchange centralizada explode, uma pergunta comum que surge é se podemos ou não usar técnicas criptográficas para resolver o problema. Em vez de confiar apenas em métodos “fiat” como licenças governamentais, auditores e examinar a governança corporativa e os antecedentes dos indivíduos que administram a exchange, as exchanges podem criar provas com criptomoedas que mostram que os fundos que mantêm na cadeia são suficientes para cobrir suas responsabilidades aos seus usuários.

Podendo ir mais além, uma exchange poderia construir um sistema em que não pudesse sacar os fundos de um depositante sem o seu consentimento. Potencialmente, poderíamos explorar todo o espectro entre o CEX aspirante a mocinho “não seja mau” e o DEX on-chain “não pode ser mau”, mas por enquanto ineficiente e que vaza a privacidade. Este artigo entrará na história das tentativas de mover as trocas um ou dois passos mais perto da falta de confiança, as limitações dessas técnicas e algumas ideias mais novas e poderosas que dependem de ZK-SNARKs e outras tecnologias avançadas.

Listas de saldos e Árvores Merkle (Merkle trees): prova de solvência à moda antiga

As primeiras tentativas das exchanges de tentar provar criptograficamente que não estão enganando seus usuários remontam há muito tempo. Em 2011, a então maior exchange de Bitcoin, MtGox, provou ter fundos enviando uma transação que moveu 424.242 BTCs para um endereço pré-anunciado. Em 2013, começaram as discussões sobre como resolver o outro lado do problema: provar o valor total dos depósitos dos clientes. Se você provar que os depósitos dos clientes são iguais a X (“prova de responsabilidades”) e provar a propriedade das chaves privadas de moedas X (“prova de ativos”), você terá uma prova de solvência: você provou que a exchange os fundos para pagar todos os seus depositantes.

A maneira mais simples de provar depósitos é simplesmente publicar uma lista de (username, balance) pares. Cada usuário pode verificar se seu saldo está incluído na lista e qualquer pessoa pode verificar a lista completa para ver se (i) todos os saldos são não negativos e (ii) a soma total é o valor reivindicado. Claro, isso quebra a privacidade, então podemos mudar um pouco o esquema: publicar uma lista de (hash (username, salt), balance) pares e enviar a cada usuário em particular seu salt valor. Mas mesmo isso vaza equilíbrios e vaza o padrão de mudanças nos saldos. O desejo de preservar a privacidade nos leva à próxima invenção: a técnica da Merkle tree.

image 46
Verde: nódulo de Charlie. Azul: nós que Charlie receberá como parte de sua prova. Amarelo: nó raiz, mostrado publicamente a todos.

A técnica da Merkle trees, consiste em colocar a tabela de saldos dos clientes em uma soma de Merkle tree. Em uma soma de Merkle tree, cada nó é um (balance, hash) em par. Os nós de folha da camada inferior representam os saldos e hashes de nome de usuário salgados de clientes individuais. Em cada nó da camada superior, o saldo é a soma dos dois saldos abaixo e o hash é o hash dos dois nós abaixo. Uma prova de soma de Merkle, como uma prova de Merkle, é um “ramo” da “árvore”, consistindo nos nós irmãos ao longo do caminho de uma folha até a raiz.

A troca enviaria a cada usuário uma prova de soma Merkle de seu saldo. O usuário teria então a garantia de que seu saldo está corretamente incluído no total. Um exemplo simples de implementação de código pode ser encontrado aqui.

# The function for computing a parent node given two child nodes
def combine_tree_nodes(L, R):
    L_hash, L_balance = L
    R_hash, R_balance = R
    assert L_balance >= 0 and R_balance >= 0
    new_node_hash = hash(
        L_hash + L_balance.to_bytes(32, 'big') +
        R_hash + R_balance.to_bytes(32, 'big')
    )
    return (new_node_hash, L_balance + R_balance)

# Builds a full Merkle tree. Stored in flattened form where
# node i is the parent of nodes 2i and 2i+1
def build_merkle_sum_tree(user_table: "List[(username, salt, balance)]"):
    tree_size = get_next_power_of_2(len(user_table))
    tree = (
        [None] * tree_size +
        [userdata_to_leaf(*user) for user in user_table] +
        [EMPTY_LEAF for _ in range(tree_size - len(user_table))]
    )
    for i in range(tree_size - 1, 0, -1):
        tree[i] = combine_tree_nodes(tree[i*2], tree[i*2+1])
    return tree

# Root of a tree is stored at index 1 in the flattened form
def get_root(tree):
    return tree[1]

# Gets a proof for a node at a particular index
def get_proof(tree, index):
    branch_length = log2(len(tree)) - 1
    # ^ = bitwise xor, x ^ 1 = sister node of x
    index_in_tree = index + len(tree) // 2
    return [tree[(index_in_tree // 2**i) ^ 1] for i in range(branch_length)]

# Verifies a proof (duh)
def verify_proof(username, salt, balance, index, user_table_size, root, proof):
    leaf = userdata_to_leaf(username, salt, balance)
    branch_length = log2(get_next_power_of_2(user_table_size)) - 1
    for i in range(branch_length):
        if index & (2**i):
            leaf = combine_tree_nodes(proof[i], leaf)
        else:
            leaf = combine_tree_nodes(leaf, proof[i])
    return leaf == root

O vazamento de privacidade nesse design é muito menor do que com uma lista totalmente pública e pode ser reduzido ainda mais ao embaralhar as ramificações cada vez que uma raiz é publicada, mas ainda existe algum vazamento de privacidade: Charlie descobre que alguém tem um saldo de 164 ETH, alguns dois usuários têm saldos que somam 70 ETH, etc. Um invasor que controla muitas contas ainda pode aprender uma quantidade significativa sobre os usuários da exchange.

Uma sutileza importante do esquema é a possibilidade de saldos negativos: e se uma exchange que tem 1390 ETH de saldos de clientes, mas apenas 890 ETH em reservas tenta compensar a diferença adicionando um saldo de -500 ETH em uma conta falsa em algum lugar na “árvore”? Acontece que esta possibilidade não quebra o esquema, embora esta seja a razão pela qual precisamos especificamente de uma árvore de soma de Merkle e não de uma Merkle tree regular. Suponha que Henry seja a conta falsa controlada pela exchange e a exchange coloque -500 ETH lá:

image 47

A verificação da prova de Greta falharia: a exchange teria que fornecer o nó -500 ETH de Henry, que ela rejeitaria como inválido. A verificação de prova de Eve e Fred também falharia, porque o nó intermediário acima de Henry tem -230 ETH total e, portanto, também é inválido! Para fugir do roubo, a exchange teria que torcer para que ninguém em toda a metade direita da árvore verificasse o comprovante de saldo.

Se a troca puder identificar 500 ETH de usuários que eles estão confiantes de que não se incomodarão em verificar a prova ou não acreditarão quando reclamarem que nunca receberam uma prova, eles poderão escapar impunes do roubo. Mas a troca também pode apenas excluir esses usuários da árvore e ter o mesmo efeito. Portanto, a técnica da Merkle tree é basicamente tão boa quanto um esquema de comprovação de responsabilidades pode ser, se apenas conseguir uma prova de responsabilidades for o objetivo. Mas suas propriedades de privacidade ainda não são ideais. Você pode ir um pouco além usando Merkle tree de maneiras mais inteligentes, como fazer cada satoshi ou wei uma folha separada, mas, em última análise, com tecnologia mais moderna, existem maneiras ainda melhores de fazer isso.

Melhorando a privacidade e robustez com ZK-SNARKs

ZK-SNARKs são uma tecnologia poderosa. Os ZK-SNARKs podem ser para a criptomoeda o que os transformadores são para a IA: uma tecnologia de propósito geral que é tão poderosa que irá esmagar completamente um monte de técnicas específicas de aplicativos para um monte de problemas que foram desenvolvidos nas décadas anteriores. E assim, é claro, podemos usar ZK-SNARKs para simplificar e melhorar muito a privacidade em protocolos de prova de responsabilidades.

A coisa mais simples que podemos fazer é colocar todos os depósitos dos usuários em uma Merkle tree (ou, ainda mais simples, um compromisso KZG) e usar um ZK-SNARK para provar que todos os saldos na “árvore” são não negativos e somam algum valor reivindicado. Se adicionarmos uma camada de hash para privacidade, a ramificação Merkle (ou prova KZG) fornecida a cada usuário não revelará nada sobre o saldo de qualquer outro usuário.

image 48
Usar compromissos KZG é uma maneira de evitar vazamento de privacidade, pois não há necessidade de fornecer “nós irmãos” como provas, e um simples ZK-SNARK pode ser usado para provar a soma dos saldos e que cada saldo é não negativo.

Podemos provar a soma e a não negatividade dos saldos no KZG acima com um ZK-SNARK de propósito especial. Aqui está um exemplo simples de como fazer isso. Introduzimos um polinômio auxiliar, que “constrói os bits” de cada saldo (assumimos, a título de exemplo, que os saldos estão abaixo) e onde a cada 16 A posição rastreia um total corrente com um deslocamento para ser somado a zero somente se o total real corresponder ao total declarado. Se é uma raiz da unidade de ordem 128, podemos provar as equações:

Contra Capa 2022 11 19T142331.174

Os primeiros valores de uma configuração válida para seriam, …I(x) 0000 0000 0012 5 10 20 -165 0000 0000 0136 12 25 50 -300

Veja aqui e aqui no meu post sobre ZK-SNARKs para mais explicações sobre como converter equações como essas em uma verificação polinomial e depois em um ZK-SNARK. Este não é um protocolo ideal, mas mostra como hoje em dia esses tipos de provas criptográficas não são tão assustadores!

Com apenas algumas equações extras, sistemas de restrição como esse podem ser adaptados a configurações mais complexas. Por exemplo, em um sistema de negociação de alavancagem, um usuário individual com saldo negativo é aceitável, mas apenas se tiver outros ativos suficientes para cobrir os fundos com alguma margem de garantia. Um SNARK poderia ser usado para provar essa restrição mais complicada, garantindo aos usuários que a exchange não está arriscando seus fundos isentando secretamente outros usuários das regras.

No futuro de longo prazo, esse tipo de prova de responsabilidades ZK talvez pudesse ser usado não apenas para depósitos de clientes em exchanges, mas para empréstimos de forma mais ampla. Qualquer pessoa que fizesse um empréstimo colocaria um registro em um polinômio ou em uma “árvore” contendo esse empréstimo, e a raiz dessa estrutura seria publicada na cadeia. Isso permitiria que qualquer pessoa que procurasse um empréstimo ZK-provasse ao credor que ainda não contraiu muitos outros empréstimos. Eventualmente, a inovação legal poderia até mesmo fazer empréstimos que foram comprometidos dessa forma com maior prioridade do que empréstimos que não foram. Isso nos leva exatamente na mesma direção de uma das ideias discutidas no artigo “Sociedade descentralizada: encontrando a alma da Web3” : uma noção geral de reputação negativa ou ônus na cadeia por meio de alguma forma de “

Prova de bens

A versão mais simples da prova de ativos é o protocolo que vimos acima: para provar que você possui X moedas, basta mover X moedas em algum momento pré-acordado ou em uma transação onde o campo de dados contenha as palavras “esses fundos pertencem para Binance”. Para evitar o pagamento de taxas de transação, você pode assinar uma mensagem off-chain; tanto o Bitcoin quanto o Ethereum têm padrões para mensagens assinadas fora da cadeia.

Há dois problemas práticos com essa técnica simples de prova de ativos:

• Lidando com o armazenamento a frio
• Colateral de uso duplo

Por motivos de segurança, a maioria das trocas mantém a grande maioria dos fundos dos clientes em “armazenamento frio”: em computadores off-line, onde as transações precisam ser assinadas e transferidas manualmente para a Internet. Air-gapping literal é comum: uma configuração de armazenamento a frio que eu costumava usar para fundos pessoais envolvia um computador permanentemente off-line gerando um código QR contendo a transação assinada, que eu digitalizaria do meu telefone. Os protocolos de troca modernos são ainda mais malucos e geralmente envolvem computação multipartidária entre vários dispositivos. Dado este tipo de configuração, fazer até mesmo uma única mensagem extra para provar o controle de um endereço é uma operação cara!

Existem vários caminhos que uma exchange pode seguir:

Mantenha alguns endereços públicos de uso prolongado — A troca geraria alguns endereços, publicaria uma prova de cada endereço uma vez para provar a propriedade e, em seguida, usaria esses endereços repetidamente. Esta é de longe a opção mais simples, embora adicione algumas restrições em como preservar a segurança e a privacidade.

Tenha muitos endereços, prove alguns aleatoriamente — A troca teria muitos endereços, talvez até usando cada endereço apenas uma vez e retirando-o após uma única transação. Nesse caso, a central pode ter um protocolo onde de tempos em tempos alguns endereços são selecionados aleatoriamente e devem ser “abertos” para comprovar a propriedade. Algumas exchanges já fazem algo assim com um auditor, mas em princípio essa técnica poderia ser transformada em um procedimento totalmente automatizado.

Opções de ZKP mais complicadas — Por exemplo, uma troca pode definir todos os seus endereços como 1 de 2 multisigs, onde uma das chaves difere por endereço e a outra é uma versão oculta de alguma chave de backup de emergência “grande” armazenada em algum complicado, mas maneira de segurança muito alta, por exemplo. Um multisig 12 de 16. Para preservar a privacidade e evitar revelar todo o conjunto de seus endereços, a exchange pode até executar uma prova de conhecimento zero na blockchain, onde comprova o saldo total de todos os endereços da cadeia que possuem esse formato.

A outra questão importante é a proteção contra o uso duplo colateral. Transferir garantias entre si para fazer prova de reservas é algo que as exchanges poderiam fazer facilmente e permitiria que elas fingissem ser solventes quando, na verdade, não são. Idealmente, a prova de solvência seria feita em tempo real, com uma prova atualizada a cada bloco. Se isso for impraticável, a próxima melhor coisa seria coordenar um cronograma fixo entre as diferentes trocas, por exemplo. Provando reservas às 14:00 UTC todas as terças-feiras.

Uma questão final é: você pode fazer prova de ativos em fiat? As exchanges não apenas mantêm criptomoedas, mas também moedas fiduciárias dentro do sistema bancário. Aqui, a resposta é: sim, mas tal procedimento inevitavelmente dependeria de modelos fiduciários “fiat”: o próprio banco pode atestar saldos, auditores podem atestar balancetes, etc. melhor que pode ser feito dentro dessa estrutura, mas ainda vale a pena.

Uma abordagem alternativa seria separar claramente entre uma entidade que administra a exchange e lida com stablecoins lastreadas em ativos como USDC, e outra entidade (o próprio USDC) que lida com o processo de entrada e saída de dinheiro para mover entre criptografia e serviços bancários tradicionais. Como os “passivos” do USDC são apenas tokens ERC20 on-chain, a prova dos passivos vem “de graça” e apenas a prova dos ativos é necessária.

Plasma e validiums: podemos tornar CEXs não custodiais?

Suponha que queremos ir além: não queremos apenas provar que a exchange tem fundos para pagar seus usuários. Em vez disso, queremos impedir que a troca roube completamente os fundos dos usuários.

A primeira grande tentativa disso foi o Plasma, uma solução de dimensionamento popular nos círculos de pesquisa da Ethereum em 2017 e 2018. O Plasma funciona dividindo o saldo em um conjunto de “moedas” individuais, onde cada moeda recebe um índice e vive em uma posição particular na árvore Merkle de um bloco de Plasma. Fazer uma transferência válida de uma moeda requer colocar uma transação na posição correta de uma árvore cuja raiz é publicada na cadeia.

image 50
Diagrama simplificado de uma versão do Plasma. As moedas são mantidas em um contrato inteligente que impõe as regras do protocolo Plasma no momento da retirada.

O OmiseGo tentou fazer uma troca descentralizada com base neste protocolo, mas desde então eles se voltaram para outras ideias — assim como o próprio Plasma Group, que agora é o otimista projeto de rollup EVM Optimism.

Não vale a pena olhar para as limitações técnicas do Plasma conforme concebidas em 2018 (por exemplo, provar a desfragmentação de moedas) como uma espécie de conto moral sobre todo o conceito. Desde o pico do discurso do Plasma em 2018, os ZK-SNARKs se tornaram muito mais viáveis ​​para casos de uso relacionados ao dimensionamento e, como dissemos acima, os ZK-SNARKs mudam tudo.

A versão mais moderna da ideia do Plasma é o que a Starkware chama de validium: basicamente o mesmo que um ZK-rollup, exceto onde os dados são mantidos fora da cadeia. Essa construção pode ser usada para muitos casos de uso, concebivelmente qualquer coisa em que um servidor centralizado precise executar algum código e provar que está executando o código corretamente. Em um validium, o operador não tem como roubar fundos, embora, dependendo dos detalhes da implementação, alguma quantidade de fundos do usuário possa ficar presa se o operador desaparecer.

Isso tudo é ótimo: longe de CEX vs DEX ser um binário, verifica-se que existe todo um espectro de opções, incluindo várias formas de centralização híbrida onde você ganha alguns benefícios como eficiência, mas ainda tem muitas proteções criptos impedindo o operador centralizado de se envolver na maioria das formas de abusos.

image 51

Mas vale a pena abordar a questão fundamental da metade direita desse espaço de design: lidar com erros do usuário. De longe, o tipo de erro mais importante é: e se um usuário esquecer sua senha, perder seus dispositivos, for hackeado ou perder o acesso à sua conta?

As trocas podem resolver esse problema: primeiro a recuperação de e-mail e, se isso falhar, formas mais complicadas de recuperação por meio de KYC. Mas para poder resolver tais problemas, a exchange precisa realmente ter controle sobre as moedas. Para conseguir recuperar fundos de contas de usuários por bons motivos, as trocas precisam ter poder que também possa ser usado para roubar fundos de contas de usuários por motivos ruins. Esta é uma troca inevitável.

A solução ideal de longo prazo é contar com a autocustódia, ampliada por tecnologias como multisig e carteiras de recuperação social para ajudar os usuários a lidar com situações de emergência. Mas, a curto prazo, existem duas alternativas claras que têm custos e benefícios claramente distintos:

image 52

Conclusões: o futuro de melhores exchanges

No curto prazo, existem duas “classes” claras de trocas: trocas com custódia e trocas sem custódia. Hoje, a última categoria é apenas DEXes como Uniswap, e no futuro também podemos ver CEXes criptograficamente “restritos”, onde os fundos do usuário são mantidos em algo como um contrato inteligente validium. Também podemos ver trocas de meia custódia nas quais confiamos nelas com fiduciário, mas não com criptomoeda.

Ambos os tipos de trocas continuarão a existir, e a maneira mais fácil de compatibilidade com versões anteriores de melhorar a segurança das trocas de custódia é adicionar prova de reserva. Isso consiste em uma combinação de prova de ativos e prova de responsabilidades. Existem desafios técnicos na criação de bons protocolos para ambos, mas podemos e devemos ir o mais longe possível para avançar em ambos e abrir o software e os processos o máximo possível para que todas as trocas possam se beneficiar.

No futuro de longo prazo, a esperança de Vitalik é que nos aproximemos cada vez mais de todas as trocas sem custódia, pelo menos no lado cripto. A recuperação da carteira existiria e pode ser necessário haver opções de recuperação altamente centralizadas para novos usuários que lidam com pequenas quantias, bem como instituições que exigem tais acordos por motivos legais, mas isso pode ser feito na camada da carteira e não dentro da própria exchange. A maneira como o magic.link interage com plataformas como o Polymarket é um exemplo dessa abordagem em ação. No lado fiduciário, o movimento entre o sistema bancário tradicional e o ecossistema cripto pode ser feito por meio de processos de entrada/saída nativos de stablecoins lastreadas em ativos, como o USDC. No entanto, ainda demorará um pouco até que possamos chegar lá totalmente.

Foto de Washington Leite
Foto de Washington Leite O autor:

Formado em Administração de Empresas, sou entusiasta da tecnologia e fascinado pelo mundo das criptomoedas, me aventuro no mundo do trade, sendo um eterno aluno. Bitcoin: The money of the future