خفیہ اسٹیٹ کے لیے زیرو-نالج کا استعمال
بلاک چین پر کوئی راز نہیں ہوتے۔ بلاک چین پر پوسٹ کی گئی ہر چیز ہر کسی کے پڑھنے کے لیے کھلی ہوتی ہے۔ یہ ضروری ہے، کیونکہ بلاک چین کی بنیاد اس بات پر ہے کہ کوئی بھی اس کی تصدیق کر سکے۔ تاہم، گیمز اکثر خفیہ اسٹیٹ پر انحصار کرتی ہیں۔ مثال کے طور پر، minesweeper (opens in a new tab) گیم کا بالکل کوئی مطلب نہیں بنتا اگر آپ صرف بلاک چین ایکسپلورر پر جا کر نقشہ دیکھ سکیں۔
سب سے آسان حل یہ ہے کہ خفیہ اسٹیٹ کو رکھنے کے لیے ایک سرور جزو کا استعمال کیا جائے۔ تاہم، ہم بلاک چین کا استعمال اس لیے کرتے ہیں تاکہ گیم ڈیولپر کی طرف سے دھوکہ دہی کو روکا جا سکے۔ ہمیں سرور کے جزو کی ایمانداری کو یقینی بنانے کی ضرورت ہے۔ سرور اسٹیٹ کا ہیش فراہم کر سکتا ہے، اور زیرو-نالج پروفز کا استعمال کر کے یہ ثابت کر سکتا ہے کہ کسی اقدام کے نتیجے کا حساب لگانے کے لیے استعمال ہونے والی اسٹیٹ درست ہے۔
اس مضمون کو پڑھنے کے بعد آپ جان جائیں گے کہ اس قسم کا خفیہ اسٹیٹ رکھنے والا سرور، اسٹیٹ دکھانے کے لیے ایک کلائنٹ، اور ان دونوں کے درمیان رابطے کے لیے ایک آن چین جزو کیسے بنایا جائے۔ ہم جو اہم ٹولز استعمال کریں گے وہ یہ ہوں گے:
| ٹول | مقصد | تصدیق شدہ ورژن |
|---|---|---|
| Zokrates (opens in a new tab) | زیرو-نالج پروفز اور ان کی تصدیق | 1.1.9 |
| Typescript (opens in a new tab) | سرور اور کلائنٹ دونوں کے لیے پروگرامنگ زبان | 5.4.2 |
| Node (opens in a new tab) | سرور چلانا | 20.18.2 |
| Viem (opens in a new tab) | بلاک چین کے ساتھ رابطہ | 2.9.20 |
| MUD (opens in a new tab) | آن چین ڈیٹا مینجمنٹ | 2.0.12 |
| React (opens in a new tab) | کلائنٹ یوزر انٹرفیس | 18.2.0 |
| Vite (opens in a new tab) | کلائنٹ کوڈ پیش کرنا | 4.2.1 |
مائن سویپر کی مثال
Minesweeper (opens in a new tab) ایک ایسی گیم ہے جس میں مائن فیلڈ کے ساتھ ایک خفیہ نقشہ شامل ہوتا ہے۔ کھلاڑی کسی مخصوص جگہ پر کھدائی کرنے کا انتخاب کرتا ہے۔ اگر اس جگہ پر کوئی مائن (بارودی سرنگ) ہو، تو گیم ختم ہو جاتی ہے۔ بصورت دیگر، کھلاڑی کو اس جگہ کے ارد گرد آٹھ چوکور خانوں میں موجود مائنز کی تعداد مل جاتی ہے۔
یہ ایپلیکیشن MUD (opens in a new tab) کا استعمال کرتے ہوئے لکھی گئی ہے، جو ایک ایسا فریم ورک ہے جو ہمیں کی-ویلیو ڈیٹا بیس (opens in a new tab) کا استعمال کرتے ہوئے آن چین ڈیٹا اسٹور کرنے اور اس ڈیٹا کو آف چین اجزاء کے ساتھ خود بخود ہم آہنگ کرنے کی سہولت دیتا ہے۔ ہم آہنگی کے علاوہ، MUD رسائی کنٹرول فراہم کرنا آسان بناتا ہے، اور دوسرے صارفین کے لیے ہماری ایپلیکیشن کو بغیر اجازت کے توسیع (opens in a new tab) دینا آسان بناتا ہے۔
مائن سویپر کی مثال چلانا
مائن سویپر کی مثال چلانے کے لیے:
-
یقینی بنائیں کہ آپ نے ضروریات انسٹال کر لی ہیں (opens in a new tab): Node (opens in a new tab)، Foundry (opens in a new tab)،
git(opens in a new tab)،pnpm(opens in a new tab)، اورmprocs(opens in a new tab)۔ -
ریپوزٹری کو کلون کریں۔
1git clone https://github.com/qbzzt/20240901-secret-state.git -
پیکجز انسٹال کریں۔
1cd 20240901-secret-state/2pnpm install3npm install -g mprocsاگر Foundry کو
pnpm installکے حصے کے طور پر انسٹال کیا گیا تھا، تو آپ کو کمانڈ لائن شیل کو دوبارہ شروع کرنے کی ضرورت ہے۔ -
کنٹریکٹس کو مرتب (کمپائل) کریں
1cd packages/contracts2forge build3cd ../.. -
پروگرام شروع کریں (بشمول ایک anvil (opens in a new tab) بلاک چین) اور انتظار کریں۔
1mprocsنوٹ کریں کہ اسٹارٹ اپ میں کافی وقت لگتا ہے۔ پیش رفت دیکھنے کے لیے، پہلے نیچے والے تیر کا استعمال کرتے ہوئے contracts ٹیب پر اسکرول کریں تاکہ MUD کنٹریکٹس کو تعینات ہوتے ہوئے دیکھ سکیں۔ جب آپ کو Waiting for file changes… کا پیغام ملے، تو کنٹریکٹس تعینات ہو چکے ہیں اور مزید پیش رفت server ٹیب میں ہوگی۔ وہاں، آپ اس وقت تک انتظار کریں جب تک کہ آپ کو Verifier address: 0x.... کا پیغام نہ مل جائے۔
اگر یہ مرحلہ کامیاب ہو جاتا ہے، تو آپ کو
mprocsاسکرین نظر آئے گی، جس کے بائیں جانب مختلف پروسیسز اور دائیں جانب فی الحال منتخب کردہ پروسیس کا کنسول آؤٹ پٹ ہوگا۔اگر
mprocsکے ساتھ کوئی مسئلہ ہے، تو آپ چاروں پروسیسز کو دستی طور پر چلا سکتے ہیں، ہر ایک کو اس کی اپنی کمانڈ لائن ونڈو میں:-
Anvil
1cd packages/contracts2anvil --base-fee 0 --block-time 2 -
کنٹریکٹس
1cd packages/contracts2pnpm mud dev-contracts --rpc http://127.0.0.1:8545 -
سرور
1cd packages/server2pnpm start -
کلائنٹ
1cd packages/client2pnpm run dev
-
-
اب آپ کلائنٹ (opens in a new tab) پر براؤز کر سکتے ہیں، New Game پر کلک کریں، اور کھیلنا شروع کریں۔
ٹیبلز
ہمیں آن چین کئی ٹیبلز (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 اسٹوریج میں نہیں لکھی جاتی، یہ صرف ایونٹس کا استعمال کرتے ہوئے آف چین پڑھنے کے قابل ہے۔
ایگزیکیوشن اور ڈیٹا فلو
یہ فلوز کلائنٹ، آن چین جزو، اور سرور کے درمیان ایگزیکیوشن کو مربوط کرتے ہیں۔
ابتدا (Initialization)
جب آپ mprocs چلاتے ہیں، تو یہ اقدامات ہوتے ہیں:
-
mprocs(opens in a new tab) چار اجزاء چلاتا ہے:- Anvil (opens in a new tab)، جو ایک مقامی بلاک چین چلاتا ہے
- Contracts (opens in a new tab)، جو MUD کے لیے کنٹریکٹس کو مرتب (اگر ضرورت ہو) اور تعینات کرتا ہے
- Client (opens in a new tab)، جو ویب براؤزرز کو UI اور کلائنٹ کوڈ پیش کرنے کے لیے Vite (opens in a new tab) چلاتا ہے۔
- Server (opens in a new tab)، جو سرور کے افعال انجام دیتا ہے
-
contractsپیکج MUD کنٹریکٹس کو تعینات کرتا ہے اور پھرPostDeploy.s.solاسکرپٹ (opens in a new tab) چلاتا ہے۔ یہ اسکرپٹ کنفیگریشن سیٹ کرتا ہے۔ گٹ ہب کا کوڈ ایک 10x5 مائن فیلڈ کی وضاحت کرتا ہے جس میں آٹھ مائنز ہیں (opens in a new tab)۔ -
سرور (opens in a new tab) MUD سیٹ اپ کرنے (opens in a new tab) سے شروع ہوتا ہے۔ دیگر چیزوں کے علاوہ، یہ ڈیٹا کی ہم آہنگی کو فعال کرتا ہے، تاکہ متعلقہ ٹیبلز کی ایک کاپی سرور کی میموری میں موجود ہو۔
-
سرور ایک فنکشن کو سبسکرائب کرتا ہے جسے جب
Configurationٹیبل تبدیل ہو (opens in a new tab) تو عمل میں لایا جائے۔ یہ فنکشن (opens in a new tab)PostDeploy.s.solکے چلنے اور ٹیبل میں ترمیم کرنے کے بعد کال کیا جاتا ہے۔ -
جب سرور انیشلائزیشن فنکشن کے پاس کنفیگریشن آ جاتی ہے، تو یہ سرور کے زیرو-نالج حصے کو شروع کرنے کے لیے
zkFunctionsکو کال کرتا ہے (opens in a new tab)۔ یہ اس وقت تک نہیں ہو سکتا جب تک ہمیں کنفیگریشن نہ مل جائے کیونکہ زیرو-نالج فنکشنز میں مائن فیلڈ کی چوڑائی اور اونچائی کو مستقل (constants) کے طور پر رکھنا ہوتا ہے۔ -
سرور کا زیرو-نالج حصہ شروع ہونے کے بعد، اگلا قدم زیرو-نالج تصدیقی کنٹریکٹ کو بلاک چین پر تعینات کرنا (opens in a new tab) اور MUD میں تصدیق کنندہ کا ایڈریس سیٹ کرنا ہے۔
-
آخر میں، ہم اپ ڈیٹس کو سبسکرائب کرتے ہیں تاکہ ہم دیکھ سکیں کہ کب کوئی کھلاڑی نئی گیم شروع کرنے (opens in a new tab) یا موجودہ گیم میں کھدائی کرنے (opens in a new tab) کی درخواست کرتا ہے۔
نئی گیم
جب کھلاڑی نئی گیم کی درخواست کرتا ہے تو یہ ہوتا ہے۔
-
اگر اس کھلاڑی کے لیے کوئی گیم جاری نہیں ہے، یا کوئی گیم ہے لیکن اس کی gameId صفر ہے، تو کلائنٹ ایک نئی گیم کا بٹن (opens in a new tab) دکھاتا ہے۔ جب صارف اس بٹن کو دباتا ہے، تو React
newGameفنکشن چلاتا ہے (opens in a new tab)۔ -
newGame(opens in a new tab) ایکSystemکال ہے۔ MUD میں تمام کالزWorldکنٹریکٹ کے ذریعے روٹ کی جاتی ہیں، اور زیادہ تر معاملات میں آپ<namespace>__<function name>کو کال کرتے ہیں۔ اس صورت میں، کالapp__newGameکو کی جاتی ہے، جسے MUD پھرGameSystemمیںnewGame(opens in a new tab) پر روٹ کر دیتا ہے۔ -
آن چین فنکشن چیک کرتا ہے کہ کھلاڑی کی کوئی گیم جاری تو نہیں ہے، اور اگر نہیں ہے تو درخواست کو
PendingGameٹیبل میں شامل کر دیتا ہے (opens in a new tab)۔ -
سرور
PendingGameمیں تبدیلی کا پتہ لگاتا ہے اور سبسکرائب شدہ فنکشن چلاتا ہے (opens in a new tab)۔ یہ فنکشنnewGame(opens in a new tab) کو کال کرتا ہے، جو بدلے میںcreateGame(opens in a new tab) کو کال کرتا ہے۔ -
createGameسب سے پہلا کام یہ کرتا ہے کہ مناسب تعداد میں مائنز کے ساتھ ایک بے ترتیب نقشہ بناتا ہے (opens in a new tab)۔ پھر، یہ خالی بارڈرز کے ساتھ نقشہ بنانے کے لیےmakeMapBorders(opens in a new tab) کو کال کرتا ہے، جو Zokrates کے لیے ضروری ہے۔ آخر میں،createGameنقشے کا ہیش حاصل کرنے کے لیےcalculateMapHashکو کال کرتا ہے، جسے گیم ID کے طور پر استعمال کیا جاتا ہے۔ -
newGameفنکشن نئی گیم کوgamesInProgressمیں شامل کرتا ہے۔ -
سرور آخری کام یہ کرتا ہے کہ
app__newGameResponse(opens in a new tab) کو کال کرتا ہے، جو آن چین ہے۔ یہ فنکشن رسائی کنٹرول کو فعال کرنے کے لیے ایک مختلفSystem،ServerSystem(opens in a new tab) میں ہے۔ رسائی کنٹرول کی وضاحت MUD کنفیگریشن فائل (opens in a new tab)،mud.config.ts(opens in a new tab) میں کی گئی ہے۔رسائی کی فہرست صرف ایک ہی ایڈریس کو
Systemکو کال کرنے کی اجازت دیتی ہے۔ یہ سرور کے فنکشنز تک رسائی کو ایک ہی ایڈریس تک محدود کر دیتا ہے، تاکہ کوئی بھی سرور کا روپ نہ دھار سکے۔ -
آن چین جزو متعلقہ ٹیبلز کو اپ ڈیٹ کرتا ہے:
PlayerGameمیں گیم بنائیں۔GamePlayerمیں ریورس میپنگ سیٹ کریں۔PendingGameسے درخواست ہٹا دیں۔
-
سرور
PendingGameمیں تبدیلی کی نشاندہی کرتا ہے، لیکن کچھ نہیں کرتا کیونکہwantsGame(opens in a new tab) غلط (false) ہے۔ -
کلائنٹ پر
gameRecord(opens in a new tab) کو کھلاڑی کے ایڈریس کے لیےPlayerGameاندراج پر سیٹ کیا جاتا ہے۔ جبPlayerGameتبدیل ہوتا ہے، توgameRecordبھی تبدیل ہو جاتا ہے۔ -
اگر
gameRecordمیں کوئی ویلیو ہے، اور گیم جیتی یا ہاری نہیں گئی ہے، تو کلائنٹ نقشہ دکھاتا ہے (opens in a new tab)۔
کھدائی (Dig)
-
کھلاڑی نقشے کے سیل کے بٹن پر کلک کرتا ہے (opens in a new tab)، جو
digفنکشن (opens in a new tab) کو کال کرتا ہے۔ یہ فنکشن آن چینdig(opens in a new tab) کو کال کرتا ہے۔ -
آن چین جزو کئی سینیٹی چیکس انجام دیتا ہے (opens in a new tab)، اور اگر کامیاب ہو جائے تو کھدائی کی درخواست کو
PendingDig(opens in a new tab) میں شامل کر دیتا ہے۔ -
سرور
PendingDigمیں تبدیلی کا پتہ لگاتا ہے (opens in a new tab)۔ اگر یہ درست ہے (opens in a new tab)، تو یہ نتیجہ اور اس کے درست ہونے کا ثبوت دونوں تیار کرنے کے لیے زیرو-نالج کوڈ کو کال کرتا ہے (opens in a new tab) (جس کی وضاحت نیچے کی گئی ہے)۔ -
سرور (opens in a new tab) آن چین
digResponse(opens in a new tab) کو کال کرتا ہے۔ -
digResponseدو کام کرتا ہے۔ سب سے پہلے، یہ زیرو نالج پروف (opens in a new tab) چیک کرتا ہے۔ پھر، اگر ثبوت درست ثابت ہوتا ہے، تو یہ دراصل نتیجے پر کارروائی کرنے کے لیےprocessDigResult(opens in a new tab) کو کال کرتا ہے۔ -
processDigResultچیک کرتا ہے کہ آیا گیم ہاری (opens in a new tab) یا جیتی (opens in a new tab) گئی ہے، اور آن چین نقشہ،Mapکو اپ ڈیٹ کرتا ہے (opens in a new tab)۔ -
کلائنٹ خود بخود اپ ڈیٹس اٹھا لیتا ہے اور کھلاڑی کو دکھائے گئے نقشے کو اپ ڈیٹ کرتا ہے (opens in a new tab)، اور اگر قابل اطلاق ہو تو کھلاڑی کو بتاتا ہے کہ یہ جیت ہے یا ہار۔
Zokrates کا استعمال
اوپر بیان کیے گئے فلوز میں ہم نے زیرو-نالج حصوں کو چھوڑ دیا تھا، انہیں ایک بلیک باکس کے طور پر سمجھتے ہوئے۔ اب آئیے اسے کھولتے ہیں اور دیکھتے ہیں کہ وہ کوڈ کیسے لکھا گیا ہے۔
نقشے کی ہیشنگ
ہم Poseidon (opens in a new tab) کو لاگو کرنے کے لیے یہ جاوا اسکرپٹ کوڈ (opens 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) کی ایک سرنی (array) لیتا ہے اور ایک 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 فنکشن دو جہتی سرنیوں کے ساتھ کام نہیں کرتا ہے۔ اس لیے ہم پہلے map1d کا استعمال کرتے ہوئے نقشے کو 512-بائٹ سرنی میں فلیٹ کرتے ہیں۔ پہلے سے طے شدہ طور پر Zokrates متغیرات مستقل (constants) ہوتے ہیں، لیکن ہمیں ایک لوپ میں اس سرنی کو اقدار تفویض کرنے کی ضرورت ہے، اس لیے ہم اسے mut (opens 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 ];map1d سے چار field اقدار کی ایک سرنی بنانے کے لیے pack128۔ 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.ts (opens in a new tab) کہا جاتا ہے۔
1import { initialize as zokratesInitialize } from "zokrates-js"Zokrates JavaScript بائنڈنگز (opens in a new tab) درآمد کریں۔ ہمیں صرف initialize (opens in a new tab) فنکشن کی ضرورت ہے کیونکہ یہ ایک پرامس (promise) واپس کرتا ہے جو تمام Zokrates تعریفوں کو حل کرتا ہے۔
1export const zkFunctions = async (width: number, height: number) : Promise<any> => {خود Zokrates کی طرح، ہم بھی صرف ایک فنکشن برآمد کرتے ہیں، جو کہ asynchronous (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// زیرو نالج ویریفکیشن کے لیے کیز بنائیں۔2// پروڈکشن سسٹم پر آپ سیٹ اپ سیریمونی استعمال کرنا چاہیں گے۔3// (https://zokrates.github.io/toolbox/trusted_setup.html#initializing-a-phase-2-ceremony).4const keySetupResults = zokrates.setup(digCompiled.program, "")5const verifierKey = keySetupResults.vk6const proverKey = keySetupResults.pkپروڈکشن سسٹم پر ہم ایک زیادہ پیچیدہ سیٹ اپ تقریب (opens in a new tab) استعمال کر سکتے ہیں، لیکن یہ مظاہرے کے لیے کافی ہے۔ یہ کوئی مسئلہ نہیں ہے کہ صارفین پروور کی (prover key) جان سکتے ہیں - وہ اب بھی اسے چیزوں کو ثابت کرنے کے لیے استعمال نہیں کر سکتے جب تک کہ وہ سچ نہ ہوں۔ چونکہ ہم اینٹروپی (دوسرا پیرامیٹر، "") کی وضاحت کرتے ہیں، اس لیے نتائج ہمیشہ ایک جیسے ہی ہوں گے۔
نوٹ: Zokrates پروگراموں کی تالیف (compilation) اور کلید کی تخلیق سست عمل ہیں۔ انہیں ہر بار دہرانے کی ضرورت نہیں ہے، صرف اس وقت جب نقشے کا سائز تبدیل ہو۔ پروڈکشن سسٹم پر آپ انہیں ایک بار کریں گے، اور پھر آؤٹ پٹ کو محفوظ کر لیں گے۔ یہاں ایسا نہ کرنے کی واحد وجہ سادگی ہے۔
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}computeWitness (opens in a new tab) فنکشن دراصل Zokrates پروگرام چلاتا ہے۔ یہ دو فیلڈز کے ساتھ ایک اسٹرکچر واپس کرتا ہے: output، جو کہ JSON اسٹرنگ کے طور پر پروگرام کا آؤٹ پٹ ہے، اور witness، جو کہ نتیجے کا زیرو نالج پروف بنانے کے لیے درکار معلومات ہے۔ یہاں ہمیں صرف آؤٹ پٹ کی ضرورت ہے۔
آؤٹ پٹ "31337" کی شکل میں ایک اسٹرنگ ہے، جو کوٹیشن مارکس میں بند ایک اعشاریہ نمبر ہے۔ لیکن viem کے لیے ہمیں جو آؤٹ پٹ درکار ہے وہ 0x60A7 کی شکل میں ایک ہیکسا ڈیسیمل نمبر ہے۔ اس لیے ہم کوٹیشن مارکس ہٹانے کے لیے .slice(1,-1) استعمال کرتے ہیں اور پھر باقی اسٹرنگ، جو کہ ایک اعشاریہ نمبر ہے، کو BigInt (opens in a new tab) میں چلانے کے لیے BigInt استعمال کرتے ہیں۔ .toString(16) اس BigInt کو ہیکسا ڈیسیمل اسٹرنگ میں تبدیل کرتا ہے، اور "0x"+ ہیکسا ڈیسیمل نمبرز کے لیے مارکر کا اضافہ کرتا ہے۔
1// کھودیں اور نتیجے کا زیرو نالج پروف واپس کریں۔2// (سرور سائیڈ کوڈ)زیرو نالج پروف میں عوامی ان پٹس (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 proof7 }generateProof (opens 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}آخر میں، وہ سب کچھ واپس کریں جس کی دوسرے کوڈ کو ضرورت ہو سکتی ہے۔
سیکیورٹی ٹیسٹس
سیکیورٹی ٹیسٹس اہم ہیں کیونکہ فعالیت کا بگ بالآخر خود کو ظاہر کر دے گا۔ لیکن اگر ایپلیکیشن غیر محفوظ ہے، تو اس کے طویل عرصے تک پوشیدہ رہنے کا امکان ہے اس سے پہلے کہ یہ کسی کے دھوکہ دہی کرنے اور دوسروں کے وسائل لے کر فرار ہونے سے ظاہر ہو۔
اجازتیں (Permissions)
اس گیم میں ایک مراعات یافتہ ہستی ہے، سرور۔ یہ واحد صارف ہے جسے ServerSystem (opens in a new tab) میں فنکشنز کو کال کرنے کی اجازت ہے۔ ہم یہ تصدیق کرنے کے لیے cast (opens in a new tab) کا استعمال کر سکتے ہیں کہ اجازت یافتہ فنکشنز کو کالز کی اجازت صرف سرور اکاؤنٹ کے طور پر ہے۔
سرور کی پرائیویٹ کی setupNetwork.ts میں ہے (opens in a new tab)۔
-
اس کمپیوٹر پر جو
anvil(بلاک چین) چلاتا ہے، یہ ماحولیاتی متغیرات (environment variables) سیٹ کریں۔1WORLD_ADDRESS=0x8d8b6b8414e1e3dcfd4168561b9be6bd3bf6ec4b2UNAUTHORIZED_KEY=0x5de4111afa1a4b94908f83103eb1f1706367c2e68ca870fc3fb9a804cdab365a3AUTHORIZED_KEY=0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d -
تصدیق کنندہ کا ایڈریس غیر مجاز ایڈریس کے طور پر سیٹ کرنے کی کوشش کرنے کے لیے
castکا استعمال کریں۔1cast send $WORLD_ADDRESS 'app__setVerifier(address)' `cast address-zero` --private-key $UNAUTHORIZED_KEYنہ صرف
castناکامی کی اطلاع دیتا ہے، بلکہ آپ براؤزر پر گیم میں MUD Dev Tools کھول سکتے ہیں، Tables پر کلک کر سکتے ہیں، اور app__VerifierAddress کو منتخب کر سکتے ہیں۔ دیکھیں کہ ایڈریس صفر نہیں ہے۔ -
تصدیق کنندہ کا ایڈریس سرور کے ایڈریس کے طور پر سیٹ کریں۔
1cast send $WORLD_ADDRESS 'app__setVerifier(address)' `cast address-zero` --private-key $AUTHORIZED_KEYapp__VerifiedAddress میں ایڈریس اب صفر ہونا چاہیے۔
ایک ہی System میں تمام MUD فنکشنز ایک ہی رسائی کنٹرول سے گزرتے ہیں، اس لیے میں اس ٹیسٹ کو کافی سمجھتا ہوں۔ اگر آپ نہیں سمجھتے، تو آپ ServerSystem (opens in a new tab) میں دیگر فنکشنز چیک کر سکتے ہیں۔
زیرو-نالج کے غلط استعمال
Zokrates کی تصدیق کرنے کے لیے ریاضی اس ٹیوٹوریل (اور میری صلاحیتوں) کے دائرہ کار سے باہر ہے۔ تاہم، ہم زیرو-نالج کوڈ پر مختلف چیکس چلا سکتے ہیں تاکہ یہ تصدیق کی جا سکے کہ اگر یہ صحیح طریقے سے نہیں کیا گیا ہے تو یہ ناکام ہو جاتا ہے۔ ان تمام ٹیسٹوں کے لیے ہمیں zero-knowledge.ts (opens in a new tab) کو تبدیل کرنے اور پوری ایپلیکیشن کو دوبارہ شروع کرنے کی ضرورت ہوگی۔ سرور کے عمل کو دوبارہ شروع کرنا کافی نہیں ہے، کیونکہ یہ ایپلیکیشن کو ایک ناممکن حالت میں ڈال دیتا ہے (کھلاڑی کی ایک گیم جاری ہے، لیکن گیم اب سرور کو دستیاب نہیں ہے)۔
غلط جواب
سب سے آسان امکان زیرو-نالج پروف میں غلط جواب فراہم کرنا ہے۔ ایسا کرنے کے لیے، ہم zkDig کے اندر جاتے ہیں اور لائن 91 میں ترمیم کرتے ہیں (opens in a new tab):
1proof.inputs[3] = "0x" + "1".padStart(64, "0")اس کا مطلب ہے کہ ہم ہمیشہ دعویٰ کریں گے کہ ایک بم ہے، قطع نظر اس کے کہ صحیح جواب کیا ہے۔ اس ورژن کے ساتھ کھیلنے کی کوشش کریں، اور آپ کو pnpm dev اسکرین کے server ٹیب میں یہ ایرر نظر آئے گا:
1 cause: {2 code: 3,3 message: 'execution reverted: revert: Zero knowledge verification fail',4 data: '0x08c379a00000000000000000000000000000000000000000000000000000000000000020000000000000005000000000000000000000000000000000000000000000000205a65726f206b6e6f776c6564676520766572696669636174696f66e206661696c'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) ہے، لیکن زیادہ نہیں۔
زیرو-نالج کے ساتھ یہ مشکل ہے۔ تصدیق کنندہ میں کچھ مستقل (constants) شامل ہوتے ہیں اور ان پر کچھ حساب کتاب چلاتا ہے۔ اس سے آپ کو یہ نہیں پتہ چلتا کہ کیا ثابت کیا جا رہا ہے۔
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 پروگرامز کو دستیاب کرائیں، اور کم از کم کچھ صارفین انہیں مناسب تصدیقی کلید کے ساتھ خود مرتب کریں۔
ایسا کرنے کے لیے:
-
Zokrates پروگرام کے ساتھ ایک فائل،
dig.zokبنائیں۔ نیچے دیا گیا کوڈ یہ فرض کرتا ہے کہ آپ نے نقشے کا اصل سائز، 10x5 رکھا ہے۔1 import "utils/pack/bool/pack128.zok" as pack128;2 import "hashes/poseidon/poseidon.zok" as poseidon;34 def hashMap(bool[12][7] map) -> field {5 bool[512] mut map1d = [false; 512];6 u32 mut counter = 0;78 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 }1415 field[4] hashMe = [16 pack128(map1d[0..128]),17 pack128(map1d[128..256]),18 pack128(map1d[256..384]),19 pack128(map1d[384..512])20 ];2122 return poseidon(hashMe);23 }242526 // مقام (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 }3031 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 } -
Zokrates کوڈ کو مرتب کریں اور تصدیقی کلید بنائیں۔ تصدیقی کلید کو اسی اینٹروپی کے ساتھ بنانا ہوگا جو اصل سرور میں استعمال ہوئی تھی، اس صورت میں ایک خالی اسٹرنگ (opens in a new tab)۔
1zokrates compile --input dig.zok2zokrates setup -e "" -
خود سے Solidity تصدیق کنندہ بنائیں، اور تصدیق کریں کہ یہ عملی طور پر بلاک چین پر موجود تصدیق کنندہ سے مماثل ہے (سرور ایک تبصرہ شامل کرتا ہے، لیکن یہ اہم نہیں ہے)۔
1zokrates export-verifier2diff verifier.sol ~/20240901-secret-state/packages/contracts/src/verifier.sol
ڈیزائن کے فیصلے
کسی بھی کافی پیچیدہ ایپلیکیشن میں مسابقتی ڈیزائن کے اہداف ہوتے ہیں جن کے لیے سمجھوتہ (trade-offs) کی ضرورت ہوتی ہے۔ آئیے کچھ سمجھوتوں پر نظر ڈالتے ہیں اور دیکھتے ہیں کہ موجودہ حل دیگر اختیارات پر کیوں ترجیح رکھتا ہے۔
زیرو-نالج کیوں
مائن سویپر کے لیے آپ کو واقعی زیرو-نالج کی ضرورت نہیں ہے۔ سرور ہمیشہ نقشہ رکھ سکتا ہے، اور پھر گیم ختم ہونے پر اسے مکمل طور پر ظاہر کر سکتا ہے۔ پھر، گیم کے اختتام پر، اسمارٹ کنٹریکٹ نقشے کے ہیش کا حساب لگا سکتا ہے، تصدیق کر سکتا ہے کہ یہ مماثل ہے، اور اگر ایسا نہیں ہوتا ہے تو سرور کو جرمانہ کر سکتا ہے یا گیم کو مکمل طور پر نظر انداز کر سکتا ہے۔
میں نے یہ آسان حل استعمال نہیں کیا کیونکہ یہ صرف ان مختصر گیمز کے لیے کام کرتا ہے جن کی اختتامی حالت (end state) واضح طور پر متعین ہو۔ جب کوئی گیم ممکنہ طور پر لامحدود ہو (جیسا کہ خود مختار دنیاؤں (opens in a new tab) کے معاملے میں)، تو آپ کو ایک ایسے حل کی ضرورت ہوتی ہے جو اسٹیٹ کو ظاہر کیے بغیر اسے ثابت کرے۔
ایک ٹیوٹوریل کے طور پر اس مضمون کو ایک مختصر گیم کی ضرورت تھی جسے سمجھنا آسان ہو، لیکن یہ تکنیک طویل گیمز کے لیے سب سے زیادہ مفید ہے۔
Zokrates کیوں؟
Zokrates (opens in a new tab) دستیاب واحد زیرو-نالج لائبریری نہیں ہے، لیکن یہ ایک عام، امپیریٹو (imperative) (opens in a new tab) پروگرامنگ زبان سے ملتی جلتی ہے اور بولین متغیرات کو سپورٹ کرتی ہے۔
اپنی ایپلیکیشن کے لیے، مختلف ضروریات کے ساتھ، آپ Circum (opens in a new tab) یا Cairo (opens in a new tab) استعمال کرنے کو ترجیح دے سکتے ہیں۔
Zokrates کو کب مرتب (کمپائل) کیا جائے
اس پروگرام میں ہم Zokrates پروگراموں کو ہر بار سرور شروع ہونے پر (opens in a new tab) مرتب کرتے ہیں۔ یہ واضح طور پر وسائل کا ضیاع ہے، لیکن یہ ایک ٹیوٹوریل ہے، جسے سادگی کے لیے بہتر بنایا گیا ہے۔
اگر میں پروڈکشن لیول کی ایپلیکیشن لکھ رہا ہوتا، تو میں چیک کرتا کہ آیا میرے پاس اس مائن فیلڈ سائز پر مرتب شدہ Zokrates پروگراموں والی کوئی فائل ہے، اور اگر ایسا ہے تو اسے استعمال کرتا۔ آن چین تصدیق کنندہ کنٹریکٹ تعینات کرنے کے لیے بھی یہی بات درست ہے۔
تصدیق کنندہ اور پروور کیز بنانا
کلید کی تخلیق (opens in a new tab) ایک اور خالص حساب کتاب ہے جسے دیے گئے مائن فیلڈ سائز کے لیے ایک سے زیادہ بار کرنے کی ضرورت نہیں ہے۔ ایک بار پھر، یہ سادگی کی خاطر صرف ایک بار کیا جاتا ہے۔
اس کے علاوہ، ہم ایک سیٹ اپ تقریب (opens in a new tab) استعمال کر سکتے ہیں۔ سیٹ اپ تقریب کا فائدہ یہ ہے کہ آپ کو زیرو-نالج پروف پر دھوکہ دینے کے لیے ہر شریک سے اینٹروپی یا کچھ درمیانی نتیجہ درکار ہوتا ہے۔ اگر کم از کم ایک تقریب کا شریک ایماندار ہے اور اس معلومات کو حذف کر دیتا ہے، تو زیرو-نالج پروفز بعض حملوں سے محفوظ رہتے ہیں۔ تاہم، اس بات کی تصدیق کرنے کا کوئی طریقہ کار نہیں ہے کہ معلومات کو ہر جگہ سے حذف کر دیا گیا ہے۔ اگر زیرو-نالج پروفز انتہائی اہم ہیں، تو آپ سیٹ اپ تقریب میں حصہ لینا چاہیں گے۔
یہاں ہم perpetual powers of tau (opens in a new tab) پر انحصار کرتے ہیں، جس میں درجنوں شرکاء تھے۔ یہ شاید کافی محفوظ ہے، اور بہت آسان ہے۔ ہم کلید کی تخلیق کے دوران اینٹروپی بھی شامل نہیں کرتے ہیں، جس سے صارفین کے لیے زیرو-نالج کنفیگریشن کی تصدیق کرنا آسان ہو جاتا ہے۔
تصدیق کہاں کی جائے
ہم زیرو-نالج پروفز کی تصدیق یا تو آن چین (جس پر گیس خرچ ہوتی ہے) یا کلائنٹ میں (verify (opens 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 میں دو جہتی سرنی کو فلیٹ کریں۔ یہ سب سے آسان آپشن ہے، اس لیے میں نے اسے منتخب کیا۔
نقشے کہاں محفوظ کیے جائیں
اس ایپلیکیشن میں gamesInProgress (opens in a new tab) میموری میں محض ایک متغیر ہے۔ اس کا مطلب ہے کہ اگر آپ کا سرور بند ہو جاتا ہے اور اسے دوبارہ شروع کرنے کی ضرورت ہوتی ہے، تو اس کی محفوظ کردہ تمام معلومات ضائع ہو جاتی ہیں۔ نہ صرف کھلاڑی اپنی گیم جاری رکھنے سے قاصر رہتے ہیں، بلکہ وہ نئی گیم بھی شروع نہیں کر سکتے کیونکہ آن چین جزو سمجھتا ہے کہ ان کی گیم ابھی بھی جاری ہے۔
یہ واضح طور پر پروڈکشن سسٹم کے لیے برا ڈیزائن ہے، جس میں آپ اس معلومات کو ڈیٹا بیس میں محفوظ کریں گے۔ یہاں متغیر استعمال کرنے کی واحد وجہ یہ ہے کہ یہ ایک ٹیوٹوریل ہے اور سادگی بنیادی غور طلب بات ہے۔
نتیجہ: کن حالات میں یہ مناسب تکنیک ہے؟
تو، اب آپ جانتے ہیں کہ ایک ایسے سرور کے ساتھ گیم کیسے لکھی جائے جو خفیہ اسٹیٹ کو محفوظ کرتا ہے جس کا تعلق آن چین سے نہیں ہے۔ لیکن آپ کو کن صورتوں میں ایسا کرنا چاہیے؟ دو اہم غور طلب باتیں ہیں۔
-
طویل چلنے والی گیم: جیسا کہ اوپر ذکر کیا گیا ہے، ایک مختصر گیم میں آپ گیم ختم ہونے کے بعد اسٹیٹ کو شائع کر سکتے ہیں اور پھر ہر چیز کی تصدیق کروا سکتے ہیں۔ لیکن یہ اس وقت کوئی آپشن نہیں ہوتا جب گیم طویل یا غیر معینہ وقت لیتی ہو، اور اسٹیٹ کو خفیہ رکھنے کی ضرورت ہو۔
-
کچھ مرکزیت قابل قبول ہے: زیرو-نالج پروفز سالمیت کی تصدیق کر سکتے ہیں، کہ کوئی ہستی نتائج کو جعلی نہیں بنا رہی ہے۔ وہ جو نہیں کر سکتے وہ یہ یقینی بنانا ہے کہ ہستی اب بھی دستیاب ہوگی اور پیغامات کا جواب دے گی۔ ایسی صورتحال میں جہاں دستیابی کو بھی غیر مرکزی بنانے کی ضرورت ہو، زیرو-نالج پروفز کافی حل نہیں ہیں، اور آپ کو ملٹی پارٹی کمپیوٹیشن (opens in a new tab) کی ضرورت ہوتی ہے۔
میرے مزید کام کے لیے یہاں دیکھیں (opens in a new tab)۔
اعترافات
- الوارو الونسو نے اس مضمون کا مسودہ پڑھا اور Zokrates کے بارے میں میری کچھ غلط فہمیوں کو دور کیا۔
باقی ماندہ کوئی بھی غلطی میری ذمہ داری ہے۔
صفحہ کی آخری اپ ڈیٹ: ۳ مارچ، ۲۰۲۶
