RV32IM இயந்திரக் குறியீடாக உள்ள எந்த நிரலையும், அதை எது உருவாக்கியிருந்தாலும், வரிசைப்படுத்தலாம். இந்தப் பக்கம் இரண்டு வழிகளைக் காட்டுகிறது: rand-guest build --lang c வழியாக C, மற்றும் நீங்களே assembly-யில் எழுதித் தாமே பொதியாக்கும் ஒரு நிரல். இரண்டும் Rust நிரலை வரிசைப்படுத்துதல் உருவாக்கும் அதே image container-இல் முடிகின்றன, இரண்டும் rand program deploy மூலம் வரிசைப்படுத்தப்படுகின்றன. முதலில், அந்தப் பக்கத்தின் படி 1-இல் உள்ளபடி, circuits checkout-ஐயும் rand-guest-ஐயும் அமைக்கவும். சங்கிலிகள் 18 முதல் 20 வரை checkout aeacf31 commit-இல் இருக்கும்; fullnode v0.6.7, v0.6.8 இரண்டும் இதையே நிலைப்படுத்துகின்றன. கீழே உள்ள வெளியீடுகள் 2026-09-19 அன்று 7ef3220-இல் உருவாக்கப்பட்டவை, அவை மீண்டும் இயக்கப்படவில்லை. guest.h, rt.c உட்பட rand-guest கோப்பகம் இரு commit-களிலும் ஒன்றே.
clang வழியாக C
உங்களுக்குத் தேவையானவை
| கருவி | பதிப்பு | எப்படி |
|---|---|---|
| clang | 23.1.1, RISC-V பின்தளத்துடன் | macOS-இல் brew install llvm; Apple-இன் கணினி clang-இல் RISC-V பின்தளம் இல்லை. அல்லது $CLANG-ஐ ஒரு 23.1.1 இருமக் கோப்புக்கு அமைக்கவும் |
rust-lld | Rust 1.98.1-இலிருந்து | rustup +1.98.1 component add llvm-tools |
பதிப்பு 23.1.1 அல்லாத எந்த clang-ஐயும் rand-guest மறுக்கிறது. RAND_GUEST_CLANG_UNPINNED=1 வேறொரு பதிப்பைக் கொண்டு கட்டமைக்கிறது; அப்போது hc வெளியிடப்பட்ட image-களுடன் பொருந்தாது என்ற எச்சரிக்கை வரும்.
guest-ஐ எழுதுதல்
ஒரு C guest கோப்பகத்தில் .c கோப்புகள் மட்டுமே இருக்கும் (விருப்பத்தேர்வாக ஒரு .ld-உம்). guest.h, _start, ஒரு சிறிய runtime ஆகியவற்றை rand-guest வழங்குகிறது. உங்கள் சொந்த guest.h அல்லது start.S-ஐச் சேர்க்க வேண்டாம்: இவற்றில் எதையேனும் கொண்ட கோப்பகத்தை build --lang c மறுக்கிறது.
commit செய்யப்பட்ட guests-compiled/c-fib/fib.c இதுதான்:
#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 rand_read_input, rand_read_public, rand_write_output, rand_poseidon2, rand_keccak, rand_sha256_compress, rand_halt ஆகியவற்றை அறிவிக்கிறது. constraint set 7 முதல் இயந்திரம் இயக்கிவரும் நீள வரம்புடைய POSEIDON2_LEN ஆன syscall 7-க்கு அதில் wrapper இல்லை; மேலும் aeacf31-இல் உள்ள rand-guest check, a7 = 7 கொண்ட ecall-ஐ மறுக்கிறது (zkp-circuits issue #1). ஆகவே சங்கிலி 20-க்கான C அல்லது assembly guest, syscall 0 முதல் 6 வரை மட்டுமே பயன்படுத்துகிறது.
கட்டமைத்தல், இயக்குதல், ஆய்தல்
$ 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, Rust fib guest தரும் அதே விடை.
build --lang c கோப்பகத்தில் உள்ள ஒவ்வொரு .c கோப்பையும் (வரிசைப்படுத்திய ஒழுங்கில்), உடன் இணைக்கப்பட்ட start.S, rt.c ஆகியவற்றுடன், பின்வருவதைக் கொண்டு தொகுக்கிறது:
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
பின்னர் நிலைப்படுத்தப்பட்ட Rust toolchain-இலிருந்து rust-lld -flavor gnu --gc-sections -T <ld> மூலம் அவற்றை இணைக்கிறது. guest அழைப்பவற்றை மட்டுமே --gc-sections வைத்துக்கொள்கிறது.
C runtime
-ffreestanding -fno-builtin நூலகச் செயல்பாடுகளை clang அடையாளம் காண்பதைத் தடுக்கின்றன, ஆனால் அவற்றுக்கான அழைப்புகளை அது உருவாக்குவதைத் தடுப்பதில்லை. ஒரு struct நகல் memcpy ஆகிறது, ஒரு பெரிய பூஜ்ய initialiser memset ஆகிறது, இயக்க நேர மதிப்பால் செய்யப்படும் 64-பிட் வகுத்தல் ஒரு helper அழைப்பாகிறது, ஏனெனில் RV32IM 32-பிட் மதிப்புகளை மட்டுமே வகுக்கிறது. rt.c இந்த எட்டையும் வரையறுக்கிறது:
| செயல்பாடு | பயன்பாடு |
|---|---|
memcpy, memmove, memset, memcmp | நகலெடுத்தல், நிரப்புதல், ஒப்பிடுதல் |
__udivdi3, __umoddi3, __divdi3, __moddi3 | 64-பிட் /, % |
இவை பைட் மடக்குகளும் shift-subtract வகுத்தலும் ஆகும். இவை மெதுவானவை: அடிக்கடி இயங்கும் மடக்கில், 32-பிட் சொற்களாக நகலெடுத்து வகுக்கவும்.
கையால் எழுதப்பட்ட நிரல்
இயந்திரக் குறியீட்டை நீங்களே எழுதலாம்: அதை assemble செய்து, அதே linker script கொண்டு இணைத்து, ELF-ஐப் பொதியாக்கவும். இந்த நிரல் இரண்டு தனிப்பட்ட உள்ளீடுகளைக் கூட்டி, கூட்டுத்தொகையை வெளியிடுகிறது.
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
ஒவ்வொரு syscall எண்ணையும் அதன் ecall-க்கு நேர் முன்பாக ஒரு li a7, n மூலம் அமைக்கவும். அப்போது checker அந்த எண்ணைச் சரிபார்க்க முடியும்.
நிலைப்படுத்தப்பட்ட clang கொண்டு assemble செய்து, rust-lld, guest-sdk/guest.ld கொண்டு இணைத்து, பின்னர் பொதியாக்கவும். circuits checkout-இன் உள்ளிருந்து இயக்கவும்:
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 ELF-இன் .text-ஐ text segment ஆகவும், ஒதுக்கப்பட்ட மற்ற ஒவ்வொரு PROGBITS பிரிவையும் ஒரே data segment ஆகவும் எடுத்துக்கொள்கிறது. RAM பூஜ்யத்திலிருந்து தொடங்குவதால் .bss விடப்படுகிறது.
container-ஐக் கையால் பொதியாக்குதல்
image container என்பது ஆறு header சொற்களும் அவற்றைத் தொடரும் சொற்களும் ஆகும் (RISC-V ISA). எந்த toolchain-உம் இல்லாமல் ஒன்றை எழுதலாம். மேலே pack எழுதிய அதே 80 பைட்டுகளை இந்த Python script எழுதுகிறது:
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 அதே hc 42986ac1…14bd-ஐ அச்சிடுகிறது, cmp add-hand.bin add.bin எந்த வேறுபாட்டையும் காணவில்லை. கையால் பொதியாக்கிய image மீது எப்போதும் rand-guest check-ஐ இயக்கவும்: decode ஆகாத எந்தச் சொல்லையும் node மறுக்கிறது, ஆனால் வரிசைப்படுத்தும் நேரத்தில் மட்டுமே.
wallet இரண்டு பழைய வடிவங்களையும் வரிசைப்படுத்துகிறது: { "base_pc", "words" } கொண்ட ஒரு .json கோப்பு, மற்றும் base 0-இல் ஏற்றப்படும் little-endian சொற்களின் ஒரு raw .bin. data segment கொண்ட ஒரே வடிவம் container மட்டுமே.
வரிசைப்படுத்துதலும் அழைத்தலும்
மேலே உள்ள ஒவ்வொரு வழியும் ஒரே மாதிரி முடிகிறது. fullnode v0.3 அல்லது அதற்குப் பிந்தைய rand wallet கொண்டு (நேரடிச் சங்கிலியான சங்கிலி 20-இல், v0.6.8 அல்லது அதற்குப் பிந்தையது: சங்கிலி 20 ஒவ்வொரு proof-ஐயும் கையொப்பத்தையும் அதன் genesis hash-உடன் பிணைப்பதால், v0.6.7 wallet அங்கு அனுப்ப இயலாது; Rust நிரலை வரிசைப்படுத்துதல் பார்க்கவும்):
rand program deploy add.bin
rand call <program id> --input 40 --input 2
வரிசைப்படுத்தல் கட்டணம் 0.001 RAND + 0.0001 RAND × words: add.bin-இன் 14 சொற்களுக்கு 0.0024 RAND, c-fib.bin-இன் 25 சொற்களுக்கு 0.0035 RAND. இரண்டும் 4,096 சொற்களுக்குக் குறைவு, ஆகவே எந்தச் சங்கிலியின் வரம்புக்குள்ளும் அடங்குகின்றன: இயல்புநிலை 4,096, சங்கிலி 20-இன் 65,535. அழைப்பு tier 10-இல் உள்ளூரில் நிரூபிக்கப்படுகிறது. சங்கிலி 15-இல் அது 0.002 RAND செலவானது. சங்கிலி 20-இல் கட்டணம் இனி 0.001 + call_fee(tier) அல்ல: அடிமட்டம் BUNDLE_BASE + gas_price × declared gas limit + byte_price × ⌈bytes / 1024⌉; நிரூபிப்பதற்கு முன் rand call gas: <exact> (declaring <limit>, tier <t>)-ஐயும் கட்டணத்தையும் அச்சிடுகிறது; சங்கிலி 18-இல் அளவிடப்பட்ட நான்கு அழைப்புகள் ஒவ்வொன்றும் 0.0057 முதல் 0.0075 RAND வரை செலவாயின (எடுத்துக்காட்டு நிரல்கள்). சங்கிலி 20-இல் ஒவ்வொரு வரிசைப்படுத்தலும் அழைப்பும் bundle பக்கத்து இரண்டு proof-களையும் சுமக்கின்றன: tier-10 செலவு அங்கீகாரம், tier-14 bundle. ஒவ்வொரு கட்டளையும் என்ன செய்கிறது என்பதை Rust நிரலை வரிசைப்படுத்துதல் விவரிக்கிறது.
நீங்கள் வரிசைப்படுத்தியதைப் பிறர் சரிபார்க்க, மூலக் குறியீட்டையும் உங்கள் circuits commit-ஐயும் (சங்கிலிகள் 18 முதல் 20 வரை aeacf31) வெளியிடவும். clang 23.1.1, Rust 1.98.1 கொண்டு, rand-guest build எந்த இயந்திரத்திலும் அதே hc-ஐத் தருகிறது.