Rand Protocol
Документация
Примеры программ

Четыре программы в chain 20

Четыре полноценные конфиденциальные программы, развёрнутые в testnet: анонимное голосование, доказательство обязательств, внебиржевой реестр вне цепочки и приватное кредитное решение — с идентификаторами программ, общей для них настройкой, тем, что chain 18 изменила для автора программы, и инструкцией, как вызвать их самостоятельно.

Эти четыре программы — по одному законченному приложению конфиденциального вызова: задача, интерфейс, гостевая программа на Rust, инструментарий на стороне хоста, а также развёртывание и вызов в действующей сети testnet. Они длиннее учебных руководств, и каждая опирается на свою часть машины. Написание программы на Rust или C — руководство по модели, которую используют все четыре. Прочитайте его первым, если read_input, публичный сегмент или восемь выходных слотов вам незнакомы.

Всё здесь впервые было запущено в цепочке 18 с fullnode v0.6.7 30 сентября 2026 года, и каждый вывод на этих страницах вставлен из тех запусков. Программы не переносятся при переходе на новую цепочку, поэтому 1 октября 2026 года все четыре были развёрнуты заново, без изменений, в цепочке 19, а затем в цепочке 20 (fullnode v0.6.8), и каждый раз вызовы повторялись. Идентификатор программы — это хеш кода и публичного сегмента, а не цепочки, поэтому все идентификаторы одинаковы; хеши транзакций в протоколах запусков принадлежат цепочке 18, а таблица ниже ссылается на транзакции цепочки 20. В цепочке 20 программа может также хранить состояние между вызовами (RPL-2); эти четыре программы его не используют, а Состояние программы и репозиторий example-programs охватывают программы, которые используют.

Четыре программы

программачто доказывает вызовна чём держитсясловуровень
Анонимное голосованиевызывающий входит в опубликованный список, не раскрывая, кто именно, и ещё не голосовалKeccak-256, публичный сегмент42712
Доказательство обязательствприватные балансы клиентов в сумме не превышают опубликованный резерв, при корне, который каждый клиент может проверитьSHA-256, дерево, построенное внутри программы99414
Внецепочечный реестрпакет переводов переводит реестр из одного состояния в следующее, причём каждый отправитель авторизован и ничего не созданоPoseidon2, состояние, переносимое между вызовами77314
Приватное кредитное решениеопубликованная модель одобряет или отклоняет приватные данные заявителя, за которые поручился аттестаторцелочисленная арифметика, модель в публичном сегменте46212

Все четыре работали в цепочке 20 до её вывода из эксплуатации 12 октября 2026 года. Цепочка 21 (fullnode v0.8.0) стартовала без программ, как и после каждого перехода, и эти четыре в ней пока не развёрнуты заново; приведённые ниже идентификаторы при этом не изменятся, поскольку идентификатор хеширует код и публичный сегмент, а не цепочку. Каждый вызов в таблице повторяет с теми же входными данными вызов в цепочке 18, показанный на странице соответствующей программы:

программаидентификатор программыразвёрнута в цепочке 20 впервый вызов в цепочке 20
анонимное голосованиеad2f719f12d01c9f3c0962092b9898b75b0914bbb817031d51be13e54c05b970f6ae5528…0f823a304e7a…427b
доказательство обязательствfce8474dfdf80b9733e04fb72d4d8d19c40ba5ab646b3d867322daf4b9b599c0a8bc281b…17d96116c15f…d62a
внецепочечный реестрc4ddd388f2d94299610c7c3409dfdfb4dcb4ae3e0bc9ec78d0c45f51d8231cab72cc95f2…3d519c9998bb…66eb
приватное кредитное решение7bbec14289f4446231b3a9a5ac18cb0613a373ca8a14fe4f046f3fde7ae6c73c413e6658…e42bd3ceb306…124a

Обозреватель показывает все программы и их вызовы по адресу randscan.org/programs. Цепочка testnet время от времени заменяется, и программы при этом не переносятся: после следующего перехода этих идентификаторов не будет, а программы придётся развёртывать заново.

Подготовка

Инструментарий. Гостевые программы собираются с помощью rand-guest из репозитория circuits на коммите, который vendor-ят и fullnode v0.6.7, и v0.6.8:

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"

Коммит важен по двум причинам. hc — функция исходного кода и инструментария, поэтому гостевая программа, пересобранная на другом коммите guest-sdk, может получить другой hc. И сигнатуры SDK менялись: на aeacf31 keccak и sha256_compress принимают ссылки на массивы, тогда как на более старых коммитах принимали сырые указатели.

Исходные тексты. Все четыре гостевые программы, их хост-скрипты и демонстрационные данные — это одна загрузка. Распакуйте её внутри checkout, потому что rand-guest build находит guest-sdk, поднимаясь вверх от каталога гостевой программы:

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

Файлы также доступны для просмотра по одному в https://randprotocol.org/examples/programs/, например allowlist/src/main.rs.

Кошелёк. Для развёртывания и вызовов нужен кошелёк rand из fullnode v0.6.8 (cargo build --release -p randprotocol-client в checkout fullnode на теге v0.6.8 либо rand, приложенный к релизу v0.6.8), ключ и RAND. В цепочке 21 кошелёк — это rand из fullnode v0.8.0 (тег v0.8.0): набор ограничений 9 изменил все ключи верификатора, поэтому ни кошелёк v0.6.8, ни кошелёк v0.7.x не могут там ни развёртывать, ни вызывать. Более старый кошелёк не мог проводить транзакции и в цепочке 20: цепочка 20 привязывает каждое доказательство и каждое подписанное сообщение к своему genesis, а кошелёк v0.6.7 этого не делает.

RPC. Публичной конечной точки https://rpc.randprotocol.org достаточно для всего, что описано на этих страницах: чтения программ и квитанций, синхронизации кошелька, развёртывания и вызова. Первая синхронизация кошелька читает каждый заголовок блока и каждый блок, содержащий ноту, — 645 запросов на высоте цепочки 18 на 30 сентября 2026 года — и заняла около трёх минут через эту конечную точку. Конечная точка допускает для каждого адреса 1 200 чтений и 6 отправок в минуту. У собственного узла (Запуск узла) таких ограничений нет.

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

В цепочке 18 один из голосов, учтённых на странице анонимного голосования, fdbcc960…fc2b, был доказан на ноутбуке и отправлен только через публичную конечную точку. В цепочках 19 и 20 все тринадцать транзакций каждый раз, то есть четыре развёртывания и девять вызовов, прошли именно так.

Что цепочка 18 изменила для программы

Вызов объявляет лимит газа и платит за него. Набор ограничений 8 измеряет каждый запуск. Обычный цикл стоит 1 газ. Исключение составляют системные вызовы хеширования:

инструкциягаз
любая инструкция RV32IM, HALT, WRITE_OUTPUT, READ_INPUT, READ_PUBLIC1
POSEIDON2 над n словами3 + 3 × ⌈n / 4⌉
SHA256, одно сжатие64
KECCAK, одна перестановка192

Доказательство несёт одно новое публичное значение — объявленный лимит, и схема обеспечивает, чтобы газ запуска не превышал его. Точный газ остаётся приватным. rand call сначала выполняет программу в эмуляторе и печатает оба значения:

gas: 5636 (declaring 6144, tier 12)

По умолчанию кошелёк округляет точный газ вверх до кратного 2^(tier − 2), то есть 1 024 на уровне 12 и 4 096 на уровне 14, так что объявленный лимит мало что говорит о запуске. --gas-limit max объявляет потолок уровня и не сообщает ничего сверх уровня. --gas-limit N объявляет точное значение.

Комиссия зависит от объявленного лимита и от байтов.

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

Цены начинались со 100 единиц за газ и 800 единиц за KiB (единица — 10⁻⁹ RAND) и понемногу смещаются с каждым блоком к целевому значению. rand_getLimits возвращает текущие. Кошелёк добавляет запас в два ценовых шага, множитель 1,125², поскольку вызов попадает в блок через два-три блока после назначения цены.

Одна деталь определяет большую часть комиссии. Начиная с цепочки 18 доказательство вызова привязано к собственной транзакции, поэтому кошелёк должен зафиксировать комиссию до появления доказательства и оценивает доказательство по предельному размеру цепочки в 4 MiB, а не по реальному. Для анонимного голосования это (1,000,000 + 100 × 6,144 + 800 × 4,097) × 1.125² = 6 191 437 единиц, 0,0062 RAND, из которых газ составляет около восьмой части. Четыре вызова на этих страницах стоили от 0,0057 до 0,0075 RAND каждый. --fee переопределяет значение по умолчанию.

Каждый пакет — это два доказательства. Цепочка 18 использует раздельную авторизацию: пакет, оплачивающий комиссию, несёт небольшое доказательство авторизации уровня 10 рядом с доказательством пакета уровня 14. Кошелёк строит оба и печатает по строке для каждого. Таким образом, вызов — это три доказательства: вызова, авторизации и пакета. На ноутбуке Apple Silicon четыре вызова здесь заняли от трёх до пяти с половиной минут каждый, с пиком памяти от 6,1 до 6,6 GB. Доказательство пакета каждый раз занимает около двух минут из этого времени. Доказательство вызова уровня 12 добавляет полминуты, а уровня 14 — две минуты.

Пределы, в которые должен укладываться вызов.

пределцепочки с 18 по 20
уровеньне выше 14: 16 383 цикла, включая строки дайджестов
перестановки Poseidon22 048 на уровне 14, включая дайджесты программы, входа и публичного сегмента
перестановки Keccak128
сжатия SHA-256128
доказательство вызова4 194 304 байта (4 MiB)
программа8 180 слов без публичного сегмента, несколько меньше с ним: цепочка 21, как и цепочки с 18 по 20, отклоняет развёртывание, которое не смог бы вместить ни один вызов уровня 14 (ProgramUncallable), что бы ни разрешал max_program_words (65 535)
публичный сегмент32 768 слов, фиксируется при развёртывании
приватный вход с запечатанным транскриптом16 071 слово

rand-guest run --tier 14 проверяет первые два предела до развёртывания. Хеш-таблица увеличивает доказательство. Доказательство реестра уровня 14, без хеш-таблицы, занимает 1,50 MB. Таблица SHA-256 доводит доказательство обязательств до 1,91 MB, а таблица Keccak доводит доказательство голосования до 3,35 MB, что составляет большую часть предела в 4 MiB.

Общие соглашения всех четырёх программ

  • Слот 0 — это статус, и 0 никогда не является допустимым статусом. У каждого исхода, включая сбои, есть номер от 1 и выше, а сбой завершается штатной остановкой, чтобы его можно было доказать. Квитанцию из одних нулей нельзя принять за результат.
  • Слот 7 не используется. Rust-гость, который завершается паникой, записывает туда 0xdeadbeef (3 735 928 559). Читатель сначала проверяет слот 7.
  • Слоты со 2-го по 6-й несут 160-битное значение: нуллификатор, корень, ссылку, обязательство. Полный 256-битный хеш занимает восемь слов и не оставил бы места для статуса. Усечение до пяти слов сохраняет 80 бит стойкости к коллизиям, и на каждой странице сказано, что именно это защищает.
  • Порядок байтов следует хешу. Значения Keccak — слова в порядке little-endian, значения SHA-256 — слова в порядке big-endian, потому что именно так каждый системный вызов читает свой блок. Если скрипт хоста и гость расходятся в этом, получаются дайджесты, которые просто никогда не совпадают.
  • Всё, что меняется от экземпляра к экземпляру, находится в публичном сегменте; всё, что меняется от вызова к вызову, — приватный вход. Корень голосования, значение резервов и веса модели фиксируются при развёртывании и привязываются к идентификатору программы. Вызов не несёт собственных публичных слов.
  • Входные слова в командной строке записываются в десятичном виде. Страницы превращают файл свидетельства во флаги командой $(sed 's/[0-9][0-9]*/--input &/g' witness.txt).

Вызовите программу сами

Имея распакованные исходники, собранный инструментарий и пополненный кошелёк (v0.6.8 в chain 20, где выполнялись эти запуски; v0.8.0 в chain 21), голосование от имени одного из демонстрационных участников выполняется четырьмя командами:

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)

Для вызова образ не нужен: rand call получает код и публичный сегмент программы от узла, проверяет, что их хеш совпадает с идентификатором, и строит доказательство по ним.

Чтобы прочитать результат, не нужны ни кошелёк, ни узел. Любая квитанция запрашивается одним запросом к публичной конечной точке:

$ 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"}}

API обозревателя возвращает вызовы программы одним запросом: https://randscan.org/api/v1/programs/<program id> возвращает call_count и recent_calls (Explorer API).

Чего они не делают

Программа в Rand — это доказательство о вычислении, и сеть не выполняет никаких действий по её выходным данным. Ни одна из этих программ не переводит RAND или токен, не хранит баланс и не помнит предыдущий вызов. Голоса подсчитывает тот, кто читает квитанции. Обязательства сопоставляются с резервами, которым нужны собственные подтверждения. Балансы реестра — это числа во внецепочечном дереве. Кредитное решение — это бит, который кредитор вправе принять или не принять. Каждая страница завершается списком того, что её доказательство оставляет на усмотрение пользователей.

Последняя проверка по коммиту fullnode 48dc04b (chain 18) от 2026-09-30, а также 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`. Если код и эта страница расходятся, прав код; сообщите нам.