EOS 07 - EOS 智能合约如何生成安全的随机数?

pendingauth · 2019年07月01日 · 81 次阅读

本文转载自币乎,作者松果,原文链接: https://bihu.com/article/1637009938

这篇文章本来准备写DAPP的业务逻辑合约weiwendappss,恰好这部分代码涉及到随机数的生成,随机数又是智能合约安全中很重要的部分(EOS链上已有多个菠菜游戏因为随机数算法被攻破遭受损失),因此先研究一下EOS智能合约中的安全随机数问题。

随机数的分类 随机数分为真随机数和伪随机数:

真随机数(true random number):由物理现象产生的随机数,比如掷钱币、骰子、电子元件噪音、核裂变等; 伪随机数(pseudo-random number):通过种子(seed)和确定性算法计算出来的随机数;

计算机编程产生的随机数一般都是伪随机数,根据预测难度,伪随机数又分为强伪随机数和弱伪随机数。

安全的随机数 随机数安全主要体现在随机性和不可预测性,要生成安全的随机数,首先需要一个稳定的熵源(entropy);

要在区块链上生成稳定熵源是比较困难的,但可以通过算法尽可能地提高破解难度,另外可以通过预言机(oracle)引入链外熵源。

在EOS智能合约中生成随机数 在weiwendappss合约中生成随机数的算法,参考了EOS Knights的随机数生成器,不过EOS Knights的随机数算法代码基于的是较老版本的eosio.cdt,为了适用于最新版(v1.6.1)的eosio.cdt,对代码进行了一些修改:

class random_gen { private: static random_gen instance; uint64_t seed = 0;

public: static random_gen& get_instance(name account) { instance.seed = current_time_point().time_since_epoch().count() + account.value; return instance; }

uint32_t range(uint32_t to) { checksum256 result = sha256((char *)&seed, sizeof(seed)); auto arr = result.extract_as_byte_array(); seed = arr[1]; seed <<= 32; seed |= arr[0]; return (uint32_t)(seed % to); }

uint32_t range(uint32_t from, uint32_t to) { if(from == to){ return from; }else if(from < to){ return range(to - from + 1) + from; } return range(to); } }; 定义了一个random_gen类作为随机数生成器,使用当前时间戳微秒数和账户名值的和作为种子。

使用get_instance函数获取实例后,调用range(to)函数可以获得 [0, to) 范围的随机数,例如:

random_gen().get_instance(account).range(5); 可以随机获取 0、1、2、3、4 这5个数之一。

range(to)函数的值域范围是一个左闭右开区间,并且是从0开始的,不能满足weiwendappss合约每日签到领币的需求,因此扩展了一个全闭区间值域范围为[from, to]的range(from, to)函数:

random_gen().get_instance(account).range(1000,5000); 可以随机获取1000~5000范围内共计4001个数之一。

Tips 这篇文章使用的随机数算法是比较简单的,因为涉及到的业务场景不复杂,如果是对安全需求更高的(比如菠菜类)DAPP,应该尽量使用更安全的随机数算法。

项目代码在Github同步更新:https://github.com/songguo6/weiwen-dapp

暂无回复。
需要 登录 后方可回复, 如果你还没有账号请点击这里 注册