Introdução
Com a comoditização dos zkevms, surgiram oportunidades interessantes para fornecer infraestrutura privada de contratos inteligentes, mantendo ao mesmo tempo a compatibilidade do evm. Os desenvolvedores podem escrever solidez e compilá-lo usando uma versão do compilador solidity ou algumas ferramentas de pós-processamento. Para fazer contratos inteligentes privados.
Existem importantes compromissos em torno do Estado privado global e da privacidade que decorrem da noção de que é necessário saber o que se está a provar para poder prová-lo. Portanto, você não pode ter um contrato inteligente privado com um estado público global que você não conhece. Segue-se que não se pode ter um contrato inteligente privado com um estado privado global. Por exemplo, o uniswap não é possível porque o provador precisa saber o saldo de ambos os pools para poder provar que a troca foi feita corretamente. mais sobre isso Por que você não pode construir um uniswap privado com ZKPs – #24 por bowaggoner
Portanto, algumas das coisas que conhecemos e amamos não são possíveis de implementar de forma privada, até que tenhamos IO, e é por isso que IO é tão importante. Isso nos permite criar um ethereum totalmente privado com exatamente as mesmas premissas de confiança.
De qualquer forma, este post é sobre como podemos adicionar dois opcodes a reth pstore e pload , compilá-los em zkevm e ter contratos inteligentes privados que tenham estado de usuário privado, mas não estado global privado.
Como
Você tem certas chamadas contratuais que são privadas. Fazemos isso aproveitando o código zkevm que existe para provar que foram executados corretamente, mas não revelando nenhuma informação sobre o que o contrato realmente fez. Além de satisfazer algum requisito, por exemplo, que um certo número de tokens tenha sido aprovado para uso de outro contrato, mas não de tokens de quem. Implementamos dois novos códigos operacionais pstore e pload semelhantes a sload e sstore, exceto que os valores são privados.
Caixa de ferramentas
Tomamos como nossa cadeia de ferramentas o zkevm. Não faremos nenhuma alteração no próprio zkevm. Trataremos isso como uma caixa preta. Em vez disso, faremos alterações em reth. Queremos que reth adicione duas novas árvores. A árvore de armazenamento privado (PST) e a árvore anuladora privada (PNT).
Cada folha do PST e PNT é publicada a cada atualização. Assim, qualquer pessoa pode fazer comprovante de adesão a qualquer folha. Mas os valores contidos nessas folhas são conhecidos apenas pelo usuário que as criou.
carregar
pload é um opcode evm que adicionamos. É semelhante ao sload. Quando o sload é executado no zkevm, o zkzkevm faz uma prova merkle de que um determinado valor está em uma determinada posição na árvore.
Da mesma forma, para pload, fazemos uma prova de pertinência daquela folha na árvore, mas também fazemos uma prova de que essa folha não foi anulada.
Digamos que queremos carregar um valor x. Então, basicamente, estamos fazendo duas provas Merkle
- provar x em PST
- provar que x.nullifier não está em PNT
Somente o usuário que conhece o valor secreto daquela folha pode calcular seu anulador e somente tal usuário pode provar que ela não foi anulada.
NOTA: sload tem uma prova de não inclusão implícita porque usa árvore Merkel ordenada. Não podemos usar uma árvore merkle ordenada para pload e pstore, então precisaremos de algum tipo de codificação para garantir que uma determinada folha não foi criada. Tal codificação poderia ser hash (contrato, slot, valor, anulador)
NOTA: Acho que também se você carregar um endereço sem nada, obterá 0x0 e isso também precisará ser considerado. Talvez seja necessário pensar em uma maneira de lidar com isso em zkzkevm de forma que o mesmo devex exista. Mas é difícil provar que um espaço de armazenamento não foi preenchido.
loja
pstore fará a mesma coisa que sstore. Mas funciona de maneira um pouco diferente.
No zkevm, toda vez que um sstore é executado, ele efetivamente executa duas provas merkle. A primeira prova que o valor atual da folha é x e a segunda prova de merkle calcula a raiz de merkle se o valor de x for substituído por y. Portanto, você pode pensar na primeira prova como uma prova resumida de todas as folhas da árvore e na segunda prova como a substituição de apenas uma única folha (x) por y.
Então armazene
- Prove que um valor x está na árvore
- Substitui por y
pstore pode fazer a mesma coisa, mas de maneira um pouco diferente
- Ele remove x obtendo x.nullifier e adicionando-o à árvore anuladora.
- Ele substitui x por y adicionando-o ao PST.
Solidez
O Solidity compila para opcodes evm.
Digamos que temos o seguinte contrato inteligente
def transfer(sender, reciver, amount) private:
bal(sender)= bal(sender) - amount
bal(reciver) = bal(reciver) + amount
# this is not adding to the users balance directly. Instead it is kind of input out put thing where the user needs to get the received funds to add to their total balance. This nuance is encapsulated in a receiver address abstraction for now. But needs more work to figure out what is needed on zkzkevm side.
return(1)
O compilador de solidez (de algum pós-processador) veria isso e substituiria todos os sloads/sstore por ploads/pstores no bytecode. Isso seria feito apenas para funções que possuem o modificador ou tag private.
Cadeias de chamadas com algumas pernas privadas e algumas pernas públicas
Pense nisso como uma versão mais programável do asteca connect. Então, digamos que temos uma carteira privada e faça com que essa carteira chame uniswap. Isso pode ser feito, mas temos que ter cuidado para limpar message.sender, tx.origin , nonce , gas_price, gas_limit e outros vazamentos de metadados. Existem algumas maneiras de fazer isso
- Crie contratos de proxy para cada chamada e depois rebalanceie em outro tx ou no final da pilha de chamadas tx atual.
- Use um contrato de proxy global
nota: tx.origin pode precisar ser higienizado na alteração reth. Mas provavelmente é apenas um empacotador, então não é tão ruim, eu acho.
Compensações
Tudo isso parece um pouco complicado apenas para conectar o asteca. Mas o poder aqui reside na capacidade de reutilizar a maior parte da infraestrutura que temos atualmente para permitir aplicações muito mais poderosas.
Contratos de cartel
Conversamos um pouco sobre o estado global privado e como é impossível fazer uniswap e coisas assim. Mas digamos que eu queira fazer um contrato inteligente para mim e meus amigos. Quero manter o código-fonte privado publicamente, mas permitir que eu e meus amigos o executemos. Portanto, isso também é possível, só precisamos flexibilizar as garantias de disponibilidade de dados dos contratos inteligentes, de modo que o código do contrato inteligente não precise ser publicado.
Há algumas nuances sobre as garantias de disponibilidade de dados dentro do cartel. Suponho que poderíamos implementar algum tipo de registro forçado onde todas as atualizações de dados são criptografadas e publicadas para que apenas os membros do cartel possam ver.
Conclusão
Parece que esta ideia será imediatamente útil de duas maneiras
- Fazendo um rollup privado onde um servidor monstro faz todas as provas de que o usuário fornece seus dados a este servidor, mas não a todos os outros
- Um rollup privado onde os usuários fazem algumas das provas para que seus acessos de armazenamento sejam ocultados do servidor monstro.
Parece útil e fácil de implementar. Não exigindo nenhum conhecimento de zk, tomando o zk como mercadoria.
PENDÊNCIA
Precisamos pensar mais sobre
- Se tornarmos os EOA privados por padrão, parece possível com alguns truques de nulificador, como fazê-los assinar “nullifier” e aquela string aleatória se torna seu nullfieir ou como nullifier_0 = hash (sign(“nullfiier”) , 0 ) nullifier_1 = hash(sign(“nullifier”,1)) e assim por diante. Mas para fazer isso teríamos que compilar todos os contratos erc20 para usar pstore e pload para erc20s. Parece que isso pode quebrar outras coisas. Mas uma privacidade manual da EOA parece não incluir mudanças de estado porque a maioria das pessoas se preocupa com o erc20 e não com a eth.
- É viável fazer uma prova zkevm de algum conjunto descontraído de coisas no celular? algumas cargas
- Se o valor que você está armazenando for gerado dinamicamente, é melhor ter um anulador que o servidor monstro possa usar para armazenar essa folha para você, em vez de criar a folha completa devido a condições de corrida.
- Como fornecer meu endereço para que eu possa receber fundos de forma privada, sem conectar todos os meus recibos
- Como posso usar o registro ou outras construções para saber se recebi fundos. Provavelmente tão simples quanto retornar um log que inclui algum tipo de “sinalização” criptografada
Fontesethresear