Solidity学习::(7)智能合约案例-2(验证签名)

椭圆曲线DSA(ECDSA)


对于这个,就不介绍了。

引用给出签名的生成和验证过程。

假如Alice要对消息m加上数字签名,而Bob需要验证该签名。

生成数字签名

  1. Alice根据随机数r和基点G求出点rG = (x, y);
  2. Alicce根据随机数r、消息m的散列值h、和私匙a计算

  3. 最后,Alice将消息m、点rG = (x, y)和s发送给Bob,其中点rG和s就是数字签名。

验证数字签名

  1. Bob接收到消息m、点rG = (x, y)和s。
  2. Bob根据消息求出散列值h。
  3. 最后,Bob根据上述信息,用Alice的公匙进行以下计算。

最后让上述计算结果与rG进行比较看是否相等。

如果签名结果正确,则计算结果应如下所示。

原书1中关于这部分看了三四遍,也没看明白。但觉得做程序的明白他大概要干个什么就好。大体上来说,对于要签名的数据m,使用它的哈希后的结果h,会生成签名。签名结果分为r,s,v三段值。其中r,s为32字节。v为一个字节,如果要用ecrecover()算法来验签,需对v值加27来组成27,28这两个值中的一个2


智能合约案例-2


一、打开remix-ide

http://remix.ethereum.org/#optimize=false


二、 先导内容

1、ecrecover函数

  • ecrecover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) returns (address)
  • ecrecover函数是由以太坊提供的一个全局函数,用于签名数据的校验。与上面所陈述的方式略有不同的是,这个函数返回的是签名者的公匙地址。如果返回结果是签名者的公匙地址,那么说明数据是正确的。
  • ecrecover函数需要四个参数,需要被签名数据的哈希结果值,r,s,v三个值。通过前面的说明,我们知道r,s,v是分别来自签名结果串。
r = signature[0:64]
s = signature[64:128]
v = signature[128:130]
  • 其中v取出来的值或者是0001。要使用时,我们先要将其转为整型,再加上27,所以我们将得到27或28。在调用函数时v将填入27或28。 

2、切片函数:

  function slice(bytes memory data,uint start,uint len) returns(bytes){
      bytes memory b=new bytes(len);
      for(uint i=0;i<len;i++){
          b[i]=data[i+start];
      }
      return b;
  }

3、 bytes类型转bytes32类型函数:

  function bytesToBytes32(bytes memory source) returns(bytes32 result){
      assembly{
          result :=mload(add(source,32))
      }
  }

四、案例合约功能

  • 若已知正确的对方公钥:0x60320b8a71bc314404ef7d194ad8cac0bee1e331
  • 且获取到原始数据的哈希sha3(msg),0x4e03657aea45a94fc7d47ba826c8d667c0d1e6e33a64a036ec44f58fa12d6c45 (web3.sha3("abc");)
  • 和发送来的已经签名的数据:0xf4128988cbe7df8315440adde412a8955f7f5ff9a5468a791433727f82717a6753bd71882079522207060b681fbd3f5623ee7ed66e33fc8e581f442acbc
  1. 本案例中合约实现的功能是:根据发送来的已签名的数据和原始数据的哈希,来推算出发送数据来的公钥地址。通过对比已知的正确的公钥,达到验证签名的目的

 五、合约代码

pragma solidity ^0.4.4;
contract Decode{
  //公匙:0x60320b8a71bc314404ef7d194ad8cac0bee1e331
  //公钥是用来算出来后对比看看是否一直一致的
  
  //sha3(msg): 0x4e03657aea45a94fc7d47ba826c8d667c0d1e6e33a64a036ec44f58fa12d6c45 (web3.sha3("abc");)
  //这个是数据的哈希,验证签名时用到
  
  //签名后的数据:0xf4128988cbe7df8315440adde412a8955f7f5ff9a5468a791433727f82717a6753bd71882079522207060b681fbd3f5623ee7ed66e33fc8e581f442acbcf6ab800
  //签名后的数据,包含r,s,v三个内容
  
  //验证签名入口函数
  function decode() returns (address){
      //这是一个已经签名的数据
      bytes memory signedString =hex"f4128988cbe7df8315440adde412a8955f7f5ff9a5468a791433727f82717a6753bd71882079522207060b681fbd3f5623ee7ed66e33fc8e581f442acbcf6ab800";
  
      bytes32 r=bytesToBytes32(slice(signedString,0,32));
      bytes32 s=bytesToBytes32(slice(signedString,32,32));
      byte v = slice(signedString,64,1)[0];
      return ecrecoverDecode(r,s,v);
      
  }
  
  //切片函数
  function slice(bytes memory data,uint start,uint len) returns(bytes){
      bytes memory b=new bytes(len);
      for(uint i=0;i<len;i++){
          b[i]=data[i+start];
      }
      return b;
  }
  //使用ecrecover恢复出公钥,后对比
  function ecrecoverDecode(bytes32 r,bytes32 s, byte v1) returns(address addr){
      uint8 v=uint8(v1)+27;
      addr=ecrecover(hex"4e03657aea45a94fc7d47ba826c8d667c0d1e6e33a64a036ec44f58fa12d6c45", v, r, s);
  }
  //bytes转换为bytes32
  function bytesToBytes32(bytes memory source) returns(bytes32 result){
      assembly{
          result :=mload(add(source,32))
      }
  }
}

六、操作展示

基本的步骤:

1、编译代码

2、部署合约

3、部署完成后,如下图 

4、点击decode函数,等待执行 

5、查看执行结果:

 

可以看到,这个输出的结果跟已知的对方公钥是一致的,那么就可以证明签名是正确的,数据确实是对方发出的。 

猜你喜欢

转载自blog.csdn.net/dieju8330/article/details/82858922
今日推荐