【问题标题】:How to generate large random numbers C如何生成大随机数 C
【发布时间】:2011-12-16 18:39:54
【问题描述】:

我正在寻找一种在 C... (100000000 - 999999999) 中生成大约 2^64 的大随机数的方法,用于公钥加密算法(如 p 和 q)。

我不想生成小于 2^64 的数字(即小于 100000000)。

有什么可以帮助我做到这一点的吗?

【问题讨论】:

  • 2^64 远大于 999999999。
  • [100000000 - 999999999] 是 900,000,000 个不同的值。这些数字是 30 位的顺序,而不是 64 位。

标签: c random rsa


【解决方案1】:

或者,您可以使用两个带有独立种子的随机数生成器,并按照建议将它们的输出数放在一起。这取决于您是否想要一个周期在 2^64 范围内的 64 位 RNG。只是不要使用取决于时间的默认调用,因为您将为每个生成器获得相同的种子。正确的方法,我就是不知道……

【讨论】:

    【解决方案2】:

    您可以用较小的数字生成较大的数字 L(例如 A 和 B)。例如,L = (2^ n)*A + B 之类的东西,其中 ^ 表示取幂,n 是某个常数整数(例如 32)。然后为 2 的幂运算编写 1<<n(按位左移)。

    因此,您可以将较小的随机数组合成较大的随机数。

    【讨论】:

    • 字母L, n, A, and b 是什么意思?你能解释一下吗?
    • 假设较小的数字u32是均匀分布的,这样的组合数字u64 = (u32 << 32) | u32也是吗?
    • @this。我想是的,但你应该问问数学家。
    • 如果B 的范围不是[0...(2^ n)-1],L = (2^ n)*A + B 是一个问题。如果B 范围更广(并且仍然是2 的幂),则最好使用L = (2^ n)*A ^ B。最好是L = (max_possible_value_of_B + (type_of_L)1) *A + B
    【解决方案3】:

    random() 返回一个 long,在 64 位系统上应该是 64 位。如果您使用的是 32 位系统,则可以执行以下操作:

    #include <inttypes.h>
    
    uint64_t num;
    
    /* add code to seed random number generator */
    
    num = rand();
    num = (num << 32) | rand();
    
    // enforce limits of value between 100000000 and 999999999
    num = (num % (999999999 - 100000000)) + 100000000;
    

    或者在 NIX 系统上,您可以将 /dev/random 读入缓冲区:

    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <inttypes.h>   
    
    int fd;
    uint64_t num; 
    if ((fd = open("/dev/random", O_RDONLY) == -1)
    {
        /* handle error */
    };
    read(fd, &num, 8);
    close(fd);
    
    // enforce limits of value between 100000000 and 999999999
    num = (num % (999999999 - 100000000)) + 100000000;
    

    一个

    【讨论】:

    • rand() 受 RAND_MAX 限制,这不是必需的 2^32。而且,您仍然需要将一些东西传递给srand()。 /dev/random 功能也可在 other platforms 上使用。
    • 这并不能确保满足“我不想生成小于 ... 100000000 的数字”的要求。
    • 添加num = (num % (999999999 - 100000000)) + 100000000;行,生成下限100000000和上限999999999的随机数。
    • 更好,但现在高于 805933941 (2^64 -1 mod 899999999) 的数字比下面的数字略低 ;-)
    • 在我的电脑上,RAND_MAX 是 2^31,而不是 2^32。
    【解决方案4】:

    你可以组合两个 4 字节的随机整数来产生一个 8 字节的整数:

    #include <stdint.h>
    ...
    uint64_t random = 
      (((uint64_t) rand() <<  0) & 0x00000000FFFFFFFFull) | 
      (((uint64_t) rand() << 32) & 0xFFFFFFFF00000000ull);
    

    由于rand 在几乎所有现代平台上都返回int 和sizeof(int) &gt;= 4,因此这段代码应该可以工作。我添加了&lt;&lt; 0 以使意图更加明确。

    0x00000000FFFFFFFF 和0xFFFFFFFF00000000 的掩码是为了防止sizeof(int) &gt; 4 的情况下两个数字中的位重叠。

    编辑

    由于@Banthar 评论说RAND_MAX 不一定是2 ^ 32,而且我认为它至少可以保证是2 ^ 16,你可以结合四个2 字节的数字来确定:

    uint64_t random = 
      (((uint64_t) rand() <<  0) & 0x000000000000FFFFull) | 
      (((uint64_t) rand() << 16) & 0x00000000FFFF0000ull) | 
      (((uint64_t) rand() << 32) & 0x0000FFFF00000000ull) |
      (((uint64_t) rand() << 48) & 0xFFFF000000000000ull);
    

    【讨论】:

    • 如果你使用^而不是|来组合数字,你就不用担心被屏蔽了。
    • Off-by-one:RAND_MAX 不太可能是 2 ^ 32。可能是(2 ^ 32) - 1。然而,即使这样也不常见。它更有可能与INT_MAX 相同,其共同值为(2 ^ 31) - 1 或(2 ^ 15) - 1。 C 指定RAND_MAX 至少为(2^15) - 1,而不是2 ^ 16。
    【解决方案5】:

    我知道我可能会被 OliCharlesworth 打耳光,但请使用带有比例和偏移量的 rand()。它在 stdlib.h 为了覆盖整个范围,您应该将其添加到另一个较小的 rand() 以填补映射中的空白。

    【讨论】:

      【解决方案6】:

      您正在寻找加密强度的 PRNG,例如 openssl/rand: http://www.openssl.org/docs/crypto/rand.html

      【讨论】:

      • 或 BCryptGenRandom 在 Windows Vista 及更高版本上。
      • +1: 使用rand() 是一个安全漏洞(预测rand() 的输出并不是很有挑战性)
      • openssl.org/docs/crypto/rand.html 2018 年 8 月的死链接。只有链接答案的问题之一。
      猜你喜欢
      • 1970-01-01
      • 2017-05-11
      • 2012-03-18
      • 2015-07-19
      • 1970-01-01
      • 2012-11-06
      • 1970-01-01
      相关资源
      最近更新 更多