EIP712 आ रहा है: क्या उम्मीद करें और इसका उपयोग कैसे करें

एथेरम वॉलेट्स जैसे मेटामास्क जल्द ही टाइप किए गए संदेश पर हस्ताक्षर करने के लिए EIP712 मानक पेश करेगा। यह मानक संरचित और पठनीय प्रारूप में संकेतों पर हस्ताक्षर करने में डेटा प्रदर्शित करने की अनुमति देता है। सुरक्षा और उपयोग के लिए EIP712 एक बेहतरीन कदम है क्योंकि उपयोगकर्ताओं को अब अपमानजनक हेक्साडेसिमल स्ट्रिंग्स पर साइन अप करने की आवश्यकता नहीं होगी, जो कि एक अभ्यास है जो भ्रामक और असुरक्षित हो सकता है।

स्मार्ट अनुबंध और डीएपी डेवलपर्स को इस नए मानक को अपनाना चाहिए क्योंकि यह पहले से ही एथेरियम इंप्रूवमेंट प्रपोजल रिपॉजिटरी में विलय हो चुका है, और प्रमुख वॉलेट प्रदाता जल्द ही इसका समर्थन करेंगे। इस ब्लॉग पोस्ट का उद्देश्य डेवलपर्स को ऐसा करने में मदद करना है। इसमें यह क्या करता है, जावास्क्रिप्ट और सॉलिडिटी कोड का नमूना, और एक कार्य प्रदर्शन का विवरण शामिल है।

EIP712 से पहले

चित्र 1: एक डीएपी से एक हस्ताक्षर अनुरोध जो EIP712 का उपयोग नहीं करता है

क्रिप्टोक्यूरेंसी स्पेस में एक कहावत: विश्वास नहीं करता; सत्यापित करें। EIP712 से पहले, उपयोगकर्ताओं के लिए उन डेटा को सत्यापित करना मुश्किल था, जिन पर उन्हें हस्ताक्षर करने के लिए कहा गया था, जिससे सभी के लिए डीएपी में उन लोगों की तुलना में अधिक विश्वास रखना आसान हो गया, जो परिणामी मूल्य हस्तांतरण के आधार के रूप में हस्ताक्षरित संदेशों का उपयोग करते हैं।

उदाहरण के लिए, चित्र 1 में एक मेटा ट्रेडर पॉप-अप दिखाया गया है जो विकेंद्रीकृत एक्सचेंज द्वारा ट्रिगर किया गया है, जिससे उपयोगकर्ताओं को सुरक्षित रूप से अपने वॉलेट पते पर संबद्ध करने के लिए ऑर्डर के हैश पर हस्ताक्षर करने की आवश्यकता होती है। दुर्भाग्य से, जैसा कि यह हैश एक हेक्साडेसिमल स्ट्रिंग है, महत्वपूर्ण तकनीकी विशेषज्ञता के बिना उपयोगकर्ता आसानी से यह सत्यापित नहीं कर सकते हैं कि यह वास्तव में उनके इच्छित आदेश का हैश है। उपयोगकर्ताओं को बिछाने के लिए, डीएपी पर आँख बंद करके भरोसा करना आसान है और इसे सत्यापित करने की तकनीकी परेशानी से गुजरने के बजाय, "साइन" पर क्लिक करें। यह सुरक्षा के लिए बुरा है।

यदि कोई उपयोगकर्ता अनजाने में दुर्भावनापूर्ण फ़िशिंग dApp पर लैंड करता है, तो यह उन्हें गलत ऑर्डर जानकारी पर साइन इन कर सकता है। उदाहरण के लिए, यह उन्हें एक ऐसे व्यापार के लिए अनुचित रूप से उच्च राशि का भुगतान करने में धोखा दे सकता है, जो अन्यथा कम खर्च होगा। इस तरह के हमलों को रोकने के लिए, उपयोगकर्ताओं को यह जानने का कुछ तरीका होना चाहिए कि वे वास्तव में क्या हस्ताक्षर कर रहे हैं, बिना किसी क्रिप्टोग्राफिक हैश को फिर से बनाने की परेशानी से गुजरना।

कार्रवाई में EIP712

चित्र 2: EAP712 का उपयोग करने वाले dApp से एक हस्ताक्षर अनुरोध

EIP712 प्रयोज्य और सुरक्षा में मजबूत सुधार प्रदान करता है। उपरोक्त उदाहरण के विपरीत, जब एक EIP712- सक्षम dApp हस्ताक्षर का अनुरोध करता है, तो उपयोगकर्ता का बटुआ उन्हें पूर्व-हैश किए गए कच्चे डेटा दिखाता है, जिसे वे तब हस्ताक्षर करने के लिए चुन सकते हैं। इससे उपयोगकर्ता के लिए इसे सत्यापित करना बहुत आसान हो जाता है।

EIP712 कैसे लागू करें

यह नया मानक कई अवधारणाओं को प्रस्तुत करता है जो डेवलपर्स को परिचित होना चाहिए, इसलिए यह अनुभाग उस पर ज़ूम इन करेगा जिसे आपको डीएपी में लागू करने के लिए जानने की आवश्यकता है।

उदाहरण के लिए, आप एक विकेन्द्रीकृत नीलामी dApp का निर्माण कर रहे हैं जिसमें बोलीदाता बोली-श्रृंखला पर हस्ताक्षर करते हैं, और एक स्मार्ट अनुबंध इन हस्ताक्षरित बोलियों को श्रृंखला में सत्यापित करता है।

1. अपने डेटा संरचनाओं को डिज़ाइन करें

सबसे पहले, उस डेटा की JSON संरचना का पता लगाएँ, जिसे आप उपयोगकर्ताओं को हस्ताक्षर करने के लिए चाहते हैं। इस उदाहरण के लिए, हम निम्नलिखित का उपयोग करते हैं:

{
    राशि: 100,
    टोकन: "0x…।"
    आईडी: 15,
    बोली: {
        userId: 323,
        बटुआ: "0x ..."
    }
}

इसके बाद हम उपरोक्त स्निपेट से दो डेटा संरचनाएं प्राप्त कर सकते हैं: बोली, जिसमें एक ERC20 टोकन और नीलामी आईडी के साथ-साथ पहचान, जिसमें एक उपयोगकर्ता नाम और बटुए का पता निर्दिष्ट होता है।

इसके बाद, बोली और पहचान को नीचे रखें, क्योंकि आप अपनी सॉलिडिटी कोड में नियुक्त करेंगे। देशी डेटा प्रकारों की पूरी सूची के लिए EIP712 मानक का संदर्भ लें, जैसे पता, बाइट्स 32, uint256, और इसी तरह।

बोली: {
    राशि: uint256,
    बोली लगाने वाला: पहचान
}
पहचान: {
    userId: uint256,
    बटुआ: पता
}

2. अपने डोमेन विभाजक को डिज़ाइन करें

अगला कदम एक डोमेन विभाजक बनाना है। यह अनिवार्य क्षेत्र एक डीएपी को दूसरे में काम करने से रोकने के लिए एक हस्ताक्षर को रोकने में मदद करता है। EIP712 के रूप में बताते हैं:

यह संभव है कि दो डीएपी ट्रांसफर (पते से पता, यूआईंट 256 राशि) जैसी समान संरचना के साथ आते हैं जो संगत नहीं होना चाहिए। एक डोमेन विभाजक को शुरू करने से डीएपी डेवलपर्स की गारंटी होती है कि कोई हस्ताक्षर टकराव नहीं हो सकता है।

डोमेन विभाजक को वास्तु और कार्यान्वयन स्तर पर सावधानीपूर्वक विचार और प्रयास की आवश्यकता होती है। डेवलपर्स और डिज़ाइनरों को यह तय करना होगा कि उनके उपयोग के मामले के लिए निम्नलिखित क्षेत्रों में से कौन सा शामिल करना या बाहर करना है।

नाम: dApp या प्रोटोकॉल नाम, उदा। "CryptoKitties"

संस्करण: वर्तमान संस्करण जो मानक "हस्ताक्षरित डोमेन" कहता है। यह आपके dApp या प्लेटफॉर्म का वर्जन नंबर हो सकता है। यह एक डीएपी संस्करण से हस्ताक्षर को दूसरों के साथ काम करने से रोकता है।

chainId: EIP-155 चेन आईडी। एक नेटवर्क के लिए एक हस्ताक्षर को रोकता है, जैसे टेस्टनेट, दूसरे पर काम करने से, जैसे कि मेननेट।

verifyingContract: अनुबंध का Ethereum पता जो परिणामी हस्ताक्षर को सत्यापित करेगा। सॉलिडिटी में यह नियम अनुबंध का अपना पता देता है, जिसे वह हस्ताक्षर का सत्यापन करते समय उपयोग कर सकता है।

नमक: एक अद्वितीय 32-बाइट मूल्य अनुबंध और डीएपी दोनों में हार्डकोड किया गया, जिसका अर्थ अंतिम उपाय के रूप में दूसरों से डीएपी को अलग करना है।

व्यवहार में, एक डोमेन विभाजक जो उपरोक्त सभी क्षेत्रों का उपयोग करता है, वह इस तरह दिख सकता है:

{
    नाम: "मेरा अद्भुत डीएपी",
    संस्करण 2",
    चेनआईड: "1",
    verifyingContract: "0x1c56346cd2a2bf3202f771f50d3d14a367b48070"
    नमक: "0x43efba6b4ccb1b6faa2625fe562bdd9a2328355"
}

चेनआईड के बारे में ध्यान देने वाली एक बात यह है कि वॉलेट प्रदाताओं को हस्ताक्षर करने से रोकना चाहिए यदि यह उस नेटवर्क से मेल नहीं खाता है जो वर्तमान में जुड़ा हुआ है। जैसा कि वॉलेट प्रदाता आवश्यक रूप से इसे लागू नहीं कर सकते हैं, हालांकि, यह महत्वपूर्ण है कि चेनआईड को ऑन-चेन सत्यापित किया जाए। एकमात्र चेतावनी यह है कि कॉन्ट्रैक्ट्स के पास यह पता लगाने का कोई तरीका नहीं है कि वे किस चेन आईडी पर हैं, इसलिए डेवलपर्स को अपने कॉन्ट्रैक्ट्स में हार्डकोड चेनआईड होना चाहिए और यह सुनिश्चित करने के लिए अतिरिक्त सावधानी बरतनी चाहिए कि यह उस नेटवर्क से मेल खाता है जिस पर वे तैनात हैं।

संपादित करें (31 मई 2019): यदि ईआईपी -1344 भविष्य के एथेरियम अपग्रेड (संभवत: इस्तांबुल) में शामिल हो जाता है, तो अनुबंधों के लिए प्रोग्राम को खोजने के लिए एक रास्ता मिल जाएगा।

2.1। मेटामास्क संस्करण 4.14.0 या इसके बाद के संस्करण को स्थापित करें

मेटामास्क के संस्करण 4.14.0 की रिलीज़ से पहले, ETHSanFrancisco सप्ताहांत पर रोलबैक के कारण इसका EIP712 समर्थन फ्लक्स में थोड़ा था। आगे बढ़ते हुए, संस्करण 4.14.0 और बाद के संस्करण को ठीक से EIP712 हस्ताक्षर का समर्थन करना चाहिए।

3. अपने डीएपी के लिए हस्ताक्षर कोड लिखें

आपके जावास्क्रिप्ट डीएपी को अब मेटामास्क से अपने डेटा पर हस्ताक्षर करने के लिए कहने की आवश्यकता है। सबसे पहले, अपने डेटा प्रकारों को परिभाषित करें:

कॉन्स्ट डोमेन = [
    {name: "name", टाइप करें: "string"},
    {name: "version", टाइप करें: "string"},
    {name: "chainId", टाइप करें: "uint256"},
    {नाम: "सत्यापनकर्ता", प्रकार: "पता"},
    {नाम: "नमक", प्रकार: "बाइट्स 32"},
];
कास्ट बोली = [
    {नाम: "राशि", प्रकार: "uint256"},
    {नाम: "बोलीदाता", प्रकार: "पहचान"},
];
कास्ट पहचान = [
    {name: "userId", टाइप करें: "uint256"},
    {नाम: "बटुआ", प्रकार: "पता"},
];

इसके बाद, अपने डोमेन विभाजक और संदेश डेटा को परिभाषित करें।

कॉन्स्ट डोमेनड्टा = {
    नाम: "मेरा अद्भुत डीएपी",
    संस्करण 2",
    ChainId: parseInt (web3.version.network, 10),
    verifyingContract: "0x1C56346CD2A2Bf3202F771f50d3D14a367B48070",
    नमक: "0xf2d857f4a3edcb9b78b4d503bfe733db1e3f6cdc2b7971ee739626c97e86a558"
};
var संदेश = {
    राशि: 100,
    बोली: {
        userId: 323,
        बटुआ: "0x333333333333333333333333333333333333333333"
    }
};

इस तरह से अपने चर को बाहर रखना:

const data = JSON.stringify ({
    प्रकार: {
        EIP712Domain: डोमेन,
        बोली: बोली,
        पहचान: पहचान,
    },
    डोमेन: domainData,
    प्राथमिक प्रकार: "बोली",
    संदेश: संदेश
});

इसके बाद, web3 पर eth_signTypedData_v3 साइनिंग कॉल करें:

web3.currentProvider.sendAsync (
{
    विधि: "eth_signTypedData_v3",
    params: [हस्ताक्षरकर्ता, डेटा],
    से: हस्ताक्षरकर्ता
},
समारोह (गलती, परिणाम) {
    अगर (गलती से) {
        वापसी दिलासा।
    }
    const हस्ताक्षर = result.result.substring (2);
    const r = "0x" + signature.substring (0, 64);
    const s = "0x" + signature.substring (64, 128);
    const v = parseInt (हस्ताक्षर.सुबस्ट्रिंग (128, 130), 16);
    // हस्ताक्षर में अब r, s और v शामिल हैं।
    }
);

ध्यान दें कि लेखन के समय, मेटामास्क और सिफर ब्राउजर पिछड़े संगतता को अनुमति देने के लिए विधि क्षेत्र में eth_signTypedData_v3 का उपयोग करते हैं जबकि dApp पारिस्थितिकी तंत्र मानक को अपनाता है। भविष्य में इन जेबों के रिलीज होने की संभावना है कि इसका नाम बदलकर सिर्फ eth_signTypedData कर दिया जाएगा।

4. सत्यापन अनुबंध के लिए प्रमाणीकरण कोड लिखें

याद रखें कि एक वॉलेट प्रदाता ईआईपी 712-टाइप किए गए डेटा पर हस्ताक्षर करने से पहले इसे पहले प्रारूपित करता है और इसे राख कर देता है। इस प्रकार, आपके अनुबंध को वही करने में सक्षम होने की आवश्यकता है ताकि वह यह निर्धारित कर सके कि किस पते पर हस्ताक्षर किए गए हैं, और आपको इस फॉर्मेटिंग / हैश फ़ंक्शन को अपने सॉलिडिटी कॉन्ट्रैक्ट कोड में दोहराना होगा। यह शायद प्रक्रिया में सबसे मुश्किल कदम है, इसलिए यहां सटीक और सावधान रहें।

सबसे पहले, अपने डेटा प्रकारों की घोषणा करें

संरचना पहचान {
    uint256 userId;
    पता बटुआ;
}
संरचना बोली {
    uint256 राशि;
    पहचान की बोली लगाने वाला;
}

इसके बाद, अपने डेटा स्ट्रक्चर्स को फिट करने के लिए टाइप हैश को परिभाषित करें। ध्यान दें कि कॉमा और कोष्ठक के बाद कोई स्थान नहीं है, और नाम और प्रकार ऊपर दिए गए जावास्क्रिप्ट कोड में निर्दिष्ट किए गए लोगों के साथ मेल खाना चाहिए।

स्ट्रिंग निजी निरंतर IDENTITY_TYPE = "पहचान (uint256 userId, पता बटुआ)";
स्ट्रिंग निजी स्थिर BID_TYPE = "बोली (uint256 राशि, पहचान बोलीदाता) पहचान (uint256 userId, पता बटुआ)";

डोमेन विभाजक प्रकार हैश को भी परिभाषित करें। ध्यान दें कि 1 के एक श्रंखला के साथ निम्नलिखित कोड मेननेट पर तैनात किए जाने वाले अनुबंध के लिए होता है, और यह तार (जैसे कि "मेरा अद्भुत डीएपी") हैशेड होना चाहिए।

uint256 निरंतर चेन आई डी = 1;
पता निरंतर सत्यापित करना
बाइट्स 32 निरंतर नमक = 0xf2d857f4a3edcb9b78b4d503bfe733db1e3f6cdc2b7971ee739626c97e86a558;
स्ट्रिंग निजी स्थिर EIP712_DOMAIN = "EIP712Domain (स्ट्रिंग नाम, स्ट्रिंग संस्करण, uint256 chainId, पता सत्यापित करने वाला कांटा, बाइट्स 32 सॉल्ट)";
बाइट्स 32 निजी स्थिर DOMAIN_SEPARATOR = keccak256 (abi.encode ()
    EIP712_DOMAIN_TYPEHASH,
    keccak256 ("मेरा अद्भुत डीएपी"),
    keccak256 ( "2"),
    chainId,
    verifyingContract,
    नमक
));

अगला, प्रत्येक डेटा प्रकार के लिए एक हैश फ़ंक्शन लिखें:

समारोह हैशियत (पहचान पहचान) निजी शुद्ध रिटर्न (बाइट्स 32) {
    वापसी keccak256 (abi.encode (
        IDENTITY_TYPEHASH,
        identity.userId,
        identity.wallet
    ));
}
फ़ंक्शन हैशबिड (बिड मेमोरी बिड) निजी शुद्ध रिटर्न (बाइट्स 32) {
    वापसी keccak256 (abi.encodePacked (
        "\\ x19 \\ X01",
       DOMAIN_SEPARATOR,
       keccak256 (abi.encode (
            BID_TYPEHASH,
            बोली की रक़म,
            hashIdentity (bid.bidder)
        ))
    ));

अंतिम लेकिन निश्चित रूप से कम से कम, अपने हस्ताक्षर सत्यापन समारोह को लिखें:

फ़ंक्शन सत्यापन (पता हस्ताक्षरकर्ता, बोली स्मृति बोली, sigR, sigS, sigV) सार्वजनिक शुद्ध रिटर्न (बूल) {
    वापसी हस्ताक्षरकर्ता == ecrecover (हैशबिड (बोली), sigV, sigR, sigS);
}

एक कार्य प्रदर्शन

उपरोक्त कोड के कार्य प्रदर्शन के लिए, इस उपकरण का उपयोग करें। मेटामास्क का एक EIP712- संगत संस्करण स्थापित करने के बाद, हस्ताक्षर अनुरोध पॉप-अप को ट्रिगर करने के लिए जावास्क्रिप्ट कोड को चलाने के लिए पृष्ठ पर बटन पर क्लिक करें। साइन पर क्लिक करें, और सॉलिडिटी कोड एक टेक्स्ट बॉक्स में दिखाई देगा।

इस कोड में उपरोक्त सभी हैशिंग कोड, मेटामास्क द्वारा निर्मित हस्ताक्षर और आपका बटुआ पता होगा। यदि आप इसे रीमिक्स आईडीई में कॉपी और पेस्ट करते हैं, तो जावास्क्रिप्ट वीएम वातावरण का चयन करें, और फिर सत्यापित फ़ंक्शन चलाएं, रीमिक्स कोडर में एक्सेकवर चलाएगा ताकि हस्ताक्षरकर्ता का पता प्राप्त हो सके, परिणाम की तुलना अपने बटुए के पते से करें, और फिर वापस लौटें। उनका मिलान होता है।

ध्यान दें कि सादगी के लिए, इस प्रदर्शन से उत्पन्न सत्यापित फ़ंक्शन ऊपर दिए गए उदाहरण से अलग है, क्योंकि मेटामास्क द्वारा उत्पन्न हस्ताक्षर गतिशील रूप से इसमें डाले जाएंगे।

चित्र 3: जब आप सत्यापित फ़ंक्शन चलाते हैं, तो रीमिक्स क्या दिखाता है

व्यावहारिक रूप से, यह वही है जो आपके स्मार्ट अनुबंध कोड पर हस्ताक्षर किए गए डेटा को सत्यापित करने के लिए करना चाहिए। अपने स्वयं के प्रयोजनों के लिए कोड को अनुकूलित करने के लिए स्वतंत्र महसूस करें। उम्मीद है, यह आपके डेटा संरचनाओं के लिए हैश फ़ंक्शन लिखने पर आपका समय बचाएगा।

मेटामास्क में "विरासत" EIP712 समर्थन पर एक नोट

ध्यान देने वाली एक और बात यह है कि जब मेटामाक EIP712 के लिए समर्थन जारी करता है, तो वह अब इस अक्टूबर 2017 ब्लॉग पोस्ट में वर्णित एक प्रयोगात्मक "विरासत" टाइप डेटा हस्ताक्षर सुविधा का समर्थन नहीं करेगा।

संपादित करें (29 सितंबर): जैसा कि मैं इसे समझता हूं, एक बार मेटामाक eth_signTypedData को पूर्ण EIP712 समर्थन के लिए इंगित करता है, यह eth_signTypedDa_v1 कॉल के माध्यम से लीगेसी टाइप किए गए डेटा को समर्थन देगा।

अंतिम नोट्स

संक्षेप में, EIP712 समर्थन आ रहा है और डेवलपर्स को इसका लाभ उठाना चाहिए। यह प्रयोज्य में महत्वपूर्ण सुधार करता है और फ़िशिंग को रोकने में मदद करता है। हालांकि वर्तमान में इसे लागू करने के लिए थोड़ा मुश्किल है, हम आशा करते हैं कि यह लेख और नमूना कोड डेवलपर्स को अपने स्वयं के डीएपी और अनुबंधों के लिए इसे अपनाने में मदद करेगा।

स्वीकृतियाँ

इस लेख को कोह वेई जी ने लिखा था, जो एक पूर्ण-स्टैक डेवलपर है जो कॉन्सेनस सिंगापुर के साथ है। उनकी अमूल्य प्रतिक्रिया और टिप्पणियों के लिए पॉल बाउचॉन और डैन फिनले को बहुत धन्यवाद।