C 如何基于字节数组生成随机数?

C 如何基于字节数组生成随机数?,c,random,cryptography,prng,C,Random,Cryptography,Prng,假设我有一个来自安全PRNG的字节数组,并且我需要使用该数据生成一个介于1和10之间的数字,我该如何正确地做到这一点?根据后续评论,您需要的似乎是[%] 您可能还需要检查相关的 注意:每次我们对一个随机数使用模运算符时,都有可能会遇到这样的情况,最终导致随机数的公平分布不平衡。你必须处理好这件事 有关这方面的详细讨论,请参阅此内容和相关答案。这取决于一系列因素。安全PRNG有时生成长字节数组而不是整数,假设它是16字节长的数组,然后提取32位整数,如下所示:buf[0]*0x1000000+bu

假设我有一个来自安全PRNG的字节数组,并且我需要使用该数据生成一个介于1和10之间的数字,我该如何正确地做到这一点?

根据后续评论,您需要的似乎是[
%
]

您可能还需要检查相关的

注意:每次我们对一个随机数使用模运算符时,都有可能会遇到这样的情况,最终导致随机数的公平分布不平衡。你必须处理好这件事


有关这方面的详细讨论,请参阅此内容和相关答案。

这取决于一系列因素。安全PRNG有时生成长字节数组而不是整数,假设它是16字节长的数组,然后提取32位整数,如下所示:
buf[0]*0x1000000+buf[1]*0x10000+buf[2]*0x100+buf[3]
或使用移位运算符。这是随机的,所以大端点/小端点无关紧要

char randbytes[16];
//...

const char *p = randbytes;

//assumes size of int is 4
unsigned int rand1 = p[0] << 24 + p[1] << 16 + p[2] << 8 + p[3]; p += 4;
unsigned int rand2 = p[0] << 24 + p[1] << 16 + p[2] << 8 + p[3]; p += 4;
unsigned int rand3 = p[0] << 24 + p[1] << 16 + p[2] << 8 + p[3]; p += 4;
unsigned int rand4 = p[0] << 24 + p[1] << 16 + p[2] << 8 + p[3];
charrandbytes[16];
//...
const char*p=randbytes;
//假设int的大小为4

unsigned int rand1=p[0]OK,所以在我使用Eclipse C/C++IDE之前,这个答案是用Java编写的:

public final static int simpleBound(Random rbg, int n) {

    final int BYTE_VALUES = 256;

    // sanity check, only return positive numbers
    if (n <= 0) {
        throw new IllegalArgumentException("Oops");
    }

    // sanity check: choice of value 0 or 0...
    if (n == 1) {
        return 0;
    }

    // sanity check: does not fit in byte
    if (n > BYTE_VALUES) {
        throw new IllegalArgumentException("Oops");
    }

    // optimization for n = 2^y
    if (Integer.bitCount(n) == 1) {
        final int mask = n - 1;
        return retrieveRandomByte(rbg) & mask;
    }

    // you can skip to this if you are sure n = 10

    // z is upper bound, and contains floor(z / n) blocks of n values
    final int z = (BYTE_VALUES / n) * n;
    int x;
    do {
        x = retrieveRandomByte(rbg);
    } while (x >= z);
    return x % n;
}
public final static int simpleBound(随机rbg,int n){
最终整数字节_值=256;
//健全性检查,仅返回正数
if(n字节_值){
抛出新的IllegalArgumentException(“Oops”);
}
//n=2^y的优化
if(整数位计数(n)==1){
最终整数掩码=n-1;
返回检索字节(rbg)和掩码;
}
//如果确定n=10,则可以跳过此步骤
//z是上限,包含n个值的楼层(z/n)块
最终整数z=(字节_值/n)*n;
int x;
做{
x=检索数和单位(rbg);
}而(x>=z);
返回x%n;
}

因此,n是范围[0..n]中的最大值,即n是互斥的。对于范围[1..10],只需将结果增加1即可。

将数组视为一个大的无符号整数。答案很简单:

(Big_Number % 10) + 1
因此,所需要的只是一种求大整数模10的方法。使用:



请不要误会我的意思,但答案是写一段代码。
:-)顺便说一句,你在找吗?@SouravGhosh是的,可以用模数来做,如果你的评论是我接受的答案。如果你选择
%
,那么你可能还想读一读关于这个问题。我个人会查找一段代码(通常称为
getInt(intmax)
)并将其整合。否则很容易产生偏差。相关。请注意备注。请添加一些关于偏差的信息,以使此答案完整。@MaartenBodewes已更新。请查看。更好。不幸的是,链接中的答案非常差。也许可以改为尝试。当然,您可以使用8位数字表示范围0..10-depends,如果您希望更改为更大的范围,以及希望从随机池中提取多少数据(您只需要4位就可以了,但16次中有6次拒绝,这相当糟糕)。请注意,您最多需要24个字节才能生成1到10之间的数(在此之后,不生成1到10之间的数字的可能性变得小于1/2^128:P)请注意,如果要降低所需的最大字节数(在本例中为20个字节),建议使用16位数字。我不知道如何翻译(Integer.bitCount(n)==1)到C,所以我不能使用这个函数。你可以简单地省略它,这只是优化所必需的。但是,。如果你需要一个关于如何将
无符号字符
转换为32位值的链接,只需尖叫:)这将给你留下一个小但可检测的偏差,为什么你需要16个字节来生成一个32位的整数???。这是从16个字节中提取的4个不同的整数,这是安全PRNG的典型输出。我在键入后改变了主意,我认为这个问题与安全无关PRNG@Maarten给定OP的Bodewes正在使用“secure PRNG”,当然长度合理,所以我同意,实际上不需要考虑偏差问题。我想使用此代码,但实际上我不需要在1和10之间进行选择,它需要变量。我可以安全地用上限/下限变量替换代码中出现的每一个1和10吗?@Muis几乎。Let
ArrayModX()
返回范围[0…X-1],然后用
X=upper-lower+1
添加下限。如果数字超出范围255,请使用比
无符号字符*a
更大的对象,如
uint32\u t*a
,然后可以替换“10”。如果“10”大于
INT\u MAX
,则会出现一些额外的问题。IOWs“带有上限/下限变量的代码”太模糊。最好说数字的类型或范围,如:
0此答案仍然有偏差,实际上不需要偏差。@Maarten Bodewes
Arraymod10偏差检测()
检测并报告二进制数上模
10
出现的偏差。是否指其他偏差?
#include <limits.h>
#include <stdlib.h>

int ArrayMod10(const unsigned char *a, size_t n) {
  int mod10 = 0;
  int base = (UCHAR_MAX + 1) % 10;
  for (size_t i = n; i-- > 0;  ) {
    mod10 = (base*mod10 + a[i]) % 10;
    base = (base * base) % 10;
  }
  return mod10;
}

void test10(size_t n) {
  unsigned char a[n];

  // fill array with your secure PRNG
  for (size_t i = 0; i<n; i++) a[i] = rand();

  return ArrayMod10(a, n) + 1;
}
int ArrayMod10BiasDetect(const unsigned char *a, size_t n, bool *biasptr) {
  bool bias = true;
  int mod10 = 0;
  int base = (UCHAR_MAX + 1) % 10;  // Note base is usually 6: 256%10, 65536%10, etc.
  for (size_t i = n; i-- > 0;  ) {
    mod10 = (base*mod10 + a[i]) % 10;
    if (n > 0) {
      if (a[i] < UCHAR_MAX) bias = false;
    } else {
      if (a[i] < UCHAR_MAX + 1 - base) bias = false;
    }
    base = (base * base) % 10;
  }
  *biaseptr = bias;
  return mod10;
}