Rand Protocol
Dokumentasi
Program RISC-V

Men-deploy program RISC-V

Dua jalur menuju image yang dapat di-deploy tanpa Rust - program C yang dibangun oleh rand-guest dengan clang yang telah dipin, dan program yang ditulis tangan lalu di-assemble dan dikemas, atau dikemas ke dalam kontainer image byte demi byte.

Program apa pun yang berupa kode mesin RV32IM dapat di-deploy, apa pun alat yang menghasilkannya. Halaman ini menunjukkan dua jalur: C melalui rand-guest build --lang c, dan program yang Anda tulis dalam assembly lalu Anda kemas sendiri. Keduanya berakhir pada kontainer image yang sama dengan yang dihasilkan Deploy a Rust program, dan keduanya di-deploy dengan rand program deploy. Siapkan terlebih dahulu checkout circuits dan rand-guest, seperti pada langkah 1 halaman tersebut. Untuk chain 18 hingga 20, checkout berada pada commit aeacf31, yang di-pin oleh fullnode v0.6.7 maupun v0.6.8. Keluaran di bawah ini dihasilkan pada 2026-09-19 pada 7ef3220 dan belum dijalankan ulang. Direktori rand-guest, termasuk guest.h dan rt.c, sama pada kedua commit tersebut.

C via clang

Yang Anda perlukan

alatversicara
clang23.1.1, dengan backend RISC-Vbrew install llvm di macOS; clang bawaan sistem Apple tidak memiliki backend RISC-V. Atau atur $CLANG ke biner 23.1.1
rust-llddari Rust 1.98.1rustup +1.98.1 component add llvm-tools

rand-guest menolak clang mana pun yang versinya bukan 23.1.1. RAND_GUEST_CLANG_UNPINNED=1 membangun dengan versi lain, disertai peringatan bahwa hc tidak akan cocok dengan image yang dipublikasikan.

Direktori guest C hanya berisi berkas .c (dan .ld opsional). rand-guest menyediakan guest.h, _start, dan runtime kecil. Jangan menambahkan guest.h atau start.S sendiri: build --lang c menolak direktori yang memiliki salah satunya.

Berikut 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 mendeklarasikan rand_read_input, rand_read_public, rand_write_output, rand_poseidon2, rand_keccak, rand_sha256_compress, dan rand_halt. Header ini tidak memiliki pembungkus untuk syscall 7, yaitu POSEIDON2_LEN dengan batas panjang yang dijalankan mesin sejak constraint set 7, dan rand-guest check pada aeacf31 menolak ecall dengan a7 = 7 (zkp-circuits issue #1). Guest C atau assembly untuk chain 20 karena itu menggunakan syscall 0 hingga 6.

Build, 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, jawaban yang sama dengan guest Rust fib.

build --lang c mengompilasi setiap berkas .c dalam direktori (berurutan), ditambah start.S dan rt.c bawaan, 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

lalu menautkannya dengan rust-lld -flavor gnu --gc-sections -T <ld> dari toolchain Rust yang di-pin. --gc-sections hanya mempertahankan apa yang dipanggil guest.

Runtime C

-ffreestanding -fno-builtin mencegah clang mengenali fungsi pustaka, tetapi tidak mencegahnya menghasilkan panggilan ke fungsi tersebut. Penyalinan struct menjadi memcpy, inisialisasi nol yang besar menjadi memset, dan pembagian 64-bit dengan nilai saat run-time menjadi panggilan helper, karena RV32IM hanya membagi nilai 32-bit. rt.c mendefinisikan delapan fungsi berikut:

fungsikegunaan
memcpy, memmove, memset, memcmpmenyalin, mengisi, membandingkan
__udivdi3, __umoddi3, __divdi3, __moddi3/ dan % 64-bit

Fungsi-fungsi ini berupa perulangan per byte dan pembagian shift-subtract. Kinerjanya lambat: dalam perulangan yang sering dijalankan, salin dan bagi dalam word 32-bit.

Program yang ditulis tangan

Anda juga dapat menulis kode mesin sendiri: rakit, tautkan dengan linker script yang sama, lalu kemas ELF-nya. Program ini menjumlahkan dua input privat dan mempublikasikan hasilnya.

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 nomor syscall dengan li a7, n tepat sebelum ecall-nya. Dengan begitu, checker dapat memverifikasi nomornya.

Rakit dengan clang yang di-pin, tautkan dengan rust-lld dan guest-sdk/guest.ld, lalu kemas. 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 section PROGBITS teralokasi lainnya sebagai satu segmen data. .bss tidak disertakan, karena RAM dimulai dari nol.

Mengemas kontainer secara manual

Kontainer image terdiri dari enam word header, lalu word-word itu sendiri (The RISC-V ISA). Anda dapat menulisnya tanpa toolchain apa pun. Skrip Python ini menulis 80 byte yang sama dengan yang ditulis 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 menemukan perbedaan. Selalu jalankan rand-guest check pada image yang dikemas manual: node menolak setiap word yang tidak dapat didekode, tetapi hanya pada saat deploy.

Wallet juga men-deploy dua bentuk yang lebih lama: berkas .json { "base_pc", "words" }, dan .bin mentah berisi word little-endian yang dimuat pada basis 0. Kontainer adalah satu-satunya bentuk yang memiliki segmen data.

Deploy dan panggil

Setiap jalur di atas berakhir dengan cara yang sama. Dengan wallet rand dari fullnode v0.3 atau lebih baru (pada chain 20, chain yang aktif, v0.6.8 atau lebih baru: wallet v0.6.7 tidak dapat mengirim di sana, karena chain 20 mengikat setiap proof dan tanda tangan pada genesis hash-nya; lihat Deploy a Rust program):

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

Biaya deploy adalah 0.001 RAND + 0.0001 RAND × words: 0,0024 RAND untuk 14 word add.bin dan 0,0035 RAND untuk 25 word c-fib.bin. Keduanya di bawah 4.096 word, sehingga muat dalam batas chain mana pun: bawaan 4.096 dan 65.535 pada chain 20. Panggilan di-prove secara lokal pada tier 10. Pada chain 15 biayanya 0,002 RAND. Pada chain 20 biayanya tidak lagi 0.001 + call_fee(tier): batas bawahnya adalah BUNDLE_BASE + gas_price × declared gas limit + byte_price × ⌈bytes / 1024⌉, rand call mencetak gas: <exact> (declaring <limit>, tier <t>) dan biayanya sebelum melakukan proving, dan empat panggilan yang diukur pada chain 18 masing-masing berbiaya 0,0057 hingga 0,0075 RAND (Example programs). Setiap deploy dan panggilan pada chain 20 juga membawa dua proof sisi bundle, otorisasi pengeluaran tier 10 dan bundle tier 14. Deploy a Rust program menjelaskan apa yang dilakukan setiap perintah.

Agar pihak lain dapat memeriksa apa yang Anda deploy, publikasikan source dan commit circuits Anda (aeacf31 untuk chain 18 hingga 20). Dengan clang 23.1.1 dan Rust 1.98.1, rand-guest build menghasilkan hc yang sama pada mesin mana pun.

Terakhir diverifikasi terhadap commit fullnode c0878c3f (chain 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 kode dan halaman ini tidak sesuai, kodelah yang benar; beri tahu kami.