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
| alat | versi | cara |
|---|---|---|
| clang | 23.1.1, dengan hujung belakang (backend) RISC-V | brew install llvm pada macOS; clang sistem Apple tidak mempunyai backend RISC-V. Atau tetapkan $CLANG kepada binari 23.1.1 |
rust-lld | daripada Rust 1.98.1 | rustup +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:
| fungsi | kegunaan |
|---|---|
memcpy, memmove, memset, memcmp | salinan, 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.