Comprendre l’utilité de zkEVM par Scroll ZKP

Scroll zkEVm

Dernière modification effectuée le 04.09.2023 14:41

Cet article est traduit de zkEVM publié par Scroll ZKP.

Scroll remercie Vitalik Buterin, Barry Whitehat, Chih-Cheng Liang, Kobi Gurkan et Georgios Konstantopoulos pour leurs critiques et leurs commentaires perspicaces.

Introduction

Nous pensons que les zk-Rollup sont le Saint Graal – c’est une solution de mise à l’échelle de niveau 2 de premier ordre, très bon marché et sûre. Cependant, les zk-Rollups existants sont spécifiques à une application, ce qui rend difficile la construction de d’applications décentralisées (DApps )composables générales dans un zk-Rollup et la migration des applications existantes.

Nous présentons zkEVM, qui permet de générer des preuves zk pour la vérification de l’Ethereum Virtual Machine (EVM) générale. Cela nous permet de construire un zk-Rollup entièrement compatible avec l’EVM, vers lequel toute application Ethereum existante peut facilement migrer.

Dans cet article, nous identifions les défis de conception de zkEVM et pourquoi c’est possible maintenant. Nous donnons également une intuition plus spécifique et décrivons les idées de haut niveau sur la façon de le construire à partir de zéro.

Contexte

zk-Rollup est reconnu comme la meilleure solution de mise à l’échelle pour Ethereum. Il est aussi sûr que la couche 1 d’Ethereum et a le temps de finalisation le plus court par rapport à toutes les autres solutions de couche 2 (comparaisons détaillées ici).

« À moyen et à long terme, les rollups ZK l'emporteront dans tous les cas d’utilisation à mesure que la technologie ZK-SNARK s’améliorera. » Vitalik Buterin

L’idée de base de zk-Rollup est d’agréger un grand nombre de transactions dans un bloc Rollup et de générer une preuve succincte pour le bloc hors chaîne. Ensuite, le contrat intelligent de la couche 1 (Ethereum) n’a plus qu’à vérifier la preuve et à appliquer directement l’état mis à jour sans réexécuter ces transactions. Cela peut aider à économiser des frais de gaz d’un ordre de grandeur puisque la vérification de la preuve est beaucoup moins chère que la réexécution des calculs. Une autre économie provient de la compression des données (c’est-à-dire qu’on ne garde que le minimum de données sur la blockchain pour la vérification).

Bien que zk-Rollup soit sûr et efficace, ses applications sont encore limitées aux paiements et aux échanges. Il est difficile de construire des DApps à usage général pour les deux raisons suivantes.

Premièrement, si vous voulez développer des DApps dans un zk-Rollup, vous devez écrire toute votre logique de contrat intelligent en utilisant un langage spécial (c’est-à-dire R1CS).

Non seulement la syntaxe du langage requis est complexe, mais cela exige également une expertise extrêmement forte en matière de preuve nulle de connaissance (zero knowledge proof).

Deuxièmement, le zk-Rollup actuel ne prend pas en charge la composabilité. Cela signifie que différentes applications zk-Rollup ne peuvent pas interagir les unes avec les autres au sein de la couche 2. Cette qualité nuit considérablement à la composabilité des applications DeFi.

En un mot, un zk-Rollup est peu convivial pour les développeurs et ses fonctionnalités sont limitées pour l’instant. C’est le plus gros problème que nous voulons résoudre. Nous voulons offrir la meilleure expérience aux développeurs et soutenir la composabilité au sein de la couche 2 en prenant directement en charge la vérification EVM native, afin que les applications Ethereum existantes puissent simplement migrer vers le zk-Rollup tel quel.

Construire des DApps générales dans les zk-Rollups

Il y a deux façons de construire des DApps générales dans un zk-Rollup :

  1. La première consiste à construire un circuit spécifique à l’application (« ASIC ») pour différentes applications numériques.
  2. L’autre consiste à construire un circuit universel « EVM » pour l’exécution des contrats intelligents.

Le terme « circuit » fait référence à la représentation du programme utilisée dans la preuve nulle de connaissance (zero knowledge proof).

Par exemple, si vous voulez prouver que hash(x) = y, vous devez réécrire la fonction de hachage en utilisant la forme circuit. La forme circuit ne supporte que des expressions très limitées (c’est-à-dire que les R1CS ne supportent que l’addition et la multiplication). Il est donc très difficile d’écrire un programme en utilisant le langage de circuit — vous devez construire toute la logique de votre programme (y compris if else, loop, etc.) en utilisant add et mul.

1- La première approche nécessite que le développeur conçoive des circuits « ASIC » spécialisés pour les différentes applications numériques. C’est la manière la plus traditionnelle d’utiliser la preuve nulle de connaissance. Chaque DApp aura une charge moins importante grâce à la conception de circuits personnalisés. Cependant, elle pose le problème de la composabilité, puisque le circuit est « statique », et de l’expérience des développeurs, puisqu’elle nécessite une forte expertise en matière de conception de circuits.

2- La deuxième approche ne nécessite pas de conception spéciale ou d’expertise pour le développeur. L’idée de haut niveau d’une telle preuve basée sur la machine est que tout programme finira par s’exécuter sur le processeur (CPU), il suffit donc de construire un circuit CPU universel pour vérifier l’étape CPU de bas niveau. Ensuite, nous pouvons utiliser ce circuit CPU pour vérifier l’exécution de n’importe quel programme. Dans notre scénario, le programme est un contrat intelligent et le CPU est un EVM. Cependant, cette approche n’est pas couramment adoptée ces dernières années en raison de ses frais généraux importants. Par exemple, même si vous ne voulez prouver que le résultat de l’addition est correct qu’en une seule étape, vous devez quand même vous permettre de payer les frais généraux d’un circuit EVM entier. Si vous avez des milliers d’étapes dans votre trace d’exécution, la surcharge du circuit EVM du côté du prover sera 1000 fois supérieure.

Récemment, de nombreuses recherches ont été menées pour optimiser les preuves zk en suivant ces deux approches, y compris (i) la proposition de nouvelles primitives conviviales zk, par exemple le hachage Poseidon (Poseidon hash) peut atteindre une efficacité de 100x supérieure à SHA256 dans le circuit, (ii) le travail en cours sur l’amélioration de l’efficacité des machines virtuelles (VM) vérifiables générales, comme dans TinyRAM, et (iii) un nombre croissant d’astuces d’optimisation générales comme Plookup, et même plus généralement des bibliothèques cryptographiques plus rapides.

Dans notre article précédent, nous avons proposé de concevoir un circuit « ASIC » pour chaque DApp et de les laisser communiquer par des engagements cryptographiques. Cependant, sur la base des commentaires de la communauté, nous avons changé notre priorité et nous allons nous concentrer sur la construction d’un circuit EVM général (appelé « zkEVM ») en suivant la deuxième approche. zkEVM permettra exactement la même expérience de développement que la couche 1. Au lieu de laisser la complexité de la conception au développeur, nous la prendrons en charge et résoudrons le problème de l’efficacité en concevant un circuit EVM personnalisé.

Défis de conception de zkEVM

zkEVM est difficile à construire. Même si l’intuition est claire depuis des années, personne n’a réussi à construire un circuit EVM natif. Contrairement à la TinyRAM, il est encore plus difficile de concevoir et de mettre en œuvre la zkEVM pour les raisons suivantes :

Premièrement, l’EVM a un support limité des courbes elliptiques. Pour l’instant, l’EVM ne supporte que l’appariement BN254. Il est difficile de faire une récursion de preuve puisque la courbe elliptique cyclique n’est pas directement supportée. Il est également difficile d’utiliser d’autres protocoles spécialisés dans ce contexte. L’algorithme de vérification doit être compatible avec l’EVM.

Deuxièmement, la taille des mots de l’EVM est de 256 bits. l’EVM fonctionne sur des entiers de 256 bits (comme la plupart des VM ordinaires fonctionnent sur des entiers de 32 à 64 bits), alors que les preuves zk fonctionnent plus « naturellement » sur des champs premiers. Faire de « l’arithmétique de champs non concordants » à l’intérieur d’un circuit nécessite des preuves d’étendue, ce qui ajoutera ~100 contraintes par étape EVM. Cela augmentera la taille du circuit EVM de deux ordres de grandeur.


Troisièmement, l’EVM possède de nombreux opcodes spéciaux. l’EVM est différent d’une machine virtuelle traditionnelle, il a de nombreux opcodes spéciaux comme CALL et il a également des types d’erreur liés au contexte d’exécution et au gaz. Cela pose de nouveaux défis à la conception des circuits.

Quatrièmement, l’EVM est une machine virtuelle basée sur la pile. L’architecture SyncVM (zksync) et Cairo (starkware) définit son propre IR/AIR dans le modèle basé sur les registres. Ils ont construit un compilateur spécialisé pour compiler le code des contrats intelligents dans une nouvelle IR compatible avec zk. Leur approche est compatible avec le langage au lieu d’être compatible avec le modèle EVM natif. Elle est plus difficile à prouver pour le modèle basé sur la pile et supporte directement la chaîne d’outils native.

Cinquièmement, la disposition de stockage d’Ethereum entraîne une énorme surcharge. L’agencement du stockage d’Ethereum dépend fortement de Keccak et d’un énorme MPT4, tous deux ne sont pas compatibles avec le zk et ont un énorme surcoût de preuve. Par exemple, le hachage Keccak est 1000x plus grand que le hachage Poseidon dans le circuit. Cependant, si vous remplacez Keccak par un autre hachage, cela posera des problèmes de compatibilité avec l’infrastructure Ethereum existante.

Sixièmement, la preuve basée sur la machine a une surcharge gigantesque. Même si vous pouvez gérer correctement tous les problèmes susmentionnés, vous devez encore trouver un moyen efficace de les composer ensemble pour obtenir un circuit EVM complet. Comme je l’ai mentionné dans la section précédente, même de simples opcodes comme l’addition peuvent entraîner l’overhead de tout le circuit EVM.

Pourquoi est-ce possible maintenant ?

Grâce aux grands progrès réalisés par les chercheurs dans ce domaine, de plus en plus de problèmes d’efficacité ont été résolus au cours des deux dernières années, et le coût de démonstration de la zkeVM est finalement réalisable !

La plus grande amélioration technologique provient des aspects suivants :

L’utilisation de l’engagement polynomial. Au cours des dernières années, la plupart des protocoles de preuve succincts à connaissance nulle s’en tiennent à R1CS avec une requête PCP encodée dans une configuration de confiance spécifique à l’application. La taille du circuit explose généralement et vous ne pouvez pas faire beaucoup d’optimisations personnalisées puisque le degré de chaque contrainte doit être de 2 (l’appariement bilinéaire ne permet qu’une multiplication dans l’exposant). Avec les schémas d’engagement polynomiaux, vous pouvez élever vos contraintes à n’importe quel degré avec une configuration universelle ou même transparente. Cela permet une grande flexibilité dans le choix du backend.

L’apparition d’arguments de table de consultation et de gadgets personnalisés. Une autre optimisation importante provient de l’utilisation des tables de consultation. L’optimisation est d’abord proposée dans Arya et est ensuite optimisée dans Plookup. Cela peut permettre d’économiser BEAUCOUP de primitives peu favorables à la zk (c’est-à-dire les opérations par bit comme AND, XOR, etc.). Les gadgets personnalisés vous permettent de faire des contraintes de haut degré avec efficacité. TurboPlonk et UltraPlonk définissent une syntaxe de programme élégante pour faciliter l’utilisation des tables de consultation et la définition de gadgets personnalisés. Cela peut être extrêmement utile pour réduire l’overhead du circuit EVM.

La preuve récursive est de plus en plus réalisable. Dans le passé, la preuve récursive présentait un surcoût énorme car elle reposait sur des courbes elliptiques cycliques adaptées à l’appariement (c’est-à-dire une construction basée sur les courbes MNT). Cela introduit un surcoût de calcul important. Cependant, de plus en plus de techniques permettent de le faire sans sacrifier l’efficacité. Par exemple, Halo peut éviter le besoin d’une courbe adaptée à la paire et amortir le coût de la récursion en utilisant un argument spécial de produit interne. Aztec montre que vous pouvez faire l’agrégation de preuve pour les protocoles existants directement (les tables de consultation peuvent réduire l’overhead de l’opération de champ non-natif et donc rendre le circuit de vérification plus petit). Cela peut améliorer considérablement l’évolutivité de la taille du circuit supporté.

L’accélération matérielle rend la preuve plus efficace. A notre connaissance, nous avons réalisé l’accélérateur GPU et ASIC/FPGA le plus rapide pour le prover. Notre article décrivant le prover ASIC a déjà été accepté par la plus grande conférence informatique (ISCA) cette année. Le prover GPU est environ 5x-10x plus rapide que l’implémentation de Filecoin. Cela peut améliorer considérablement l’efficacité de calcul du prover.

Ok, alors comment ça marche et comment le construire ?

Outre la forte intuition et l’amélioration de la technologie, nous devons encore avoir une idée plus claire de ce que nous devons prouver et définir une architecture plus spécifique. Nous présenterons plus de détails techniques et de comparaisons dans les articles suivants. Ici, nous décrivons le flux de travail global et certaines idées clés.

Flux de travail pour les développeurs et les utilisateurs

Les développeurs peuvent mettre en œuvre des contrats intelligents en utilisant n’importe quel langage compatible avec EVM et déployer le bytecode compilé sur Scroll. Ensuite, les utilisateurs peuvent envoyer des transactions pour interagir avec ces contrats intelligents déployés. L’expérience des utilisateurs et des développeurs sera exactement la même que celle de la couche 1. Toutefois, les frais de gaz sont considérablement réduits et les transactions sont pré-confirmées instantanément sur Scroll (le retrait ne prend que quelques minutes pour être finalisé).

Flux de travail pour zkEVM

Même si le flux de travail extérieur reste le même, la procédure de traitement sous-jacente pour la couche 1 et la couche 2 est entièrement différente :

  • La couche 1 repose sur la réexécution des contrats intelligents.
  • La couche 2 repose sur la preuve de validité du circuit zkEVM.

Expliquons plus en détail comment les choses se passent différemment pour les transactions de la couche 1 et de la couche 2.

Dans la couche 1, les bytecodes des smart contracts déployés sont stockés dans le stockage Ethereum. Les transactions seront diffusées dans un réseau P2P. Pour chaque transaction, chaque nœud complet doit charger le bytecode correspondant et l’exécuter sur EVM pour atteindre le même état (la transaction sera utilisée comme donnée d’entrée).

Dans la couche 2, le bytecode est également stocké dans le stockage et les utilisateurs se comporteront de la même manière. Les transactions seront envoyées hors chaîne à un nœud zkEVM centralisé. Ensuite, au lieu de simplement exécuter le bytecode, zkEVM générera une preuve succincte pour prouver que les états sont mis à jour correctement après l’application des transactions. Enfin, le contrat de la couche 1 vérifiera la preuve et mettra à jour les états sans ré-exécuter les transactions.

Regardons de plus près le processus d’exécution et voyons ce que zkEVM doit prouver à la fin de la journée. Dans l’exécution native, EVM va charger le bytecode et exécuter les opcodes dans le bytecode un par un depuis le début. Chaque opcode peut être considéré comme effectuant les trois sous-étapes suivantes : (i) lire des éléments de la pile, de la mémoire ou du stockage (ii) effectuer un calcul sur ces éléments (iii) réécrire les résultats dans la pile, la mémoire ou le stockage. Par exemple, l’opcode add doit lire deux éléments de la pile, les additionner et réécrire le résultat dans la pile.

Ainsi, il est clair que la preuve de zkEVM doit contenir les aspects suivants correspondant au processus d’exécution

  • Le bytecode est correctement chargé depuis le stockage persistant (Vous exécutez le bon opcode chargé depuis une adresse donnée)
  • Les opcodes dans le bytecode sont exécutés un par un de manière cohérente (Le bytecode est exécuté dans l’ordre sans manquer ou sauter aucun opcode)
  • Chaque opcode est exécuté correctement (Les trois sous-étapes de chaque opcode sont exécutées correctement, R/W + calcul)

zkEVM Point fort du design

Lors de la conception de l’architecture de zkEVM, nous devons traiter/adresser les trois aspects susmentionnés un par un.

Nous devons concevoir un circuit pour un accumulateur cryptographique.

Cette partie agit comme un « stockage vérifiable », nous avons besoin d’une technique pour prouver que nous lisons correctement. Un accumulateur cryptographique peut être utilisé pour y parvenir efficacement. Prenons l’exemple de l’arbre de Merkle. Le bytecode déployé sera stocké comme une feuille dans l’arbre de Merkle. Ensuite, le vérificateur peut vérifier que le bytecode est chargé correctement à partir d’une adresse donnée en utilisant une preuve succincte (c’est-à-dire vérifier le chemin de Merkle en circuit). Pour le stockage Ethereum, nous avons besoin que le circuit soit compatible avec la fonction de hachage Merkle Patricia Trie et Keccak.

Nous devons concevoir un circuit pour relier le bytecode avec la trace d’exécution réelle.

Un problème pour déplacer le bytecode dans un circuit statique est celui des opcodes conditionnels comme jump (correspondant à la boucle, à l’instruction if else dans les smart contracts). Il peut sauter n’importe où. La destination n’est pas déterminée avant que l’on ait exécuté le bytecode avec une entrée spécifique. C’est la raison pour laquelle nous devons vérifier la trace d’exécution réelle. La trace d’exécution peut être considérée comme un « bytecode déroulé », elle comprendra la séquence d’opcodes dans l’ordre d’exécution réel (c’est-à-dire que si vous sautez à une autre position, la trace contiendra l’opcode et la position destinés).

Le prover fournira la trace d’exécution directement comme témoin du circuit. Nous devons prouver que la trace d’exécution fournie est bien celle qui a été « déroulée » à partir du bytecode avec une entrée spécifique. L’idée est de forcer la valeur du compteur du programme à être cohérente. Pour gérer la destination indéterminée, l’idée est de laisser le prover tout fournir. Ensuite, vous pouvez vérifier la cohérence efficacement en utilisant un argument de recherche (c’est-à-dire, prouver que les opcodes avec le bon compteur global est inclus dans le « bus »).

Nous devons concevoir des circuits pour chaque opcode (prouver que la lecture, l’écriture et les calculs dans chaque opcode sont corrects).

C’est la partie la plus importante — Prouver que chaque opcode dans la trace d’exécution est correct et cohérent. Cela apportera un énorme surcoût si vous mettez toutes les choses ensemble directement. L’idée d’optimisation importante ici est que

  • Nous pouvons séparer R/W et calcul en deux preuves. L’une va chercher les éléments nécessaires pour tous les opcodes dans un « bus ». L’autre prouvera que le calcul effectué sur les éléments du « bus » est exécuté correctement. Cela peut réduire considérablement l’overhead de chaque partie (c’est-à-dire qu’il n’est pas nécessaire de considérer l’ensemble du stockage de l’EVM dans la preuve de calcul). Dans une spécification plus détaillée, la première est appelée « preuve d’état » et la seconde est appelée « preuve EVM ». Une autre observation est que le « mappage de bus » peut être traité efficacement par l’argument de consultation.
  • Nous pouvons concevoir une contrainte personnalisée de plus haut degré pour chaque opcode (par exemple, le mot EVM peut être résolu efficacement en le découpant en plusieurs morceaux). Nous pouvons choisir d' »ouvrir » une contrainte par un polynôme sélecteur en fonction de nos besoins. Cela permet d’éviter la surcharge de tout le circuit EVM à chaque étape.

Cette architecture a été spécifiée pour la première fois par la Fondation Ethereum. Elle est encore à un stade précoce et en développement actif. Nous collaborons étroitement avec eux pour trouver la meilleure façon de mettre en œuvre le circuit EVM. Jusqu’à présent, les traits les plus importants sont définis et certains opcodes ont déjà été implémentés ici (en utilisant la syntaxe UltraPlonk dans le repo Halo2). Plus de détails seront présentés dans les articles suivants. Nous invitons les lecteurs intéressés à lire ce document. Le processus de développement sera transparent. Il s’agira d’un effort communautaire et d’une conception entièrement ouverte. Nous espérons que d’autres personnes pourront nous rejoindre et contribuer à ce projet.

Qu’est-ce qu’il peut apporter de plus ?

zkEVM est bien plus qu’une simple mise à l’échelle de la couche 2. Il peut être considéré comme un moyen direct de faire évoluer la couche 1 d’Ethereum via la preuve de validité de la couche 1. Cela signifie que vous pouvez mettre à l’échelle la couche 1 existante sans aucune couche 2 spéciale.

Par exemple, vous pouvez utiliser zkEVM comme un nœud complet. La preuve peut être utilisée pour prouver les transitions entre les états existants directement — Pas besoin de porter quoi que ce soit à la couche 2, vous pouvez prouver pour toutes les transactions de la couche 1 directement ! Plus largement, vous pouvez utiliser zkEVM pour générer une preuve succincte pour l’ensemble de l’Ethereum comme Mina. La seule chose que vous devez ajouter est la récursion de preuve (c’est-à-dire intégrer le circuit de vérification d’un bloc à la zkEVM).

Conclusion

zkEVM peut offrir la même expérience aux développeurs et aux utilisateurs. C’est un ordre de magnitudes moins cher sans sacrifier la sécurité. Une architecture a été proposée pour le construire de manière modulaire. Elle exploite les récentes percées dans le domaine de la preuve à connaissance zéro pour réduire les frais généraux (y compris les contraintes personnalisées, les arguments de recherche, la récursion de la preuve et l’accélération matérielle). Nous sommes impatients de voir d’autres personnes se joindre à l’effort de la communauté zkEVM et de réfléchir avec nous !

En savoir plus sur nous

Scroll Tech est une nouvelle société axée sur la technologie. Notre objectif est de construire un zk-Rollup compatible EVM avec un solide réseau de preuves (voir un aperçu ici). Toute l’équipe se concentre maintenant sur le développement. Nous recrutons activement des développeurs passionnés, contactez-nous à l’adresse [email protected]. Si vous avez des questions sur le contenu technique, contactez-moi à [email protected]. Ma messagerie privée Twitter est également ouverte.

Articles qui pourraient vous intéresser