• Solidity基础语法代码2


    // SPDX-License-Identifier: MIT

    pragma solidity ^0.8.0;

    /*

        哈希算法具有两个特性:

            1. 输入值相同,输出值一定相同

            2. 不管输入值有多大,输出值是定长的,并且哈希算法是不可逆向运算的

        通常把哈希算法用在签名运算,或者是获取一个特定的id

        执行签名与验证签名操作步骤:

        1. getMessageHash 输入"secret message" 得到: 0x9c97d796ed69b7e69790ae723f51163056db3d55a7a6a82065780460162d4812

        2. 浏览器按f12打开控制台,输入ethereum.enable() 前提要装小狐狸钱包,这个函数会获取一个地址: "0xEc80445eb3363b49c93a902662bD11e3C8D197E8"

        3. 在浏览器定义变量:

           account = "0xEc80445eb3363b49c93a902662bD11e3C8D197E8"

           hash = "0x9c97d796ed69b7e69790ae723f51163056db3d55a7a6a82065780460162d4812"

        4. 执行函数得到签名

           ethereum.request({method: "personal_sign", params: [account, hash]})

           在小狐狸钱包点确认签名,得到签名数据: 0x686a1e541227e4edce4270a2508b486372eaa7eb63171605743b392d35f96ae721a4f58cc763497f7eb24b108e5fc9f6df1a0679c973d897c2d9d9ec0611cf0f1b

        5. 将getMessageHash得到的哈希值放在getEthSignedMessageHash再次签名,得到: 0x95a786464acc06fafc0d46036515722ec35acb840ecc291f251e086ebfeb9099

        6. 恢复签名进行验证在recover输入,参数1:步骤5哈希值 参数3:步骤4哈希值 点击call得到地址: 0xEc80445eb3363b49c93a902662bD11e3C8D197E8 该地址与步骤2地址相同,代表恢复完成了

        7. 再使用验证方法完整的验证一遍,在verfiy输入,参数1:步骤2地址 参数2:消息原文"secret message" 参数3:签名之后的数据即步骤4哈希值,结果返回true 签名验证通过

    */

    contract HashFunc {

        // 哈希返回值bytes32定长值

        function hash(string memory text, uint num, address addr) external pure returns (bytes32) {

            // 使用keccak256计算哈希,要先通过abi打包

            return keccak256(abi.encodePacked(text, num, addr));

        }

        // 使用abi.encode方式打包 会将结果哈希值补0

        function encode(string memory text1, string memory text2) external pure returns (bytes memory) {

            return abi.encode(text1, text2);

        }

        // 使用abi.encodePacded方式打包 不会将结果哈希值补0 不同的参数会产生相同的结果

        // "AAAA","BBB" 与 "AAA","ABBB" 结果都是 0x41414141424242

        function encodePacded(string memory text1, string memory text2) external pure returns (bytes memory) {

            return abi.encodePacked(text1, text2);

        }

        // 哈希碰撞实验,输入不同的参数来得到相同的哈希值

        // "AAAA","BBB" 与 "AAA","ABBB" 结果都是 0x11db58448f2a53848bef361744f19e6fdabef68b8267b1ff669de1b4c42da0da

        // 避免这种错误有两种解决方案:1. 使用encode打包 2. 在两个字符串之间添加一个数字类型:"AAAA",123,"BBB" 与 "AAA",123,"ABBB"

        function collision(string memory text1, string memory text2) external pure returns (bytes32) {

            return keccak256(abi.encodePacked(text1, text2));

        }

    }

    /*

      通过智能合约来验证签名,验证签名分4个步骤:

        1. 将消息签名 2. 将消息进行哈希 3. 再把消息和私钥进行签名(链下完成) 4. 恢复签名

    */

    contract VerfiySig {

        /*

            定义消息签名验证函数

            参数1. 签名人地址

            参数2. 消息原文

            参数3. 签名的结果

        */

        function verfiy(address _signer, string memory _message, bytes memory _sig)

            external pure returns (bool)

        {

            bytes32 messageHash = getMessageHash(_message);

            bytes32 ethSignedMessageHash = getEthSignedMessageHash(messageHash);

            // 恢复签名地址

            return recover(ethSignedMessageHash, _sig) == _signer;

        }

        // 将消息进行哈希运算

        function getMessageHash(string memory _message) public pure returns (bytes32) {

            return keccak256(abi.encodePacked(_message));

        }

        // 将哈希值再次进行哈希运算

        function getEthSignedMessageHash(bytes32 _messageHash) public pure returns (bytes32) {

            // 这里需要进行两次哈希运行,可以增加破解难度, 一次哈希运算有破解的可能性

            return keccak256(abi.encodePacked(

                "\x19Ethereum Signed Message:\n32",

                _messageHash

            ));

        }

        // 定义恢复函数 参数1:上面函数运算结果 参数2:不定长签名结果

        function recover(bytes32 _ethSignedMessageHash, bytes memory _sig)

           public pure returns (address)

        {

            // 返回非对称加密三个值r,s,v

            (bytes32 r, bytes32 s, uint8 v) = _split(_sig);

            // 使用智能合约内部函数恢复签名

            return ecrecover(_ethSignedMessageHash, v, r, s);

        }

        // 定义分割签名函数 输入长度要65位 32+32+1 uint8是1位

        function _split(bytes memory _sig) internal pure returns (bytes32 r, bytes32 s, uint8 v) {

            require(_sig.length == 65, "invalid signature length");

            // 使用内联汇编将bytes参数分割,原理就是签名参数就是用r、s、v三个参数拼接出来的

            assembly {

                // 使用mload内存读取,读取签名变量,使用add跳过32位长度,获取到_sig32位之后的32位

                r := mload(add(_sig, 32))      

                s := mload(add(_sig, 64))

                v := byte(0, mload(add(_sig, 96)))

            }

        }

    }


     

  • 相关阅读:
    使用Ascend八卡训练报错,len to make them match
    [flask]统一API响应格式
    【Android抓包】- Stetho
    AD7793驱动程序(详细)
    力扣:104. 二叉树的最大深度(Python3)
    (mac)Prometheus监控之Node_exporter(CPU、内存、磁盘、网络等)
    Django中事务的基本使用
    MYSQL慢SQL优化进阶
    STM32-HAL库08-TIM的输出比较模式(输出PWM的另一种方式)
    Linux centos7配置JDK环境
  • 原文地址:https://blog.csdn.net/yz2015/article/details/134479310