首页 > 其他分享 >solidity签名机制和go联合调试学习

solidity签名机制和go联合调试学习

时间:2024-06-16 23:45:15浏览次数:27  
标签:name err uint256 solidity bytes32 version go 调试 string

1.solidity实现:

1.1.引入eip712合约:

// SPDX-License-Identifier: MIT

pragma solidity ^ 0.8.0;

/**
 * @dev https://eips.ethereum.org/EIPS/eip-712[EIP 712] is a standard for hashing and signing of typed structured data.
 *
 * The encoding specified in the EIP is very generic, and such a generic implementation in Solidity is not feasible,
 * thus this contract does not implement the encoding itself. Protocols need to implement the type-specific encoding
 * they need in their contracts using a combination of `abi.encode` and `keccak256`.
 *
 * This contract implements the EIP 712 domain separator ({_domainSeparatorV4}) that is used as part of the encoding
 * scheme, and the final step of the encoding to obtain the message digest that is then signed via ECDSA
 * ({_hashTypedDataV4}).
 *
 * The implementation of the domain separator was designed to be as efficient as possible while still properly updating
 * the chain id to protect against replay attacks on an eventual fork of the chain.
 *
 * NOTE: This contract implements the version of the encoding known as "v4", as implemented by the JSON RPC method
 * https://docs.metamask.io/guide/signing-data.html[`eth_signTypedDataV4` in MetaMask].
 *
 * _Available since v3.4._
 */
abstract contract EIP712 {
    /* solhint-disable var-name-mixedcase */
    // Cache the domain separator as an immutable value, but also store the chain id that it corresponds to, in order to
    // invalidate the cached domain separator if the chain id changes.
    // bytes32 private immutable _CACHED_DOMAIN_SEPARATOR;
    // uint256 private immutable _CACHED_CHAIN_ID;

    // bytes32 private immutable _HASHED_NAME;
    // bytes32 private immutable _HASHED_VERSION;
    // bytes32 private immutable _TYPE_HASH;
    /* solhint-enable var-name-mixedcase */

    /**
     * @dev Initializes the domain separator and parameter caches.
     *
     * The meaning of `name` and `version` is specified in
     * https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator[EIP 712]:
     *
     * - `name`: the user readable name of the signing domain, i.e. the name of the DApp or the protocol.
     * - `version`: the current major version of the signing domain.
     *
     * NOTE: These parameters cannot be changed except through a xref:learn::upgrading-smart-contracts.adoc[smart
     * contract upgrade].
     */
    // constructor(string memory name, string memory version) {
    //     bytes32 hashedName = keccak256(bytes(name));
    //     bytes32 hashedVersion = keccak256(bytes(version));
    //     bytes32 typeHash = keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)");
    //     _HASHED_NAME = hashedName;
    //     _HASHED_VERSION = hashedVersion;
    //     _CACHED_CHAIN_ID = _getChainId();
    //     _CACHED_DOMAIN_SEPARATOR = _buildDomainSeparator(typeHash, hashedName, hashedVersion);
    //     _TYPE_HASH = typeHash;
    // }
    bool private eipInitialized;

    bytes32 private _CACHED_DOMAIN_SEPARATOR;
    uint256 private _CACHED_CHAIN_ID;

    bytes32 private _HASHED_NAME;
    bytes32 private _HASHED_VERSION;
    bytes32 private _TYPE_HASH;
    function eip712Initialize(
        string memory name,
        string memory version
    ) internal {
        require(!eipInitialized, "eipInitialized: Already initialized!");
        bytes32 hashedName = keccak256(bytes(name));
        bytes32 hashedVersion = keccak256(bytes(version));
        bytes32 typeHash = keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)");
        _HASHED_NAME = hashedName;
        _HASHED_VERSION = hashedVersion;
        _CACHED_CHAIN_ID = _getChainId();
        _CACHED_DOMAIN_SEPARATOR = _buildDomainSeparator(typeHash, hashedName, hashedVersion);
        _TYPE_HASH = typeHash;
        eipInitialized = true;
    }
    /**
     * @dev Returns the domain separator for the current chain.
     */
    function _domainSeparatorV4() internal view virtual returns (bytes32) {
        if (_getChainId() == _CACHED_CHAIN_ID) {
            return _CACHED_DOMAIN_SEPARATOR;
        } else {
            return _buildDomainSeparator(_TYPE_HASH, _HASHED_NAME, _HASHED_VERSION);
        }
    }

    function _buildDomainSeparator(bytes32 typeHash, bytes32 name, bytes32 version) private view returns (bytes32) {
        return keccak256(
            abi.encode(
                typeHash,
                name,
                version,
                _getChainId(),
                address(this)
            )
        );
    }

    /**
     * @dev Given an already https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct[hashed struct], this
     * function returns the hash of the fully encoded EIP712 message for this domain.
     *
     * This hash can be used together with {ECDSA-recover} to obtain the signer of a message. For example:
     */
    function _hashTypedDataV4(bytes32 structHash) internal view virtual returns (bytes32) {
        return keccak256(abi.encodePacked("\x19\x01", _domainSeparatorV4(), structHash));
    }

    function _getChainId() private view returns (uint256 chainId) {
        this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
        // solhint-disable-next-line no-inline-assembly
        assembly {
            chainId := chainid()
        }
    }
}

1.2.eip712合约初始化:

// 初始化:主要是初始化eip712
    function initialize() external onlyAdmin {
        require(!initialized, "initialize: Already initialized!");
        eip712Initialize("RewardDistributor", "1.0.0");
        initialized = true;
    }
    

RewardDistributor是初始化eip712的name,

版本是1.0.0

1.3.eip712自定义初始化结构体:

_hashTypedDataV4(
                keccak256(
                    abi.encode(
                        keccak256(
                            "distribute(uint256 season,address to,uint256 uniqueId)"
                        ),
                        season,
                        to,
                        uniqueId
                    )
                )
            );

 注意:"distribute(uint256 season,address to,uint256 uniqueId)"这个字符串

1. 参数的顺序不能错,season/to/uniqueId

2. 这个字符串中间不能多出一些空格,只有类型后面有空格:"distribute(uint256 season,address to,       uint256 uniqueId)"这样就会导致签名不对

 

2.go实现:

2.1.eip712签名实现:

func SignWithEip712(privateKey *ecdsa.PrivateKey, typedData *apitypes.TypedData) ([]byte, error) {
	if privateKey == nil || typedData == nil {
		return nil, errors.New("invalid parameter")
	}

	// 1、获取需要签名的数据的 Keccak-256 的哈希
	domainSeparator, err := typedData.HashStruct("EIP712Domain", typedData.Domain.Map())
	if err != nil {
		return nil, err
	}
	typedDataHash, err := typedData.HashStruct(typedData.PrimaryType, typedData.Message)
	if err != nil {
		return nil, err
	}

	fmt.Printf("\n")
	fmt.Printf("domainSeparator: %s\n", hexutil.Encode(domainSeparator))
	fmt.Printf("typedDataHash: %s\n", hexutil.Encode(typedDataHash))

	rawData := []byte(fmt.Sprintf("\x19\x01%s%s", string(domainSeparator), string(typedDataHash)))
	sigHash := crypto.Keccak256(rawData)
	fmt.Printf("rawData: %s\n", hexutil.Encode(rawData))
	fmt.Printf("sigHash: %s\n", hexutil.Encode(sigHash))
	// 2、使用私钥签名哈希,得到签名
	signature, err := crypto.Sign(sigHash, privateKey)
	if err != nil {
		return nil, err
	}
	if signature[64] < 27 {
		signature[64] += 27
	}
	return signature, nil
}

2.2.自定义结构体实现:

func MedalNftSigner(
	privateKeyStr string,
	chainId int64,
	contract string,
	season int64,
	uniqueId int64,
	to string,
) (string, error) {
	// 签名
	typedData := &apitypes.TypedData{
		Types: apitypes.Types{
			"EIP712Domain": {
				{Name: "name", Type: "string"},
				{Name: "version", Type: "string"},
				{Name: "chainId", Type: "uint256"},
				{Name: "verifyingContract", Type: "address"},
			},
			"distribute": {
				{Name: "season", Type: "uint256"},
				{Name: "to", Type: "address"},
				{Name: "uniqueId", Type: "uint256"},
			},
		},
		Domain: apitypes.TypedDataDomain{
			Name:              "RewardDistributor",
			Version:           "1.0.0",
			ChainId:           math.NewHexOrDecimal256(chainId),
			VerifyingContract: contract,
			Salt:              "",
		},
		Message: map[string]interface{}{
			"season":   math.NewHexOrDecimal256(season),
			"to":       to,
			"uniqueId": math.NewHexOrDecimal256(uniqueId),
		},
		PrimaryType: "distribute",
	}

	privateKey, err := crypto.HexToECDSA(privateKeyStr)
	if err != nil {
		return "", err
	}

	signature, err := SignWithEip712(privateKey, typedData)
	if err != nil {
		return "", err
	}
	return hexutil.Encode(signature), nil
}

注意这部分参数的位置要和合约中的一致:

Message: map[string]interface{}{
"season":   math.NewHexOrDecimal256(season),
"to":       to,
"uniqueId": math.NewHexOrDecimal256(uniqueId),
},
PrimaryType: "distribute",

 

然后测试的话就没有问题了

标签:name,err,uint256,solidity,bytes32,version,go,调试,string
From: https://www.cnblogs.com/zhanchenjin/p/18251490

相关文章

  • Google Chrome Proxy error All In One
    GoogleChromeProxyerrorAllInOnemacOSWi-FiproxieswebproxyHTTPsecuritywebproxyHTTPSsocksproxydemos(......
  • c# 检测密码强度,评分规则仿google
    参考delphi的代码更改为C#Delphi检测密码强度规则(仿google)仿google评分规则一、密码长度:5分:小于等于4个字符10分:5到7字符25分:大于等于8个字符二、字母:0分:没有字母10分:全都是小(大)写字母20分:大小写混合字母三、数字:0分:没有数字10......
  • typora通过picgo配置图床
    满足大部分需求:gitee图床教程链接:https://zhuanlan.zhihu.com/p/567668223?utm_id=0但gitee有1M的图片限制,若需要高清图片,可配置腾讯云cos图床高清图片需求:腾讯云cos图床教程链接:https://cloud.tencent.com/developer/article/1834573两者优缺点对比:gitee腾讯云cos......
  • 【四种语言一网打尽(C\C++\Python\Golang)】L1-012 计算指数
    L1-012计算指数真的没骗你,这道才是简单题——对任意给定的不超过10的正整数n,要求你输出2^n。不难吧?输入格式:输入在一行中给出一个不超过10的正整数n。输出格式:在一行中按照格式2^n=计算结果输出2^n的值。输入样例:5输出样例:2^5=32C语言参考......
  • solidity byte32转字符串日志输出学习
    直接上代码://SPDX-License-Identifier:MITpragmasolidity^0.8.0;abstractcontractEIP712{eventLogValues(bytes32domainSeparator,bytes32structHash);function_hashTypedDataV4(bytes32structHash)internalvirtualreturns(bytes32){......
  • 【四种语言一网打尽(C\C++\Python\Golang)】L1-009 N个数求和
    L1-009N个数求和本题的要求很简单,就是求N个数字的和。麻烦的是,这些数字是以有理数分子/分母的形式给出的,你输出的和也必须是有理数的形式。输入格式:输入第一行给出一个正整数N(≤100)。随后一行按格式a1/b1a2/b2…给出N个有理数。题目保证所有分子和分母都在长整型范围......
  • Go Goroutine 究竟可以开多少?(详细介绍)
    GoGoroutine究竟可以开多少?Go语言因其高效的并发处理能力而备受欢迎,而Goroutine则是Go语言实现并发编程的核心。Goroutine比传统的线程更加轻量,允许开发者轻松地处理大量并发任务。那么,Go语言中的Goroutine究竟可以开多少呢?在回答这个问题之前,我们需要先了解两个关键问题......
  • 百度翻译逆向Acs-Token逆向百度翻译爬虫(调试篇)
    文章声明本文章中所有内容仅供学习交流,严禁用于商业用途和非法用途,否则由此产生的一切后果均与文章作者无关,若有侵权,请联系我立即删除!概要-该篇文章是基于translate接口的分析-用到的工具Edge浏览器逆向目标求参数Acs-Token上一篇百度翻译是技巧篇,这篇来带着......
  • 如何从0到1实现一个go语言代码项目
    创建一个Go语言项目是一个逐步的过程,这里我将为你提供一个简单的项目示例,包括一些基础步骤来帮助你从0开始实现一个Go语言项目。步骤1:安装Go语言环境首先,你需要在你的计算机上安装Go语言环境。你可以从[Go官网](https://golang.org/dl/)下载适合你操作系统的安装包。......
  • 基于Typora、Gitee和picgo搭建图床
    基于Typora、Gitee和picgo搭建图床使用Typora编辑文本上传图片的时候,会发现图片都是保存在本地的,如果上传到博客图片会显示不出来,还需要自己手动一张一张往上贴,怎么解决?(1)首先下载一个picgo链接:https://pan.baidu.com/s/1Uf5BH7EegbhcLJ-CwUpceQ?pwd=ezta提取码:ezta......