Baca halaman ini sebelum Anda menulis program untuk Rand. Halaman ini menjelaskan mesin tempat kode Anda berjalan, apa yang ditolak oleh toolchain, bagaimana program berkomunikasi dengan dunia luar, dan berkas apa yang Anda deploy. Halaman berikutnya memakainya: Deploy program Rust, Deploy program RISC-V, dan kedua transpiler.
Mesin
Program Rand berformat RV32IM: set bilangan bulat dasar RISC-V 32-bit ditambah ekstensi perkalian dan pembagian. Program berjalan di dalam zkVM Rand, yang membuktikan setiap eksekusi dengan batch STARK Plonky3. Verifier tidak pernah melihat satu pun instruksi. Verifier memeriksa bukti terhadap hc, digest Poseidon2 dalam sirkuit dari program tersebut.
| kelompok | instruksi |
|---|---|
| upper / jumps | LUI AUIPC JAL JALR |
| branches | BEQ BNE BLT BGE BLTU BGEU |
| loads / stores | LW SW LB LH LBU LHU SB SH |
| ALU | ADDI SLTI SLTIU XORI ORI ANDI SLLI SRLI SRAI ADD SUB SLL SLT SLTU XOR SRL SRA OR AND |
| RV32M | MUL MULH MULHU MULHSU DIV DIVU REM REMU |
| sistem | hanya ECALL |
JALR mengosongkan bit 0 dari targetnya, sebagaimana ditetapkan RV32I, dan encoding-nya harus memiliki funct3 = 0. Kedua aturan ini hadir bersama constraint set 7 (chain 16); sebelumnya target ganjil tidak dapat di-fetch dan eksekusinya tidak dapat dibuktikan. Target yang genap tetapi bukan kelipatan empat tetap tidak dapat di-fetch.
Tidak ada floating point, tidak ada atomics (ekstensi A), tidak ada instruksi terkompresi (ekstensi C), dan tidak ada register 64-bit. Pembagian 64-bit dalam C menjadi pemanggilan ke helper perangkat lunak; lihat jalur C.
Apa yang ditolak
rand-guest check menjalankan setiap word teks melalui decoder milik mesin itu sendiri. Program yang lolos tidak dapat gagal di dalam sirkuit karena alasan encoding, nomor syscall, atau tata letak. Pemeriksa menolak:
| temuan | arti |
|---|---|
Compressed | encoding RVC 16-bit; mesin hanya men-decode word 32-bit |
Undecodable | opcode, funct, atau jumlah pergeseran yang tidak diimplementasikan oleh mesin |
Fence | FENCE atau FENCE.I; mesin tidak memiliki pengurutan memori |
Csr | instruksi CSR apa pun; mesin tidak memiliki CSR |
Ebreak | EBREAK; trap tidak dimodelkan |
Syscall | sebuah ecall yang a7-nya diatur oleh li tepat sebelumnya dan tidak menunjuk syscall mana pun |
Cap | jumlah word melebihi --max-words, dihitung sebagaimana loader menghitungnya |
Layout | basis teks yang tidak rata pada batas word |
Program empat word dengan fence, ebreak, dan ecall bernomor 9, sebagaimana dilaporkan oleh rand-guest check (kode keluar 1):
$ rand-guest check bad.elf
note: the loader refuses this image (Decode { index: 0, word: 267386895, err: Opcode(15) }), so its data prologue could not be counted; the word count below is the text alone
0x00001000 0x0ff0000f Fence: FENCE/FENCE.I: the machine has no memory ordering instructions
0x00001004 0x00100073 Ebreak: EBREAK: traps are not modelled
0x0000100c 0x00000073 Syscall: ecall with a7 = 9, which is no syscall the machine implements
4 words against a cap of 4096 (fits); 0 ecall(s) with a non-static a7
REJECTED
Sebuah ecall yang a7-nya tidak dapat dilihat pemeriksa (diatur oleh selain li, atau setelah sebuah branch) dihitung sebagai unresolved_ecalls, bukan ditolak. Mesin tetap melakukan trap pada nomor yang salah saat run time.
Pemeriksa tidak memeriksa nilai pointer, panjang, atau indeks input, stack 64 KiB terhadap RAM, maupun perataan alamat yang dihitung saat run time. Akses yang tidak rata merupakan pelanggaran constraint, sehingga toolchain dikompilasi dengan -unaligned-scalar-mem. rand-guest run melaporkan setiap trap saat run time.
Syscall
ECALL membaca nomor syscall dari a7, argumen pertama dari a0, dan argumen kedua dari a1. Sebuah nilai dikembalikan di a0.
| # | syscall | efek | gas | Rust (guest-sdk) | C (guest.h) |
|---|---|---|---|---|---|
| 0 | HALT | mengakhiri eksekusi | 1 | halt() | rand_halt() |
| 1 | WRITE_OUTPUT slot word | menetapkan output publik slot < 8, paling banyak sekali per slot; slot yang belum ditulis bernilai nol | 1 | write_output(slot, word) | rand_write_output |
| 2 | READ_INPUT idx | mengembalikan word input privat idx, terikat pada komitmen bergaram H_IN | 1 | read_input(idx) | rand_read_input |
| 3 | POSEIDON2 ptr n | meng-hash n ≤ 4096 word pada alamat word ptr dan menulis digest 8 word di atas ptr..ptr+8; tanpa padding | 3 + 3·⌈n/4⌉ | unsafe poseidon2(ptr, n) | rand_poseidon2 |
| 4 | KECCAK ptr | satu permutasi Keccak-f[1600] di tempat pada 50 word | 192 | keccak(state), keccak256(msg) | rand_keccak |
| 5 | SHA256 ptr | satu kompresi SHA-256 di tempat pada 24 word | 64 | sha256_compress(buf), sha256(msg) | rand_sha256_compress |
| 6 | READ_PUBLIC idx | mengembalikan word segmen publik idx, terikat pada H_PUB tanpa garam | 1 | read_public(idx) | rand_read_public |
| 7 | POSEIDON2_LEN ptr n | POSEIDON2 dengan panjang n terikat ke dalam sponge, minimal satu permutasi (constraint set 7) | 3 + 3·max(⌈n/4⌉, 1) | poseidon2_len(buf, n) | tidak ada |
Setiap instruksi lainnya berbiaya 1 gas: gas dihitung satu per baris cpu, dan hanya syscall hash yang berbobot lebih (constraint set 8, sejak chain 18). Satu pemanggilan Poseidon2 terdiri dari baris ecall-nya, dua baris write-back, dan ⌈n/4⌉ baris absorb dengan 3 gas masing-masing.
POSEIDON2 tidak melakukan padding. Sponge menimpa lane pertamanya dengan setiap potongan empat word, sehingga [a], [a, 0], [a, 0, 0], dan [a, 0, 0, 0] menghasilkan satu digest yang sama. Program yang meng-hash data dengan panjang yang dapat bervariasi harus menyertakan panjang di dalam pesan, meng-hash encoding dengan panjang tetap, atau memanggil POSEIDON2_LEN, yang menanamkan n ke dalam kapasitas sponge dan menghasilkan digest yang berbeda untuk word yang sama. Di Rust SDK, poseidon2 adalah unsafe fn atas raw pointer dan poseidon2_len adalah pemanggilan aman atas slice; keccak dan sha256_compress menerima &mut [u32; 50] dan &mut [u32; 24].
Satu celah toolchain. Pada circuits aeacf31, mesin, emulator, dan Rust SDK mengimplementasikan syscall 7, tetapi rand-guest check tidak: daftar syscall-nya berhenti di 6, sehingga ia melaporkan ecall dengan a7 = 7 sebagai temuan Syscall dan rand-guest build keluar dengan kode bukan nol pada guest yang memanggil poseidon2_len (circuits issue #1). guest.h juga tidak memiliki wrapper untuknya. Sampai hal ini diperbaiki, guest yang dibangun dengan tool bawaan memakai POSEIDON2 pada pesan dengan panjang tetap.
Sebuah bukti mempublikasikan persis ini: hc, H_IN, H_PUB, tier, batas gas yang dideklarasikan, dan delapan word output. Dua batasan berlaku di chain saat ini:
- Segmen publik ditetapkan saat deploy. Di chain 20,
rand program deploy --publicmenetapkan word publik sebuah program (paling banyakmax_program_public_words, 32.768), dan setiap pemanggilan diperiksa terhadapnya. Tidak ada word publik per pemanggilan milik program itu sendiri. Chain 20, seperti chain 19, menambahkan delapan word ke segmen setiap pemanggilan setelah word tersebut, yaitu call binding yang mengikat bukti pada transaksinya (di chain 20 ia juga mencakup genesis hash); guest membaca word miliknya sendiri pada indeks yang sama seperti sebelumnya.InvokeRPL-2 menambahkan transisi yang dideklarasikan setelah binding, yang dibaca program mulai daripublic_len + 8(Program). Pada chain tanpa field batas, seperti chain 12, segmen publik kosong danREAD_PUBLICtidak memiliki apa pun untuk dibaca. - Word input privat sebuah pemanggilan dibatasi oleh sealed envelope.
max_call_envelope_byteschain 20 sebesar 65.536 memungkinkan 16.071 word; chain tanpa field tersebut memungkinkan 4.295.
Pemanggilan KECCAK atau SHA256 menambahkan sebuah tabel ke bukti, dan header bukti kemudian menunjukkan bahwa pemanggilan tersebut melakukan hash. Bukti yang membawa keccak berukuran sekitar 3,3 MB: melebihi batas bukti bawaan 2 MiB, di bawah 4 MiB milik chain 20, dan satu pemanggilan boleh memakai paling banyak 128 permutasi Keccak-f dan 128 kompresi SHA-256 (Program).
Memori
- 32 register;
x0bernilai nol. - RAM dimulai dari nol. Setiap alamat berada di bawah
2³⁰. - Skrip linker bawaan,
guest-sdk/guest.ld, menempatkan program pada0x1000, lalu.rodata,.data, dan.bss, kemudian stack 64 KiB pada__stack_top. - Program dengan segmen data memerlukan ruang di bawah teksnya untuk prolog loader (bagian berikutnya). Berkas
.ld-nya sendiri menaikkanORIGINke0x10000, seperti yang dilakukanevm.lddansbpf.ld.
Kontainer image
rand-guest build dan rand-guest pack menulis satu format berkas, yaitu kontainer image. Semua angka berupa word 32-bit little-endian:
[0x444e4152 ("RAND"), 1, text_base, n_text, data_base, n_data] text… data…
Loader mengubah kontainer menjadi program { base_pc, words }:
- Loader menulis pasangan
li/swuntuk setiap word data yang bukan nol. Word nol dilewati, karena RAM sudah terbaca nol. - Loader menempatkan prolog itu tepat di bawah
text_base, sehinggabase_pc = text_base − 4 × prologue words. Prolog berlanjut langsung ke_startmilik program itu sendiri. hcdan id program dihitung atas seluruhwords, termasuk prolog. Jadihcmengikat data sekaligus kode.
Kontainer tanpa data tidak menghasilkan prolog, serta program dan hc yang sama dengan biner datar tanpa header pada basis yang sama.
rand program deploy di fullnode v0.3 dan yang lebih baru mengenali kontainer dari word pertamanya. 0x444e4152 tidak pernah ter-decode sebagai instruksi, sehingga .bin mentah tidak mungkin tertukar dengan kontainer. Berkas yang diawali magic tetapi cacat merupakan kesalahan, bukan fallback.
Dua identitas
| nama | apa itu | siapa yang memakainya |
|---|---|---|
hc | digest Poseidon2 sirkuit atas (base_pc, len, words) | setiap bukti dari sebuah panggilan diverifikasi terhadapnya; rand_getProgram menampilkannya sebagai code_hash |
| program id | blake3("rand-program" ‖ base_pc ‖ words); deploy dengan --public turut mengikat public words, di bawah tag rand-program-2 | kunci tempat program yang telah di-deploy disimpan dan dipanggil |
rand-guest build dan rand-guest info mencetak keduanya. hc bersifat mengikat tetapi tidak menyembunyikan: siapa pun yang memiliki program kandidat dapat mengonfirmasinya.
Batas program
Sebuah deploy boleh memuat paling banyak sejumlah batas program milik rantai tersebut, dalam satuan word.
| rantai | batas |
|---|---|
genesis tanpa max_program_words (rantai 12) | 4,096 |
genesis dengan max_program_words | nilai tersebut, 1..=65535 |
| batas keras zkVM, pada rantai mana pun | 65,535 |
Batas ini merupakan bagian dari hash genesis, sehingga tidak dapat diubah pada rantai yang sedang berjalan. rand-guest memeriksa terhadap --max-words (bawaan 4,096). rand program deploy menanyakannya kepada node melalui rand_estimateFee dan menolak program yang melebihi batas sebelum membuktikan apa pun.
Rantai 20, rantai yang sedang aktif, menaikkan batas tersebut. Hash genesis-nya adalah 6210cf071a390d7ac61d8cbea5dd9d139d1a493a862b54a45a498f36af2d5135 dan max_program_words-nya 65,535. Rantai ini mempertahankan batasan yang diperkenalkan rantai 13 (rantai v0.4), kecuali batas bukti, yang dipangkas setengah oleh rantai 17 hingga 20. Batasan lainnya:
| batasan | rantai 20 |
|---|---|
max_proof_bytes | 4,194,304 (4 MiB); 8 MiB pada rantai 13 hingga 16 |
max_block_bytes | 20,971,520 (20 MiB) |
max_call_envelope_bytes | 65,536 |
max_program_public_words | 32,768 |
Pada rantai 20, seperti pada rantai 19, batas word bukanlah batasan yang mengikat. Genesis-nya menetapkan hardening_v6, yang menyebabkan sebuah deploy ditolak (ProgramUncallable) bila tidak ada panggilan yang mampu membuktikan program tersebut. Sebuah panggilan dibatasi pada tingkat 14, yang tabel Poseidon2-nya memuat 2,048 permutasi. Digest program memakai satu permutasi per empat word, baris salt masukan satu, dan delapan word pengikat panggilan dua, sehingga tersisa 2,045: 8,180 word untuk program tanpa masukan publik, dan lebih sedikit bila ada masukan publik (8,168 dengan sembilan public words). Pool setiap node menolak deploy semacam itu pada rantai mana pun.
Agregasi blok dimatikan pada rantai 20: genesis-nya tidak memiliki bagian aggregation. Rantai 20 aktif sejak 2026-10-01 06:17 UTC pada fullnode v0.6.8, sebuah hard fork yang dipotong dari state rantai 19 pada ketinggian 7,258 (rantai 19 berhenti pada 7,700); rantai 19 (aktif sejak 03:43 UTC pada hari yang sama) sendiri merupakan re-genesis dari rantai 18 pada ketinggian 141,935. Program tidak terbawa melewati pemotongan, sehingga tidak ada program yang di-deploy pada rantai sebelumnya yang ada di rantai 20. Rantai 20 juga merupakan rantai pertama dengan state program RPL-2 (Program). Rantai ini berjalan di jaringan melalui node bootstrap berikut:
/ip4/164.90.239.200/tcp/30303/p2p/12D3KooWEQEbUwZRgqhDPXhW7vNBmcRcnhUDGUADe81VFdv3ALYe
/ip4/165.245.173.74/tcp/30303/p2p/12D3KooWJyc5oDHggAr89e9QrRFBy9Tg8TxXh18yzrb1SM6KKLYw
/ip4/188.166.235.187/tcp/30303/p2p/12D3KooWSyX84P1DAbWByLHpRBMLRWD53r3Jj4aqVt6tHoF8B2ZQ
| image | word | muat dalam 4,096 | muat dalam 65,535 | di-deploy pada rantai 20 (8,180 dapat dipanggil) |
|---|---|---|---|---|
fib (Rust) | 26 | ya | ya | ya |
c-fib (C) | 25 | ya | ya | ya |
| ERC-20, diterjemahkan (tahap dua) | 11,686 | tidak | ya | tidak |
evm.bin, interpreter EVM | 18,009 | tidak | ya | tidak |
sbpf.bin, interpreter sBPF | 8,317 | tidak | ya | tidak |
| SPL Token, diterjemahkan | 65,096 | tidak | ya, dengan sisa 439 | tidak |
Tingkat
Tingkat t sebuah bukti membatasi eksekusi pada 2ᵗ − 1 baris: siklus ditambah baris digest (satu per empat program word, satu per empat input word, dan digest masukan publik). Tingkat juga menetapkan anggaran Poseidon2 yang terpisah. rand-guest run --tier t melaporkan keduanya:
tier 10: fits (cycles 146 of 1023, Poseidon2 permutations 10 of 128)
Tingkat bersifat publik, demikian pula batas gas yang dideklarasikan bukti. Pada rantai 20, biaya panggilan mengikuti batas tersebut dan ukuran bukti, bukan tingkat: setidaknya 0.001 RAND + gas_price × gas_limit + byte_price × ⌈bytes / 1024⌉, pada harga rantai saat ini, yang bermula pada 100 dan 800 unit 10⁻⁹ RAND, bergerak mengikuti keterisian blok, dan pada rantai 20 berhenti pada 10,000 dan 80,000 unit (Biaya). Sebuah batas tidak boleh melebihi plafon header, (2ᵗ − 1) + 2ᵗ⁻² ditambah 191 per blok Keccak dan 63 per blok SHA-256 yang dideklarasikan bukti: 1,279 pada tingkat 10 dan 20,479 pada tingkat 14 tanpa tabel hash. rand-guest run melaporkan siklus dan permutasi, bukan gas. rand call menjalankan program terlebih dahulu dan mencetak gas yang dipakainya serta batas yang dideklarasikannya, secara bawaan gas yang tepat dibulatkan ke atas ke kelipatan 2ᵗ⁻² berikutnya, sebelum membuktikan:
gas: 5636 (declaring 6144, tier 12)
Baris tersebut berasal dari sebuah panggilan pada rantai 18 pada 2026-09-30 (Pemungutan suara anonim). Pada rantai tanpa bagian gas dalam genesis, yakni rantai 15 dan sebelumnya, biayanya merupakan jadwal bertingkat: 0.001 + (0.001 + 0.0001 × (t − 10) / 2) RAND. Memori yang dibutuhkan sebuah bukti naik tajam seiring tingkat; lihat Perangkat keras validator dan aggregator.
Sejak fullnode v0.5.6 (2026-09-25), sebuah panggilan boleh mendeklarasikan paling tinggi tingkat 14: node menolak bukti panggilan bertingkat lebih tinggi dengan CallTierTooHigh sebelum membangun verifier key, dan blok yang memuatnya tidak valid. Anggaran tingkat 14 adalah 16,383 baris dan 2,048 permutasi Poseidon2, dan digest program itu sendiri menghabiskan sekitar satu permutasi per empat word, sehingga program di atas 8,180 word tidak dapat dipanggil, dan rantai 20, seperti rantai 19, menolak deploy-nya. Menulis program dalam Rust atau C menguraikan anggaran tersebut.