Skip to content

Latest commit

 

History

History
84 lines (68 loc) · 4.05 KB

File metadata and controls

84 lines (68 loc) · 4.05 KB

第二十八课 Hash

哈希函数(hash function)是一个密码学概念,它可以将任意长度的消息转换为一个固定长度的值,这个值也称作哈希(hash)。

hash的特点

  1. 单向性:从输入的消息到它的哈希的正向运算简单且唯一确定,而反过来非常难,只能靠暴力枚举。
  2. 灵敏性:输入的消息改变一点对它的哈希改变很大。
  3. 高效性:从输入的消息到哈希的运算高效。
  4. 均一性:每个哈希值被取到的概率应该基本相等。
  5. 抗碰撞性:
    • 弱抗碰撞性:给定一个消息x,找到另一个消息x',使得hash(x) = hash(x')是困难的。
    • 强抗碰撞性:找到任意x和x',使得hash(x) = hash(x')是困难的。

Hash的应用

  1. 生成数据唯一标识
  2. 加密签名
  3. 安全加密

Keccak256

Keccak256函数是Solidity中最常用的哈希函数,用法非常简单:

哈希 = keccak256(数据);

Keccak256和sha3

  • sha3由keccak标准化而来,在很多场合下Keccak和SHA3是同义词,但在2015年8月SHA3最终完成标准化时,NIST调整了填充算法。所以SHA3就和keccak计算的结果不一样,这点在实际开发中要注意。
  • 以太坊在开发的时候sha3还在标准化中,所以采用了keccak,所以Ethereum和Solidity智能合约代码中的SHA3是指Keccak256,而不是标准的NIST-SHA3,为了避免混淆,直接在合约代码中写成Keccak256是最清晰的。

第二十九课 函数选择器Selector

当我们调用智能合约时,本质上是向目标合约发送了一段calldata,在remix中发送一次交易后,可以在详细信息中看见input即为此次交易的calldata。发送的calldata中前4个字节是selector(函数选择器)。

msg.data

msg.data是Solidity中的一个全局变量,值为完整的calldata(调用函数时传入的数据)。

其实calldata就是告诉智能合约 ,我要调用哪个函数,以及参数是什么。

method id、selector和函数签名

  • method id定义为函数签名的Keccak哈希后的前4个字节,当selector与method id相匹配时,即表示调用该函数.
  • 函数签名:为"函数名(逗号分隔的参数类型)"。

构造selector

在函数签名中,uint和int要写为uint256和int256。

基础参数类型

基础类型的参数有:uint256(uint8, ... , uint256)、bool, address等。在计算method id时,只需要计算bytes4(keccak256("函数名(参数类型1,参数类型2,...)"))。

eg:

        // elementary(基础)类型参数selector
        // 输入:param1: 1,param2: 0
        // elementaryParamSelector(uint256,bool) : 0x3ec37834
        function elementaryParamSelector(uint256 param1, bool param2) external returns(bytes4 selectorWithElementaryParam){
            emit SelectorEvent(this.elementaryParamSelector.selector);
            return bytes4(keccak256("elementaryParamSelector(uint256,bool)"));
        }
映射类型参数

映射类型参数通常有:contract、enum、struct等。在计算method id时,需要将该类型转化成为ABI类型。 eg:

    contract DemoContract {
        // empty contract
    }

    contract Selector{
        // Struct User
        struct User {
            uint256 uid;
            bytes name;
        }
        // Enum School
        enum School { SCHOOL1, SCHOOL2, SCHOOL3 }
        ...
        // mapping(映射)类型参数selector
        // 输入:demo: 0x9D7f74d0C41E726EC95884E0e97Fa6129e3b5E99, user: [1, "0xa0b1"], count: [1,2,3], mySchool: 1
        // mappingParamSelector(address,(uint256,bytes),uint256[],uint8) : 0xe355b0ce
        function mappingParamSelector(DemoContract demo, User memory user, uint256[] memory count, School mySchool) external returns(bytes4 selectorWithMappingParam){
            emit SelectorEvent(this.mappingParamSelector.selector);
            return bytes4(keccak256("mappingParamSelector(address,(uint256,bytes),uint256[],uint8)"));
        }
        ...
    }