استخدام العناوين المتخفية
أنت بيل. لأسباب لن نخوض فيها، تريد التبرع لحملة "أليس لملكة العالم" وتريد أن تعرف أليس أنك تبرعت حتى تمنحك مكافأة إذا فازت. لسوء الحظ، فوزها ليس مضمونًا. هناك حملة منافسة، "كارول لإمبراطورة النظام الشمسي". إذا فازت كارول، واكتشفت أنك تبرعت لأليس، فستكون في ورطة. لذلك لا يمكنك ببساطة تحويل 200 ETH من حسابك إلى حساب أليس.
يقدم ERC-5564 (opens in a new tab) الحل. يشرح هذا الـ ERC كيفية استخدام العناوين المتخفية (opens in a new tab) من أجل تحويل مجهول الهوية.
تحذير: علم التشفير وراء العناوين المتخفية سليم، على حد علمنا. ومع ذلك، هناك هجمات قناة جانبية محتملة. أدناه، سترى ما يمكنك القيام به لتقليل هذه المخاطر.
كيف تعمل العناوين المتخفية
سيحاول هذا المقال شرح العناوين المتخفية بطريقتين. الأولى هي كيفية استخدامها. هذا الجزء كافٍ لفهم بقية المقال. ثم، هناك شرح للرياضيات وراءها. إذا كنت مهتمًا بـ علم التشفير، فاقرأ هذا الجزء أيضًا.
النسخة المبسطة (كيفية استخدام العناوين المتخفية)
تنشئ أليس مفتاحين خاصين وتنشر المفاتيح العامة المقابلة (والتي يمكن دمجها في عنوان وصفي واحد مزدوج الطول). ينشئ بيل أيضًا مفتاحًا خاصًا وينشر المفتاح العام المقابل.
باستخدام مفتاح عام لأحد الأطراف ومفتاح خاص للطرف الآخر، يمكنك استنتاج سر مشترك لا يعرفه سوى أليس وبيل (لا يمكن استنتاجه من المفاتيح العامة وحدها). باستخدام هذا السر المشترك، يحصل بيل على عنوان متخفي ويمكنه إرسال الأصول إليه.
تحصل أليس أيضًا على العنوان من السر المشترك، ولكن لأنها تعرف المفاتيح الخاصة للمفاتيح العامة التي نشرتها، يمكنها أيضًا الحصول على مفتاح خاص الذي يتيح لها السحب من ذلك العنوان.
الرياضيات (لماذا تعمل العناوين المتخفية بهذا الشكل)
تستخدم العناوين المتخفية القياسية تشفير المنحنى الإهليلجي (ECC) (opens in a new tab) للحصول على أداء أفضل مع عدد أقل من بتات المفاتيح، مع الحفاظ على نفس مستوى الأمان. ولكن في الغالب يمكننا تجاهل ذلك والتظاهر بأننا نستخدم الحساب العادي.
هناك رقم يعرفه الجميع، G. يمكنك الضرب في G. ولكن بسبب طبيعة ECC، من المستحيل عمليًا القسمة على G. الطريقة التي يعمل بها تشفير المفتاح العام بشكل عام في إيثيريوم هي أنه يمكنك استخدام مفتاح خاص، Ppriv، لتوقيع المعاملات التي يتم التحقق منها بعد ذلك بواسطة مفتاح عام، Ppub = GPpriv.
تنشئ أليس مفتاحين خاصين، Kpriv و Vpriv. سيتم استخدام Kpriv لإنفاق الأموال من العنوان المتخفي، و Vpriv لعرض العناوين التي تنتمي إلى أليس. ثم تنشر أليس المفاتيح العامة: Kpub = GKpriv و Vpub = GVpriv
ينشئ بيل مفتاحًا خاصًا ثالثًا، Rpriv، وينشر Rpub = GRpriv في سجل مركزي (كان بإمكان بيل أيضًا إرساله إلى أليس، لكننا نفترض أن كارول تستمع).
يحسب بيل RprivVpub = GRprivVpriv، والذي يتوقع أن تعرفه أليس أيضًا (موضح أدناه). تسمى هذه القيمة S، السر المشترك. يمنح هذا بيل مفتاحًا عامًا، Ppub = Kpub+G*hash(S). من هذا المفتاح العام، يمكنه حساب عنوان وإرسال أي موارد يريدها إليه. في المستقبل، إذا فازت أليس، يمكن لبيل أن يخبرها بـ Rpriv لإثبات أن الموارد جاءت منه.
تحسب أليس RpubVpriv = GRprivVpriv. هذا يمنحها نفس السر المشترك، S. ولأنها تعرف المفتاح الخاص، Kpriv، يمكنها حساب Ppriv = Kpriv+hash(S). يتيح لها هذا المفتاح الوصول إلى الأصول في العنوان الذي ينتج عن Ppub = GPpriv = GKpriv+G*hash(S) = Kpub+G*hash(S).
لدينا مفتاح عرض منفصل للسماح لأليس بالتعاقد من الباطن مع خدمات حملة ديف للسيطرة على العالم. أليس مستعدة للسماح لديف بمعرفة العناوين العامة وإبلاغها عند توفر المزيد من الأموال، لكنها لا تريده أن ينفق أموال حملتها.
نظرًا لأن العرض والإنفاق يستخدمان مفاتيح منفصلة، يمكن لأليس إعطاء ديف Vpriv. ثم يمكن لديف حساب S = RpubVpriv = GRprivVpriv وبهذه الطريقة يحصل على المفاتيح العامة (Ppub = Kpub+G*hash(S)). ولكن بدون Kpriv لا يمكن لديف الحصول على المفتاح الخاص.
باختصار، هذه هي القيم التي يعرفها المشاركون المختلفون.
| أليس | منشور | بيل | ديف |
|---|---|---|---|
| G | G | G | G |
| Kpriv | - | - | - |
| Vpriv | - | - | Vpriv |
| Kpub = GKpriv | Kpub | Kpub | Kpub |
| Vpub = GVpriv | Vpub | Vpub | Vpub |
| - | - | Rpriv | - |
| Rpub | Rpub | Rpub = GRpriv | Rpub |
| S = RpubVpriv = GRprivVpriv | - | S = RprivVpub = GRprivVpriv | S = RpubVpriv = GRprivVpriv |
| Ppub = Kpub+G*hash(S) | - | Ppub = Kpub+G*hash(S) | Ppub = Kpub+G*hash(S) |
| Address=f(Ppub) | - | Address=f(Ppub) | Address=f(Ppub) |
| Ppriv = Kpriv+hash(S) | - | - | - |
عندما تسير الأمور بشكل خاطئ مع العناوين المتخفية
لا توجد أسرار على سلسلة الكتل. في حين أن العناوين المتخفية يمكن أن توفر لك الخصوصية، فإن هذه الخصوصية عرضة لتحليل حركة المرور. لنأخذ مثالاً بسيطًا، تخيل أن بيل يمول عنوانًا ويرسل على الفور معاملة لنشر قيمة Rpub. بدون Vpriv الخاص بـ أليس، لا يمكننا التأكد من أن هذا عنوان متخفي، ولكن هذا هو الاحتمال الأرجح. ثم، نرى معاملة أخرى تقوم بـ تحويل كل الـ ETH من ذلك العنوان إلى عنوان صندوق حملة أليس. قد لا نتمكن من إثبات ذلك، ولكن من المحتمل أن بيل قد تبرع للتو لحملة أليس. من المؤكد أن كارول ستعتقد ذلك.
من السهل على بيل فصل نشر Rpub عن تمويل العنوان المتخفي (القيام بهما في أوقات مختلفة، ومن عناوين مختلفة). ومع ذلك، هذا غير كافٍ. النمط الذي تبحث عنه كارول هو أن بيل يمول عنوانًا، ثم يسحب صندوق حملة أليس منه.
أحد الحلول هو ألا تسحب حملة أليس الأموال مباشرة، بل تستخدمها للدفع لطرف ثالث. إذا أرسلت حملة أليس 10 ETH إلى خدمات حملة ديف للسيطرة على العالم، فإن كارول تعرف فقط أن بيل تبرع لأحد عملاء ديف. إذا كان لدى ديف عدد كافٍ من العملاء، فلن تتمكن كارول من معرفة ما إذا كان بيل قد تبرع لأليس التي تتنافس معها، أو لآدم أو ألبرت أو أبيجيل الذين لا تهتم بهم كارول. يمكن لأليس تضمين قيمة تجزئة مع الدفعة، ثم تزويد ديف بالصورة المسبقة (preimage)، لإثبات أنها كانت تبرعها. بدلاً من ذلك، كما لوحظ أعلاه، إذا أعطت أليس ديف Vpriv الخاص بها، فهو يعرف بالفعل من أين جاءت الدفعة.
المشكلة الرئيسية في هذا الحل هي أنه يتطلب من أليس الاهتمام بالسرية عندما تفيد هذه السرية بيل. قد ترغب أليس في الحفاظ على سمعتها حتى يتبرع لها بوب صديق بيل أيضًا. ولكن من الممكن أيضًا ألا تمانع في فضح بيل، لأنه حينها سيخاف مما سيحدث إذا فازت كارول. قد ينتهي الأمر ببيل بتقديم المزيد من الدعم لأليس.
استخدام طبقات تخفي متعددة
بدلاً من الاعتماد على أليس للحفاظ على الخصوصية الخاصة بـ بيل، يمكن لبيل القيام بذلك بنفسه. يمكنه إنشاء عناوين وصفية متعددة لأشخاص خياليين، بوب وبيلا. ثم يرسل بيل ETH إلى بوب، و"بوب" (وهو في الواقع بيل) يرسله إلى بيلا. "بيلا" (وهي أيضًا بيل) ترسله إلى أليس.
لا يزال بإمكان كارول إجراء تحليل لحركة المرور ورؤية مسار بيل-إلى-بوب-إلى-بيلا-إلى-أليس. ومع ذلك، إذا استخدم "بوب" و"بيلا" أيضًا ETH لأغراض أخرى، فلن يبدو أن بيل قد قام بـ تحويل أي شيء إلى أليس، حتى لو سحبت أليس على الفور من العنوان المتخفي إلى عنوان حملتها المعروف.
كتابة تطبيق للعنوان المتخفي
يشرح هذا المقال تطبيقًا للعنوان المتخفي متاحًا على GitHub (opens in a new tab).
الأدوات
هناك مكتبة عناوين متخفية بـ TypeScript (opens in a new tab) يمكننا استخدامها. ومع ذلك، يمكن أن تكون عمليات علم التشفير مكثفة لوحدة المعالجة المركزية. أفضل تنفيذها بلغة مجمعة، مثل Rust (opens in a new tab)، واستخدام WASM (opens in a new tab) لتشغيل الكود في المتصفح.
سنستخدم Vite (opens in a new tab) و React (opens in a new tab). هذه أدوات متوافقة مع معايير الصناعة؛ إذا لم تكن على دراية بها، يمكنك استخدام هذا البرنامج التعليمي. لاستخدام Vite، نحتاج إلى Node.
رؤية العناوين المتخفية أثناء العمل
-
قم بتثبيت الأدوات اللازمة: Rust (opens in a new tab) و Node (opens in a new tab).
-
استنسخ مستودع GitHub.
git clone https://github.com/qbzzt/251022-stealth-addresses.git cd 251022-stealth-addresses -
قم بتثبيت المتطلبات الأساسية وتجميع كود Rust.
cd src/rust-wasm rustup target add wasm32-unknown-unknown cargo install wasm-pack wasm-pack build --target web -
ابدأ خادم الويب.
cd ../.. npm install npm run dev -
تصفح إلى التطبيق (opens in a new tab). تحتوي صفحة التطبيق هذه على إطارين: أحدهما لواجهة مستخدم أليس والآخر لواجهة بيل. الإطاران لا يتواصلان؛ هما فقط في نفس الصفحة للراحة.
-
بصفتك أليس، انقر فوق Generate a Stealth Meta-Address (إنشاء عنوان وصفي متخفي). سيعرض هذا العنوان المتخفي الجديد والمفاتيح الخاصة المقابلة. انسخ العنوان الوصفي المتخفي إلى الحافظة.
-
بصفتك بيل، الصق العنوان الوصفي المتخفي الجديد وانقر فوق Generate an address (إنشاء عنوان). يمنحك هذا العنوان لتمويله لأليس.
-
انسخ العنوان والمفتاح العام الخاص بـ بيل والصقهما في منطقة "Private key for address generated by Bill" (المفتاح الخاص للعنوان الذي أنشأه بيل) في واجهة مستخدم أليس. بمجرد ملء هذه الحقول، سترى المفتاح الخاص للوصول إلى الأصول في ذلك العنوان.
-
يمكنك استخدام آلة حاسبة عبر الإنترنت (opens in a new tab) للتأكد من أن المفتاح الخاص يتوافق مع العنوان.
كيف يعمل البرنامج
مكون WASM
الكود المصدري الذي يتم تجميعه في WASM مكتوب بلغة Rust (opens in a new tab). يمكنك رؤيته في src/rust_wasm/src/lib.rs (opens in a new tab). هذا الكود هو في الأساس واجهة بين كود JavaScript و مكتبة eth-stealth-addresses (opens in a new tab).
Cargo.toml
Cargo.toml (opens in a new tab) في Rust يشبه package.json (opens in a new tab) في JavaScript. يحتوي على معلومات الحزمة، وإعلانات التبعية، إلخ.
[package]
name = "rust-wasm"
version = "0.1.0"
edition = "2024"
[dependencies]
eth-stealth-addresses = "0.1.0"
hex = "0.4.3"
wasm-bindgen = "0.2.104"
getrandom = { version = "0.2", features = ["js"] }
تحتاج حزمة getrandom (opens in a new tab) إلى إنشاء قيم عشوائية. لا يمكن القيام بذلك بوسائل خوارزمية بحتة؛ فهو يتطلب الوصول إلى عملية فيزيائية كمصدر لـ إنتروبيا. يحدد هذا التعريف أننا سنحصل على هذه الـ إنتروبيا عن طريق سؤال المتصفح الذي نعمل فيه.
console_error_panic_hook = "0.1.7"
تمنحنا هذه المكتبة (opens in a new tab) رسائل خطأ ذات مغزى أكبر عندما يصاب كود WASM بالذعر (panics) ولا يمكنه الاستمرار.
[lib]
crate-type = ["cdylib", "rlib"]
نوع المخرجات المطلوب لإنتاج كود WASM.
lib.rs
هذا هو كود Rust الفعلي.
use wasm_bindgen::prelude::*;
التعريفات لإنشاء حزمة WASM من Rust. وهي موثقة هنا (opens in a new tab).
use eth_stealth_addresses::{
generate_stealth_meta_address,
generate_stealth_address,
compute_stealth_key
};
الدوال التي نحتاجها من مكتبة eth-stealth-addresses (opens in a new tab).
use hex::{decode,encode};
تستخدم Rust عادةً مصفوفات (opens in a new tab) البايت ([u8; <size>]) للقيم. ولكن في JavaScript، نستخدم عادةً السلاسل السداسية العشرية. تترجم مكتبة hex (opens in a new tab) لنا من تمثيل إلى آخر.
#[wasm_bindgen]
قم بإنشاء روابط WASM لتتمكن من استدعاء هذه الدالة من JavaScript.
pub fn wasm_generate_stealth_meta_address() -> String {
أسهل طريقة لإرجاع كائن بحقول متعددة هي إرجاع سلسلة JSON.
let (address, spend_private_key, view_private_key) =
generate_stealth_meta_address();
تُرجع generate_stealth_meta_address (opens in a new tab) ثلاثة حقول:
- العنوان الوصفي (Kpub و Vpub)
- المفتاح الخاص للعرض (Vpriv)
- المفتاح الخاص للإنفاق (Kpriv)
تتيح لنا صيغة الصفوف (tuple) (opens in a new tab) فصل هذه القيم مرة أخرى.
format!("{{\"address\":\"{}\",\"view_private_key\":\"{}\",\"spend_private_key\":\"{}\"}}",
encode(address),
encode(view_private_key),
encode(spend_private_key)
)
}
استخدم ماكرو format! (opens in a new tab) لإنشاء السلسلة المشفرة بـ JSON. استخدم hex::encode (opens in a new tab) لتغيير المصفوفات إلى سلاسل سداسية عشرية.
fn str_to_array<const N: usize>(s: &str) -> Option<[u8; N]> {
تحول هذه الدالة سلسلة سداسية عشرية (مقدمة من JavaScript) إلى مصفوفة بايت. نستخدمها لتحليل القيم المقدمة بواسطة كود JavaScript. هذه الدالة معقدة بسبب كيفية تعامل Rust مع المصفوفات والمتجهات.
يُطلق على تعبير <const N: usize> اسم عام (generic) (opens in a new tab). N هو معلمة تتحكم في طول المصفوفة المرجعة. تسمى الدالة في الواقع str_to_array::<n>، حيث n هو طول المصفوفة.
القيمة المرجعة هي Option<[u8; N]>، مما يعني أن المصفوفة المرجعة اختيارية (opens in a new tab). هذا نمط نموذجي في Rust للدوال التي قد تفشل.
على سبيل المثال، إذا استدعينا str_to_array::10("bad060a7")، فمن المفترض أن تُرجع الدالة مصفوفة من عشر قيم، لكن الإدخال هو أربعة بايتات فقط. يجب أن تفشل الدالة، وتفعل ذلك عن طريق إرجاع None. ستكون القيمة المرجعة لـ str_to_array::4("bad060a7") هي Some<[0xba, 0xd0, 0x60, 0xa7]>.
// تُرجع decode Result<Vec<u8>, _>
let vec = decode(s).ok()?;
تُرجع دالة hex::decode (opens in a new tab) Result<Vec<u8>, FromHexError>. يمكن أن يحتوي نوع Result (opens in a new tab) إما على نتيجة ناجحة (Ok(value)) أو خطأ (Err(error)).
تحول طريقة .ok() الـ Result إلى Option، والتي تكون قيمتها إما قيمة Ok() إذا نجحت أو None إذا لم تنجح. أخيرًا، يقوم عامل علامة الاستفهام (opens in a new tab) بإحباط الدوال الحالية وإرجاع None إذا كان Option فارغًا. بخلاف ذلك، فإنه يفك تغليف القيمة ويرجعها (في هذه الحالة، لتعيين قيمة لـ vec).
تبدو هذه طريقة معقدة بشكل غريب للتعامل مع الأخطاء، لكن Result و Option يضمنان التعامل مع جميع الأخطاء، بطريقة أو بأخرى.
if vec.len() != N { return None; }
إذا كان عدد البايتات غير صحيح، فهذا فشل، ونرجع None.
// تستهلك try_into vec وتحاول إنشاء [u8; N]
let array: [u8; N] = vec.try_into().ok()?;
تحتوي Rust على نوعين من المصفوفات. المصفوفات (Arrays) (opens in a new tab) لها حجم ثابت. يمكن أن تنمو المتجهات (Vectors) (opens in a new tab) وتتقلص. تُرجع hex::decode متجهًا، لكن مكتبة eth_stealth_addresses تريد تلقي مصفوفات. تقوم .try_into() (opens in a new tab) بتحويل قيمة إلى نوع آخر، على سبيل المثال، متجه إلى مصفوفة.
Some(array)
}
لا تتطلب منك Rust استخدام الكلمة الأساسية return (opens in a new tab) عند إرجاع قيمة في نهاية الدالة.
#[wasm_bindgen]
pub fn wasm_generate_stealth_address(stealth_address: &str) -> Option<String> {
تتلقى هذه الدالة عنوانًا وصفيًا عامًا، والذي يتضمن كلاً من Vpub و Kpub. تُرجع العنوان المتخفي، والمفتاح العام المراد نشره (Rpub)، وقيمة مسح ضوئي من بايت واحد تسرع من تحديد العناوين المنشورة التي قد تنتمي إلى أليس.
قيمة المسح الضوئي هي جزء من السر المشترك (S = GRprivVpriv). هذه القيمة متاحة لأليس، والتحقق منها أسرع بكثير من التحقق مما إذا كان f(Kpub+G*hash(S)) يساوي العنوان المنشور.
let (address, r_pub, scan) =
generate_stealth_address(&str_to_array::<66>(stealth_address)?);
نستخدم generate_stealth_address (opens in a new tab) الخاصة بالمكتبة.
format!("{{\"address\":\"{}\",\"rPub\":\"{}\",\"scan\":\"{}\"}}",
encode(address),
encode(r_pub),
encode(&[scan])
).into()
}
قم بإعداد سلسلة المخرجات المشفرة بـ JSON.
#[wasm_bindgen]
pub fn wasm_compute_stealth_key(
address: &str,
bill_pub_key: &str,
view_private_key: &str,
spend_private_key: &str
) -> Option<String> {
.
.
.
}
تستخدم هذه الدالة compute_stealth_key (opens in a new tab) الخاصة بالمكتبة لحساب المفتاح الخاص للسحب من العنوان (Rpriv). يتطلب هذا الحساب هذه القيم:
- العنوان (Address=f(Ppub))
- المفتاح العام الذي أنشأه بيل (Rpub)
- المفتاح الخاص للعرض (Vpriv)
- المفتاح الخاص للإنفاق (Kpriv)
#[wasm_bindgen(start)]
يحدد #[wasm_bindgen(start)] (opens in a new tab) أنه يتم تنفيذ الدالة عند تهيئة كود WASM.
pub fn main() {
console_error_panic_hook::set_once();
}
يحدد هذا الكود إرسال مخرجات الذعر (panic) إلى وحدة تحكم JavaScript. لرؤية ذلك أثناء العمل، استخدم التطبيق وامنح بيل عنوانًا وصفيًا غير صالح (فقط قم بتغيير رقم سداسي عشري واحد). سترى هذا الخطأ في وحدة تحكم JavaScript:
rust_wasm.js:236 panicked at /home/ori/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/subtle-2.6.1/src/lib.rs:701:9:
assertion `left == right` failed
left: 0
right: 1
متبوعًا بتتبع المكدس (stack trace). ثم امنح بيل العنوان الوصفي الصالح، وامنح أليس إما عنوانًا غير صالح أو مفتاحًا عامًا غير صالح. سترى هذا الخطأ:
rust_wasm.js:236 panicked at /home/ori/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/eth-stealth-addresses-0.1.0/src/lib.rs:78:9:
keys do not generate stealth address
مرة أخرى، متبوعًا بتتبع المكدس.
واجهة المستخدم
واجهة المستخدم مكتوبة باستخدام React (opens in a new tab) ويتم تقديمها بواسطة Vite (opens in a new tab). يمكنك التعرف عليها باستخدام هذا البرنامج التعليمي. ليست هناك حاجة لـ Wagmi (opens in a new tab) هنا لأننا لا نتفاعل مباشرة مع سلسلة الكتل أو محفظة.
الجزء الوحيد غير الواضح في واجهة المستخدم هو اتصال WASM. إليك كيف يعمل.
vite.config.js
يحتوي هذا الملف على تكوين Vite (opens in a new tab).
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import wasm from "vite-plugin-wasm";
// https://vite.dev/config/
export default defineConfig({
plugins: [react(), wasm()],
})
نحتاج إلى إضافتين لـ Vite: react (opens in a new tab) و wasm (opens in a new tab).
App.jsx
هذا الملف هو المكون الرئيسي للتطبيق. إنه حاوية تتضمن مكونين: Alice و Bill، وهما واجهتا المستخدم لهؤلاء المستخدمين. الجزء ذو الصلة بـ WASM هو كود التهيئة.
import init from './rust-wasm/pkg/rust_wasm.js'
عندما نستخدم wasm-pack (opens in a new tab)، فإنه ينشئ ملفين نستخدمهما هنا: ملف wasm يحتوي على الكود الفعلي (هنا، src/rust-wasm/pkg/rust_wasm_bg.wasm) وملف JavaScript يحتوي على التعريفات لاستخدامه (هنا، src/rust_wasm/pkg/rust_wasm.js). التصدير الافتراضي لملف JavaScript هذا هو الكود الذي يجب تشغيله لبدء WASM.
function App() {
.
.
.
useEffect(() => {
const loadWasm = async () => {
try {
await init();
setWasmReady(true)
} catch (err) {
console.error('Error loading wasm:', err)
alert("Wasm error: " + err)
}
}
loadWasm()
}, []
)
يتيح لك خطاف (hook) useEffect (opens in a new tab) تحديد دالة يتم تنفيذها عندما تتغير متغيرات الحالة (state). هنا، قائمة متغيرات الحالة فارغة ([])، لذلك يتم تنفيذ هذه الدالة مرة واحدة فقط عند تحميل الصفحة.
يجب أن تعود دالة التأثير (effect) على الفور. لاستخدام كود غير متزامن، مثل init الخاص بـ WASM (والذي يجب أن يحمل ملف .wasm وبالتالي يستغرق وقتًا) نحدد دالة async (opens in a new tab) داخلية ونقوم بتشغيلها بدون await.
Bill.jsx
هذه هي واجهة المستخدم الخاصة بـ بيل. لها إجراء واحد، وهو إنشاء عنوان بناءً على العنوان الوصفي المتخفي الذي قدمته أليس.
import { wasm_generate_stealth_address } from './rust-wasm/pkg/rust_wasm.js'
بالإضافة إلى التصدير الافتراضي، يقوم كود JavaScript الذي تم إنشاؤه بواسطة wasm-pack بتصدير دالة لكل دالة في كود WASM.
<button onClick={() => {
setPublicAddress(JSON.parse(wasm_generate_stealth_address(stealthMetaAddress)))
}}>
لاستدعاء دوال WASM، نقوم فقط باستدعاء الدالة المصدرة بواسطة ملف JavaScript الذي تم إنشاؤه بواسطة wasm-pack.
Alice.jsx
الكود في Alice.jsx مشابه، باستثناء أن أليس لديها إجراءان:
- إنشاء عنوان وصفي
- الحصول على المفتاح الخاص لعنوان نشره بيل
الخاتمة
العناوين المتخفية ليست حلاً سحريًا؛ يجب استخدامها بشكل صحيح. ولكن عند استخدامها بشكل صحيح، يمكنها تمكين الخصوصية على سلسلة الكتل العامة.