Используйте эту страницу, чтобы сгенерировать ключ для нужной задачи, разобрать или проверить адрес и понять, что раскрывает передача ключа другому лицу. В этой цепочке нет учётных записей: баланс — это факт о файле ключа, а не о цепочке.
Два ключа, два вида адреса
| ключ узла | ключ кошелька | |
|---|---|---|
| создаётся командой | rand-node keygen | rand keygen |
| секрет | 32-байтовое seed-значение | 256-битный ключ расходования |
| публичная идентичность | 32-байтовый адрес, base58, от 32 до 44 символов | экранированный адрес rand1…, 1 665 или 1 666 символов |
| подписывает | блоки, голоса, эмиссии крана, Unbond, Withdraw, Registration, начиная с chain 20 — голос AdmitValidator, а в chain 21 — платежи и ротации мультиподписного счёта и голос SetRandPrice; как ключ эмиссии токена Key — TokenMint и SetAuthority. Начиная с chain 20 каждое из этих сообщений также покрывает хеш генезиса (Транзакции) | ничего: перевод авторизуется своими доказательствами |
| появляется в цепочке как | автор блока, строка реестра валидаторов, эмитент эмиссии крана, авторитет key токена | никогда в переводе, где он запечатан внутри конвертов. Он публикуется там, где в пул входит стоимость с открытой суммой: депозит через мост, эмиссия токена и, начиная с chain 20, выплата invoke называют адрес получателя; адрес выплат валидатора находится в реестре, генезис chain 20 называет казначейство комиссий моста, а начиная с chain 14 эмиссия крана и нота alloc в генезисе публикуют pk владельца — первые 32 байта адреса |
| файл | { "seed", "address", "public_key" }, режим 0600 | { "version": 2, "spend_key": "<64 hex>" }, режим 0600 |
Эти два вида никогда не смешиваются. Валидаторы идентифицируются ключом первого вида, и та же форма ключа Dilithium2 служит ключом эмиссии токена Key (rand token create --authority-key-out записывает файл формата rand-node keygen), ключом паузы моста и его шестью постквантовыми ключами хранителей. Ключи аттестации хранителей — secp256k1, с 20-байтовыми адресами в стиле Ethereum (Мост). Стоимость хранится под ключом второго вида.
Прозрачный адрес
Ключ узла — это 32-байтовое seed-значение, из которого детерминированно выводится пара ключей Dilithium2: 1 312-байтовый открытый ключ и подписи по 2 420 байт. Адрес — это BLAKE3-хеш открытого ключа с разделением доменов, представленный в base58:
address = blake3("rand-address" || public_key) // 32 bytes, shown as base58
Подписанные объекты (голоса, блоки, эмиссии, действия стейкинга) несут полный открытый ключ, поэтому верификатор проверяет blake3("rand-address" || public_key) == address, а не доверяет голому адресу. Из того же seed-значения получается и идентичность узла в libp2p — ключ ed25519 из blake3("rand-p2p-identity" || seed); это идентификатор пира после /p2p/ в bootstrap multiaddr.
rand-node keygen --out node.key.json # prints the address
rand-node address --key node.key.json # address, public key (hex), libp2p peer id
Пример: EdrEC2QRQrQF64iRXxF9927jNj6RidiHHByzx5xD6F1e — один из валидаторов chain 21. Chains 15–21 повторно используют восемнадцать ключей, ротированных для chain 14, поэтому их адреса и идентификаторы пиров не изменились, и ни один адрес или идентификатор пира валидатора chain 13 больше не используется; ещё восемь валидаторов вошли в стейк на chain 15, и все 26 находятся в файле генезиса начиная с chain 16.
Экранированный адрес
Кошелёк — это один секрет, 256-битный ключ расходования sk, а всё остальное — его производные. Вывод выполняется функцией Poseidon2 с доменным тегом в качестве первого поглощаемого слова (H(domain, msg)) — той же функцией, которую zkVM вычисляет в схеме:
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)
Адрес — это 32 байта pk, за которыми следует 1 184-байтовый ключ инкапсуляции ML-KEM-768, в base58 после префикса rand1: 1 665 или 1 666 символов (длина в base58 зависит от ведущих байтов; примерно один адрес из четырнадцати короче), около 1,6 KB, без контрольной суммы. Отправителю нужен ключ инкапсуляции, чтобы запечатать конверт ноты, поэтому он и входит в адрес. Он публичен по замыслу: платить на него может любой, а обладание им ничего не говорит о том, что на нём хранится.
rand keygen # wallet.key.json; refuses to overwrite an existing file
rand address # rand1… on stdout, its fingerprint XXXX-XXXX-XXXX-XXXX on stderr
Начиная с v0.5.10 rand address выводит в stdout ровно адрес и перевод строки, поэтому в скрипте работает $(rand address). Отпечаток направляется в stderr.
Разбор — в точности как в ShieldedAddress::parse: отбросить rand1, декодировать base58 и потребовать ровно 32 + 1 184 = 1 216 байт; первые 32 — это pk в виде восьми little-endian слов u32, остальное — ключ инкапсуляции. RPC отклоняет любой параметр длиннее 2 000 символов ещё до разбора.
Рядом с файлом ключа кошелёк хранит <key>.key.json.notes.json — кэш нот, которые этот ключ раскрыл. Он содержит открытые тексты нот, поэтому записывается с режимом 0600, как и ключ; каждая его строка восстанавливается повторным сканированием с листа 0.
Передача адреса: отпечаток и ссылки randpay:
Адрес слишком длинен, чтобы читать его вслух или сверять на глаз, и не имеет контрольной суммы, поэтому начиная с v0.5.10 каждый кошелёк показывает рядом с ним отпечаток. Отпечаток служит только для отображения: ни в цепочке, ни в сетевом протоколе его нет.
fingerprint = first 80 bits of blake3("rand-address-fingerprint-1" || pk_bytes || kem_ek)
= 16 Crockford base32 characters, shown as XXXX-XXXX-XXXX-XXXX
Хеш берётся от 1 216 сырых байт, которые кодирует адрес. Алфавит — 0123456789ABCDEFGHJKMNPQRSTVWXYZ; при разборе регистр и дефисы игнорируются, O читается как 0, а I или L — как 1.
Ссылка randpay: несёт адрес и, при необходимости, то, что на него нужно заплатить:
randpay:<rand1…>[?amount=<decimal>][&asset=<index | 64 hex | rpl1…>][&memo=<percent-encoded UTF-8>]
amount указывается в отображаемых единицах актива (десятичный RAND с девятью знаками, токен — с собственным decimals из строки реестра) и не должен быть нулевым. memo — не более 510 байт UTF-8. Схема сопоставляется без учёта регистра; неизвестный параметр, повторённый параметр или некорректное процентное кодирование отклоняются.
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> принимает адрес rand1…, ссылку randpay: или имя сохранённого контакта — в этом порядке. amount, asset и memo из ссылки заполняют то, что не задано в командной строке, а значение, заданное обоими способами и расходящееся, отклоняется. Перед построением доказательства send печатает to <contact, if any> · fingerprint XXXX-XXXX-XXXX-XXXX · <amount> <asset> и запрашивает подтверждение; скрипт передаёт --yes. Контакты хранятся рядом с ключом в <key>.contacts.json, режим 0600. Мемо передаётся внутри конверта ноты (Ноты).
Команды rand balance <address> и RPC для баланса не существует: цепочка не может ответить на такой запрос ни для кого. Кошелёк вычисляет свой баланс, сканируя все конверты в цепочке своим ключом просмотра (Ноты).
Ключи, которые можно передать другому
Раскрытие — свойство ключей, и цепочка не может принудить ни к какому из них.
| ключ | что раскрывает | гранулярность |
|---|---|---|
ключ просмотра nk (64 hex) | все ноты, когда-либо полученные кошельком, и, через ovk, все когда-либо отправленные, с нуллификатором каждой траты | всё или ничего, ретроспективно и на будущее |
ключ транзакции TxKey (32 байта) | ровно один запечатанный им конверт: ноту и, начиная с chain 18, её мемо | один платёж |
ключ вызова K_call | транскрипт приватных входных данных одного конфиденциального вызова | один вызов |
Ключ просмотра не может тратить. Начиная с chain 17 (разделённая авторизация) само доказательство пакета строится из nk, и каждый пакет несёт также второе, небольшое доказательство авторизации, которое может построить только ключ расходования и которое привязано к одной транзакции (Ноты). Именно это позволяет передать делегированному pruver’у nk, а значит и всю историю кошелька, без возможности тратить; доказательство авторизации кошелёк всегда строит на собственной машине. Адреса, ключи и существующие ноты при разделении не меняются. Кошелёк выводит nk при каждом запуске и никогда его не хранит; каждый TxKey генерируется заново для каждого конверта и отбрасывается после запечатывания. Узлу можно передать ключ просмотра через rand_importViewingKey (в памяти, не более 64 на узел, до перезапуска), чтобы он сканировал от имени владельца — это путь обозревателя, — а rand_checkTransaction(hash, key) проверяет один платёж по TxKey одним вызовом без состояния. rand viewing-key печатает nk, а rand tx-key <hash> печатает ключ каждого выхода транзакции, который этот кошелёк может раскрыть.
Идентификаторы токенов — не адреса
У токена RPL есть третий вид текстового идентификатора, и он называет токен, а не держателя. 32-байтовый идентификатор актива токена показывается как 64 hex-символа и как rpl1…: bech32m (BIP-350) с человекочитаемой частью rpl над 32 байтами идентификатора, 52 символа данных плюс 6 символов контрольной суммы, 62 символа. Разбор строгий: неверная контрольная сумма, другая человекочитаемая часть, полезная нагрузка не ровно в 32 байта или смешанный регистр отклоняются, поэтому опечатка никогда не приведёт к другому токену. Нота не несёт идентификатор; её слово asset — это плотный индекс токена в реестре (Токены RPL).
Получатель в мосте
В сетевом формате моста есть 32-байтовый слот получателя, и экранированный адрес в него не помещается. Сегодня в слоте находится хеш адреса:
recipient_hash = blake3("rand-shielded-recipient" || pk_bytes || kem_ek)
Депозитор в исходной цепочке называет хеш, хранители его подписывают, а транзакция BridgeAttest несёт полный адрес, чтобы реестр мог сверить его с хешем (Мост).
Короткий экранированный адрес: опробован в chain 11, отменён
Цепочка 11 (тег fullnode v0.2, 2026-09-17) заменила длинный адрес идентификатором получателя длиной от 53 до 55 символов, rand1 + base58(blake3(ключ подписи получателя) ‖ контрольная сумма), а инкапсуляционный ключ ML-KEM перенесла в подписанную запись получателя, которую отправитель получал из реестра обозревателя или внутри платёжного запроса. Она проработала один день и в тот же день была отменена (fullnode 17db41d); цепочка 12 вернулась к длинному адресу в точности так, как описано выше, и все последующие цепочки, включая цепочку 20, сохраняют его.
Почему от неё отказались. Идентификатор получателя — это хеш, а отправитель не может запечатать ноту на хеш. Для первого платежа на кошелёк, который никогда не регистрировался, получатель должен был передать платёжный запрос или файл записи, а сама регистрация оплачивалась переводом самому себе, который новый пустой кошелёк выполнить не может. Оба способа доставки к тому же сообщали реестру, кому вскоре будет сделан платёж. Конструкция, сохраняющая короткий адрес, безусловную возможность отправки и криптографическую приватность, — это гибридный адрес: 32-байтовый ключ X25519 внутри адреса (около 93 символов), постквантовый ключ — по запросу в реестре; при этом первый платёж на незарегистрированный кошелёк конфиденциален против классических противников, а каждый последующий полностью постквантовый. Это описано далее; пока она не выпущена, адресом остаётся длинный адрес.
Спецификация цепочки 11 и её реализация остаются в истории fullnode (docs/superpowers/specs/2026-09-17-short-shielded-address.md, тег v0.2) ради частей, которые гибридная конструкция использует повторно: производного ключа подписи получателя, подписанной записи и её верификатора, а также реестра как состояния цепочки.