想象一下,我能够使用类似Knuth shuffle和种子随机数发生器之类的东西来洗牌0到2 ^ 32之间的所有数字。
从概念上讲,我需要两个数组(使用 Z 5 而不是 Z 2 32 为简洁起见):
[2, 0, 1, 4, 3] // perm
[1, 2, 0, 4, 3] // inv === p^-1
如果我有这些数组,我可以有效地查找排列中的第n个元素,并在purmutation值v中找出元素;
v = perm[n];
n == inv[v]; // true
我不想存储两个代表这个混洗集的16 GB uint数组,因为我从不对整个混洗序列感兴趣。我只对第n个元素的价值感兴趣。
我理想地想要写两个像这样工作的纯函数:
uint nthShuffled = permutate<uint>(key, n); // O(log n)
uint n == invert<uint>(key, nthShuffled); // O(log n)
要求:
据我所知,理论上必须至少有2个 32 !唯一键是为了表示任何可能的排列,但我相信我可以在良好的散列函数背后隐藏这个问题。
那里有什么东西接近这个吗?
答案 0 :(得分:4)
任何分组密码实际上都是伪随机排列。 32位分组密码会置换0
和2 ^ 32 - 1
之间的整数。
给定密钥,使用此密钥加密N
会得到N-th
伪随机数。
唯一的问题是找到一个好的32位分组密码。我所知道的唯一一个是SKIP32,但我对它的力量一无所知。
SKIP32的密钥大小为80位。如果它是一个好的密码,那就足够了。
但同样,我不知道密码。
如果将范围增加到2 ^ 64 - 1
整数是一个选项,您可以简单地使用一个众所周知的64位分组密码,如Triple-DES或Blowfish。
答案 1 :(得分:3)
” 排列中前100个元素的知识不提供关于排列中可能是第101个元素的信息。 “
您需要将整个数组存储在内存中。我建议使用stxxl,它是通过将大量容器存储在磁盘上而设计用于大型数据类型的。 根据随机置换的本质,你不能推断给定[n]的[n-1]或[n + 1]的值。所以它看起来不像空间可以优化。
答案 2 :(得分:2)
从加密的角度来看,您需要一个具有32位块的分组密码。
Format-Preserving Encryption关于任意(通常是小)域的加密问题(又称“键控置换”)。
对于该特定问题存在generic "perfect" solution - 但计算涉及通过超几何分布进行采样,这意味着存在大量具有浮点和任意精度数的混乱,这是昂贵的。
还有“近似”解决方案,其中严格地说,在所有可能的排列中均匀地选择排列,但是差异可以任意小,以至于不可能区分所实现的排列。和一个真正随机选择的排列。请参阅Thorp shuffle。
没有标准且安全的32位分组密码,因为32位不够以确保在常用分组密码的情况下的安全性(加密长数据流,例如作为SSL); 64位块已经不受欢迎了。所以你在这里有点自己。
答案 3 :(得分:1)
Hashing不会解决随机数序列。
存储2 ^ 32位。那是.5 GB。
随着时间的推移,运行Fischer-Yates shuffle和“cross off”位。如果您想知道第5个元素的内容,那么您将超过4,第5个随机值将是您的数字。
要获得第n个排列,那么你需要回溯。运行算法n次,得到如下数字:
Find 5th index after 4 permutations:
First iteration:
1st : skip (run through the RNG)
2nd : skip
3rd : skip
4th : 7th index to 5th index
Second iteration: (run using same seed as 1st iteration)
1st : skip
2nd : skip
3rd : 3rd index to 7th index
4th : 7th index to 5th index
Third iteration:
1st : skip
2nd : 4th index to 7th index
3rd : 3rd index to 7th index
4th : 7th index to 5th index
Fourth iteration:
1st : 8th index to 4th index
2nd : 4th index to 7th index
3rd : 3rd index to 7th index
4th : 7th index to 5th index
在最后一次迭代中,您知道第8个索引引导成为第5个索引。
编辑:我写了一个快速程序来测试速度。每个排列需要几分钟。它很慢,但仍可使用。