2017-08-02 19 views
1

インテルIvyブリッジCPUを使用していて、C#でRDRANDオペコード(https://software.intel.com/en-us/articles/intel-digital-random-number-generator-drng-software-implementation-guide)を使用します。インテルのRDRANDを.NETで使用するインラインアセンブリを使用する方法

C#でこのCPU命令を呼び出すにはどうすればよいですか?私はここでC#からアセンブリコードを実行する例を見てきました:x86/x64 CPUID in C#

しかし、私はRDRANDの使い方がわかりません。コードは、コードを実行しているCPUが命令をサポートしているかどうかをチェックする必要はありません。

私はこのCをしました++インテルのdrng_samplesから来る組立バイトコードを実行する例を:

int rdrand32_step (uint32_t *rand) 
{ 
    unsigned char ok; 

    /* rdrand edx */ 
    asm volatile(".byte 0x0f,0xc7,0xf0; setc %1" 
     : "=a" (*rand), "=qm" (ok) 
     : 
     : "edx" 
    ); 

    return ok; 
} 

C#でアセンブリコードの実行例は、C++のコードは、Intel drngサンプルから来ると組み合わせることができますかコード?

+0

['RNGCryptoServiceProvider'](https://msdn.microsoft.com/library/system.security.cryptography.rngcryptoserviceprovider)を使用するだけで十分です。これは、擬似乱数よりも優れている必要があるほとんどの目的に適しています。 –

+0

@JeroenMostertご意見ありがとうございます。しかし、科学的に正確なソフトウェア実験の目的に合うように、本当にランダムになることが本当に必要です。私はTrueRNGV3を注文しましたが、到着するには時間がかかりすぎ、その間に代替案を探していましたが、RDRANDは有望です。 –

+1

C#でプロセッサ固有のアセンブリを実行することはできません。 C++コードを記述し、C++/CLIまたはP/Invokeを使用してラップすることができます(ここではhttps://stackoverflow.com/questions/13436130/)。 –

答えて

4

実行時にマネージコードがコールバックする(アンマネージド)アセンブリコードを生成するSOがあります。それは非常に興味深いですが、私は、この目的のために単純にC++/CLIを使用することを提案します。これは、interopシナリオを単純化するために設計されたものです。新しいVisual C++ CLRのクラスライブラリを作成し、それを単一rdrandwrapper.cppを与える:

#include <immintrin.h> 

using namespace System; 

namespace RdRandWrapper { 

#pragma managed(push, off) 
    bool getRdRand(unsigned int* pv) { 
    const int max_rdrand_tries = 10; 
    for (int i = 0; i < max_rdrand_tries; ++i) { 
     if (_rdrand32_step(pv)) return true; 
    } 
    return false; 
    } 
#pragma managed(pop) 

    public ref class RandomGeneratorError : Exception 
    { 
    public: 
    RandomGeneratorError() : Exception() {} 
    RandomGeneratorError(String^ message) : Exception(message) {} 
    }; 

    public ref class RdRandom 
    { 
    public: 
    int Next() { 
     unsigned int v; 
     if (!getRdRand(&v)) { 
     throw gcnew RandomGeneratorError("Failed to get hardware RNG number."); 
     } 
     return v & 0x7fffffff; 
    } 
    }; 
} 

これは単に1つの非負整数の乱数を得ることにRandom.Nextを模倣しようとすると非常に最低限の実装です。質問では、RDRANDがCPU上で実際に利用可能であることを検証しようとはしませんが、命令が存在しても動作しない場合を処理します。 (これが壊れていない限り、現在のハードウェアでは発生しません。詳細はhere

結果のアセンブリは、管理対象のC#コードで使用できる混合アセンブリです。アセンブリされていないコードには特定のビットが1つしかないため、正しく動作しません。デフォルトでは、プロジェクトは「Any CPU」としてコンパイルされるように設定されています。

using System; 
using RdRandWrapper; 

class Program { 
    static void Main(string[] args) { 
    var r = new RdRandom(); 
    for (int i = 0; i != 10; ++i) { 
     Console.WriteLine(r.Next()); 
    } 
    } 
} 

私はパフォーマンスについての主張はしていませんが、おそらくそれほど大きくはありません。このように多くのランダムな値を取得したい場合は、interopのオーバーヘッドを減らすために、1回の呼び出しで多数のランダムな値を取得するために、オーバーロードをNext(int[] values)にすることをお勧めします。

+0

私は最初にVisual StudioのC++開発チェーンをインストールする必要があります:)素晴らしい答え。私はそれを試してみましょう。 –

+0

作業して完全な答え!助けてくれてありがとう! –

+0

パフォーマンスに関しては、1通話あたりInt64を要求すると〜366mbit /秒のランダムデータが得られます。そして、それぞれの呼び出しは以前の呼び出しとは異なる値になりました。それは十分です:) –

関連する問題