Python:random.random()种子在哪里?

Aca*_*ile 5 python random cryptography random-seed

说我有一些python代码:

import random
r=random.random()
Run Code Online (Sandbox Code Playgroud)

从一般来说,种子的价值在哪里?
如果我的操作系统没有随机,那么播种在哪里呢?
为什么不推荐用于加密?有没有办法知道随机数是什么?

Bor*_*jaX 14

遵循da代码.

要查看random模块在您的系统中"存在"的位置,您可以在终端中执行:

>>> import random
>>> random.__file__
'/usr/lib/python2.7/random.pyc'
Run Code Online (Sandbox Code Playgroud)

这为您提供了.pyc("编译")文件的路径,该文件通常与.py可以找到可读代码的原始文件并排放置.

让我们看看发生了什么/usr/lib/python2.7/random.py:

你会看到它创建了一个Random类的实例,然后(在文件的底部)"提升"该实例的方法到模块的功能.干净的把戏.在random任何地方导入模块时,Random会创建该类的新实例,然后初始化其值,并将这些方法重新分配为模块的功能(使其在每次导入时非常随机)

_inst = Random()
seed = _inst.seed
random = _inst.random
uniform = _inst.uniform
triangular = _inst.triangular
randint = _inst.randint
Run Code Online (Sandbox Code Playgroud)

这个Random类在其__init__方法中唯一做的就是播种它:

class Random(_random.Random):
    ...
    def __init__(self, x=None):
        self.seed(x)    
...
_inst = Random()
seed = _inst.seed
Run Code Online (Sandbox Code Playgroud)

那么......如果xNone(没有指定种子)会发生什么?好吧,让我们检查一下这个self.seed方法:

def seed(self, a=None):
    """Initialize internal state from hashable object.

    None or no argument seeds from current time or from an operating
    system specific randomness source if available.

    If a is not None or an int or long, hash(a) is used instead.
    """

    if a is None:
        try:
            a = long(_hexlify(_urandom(16)), 16)
        except NotImplementedError:
            import time
            a = long(time.time() * 256) # use fractional seconds

    super(Random, self).seed(a)
    self.gauss_next = None
Run Code Online (Sandbox Code Playgroud)

评论已经告诉我们发生了什么......这种方法试图使用操作系统提供的默认随机生成器,如果没有,那么它将使用当前时间作为种子值.

但是,等等......那到底是什么_urandom(16)东西呢?

那么,答案就在这个random.py文件的开头:

from os import urandom as _urandom
from binascii import hexlify as _hexlify
Run Code Online (Sandbox Code Playgroud)

Tadaaa ...种子是一个16字节的数字来自os.urandom

假设我们处于文明的操作系统中,例如Linux(带有真正的随机数生成器).random模块使用的种子与执行以下操作相同:

>>> long(binascii.hexlify(os.urandom(16)), 16)
46313715670266209791161509840588935391L
Run Code Online (Sandbox Code Playgroud)

为什么指定一个种子值被认为不那么大的原因是这些random函数并不是真正的"随机"...它们只是一个非常奇怪的数字序列.但是给定相同的种子,该序列将是相同的.你可以自己试试:

>>> import random
>>> random.seed(1)
>>> random.randint(0,100)
13
>>> random.randint(0,100)
85
>>> random.randint(0,100)
77
Run Code Online (Sandbox Code Playgroud)

无论何时或如何,甚至在那里您运行的代码(只要用于生成随机数算法保持不变),如果你的种子1,你总是会得到的整数13,85,77...哪种击败目的(见关于伪随机数生成).另一方面,还有的用例,其中这其实是一个理想的功能,虽然.

这就是为什么被认为是"更好"依赖于操作系统随机数发生器.这些通常是基于硬件中断来计算的,这些中断非常非常随机(包括硬盘读取中断,人类用户键入的键击,移动鼠标......)在Linux中,OS生成器是/ dev/random.或者,有点挑剔,/dev/urandom(这就是Python os.urandom内部实际使用的)不同之处在于(如前所述)/dev/random使用硬件中断来生成随机序列.如果没有中断,/dev/random可能会耗尽,您可能需要等待一段时间才能获得下一个随机数./dev/urandom/dev/random内部使用,但它保证它总是随机编号为您准备好.

如果你正在使用linux,只需cat /dev/random在终端上做(并准备点击,Ctrl+C因为它会真正开始输出,非常随机的东西)

borrajax@borrajax:/tmp$ cat /dev/random
_+?_??zta????K?????q??k??/???qSlV??{?Gzk`???#p$?*C?F"?B9??o~,?QH?????f????po?2o?(=??t?0?p|m?e
???-?5????ED?l?Qt?/??,uD?w&m????/??;??5Ce?+?M????
~ ?4D??XN?????d??$7??kte?s???7_???-     ?d|????cY-?j>?
                    ?b}#?W<????8???{?1»
.       75???c4$3z???/??(?(???`???k?fC_^C
Run Code Online (Sandbox Code Playgroud)

Python使用OS随机生成器或时间作为种子.这意味着我可以想象Python random模块潜在弱点的唯一地方就是使用它:

  • 在没有实际随机数生成器的OS中,
  • 在一个time.time始终报告同一时间的设备(基本上有一个时钟损坏)

如果您担心random模块的实际随机性,您可以直接os.urandom或使用pycrypto加密库中的随机数生成器.那些可能更随意.我说更随意因为......

/sf/answers/150224371/

图像灵感来自另一个SO答案

  • 非常详细的答案. (2认同)