(Secure) Random string?
在Lua中,通常使用
但是,这种方法有一个主要缺点。返回的数字始终与当前时间一样随机,并且每个随机数的间隔为一秒,如果在很短的时间内需要多个随机值,则该时间太长。
Lua用户Wiki:http://lua-users.org/wiki/MathLibraryTutorial以及相应的RandomStringS记录甚至指出了此问题:http://lua-users.org/wiki/RandomStrings。
因此,我坐下来编写了另一种算法(如果可以称之为),该算法通过(错误地)使用表的内存地址来生成随机数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | math.randomseed(os.time()) function realrandom(maxlen) local tbl = {} local num = tonumber(string.sub(tostring(tbl), 8)) if maxlen ~= nil then num = num % maxlen end return num end function string.random(length,pattern) local length = length or 11 local pattern = pattern or '%a%d' local rand ="" local allchars ="" for loop=0, 255 do allchars = allchars .. string.char(loop) end local str=string.gsub(allchars, '[^'..pattern..']','') while string.len(rand) ~= length do local randidx = realrandom(string.len(str)) local randbyte = string.byte(str, randidx) rand = rand .. string.char(randbyte) end return rand end |
一开始,一切似乎都是随机的,而且我敢肯定,至少对于当前程序而言。
所以我的问题是,
还是有一种更好的方法可以在比一秒钟更短的时间间隔内生成随机数(如上所述,这意味着不应该使用
编辑:
RNG的播种方式似乎存在重大误解。在生产代码中,对
我所说的随机值是每秒仅随机一次,此粘贴很容易说明:http://codepad.org/4cDsTpcD
由于无论我进行何种编辑,该问题都会被否决,因此我也取消了以前接受的答案-希望有一个更好的答案,即使只是更好的意见。我知道关于随机值/数字的问题已经讨论过很多次了,但是我没有找到与Lua有关的问题-请记住这一点!
您不应该在每次调用random时都调用种子,而应该在程序初始化时仅调用一次(除非您从某个地方获取种子,例如,复制以前的某些"随机"行为)。
在统计意义上,标准Lua随机生成器的质量很差(事实上,事实上,它是标准C随机生成器),如果需要,请不要使用它。例如,使用
如果需要更安全的随机性,请在Linux上从
依赖表指针值是一个坏主意。例如,考虑一下Java中的替代Lua实现-没有告诉他们它们将返回什么。 (此外,指针值可能是可预测的,在某些情况下,每次调用程序时,指针值可能是相同的。)
如果您希望种子具有更高的精度(并且仅在启动程序的频率高于每秒一次的情况下才需要),则应使用分辨率更高的计时器。例如,来自LuaSocket的
1 2 3 4 5 6 7 | require 'socket' math.randomseed(socket.gettime() * 1e6) for i = 1, 1e3 do print(math.random()) end |
This method however has one major
weakness; The returned number is
always just as random as the current
time, AND the interval for each random
number is one second, which is way too
long if one needs many random values
in a very short time.
仅当您实施不正确时,它才具有这些缺点。
应当很少调用
查看此样本发生了什么:
1 2 3 4 5 6 7 8 9 | > math.randomseed(1) > return math.random(), math.random(), math.random() 0.84018771715471 0.39438292681909 0.78309922375861 > math.randomseed(2) > return math.random(), math.random(), math.random() 0.70097636929759 0.80967634907443 0.088795455214007 > math.randomseed(1) > return math.random(), math.random(), math.random() 0.84018771715471 0.39438292681909 0.78309922375861 |
将种子从1更改为2时,会得到不同的随机结果。但是当我回到1时,"随机序列"被重置。我获得与以前相同的值。
您唯一需要担心非随机性的情况是程序应该每秒执行一次以上。正如其他人所说,在那种情况下,最简单的解决方案是使用具有更高清晰度的时钟。
换一种说法:
-
在程序开始时用适当的种子(
os.time() 可以满足99%的情况)调用math.randomseed -
每次需要随机数时调用
math.random 。
问候!
对问题的第一部分的一些想法:
So my question is, how random are these numbers returned by
realrandom really?
您的函数正在尝试通过使用其默认实现
还有一个更大的问题。尽管在您的平台上在进程中创建的第n个表的地址似乎是随机的,但tt可能根本不是随机的。或者它可能仅变化几位。例如,在我的win7盒子上,只有几处变化,并且不是非常随机的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | C:...>for /L %i in (1,1,20) do @ lua -e"print{}" table: 0042E5D8 table: 0061E5D8 table: 0024E5D8 table: 0049E5D8 table: 0042E5D8 table: 0042E5D8 table: 0042E5D8 table: 0064E5D8 table: 0042E5D8 table: 002FE5D8 table: 0042E5D8 table: 0049E5D8 table: 0042E5D8 table: 0042E5D8 table: 0042E5D8 table: 0024E5D8 table: 0042E5D8 table: 0042E5D8 table: 0061E5D8 table: 0042E5D8 |
当然,其他平台也会有所不同。我什至希望有一个平台,其中第一个分配表的地址是完全确定的,因此在程序的每次运行中都相同。
简而言之,过程映像中任意对象的地址并不是很好的随机性来源。
编辑:为了完整起见,我想补充一整夜想到的其他一些想法。
stock
1 2 3 4 5 | switch (lua_type(L, 1)) { ... default: lua_pushfstring(L,"%s: %p", luaL_typename(L, 1), lua_topointer(L, 1)); break; |
如果您真的在调用此函数,则字符串的末尾将是一个地址,以标准C
还要注意,在库代码中执行类似的操作可能会使您感到惊讶。
首先,如果传递给
其次,在模块加载时,某些其他模块或用户提供的代码可能已用其他东西替换了库存
第三,您可能根本不会加载到库存的Lua解释器中,并且更大的应用程序(Lightroom,WoW,Wireshark等)可能会选择用其自己的实现替换基本库函数。对于
我想到了一些重要的事情:
- 在大多数其他语言中,通常只在程序开始时调用一次随机的"种子"函数,或者在整个执行过程中仅在有限的时间调用一次。通常,您不希望每次生成随机数/序列时都调用它。如果在程序启动时调用一次,则会遇到"每秒一次"的限制。通过每次都调用它,实际上可能会减少结果的随机性。
- 您的realrandom()函数似乎依赖于Lua的私有实现细节。如果此详细信息更改为始终返回相同的数字,或者仅返回偶数等,则在下一个主要版本中会发生什么。仅仅因为它现在可以正常工作还不能提供足够的保证,尤其是在需要安全的RNG的情况下。
- 当您说"一切似乎都是随机的"时,您如何衡量这一表现?我们人类很难确定一个序列是否是随机的,仅仅查看一个数字序列实际上是不可能真正分辨出它们是否是随机的。有许多方法可以量化一个系列的"随机性",包括频率分布,自相关,压缩等,还有许多我无法理解的方法。
- 如果您要为生产编写真正的"安全PRNG",请不要自己编写!由花费了数十年/数十年研究,设计并尝试将其破坏的专家调查和使用一个库或算法。真正安全的随机数生成很难。
如果您需要更多信息,请从Wikipedia上的PRNG文章开始,并根据需要使用那里的引用/链接。