توضیح‌نامه‌ی ۰۳

راستی‌آزمایی روی زنجیره: ۲۵۶ بایت و یک جفت‌سازی چه می‌خرند

معما

قرارداد هوشمندی که آرای ما را می‌پذیرد روی راریمو L2 زندگی می‌کند. باید در یک تراکنش واحد تصمیم بگیرد آیا یک کاربر:

…همه‌ی این‌ها بدون این‌که هرگز سند را ببیند.

رویکرد ساده‌انگارانه — بازمحاسبه‌ی کل بررسی امضای گذرنامه درون قرارداد هوشمند — ناممکن است. این کار نیاز به اجرای میلیون‌ها عمل حسابی روی زنجیره دارد، با هزینه‌ی صدها دلار به ازای هر رای.

به‌جای آن، قرارداد یک بررسی کوچک انجام می‌دهد که جایگزین کل محاسبه می‌شود. آن بررسی کوچک همان چیزی است که هویت ZK را عملی می‌کند.

کاربر چه چیزی آپلود می‌کند

تلفن کار سنگین را انجام می‌دهد. سه چیز تولید می‌کند:

شیءاندازهاز کجا می‌آید
اثبات~ ۲۵۶ بایتخروجی اثبات‌گر Groth16 پس از اجرای مدار روی ورودی‌های خصوصی
سیگنال‌های عمومی~ ۲۴ عدد، ~ ۷۶۸ بایتخروجی‌های اعلام‌شده‌ی مدار: nullifier، ریشه‌ی ICAO، شناسه‌ی رویداد، تاریخ‌ها، تابعیت و غیره
شناسه‌ی مداریک رشته‌ی کوتاهبه قرارداد می‌گوید از کدام کلید راستی‌آزمایی استفاده کند (passport_rsa_2048_sha256_e65537، inid_rsa_2048، …)

این تمام چیزی است که زنجیره از کاربر می‌بیند. نه نام، نه شماره‌ی گذرنامه، نه امضا. فقط یک اثبات + یک فهرست با اندازه‌ی ثابت از اعداد + یک برچسب.

قرارداد چه می‌کند — در پنج خط

function verify(circuitID, proof, publicSignals) {
    VerifyingKey vk = circuitRegistry[circuitID];     // lookup
    require(publicSignals.icaoRoot == currentRoot);   // sanity check
    require(!nullifierUsed[publicSignals.nullifier]); // anti-replay
    require(groth16Verify(vk, proof, publicSignals)); // THE math step
    nullifierUsed[publicSignals.nullifier] = true;
}

همه چیز بایگانی است جز خط چهارم. آن خط چهارم همان دلیلی است که هر چیزی در این سیستم کار می‌کند.

خط چهارم: groth16Verify واقعن چه می‌کند

یک اثبات Groth16 از سه نقطه‌ی منحنی بیضوی تشکیل شده:

کلید راستی‌آزمایی (یک‌بار به ازای هر مدار متعهد می‌شود) به قرارداد می‌دهد:

قرارداد یک ترکیب خطی روی سیگنال‌های عمومی محاسبه می‌کند:

ICₚ = IC₀ + s₁·IC₁ + s₂·IC₂ + … + sₙ·ICₙ

…و سپس یک معادله‌ی واحد را بررسی می‌کند که شامل یک جفت‌سازی است — یک عمل خاص روی نقاط منحنی بیضوی که با e(·, ·) نوشته می‌شود:

e(A, B) == e(α, β) · e(ICₚ, γ) · e(C, δ)

اگر این معادله برقرار باشد، اثبات معتبر است. اگر نباشد، نیست. هیچ حالت میانی نیست، و هیچ چیز دیگری برای بررسی نیست.

این تک‌معادله از نظر ریاضی معادل با راستی‌آزمایی هر ضرب و جمع است که اثبات‌گر ادعا کرده انجام داده. نسبت فشرده‌سازی شگفت‌انگیز است: میلیون‌ها قید روی سمت اثبات‌گر در یک بررسی جفت‌سازی روی سمت راستی‌آزما فرومی‌ریزد. این قلب «succinct» در zk-SNARK است.

چرا EVM می‌تواند این را در میلی‌ثانیه انجام دهد

زنجیره‌های سازگار با اتریوم یک نشانی ویژه — 0x08 — دارند که عمل جفت‌سازی BN254 را در کد بومی انجام می‌دهد، نه در EVM تفسیری. این یک قرارداد precompiled نامیده می‌شود. فراخوانی آن مقدار ثابتی gas می‌خواهد (~ ۱۲۰k برای جفت‌سازی + ~ ۶k به ازای هر سیگنال عمومی). روی راریمو L2 با ~ ۰٫۰۰۱ دلار به ازای هر تراکنش، این به‌خوبی زیر یک سنت به ازای هر راستی‌آزمایی است.

بدون precompile، راستی‌آزمایی ZK روی زنجیره از نظر اقتصادی شدنی نبود. راریمو L2، مانند اتریوم و هر L2 مهم، این را دارد. این همان عنصر اولیه‌ای است که میکسرهای سبک tornado، رول‌آپ‌های Aztec و زنجیره‌های zk-EVM را قدرت می‌دهد؛ ما در حال استفاده‌ی دوباره از دهه‌ها مهندسی رمزنگاری هستیم، نه اختراع آن.

عدم‌تقارن: اثبات‌گر در مقابل راستی‌آزما

اعداد زیر برای مدار ثبت‌نام ما (~ ۵ میلیون قید) معمول‌اند:

گامکجا اجرا می‌شودزمانهزینه
تولید witnessتلفن (ماژول بومی)~ ۲۰–۶۰ ثانیهباتری
تولید اثباتتلفن (rapidsnark-wrp)~ ۳۰–۹۰ ثانیهباتری
فرستادن تراکنشرله~ ۱ ثانیه~ ۰٫۰۰۱ دلار gas RMO
راستی‌آزمایی روی زنجیرهقرارداد هوشمند~ ۳ میلی‌ثانیه~ ۱۲۰k gas

این عدم‌تقارن کل هدف است. تلفن کاری متناسب با مدار انجام می‌دهد (میلیون‌ها عمل)؛ زنجیره کاری با زمان ثابت بدون توجه به پیچیدگی مدار. یک بررسی گذرنامه با ۵ میلیون قید و یک بررسی با ۵ میلیارد قید، هر دو در حدود همان ۳ میلی‌ثانیه راستی‌آزمایی می‌شوند.

چرا به ثبت مدار نیاز داریم

یک کلید راستی‌آزمایی Groth16 فقط برای دقیقن یک مدار کار می‌کند. اسناد و الگوریتم‌های امضای مختلف به مدارهای مختلف نیاز دارند:

کلاس سندشناسه‌ی مدارکلید راستی‌آزمایی
گذرنامه‌ی بیومتریک ایرانی (RSA 2048، SHA-256، e=65537)passport_rsa_2048_sha256_e65537vk1.json
گذرنامه‌ی بیومتریک ایرانی (RSA 3072، SHA-1، e=58333)passport_rsa_2048_sha1_e58333vk2.json
کارت ملی هوشمند ایرانیinid_rsa_2048vk3.json
گذرنامه‌ی آلمانی (ECDSA brainpoolP384r1) — برنامه‌ریزی‌شدهpassport_ecdsa_p384_sha384(M7)

هر شناسه‌ی مدار به یک کلید راستی‌آزمایی متمایز نگاشت می‌شود. sso-svc ما یک ثبت از این کلیدها نگه می‌دارد؛ کیف پول به سرویس می‌گوید از کدام مدار استفاده کرده، و سرویس کلید درست را انتخاب می‌کند. افزودن یک کلاس سند جدید یک تغییر پیکربندی است، نه تغییر کد.

سیگنال‌های عمومی چه چیزی را افشا می‌کنند — و چه نمی‌کنند

قرارداد سیگنال‌های عمومی را به‌عنوان اعداد با موقعیت ثابت می‌خواند. برای مدار query INID اینها ۲۳ مقدارند؛ برای مدار گذرنامه، ۲۴. نگاشت مشخص برای یک ثبت‌نام INID:

اندیسمعناحساس؟
۰Nullifier (مختص این رویداد)نه — قابل‌پیوند به هویت نیست
۵شناسه‌ی رویداد (کدام پیشنهاد)نه — به‌هر‌حال عمومی است
۶کد تابعیت (مثلن IR)نه — فقط در سطح کشور
۸هش شماره‌ی شخصی (فقط INID)نه — هش‌شده؛ هیچ preimage روی زنجیره نیست
۱۰زمان‌مهر تولید هویتنه — ساعت دیواری
۱۲سلکتور (کدام ادعاها منتشر شوند)نه — طراحانه منتشر می‌شود
۱۳تاریخ فعلینه — ساعت دیواری
۲۱نتیجه‌ی بررسی تابعیت (ایران؟ بله/خیر)نه — بولی
۲۲ریشه‌ی RegistrationSMTنه — وضعیت زنجیره

هیچ فیلدی برای نام، شماره‌ی سند، هش عکس، تاریخ تولد یا تاریخ انقضا وجود ندارد. آن مقادیر در اثبات شرکت می‌کنند اما از سوی مدار مصرف می‌شوند — هرگز در سیگنال‌های عمومی یا روی زنجیره ظاهر نمی‌شوند. اثبات‌های دانش‌صفر را ببینید برای این‌که چرا این یک تضمین ریاضی است، نه یک خط‌مشی.

Nullifierها: قرارداد چگونه «یک رای به ازای هر شخص» را اعمال می‌کند

یک nullifier قطعی است: همان راز + همان event_id همیشه همان nullifier را تولید می‌کند. اما همچنین یک‌طرفه است: با داشتن nullifier، هیچ‌کس نمی‌تواند راز را بازیابی کند یا آن را به هویت کاربر پیوند بزند.

قرارداد به‌سادگی هر nullifier را که دیده ثبت می‌کند. یک اثبات دوم از همان شخص روی همان پیشنهاد همان nullifier را تولید می‌کند؛ قرارداد آن را رد می‌کند.

در رویدادهای مختلف، همان شخص nullifierهای متفاوت تولید می‌کند — طراحانه. این همان چیزی است که سیستم را بین رویدادها ناشناس می‌کند: هیچ‌کس نمی‌تواند رای شما به پیشنهاد #۴۲ را به رای شما به پیشنهاد #۴۳ پیوند بزند، با وجود این‌که هر دو معتبرند.

چه چیزی هنوز می‌تواند روی زنجیره خراب شود

فهرست صادقانه:

حالت شکستچه می‌کنیم درباره‌اش
بارگذاری کلید راستی‌آزمایی اشتباهپیکربندی ثبت مدار بازنگری و پین می‌شود؛ آزمون‌ها هر VK را پیش از استقرار راستی‌آزمایی می‌کنند.
currentRoot منسوخ (فورک زنجیره، انحراف اسنپ‌شات)ریشه‌ی ICAO را در StateKeeper خود نگه می‌داریم؛ M6 ما را تنها ادمین می‌کند. پشته‌ی حاکمیتی و M6 را ببینید.
حمله‌ی بازپخشنگاشت nullifier از آن درون یک رویداد جلوگیری می‌کند.
باگ precompile جفت‌سازی در سطح زنجیرهخطر به‌ارث‌رسیده از اتریوم — برای BN254 در تولید رخ نداده.
ارتقای قرارداد هوشمند با درب پشتیبا انتقال به مالتی‌سیگ Gnosis Safe پیش از راه‌اندازی عمومی کاهش می‌یابد.

هیچ‌کدام از این‌ها شکست رمزنگارانهی خود اثبات نیست. همه خطرات عملیاتی اجرای قرارداد هستند، و با فرایند و حاکمیت قابل رفع‌اند — که موضوع M6 است.

واژه‌نامه

اصطلاحمعنا
Groth16یک سیستم اثبات zk-SNARK مشخص، ۲۰۱۶. کوچک‌ترین راستی‌آزما، گسترده‌پذیرفته‌شده.
BN254منحنی بیضوی که اثبات‌های ما روی آن زندگی می‌کنند. سازگار با جفت‌سازی، در EVM precompiled.
Precompileیک عمل اتریومی به‌صورت کد بومی در یک نشانی رزرو‌شده (0x08 = جفت‌سازی). ارزان، سریع.
کلید راستی‌آزمایی (VK)فایل کوچک (~ چند کیلوبایت) که قرارداد برای بررسی اثبات‌های یک مدار مشخص بهره می‌برد.
سیگنال‌های عمومیخروجی‌های اعلام‌شده‌ی مدار، روی زنجیره مشاهده‌شدنی. هرگز شامل داده‌ی خام سند نیستند.
جفت‌سازییک تابع دوخطی e(P, Q) روی نقاط منحنی بیضوی؛ تنها عمل «جادویی» در راستی‌آزمایی Groth16.
Witnessمقادیر میانی سمت تلفن؛ هرگز آپلود نمی‌شوند.
Nullifierمقدار قطعی ضد-بازپخش هویت‌پوشاننده، به ازای هر رویداد.

بعدی

زنجیره‌ی اعتماد گذرنامه — داده‌ی موجود در اثبات واقعن از کجا می‌آید، چرا به آن اعتماد می‌کنیم، و در برابر چه چیزی نمی‌توانیم محافظت کنیم اگر کلید صادرکننده به خطر بیفتد.