Rand Protocol
Документация
Основные понятия

Счета и адреса

Два вида ключей в сети, как выводится экранированный адрес rand1, что раскрывает ключ просмотра и почему короткий адрес chain 11 был отменён.

Используйте эту страницу, чтобы сгенерировать ключ для нужной задачи, разобрать или проверить адрес и понять, что раскрывает передача ключа другому лицу. В этой цепочке нет учётных записей: баланс — это факт о файле ключа, а не о цепочке.

Два ключа, два вида адреса

ключ узлаключ кошелька
создаётся командойrand-node keygenrand 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) ради частей, которые гибридная конструкция использует повторно: производного ключа подписи получателя, подписанной записи и её верификатора, а также реестра как состояния цепочки.

Последняя проверка по коммиту fullnode c0878c3f (chain 21) от 2026-10-12. Если код и эта страница расходятся, прав код; сообщите нам.