素槿
Published on 2025-08-22 / 3 Visits
0

C语言随机数生成

0. 头文件和辅助函数

#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <cpuid.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <time.h>
#include <immintrin.h>

void printHex(unsigned char* c, int n)
{
    int i;
    for (i = 0; i < n; i++) {
        printf("%02X", c[i]);
    }
}

1. 使用/dev/random或/dev/urandom做熵源

/**
 * 使用/dev/urandom使用非阻塞熵源
 */
int random_generator_dev(unsigned char* random, const uint64_t len)
{
    if (random == NULL || len <= 0) return 1;
    const char* file = "/dev/random";

    int fd = open(file, O_RDONLY);
    if (-1 == fd) return 2;
    int nread = read(fd, random, len);
    close(fd);
    if (nread != len) return 3;
    return 0;
}

2. 使用CPU硬件生成器

编译时需要添加 -mrdrnd编译选项

提供内置接口和汇编指令两种实现方式。

#ifndef bit_RDRND
#define bit_RDRND 0x40000000
#endif

/**
 * @brief 检测是否支持rdrand指令
 *
 * @return int 支持返回0, 不支持返回1.
 */
int cpu_supports_rdrand()
{
    uint32_t eax = 0, ebx = 0, ecx = 0, edx = 0;
    __get_cpuid(1, &eax, &ebx, &ecx, &edx);
    return !(ecx & bit_RDRND);
}

/**
 * @brief 随机数生成
 *
 * @param rand_num
 * @return int 0-有效,1-无效
 */
#if 0
int random_rdrand(uint64_t* rand_num)
{
    uint64_t foo             = 0;
    int      cf_error_status = 0;
    __asm__ volatile(
        "\n\
            rdrand %%rax;\n\
            mov $1,%%edx;\n\
            cmovae %%rax,%%rdx;\n\
            mov %%edx,%1;\n\
            mov %%rax, %0;"
        : "=r"(foo), "=r"(cf_error_status)::"%rax", "%rdx");
    *rand_num = foo;
    return !cf_error_status;
}
#else
int random_rdrand(uint64_t* rand_num)
{
    if (!rand_num) return 1;

    if (_rdrand64_step((unsigned long long*)rand_num)) return 0;

    return 2;
}
#endif

int random_generator_rd(unsigned char* random, const uint64_t len)
{
    if (random == NULL || len <= 0) return -1;
    uint64_t type_len   = sizeof(uint64_t);
    uint64_t loop       = len / type_len;
    uint64_t left       = len - loop * type_len;
    uint64_t random_gen = 0;
    uint64_t i;
    for (i = 0; i < loop; i++) {
        if (!random_rdrand(&random_gen))
            memcpy(random + i * type_len, &random_gen, type_len);
    }
    if (left) {
        if (!random_rdrand(&random_gen))
            memcpy(random + type_len * loop, &random_gen, left);
        else
            return -1;
    }
    return 0;
}

3. 使用PCG软算法生成

// ----------------------------------------------

#define PCG32_INITIALIZER                            \
    {                                                \
        0x853c49e6748fea9bULL, 0xda3e39cb94b95bdbULL \
    }

typedef struct {
    uint64_t state;
    uint64_t inc;
} pcg32_random_t;

static pcg32_random_t pcg32_global = PCG32_INITIALIZER;

uint32_t pcg32_random_r(pcg32_random_t* rng);

void pcg32_srandom_r(pcg32_random_t* rng, uint64_t initstate, uint64_t initseq)
{
    rng->state = 0U;
    rng->inc   = (initseq << 1u) | 1u;
    pcg32_random_r(rng);
    rng->state += initstate;
    pcg32_random_r(rng);
}

void pcg32_srandom(uint64_t seed, uint64_t seq)
{
    pcg32_srandom_r(&pcg32_global, seed, seq);
}

uint32_t pcg32_random_r(pcg32_random_t* rng)
{
    uint64_t oldstate = rng->state;
    // Advance internal state
    rng->state = oldstate * 6364136223846793005ULL + (rng->inc | 1);
    // Calculate output function (XSH RR), uses old state for max ILP
    uint32_t xorshifted = ((oldstate >> 18u) ^ oldstate) >> 27u;
    uint32_t rot        = oldstate >> 59u;
    return (xorshifted >> rot) | (xorshifted << ((-rot) & 31));
}

uint32_t pcg32_random() { return pcg32_random_r(&pcg32_global); }

int random_rdpcg(uint32_t* random)
{
    if (random == NULL) return 1;
    *random = pcg32_random();
    return 0;
}

int random_generator_pcg(unsigned char* random, const uint32_t len)
{
    if (random == NULL || len <= 0) return -1;
    uint32_t type_len   = sizeof(uint32_t);
    uint32_t loop       = len / type_len;
    uint32_t left       = len - loop * type_len;
    uint32_t random_gen = 0;
    uint32_t i;

    for (i = 0; i < loop; i++) {
        if (!random_rdpcg(&random_gen))
            memcpy(random + i * type_len, &random_gen, type_len);
    }
    if (left) {
        if (!random_rdpcg(&random_gen))
            memcpy(random + type_len * loop, &random_gen, left);
        else
            return -1;
    }
    return 0;
}

void pcg_test()
{
    uint32_t random;
    int      rounds = 9;
    pcg32_srandom(time(NULL) ^ (intptr_t)&printf, (intptr_t)&rounds);

    for (size_t i = 0; i < 10; i++) {
        random_rdpcg(&random);
        printHex((unsigned char*)&random, 4);
        printf("\n");
    }

    unsigned char random[1024] = {0};
    int           rounds       = 9;
    pcg32_srandom(time(NULL) ^ (intptr_t)&printf, (intptr_t)&rounds);

    for (size_t i = 1; i < 57; i += 2) {
        random_generator_pcg(random, i);
        printHex(random, i);
        printf("\n");
    }
}

int main(int argc, char const* argv[])
{
    pcg_test();
    return 0;
}