Rand Protocol
दस्तावेज़ीकरण
उदाहरण प्रोग्राम

देयताओं का प्रमाण

एक गोपनीय प्रोग्राम जो निजी ग्राहक शेषों पर SHA-256 Merkle योग वृक्ष बनाता है और सिद्ध करता है कि कुल राशि एक प्रकाशित आरक्षित आँकड़े से आच्छादित है - इंटरफ़ेस, Rust गेस्ट, साधारण Python में ग्राहक की समावेशन जाँच, बजट, और chain 18 पर चालू प्रोग्राम।

कस्टोडियन पर प्रत्येक ग्राहक का एक बैलेंस बकाया होता है। यह प्रोग्राम सिद्ध करता है कि बैलेंसों का योग कस्टोडियन द्वारा प्रकाशित रिज़र्व आँकड़े से अधिक नहीं है, और इसके लिए न तो कोई एक बैलेंस प्रकाशित होता है और न ही कुल योग। प्रत्येक ग्राहक Python की कुछ पंक्तियों से, बिना किसी विशेष टूलिंग के, यह जाँच सकता है कि उसका अपना बैलेंस गिना गया था।

उदाहरण प्रोग्राम में वह सेटअप है जो चारों उदाहरण पृष्ठों में साझा है।

1. यह क्या सिद्ध करता है

कस्टोडियन एक मर्कल सम ट्री बनाता है। एक लीफ एक खाता है: ग्राहक की id और बैलेंस का हैश, जिसके साथ बैलेंस रखा रहता है। एक नोड उसके दो चाइल्ड और उनके योगों का हैश है, जिसके साथ दोनों योगों का जोड़ रखा रहता है। इसलिए रूट अपने नीचे के प्रत्येक बैलेंस का कुल योग वहन करता है।

ट्री प्रोग्राम के भीतर खातों की निजी सूची से बनाया जाता है। कॉल यह सिद्ध करती है:

  1. रसीद में प्रकाशित रूट, कस्टोडियन द्वारा दिए गए खातों पर बने सम ट्री का रूट है;
  2. उसमें प्रत्येक योग अपने नीचे के दोनों योगों का सही योग है, बिना किसी ओवरफ़्लो के;
  3. रूट पर कुल योग, डिप्लॉय के समय निर्धारित रिज़र्व आँकड़े से अधिक नहीं है।

बिंदु 2 वह है जो बिना प्रमाण के प्रकाशित सम ट्री नहीं दे सकता। साधारण सम ट्री पर ज्ञात हमला वह कस्टोडियन है जो किसी पैरेंट का योग उसके चाइल्ड के योग से कम लिख देता है, जिसे कोई ग्राहक एक अकेले पाथ से नहीं पकड़ सकता। यहाँ योग प्रोग्राम द्वारा गणना किए जाते हैं, और किसी अन्य अंकगणित का प्रमाण अस्तित्व में ही नहीं होता।

प्रमाण जिसे कवर नहीं करता वह है पूर्णता: कौन से खाते शामिल हों, यह कस्टोडियन चुनता है। यह कमी ग्राहक पूरी करते हैं। प्रत्येक ग्राहक जाँचता है कि उसकी id और उसके बैलेंस वाला लीफ प्रकाशित रूट के नीचे है (खंड 7)। छोड़ा गया खाता उसके स्वामी द्वारा पकड़ लिया जाता है।

2. इंटरफ़ेस

सार्वजनिक वर्डअर्थ
0, 1रिज़र्व आँकड़ा, एसेट की सबसे छोटी इकाइयों में एक u64, पहले निचला वर्ड फिर ऊपरी
2एक स्नैपशॉट लेबल; प्रोग्राम इसे नहीं पढ़ता, पर प्रोग्राम id इसे बाँधती है
निजी वर्डअर्थ
0खातों की संख्या n, अधिकतम 32
फिर, प्रति खाताid (चार big-endian वर्ड के रूप में 16 बाइट), बैलेंस का निचला वर्ड, बैलेंस का ऊपरी वर्ड
आउटपुट स्लॉटअर्थ
0स्टेटस: 1 कवर, 2 कवर नहीं, 3 32 से अधिक खाते, 4 किसी योग में ओवरफ़्लो
1n
2 से 6रूट हैश के पहले 20 बाइट, पाँच big-endian वर्ड के रूप में
7अप्रयुक्त; Rust panic यहाँ 0xdeadbeef लिखता है

रिज़र्व आँकड़ा दो कारणों से सार्वजनिक सेगमेंट में है, आउटपुट में नहीं। जगह नहीं है: स्टेटस, गणना और 160-बिट रूट स्लॉट भर देते हैं। और यह प्रमाण के अस्तित्व में आने से पहले दावे को घोषित कर देता है: प्रोग्राम डिप्लॉय करने से “R का रिज़र्व, स्नैपशॉट S” प्रकाशित होता है, और फिर कॉल या तो सिद्ध करती है कि बैलेंस R के भीतर हैं या स्टेटस 2 लौटाती है।

हैश, ठीक-ठीक:

leaf  = SHA-256( be32(0) ‖ id (16 bytes) ‖ be64(balance) )                                  28 bytes
node  = SHA-256( be32(1) ‖ left hash ‖ be64(left sum) ‖ right hash ‖ be64(right sum) )      84 bytes
empty = leaf with id 0 and balance 0

ट्री में हमेशा 32 लीफ होते हैं। खाते उसे बाईं ओर से भरते हैं और शेष को खाली लीफ भरते हैं। आरंभिक 0 और 1 यह सुनिश्चित करते हैं कि किसी लीफ को कभी नोड के रूप में न पढ़ा जाए।

बाइट क्रम। SHA-256 पूरी तरह big-endian है, और SHA256 syscall अपना 64-बाइट ब्लॉक सोलह big-endian वर्ड के रूप में लेता है। इसलिए यह प्रोग्राम id को चार big-endian वर्ड के रूप में पढ़ता है और रूट को big-endian वर्ड के रूप में प्रकाशित करता है: hex में छपा आउटपुट 2 रूट के पहले आठ hex अंक है। यह Keccak प्रोग्राम से विपरीत परिपाटी है, क्योंकि दोनों हैश विपरीत बाइट क्रमों पर परिभाषित हैं।

3. गेस्ट

my-guests/solvency/src/main.rs, पूर्ण:

#![no_std]
#![no_main]

use guest_sdk::{halt, read_input, read_public, sha256_compress, write_output};

/// The tree always has 32 leaves. Accounts fill it from the left; the rest are empty leaves.
const LEAVES: usize = 32;

const SOLVENT: u32 = 1;
const INSOLVENT: u32 = 2;
const TOO_MANY: u32 = 3;
const OVERFLOW: u32 = 4;

const LEAF_TAG: u32 = 0;
const NODE_TAG: u32 = 1;

/// SHA-256's initial state (FIPS 180-4 §5.3.3).
const IV: [u32; 8] = [
    0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19,
];

#[derive(Clone, Copy)]
struct Node {
    hash: [u32; 8],
    sum: u64,
}

/// SHA-256 of the 28 bytes `be32(0) ‖ id (16 bytes) ‖ be64(balance)`. The message, its `0x80`
/// terminator and its bit length fit one 64-byte block, so a leaf is one compression.
fn leaf(id: &[u32; 4], balance: u64) -> Node {
    let mut buf = [0u32; 24];
    buf[0] = LEAF_TAG;
    buf[1..5].copy_from_slice(id);
    buf[5] = (balance >> 32) as u32;
    buf[6] = balance as u32;
    buf[7] = 0x8000_0000;
    buf[15] = 28 * 8;
    buf[16..].copy_from_slice(&IV);
    sha256_compress(&mut buf);
    let mut hash = [0u32; 8];
    hash.copy_from_slice(&buf[16..]);
    Node { hash, sum: balance }
}

/// SHA-256 of the 84 bytes `be32(1) ‖ left hash ‖ be64(left sum) ‖ right hash ‖ be64(right sum)`:
/// two compressions. `None` when the two sums do not fit a u64.
fn parent(l: &Node, r: &Node) -> Option<Node> {
    let sum = l.sum.checked_add(r.sum)?;
    let mut buf = [0u32; 24];
    buf[16..].copy_from_slice(&IV);
    // Block 1: words 0..16 of the message.
    buf[0] = NODE_TAG;
    buf[1..9].copy_from_slice(&l.hash);
    buf[9] = (l.sum >> 32) as u32;
    buf[10] = l.sum as u32;
    buf[11..16].copy_from_slice(&r.hash[..5]);
    sha256_compress(&mut buf);
    // Block 2: the last five words, the terminator, zeros, the bit length.
    buf[..3].copy_from_slice(&r.hash[5..]);
    buf[3] = (r.sum >> 32) as u32;
    buf[4] = r.sum as u32;
    buf[5] = 0x8000_0000;
    buf[6..15].fill(0);
    buf[15] = 84 * 8;
    sha256_compress(&mut buf);
    let mut hash = [0u32; 8];
    hash.copy_from_slice(&buf[16..]);
    Some(Node { hash, sum })
}

/// Public segment, fixed at deploy: [reserves low word, reserves high word, snapshot label].
/// Private input: [n, then n accounts of (id: 4 words, balance low, balance high)].
/// Outputs: [status, n, root (first 5 words), 0].
#[no_mangle]
pub extern "C" fn main() -> ! {
    let reserves = read_public(0) as u64 | (read_public(1) as u64) << 32;

    let n = read_input(0) as usize;
    if n > LEAVES {
        write_output(0, TOO_MANY);
        halt();
    }

    let empty = leaf(&[0; 4], 0);
    let mut row = [empty; LEAVES];
    for (i, slot) in row.iter_mut().enumerate().take(n) {
        let at = 1 + 6 * i as u32;
        let id = [read_input(at), read_input(at + 1), read_input(at + 2), read_input(at + 3)];
        let balance = read_input(at + 4) as u64 | (read_input(at + 5) as u64) << 32;
        *slot = leaf(&id, balance);
    }

    // Fold the row in place, a level at a time, until one node is left.
    let mut width = LEAVES;
    while width > 1 {
        width /= 2;
        for i in 0..width {
            match parent(&row[2 * i], &row[2 * i + 1]) {
                Some(p) => row[i] = p,
                None => {
                    write_output(0, OVERFLOW);
                    halt();
                }
            }
        }
    }
    let root = row[0];

    write_output(0, if root.sum <= reserves { SOLVENT } else { INSOLVENT });
    write_output(1, n as u32);
    for k in 0..5 {
        write_output(2 + k as u32, root.hash[k]);
    }
    halt();
}

पैडिंग हाथ से लिखी गई है। guest_sdk::sha256 कोई भी बाइट स्ट्रिंग लेता है और उसे एक-एक बाइट करके कॉपी करता है। यहाँ प्रत्येक संदेश ज्ञात लंबाई के पूरे वर्डों का है, इसलिए प्रोग्राम 16-वर्ड ब्लॉक को सीधे भरता है: संदेश के वर्ड, फिर 0x80000000, शून्य, और अंतिम वर्ड में बिट लंबाई। एक लीफ एक कम्प्रेशन है। एक नोड के 84 बाइट दूसरे ब्लॉक में चले जाते हैं, इसलिए एक नोड दो कम्प्रेशन है।

बैलेंस u64 हैं और योग जाँचे जाते हैं। बैलेंस ऋणात्मक नहीं हो सकता क्योंकि इस टाइप में ऋणात्मक मान होते ही नहीं, जिससे कुल योग घटाने का दूसरा पारंपरिक तरीका समाप्त हो जाता है। checked_add ओवरफ़्लो को लिपटे हुए (wrapped) योग के बजाय स्टेटस 4 में बदल देता है।

दिवालियापन का परिणाम भी एक परिणाम है। स्टेटस 2 एक सामान्य halt है जिसमें रूट प्रकाशित होता है। कस्टोडियन रिज़र्व आँकड़े से अधिक बैलेंसों के लिए स्टेटस 1 की रसीद प्राप्त नहीं कर सकता, और स्टेटस 2 की रसीद ठीक इसी बात का प्रमाण है।

4. होस्ट पक्ष

solvency.py केवल Python की स्टैंडर्ड लाइब्रेरी का उपयोग करता है:

solvency.py setup   <accounts.csv> <reserves> <snapshot label>   writes public.txt, prints the root
solvency.py witness <accounts.csv>                 prints the private words
solvency.py path    <accounts.csv> <row>           prints that account's inclusion proof (JSON)
solvency.py verify  <proof.json> <root prefix hex> checks a proof against a receipt's root

इसमें दिए गए दो हैश ही वह पूरा विनिर्देश हैं जिसकी किसी ग्राहक को आवश्यकता है:

def leaf(ident: bytes, balance: int):
    return hashlib.sha256(struct.pack(">I", 0) + ident + struct.pack(">Q", balance)).digest(), balance

def parent(l, r):
    h = hashlib.sha256(struct.pack(">I", 1) + l[0] + struct.pack(">Q", l[1]) + r[0] + struct.pack(">Q", r[1]))
    return h.digest(), l[1] + r[1]

डेमो में demo-accounts.csv में बारह खाते हैं, प्रति पंक्ति एक id,balance, और बैलेंस 10⁻⁸ की इकाइयों में हैं (वह परिशुद्धता जो zUSD जैसा ब्रिज किया गया टोकन उपयोग करता है)। इनका कुल योग 100,215.185678 है। कस्टोडियन 101,000 के रिज़र्व का दावा करता है:

$ python3 solvency.py setup demo-accounts.csv 10100000000000 20260930
root 46b78564d60f75bdc9552d8ad1c4aadf411354054be3ffb80337b8549471a82c
root prefix 46b78564d60f75bdc9552d8ad1c4aadf41135405
root words 1186432356 3591337405 3377802634 3519326943 1091785733
liabilities 10021518567800
wrote public.txt
$ cat public.txt
2531887104 2351 20260930

2351 × 2³² + 2531887104 का मान 10,100,000,000,000 है। liabilities पंक्ति कस्टोडियन का अपना दृश्य है। यह कभी प्रकाशित नहीं होती।

id अद्वितीय और अनुमान से परे होनी चाहिए। यदि समान बैलेंस वाले दो ग्राहकों को एक ही लीफ दिया जाए, तो कस्टोडियन दोनों के लिए एक ही देनदारी गिन सकता है। ऐसी id जिसे केवल उसका ग्राहक अपनी के रूप में पहचान सके, इसे रोकती है, और ऐसी id जिसका अनुमान न लगाया जा सके, उस ग्राहक को रोकती है जो किसी सिबलिंग का हैश देखकर पड़ोसी के बैलेंस के अनुमान परखना चाहे। डेमो एक हैश के पहले 16 बाइट का उपयोग करता है। वास्तविक परिनियोजन id को ग्राहक के खाते और प्रति-स्नैपशॉट नॉन्स से व्युत्पन्न करेगा और उसे ग्राहक को दिखाएगा।

5. बिल्ड और रन

$ rand-guest build my-guests/solvency --max-words 65535
994 words against a cap of 65535 (fits); 0 ecall(s) with a non-static a7
OK
wrote my-guests/solvency/image.bin and its .sha256 (994 words, hc 5559791a05bd9269bf7fc4e893c05e8b21defe5ef966d831b49ea463fb4552d3, program id 697412b5db65647164c21b27e4b4feb0b5f0b9fce2381157cd0786bfecf1769f)
$ cd my-guests/solvency
$ python3 solvency.py witness demo-accounts.csv > witness.txt
$ rand-guest run image.bin --public $(cat public.txt) --input $(cat witness.txt) --tier 14
out[0] = 1
out[1] = 12
out[2] = 1186432356
out[3] = 3591337405
out[4] = 3377802634
out[5] = 3519326943
out[6] = 1091785733
out[7] = 0
cycles 7492
tier 14
tier 14: fits (cycles 7762 of 16383, Poseidon2 permutations 270 of 2048)

स्टेटस 1, बारह खाते, और स्क्रिप्ट द्वारा छापे गए रूट के पाँच वर्ड। विटनेस 73 वर्ड का है: गणना और प्रति खाता छह।

रिज़र्व आँकड़ा घटाकर 100 इकाई (--public 100 0 1) करने पर वही खाते out[0] = 2 देते हैं। 33 की गणना out[0] = 3 देती है। ऐसे दो खाते जिनके बैलेंसों का योग 2⁶⁴ से आगे चला जाए, out[0] = 4 देते हैं।

6. बजट

12 खाते32 खाते
निजी वर्ड73193
साइकिल7,49210,681
SHA-256 कम्प्रेशन7595
टियर1414

कम्प्रेशनों की गणना है: n लीफ, एक खाली लीफ (एक बार गणना करके कॉपी किया गया), और 31 नोडों में से प्रत्येक के लिए दो। एक कॉल अधिकतम 128 कम्प्रेशन उपयोग कर सकती है, और टियर 14 वह सर्वोच्च टियर है जिसे कोई कॉल उपयोग कर सकती है, इसलिए 32 खाते इस डिज़ाइन में एक कॉल द्वारा सिद्ध की जा सकने वाली सीमा के निकट हैं। 64-लीफ ट्री को 190 कम्प्रेशन चाहिए और वह समाहित नहीं होता।

यह प्रदर्शन का आकार है। इससे आगे जाने का अर्थ है ट्री को कई कॉलों में बाँटना और प्रत्येक सबट्री के रूट और योग की कमिटमेंट को एक अंतिम कॉल में ले जाना, वही पैटर्न जिसका वर्णन प्रोग्राम लिखें बजट से बड़े किसी भी कार्य के लिए करता है। यह उदाहरण ऐसा नहीं करता।

चेन 18 से एक कम्प्रेशन की लागत 64 गैस है, जबकि एक सामान्य साइकिल की 1। वॉलेट किसी रन की सटीक गैस और उसके द्वारा घोषित सीमा छापता है:

gas: 12489 (declaring 16384, tier 14)

प्रत्येक पंक्ति (row) की लागत 1 गैस है और एक कम्प्रेशन की 63 अधिक: 7,764 पंक्तियाँ और 75 × 63 मिलकर 12,489 होते हैं। गैस का एक-तिहाई से अधिक भाग हैशिंग है। (वॉलेट rand-guest run से दो पंक्तियाँ अधिक गिनता है, उस ट्रांज़ैक्शन बाइंडिंग के लिए जो चेन 18 किसी कॉल के सार्वजनिक सेगमेंट में जोड़ती है।)

7. ग्राहक की जाँच

कस्टोडियन प्रत्येक ग्राहक को उसका पाथ देता है: पाँचों स्तरों में से प्रत्येक पर सिबलिंग हैश और सिबलिंग योग।

$ python3 solvency.py path demo-accounts.csv 6 > proof6.json
$ head -12 proof6.json
{
 "id": "f8f4e4a0c855aad0d0f9ae5bab108333",
 "balance": 1820025000000,
 "path": [
  {
   "hash": "e39eaaabec5cca1fe4c76ce656692be631a39e807876f93bdd7baf8b057d6997",
   "sum": 6600000000,
   "sibling_is_left": false
  },
  {
   "hash": "4732f069886c966e6429ee9063f73429bf153eb2575cf2a28f00f27b7d0d89c6",
   "sum": 31500000000,

ग्राहक अपनी id और बैलेंस से रूट की पुनर्गणना करता है और उसके पहले 20 बाइट की तुलना रसीद के आउटपुट 2 से 6 से करता है:

$ python3 solvency.py verify proof6.json 46b78564d60f75bdc9552d8ad1c4aadf41135405
root prefix 46b78564d60f75bdc9552d8ad1c4aadf41135405 MATCH

ट्री में मौजूद बैलेंस से एक इकाई अधिक बैलेंस का पाथ रूट तक नहीं पहुँचता:

$ python3 solvency.py verify tampered.json 46b78564d60f75bdc9552d8ad1c4aadf41135405
root prefix e9a1b4cbe49e412214b97afe73348fa7c555fa7a DOES NOT MATCH

पूरी जाँच ऊपर दिए गए leaf और parent फ़ंक्शनों को पाँच बार लागू करना है। जो ग्राहक कस्टोडियन की स्क्रिप्ट नहीं चलाना चाहता, वह इसे स्वयं लिख सकता है।

पाथ ग्राहक को उसके सिबलिंगों के योग दिखाता है। ऊपर के पाथ का पहला चरण प्रकट करता है कि पड़ोसी लीफ में 6,600,000,000 इकाइयाँ हैं, और प्रत्येक ऊपरी चरण एक सबट्री का कुल योग प्रकट करता है। यह साधारण सम ट्री में अंतर्निहित है। प्रत्येक स्नैपशॉट पर लीफों को फेंटने से यह सीमित होता है कि ग्राहक समय के साथ क्या जान सकता है, और योगों को पूरी तरह छिपाने के लिए साधारण संख्याओं के स्थान पर कमिटमेंट चाहिए, जो यह उदाहरण नहीं करता।

8. डिप्लॉय

$ rand fee deploy 994 --public-words 3
0.1007 RAND
$ rand program deploy image.bin --public public.txt
program id: fce8474dfdf80b9733e04fb72d4d8d19c40ba5ab646b3d867322daf4b9b599c0 (994 words, hc 1a7959556992bd05e8c47fbf8b5ec0935efede2131d866f963a49eb4d35245fb, public input 3 words, digest 70d5ae8935d646f7a0dd426c30aaf68e9bc382534d8a6ced90e363e129403608)
proving the spend authorisation on this machine (tier 10; seconds)…
authorisation proved in 6.8s: tier 10, 1368908 bytes
proving the bundle (tier 14; about a minute and a half on a laptop)…
proved in 116.7s: tier 14, 1500710 bytes
submitted deploy 39e8f35e0bdc7bc105ce942dc492b52f7a5efbb682ab6ebecc17cb310a161ada
  0 RAND out, 59.8545 RAND change, fee 0.1007 RAND, anchored at height 97831, proved in 116.7s (bundle) + 6.8s (auth)

प्रोग्राम id रिज़र्व आँकड़े और स्नैपशॉट लेबल को कोड के साथ बाँधती है। नया स्नैपशॉट एक नया डिप्लॉय है, लगभग एक RAND के दसवें भाग की लागत पर, और उसकी id नए दावे की सार्वजनिक घोषणा है।

9. कॉल

$ rand call fce8474dfdf80b9733e04fb72d4d8d19c40ba5ab646b3d867322daf4b9b599c0 \
    $(sed 's/[0-9][0-9]*/--input &/g' witness.txt)
proving the call locally (73 inputs stay private, over the program's 3-word public input)…
gas: 12489 (declaring 16384, tier 14)
fee 0.007487437 RAND (incl. two price steps of headroom)
proved in 122.9s: tier 14, 1911152 bytes, outputs [1, 12, 1186432356, 3591337405, 3377802634, 3519326943, 1091785733, 0]
proving the spend authorisation on this machine (tier 10; seconds)…
authorisation proved in 6.8s: tier 10, 1375371 bytes
proving the bundle (tier 14; about a minute and a half on a laptop)…
proved in 111.9s: tier 14, 1500198 bytes
submitted call 5d276bf7cb65cfcd2244ffd05baceaf6cb8082aeed6129a5e87e8737b3374e17
  0 RAND out, 59.709221126 RAND change, fee 0.007487437 RAND, anchored at height 98336, proved in 111.9s (bundle) + 6.8s (auth)
{
  "h_in": "b151f38fbbefd08c9f36e65da89f016ba7fc0ccdb52bddda6544e3d86372d331",
  "h_pub": "70d5ae8935d646f7a0dd426c30aaf68e9bc382534d8a6ced90e363e129403608",
  "height": 98574,
  "index": 0,
  "outputs": [
    1,
    12,
    1186432356,
    3591337405,
    3377802634,
    3519326943,
    1091785733,
    0
  ],
  "program": "fce8474dfdf80b9733e04fb72d4d8d19c40ba5ab646b3d867322daf4b9b599c0",
  "tier": 14,
  "tx": "5d276bf7cb65cfcd2244ffd05baceaf6cb8082aeed6129a5e87e8737b3374e17"
}
input transcript published; open it with `rand open-call 5d276bf7cb65cfcd2244ffd05baceaf6cb8082aeed6129a5e87e8737b3374e17`

स्टेटस 1, बारह खाते, और hex में रूट 46b78564 d60f75bd c9552d8a d1c4aadf 41135405। ट्रांज़ैक्शन में कहीं भी कोई बैलेंस या कुल योग नहीं बताया गया है।

यह tier-14 call है, इसलिए call proof सबसे धीमा भाग है: 123 s, फिर spend प्राधिकरण के लिए 7 s और bundle के लिए 112 s, कुल मिलाकर पाँच मिनट, और अधिकतम मेमोरी उपयोग 6.6 GB। proof 1,911,152 bytes का है। इसमें से लगभग 0.4 MB SHA-256 तालिका का है।

10. स्वयं जाँचें

  1. दावा। program id पर rand_getProgramPublic रिज़र्व का आँकड़ा और लेबल लौटाता है। custodian के पास वास्तव में वह रिज़र्व है या नहीं, यह इस proof के दायरे से बाहर है: इसे ऑन-चेन बैलेंस से, किसी ऑडिटर के पत्र से, या ब्रिज की गई परिसंपत्ति के मामले में उस चेन के अपने rand_getTokenSupply से दिखाया जाता है।
  2. कोड। उसी circuits commit पर my-guests/solvency को फिर से बिल्ड करें और hc की तुलना program के code_hash से करें।
  3. रसीद। स्थिति 1 हो, स्लॉट 7 3735928559 न हो, और program id के बराबर हो। आउटपुट 2 से 6 वह root हैं जिससे हर ग्राहक मिलान करता है।
  4. आपकी अपनी leaf, जैसा कि खंड 7 में बताया गया है।

कोई भी डेमो खातों के साथ call दोहरा सकता है, या कोई बैलेंस बदलकर root को बदलते हुए देख सकता है।

proof आपको क्या नहीं देता

  • स्वयं रिज़र्व। proof किसी संख्या के सापेक्ष देनदारियों का है। उस संख्या के लिए अलग साक्ष्य चाहिए।
  • ग्राहकों के बिना पूर्णता। custodian द्वारा छोड़ा गया खाता केवल वही ग्राहक पकड़ सकता है जिसका वह खाता है। जितने अधिक ग्राहक जाँच करते हैं, गड़बड़ी की गुंजाइश उतनी ही कम रह जाती है।
  • रिज़र्व के समय से मेल खाता क्षण। custodian स्नैपशॉट के एक घंटे के लिए धन उधार ले सकता है। बिना पूर्व घोषणा के, बार-बार लिए गए स्नैपशॉट इस गुंजाइश को कम करते हैं।
  • छिपे हुए पड़ोसी। किसी ग्राहक का path सहोदर योग (sibling sums) दिखाता है (खंड 7)।
  • एक call में 32 से अधिक खाते। देखें बजट।

2026-09-30 को fullnode कमिट 48dc04b (चेन 18) के विरुद्ध अंतिम बार सत्यापित, और circuits `aeacf31` (`guest-sdk/src/lib.rs`, `rand-guest`), the commit fullnode v0.6.7 vendors; every `rand-guest`, `python3` and `rand` output on this page was produced on 2026-09-30, the deploy and the call on chain 18। जहाँ कोड और यह पृष्ठ असहमत हों, वहाँ कोड सही है; हमें बताएँ।