8

I need to get random number from Intel's random generator in processor (Intel Core i3). I don't want to use any library. I want use assembler paste in C++, but I don't khow which registers and instructions should use.

jww
  • 97,681
  • 90
  • 411
  • 885

2 Answers2

11

Calling the RDRAND instruction on supported CPUs (currently, only Ivy Bridge and Haswell Intel CPUs) will place a random value into a specified register. For instance, this will give you a random 64-bit value:

RDRAND %rax

On success, the carry bit will be set. See Intel's Bull Mountain Software Implementation Guide for more details. ("Bull Mountain" is the code name for Intel's hardware RNG.)

  • Can you elaborate further on whether it's a PRNG or an entroy generator? – Mark B Jul 10 '12 at 06:08
  • Click the link. TLDR: It's a true random number generator. – Gunther Piez Jul 10 '12 at 09:19
  • https://www.felixcloutier.com/x86/rdrand is the asm manual: available in 16 or 32-bit operand-size as well. In C++, normally use an intrinsic for it, like `int success = _rdrand64_step(&output)`. Or `while( !_rdrand64_step(&output) ){}`. (Defined in ``. [RDRAND and RDSEED intrinsics GCC and Intel C++](https://stackoverflow.com/q/29372893)) – Peter Cordes May 08 '22 at 06:24
6

... but I don't khow which registers and instructions should use.

Below is the inline assembler I use on Linux machines with GCC. I believe I ripped a significant portion from an Intel manual. It was probably written by David Johnston, who provides the awesome technical answers to questions. He is also the guy designed the hardware at Intel.


int RDRAND_bytes(byte* buff, size_t bsize)
{
    if (!HasRDRAND())
        return -1;

    size_t idx = 0, rem = bsize;
    size_t safety = bsize / sizeof(unsigned int) + 4;

    unsigned int val;
    while (rem > 0 && safety > 0)
    {
        char rc;    
        __asm__ volatile(
                "rdrand %0 ; setc %1"
                : "=r" (val), "=qm" (rc)
        );

        // 1 = success, 0 = underflow
        if (rc)
        {
            size_t cnt = (rem < sizeof(val) ? rem : sizeof(val));
            memcpy(buff + idx, &val, cnt);

            rem -= cnt;
            idx += cnt;
        }
        else
        {
            safety--;
        }
    }

    // Wipe temp on exit
    *((volatile unsigned int*)&val) = 0;

    // 0 = success; non-0 = failure (possibly partial failure).
    return (int)(bsize - rem);
}

And the code below is used for HasRDRAND. It detect both AMD and Intel CPUs (I think that's all the CPUs that provide RDRAND).

struct CPUIDinfo {
    unsigned int EAX;
    unsigned int EBX;
    unsigned int ECX;
    unsigned int EDX;
};

// Be careful below. EBX/RBX needs to be preserved depending on the memory model and use of PIC.
void cpuid_info(CPUIDinfo *info, const unsigned int func, const unsigned int subfunc) {
    __asm__ __volatile__ (
            "cpuid"
            : "=a"(info->EAX), "=b"(info->EBX), "=c"(info->ECX), "=d"(info->EDX)
            : "a"(func), "c"(subfunc)
    );
}

int HasAmdCpu() {
    CPUIDinfo info;
    cpuid_info(&info, 0, 0);
    if (memcmp((char *) (&info.EBX), "htuA", 4) == 0
            && memcmp((char *) (&info.EDX), "itne", 4) == 0
            && memcmp((char *) (&info.ECX), "DMAc", 4) == 0) {

        return 1;
    }


int HasIntelCpu() {
    CPUIDinfo info;
    cpuid_info(&info, 0, 0);
    if (memcmp((char *) (&info.EBX), "Genu", 4) == 0
            && memcmp((char *) (&info.EDX), "ineI", 4) == 0
            && memcmp((char *) (&info.ECX), "ntel", 4) == 0) {

        return 1;
    }

    return 0;
}

int HasRDRAND() {    
    if (!HasAmdCpu() || !HasIntelCpu())
        return 0;

    CPUIDinfo info;
    cpuid_info(&info, 1, 0);

    static const unsigned int RDRAND_FLAG = (1 << 30);
    if ((info.ECX & RDRAND_FLAG) == RDRAND_FLAG)
        return 1;

    return 0;
}

Also see How to use RDRAND intrinsics? It does not answer your immediate question, but it may be an alternative for you (and may help others).

Community
  • 1
  • 1
jww
  • 97,681
  • 90
  • 411
  • 885
  • 3
    It started as my work, but what you have there was cleaned up and improved on by the low level software experts at intel, who put effort into cross compiler and cross word-width compatibility. – David Johnston Jan 26 '15 at 20:17
  • For reference on the AMD availability of `RDRAND`, see [AMD64 Architecture Programmer’s Manual Volume 3: General-Purpose and System Instructions](http://support.amd.com/TechDocs/24594.pdf). – jww Oct 12 '15 at 01:31