You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何从/dev/urandom获取带前置零掩码的32字节随机数据?

问题背景

我正在开发一个寻找比特币地址部分碰撞的程序,已获取urandom的源码但不知从何入手。我需要从/dev/urandom获取总计32字节的随机字节(包含掩码零),因为程序需要256位数据,转换为十六进制时开头需带有零掩码,示例十六进制输出如下:

000000000000000000000000000000000000000000000000000000000000002d4

注意实际十六进制值前的零(我称之为掩码),Python中很多生成比特币地址的库都需要这种格式。

我在使用以下代码时遇到了问题(该代码并非来自random.c),现在认为修改urandom本身可能更有帮助:

static bool init_rand(void *data, size_t size)
{
    FILE *stream = fopen("/dev/urandom", "r");
    if (stream == NULL)
        return false;
    bool ok = (fread(data, sizeof(uint8_t), size, stream) == size);
    fclose(stream);
    return ok;
}

static bool init_rand(void *data, size_t size)
{
    size_t size0 = size / sizeof(unsigned) + 1;
    assert(size0 * sizeof(unsigned) >= size);
    unsigned data0[size0];
    for (size_t i = 0; i < size0; i++)
    {
        int err = rand_s(data0 + i);
        if (err != 0)
            return false;
    }
    memcpy(data, data0, size);
    return true;
}

static struct seed *make_seed(void)
{
    struct seed *seed = (struct seed *)malloc(sizeof(struct seed));
    assert(seed != NULL);
    seed->counter = 0;
    if (!init_rand(seed, sizeof(struct seed)))
    {
        fprintf(stderr, "error: failed to init random seed\n");
        exit(EXIT_FAILURE);
    }
    if (seed->counter == 0)     // Sanity check...
    {
        fprintf(stderr, "error: random seed initialization failed\n");
        exit(EXIT_FAILURE);
    }
    return seed;
}

请问是否可以修改Linux内核驱动中的random.c,使其生成已带有零掩码的字节?


解决方案分析

完全没必要修改Linux内核的random.c,原因及替代方案如下:

  1. 内核修改的弊端

    • 成本极高:需要重新编译内核、维护自定义内核分支,后续系统更新会覆盖改动,兼容性极差。
    • 破坏设计初衷:/dev/urandom的核心作用是提供完全随机的字节流,强行加入固定前缀会破坏随机性,违背内核随机设备的设计原则。
  2. 用户空间实现需求的两种场景
    你的需求本质是两种情况,都可以在用户空间轻松实现:

    场景1:十六进制格式化时补零到64位(对应示例的满长度零前缀显示)

    读取32字节随机数据后,格式化输出时确保每个字节都以两位十六进制表示(高位补零),就能得到满64位的十六进制字符串,符合Python比特币库的格式要求。示例代码:

    #include <stdio.h>
    #include <stdlib.h>
    #include <fcntl.h>
    #include <unistd.h>
    #include <stdint.h>
    
    int main() {
        uint8_t data[32];
        int fd = open("/dev/urandom", O_RDONLY);
        if (fd == -1) {
            perror("open /dev/urandom");
            exit(EXIT_FAILURE);
        }
        if (read(fd, data, sizeof(data)) != sizeof(data)) {
            perror("read /dev/urandom");
            close(fd);
            exit(EXIT_FAILURE);
        }
        close(fd);
    
        // 格式化输出64位十六进制,每个字节补零到两位
        for (size_t i = 0; i < sizeof(data); i++) {
            printf("%02x", data[i]);
        }
        printf("\n");
        return EXIT_SUCCESS;
    }
    

    场景2:生成的32字节数据中前N个字节固定为0(掩码)

    如果是需要实际二进制数据的前若干字节为0,只需在读取随机数据后,手动将指定范围的字节置0即可,无需改动内核。示例代码(假设前28字节为掩码零):

    #include <stdio.h>
    #include <stdlib.h>
    #include <fcntl.h>
    #include <unistd.h>
    #include <stdint.h>
    #include <string.h>
    
    #define MASK_LENGTH 28  // 前28字节为零掩码
    
    int main() {
        uint8_t data[32];
        int fd = open("/dev/urandom", O_RDONLY);
        if (fd == -1) {
            perror("open /dev/urandom");
            exit(EXIT_FAILURE);
        }
        if (read(fd, data, sizeof(data)) != sizeof(data)) {
            perror("read /dev/urandom");
            close(fd);
            exit(EXIT_FAILURE);
        }
        close(fd);
    
        // 设置前MASK_LENGTH字节为0
        memset(data, 0, MASK_LENGTH);
    
        // 输出十六进制
        for (size_t i = 0; i < sizeof(data); i++) {
            printf("%02x", data[i]);
        }
        printf("\n");
        return EXIT_SUCCESS;
    }
    
  3. 针对你现有代码的优化
    你提供的init_rand函数用于初始化seed结构体,若需要结构体中部分字段为零掩码,只需在调用init_rand后,手动将对应字段赋值为0即可,无需修改内核或随机设备逻辑。


内容的提问来源于stack exchange,提问作者diviserbyzero

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.06 08:45:38