মূল কন্টেন্টে যান

গোপন ঠিকানা ব্যবহার করা

গোপন ঠিকানা
গোপনীয়তা
ক্রিপ্টোগ্রাফি
Rust
wasm
মধ্যবর্তী
ওরি পোমেরান্টজ
30 নভেম্বর, 2025
15 মিনিট পড়ার সময়

ধরে নিন আপনি বিল। এমন কিছু কারণে যা আমরা এখানে আলোচনা করব না, আপনি "অ্যালিস ফর কুইন অফ দ্য ওয়ার্ল্ড" ক্যাম্পেইনে অনুদান দিতে চান এবং চান যে অ্যালিস জানুক আপনি অনুদান দিয়েছেন, যাতে সে জিতলে আপনাকে পুরস্কার দিতে পারে। দুর্ভাগ্যবশত, তার জয় নিশ্চিত নয়। একটি প্রতিযোগী ক্যাম্পেইন রয়েছে, "ক্যারল ফর এমপ্রেস অফ দ্য সোলার সিস্টেম"। যদি ক্যারল জেতে এবং সে জানতে পারে যে আপনি অ্যালিসকে অনুদান দিয়েছেন, তবে আপনি সমস্যায় পড়বেন। তাই আপনি কেবল আপনার অ্যাকাউন্ট থেকে অ্যালিসের অ্যাকাউন্টে 200 ETH হস্তান্তর করতে পারবেন না।

ERC-5564 (নতুন ট্যাবে খোলে)-এ এর সমাধান রয়েছে। এই ERC ব্যাখ্যা করে কীভাবে বেনামে হস্তান্তর করার জন্য গোপন ঠিকানা (নতুন ট্যাবে খোলে) ব্যবহার করতে হয়।

সতর্কতা: গোপন ঠিকানার পেছনের ক্রিপ্টোগ্রাফি, যতদূর আমরা জানি, বেশ সুরক্ষিত। তবে, সম্ভাব্য সাইড-চ্যানেল আক্রমণের ঝুঁকি রয়েছে। এই ঝুঁকি কমাতে আপনি কী করতে পারেন তা নিচে দেখতে পাবেন।

গোপন ঠিকানা কীভাবে কাজ করে

এই নিবন্ধটি দুটি উপায়ে গোপন ঠিকানা ব্যাখ্যা করার চেষ্টা করবে। প্রথমটি হলো কীভাবে এগুলো ব্যবহার করতে হয়। নিবন্ধের বাকি অংশ বোঝার জন্য এই অংশটিই যথেষ্ট। এরপর রয়েছে এর পেছনের গণিতের একটি ব্যাখ্যা। আপনি যদি ক্রিপ্টোগ্রাফি নিয়ে আগ্রহী হন, তবে এই অংশটিও পড়ুন।

সহজ সংস্করণ (কীভাবে গোপন ঠিকানা ব্যবহার করবেন)

অ্যালিস দুটি প্রাইভেট কী তৈরি করে এবং সংশ্লিষ্ট পাবলিক কীগুলো প্রকাশ করে (যাকে একটি একক ডাবল-লেংথ মেটা-ঠিকানায় একত্রিত করা যেতে পারে)। বিলও একটি প্রাইভেট কী তৈরি করে এবং সংশ্লিষ্ট পাবলিক কী প্রকাশ করে।

এক পক্ষের পাবলিক কী এবং অন্য পক্ষের প্রাইভেট কী ব্যবহার করে, আপনি একটি শেয়ার্ড সিক্রেট (shared secret) বের করতে পারেন যা কেবল অ্যালিস এবং বিলের জানা থাকে (এটি কেবল পাবলিক কীগুলো থেকে বের করা যায় না)। এই শেয়ার্ড সিক্রেট ব্যবহার করে, বিল গোপন ঠিকানা পায় এবং সেখানে সম্পদ পাঠাতে পারে।

অ্যালিসও শেয়ার্ড সিক্রেট থেকে ঠিকানাটি পায়, কিন্তু যেহেতু সে তার প্রকাশিত পাবলিক কীগুলোর প্রাইভেট কীগুলো জানে, তাই সে সেই প্রাইভেট কীটিও পেতে পারে যা তাকে ওই ঠিকানা থেকে সম্পদ তোলার সুযোগ দেয়।

গণিত (কেন গোপন ঠিকানা এভাবে কাজ করে)

স্ট্যান্ডার্ড গোপন ঠিকানাগুলো একই স্তরের নিরাপত্তা বজায় রেখে কম কী বিট দিয়ে আরও ভালো পারফরম্যান্স পেতে এলিপটিক-কার্ভ ক্রিপ্টোগ্রাফি (ECC) (নতুন ট্যাবে খোলে) ব্যবহার করে। তবে বেশিরভাগ ক্ষেত্রে আমরা এটি উপেক্ষা করতে পারি এবং ধরে নিতে পারি যে আমরা সাধারণ পাটিগণিত ব্যবহার করছি।

এমন একটি সংখ্যা আছে যা সবাই জানে, G। আপনি G দিয়ে গুণ করতে পারেন। কিন্তু ECC-এর প্রকৃতির কারণে, G দিয়ে ভাগ করা প্রায় অসম্ভব। ইথেরিয়াম-এ পাবলিক কী ক্রিপ্টোগ্রাফি সাধারণত যেভাবে কাজ করে তা হলো, আপনি ট্রানজ্যাকশন সাইন করতে একটি প্রাইভেট কী, Ppriv ব্যবহার করতে পারেন, যা পরে একটি পাবলিক কী, Ppub = GPpriv দ্বারা যাচাই করা হয়।

অ্যালিস দুটি প্রাইভেট কী তৈরি করে, Kpriv এবং VprivKpriv ব্যবহার করা হবে গোপন ঠিকানা থেকে অর্থ খরচ করতে, এবং 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) থেকে পাওয়া যায়।

অ্যালিস যাতে ডেভস ওয়ার্ল্ড ডমিনেশন ক্যাম্পেইন সার্ভিসেস-কে সাবকন্ট্রাক্ট দিতে পারে, সেজন্য আমাদের একটি আলাদা ভিউয়িং কী (viewing key) রয়েছে। অ্যালিস ডেভকে পাবলিক ঠিকানাগুলো জানাতে এবং আরও অর্থ এলে তাকে অবহিত করতে ইচ্ছুক, কিন্তু সে চায় না ডেভ তার ক্যাম্পেইনের অর্থ খরচ করুক।

যেহেতু দেখা এবং খরচ করার জন্য আলাদা কী ব্যবহার করা হয়, অ্যালিস ডেভকে Vpriv দিতে পারে। তখন ডেভ S = RpubVpriv = GRprivVpriv হিসাব করতে পারে এবং সেভাবে পাবলিক কীগুলো (Ppub = Kpub+G*hash(S)) পেতে পারে। কিন্তু Kpriv ছাড়া ডেভ প্রাইভেট কী পেতে পারে না।

সংক্ষেপে, এগুলো হলো বিভিন্ন অংশগ্রহণকারীর জানা মান।

অ্যালিসপ্রকাশিতবিলডেভ
GGGG
Kpriv---
Vpriv--Vpriv
Kpub = GKprivKpubKpubKpub
Vpub = GVprivVpubVpubVpub
--Rpriv-
RpubRpubRpub = GRprivRpub
S = RpubVpriv = GRprivVpriv-S = RprivVpub = GRprivVprivS = 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-এ উপলব্ধ (নতুন ট্যাবে খোলে) একটি গোপন-ঠিকানা অ্যাপ্লিকেশন ব্যাখ্যা করে।

টুলস

আমরা ব্যবহার করতে পারি এমন একটি TypeScript গোপন ঠিকানা লাইব্রেরি (নতুন ট্যাবে খোলে) রয়েছে। তবে, ক্রিপ্টোগ্রাফিক অপারেশনগুলো CPU-নিবিড় হতে পারে। আমি এগুলোকে একটি কম্পাইল করা ভাষায়, যেমন Rust (নতুন ট্যাবে খোলে)-এ প্রয়োগ করতে এবং ব্রাউজারে কোড চালানোর জন্য WASM (নতুন ট্যাবে খোলে) ব্যবহার করতে পছন্দ করি।

আমরা Vite (নতুন ট্যাবে খোলে) এবং React (নতুন ট্যাবে খোলে) ব্যবহার করতে যাচ্ছি। এগুলো হলো ইন্ডাস্ট্রি-স্ট্যান্ডার্ড টুল; আপনি যদি এগুলোর সাথে পরিচিত না হন, তবে আপনি এই টিউটোরিয়ালটি ব্যবহার করতে পারেন। Vite ব্যবহার করার জন্য, আমাদের Node প্রয়োজন।

গোপন ঠিকানাগুলো কীভাবে কাজ করে তা দেখুন

  1. প্রয়োজনীয় টুলগুলো ইনস্টল করুন: Rust (নতুন ট্যাবে খোলে) এবং Node (নতুন ট্যাবে খোলে)

  2. GitHub রিপোজিটরিটি ক্লোন করুন।

    git clone https://github.com/qbzzt/251022-stealth-addresses.git
    cd 251022-stealth-addresses
    
  3. পূর্বশর্তগুলো ইনস্টল করুন এবং Rust কোড কম্পাইল করুন।

    cd src/rust-wasm
    rustup target add wasm32-unknown-unknown   
    cargo install wasm-pack   
    wasm-pack build --target web
    
  4. ওয়েব সার্ভার চালু করুন।

    cd ../..
    npm install
    npm run dev
    
  5. অ্যাপ্লিকেশনটিতে (নতুন ট্যাবে খোলে) ব্রাউজ করুন। এই অ্যাপ্লিকেশন পৃষ্ঠায় দুটি ফ্রেম রয়েছে: একটি অ্যালিসের ইউজার ইন্টারফেসের জন্য এবং অন্যটি বিলের জন্য। ফ্রেম দুটি একে অপরের সাথে যোগাযোগ করে না; সুবিধার জন্য এগুলো কেবল একই পৃষ্ঠায় রাখা হয়েছে।

  6. অ্যালিস হিসেবে, Generate a Stealth Meta-Address-এ ক্লিক করুন। এটি নতুন গোপন ঠিকানা এবং সংশ্লিষ্ট প্রাইভেট কীগুলো প্রদর্শন করবে। গোপন মেটা-ঠিকানাটি ক্লিপবোর্ডে কপি করুন।

  7. বিল হিসেবে, নতুন গোপন মেটা-ঠিকানাটি পেস্ট করুন এবং Generate an address-এ ক্লিক করুন। এটি আপনাকে অ্যালিসের জন্য ফান্ড পাঠানোর ঠিকানা দেয়।

  8. ঠিকানা এবং বিলের পাবলিক কী কপি করুন এবং অ্যালিসের ইউজার ইন্টারফেসের "Private key for address generated by Bill" অংশে পেস্ট করুন। এই ফিল্ডগুলো পূরণ হয়ে গেলে, আপনি সেই ঠিকানায় থাকা সম্পদে অ্যাক্সেস করার প্রাইভেট কী দেখতে পাবেন।

  9. প্রাইভেট কীটি ঠিকানার সাথে মিলে কি না তা নিশ্চিত করতে আপনি একটি অনলাইন ক্যালকুলেটর (নতুন ট্যাবে খোলে) ব্যবহার করতে পারেন।

প্রোগ্রামটি কীভাবে কাজ করে

WASM কম্পোনেন্ট

যে সোর্স কোডটি WASM-এ কম্পাইল হয় তা Rust (নতুন ট্যাবে খোলে)-এ লেখা। আপনি এটি src/rust_wasm/src/lib.rs (নতুন ট্যাবে খোলে)-এ দেখতে পারেন। এই কোডটি মূলত JavaScript কোড এবং eth-stealth-addresses লাইব্রেরির (নতুন ট্যাবে খোলে) মধ্যে একটি ইন্টারফেস।

Cargo.toml

Rust-এ Cargo.toml (নতুন ট্যাবে খোলে) হলো JavaScript-এর package.json (নতুন ট্যাবে খোলে)-এর সমতুল্য। এতে প্যাকেজের তথ্য, ডিপেন্ডেন্সি ডিক্লারেশন ইত্যাদি থাকে।

getrandom (নতুন ট্যাবে খোলে) প্যাকেজটির র‍্যান্ডম মান তৈরি করা প্রয়োজন। এটি কেবল অ্যালগরিদমিক উপায়ে করা যায় না; এনট্রপি-এর উৎস হিসেবে একটি ফিজিক্যাল প্রসেসে অ্যাক্সেস প্রয়োজন। এই সংজ্ঞাটি নির্দিষ্ট করে যে আমরা যে ব্রাউজারে চলছি তাকে জিজ্ঞাসা করে সেই এনট্রপি পাব।

console_error_panic_hook = "0.1.7"

যখন WASM কোড প্যানিক করে এবং চলতে পারে না, তখন এই লাইব্রেরিটি (নতুন ট্যাবে খোলে) আমাদের আরও অর্থপূর্ণ এরর মেসেজ দেয়।

[lib]
crate-type = ["cdylib", "rlib"]

WASM কোড তৈরি করার জন্য প্রয়োজনীয় আউটপুট টাইপ।

lib.rs

এটি হলো আসল Rust কোড।

use wasm_bindgen::prelude::*;

Rust থেকে একটি WASM প্যাকেজ তৈরি করার সংজ্ঞা। এগুলো এখানে (নতুন ট্যাবে খোলে) নথিভুক্ত করা আছে।

use eth_stealth_addresses::{
    generate_stealth_meta_address,
    generate_stealth_address,
    compute_stealth_key
};

eth-stealth-addresses লাইব্রেরি (নতুন ট্যাবে খোলে) থেকে আমাদের প্রয়োজনীয় ফাংশনগুলো।

use hex::{decode,encode};

Rust সাধারণত মানের জন্য বাইট অ্যারে (নতুন ট্যাবে খোলে) ([u8; <size>]) ব্যবহার করে। কিন্তু JavaScript-এ, আমরা সাধারণত হেক্সাডেসিমাল স্ট্রিং ব্যবহার করি। hex লাইব্রেরিটি (নতুন ট্যাবে খোলে) আমাদের জন্য একটি রূপ থেকে অন্য রূপে অনুবাদ করে।

#[wasm_bindgen]

JavaScript থেকে এই ফাংশনটি কল করতে সক্ষম হওয়ার জন্য WASM বাইন্ডিং তৈরি করুন।

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 (নতুন ট্যাবে খোলে) তিনটি ফিল্ড রিটার্ন করে:

  • মেটা-ঠিকানা (Kpub এবং Vpub)
  • ভিউয়িং প্রাইভেট কী (Vpriv)
  • স্পেন্ডিং প্রাইভেট কী (Kpriv)

টাপল (tuple) (নতুন ট্যাবে খোলে) সিনট্যাক্স আমাদের সেই মানগুলোকে আবার আলাদা করতে দেয়।

    format!("{{\"address\":\"{}\",\"view_private_key\":\"{}\",\"spend_private_key\":\"{}\"}}",
        encode(address),
        encode(view_private_key),
        encode(spend_private_key)
    )
}

JSON-এনকোড করা স্ট্রিং তৈরি করতে format! (নতুন ট্যাবে খোলে) ম্যাক্রো ব্যবহার করুন। অ্যারেগুলোকে হেক্স স্ট্রিংয়ে পরিবর্তন করতে hex::encode (নতুন ট্যাবে খোলে) ব্যবহার করুন।

fn str_to_array<const N: usize>(s: &str) -> Option<[u8; N]> {

এই ফাংশনটি একটি হেক্স স্ট্রিংকে (JavaScript দ্বারা প্রদত্ত) একটি বাইট অ্যারেতে পরিণত করে। JavaScript কোড দ্বারা প্রদত্ত মানগুলো পার্স করতে আমরা এটি ব্যবহার করি। Rust কীভাবে অ্যারে এবং ভেক্টর পরিচালনা করে তার কারণে এই ফাংশনটি জটিল।

<const N: usize> এক্সপ্রেশনটিকে একটি জেনেরিক (generic) (নতুন ট্যাবে খোলে) বলা হয়। N হলো একটি প্যারামিটার যা রিটার্ন করা অ্যারের দৈর্ঘ্য নিয়ন্ত্রণ করে। ফাংশনটিকে আসলে str_to_array::<n> বলা হয়, যেখানে n হলো অ্যারের দৈর্ঘ্য।

রিটার্ন মান হলো Option<[u8; N]>, যার মানে রিটার্ন করা অ্যারেটি ঐচ্ছিক (optional) (নতুন ট্যাবে খোলে)। ব্যর্থ হতে পারে এমন ফাংশনগুলোর জন্য এটি 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 (নতুন ট্যাবে খোলে) ফাংশনটি একটি Result<Vec<u8>, FromHexError> রিটার্ন করে। Result (নতুন ট্যাবে খোলে) টাইপে একটি সফল ফলাফল (Ok(value)) বা একটি এরর (Err(error)) থাকতে পারে।

.ok() মেথডটি Result-কে একটি Option-এ পরিণত করে, যার মান সফল হলে Ok() মান হয় অথবা না হলে None হয়। সবশেষে, প্রশ্নবোধক চিহ্ন অপারেটর (নতুন ট্যাবে খোলে) বর্তমান ফাংশনগুলোকে বাতিল করে এবং Option খালি থাকলে একটি None রিটার্ন করে। অন্যথায়, এটি মানটিকে আনর‍্যাপ (unwrap) করে এবং সেটি রিটার্ন করে (এই ক্ষেত্রে, vec-এ একটি মান অ্যাসাইন করতে)।

এররগুলো পরিচালনা করার জন্য এটি একটি অদ্ভুত জটিল পদ্ধতি বলে মনে হতে পারে, তবে Result এবং Option নিশ্চিত করে যে সমস্ত এরর কোনো না কোনোভাবে পরিচালিত হয়।

    if vec.len() != N { return None; }

যদি বাইটের সংখ্যা ভুল হয়, তবে এটি একটি ব্যর্থতা, এবং আমরা None রিটার্ন করি।

    // try_into vec কনজিউম করে এবং [u8; N] তৈরি করার চেষ্টা করে
    let array: [u8; N] = vec.try_into().ok()?;

Rust-এ দুটি অ্যারে টাইপ রয়েছে। অ্যারেগুলোর (নতুন ট্যাবে খোলে) একটি নির্দিষ্ট আকার থাকে। ভেক্টরগুলো (নতুন ট্যাবে খোলে) বড় এবং ছোট হতে পারে। hex::decode একটি ভেক্টর রিটার্ন করে, কিন্তু eth_stealth_addresses লাইব্রেরি অ্যারে গ্রহণ করতে চায়। .try_into() (নতুন ট্যাবে খোলে) একটি মানকে অন্য টাইপে রূপান্তর করে, উদাহরণস্বরূপ, একটি ভেক্টরকে একটি অ্যারেতে।

    Some(array)
}

একটি ফাংশনের শেষে কোনো মান রিটার্ন করার সময় Rust-এ আপনাকে return (নতুন ট্যাবে খোলে) কীওয়ার্ড ব্যবহার করতে হয় না।

#[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 (নতুন ট্যাবে খোলে) ব্যবহার করি।

    format!("{{\"address\":\"{}\",\"rPub\":\"{}\",\"scan\":\"{}\"}}",
        encode(address),
        encode(r_pub),
        encode(&[scan])
    ).into()
}

JSON-এনকোড করা আউটপুট স্ট্রিং প্রস্তুত করুন।

এই ফাংশনটি ঠিকানা থেকে অর্থ তোলার প্রাইভেট কী (Rpriv) হিসাব করতে লাইব্রেরির compute_stealth_key (নতুন ট্যাবে খোলে) ব্যবহার করে। এই হিসাবের জন্য এই মানগুলো প্রয়োজন:

  • ঠিকানা (Address=f(Ppub))
  • বিল দ্বারা তৈরি করা পাবলিক কী (Rpub)
  • ভিউ প্রাইভেট কী (Vpriv)
  • স্পেন্ড প্রাইভেট কী (Kpriv)
#[wasm_bindgen(start)]

#[wasm_bindgen(start)] (নতুন ট্যাবে খোলে) নির্দিষ্ট করে যে WASM কোড ইনিশিয়ালাইজ হওয়ার সময় ফাংশনটি এক্সিকিউট হয়।

pub fn main() {
    console_error_panic_hook::set_once();
}

এই কোডটি নির্দিষ্ট করে যে প্যানিক আউটপুট 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

এরপরে একটি স্ট্যাক ট্রেস থাকবে। তারপর বিলকে বৈধ মেটা-ঠিকানা দিন এবং অ্যালিসকে একটি অবৈধ ঠিকানা বা একটি অবৈধ পাবলিক কী দিন। আপনি এই এররটি দেখতে পাবেন:

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 (নতুন ট্যাবে খোলে) ব্যবহার করে লেখা হয়েছে এবং Vite (নতুন ট্যাবে খোলে) দ্বারা সার্ভ করা হয়েছে। আপনি এই টিউটোরিয়ালটি ব্যবহার করে এগুলো সম্পর্কে জানতে পারেন। এখানে Wagmi (নতুন ট্যাবে খোলে)-এর কোনো প্রয়োজন নেই কারণ আমরা সরাসরি কোনো ব্লকচেইন বা ওয়ালেট-এর সাথে ইন্টারঅ্যাক্ট করি না।

ইউজার ইন্টারফেসের একমাত্র অস্পষ্ট অংশ হলো WASM কানেক্টিভিটি। এটি যেভাবে কাজ করে তা নিচে দেওয়া হলো।

vite.config.js

এই ফাইলে Vite কনফিগারেশন (নতুন ট্যাবে খোলে) রয়েছে।

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 (নতুন ট্যাবে খোলে) এবং wasm (নতুন ট্যাবে খোলে)

App.jsx

এই ফাইলটি অ্যাপ্লিকেশনের প্রধান কম্পোনেন্ট। এটি একটি কন্টেইনার যার মধ্যে দুটি কম্পোনেন্ট রয়েছে: Alice এবং Bill, যা ওই ব্যবহারকারীদের জন্য ইউজার ইন্টারফেস। WASM-এর জন্য প্রাসঙ্গিক অংশটি হলো ইনিশিয়ালাইজেশন কোড।

import init from './rust-wasm/pkg/rust_wasm.js'

যখন আমরা wasm-pack (নতুন ট্যাবে খোলে) ব্যবহার করি, তখন এটি দুটি ফাইল তৈরি করে যা আমরা এখানে ব্যবহার করি: আসল কোডসহ একটি wasm ফাইল (এখানে, src/rust-wasm/pkg/rust_wasm_bg.wasm) এবং এটি ব্যবহার করার সংজ্ঞাসহ একটি JavaScript ফাইল (এখানে, src/rust_wasm/pkg/rust_wasm.js)। সেই JavaScript ফাইলের ডিফল্ট এক্সপোর্ট হলো সেই কোড যা WASM ইনিশিয়েট করার জন্য চালাতে হয়।

useEffect হুক (নতুন ট্যাবে খোলে) আপনাকে এমন একটি ফাংশন নির্দিষ্ট করতে দেয় যা স্টেট ভেরিয়েবলগুলো পরিবর্তিত হলে এক্সিকিউট হয়। এখানে, স্টেট ভেরিয়েবলের তালিকাটি খালি ([]), তাই পৃষ্ঠাটি লোড হওয়ার সময় এই ফাংশনটি কেবল একবার এক্সিকিউট হয়।

ইফেক্ট ফাংশনটিকে সাথে সাথে রিটার্ন করতে হয়। অ্যাসিনক্রোনাস কোড ব্যবহার করতে, যেমন WASM init (যাকে .wasm ফাইলটি লোড করতে হয় এবং তাই সময় নেয়) আমরা একটি অভ্যন্তরীণ async (নতুন ট্যাবে খোলে) ফাংশন সংজ্ঞায়িত করি এবং এটিকে কোনো await ছাড়াই চালাই।

Bill.jsx

এটি বিলের জন্য ইউজার ইন্টারফেস। এর একটিমাত্র কাজ রয়েছে, অ্যালিস দ্বারা প্রদত্ত গোপন মেটা-ঠিকানার ওপর ভিত্তি করে একটি ঠিকানা তৈরি করা।

import { wasm_generate_stealth_address } from './rust-wasm/pkg/rust_wasm.js'

ডিফল্ট এক্সপোর্ট ছাড়াও, wasm-pack দ্বারা তৈরি করা JavaScript কোডটি WASM কোডের প্রতিটি ফাংশনের জন্য একটি ফাংশন এক্সপোর্ট করে।

            <button onClick={() => {
              setPublicAddress(JSON.parse(wasm_generate_stealth_address(stealthMetaAddress)))
            }}>

WASM ফাংশনগুলো কল করতে, আমরা কেবল wasm-pack দ্বারা তৈরি করা JavaScript ফাইলের এক্সপোর্ট করা ফাংশনটিকে কল করি।

Alice.jsx

Alice.jsx-এর কোডটি প্রায় একই রকম, তবে অ্যালিসের দুটি কাজ রয়েছে:

  • একটি মেটা-ঠিকানা তৈরি করা
  • বিল দ্বারা প্রকাশিত একটি ঠিকানার জন্য প্রাইভেট কী পাওয়া

উপসংহার

গোপন ঠিকানা কোনো সর্বরোগের ওষুধ নয়; এগুলোকে সঠিকভাবে ব্যবহার করতে হবে। তবে সঠিকভাবে ব্যবহার করা হলে, এগুলো একটি পাবলিক ব্লকচেইন-এ গোপনীয়তা সক্ষম করতে পারে।

আমার আরও কাজের জন্য এখানে দেখুন (নতুন ট্যাবে খোলে)