ZK-फ्रेंडली हैश फंक्शंस वे हैश फंक्शंस हैं जिन्हें पारंपरिक क्रिप्टोग्राफ़िक हैश फंक्शंस की तुलना में प्रूव (prove) और वेरीफाई (verify) करने के लिए बहुत कम कंस्ट्रेंट्स (constraints) की आवश्यकता होती है।
SHA256 या keccak256 जैसे हैश फंक्शंस बिटवाइज़ ऑपरेटरों (bitwise operators) जैसे XOR या बिट रोटेशन (bit rotation) का भारी उपयोग करते हैं। XOR या बिट रोटेशन के सही निष्पादन (execution) को प्रूव करने के लिए संख्या को 32 बिट्स के रूप में दर्शाने की आवश्यकता होती है, जिसके लिए 32 अलग-अलग सिग्नल्स (signals) की आवश्यकता होती है। चूँकि पारंपरिक हैश फंक्शंस का डिफ़ॉल्ट वर्ड साइज़ (word size) 32 बिट्स होता है, इसलिए इस डेटा प्रकार पर ऑपरेशन्स के लिए 32 सिग्नल्स की आवश्यकता होती है।
एक ZK-फ्रेंडली हैश फंक्शन नेटिव फील्ड एलिमेंट (native field element) को डिफ़ॉल्ट डेटा प्रकार के रूप में उपयोग करता है और उन ऑपरेशन्स से बचता है जो फील्ड एलिमेंट को बिट्स में विघटित (decompose) करते हैं। फील्ड एलिमेंट्स पर नेटिव ऑपरेशन्स केवल जोड़ (addition) और गुणा (multiplication) हैं, इसलिए ZK-फ्रेंडली हैश फंक्शन ऑपरेशन्स में केवल मॉड्यूलर जोड़ और गुणा का उपयोग किया जाना चाहिए।
हैश फंक्शन की वे विशेषताएँ जिनकी हमें परवाह है, वे हैं:
- Preimage resistance — हैश का आउटपुट दिए जाने पर, इनपुट की गणना करना असंभव (infeasible) होना चाहिए।
- Collision resistance — इनपुट-आउटपुट पेयर (pair) दिए जाने पर, ऐसा दूसरा इनपुट खोजना कम्प्यूटेशनल रूप से असंभव होना चाहिए जिसका परिणाम समान आउटपुट हो।
- Pseudorandomness — आउटपुट रैंडम (random) प्रतीत होना चाहिए — इनपुट और आउटपुट के बीच कोई सांख्यिकीय (statistical) संबंध नहीं होना चाहिए।
हम उच्च स्तर (high level) पर वर्णन करेंगे कि दो सबसे लोकप्रिय ZK-फ्रेंडली हैश फंक्शंस, Minimal Multiplicative Complexity (MiMC) और Poseidon, कैसे काम करते हैं। हालाँकि, वे सुरक्षित क्यों हैं इसका विश्लेषण इस लेख के दायरे से बाहर है। वास्तव में, इन हैश फंक्शंस की सुरक्षा – सबसे अधिक बैटल-टेस्टेड (battle-tested) होने के बावजूद — अभी भी कुछ हद तक एक खुला सवाल है।
MiMC
इस हैश फंक्शन का इनपुट एक सिंगल फील्ड एलिमेंट है और आउटपुट भी एक सिंगल फील्ड एलिमेंट है।
MiMC 91 रैंडम स्थिरांकों (random constants) को इनिशियलाइज़ (initialize) करता है और उन्हें एक ऐरे C में स्टोर करता है। इनकी गणना नियतात्मक (deterministic) और पारदर्शी तरीके से की जा सकती है, जैसे कि स्ट्रिंग “MiMC” को लेना और इसे SHA256 के साथ 91 बार हैश करना, और प्रत्येक हैश रैंडम संख्या के रूप में कार्य करता है। ये स्थिरांक (constants) फिक्स्ड, पब्लिक और सभी पार्टियों को ज्ञात होते हैं। पारंपरिक रूप से, C[0] = 0। फिर, MiMC एक फील्ड एलिमेंट को अपने इनपुट के रूप में लेता है और इटेरेटिव (iterative) रूप से गणना करता है:
जहाँ कोई फिक्स्ड घातांक (exponent) है, जो अक्सर 3 या 7 होता है। एक स्थिरांक है जिसे 0 पर सेट किया जाता है (हम एक इनपुट केवल उसे शून्य पर सेट करने के लिए क्यों प्रदान करते हैं, इस पर बाद में चर्चा की जाएगी)।
MiMC के सुरक्षित होने के लिए, यह आवश्यक है कि gcd(e, p - 1) == 1 हो, जहाँ gcd महत्तम समापवर्तक (greatest common divisor) है। Circom के डिफ़ॉल्ट फील्ड साइज़ के लिए, gcd(3, p - 1) ≠ 1 है लेकिन gcd(7, p - 1) = 1 है।
from math import gcd
p = 21888242871839275222246405745257275088548364400416034343698204186575808495617
gcd(3, p - 1)
# 3
gcd(7, p - 1)
# 1
इसलिए, Circomlib MiMC7 को एक हैश के रूप में प्रदान करता है (जहाँ 7 घातांक है)। हालांकि, अन्य फील्ड साइज़ का उपयोग करने वाली लाइब्रेरीज़ e = 3 का उपयोग कर सकती हैं (ऐसा क्यों है यह समझने के लिए, कृपया लेख के अंत में लिंक किए गए रिसोर्स को देखें)।
नीचे सिंगल इनपुट के साथ MiMC7 का उपयोग करने का एक न्यूनतम (minimal) उदाहरण दिया गया है:
include "circomlib/mimc.circom";
template ExampleMiMC() {
signal input a;
signal output out;
component hash = MiMC7(91);
hash.x_in <== a;
hash.k <== 0;
out <== hash.out;
}
यदि हम हैश में कई फील्ड एलिमेंट्स पास करना चाहते हैं और एक सिंगल फील्ड एलिमेंट आउटपुट करना चाहते हैं, तो हम निम्नलिखित दृष्टिकोण (approach) का उपयोग करते हैं:
- हम पहले इनपुट एलिमेंट को हैश करते हैं।
- उस हैश का आउटपुट अगले हैश के
kका मान बन जाता है। - अगले हैश का इनपुट, इनपुट का अगला भाग होता है।
इसे इस प्रकार से विज़ुअलाइज़ (visualize) किया जा सकता है:

MultiMiMC7 टेम्पलेट हमारे लिए यह काम पूरा करता है:
include "circomlib/mimc.circom";
template ExampleMultiMiMC(n) {
signal input in[n];
signal output out;
component hash = MultiMiMC7(n, 91);
for (var i = 0; i < n; i++) {
hash.in[i] <== in[i];
}
hash.k <== 0;
out <== hash.out;
}
Poseidon
Poseidon, MiMC के समान ही है, सिवाय इसके कि यह मैट्रिक्स गुणा (matrix multiplication) का एक स्टेप जोड़ता है। अर्थात, यदि इनपुट एक सिंगल एलिमेंट है, तो इसे [0, input] तक विस्तारित (expand) किया जाता है, और इस वेक्टर को सावधानीपूर्वक ट्यून किए गए (carefully tuned) 2 x 2 मैट्रिसेस की एक श्रृंखला से गुणा किया जाता है। “सावधानीपूर्वक ट्यूनिंग” का अर्थ यहाँ यह है कि इसमें एक निश्चित क्रिप्टोग्राफ़िक विशेषता है जिस पर हम यहाँ विस्तार से चर्चा नहीं करेंगे।
इसलिए, एक सिंगल एलिमेंट के जोड़ (additions) और घातांकों (exponentiations) की एक श्रृंखला से गुजरने के बजाय (जैसा कि MiMC में होता है), Poseidon में एक वेक्टर एलिमेंट-वाइज़ (element-wise) जोड़, मैट्रिक्स गुणा (जो उसी डायमेंशन का एक वेक्टर बनाता है) और घातांकों की एक श्रृंखला से होकर गुजरता है।
हालाँकि मैट्रिक्स गुणा अधिक कंस्ट्रेंट्स जोड़ता है, यह हैश में अधिक “फैलाव” (dispersion) पैदा करता है, इसलिए Poseidon को MiMC जितने राउंड्स (rounds) की आवश्यकता नहीं होती है।
नीचे सिंगल इनपुट के साथ Poseidon का उपयोग करने का एक न्यूनतम उदाहरण दिया गया है:
include "circomlib/poseidon.circom";
template Example(n) {
signal input in[n];
signal output out;
component hash = Poseidon(n);
for (var i = 0; i < n; i++) {
hash.inputs[0] <== in[i];
}
out <== hash.out;
}
component main = Example(1);
/* INPUT = {
"in": [5]
} */
एक से अधिक इनपुट सिग्नल का उपयोग करने के लिए, हम Poseidon के लिए टेम्पलेट आर्ग्यूमेंट (template argument) n को वांछित मान (desired value) में बदलते हैं और सही आकार का ऐरे प्रदान करते हैं।
Poseidon vs MiMC परफॉरमेंस
सिंगल इनपुट लेने वाले हैशेज़ के लिए, MiMC के अंतर्निहित (underlying) R1CS में 364 कंस्ट्रेंट्स होते हैं:

जबकि Poseidon में 213 होते हैं:

अब, आइए दो इनपुट होने पर उत्पन्न होने वाले कंस्ट्रेंट्स की संख्या की तुलना करें।
MiMC7 के लिए, दो इनपुट के साथ कंस्ट्रेंट्स की संख्या दोगुनी हो जाती है:

लेकिन Poseidon के लिए, कंस्ट्रेंट्स की संख्या मुश्किल से ही बढ़ती है:

इस बेहतर परफॉरमेंस का प्राथमिक कारण यह है कि, MiMC के विपरीत, Poseidon इनपुट में प्रत्येक फील्ड एलिमेंट के लिए हैश को दोबारा नहीं करता है। इसके बजाय, एक बड़े इनपुट को हैश करने के लिए, यह इनपुट वेक्टर के साथ गुणा करने के लिए एक बड़े मैट्रिक्स का उपयोग करता है। Circomlib का Poseidon 17 फील्ड एलिमेंट्स से बड़े इनपुट का समर्थन नहीं करता है। यदि हमें एक बड़े डेटासेट को हैश करने की आवश्यकता है, तो यह समस्याग्रस्त हो सकता है। हालाँकि, यदि हम एक Merkle tree बना रहे हैं, तो हमें केवल दो इनपुट को हैश करने की आवश्यकता है।
और भी अधिक सुरक्षा की तलाश
जैसा कि पहले बताया गया है, Poseidon और MiMC की सुरक्षा विशेषताओं को SHA-256 जैसे अत्यधिक बैटल-हार्डन्ड (battle-hardened) हैश फंक्शंस जितना अच्छी तरह से नहीं समझा गया है।
एक ऐसा ZK-फ्रेंडली हैश फंक्शन मौजूद है जिसमें Poseidon और MiMC की तुलना में और भी मजबूत सुरक्षा मान्यताएँ (security assumptions) हैं, जो एलिप्टिक कर्व्स (elliptic curves) पर आधारित है। एलिप्टिक कर्व पॉइंट्स के डिस्क्रीट लॉग (discrete log) की गणना करना क्वांटम कंप्यूटर के बिना असंभव माना जाता है। Pedersen हैश एक ZK-फ्रेंडली हैश फंक्शन है जो हैश की गणना करने के लिए कोर सबरूटीन (core subroutine) के रूप में एलिप्टिक कर्व ऑपरेशन्स का उपयोग करता है। एक सर्किट में एलिप्टिक कर्व अरिथमेटिक (elliptic curve arithmetic) करना Poseidon या MiMC जितना कुशल (efficient) नहीं होगा, लेकिन यह पारंपरिक क्रिप्टोग्राफ़िक हैशेज़ की तुलना में अधिक कुशल है।
MiMC और Poseidon बग्स पर बाउन्टीज़ (Bounties)
वर्तमान में, Ethereum Foundation के पास इस लेख में वर्णित MiMC हैश के एक संस्करण (variant) पर हैश कोलिज़न (hash collision) खोजने के लिए $20,000 की बाउन्टी है।
Ethereum Foundation वर्तमान में Poseidon Cryptanalysis Initiative के माध्यम से Poseidon की सुरक्षा में शोध का आर्थिक रूप से समर्थन भी कर रहा है। Ethereum के संस्थापक ने संकेत दिया है कि Ethereum ZK का उपयोग करके नेटवर्क स्थिति (network state) को प्रूव करना आसान बनाने के लिए, Ethereum के लिए पसंदीदा हैश फंक्शन के रूप में Poseidon का उपयोग करने की ओर स्विच कर सकता है।
आभार (Acknowledgement)
इस लेख को बनाते समय Risc Zero के निम्नलिखित रिसोर्स का संदर्भ लिया गया था: