ایک قرض دہندہ اپنا اسکورنگ ماڈل شائع کرتا ہے۔ درخواست گزار اسے اپنے ڈیٹا پر چلاتا ہے اور قرض دہندہ کو ایک رسید دیتا ہے جس پر “منظور” یا “مسترد” لکھا ہوتا ہے۔ قرض دہندہ ڈیٹا کبھی نہیں دیکھتا، اور درخواست گزار نہ ماڈل بدل سکتا ہے اور نہ اس میں من گھڑت ڈیٹا ڈال سکتا ہے۔
یہ نجی ان پٹ پر عوامی پروگرام اور عوامی پیرامیٹرز کے ساتھ کسی حساب کو ثابت کرنے کی سب سے چھوٹی کارآمد مثال ہے۔ ماڈل عددِ صحیح کے حساب میں دو تہوں والا نیورل نیٹ ورک ہے۔ یہی ساخت ہر اس قاعدے پر لاگو ہوتی ہے جسے کوئی ریگولیٹر یا فریقِ معاملہ پڑھ سکنا چاہے: قیمت کا فارمولا، اہلیت کی جانچ، خطرے کی حد۔
مثالی پروگرام میں وہ ابتدائی ترتیب درج ہے جو چاروں مثالی صفحات میں مشترک ہے۔
1. یہ کیا ثابت کرتا ہے
تین فریق:
- قرض دہندہ پروگرام کو اس طرح ڈیپلائے کرتا ہے کہ ماڈل اس کا عوامی حصہ ہو۔ پروگرام آئی ڈی اسی ماڈل کی شناخت ہے۔ کوئی بھی چین سے اوزان واپس پڑھ سکتا ہے۔
- ایک توثیق کنندہ (کریڈٹ بیورو، بینک، آجر) درخواست گزار کا ڈیٹا جانتا ہے۔ وہ درخواست گزار کو فیچرز کی قدریں، 16 بائٹ کا ایک بے ترتیب سالٹ، اور کمٹمنٹ
SHA-256(salt ‖ features)پر اپنا دستخط دیتا ہے۔ - درخواست گزار سالٹ اور فیچرز کو نجی ان پٹ کے طور پر دے کر پروگرام کو کال کرتا ہے۔
یہ کال ثابت کرتی ہے کہ:
- ہر فیچر اس حد کے اندر ہے جو ماڈل نے اس کے لیے مقرر کی ہے؛
- ان فیچرز پر ماڈل کا اسکور دہلیزی قدر کے برابر یا اس سے زیادہ ہے (اسٹیٹس
1) یا اس سے کم ہے (اسٹیٹس2)؛ - شائع شدہ کمٹمنٹ سالٹ اور انہی فیچرز کا SHA-256 ہے۔
قرض دہندہ رسید کی پروگرام آئی ڈی اور اسٹیٹس جانچتا ہے، اور یہ کہ کمٹمنٹ وہی ہے جس پر توثیق کنندہ نے دستخط کیے تھے۔ اسے درخواست گزار کے بارے میں صرف ایک بٹ معلوم ہوتا ہے۔
نجی ان پٹ بذاتِ خود دنیا کے بارے میں کچھ ثابت نہیں کرتے۔ نکتہ 3 کے بغیر درخواست گزار کوئی بھی اعداد درج کر سکتا تھا۔ کمٹمنٹ ہی ثبوت میں موجود اعداد کو ان اعداد سے جوڑتی ہے جن کی کسی نے ضمانت دی ہو۔ دستخط کی جانچ خود قرض دہندہ چین سے باہر کرتا ہے: Dilithium یا ECDSA کی تصدیق کال کے بجٹ میں نہیں سماتی، اور اسے ثبوت کے اندر ہونے کی ضرورت بھی نہیں، کیونکہ کمٹمنٹ عوامی ہے۔
2. انٹرفیس
ہر عوامی لفظ ایک i32 ہے، جو اپنے ٹو کمپلیمنٹ u32 کی صورت میں محفوظ ہوتا ہے۔
| عوامی لفظ | مطلب |
|---|---|
| 0 | فیچرز کی تعداد n، 1 سے 16 تک |
| 1 | پوشیدہ اکائیوں کی تعداد h، 1 سے 16 تک |
| 2 | دہلیزی قدر |
| 3 | کسری بٹس کی تعداد، یعنی شفٹ s، 0 سے 31 تک |
پھر 2n الفاظ | ہر فیچر کی اجازت یافتہ min اور max |
پھر h × n الفاظ | پہلی تہ کے اوزان، قطار بہ قطار |
پھر h الفاظ | پہلی تہ کے بائیس |
پھر h الفاظ | دوسری تہ کے اوزان |
| پھر 1 لفظ | دوسری تہ کا بائیس |
| نجی لفظ | مطلب |
|---|---|
| 0 سے 3 | سالٹ، 16 بائٹس، چار big-endian الفاظ کی صورت میں |
| 4 اور آگے | n فیچرز، ہر ایک i32 |
| آؤٹ پٹ خانہ | مطلب |
|---|---|
| 0 | اسٹیٹس: 1 منظور، 2 مسترد، 3 کوئی فیچر حد سے باہر ہے، 4 خراب ماڈل (کوئی سائز حدود سے باہر ہے، یا حساب اوور فلو ہو گیا) |
| 1 | غیر مستعمل |
| 2 سے 6 | کمٹمنٹ کے پہلے 20 بائٹس، پانچ big-endian الفاظ کی صورت میں |
| 7 | غیر مستعمل؛ Rust کا panic یہاں 0xdeadbeef لکھتا ہے |
کمٹمنٹ صرف اسٹیٹس 1 یا 2 کے ساتھ شائع ہوتی ہے۔ حد سے باہر ان پٹ ہونے پر عمل کسی بھی ہیش سے پہلے رک جاتا ہے۔
3. حساب
ماڈل صرف اعدادِ صحیح پر مشتمل ہے۔ مشین میں فلوٹنگ پوائنٹ نہیں ہے، اور تصدیق کنندہ کو اسکور ہوبہو دوبارہ حاصل کر سکنا چاہیے، جس کی ضمانت فلوٹنگ پوائنٹ مختلف مشینوں پر نہیں دیتا۔
hidden[j] = max( (b1[j] + Σ w1[j][i] · x[i]) >> s , 0 ) for each hidden unit j
score = (b2 + Σ w2[j] · hidden[j]) >> s
approved = score >= threshold
اوزان s کسری بٹس کے ساتھ فکسڈ پوائنٹ ہیں: s = 8 کی صورت میں 256 کا وزن 1.0 کے برابر ہے۔ مجموعے i64 ہیں، اور ہر ضرب اور جمع جانچی جاتی ہے، چنانچہ اتنے بڑے اوزان والا ماڈل جو اوور فلو کر دے، غلط اسکور کے بجائے اسٹیٹس 4 دیتا ہے۔ Rust میں منفی i64 پر >> منفی لامتناہی کی جانب گول کرتا ہے، اور Python کا >> بھی یہی کرتا ہے، اسی وجہ سے دس سطروں کا ایک Python فنکشن حوالہ بن سکتا ہے۔
ڈیمو ماڈل میں آٹھ فیچرز اور چار پوشیدہ اکائیاں ہیں۔ اس کے اوزان اس صفحے کے لیے ہاتھ سے لکھے گئے ہیں۔ یہ تربیت یافتہ ماڈل نہیں ہے اور قرض کے بارے میں کچھ نہیں بتاتا۔
{
"shift": 8,
"threshold": 600,
"features": [
{"name": "age_years", "min": 18, "max": 120},
{"name": "income_thousands", "min": 0, "max": 100000},
{"name": "debt_to_income_pct", "min": 0, "max": 1000},
{"name": "on_time_payments_pct", "min": 0, "max": 100},
{"name": "utilisation_pct", "min": 0, "max": 100},
{"name": "history_years", "min": 0, "max": 100},
{"name": "inquiries_12m", "min": 0, "max": 100},
{"name": "delinquencies", "min": 0, "max": 100}
],
"w1": [
[ 64, 96, -512, 1536, -640, 1024, -2048, -8192],
[ 0, 256, -1024, 0, 0, 0, 0, 0],
[ 0, 0, 0, 2560, -1280, 0, -4096, -16384],
[ 128, 0, 0, 0, 0, 2048, 0, 0]
],
"b1": [25600, 12800, -128000, 0],
"w2": [160, 96, 224, 128],
"b2": 76800
}
4. گیسٹ
my-guests/score/src/main.rs، مکمل:
#![no_std]
#![no_main]
use guest_sdk::{halt, read_input, read_public, sha256_compress, write_output};
const MAX_FEATURES: usize = 16;
const MAX_HIDDEN: usize = 16;
const APPROVED: u32 = 1;
const DECLINED: u32 = 2;
const OUT_OF_RANGE: u32 = 3;
const BAD_MODEL: u32 = 4;
/// SHA-256's initial state (FIPS 180-4 §5.3.3).
const IV: [u32; 8] = [
0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19,
];
/// SHA-256 of `words`, each word taken as four big-endian bytes. The message is whole words,
/// so the padding is whole words too: `0x80000000`, zeros, then the bit length in the last
/// word of a block (the length's high word is always zero here).
fn sha256_words(words: &[u32]) -> [u32; 8] {
let mut buf = [0u32; 24];
buf[16..].copy_from_slice(&IV);
let mut fill = 0;
for &w in words {
buf[fill] = w;
fill += 1;
if fill == 16 {
sha256_compress(&mut buf);
fill = 0;
}
}
buf[fill] = 0x8000_0000;
fill += 1;
if fill > 14 {
buf[fill..16].fill(0);
sha256_compress(&mut buf);
fill = 0;
}
buf[fill..15].fill(0);
buf[15] = 32 * words.len() as u32;
sha256_compress(&mut buf);
let mut out = [0u32; 8];
out.copy_from_slice(&buf[16..]);
out
}
/// `weight · x`, added to `acc`; `None` when it does not fit an i64.
fn mul_add(acc: i64, weight: u32, x: i64) -> Option<i64> {
acc.checked_add((weight as i32 as i64).checked_mul(x)?)
}
/// Runs the model in the public segment over the private features.
fn score(features: &[i32], hidden: usize, shift: u32) -> Option<i64> {
let n = features.len();
// The public segment after the header and the feature ranges:
// hidden × n first-layer weights, hidden biases, hidden second-layer weights, one bias.
let w1 = 4 + 2 * n;
let b1 = w1 + hidden * n;
let w2 = b1 + hidden;
let b2 = w2 + hidden;
let mut out = read_public(b2 as u32) as i32 as i64;
for j in 0..hidden {
let mut acc = read_public((b1 + j) as u32) as i32 as i64;
for (i, &x) in features.iter().enumerate() {
acc = mul_add(acc, read_public((w1 + j * n + i) as u32), x as i64)?;
}
// Fixed point: drop the fractional bits, then ReLU.
let h = (acc >> shift).max(0);
out = mul_add(out, read_public((w2 + j) as u32), h)?;
}
Some(out >> shift)
}
/// Public segment, fixed at deploy (every value an i32):
/// [features n, hidden units, threshold, fractional bits,
/// n × (min, max), hidden × n weights, hidden biases, hidden weights, bias]
/// Private input: [salt (4 words), n features].
/// Outputs: [status, 0, commitment (first 5 words), 0], where
/// commitment = SHA-256(salt ‖ features), every word big-endian.
#[no_mangle]
pub extern "C" fn main() -> ! {
let n = read_public(0) as usize;
let hidden = read_public(1) as usize;
let threshold = read_public(2) as i32 as i64;
let shift = read_public(3);
if n == 0 || n > MAX_FEATURES || hidden == 0 || hidden > MAX_HIDDEN || shift > 31 {
write_output(0, BAD_MODEL);
halt();
}
// The committed message: the salt, then the features, in input order.
let mut message = [0u32; 4 + MAX_FEATURES];
for (i, w) in message.iter_mut().enumerate().take(4 + n) {
*w = read_input(i as u32);
}
let mut features = [0i32; MAX_FEATURES];
let mut in_range = true;
for i in 0..n {
let x = message[4 + i] as i32;
let min = read_public(4 + 2 * i as u32) as i32;
let max = read_public(5 + 2 * i as u32) as i32;
in_range &= min <= x && x <= max;
features[i] = x;
}
if !in_range {
write_output(0, OUT_OF_RANGE);
halt();
}
let status = match score(&features[..n], hidden, shift) {
Some(s) if s >= threshold => APPROVED,
Some(_) => DECLINED,
None => BAD_MODEL,
};
let commitment = sha256_words(&message[..4 + n]);
write_output(0, status);
for k in 0..5 {
write_output(2 + k as u32, commitment[k]);
}
halt();
}
ماڈل ڈیٹا ہے، کوڈ نہیں۔ اوزان read_public کے ذریعے پڑھے جاتے ہیں، اس لیے ایک ہی ڈیپلائے شدہ امیج 16 فیچرز اور 16 پوشیدہ اکائیوں تک کے کسی بھی ماڈل کے لیے کام کرتا ہے۔ ماڈل بدلنے کا مطلب ہے اسی کوڈ کا نئے عوامی حصے کے ساتھ نیا ڈیپلائے، اور نئی پروگرام آئی ڈی۔ قرض دہندہ درخواست گزار کے علم کے بغیر اوزان نہیں بدل سکتا، اور درخواست گزار کوئی نرم تر ماڈل نہیں چن سکتا: رسید پروگرام آئی ڈی بتاتی ہے، اور آئی ڈی اوزان کی پابند ہے۔
حدیں ماڈل کا حصہ ہیں۔ ان کے بغیر بھی درخواست گزار کسی قدر کے بارے میں جھوٹ نہیں بول سکتا تھا (کمٹمنٹ اسے روکتی ہے)، لیکن توثیق کنندہ کسی بے معنی قدر پر دستخط کر سکتا تھا، جیسے −5 سال کی عمر، جسے منفی وزن والا ماڈل انعام دیتا۔ یہ جانچ حساب کو بھی محدود رکھتی ہے۔
سالٹ دو کام کرتا ہے۔ یہ کمٹمنٹ کو ناقابلِ قیاس بناتا ہے: آٹھ چھوٹے اعدادِ صحیح میں اینٹروپی کم ہوتی ہے، اور سالٹ کے بغیر کوئی بھی ممکنہ درخواست گزاروں کو ہیش کر کے موازنہ کر سکتا تھا۔ اور یہ 128 بے ترتیب بٹس کو حساب سے گزارتا ہے۔ قیود کے مجموعہ 7 میں ثبوت کے بس ٹوٹلز کو چھپائے جانے سے پہلے، چند چھوٹے نجی الفاظ پر مبنی کال کو خود ثبوت سے بروٹ فورس کیا جا سکتا تھا، اور fullnode کے نوٹس ایسے پروگراموں کو بے ترتیب الفاظ پڑھنے کی ہدایت دیتے تھے۔ چین 18 قیود کا مجموعہ 8 چلاتی ہے، جس میں یہ مسئلہ حل ہو چکا ہے، لیکن سالٹ کی لاگت صرف چار ان پٹ الفاظ ہے اور یہ سوال ہی ختم کر دیتا ہے۔
5. ہوسٹ کی جانب
score.py صرف Python کی معیاری لائبریری استعمال کرتا ہے:
score.py setup <model.json> writes public.txt
score.py witness <model.json> <salt: 32 hex> <x0> <x1> … prints the private words;
stderr: the score, the decision, the commitment
score.py commit <salt: 32 hex> <x0> <x1> … prints the commitment alone
حوالہ جاتی اسکورر اور کمٹمنٹ، مکمل:
def score(m, x):
"""The guest's arithmetic exactly: integers, a floor shift after each layer, ReLU between."""
out = m["b2"]
for row, b, w2 in zip(m["w1"], m["b1"], m["w2"]):
h = max((b + sum(w * xi for w, xi in zip(row, x))) >> m["shift"], 0)
out += w2 * h
return out >> m["shift"]
def commitment(salt: bytes, x):
return hashlib.sha256(salt + b"".join(struct.pack(">i", xi) for xi in x)).digest()
$ cd my-guests/score
$ python3 score.py setup model.json
wrote public.txt (61 words)
$ cat public.txt
8 4 600 8 18 120 0 100000 0 1000 0 100 0 100 0 100 0 100 0 100 64 96 4294966784 1536 4294966656 1024 4294965248 4294959104 0 256 4294966272 0 0 0 0 0 0 0 0 2560 4294966016 0 4294963200 4294950912 128 0 0 0 0 2048 0 0 25600 12800 4294839296 0 160 96 224 128 76800
بڑے اعداد منفی اوزان ہیں: 4294966784 دراصل −512 ہے۔
گیسٹ کو اس حوالے کے مقابل 300 بے ترتیب درخواست گزاروں پر جانچا گیا، جس میں فیصلے اور کمٹمنٹ کے پانچوں الفاظ کا موازنہ کیا گیا، اور ان درخواست گزاروں پر بھی جن کے اسکور 599 اور 600 ہیں۔ دونوں ہر ایک پر متفق ہیں۔
6. بلڈ اور رن
$ rand-guest build my-guests/score --max-words 65535
462 words against a cap of 65535 (fits); 0 ecall(s) with a non-static a7
OK
wrote my-guests/score/image.bin and its .sha256 (462 words, hc c63d7b15a165a11d007ce48bc37563b71f77fcc4991ffe0182c8cf4c77b6e7b5, program id ce8d234faf737c24bdd2826933ac843973c140c53e76fbb2cccaef3073da9818)
ایک درخواست گزار جس کی عمر 41 سال، آمدنی 85 ہزار، قرض بمقابلہ آمدنی 28%، 97% ادائیگیاں بروقت، استعمال 22%، 12 سال کی تاریخ، ایک انکوائری اور کوئی نادہندگی نہیں:
$ python3 score.py witness model.json 00112233445566778899aabbccddeeff 41 85 28 97 22 12 1 0 > witness.txt
score 1075 approved
commitment 9430c3818f5966f8dd33f78e05a7d079355191e6
$ cat witness.txt
1122867 1146447479 2291772091 3437096703 41 85 28 97 22 12 1 0
$ rand-guest run image.bin --public $(cat public.txt) --input $(cat witness.txt) --tier 14
out[0] = 1
out[1] = 0
out[2] = 2486223745
out[3] = 2405000952
out[4] = 3711170446
out[5] = 94883961
out[6] = 894538214
out[7] = 0
cycles 1810
tier 12
tier 14: fits (cycles 1946 of 16383, Poseidon2 permutations 136 of 2048)
2486223745 دراصل 0x9430c381 ہے، یعنی کمٹمنٹ کے پہلے چار بائٹس۔ اسکور، 1075، آؤٹ پٹ میں کہیں ظاہر نہیں ہوتا۔
دوسرا درخواست گزار (23، 31، 55، 82، 91، 2، 6، 2، ایک مختلف سالٹ کے ساتھ) 417 اسکور کرتا ہے اور اپنی کمٹمنٹ کے ساتھ out[0] = 2 دیتا ہے، انہی 1,810 سائیکلوں میں۔ پہلا درخواست گزار، عمر 17 کر دینے پر، out[0] = 3 دیتا ہے اور کوئی کمٹمنٹ نہیں۔
7. بجٹ
| پروگرام | 462 الفاظ |
| عوامی حصہ | 61 الفاظ |
| نجی الفاظ | 12 |
| سائیکل | 1,810 |
| SHA-256 کمپریشنز | 1 (48 بائٹس کا پیغام ایک بلاک میں سما جاتا ہے) |
| درجہ | 12 |
یہ چاروں پروگراموں میں سب سے سستا ہے۔ فارورڈ پاس 36 ضربوں پر مشتمل ہے۔ پروگرام کی حدود پر ماڈل، یعنی 16 فیچرز اور 16 پوشیدہ اکائیاں، 272 ضربوں اور 325 الفاظ کے عوامی حصے پر مشتمل ہوتا ہے۔ ایمولیٹر میں اس کی پیمائش 7,900 سائیکل ہے، جو درجہ 14 کا تقریباً نصف ہے۔
رن ڈیٹا پر منحصر نہیں: 200 بے ترتیب درخواست گزاروں میں سے ہر ایک نے، خواہ منظور ہوا ہو یا مسترد، ٹھیک 1,810 سائیکل لیے۔ کال جو گیس کی حد ظاہر کرتی ہے وہ عوامی ہوتی ہے اور رن کی گیس سے گول کی جاتی ہے، اس لیے جس پروگرام کے سائیکلوں کی تعداد اس کے ان پٹ کے ساتھ بدلے، وہ ان کا کچھ حصہ افشا کر دے گا۔ اس پروگرام کے پاس اس راستے سے افشا کرنے کو کچھ نہیں۔
چین 18 سے والیٹ رن کی ٹھیک گیس اور ظاہر کی جانے والی حد پرنٹ کرتا ہے:
gas: 2011 (declaring 2048, tier 12)
1,948 قطاریں، ہر ایک 1 گیس کی، اور ایک کمپریشن کے لیے مزید 63۔
8. ڈیپلائے
ماڈل کے 61 الفاظ کی ادائیگی کوڈ کے الفاظ کی طرح ہوتی ہے: 0.001 + 0.0001 × (462 + 61) = 0.0533 RAND۔
$ rand fee deploy 462 --public-words 61
0.0533 RAND
$ rand program deploy image.bin --public public.txt
program id: 7bbec14289f4446231b3a9a5ac18cb0613a373ca8a14fe4f046f3fde7ae6c73c (462 words, hc 157b3dc61da165a18be47c00b76375c3c4fc771f01fe1f994ccfc882b5e7b677, public input 61 words, digest a08a7c691c45babeb39e953930d4d7174662b7b8adcc2d0f4e6c193d362d6668)
proving the spend authorisation on this machine (tier 10; seconds)…
authorisation proved in 7.4s: tier 10, 1364940 bytes
proving the bundle (tier 14; about a minute and a half on a laptop)…
proved in 123.5s: tier 14, 1497319 bytes
submitted deploy d47a9323ea53bfafc3faa36d004416d374bf3c2a48971d87e346be426b0caf14
0 RAND out, 59.7229 RAND change, fee 0.0533 RAND, anchored at height 98062, proved in 123.5s (bundle) + 7.4s (auth)
9. کال
$ rand call 7bbec14289f4446231b3a9a5ac18cb0613a373ca8a14fe4f046f3fde7ae6c73c \
$(sed 's/[0-9][0-9]*/--input &/g' witness.txt)
proving the call locally (12 inputs stay private, over the program's 61-word public input)…
gas: 2011 (declaring 2048, tier 12)
fee 0.005673037 RAND (incl. two price steps of headroom)
proved in 30.6s: tier 12, 1838256 bytes, outputs [1, 0, 2486223745, 2405000952, 3711170446, 94883961, 894538214, 0]
proving the spend authorisation on this machine (tier 10; seconds)…
authorisation proved in 6.8s: tier 10, 1369611 bytes
proving the bundle (tier 14; about a minute and a half on a laptop)…
proved in 124.3s: tier 14, 1499112 bytes
submitted call 454c1b9eb1e159e682d4ff26b71f77d8a950b813533d91a89293dd432fdcf6f7
0 RAND out, 59.696058627 RAND change, fee 0.005673037 RAND, anchored at height 98832, proved in 124.3s (bundle) + 6.8s (auth)
{
"h_in": "ef80c744a8cdea62b56e334baaf7372e4a2e6c8282d37aa8ae96b4f039ec1a22",
"h_pub": "a08a7c691c45babeb39e953930d4d7174662b7b8adcc2d0f4e6c193d362d6668",
"height": 98993,
"index": 0,
"outputs": [
1,
0,
2486223745,
2405000952,
3711170446,
94883961,
894538214,
0
],
"program": "7bbec14289f4446231b3a9a5ac18cb0613a373ca8a14fe4f046f3fde7ae6c73c",
"tier": 12,
"tx": "454c1b9eb1e159e682d4ff26b71f77d8a950b813533d91a89293dd432fdcf6f7"
}
input transcript published; open it with `rand open-call 454c1b9eb1e159e682d4ff26b71f77d8a950b813533d91a89293dd432fdcf6f7`
اسٹیٹس 1 اور hex میں کمٹمنٹ 9430c381 8f5966f8 dd33f78e 05a7d079 355191e6۔ h_pub ماڈل کے 61 الفاظ کا ڈائجسٹ ہے۔ فیچرز، سالٹ اور اسکور ٹرانزیکشن میں شامل نہیں ہیں۔
Apple Silicon لیپ ٹاپ پر کال میں تین منٹ سے کچھ زیادہ لگے: کال کے ثبوت کے لیے 31 s، خرچ کی اجازت کے لیے 7 s اور بنڈل کے لیے 124 s، اور زیادہ سے زیادہ میموری 6.2 GB۔ ثبوت کا حجم 1,838,256 بائٹس ہے۔
10. خود جانچیے
قرض دہندہ کی جانب، صرف رسید اور توثیق کنندہ کی دستخط شدہ کمٹمنٹ کے ساتھ:
- ماڈل۔ پروگرام آئی ڈی پر
rand_getProgramPublic61 الفاظ واپس کرتا ہے۔ ان کا موازنہ شائع شدہmodel.jsonسے کیجیے (score.py setupانہیں دوبارہ بناتا ہے)۔ - کوڈ۔
my-guests/scoreکو اسی circuits کمٹ پر دوبارہ بلڈ کیجیے اورhcکا موازنہ پروگرام کےcode_hashسے کیجیے۔ - رسید۔
programماڈل کی آئی ڈی ہے، آؤٹ پٹ 0 کی قدر1ہے، خانہ 7 کی قدر3735928559نہیں ہے۔ - کمٹمنٹ۔ آؤٹ پٹ 2 سے 6، hex میں پرنٹ کیے جائیں تو، اس کمٹمنٹ کے پہلے 20 بائٹس ہیں جس پر توثیق کنندہ نے دستخط کیے:
$ python3 score.py commit 00112233445566778899aabbccddeeff 41 85 28 97 22 12 1 0
9430c3818f5966f8dd33f78e05a7d079355191e6
انکار بھی ایک رسید ہے۔ دوسرے درخواست گزار کی کال، chain 18 پر 119e7834…1b3b (جو chain 20 پر c8a60183…9f73 کے طور پر دہرائی گئی اور وہاں بھی انکار ہی دیتی ہے)، اسی طریقے سے ثابت اور کمٹ کی گئی:
$ python3 score.py witness model.json 0f1e2d3c4b5a69788796a5b4c3d2e1f0 23 31 55 82 91 2 6 2 > witness.txt
score 417 declined
commitment 0313ea462178574c49a10fe7ea1d84207652e1a3
$ rand call 7bbec14289f4446231b3a9a5ac18cb0613a373ca8a14fe4f046f3fde7ae6c73c \
$(sed 's/[0-9][0-9]*/--input &/g' witness.txt)
…
gas: 2011 (declaring 2048, tier 12)
proved in 26.1s: tier 12, 1836624 bytes, outputs [2, 0, 51636806, 561534796, 1235292135, 3927802912, 1985143203, 0]
…
submitted call 119e7834033edd19bba8e10c1a764e8bdbc0b1c8415a42f041faa392c6411b3b
اسٹیٹس 2 ہے، اور 51636806 دراصل 0x0313ea46 ہے۔ گیس، اعلان کردہ حد اور درجہ وہی ہیں جو منظور شدہ کال کے تھے۔ چنانچہ chain پر دونوں کالیں صرف اسٹیٹس ورڈ اور کمٹمنٹ میں مختلف ہیں، کسی اور چیز میں نہیں۔ درخواست گزار کے پاس انکار کو شائع کرنے کی کوئی وجہ نہیں۔ لیکن قرض دہندہ دونوں صورتوں میں رسید طلب کر سکتا ہے، اور جس درخواست گزار کو انکار ملا ہو وہ منظوری کی رسید پیش نہیں کر سکتا۔
ثبوت آپ کو کیا نہیں دیتا
- درست ڈیٹا۔ ثبوت یہ دکھاتا ہے کہ ماڈل کمٹ شدہ اقدار پر چلا۔ یہ اقدار درست ہیں یا نہیں، اس کی ضمانت تصدیق کنندہ کا قول ہے، اور اس کے لیے قرض دہندہ کو تصدیق کنندہ کے دستخط پر بھروسا کرنا پڑتا ہے۔
- ایسا درخواست گزار جسے جوڑا نہ جا سکے۔ کمٹمنٹ ایک مستقل شناخت کنندہ ہے: تصدیق کنندہ اسے پہچان سکتا ہے، اور ایک ہی کمٹمنٹ والی دو رسیدوں کا مطلب ہے ایک ہی درخواست گزار اور ایک ہی ڈیٹا۔ اگر تصدیق کنندہ ہر درخواست کے لیے نیا سالٹ دے تو دوسرا مسئلہ حل ہو جاتا ہے، پہلا نہیں۔
- خفیہ ماڈل۔ اوزان عوامی ہیں۔ جس قاعدے کو لوگوں کا پڑھ سکنا ضروری ہو، اس کے لیے یہی تو مقصد ہے۔ لیکن جو قرض دہندہ اپنے ماڈل کو تجارتی راز سمجھتا ہو، اس کے لیے یہ ایک خامی ہے۔ درخواست گزار وہ ان پٹ بھی تلاش کر سکتا ہے جن سے وہ پاس ہو جائے، مگر جب تک تصدیق کنندہ ان پر دستخط نہ کرے وہ انہیں استعمال نہیں کر سکتا۔
- بددیانت تصدیق کنندہ کی ٹٹول سے تحفظ۔ جو بھی خصوصیات جانتا ہو وہ عوامی ماڈل خود چلا سکتا ہے۔ یہاں رازداری درخواست گزار کو قرض دہندہ اور عوام سے حاصل ہے، اس فریق سے نہیں جس نے ڈیٹا فراہم کیا۔
- بڑا ماڈل۔ سولہ خصوصیات اور سولہ پوشیدہ اکائیاں ایک اسکور کارڈ ہیں، گہرا نیٹ ورک نہیں۔ ایک کال کی بالائی حد درجہ 14 ہے، یعنی تقریباً سولہ ہزار سائیکل۔