简述EIP-155,EIP-191,EIP-712的区别

签名交易:

单纯的转账交易:将(nonce, gasPrice, gasLimit, to, value, data:空, v, r, s)发往节点。注意,这里data是空的。(此处需要EIP-155基础)
部署合约交易:将(nonce, gasPrice, gasLimit, to:空, value, data:合约创建字节码, v, r, s)发往节点。注意,to是空的,data是合约创建字节码,节点看到to是空的就知道这是部署合约交易。
调用合约函数交易:将(nonce, gasPrice, gasLimit, to, value, data:selector+函数参数, v, r, s)发往节点。注意,data是selector+函数参数,例如bytes4(keccak256(bytes(“foo(uint256,address,string,uint256[2])”))), x, addr, name, array。
其中,v,r,s是已签名的“消息”,可以理解成前六个参数是消息明文,后三个参数是签名后的消息(密文)。将【明文,密文】组成的交易签名后即可成为签名“交易”发送给节点。
故这个过程中需要2次签名,一次是消息签名,一次是交易签名。

先说消息签名:

1)0x1901 以太坊消息(EIP-191签名标准)

简单点来说就是添加了"\x19Ethereum Signed Message:\n"这个字符串的签名,添加这个字符串只是单纯的为了表明这是以太坊的签名

签名逻辑:

encodepacked(参数1,参数2,参数3,…)
-> Hash1=keccak256(encodepacked(参数1,参数2,参数3,…)
-> keccak256(abi.encodePacked(“\x19Ethereum Signed Message:\n32”, Hash1))
-> 加入私钥进行运算得到"消息签名”。

2)0x1900

EIP-191提出了在签名中加入validator参数(一般为合约自身的address参数),以防止重放攻击的手法。实际应用中使用EIP-712更多。

3)0x1945(EIP-712)

EIP-712的消息由三部分组成(712的结构式):
encode(‘\x19\x01’, domainSeparator, message),然后进行哈希计算
其中domainSeparator, message需要其“结构类型”的keccak256(哈希)及其“实际值”的keccak256,之后进行encode编码后再次进行keccak256。
(注:domainSeparator(域名分隔符)是在construct的时候就被定义好了的,声明我这个合约是要做什么的)

展开说明domainSqparator:

domainSeparator由两部分组成,
第一部分为对结构体的keccak256——encodeType,
第二部分为结构体的具体实现——encodeData;

①encodeType:

domainSeparator结构体如下所示:(一般来说salt(随机数)会省略)

struct EIP712Domain{
    
     
string name, //用户可读的域名,如DAPP的名字 
// 目前签名的域的版本号 uint256 chainId, // EIP-155中定义的chain ID,如以太坊主网为1 
string version, 
address verifyingContract, // 用于验证签名的合约地址 
bytes32 salt // 随机数 
}
encodeType = keccak256('EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)')

②encodeData则是对结构体具体数值的编码:

keccak256(bytes(name)), keccak256(bytes(‘1’)), 1, address(this(可更改)) (salt可不使用)
(注:对于string,bytes类型需要进行keccak256编码统一)

encodeData=keccak256(bytes(name), keccak256(bytes('1')), 1, address(this))

综上↓:

domainSqparator = keccak256( // domainSqparator 的定义可以看作是常量,因为合约创建之初就给定了
	abi.encode(keccak256('EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)'), 
	keccak256(bytes(name)), 
	keccak256(bytes('1')), 
	chainId, address(this) 
)

或者可以理解为:

domainSqparator = keccak256( encodeType , encodeData)

//***********************************************************************
//********************* 分割线*******************************************
//***********************************************************************

展开说明message

MESSAGE由两部分组成,
第一部分为对结构体类型的哈希——TYPEHASH,
第二部分为结构体的具体实现——message;

struct message {
    
    
	address owner,
	address spender,
	uint256 value,
	uint256 nonce,
	uint256 deadline
}

① TYPEHASH = keccak256(‘message(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)’)

② message = owner, spender, value, nonces[owner]++, deadline

综上↓

MESSAGE=keccak256(abi.encode(PERMIT_TYPEHASH, message))
(注意:domainSeparator,message都经过encode编码(按序拼接),keccak256处理)

//***********************************************************************
//********************** 分割线********************************************
//***********************************************************************

将上述拼接在一起再次进行编码、哈希,成为符合EIP-712标准的消息:

digest = keccak256( abi.encodePacked( ‘\x19\x01’, domainSqparator , MESSAGE )

此时的消息(digest)成为符合EIP-712标准的待签名消息,即通用签名方法中的data。
(注:待签名消息!=待签名交易 将已签名消息作为data打包进交易中给发送者签名,才能成为一个签名交易)

//***********************************************************************
//********************** 分割线********************************************
//***********************************************************************

链下签名:

async function signTypedData(signer) {
    
     

// 将domain的类型与赋值描述清楚
const domain = {
    
     name: "Uniswap V2", version: "1", chainId: 1, verifyingContract: "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC", } 

// 给出数据类型与名称
const types = {
    
     Permit: [ 
{
    
     name: "owner", type: "address" }, 
{
    
     name: "spender", type: "address" }, 
{
    
     name: "value", type: "uint256" }, 
{
    
     name: "nonce", type: "uint256" }, 
{
    
     name: "deadline", type: "uint256" }, ], } // The data to sign 

// 输入确定的数据数值
const value = {
    
     owner: xx, spender: xx, value: xx, nonce: xx, deadline: xx, } 

// 签名
const signature = await signer._signTypedData(domain, types, value) return signature }

*参考文献:
https://eips.ethereum.org/EIPS/eip-712#rationale-for-typehash
https://mirror.xyz/xyyme.eth/cJX3zqiiUg2dxB1nmbXbDcQ1DSdajHP5iNgBc6wEZz4
https://learnblockchain.cn/article/5012#%E7%AD%BE%E5%90%8D%E6%B6%88%E6%81%AF%EF%BC%88%20=presigned%20message%20=%20%E9%A2%84%E7%AD%BE%E5%90%8D%EF%BC%89
https://learnblockchain.cn/article/2753#%E5%85%83%E4%BA%A4%E6%98%93
https://mirror.xyz/adshao.eth/qmzSfrOB8s6_-s1AsflYNqEkTynShdpBE0EliqjGC1U

猜你喜欢

转载自blog.csdn.net/weixin_43380357/article/details/129737555
今日推荐