इस पेज को Rand के लिए प्रोग्राम लिखने से पहले पढ़ें। यह बताता है कि आपका कोड किस मशीन पर चलता है, टूलचेन क्या अस्वीकार करता है, प्रोग्राम बाहरी दुनिया से कैसे संवाद करता है, और आप कौन-सी फ़ाइल डिप्लॉय करते हैं। आगे के पेज इसी पर आधारित हैं: Rust प्रोग्राम डिप्लॉय करें, RISC-V प्रोग्राम डिप्लॉय करें, और दोनों ट्रांसपाइलर।
मशीन
Rand प्रोग्राम RV32IM हैं: 32-बिट RISC-V बेस इंटीजर सेट और साथ में गुणा तथा भाग एक्सटेंशन। ये Rand zkVM के भीतर चलते हैं, जो हर रन को Plonky3 बैच STARK से प्रमाणित करता है। सत्यापनकर्ता कभी कोई निर्देश नहीं देखता। वह प्रूफ को hc के विरुद्ध जाँचता है, जो प्रोग्राम का इन-सर्किट Poseidon2 डाइजेस्ट है।
| समूह | निर्देश |
|---|---|
| अपर / जंप | LUI AUIPC JAL JALR |
| ब्रांच | BEQ BNE BLT BGE BLTU BGEU |
| लोड / स्टोर | 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 |
| सिस्टम | केवल ECALL |
JALR अपने लक्ष्य का बिट 0 साफ़ करता है, जैसा RV32I कहता है, और इसकी एन्कोडिंग में funct3 = 0 होना अनिवार्य है। ये दोनों नियम कंस्ट्रेंट सेट 7 (chain 16) के साथ आए; उससे पहले विषम लक्ष्य को फ़ेच नहीं किया जा सकता था और रन को प्रमाणित नहीं किया जा सकता था। जो लक्ष्य सम है पर चार का गुणज नहीं है, उसे अब भी फ़ेच नहीं किया जा सकता।
इसमें फ़्लोटिंग पॉइंट नहीं है, एटॉमिक्स (A एक्सटेंशन) नहीं हैं, कंप्रेस्ड निर्देश (C एक्सटेंशन) नहीं हैं और 64-बिट रजिस्टर नहीं हैं। C में 64-बिट भाग एक सॉफ़्टवेयर हेल्पर के कॉल में बदल जाता है; देखें C पथ।
क्या अस्वीकार किया जाता है
rand-guest check हर टेक्स्ट वर्ड को मशीन के अपने डिकोडर से गुज़ारता है। जो प्रोग्राम इसमें पास हो जाता है, वह सर्किट में एन्कोडिंग, सिस्कॉल-संख्या या लेआउट के कारण विफल नहीं हो सकता। चेकर इन्हें अस्वीकार करता है:
| निष्कर्ष | यह क्या है |
|---|---|
Compressed | 16-बिट RVC एन्कोडिंग; मशीन केवल 32-बिट वर्ड डिकोड करती है |
Undecodable | ऐसा ऑपकोड, funct या शिफ़्ट मान जिसे मशीन लागू नहीं करती |
Fence | FENCE या FENCE.I; मशीन में कोई मेमोरी ऑर्डरिंग नहीं है |
Csr | कोई भी CSR निर्देश; मशीन में CSR नहीं हैं |
Ebreak | EBREAK; ट्रैप मॉडल नहीं किए गए हैं |
Syscall | ऐसा ecall जिसका a7 ठीक पहले किसी li द्वारा सेट हो और किसी सिस्कॉल को इंगित न करे |
Cap | --max-words से अधिक वर्ड, उसी तरह गिने गए जैसे लोडर गिनता है |
Layout | ऐसा टेक्स्ट बेस जो वर्ड-संरेखित नहीं है |
एक चार-वर्ड प्रोग्राम जिसमें एक fence, एक ebreak और ecall संख्या 9 है, जैसा rand-guest check इसे रिपोर्ट करता है (एग्ज़िट कोड 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
जिस ecall का a7 चेकर नहीं देख सकता (जो li के अलावा किसी और चीज़ से, या किसी ब्रांच के बाद सेट हो), उसे अस्वीकार नहीं किया जाता बल्कि unresolved_ecalls में गिना जाता है। रन टाइम पर ग़लत संख्या मिलने पर मशीन फिर भी ट्रैप करती है।
चेकर पॉइंटर मान, लंबाइयाँ या इनपुट इंडेक्स, RAM के सापेक्ष 64 KiB स्टैक, या रन टाइम पर गणना किए गए पतों का संरेखण नहीं जाँचता। असंरेखित एक्सेस कंस्ट्रेंट का उल्लंघन है, इसलिए टूलचेन -unaligned-scalar-mem के साथ कंपाइल करता है। rand-guest run रन टाइम के किसी भी ट्रैप की रिपोर्ट करता है।
सिस्कॉल
ECALL सिस्कॉल संख्या a7 से, पहला आर्ग्युमेंट a0 से और दूसरा a1 से पढ़ता है। लौटाया गया मान a0 में आता है।
| # | सिस्कॉल | प्रभाव | गैस | Rust (guest-sdk) | C (guest.h) |
|---|---|---|---|---|---|
| 0 | HALT | रन समाप्त करता है | 1 | halt() | rand_halt() |
| 1 | WRITE_OUTPUT slot word | सार्वजनिक आउटपुट slot < 8 सेट करता है, प्रति स्लॉट अधिकतम एक बार; जिन स्लॉट में नहीं लिखा गया वे शून्य रहते हैं | 1 | write_output(slot, word) | rand_write_output |
| 2 | READ_INPUT idx | निजी इनपुट वर्ड idx लौटाता है, जो सॉल्टेड कमिटमेंट H_IN से बँधा है | 1 | read_input(idx) | rand_read_input |
| 3 | POSEIDON2 ptr n | वर्ड पता ptr पर n ≤ 4096 वर्ड हैश करता है और 8-वर्ड डाइजेस्ट ptr..ptr+8 पर लिखता है; कोई पैडिंग नहीं | 3 + 3·⌈n/4⌉ | unsafe poseidon2(ptr, n) | rand_poseidon2 |
| 4 | KECCAK ptr | 50 वर्ड पर इन-प्लेस एक Keccak-f[1600] परम्यूटेशन | 192 | keccak(state), keccak256(msg) | rand_keccak |
| 5 | SHA256 ptr | 24 वर्ड पर इन-प्लेस एक SHA-256 कम्प्रेशन | 64 | sha256_compress(buf), sha256(msg) | rand_sha256_compress |
| 6 | READ_PUBLIC idx | सार्वजनिक-सेगमेंट वर्ड idx लौटाता है, जो अनसॉल्टेड H_PUB से बँधा है | 1 | read_public(idx) | rand_read_public |
| 7 | POSEIDON2_LEN ptr n | POSEIDON2, जिसमें लंबाई n स्पंज में बँधी होती है, कम से कम एक परम्यूटेशन (कंस्ट्रेंट सेट 7) | 3 + 3·max(⌈n/4⌉, 1) | poseidon2_len(buf, n) | कोई नहीं |
हर अन्य निर्देश की लागत 1 गैस है: गैस प्रति cpu पंक्ति एक है, और केवल हैश सिस्कॉल का भार अधिक है (कंस्ट्रेंट सेट 8, chain 18 से)। एक Poseidon2 कॉल में उसकी ecall पंक्ति, दो राइट-बैक पंक्तियाँ और ⌈n/4⌉ अब्ज़ॉर्ब पंक्तियाँ होती हैं, प्रत्येक 3 गैस की।
POSEIDON2 पैडिंग नहीं करता। स्पंज हर चार-वर्ड खंड से अपनी पहली लेनों को अधिलेखित कर देता है, इसलिए [a], [a, 0], [a, 0, 0] और [a, 0, 0, 0] का हैश एक ही डाइजेस्ट होता है। जो प्रोग्राम परिवर्तनशील लंबाई वाले डेटा को हैश करता है, उसे लंबाई को संदेश में शामिल करना होगा, निश्चित-लंबाई एन्कोडिंग को हैश करना होगा, या POSEIDON2_LEN को कॉल करना होगा, जो n को स्पंज की कैपेसिटी में डालता है और उन्हीं वर्ड का अलग डाइजेस्ट देता है। Rust SDK में poseidon2 एक रॉ पॉइंटर पर unsafe fn है और poseidon2_len स्लाइस पर सुरक्षित कॉल है; keccak और sha256_compress क्रमशः &mut [u32; 50] और &mut [u32; 24] लेते हैं।
टूलचेन में एक कमी। सर्किट aeacf31 पर मशीन, एमुलेटर और Rust SDK सिस्कॉल 7 को लागू करते हैं, पर rand-guest check नहीं करता: इसकी सिस्कॉल सूची 6 पर रुक जाती है, इसलिए यह a7 = 7 वाले ecall को Syscall निष्कर्ष के रूप में रिपोर्ट करता है और poseidon2_len को कॉल करने वाले गेस्ट पर rand-guest build गैर-शून्य कोड के साथ बाहर निकलता है (circuits issue #1)। guest.h में भी इसका कोई रैपर नहीं है। जब तक यह ठीक नहीं होता, मानक टूल से बना गेस्ट निश्चित-लंबाई संदेशों पर POSEIDON2 का उपयोग करता है।
एक प्रूफ ठीक यही प्रकाशित करता है: hc, H_IN, H_PUB, टियर, घोषित गैस सीमा, और आठ आउटपुट वर्ड। आज चेन पर दो सीमाएँ लागू हैं:
- सार्वजनिक सेगमेंट डिप्लॉय के समय निश्चित हो जाता है। chain 20 पर
rand program deploy --publicकिसी प्रोग्राम के सार्वजनिक वर्ड सेट करता है (अधिकतमmax_program_public_words, 32,768), और हर कॉल उनके विरुद्ध जाँची जाती है। प्रोग्राम के अपने कोई प्रति-कॉल सार्वजनिक वर्ड नहीं होते। chain 20, chain 19 की तरह, हर कॉल के सेगमेंट में उनके बाद आठ वर्ड जोड़ता है, जो कॉल बाइंडिंग है और प्रूफ को उसके ट्रांज़ैक्शन से जोड़ती है (chain 20 पर इसमें जेनेसिस हैश भी शामिल है); गेस्ट अपने वर्ड पहले जैसे ही इंडेक्स पर पढ़ता है। RPL-2Invokeबाइंडिंग के बाद घोषित ट्रांज़िशन जोड़ता है, जिसे प्रोग्रामpublic_len + 8से आगे पढ़ता है (प्रोग्राम)। जिस चेन में सीमा फ़ील्ड नहीं हैं, जैसे chain 12, वहाँ सार्वजनिक सेगमेंट ख़ाली होता है औरREAD_PUBLICके पास पढ़ने को कुछ नहीं होता। - किसी कॉल के निजी इनपुट वर्ड सील किए गए एन्वेलप से सीमित होते हैं। chain 20 का
max_call_envelope_bytes, जो 65,536 है, 16,071 वर्ड की अनुमति देता है; जिस चेन में यह फ़ील्ड नहीं है, वह 4,295 की अनुमति देती है।
KECCAK या SHA256 कॉल प्रूफ में एक टेबल जोड़ती है, और तब प्रूफ का हेडर दिखाता है कि कॉल ने हैश किया। keccak वाला प्रूफ लगभग 3.3 MB का होता है: डिफ़ॉल्ट 2 MiB प्रूफ सीमा से अधिक, chain 20 की 4 MiB से कम, और एक कॉल अधिकतम 128 Keccak-f परम्यूटेशन और 128 SHA-256 कम्प्रेशन का उपयोग कर सकती है (प्रोग्राम)।
मेमोरी
- 32 रजिस्टर;
x0शून्य है। - RAM शून्य से शुरू होती है। हर पता
2³⁰से नीचे है। - डिफ़ॉल्ट लिंकर स्क्रिप्ट,
guest-sdk/guest.ld, प्रोग्राम को0x1000पर रखती है, फिर.rodata,.dataऔर.bss, फिर__stack_topपर 64 KiB स्टैक। - डेटा सेगमेंट वाले प्रोग्राम को अपने टेक्स्ट के नीचे लोडर के प्रोलॉग (अगला खंड) के लिए जगह चाहिए। उसका अपना
.ldORIGINको बढ़ाकर0x10000कर देता है, जैसाevm.ldऔरsbpf.ldकरते हैं।
इमेज कंटेनर
rand-guest build और rand-guest pack एक ही फ़ाइल फ़ॉर्मेट लिखते हैं, इमेज कंटेनर। सभी संख्याएँ लिटिल-एंडियन 32-बिट वर्ड हैं:
[0x444e4152 ("RAND"), 1, text_base, n_text, data_base, n_data] text… data…
लोडर कंटेनर को एक प्रोग्राम { base_pc, words } में बदलता है:
- यह हर गैर-शून्य डेटा वर्ड के लिए एक
li/swजोड़ी लिखता है। शून्य वर्ड छोड़ दिए जाते हैं, क्योंकि RAM पहले से शून्य पढ़ती है। - यह उस प्रोलॉग को सीधे
text_baseके नीचे रखता है, इसलिएbase_pc = text_base − 4 × prologue words। प्रोलॉग से निष्पादन सीधे प्रोग्राम के अपने_startमें चला जाता है। hcऔर प्रोग्राम id की गणना पूरेwordsपर होती है, प्रोलॉग सहित। इसलिएhcकोड के साथ-साथ डेटा को भी बाँधता है।
जिस कंटेनर में डेटा नहीं है, उससे कोई प्रोलॉग नहीं बनता, और उसी बेस पर हेडर-रहित फ़्लैट बाइनरी जैसा ही प्रोग्राम और hc मिलता है।
fullnode v0.3 और उसके बाद के संस्करणों में rand program deploy कंटेनर को उसके पहले वर्ड से पहचानता है। 0x444e4152 कभी किसी निर्देश के रूप में डिकोड नहीं होता, इसलिए किसी रॉ .bin को कंटेनर समझ लेने की भूल नहीं हो सकती। जो फ़ाइल मैजिक से शुरू होती है पर विकृत है, वह त्रुटि है, फ़ॉलबैक नहीं।
दो पहचानें
| नाम | यह क्या है | इसका उपयोग कौन करता है |
|---|---|---|
hc | (base_pc, len, words) का सर्किट द्वारा परिकलित Poseidon2 डाइजेस्ट | किसी कॉल के प्रत्येक प्रमाण का सत्यापन इसी के विरुद्ध होता है; rand_getProgram इसे code_hash के रूप में दिखाता है |
| प्रोग्राम id | blake3("rand-program" ‖ base_pc ‖ words); --public के साथ किया गया डिप्लॉय सार्वजनिक words को भी rand-program-2 टैग के अंतर्गत बाँधता है | वह कुंजी जिसके अंतर्गत डिप्लॉय किया गया प्रोग्राम संग्रहीत होता है और कॉल किया जाता है |
rand-guest build और rand-guest info दोनों को प्रिंट करते हैं। hc बाध्यकारी (binding) है, पर गोपनीय (hiding) नहीं: जिसके पास कोई संभावित प्रोग्राम है, वह इसकी पुष्टि कर सकता है।
प्रोग्राम की सीमा
एक डिप्लॉय में अधिकतम उतने words हो सकते हैं जितनी चेन की प्रोग्राम सीमा है।
| चेन | सीमा |
|---|---|
max_program_words के बिना जेनेसिस (चेन 12) | 4,096 |
max_program_words वाला जेनेसिस | वही मान, 1..=65535 |
| zkVM की कठोर सीमा, कोई भी चेन | 65,535 |
यह सीमा जेनेसिस हैश का हिस्सा है, इसलिए चल रही चेन पर इसे बदला नहीं जा सकता। rand-guest इसकी जाँच --max-words (डिफ़ॉल्ट 4,096) के विरुद्ध करता है। rand program deploy नोड से rand_estimateFee द्वारा पूछता है और सीमा से बड़े प्रोग्राम को कुछ भी प्रमाणित करने से पहले ही अस्वीकार कर देता है।
चेन 20, जो लाइव चेन है, यह सीमा बढ़ाती है। इसका जेनेसिस हैश 6210cf071a390d7ac61d8cbea5dd9d139d1a493a862b54a45a498f36af2d5135 है और इसका max_program_words 65,535 है। यह चेन 13 (v0.4 चेन) द्वारा लागू की गई सीमाएँ बनाए रखती है, सिवाय प्रमाण सीमा के, जिसे चेन 17 से 20 आधा कर देती हैं। इसकी अन्य सीमाएँ:
| सीमा | चेन 20 |
|---|---|
max_proof_bytes | 4,194,304 (4 MiB); चेन 13 से 16 पर 8 MiB |
max_block_bytes | 20,971,520 (20 MiB) |
max_call_envelope_bytes | 65,536 |
max_program_public_words | 32,768 |
चेन 20 पर, चेन 19 की तरह, words की सीमा निर्णायक सीमा नहीं है। इसका जेनेसिस hardening_v6 सेट करता है, जिसके अंतर्गत किसी डिप्लॉय को (ProgramUncallable) अस्वीकार कर दिया जाता है जब कोई भी कॉल उस प्रोग्राम को कभी प्रमाणित न कर सके। एक कॉल की सीमा टियर 14 है, जिसकी Poseidon2 तालिका में 2,048 परम्यूटेशन आते हैं। प्रोग्राम डाइजेस्ट हर चार words पर एक परम्यूटेशन लेता है, इनपुट की salt पंक्ति एक और आठ कॉल-बाइंडिंग words दो, जिससे 2,045 बचते हैं: सार्वजनिक इनपुट के बिना प्रोग्राम के लिए 8,180 words, और सार्वजनिक इनपुट होने पर इससे कम (नौ सार्वजनिक words के साथ 8,168)। प्रत्येक नोड का पूल किसी भी चेन पर ऐसे डिप्लॉय को अस्वीकार कर देता है।
चेन 20 पर ब्लॉक एग्रीगेशन बंद है: इसके जेनेसिस में कोई aggregation खंड नहीं है। चेन 20 fullnode v0.6.8 पर 2026-10-01 06:17 UTC से लाइव है; यह चेन 19 की स्थिति से ऊँचाई 7,258 पर काटा गया हार्ड फ़ोर्क है (चेन 19 ऊँचाई 7,700 पर रुकी); चेन 19 (उसी दिन 03:43 UTC से लाइव) स्वयं ऊँचाई 141,935 पर चेन 18 का पुनः-जेनेसिस थी। प्रोग्राम किसी कट के पार नहीं जाते, इसलिए किसी पिछली चेन पर डिप्लॉय किया गया कोई भी प्रोग्राम चेन 20 पर मौजूद नहीं है। चेन 20 RPL-2 प्रोग्राम स्टेट वाली पहली चेन भी है (प्रोग्राम)। यह नेटवर्क पर इन बूटस्ट्रैप नोड्स के माध्यम से चलती है:
/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
| इमेज | words | 4,096 में समाता है | 65,535 में समाता है | चेन 20 पर डिप्लॉय होता है (8,180 कॉल-योग्य) |
|---|---|---|---|---|
fib (Rust) | 26 | हाँ | हाँ | हाँ |
c-fib (C) | 25 | हाँ | हाँ | हाँ |
| ERC-20, अनूदित (चरण दो) | 11,686 | नहीं | हाँ | नहीं |
evm.bin, EVM इंटरप्रेटर | 18,009 | नहीं | हाँ | नहीं |
sbpf.bin, sBPF इंटरप्रेटर | 8,317 | नहीं | हाँ | नहीं |
| SPL Token, अनूदित | 65,096 | नहीं | हाँ, 439 शेष रहते हुए | नहीं |
टियर
किसी प्रमाण का टियर t रन को 2ᵗ − 1 पंक्तियों तक सीमित करता है: साइकिल और डाइजेस्ट पंक्तियाँ (हर चार प्रोग्राम words पर एक, हर चार इनपुट words पर एक, और सार्वजनिक-इनपुट डाइजेस्ट)। टियर एक अलग Poseidon2 बजट भी तय करता है। rand-guest run --tier t दोनों की रिपोर्ट देता है:
tier 10: fits (cycles 146 of 1023, Poseidon2 permutations 10 of 128)
टियर सार्वजनिक है, और प्रमाण द्वारा घोषित गैस सीमा भी। चेन 20 पर कॉल शुल्क टियर के बजाय उसी सीमा और प्रमाण के आकार पर निर्भर करता है: चेन की वर्तमान कीमतों पर कम से कम 0.001 RAND + gas_price × gas_limit + byte_price × ⌈bytes / 1024⌉; ये कीमतें 10⁻⁹ RAND की 100 और 800 इकाइयों से शुरू होती हैं, ब्लॉक के भराव के साथ बदलती हैं और चेन 20 पर 10,000 और 80,000 इकाइयों पर रुकती हैं (शुल्क)। कोई सीमा हेडर की अधिकतम सीमा से अधिक नहीं हो सकती, जो (2ᵗ − 1) + 2ᵗ⁻² है, साथ में प्रमाण द्वारा घोषित प्रत्येक Keccak ब्लॉक पर 191 और प्रत्येक SHA-256 ब्लॉक पर 63: हैश तालिका के बिना टियर 10 पर 1,279 और टियर 14 पर 20,479। rand-guest run साइकिल और परम्यूटेशन की रिपोर्ट देता है, गैस की नहीं। rand call प्रमाणित करने से पहले प्रोग्राम को चलाता है और उसके द्वारा खर्च की गई गैस तथा घोषित सीमा प्रिंट करता है, जो डिफ़ॉल्ट रूप से सटीक गैस को 2ᵗ⁻² के अगले गुणज तक बढ़ाकर निकाली जाती है:
gas: 5636 (declaring 6144, tier 12)
यह पंक्ति 2026-09-30 को चेन 18 पर की गई एक कॉल की है (एक अनाम मतदान)। जेनेसिस gas खंड के बिना वाली चेन पर, यानी चेन 15 और उससे पहले, शुल्क एक टियर अनुसूची थी: 0.001 + (0.001 + 0.0001 × (t − 10) / 2) RAND। किसी प्रमाण के लिए आवश्यक मेमोरी टियर के साथ तेज़ी से बढ़ती है; देखें वैलिडेटर और एग्रीगेटर हार्डवेयर।
fullnode v0.5.6 (2026-09-25) से कोई कॉल अधिकतम टियर 14 घोषित कर सकती है: नोड उच्चतर टियर वाले कॉल प्रमाण को सत्यापन कुंजी बनाने से पहले ही CallTierTooHigh के साथ अस्वीकार कर देता है, और ऐसा प्रमाण ले जाने वाला ब्लॉक अमान्य होता है। टियर-14 का बजट 16,383 पंक्तियाँ और 2,048 Poseidon2 परम्यूटेशन है, और प्रोग्राम का अपना डाइजेस्ट लगभग हर चार words पर एक परम्यूटेशन खर्च करता है, इसलिए 8,180 words से बड़े प्रोग्राम को कॉल नहीं किया जा सकता, और चेन 20, चेन 19 की तरह, उसका डिप्लॉय अस्वीकार कर देती है। Rust या C में प्रोग्राम लिखें इस बजट को विस्तार से समझाता है।