Rand Protocol
Documentation
Programmes d'exemple

Quatre programmes sur la chain 20

Quatre programmes confidentiels complets déployés sur le testnet - un vote anonyme, une preuve de passifs, un registre hors chaîne et une décision de crédit privée - avec leurs identifiants de programme, la configuration qu'ils partagent, ce que la chain 18 a changé pour l'auteur d'un programme, et comment les appeler vous-même.

Ces quatre programmes sont chacun une application complète d’un appel confidentiel : un problème, une interface, un guest en Rust, l’outillage côté hôte, puis un déploiement et un appel sur le testnet en ligne. Ils sont plus longs que les tutoriels, et chacun s’appuie sur une partie différente de la machine. Écrire un programme en Rust ou en C est le guide du modèle qu’ils utilisent tous. Lisez-le d’abord si read_input, le segment public ou les huit emplacements de sortie vous sont nouveaux.

Tout ce qui figure ici a d’abord été exécuté sur la chaîne 18 avec fullnode v0.6.7, le 2026-09-30, et chaque sortie de ces pages est copiée de ces exécutions. Les programmes ne survivent pas à un changement de chaîne ; le 2026-10-01, les quatre ont donc été redéployés, sans modification, sur la chaîne 19 puis sur la chaîne 20 (fullnode v0.6.8), et les appels ont été répétés à chaque fois. Un identifiant de programme est un hachage du code et du segment public, non de la chaîne ; tous les identifiants sont donc les mêmes. Les hachages de transaction des transcriptions sont ceux de la chaîne 18, et le tableau ci-dessous renvoie à ceux de la chaîne 20. Sur la chaîne 20, un programme peut aussi conserver un état entre deux appels (RPL-2) ; ces quatre-là n’en font pas usage, et État du programme ainsi que le dépôt example-programs couvrent ceux qui le font.

Les quatre programmes

programmece que prouve un appels’appuie surmotspalier
Un vote anonymel’appelant est membre d’une liste publiée, sans dire lequel, et n’a pas déjà votéKeccak-256, un segment public42712
Une preuve de passifsles soldes privés des clients totalisent au plus une réserve publiée, sous une racine que chaque client peut vérifierSHA-256, un arbre construit dans le programme99414
Un registre hors chaîneun lot de transferts fait passer un registre d’un état au suivant, chaque émetteur étant autorisé et rien n’étant crééPoseidon2, un état conservé entre les appels77314
Une décision de crédit privéeun modèle publié approuve ou refuse des données privées de demandeur qu’un attestataire a certifiéesarithmétique entière, un modèle dans le segment public46212

Les quatre sont en ligne sur la chaîne 20. Chaque appel du tableau reprend, avec les mêmes entrées, l’appel de la chaîne 18 présenté sur la page du programme :

programmeidentifiant du programmedéployé sur la chaîne 20 danspremier appel sur la chaîne 20
vote anonymead2f719f12d01c9f3c0962092b9898b75b0914bbb817031d51be13e54c05b970f6ae5528…0f823a304e7a…427b
preuve de passifsfce8474dfdf80b9733e04fb72d4d8d19c40ba5ab646b3d867322daf4b9b599c0a8bc281b…17d96116c15f…d62a
registre hors chaînec4ddd388f2d94299610c7c3409dfdfb4dcb4ae3e0bc9ec78d0c45f51d8231cab72cc95f2…3d519c9998bb…66eb
décision de crédit privée7bbec14289f4446231b3a9a5ac18cb0613a373ca8a14fe4f046f3fde7ae6c73c413e6658…e42bd3ceb306…124a

L’explorateur liste chaque programme et ses appels sur randscan.org/programs. Une chaîne testnet est remplacée de temps à autre, et les programmes ne sont pas reportés : après la prochaine coupure, ces identifiants auront disparu et les programmes devront être redéployés.

Mise en place

La chaîne d’outils. Les guests se compilent avec rand-guest, issu du dépôt circuits, au commit que fullnode v0.6.7 et v0.6.8 intègrent tous deux :

git clone https://github.com/randprotocol/zkp-circuits circuits
cd circuits
git checkout aeacf31                      # branch feat/v067-circuits
rustup toolchain install 1.98.1
rustup target add riscv32im-unknown-none-elf --toolchain 1.98.1
(cd rand-guest && cargo +1.98.1 build --release)
alias rand-guest="$PWD/rand-guest/target/release/rand-guest"

Le commit importe pour deux raisons. hc est une fonction du code source et de la chaîne d’outils ; un guest recompilé à un autre commit de guest-sdk peut donc obtenir un hc différent. Et les signatures du SDK ont changé : à aeacf31, keccak et sha256_compress prennent des références à des tableaux là où d’anciens commits prenaient des pointeurs bruts.

Les sources. Les quatre guests, leurs scripts hôtes et les données de démonstration forment un seul téléchargement. Décompressez-les à l’intérieur du checkout, car rand-guest build trouve guest-sdk en remontant depuis le répertoire du guest :

mkdir -p my-guests
curl -sSf https://randprotocol.org/examples/rand-example-programs.tar.gz | tar -xz --strip-components=1 -C my-guests
ls my-guests
# allowlist  ledger  ledger-host  score  solvency

Les fichiers sont aussi consultables un à un sous https://randprotocol.org/examples/programs/, par exemple allowlist/src/main.rs.

Le portefeuille. Déployer et appeler exigent le portefeuille rand de fullnode v0.6.8 (cargo build --release -p randprotocol-client dans un checkout de fullnode au tag v0.6.8, ou le rand joint à la version v0.6.8), une clé et des RAND. Un portefeuille plus ancien ne peut pas transiger sur la chaîne 20 : la chaîne 20 lie chaque preuve et chaque message signé à son genesis, ce que ne fait pas un portefeuille v0.6.7.

Un RPC. Le point d’accès public, https://rpc.randprotocol.org, suffit pour tout ce que décrivent ces pages : lire les programmes et les reçus, synchroniser un portefeuille, déployer et appeler. La première synchronisation d’un portefeuille lit chaque en-tête de bloc et chaque bloc qui contient une note, soit 645 requêtes à la hauteur de la chaîne 18 le 2026-09-30, et a duré environ trois minutes via ce point d’accès. Le point d’accès autorise à chaque adresse 1 200 lectures et 6 envois par minute. Un nœud à vous (Exécuter un nœud) n’a pas de telles limites.

export RAND_RPC=https://rpc.randprotocol.org
export RAND_KEY=$HOME/wallet.key.json

Sur la chaîne 18, l’un des votes comptés sur la page du vote anonyme, fdbcc960…fc2b, a été prouvé sur un ordinateur portable et envoyé uniquement par le point d’accès public. Sur les chaînes 19 et 20, les treize transactions de chaque série, soit les quatre déploiements et les neuf appels, ont suivi ce chemin.

Ce que la chaîne 18 a changé pour un programme

Un appel déclare une limite de gas, et la paie. L’ensemble de contraintes 8 mesure chaque exécution. Un cycle ordinaire vaut 1 gas. Les appels système de hachage font exception :

instructiongas
toute instruction RV32IM, HALT, WRITE_OUTPUT, READ_INPUT, READ_PUBLIC1
POSEIDON2 sur n mots3 + 3 × ⌈n / 4⌉
SHA256, une compression64
KECCAK, une permutation192

La preuve porte une nouvelle valeur publique, la limite déclarée, et le circuit impose que le gas de l’exécution soit inférieur ou égal à cette limite. Le gas exact reste privé. rand call exécute d’abord le programme dans l’émulateur et affiche les deux :

gas: 5636 (declaring 6144, tier 12)

Par défaut, le portefeuille arrondit le gas exact au multiple supérieur de 2^(tier − 2), soit 1 024 au palier 12 et 4 096 au palier 14 ; la limite déclarée en dit donc peu sur l’exécution. --gas-limit max déclare le plafond du palier et ne dit rien au-delà du palier. --gas-limit N déclare un chiffre exact.

Les frais suivent la limite déclarée et les octets.

floor = 0.001 RAND  +  gas price × declared limit  +  byte price × ⌈bytes / 1024⌉

Les prix ont démarré à 100 unités par gas et 800 unités par KiB (une unité vaut 10⁻⁹ RAND), puis évoluent un peu à chaque bloc vers une cible. rand_getLimits fournit les prix courants. Le portefeuille ajoute une marge de deux pas de prix, un facteur de 1,125², car un appel atterrit deux ou trois blocs après avoir été tarifé.

Un détail détermine l’essentiel des frais. Depuis la chaîne 18, la preuve d’un appel est liée à sa propre transaction ; le portefeuille doit donc fixer les frais avant que la preuve existe, et il tarife la preuve au plafond de la chaîne, 4 MiB, au lieu de sa taille réelle. Pour le vote anonyme, cela donne (1,000,000 + 100 × 6,144 + 800 × 4,097) × 1.125² = 6 191 437 unités, soit 0,0062 RAND, dont le gas représente environ un huitième. Les quatre appels de ces pages ont coûté entre 0,0057 et 0,0075 RAND chacun. --fee remplace la valeur par défaut.

Chaque bundle comprend deux preuves. La chaîne 18 applique une autorisation séparée : le bundle qui paie des frais porte une petite preuve d’autorisation de palier 10 à côté de la preuve de bundle de palier 14. Le portefeuille produit les deux et affiche une ligne pour chacune. Un appel compte donc trois preuves : l’appel, l’autorisation et le bundle. Sur un ordinateur portable Apple Silicon, les quatre appels présentés ici ont pris entre trois et cinq minutes et demie chacun, avec un pic de mémoire de 6,1 à 6,6 GB. La preuve de bundle représente à chaque fois environ deux minutes de ce total. Une preuve d’appel de palier 12 ajoute une demi-minute et une de palier 14 ajoute deux minutes.

Les plafonds qu’un appel doit respecter.

limitechaînes 18 à 20
palierau plus 14 : 16 383 cycles, lignes de condensats comprises
permutations Poseidon22 048 au palier 14, condensats du programme, de l’entrée et du segment public compris
permutations Keccak128
compressions SHA-256128
preuve d’appel4 194 304 octets (4 MiB)
programme8 180 mots sans segment public, quelques-uns de moins avec un : la chaîne 20, comme les chaînes 18 et 19, refuse un déploiement qu’aucun appel de palier 14 ne pourrait contenir (ProgramUncallable), quelle que soit la valeur que max_program_words (65 535) autorise
segment public32 768 mots, fixé au déploiement
entrée privée avec une transcription scellée16 071 mots

rand-guest run --tier 14 vérifie les deux premiers avant le déploiement. Une table de hachage agrandit une preuve. La preuve de palier 14 du registre, sans table de hachage, pèse 1,50 MB. La table SHA-256 porte la preuve des passifs à 1,91 MB, et la table Keccak porte celle du vote à 3,35 MB, soit l’essentiel du plafond de 4 MiB.

Conventions communes aux quatre programmes

  • L’emplacement 0 est un statut, et 0 n’en est jamais un valide. Chaque issue, échecs compris, porte un numéro à partir de 1, et un échec s’arrête proprement afin de pouvoir être prouvé. Un reçu entièrement à zéro ne peut pas être pris pour un résultat.
  • L’emplacement 7 n’est pas touché. Un guest Rust qui panique y écrit 0xdeadbeef (3 735 928 559). Un lecteur vérifie d’abord l’emplacement 7.
  • Les emplacements 2 à 6 portent une valeur de 160 bits : un nullifier, une racine, un lien, un engagement. Un hachage complet de 256 bits fait huit mots et ne laisserait aucune place à un statut. La troncature à cinq mots conserve 80 bits de résistance aux collisions, et chaque page indique ce que cela protège.
  • L’ordre des octets suit la fonction de hachage. Les valeurs Keccak sont des mots en little-endian et les valeurs SHA-256 des mots en big-endian, car c’est ainsi que chaque appel système lit son bloc. Un script hôte et un guest en désaccord sur ce point produisent des condensats qui ne correspondent tout simplement jamais.
  • Tout ce qui varie selon l’instance se trouve dans le segment public ; tout ce qui varie selon l’appel est une entrée privée. La racine d’un scrutin, un chiffre de réserves et les poids d’un modèle sont fixés au déploiement et liés à l’identifiant du programme. Un appel ne porte aucun mot public qui lui soit propre.
  • Les mots d’entrée sont en décimal sur la ligne de commande. Les pages transforment un fichier de témoin en options avec $(sed 's/[0-9][0-9]*/--input &/g' witness.txt).

Lancer un appel soi-même

Une fois les sources décompressées, la chaîne d’outils compilée et un portefeuille v0.6.8 approvisionné, voter en tant que l’un des membres de la démo tient en quatre commandes :

cd my-guests/allowlist
python3 allowlist.py witness 10 1 demo-secrets.txt 6 1 > witness.txt    # member 6, choice 1
rand-guest build . --max-words 65535      # only needed to run it in the emulator first
rand call ad2f719f12d01c9f3c0962092b9898b75b0914bbb817031d51be13e54c05b970 \
    $(sed 's/[0-9][0-9]*/--input &/g' witness.txt)

L’appel n’a pas besoin de l’image : rand call récupère auprès du nœud le code et le segment public du programme, vérifie qu’ils hachent bien vers l’identifiant, puis produit la preuve à partir de ceux-ci.

Lire un résultat ne demande ni portefeuille ni nœud. Tout reçu s’obtient en une seule requête vers le point d’accès public :

$ curl -s https://rpc.randprotocol.org -H 'content-type: application/json' \
    -d '{"jsonrpc":"2.0","id":1,"method":"rand_getReceipt","params":["8aa13d1f76d28f63a46c30bb09ef44b1ba35083ca80ba7301997f98e5f783666"]}'
{"id":1,"jsonrpc":"2.0","result":{"h_in":"ea71e7701e62d49cac37b239bef132178f481835027d62b34da45fd6cf2667c6","h_pub":"2296cfca8db9d38bd0b7579056c9dea3c8d8005df7b42e2b1e954a75fed67510","height":98335,"index":0,"outputs":[1,2,392974773,873526743,1921224601,3950868247,2248722827,0],"program":"ad2f719f12d01c9f3c0962092b9898b75b0914bbb817031d51be13e54c05b970","tier":12,"tx":"8aa13d1f76d28f63a46c30bb09ef44b1ba35083ca80ba7301997f98e5f783666"}}

L’API de l’explorateur donne les appels d’un programme en une seule requête : https://randscan.org/api/v1/programs/<program id> renvoie call_count et recent_calls (API de l’explorateur).

Ce que ces programmes ne font pas

Un programme sur Rand est une preuve portant sur un calcul, et la chaîne n’agit sur aucune de ses sorties. Aucun de ces programmes ne déplace de RAND ni de jeton, ne détient de solde, ni ne garde mémoire d’un appel précédent. Le vote est dépouillé par quiconque lit les reçus. Les engagements sont comparés à des réserves qui exigent leurs propres preuves. Les soldes du registre sont des nombres dans un arbre hors chaîne. La décision de crédit est un bit qu’un prêteur choisit d’honorer. Chaque page se termine par la liste de ce que sa preuve laisse à la charge de ceux qui l’utilisent.

Dernière vérification par rapport au commit 48dc04b de fullnode (chaîne 18) le 2026-09-30, et circuits `aeacf31` (`guest-sdk/src/lib.rs`, `rand-guest`), the commit fullnode v0.6.7 vendors; `docs/fees.md`, `docs/zkvm.md`, `docs/cli.md` and `crates/randprotocol-client/src/main.rs` at fullnode `48dc04b`; the four deploys and the four calls were made on chain 18 on 2026-09-30, and every receipt was read back from `https://rpc.randprotocol.org`. Lorsque le code et cette page divergent, c'est le code qui a raison ; signalez-le-nous.