ஆஃப்லைன் தரவு ஒருமைப்பாட்டிற்கான மெர்கல் சான்றுகள்
அறிமுகம்
எத்திரியம் சேமிப்பகத்தில் அனைத்தையும் சேமிக்கவே நாம் விரும்புவோம், இது ஆயிரக்கணக்கான கணினிகளில் சேமிக்கப்படுகிறது மற்றும் மிக அதிக கிடைக்கும் தன்மையையும் (தரவை தணிக்கை செய்ய முடியாது) ஒருமைப்பாட்டையும் (தரவை அங்கீகரிக்கப்படாத முறையில் மாற்ற முடியாது) கொண்டுள்ளது, ஆனால் 32-பைட் சொல்லைச் சேமிக்க பொதுவாக 20,000 எரிவாயு செலவாகும். நான் இதை எழுதும் போது, அந்த செலவு $6.60 க்கு சமம். ஒரு பைட்டுக்கு 21 சென்ட்கள் என்பது பல பயன்பாடுகளுக்கு மிகவும் விலை உயர்ந்தது.
இந்தப் பிரச்சனையைத் தீர்க்க, எத்திரியம் சுற்றுச்சூழல் அமைப்பு பரவலாக்கப்பட்ட முறையில் தரவைச் சேமிக்க பல மாற்று வழிகளை உருவாக்கியுள்ளது. பொதுவாக அவை கிடைக்கும் தன்மை மற்றும் விலை ஆகியவற்றுக்கு இடையேயான சமரசத்தை உள்ளடக்கியது. இருப்பினும், ஒருமைப்பாடு பொதுவாக உறுதி செய்யப்படுகிறது.
இந்தக் கட்டுரையில், மெர்கல் சான்றுகளைப் (opens in a new tab) பயன்படுத்தி, தொகுதிச்சங்கிலியில் தரவைச் சேமிக்காமல் தரவு ஒருமைப்பாட்டை எவ்வாறு உறுதி செய்வது என்பதை நீங்கள் கற்றுக் கொள்வீர்கள்.
இது எவ்வாறு செயல்படுகிறது?
கோட்பாட்டளவில் நாம் தரவின் ஹாஷை சங்கிலிசார் சேமிக்கலாம், மேலும் தேவைப்படும் பரிவர்த்தனைகளில் அனைத்து தரவையும் அனுப்பலாம். இருப்பினும், இது இன்னும் மிகவும் விலை உயர்ந்தது. ஒரு பரிவர்த்தனைக்கு ஒரு பைட் தரவுக்கு சுமார் 16 எரிவாயு செலவாகும், தற்போது சுமார் அரை சென்ட் அல்லது ஒரு கிலோபைட்டுக்கு சுமார் $5 ஆகும். ஒரு மெகாபைட்டுக்கு $5000 என்பது, தரவை ஹாஷ் செய்வதற்கான கூடுதல் செலவு இல்லாவிட்டாலும், பல பயன்பாடுகளுக்கு இன்னும் மிகவும் விலை உயர்ந்தது.
தரவின் வெவ்வேறு துணைக்குழுக்களை மீண்டும் மீண்டும் ஹாஷ் செய்வதே இதற்கான தீர்வாகும், எனவே நீங்கள் அனுப்பத் தேவையில்லாத தரவுகளுக்கு ஒரு ஹாஷை மட்டும் அனுப்பலாம். மெர்க்கல் மரத்தைப் பயன்படுத்தி இதைச் செய்கிறீர்கள், இது ஒரு மரத் தரவுக் கட்டமைப்பாகும், இதில் ஒவ்வொரு கணுவும் அதன் கீழே உள்ள கணுக்களின் ஹாஷ் ஆகும்:
வேர் ஹாஷ் மட்டுமே சங்கிலிசார் சேமிக்கப்பட வேண்டிய பகுதியாகும். ஒரு குறிப்பிட்ட மதிப்பை நிரூபிக்க, வேரைப் பெற அதனுடன் இணைக்கப்பட வேண்டிய அனைத்து ஹாஷ்களையும் நீங்கள் வழங்குகிறீர்கள். எடுத்துக்காட்டாக, C என்பதை நிரூபிக்க நீங்கள் D, H(A-B) மற்றும் H(E-H) ஆகியவற்றை வழங்குகிறீர்கள்.
செயல்படுத்தல்
மாதிரிக் குறியீடு இங்கே வழங்கப்பட்டுள்ளது (opens in a new tab).
புறச்சங்கிலி குறியீடு
இந்தக் கட்டுரையில் புறச்சங்கிலி கணக்கீடுகளுக்கு JavaScript ஐப் பயன்படுத்துகிறோம். பெரும்பாலான பரவலாக்கப்பட்ட பயன்பாடுகள் அவற்றின் புறச்சங்கிலி கூறுகளை JavaScript இல் கொண்டுள்ளன.
மெர்கல் வேரை உருவாக்குதல்
முதலில் நாம் சங்கிலிக்கு மெர்கல் வேரை வழங்க வேண்டும்.
const ethers = require("ethers")
ethers தொகுப்பிலிருந்து ஹாஷ் செயற்கூறைப் பயன்படுத்துகிறோம் (opens in a new tab).
// நாம் ஒருமைப்பாட்டைச் சரிபார்க்க வேண்டிய மூலத் தரவு. முதல் இரண்டு பைட்டுகள் ஒரு
// பயனர் அடையாளங்காட்டி, மற்றும் கடைசி இரண்டு பைட்டுகள்
// பயனர் தற்போது வைத்திருக்கும் டோக்கன்களின் அளவு.
const dataArray = [
0x0bad0010, 0x60a70020, 0xbeef0030, 0xdead0040, 0xca110050, 0x0e660060,
0xface0070, 0xbad00080, 0x060d0091,
]
ஒவ்வொரு உள்ளீட்டையும் ஒற்றை 256-பிட் முழு எண்ணாக குறியாக்கம் செய்வது, எடுத்துக்காட்டாக JSON ஐப் பயன்படுத்துவதை விட குறைவான வாசிப்புத்திறன் கொண்ட குறியீட்டை உருவாக்குகிறது. இருப்பினும், ஒப்பந்தத்தில் தரவை மீட்டெடுக்க கணிசமாக குறைவான செயலாக்கம் தேவைப்படுகிறது, எனவே எரிவாயு செலவுகள் மிகவும் குறைவாக இருக்கும். நீங்கள் சங்கிலிசார் JSON ஐப் படிக்கலாம் (opens in a new tab), ஆனால் தவிர்க்க முடிந்தால் அது ஒரு மோசமான யோசனையாகும்.
// ஹாஷ் மதிப்புகளின் அணிவரிசை, BigInt-களாக
const hashArray = dataArray
இந்த நிலையில் நமது தரவு தொடங்குவதற்கு 256-பிட் மதிப்புகளாக உள்ளது, எனவே எந்த செயலாக்கமும் தேவையில்லை. சரங்கள் போன்ற சிக்கலான தரவுக் கட்டமைப்பைப் பயன்படுத்தினால், ஹாஷ்களின் வரிசையைப் பெற முதலில் தரவை ஹாஷ் செய்வதை உறுதிசெய்ய வேண்டும். பயனர்கள் மற்ற பயனர்களின் தகவல்களை அறிந்தால் நாங்கள் கவலைப்பட மாட்டோம் என்பதாலும் இது என்பதை நினைவில் கொள்க. இல்லையெனில் பயனர் 0 க்கான மதிப்பை பயனர் 1 அறியாதபடியும், பயனர் 3 க்கான மதிப்பை பயனர் 2 அறியாதபடியும் நாம் ஹாஷ் செய்திருக்க வேண்டும்.
// ஹாஷ் செயற்கூறு எதிர்பார்க்கும் சரத்திற்கும் மற்றும்
// நாம் மற்ற எல்லா இடங்களிலும் பயன்படுத்தும் BigInt-க்கும் இடையே மாற்றவும்.
const hash = (x) =>
BigInt(ethers.utils.keccak256("0x" + x.toString(16).padStart(64, 0)))
ethers ஹாஷ் செயற்கூறு 0x60A7 போன்ற ஹெக்ஸாடெசிமல் எண்ணைக் கொண்ட JavaScript சரத்தைப் பெற எதிர்பார்க்கிறது, மேலும் அதே அமைப்பைக் கொண்ட மற்றொரு சரத்துடன் பதிலளிக்கிறது. இருப்பினும், குறியீட்டின் மற்ற பகுதிகளுக்கு BigInt ஐப் பயன்படுத்துவது எளிதானது, எனவே நாங்கள் ஹெக்ஸாடெசிமல் சரமாக மாற்றி மீண்டும் பழைய நிலைக்குக் கொண்டு வருகிறோம்.
// ஒரு ஜோடியின் சமச்சீர் ஹாஷ், எனவே வரிசை மாற்றப்பட்டாலும் நாம் கவலைப்பட மாட்டோம்.
const pairHash = (a, b) => hash(hash(a) ^ hash(b))
இந்தச் செயற்கூறு சமச்சீரானது (a xor (opens in a new tab) b இன் ஹாஷ்). இதன் பொருள், மெர்கல் சான்றைச் சரிபார்க்கும் போது, சான்றிலிருந்து பெறப்பட்ட மதிப்பை கணக்கிடப்பட்ட மதிப்புக்கு முன்னால் அல்லது பின்னால் வைக்க வேண்டுமா என்பதைப் பற்றி நாம் கவலைப்படத் தேவையில்லை. மெர்கல் சான்று சரிபார்ப்பு சங்கிலிசார் செய்யப்படுகிறது, எனவே அங்கு நாம் எவ்வளவு குறைவாகச் செய்கிறோமோ அவ்வளவு நல்லது.
எச்சரிக்கை:
குறியாக்கவியல் பார்ப்பதை விட கடினமானது.
இந்தக் கட்டுரையின் ஆரம்பப் பதிப்பில் hash(a^b) என்ற ஹாஷ் செயற்கூறு இருந்தது.
அது ஒரு மோசமான யோசனையாகும், ஏனெனில் a மற்றும் b ஆகியவற்றின் முறையான மதிப்புகளை நீங்கள் அறிந்திருந்தால், விரும்பிய எந்த a' மதிப்பையும் நிரூபிக்க b' = a^b^a' ஐப் பயன்படுத்தலாம்.
இந்தச் செயற்கூறு மூலம் நீங்கள் b' ஐக் கணக்கிட வேண்டும், இதனால் hash(a') ^ hash(b') அறியப்பட்ட மதிப்புக்கு (வேரை நோக்கிய வழியில் அடுத்த கிளை) சமமாக இருக்கும், இது மிகவும் கடினமானது.
// ஒரு குறிப்பிட்ட கிளை காலியாக உள்ளது என்பதைக் குறிக்கும் மதிப்பு,
// மதிப்பைக் கொண்டிருக்கவில்லை
const empty = 0n
மதிப்புகளின் எண்ணிக்கை இரண்டின் முழு எண் அடுக்காக இல்லாதபோது, நாம் காலியான கிளைகளைக் கையாள வேண்டும். இந்த நிரல் அதைச் செய்யும் விதம் பூஜ்ஜியத்தை ஒரு இடநிரப்பியாக வைப்பதாகும்.
// ஹாஷ் அணிவரிசையின் மரத்தில் ஒரு நிலை மேலே கணக்கிட,
// ஒவ்வொரு ஜோடியின் ஹாஷையும் வரிசையாக எடுக்கவும்
const oneLevelUp = (inputArray) => {
var result = []
var inp = [...inputArray] // உள்ளீட்டை மேலெழுதுவதைத் தவிர்க்க // தேவைப்பட்டால் வெற்று மதிப்பைச் சேர்க்கவும் (அனைத்து இலைகளும் // ஜோடியாக இருக்க வேண்டும்)
if (inp.length % 2 === 1) inp.push(empty)
for (var i = 0; i < inp.length; i += 2)
result.push(pairHash(inp[i], inp[i + 1]))
return result
} // oneLevelUp
இந்தச் செயற்கூறு தற்போதைய அடுக்கில் உள்ள மதிப்புகளின் ஜோடிகளை ஹாஷ் செய்வதன் மூலம் மெர்க்கல் மரத்தில் ஒரு நிலை "ஏறுகிறது". இது மிகவும் திறமையான செயலாக்கம் அல்ல என்பதை நினைவில் கொள்க, உள்ளீட்டை நகலெடுப்பதைத் தவிர்த்து, சுழற்சியில் பொருத்தமான போது hashEmpty ஐச் சேர்த்திருக்கலாம், ஆனால் இந்தக் குறியீடு வாசிப்புத்திறனுக்காக உகந்ததாக்கப்பட்டுள்ளது.
const getMerkleRoot = (inputArray) => {
var result
result = [...inputArray] // ஒரே ஒரு மதிப்பு இருக்கும் வரை மரத்தில் மேலே ஏறவும், அதுவே // வேர். // // ஒரு அடுக்கில் ஒற்றைப்படை எண்ணிக்கையிலான உள்ளீடுகள் இருந்தால் // oneLevelUp-ல் உள்ள குறியீடு ஒரு வெற்று மதிப்பைச் சேர்க்கிறது, எனவே உதாரணமாக, // 10 இலைகள் இருந்தால், இரண்டாவது அடுக்கில் 5 கிளைகள், மூன்றாவது அடுக்கில் 3 // கிளைகள், நான்காவது அடுக்கில் 2 மற்றும் வேர் ஐந்தாவதாக இருக்கும்
while (result.length > 1) result = oneLevelUp(result)
return result[0]
}
வேரைப் பெற, ஒரே ஒரு மதிப்பு மட்டுமே எஞ்சியிருக்கும் வரை ஏறுங்கள்.
மெர்கல் சான்றை உருவாக்குதல்
மெர்கல் சான்று என்பது மெர்கல் வேரைத் திரும்பப் பெற நிரூபிக்கப்படும் மதிப்புடன் சேர்த்து ஹாஷ் செய்ய வேண்டிய மதிப்புகளாகும். நிரூபிக்க வேண்டிய மதிப்பு பெரும்பாலும் பிற தரவுகளிலிருந்து கிடைக்கிறது, எனவே அதை குறியீட்டின் ஒரு பகுதியாக வழங்குவதை விட தனித்தனியாக வழங்க விரும்புகிறேன்.
// ஒரு மெர்கல் சான்று என்பது உள்ளீடுகளின் பட்டியலின் மதிப்பைக் கொண்டுள்ளது
// அதனுடன் ஹாஷ் செய்ய. நாம் ஒரு சமச்சீர் ஹாஷ் செயற்கூறைப் பயன்படுத்துவதால்,
// சான்றைச் சரிபார்க்க உருப்படியின் இருப்பிடம் தேவையில்லை, அதை உருவாக்க மட்டுமே தேவை
const getMerkleProof = (inputArray, n) => {
var result = [], currentLayer = [...inputArray], currentN = n
// நாம் உச்சியை அடையும் வரை
while (currentLayer.length > 1) {
// ஒற்றைப்படை நீள அடுக்குகள் இல்லை
if (currentLayer.length % 2)
currentLayer.push(empty)
result.push(currentN % 2
// currentN ஒற்றைப்படையாக இருந்தால், அதற்கு முந்தைய மதிப்புடன் சான்றில் சேர்க்கவும்
? currentLayer[currentN-1]
// அது இரட்டைப்படையாக இருந்தால், அதற்குப் பிந்தைய மதிப்பைச் சேர்க்கவும்
: currentLayer[currentN+1])
நாங்கள் (v[0],v[1]), (v[2],v[3]) போன்றவற்றை ஹாஷ் செய்கிறோம். எனவே இரட்டைப்படை மதிப்புகளுக்கு அடுத்ததும், ஒற்றைப்படை மதிப்புகளுக்கு முந்தையதும் தேவை.
// அடுத்த மேல் அடுக்குக்கு நகரவும்
currentN = Math.floor(currentN/2)
currentLayer = oneLevelUp(currentLayer)
} // while currentLayer.length > 1
return result
} // getMerkleProof
சங்கிலிசார் குறியீடு
இறுதியாக சான்றைச் சரிபார்க்கும் குறியீடு எங்களிடம் உள்ளது. சங்கிலிசார் குறியீடு Solidity (opens in a new tab) இல் எழுதப்பட்டுள்ளது. எரிவாயு ஒப்பீட்டளவில் விலை உயர்ந்தது என்பதால் இங்கு உகப்பாக்கம் மிகவும் முக்கியமானது.
//SPDX-License-Identifier: Public Domain
pragma solidity ^0.8.0;
import "hardhat/console.sol";
இதை நான் Hardhat மேம்பாட்டுச் சூழலைப் (opens in a new tab) பயன்படுத்தி எழுதினேன், இது உருவாக்கும் போது Solidity இலிருந்து கன்சோல் வெளியீட்டைக் (opens in a new tab) கொண்டிருக்க அனுமதிக்கிறது.
contract MerkleProof {
uint merkleRoot;
function getRoot() public view returns (uint) {
return merkleRoot;
}
// மிகவும் பாதுகாப்பற்றது, தயாரிப்பு குறியீட்டில் இதற்கான அணுகல்
// இந்த செயற்கூறு கண்டிப்பாகக் கட்டுப்படுத்தப்பட வேண்டும், அநேகமாக ஒரு
// உரிமையாளருக்கு
function setRoot(uint _merkleRoot) external {
merkleRoot = _merkleRoot;
} // setRoot
மெர்கல் வேருக்கான செட் மற்றும் கெட் செயற்கூறுகள். மெர்கல் வேரை அனைவரும் புதுப்பிக்க அனுமதிப்பது ஒரு தயாரிப்பு அமைப்பில் மிகவும் மோசமான யோசனையாகும். மாதிரிக் குறியீட்டிற்கான எளிமைக்காக நான் இதை இங்கே செய்கிறேன். தரவு ஒருமைப்பாடு உண்மையில் முக்கியமான ஒரு அமைப்பில் இதைச் செய்ய வேண்டாம்.
function hash(uint _a) internal pure returns(uint) {
return uint(keccak256(abi.encode(_a)));
}
function pairHash(uint _a, uint _b) internal pure returns(uint) {
return hash(hash(_a) ^ hash(_b));
}
இந்தச் செயற்கூறு ஒரு ஜோடி ஹாஷை உருவாக்குகிறது. இது hash மற்றும் pairHash க்கான JavaScript குறியீட்டின் Solidity மொழிபெயர்ப்பாகும்.
குறிப்பு: இது வாசிப்புத்திறனுக்கான உகப்பாக்கத்தின் மற்றொரு நிகழ்வாகும். செயற்கூறு வரையறையின் (opens in a new tab) அடிப்படையில், தரவை bytes32 (opens in a new tab) மதிப்பாகச் சேமித்து மாற்றங்களைத் தவிர்க்க முடியும்.
// ஒரு மெர்கல் சான்றைச் சரிபார்க்கவும்
function verifyProof(uint _value, uint[] calldata _proof)
public view returns (bool) {
uint temp = _value;
uint i;
for(i=0; i<_proof.length; i++) {
temp = pairHash(temp, _proof[i]);
}
return temp == merkleRoot;
}
} // MarkleProof
கணிதக் குறியீட்டில் மெர்கல் சான்று சரிபார்ப்பு இப்படி இருக்கும்: H(proof_n, H(proof_n-1, H(proof_n-2, ... H(proof_1, H(proof_0, value))...))). இந்தக் குறியீடு அதைச் செயல்படுத்துகிறது.
மெர்கல் சான்றுகளும் ரோலப்களும் கலக்காது
மெர்கல் சான்றுகள் ரோலப்களுடன் நன்றாகச் செயல்படாது. காரணம், ரோலப்கள் அனைத்து பரிவர்த்தனை தரவையும் அடுக்கு 1 (l1) இல் எழுதுகின்றன, ஆனால் அடுக்கு 2 (l2) இல் செயலாக்குகின்றன. ஒரு பரிவர்த்தனையுடன் மெர்கல் சான்றை அனுப்புவதற்கான செலவு ஒரு அடுக்குக்கு சராசரியாக 638 எரிவாயு ஆகும் (தற்போது அழைப்புத் தரவில் உள்ள ஒரு பைட் பூஜ்ஜியமாக இல்லாவிட்டால் 16 எரிவாயுவும், பூஜ்ஜியமாக இருந்தால் 4 எரிவாயுவும் செலவாகும்). நம்மிடம் 1024 சொற்கள் தரவு இருந்தால், ஒரு மெர்கல் சான்றுக்கு பத்து அடுக்குகள் அல்லது மொத்தம் 6380 எரிவாயு தேவைப்படும்.
எடுத்துக்காட்டாக ஆப்டிமிசம் (opens in a new tab) ஐப் பார்த்தால், அடுக்கு 1 (l1) எரிவாயுவை எழுதுவதற்கு சுமார் 100 Gwei செலவாகும் மற்றும் அடுக்கு 2 (l2) எரிவாயுவுக்கு 0.001 Gwei செலவாகும் (அது சாதாரண விலை, நெரிசலுடன் இது உயரக்கூடும்). எனவே ஒரு அடுக்கு 1 (l1) எரிவாயுவின் விலைக்கு நாம் அடுக்கு 2 (l2) செயலாக்கத்திற்கு ஒரு லட்சம் எரிவாயுவைச் செலவிடலாம். சேமிப்பகத்தை நாம் மேலெழுத மாட்டோம் என்று வைத்துக்கொண்டால், ஒரு அடுக்கு 1 (l1) எரிவாயுவின் விலைக்கு அடுக்கு 2 (l2) இல் உள்ள சேமிப்பகத்தில் சுமார் ஐந்து சொற்களை எழுதலாம் என்று அர்த்தம். ஒரு மெர்கல் சான்றுக்கு நாம் முழு 1024 சொற்களையும் சேமிப்பகத்தில் எழுதலாம் (அவை பரிவர்த்தனையில் வழங்கப்படுவதற்குப் பதிலாக, தொடங்குவதற்கு சங்கிலிசார் கணக்கிடப்படலாம் என்று வைத்துக்கொள்வோம்) மற்றும் இன்னும் பெரும்பாலான எரிவாயு மீதமிருக்கும்.
முடிவுரை
நிஜ வாழ்க்கையில் நீங்கள் ஒருபோதும் மெர்க்கல் மரங்களை நீங்களே செயல்படுத்த மாட்டீர்கள். நீங்கள் பயன்படுத்தக்கூடிய நன்கு அறியப்பட்ட மற்றும் தணிக்கை செய்யப்பட்ட நூலகங்கள் உள்ளன, பொதுவாகச் சொல்வதானால், குறியாக்கவியல் அடிப்படைகளை நீங்களே செயல்படுத்தாமல் இருப்பது நல்லது. ஆனால் இப்போது நீங்கள் மெர்கல் சான்றுகளைப் பற்றி நன்றாகப் புரிந்துகொண்டிருப்பீர்கள் என்றும், அவற்றைப் பயன்படுத்துவது எப்போது மதிப்புக்குரியது என்பதை உங்களால் தீர்மானிக்க முடியும் என்றும் நம்புகிறேன்.
மெர்கல் சான்றுகள் ஒருமைப்பாட்டைப் பாதுகாக்கும் அதே வேளையில், அவை கிடைக்கும் தன்மையைப் பாதுகாக்காது என்பதை நினைவில் கொள்க. தரவுச் சேமிப்பகம் அணுகலை அனுமதிக்க வேண்டாம் என்று முடிவு செய்தால், அவற்றை அணுகுவதற்கு உங்களால் மெர்க்கல் மரத்தை உருவாக்க முடியாவிட்டால், வேறு யாரும் உங்கள் சொத்துக்களை எடுக்க முடியாது என்பதை அறிவது சிறிய ஆறுதலாகும். எனவே IPFS போன்ற சில வகையான பரவலாக்கப்பட்ட சேமிப்பகத்துடன் மெர்க்கல் மரங்களைப் பயன்படுத்துவது சிறந்தது.
எனது மேலும் பல பணிகளுக்கு இங்கே பார்க்கவும் (opens in a new tab).


