این پروګرام د یوه ټاکلي لېست غړي ته اجازه ورکوي چې یوه رایه ورکړي، پرته له دې چې څرګنده کړي چې کوم غړی دی. لېست د Keccak-256 هشونو یوه Merkle ونه ده، چې په هماغه ډول جوړېږي لکه د Ethereum د airdrop لېست، نو هماغه وسایل یې جوړوي. پروګرام په زنځیر 18 ځای پر ځای شوی، او وروستۍ برخه یې د نمایشي غړو سره بلي چې تاسو یې پخپله کارولی شئ.
بېلګه پروګرامونه هغه چمتووالی لري چې څلور واړه بېلګه پاڼې یې شریکوي: د circuits checkout، والټ، او د سرچینو د ترلاسه کولو ځای.
1. څه ثابتوي
یو تنظیموونکی د غړو لېست لري. هر غړی یو 32-بایټي راز لري. تنظیموونکی هېڅکله رازونه نه ویني: هر غړی یوه پاڼه ورسپاري، keccak256(secret ‖ tag)، او تنظیموونکی د پاڼو پر سر یوه Merkle ونه جوړوي.
یوه رایه یو بلنه ده. دا پرته له دې چې بل څه څرګند کړي، ثابتوي چې:
- بلونکی یو داسې راز پېژني چې پاڼه یې په ونه کې ده؛
- خپره شوې انتخاب یو له اجازه لرونکو انتخابونو څخه دی؛
- خپور شوی باطلوونکی
keccak256(secret ‖ tag ‖ poll id)دی.
باطلوونکی په یوه ټولټاکنه کې د یوه راز د هرې رایې لپاره یو شان وي، او په هره بله ټولټاکنه کې توپیر لري. څوک چې رایې شمېري، هر باطلوونکی یو ځل شمېري. دا له پاڼې سره نه تړل کېږي: له باطلوونکي څخه بېرته پاڼې ته رسېدل راز ته اړتیا لري.
زنځیر دویمه رایه نه ردوي. په Rand کې پروګرام ذخیره نه لري، نو باطلوونکی نشي په یاد ساتلی (پروګرامونه). د یوه راز سره دوه بلنې دواړه تاییدېږي او دواړه رسید پرېږدي. د «یو باطلوونکی، یوه رایه» قاعده د شمېرونکي له خوا، د رسیدونو پر سر، پلي کېږي. هر څوک کولی شي هماغه شمېرنه وکړي، او همدا شی د رایو مجموعه د څېړلو وړ ګرځوي.
2. انٹرفېس
ونه، ټولټاکنه او د انتخابونو شمېر د هرې رایې لپاره یو شان دي، نو دوی په عامه برخه کې ځي، چې د ځای پر ځای کولو پر مهال ټاکل کېږي. بیا د پروګرام پېژندنه یوازې همدا ټولټاکنه نوموي او بله نه.
| عامه کلمه | مانا |
|---|---|
| 0 | د ونې ژورتیا d، له 1 تر 20 |
| 1 | د ټولټاکنې پېژندنه |
| 2 | د انتخابونو شمېر؛ انتخاب 0 .. choices − 1 دی |
| 3 تر 10 | رېښه، 32 بایټه د اتو little-endian کلمو په توګه |
| خصوصي کلمه | مانا |
|---|---|
| 0 تر 7 | راز |
| 8 | د غړي د پاڼې شاخص |
| 9 | انتخاب |
| 10 او وروسته | د Merkle لار: d خور-ورور غوټې، هره یې 8 کلمې، له پاڼې پورته |
| د وتنې ځای | مانا |
|---|---|
| 0 | حالت: 1 رایه ورکړل شوه، 2 غړی نه دی، 3 انتخاب له حد بهر، 4 ناسم چمتووالی |
| 1 | انتخاب |
| 2 تر 6 | د باطلوونکي لومړي 20 بایټه، د پنځو little-endian کلمو په توګه |
| 7 | نه کارول کېږي؛ د Rust panic دلته 0xdeadbeef لیکي |
یو 32-بایټي هش اته کلمې دی، او اته کلمې ټوله وتنه ده. د 160 بیټونو خپرول د حالت او انتخاب لپاره ځای پرېږدي. دوه غړي به یوازې د هش ټکر له لارې یو 160-بیټي باطلوونکی شریک کړي، چې موندل یې شاوخوا 2⁸⁰ هڅې غواړي.
د بایټونو ترتیب. Keccak پر بایټونو کار کوي. د ماشین KECCAK syscall حالت د کلمو په توګه اخلي، چې د حالت بایټ i د کلمې i / 4 په بایټ i mod 4 کې وي. نو 32 بایټه په یو وخت کې د څلورو بایټونو په لوستلو، little-endian، په اتو کلمو بدلېږي، او په عامه برخه کې رېښه یوازې د رېښې بایټونه دي چې په همدې ډول لوستل شوي.
3. مېلمه پروګرام
my-guests/allowlist/src/main.rs، بشپړ:
#![no_std]
#![no_main]
use guest_sdk::{halt, keccak, read_input, read_public, write_output};
const MAX_DEPTH: u32 = 20;
const OK: u32 = 1;
const NOT_MEMBER: u32 = 2;
const BAD_CHOICE: u32 = 3;
const BAD_SETUP: u32 = 4;
/// The 32 bytes hashed after a secret to make its leaf: the ASCII tag, zero-padded.
const LEAF_TAG: [u32; 8] = tag_words(b"rand-allowlist-leaf-v1");
/// The first 28 bytes hashed after a secret to make its nullifier; the poll id is the last 4.
const NULL_TAG: [u32; 8] = tag_words(b"rand-allowlist-null-v1");
/// An ASCII tag as eight words: byte `i` of the tag is byte `i % 4` of word `i / 4`.
const fn tag_words(tag: &[u8]) -> [u32; 8] {
let mut w = [0u32; 8];
let mut i = 0;
while i < tag.len() {
w[i / 4] |= (tag[i] as u32) << (8 * (i % 4));
i += 1;
}
w
}
/// Keccak-256 of a 64-byte message, the hash Ethereum calls `keccak256(abi.encodePacked(a, b))`.
/// The message is one rate block, so this is one permutation: the two halves go into the first
/// 16 words of the state, `0x01` follows them, and `0x80` closes the 136-byte rate.
///
/// `a_second` is 0 or 1. When it is 1 the halves trade places. The place is computed as an
/// offset, not chosen by a branch, so both orders execute the same instructions.
fn hash2(a: &[u32; 8], b: &[u32; 8], a_second: u32) -> [u32; 8] {
let at = 8 * (a_second & 1) as usize;
let mut st = [0u32; 50];
st[at..at + 8].copy_from_slice(a);
st[8 - at..16 - at].copy_from_slice(b);
st[16] = 0x01;
st[33] = 0x8000_0000;
keccak(&mut st);
let mut out = [0u32; 8];
out.copy_from_slice(&st[..8]);
out
}
fn read8(at: u32) -> [u32; 8] {
let mut w = [0u32; 8];
for (i, x) in w.iter_mut().enumerate() {
*x = read_input(at + i as u32);
}
w
}
/// Public segment, fixed at deploy: [depth, poll id, number of choices, root (8 words)].
/// Private input: [secret (8 words), leaf index, choice, siblings (8 words per level)].
/// Outputs: [status, choice, nullifier (5 words), 0].
#[no_mangle]
pub extern "C" fn main() -> ! {
let depth = read_public(0);
let poll = read_public(1);
let choices = read_public(2);
if depth == 0 || depth > MAX_DEPTH {
write_output(0, BAD_SETUP);
halt();
}
let secret = read8(0);
let index = read_input(8);
let choice = read_input(9);
// Walk from the leaf to the root. Bit `level` of the index says whether the running hash
// is the right child at that level.
let mut cur = hash2(&secret, &LEAF_TAG, 0);
let mut level = 0;
while level < depth {
let sib = read8(10 + 8 * level);
cur = hash2(&cur, &sib, index >> level);
level += 1;
}
let mut diff = 0u32;
for k in 0..8 {
diff |= cur[k] ^ read_public(3 + k as u32);
}
let mut ctx = NULL_TAG;
ctx[7] = poll;
let nullifier = hash2(&secret, &ctx, 0);
if diff != 0 {
write_output(0, NOT_MEMBER);
} else if choice >= choices {
write_output(0, BAD_CHOICE);
} else {
write_output(0, OK);
write_output(1, choice);
for k in 0..5 {
write_output(2 + k as u32, nullifier[k]);
}
}
halt();
}
په دې کې درې شیان د کاپي کولو وړ دي.
د هر هش لپاره یو پرمیوټیشن. guest_sdk::keccak256 هر بایټ لړۍ اخلي، او د دې بیه د بایټ حلقو په بڼه ورکوي. دلته هر پیغام دقیقاً 64 بایټه دی، چې له 136-بایټي نرخ کم دی، نو ډکونه دوه ثابتې کلمې دي او هش یو KECCAK بلنه ده پر هغه حالت چې د کلمو د کاپي له لارې ډک شوی. د Ethereum په اصطلاح، hash2(a, b, 0) د دوو bytes32 لپاره keccak256(abi.encodePacked(a, b)) دی.
پاڼه او باطلوونکی د ونې له غوټې سره نشي ګډوډېدلی. یوه غوټه دوه 32-بایټي ماشوم هشونه هش کوي. یوه پاڼه یو راز او یو ټاکلی ASCII ټګ هش کوي، او یو باطلوونکی یو راز، بل ټګ او د ټولټاکنې پېژندنه هش کوي. د دې لپاره چې پاڼه د غوټې په توګه تېره شي، یو له ماشومانو یې باید له ټګ سره برابر وي، چې مانا یې د Keccak د preimage موندل دي.
لار د شاخص پر بنسټ له څانګېدو پرته وهل کېږي. لومړۍ نسخې د دوو نیمایو ترتیب د ماسک شوي تبادلې په مرسته ټاکه، او کمپایلر ماسک بېرته په څانګه بدل کړ: اجرا د پاڼې په شاخص کې د هر 1 بیټ لپاره 9 نور سایکلونه واخیستل. د سایکلونو شمېر پخپله نه خپرېږي، خو هغه د ګاز حد چې یوه بلنه یې اعلانوي له همدې څخه ګردېږي (6مه برخه)، نو هغه اجرا چې په شاخص پورې تړلې وي، کولی شي د شاخص یو څه برخه افشا کړي. د هرې نیمایي په یوه محاسبه شوي افسیټ کې لیکلو دا ستونزه حل کړه: اوس هر د پاڼې شاخص هماغه 3,208 سایکلونه چلوي.
4. د کوربه اړخ
تنظیموونکی او رایه ورکوونکي هماغه Keccak ته اړتیا لري چې ماشین یې محاسبه کوي. allowlist.py له تړاوونو پاک Python سکریپټ دی چې خپل Keccak-f[1600] لري (د Python hashlib.sha3_256 SHA-3 دی، چې په بل ډول ډکوي او بېل ډایجسټونه ورکوي). دا دوه دندې ترسره کوي:
allowlist.py setup <depth> <poll id> <choices> <secrets file> writes public.txt, prints the root
allowlist.py witness <depth> <poll id> <secrets file> <member> <choice>
prints the private words and the nullifier
ټوله ونه، د سکریپټ په اصطلاح:
LEAF_TAG = b"rand-allowlist-leaf-v1".ljust(32, b"\0")
NULL_TAG = b"rand-allowlist-null-v1".ljust(28, b"\0")
EMPTY = bytes(32) # an unused leaf: no secret hashes to it
def levels(depth, secrets):
row = [keccak256(s + LEAF_TAG) for s in secrets]
row += [EMPTY] * ((1 << depth) - len(row))
out = [row]
while len(row) > 1:
row = [keccak256(row[i] + row[i + 1]) for i in range(0, len(row), 2)]
out.append(row)
return out
nullifier = keccak256(secret + NULL_TAG + poll.to_bytes(4, "little"))
په تولید کې تنظیموونکی پاڼې لري، نه رازونه، او هر رایه ورکوونکی له خپرو شویو پاڼو څخه خپل شاهد جوړوي. سکریپټ د رازونو دوتنه ځکه اخلي چې نمایش دواړه رولونه لوبوي.
نمایشي ټولټاکنه ژورتیا 10 (1,024 پاڼې)، د ټولټاکنې پېژندنه 1 او درې انتخابونه لري. د دې د اتو غړو رازونه په demo-secrets.txt کې دي، په هره کرښه کې یو 64-hex راز، او په قصد عامه دي ترڅو هر څوک وکولی شي پروګرام وبلي:
$ python3 allowlist.py setup 10 1 3 demo-secrets.txt
root ce8d6ef78a2ccaab688afa50ff969b0f89b23e7f32d8c3746848b46f773f4750
wrote public.txt
$ cat public.txt
10 1 3 4151217614 2882153610 1358596712 261854975 2134815369 1958991922 1874085992 1346846583
د رېښې لومړۍ کلمه، 4151217614، 0xf76e8dce ده: د رېښې لومړي څلور بایټه ce 8d 6e f7 چې little-endian لوستل شوي.
5. جوړول او چلول
$ rand-guest build my-guests/allowlist --max-words 65535
427 words against a cap of 65535 (fits); 0 ecall(s) with a non-static a7
OK
wrote my-guests/allowlist/image.bin and its .sha256 (427 words, hc 420876739f0987ae7f0fbd23a98312ed4452b7e77cf6153e424ed02aca7b5afe, program id 93c780859b60516408099dc45247a21aead612f0c65c667248253533dd932bb3)
پنځم غړی انتخاب 2 ته رایه ورکوي. شاهد 90 کلمې دی: 8 د راز لپاره، شاخص، انتخاب او 80 د لارې لپاره.
$ cd my-guests/allowlist
$ python3 allowlist.py witness 10 1 demo-secrets.txt 5 2 > witness.txt
nullifier b5516c17d7f51034998f837217777deb8bc90886
nullifier words 392974773 873526743 1921224601 3950868247 2248722827
$ rand-guest run image.bin --public $(cat public.txt) --input $(cat witness.txt) --tier 14
out[0] = 1
out[1] = 2
out[2] = 392974773
out[3] = 873526743
out[4] = 1921224601
out[5] = 3950868247
out[6] = 2248722827
out[7] = 0
cycles 3208
tier 12
tier 14: fits (cycles 3342 of 16383, Poseidon2 permutations 134 of 2048)
پنځه د باطلوونکي کلمې هماغه دي چې سکریپټ له ماشین بهر محاسبه کړې وې. ناکامۍ په پاکه توګه د یوه حالت سره ودرېږي، نو هغه هم ثابتېدای شي. هماغه شاهد چې د راز لومړۍ کلمه یې بدله شوې وي out[0] = 2 ورکوي او بل هېڅ نه، او هغه غړی چې د 3 څخه انتخاب 3 غواړي out[0] = 3 ورکوي.
6. بودیجه
| پروګرام | 427 کلمې |
| سایکلونه | د 10-ژورتیا ونې لپاره 3,208؛ د ډایجسټ قطارونو سره 3,342 |
| د Keccak پرمیوټیشنونه | 12: یوه پاڼه، لس غوټې، یو باطلوونکی. د یوې بلنې حد 128 دی |
| د Poseidon2 پرمیوټیشنونه | له 2,048 څخه 134، چې ټول یې د پروګرام، ننوتنې او عامه ډایجسټونه دي |
| کچه | 12 |
د ژورتیا هره اضافي کچه یو پرمیوټیشن او شاوخوا 270 سایکلونه لګوي. یوه 20-ژورتیا ونه (یو میلیون غړي) 5,866 سایکلونه او 22 پرمیوټیشنونه اندازه کوي، چې کچه 14 ده، هغه لوړه کچه چې یوه بلنه یې کارولی شي.
له زنځیر 18 راهیسې یوه بلنه د ګاز بیه ورکوي، او د Keccak پرمیوټیشن ګران لارښوونه ده: 192 ګاز د یوه عادي سایکل د 1 په پرتله. والټ د یوې اجرا دقیق ګاز او هغه حد چاپوي چې د هغې لپاره یې اعلانوي:
gas: 5636 (declaring 6144, tier 12)
د اجرا هر قطار 1 ګاز لګوي، او د Keccak قطار 191 نور لګوي: 3,344 قطارونه جمع 12 × 191 کېږي 5,636، او دوه پنځمه برخه یې دولس هشونه دي. والټ د rand-guest run په پرتله دوه نور قطارونه شمېري. په زنځیر 18 کې د بلنې ثبوت له خپلې معاملې سره تړل کېږي، او دا تړاو د عامې برخې د اتو اضافي کلمو په توګه لېږدول کېږي، چې دوه ډایجسټ قطارونه زیاتوي. اعلان شوی حد، 6,144، هغه دقیق شمېر دی چې د 1,024 تر یوه مضرب پورې پورته ګرد شوی. حد عامه دی او دقیق شمېر نه دی.
هغه ثبوت چې د Keccak جدول لېږدوي لوی دی. دا یو 3,346,865 بایټه دی، په زنځیرونو 18 تر 20 کې د 4,194,304 (4 MiB) حد په پرتله. پورته د 20-ژورتیا شمېرې د امولېټر اندازې دي، او د دې پاڼې لپاره په هغه ژورتیا کې هېڅ ثبوت نه دی جوړ شوی.
7. ځای پر ځای کول
ځای پر ځای کول عامه برخه لېږدوي، نو فیس یې 11 کلمې د 427 کوډ کلمو سره شمېري: 0.001 + 0.0001 × 438 = 0.0448 RAND.
$ rand fee deploy 427 --public-words 11
0.0448 RAND
$ rand program deploy image.bin --public public.txt
program id: ad2f719f12d01c9f3c0962092b9898b75b0914bbb817031d51be13e54c05b970 (427 words, hc 73760842ae87099f23bd0f7fed1283a9e7b752443e15f67c2ad04e42fe5a7bca, public input 11 words, digest 2296cfca8db9d38bd0b7579056c9dea3c8d8005df7b42e2b1e954a75fed67510)
proving the spend authorisation on this machine (tier 10; seconds)…
authorisation proved in 22.9s: tier 10, 1370827 bytes
proving the bundle (tier 14; about a minute and a half on a laptop)…
proved in 190.2s: tier 14, 1497544 bytes
submitted deploy 05f8bfcbf9fccedbd53c3ba41bcc32dc8070ed3433364fc591b4f00699438de6
0 RAND out, 59.9552 RAND change, fee 0.0448 RAND, anchored at height 97632, proved in 190.2s (bundle) + 22.9s (auth)
هغه پېژندنه چې deploy یې چاپوي، ad2f719f…b970، هغه نه ده چې rand-guest build چاپ کړې وه. د عامې برخې سره پېژندنه blake3("rand-program-2", base_pc ‖ len ‖ words ‖ len ‖ public) ده، نو رېښه، د ټولټاکنې پېژندنه او د انتخابونو شمېر تړي. د هماغو غړو پر سر دویمه ټولټاکنه د هماغه کوډ دویم ځای پر ځای کول دي د بلې ټولټاکنې پېژندنې سره، او بېله د پروګرام پېژندنه او بېل باطلوونکي ترلاسه کوي.
hc هم په بل ډول لیکل کېږي: rand-guest خپلې اته کلمې هره big-endian چاپوي او والټ د هرې کلمې بایټونه little-endian چاپوي، نو 42087673 په 73760842 بدل شو. دا هماغه ډایجسټ دی.
$ rand program show ad2f719f12d01c9f3c0962092b9898b75b0914bbb817031d51be13e54c05b970
{
"base_pc": 4096,
"code_hash": "73760842ae87099f23bd0f7fed1283a9e7b752443e15f67c2ad04e42fe5a7bca",
"deployed_at": 97821,
"id": "ad2f719f12d01c9f3c0962092b9898b75b0914bbb817031d51be13e54c05b970",
"public_digest": "2296cfca8db9d38bd0b7579056c9dea3c8d8005df7b42e2b1e954a75fed67510",
"public_words_len": 11,
"words_len": 427
}
هر څوک کولی شي عامه برخه بېرته ولولي. rand_getProgramPublic کلمې د little-endian بایټونو په توګه بېرته ورکوي، نو رېښه هماغسې ښکاري لکه څنګه چې چاپ شوې وه:
$ curl -s https://rpc.randprotocol.org -H 'content-type: application/json' \
-d '{"jsonrpc":"2.0","id":1,"method":"rand_getProgramPublic","params":["ad2f719f12d01c9f3c0962092b9898b75b0914bbb817031d51be13e54c05b970"]}'
{"id":1,"jsonrpc":"2.0","result":"0a0000000100000003000000ce8d6ef78a2ccaab688afa50ff969b0f89b23e7f32d8c3746848b46f773f4750"}
8. رایه ورکول
rand call د هرې محرمې کلمې لپاره یو --input اخلي، په لسیزه بڼه. sed د شاهد فایل په همدې بیرغونو (flags) بدلوي:
$ rand call ad2f719f12d01c9f3c0962092b9898b75b0914bbb817031d51be13e54c05b970 \
$(sed 's/[0-9][0-9]*/--input &/g' witness.txt)
proving the call locally (90 inputs stay private, over the program's 11-word public input)…
gas: 5636 (declaring 6144, tier 12)
fee 0.006191437 RAND (incl. two price steps of headroom)
proved in 29.2s: tier 12, 3346865 bytes, outputs [1, 2, 392974773, 873526743, 1921224601, 3950868247, 2248722827, 0]
proving the spend authorisation on this machine (tier 10; seconds)…
authorisation proved in 8.2s: tier 10, 1367303 bytes
proving the bundle (tier 14; about a minute and a half on a laptop)…
proved in 117.2s: tier 14, 1504260 bytes
submitted call 8aa13d1f76d28f63a46c30bb09ef44b1ba35083ca80ba7301997f98e5f783666
0 RAND out, 59.716708563 RAND change, fee 0.006191437 RAND, anchored at height 98185, proved in 117.2s (bundle) + 8.2s (auth)
{
"h_in": "ea71e7701e62d49cac37b239bef132178f481835027d62b34da45fd6cf2667c6",
"h_pub": "2296cfca8db9d38bd0b7579056c9dea3c8d8005df7b42e2b1e954a75fed67510",
"height": 98335,
"index": 0,
"outputs": [
1,
2,
392974773,
873526743,
1921224601,
3950868247,
2248722827,
0
],
"program": "ad2f719f12d01c9f3c0962092b9898b75b0914bbb817031d51be13e54c05b970",
"tier": 12,
"tx": "8aa13d1f76d28f63a46c30bb09ef44b1ba35083ca80ba7301997f98e5f783666"
}
input transcript published; open it with `rand open-call 8aa13d1f76d28f63a46c30bb09ef44b1ba35083ca80ba7301997f98e5f783666`
رسید هغه څه دي چې زنځیر یې ساتي: حالت 1، انتخاب 2، او د باطلوونکي پنځه کلمې، د رایهګیرۍ د پروګرام د id لاندې. h_pub د رایهګیرۍ د عامې برخې ډایجسټ دی، هماغه ارزښت چې program show چاپ کړ. h_in د ۹۰ محرمو کلمو مالګهلرونکې ژمنه ده، او له مالګې پرته هېڅ نه پرانیزي.
دې غوښتنې د Apple Silicon په یوه لپټاپ کې درې دقیقې ونیولې او تر 6.1 GB پورې یې حافظه وکاروله: 29 s د غوښتنې د ثبوت لپاره، 8 s د لګښت د اجازې لپاره او 117 s د هغې بستې لپاره چې فیس ورکوي. فیس، 0.0062 RAND، زیاتره د بایټونو له امله دی. په chain 20 کې څلور پروګرامونه یې حساب وړاندې کوي.
د لېږد لیکه. په ډیفالټ ډول والټ محرم ورودي په یوه لفافه کې مهر کوي چې یوازې د غوښتونکي د لیدو کیلي یې پرانیستلای شي، او له غوښتنې سره یې خپروي. دا د غوښتونکي لپاره ثبت دی، افشا کول نه دي: بل هېڅوک یې نشي پرانیستلای. هغه رایهورکوونکی چې هېڅ ثبت نه غواړي، --no-envelope ورکوي. له هغې وروسته هېڅوک، په شمول د رایهورکوونکي، هېڅکله نشي ښودلای چې ورودي څه وو.
9. رایې وشمېرئ
شمېرونکی له زنځیر پرته بل څه ته اړتیا نه لري:
- رایهګیري. د پروګرام عامه برخه راوباسئ او ریښه د پاڼو له خپور شوي لېست سره پرتله کړئ (ونه د
allowlist.pyدlevelsپه مرسته بیا جوړه کړئ). میلمه پروګرام له سرچینې بیا جوړ کړئ اوhcد پروګرام لهcode_hashسره پرتله کړئ. - رسیدونه. هر هغه رسید واخلئ چې
programیې د رایهګیرۍ id وي او ۰ شمېره وتنه یې1وي. هغه رسید چې بل هر حالت ولري، یا په ۷ شمېره ځای کې3735928559ولري، رایه نه ده. - شمېرنه. د ۲ تر ۶ پورې وتنو له مخې یې ډلهبندي کړئ. هر باطلوونکی یو ځل وشمېرئ، د زنځیر په ترتیب کې د هغه لومړی رسید، او ۱ شمېره وتنه یې په شمېرنه کې ورزیاته کړئ.
درې نورې غوښتنې هم وشوې څو شمېرونکي ته کار پیدا شي. ۵ شمېره غړي دویم ځل رایه ورکړه، دا ځل ۰ انتخاب ته. ۲ شمېره غړي ۱ انتخاب ته رایه ورکړه. ۳ شمېره غړي ۰ انتخاب ته رایه ورکړه، له داسې والټ څخه چې یوازې عامه RPC پایټکی یې کاراوه. دا د ۵ شمېره غړي دویمه رایه ده:
$ python3 allowlist.py witness 10 1 demo-secrets.txt 5 0 > witness.txt
nullifier b5516c17d7f51034998f837217777deb8bc90886
nullifier words 392974773 873526743 1921224601 3950868247 2248722827
$ rand call ad2f719f12d01c9f3c0962092b9898b75b0914bbb817031d51be13e54c05b970 \
$(sed 's/[0-9][0-9]*/--input &/g' witness.txt)
…
proved in 31.0s: tier 12, 3345265 bytes, outputs [1, 0, 392974773, 873526743, 1921224601, 3950868247, 2248722827, 0]
…
submitted call 0f596b87f5137a165d6abc691dbe04f7533db619911d81449fea9ede602c40d0
زنځیر دویمه رایه ومنله، لکه څنګه چې باید یې منلې وای: ثبوت معتبر دی. د هغې رسید د لومړۍ رایې هماغه پنځه باطلوونکې کلمې لري.
tally.py دا درې قاعدې پلي کوي. دا د پروګرام غوښتنې له سپړونکي او هر رسید له عامه RPC څخه لولي، نو نه والټ ته اړتیا لري او نه نوډ ته:
$ python3 tally.py ad2f719f12d01c9f3c0962092b9898b75b0914bbb817031d51be13e54c05b970
8aa13d1f… height 98335 choice 2 nullifier b5516c17d7f51034… counted
0f596b87… height 99194 choice 0 nullifier b5516c17d7f51034… repeat, dropped
2db517df… height 99339 choice 1 nullifier 52f2455918bbc811… counted
fdbcc960… height 101833 choice 0 nullifier cd86c5454b809914… counted
tally: choice 0: 1, choice 1: 1, choice 2: 1
د ۵ شمېره غړي د نظر بدلون حساب نه شو، او په څلورو رسیدونو کې له پخپله باطلوونکي پرته بل هېڅ شی نه ښيي چې دوه یې د لېست له یوه غړي څخه راغلي دي. رایهګیري پرانیستې ده: د اتو نمایشي غړو څخه د هر یوه په توګه رایه ورکړئ او شمېرنه بیا وچلوئ.
هغه څه چې ثبوت یې تاسو ته نه درکوي
- د هر راز لپاره یوه رایه، نه د هر کس لپاره یوه رایه. تنظیمونکی پرېکړه کوي چې پاڼه چا ته ورکړل شي. هغه غړی چې دوې پاڼې ثبت کړي، دوې رایې لري.
- د رایهورکوونکي راز یوازې د خپل تصادفیت په اندازه باوري دی. هغه راز چې له یوه اټکلوړ متن څخه اخیستل شوی وي، د اټکلونو په هش کولو او له خپرو شویو پاڼو سره په پرتله کولو موندل کېدای شي. ۳۲ تصادفي بایټونه وکاروئ.
- انتخاب عام دی. رسید ښيي چې یو باطلوونکي کوم انتخاب ته رایه ورکړې ده. هېڅوک نشي ویلای چې باطلوونکی کوم غړی دی، خو هغه رایهګیري چې لږ رایهورکوونکي او خپره شوې ګډونکچه ولري، د کوچنیو شمېرو احصائیه ده، نه کریپټوګرافي.
- وخت او فیسونه میټاډیټا دي. د فیس بسته پټه (shielded) ده او هېڅوک نه نوموي، خو هغه رایهورکوونکی چې خپل والټ تمویل کړي او یوه دقیقه وروسته په یوه خلوت ساعت کې رایه ورکړي، څارونکي ته یې یو څه ویلي دي.
- شمېرنه له زنځیر بهر ده. زنځیر رسیدونه ساتي. د هغو شمېرل، او د دویم باطلوونکي ردول، د هغه چا کار دی چې دا لولي.