我需要发出一系列{1,2,3,4 ...}的门票(至少看似是)随机数{10,934,3,453,867,122,4,386,564 ......}。当呈现时,我必须能够计算其原始索引(例如122→3。)
换句话说,我需要在区间[1 ... N]上有一个看似随机的排列p
,它具有逆置换p-1
。 N约为10 7 。
原因是:
答案 0 :(得分:2)
我会在计数器模式下使用一些众所周知的密码(例如DES)。
对于正常目的,DES通常被认为是相当破碎的,但它似乎很合适地满足您的需求,并且具有比大多数新算法更小的块大小。对你来说,这意味着它产生一个较小的结果(64位,如果内存服务)。一旦你将它转换为可读字符(例如,base 64),你最终会得到10个字符左右。要检索原始号码,只需使用密钥解密即可。
结果看起来非常随机 - 基本上唯一已知的将它们排序回序的方法就是破坏DES,这可以完成(已经完成),但这样做的资源非常重要。
如果你确实需要比这更好的安全性,你可以使用AES而不是DES(代价是产生更长的“密钥”值)。
答案 1 :(得分:0)
您可以使用Linear congruential generator生成此类序列。 X0是种子(如果你愿意,可以是排列的索引)。 m 应等于N + 1。选择 c 和 a 以确保完整的期间长度(如上面链接中的期间长度'部分所述)。这将为您提供大小为N的一对一映射。
要恢复索引,您可以使用系列中的少量连续伪随机数来破解LCG,即not too hard。当然你可以保留m,a和c并省去麻烦。
有关更安全的方法,请查看David Eisenstat的评论。您只需要密钥即可恢复索引。在缺点方面,如果您使用标准FPE,则N必须为2 ^ x-1(例如2 ^ 128-1)。
答案 2 :(得分:0)
1生成伪随机混乱,你可以使用Fisher-Yates算法:
https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle
What distribution do you get from this broken random shuffle?
for (int i = tickets.Length - 1; i > 0; i--)
{
int n = random(i + 1);
Swap(tickets[i], tickets[n]);
}
谨防不使用“错误”算法(他有偏见)。
你将获得排列,然后是逆排列。
2问题伴随着随机播放。
因为有10000000!排列,你应该有一个非常大的种子
然后问题在于随机生成器。标准的大概是32位,也许多一点,但远不是10000000!
你应该看到像fortuna这样的东西: