2017-08-02 101 views
1

我正在使用英特爾Ivy Bridge 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++代碼從英特爾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,因爲它旨在簡化互操作場景。創建一個新的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; 
    } 
    }; 
} 

這是隻是試圖模仿Random.Next在得到一個非負的隨機整數一個非常裸機實現。根據這個問題,它不會試圖驗證CPU是否實際可用RDRAND,但它確實可以處理指令存在但無法工作的情況。 (在當前硬件上這是「不可能發生的」,除非它被破壞,詳情如下here)。

生成的程序集是一個可以由託管C#代碼使用的混合程序集。確保將程序集編譯爲x86或x64,與非託管代碼相同(默認情況下,項目被設置爲「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()); 
    } 
    } 
} 

我對性能沒有任何要求,但它可能不是很好。如果你想以這種方式獲得很多隨機值,你可能需要一個Next(int[] values)重載來在一次調用中獲得很多隨機值,以減少互操作的開銷。

+0

我將首先需要爲Visual Studio安裝C++開發鏈,然後:)很好的答案。我會試一試。 –

+0

工作和完成答案!非常感謝你的幫助! –

+0

關於性能,每次請求Int64時,我會得到約366mbit /秒的隨機數據。每次通話都會導致與以前通話不同的值。這將足以:) –