Rand Protocol
Documentazione
Concetti fondamentali

Account e indirizzi

I due tipi di chiavi presenti sulla chain, come viene derivato un indirizzo rand1 shielded, che cosa rivela una viewing key e perché l'indirizzo breve della chain 11 è stato ripristinato.

Usa questa pagina per generare la chiave giusta per ogni scopo, per analizzare o validare un indirizzo e per sapere che cosa si rivela consegnando una chiave a qualcuno. Su questa chain non esistono account: un saldo è un fatto che riguarda un file di chiavi, mai la chain.

Due chiavi, due tipi di indirizzo

chiave del nodochiave del wallet
scritta darand-node keygenrand keygen
segretoun seed di 32 byteuna spend key a 256 bit
identità pubblicaun indirizzo di 32 byte, base58, da 32 a 44 caratteriun indirizzo schermato, rand1…, di 1.665 o 1.666 caratteri
firmablocchi, voti, mint del faucet, Unbond, Withdraw, una Registration e, sulla chain 20, un voto AdmitValidator; come autorità di mint Key di un token, TokenMint e SetAuthority. Sulla chain 20 ciascuno di questi messaggi copre anche l’hash di genesi (Transazioni)niente: un trasferimento è autorizzato dalle sue prove
appare on-chain comeproponente di un blocco, riga del registro dei validatori, minter di un mint del faucet, autorità key di un tokenmai in un trasferimento, dove è sigillata dentro le buste. È pubblicata dove il valore entra nel pool con un importo pubblico: un deposito del bridge, un mint di token e, sulla chain 20, il pagamento di un’invocazione indicano l’indirizzo del destinatario; l’indirizzo di pagamento di un validatore è nel registro, il genesi della chain 20 indica la tesoreria delle commissioni del bridge e, dalla chain 14, un mint del faucet e una nota alloc di genesi pubblicano la pk del proprietario, i primi 32 byte dell’indirizzo
file{ "seed", "address", "public_key" }, modalità 0600{ "version": 2, "spend_key": "<64 hex>" }, modalità 0600

Le due non si mescolano mai. I validatori sono identificati dal primo tipo, e la stessa forma di chiave Dilithium2 serve per l’autorità di mint Key di un token (rand token create --authority-key-out scrive un file con la forma di quello di rand-node keygen), per la chiave di pausa del bridge e per le sue sei chiavi guardiane post-quantistiche. Le chiavi di attestazione dei guardiani sono secp256k1, con indirizzi di 20 byte in stile Ethereum (Bridge). Il valore è detenuto sotto il secondo tipo.

L’indirizzo trasparente

Una chiave del nodo è un seed di 32 byte da cui si deriva in modo deterministico una coppia di chiavi Dilithium2: una chiave pubblica di 1.312 byte e firme di 2.420 byte. L’indirizzo è un hash BLAKE3 con separazione di dominio della chiave pubblica, reso in base58:

address = blake3("rand-address" || public_key)      // 32 bytes, shown as base58

Gli oggetti firmati (voti, blocchi, mint, azioni di staking) portano la chiave pubblica completa, così un verificatore controlla blake3("rand-address" || public_key) == address invece di fidarsi di un indirizzo nudo. Lo stesso seed produce anche l’identità libp2p del nodo, una chiave ed25519 ricavata da blake3("rand-p2p-identity" || seed), che è il peer id dopo /p2p/ in un multiaddr di bootstrap.

rand-node keygen --out node.key.json      # prints the address
rand-node address --key node.key.json     # address, public key (hex), libp2p peer id

Esempio: EdrEC2QRQrQF64iRXxF9927jNj6RidiHHByzx5xD6F1e è uno dei validatori della chain 20. Le chain da 15 a 20 riutilizzano le diciotto chiavi ruotate per la chain 14, quindi i loro indirizzi e peer id non cambiano e nessun indirizzo o peer id di validatore della chain 13 è ancora in uso; altri otto validatori si sono vincolati sulla chain 15 e tutti e 26 sono nel file di genesi dalla chain 16 in poi.

L’indirizzo schermato

Un wallet è un solo segreto, la spend key a 256 bit sk, e tutto il resto ne è una derivazione. La derivazione usa Poseidon2 con un tag di dominio come prima parola assorbita (H(domain, msg)), la stessa funzione che la zkVM calcola nel circuito:

spend key   sk                          256 bits, in wallet.key.json
   │
   ├─ viewing key   nk = H(NK, sk)      sees the whole history; cannot spend
   │     ├─ pk = H(PK, nk)              the field a note names its owner by
   │     ├─ nullifier(cm) = H(NF, nk, cm)   what a spend publishes
   │     ├─ ovk                         opens envelopes this wallet sent
   │     └─ ML-KEM-768 decapsulation key    opens envelopes sent to this wallet
   └─ address   rand1 + base58(pk || kem_ek)

L’indirizzo è composto dai 32 byte di pk seguiti dalla chiave di incapsulamento ML-KEM-768 di 1.184 byte, in base58 dopo il prefisso rand1: 1.665 o 1.666 caratteri (la lunghezza in base58 dipende dai byte iniziali; circa un indirizzo su quattordici è quello più corto), circa 1,6 KB, e nessun checksum. Il mittente ha bisogno della chiave di incapsulamento per sigillare la busta della nota, ed è per questo che si trova nell’indirizzo. È pubblica per progetto: chiunque può pagarla e possederla non dice nulla su ciò che essa detiene.

rand keygen                      # wallet.key.json; refuses to overwrite an existing file
rand address                     # rand1… on stdout, its fingerprint XXXX-XXXX-XXXX-XXXX on stderr

Dalla v0.5.10 rand address stampa su stdout esattamente l’indirizzo e un a capo, quindi $(rand address) funziona in uno script. L’impronta va su stderr.

L’analisi, esattamente come la esegue ShieldedAddress::parse: si rimuove rand1, si decodifica il base58 e si richiedono esattamente 32 + 1.184 = 1.216 byte; i primi 32 sono pk come otto parole u32 little-endian, il resto è la chiave di incapsulamento. L’RPC rifiuta qualsiasi parametro più lungo di 2.000 caratteri prima di analizzarlo.

Accanto al file di chiavi, il wallet conserva <key>.key.json.notes.json, una cache delle note che questa chiave ha aperto. Contiene i testi in chiaro delle note, perciò è scritta in modalità 0600 come la chiave; ogni sua riga è recuperabile ripetendo la scansione dalla foglia 0.

Un indirizzo è troppo lungo per essere letto ad alta voce o confrontato a occhio e non ha checksum, perciò dalla v0.5.10 ogni wallet mostra accanto ad esso un’impronta. L’impronta serve solo per la visualizzazione: nulla on-chain né sulla rete ne porta una.

fingerprint = first 80 bits of blake3("rand-address-fingerprint-1" || pk_bytes || kem_ek)
            = 16 Crockford base32 characters, shown as XXXX-XXXX-XXXX-XXXX

L’hash è calcolato sui 1.216 byte grezzi che l’indirizzo codifica. L’alfabeto è 0123456789ABCDEFGHJKMNPQRSTVWXYZ; l’analisi ignora maiuscole e trattini e legge O come 0 e I o L come 1.

Un link randpay: porta un indirizzo e, facoltativamente, che cosa pagargli:

randpay:<rand1…>[?amount=<decimal>][&asset=<index | 64 hex | rpl1…>][&memo=<percent-encoded UTF-8>]

amount è nelle unità di visualizzazione dell’asset (RAND decimale con nove decimali, un token con i decimals della propria riga di registro) e non deve essere zero. memo è al massimo di 510 byte di UTF-8. Lo schema viene riconosciuto senza distinguere maiuscole e minuscole; un parametro sconosciuto, ripetuto o con una codifica percentuale errata viene rifiutato.

rand address --uri --amount 1.5 --memo "invoice #42" --qr   # a randpay: link, as a terminal QR
rand contacts add alice rand1q9f…                            # shows the fingerprint, asks add? [y/N]
rand send alice 1.5 --memo "coffee"                          # to a contact, with a memo

rand send <TO> accetta un indirizzo rand1…, un link randpay: o il nome di un contatto salvato, provati in quest’ordine. amount, asset e memo di un link completano ciò che la riga di comando omette, e un valore indicato in entrambi i modi che non coincide viene rifiutato. Prima di generare la prova, send stampa to <contact, if any> · fingerprint XXXX-XXXX-XXXX-XXXX · <amount> <asset> e chiede conferma; uno script passa --yes. I contatti sono memorizzati accanto alla chiave in <key>.contacts.json, modalità 0600. Il memo viaggia dentro la busta della nota (Note).

Non esistono rand balance <address> né una RPC per il saldo: la chain non può rispondere a questa domanda per nessuno. Un wallet calcola il proprio saldo scansionando con la sua viewing key ogni busta presente sulla chain (Note).

Chiavi che puoi consegnare a qualcun altro

La divulgazione è una proprietà delle chiavi, e la chain non può imporne alcuna.

chiaveapregranularità
la viewing key nk (64 hex)ogni nota che il wallet abbia mai ricevuto e, tramite ovk, ogni nota che abbia mai inviato, con il nullifier di ciascuna spesatutto o niente, retroattiva e valida per il futuro
una chiave di transazione TxKey (32 byte)esattamente la singola busta che ha sigillato: la nota e, dalla chain 18, il suo memoun pagamento
una chiave di chiamata K_callla trascrizione degli input privati di una chiamata confidenzialeuna chiamata

Una viewing key non può spendere. Dalla chain 17 (autorizzazione divisa) la prova del bundle è realizzata a partire da nk, e ogni bundle porta anche una seconda, piccola prova di autorizzazione che solo la spend key può produrre e che è legata a quella singola transazione (Note). È ciò che permette di consegnare nk a un prover delegato, e quindi l’intera cronologia del wallet, senza che possa spendere; il wallet produce sempre la prova di autorizzazione sulla propria macchina. Indirizzi, chiavi e note esistenti non cambiano con la divisione. Il wallet deriva nk a ogni esecuzione e non lo memorizza mai; ogni TxKey è estratta ex novo per ogni busta e scartata dopo la sigillatura. A un nodo si può consegnare una viewing key con rand_importViewingKey (in memoria, al massimo 64 per nodo, scompare al riavvio) perché effettui la scansione per conto del titolare — è il percorso dell’explorer — e rand_checkTransaction(hash, key) verifica un pagamento rispetto a una TxKey in un’unica chiamata senza stato. rand viewing-key stampa nk, e rand tx-key <hash> stampa la chiave di ciascun output di una transazione che questo wallet è in grado di aprire.

Gli id dei token non sono indirizzi

Un token RPL ha un terzo tipo di identificatore testuale, e nomina un token, mai un detentore. L’id di asset di 32 byte del token è mostrato come 64 caratteri esadecimali e come rpl1…: bech32m (BIP-350) con la parte leggibile rpl sui 32 byte dell’id, 52 caratteri di dati più un checksum di 6 caratteri, 62 caratteri. L’analisi è rigorosa: un checksum errato, un’altra parte leggibile, un payload che non sia esattamente di 32 byte o l’uso misto di maiuscole e minuscole vengono rifiutati, così un errore di battitura non si risolve mai in un token diverso. Una nota non porta l’id; la sua parola asset è l’indice denso del token nel registro (Token RPL).

Il destinatario del bridge

Il formato di trasmissione del bridge ha uno slot di 32 byte per il destinatario, e un indirizzo schermato non vi entra. Oggi lo slot porta un hash dell’indirizzo:

recipient_hash = blake3("rand-shielded-recipient" || pk_bytes || kem_ek)

Il depositante sulla chain di origine indica l’hash, i guardiani lo firmano e la transazione BridgeAttest porta l’indirizzo completo perché il ledger lo verifichi rispetto ad esso (Bridge).

L’indirizzo schermato breve: provato sulla chain 11, ripristinato

La chain 11 (tag del fullnode v0.2, 2026-09-17) ha sostituito l’indirizzo lungo con un receiver id di 53–55 caratteri, rand1 + base58(blake3(receiver signing key) ‖ checksum), e ha spostato la chiave di incapsulamento ML-KEM in un receiver record firmato, che il mittente recuperava dal registro dell’explorer oppure riceveva direttamente all’interno di una richiesta di pagamento. È rimasta in funzione un giorno ed è stata ripristinata lo stesso giorno (fullnode 17db41d); la chain 12 è tornata all’indirizzo lungo, esattamente come descritto sopra, e ogni chain successiva, chain 20 inclusa, lo mantiene.

Perché è stata abbandonata. Un receiver id è un hash, e un mittente non può sigillare una nota verso un hash. Il primo pagamento a un wallet che non si era mai registrato richiedeva che il destinatario consegnasse una richiesta di pagamento o un file di record, e la registrazione stessa veniva pagata con un auto-trasferimento, che un wallet nuovo e vuoto non può effettuare. Entrambi i percorsi di consegna, inoltre, rivelavano al registro chi stava per essere pagato. Il progetto che mantiene un indirizzo breve, l’invio incondizionato e la privacy crittografica è un indirizzo ibrido: una chiave X25519 di 32 byte inclusa nell’indirizzo (circa 93 caratteri), la chiave post-quantistica tramite lookup, con il primo pagamento a un wallet non registrato riservato nei confronti di avversari classici e ogni pagamento successivo interamente post-quantistico. Questo è specificato di seguito; finché non verrà rilasciato, l’indirizzo lungo resta l’indirizzo.

La specifica della chain 11 e la sua implementazione restano nella cronologia del fullnode (docs/superpowers/specs/2026-09-17-short-shielded-address.md, tag v0.2) per le parti che il progetto ibrido riutilizza: la receiver signing key derivata, il record firmato e il relativo verificatore, e il registro come stato della chain.

Ultima verifica rispetto al commit c0878c3f del fullnode (chain 21) il 2026-10-12. Dove il codice e questa pagina non concordano, ha ragione il codice; segnalacelo.