20190121NIP6_NULS主网底层添加随机数支持

 NIP: 6
 标题: NULS主网底层添加随机数支持的提案
 作者: Niels Wang <niels@nuls.io>
 讨论渠道: https://nuls.community/d/330-nuls
 状态: 接受
 类型: 核心
 创建日期: 2019/01/21

前言

随着DAPP越来越受到开发者们的青睐,运行在区块链上的DAPP也越来越多,不可避免的暴露出一些问题,比如很多博彩、游戏、抽奖活动、密码应用项目中,虽然标榜自己的去中心化特性,但实际上是不是真的安全、公平并不能百分之百的保证,核心问题就是去中心化随机数问题,目前大部分用到随机数的DAPP中,使用的随机数都不能做到既保证公平,又能让黑客无法根据随机过程提前预测随机结果。为此,通过NULS核心团队中大部分成员研究并讨论后,希望可以在NULS共识中增加一个机制,解决去中心化随机数种子生成问题。

NULS采用POC共识,参与共识的节点在满足条件的前提下,是持续参与出块(网络维护)的,并且参与出块的节点中绝大部分都是诚实可信的,我们可以利用这个优势,制定一个随机种子生成机制,服务于在NULS上搭建的DAPP。此随机种子需要满足随机性、不可预测性,做到既保证公平,又能让黑客无法根据随机过程提前预测或者控制随机结果。

摘要

本次设计的实现方式是基于POC共识的两段式提交的随机种子生成机制。即每个节点在出块的同时生成一个随机种子,并对该随机种子进行加密处理,将生成的密文包含在区块头中,同时获取该节点上次出块时生成的随机种子,将该种子的明文包含在区块头中,如此这般每个节点生成的随机种子都由前一个本节点出的块进行确认,确保不可随意篡改。生成最终随机种子的方式可以通过不同的算法,集合多个区块中的随机种子得出,从而保证随机性和安全性

动机

为了解决分布式随机数的安全、公平问题,对区块链网络底层进行优化,提供随机数种子获取机制,供DAPP开发者使用。

规范

  • 业务流程更改内容

    1、更改区块头创建流程

    在区块中增加数据,用于最终生成随机种子。

    2、更改新区块存储流程

    从区块头中解析随机种子,并根据高度进行存储

    3、增加获取随机种子接口

    增加RPC接口和SDK接口,用于应用获取随机种子。

1、在区块头的扩展字段(extend)中添加40个字节的数据,具体数据结构如下:

Length Field Data Type Remark
32 seed byte[32] 本区块提供的随机种子
8 nextSeedHash byte[8] 下一区块将提供的随机种子的SHA256-tiwce结果的截取值,用于验证

2、节点第一次出块时的处理逻辑

当节点第一次出块时,默认将seed设置为0,代表本次未产生新的随机种子。

3、节点丢失nextSeed的处理逻辑

当节点因为重启、断电、服务器迁移等原因,导致丢失seed时,可以将seed设置为0,代表当前区块丢失随机种子。

4、当一个节点连续出两个块时的处理逻辑

当一个节点在某个时间连续出块时,丢弃第二个块中的随机种子。这样做的原因是尽可能的确保随机种子的不可控。

5、提供多种供智能合约访问的获取随机种子的接口

  • 智能合约Native接口设计

    • 调用方式:Utils.getRandomSeed(param,param1)

    • 参数说明:

      Parameter Data type Required Remark
      Height Long True 获取种子的对应高度
      SeedsCount Integer True 从该高度向前寻找的区块种子数量
      algorithm String False 算法标识,底层可以支持多种随机种子生成方式

      [^注4]: algorithm:后续可以实现“1次SHA-256”,“2次SHA-256”,“Merkle Root”,Xor,"RIPEMD-160"等等算法,具体标识字符串以最终实现为准。

    • 返回值说明:

      Field Data type Remark
      success boolean 是否成功获取随机种子,成功:true,失败:false
      seed BigInteger 随机种子
      algorithm String 算法标识
    • 随机种子计算方式

      1、根据高度顺序拼接所有的区块种子
      2、对拼接后的字节数组进行SHA3-256计算
      3、将计算结果再进行一次SHA3-256计算
      4、返回计算结果
      
  • RPC接口

    • 调用方式:GET:/randomSeed

    • 参数说明:

      Parameter Data type Required Remark
      Height Long True 获取种子的对应高度
      SeedsCount Integer True 从该高度向前寻找的区块种子数量
      algorithm String False 算法标识,底层可以支持多种随机种子生成方式
    • 返回值说明:

      Field Data type Remark
      success boolean 是否成功获取随机种子,成功:true,失败:false
      seed String 随机种子
      algorithm String 算法标识

论据

当前区块链随机数生成的主要方式如下:

​ 1、根据链上未来数据生成,如未来块区块Hash等。

​ 2、结合外部数据生成,这种方式比较多样,如中心化随机数生成服务,由用户参与随机数生成的两段式提交等等。

第一种方式有一个缺点,就是出块节点可以控制随机数的生成结果,当随机数影响很大利益时,很难保证公平性。第二种虽然有很多种实现方式,但要么违背去中心化的初衷,要么没有很好的用户体验,要么不能很好的做到安全、不可预测。

针对这种情况,我们结合两种生成随机数的方式提出了NULS的解决方案,是使用未来块中的数据进行随机,但未来块中的数据在前期就已经先公布了Hash,已经不可以再篡改,同时每个随机种子的生成可以通过多个区块中的种子进行组合,每个种子生产前并不能知道前面块的种子,就让出块节点失去了控制随机数的可能。

本方案的优点:

​ 1、更公平,基于底层共识实现,全部共识节点参与,串联难度大。

​ 2、更安全,种子Hash与明文种子两段式提交,提交Hash时不能计算结果,提交结果时不能篡改。底层直接提供接口获取随机种子,随时可以根据参数进行验证。

​ 3、更灵活,随机种子计算方法支持多种算法,增加随机算法复杂度,提高作恶成本。

​ 4、更方便,底层直接提供接口获取随机种子,应用端使用时方便获取,安全、高效。在提供智能合约SDK接口的同时,还提供RPC接口的访问方式,不限制应用的使用场景。

风险点:

​ 1、如果一个应用指定未来某个高度生成随机数种子,那么该高度的区块打包者可以提前10s(出块间隔)知晓该随机种子。出块者如果提前发现自己区块的随机种子,对某个应用中自己的结果有非常不好的影响,那么他可以选择不提交该区块的随机种子。

针对该风险点,建议应用生成随机数时指定未来块高度时,不要指定过于靠近的区块,比如彩票应用,如果在停止投注后1个区块来开奖,就会有这个风险,但如果高度设置多一些,就可以避免。虽然可以通过共识惩罚的方式来增加作恶者的成本,但对共识的入侵太大了,并且该情况出现时只有刚好随机数是以某个节点来计算时才能有效,并且必须在10s内做出选择,选择的空间也只是提交和不提交两种,影响较小。所以大部分应用可以忽略这个风险点,小部分需要严格处理的应用可以在应用中编写逻辑,当选择的高度的区块本身没有提交随机种子,则等待下一个随机种子生成后再生成随机数。

向后兼容性

  • 向后不兼容

    因为添加了新的Native接口,当有智能合约调用该接口时,在历史版本中会出现异常,将导致网络分叉。

    本次修改可以通过协议升级的方式,在全部出块节点已有90%更新后,延迟30000块进行新协议生效,并在社区中大力宣传新版本内容,引导用户升级钱包。

测试用例

待完善

历史记录