استخدم هذه الصفحة لاختيار المكتبة المناسبة عند التشغيل البيني مع السلسلة، وللتحقق من معامل ما مقابل ما تفرضه العقدة، ولإعادة حساب معرّف أو التزام بنفسك. كل قيمة هنا هي القيمة التي يشغّلها الكود على chain 20 (fullnode v0.6.8).
الأوليات التشفيرية وأين تُستخدم
| الأولية | المعاملات | الاستخدام |
|---|---|---|
| Dilithium2 | مفتاح عام بحجم 1,312 بايت، وتوقيع بحجم 2,420 بايت؛ تُشتق أزواج المفاتيح من بذرة بحجم 32 بايت | أصوات المدقّقين (validators) واقتراحات الكتل؛ سكّ الـ faucet؛ Unbond وWithdraw وRegistration الخاص بالمدقّق؛ أصوات AdmitValidator (chain 20)؛ إجراءات المجمِّع (aggregator)؛ صلاحية السكّ Key لرمز RPL (TokenMint وSetAuthority)؛ التوقيعات المشتركة ما بعد الكمّية لحرّاس الجسر، ومفتاح الإيقاف المؤقت فيه، وعلى chain 20 إثباتات الحيازة للمفاتيح الجديدة في عملية التدوير (أدناه) |
| ML-KEM-768 | مفتاح تغليف بحجم 1,184 بايت، ونص مشفّر بحجم 1,088 بايت | إغلاق مفتاح كل معاملة في مظروف الملاحظة (note) على عنوان المستلم؛ إغلاق مظروف مدخلات الاستدعاء على مدقّق حسابات؛ إغلاق مهمة إثبات على مُثبِت (prover) مقترن |
| ChaCha20-Poly1305 | مفتاح بحجم 32 بايت، وnonce عشوائي بحجم 12 بايت يُلحق في المقدمة، ووسم بحجم 16 بايت | كل جزء من المظروف: أجسام الملاحظات، ومفاتيح المعاملات المغلّفة، ونصوص مدخلات الاستدعاء؛ ومهام المُثبِت المقترن وردوده |
| BLAKE3 | ناتج بحجم 32 بايت، دائمًا مع سلسلة نطاق (domain) في المقدمة | العناوين، ومعرّفات المعاملات، وربط المعاملة وربط الاستدعاء، ومعرّفات البرامج، ومعرّفات أصول الرموز، وجذر الحالة وأشجار Merkle الخاصة به، وهوية p2p، ورسائل التوقيع، ومعرّفات أصول الجسر، والتعمية (blinding) في إيداع الجسر وتعميات ملاحظات رسوم الجسر |
| Poseidon2 فوق Goldilocks | عرض 8، ومعدّل 4، وسعة 4، وإسفنجة كتابة فوقية بلا حشو؛ عناصر الرسالة كلمات من 32 بت؛ ثوابت الجولات الـ 86 جدول حرفي في مصدر العقدة (poseidon2_constants.rs) منذ إصدار chain-15، وهي القيم نفسها التي كان السحب المبذور ينتجها سابقًا | كل ما هو داخل الإثبات: المفاتيح، والتزامات الملاحظات، والـ nullifiers، وشجرة الالتزامات، وملخّص البرنامج hc، والتزامات المدخلات H_IN وH_PUB، وملخّص الحزمة، والتزام التفويض |
| secp256k1 ECDSA + keccak256 | توقيعات low-s، وعناوين حرّاس بصيغة Ethereum بحجم 20 بايت، وmu = keccak256(keccak256(body)) | شهادات حرّاس الجسر، بحيث يعمل المفتاح نفسه على عقود EVM وبرنامج Solana وعلى Rand؛ وعلى Rand تحتاج كل شهادة أيضًا إلى نصاب Dilithium2 أدناه |
| bech32m (BIP-350) | الجزء المقروء rpl، وحمولة بحجم 32 بايت، و52 محرف بيانات + 6 محارف تحقّق = 62 | الصيغة النصية rpl1… لمعرّف أصل رمز RPL |
| Plonky3 batch STARK | Goldilocks p = 2⁶⁴ − 2³² + 1، وFRI مخفي (hiding)، وblowup 8، وarity للطيّ 8، و80 استعلامًا، و20 بتًّا لإثبات العمل | كل إثبات حزمة، وإثبات تفويض، وإثبات استدعاء؛ ويحمل إثبات الحزمة وإثبات التفويض الخاص به كلمات الربط الثماني لمعاملتهما بوصفها مقطع المدخلات العامة |
تختلف المعاملات المستهدفة في الورقة البيضاء في مواضع عمّا ينفّذه التطبيق (مثلًا ملخّص نص الإثبات (transcript) بحجم 384 بت في الورقة مقابل نص Poseidon2 في zkVM). تصف هذه الصفحات الكود.
التوقيعات المشتركة ما بعد الكمّية على الجسر
شهادات حرّاس الجسر هي توقيعات secp256k1 ECDSA، وهي توقيعات يستطيع خصم كمّي تزويرها. ومنذ chain 14 يجب أن يحمل كل BridgeAttest — إيداعًا كان أو تدويرًا لمجموعة الحرّاس — نصابًا من توقيعات Dilithium2 من الحرّاس أنفسهم على الملخّص نفسه:
M = "rand-bridge-pq-cosign-1" || rand_chain_id (u64 BE) || mu // 63 bytes, deterministic signing
حيث mu = keccak256(keccak256(body)) هو ما يوقّعه نصاب ECDSA. ويمنع معرّف سلسلة Rand في M أن يُقبل توقيع مشترك من testnet على سلسلة Rand أخرى حتى لو أُعيد استخدام مفاتيح الحرّاس. ويربط M معرّف السلسلة وحده، وعلى chain 20 أيضًا: فهو الرسالة الموقّعة الوحيدة التي لم ينقلها binding_domain وراء ملخّص التكوين الأول (genesis hash)، لأن خدمات الحرّاس التي توقّعها تقع في مستودع آخر. ونسخة من سلسلة بمعرّف السلسلة نفسه ومجموعة الحرّاس نفسها ستقبل التوقيعات المشتركة لإيداعاتها؛ ولا يوجد فهرس مجموعة الحرّاس في M، فيبقى التوقيع المشترك صالحًا بعد تدوير مجموعة ECDSA. حقل pq_signatures في الإجراء قائمة من PqSignature { index: u8, signature }، تُفحص فحصًا رخيصًا قبل المكلف: quorum(n) ≤ len ≤ n (PqNoQuorum)، والفهارس متزايدة تزايدًا صارمًا (PqIndexOrder)، وكل فهرس دون n (PqIndexOutOfRange)، وكل توقيع بحجم 2,420 بايت تمامًا (PqBadSignatureLength)، وأخيرًا يُتحقَّق من كل توقيع بالمفتاح pq_guardians[index] (PqBadSignature). ولا يشترط أن يكون الموقّعون ما بعد الكمّيين هم موقّعي ECDSA؛ إذ يُحسب كل نصاب على حدة. والحقل داخل ربط المعاملة، فلا يمكن نزعه أو استبداله في نسخة.
مجموعة PQ هي bridge.pq_guardians في التكوين الأول (genesis) — ثمانية مفاتيح بحجم 1,312 بايت على chain 20، كما في chains من 15 إلى 19، متوازية الفهارس مع مجموعة ECDSA في التكوين الأول، مجموعة الحرّاس 1 (كان في chain 14 ستة، موازية للمجموعة 0). ولا يحرّكها تدوير مجموعة حرّاس ECDSA أبدًا. وفي chain 14 كانت ثابتة طوال عمر السلسلة؛ ومنذ chain 15 يحمل التكوين الأول مجموعة rules_v2 الخاصة بالجسر، وبموجبها يستطيع نصاب PQ استبدال مجموعة PQ كاملة (RotatePqGuardians) أو مفتاح الإيقاف المؤقت (RotatePauseKey)، كلٌّ تحت rotation_nonce الخاص بالجسر. ويضيف التكوين الأول لـ chain 20 bridge.rotation: يجب أن يكون التدوير إجراء V2، يحمل توقيع Dilithium2 الخاص بكل مفتاح جديد على الرسالة نفسها (إثبات الحيازة)، ويسري بعد يوم من استقراره ما لم يلغِه مفتاح الإيقاف المؤقت الحالي (Bridge). ويقدّم rand_getBridgeState المفاتيح، ويسرد bridge_attest المفكوك pq_signers، أي فهارس من وقّعوا. ويفوّض نصاب PQ نفسه رسائل حوكمة الجسر، وكلٌّ منها بتخطيط ثابت big-endian يحمل معرّف السلسلة وnonce. وعلى chain 20 (التكوين الأول binding_domain: 1) يكون رقم الإصدار في كل نطاق 2 ويقع ملخّص التكوين الأول بحجم 32 بايت بين النطاق ومعرّف السلسلة؛ وتستخدم chains من 14 إلى 19 صيغ -1:
| الرسالة | النطاق (chains 14–19 / chain 20) | يوقّعها |
|---|---|---|
M_pause | rand-bridge-pause-1 / -2 | مفتاح الإيقاف المؤقت الوحيد في التكوين الأول (Dilithium2)، وهو يستطيع الإيقاف ولا يستطيع رفعه |
M_unpause | rand-bridge-pq-unpause-1 / -2 | نصاب من حرّاس PQ |
M_list | rand-bridge-pq-list-1 / -2 | نصاب من حرّاس PQ (ListBacking) |
M_register | rand-bridge-pq-register-1 / -2 | نصاب من حرّاس PQ (RegisterBridgedToken) |
M_rotate_pq | rand-bridge-pq-rotate-pq-1 / -2 | نصاب من مجموعة PQ الحالية (RotatePqGuardians، سلاسل rules_v2)؛ وعلى chain 20 أيضًا كل مفتاح جديد بوصفه إثبات حيازته |
M_rotate_pause | rand-bridge-pq-rotate-pause-1 / -2 | نصاب من مجموعة PQ الحالية (RotatePauseKey، سلاسل rules_v2)؛ وعلى chain 20 أيضًا المفتاح الجديد |
M_cancel | rand-bridge-cancel-rotation-1 / -2، مع بايت kind لاحق | مفتاح الإيقاف المؤقت الحالي (CancelRotation، السلاسل التي فيها bridge.rotation: chain 20) |
STARK في الإنتاج
يعمل zkVM على مجموعة القيود 8: تسعة جداول إلزامية (program وcpu وmemory وalu وrange وnibble وposeidon2 وinput وpublic) إضافةً إلى جدولَي keccak وsha256 لا يحملهما الإثبات إلا إذا استدعى برنامجه الضيف (guest) استدعاء النظام المطابق، وتربطها سبعة عشر ناقلًا (bus) وتُثبَت كلها كـ batch STARK واحد. ومنذ مجموعة القيود 7 يضم كل جدول مُعلَن 2⁷ صفوف على الأقل، ويُعمّى الطرف الأخير لـ LogUp في كل جدول عبر الناقل السابع عشر BLIND. والواجهة العامة للإثبات 35 عنصرًا من الحقل (pv::NUM): pc الدخول، والطبقة (tier)، وكلمات الخرج الثماني، وملخّص البرنامج hc (8 كلمات)، والتزام المدخلات الخاصة المملّح H_IN (8)، وملخّص المقطع العام غير المملّح H_PUB (8)، ومنذ مجموعة القيود 8 حدّ الغاز المُعلَن GAS_LIMIT.
| المعامل | الإنتاج | ملاحظة |
|---|---|---|
| استعلامات FRI | 80 | أُلغي إعادة الضبط إلى 27 استعلامًا في مجموعتَي القيود 3 و4 بعد تدقيق 2026-09-12: فقد ترك ~42 بتًّا مثبتة |
| blowup | 8 (log_blowup = 3) | الدرجة القصوى للقيود في كل جدول مثبّتة تحت السقف 8 |
| arity للطيّ | 8 | |
| بتات إثبات العمل | 20 | |
| السلامة (soundness) | 3·80 + 20 = 260 بتًّا بالتخمين (ethSTARK)؛ وحوالي 86 بتًّا مثبتة تحت فجوات القرب (proximity gaps) | |
| المعرفة الصفرية | إحصائية: يُرجَّح LDE وكثير حدود دفعة FRI عشوائيًا، فيختلف إثباتان لتشغيل واحد | منذ مجموعة القيود 7 يضم كل جدول مُعلَن 2⁷ صفوف على الأقل، أي أكثر من 82 نقطة يفتحها الإثبات، وتُعمّى أطراف LogUp |
| الطبقات (tiers) | 10 و12 و14 و16 و18 و20 | يكشف الإثبات الطبقة ولا يكشف عدد الدورات أبدًا؛ ومنذ fullnode v0.5.6 يُرفض إثبات استدعاء فوق الطبقة 14 (CallTierTooHigh)، ويُثبَّت إثبات الحزمة على الطبقة 14 وإثبات التفويض على الطبقة 10 |
| سقف الإثبات | max_proof_bytes في التكوين الأول: 4 MiB (4,194,304) على chains من 17 إلى 20؛ و8 MiB على chains من 13 إلى 16؛ و2 MiB (MAX_PROOF_BYTES) على تكوين أول بدونه، مثل chain 12 | 2 MiB أعلى من كل إثبات خالٍ من جداول التجزئة تستطيع البرامج الضيفة المنشورة إنتاجه، وأدنى من إثبات يحمل keccak؛ و4 MiB يقبل الاثنين |
| الغاز | 1 لكل صف cpu؛ 3 لكل صف امتصاص Poseidon2؛ 64 لكل صف SHA256؛ 192 لكل صف KECCAK | يتراكم في عمود GAS بجدول cpu ويُثبَت أنه لا يتجاوز GAS_LIMIT؛ ويرفض المتحقّق (verifier) حدًّا أعلى من gas_max(t, k, s) = (2ᵗ − 1) + 2ᵗ⁻² + 191·(2ᵏ/32) + 63·(2ˢ/64)، وهو 1,279 لترويسة طبقة 10 خالية من التجزئة و20,479 لترويسة طبقة 14 |
تم قياس الأحجام عند مجموعة القيود 6 (Apple Silicon، بناء إصدار): بلغ حجم إثبات إنتاجي خالٍ من keccak 1,298,729 بايت عند المستوى 10 و1,359,978 بايت عند المستوى 12؛ وبلغ إثبات يحمل keccak عند المستوى 10 3,198,430 بايت، أي أكثر من الحد الافتراضي 2 MiB وأقل من 8 MiB في السلاسل من 13 إلى 15. وقيس إثبات المستوى 14 لضيف الحزمة المتقاعد ذي المدخلين والمخرجين الاثنين على السلسلة 8 فبلغ 1,321,773 بايت، وعلى السلسلة 13 ما بين 1,418,406 و1,420,423 بايت. أما ضيف حزمة الأصول المخفية بأربعة مدخلات وأربعة مخرجات في السلسلة 14 فيبقى عند المستوى 14 دون أي من جدولَي التجزئة، وقد بلغت إثباته 1,422,116 و1,423,170 بايت على السلسلة 14 (2026-09-20)، وثبّتت السلسلة 15 الضيف نفسه (hc_bundle دون تغيير)؛ وكان إثبات الحزمة يصرّح هناك بـ public_log_height يساوي 4، وهو ارتفاع كلمات الربط الثماني، ورفضت العقدة أي قيمة أخرى قبل بناء مفتاح المتحقق. أما إثبات استدعاء ERC-20 approve الحامل لـ keccak الذي أُنجز على السلسلة 13 في 2026-09-19 (المستوى 16) فحجمه 3,412,405 بايت؛ وكل سلسلة منذ fullnode v0.5.6 ترفض ذلك الاستدعاء عند المستوى 16.
تضيف أعمدة التعمية وحدود الجداول الدنيا في مجموعة القيود 7 نحو 5% إلى الإثبات الخالي من التجزئة: فقد قاس fullnode في 2026-09-28 أن fib يبلغ 1,367,688 بايت عند المستوى 10 و1,424,299 عند المستوى 12، وإثبات المستوى 10 الحامل لـ keccak يبلغ 3,283,898، وإثبات حزمة الأصول المخفية عند المستوى 14 يبلغ 1,498,821 (الضيف v1) و1,497,156 (الضيف v2). ومنذ ذلك الحين يصرّح إثبات الحزمة بـ public_log_height يساوي 7. وتضيف مجموعة القيود 8 أقل من 1%. وقيس على السلسلة 18 في 2026-09-30 (Apple Silicon): إثباتات المصادقة من 1,364,940 إلى 1,375,371 بايت (المستوى 10)، وإثباتات الحزمة من 1,494,151 إلى 1,504,260 بايت (المستوى 14، الضيف v3)، وإثباتات الاستدعاء 1,498,589 بايت عند المستوى 14 دون جدول تجزئة، و1,911,152 عند المستوى 14 مع جدول SHA-256، و3,346,865 عند المستوى 12 مع جدول Keccak. وكلها تقع ضمن سقف 4 MiB للسلاسل من 18 إلى 20.
يستغرق التحقق نحو 16 ms مع مفتاح متحقق دافئ، ونحو 230 ms في المرة الأولى التي يُبنى فيها مفتاح (tier, heights). أما ملف FRI المسمى test (16 استعلامًا) فهو موجود لحزمة الاختبارات وغير آمن؛ ويثبّت genesis السلسلة 20 الملف production. لا يغيّر fullnode v0.6.8 أي قيد: فالسلسلة 20 تثبّت hc_bundle وhc_auth نفسيهما اللذين تثبّتهما السلاسل من 17 إلى 19.
تراكيب التجزئة التي يمكنك إعادة إنتاجها
BLAKE3 مع نطاق: blake3(domain || data)، وسلسلة النطاق دون فاصل.
نطاق الربط. يضبط genesis السلسلة 20 القيمة binding_domain: 1 (fullnode v0.6.8، تدقيق v6 BIND-1). وفي سلسلة كهذه يربط كل ربط للإثبات وكل رسالة إجراء موقّعة كانت تربط معرّف السلسلة وحده تجزئة genesis أيضًا: يرتفع رقم إصدار النطاق بواحد وتأتي تجزئة genesis ذات 32 بايت أولًا في الصورة الأولية، قبل معرّف السلسلة. ثم إن إثباتًا أو توقيعًا صُنع لسلسلة واحدة لا يُقبل في أي سلسلة أخرى، حتى لو أعادت استخدام معرّف السلسلة والمفاتيح، كما يحدث عند إعادة الإطلاق. وكلمات الربط مدخل عام للإثباتات، فلم يتغير أي ضيف ولا أي مفتاح متحقق. ويعرض الجدول الصيغتين معًا؛ وتستخدم السلاسل من 14 إلى 19 الأولى، بايتًا ببايت. وما كان مرتبطًا بـ genesis من قبل ولم يتغير: الأصوات والمقترحات (منذ consensus_domain: 1)، وRegistration بصيغته v2، وصوت AdmitValidator. وما لم يُنقل: التوقيع المشترك للجسر على السك (أعلاه). تحتاج المحفظة إلى v0.6.8 للإرسال على السلسلة 20، وتحدد الصيغة بمعرّف السلسلة لا بما تدّعيه العقدة؛ ويبلغ عنها rand_getLimits.binding_domain.
| القيمة | التركيب |
|---|---|
| العنوان الشفاف | blake3("rand-address" || dilithium2_public_key)، بصيغة base58 |
| معرّف المعاملة | blake3("rand-txid-3" || bincode(view))، حيث view هي المعاملة بعد استبدال بايتات إثبات الحزمة بـ blake3(proof) وإثبات المصادقة فيها بـ blake3(auth_proof)؛ ويدخل auth_commit كما هو. وكان النطاق rand-txid-2، دون حقول مصادقة، حتى السلسلة 16 |
| ربط المعاملة | blake3("rand-tx-bind-1" || bincode(chain_id, bundle', action')) في السلاسل من 14 إلى 19؛ وblake3("rand-tx-bind-2" || bincode(genesis_hash, chain_id, bundle', action')) في السلسلة 20. ثماني كلمات u32 بترتيب little-endian، حيث تستبدل ' المتجه الفارغ بكل من bundle.proof وbundle.auth_proof وproof الخاص بـ Aggregate؛ وbincode بأعداد صحيحة ثابتة العرض بترتيب little-endian. يُصنع كل إثبات حزمة وكل إثبات مصادقة فوق هذه الكلمات ويُتحقق منه مقابلها |
| ربط الاستدعاء | blake3("rand-call-bind-1" || …)، أو rand-call-bind-2 مع تجزئة genesis أولًا في السلسلة 20: تركيب ربط المعاملة نفسه مع تفريغ proof الخاص بـ Call (أو Invoke) هو أيضًا. وفي genesis من نوع hardening_v6، مثل السلسلة 20، يكون المقطع العام لإثبات الاستدعاء كلمات البرنامج العامة وقت النشر متبوعة بهذه الكلمات الثماني، ويضيف إثبات Invoke انتقاله كلمات سياق بعدها |
| معرّف البرنامج | blake3("rand-program" || base_pc as 4 LE bytes || words as 4 LE bytes each) |
| هوية p2p | مفتاح ed25519 من blake3("rand-p2p-identity" || seed) |
| معرّف أصل الجسر (لكل دعم) | blake3("rand-bridge-asset" || token_chain as 2 BE bytes || token_address (32 bytes)) — يحسبه rand_bridgeAssetId ويطبعه rand_getAssets لكل صف دعم؛ وهو يعرّف عملة المصدر على الشبكة، لا الرمز |
| معرّف أصل رمز RPL، أصلي | blake3("rand-rpl-asset" || bincode(name, symbol, decimals, authority, initial: Option<InitialMint>, salt))، وsalt قيمة من 32 بايت يختارها المنشئ؛ تُعرض بصيغة hex وبصيغة rpl1… |
| معرّف أصل رمز RPL، مُجسَّر | blake3("rand-rpl-asset" || bincode(name, symbol, BRIDGE_DECIMALS, salt)) — لا على زوج (chain, token)، لأن الرمز المُجسَّر الواحد يمتد على عدة أدعمة |
| تعمية إيداع الجسر | r = blake3("rand-deposit-r-1" || mu)، وهي قيمة r الوحيدة التي يقبلها القبول لـ BridgeAttest (وإلا WrongDepositBlinding) |
| تعمية مذكرات رسوم الجسر (السلسلة 20) | مذكرة رسوم الإيداع: r = blake3("rand-bridge-fee-r-1" || mu)؛ ومذكرة رسوم الحرق: r = blake3("rand-bridge-burn-fee-r-1" || txid)؛ وتُقرأ كلتاهما كثماني كلمات little-endian. ليس لهذه المذكرات مظروف: كل الحقول عامة، والمالك هو bridge.fees.recipient في genesis |
| مستلم الجسر | blake3("rand-shielded-recipient" || pk_bytes || kem_ek) على العنوان المحمي الكامل |
رسالة Mint للصنبور | blake3("rand-mint-2" || bincode(chain_id, cm, pk, time, r, envelope, amount))؛ وفي السلسلة 20 blake3("rand-mint-3" || bincode(genesis_hash, chain_id, cm, pk, time, r, envelope, amount)) |
رسالتا TokenMint وSetAuthority | blake3("rand-rpl-mint-1" or "rand-rpl-authority-1", chain_id || asset_id || nonce || body)؛ ويتضمن body السك القيمة blake3(bincode(envelope)). وفي السلسلة 20 rand-rpl-mint-2 وrand-rpl-authority-2، مع تجزئة genesis أولًا |
رسالة Registration | blake3("rand-register-2" || bincode(genesis_hash, chain_id, validator, payout)) في genesis يحوي staking.registration_v2 أو binding_domain: 1، مثل السلسلة 20 (يُرفض هناك التسجيل بصيغة v1)؛ وblake3("rand-register" || bincode(chain_id, payout)) فيما عدا ذلك |
صوت AdmitValidator (السلسلة 20) | blake3("rand-admit-validator-1" || genesis_hash || candidate_address)، يوقّعه كل مدقّق مصوّت |
رسالة Unbond | blake3("rand-unbond" || bincode(chain_id, validator, amount, nonce))؛ وفي السلسلة 20 blake3("rand-unbond-2" || bincode(genesis_hash, chain_id, validator, amount, nonce)) |
رسالة Withdraw | blake3("rand-withdraw" || bincode(chain_id, validator, amount, nonce, time, r, envelope))؛ وفي السلسلة 20 rand-withdraw-2، مع تجزئة genesis أولًا |
| عقدة Merkle (أشجار الحالة) | blake3("rand-merkle-node" || left || right) |
| ورقة سجل الرموز | blake3("rand-token-leaf-1" || bincode(TokenInfo))، بترتيب الفهرس، تحت tokens_root |
| جذر الحالة | في السلسلة 20، blake3("rand-state-admitted-1" || inner || admitted_root) حول inner = blake3("rand-state-8" || tree_root || nullifier_root || validators_root || programs_root || bridge_root || tokens_root || faucet_epoch || faucet_minted_in_epoch || bond_queue_root || gas_price || byte_price || program_state_root)، حيث program_state_root = blake3("rand-program-state-1" || cells_root || vaults_root) (RPL-2)، وعدّادا الصنبور والسعران الحيان كل منها 8 بايتات big-endian، والغلاف يلتزم بالمجموعة المقبولة (staking.admission_by_vote). أما جذر السلسلة 19 فكان blake3("rand-state-7" || …) على الحقول نفسها حتى byte_price (يلحق قسم staking في genesis الحقول الثلاثة بعد tokens_root تحت rand-state-5، كما في السلاسل من 15 إلى 17؛ ويلحق قسم gas.dynamic في genesis السعرين وينقل النطاق إلى rand-state-7)؛ وrand-state-4 على الحقول الستة الأولى في السلسلة 14؛ وrand-state-2 على الأربعة الأولى في سلسلة بلا قسم bridge أو tokens أو aggregation (الإجماع) |
Poseidon2 مع وسم نطاق: H(domain, msg) = sponge_hash([domain, msg...])، والوسم أول كلمة تُمتص، وكل كلمة عنصر من Goldilocks، ويُقسَّم الملخص ذو العناصر الأربعة إلى ثماني كلمات u32 (النصف الأدنى ثم النصف الأعلى لكل عنصر). وسوم النطاق:
| الوسم | القيمة | البناء |
|---|---|---|
NK | 1 | مفتاح العرض nk = H(1, sk) |
PK | 2 | القيمة العامة للملاحظة pk = H(2, nk) |
NF | 3 | المُبطِل (nullifier) H(3, nk || cm) |
CM | 4 | التزام الملاحظة H(4, pk(8) || from(8) || amount_lo || amount_hi || asset || time || r(8)) — 28 كلمة |
OVK, KEM_SEED | 5, 6 | مفتاح العرض الصادر وبذرة ML-KEM، عبر دالة تجزئة عريضة بنمط العدّاد [domain, nk, counter] |
NODE | 7 | عقدة الشجرة H(7, left || right)؛ والورقة الفارغة كلها أصفار |
HC | 8 | بصمة البرنامج؛ يوضع الوسم وbase_pc وlen في مسارات السعة (capacity) من التبديل الأول، ثم تُمتص الكلمات أربعًا في كل كتلة |
OUT | 9 | بصمة المخرجات لبرنامج الضيف الخاص بالتحويل |
IN | 10 | H_IN: ترويسة سعة [10, n_in, 0]، ثم ملح من 4 كلمات، ثم المدخلات |
BUNDLE | 11 | بصمة الحزمة المتقاعدة ذات المدخلين والمخرجين على 47 كلمة عامة؛ ولا تثبّت أي سلسلة ذلك البرنامج الضيف بعد الآن |
| الحزمة المخفية | 64 | بصمة حزمة الأصل المخفي على 81 كلمة في السلاسل من 14 إلى 16: المرساة، وأربعة مُبطِلات، وأربعة التزامات، وfee، وburn_a، وburn_r (كلمتان لكل منهما)، وburn_asset، وtime، وكلمة التلوّث (taint) أخيرًا. وفي السلاسل من 17 إلى 20 (الإصدار 3 من برنامج الحزمة الضيف) تبلغ 89 كلمة: إذ تقع الكلمات الثماني لالتزام التفويض c قبل كلمة التلوّث مباشرة. أما الأصل الخاص A فليس فيها. والوسم محلي للعقدة ويبتعد عن الوسوم المضمّنة من 1 إلى 15 |
AUTH | 65 | التزام التفويض c = H(65, nk || salt)، من 16 كلمة، بملح جديد من 256 بتًا لكل حزمة؛ ويُنشره إثبات الحزمة ضمن بصمته، وإثبات التفويض بوصفه كلماته الثماني الخارجة، وتحمله الحزمة باسم auth_commit (السلاسل من 17 إلى 20). محلي للعقدة، مثل 64 |
PUB | 15 | H_PUB: ترويسة [15, n_pub, 0]، بلا ملح؛ وفي البرنامج، على السلسلة 20، تُثبَّت الكلمات عند النشر (بحد أقصى 32,768)، ويتألف مقطع كل استدعاء من تلك الكلمات متبوعة بالكلمات الثماني لربط الاستدعاء، ويُفحص الاستدعاء مقابل بصمة ذلك المقطع؛ أما في إثبات الحزمة وإثبات التفويض فالمقطع هو كلمات الربط الثماني للمعاملة؛ والتكوين الأول (genesis) الخالي من max_program_public_words لا يقبل إلا المقطع الفارغ |
hc وH_IN وH_PUB ليست دوال إسفنجية (sponge) بسيطة مسبوقة بالرسالة: إذ تدخل الترويسة في السعة (capacity) كي تمتص صفوف البصمة في جدول cpu أربع كلمات بالضبط في كل تبديل. أعد إنتاجها بالحزمة المضمّنة (randprotocol_zkvm::hash::{input_digest, public_digest}، isa::Program::digest) بدلًا من الحساب اليدوي.
الإسفنجة البسيطة لا تُحشي، ولذلك تُجزَّأ [a] و[a, 0] إلى القيمة نفسها داخل الكتلة الأولى. وكل بناء أعلاه يجزّئ رسالة ذات طول ثابت تحت وسمه الخاص. وللبيانات التي قد يتغير طولها، أضافت مجموعة القيود 7 إسفنجة مقيَّدة بالطول (hash::sponge_hash_len، واستدعاء النظام POSEIDON2_LEN): تبدأ من الحالة [0, 0, 0, 0, n, 0, 0, 0]، حيث n عدد الكلمات، وتُجري تبديلًا واحدًا على الأقل. وهي تجزئة مختلفة للكلمات نفسها، ولا تستخدمها أي ملاحظة ولا مُبطِل ولا جذر ولا بصمة على السلسلة.
خاصيتان يجدر تذكّرهما: hc مُلزِم لكنه غير مُخفٍ (لا ملح فيه، فيمكن تأكيد برنامج مُخمَّن، ويمكن ربط نشرين لبرنامج واحد أحدهما بالآخر)، أما H_IN فهو مُخفٍ كما هو مُلزِم (ملح جديد من 128 بتًا لكل إثبات)، ولذلك فإن نشر H_IN لا يكشف شيئًا عن المدخلات حتى يفتحه حامل الملح.
اشتقاق المفاتيح
| المفتاح | يُشتق من |
|---|---|
| زوج مفاتيح Dilithium2 (العقدة) | حتمي من البذرة ذات 32 بايتًا |
| libp2p ed25519 (العقدة) | blake3("rand-p2p-identity" || seed) |
مفتاح العرض، وpk، وovk، وزوج مفاتيح ML-KEM (المحفظة) | اشتقاقات Poseidon2 من مفتاح الإنفاق كما في الجدول أعلاه؛ وزوج ML-KEM هو MlKem768::from_seed(kem_seed) |
تحمل الأوراق البحثية في صفحة الأوراق الحجج الأمنية: الخيارات المقاومة للحوسبة الكمومية، وحساب سلامة FRI ولماذا يُبقى على 80 استعلامًا، وحدّ طول الأثر (trace).