التشفير والمفاتيح: كيف تعمل المحافظ الرقمية (Public & Private Keys) برمجياً؟


ماذا سنتعلم اليوم؟ سنقوم ببناء سكربت بسيط يوضح كيفية عمل المفاتيح العامة والخاصة، وكيف تستخدم المحافظ الرقمية هذه المفاتيح لتوقيع المعاملات والتحقق منها برمجياً باستخدام JavaScript (Ethers.js).

الخطوة 1: توليد المفتاح الخاص (Private Key)

المفتاح الخاص هو أساس أمان محفظتك الرقمية. هو عبارة عن رقم سري للغاية لا يجب أن يعرفه أحد سواك. من هذا المفتاح، يمكن اشتقاق المفتاح العام.

ملاحظة تقنية: المفتاح الخاص في الواقع هو رقم عشوائي كبير جداً (256 بت). يتم تمثيله عادةً كسلسلة سداسية عشرية.

// استيراد مكتبة ethers.js
const { Wallet } = require('ethers');

// توليد مفتاح خاص جديد بشكل عشوائي
const privateKeyWallet = Wallet.createRandom();

console.log('المفتاح الخاص (Private Key):', privateKeyWallet.privateKey);

في هذا الجزء، استخدمنا Wallet.createRandom() من Ethers.js لتوليد مفتاح خاص عشوائي. هذا المفتاح هو الذي يمنحك السيطرة الكاملة على أصولك الرقمية.

الخطوة 2: اشتقاق المفتاح العام (Public Key) والعنوان (Address)

من المفتاح الخاص، يمكننا اشتقاق المفتاح العام، ومن ثم عنوان المحفظة. هذا العنوان هو ما تشاركه مع الآخرين لاستقبال الأموال.

ملاحظة تقنية: المفتاح العام مشتق من المفتاح الخاص باستخدام خوارزمية التشفير الإهليلجي (Elliptic Curve Cryptography - ECC). عنوان المحفظة هو في الأساس تجزئة (hash) للمفتاح العام.

// استيراد مكتبة ethers.js (إذا لم تكن مستوردة بالفعل في الكود الكامل)
// const { Wallet } = require('ethers');

// استخدام المفتاح الخاص الذي تم توليده في الخطوة السابقة
// const privateKeyWallet = Wallet.createRandom(); // أو يمكنك تحميل محفظة من مفتاح خاص موجود: new Wallet("مفتاحك الخاص هنا");

console.log('المفتاح العام (Public Key):', privateKeyWallet.publicKey);
console.log('عنوان المحفظة (Address):', privateKeyWallet.address);

هنا، privateKeyWallet.publicKey يعطينا المفتاح العام، و privateKeyWallet.address يعطينا عنوان المحفظة المشتق منه. لاحظ أن المفتاح العام أطول بكثير من العنوان، حيث أن العنوان هو تجزئة مختصرة للمفتاح العام لتسهيل الاستخدام.

الخطوة 3: توقيع الرسائل والمعاملات (Signing Messages/Transactions)

لتأكيد أنك صاحب المفتاح الخاص وتفويض معاملة أو رسالة معينة، تقوم "بتوقيعها" باستخدام مفتاحك الخاص. يمكن لأي شخص التحقق من هذا التوقيع باستخدام مفتاحك العام.

ملاحظة تقنية: التوقيع الرقمي يضمن ثلاثة أشياء: الأصالة (أن المرسل هو من يدعي)، التكامل (أن الرسالة لم تتغير)، وعدم التنصل (لا يمكن للمرسل أن ينكر توقيعه لاحقاً).

// استيراد مكتبة ethers.js (إذا لم تكن مستوردة بالفعل في الكود الكامل)
const { Wallet, verifyMessage } = require('ethers');

// استخدام المفتاح الخاص الذي تم توليده
// const privateKeyWallet = Wallet.createRandom(); // أو تحميل محفظة من مفتاح خاص موجود

const message = "مرحباً يا عالم البلوكتشين! هذه رسالة موقّعة.";

// توقيع الرسالة باستخدام المفتاح الخاص
const signature = await privateKeyWallet.signMessage(message);

console.log('الرسالة الأصلية:', message);
console.log('التوقيع الرقمي (Signature):', signature);

// التحقق من التوقيع باستخدام المفتاح العام (أو العنوان)
const recoveredAddress = verifyMessage(message, signature);

console.log('العنوان المستعاد من التوقيع:', recoveredAddress);
console.log('هل العنوان المستعاد يطابق عنوان المحفظة؟', recoveredAddress === privateKeyWallet.address);

في هذه الخطوة، قمنا بتوقيع رسالة باستخدام privateKeyWallet.signMessage(). ثم استخدمنا verifyMessage() للتحقق من أن التوقيع صحيح وأن من قام بالتوقيع يملك بالفعل المفتاح الخاص المرتبط بالعنوان. هذا هو جوهر عمل المحافظ الرقمية!

الكود النهائي الكامل

لنفترض أنك قمت بتثبيت ethers: npm install ethers

const { Wallet, verifyMessage } = require('ethers');

async function main() {
    console.log("--- بداية الدرس: التشفير والمفاتيح في المحافظ الرقمية ---");

    // الخطوة 1: توليد مفتاح خاص جديد
    const privateKeyWallet = Wallet.createRandom();
    console.log('\n--- الخطوة 1: توليد المفتاح الخاص ---');
    console.log('المفتاح الخاص (Private Key):', privateKeyWallet.privateKey);

    // الخطوة 2: اشتقاق المفتاح العام والعنوان
    console.log('\n--- الخطوة 2: اشتقاق المفتاح العام والعنوان ---');
    console.log('المفتاح العام (Public Key):', privateKeyWallet.publicKey);
    console.log('عنوان المحفظة (Address):', privateKeyWallet.address);

    // الخطوة 3: توقيع رسالة والتحقق منها
    console.log('\n--- الخطوة 3: توقيع رسالة والتحقق منها ---');
    const message = "مرحباً يا عالم البلوكتشين! هذه رسالة موقّعة.";
    const signature = await privateKeyWallet.signMessage(message);

    console.log('الرسالة الأصلية:', message);
    console.log('التوقيع الرقمي (Signature):', signature);

    const recoveredAddress = verifyMessage(message, signature);

    console.log('العنوان المستعاد من التوقيع:', recoveredAddress);
    console.log('هل العنوان المستعاد يطابق عنوان المحفظة؟', recoveredAddress === privateKeyWallet.address);
    console.log('--- نهاية الدرس ---');
}

main().catch(error => {
    console.error(error);
    process.exit(1);
});

النتيجة المتوقعة

عند تشغيل السكربت، ستحصل على مخرجات مشابهة لما يلي (المفاتيح والعناوين ستكون مختلفة في كل مرة يتم تشغيل السكربت):

--- بداية الدرس: التشفير والمفاتيح في المحافظ الرقمية ---

--- الخطوة 1: توليد المفتاح الخاص ---
المفتاح الخاص (Private Key): 0x... (سلسلة سداسية عشرية طويلة جداً)

--- الخطوة 2: اشتقاق المفتاح العام والعنوان ---
المفتاح العام (Public Key): 0x... (سلسلة سداسية عشرية أطول)
عنوان المحفظة (Address): 0x... (عنوان Ethereum نموذجي يبدأ بـ 0x)

--- الخطوة 3: توقيع رسالة والتحقق منها ---
الرسالة الأصلية: مرحباً يا عالم البلوكتشين! هذه رسالة موقّعة.
التوقيع الرقمي (Signature): 0x... (سلسلة سداسية عشرية طويلة جداً تمثل التوقيع)
العنوان المستعاد من التوقيع: 0x... (نفس عنوان المحفظة الذي تم توليده)
هل العنوان المستعاد يطابق عنوان المحفظة؟ true
--- نهاية الدرس ---