美文网首页
比特币源码研读之一随机种子生成

比特币源码研读之一随机种子生成

作者: 韬声依旧在路上 | 来源:发表于2018-05-07 11:00 被阅读288次

本文由【区块链研习社】优质内容计划支持,更多关于区块链的深度好文,请点击【区块链研习社

本文作者:区块链研习比特币源码研读班 韬声依旧在路上

从今天开始我为大家解读比特币源码的随机种子生成功能,该源码所在位置为bitcoin/src/random.hbitcoin/src/random.cpp。该源文件主要实现的功能就是实现随机数的生成,然后用于随后的私钥生成最后生成比特币地址。

使用场景假设

我们先搜索一下随机种子生成用到哪些地方,在VSCode的搜索标签中输入src/*.cpp,然后按回车即可在左侧窗口看到如下结果。

搜索结果 - 图片来自简书App

那我们大胆猜测一下随机种子生成使用的可能的场景如下

文件名 可能场景
addrdb.cpp 数据库读写
blockencodings.php 区块头部数据写入
bloom.cpp 随机数据结构过滤
coins.cpp 比特币批量写入
dbwrapper.cpp LevelDB数据库封装
httprpc.cpp HTTPRPC接口

核心方法声明

我们先来看bitcoin/src/random.h文件中定义了那些方法

/* Seed OpenSSL PRNG with additional entropy data */
void RandAddSeed();
/**
 * Functions to gather random data via the OpenSSL PRNG
 */
void GetRandBytes(unsigned char* buf, int num);
uint64_t GetRand(uint64_t nMax);
int GetRandInt(int nMax);
uint256 GetRandHash();

void RandAddSeedSleep();

/**
 * Function to gather random data from multiple sources, failing whenever any
 * of those source fail to provide a result.
 */
void GetStrongRandBytes(unsigned char* buf, int num);

/** Get 32 bytes of system entropy. Do not use this in application code: use
 * GetStrongRandBytes instead.
 */
void GetOSRand(unsigned char *ent32);

/** Check that OS randomness is available and returning the requested number
 * of bytes.
 */
bool Random_SanityCheck();

/** Initialize the RNG. */
void RandomInit();
方法名称 实现功能
void RandAddSeed(); 利用OpenSSL的伪随机数发生器(PRNG)生成带有熵数据的种子
void GetRandBytes(unsigned char* buf, int num); 通过OpenSSL的PRNG生成随机数据
uint64_t GetRand(uint64_t nMax); 获取随机数
int GetRandInt(int nMax); 获取随机整数
uint256 GetRandHash(); 获取随机哈希值
void RandAddSeedSleep(); 设置随机数生成休眠时间并写入数据到RNG
void GetStrongRandBytes(unsigned char* buf, int num); 从多个数据源获取随机数,若失败则返回
void GetOSRand(unsigned char *ent32); 获取操作系统中的随机数
bool Random_SanityCheck(); 检查操作系统中随机函数是否可用
void RandomInit(); 初始化RNG

重要方法解读

RandAddSeed方法

方法定义位置bitcoin/src/random.h文件的第16行,具体实现在bitcoin/src/random.cpp的第130到136行。

void RandAddSeed()
{
    // Seed with CPU performance counter
    int64_t nCounter = GetPerformanceCounter();
    RAND_add(&nCounter, sizeof(nCounter), 1.5);
    memory_cleanse((void*)&nCounter, sizeof(nCounter));
}

具体执行的步骤如下

  • 获取硬件的时间戳计数器
  • 生成随机数
  • 执行内存清理

GetOSRand方法

方法定义位置bitcoin/src/random.h文件的第136行,具体实现在bitcoin/src/random.cpp的第201到271行。

/** Get 32 bytes of system entropy. */
void GetOSRand(unsigned char *ent32)
{
#if defined(WIN32)
    HCRYPTPROV hProvider;
    int ret = CryptAcquireContextW(&hProvider, nullptr, nullptr, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT);
    if (!ret) {
        RandFailure();
    }
    ret = CryptGenRandom(hProvider, NUM_OS_RANDOM_BYTES, ent32);
    if (!ret) {
        RandFailure();
    }
    CryptReleaseContext(hProvider, 0);
#elif defined(HAVE_SYS_GETRANDOM)
    /* Linux. From the getrandom(2) man page:
     * "If the urandom source has been initialized, reads of up to 256 bytes
     * will always return as many bytes as requested and will not be
     * interrupted by signals."
     */
    int rv = syscall(SYS_getrandom, ent32, NUM_OS_RANDOM_BYTES, 0);
    if (rv != NUM_OS_RANDOM_BYTES) {
        if (rv < 0 && errno == ENOSYS) {
            /* Fallback for kernel <3.17: the return value will be -1 and errno
             * ENOSYS if the syscall is not available, in that case fall back
             * to /dev/urandom.
             */
            GetDevURandom(ent32);
        } else {
            RandFailure();
        }
    }
#elif defined(HAVE_GETENTROPY) && defined(__OpenBSD__)
    /* On OpenBSD this can return up to 256 bytes of entropy, will return an
     * error if more are requested.
     * The call cannot return less than the requested number of bytes.
       getentropy is explicitly limited to openbsd here, as a similar (but not
       the same) function may exist on other platforms via glibc.
     */
    if (getentropy(ent32, NUM_OS_RANDOM_BYTES) != 0) {
        RandFailure();
    }
#elif defined(HAVE_GETENTROPY_RAND) && defined(MAC_OSX)
    // We need a fallback for OSX < 10.12
    if (&getentropy != nullptr) {
        if (getentropy(ent32, NUM_OS_RANDOM_BYTES) != 0) {
            RandFailure();
        }
    } else {
        GetDevURandom(ent32);
    }
#elif defined(HAVE_SYSCTL_ARND)
    /* FreeBSD and similar. It is possible for the call to return less
     * bytes than requested, so need to read in a loop.
     */
    static const int name[2] = {CTL_KERN, KERN_ARND};
    int have = 0;
    do {
        size_t len = NUM_OS_RANDOM_BYTES - have;
        if (sysctl(name, ARRAYLEN(name), ent32 + have, &len, nullptr, 0) != 0) {
            RandFailure();
        }
        have += len;
    } while (have < NUM_OS_RANDOM_BYTES);
#else
    /* Fall back to /dev/urandom if there is no specific method implemented to
     * get system entropy for this OS.
     */
    GetDevURandom(ent32);
#endif
}

具体执行的步骤如下

  1. 根据宏定义判断是否为Windows32位系统并根据系统内置的函数提供者并配合随机函数生成随机数
  2. 如果是Linux系统则使用urandom来获取对应字节的随机数
  3. 如果存在系统熵并且系统是macOSX,那么判断系统版本并返回系统使用的urandom生成随机数

总结

现在才知道只是一个随机种子生成就这么多实现逻辑,那么对于整个比特币系统而言,那是多么一个庞大的工程,我自己也是刚刚上路,自己对于C++语言的掌握还停留在入门阶段,结合源码研读和手头上的几本书就开始研读之路了,我必须抱着谦虚敬畏的态度去看待比特币,我也相信时间会让我成长,也让我看清区块链行业的风险和机遇,我更是想通过研读比特币源码来提升自己的编程水平,当然看待这个行业的角度我希望有不一样的视角。本文会不断随着对比特币源码的解读不定期的进行更新,欢迎大家关注和探索比特币底层的逻辑世界。

相关文章

  • 比特币源码研读

    forest21000版 比特币源码研读之一比特币源码研读之二比特币源码研读之三比特币源码研读之四比特币源码研读之...

  • 比特币源码研读之一随机种子生成

    本文由【区块链研习社】优质内容计划支持,更多关于区块链的深度好文,请点击【区块链研习社】 本文作者:区块链研习比特...

  • 比特币源码研读之一

    比特币源码研读之一——区块链研习社 《比特币源码研读班》 一看文件夹结构 和 github编译依赖,分析的依赖库 ...

  • 比特币源码研读之十一

    比特币源码研读系列已经发表了十篇了,通过这十篇源码研读系列让我对比特币源码及比特币运行原理有了进一步的理解,也让我...

  • 比特币源码研读之一

    作者:区块链研习比特币源码研读班 菜菜子 一、源码下载 本文比特币源码下载地址为:https://github.c...

  • 比特币源码研读之一

    本人15年毕业后一直从事Java电商平台的开发工作,2017年4月开始接触区块链技术,随后慢慢自学了《精通比特币》...

  • 比特币源码研读之二

    区块链研习社比特币源码研读班今天研读第二,第三流程,SetupEnvironment和noui_connect函数...

  • 比特币BTC源码分析(1):地址生成过程

    一、生成一个比特币钱地址 二、根据源码整理比特币地址生成过程 1、取得公钥PubKey 2、使用 RIPEMD16...

  • 01:比特币源码编译|比特币源码研读

    2018年8月报名了区块链研习社的「比特币源码研读班」(5期)。首先要准备比特币源码的编译,因为对这块几乎是小白水...

  • 编译bitcoin源码

    ——区块链研习社 《比特币源码研读班》 本文基于ubuntu 16.04 64编译ok 一 下载源码(如没安装gi...

网友评论

      本文标题:比特币源码研读之一随机种子生成

      本文链接:https://www.haomeiwen.com/subject/svtykftx.html