Rand Protocol
مستندات
مفاهیم اصلی

حساب‌ها و نشانی‌ها

دو نوع کلید در زنجیره، شیوهٔ مشتق‌شدن نشانی محافظت‌شدهٔ rand1، آنچه یک کلید مشاهده افشا می‌کند، و دلیل بازگشت نشانی کوتاه زنجیرهٔ 11.

از این صفحه برای ساختن کلید مناسب هر کار، تجزیه یا اعتبارسنجی یک نشانی، و دانستن اینکه دادنِ یک کلید به دیگری چه چیزی را آشکار می‌کند استفاده کنید. در این زنجیره حساب وجود ندارد: موجودی واقعیتی دربارهٔ یک فایل کلید است، نه دربارهٔ زنجیره.

دو کلید، دو نوع نشانی

کلید نودکلید کیف پول
نوشته‌شده باrand-node keygenrand keygen
رازیک seed با اندازهٔ ۳۲ بایتیک کلید خرج ۲۵۶ بیتی
هویت عمومییک نشانی ۳۲ بایتی، base58، به طول ۳۲ تا ۴۴ نویسهیک نشانی محافظت‌شده، rand1…، به طول 1,665 یا 1,666 نویسه
امضا می‌کندبلوک‌ها، رأی‌ها، ضرب‌های faucet، Unbond، Withdraw، یک Registration و در زنجیرهٔ ۲۰ یک رأی AdmitValidator؛ و به‌عنوان مرجع ضرب از نوع Key برای یک توکن، TokenMint و SetAuthority. در زنجیرهٔ ۲۰ هر یک از این پیام‌ها هش genesis را هم پوشش می‌دهد (تراکنش‌ها)هیچ چیز: یک انتقال با اثبات‌های خودش مجاز می‌شود
در زنجیره ظاهر می‌شود به‌صورتپیشنهاددهندهٔ بلوک، یک ردیف در دفتر ثبت validatorها، ضربکنندهٔ یک ضرب faucet، مرجع key یک توکنهرگز در یک انتقال، جایی که درون envelopeها مهروموم شده است. آن‌جا منتشر می‌شود که ارزش با مقدار عمومی وارد استخر می‌شود: یک واریز پل، یک ضرب توکن و در زنجیرهٔ ۲۰ پرداخت یک invoke نشانی گیرنده را نام می‌برند؛ نشانی پرداخت یک validator در دفتر ثبت است، genesis زنجیرهٔ ۲۰ خزانهٔ کارمزد پل را نام می‌برد، و از زنجیرهٔ ۱۴ به بعد یک ضرب faucet و یک یادداشت alloc در genesis مقدار pk مالک، یعنی ۳۲ بایت اول نشانی، را منتشر می‌کنند
فایل{ "seed", "address", "public_key" }، با دسترسی 0600{ "version": 2, "spend_key": "<64 hex>" }، با دسترسی 0600

این دو هرگز با هم مخلوط نمی‌شوند. validatorها با نوع اول شناسایی می‌شوند، و همان شکل کلید Dilithium2 برای مرجع ضرب Key یک توکن (rand token create --authority-key-out فایلی با شکل فایل rand-node keygen می‌نویسد)، کلید توقف پل و شش کلید نگهبان پساکوانتومی آن به کار می‌رود. کلیدهای گواهی نگهبان‌ها از نوع secp256k1 هستند، با نشانی‌های ۲۰ بایتی به سبک Ethereum (پل). ارزش زیر نوع دوم نگه‌داری می‌شود.

نشانی شفاف

کلید نود یک seed ۳۲ بایتی است که یک جفت‌کلید Dilithium2 به‌صورت قطعی از آن مشتق می‌شود: یک کلید عمومی ۱,۳۱۲ بایتی و امضاهای ۲,۴۲۰ بایتی. نشانی یک هش BLAKE3 با تفکیک دامنه از کلید عمومی است که در base58 نمایش داده می‌شود:

address = blake3("rand-address" || public_key)      // 32 bytes, shown as base58

اشیای امضاشده (رأی‌ها، بلوک‌ها، ضرب‌ها، اقدامات staking) کلید عمومی کامل را حمل می‌کنند، بنابراین یک verifier به‌جای اعتماد به یک نشانی تنها، blake3("rand-address" || public_key) == address را بررسی می‌کند. همان seed هویت libp2p نود را هم می‌دهد، یعنی یک کلید ed25519 از blake3("rand-p2p-identity" || seed)، که همان شناسهٔ همتا پس از /p2p/ در یک multiaddr راه‌انداز است.

rand-node keygen --out node.key.json      # prints the address
rand-node address --key node.key.json     # address, public key (hex), libp2p peer id

مثال: EdrEC2QRQrQF64iRXxF9927jNj6RidiHHByzx5xD6F1e یکی از validatorهای زنجیرهٔ ۲۰ است. زنجیره‌های ۱۵ تا ۲۰ همان هجده کلیدی را که برای زنجیرهٔ ۱۴ چرخانده شد دوباره به کار می‌برند، پس نشانی‌ها و شناسه‌های همتای آن‌ها بدون تغییر است و هیچ نشانی یا شناسهٔ همتای validator از زنجیرهٔ ۱۳ دیگر در کار نیست؛ هشت validator دیگر در زنجیرهٔ ۱۵ وثیقه گذاشتند و هر ۲۶ نفر از زنجیرهٔ ۱۶ به بعد در فایل genesis هستند.

نشانی محافظت‌شده

یک کیف پول یک راز است، کلید خرج ۲۵۶ بیتی sk، و هر چیز دیگر مشتقی از آن است. اشتقاق با Poseidon2 انجام می‌شود و یک برچسب دامنه نخستین واژهٔ جذب‌شده است (H(domain, msg))، همان تابعی که zkVM در مدار محاسبه می‌کند:

spend key   sk                          256 bits, in wallet.key.json
   │
   ├─ viewing key   nk = H(NK, sk)      sees the whole history; cannot spend
   │     ├─ pk = H(PK, nk)              the field a note names its owner by
   │     ├─ nullifier(cm) = H(NF, nk, cm)   what a spend publishes
   │     ├─ ovk                         opens envelopes this wallet sent
   │     └─ ML-KEM-768 decapsulation key    opens envelopes sent to this wallet
   └─ address   rand1 + base58(pk || kem_ek)

نشانی عبارت است از ۳۲ بایت pk و پس از آن کلید کپسوله‌سازی ML-KEM-768 با اندازهٔ ۱,۱۸۴ بایت، به‌صورت base58 پس از پیشوند rand1: 1,665 یا 1,666 نویسه (طول base58 به بایت‌های ابتدایی بستگی دارد؛ حدود یکی از هر چهارده نشانی کوتاه‌تر است)، حدود 1.6 KB، و بدون checksum. فرستنده برای مهروموم کردن envelope یادداشت به کلید کپسوله‌سازی نیاز دارد، و دلیل حضور آن در نشانی همین است. این کلید عمداً عمومی است: هر کس می‌تواند به آن پرداخت کند، و در دست داشتن آن چیزی دربارهٔ آنچه نشانی نگه می‌دارد نمی‌گوید.

rand keygen                      # wallet.key.json; refuses to overwrite an existing file
rand address                     # rand1… on stdout, its fingerprint XXXX-XXXX-XXXX-XXXX on stderr

از v0.5.10 دستور rand address دقیقاً نشانی و یک خط‌جدید را روی stdout چاپ می‌کند، پس $(rand address) در یک اسکریپت کار می‌کند. اثر انگشت به stderr می‌رود.

تجزیه، دقیقاً همان‌طور که ShieldedAddress::parse انجام می‌دهد: rand1 را بردارید، base58 را رمزگشایی کنید و دقیقاً 32 + 1,184 = 1,216 بایت را الزامی بدانید؛ ۳۲ بایت اول pk به‌صورت هشت واژهٔ u32 با ترتیب little-endian است و بقیه کلید کپسوله‌سازی. RPC هر پارامتری را که از 2,000 نویسه بلندتر باشد پیش از تجزیه رد می‌کند.

کیف پول کنار فایل کلید، فایل <key>.key.json.notes.json را نگه می‌دارد، یک حافظهٔ نهان از یادداشت‌هایی که این کلید گشوده است. این فایل متن‌های آشکار یادداشت‌ها را دارد، پس مانند کلید با دسترسی 0600 نوشته می‌شود؛ هر ردیف آن با اسکن دوبارهٔ زنجیره از برگ 0 قابل بازیابی است.

به‌اشتراک‌گذاری نشانی: اثر انگشت و پیوندهای randpay:

یک نشانی برای خواندن با صدای بلند یا مقایسه با چشم بسیار بلند است و checksum ندارد، بنابراین از v0.5.10 هر کیف پول کنار آن یک اثر انگشت نشان می‌دهد. اثر انگشت فقط برای نمایش است: هیچ چیز روی زنجیره یا روی شبکه آن را حمل نمی‌کند.

fingerprint = first 80 bits of blake3("rand-address-fingerprint-1" || pk_bytes || kem_ek)
            = 16 Crockford base32 characters, shown as XXXX-XXXX-XXXX-XXXX

هش روی 1,216 بایت خامی است که نشانی رمزگذاری می‌کند. الفبا 0123456789ABCDEFGHJKMNPQRSTVWXYZ است؛ تجزیه به بزرگی و کوچکی حروف و به خط تیره توجه نمی‌کند و O را 0 و I یا L را 1 می‌خواند.

یک پیوند randpay: یک نشانی و، به‌صورت اختیاری، آنچه باید به آن پرداخت شود را حمل می‌کند:

randpay:<rand1…>[?amount=<decimal>][&asset=<index | 64 hex | rpl1…>][&memo=<percent-encoded UTF-8>]

amount بر حسب واحدهای نمایشی دارایی است (RAND اعشاری با نُه رقم اعشار، و یک توکن با decimals خودِ ردیف دفتر ثبتش) و نباید صفر باشد. memo حداکثر 510 بایت UTF-8 است. طرح (scheme) بدون توجه به بزرگی و کوچکی حروف تطبیق داده می‌شود؛ پارامتر ناشناخته، پارامتر تکراری یا رمزگذاری درصدی نادرست رد می‌شود.

rand address --uri --amount 1.5 --memo "invoice #42" --qr   # a randpay: link, as a terminal QR
rand contacts add alice rand1q9f…                            # shows the fingerprint, asks add? [y/N]
rand send alice 1.5 --memo "coffee"                          # to a contact, with a memo

rand send <TO> یک نشانی rand1…، یک پیوند randpay: یا نام یک مخاطب ذخیره‌شده را می‌پذیرد و به همین ترتیب امتحان می‌کند. مقادیر amount، asset و memo در پیوند، آنچه را خط فرمان خالی گذاشته پر می‌کنند، و مقداری که از دو راه داده شود و ناسازگار باشد رد می‌شود. پیش از اثبات، send سطر to <contact, if any> · fingerprint XXXX-XXXX-XXXX-XXXX · <amount> <asset> را چاپ می‌کند و تأیید می‌خواهد؛ یک اسکریپت --yes می‌دهد. مخاطبان کنار کلید در <key>.contacts.json با دسترسی 0600 ذخیره می‌شوند. پیام همراه درون envelope یادداشت حرکت می‌کند (یادداشت‌ها).

نه rand balance <address> وجود دارد و نه RPC موجودی: زنجیره نمی‌تواند برای کسی به آن پاسخ دهد. کیف پول موجودی‌اش را با اسکن همهٔ envelopeهای روی زنجیره به کمک کلید مشاهدهٔ خود محاسبه می‌کند (یادداشت‌ها).

کلیدهایی که می‌توانید به دیگری بدهید

افشا ویژگی کلیدهاست، و زنجیره نمی‌تواند هیچ‌یک از آن را اجبار کند.

کلیدچه چیزی را می‌گشایددانه‌بندی
کلید مشاهده nk (64 hex)هر یادداشتی که کیف پول تاکنون دریافت کرده و، از طریق ovk، هر یادداشتی که تاکنون فرستاده، همراه با nullifier هر خرجهمه یا هیچ، هم برای گذشته و هم برای آینده
کلید تراکنش TxKey (32 بایت)دقیقاً همان یک envelope که آن را مهروموم کرده است: یادداشت و، از زنجیرهٔ ۱۸، پیام همراه آنیک پرداخت
کلید فراخوانی K_callرونوشت ورودی خصوصی یک فراخوانی محرمانهیک فراخوانی

یک کلید مشاهده نمی‌تواند خرج کند. از زنجیرهٔ ۱۷ (مجوزدهی تفکیک‌شده) خودِ اثبات بسته از nk ساخته می‌شود، و هر بسته یک اثبات مجوز دوم و کوچک هم دارد که فقط کلید خرج می‌تواند آن را بسازد و به همان یک تراکنش بسته شده است (یادداشت‌ها). همین باعث می‌شود بتوان nk را، و در نتیجه کل تاریخچهٔ کیف پول را، به یک prover واگذارشده داد بی‌آنکه بتواند خرج کند؛ کیف پول اثبات مجوز را همیشه روی دستگاه خودش می‌سازد. نشانی‌ها، کلیدها و یادداشت‌های موجود با این تفکیک تغییری نمی‌کنند. کیف پول nk را در هر اجرا مشتق می‌کند و هرگز ذخیره‌اش نمی‌کند؛ هر TxKey برای هر envelope تازه انتخاب می‌شود و پس از مهروموم کردن دور ریخته می‌شود. می‌توان با rand_importViewingKey یک کلید مشاهده را به یک نود داد (در حافظه، حداکثر 64 کلید برای هر نود، با راه‌اندازی مجدد از بین می‌رود) تا از طرف دارنده اسکن کند — مسیری که explorer می‌رود — و rand_checkTransaction(hash, key) یک پرداخت را با یک TxKey در یک فراخوانی بدون حالت بررسی می‌کند. rand viewing-key مقدار nk را چاپ می‌کند، و rand tx-key <hash> کلید هر خروجی از تراکنشی را که این کیف پول می‌تواند بگشاید چاپ می‌کند.

شناسه‌های توکن نشانی نیستند

یک توکن RPL نوع سومی از شناسهٔ متنی دارد، و آن یک توکن را نام می‌برد، نه یک دارنده را. شناسهٔ دارایی ۳۲ بایتی توکن به‌صورت 64 نویسهٔ hex و به‌صورت rpl1… نشان داده می‌شود: bech32m (BIP-350) با بخش خوانا برای انسان rpl روی ۳۲ بایت شناسه، 52 نویسهٔ داده به‌اضافهٔ checksum ۶ نویسه‌ای، 62 نویسه. تجزیه سخت‌گیرانه است: checksum نادرست، بخش خوانا برای انسان دیگر، بار داده‌ای که دقیقاً ۳۲ بایت نباشد، یا حروف آمیخته (بزرگ و کوچک) رد می‌شود، پس یک اشتباه تایپی هرگز به توکن دیگری ختم نمی‌شود. یک یادداشت شناسه را حمل نمی‌کند؛ واژهٔ asset آن شاخص فشردهٔ توکن در دفتر ثبت است (توکن‌های RPL).

گیرندهٔ پل

قالب سیمی پل یک شکاف ۳۲ بایتی برای گیرنده دارد و یک نشانی محافظت‌شده در آن جا نمی‌شود. امروز این شکاف یک هش از نشانی را حمل می‌کند:

recipient_hash = blake3("rand-shielded-recipient" || pk_bytes || kem_ek)

واریزکنندهٔ زنجیرهٔ مبدأ هش را نام می‌برد، نگهبان‌ها آن را امضا می‌کنند، و تراکنش BridgeAttest نشانی کامل را حمل می‌کند تا دفتر کل آن را با هش تطبیق دهد (پل).

نشانی محافظت‌شدهٔ کوتاه: در زنجیرهٔ ۱۱ آزمایش شد و برگردانده شد

زنجیره ۱۱ (تگ fullnode با نام v0.2، ‏2026-09-17) آدرس بلند را با یک شناسه گیرنده (receiver id) به طول ۵۳ تا ۵۵ نویسه جایگزین کرد: rand1 + base58(blake3(receiver signing key) ‖ checksum). کلید کپسوله‌سازی ML-KEM هم به یک رکورد گیرنده (receiver record) امضاشده منتقل شد که فرستنده یا از رجیستری explorer دریافت می‌کرد یا به‌صورت درون‌خطی در درخواست پرداخت به دستش می‌رسید. این طراحی یک روز دوام آورد و همان روز بازگردانده شد (fullnode 17db41d). زنجیره ۱۲ به همان آدرس بلند بازگشت، دقیقاً مطابق آنچه در بالا آمد، و هر زنجیره‌ای پس از آن، از جمله زنجیره ۲۰، آن را حفظ کرده است.

چرا کنار گذاشته شد. شناسه گیرنده یک درهم‌ساز (hash) است و فرستنده نمی‌تواند یک یادداشت (note) را روی یک درهم‌ساز مهر کند. نخستین پرداخت به کیف پولی که هرگز ثبت‌نام نکرده بود، مستلزم آن بود که گیرنده یک درخواست پرداخت یا یک فایل رکورد را تحویل دهد، و خود ثبت‌نام با یک انتقال به خود پرداخت می‌شد که کیف پول تازه و خالی نمی‌تواند انجام دهد. هر دو مسیر تحویل همچنین به رجیستری می‌گفتند که چه کسی در شرف دریافت پرداخت است. طراحی‌ای که آدرس کوتاه، ارسال‌پذیری بی‌قیدوشرط و حریم خصوصی رمزنگاشتی را با هم حفظ می‌کند، آدرس ترکیبی (hybrid) است: یک کلید X25519 به‌طول ۳۲ بایت به‌صورت درون‌خطی (حدود ۹۳ نویسه) و کلید پساکوانتومی از راه جست‌وجو. در این طرح نخستین پرداخت به کیف پول ثبت‌نام‌نشده در برابر مهاجمان کلاسیک محرمانه است و هر پرداخت بعدی کاملاً پساکوانتومی. این طرح در ادامه مشخص شده است؛ تا زمانی که عرضه شود، آدرس بلند همان آدرس است.

مشخصات زنجیره ۱۱ و پیاده‌سازی آن در تاریخچه fullnode باقی می‌مانند (docs/superpowers/specs/2026-09-17-short-shielded-address.md، تگ v0.2) برای بخش‌هایی که طراحی ترکیبی دوباره از آن‌ها استفاده می‌کند: کلید امضای گیرنده‌ی مشتق‌شده، رکورد امضاشده و راستی‌آزمای آن، و رجیستری به‌عنوان وضعیت زنجیره.

آخرین بار با کامیت c0878c3f از fullnode (زنجیرهٔ 21) در تاریخ 2026-10-12 بررسی شد. هرجا کد و این صفحه با هم اختلاف دارند، حق با کد است؛ به ما اطلاع دهید.