اہم مواد پر جائیں

خفیہ اسٹیٹ کے لیے زیرو نالج کا استعمال

سرور
آف چین
مرکزی
زیرو-نالج
zokrates
mud
ترقی
Ori Pomerantz
15 مارچ، 2025
34 منٹ کی پڑھائی

بلاک چین پر کوئی راز نہیں ہوتے۔ بلاک چین پر جو کچھ بھی پوسٹ کیا جاتا ہے وہ سب کے پڑھنے کے لیے کھلا ہے۔ یہ ضروری ہے، کیونکہ بلاک چین اس پر مبنی ہے کہ کوئی بھی اس کی تصدیق کر سکے۔ تاہم، گیمز اکثر خفیہ اسٹیٹ پر انحصار کرتے ہیں۔ مثال کے طور پر، مائن سویپرopens in a new tab کے گیم کا کوئی مطلب نہیں بنتا اگر آپ صرف ایک بلاک چین ایکسپلورر پر جا کر نقشہ دیکھ سکتے ہیں۔

سب سے آسان حل یہ ہے کہ خفیہ اسٹیٹ کو رکھنے کے لیے ایک سرور کمپونینٹ کا استعمال کیا جائے۔ تاہم، ہم بلاک چین کا استعمال اس لیے کرتے ہیں تاکہ گیم ڈیولپر کی طرف سے دھوکہ دہی کو روکا جا سکے۔ ہمیں سرور کمپونینٹ کی ایمانداری کو یقینی بنانے کی ضرورت ہے۔ سرور اسٹیٹ کا ایک ہیش فراہم کر سکتا ہے، اور زیرو نالج پروفز کا استعمال کر کے یہ ثابت کر سکتا ہے کہ ایک چال کے نتیجے کا حساب لگانے کے لیے استعمال کیا گیا اسٹیٹ صحیح ہے۔

اس مضمون کو پڑھنے کے بعد آپ جان جائیں گے کہ اس قسم کا خفیہ اسٹیٹ رکھنے والا سرور، اسٹیٹ دکھانے کے لیے ایک کلائنٹ، اور دونوں کے درمیان مواصلات کے لیے ایک آن چین کمپونینٹ کیسے بنایا جائے۔ ہم جو اہم ٹولز استعمال کریں گے وہ یہ ہیں:

ٹولمقصدورژن پر تصدیق شدہ
Zokratesopens in a new tabزیرو نالج پروفز اور ان کی تصدیق1.1.9
Typescriptopens in a new tabسرور اور کلائنٹ دونوں کے لیے پروگرامنگ زبان5.4.2
Nodeopens in a new tabسرور چلانا20.18.2
Viemopens in a new tabبلاک چین کے ساتھ مواصلات2.9.20
MUDopens in a new tabآن چین ڈیٹا مینجمنٹ2.0.12
Reactopens in a new tabکلائنٹ یوزر انٹرفیس18.2.0
Viteopens in a new tabکلائنٹ کوڈ کی سرونگ4.2.1

مائن سویپر کی مثال

مائن سویپرopens in a new tab ایک ایسا گیم ہے جس میں ایک مائن فیلڈ کے ساتھ ایک خفیہ نقشہ شامل ہے۔ کھلاڑی ایک مخصوص مقام پر کھودنے کا انتخاب کرتا ہے۔ اگر اس مقام پر کوئی مائن ہے، تو گیم ختم ہو جاتا ہے۔ ورنہ، کھلاڑی کو اس مقام کے آس پاس کے آٹھ چوکوروں میں مائنز کی تعداد ملتی ہے۔

یہ ایپلیکیشن MUDopens in a new tab کا استعمال کرتے ہوئے لکھی گئی ہے، جو ایک ایسا فریم ورک ہے جو ہمیں کی-ویلیو ڈیٹا بیسopens in a new tab کا استعمال کرتے ہوئے آن چین ڈیٹا اسٹور کرنے اور اس ڈیٹا کو خود بخود آف چین کمپونینٹس کے ساتھ سنکرونائز کرنے کی اجازت دیتا ہے۔ سنکرونائزیشن کے علاوہ، MUD رسائی کنٹرول فراہم کرنا آسان بناتا ہے، اور دوسرے صارفین کے لیے ہماری ایپلیکیشن کو بغیر اجازت کے توسیعopens in a new tab دینا بھی آسان بناتا ہے۔

مائن سویپر کی مثال چلانا

مائن سویپر کی مثال چلانے کے لیے:

  1. یقینی بنائیں کہ آپ نے پیشگی شرائط انسٹال کر لی ہیںopens in a new tab: Nodeopens in a new tab, Foundryopens in a new tab, gitopens in a new tab, pnpmopens in a new tab, اور mprocsopens in a new tab۔

  2. ریپوزٹری کو کلون کریں۔

    1git clone https://github.com/qbzzt/20240901-secret-state.git
  3. پیکجز انسٹال کریں۔

    1cd 20240901-secret-state/
    2pnpm install
    3npm install -g mprocs

    اگر pnpm install کے حصے کے طور پر Foundry انسٹال کیا گیا تھا، تو آپ کو کمانڈ لائن شیل کو دوبارہ شروع کرنے کی ضرورت ہے۔

  4. کنٹریکٹس کو کمپائل کریں

    1cd packages/contracts
    2forge build
    3cd ../..
  5. پروگرام شروع کریں (بشمول ایک anvilopens in a new tab بلاک چین) اور انتظار کریں۔

    1mprocs

    نوٹ کریں کہ اسٹارٹ اپ میں کافی وقت لگتا ہے۔ پیشرفت دیکھنے کے لیے، پہلے نیچے کے تیر کا استعمال کرتے ہوئے کنٹریکٹس ٹیب پر اسکرول کریں تاکہ MUD کنٹریکٹس کو ڈیپلائے ہوتے دیکھیں۔ جب آپ کو فائل کی تبدیلیوں کا انتظار ہے… کا پیغام ملے، تو کنٹریکٹس ڈیپلائے ہو چکے ہیں اور مزید پیشرفت سرور ٹیب میں ہوگی۔ وہاں، آپ اس وقت تک انتظار کریں جب تک آپ کو ویریفائر ایڈریس: 0x.... کا پیغام نہ مل جائے۔

    اگر یہ مرحلہ کامیاب ہو جاتا ہے، تو آپ کو mprocs اسکرین نظر آئے گی، جس میں بائیں طرف مختلف پروسیسز اور دائیں طرف فی الحال منتخب کردہ پروسیس کے لیے کنسول آؤٹ پٹ ہوگا۔

    mprocs اسکرین

    اگر mprocs کے ساتھ کوئی مسئلہ ہے، تو آپ چاروں پروسیسز کو دستی طور پر چلا سکتے ہیں، ہر ایک کو اپنی کمانڈ لائن ونڈو میں:

    • Anvil

      1cd packages/contracts
      2anvil --base-fee 0 --block-time 2
    • کنٹریکٹس

      1cd packages/contracts
      2pnpm mud dev-contracts --rpc http://127.0.0.1:8545
    • سرور

      1cd packages/server
      2pnpm start
    • کلائنٹ

      1cd packages/client
      2pnpm run dev
  6. اب آپ کلائنٹopens in a new tab پر براؤز کر سکتے ہیں، نیا گیم پر کلک کریں، اور کھیلنا شروع کر سکتے ہیں۔

ٹیبلز

ہمیں آن چین کئی ٹیبلزopens in a new tab کی ضرورت ہے۔

  • Configuration: یہ ٹیبل ایک سنگلٹن ہے، اس میں کوئی کلید نہیں ہے اور ایک ہی ریکارڈ ہے۔ اس کا استعمال گیم کی کنفیگریشن کی معلومات کو رکھنے کے لیے کیا جاتا ہے:

    • height: ایک مائن فیلڈ کی اونچائی
    • width: ایک مائن فیلڈ کی چوڑائی
    • numberOfBombs: ہر مائن فیلڈ میں بموں کی تعداد
  • VerifierAddress: یہ ٹیبل بھی ایک سنگلٹن ہے۔ اس کا استعمال کنفیگریشن کے ایک حصے کو رکھنے کے لیے کیا جاتا ہے، یعنی ویریفائر کنٹریکٹ (verifier) کا ایڈریس۔ ہم اس معلومات کو Configuration ٹیبل میں رکھ سکتے تھے، لیکن یہ ایک مختلف کمپونینٹ، یعنی سرور کے ذریعہ سیٹ کیا جاتا ہے، لہذا اسے ایک الگ ٹیبل میں رکھنا آسان ہے۔

  • PlayerGame: کلید کھلاڑی کا ایڈریس ہے۔ ڈیٹا یہ ہے:

    • gameId: 32 بائٹ کی ویلیو جو اس نقشے کا ہیش ہے جس پر کھلاڑی کھیل رہا ہے (گیم شناخت کنندہ)۔
    • win: ایک بولین جو یہ بتاتا ہے کہ آیا کھلاڑی نے گیم جیت لیا ہے۔
    • lose: ایک بولین جو یہ بتاتا ہے کہ آیا کھلاڑی نے گیم ہار دیا ہے۔
    • digNumber: گیم میں کامیاب کھدائیوں کی تعداد۔
  • GamePlayer: یہ ٹیبل الٹی میپنگ رکھتا ہے، gameId سے کھلاڑی کے ایڈریس تک۔

  • Map: کلید تین ویلیوز کا ایک ٹوپل ہے:

    • gameId: 32 بائٹ کی ویلیو جو اس نقشے کا ہیش ہے جس پر کھلاڑی کھیل رہا ہے (گیم شناخت کنندہ)۔
    • x کوآرڈینیٹ
    • y کوآرڈینیٹ

    ویلیو ایک واحد نمبر ہے۔ اگر بم کا پتہ چلا تو یہ 255 ہے۔ ورنہ، یہ اس مقام کے ارد گرد بموں کی تعداد جمع ایک ہے۔ ہم صرف بموں کی تعداد کا استعمال نہیں کر سکتے، کیونکہ ڈیفالٹ طور پر EVM میں تمام اسٹوریج اور MUD میں تمام قطار کی ویلیوز صفر ہوتی ہیں۔ ہمیں "کھلاڑی نے ابھی تک یہاں کھدائی نہیں کی ہے" اور "کھلاڑی نے یہاں کھدائی کی، اور پایا کہ ارد گرد صفر بم ہیں" کے درمیان فرق کرنے کی ضرورت ہے۔

اس کے علاوہ، کلائنٹ اور سرور کے درمیان مواصلات آن چین کمپونینٹ کے ذریعے ہوتی ہے۔ یہ بھی ٹیبلز کا استعمال کرتے ہوئے نافذ کیا گیا ہے۔

  • PendingGame: نیا گیم شروع کرنے کے لیے غیر خدمتی درخواستیں۔
  • PendingDig: ایک مخصوص گیم میں ایک مخصوص جگہ پر کھودنے کے لیے غیر خدمتی درخواستیں۔ یہ ایک آف چین ٹیبلopens in a new tab ہے، جس کا مطلب ہے کہ یہ EVM اسٹوریج میں نہیں لکھا جاتا، یہ صرف ایونٹس کا استعمال کرتے ہوئے آف چین پڑھا جا سکتا ہے۔

ایگزیکیوشن اور ڈیٹا فلو

یہ فلو کلائنٹ، آن چین کمپونینٹ، اور سرور کے درمیان ایگزیکیوشن کو مربوط کرتے ہیں۔

ابتدا

جب آپ mprocs چلاتے ہیں، تو یہ اقدامات ہوتے ہیں:

  1. mprocsopens in a new tab چار کمپونینٹس چلاتا ہے:

  2. contracts پیکج MUD کنٹریکٹس کو ڈیپلائے کرتا ہے اور پھر PostDeploy.s.sol اسکرپٹopens in a new tab چلاتا ہے۔ یہ اسکرپٹ کنفیگریشن سیٹ کرتا ہے۔ گٹ ہب سے کوڈ ایک 10x5 مائن فیلڈ کی وضاحت کرتا ہے جس میں آٹھ مائنز ہیںopens in a new tab۔

  3. سرورopens in a new tab MUD کو سیٹ اپ کر کےopens in a new tab شروع ہوتا ہے۔ دیگر چیزوں کے علاوہ، یہ ڈیٹا سنکرونائزیشن کو فعال کرتا ہے، تاکہ متعلقہ ٹیبلز کی ایک کاپی سرور کی میموری میں موجود ہو۔

  4. سرور ایک فنکشن کو سبسکرائب کرتا ہے تاکہ جب Configuration ٹیبل تبدیل ہوopens in a new tab تو اسے ایگزیکیوٹ کیا جائے۔ یہ فنکشنopens in a new tab PostDeploy.s.sol کے ایگزیکیوٹ ہونے اور ٹیبل میں ترمیم کرنے کے بعد کال کیا جاتا ہے۔

  5. جب سرور انیشیئلائزیشن فنکشن کے پاس کنفیگریشن ہوتی ہے، تو یہ zkFunctions کو کال کرتا ہےopens in a new tab تاکہ سرور کے زیرو نالج حصے کو انیشیئلائز کیا جا سکے۔ یہ اس وقت تک نہیں ہو سکتا جب تک کہ ہمیں کنفیگریشن نہ مل جائے کیونکہ زیرو نالج فنکشنز کو مائن فیلڈ کی چوڑائی اور اونچائی کو مستقل کے طور پر رکھنا ہوتا ہے۔

  6. سرور کا زیرو نالج حصہ انیشیئلائز ہونے کے بعد، اگلا قدم زیرو نالج ویریفیکیشن کنٹریکٹ کو بلاک چین پر ڈیپلائے کرناopens in a new tab اور MUD میں ویریفائی ایڈریس سیٹ کرنا ہے۔

  7. آخر میں، ہم اپ ڈیٹس کو سبسکرائب کرتے ہیں تاکہ ہم دیکھ سکیں کہ جب کوئی کھلاڑی یا تو نیا گیم شروع کرنےopens in a new tab کی درخواست کرتا ہے یا موجودہ گیم میں کھدائی کرنےopens in a new tab کی درخواست کرتا ہے۔

نیا گیم

جب کھلاڑی نیا گیم کی درخواست کرتا ہے تو یہ ہوتا ہے۔

  1. اگر اس کھلاڑی کے لیے کوئی گیم جاری نہیں ہے، یا ایک ہے لیکن اس کا گیم آئی ڈی صفر ہے، تو کلائنٹ ایک نیا گیم بٹنopens in a new tab دکھاتا ہے۔ جب صارف اس بٹن کو دباتا ہے، تو React newGame فنکشنopens in a new tab چلاتا ہے۔

  2. newGameopens in a new tab ایک System کال ہے۔ MUD میں تمام کالز World کنٹریکٹ کے ذریعے روٹ کی جاتی ہیں، اور زیادہ تر معاملات میں آپ <namespace>__<function name> کو کال کرتے ہیں۔ اس معاملے میں، کال app__newGame پر ہوتی ہے، جسے MUD پھر GameSystem میں newGame پرopens in a new tab روٹ کرتا ہے۔

  3. آن چین فنکشن چیک کرتا ہے کہ کھلاڑی کا کوئی گیم جاری نہیں ہے، اور اگر نہیں ہے تو درخواست کو PendingGame ٹیبل میں شامل کر دیتا ہےopens in a new tab۔

  4. سرور PendingGame میں تبدیلی کا پتہ لگاتا ہے اور سبسکرائب شدہ فنکشنopens in a new tab چلاتا ہے۔ یہ فنکشن newGameopens in a new tab کو کال کرتا ہے، جو بدلے میں createGameopens in a new tab کو کال کرتا ہے۔

  5. سب سے پہلے createGame مناسب تعداد میں مائنز کے ساتھ ایک بے ترتیب نقشہ بناتا ہےopens in a new tab۔ پھر، یہ makeMapBordersopens in a new tab کو خالی بارڈرز کے ساتھ ایک نقشہ بنانے کے لیے کال کرتا ہے، جو Zokrates کے لیے ضروری ہے۔ آخر میں، createGame calculateMapHash کو کال کرتا ہے، تاکہ نقشے کا ہیش حاصل کیا جا سکے، جسے گیم آئی ڈی کے طور پر استعمال کیا جاتا ہے۔

  6. newGame فنکشن نئے گیم کو gamesInProgress میں شامل کرتا ہے۔

  7. سرور جو آخری کام کرتا ہے وہ app__newGameResponseopens in a new tab کو کال کرنا ہے، جو آن چین ہے۔ یہ فنکشن ایک مختلف System میں ہے، ServerSystemopens in a new tab، تاکہ رسائی کنٹرول کو فعال کیا جا سکے۔ رسائی کنٹرول MUD کنفیگریشن فائلopens in a new tab میں بیان کیا گیا ہے، mud.config.tsopens in a new tab۔

    رسائی کی فہرست صرف ایک ہی ایڈریس کو System کال کرنے کی اجازت دیتی ہے۔ یہ سرور فنکشنز تک رسائی کو ایک ہی ایڈریس تک محدود کرتا ہے، تاکہ کوئی بھی سرور کی نقالی نہ کر سکے۔

  8. آن چین کمپونینٹ متعلقہ ٹیبلز کو اپ ڈیٹ کرتا ہے:

    • PlayerGame میں گیم بنائیں۔
    • GamePlayer میں الٹی میپنگ سیٹ کریں۔
    • PendingGame سے درخواست کو ہٹا دیں۔
  9. سرور PendingGame میں تبدیلی کی نشاندہی کرتا ہے، لیکن کچھ نہیں کرتا کیونکہ wantsGameopens in a new tab غلط ہے۔

  10. کلائنٹ پر gameRecordopens in a new tab کو کھلاڑی کے ایڈریس کے لیے PlayerGame انٹری پر سیٹ کیا جاتا ہے۔ جب PlayerGame تبدیل ہوتا ہے، تو gameRecord بھی تبدیل ہوتا ہے۔

  11. اگر gameRecord میں کوئی ویلیو ہے، اور گیم جیتا یا ہارا نہیں گیا ہے، تو کلائنٹ نقشہ دکھاتا ہےopens in a new tab۔

کھدائی

  1. کھلاڑی نقشے کے سیل کے بٹن پر کلک کرتا ہےopens in a new tab، جو dig فنکشنopens in a new tab کو کال کرتا ہے۔ یہ فنکشن dig کو آن چینopens in a new tab کال کرتا ہے۔

  2. آن چین کمپونینٹ کئی سینیٹی چیکس انجام دیتا ہےopens in a new tab، اور اگر کامیاب ہو جاتا ہے تو کھدائی کی درخواست کو PendingDigopens in a new tab میں شامل کر دیتا ہے۔

  3. سرور PendingDig میں تبدیلی کا پتہ لگاتا ہےopens in a new tab۔ اگر یہ درست ہےopens in a new tab، تو یہ زیرو نالج کوڈ کو کال کرتا ہےopens in a new tab (نیچے بیان کیا گیا ہے) تاکہ نتیجہ اور اس کے درست ہونے کا ثبوت دونوں پیدا کیا جا سکے۔

  4. سرورopens in a new tab آن چین digResponseopens in a new tab کو کال کرتا ہے۔

  5. digResponse دو کام کرتا ہے۔ سب سے پہلے، یہ زیرو نالج پروفopens in a new tab کو چیک کرتا ہے۔ پھر، اگر پروف چیک ہو جاتا ہے، تو یہ processDigResultopens in a new tab کو کال کرتا ہے تاکہ نتیجے کو دراصل پروسیس کیا جا سکے۔

  6. processDigResult چیک کرتا ہے کہ آیا گیم ہارopens in a new tab گیا ہے یا جیتopens in a new tab لیا گیا ہے، اور Map، یعنی آن چین نقشے کو اپ ڈیٹ کرتا ہےopens in a new tab۔

  7. کلائنٹ خود بخود اپ ڈیٹس اٹھاتا ہے اور کھلاڑی کو دکھائے گئے نقشے کو اپ ڈیٹ کرتا ہےopens in a new tab، اور اگر قابل اطلاق ہو تو کھلاڑی کو بتاتا ہے کہ یہ جیت ہے یا ہار۔

Zokrates کا استعمال

اوپر بیان کیے گئے فلو میں ہم نے زیرو نالج حصوں کو نظر انداز کر دیا، انہیں ایک بلیک باکس کے طور پر سمجھا۔ اب آئیے اسے کھول کر دیکھتے ہیں کہ وہ کوڈ کیسے لکھا گیا ہے۔

نقشے کی ہیشنگ

ہم یہ جاوا اسکرپٹ کوڈopens in a new tab Poseidonopens in a new tab کو نافذ کرنے کے لیے استعمال کر سکتے ہیں، جو ہمارا استعمال کردہ Zokrates ہیش فنکشن ہے۔ تاہم، جبکہ یہ تیز ہوگا، یہ صرف Zokrates ہیش فنکشن کا استعمال کرنے سے زیادہ پیچیدہ بھی ہوگا۔ یہ ایک ٹیوٹوریل ہے، اور اس لیے کوڈ کو سادگی کے لیے بہتر بنایا گیا ہے، نہ کہ کارکردگی کے لیے۔ لہذا، ہمیں دو مختلف Zokrates پروگراموں کی ضرورت ہے، ایک صرف ایک نقشے (hash) کے ہیش کا حساب لگانے کے لیے اور دوسرا نقشے (dig) پر کسی مقام پر کھدائی کے نتیجے کا زیرو نالج پروف بنانے کے لیے۔

ہیش فنکشن

یہ وہ فنکشن ہے جو ایک نقشے کے ہیش کا حساب لگاتا ہے۔ ہم اس کوڈ کا لائن بہ لائن جائزہ لیں گے۔

1import "hashes/poseidon/poseidon.zok" as poseidon;
2import "utils/pack/bool/pack128.zok" as pack128;

یہ دو لائنیں Zokrates اسٹینڈرڈ لائبریریopens in a new tab سے دو فنکشن درآمد کرتی ہیں۔ پہلا فنکشنopens in a new tab ایک Poseidon ہیشopens in a new tab ہے۔ یہ field عناصرopens in a new tab کی ایک صف لیتا ہے اور ایک field لوٹاتا ہے۔

Zokrates میں فیلڈ عنصر عام طور پر 256 بٹس سے کم لمبا ہوتا ہے، لیکن زیادہ نہیں۔ کوڈ کو آسان بنانے کے لیے، ہم نقشے کو 512 بٹس تک محدود کرتے ہیں، اور چار فیلڈز کی ایک صف کو ہیش کرتے ہیں، اور ہر فیلڈ میں ہم صرف 128 بٹس استعمال کرتے ہیں۔ pack128 فنکشنopens in a new tab اس مقصد کے لیے 128 بٹس کی ایک صف کو field میں تبدیل کرتا ہے۔

1 def hashMap(bool[${width+2}][${height+2}] map) -> field {

یہ لائن ایک فنکشن کی تعریف شروع کرتی ہے۔ hashMap کو map نامی ایک ہی پیرامیٹر ملتا ہے، جو ایک دو جہتی bool(ean) صف ہے۔ نقشے کا سائز width+2 ضرب height+2 ہے ان وجوہات کی بنا پر جو نیچے بیان کی گئی ہیں۔

ہم ${width+2} اور ${height+2} استعمال کر سکتے ہیں کیونکہ Zokrates پروگرام اس ایپلیکیشن میں ٹیمپلیٹ اسٹرنگزopens in a new tab کے طور پر محفوظ ہیں۔ ${ اور } کے درمیان کوڈ کا جاوا اسکرپٹ کے ذریعے جائزہ لیا جاتا ہے، اور اس طرح پروگرام کو مختلف نقشے کے سائز کے لیے استعمال کیا جا سکتا ہے۔ نقشہ پیرامیٹر میں اس کے چاروں طرف ایک مقام چوڑا بارڈر ہے جس میں کوئی بم نہیں ہے، یہی وجہ ہے کہ ہمیں چوڑائی اور اونچائی میں دو کا اضافہ کرنے کی ضرورت ہے۔

واپسی کی قیمت ایک field ہے جس میں ہیش ہوتا ہے۔

1 bool[512] mut map1d = [false; 512];

نقشہ دو جہتی ہے۔ تاہم، pack128 فنکشن دو جہتی صفوں کے ساتھ کام نہیں کرتا ہے۔ لہذا ہم پہلے نقشے کو 512 بائٹ کی صف میں ہموار کرتے ہیں، map1d کا استعمال کرتے ہوئے۔ ڈیفالٹ کے طور پر Zokrates متغیرات مستقل ہوتے ہیں، لیکن ہمیں اس صف کو ایک لوپ میں اقدار تفویض کرنے کی ضرورت ہے، لہذا ہم اسے mutopens in a new tab کے طور پر بیان کرتے ہیں۔

ہمیں صف کو شروع کرنے کی ضرورت ہے کیونکہ Zokrates میں undefined نہیں ہے۔ تاثر [false; 512] کا مطلب ہے 512 false اقدار کی ایک صفopens in a new tab۔

1 u32 mut counter = 0;

ہمیں ان بٹس کے درمیان فرق کرنے کے لیے ایک کاؤنٹر کی بھی ضرورت ہے جو ہم نے map1d میں پہلے ہی بھر دیے ہیں اور جو نہیں بھرے۔

1 for u32 x in 0..${width+2} {

یہ ہے کہ آپ Zokrates میں for لوپopens in a new tab کا اعلان کیسے کرتے ہیں۔ ایک Zokrates for لوپ کی مقررہ حدود ہونی چاہئیں، کیونکہ جبکہ یہ ایک لوپ کی طرح لگتا ہے، کمپائلر دراصل اسے "کھول" دیتا ہے۔ تاثر ${width+2} ایک کمپائل ٹائم مستقل ہے کیونکہ width ٹائپ اسکرپٹ کوڈ کے ذریعے کمپائلر کو کال کرنے سے پہلے سیٹ کیا جاتا ہے۔

1 for u32 y in 0..${height+2} {
2 map1d[counter] = map[x][y];
3 counter = counter+1;
4 }
5 }

نقشے میں ہر مقام کے لیے، اس قدر کو map1d صف میں ڈالیں اور کاؤنٹر میں اضافہ کریں۔

1 field[4] hashMe = [
2 pack128(map1d[0..128]),
3 pack128(map1d[128..256]),
4 pack128(map1d[256..384]),
5 pack128(map1d[384..512])
6 ];

pack128 map1d سے چار field اقدار کی ایک صف بنانے کے لیے۔ Zokrates میں array[a..b] کا مطلب ہے صف کا وہ ٹکڑا جو a سے شروع ہوتا ہے اور b-1 پر ختم ہوتا ہے۔

1 return poseidon(hashMe);
2}

اس صف کو ہیش میں تبدیل کرنے کے لیے poseidon کا استعمال کریں۔

ہیش پروگرام

سرور کو گیم شناخت کنندہ بنانے کے لیے براہ راست hashMap کو کال کرنے کی ضرورت ہے۔ تاہم، Zokrates صرف main فنکشن کو شروع کرنے کے لیے کال کر سکتا ہے، لہذا ہم ایک main کے ساتھ ایک پروگرام بناتے ہیں جو ہیش فنکشن کو کال کرتا ہے۔

1${hashFragment}
2
3def main(bool[${width+2}][${height+2}] map) -> field {
4 return hashMap(map);
5}

کھدائی پروگرام

یہ ایپلیکیشن کا زیرو نالج حصہ کا دل ہے، جہاں ہم وہ ثبوت تیار کرتے ہیں جو کھدائی کے نتائج کی تصدیق کے لیے استعمال ہوتے ہیں۔

1${hashFragment}
2
3// The number of mines in location (x,y)
4def map2mineCount(bool[${width+2}][${height+2}] map, u32 x, u32 y) -> u8 {
5 return if map[x+1][y+1] { 1 } else { 0 };
6}

نقشے کا بارڈر کیوں

زیرو نالج پروف حسابی سرکٹسopens in a new tab کا استعمال کرتے ہیں، جن میں if اسٹیٹمنٹ کا کوئی آسان مساوی نہیں ہوتا ہے۔ اس کے بجائے، وہ مشروط آپریٹرopens in a new tab کے مساوی کا استعمال کرتے ہیں۔ اگر a صفر یا ایک ہو سکتا ہے، تو آپ if a { b } else { c } کا حساب ab+(1-a)c کے طور پر کر سکتے ہیں۔

اس کی وجہ سے، ایک Zokrates if اسٹیٹمنٹ ہمیشہ دونوں شاخوں کا جائزہ لیتا ہے۔ مثال کے طور پر، اگر آپ کے پاس یہ کوڈ ہے:

1bool[5] arr = [false; 5];
2u32 index=10;
3return if index>4 { 0 } else { arr[index] }

اس میں خرابی ہوگی، کیونکہ اسے arr[10] کا حساب لگانے کی ضرورت ہے، چاہے وہ قدر بعد میں صفر سے ضرب دی جائے۔

یہی وجہ ہے کہ ہمیں نقشے کے چاروں طرف ایک مقام چوڑا بارڈر کی ضرورت ہے۔ ہمیں کسی مقام کے ارد گرد مائنز کی کل تعداد کا حساب لگانے کی ضرورت ہے، اور اس کا مطلب ہے کہ ہمیں اس مقام سے ایک قطار اوپر اور نیچے، بائیں اور دائیں کو دیکھنے کی ضرورت ہے، جہاں ہم کھدائی کر رہے ہیں۔ جس کا مطلب ہے کہ وہ مقام Zokrates کو فراہم کردہ نقشے کی صف میں موجود ہونا چاہیے۔

1def main(private bool[${width+2}][${height+2}] map, u32 x, u32 y) -> (field, u8) {

ڈیفالٹ کے طور پر Zokrates ثبوتوں میں ان کے ان پٹ شامل ہوتے ہیں۔ یہ جاننا کوئی فائدہ مند نہیں ہے کہ کسی جگہ کے ارد گرد پانچ مائنز ہیں جب تک کہ آپ کو حقیقت میں یہ نہ معلوم ہو کہ وہ کون سی جگہ ہے (اور آپ اسے صرف اپنی درخواست سے نہیں ملا سکتے، کیونکہ تب پروور مختلف اقدار کا استعمال کر سکتا ہے اور آپ کو اس کے بارے میں نہیں بتا سکتا)۔ تاہم، ہمیں نقشے کو خفیہ رکھنے کی ضرورت ہے، جبکہ اسے Zokrates کو فراہم کرتے ہوئے۔ حل یہ ہے کہ ایک private پیرامیٹر کا استعمال کیا جائے، ایک ایسا جو ثبوت سے ظاہر نہیں ہوتا ہے۔

اس سے غلط استعمال کا ایک اور راستہ کھلتا ہے۔ پروور صحیح کوآرڈینیٹس کا استعمال کر سکتا ہے، لیکن مقام کے ارد گرد کسی بھی تعداد میں مائنز کے ساتھ ایک نقشہ بنا سکتا ہے، اور ممکنہ طور پر خود مقام پر بھی۔ اس غلط استعمال کو روکنے کے لیے، ہم زیرو نالج پروف کو نقشے کا ہیش شامل کرتے ہیں، جو گیم شناخت کنندہ ہے۔

1 return (hashMap(map),

یہاں واپسی کی قیمت ایک ٹوپل ہے جس میں نقشہ ہیش صف اور کھدائی کا نتیجہ شامل ہے۔

1 if map2mineCount(map, x, y) > 0 { 0xFF } else {

اگر خود مقام پر کوئی بم ہو تو ہم 255 کو ایک خاص قدر کے طور پر استعمال کرتے ہیں۔

1 map2mineCount(map, x-1, y-1) + map2mineCount(map, x, y-1) + map2mineCount(map, x+1, y-1) +
2 map2mineCount(map, x-1, y) + map2mineCount(map, x+1, y) +
3 map2mineCount(map, x-1, y+1) + map2mineCount(map, x, y+1) + map2mineCount(map, x+1, y+1)
4 }
5 );
6}

اگر کھلاڑی نے کسی مائن کو نہیں مارا ہے، تو مقام کے ارد گرد کے علاقے کے لیے مائن کاؤنٹ شامل کریں اور اسے واپس کریں۔

TypeScript سے Zokrates کا استعمال

Zokrates کا ایک کمانڈ لائن انٹرفیس ہے، لیکن اس پروگرام میں ہم اسے TypeScript کوڈopens in a new tab میں استعمال کرتے ہیں۔

Zokrates تعریفوں پر مشتمل لائبریری کو zero-knowledge.tsopens in a new tab کہا جاتا ہے۔

1import { initialize as zokratesInitialize } from "zokrates-js"

Zokrates جاوا اسکرپٹ بائنڈنگزopens in a new tab کو درآمد کریں۔ ہمیں صرف initializeopens in a new tab فنکشن کی ضرورت ہے کیونکہ یہ ایک وعدہ لوٹاتا ہے جو تمام Zokrates تعریفوں کو حل کرتا ہے۔

1export const zkFunctions = async (width: number, height: number) : Promise<any> => {

Zokrates کی طرح، ہم بھی صرف ایک فنکشن برآمد کرتے ہیں، جو غیر ہم آہنگopens in a new tab بھی ہے۔ جب یہ بالآخر واپس آتا ہے، تو یہ کئی فنکشن فراہم کرتا ہے جیسا کہ ہم نیچے دیکھیں گے۔

1const zokrates = await zokratesInitialize()

Zokrates کو شروع کریں، لائبریری سے ہمیں ہر چیز حاصل کریں۔

1const hashFragment = `
2 import "utils/pack/bool/pack128.zok" as pack128;
3 import "hashes/poseidon/poseidon.zok" as poseidon;
4 .
5 .
6 .
7 }
8 `
9
10const hashProgram = `
11 ${hashFragment}
12 .
13 .
14 .
15 `
16
17const digProgram = `
18 ${hashFragment}
19 .
20 .
21 .
22 `
سب دکھائیں

اگلا ہمارے پاس ہیش فنکشن اور دو Zokrates پروگرام ہیں جو ہم نے اوپر دیکھے۔

1const digCompiled = zokrates.compile(digProgram)
2const hashCompiled = zokrates.compile(hashProgram)

یہاں ہم ان پروگراموں کو کمپائل کرتے ہیں۔

1// Create the keys for zero knowledge verification.
2// On a production system you'd want to use a setup ceremony.
3// (https://zokrates.github.io/toolbox/trusted_setup.html#initializing-a-phase-2-ceremony).
4const keySetupResults = zokrates.setup(digCompiled.program, "")
5const verifierKey = keySetupResults.vk
6const proverKey = keySetupResults.pk

ایک پروڈکشن سسٹم پر ہم ایک زیادہ پیچیدہ سیٹ اپ تقریبopens in a new tab کا استعمال کر سکتے ہیں، لیکن یہ ایک مظاہرے کے لیے کافی ہے۔ یہ کوئی مسئلہ نہیں ہے کہ صارفین پروور کی جان سکتے ہیں - وہ پھر بھی اسے چیزوں کو ثابت کرنے کے لیے استعمال نہیں کر سکتے جب تک کہ وہ سچ نہ ہوں۔ کیونکہ ہم اینٹروپی کی وضاحت کرتے ہیں (دوسرا پیرامیٹر، "")، نتائج ہمیشہ ایک جیسے ہی ہوں گے۔

نوٹ: Zokrates پروگراموں کی تالیف اور کلید کی تخلیق سست عمل ہیں۔ انہیں ہر بار دہرانے کی ضرورت نہیں ہے، صرف اس وقت جب نقشے کا سائز تبدیل ہوتا ہے۔ ایک پروڈکشن سسٹم پر آپ انہیں ایک بار کریں گے، اور پھر آؤٹ پٹ کو اسٹور کریں گے۔ میں یہاں صرف سادگی کی خاطر ایسا نہیں کر رہا ہوں۔

calculateMapHash

1const calculateMapHash = function (hashMe: boolean[][]): string {
2 return (
3 "0x" +
4 BigInt(zokrates.computeWitness(hashCompiled, [hashMe]).output.slice(1, -1))
5 .toString(16)
6 .padStart(64, "0")
7 )
8}

computeWitnessopens in a new tab فنکشن دراصل Zokrates پروگرام چلاتا ہے۔ یہ دو فیلڈز کے ساتھ ایک ڈھانچہ لوٹاتا ہے: output، جو ایک JSON سٹرنگ کے طور پر پروگرام کا آؤٹ پٹ ہے، اور witness، جو نتیجے کا زیرو نالج پروف بنانے کے لیے درکار معلومات ہے۔ یہاں ہمیں صرف آؤٹ پٹ کی ضرورت ہے۔

آؤٹ پٹ "31337" کی شکل میں ایک سٹرنگ ہے، جو کوٹیشن مارکس میں بند ایک اعشاریہ نمبر ہے۔ لیکن viem کے لیے ہمیں جو آؤٹ پٹ چاہیے وہ 0x60A7 کی شکل میں ایک ہیکساڈیسیمل نمبر ہے۔ لہذا ہم کوٹیشن مارکس کو ہٹانے کے لیے .slice(1,-1) کا استعمال کرتے ہیں اور پھر باقی سٹرنگ کو، جو ایک اعشاریہ نمبر ہے، ایک BigIntopens in a new tab میں تبدیل کرنے کے لیے BigInt کا استعمال کرتے ہیں۔ .toString(16) اس BigInt کو ایک ہیکساڈیسیمل سٹرنگ میں تبدیل کرتا ہے، اور "0x"+ ہیکساڈیسیمل نمبروں کے لیے مارکر شامل کرتا ہے۔

1// Dig and return a zero knowledge proof of the result
2// (server-side code)

زیرو نالج پروف میں عوامی ان پٹس (x اور y) اور نتائج (نقشے کا ہیش اور بموں کی تعداد) شامل ہیں۔

1 const zkDig = function(map: boolean[][], x: number, y: number) : any {
2 if (x<0 || x>=width || y<0 || y>=height)
3 throw new Error("Trying to dig outside the map")

یہ چیک کرنا کہ آیا کوئی انڈیکس Zokrates میں حد سے باہر ہے، ایک مسئلہ ہے، لہذا ہم اسے یہاں کرتے ہیں۔

1const runResults = zokrates.computeWitness(digCompiled, [map, `${x}`, `${y}`])

کھدائی پروگرام پر عمل کریں۔

1 const proof = zokrates.generateProof(
2 digCompiled.program,
3 runResults.witness,
4 proverKey)
5
6 return proof
7 }

generateProofopens in a new tab کا استعمال کریں اور ثبوت واپس کریں۔

1const solidityVerifier = `
2 // Map size: ${width} x ${height}
3 \n${zokrates.exportSolidityVerifier(verifierKey)}
4 `

ایک Solidity ویریفائر، ایک سمارٹ کنٹریکٹ جسے ہم بلاک چین پر تعینات کر سکتے ہیں اور digCompiled.program کے ذریعے تیار کردہ ثبوتوں کی تصدیق کے لیے استعمال کر سکتے ہیں۔

1 return {
2 zkDig,
3 calculateMapHash,
4 solidityVerifier,
5 }
6}

آخر میں، ہر وہ چیز واپس کریں جس کی دوسرے کوڈ کو ضرورت ہو سکتی ہے۔

سیکیورٹی ٹیسٹ

سیکیورٹی ٹیسٹ اہم ہیں کیونکہ ایک فنکشنلٹی بگ بالآخر خود کو ظاہر کر دے گا۔ لیکن اگر ایپلیکیشن غیر محفوظ ہے، تو یہ ممکنہ طور پر ایک طویل عرصے تک چھپی رہے گی اس سے پہلے کہ یہ کسی کے دھوکہ دہی اور دوسروں سے تعلق رکھنے والے وسائل سے بچ نکلنے سے ظاہر ہو۔

اجازتیں

اس گیم میں ایک مراعات یافتہ ادارہ ہے، سرور۔ یہ واحد صارف ہے جسے ServerSystemopens in a new tab میں فنکشنز کو کال کرنے کی اجازت ہے۔ ہم castopens in a new tab کا استعمال کر سکتے ہیں تاکہ یہ تصدیق کی جا سکے کہ اجازت یافتہ فنکشنز کی کالز صرف سرور اکاؤنٹ کے طور پر ہی کی جا سکتی ہیں۔

سرور کی نجی کلید setupNetwork.ts میں ہےopens in a new tab۔

  1. anvil (بلاک چین) چلانے والے کمپیوٹر پر، یہ ماحولیاتی متغیرات سیٹ کریں۔

    1WORLD_ADDRESS=0x8d8b6b8414e1e3dcfd4168561b9be6bd3bf6ec4b
    2UNAUTHORIZED_KEY=0x5de4111afa1a4b94908f83103eb1f1706367c2e68ca870fc3fb9a804cdab365a
    3AUTHORIZED_KEY=0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d
  2. cast کا استعمال کریں تاکہ تصدیق کنندہ کا پتہ ایک غیر مجاز پتے کے طور پر سیٹ کرنے کی کوشش کی جا سکے۔

    1cast send $WORLD_ADDRESS 'app__setVerifier(address)' `cast address-zero` --private-key $UNAUTHORIZED_KEY

    نہ صرف cast ایک ناکامی کی اطلاع دیتا ہے، بلکہ آپ براؤزر پر گیم میں MUD Dev Tools کھول سکتے ہیں، ٹیبلز پر کلک کر سکتے ہیں، اور app__VerifierAddress کو منتخب کر سکتے ہیں۔ دیکھیں کہ پتہ صفر نہیں ہے۔

  3. ویریفائر ایڈریس کو سرور کے ایڈریس کے طور پر سیٹ کریں۔

    1cast send $WORLD_ADDRESS 'app__setVerifier(address)' `cast address-zero` --private-key $AUTHORIZED_KEY

    app__VerifiedAddress میں پتہ اب صفر ہونا چاہیے۔

ایک ہی System میں تمام MUD فنکشنز ایک ہی ایکسیس کنٹرول سے گزرتے ہیں، لہذا میں اس ٹیسٹ کو کافی سمجھتا ہوں۔ اگر آپ نہیں کرتے ہیں، تو آپ ServerSystemopens in a new tab میں دیگر فنکشنز کو چیک کر سکتے ہیں۔

زیرو نالج کے غلط استعمال

Zokrates کی تصدیق کے لیے ریاضی اس ٹیوٹوریل (اور میری صلاحیتوں) کے دائرہ سے باہر ہے۔ تاہم، ہم زیرو نالج کوڈ پر مختلف چیک چلا سکتے ہیں تاکہ یہ تصدیق کی جا سکے کہ اگر اسے صحیح طریقے سے نہیں کیا گیا تو یہ ناکام ہو جاتا ہے۔ ان تمام ٹیسٹوں کے لیے ہمیں zero-knowledge.tsopens in a new tab کو تبدیل کرنے اور پوری ایپلیکیشن کو دوبارہ شروع کرنے کی ضرورت ہوگی۔ سرور پروسیس کو دوبارہ شروع کرنا کافی نہیں ہے، کیونکہ یہ ایپلیکیشن کو ایک ناممکن حالت میں ڈال دیتا ہے (کھلاڑی کا ایک گیم جاری ہے، لیکن گیم اب سرور کے لیے دستیاب نہیں ہے)۔

غلط جواب

سب سے آسان امکان زیرو نالج پروف میں غلط جواب فراہم کرنا ہے۔ ایسا کرنے کے لیے، ہم zkDig کے اندر جاتے ہیں اور لائن 91 میں ترمیم کرتے ہیںopens in a new tab:

1proof.inputs[3] = "0x" + "1".padStart(64, "0")

اس کا مطلب ہے کہ ہم ہمیشہ دعویٰ کریں گے کہ ایک بم ہے، چاہے صحیح جواب کچھ بھی ہو۔ اس ورژن کے ساتھ کھیلنے کی کوشش کریں، اور آپ pnpm dev اسکرین کے سرور ٹیب میں یہ خرابی دیکھیں گے:

1 cause: {
2 code: 3,
3 message: 'execution reverted: revert: Zero knowledge verification fail',
4 data: '0x08c379a0000000000000000000000000000000000000000000000000000000000000002000000000000000
500000000000000000000000000000000000000000000000205a65726f206b6e6f776c6564676520766572696669636174696f6
6e206661696c'
7 },

تو اس قسم کی دھوکہ دہی ناکام ہو جاتی ہے۔

غلط ثبوت

کیا ہوتا ہے اگر ہم صحیح معلومات فراہم کریں، لیکن ثبوت کا ڈیٹا غلط ہو؟ اب، لائن 91 کو اس سے بدل دیں:

1proof.proof = {
2 a: ["0x" + "1".padStart(64, "0"), "0x" + "2".padStart(64, "0")],
3 b: [
4 ["0x" + "1".padStart(64, "0"), "0x" + "2".padStart(64, "0")],
5 ["0x" + "1".padStart(64, "0"), "0x" + "2".padStart(64, "0")],
6 ],
7 c: ["0x" + "1".padStart(64, "0"), "0x" + "2".padStart(64, "0")],
8}

یہ اب بھی ناکام رہتا ہے، لیکن اب یہ بغیر کسی وجہ کے ناکام ہوجاتا ہے کیونکہ یہ ویریفائر کال کے دوران ہوتا ہے۔

ایک صارف زیرو ٹرسٹ کوڈ کی تصدیق کیسے کر سکتا ہے؟

اسمارٹ معاہدوں کی تصدیق کرنا نسبتاً آسان ہے۔ عام طور پر، ڈیولپر سورس کوڈ کو ایک بلاک ایکسپلورر پر شائع کرتا ہے، اور بلاک ایکسپلورر اس بات کی تصدیق کرتا ہے کہ سورس کوڈ معاہدے کی تعیناتی کے لین دین میں کوڈ کو کمپائل کرتا ہے۔ MUD Systems کے معاملے میں یہ تھوڑا زیادہ پیچیدہopens in a new tab ہے، لیکن زیادہ نہیں۔

یہ زیرو نالج کے ساتھ زیادہ مشکل ہے۔ ویریفائر میں کچھ مستقل شامل ہوتے ہیں اور ان پر کچھ حسابات چلاتے ہیں۔ یہ آپ کو نہیں بتاتا کہ کیا ثابت کیا جا رہا ہے۔

1 function verifyingKey() pure internal returns (VerifyingKey memory vk) {
2 vk.alpha = Pairing.G1Point(uint256(0x0f43f4fe7b5c2326fed4ac6ed2f4003ab9ab4ea6f667c2bdd77afb068617ee16), uint256(0x25a77832283f9726935219b5f4678842cda465631e72dbb24708a97ba5d0ce6f));
3 vk.beta = Pairing.G2Point([uint256(0x2cebd0fbd21aca01910581537b21ae4fed46bc0e524c055059aa164ba0a6b62b), uint256(0x18fd4a7bc386cf03a95af7163d5359165acc4e7961cb46519e6d9ee4a1e2b7e9)], [uint256(0x11449dee0199ef6d8eebfe43b548e875c69e7ce37705ee9a00c81fe52f11a009), uint256(0x066d0c83b32800d3f335bb9e8ed5e2924cf00e77e6ec28178592eac9898e1a00)]);

حل، کم از کم جب تک بلاک ایکسپلوررز اپنے صارف انٹرفیس میں Zokrates کی تصدیق شامل نہیں کر لیتے، یہ ہے کہ ایپلیکیشن ڈیولپرز Zokrates پروگراموں کو دستیاب کرائیں، اور کم از کم کچھ صارفین انہیں مناسب تصدیقی کلید کے ساتھ خود کمپائل کریں۔

ایسا کرنے کے لیے:

  1. Zokrates انسٹال کریںopens in a new tab۔

  2. ایک فائل بنائیں، dig.zok، Zokrates پروگرام کے ساتھ۔ نیچے دیا گیا کوڈ یہ فرض کرتا ہے کہ آپ نے اصل نقشے کا سائز، 10x5، رکھا ہے۔

    1 import "utils/pack/bool/pack128.zok" as pack128;
    2 import "hashes/poseidon/poseidon.zok" as poseidon;
    3
    4 def hashMap(bool[12][7] map) -> field {
    5 bool[512] mut map1d = [false; 512];
    6 u32 mut counter = 0;
    7
    8 for u32 x in 0..12 {
    9 for u32 y in 0..7 {
    10 map1d[counter] = map[x][y];
    11 counter = counter+1;
    12 }
    13 }
    14
    15 field[4] hashMe = [
    16 pack128(map1d[0..128]),
    17 pack128(map1d[128..256]),
    18 pack128(map1d[256..384]),
    19 pack128(map1d[384..512])
    20 ];
    21
    22 return poseidon(hashMe);
    23 }
    24
    25
    26 // The number of mines in location (x,y)
    27 def map2mineCount(bool[12][7] map, u32 x, u32 y) -> u8 {
    28 return if map[x+1][y+1] { 1 } else { 0 };
    29 }
    30
    31 def main(private bool[12][7] map, u32 x, u32 y) -> (field, u8) {
    32 return (hashMap(map) ,
    33 if map2mineCount(map, x, y) > 0 { 0xFF } else {
    34 map2mineCount(map, x-1, y-1) + map2mineCount(map, x, y-1) + map2mineCount(map, x+1, y-1) +
    35 map2mineCount(map, x-1, y) + map2mineCount(map, x+1, y) +
    36 map2mineCount(map, x-1, y+1) + map2mineCount(map, x, y+1) + map2mineCount(map, x+1, y+1)
    37 }
    38 );
    39 }
    سب دکھائیں
  3. Zokrates کوڈ کو کمپائل کریں اور تصدیقی کلید بنائیں۔ تصدیقی کلید اسی اینٹروپی کے ساتھ بنانی ہوگی جو اصل سرور میں استعمال کی گئی تھی، اس معاملے میں ایک خالی سٹرنگopens in a new tab۔

    1zokrates compile --input dig.zok
    2zokrates setup -e ""
  4. اپنا Solidity ویریفائر خود بنائیں، اور تصدیق کریں کہ یہ بلاک چین پر موجود ویریفائر سے فنکشنل طور پر یکساں ہے (سرور ایک تبصرہ شامل کرتا ہے، لیکن یہ اہم نہیں ہے)۔

    1zokrates export-verifier
    2diff verifier.sol ~/20240901-secret-state/packages/contracts/src/verifier.sol

ڈیزائن کے فیصلے

کسی بھی کافی پیچیدہ ایپلیکیشن میں مسابقتی ڈیزائن کے اہداف ہوتے ہیں جن کے لیے سمجھوتہ کی ضرورت ہوتی ہے۔ آئیے کچھ سمجھوتوں کو دیکھتے ہیں اور یہ کہ موجودہ حل دوسرے اختیارات سے کیوں بہتر ہے۔

زیرو نالج کیوں

مائن سویپر کے لیے آپ کو حقیقت میں زیرو نالج کی ضرورت نہیں ہے۔ سرور ہمیشہ نقشہ رکھ سکتا ہے، اور پھر گیم ختم ہونے پر اس سب کو ظاہر کر سکتا ہے۔ پھر، گیم کے اختتام پر، سمارٹ کنٹریکٹ نقشے کے ہیش کا حساب لگا سکتا ہے، تصدیق کر سکتا ہے کہ یہ میل کھاتا ہے، اور اگر ایسا نہیں ہوتا ہے تو سرور کو سزا دے سکتا ہے یا گیم کو مکمل طور پر نظر انداز کر سکتا ہے۔

میں نے یہ آسان حل استعمال نہیں کیا کیونکہ یہ صرف اچھی طرح سے متعین اختتامی حالت والے مختصر گیمز کے لیے کام کرتا ہے۔ جب ایک گیم ممکنہ طور پر لامحدود ہو (جیسے کہ خود مختار دنیاؤںopens in a new tab کے معاملے میں)، آپ کو ایک ایسے حل کی ضرورت ہے جو حالت کو ظاہر کیے بغیر ثابت کرے۔

ایک ٹیوٹوریل کے طور پر اس مضمون کو ایک مختصر گیم کی ضرورت تھی جو سمجھنے میں آسان ہو، لیکن یہ تکنیک طویل گیمز کے لیے سب سے زیادہ مفید ہے۔

Zokrates کیوں؟

Zokratesopens in a new tab واحد زیرو نالج لائبریری دستیاب نہیں ہے، لیکن یہ ایک عام، امپیریٹوopens in a new tab پروگرامنگ زبان کی طرح ہے اور بولین متغیرات کو سپورٹ کرتی ہے۔

آپ کی ایپلیکیشن کے لیے، مختلف ضروریات کے ساتھ، آپ Circumopens in a new tab یا Cairoopens in a new tab کا استعمال کرنا پسند کر سکتے ہیں۔

Zokrates کو کب کمپائل کریں

اس پروگرام میں ہم Zokrates پروگراموں کو ہر بار سرور شروع ہونے پرopens in a new tab کمپائل کرتے ہیں۔ یہ واضح طور پر وسائل کا ضیاع ہے، لیکن یہ ایک ٹیوٹوریل ہے، جو سادگی کے لیے بہتر بنایا گیا ہے۔

اگر میں پروڈکشن لیول کی ایپلیکیشن لکھ رہا ہوتا، تو میں چیک کرتا کہ آیا میرے پاس اس مائن فیلڈ سائز پر کمپائل شدہ Zokrates پروگراموں کے ساتھ ایک فائل ہے، اور اگر ایسا ہے تو اسے استعمال کرتا۔ یہی بات آن چین پر ویریفائر کنٹریکٹ کی تعیناتی پر بھی لاگو ہوتی ہے۔

ویریفائر اور پروور کیز بنانا

کلید کی تخلیقopens in a new tab ایک اور خالص حساب ہے جسے ایک دیے گئے مائن فیلڈ سائز کے لیے ایک سے زیادہ بار کرنے کی ضرورت نہیں ہے۔ ایک بار پھر، یہ صرف سادگی کی خاطر ایک بار کیا جاتا ہے۔

مزید برآں، ہم ایک سیٹ اپ تقریبopens in a new tab کا استعمال کر سکتے ہیں۔ ایک سیٹ اپ تقریب کا فائدہ یہ ہے کہ آپ کو زیرو نالج پروف پر دھوکہ دینے کے لیے یا تو اینٹروپی یا ہر شریک سے کچھ درمیانی نتیجہ کی ضرورت ہوتی ہے۔ اگر کم از کم ایک تقریب کا شریک ایماندار ہے اور اس معلومات کو حذف کر دیتا ہے، تو زیرو نالج پروف کچھ حملوں سے محفوظ ہیں۔ تاہم، یہ تصدیق کرنے کا کوئی میکانزم نہیں ہے کہ معلومات کو ہر جگہ سے حذف کر دیا گیا ہے۔ اگر زیرو نالج پروف انتہائی اہم ہیں، تو آپ سیٹ اپ تقریب میں حصہ لینا چاہتے ہیں۔

یہاں ہم پرپیچوئل پاورز آف ٹاؤopens in a new tab پر انحصار کرتے ہیں، جس میں درجنوں شرکاء تھے۔ یہ شاید کافی محفوظ ہے، اور بہت آسان ہے۔ ہم کلید کی تخلیق کے دوران اینٹروپی بھی شامل نہیں کرتے ہیں، جس سے صارفین کے لیے زیرو نالج کنفیگریشن کی تصدیق کرنا آسان ہو جاتا ہے۔

کہاں تصدیق کریں

ہم زیرو نالج پروف کو یا تو آن چین (جس پر گیس خرچ ہوتی ہے) یا کلائنٹ میں ( verifyopens in a new tab کا استعمال کرتے ہوئے) تصدیق کر سکتے ہیں۔ میں نے پہلا انتخاب کیا، کیونکہ یہ آپ کو ویریفائر کی تصدیق کرنے کی اجازت دیتا ہے اور پھر اس بات پر بھروسہ کرتا ہے کہ جب تک اس کے لیے کنٹریکٹ کا پتہ وہی رہتا ہے، اس میں کوئی تبدیلی نہیں آتی ہے۔ اگر کلائنٹ پر تصدیق کی جاتی، تو آپ کو ہر بار کلائنٹ ڈاؤن لوڈ کرنے پر موصول ہونے والے کوڈ کی تصدیق کرنی پڑتی۔

نیز، جبکہ یہ گیم سنگل پلیئر ہے، بہت سے بلاک چین گیمز ملٹی پلیئر ہیں۔ آن چین تصدیق کا مطلب ہے کہ آپ صرف ایک بار زیرو نالج پروف کی تصدیق کرتے ہیں۔ اسے کلائنٹ میں کرنے کے لیے ہر کلائنٹ کو آزادانہ طور پر تصدیق کرنے کی ضرورت ہوگی۔

نقشے کو TypeScript یا Zokrates میں فلیٹ کریں؟

عام طور پر، جب پروسیسنگ یا تو TypeScript یا Zokrates میں کی جا سکتی ہے، تو اسے TypeScript میں کرنا بہتر ہے، جو بہت تیز ہے، اور زیرو نالج پروف کی ضرورت نہیں ہے۔ یہی وجہ ہے، مثال کے طور پر، کہ ہم Zokrates کو ہیش فراہم نہیں کرتے ہیں اور اسے یہ تصدیق کرنے کے لیے کہتے ہیں کہ یہ درست ہے۔ ہیشنگ کو Zokrates کے اندر کرنا پڑتا ہے، لیکن واپس کیے گئے ہیش اور آن چین ہیش کے درمیان مماثلت اس کے باہر ہو سکتی ہے۔

تاہم، ہم اب بھی Zokrates میں نقشے کو فلیٹ کرتے ہیںopens in a new tab، جبکہ ہم اسے TypeScript میں کر سکتے تھے۔ وجہ یہ ہے کہ دوسرے اختیارات، میری رائے میں، بدتر ہیں۔

  • Zokrates کوڈ کو بولین کی ایک جہتی صف فراہم کریں، اور دو جہتی نقشہ حاصل کرنے کے لیے x*(height+2) +y جیسے تاثر کا استعمال کریں۔ یہ کوڈopens in a new tab کو قدرے زیادہ پیچیدہ بنا دے گا، لہذا میں نے فیصلہ کیا کہ کارکردگی کا فائدہ ایک ٹیوٹوریل کے لیے اس کے قابل نہیں ہے۔

  • Zokrates کو ایک جہتی صف اور دو جہتی صف دونوں بھیجیں۔ تاہم، اس حل سے ہمیں کچھ حاصل نہیں ہوتا۔ Zokrates کوڈ کو یہ تصدیق کرنی ہوگی کہ اسے فراہم کردہ ایک جہتی صف واقعی دو جہتی صف کی صحیح نمائندگی ہے۔ تو کارکردگی میں کوئی فائدہ نہیں ہوگا۔

  • Zokrates میں دو جہتی صف کو فلیٹ کریں۔ یہ سب سے آسان آپشن ہے، لہذا میں نے اسے منتخب کیا۔

نقشوں کو کہاں اسٹور کریں

اس ایپلیکیشن میں gamesInProgressopens in a new tab صرف میموری میں ایک متغیر ہے۔ اس کا مطلب ہے کہ اگر آپ کا سرور مر جاتا ہے اور اسے دوبارہ شروع کرنے کی ضرورت ہے، تو اس میں محفوظ تمام معلومات ضائع ہو جاتی ہیں۔ نہ صرف کھلاڑی اپنا کھیل جاری رکھنے سے قاصر ہیں، بلکہ وہ نیا کھیل بھی شروع نہیں کر سکتے کیونکہ آن چین جزو سوچتا ہے کہ ان کا ابھی بھی ایک کھیل جاری ہے۔

یہ واضح طور پر ایک پروڈکشن سسٹم کے لیے خراب ڈیزائن ہے، جس میں آپ اس معلومات کو ایک ڈیٹا بیس میں محفوظ کریں گے۔ میں نے یہاں ایک متغیر کا استعمال صرف اس لیے کیا کیونکہ یہ ایک ٹیوٹوریل ہے اور سادگی سب سے اہم غور ہے۔

نتیجہ: کن حالات میں یہ مناسب تکنیک ہے؟

تو، اب آپ جانتے ہیں کہ ایک سرور کے ساتھ ایک گیم کیسے لکھنا ہے جو خفیہ حالت کو اسٹور کرتا ہے جو آن چین سے تعلق نہیں رکھتا۔ لیکن کن معاملات میں آپ کو ایسا کرنا چاہیے؟ دو اہم غور ہیں۔

  • طویل چلنے والا کھیل: جیسا کہ اوپر ذکر کیا گیا ہے، ایک مختصر کھیل میں آپ صرف کھیل ختم ہونے کے بعد حالت کو شائع کر سکتے ہیں اور پھر ہر چیز کی تصدیق کروا سکتے ہیں۔ لیکن یہ ایک آپشن نہیں ہے جب کھیل میں لمبا یا غیر معینہ وقت لگتا ہے، اور حالت کو خفیہ رکھنے کی ضرورت ہے۔

  • کچھ مرکزیت قابل قبول: زیرو نالج پروف سالمیت کی تصدیق کر سکتے ہیں، کہ کوئی ادارہ نتائج کو جعلی نہیں بنا رہا ہے۔ جو وہ نہیں کر سکتے وہ یہ یقینی بنانا ہے کہ ادارہ اب بھی دستیاب ہوگا اور پیغامات کا جواب دے گا۔ ان حالات میں جہاں دستیابی کو بھی غیر مرکزی کرنے کی ضرورت ہے، زیرو نالج پروف ایک کافی حل نہیں ہیں، اور آپ کو ملٹی پارٹی کمپیوٹیشنopens in a new tab کی ضرورت ہے۔

میرے مزید کام کے لیے یہاں دیکھیںopens in a new tab۔

اعترافات

  • الوارو الونسو نے اس مضمون کا ایک مسودہ پڑھا اور Zokrates کے بارے میں میری کچھ غلط فہمیوں کو دور کیا۔

کوئی بھی باقی غلطیاں میری ذمہ داری ہیں۔

صفحہ کی آخری تازہ کاری: 6 ستمبر، 2025

کیا یہ ٹیوٹوریل کارآمد تھا؟