BTC之隨機數(shù)生成

1冈涧、概念

有兩個最主要的方法來生成隨機數(shù):

a) 通過測量某些隨機的物理現(xiàn)象茂附,然后補償測量過程中可能出現(xiàn)的偏差。比如大氣噪聲督弓、熱噪聲和其他外部電磁以及量子現(xiàn)象逻锐。從自然資源中獲取熵的速度取決于被測量的潛在物理現(xiàn)象伸辟,因此它們的速率是有限的哟楷,往往比較慢爱沟。
b) 使用計算算法,可以產(chǎn)生明顯隨機結果的長序列奸攻,實際上由較短的初始值(稱為種子)確定蒜危。結果是,如果種子的值是已知的睹耐,整個看似隨機的序列可以被重復產(chǎn)生辐赞。這類隨機數(shù)生成器被稱為偽隨機數(shù)生成器。這類生成器類型是非阻塞的硝训,可以大量產(chǎn)生數(shù)據(jù)响委。

2新思、不同的隨機數(shù)生成方法

  • 類Linux系統(tǒng)下的 /dev/random

/dev/random 可以用作隨機數(shù)生成器或者偽隨機數(shù)生成器,取決于不同的實現(xiàn)赘风。
在linux下夹囚,隨機數(shù)生成器有一個容納噪聲數(shù)據(jù)的熵池,在讀取時邀窃,/dev/random設備會返回小于熵池噪聲總數(shù)的隨機字節(jié)荸哟。/dev/random可生成高隨機性的公鑰一次性密碼本。若熵池空了瞬捕,對/dev/random的讀操作將會被阻塞鞍历,直到收集到了足夠的環(huán)境噪聲為止。這樣的設計使得/dev/random是真正的隨機數(shù)發(fā)生器肪虎,提供了最大可能的隨機數(shù)據(jù)熵劣砍,建議在需要生成高強度的密鑰時使用。

/dev/urandom(“unblocked”扇救,非阻塞的隨機數(shù)發(fā)生器)刑枝,它會重復使用熵池中的數(shù)據(jù)以產(chǎn)生偽隨機數(shù)據(jù)。這表示對/dev/urandom的讀取操作不會產(chǎn)生阻塞爵政,但其輸出的熵可能小于/dev/random的。它可以作為生成較低強度密碼的偽隨機數(shù)生成器陶缺,不建議用于生成高強度長期密碼钾挟。

FreeBSD操作系統(tǒng)實現(xiàn)了256位的Yarrow算法變體,以提供偽隨機數(shù)流饱岸。與Linux的/dev/random不同掺出,F(xiàn)reeBSD的/dev/random不會產(chǎn)生阻塞,與Linux的/dev/urandom相似苫费,提供了密碼學安全的偽隨機數(shù)發(fā)生器汤锨,而不是基于熵池。而FreeBSD的/dev/urandom則只是簡單的鏈接到了/dev/random百框。

void GetDevURandom(unsigned char *ent32)
{
    int f = open("/dev/urandom", O_RDONLY);
    if (f == -1) {
        RandFailure();
    }
    int have = 0;
    do {
        ssize_t n = read(f, ent32 + have, NUM_OS_RANDOM_BYTES - have);
        if (n <= 0 || n + have > NUM_OS_RANDOM_BYTES) {
            close(f);
            RandFailure();
        }
        have += n;
    } while (have < NUM_OS_RANDOM_BYTES);
    close(f);
}
  • 類Linux系統(tǒng)其他獲取隨機數(shù)方法

  • Linux下的SYS_getrandom

int rv = syscall(SYS_getrandom, ent32, NUM_OS_RANDOM_BYTES, 0);
  • OpenBSD下的getentropy
getentropy(ent32, NUM_OS_RANDOM_BYTES)
  • FreeBSD下的sysctl
    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);
  • OpenSSL的隨機數(shù)生成

OpenSSL的提供了RAND_bytes方法生成隨機數(shù)闲礼。在使用之前需要使用RAND_add向PRNG中添加種子及熵值。種子可以通過TSC生成铐维。

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

void GetRandBytes(unsigned char* buf, int num)
{
    if (RAND_bytes(buf, num) != 1) {
        RandFailure();
    }
}
  • Windows平臺

CryptoAPI提供了CryptGenRandom方法產(chǎn)生隨機數(shù)柬泽。CryptGenRandom已經(jīng)被廢棄,應該使用新版CNG API:BCryptGenRandom

    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);
  • 硬件方法:

CPU指令rdrand從芯片的硬件隨機數(shù)生成器中獲取隨機數(shù)

    uint32_t eax, ebx, ecx, edx;
    if (__get_cpuid(1, &eax, &ebx, &ecx, &edx) && (ecx & CPUID_F1_ECX_RDRAND)) {
    }

32位:

            uint32_t r1, r2;
            __asm__ volatile (".byte 0x0f, 0xc7, 0xf0;" // rdrand %eax
                              ".byte 0x0f, 0xc7, 0xf2;" // rdrand %edx
                              "setc %2" :
                              "=a"(r1), "=d"(r2), "=q"(ok) :: "cc");
            if (!ok) return false;
            WriteLE32(ent32 + 8 * iter, r1);
            WriteLE32(ent32 + 8 * iter + 4, r2);
        }

64位:

        uint64_t r1, r2, r3, r4;
        __asm__ volatile (".byte 0x48, 0x0f, 0xc7, 0xf0, " // rdrand %rax
                                "0x48, 0x0f, 0xc7, 0xf3, " // rdrand %rbx
                                "0x48, 0x0f, 0xc7, 0xf1, " // rdrand %rcx
                                "0x48, 0x0f, 0xc7, 0xf2; " // rdrand %rdx
                          "setc %4" :
                          "=a"(r1), "=b"(r2), "=c"(r3), "=d"(r4), "=q"(ok) :: "cc");
        if (!ok) return false;
        WriteLE64(ent32, r1);
        WriteLE64(ent32 + 8, r2);
        WriteLE64(ent32 + 16, r3);
        WriteLE64(ent32 + 24, r4);

3嫁蛇、BTC生成隨機數(shù)的方法

BTC采用了多種方式混合的形式锨并,將OpenSSL隨機數(shù)生成、OS隨機數(shù)生成睬棚、硬件隨機數(shù)生成再混淆隨機數(shù)發(fā)生器的狀態(tài)來生成強隨機數(shù)第煮。

void GetStrongRandBytes(unsigned char* out, int num)
{
    assert(num <= 32);
    CSHA512 hasher;
    unsigned char buf[64];

    // First source: OpenSSL's RNG
    RandAddSeedPerfmon();
    GetRandBytes(buf, 32);
    hasher.Write(buf, 32);

    // Second source: OS RNG
    GetOSRand(buf);
    hasher.Write(buf, 32);

    // Third source: HW RNG, if available.
    if (GetHWRand(buf)) {
        hasher.Write(buf, 32);
    }

    // Combine with and update state
    {
        std::unique_lock<std::mutex> lock(cs_rng_state);
        hasher.Write(rng_state, sizeof(rng_state));
        hasher.Write((const unsigned char*)&rng_counter, sizeof(rng_counter));
        ++rng_counter;
        hasher.Finalize(buf);
        memcpy(rng_state, buf + 32, 32);
    }

    // Produce output
    memcpy(out, buf, num);
    memory_cleanse(buf, 64);
}

參考文檔:

https://en.wikipedia.org/wiki/Random_number_generation#%22True%22_vs._pseudo-random_numbers

https://zh.wikipedia.org/wiki//dev/random

https://www.openssl.org/docs/man1.0.2/crypto/RAND_seed.html

https://zh.wikipedia.org/zh-hans/RdRand

版權歸本人所有,如需轉載,請注明出處

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末解幼,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子包警,更是在濱河造成了極大的恐慌撵摆,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,839評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件揽趾,死亡現(xiàn)場離奇詭異台汇,居然都是意外死亡,警方通過查閱死者的電腦和手機篱瞎,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,543評論 2 382
  • 文/潘曉璐 我一進店門苟呐,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人俐筋,你說我怎么就攤上這事牵素。” “怎么了澄者?”我有些...
    開封第一講書人閱讀 153,116評論 0 344
  • 文/不壞的土叔 我叫張陵笆呆,是天一觀的道長。 經(jīng)常有香客問我粱挡,道長赠幕,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,371評論 1 279
  • 正文 為了忘掉前任询筏,我火速辦了婚禮榕堰,結果婚禮上,老公的妹妹穿的比我還像新娘嫌套。我一直安慰自己逆屡,他們只是感情好,可當我...
    茶點故事閱讀 64,384評論 5 374
  • 文/花漫 我一把揭開白布踱讨。 她就那樣靜靜地躺著魏蔗,像睡著了一般。 火紅的嫁衣襯著肌膚如雪痹筛。 梳的紋絲不亂的頭發(fā)上莺治,一...
    開封第一講書人閱讀 49,111評論 1 285
  • 那天,我揣著相機與錄音帚稠,去河邊找鬼产雹。 笑死,一個胖子當著我的面吹牛翁锡,可吹牛的內(nèi)容都是我干的蔓挖。 我是一名探鬼主播,決...
    沈念sama閱讀 38,416評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼馆衔,長吁一口氣:“原來是場噩夢啊……” “哼瘟判!你這毒婦竟也來了怨绣?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 37,053評論 0 259
  • 序言:老撾萬榮一對情侶失蹤拷获,失蹤者是張志新(化名)和其女友劉穎篮撑,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體匆瓜,經(jīng)...
    沈念sama閱讀 43,558評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡赢笨,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,007評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了驮吱。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片茧妒。...
    茶點故事閱讀 38,117評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖左冬,靈堂內(nèi)的尸體忽然破棺而出桐筏,到底是詐尸還是另有隱情,我是刑警寧澤拇砰,帶...
    沈念sama閱讀 33,756評論 4 324
  • 正文 年R本政府宣布梅忌,位于F島的核電站,受9級特大地震影響除破,放射性物質發(fā)生泄漏牧氮。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,324評論 3 307
  • 文/蒙蒙 一瑰枫、第九天 我趴在偏房一處隱蔽的房頂上張望踱葛。 院中可真熱鬧,春花似錦躁垛、人聲如沸剖毯。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,315評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至擂达,卻和暖如春土铺,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背板鬓。 一陣腳步聲響...
    開封第一講書人閱讀 31,539評論 1 262
  • 我被黑心中介騙來泰國打工悲敷, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人俭令。 一個月前我還...
    沈念sama閱讀 45,578評論 2 355
  • 正文 我出身青樓后德,卻偏偏與公主長得像,于是被迫代替她去往敵國和親抄腔。 傳聞我的和親對象是個殘疾皇子瓢湃,可洞房花燭夜當晚...
    茶點故事閱讀 42,877評論 2 345

推薦閱讀更多精彩內(nèi)容

  • 很多庫例程產(chǎn)生的“隨機”數(shù)是準備用于仿真理张、游戲等等;它們在被用于密鑰生成一類的安全函數(shù)時是不夠隨機的绵患。其問題在于這...
    夏大王2019閱讀 1,762評論 0 0
  • 最近項目上線部署的時候雾叭,發(fā)現(xiàn)一個問題。Tomcat在啟動過程中耗費了很長的時間落蝙。查看日志织狐,發(fā)現(xiàn)耗時最長的地方是: ...
    倔強的小亮閱讀 4,929評論 0 3
  • 一、bash有內(nèi)建的隨機數(shù)生成器: 在shell中有一個環(huán)境變量RANDOM,它的范圍是0--32767 1筏勒、如果...
    靜默閱讀 2,699評論 1 1
  • 方法1 (數(shù)據(jù)類型)(最小值+Math.random()*(最大值-最小值+1)) 例: (int)(1+Math...
    GB_speak閱讀 40,961評論 2 6
  • 臨海的空氣會黏人移迫,每個毛孔都被黏得暈暈乎乎的。 一下火車就有種作繭自縛的感覺奏寨,風纏著你起意,鉆入你的七竅、毛孔病瞳、發(fā)...
    王馨積水成淵閱讀 615評論 0 3