Użyj tej strony, aby wygenerować właściwy klucz do danego zadania, sparsować lub zweryfikować adres i wiedzieć, co ujawnia przekazanie komuś klucza. W tym łańcuchu nie ma kont: saldo jest faktem dotyczącym pliku klucza, nigdy łańcucha.
Dwa klucze, dwa rodzaje adresu
| klucz węzła | klucz portfela | |
|---|---|---|
| zapisywany przez | rand-node keygen | rand keygen |
| sekret | 32-bajtowe ziarno | 256-bitowy klucz wydawania |
| tożsamość publiczna | 32-bajtowy adres, base58, od 32 do 44 znaków | adres osłonięty, rand1…, 1665 lub 1666 znaków |
| podpisuje | bloki, głosy, emisje z faucetu, Unbond, Withdraw, Registration, a w chain 20 głos AdmitValidator; jako uprawnienie emisyjne Key tokena: TokenMint i SetAuthority. W chain 20 każda z tych wiadomości obejmuje także hasz genesis (Transakcje) | nic: transfer jest autoryzowany przez swoje dowody |
| pojawia się w łańcuchu jako | proponent bloku, wiersz rejestru walidatorów, emitent emisji z faucetu, uprawnienie key tokena | nigdy w transferze, gdzie jest zapieczętowany w kopertach. Jest publikowany tam, gdzie wartość wchodzi do puli z jawną kwotą: depozyt mostu, emisja tokena oraz, w chain 20, wypłata z wywołania (invoke) wskazują adres odbiorcy; adres wypłat walidatora znajduje się w rejestrze, genesis chain 20 wskazuje skarbiec opłat mostu, a od chain 14 emisja z faucetu i nota genesis alloc publikują pk właściciela, czyli pierwsze 32 bajty adresu |
| plik | { "seed", "address", "public_key" }, tryb 0600 | { "version": 2, "spend_key": "<64 hex>" }, tryb 0600 |
Te dwa rodzaje nigdy się nie mieszają. Walidatorzy są identyfikowani przez pierwszy rodzaj, a ten sam kształt klucza Dilithium2 służy jako uprawnienie emisyjne Key tokena (rand token create --authority-key-out zapisuje plik w kształcie pliku z rand-node keygen), klucz wstrzymania mostu i jego sześć postkwantowych kluczy strażników. Klucze poświadczeń strażników to secp256k1, z 20-bajtowymi adresami w stylu Ethereum (Most). Wartość jest przechowywana pod drugim rodzajem.
Adres jawny
Klucz węzła to 32-bajtowe ziarno, z którego deterministycznie wyprowadza się parę kluczy Dilithium2: 1312-bajtowy klucz publiczny i 2420-bajtowe podpisy. Adres jest haszem BLAKE3 klucza publicznego z separacją domen, zapisanym w base58:
address = blake3("rand-address" || public_key) // 32 bytes, shown as base58
Podpisane obiekty (głosy, bloki, emisje, akcje stakingu) niosą pełny klucz publiczny, więc weryfikator sprawdza blake3("rand-address" || public_key) == address, zamiast ufać samemu adresowi. To samo ziarno daje także tożsamość libp2p węzła, klucz ed25519 z blake3("rand-p2p-identity" || seed), który jest identyfikatorem peera po /p2p/ w multiadresie 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
Przykład: EdrEC2QRQrQF64iRXxF9927jNj6RidiHHByzx5xD6F1e to jeden z walidatorów chain 20. Chain 15 do 20 używają ponownie osiemnastu kluczy rotowanych dla chain 14, więc ich adresy i identyfikatory peerów nie zmieniły się, a żaden adres walidatora ani identyfikator peera z chain 13 nie jest już używany; osiem kolejnych walidatorów dołączyło ze stakiem w chain 15, a od chain 16 wszystkich 26 jest w pliku genesis.
Adres osłonięty
Portfel to jeden sekret, 256-bitowy klucz wydawania sk, a wszystko inne jest jego pochodną. Wyprowadzanie opiera się na Poseidon2 z tagiem domeny jako pierwszym wchłanianym słowem (H(domain, msg)), czyli na tej samej funkcji, którą zkVM oblicza w obwodzie:
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)
Adres to 32 bajty pk po których następuje 1184-bajtowy klucz enkapsulacji ML-KEM-768, w base58 po prefiksie rand1: 1665 lub 1666 znaków (długość base58 zależy od początkowych bajtów; mniej więcej co czternasty adres jest krótszy), około 1,6 KB, bez sumy kontrolnej. Nadawca potrzebuje klucza enkapsulacji, aby zapieczętować kopertę noty, dlatego jest on w adresie. Jest publiczny z założenia: każdy może na niego płacić, a jego posiadanie nic nie mówi o tym, co adres przechowuje.
rand keygen # wallet.key.json; refuses to overwrite an existing file
rand address # rand1… on stdout, its fingerprint XXXX-XXXX-XXXX-XXXX on stderr
Od v0.5.10 rand address wypisuje na stdout dokładnie adres i znak nowej linii, więc $(rand address) działa w skrypcie. Odcisk trafia na stderr.
Parsowanie, dokładnie tak jak robi to ShieldedAddress::parse: usuń rand1, zdekoduj base58 i wymagaj dokładnie 32 + 1184 = 1216 bajtów; pierwsze 32 to pk jako osiem słów u32 w porządku little-endian, reszta to klucz enkapsulacji. RPC odrzuca każdy parametr dłuższy niż 2000 znaków przed jego sparsowaniem.
Obok pliku klucza portfel przechowuje <key>.key.json.notes.json, pamięć podręczną not, które ten klucz otworzył. Zawiera ona jawne treści not, więc jest zapisywana w trybie 0600 jak klucz; każdy jej wiersz można odtworzyć, skanując ponownie od liścia 0.
Udostępnianie adresu: odcisk i linki randpay:
Adres jest zbyt długi, by czytać go na głos lub porównywać na oko, i nie ma sumy kontrolnej, dlatego od v0.5.10 każdy portfel pokazuje obok niego odcisk. Odcisk służy wyłącznie do wyświetlania: nic w łańcuchu ani w sieci go nie niesie.
fingerprint = first 80 bits of blake3("rand-address-fingerprint-1" || pk_bytes || kem_ek)
= 16 Crockford base32 characters, shown as XXXX-XXXX-XXXX-XXXX
Hasz jest liczony z 1216 surowych bajtów, które koduje adres. Alfabet to 0123456789ABCDEFGHJKMNPQRSTVWXYZ; parsowanie ignoruje wielkość liter i łączniki oraz odczytuje O jako 0, a I lub L jako 1.
Link randpay: niesie adres i opcjonalnie to, co ma na niego zostać zapłacone:
randpay:<rand1…>[?amount=<decimal>][&asset=<index | 64 hex | rpl1…>][&memo=<percent-encoded UTF-8>]
amount jest podawany w jednostkach wyświetlania aktywa (dziesiętny RAND z dziewięcioma miejscami po przecinku, token z własnym decimals wiersza rejestru) i nie może być zerem. memo to co najwyżej 510 bajtów UTF-8. Schemat jest rozpoznawany bez względu na wielkość liter; nieznany parametr, powtórzony parametr lub błędne kodowanie procentowe są odrzucane.
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> przyjmuje adres rand1…, link randpay: lub nazwę zapisanego kontaktu, sprawdzane w tej kolejności. amount, asset i memo z linku uzupełniają to, czego brakuje w wierszu poleceń, a wartość podana obiema drogami, która się różni, jest odrzucana. Przed wygenerowaniem dowodu send wypisuje to <contact, if any> · fingerprint XXXX-XXXX-XXXX-XXXX · <amount> <asset> i prosi o potwierdzenie; skrypt przekazuje --yes. Kontakty są przechowywane obok klucza w <key>.contacts.json, w trybie 0600. Memo podróżuje wewnątrz koperty noty (Noty).
Nie istnieje rand balance <address> ani RPC salda: łańcuch nie potrafi na to odpowiedzieć nikomu. Portfel oblicza swoje saldo, skanując swoim kluczem podglądu wszystkie koperty w łańcuchu (Noty).
Klucze, które możesz przekazać komuś innemu
Ujawnienie jest własnością kluczy, a łańcuch nie może wymusić żadnego z nich.
| klucz | otwiera | ziarnistość |
|---|---|---|
klucz podglądu nk (64 hex) | każdą notę, jaką portfel kiedykolwiek otrzymał, a przez ovk każdą notę, jaką kiedykolwiek wysłał, wraz z nullifierem każdego wydania | wszystko albo nic, wstecz i w przód |
klucz transakcji TxKey (32 bajty) | dokładnie jedną kopertę, którą zapieczętował: notę i, od chain 18, jej memo | jedna płatność |
klucz wywołania K_call | zapis prywatnych danych wejściowych jednego poufnego wywołania | jedno wywołanie |
Klucz podglądu nie może wydawać. Od chain 17 (podzielona autoryzacja) sam dowód pakietu jest tworzony z nk, a każdy pakiet niesie też drugi, mały dowód autoryzacji, który może wytworzyć tylko klucz wydawania i który jest związany z jedną transakcją (Noty). Dzięki temu delegowanemu proverowi można przekazać nk, a więc całą historię portfela, bez możliwości wydawania; portfel zawsze tworzy dowód autoryzacji na własnej maszynie. Adresy, klucze i istniejące noty nie zmieniają się przez ten podział. Portfel wyprowadza nk przy każdym uruchomieniu i nigdy go nie przechowuje; każdy TxKey jest losowany od nowa dla każdej koperty i porzucany po zapieczętowaniu. Węzłowi można przekazać klucz podglądu przez rand_importViewingKey (w pamięci, najwyżej 64 na węzeł, znika po restarcie), aby skanował w imieniu posiadacza — to ścieżka eksploratora — a rand_checkTransaction(hash, key) sprawdza jedną płatność względem TxKey w jednym bezstanowym wywołaniu. rand viewing-key wypisuje nk, a rand tx-key <hash> wypisuje klucz każdego wyjścia transakcji, które ten portfel potrafi otworzyć.
Identyfikatory tokenów nie są adresami
Token RPL ma trzeci rodzaj tekstowego identyfikatora, który nazywa token, nigdy posiadacza. 32-bajtowy identyfikator aktywa tokena jest pokazywany jako 64 znaki hex oraz jako rpl1…: bech32m (BIP-350) z częścią czytelną dla człowieka rpl nad 32 bajtami identyfikatora, 52 znaki danych plus 6-znakowa suma kontrolna, 62 znaki. Parsowanie jest ścisłe: błędna suma kontrolna, inna część czytelna dla człowieka, ładunek o długości innej niż dokładnie 32 bajty lub mieszana wielkość liter są odrzucane, więc literówka nigdy nie wskaże innego tokena. Nota nie niesie identyfikatora; jej słowo asset to gęsty indeks tokena w rejestrze (Tokeny RPL).
Odbiorca w moście
Format przesyłania mostu ma 32-bajtowe pole odbiorcy, a adres osłonięty się w nim nie mieści. Obecnie to pole niesie hasz adresu:
recipient_hash = blake3("rand-shielded-recipient" || pk_bytes || kem_ek)
Depozytor w łańcuchu źródłowym wskazuje hasz, strażnicy go podpisują, a transakcja BridgeAttest niesie pełny adres, aby księga mogła go z nim porównać (Most).
Krótki adres osłonięty: wypróbowany w chain 11, wycofany
Chain 11 (tag v0.2 w fullnode, 2026-09-17) zastąpił długi adres identyfikatorem odbiorcy (ang. receiver id) o długości 53–55 znaków, rand1 + base58(blake3(receiver signing key) ‖ checksum), a klucz enkapsulacji ML-KEM przeniósł do podpisanego rekordu odbiorcy, który nadawca pobierał z rejestru eksploratora albo otrzymywał w treści żądania płatności. Działał przez dobę i tego samego dnia został wycofany (fullnode 17db41d); chain 12 wrócił do długiego adresu, dokładnie takiego, jak opisano powyżej, i każdy kolejny chain, w tym chain 20, go zachowuje.
Dlaczego go wycofano. Identyfikator odbiorcy jest skrótem, a nadawca nie może zaszyfrować noty dla skrótu. Pierwsza płatność do portfela, który nigdy się nie zarejestrował, wymagała, by odbiorca przekazał żądanie płatności lub plik rekordu, a sama rejestracja była opłacana transferem własnym, którego nowy, pusty portfel wykonać nie może. Obie ścieżki dostarczenia ujawniały też rejestrowi, kto za chwilę otrzyma płatność. Projekt, który zachowuje krótki adres, bezwarunkową możliwość wysyłania i kryptograficzną prywatność, to adres hybrydowy: 32-bajtowy klucz X25519 w treści adresu (około 93 znaków), klucz postkwantowy pobierany z rejestru, przy czym pierwsza płatność do niezarejestrowanego portfela jest poufna wobec przeciwników klasycznych, a każda kolejna jest w pełni postkwantowa. Jest to opisane w następnej części; do czasu jej wdrożenia adresem pozostaje adres długi.
Specyfikacja chain 11 i jej implementacja pozostają w historii fullnode (docs/superpowers/specs/2026-09-17-short-shielded-address.md, tag v0.2) ze względu na elementy, które projekt hybrydowy wykorzystuje ponownie: pochodny klucz podpisu odbiorcy, podpisany rekord wraz z jego weryfikatorem oraz rejestr jako stan łańcucha.