Rand est open source. Le full node, l’explorateur, le bridge, la recherche sur les preuves et les clients wallet vivent chacun dans leur propre dépôt sur GitHub. Lisez le code, exécutez les tests, envoyez des correctifs. Cette page est la carte : où se trouve chaque composant, avec quoi il est construit, jusqu’où le système de preuve est arrivé, et où il s’arrête aujourd’hui.
Dépôts
| dépôt | contenu | langage |
|---|---|---|
randprotocol/fullnode | Full node et wallet de référence : HotStuff BFT chaîné, réseau libp2p, le pool de notes RAND protégé, le vérificateur de preuves zkVM, JSON-RPC, la CLI wallet rand et le prouveur délégué rand-prover. | Rust |
randprotocol/randscan.org | Explorateur de blocs derrière randscan.org : un indexeur axum avec une API REST et WebSocket sur PostgreSQL, et un frontend Next.js. | Rust · TypeScript |
randprotocol/bridge | Bridge à gardiens pour USDT et USDC depuis Ethereum, Binance Smart Chain, Tron et Solana : les contrats de garde, le format d’attestation partagé et ses vecteurs de test. | Solidity · Rust |
randprotocol/zkp-circuits | Présentations pas à pas des systèmes de preuve (Groth16 contre STARK, pool protégé, signatures en anneau, mixer), research/, la zkVM de référence de Rand, recursion/, la VM de récursion, la chaîne d’outils invitée et les deux traducteurs, ainsi que les noyaux CUDA. La compilation du fullnode exige que ce dépôt soit cloné à côté, sous le nom circuits/. | Rust |
randprotocol/clients | Les clients wallet : bureau, web, iOS et Android. | Rust · Swift · Java · JavaScript |
La pile
Du Rust de bout en bout. Rand est sa propre chaîne : un nœud HotStuff BFT avec une couche de gossip libp2p, un pool de notes entièrement protégé comme registre, des signatures et un chiffrement de notes post-quantiques, et la zkVM de Rand pour le calcul confidentiel, le tout dans le dépôt fullnode. Le système de preuve lui-même est la partie en recherche active, plus bas.
| couche | ce qui s’exécute |
|---|---|
| Consensus | HotStuff BFT chaîné, quorums pondérés par la mise, validation en trois chaînes |
| Réseau | libp2p : TCP, Noise, Yamux, gossipsub, Kademlia, mDNS sur les LAN |
| Registre | Pool de notes protégé : arbre Poseidon2 de profondeur 32, ensemble de nullifiers, un bundle à actifs cachés 4 entrées-4 sorties par transaction (2 entrées-2 sorties jusqu’à la chaîne 13) ; depuis la chaîne 17, une seconde preuve d’authentification de palier 10 à côté de la preuve du bundle (autorisation scindée) ; depuis la chaîne 18, des enveloppes de note de 1 860 octets avec un mémo chiffré |
| Jetons | RPL : un jeton est une entrée du registre du ledger avec un identifiant rpl1…, pas un contrat ; il circule sous forme de notes dans le même pool |
| Staking | Registre public des validateurs : mise issue d’un bundle, désengagement sur deux époques, époques de 1 000 blocs ; depuis la chaîne 20, un nouveau validateur est admis par un vote de l’ensemble |
| Calcul confidentiel | zkVM de Rand : RV32IM sous un STARK Plonky3 par lots, FRI à masquage ZK, ensemble de contraintes 8 ; depuis la chaîne 18, un appel déclare une limite de gas que le circuit applique et paie par gas et par KiB ; depuis la chaîne 20, un programme conserve son état dans des cellules et détient de la valeur dans un coffre (RPL-2) |
| Cryptographie | Dilithium2 · ML-KEM-768 · Poseidon2 · BLAKE3 · ChaCha20-Poly1305 |
| Stockage | Une RocksDB par nœud, commits avec fsync, contrôle d’intégrité au démarrage ; élagage facultatif de l’historique (--prune-history 24h), les nœuds d’archive conservant tout |
| Bridge | Verrouillages attestés par des gardiens sur quatre chaînes, avec un quorum de cosignatures Dilithium2 sur chaque émission ; un actif bridgé est une note dans le même pool |
| Langage | Rust partout ; Solidity pour le bridge, TypeScript pour l’explorateur |
Une seule relation pour tous les programmes
La relation d’exécution universelle R_exec du whitepaper existe sous forme de code : rand_zkvm, une machine RV32IM prouvée sous un unique STARK par lots sur Plonky3 au-dessus du corps Goldilocks. Elle prouve que quelque trace a exécuté le programme hc vers ces sorties publiques, sur des entrées engagées par un H_IN salé, et rien du programme n’est jamais un paramètre du vérificateur. Publier un programme confidentiel signifie enregistrer un hash, jamais générer un circuit sur mesure.
Le système de preuve est transparent, sans setup de confiance ni courbe à couplage, et son hypothèse est une fonction de hachage résistante aux collisions. Tout autre composant qui touche aux preuves est censé converger vers cette crate plutôt que de développer la sienne. La crate se trouve dans zkp-circuits/research et est intégrée au fullnode à l’ensemble de contraintes 8 (circuits aeacf31, fullnode v0.6.7 et v0.6.8). Les tableaux et mesures ci-dessous décrivent l’ensemble de contraintes 5 (jalon M4.2), sauf lorsqu’une ligne nomme un ensemble plus récent ; ils sont tirés des fichiers docs/zkvm.md, docs/zkvm-milestones.md et docs/confidential.md du fullnode à la date du 2026-09-13, et les mesures sont citées telles que relevées sur un portable Apple Silicon, non comme des objectifs.
Huit tables sur des bus nommés, une neuvième à la demande
Un seul engagement, une seule ouverture FRI. Les tables ne s’appellent jamais entre elles ; elles échangent des faits sur des bus LogUp nommés (PROGRAM, PROGRAM_WORD, MEMORY, ALU, POSEIDON2, INPUT_DIGEST, INPUT_READ, KECCAK et les consultations de plage et de quartet) et le vérificateur contrôle que chaque bus est équilibré globalement. Le degré maximal des contraintes de chaque table est fixé par un test sous le plafond de 8 que permet le blowup FRI.
| table | nature | rôle |
|---|---|---|
program | témoin | Mots d’instruction bruts décodés dans le circuit depuis M3.4, condensés par le cpu en hc |
cpu | témoin | Une ligne par cycle, plus des lignes de condensat qui absorbent le programme dans hc et les entrées salées dans H_IN |
memory | témoin | Registres et RAM dans une seule table, triés par (space, addr, ts) ; accès inférieurs au mot depuis M2.5 |
alu | témoin | Arithmétique par membres d’un octet, décalages, comparaisons ; multiplication et division RV32M depuis M2.6 |
range | prétraitée · 256 lignes | Contrôles de plage et consultation des puissances de deux |
nibble | prétraitée · 256 lignes | AND, OR, XOR sur 4 bits ; une correspondance est en soi un contrôle de plage sur les deux opérandes |
poseidon2 | témoin | Une ligne par ronde de permutation, en blocs de 32 lignes ; alimente le bus POSEIDON2 et les deux condensats |
input | témoin · depuis M4.1 | Une ligne par mot d’entrée privé ; alimente INPUT_DIGEST et INPUT_READ, de sorte qu’une lecture ne peut échapper à l’engagement |
keccak | témoin · facultative | Keccak-f[1600] en blocs de 32 lignes, présente seulement dans une preuve dont l’invité a appelé KECCAK (M4.2) |
Trois ensembles de contraintes ont été livrés depuis. L’ensemble 6 a ajouté une table public obligatoire pour l’entrée publique d’un programme fixée au déploiement, liée au condensat non salé H_PUB, ainsi qu’une table sha256 facultative à côté de keccak. L’ensemble 7 (chaîne 16) masque chaque terminal LogUp sur un nouveau bus BLIND et impose à chaque table déclarée un plancher de 2⁷ lignes, et ajoute l’appel système POSEIDON2_LEN à longueur liée. L’ensemble 8 (chaîne 18) ajoute une colonne GAS à la table cpu et une valeur publique, le GAS_LIMIT déclaré.
Ce que révèle une preuve
Public : le hash de code hc (huit mots de condensat dans le circuit), l’engagement d’entrée salé H_IN (huit mots), le palier de gas et huit mots de sortie. Depuis l’ensemble de contraintes 6 également H_PUB, le condensat de l’entrée publique, et depuis l’ensemble de contraintes 8 la limite de gas déclarée. L’en-tête de la preuve déclare les hauteurs des tables Keccak et SHA-256, il montre donc si un appel a haché et, au-dessus du plancher de 2⁷, approximativement dans quelle mesure.
Caché : les entrées privées (H_IN est salé, il est donc masquant autant que liant) ; chaque mot d’instruction, car le vérificateur contrôle hc et jamais le programme ; chaque valeur de registre et de mémoire ; chaque branche prise ; le nombre exact de cycles et le gas exact utilisé ; et les appels système exécutés, hormis ce que montrent les hauteurs des deux tables de hachage.
Le palier est public pour chaque preuve parce que la taille d’un STARK révèle déjà la hauteur de sa trace ; cacher l’indice n’apporterait rien. hc est liant, pas masquant : voir où il s’arrête aujourd’hui.
Mesures, à l’ensemble de contraintes 5
| FRI | 80 requêtes · 20 bits de PoW · blowup 8 · arité 8 · ZK activé ; 260 bits conjecturés, environ 86 prouvés. Le réglage à 27 requêtes de M2 a été annulé par l’audit du 2026-09-12 |
| Appel | private_payment au palier 10 : environ 7 s pour prouver, environ 1,2 MB de preuve à 80 requêtes (435 KB à 27), contre 21,6 s et 892 KB à M1 |
| Transfert | Le guest de bundle 2 entrées-2 sorties des chaînes jusqu’à la 13 : 3 811 mots, environ 9 160 cycles, palier 14 ; environ 100 s pour prouver, environ 1,3 MB de preuve. Le guest à actifs cachés 4 entrées-4 sorties de la chaîne 14 est fixé au même palier : environ 100 s, environ 1,42 MB |
| Vérification | Environ 16 ms avec une clé chaude ; la première vérification à une nouvelle clé (palier, hauteurs) prend environ 230 ms |
| Bloc | Budget de 4 MiB et plafond de preuves de 2 MiB : environ trois transferts protégés par bloc à 80 requêtes |
Portable Apple Silicon, build release. C’est la séparation des tables d’octets de M2.3 qui a fait baisser le temps de preuve ; c’est le profil à 80 requêtes qui a fait remonter la taille des preuves. La clé du vérificateur est indépendante du contenu du programme, indexée par le palier et par les hauteurs de programme, d’entrée et de keccak déclarées par la preuve, de sorte qu’un nœud chauffe une clé et la réutilise.
Les jeux de contraintes suivants ont fait évoluer les tailles. Avec le jeu de contraintes 7, une preuve de palier 10 pèse 1 367 688 octets au profil de production, et une preuve de palier 10 qui embarque Keccak 3 283 898 (mesuré le 2026-09-28). Depuis la chain 17, un transfert porte deux preuves : la preuve de bundle de palier 14, d’environ 1,49 MB, et la preuve d’authentification de palier 10, d’environ 1,37 MB et d’environ 7 s de preuve. Le genesis de la chain 20 fixe un bloc de 20 MiB et un plafond de preuve de 4 MiB, et un appel ne peut pas dépasser le palier 14.
Trois cibles, un seul circuit
Seul RISC-V s’exécute nativement. Les programmes Solidity et Solana s’exécutent soit sur un guest interpréteur au sein de la même relation, avec leur bytecode en entrée, soit sont traduits hors chaîne en programmes RISC-V dont les sorties sont identiques mot pour mot à celles de l’interpréteur. Les opcodes coûteux appellent des tables de coprocesseur dédiées plutôt qu’une simulation bit à bit.
| cible | chemin | coprocesseurs |
|---|---|---|
| RISC-V | Natif. RV32IM, soit assemblé à la main via asm.rs, soit en Rust no_std compilé pour riscv32im-unknown-none-elf et chargé comme binaire plat depuis M4.1, soit construit à partir de Rust ou de C par rand-guest dans le conteneur d’image (Déployer un programme Rust) | Poseidon2 (et POSEIDON2_LEN depuis le jeu 7) ; Keccak-f[1600] depuis M4.2 ; SHA-256 depuis le jeu 6 |
| Solidity | solc --bin-runtime vers du bytecode EVM, puis soit le guest interpréteur evm.bin (bytecode en entrée), soit evm2rv, qui traduit le bytecode en C que rand-guest compile en une image RV32IM aux sorties identiques (Le transpileur Ethereum) | Keccak-256 (table livrée), arithmétique modulaire sur 256 bits, ECRECOVER, appels système de témoins de Merkle pour le stockage |
| Solana / SVM | un ELF sBPF, exécuté par le guest interpréteur sbpf.bin ou traduit par sbpf2rv en une image RV32IM aux sorties identiques (Le transpileur Solana) | SHA-256, vérification Ed25519, multiplication 64 bits |
Jalons
Le jalon 1 a prouvé la machine généraliste. Le jalon 3 en a fait un pool blindé : un transfert avec appartenance dans le circuit se prouve sous R_exec, et le vérifieur contrôle hc sans jamais voir un mot de programme. Le jalon 4 est la compatibilité : son chargeur, son engagement d’entrée et sa table Keccak ont été livrés avec les jeux de contraintes 4 et 5, et la table SHA-256 avec le jeu 6. Les guests interpréteurs EVM et sBPF, la chaîne d’outils rand-guest et les deux traducteurs sont construits. Le transfert ERC-20 a été prouvé, sur une machine de 128 GB ; la preuve SPL Token, au palier 20, ne l’a pas été. Le jalon 5 est la VM de récursion qui sous-tend l’agrégation de blocs, construite et désactivée sur toutes les chains. Les jeux de contraintes 7 et 8 ont suivi les revues de septembre et le modèle de gas.
| id | périmètre | critère de sortie | statut |
|---|---|---|---|
| M1 | Cinq tables, ISA de base RV32I, HALT/WRITE_OUTPUT/READ_INPUT, ZK activé, remplissage par paliers, assembleur, émulateur | fib, memcpy, bubble_sort, alu_mix et balance_check se prouvent et se vérifient ; chaque test de triche est rejeté | terminé. 44 tests ; une revue ultérieure a comblé cinq failles de solidité en une seule vague |
| M1.5 | Clés de visualisation : un guest de transfert blindé à une entrée et une sortie, enveloppes de notes sous ML-KEM-768 et ChaCha20-Poly1305, divulgation à portée de partie et de transaction, un registre simulé | Un transfert se prouve au palier 12 et le registre l’accepte ; chaque portée de divulgation ouvre exactement ses propres lignes ; une clé de visualisation ne peut pas dépenser | terminé. Non intégré au nœud |
| M2 | Cache de clés de vérification, FRI réajusté à une cible conjecturée de 100 bits, table d’octets scindée en plage et quartet, chargements et stockages de sous-mots, extension RV32M | Livré plus étroit que prévu : le chargeur de binaire plat et une liaison READ_INPUT plus ferme ont été reportés à M4.1 | terminé. fib au palier 10 : preuve de 892 KB à 268 KB, preuve de 21,6 s à 3,1 s, première vérification de 2,17 s à 16 ms. Jeu de contraintes 3, un hard fork |
| M3 | Puce et appel système Poseidon2 ; NOTE_COMMIT, NULLIFY et MERKLE_VERIFY comme routines du guest au-dessus ; l’engagement dépensé retiré de la sortie publique ; la table de programme comme témoin avec hc digéré dans le circuit | La relation de transfert se prouve sous R_exec avec appartenance dans le circuit, et verify(hc, proof) ne voit jamais un mot de programme | terminé. Guest de transfert : 4 554 instructions, 4 903 cycles, palier 14. Le parcours de Merkle est désormais une boucle comptée, si bien que la taille du programme ne dépend plus de la profondeur de l’arbre |
| CUDA | Backend de prouveur GPU : NTT et engagements Merkle Poseidon2 sous forme de noyaux CUDA derrière les traits Dft et Mmcs de Plonky3 ; rand send, call et deploy acceptent --cuda | Chaque guest se prouve et se vérifie via le jumeau de référence en Rust pur et le pilote factice ; le vérifieur CPU ne distingue pas les backends | terminé ; première exécution sur matériel le 2026-09-28. Sur un NVIDIA H100, les noyaux se compilent en PTX pour sm_80 et sm_90 et correspondent à la référence CPU et Plonky3. La re-mesure de production sur un nœud GPU de la flotte reste à faire. Un appel CUDA ne peut pas sceller une enveloppe d’entrée, car le sel ne quitte jamais le prouveur |
| M4.1 | Le chargeur de binaire plat et les premiers guests Rust no_std compilés pour riscv32im-unknown-none-elf ; l’engagement d’entrée salé H_IN avec sa propre table d’entrée, de sorte que READ_INPUT soit une recherche dans un vecteur engagé | Un guest construit par la chaîne d’outils standard se charge, se prouve et se vérifie ; deux lectures d’un même indice d’entrée concordent et les entrées sont liées à H_IN | terminé. Livré le 2026-09-11 comme jeu de contraintes 4 : 26 valeurs publiques, huit tables, un hard fork |
| M4.2 | Une table de coprocesseur Keccak-f[1600] écrite à la main et un appel système KECCAK, présents dans une preuve seulement si le guest les a utilisés ; hauteur de mémoire déclarée par la preuve ; une clé de vérification indexée sur quatre composantes ; FRI de retour à 80 requêtes après l’audit du 2026-09-12 | keccak256 se prouve comme guest compilé, et une preuve sans la table a exactement la même forme qu’une preuve de M4.1 | terminé. Livré le 2026-09-12 comme jeu de contraintes 5, un hard fork. Une preuve avec Keccak est plus grande d’environ 1,9 MB, au-delà du plafond par défaut de 2 MiB. Une chain dont le genesis relève le plafond en admet une : la chain 13 (8 MiB) a accepté le 2026-09-19 un appel de 3,41 MB embarquant Keccak, et le plafond de la chain 20 est de 4 MiB |
| M4.3 · M4.4 | Guests interpréteurs EVM et sBPF compilés en RV32IM, avec le bytecode étranger en entrée ; une table de coprocesseur SHA-256 aux côtés de Keccak ; puis la chaîne d’outils rand-guest et les traducteurs evm2rv et sbpf2rv (2026-09-18) | Un transfert ERC-20 et un Transfer SPL se prouvent chacun sous R_exec | construit ; une preuve de sortie réalisée. evm.bin (18 009 mots) et sbpf.bin (8 317) exécutent les vecteurs ERC-20 et SPL Token, et les images traduites leur correspondent mot pour mot. Le transfer ERC-20 a été prouvé au palier 18 sur un droplet de 128 GB le 2026-09-19 (pic de 85,0 GB, 53,8 min) ; la preuve SPL Token, au palier 20, est extrapolée à environ 330 GB et n’a pas été réalisée (mémoire de preuve). Aucun des deux n’est appelable sur la chain : un appel est plafonné au palier 14 |
| M5 | La VM de récursion (rVM) : une machine native Goldilocks à 24 instructions dont les programmes vérifient les preuves zkVM de Rand, un programme d’agrégation générique en N par forme de preuve interne, une séparation des backends CPU et CUDA, et un auto-vérifieur (M5.1 à M5.4, 2026-09-13 au 2026-09-16) | 50 vraies preuves de bundle de production acceptées et 50 preuves altérées refusées à l’étape nommée ; une preuve rVM du programme vérifieur sur une vraie preuve de bundle se vérifie nativement (profil de test) | construit ; les preuves de production exigent une grosse machine. Intégré comme crates/randprotocol-rvm. L’agrégation côté chain est fusionnée et désactivée sur toutes les chains (ci-dessous) |
| jeu 7 | Chaque terminal LogUp masqué ; chaque table déclarée plancher à 2⁷ lignes ; contrôles de plage sur 32 bits pour les mots d’entrée, publics et de sel ; l’appel système POSEIDON2_LEN ; un correctif JALR ; clés de vérification salées à partir de key_derivation_v2 | Les correctifs des revues zkVM des 2026-09-27 et 28 qui déplacent une clé de vérification, regroupés en une seule coupe | terminé. Fullnode v0.6.1, chain 16 (2026-09-28), un hard fork |
| jeu 8 | Le compteur de gas : une colonne GAS dans la table cpu et un GAS_LIMIT public, avec GAS ≤ GAS_LIMIT prouvé dans le circuit ; le gas exact de l’exécution reste privé | Un appel paie la limite qu’il déclare, et chaque preuve de bundle déclare la même limite figée | terminé. Fullnode v0.6.7-rc1, chain 18 (2026-09-29), un hard fork. bundle_gas_limit vaut 20 479 |
Phases du pool blindé
Le registre du fullnode a été livré en trois phases, chacune un hard fork (docs/shielded.md §7). S1 a remplacé le registre de comptes par un pool de notes ; S3 a réintroduit le pont sous forme de notes et a été livrée en premier ; S2 a ajouté le staking par-dessus. Les trois sont sur main et sur la chain actuelle.
Les lignes sous S2 correspondent au travail de la v0.5. Chacune est un hard fork. Elles ont été regroupées dans une chaîne neuve, la chaîne 14, créée le 2026-09-20 à partir du build b3c594c, puis étiquetée v0.5 le jour même après un aller-retour zUSD en conditions réelles via les points d’accès source déployés. La chaîne 15, en ligne depuis le 2026-09-26 sur v0.5.8 et les versions suivantes, a repris l’ensemble, avec les correctifs conditionnés au genesis des audits v4 et v5 activés : un faucet à liste d’autorisation avec un budget par epoch, une activation différée des bonds, un plafond de poids de stake, des enregistrements liés au genesis, consensus_domain 1, les règles de bridge v2 ainsi que le plafond du registre de tokens, des frais d’enregistrement brûlés et une borne de 2⁶³ sur les notes. La chaîne 20, en ligne depuis le 2026-10-01 à 06:17 UTC sur v0.6.8 (c9c9bd3c), un hard fork de la chaîne 19, conserve tout cela et y ajoute le travail des versions v0.6, listé ci-dessous.
| id | périmètre | critère de sortie | statut |
|---|---|---|---|
| S1 | Le pool lui-même : notes, lots prouvés à 2 entrées et 2 sorties, arbre d’engagements Poseidon2 de profondeur 32 et ensemble de nullifiers, le portefeuille rand avec prouveur local, le RPC expurgé | Un transfert protégé entre portefeuilles, une course de double dépense entre deux validateurs et un déploiement suivi d’un appel payés par des lots passent tous dans la suite de tests du cluster | terminé. En ligne sur la flotte publique depuis la chaîne 6 (2026-09-12) |
| S3 | Le bridge sous forme de notes : un avoir ponté porte l’indice d’actif du registre, une attestation dépose une note unique que la chaîne calcule elle-même, BridgeBurn est l’unique transaction à deux lots ; enveloppes scellées pour les entrées d’appel, ouvrables par l’appelant, par une clé propre à l’appel ou par un auditeur désigné | Un actif ponté est émis, dépensé et brûlé sous forme de note ; un appelant peut divulguer ce sur quoi un programme a tourné sans le publier, et rand open-call vérifie l’ouverture par rapport à H_IN | terminé. Livré en premier. Les chaînes 9 à 13 ont laissé la section bridge hors de leur genesis ; toutes les chaînes depuis la 14 l’incluent. Depuis la chaîne 14, une burn tient en un seul lot, et non deux |
| S2 | Le staking sur la chaîne protégée : un registre public des validateurs, Bond à partir de la burn d’un lot, Unbond sur deux epochs, Withdraw vers une note à une adresse de versement, des epochs de 1 000 blocs qui recalculent l’ensemble, et un audit de l’offre portant sur le registre et le pool | Un cinquième validateur s’enregistre, place un bond et propose à partir de l’epoch suivante ; un autre se retire de l’ensemble par unbond et retire ses fonds vers une note que son portefeuille de versement dépense ; les deux passent dans la suite de tests du cluster | terminé. L’arbre d’engagements local du portefeuille a suivi le 2026-09-21 : un portefeuille calcule ses propres témoins et n’indique plus à son nœud quelle feuille il dépense |
| RPL | Le standard de token (docs/tokens.md) : un token est une entrée de registre dans le grand livre avec un identifiant bech32m rpl1… de 62 caractères ; la création est sans permission moyennant des frais d’enregistrement en RAND ; l’autorité de mint est fixée à l’enregistrement : aucune, une clé ou le bridge ; les symboles ne sont pas uniques ; rand token create, mint, set-authority, burn, info, list, ainsi que rand_getTokens, rand_getToken, rand_getTokenSupply | Un token est enregistré, émis, envoyé avec rand send --asset et brûlé sous forme de notes dans le même pool | en service depuis la chaîne 14 (v0.5). Sur la chaîne 20, les frais d’enregistrement sont de 1 RAND, brûlés, le registre contient au plus 4 096 tokens, et le genesis inscrit zUSD à l’indice 1 |
| RPL-2 | L’état des programmes (docs/program-state.md) : des cellules par programme (une clé de 8 mots vers une valeur de 8 mots, dans la racine d’état), un coffre public par actif, un token émis uniquement par son programme, et l’action Invoke (Action 33), un appel qui déclare les cellules qu’il lit et écrit ainsi que les notes qu’il verse ; rand program invoke, state, vault, ainsi que rand_getProgramCell, rand_getProgramCells, rand_getProgramVault | Le grand livre n’applique une transition que si chaque lecture déclarée est toujours valide et que le coffre couvre chaque versement ; une lecture périmée est refusée et à nouveau prouvée | en service depuis la chaîne 20 (v0.6.8). cell_fee de 0,01 RAND par cellule créée ; au plus 8 lectures, 8 écritures et 4 versements par invoke. Voir Programmes |
| lot à actif caché | Chaque transaction porte exactement un lot de 4 entrées et 4 sorties à la place de celui de 2 entrées et 2 sorties : les emplacements 0–1 contiennent l’actif privé (des leurres sur un transfert en RAND seul), les emplacements 2–3 sont toujours en RAND et paient les frais. Le transfert de token à deux lots et la burn de bridge à deux lots disparaissent | Un transfert de RAND et un transfert de n’importe quel token RPL publient exactement la même forme, de sorte que l’actif déplacé est caché | en service depuis la chaîne 14 (v0.5). Niveau 14, environ 100 s de preuve, environ 1,42 MB de preuve sur les chaînes 14 et 15 ; hc_bundle 83d3a370… à ce moment-là. Les chaînes 18 à 20 imposent le guest de lot v3, hc_bundle 60af094a…, environ 1,49 MB |
| liaison de transaction | Chaque preuve de lot est produite sur, et vérifiée par rapport à, H("rand-tx-bind-1", chain_id ‖ tx with proofs blanked), porté dans le segment des entrées publiques | Une preuve copiée, non modifiée, soumise à nouveau avec une destination, un validateur ou un mémo modifié est refusée | en service depuis la chaîne 14 (v0.5). Depuis la chaîne 20 (binding_domain 1), la préimage est H("rand-tx-bind-2", genesis hash ‖ chain_id ‖ …), et chaque message d’action signé porte lui aussi le hash du genesis, de sorte que rien de ce qui a été prouvé ou signé pour une chaîne ne se vérifie sur une autre |
| B1–B4 | Renforcement du bridge (docs/bridge.md §§14–20). B1 : un plafond de mint quotidien par backing, et une clé de pause qui ne peut que mettre en pause (la reprise exige le quorum PQ). B2 : un horodatage de bloc de plus de 60 s après celui de son parent est invalide, et un validateur ne vote pas pour un bloc en avance de plus de 15 s sur son horloge, si bien que les validateurs ont besoin de NTP. B3 : un quorum de cosignatures Dilithium2 sur chaque mint. B4 : l’inscription d’un token ponté ou d’un backing après le genesis sous le quorum de gardiens PQ, sans coupure de chaîne | zUSD, un token à sept backings (USDT et USDC sur Ethereum, Binance Smart Chain, Tron et Solana), est enregistré par transaction, et total_supply == Σ backings.locked tient par construction. Le test local en neuf phases (zusd_e2e.rs : quatre validateurs, vraies preuves, faucet, enregistrement, dépôt, transfert, burn, audit) a réussi 9 phases sur 9 | en service depuis la chaîne 14 (v0.5). Sur la chaîne 20 : plafond de mint de 100 000 zUSD par jour et par backing, plus un plafond global de 4 000 zUSD par période glissante de 24 heures (règles de bridge v2), ensemble de gardiens 1 avec huit gardiens PQ, des frais de 10 bps en zUSD sur chaque mint et chaque burn (bridge.fees), et des rotations de gardiens qui exigent la possession et attendent 86 400 s (bridge.rotation). zUSD est inscrit dans le genesis de la chaîne 20 avec ses sept backings et les 99 zUSD verrouillés au moment de la coupure |
| audit v3 | Les correctifs du troisième cycle d’audit interne, dirigé par un cofondateur (2026-09-19 ; aucun audit indépendant n’a été réalisé). POOL-1 : un Mint de faucet porte l’ouverture de sa note (pk, time, r), l’admission recalcule l’engagement, et le minter signe rand-mint-2 ; les notes d’allocation du genesis portent aussi une ouverture. RPC-1 : rand_getWitness(es) exécute au plus deux reconstructions d’arbre à la fois et répond -32000 busy après 10 s. OPS-1 : les dix-huit clés de validateur ont été renouvelées, générées hors du dépôt, et aucune clé n’est suivie dans le dépôt | Un mint dont l’engagement s’ouvre sur plus que son montant est refusé ; aucune clé de la chaîne 14 n’a jamais figuré dans le dépôt | en service depuis la chaîne 14 (v0.5). PRIV-1, la requête de témoin qui désigne la feuille, a été close le 2026-09-21 par l’arbre propre du portefeuille |
Versions depuis la v0.5
Chaque version est un tag git accompagné d’une entrée dans le CHANGELOG.md du fullnode. Une version qui modifie le consensus, le format de transmission ou une clé de vérification est livrée avec une nouvelle chaîne ; les autres sont déployées sur la chaîne en ligne un nœud à la fois.
| version | ce qu’elle apporte | chaîne |
|---|---|---|
| v0.5 à v0.5.8 | Jetons RPL, zUSD et le pont durci (ci-dessus) ; les correctifs d’audit ; l’élagage de l’historique ; le durcissement du consensus et de la synchronisation | 14, 15 |
| v0.5.9 | Correctifs de rescan : le faucet ne frappe qu’à partir des validateurs de genesis, repli exponentiel de la synchronisation, contrôles préalables du gossip | 15 |
| v0.5.10 | Partage d’adresses : empreintes, liens randpay: et codes QR ; le mémo chiffré, activé pour la première fois par la chaîne 18 | 15 |
| v0.5.11 | Acquisition (vesting) à verrouillage temporel dans le genesis pour les allocations de l’équipe, des investisseurs et des partenaires. Conditionnée au genesis et active sur aucune chaîne | aucune |
| v0.6 | Le zkVM, la rVM et les correctifs d’agrégation issus des revues de septembre | 15 |
| v0.6.1 | Jeu de contraintes 7 : masquage LogUp, plancher de table de 2⁷, contrôles de plage sur 32 bits, POSEIDON2_LEN, le correctif JALR. La chaîne 16 a été créée avec hardening_v6 et le guest de bundle v2 | 16 |
| v0.6.2 | Preuve déléguée, phase 1 : le binaire rand-prover et l’option --prover du portefeuille. Un prouveur de phase 1 reçoit la clé de dépense | 16 |
| v0.6.3, v0.6.4 | Preuve déléguée, phase 2 : autorisation scindée. La preuve de bundle ne prend plus la clé de dépense, une preuve d’autorisation de palier 10 la prend, et le domaine de l’identifiant de transaction devient rand-txid-3 | 17 |
| v0.6.6, v0.6.7-rc1 | Gas : jeu de contraintes 8, une limite de gas déclarée par preuve, des prix dynamiques du gas et des octets ; le mémo activé. v0.6.6 n’a jamais été publiée sous forme de tag | 18 |
| v0.6.7 | Correctifs sur la chaîne 18 qui ne changent aucune règle de consensus : élagage des preuves scellées (dormant), verrouillage du format d’enveloppe, hygiène des clés de visualisation, l’allocateur de la rVM, aliasing des noyaux GPU, couverture de test de l’ALU. Taguée avant la fin de sa suite de tests complète sur tout le workspace | 18, 19 |
| v0.6.8 | RPL-2 : cellules de programme, coffres de programme et l’action Invoke. Frais de pont zUSD, dans les deux sens. Les derniers correctifs de l’audit v6 : aucune libération automatique de verrou (CON-4) et un pacemaker à certificat de timeout (CH-1) ; un écouteur --public-rpc, des limites de lecture, des pairs validateurs réservés, des budgets de synchronisation et de gossip, le plafond d’octets du pool, une borne sur le degré déclaré dans l’en-tête d’une preuve (ZKV-4) ; et les règles conditionnées au genesis que la chaîne 20 active : la liaison au hash du genesis, testnet, une fenêtre de preuve de 1 024 blocs, des plafonds de prix du gas et la charge en octets payante, l’admission par vote, le plafond d’entrée de stake exprimé en fraction, la possession et un délai pour les rotations du pont. Les portefeuilles ont besoin de cette version pour envoyer sur la chaîne 20 | 20 |
Où cela s’arrête aujourd’hui
Les écarts par rapport au livre blanc, énoncés plutôt qu’atténués. Chacun est suivi dans la documentation propre à la crate, avec le jalon qui le referme.
hcest liant mais pas masquant : il ne porte aucun sel, de sorte qu’un programme deviné peut être confirmé et que deux déploiements du même programme sont liables. Ce que M3.4 a supprimé, c’est que le vérificateur détienne tout le programme en clair.- Un portefeuille construit avant le 2026-09-21 demande des témoins à son nœud, et une demande de témoin désigne la feuille sur le point d’être dépensée. Un
randactuel conserve sa propre copie de l’arbre et ne demande jamais rien ; le nœud sert toujoursrand_getWitnesspour les anciens portefeuilles. - Les dépôts sont publics à la frontière : une frappe du faucet, une note de genesis et un dépôt via le pont portent tous leur montant en clair (depuis la chaîne 14, une frappe et une note de genesis portent aussi leur ouverture, de sorte que la clé du propriétaire est également publique), la même visibilité à un saut que celle d’un dépôt de transparent vers protégé, où que ce soit.
- La connaissance nulle est statistique, non parfaite. C’est la propriété que le FRI masquant de Plonky3 0.7 fournit réellement, et la crate le dit.
- Le hash du transcript est Poseidon2 avec des constantes de ronde de développement, et non le SHA3-384 / BLAKE3-384 des articles. Un changement de configuration, pas une réécriture.
- Avec 80 requêtes FRI, une preuve de bundle pesait environ 1,42 MB sur les chaînes 14 et 15 (environ 1,3 MB jusqu’à la chaîne 13). Depuis la chaîne 17, un transfert porte environ 2,85 MB de preuve : la preuve de bundle, environ 1,49 MB, et la preuve d’autorisation, environ 1,37 MB. Sur une chaîne par défaut, avec des blocs de 4 MiB et un plafond de preuve de 2 MiB, une preuve contenant du Keccak dépasse d’emblée le plafond de preuve ; le genesis de la chaîne 20 fixe des blocs de 20 MiB et un plafond de preuve de 4 MiB (les chaînes 13 à 16 fixent 8 MiB).
- L’en-tête d’une preuve d’appel n’est pas masqué. Il déclare le palier et les hauteurs des tables Keccak et SHA-256, et indique donc si un appel a effectué un hachage. Les appels validés sur la chaîne 15 avant le plancher du prouveur v0.6 exposaient davantage : une table privée de moins de 2⁷ lignes pouvait être lue dans la preuve. Le plancher du prouveur v0.6 a fermé cette faille pour les nouveaux appels, et le jeu de contraintes 7 avec
hardening_v6en a fait une règle de la chaîne à partir de la chaîne 16. - Un appel est plafonné au palier 14, avec au plus 2¹² lignes Keccak (128 permutations) et 2¹³ lignes SHA-256 (128 compressions), et sous
hardening_v6, un programme de plus de 8 180 mots ne peut pas être déployé. Les guests interpréteurs EVM et sBPF ainsi que les images ERC-20 et SPL Token traduites dépassent tous cette taille. - Quiconque détient le témoin voit tout. Le ZK protège la vue du vérificateur, pas celle du prouveur. Depuis la chaîne 17, un portefeuille peut confier la preuve de bundle à un
rand-proverappairé sans lui remettre la clé de dépense, mais ce prouveur détient toujours la clé de visualisation et voit les notes. Le backend CUDA a tourné pour la première fois sur du matériel le 2026-09-28 et n’a pas encore de mesure en production.
Organisation du dépôt
Le workspace Cargo du fullnode, tel qu’il est décrit dans son README et son répertoire crates/.
| chemin | ce qu’il contient |
|---|---|
crates/randprotocol-core/ | Logique pure, sans E/S : cryptographie, notes et arbre d’engagements, règles du registre, gas, genesis, la machine à états HotStuff |
crates/randprotocol-zkvm/ | Le zkVM de Rand, importé depuis zkp-circuits/research au jeu de contraintes 8 (circuits aeacf31 ; resynchronisé avec deploy/sync-zkvm.sh), ainsi que le vérificateur de preuves côté chaîne et son cache de clés de vérification |
crates/randprotocol-rvm/ | La VM de récursion, importée depuis zkp-circuits/recursion : une machine native au corps fini dont les programmes vérifient les preuves du zkVM de Rand |
crates/bridge-codec/ | Le format de transmission et la règle de quorum du pont à gardiens, partagés octet pour octet avec les contrats Solidity et le programme Solana |
crates/randprotocol-node/ | Stockage RocksDB, réseau libp2p, mempool, synchronisation des blocs, le serveur JSON-RPC et le binaire rand-node |
crates/randprotocol-client/ | Le binaire de portefeuille rand et la bibliothèque RpcClient, sans dépendance à RocksDB ni à libp2p |
crates/randprotocol-prover/ | Le binaire rand-prover : un prouveur délégué qui prouve des bundles pour les portefeuilles appairés |
deploy/ | Fichiers de genesis du testnet, nodes.env, scripts d’exécution, provisionnement cloud, scripts de bascule et de reconstruction. Aucune clé n’y est suivie depuis la préparation de la chaîne 14 |
docs/ | Documentation de référence et spécification de conception |
scripts/ | Testnet local à deux validateurs |
Spécifié, pas encore livré
Ces composants sont décrits dans les articles ou dans la documentation du fullnode, mais ne tournent pas : soit ils sont absents des dépôts, soit ils sont construits et activés sur aucune chaîne. Ils sont listés pour que l’écart entre la spécification et le code soit lisible plutôt que déduit.
| composant | état |
|---|---|
| bridge · guardian | Les démons guardian et relayer qui exécutent le format d’attestation de bout en bout ; les contrats, le codec et la moitié réceptrice du fullnode sont livrés, les démons ne le sont pas |
| fullnode · aggregation | Agrégation de blocs avec la VM de récursion : scellement, élagage et synchronisation en forme scellée. Construite et désactivée sur toutes les chaînes ; rand-node refuse un genesis comportant une section aggregation. Elle requiert encore l’exercice de bout en bout avec un agrégat forgé, et elle ne supprime que la preuve de bundle, pas la preuve d’autorisation. Les preuves rVM de production exigent une grande machine : sous le jeu de contraintes 7, un agrégat de deux a demandé 133 GB, de trois 221 GB, et la preuve de sortie plus de 256 GB (mesuré les 2026-09-28 et 29 ; non re-mesuré sous le jeu de contraintes 8) |
| fullnode · vesting | Allocations de genesis à verrouillage temporel pour l’équipe, les investisseurs et les partenaires (v0.5.11, docs/vesting.md). Conditionnées au genesis : sans section vesting, les quatre actions de vesting sont refusées, et aucune chaîne n’en a. L’audit de l’offre de la chaîne 20 indique zéro pour tous les compteurs de vesting. Depuis v0.6.8, une entrée révocable est révoquée par un seuil de ses révocateurs, et uniquement vers la trésorerie que nomme son entrée de genesis |
| fullnode · slashing | Le slashing et l’emprisonnement (jailing) pour équivocation du leader sont construits dans v0.6.8 derrière staking.slashing et désactivés sur la chaîne 20 (son genesis n’en comporte pas, alors que les 26 clés de validateur appartiennent à un seul opérateur). Les récompenses de bloc, la balise de leader par tirage au sort par hash, un accumulateur de nullifiers et les appels entre programmes ne sont pas construits. L’état persistant par programme a été livré avec RPL-2 (ci-dessus) |
prover/ | Démon de preuve GPU : réclame des lots dans la file, entre en concurrence à la soumission. Les noyaux CUDA se trouvent dans zkp-circuits et ont tourné pour la première fois sur un NVIDIA H100 le 2026-09-28 ; le démon de marché n’existe pas. rand-prover, qui est livré, prouve pour les portefeuilles qui lui sont appairés et n’est pas un marché |
| zkp-circuits · M4.4 exit proof | Une preuve d’un transfert SPL Token (palier 20), extrapolée à environ 330 GB. Le transfert ERC-20 (palier 18) a été prouvé sur un droplet de 128 GB le 2026-09-19. Ni l’un ni l’autre ne peut être appelé sur la chaîne 20, qui plafonne un appel au palier 14 |
Compilation et tests
Workflow Rust standard dans chaque dépôt. Le fullnode est un unique workspace Cargo avec une chaîne d’outils figée et une suite de tests de cluster qui démarre de vrais nœuds via TCP. Sa compilation exige que le dépôt circuits soit extrait à côté, dans un répertoire nommé circuits, au commit à partir duquel les crates vendorisées ont été synchronisées (aeacf31 pour v0.6.7 et v0.6.8). La zkVM est un crate autonome de zkp-circuits, avec sa propre chaîne d’outils figée et une démo qui explique ce qu’un appel confidentiel révèle et ce qu’il ne révèle pas.
Le fullnode :
git clone https://github.com/randprotocol/fullnode.git
git clone https://github.com/randprotocol/zkp-circuits.git circuits # the sibling directory must be named circuits
git -C circuits checkout "$(sed -n 's/^circuits: //p' fullnode/crates/randprotocol-zkvm/guests-compiled/PROVENANCE.md)"
cd fullnode
# Rust 1.98.1 is pinned by rust-toolchain.toml; first build pulls RocksDB and Plonky3, 10 to 20 minutes
cargo build --release # target/release/rand-node, target/release/rand, target/release/rand-prover
# All crates; release because STARK proving is slow in debug. One to two hours, mostly proving
cargo test --release
# One machine, two validators
scripts/local-testnet.sh
target/release/rand --rpc http://127.0.0.1:8545 status
La zkVM de recherche, dans zkp-circuits/research :
# Toolchain is pinned by rust-toolchain.toml; the first build pulls Plonky3
cargo build --release
# Narrated demo: thirteen proofs, one at production FRI parameters (~6-7 min)
cargo run --release
# Emulator, per-table constraints, cheating provers, ZK, end-to-end, viewing keys, compiled guests (395 tests, ~17 min)
cargo test
La suite du fullnode, telle que mesurée à v0.6.1 sur une machine de 16 vCPU : core 521 tests, node 373, client 117, la suite du prover tricheur 116, les tricheries de bundle caché 21 (75 min), le flux du wallet 6 (53 min), le cluster 26 (44 min) et la porte de bout en bout zUSD 2 (51 min). Les preuves de production de la VM de récursion n’en font pas partie et nécessitent la mémoire indiquée ci-dessus.
Running a node explique comment rejoindre le testnet public avec cette compilation ; le genesis du testnet, les pairs d’amorçage et les scripts d’exécution sont fournis dans le répertoire deploy/ du fullnode, et la page de téléchargement en donne la version courte.
Contribuer
Le fullnode est publié sous licence GNU General Public License v3.0 (GPL-3.0-only) ; il était auparavant sous Apache-2.0. Ouvrez des issues pour les bugs et les propositions de conception sur le dépôt concerné par la modification. Les pull requests sont les bienvenues : exécutez cargo fmt && cargo clippy avant de soumettre et gardez des changements circonscrits. Les issues du fullnode sont le point de départ.
L’architecture, le circuit de confidentialité, la preuve du jeton de frais et le compromis post-quantique sont tous documentés dans le livre blanc de la page des articles. Le répertoire docs/ du dépôt du fullnode est la source à laquelle chaque page de cette documentation est comparée.