mt19937 PRNGを簡潔、移植性、完全にシードする方法


112

私は誰かが<random>乱数を生成するために使用することを提案する多くの答えを見るようです、通常は次のようなコードと共に:

std::random_device rd;  
std::mt19937 gen(rd());
std::uniform_int_distribution<> dis(0, 5);
dis(gen);

通常、これは次のようなある種の「不吉な嫌悪」に取って代わります。

srand(time(NULL));
rand()%6;

我々は可能性がある批判侃々諤々で古い方法をtime(NULL)、低エントロピーを提供しtime(NULL)、予測可能であり、最終結果は不均一です。

しかし、それはすべて新しい方法に当てはまります。光沢のあるベニヤしかありません。

  • rd()単一のを返しますunsigned int。これは、少なくとも16ビット、おそらく32ビットです。MTの19937ビットの状態をシードするのに十分ではありません。

  • 使用してstd::mt19937 gen(rd());gen()(32ビットで播種し、第一の出力を見て)良好な出力分布を与えません。7と13が最初の出力になることはありません。2つの種子は0を生成します。12の種子は1226181350を生成します。(リンク

  • std::random_device固定シードを持つ単純なPRNGとして実装できます。したがって、実行ごとに同じシーケンスが生成される可能性があります。(リンク)これはさらに悪いですtime(NULL)

さらに悪いことに、前述のコードスニペットに含まれる問題にもかかわらず、コピーして貼り付けるのは非常に簡単です。これに対するいくつかの解決策は、すべての人に適しているわけではないかもしれない大量の ライブラリを取得する必要があります。

これに照らして、私の質問は、mt19937 PRNGをC ++で簡潔、移植可能、および完全にシードするにどうすればよいですか?

上記の問題を考えると、良い答え:

  • mt19937 / mt19937_64を完全にシードする必要があります。
  • だけに頼ることはできないstd::random_deviceか、time(NULL)エントロピーの源として。
  • Boostや他のライブラリに依存すべきではありません。
  • 少数の行に収まるようにして、回答にコピー貼り付けして見栄えをよくする必要があります。

考え

  • 私の現在の考えは、か​​らの出力をstd::random_device(おそらくXORを介して)マッシュアップしtime(NULL)アドレス空間のランダム化から派生した値、およびハードコーディングされた定数(配布中に設定できる)を使用して、エントロピーでベストエフォートショットを取得できると考えています。

  • std::random_device::entropy() ていないものの良い指標を与えるstd::random_deviceか、しない場合がありますが。


24
@ファビエン:それについて移植性があるのは何ですか?これはC ++の質問であり、Linuxの質問ではありません。
オービットでの軽さのレース

6
私の個人的な考えは、おそらく値から引き出すことができたということであったstd::random_devicetime(NULL)と、関数アドレスは、ベストエフォート型のエントロピー源の種類を生成するために一緒にXOR演算します。
リチャード

5
does_random_device_actually_work()などの関数があれば、少なくとも正常に機能を低下させたり、ユーザーに警告やエラーを生成したりできると便利です。

4
適切な解決策は短くありません、短い解決策は適切ではありません。私は私の中で使う私のアプローチseed11ライブラリを実装するために基本的にstd::random_deviceシードされた発電機を作成するヘルパー関数をあなたのプラットフォーム上で適切にあなたのプログラムを実行するためにしている計画を、と提供(seed11::make_seeded<std::mt19937>()
milleniumbug

5
余談ですが、2番目の箇条書きは新しいものを追加しません。12回出現する値を見つけたのは当然のことです。2 ^ 32の独立した一様にランダムなサンプルがあると仮定すると、正確に12回表示される値は3つを超えると予想されます。

回答:


58

std::random_deviceCSPRNGが利用できない場合に確定的フォールバックが許可されるというのが最大の欠点だと私は主張します。std::random_device生成されるバイトは確定的である可能性があるため、これだけでを使用してPRNGをシードしないのは良い理由です。残念ながら、これがいつ発生するかを調べたり、低品質の乱数の代わりに失敗を要求したりするためのAPIは提供されていません。

つまり、完全にポータブルなソリューションはありませんが、適切で最小限のアプローチがあります。CSPRNG(sysrandom以下で定義)の最小のラッパーを使用して、PRNGをシードできます。

ウィンドウズ


CryptGenRandomCSPRNGを信頼できます。たとえば、次のコードを使用できます。

bool acquire_context(HCRYPTPROV *ctx)
{
    if (!CryptAcquireContext(ctx, nullptr, nullptr, PROV_RSA_FULL, 0)) {
        return CryptAcquireContext(ctx, nullptr, nullptr, PROV_RSA_FULL, CRYPT_NEWKEYSET);
    }
    return true;
}


size_t sysrandom(void* dst, size_t dstlen)
{
    HCRYPTPROV ctx;
    if (!acquire_context(&ctx)) {
        throw std::runtime_error("Unable to initialize Win32 crypt library.");
    }

    BYTE* buffer = reinterpret_cast<BYTE*>(dst);
    if(!CryptGenRandom(ctx, dstlen, buffer)) {
        throw std::runtime_error("Unable to generate random bytes.");
    }

    if (!CryptReleaseContext(ctx, 0)) {
        throw std::runtime_error("Unable to release Win32 crypt library.");
    }

    return dstlen;
}

Unixライク


多くのUnixライクなシステムでは、可能な場合は/ dev / urandomを使用する必要があります(ただし、これはPOSIX準拠システムでの存在が保証されているわけではありません)。

size_t sysrandom(void* dst, size_t dstlen)
{
    char* buffer = reinterpret_cast<char*>(dst);
    std::ifstream stream("/dev/urandom", std::ios_base::binary | std::ios_base::in);
    stream.read(buffer, dstlen);

    return dstlen;
}

その他の


CSPRNGが利用できない場合は、に依存することを選択できますstd::random_device。ただし、さまざまなコンパイラ(特にMinGW)がPRNGとして実装しているため(実際には、適切なランダムではないことを人間に警告するために毎回同じシーケンスを生成するため)、可能であればこれを避けます。

種まき


オーバーヘッドが最小限のピースができたので、ランダムエントロピーのビットを生成して、PRNGをシードできます。この例では(明らかに不十分な)32ビットを使用してPRNGをシードし、この値を増やす必要があります(これはCSPRNGに依存します)。

std::uint_least32_t seed;    
sysrandom(&seed, sizeof(seed));
std::mt19937 gen(seed);

ブーストとの比較


ソースコードをざっと見てみると、boost :: random_device(真のCSPRNG)の類似点がわかります。BoostはMS_DEF_PROVWindowsで使用します。これはのプロバイダータイプですPROV_RSA_FULL。不足しているのは、暗号化コンテキストを検証することだけですCRYPT_VERIFYCONTEXT。これは、で実行できます。* Nixでは、Boostはを使用し/dev/urandomます。IE、このソリューションは移植性が高く、十分にテストされており、使いやすいです。

Linuxスペシャライゼーション


セキュリティのために簡潔さを犠牲にしてもかまわない場合getrandomは、Linux 3.17以降、および最近のSolarisでは優れた選択肢です。カーネルとgetrandom同じように動作/dev/urandomしますが、カーネルがブート後にまだCSPRNGを初期化していない場合はブロックされます。次のスニペットは、Linux getrandomが使用可能かどうかを検出し、使用できない場合はにフォールバックし/dev/urandomます。

#if defined(__linux__) || defined(linux) || defined(__linux)
#   // Check the kernel version. `getrandom` is only Linux 3.17 and above.
#   include <linux/version.h>
#   if LINUX_VERSION_CODE >= KERNEL_VERSION(3,17,0)
#       define HAVE_GETRANDOM
#   endif
#endif

// also requires glibc 2.25 for the libc wrapper
#if defined(HAVE_GETRANDOM)
#   include <sys/syscall.h>
#   include <linux/random.h>

size_t sysrandom(void* dst, size_t dstlen)
{
    int bytes = syscall(SYS_getrandom, dst, dstlen, 0);
    if (bytes != dstlen) {
        throw std::runtime_error("Unable to read N bytes from CSPRNG.");
    }

    return dstlen;
}

#elif defined(_WIN32)

// Windows sysrandom here.

#else

// POSIX sysrandom here.

#endif

OpenBSD


最後の注意点が1つあります/dev/urandom。最新のOpenBSDにはありません。代わりにgetentropyを使用してください

#if defined(__OpenBSD__)
#   define HAVE_GETENTROPY
#endif

#if defined(HAVE_GETENTROPY)
#   include <unistd.h>

size_t sysrandom(void* dst, size_t dstlen)
{
    int bytes = getentropy(dst, dstlen);
    if (bytes != dstlen) {
        throw std::runtime_error("Unable to read N bytes from CSPRNG.");
    }

    return dstlen;
}

#endif

他の考え


暗号で保護されたランダムバイトが必要な場合は、fstreamをPOSIXのバッファリングされていないオープン/読み取り/クローズで置き換える必要があります。これは、とが標準バッファを介して割り当てられる(したがってメモリからワイプされない)内部バッファbasic_filebufFILE含むためです。

これは、次のように変更sysrandomすることで簡単に実行できます。

size_t sysrandom(void* dst, size_t dstlen)
{
    int fd = open("/dev/urandom", O_RDONLY);
    if (fd == -1) {
        throw std::runtime_error("Unable to open /dev/urandom.");
    }
    if (read(fd, dst, dstlen) != dstlen) {
        close(fd);
        throw std::runtime_error("Unable to read N bytes from CSPRNG.");
    }

    close(fd);
    return dstlen;
}

ありがとう


FILEバッファリングされた読み取りを使用することを指摘してくれたBen Voigtに特に感謝します。したがって、使用しないでください。

言及してくれたPeter Cordes getrandomと、OpenBSDのの欠如にも感謝し/dev/urandomます。


11
これは私が過去にやったことですが、質問、または少なくとも1つの質問は、WTFがこれらのプラットフォームのライブラリライターがこれを行うことができないということですか?ファイルアクセスとスレッド(たとえば)がライブラリ実装によって抽象化されることを期待しているので、なぜ乱数を生成しないのですか?

2
OPここ:この回答が種まきをもう少しよく示していたらいいですね。可能な限り、技術的な解釈やコーダー側の考慮を必要とせずに、質問に投稿した単純な例よりもうまく機能するコピー貼り付け可能なコードを生成する回答を期待しています。
リチャード

4
/dev/randomRNGのシードにはより良い選択だと思いましたが、利用可能なエントロピーが低いためにブロック/dev/urandomする場合でも、計算上安全であると考えられている/dev/randomため、urandomワンタイムパッド以外のすべてに推奨される選択です。unix.stackexchange.com/questions/324209/…も参照してください。urandomただし、起動後の非常に早い段階から予測可能なシードに注意してください。
Peter Cordes

2
Linuxのgetrandom(2)システムコールは/dev/urandom、カーネルのランダム性ソースがまだ初期化されていない場合にブロックされることを除いて、opening and reading に似ています。私はこれがそうするような他の場合にブロックすることなく、初期ブートの低品質ランダム性問題からあなたを救うと思います/dev/random
Peter Cordes

1
@PeterCordesは確かにあり、利用可能な場合はそれが素晴らしいオプションです。ただし、BSDやその他の* Nixesでは機能しません/dev/urandom。これは一般的に機能するものです。これに関するPythonメーリングリストのディスカッションは、私が一般的に購読しているものです:bugs.python.org/issue27266
Alexander Huszagh

22

ある意味で、これは移植性のある方法では実行できません。つまり、C ++を実行している有効な完全に確定的なプラットフォーム(たとえば、マシンクロックを確定的にステップし、「確定した」I / Oを使用するシミュレータ)で、PRNGをシードするランダム性のソースがないものを想像できます。


1
@kbelder:1.ユーザーは人だと誰が言うのですか?2.すべてのプログラムにユーザーインタラクションがあるわけではなく、常にユーザーがいるとは限りません...
einpoklum

8
私はこの反応に感謝しますが、プログラムが妥当なベストエフォートの試みを行うべきだとも感じます。
Richard

3
@Richardは同意しますが、問題は、C ++標準の作成者がこれらの種類の奇妙な状況に対応する(または少なくとも最低限を試みる)必要があることです。そのため、このような希望に満ちた標準的な定義が得られ、適切な結果が得られる可能性がありますが、機能的に価値のないものが返されたとしても、コンパイラは標準に準拠できます。-したがって、プラットフォームごと、コンパイラごと、コンパイラごとの特殊なケースが効果的に必要になるため、制限(「短いため、他のライブラリに依存することはできません」)は応答を排除します。(例:Boostがこれほどうまく機能していること)
RM

2
@Richardが説明していることは、標準で得られるものを手に入れることができるということです。もっと上手にしたいなら(これは高貴な目標です)、多かれ少なかれ憎悪を受け入れる必要があります:)
hobbs

1
@Richard:時には、役に立たない標準準拠のC ++実装を作成することが可能であることを受け入れる必要があるだけです。重要なことに使用される実装有用であるように設計されているので、「適切な実装は何か合理的なことをする」というような議論に耐えなければならないことがあります。私はそれstd::random_deviceがそのカテゴリに入ると期待していましたが、実際の実装では固定シードPRNGを使用するのではないようです。それはアインポクルムの主張をはるかに超えています。
Peter Cordes

14

std::seed_seqエントロピーを取得するAlexander Huszaghの方法を使用して、a を使用して、ジェネレーターの少なくとも必要な状態サイズまで埋めることができます。

size_t sysrandom(void* dst, size_t dstlen); //from Alexander Huszagh answer above

void foo(){

    std::array<std::mt19937::UIntType, std::mt19937::state_size> state;
    sysrandom(state.begin(), state.length*sizeof(std::mt19937::UIntType));
    std::seed_seq s(state.begin(), state.end());

    std::mt19937 g;
    g.seed(s);
}

埋めるか、作成するための適切な方法があった場合SeedSequenceからUniformRandomBitGeneratorを使用して、標準ライブラリにstd::random_deviceはるかに簡単になり、適切にシードするため。


1
seed_seqには問題がありますが、pcg-random.org
posts /

C ++標準や、seed_seqからシードするときに乱数ジェネレータが配列全体を使用することを保証するものはありません。科学的シミュレーションにrngを使用している場合、明らかに暗号化にもこの方法を使用すると失敗します。これの唯一のユースケースはビデオゲームをランダム化することですが、それはやり過ぎです。
Kostas

5

私が取り組んでいる実装state_sizeは、mt19937PRNG のプロパティを利用して、初期化時に提供するシードの数を決定します。

using Generator = std::mt19937;

inline
auto const& random_data()
{
    thread_local static std::array<typename Generator::result_type, Generator::state_size> data;
    thread_local static std::random_device rd;

    std::generate(std::begin(data), std::end(data), std::ref(rd));

    return data;
}

inline
Generator& random_generator()
{
    auto const& data = random_data();

    thread_local static std::seed_seq seeds(std::begin(data), std::end(data));
    thread_local static Generator gen{seeds};

    return gen;
}

template<typename Number>
Number random_number(Number from, Number to)
{
    using Distribution = typename std::conditional
    <
        std::is_integral<Number>::value,
        std::uniform_int_distribution<Number>,
        std::uniform_real_distribution<Number>
    >::type;

    thread_local static Distribution dist;

    return dist(random_generator(), typename Distribution::param_type{from, to});
}

サイズと範囲std::random_device::result_typeが異なる可能性があるため、改善の余地があると思いstd::mt19937::result_typeます。

std :: random_deviceに関するメモ。

C++11(/14/17)基準によると:

26.5.6クラスrandom_device [ rand.device ]

2実装の制限により非決定的な乱数が生成されない場合、実装では乱数エンジンを使用できます。

これは、ある制限によって非決定的な値を生成できない場合にのみ、実装が決定的な値を生成できることを意味します。

MinGW上のコンパイラWindows有名では提供されません非決定論的にそのから値をstd::random_deviceそれらがオペレーティングシステムから容易に入手可能であるにもかかわらず、。だから私はこれをバグと考え、実装やプラットフォーム全体でよくあることではないと思います。


1
これはMTの状態を埋める可能std::random_device性がありますが、それでも依然に依存しているため、それに起因する問題に対して脆弱です。
Richard

1
質問では十分明確に述べたと思います。しかし、明確化/議論することは幸せです。
リチャード

2
@リチャード実際に合理的な実装がされていない実際のシステムはありますstd::random_deviceか?私は標準がPRNGフォールバックを許可することを知っていますC++が、使用するすべてのデバイスに非決定的なランダムソースがあることを要求するのは難しいので、それは自分自身をカバーすることだと感じます。そしてもし彼らがそうしなければ、とにかくそれについてあなたは何ができますか?
Galik 2017

5
@AlexanderHuszaghわからない 私の意図は、「ポータブルソリューション」をデバイスに依存させることです。デバイスが非決定的ジェネレーターをサポートしている場合は、そうする必要がありstd::random_deviceます。それが規格の精神だと思います。だから私は検索しましたがMinGW、この点で壊れているのを見つけることができます。私が見つけた他のものでこの問題を報告している人はいません。そのため、私のライブラリではMinGW、サポートされていないとマークしました。より広い問題があった場合、私はそれを再考します。今のところ、その証拠は見当たりません。
Galik

5
MinGWがstd::random_deviceプラットフォームのランダム性機能を提供しない形式で利用できるようにして、MinGWが誰にとっても台無しになっていることに本当に失望しています。低品質の実装は、既存のAPIの目的を無効にします。彼らはそれが機能するまでそれをまったく実装しなかった方がいいIMOです。(以上、MinGWのはまだゲームや何のために別の種を与えながら、セキュリティがリスク原因避けることができるように、高品質のランダム性は、入手できなかった場合、APIは、要求の失敗への道を提供している場合。)
ピーター・コルド

2

セキュアにする必要がないことを前提として、時間を使用してシードすることには何の問題もありません(これが必要であるとは言いませんでした)。洞察は、ハッシュを使用して非ランダム性を修正できるということです。特に重いモンテカルロシミュレーションを含め、すべてのケースでこれが適切に機能することがわかりました。

このアプローチの優れた機能の1つは、ランダム化されていない他のシードのセットからの初期化に一般化されることです。たとえば、各スレッドに独自のRNG(スレッド安全性)を持たせたい場合は、ハッシュされたスレッドIDに基づいて初期化するだけです。

以下は、私のコードベースから抽出しSSCCEです(簡単にするために、一部のOOサポート構造が省略されています)。

#include <cstdint> //`uint32_t`
#include <functional> //`std::hash`
#include <random> //`std::mt19937`
#include <iostream> //`std::cout`

static std::mt19937 rng;

static void seed(uint32_t seed) {
    rng.seed(static_cast<std::mt19937::result_type>(seed));
}
static void seed() {
    uint32_t t = static_cast<uint32_t>( time(nullptr) );
    std::hash<uint32_t> hasher; size_t hashed=hasher(t);
    seed( static_cast<uint32_t>(hashed) );
}

int main(int /*argc*/, char* /*argv*/[]) {
    seed();
    std::uniform_int_distribution<> dis(0, 5);
    std::cout << dis(rng);
}

1
安全のためにそれを必要としないのであれば、時間のシードはおそらく実際には十分であるというあなたの意見に同意します。しかし、私はあなたの答えの残りに同意することはできません。時間のハッシュをシードすることは、時間自体をシードすることと同じです。
DW

@DW経験的には、はるかに優れています。その理由は、ハッシュが不連続であり、値の範囲がはるかに広いためです(これを自分で試してください:シードして12それらによって生成されたフロートのシーケンスが実際に発散するまでに時間がかかることを確認してください)。
イマレット2017

それが重要な理由はわかりません。一度に実行できるシードは1つだけです。シードの可能な値のスペース(シードのエントロピー)はどちらの方法でも同じです。ハッシュによってエントロピーが増加することはありません。おそらくあなたは質問を編集して、なぜハッシュがより良いのかを説明できますか?
DW

0

ここに私自身の質問があります:

#include <random>
#include <chrono>
#include <cstdint>
#include <algorithm>
#include <functional>
#include <iostream>

uint32_t LilEntropy(){
  //Gather many potential forms of entropy and XOR them
  const  uint32_t my_seed = 1273498732; //Change during distribution
  static uint32_t i = 0;        
  static std::random_device rd; 
  const auto hrclock = std::chrono::high_resolution_clock::now().time_since_epoch().count();
  const auto sclock  = std::chrono::system_clock::now().time_since_epoch().count();
  auto *heap         = malloc(1);
  const auto mash = my_seed + rd() + hrclock + sclock + (i++) +
    reinterpret_cast<intptr_t>(heap)    + reinterpret_cast<intptr_t>(&hrclock) +
    reinterpret_cast<intptr_t>(&i)      + reinterpret_cast<intptr_t>(&malloc)  +
    reinterpret_cast<intptr_t>(&LilEntropy);
  free(heap);
  return mash;
}

//Fully seed the mt19937 engine using as much entropy as we can get our
//hands on
void SeedGenerator(std::mt19937 &mt){
  std::uint_least32_t seed_data[std::mt19937::state_size];
  std::generate_n(seed_data, std::mt19937::state_size, std::ref(LilEntropy));
  std::seed_seq q(std::begin(seed_data), std::end(seed_data));
  mt.seed(q);
}

int main(){
  std::mt19937 mt;
  SeedGenerator(mt);

  for(int i=0;i<100;i++)
    std::cout<<mt()<<std::endl;
}

ここでのアイデアは、XORを使用して多くのエントロピーの潜在的なソース(高速時間、低速時間std::random-device、静的変数の場所、ヒープの場所、関数の場所、ライブラリの場所、プログラム固有の値)を組み合わせて、 mt19937。少なくとも1回ソースが「良好」である限り、結果は少なくとも「良好」になります。

この回答は、望ましいほど短くはなく、1つ以上のロジックの誤りを含んでいる可能性があります。だから私はそれを進行中の作業と考えています。フィードバックがあればコメントしてください。


3
アドレスのランダム性はほとんどありません。常に同じ割り当てが行われるため、メモリ全体にアクセスできる小規模な組み込みシステムでは、毎回同じ結果が得られる可能性があります。大規模なシステムでは十分な可能性があると思いますが、マイクロコントローラーでは問題があるかもしれません。
meneldal 2017

1
&i ^ &myseedどちらも同じ翻訳単位で静的な保存期間を持つオブジェクトなので、どちらか一方だけのエントロピーよりもかなり少ないエントロピーを持つべきだと思います。そして、あなたは実際にmyseed?の初期化からの特別な値を使用していないようです
aschepler 2017

7
割り当て解除されたポインタをintに変換することは、未定義の動作です。それがまだ存在している間にそれを行います。 ^恐ろしいハッシュ結合器です。2つの値の両方に多くのエントロピーがあるが、互いに比較しない場合、それは削除されます。 +通常はより良いです(x + xはxで1ビットのエントロピーを書き込むだけですが、x ^ xはそれらすべてを書き込みます)。機能は安全でないと私は思う(rd()
Yakk-Adam Nevraumont 2017

2
ああ、+私は署名されていないことを意味します(+署名されたものはUBベイトです)。これらはいくぶんとんでもないUBケースですが、移植性があると言っていました。また、可能であれば関数のアドレスを整数値として取得することを検討してください(可能であれば不確かですか?)
Yakk-Adam Nevraumont 2017

1
@meneldal:フルストレングスのPCでも、割り当ては物理的な場所が異なる可能性がありますが(プロセス外部のマシンの状態によって異なります)、ポインターはプロセスの仮想アドレス空間によって抽象化され、特に再現性が高い可能性があります。 ASLRが有効ではありません。
Ben Voigt 2017

0
  • getentropy()を使用して、疑似乱数ジェネレータ(PRNG)をシードします。
  • ランダムな値が必要な場合は、(たとえば、/dev/urandomまたはの代わりに)getrandom()を使用します/dev/random

これらは、Linux、Solaris、OpenBSDなどの最新のUNIXライクなシステムで使用できます。


-2

特定のプラットフォームには、などのエントロピーのソースがある場合があります/dev/random。エポックウィズからのナノ秒は、std::chrono::high_resolution_clock::now()おそらく標準ライブラリで最高のシードです。

以前(uint64_t)( time(NULL)*CLOCKS_PER_SEC + clock() )は、セキュリティが重要ではないアプリケーションのために、より多くのエントロピーを得るために何かを使用していました。


2
/dev/urandom特にこのような場合は、本当にを使用する必要があります。/dev/randomブロックし、そのための正当な理由がないことがよくあります([/ dev / randomによって生成されるバイトのランダム性を推定するさまざまなOSの数に関する長い説明を挿入])。
Alexander Huszagh 2017

2
@AlexanderHuszagh確かに、私は/dev/urandom存在しないシステムでコーディングする必要があり、ブロッキングの代替手段は決定論でした。ボックスにはまたはが付いている/dev/hwrng場合/dev/hw_randomもありますが、さらに優れているはずです。
Davislor 2017

さて、私は「などと述べた/dev/randomと、その約聖戦巻き起こしているようだ、」/dev/random/dev/urandom私はその一例を与えたとき、私は意図していなかったことをLinux上を...
Davislor
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.