2017-08-02 233 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 /秒的随机数据。每次通话都会导致与以前通话不同的值。这将足以:) –