Rand Protocol
Dokumentasi
Program RISC-V

Mengerahkan program RISC-V

Dua laluan menuju imej yang boleh dikerahkan tanpa Rust - program C yang dibina oleh rand-guest dengan clang yang disematkan, dan program yang ditulis tangan lalu dihimpun dan dibungkus, atau dibungkus ke dalam kontena imej bait demi bait.

Mana-mana program yang merupakan kod mesin RV32IM boleh digunakan (deploy), walau apa pun yang menghasilkannya. Halaman ini menunjukkan dua laluan: C melalui rand-guest build --lang c, dan program yang anda tulis dalam bahasa himpunan (assembly) lalu anda pakej sendiri. Kedua-duanya berakhir dengan bekas imej (image container) yang sama seperti yang dihasilkan oleh Deploy a Rust program, dan kedua-duanya digunakan dengan rand program deploy. Sediakan dahulu checkout circuits dan rand-guest, seperti dalam langkah 1 halaman tersebut. Bagi rantaian 18 hingga 20, checkout berada pada commit aeacf31, yang dipin oleh fullnode v0.6.7 dan v0.6.8. Output di bawah dihasilkan pada 2026-09-19 pada 7ef3220 dan belum dijalankan semula. Direktori rand-guest, termasuk guest.h dan rt.c, adalah sama pada kedua-dua commit.

C melalui clang

Apa yang anda perlukan

alatversicara
clang23.1.1, dengan hujung belakang (backend) RISC-Vbrew install llvm pada macOS; clang sistem Apple tidak mempunyai backend RISC-V. Atau tetapkan $CLANG kepada binari 23.1.1
rust-llddaripada Rust 1.98.1rustup +1.98.1 component add llvm-tools

rand-guest menolak mana-mana clang yang versinya bukan 23.1.1. RAND_GUEST_CLANG_UNPINNED=1 membina dengan versi lain, disertai amaran bahawa hc tidak akan sepadan dengan imej yang diterbitkan.

Tulis guest

Direktori guest C hanya mengandungi fail .c (dan satu fail .ld pilihan). rand-guest membekalkan guest.h, _start dan runtime kecil. Jangan tambah guest.h atau start.S anda sendiri: build --lang c menolak direktori yang mempunyai salah satunya.

Ini ialah guests-compiled/c-fib/fib.c yang telah di-commit:

#include "guest.h"

static uint32_t fib(uint32_t n) {
    uint32_t a = 0, b = 1;
    for (uint32_t i = 0; i < n; i++) {
        uint32_t c = a + b;
        a = b;
        b = c;
    }
    return a;
}

void main(void) {
    rand_write_output(0, fib(rand_read_input(0)));
    rand_halt();
}

guest.h mengisytiharkan rand_read_input, rand_read_public, rand_write_output, rand_poseidon2, rand_keccak, rand_sha256_compress dan rand_halt. Ia tidak mempunyai pembungkus (wrapper) untuk syscall 7, iaitu POSEIDON2_LEN terikat panjang yang dijalankan oleh mesin sejak constraint set 7, dan rand-guest check pada aeacf31 menolak ecall dengan a7 = 7 (zkp-circuits isu #1). Guest C atau assembly untuk rantaian 20 oleh itu menggunakan syscall 0 hingga 6.

Bina, jalankan, periksa

$ rand-guest build --lang c guests-compiled/c-fib --out c-fib.bin
25 words against a cap of 4096 (fits); 0 ecall(s) with a non-static a7
OK
wrote c-fib.bin and its .sha256 (25 words, hc 76e723cb4c218f9a7f657f39b9f95ee2353d8fbeb601aaea394afa29928f3aee, program id c213cf5c94679cab4585ed1e81b61736a7d2fe5605dc7884e4acec4144665999)

$ rand-guest run c-fib.bin --input 20 --tier 10
out[0] = 6765
out[1] = 0
out[2] = 0
out[3] = 0
out[4] = 0
out[5] = 0
out[6] = 0
out[7] = 0
cycles 116
tier 10
tier 10: fits (cycles 126 of 1023, Poseidon2 permutations 10 of 128)

fib(20) = 6765, jawapan yang sama seperti guest fib dalam Rust.

build --lang c mengkompil setiap fail .c dalam direktori (mengikut susunan terisih), ditambah start.S dan rt.c yang disertakan, dengan:

clang --no-default-config --target=riscv32-unknown-none-elf -march=rv32im -mabi=ilp32 -mno-relax
      -nostdlib -ffreestanding -fno-builtin -ffunction-sections -fdata-sections -Os
      -ffile-prefix-map=<checkout>=/rand-circuits -c

dan memautkannya dengan rust-lld -flavor gnu --gc-sections -T <ld> daripada toolchain Rust yang dipin. --gc-sections hanya mengekalkan apa yang dipanggil oleh guest.

Runtime C

-ffreestanding -fno-builtin menghalang clang daripada mengenali fungsi pustaka, tetapi tidak daripada menjana panggilan kepadanya. Salinan struct menjadi memcpy, penginisialan sifar yang besar menjadi memset, dan pembahagian 64-bit dengan nilai masa larian menjadi panggilan pembantu, kerana RV32IM hanya membahagi nilai 32-bit. rt.c mentakrifkan lapan fungsi ini:

fungsikegunaan
memcpy, memmove, memset, memcmpsalinan, pengisian, perbandingan
__udivdi3, __umoddi3, __divdi3, __moddi3/ dan % 64-bit

Fungsi-fungsi ini ialah gelung bait dan pembahagian tolak-anjak. Ia perlahan: dalam gelung yang kerap dijalankan, salin dan bahagi dalam perkataan (word) 32-bit.

Program yang ditulis tangan

Anda juga boleh menulis kod mesin sendiri: himpunkan (assemble), paut dengan skrip pemaut yang sama, dan pakej ELF tersebut. Program ini menambah dua input persendirian dan menerbitkan hasil tambahnya.

add.S:

# Reads private inputs 0 and 1, writes their sum to output slot 0, halts.
    .section .text._start
    .globl _start
_start:
    li   a7, 2          # READ_INPUT
    li   a0, 0
    ecall               # a0 = input 0
    mv   t0, a0
    li   a7, 2          # READ_INPUT
    li   a0, 1
    ecall               # a0 = input 1
    add  t1, t0, a0
    li   a7, 1          # WRITE_OUTPUT slot, word
    li   a0, 0
    mv   a1, t1
    ecall
    li   a7, 0          # HALT
    ecall

Tetapkan setiap nombor syscall dengan li a7, n terus sebelum ecallnya. Pemeriksa kemudian dapat mengesahkan nombor tersebut.

Himpunkan dengan clang yang dipin, paut dengan rust-lld dan guest-sdk/guest.ld, kemudian pakej. Jalankan dari dalam checkout circuits:

CLANG=/opt/homebrew/opt/llvm/bin/clang
LLD=$(rustc +1.98.1 --print sysroot)/lib/rustlib/$(rustc +1.98.1 -vV | sed -n 's/host: //p')/bin/rust-lld
$CLANG --no-default-config --target=riscv32-unknown-none-elf -march=rv32im -mabi=ilp32 -mno-relax -c add.S -o add.o
$LLD -flavor gnu -T guest-sdk/guest.ld add.o -o add.elf
$ rand-guest pack add.elf --out add.bin
wrote add.bin (80 bytes) and add.bin.sha256

$ rand-guest check add.bin
14 words against a cap of 4096 (fits); 0 ecall(s) with a non-static a7
OK

$ rand-guest run add.bin --input 40 --input 2
out[0] = 42
out[1] = 0
out[2] = 0
out[3] = 0
out[4] = 0
out[5] = 0
out[6] = 0
out[7] = 0
cycles 14
tier 10

$ rand-guest info add.bin
form: image container
text 14 words at 0x1000; data 0 words (0 non-zero) at 0x0; prologue 0 words; program 14 words from base_pc 0x1000
hc 42986ac1f93396d7de75f6757149523e7f1e9c5999d748af9b1915ada8ee14bd
program id 3b34c9d16adbd81a4849148675a914d10e5da0bd5b6aa64967e5f8a5fc75d941
14 words against a cap of 4096: fits

pack mengambil .text ELF sebagai segmen teks dan setiap seksyen PROGBITS lain yang diperuntukkan sebagai satu segmen data. .bss ditinggalkan, kerana RAM bermula pada sifar.

Memakej bekas secara manual

Bekas imej terdiri daripada enam perkataan pengepala dan kemudian perkataan-perkataan itu sendiri (The RISC-V ISA). Anda boleh menulisnya tanpa sebarang toolchain. Skrip Python ini menulis 80 bait yang sama seperti yang ditulis oleh pack di atas:

import struct

text = [
    0x00200893,  # li   a7, 2      READ_INPUT
    0x00000513,  # li   a0, 0
    0x00000073,  # ecall           a0 = input 0
    0x00050293,  # mv   t0, a0
    0x00200893,  # li   a7, 2      READ_INPUT
    0x00100513,  # li   a0, 1
    0x00000073,  # ecall           a0 = input 1
    0x00a28333,  # add  t1, t0, a0
    0x00100893,  # li   a7, 1      WRITE_OUTPUT
    0x00000513,  # li   a0, 0      slot 0
    0x00030593,  # mv   a1, t1     word
    0x00000073,  # ecall
    0x00000893,  # li   a7, 0      HALT
    0x00000073,  # ecall
]
#          magic ("RAND")  version  text_base  n_text     data_base  n_data
header = [0x444E4152,      1,       0x1000,    len(text), 0,         0]
with open("add-hand.bin", "wb") as f:
    f.write(struct.pack(f"<{len(header) + len(text)}I", *header, *text))

rand-guest info add-hand.bin mencetak hc 42986ac1…14bd yang sama, dan cmp add-hand.bin add.bin tidak menemui sebarang perbezaan. Sentiasa jalankan rand-guest check pada imej yang dipakej secara manual: nod menolak mana-mana perkataan yang tidak dapat dinyahkod, tetapi hanya pada masa deploy.

Dompet juga menggunakan dua bentuk lama: fail .json { "base_pc", "words" }, dan .bin mentah yang mengandungi perkataan little-endian yang dimuatkan pada pangkalan 0. Bekas ialah satu-satunya bentuk yang mempunyai segmen data.

Deploy dan panggil

Setiap laluan di atas berakhir dengan cara yang sama. Dengan dompet rand daripada fullnode v0.3 atau lebih baharu (pada rantaian 20, rantaian yang sedang aktif, v0.6.8 atau lebih baharu: dompet v0.6.7 tidak dapat menghantar di sana, kerana rantaian 20 mengikat setiap bukti dan tandatangan kepada hash genesisnya; lihat Deploy a Rust program):

rand program deploy add.bin
rand call <program id> --input 40 --input 2

Yuran deploy ialah 0.001 RAND + 0.0001 RAND × words: 0.0024 RAND bagi 14 perkataan add.bin dan 0.0035 RAND bagi 25 perkataan c-fib.bin. Kedua-duanya di bawah 4,096 perkataan, jadi muat dalam had mana-mana rantaian: lalai 4,096 dan 65,535 bagi rantaian 20. Panggilan itu dibuktikan secara setempat pada tier 10. Pada rantaian 15 kosnya 0.002 RAND. Pada rantaian 20 yuran tidak lagi 0.001 + call_fee(tier): lantainya ialah BUNDLE_BASE + gas_price × declared gas limit + byte_price × ⌈bytes / 1024⌉, rand call mencetak gas: <exact> (declaring <limit>, tier <t>) dan yuran sebelum membuktikan, dan empat panggilan yang diukur pada rantaian 18 masing-masing berharga 0.0057 hingga 0.0075 RAND (Example programs). Setiap deploy dan panggilan pada rantaian 20 juga membawa dua bukti sisi bundle, pengesahan perbelanjaan tier 10 dan bundle tier 14. Deploy a Rust program menerangkan fungsi setiap arahan.

Supaya orang lain dapat menyemak apa yang anda deploy, terbitkan kod sumber dan commit circuits anda (aeacf31 bagi rantaian 18 hingga 20). Dengan clang 23.1.1 dan Rust 1.98.1, rand-guest build menghasilkan hc yang sama pada mana-mana mesin.

Disahkan kali terakhir terhadap commit fullnode c0878c3f (rantai 21) pada 2026-10-12, dan circuits `7ef3220` (`rand-guest/README.md`, `guests-compiled/c-fib`, `guest-sdk/guest.ld`); every `rand-guest` output on this page was produced on 2026-09-19, circuits `aeacf31` (`rand-guest/guest.h`, `rand-guest/src/check.rs`; `git diff 7ef3220 aeacf31 -- guest-sdk rand-guest`), read on 2026-09-30; no output on this page was re-run at that commit, fullnode tag v0.6.8 `c9c9bd3c` (`docs/deploy.md` on `binding_domain`, `.github/workflows/ci.yml` circuits pin) and `rand_getLimits` on chain 20, read on 2026-10-01; nothing on this page was deployed or called on chain 20, fullnode tag v0.8.0 `c0878c3f` (`CHANGELOG.md`, `docs/zkvm.md` §8a) and `rand_getLimits` on chain 21, read on 2026-10-12; nothing on this page was deployed or called on chain 21. Jika kod dan halaman ini tidak selari, kodlah yang betul; sila maklumkan kepada kami.