Rand Protocol
ஆவணமாக்கல்
எடுத்துக்காட்டு நிரல்கள்

பொறுப்புகளுக்கான ஒரு சான்று

தனிப்பட்ட வாடிக்கையாளர் இருப்புகளின் மீது SHA-256 Merkle கூட்டுத்தொகை மரத்தை உருவாக்கி, அவற்றின் மொத்தம் வெளியிடப்பட்ட இருப்புநிதித் தொகையால் ஈடுசெய்யப்படுகிறது என்பதை நிரூபிக்கும் ஒரு ரகசிய நிரல் - இடைமுகம், Rust guest, எளிய Python இல் ஒரு வாடிக்கையாளரின் உள்ளடக்கச் சரிபார்ப்பு, வரவுசெலவு வரம்பு, மற்றும் chain 18 இல் இயங்கும் நிரல்.

ஒரு காப்பாளர் ஒவ்வொரு வாடிக்கையாளருக்கும் ஒரு இருப்புத்தொகையைச் செலுத்த வேண்டியவர். காப்பாளர் வெளியிட்ட கையிருப்புத் தொகையை இருப்புகளின் கூட்டுத்தொகை மீறவில்லை என்பதை இந்த நிரல் நிரூபிக்கிறது. இதற்காக எந்த ஒரு இருப்பையோ மொத்தத் தொகையையோ அது வெளியிடுவதில்லை. தமது இருப்பு கணக்கில் சேர்க்கப்பட்டதா என்பதை ஒவ்வொரு வாடிக்கையாளரும் சில வரி Python கொண்டு சரிபார்க்கலாம். அதற்குச் சிறப்புக் கருவிகள் எதுவும் தேவையில்லை.

நான்கு எடுத்துக்காட்டுப் பக்கங்களுக்கும் பொதுவான அமைப்பு எடுத்துக்காட்டு நிரல்கள் பக்கத்தில் உள்ளது.

1. இது எதை நிரூபிக்கிறது

காப்பாளர் ஒரு Merkle கூட்டுத்தொகை மரத்தை உருவாக்குகிறார். ஓர் இலை ஒரு கணக்கைக் குறிக்கிறது. அது வாடிக்கையாளரின் அடையாளம், இருப்பு ஆகியவற்றின் ஹாஷ் ஆகும், அதனுடன் இருப்பும் இருக்கும். ஒரு கணு அதன் இரண்டு குழந்தைக் கணுக்களின் ஹாஷ் ஆகும். அது அவற்றின் கூட்டுத்தொகைகளையும் உள்ளடக்கும், அந்த இரண்டு கூட்டுத்தொகைகளின் கூட்டல் அதனுடன் இருக்கும். ஆகவே வேர் தனக்குக் கீழுள்ள அனைத்து இருப்புகளின் மொத்தத்தையும் கொண்டிருக்கிறது.

மரம் நிரலுக்குள்ளேயே உருவாக்கப்படுகிறது. அதற்கு உள்ளீடு கணக்குகளின் தனிப்பட்ட பட்டியல். அழைப்பு பின்வருவனவற்றை நிரூபிக்கிறது:

  1. ரசீதில் வெளியிடப்பட்ட வேர், காப்பாளர் வழங்கிய கணக்குகளின் மீது அமைந்த கூட்டுத்தொகை மரத்தின் வேர் ஆகும்;
  2. அதிலுள்ள ஒவ்வொரு கூட்டுத்தொகையும் அதன் கீழுள்ள இரண்டின் உண்மையான கூட்டுத்தொகை, மேலும் எங்கும் வழிதல் (overflow) இல்லை;
  3. வேரிலுள்ள மொத்தம், நிறுவும்போது நிர்ணயிக்கப்பட்ட கையிருப்புத் தொகையை மீறவில்லை.

நிரூபணம் இல்லாமல் வெளியிடப்படும் கூட்டுத்தொகை மரத்தால் தர முடியாதது புள்ளி 2. வெறும் கூட்டுத்தொகை மரத்தின் மீதான அறியப்பட்ட தாக்குதல் இதுதான்: காப்பாளர் ஒரு பெற்றோர் கணுவின் கூட்டுத்தொகையை அதன் குழந்தைகளின் கூட்டுத்தொகையைவிடச் சிறியதாக எழுதுகிறார். ஒரே ஒரு பாதையைக் கொண்டு எந்த வாடிக்கையாளராலும் இதைக் கண்டறிய முடியாது. இங்கே கூட்டுத்தொகைகளை நிரலே கணக்கிடுகிறது, வேறு எந்தக் கணக்கீட்டுக்கும் நிரூபணம் இருக்க முடியாது.

நிரூபணம் உள்ளடக்காதது முழுமை: எந்தக் கணக்குகள் சேர்க்கப்படுகின்றன என்பதைக் காப்பாளரே தேர்வு செய்கிறார். இந்த இடைவெளியை வாடிக்கையாளர்கள் மூடுகின்றனர். தமது அடையாளமும் தமது இருப்பும் கொண்ட ஓர் இலை வெளியிடப்பட்ட வேரின் கீழ் உள்ளதா என்பதை ஒவ்வொருவரும் சரிபார்க்கின்றனர் (பிரிவு 7). விடுபட்ட கணக்கை அதன் உரிமையாளர் கண்டுபிடிப்பார்.

2. இடைமுகம்

பொதுச் சொல்பொருள்
0, 1கையிருப்புத் தொகை, சொத்தின் மிகச்சிறிய அலகுகளில் ஒரு u64, முதலில் கீழ்ச் சொல் பின்னர் மேல்ச் சொல்
2ஒரு பதிவுநிலை (snapshot) குறிச்சீட்டு; நிரல் இதைப் படிப்பதில்லை, ஆனால் நிரல் அடையாளம் இதைப் பிணைக்கிறது
தனிப்பட்ட சொல்பொருள்
0கணக்குகளின் எண்ணிக்கை n, அதிகபட்சம் 32
பின்னர், ஒவ்வொரு கணக்குக்கும்அடையாளம் (நான்கு big-endian சொற்களாக 16 பைட்டுகள்), இருப்பின் கீழ்ச் சொல், இருப்பின் மேல்ச் சொல்
வெளியீட்டு இடம்பொருள்
0நிலை: 1 ஈடுசெய்யப்பட்டது, 2 ஈடுசெய்யப்படவில்லை, 3 32-க்கு மேற்பட்ட கணக்குகள், 4 ஒரு கூட்டுத்தொகை வழிந்தது
1n
2 முதல் 6வேர் ஹாஷின் முதல் 20 பைட்டுகள், ஐந்து big-endian சொற்களாக
7பயன்படுத்தப்படவில்லை; ஒரு Rust பேனிக் இங்கே 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 அமைப்பு அழைப்பு அதன் 64-பைட் தொகுதியைப் பதினாறு big-endian சொற்களாக எடுத்துக்கொள்கிறது. எனவே இந்த நிரல் அடையாளத்தை நான்கு big-endian சொற்களாகப் படிக்கிறது, வேரை big-endian சொற்களாக வெளியிடுகிறது: வெளியீடு 2-ஐ hex வடிவில் அச்சிட்டால் அது வேரின் முதல் எட்டு 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();
}

நிரப்புதல் (padding) கையால் எழுதப்படுகிறது. guest_sdk::sha256 எந்த பைட் சரத்தையும் ஏற்று, அதை ஒவ்வொரு பைட்டாக நகலெடுக்கிறது. இங்குள்ள ஒவ்வொரு செய்தியும் அறியப்பட்ட நீளம் கொண்ட முழுச் சொற்களால் ஆனது. எனவே நிரல் 16-சொல் தொகுதியை நேரடியாக நிரப்புகிறது: முதலில் செய்திச் சொற்கள், பின்னர் 0x80000000, பூஜ்ஜியங்கள், கடைசிச் சொல்லில் பிட் நீளம். ஓர் இலைக்கு ஒரு சுருக்கம் போதும். ஒரு கணுவின் 84 பைட்டுகள் இரண்டாவது தொகுதிக்குள் நீள்கின்றன, எனவே ஒரு கணுவுக்கு இரண்டு சுருக்கங்கள் தேவை.

இருப்புகள் u64, கூட்டுத்தொகைகள் சரிபார்க்கப்படுகின்றன. இந்த வகைக்கு எதிர்ம மதிப்புகள் இல்லாததால் இருப்பு எதிர்மமாக இருக்க முடியாது. மொத்தத்தைக் குறைப்பதற்கான மற்றொரு மரபார்ந்த வழியை இது நீக்குகிறது. checked_add வழிதலைச் சுற்றிவந்த கூட்டுத்தொகையாக அல்லாமல் நிலை 4 ஆக மாற்றுகிறது.

கடன்தீர்க்க இயலாமையும் ஒரு முடிவுதான். நிலை 2 என்பது வேர் வெளியிடப்பட்ட ஒரு சாதாரண நிறுத்தம். கையிருப்புத் தொகையை மீறும் இருப்புகளுக்கு நிலை 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 வரி காப்பாளரின் சொந்தப் பார்வை மட்டுமே. அது ஒருபோதும் வெளியிடப்படுவதில்லை.

அடையாளங்கள் தனித்தன்மையுடையவையாகவும் ஊகிக்க இயலாதவையாகவும் இருக்க வேண்டும். ஒரே இருப்புடைய இரண்டு வாடிக்கையாளர்களுக்கு ஒரே இலை வழங்கப்பட்டால், இருவருக்கும் சேர்த்து ஒரே கடன்பொறுப்பைக் காப்பாளர் கணக்கிடக்கூடும். தனக்குரியது என அதன் வாடிக்கையாளர் மட்டுமே அடையாளம் காணக்கூடிய அடையாளம் இதைத் தடுக்கிறது. அண்டை இலையின் ஹாஷைப் பார்க்கும் வாடிக்கையாளர் அண்டையவரின் இருப்பை ஊகித்துச் சோதிப்பதை, ஊகிக்க இயலாத அடையாளம் தடுக்கிறது. செயல்விளக்கம் ஒரு ஹாஷின் முதல் 16 பைட்டுகளைப் பயன்படுத்துகிறது. உண்மையான பயன்பாட்டில் அடையாளம் வாடிக்கையாளரின் கணக்கிலிருந்தும் ஒவ்வொரு பதிவுநிலைக்குமான ஒரு nonce-இலிருந்தும் பெறப்பட்டு, வாடிக்கையாளருக்குக் காட்டப்படும்.

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 சுருக்கங்கள் தேவை, அது பொருந்தாது.

இது செயல்விளக்க அளவு மட்டுமே. இதைத் தாண்ட, மரத்தைப் பல அழைப்புகளில் பிரித்து, ஒவ்வொரு துணை மரத்தின் வேர், கூட்டுத்தொகை ஆகியவற்றுக்கான ஒரு உறுதிப்பாட்டை (commitment) இறுதி அழைப்புக்குள் கொண்டுசெல்ல வேண்டும். வரம்பை மீறும் எந்தப் பணிக்கும் நிரல் எழுதுதல் பக்கம் விவரிக்கும் முறை இது. இந்த எடுத்துக்காட்டு அதைச் செய்வதில்லை.

chain 18 முதல் ஒரு சுருக்கத்தின் செலவு 64 கேஸ், சாதாரணச் சுழற்சிக்கு 1. ஓர் இயக்கத்தின் துல்லியமான கேஸையும் அது அறிவிக்கும் வரம்பையும் wallet அச்சிடுகிறது:

gas: 12489 (declaring 16384, tier 14)

ஒவ்வொரு வரிசைக்கும் 1 கேஸ் செலவாகிறது, ஒரு சுருக்கத்துக்கு மேலும் 63: 7,764 வரிசைகளுடன் 75 × 63 சேர்த்தால் 12,489. கேஸில் மூன்றில் ஒரு பங்குக்கு மேல் ஹாஷிங்கிற்குச் செல்கிறது. (wallet rand-guest run-ஐவிட இரண்டு வரிசைகள் அதிகமாகக் கணக்கிடுகிறது. ஓர் அழைப்பின் பொதுப் பகுதியில் chain 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,

வாடிக்கையாளர் தமது சொந்த அடையாளம், இருப்பு ஆகியவற்றிலிருந்து வேரை மீண்டும் கணக்கிட்டு, அதன் முதல் 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)

நிரல் அடையாளம் கையிருப்புத் தொகையையும் பதிவுநிலைக் குறிச்சீட்டையும் குறியீட்டுடன் பிணைக்கிறது. ஒரு புதிய பதிவுநிலை என்பது ஒரு புதிய நிறுவல். அதன் செலவு சுமார் பத்தில் ஒரு RAND, அதன் அடையாளமே புதிய கோரிக்கையின் பொது அறிவிப்பு.

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 அழைப்பு என்பதால், அழைப்பு நிரூபணமே மெதுவான பகுதி: 123 s, பின்னர் செலவு அங்கீகாரத்திற்கு 7 s, தொகுப்பிற்கு 112 s என மொத்தம் ஐந்து நிமிடங்கள்; உச்ச நினைவகப் பயன்பாடு 6.6 GB. நிரூபணத்தின் அளவு 1,911,152 bytes. அதில் SHA-256 அட்டவணை சுமார் 0.4 MB.

10. நீங்களே சரிபாருங்கள்

  1. கோரிக்கை. நிரல் அடையாளத்தின் மீது rand_getProgramPublic அழைப்பு இருப்புத் தொகையையும் லேபிளையும் திருப்பித் தருகிறது. அந்த இருப்பைப் பாதுகாவலர் உண்மையில் வைத்திருக்கிறாரா என்பது இந்த நிரூபணத்தின் எல்லைக்கு வெளியே உள்ளது: அது சங்கிலியிலுள்ள இருப்பு, தணிக்கையாளரின் கடிதம், அல்லது பாலம் வழியாக வந்த சொத்தெனில் அந்தச் சங்கிலியின் சொந்த rand_getTokenSupply மூலம் காட்டப்படுகிறது.
  2. குறியீடு. அதே circuits commit-இல் my-guests/solvency ஐ மீண்டும் உருவாக்கி, hc ஐ நிரலின் code_hash உடன் ஒப்பிடுங்கள்.
  3. ரசீது. நிலை 1, இடம் 7 3735928559 அல்ல, program நிரல் அடையாளத்திற்குச் சமம். வெளியீடுகள் 2 முதல் 6 வரை, ஒவ்வொரு வாடிக்கையாளரும் ஒப்பிட்டுச் சரிபார்க்கும் வேர் ஆகும்.
  4. உங்கள் சொந்த இலை, பிரிவு 7-இல் உள்ளபடி.

டெமோ கணக்குகளைக் கொண்டு யார் வேண்டுமானாலும் இந்த அழைப்பை மீண்டும் செய்யலாம், அல்லது ஓர் இருப்பை மாற்றி வேர் மாறுவதைக் காணலாம்.

நிரூபணம் உங்களுக்கு எதைத் தருவதில்லை

  • இருப்புகளையே. இந்த நிரூபணம் ஓர் எண்ணுக்கு எதிரான பொறுப்புகளைப் பற்றியது. அந்த எண்ணுக்குத் தனிச் சான்று தேவை.
  • வாடிக்கையாளர்கள் இல்லாமல் முழுமை. பாதுகாவலர் விட்டுவிட்ட ஒரு கணக்கை, அது யாருக்குரியதோ அந்த வாடிக்கையாளர் மட்டுமே கண்டறிய முடியும். எவ்வளவு அதிகமான வாடிக்கையாளர்கள் சரிபார்க்கிறார்களோ, அவ்வளவு குறைவான இடமே மீதமிருக்கும்.
  • இருப்புகளின் நேரத்துடன் பொருந்தும் ஒரு கணம். நிலைப்படம் எடுக்கப்படும் அந்த ஒரு மணிநேரத்திற்காகப் பாதுகாவலர் நிதியைக் கடன் வாங்கலாம். முன்னறிவிப்பில்லாத நேரங்களில் அடிக்கடி எடுக்கப்படும் நிலைப்படங்கள் அந்த வாய்ப்பைக் குறைக்கின்றன.
  • மறைக்கப்பட்ட அண்டைக் கணக்குகள். ஒரு வாடிக்கையாளரின் பாதை உடன்பிறப்புக் கூட்டுத்தொகைகளைக் காட்டுகிறது (பிரிவு 7).
  • ஓர் அழைப்பில் 32-க்கும் அதிகமான கணக்குகள். வரவுசெலவு வரம்பைப் பாருங்கள்.

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 உடன் 2026-09-30 அன்று இறுதியாகச் சரிபார்க்கப்பட்டது. நிரலும் இந்தப் பக்கமும் முரண்படும் இடங்களில் நிரலே சரியானது; எங்களுக்குத் தெரிவியுங்கள்.