我们增加了[可能] [几乎]是偶然的事实的随机性


随机数更美味,如果有一点胡椒

我们将理论与实践相结合-我们将证明改善随机序列的熵是可能的,然后我们将研究实现此目的的源代码。

我真的想写一个事实,即高质量(即高度熵)随机数生成对于解决大量问题至关重要,但这可能是多余的。 我希望每个人都非常了解这一点。

为了追求高质量的随机数,人们发明了非常机灵的设备(例如,请参见此处此处 )。 原则上,操作系统的API内置了相当不错的随机性源,但这是一个严重的问题,令人生疑的蠕虫总是会吃掉我们一些东西:我使用的RNG是否足够好并且被宠坏了……比方说,是第三方?

一点理论


首先,我们显示出使用正确的方法,不会降低现有RNG的质量。 最简单的正确方法是通过XOR操作在序列上叠加任何其他序列。 例如, 主要序列可能是系统的RNG,我们已经认为它不错,但是仍然存在一些疑问,我们希望安全地运行它。 另一个序列可能是例如伪随机数生成器,其输出看起来不错,但是我们知道其实际熵非常低。 结果序列将是对主序列和辅助序列的位进行XOR操作的结果。 一个重要的细微差别:主要序列和次要序列必须彼此独立。 也就是说,它们的熵必须取自根本不同的来源,而它们的相互依赖性无法计算。

x表示主序列下一位,用y表示附加序列的相应位。 结果序列的位用r表示:
r =x⊕y

首次尝试证明。 让我们尝试遍历xyr的信息熵。 我们将零x的概率表示为p x0 ,将零y的概率表示为p y0 。 信息熵xy是根据Shannon公式计算的:

H x =-(p x0 log 2 p x0 +(1 − p x0 )log 2 (1 − p x0 ))
H y =-(p y0 log 2 p y0 +(1 − p y0 )log 2 (1 − p y0 ))

当输入中有两个零或两个单位时,结果序列中的零出现。 零r的概率:

p r0 = p x0 p y0 +(1 − p x0 )(1 − p y0
H r =-(p r0 log 2 p r0 +(1 − p r0 )log 2 (1 − p r0 ))

为了证明主序列的不变性,有必要证明
对于p x0p y0的任何值, Hr-Hx≥0 。 我无法通过分析来证明这一点,但可视化计算表明,熵的增加形成了光滑的表面,在任何地方都不会减负:


例如,如果将高度偏斜的附加信号p y0 = 0.1添加到偏斜的主信号c p x0 = 0.3(熵0.881),则得到的结果p r0 = 0.66,熵0.925。

因此,熵不能被破坏,但这还不准确。 因此,需要第二次尝试。 但是,通过熵也可以证明这一点。 方案(所有步骤都非常简单,您可以自己完成):

  1. 我们证明熵在点0 = 1/2处具有最大值。
  2. 我们证明对于任何p x0p y0, p r0 值都不能比p x0差 1/2。

第二次尝试证明。 通过猜测的能力。 假设攻击者先验地具有有关主序列和次序列的一些信息。 信息的拥有以某种可能性来表达,即有可能提前猜测xy以及结果r的能力 。 猜测xy的概率分别由g xg y表示(来自单词guess)。 当正确猜出两个值或两个都不正确时,都会猜出结果序列的位,因此猜测的概率为:
g r = g x g y +(1 − g x )(1 − g y )= 2 g x g y -g x -g y + 1

当我们有一个完美的猜测者时,我们有g = 1。 如果我们什么都不知道,则g是...不,不是零,而是1/2。 如果我们通过抛硬币做出决定,这正是猜测结果的可能性。 一个非常有趣的情况是g <1/2。 一方面,这样一个猜测者在他自己内部的某处具有有关预测值的数据,但由于某种原因使它的输出反转,因此硬币变得更糟 。 请记住“比硬币更糟”这句话,下面对我们很有用。 从传播的数学理论(以及因此而为我们所熟悉的信息定量理论)的角度来看,这种情况是荒谬的,因为它不是信息理论,而是虚假信息理论,但是在生活中,这种情况比我们想要的更多。

考虑极限情况:

  • g x = 1 ,即序列x是完全可预测的:
    g r = g x g y +(1 − g x )(1 − g y )= 1 g y +(1-1)(1 − g y )= g y
    即,猜测结果的概率等于猜测附加序列的概率。
  • g y = 1 :与前一个类似。 猜测结果的概率等于猜测主序列的概率。
  • g x = 1/2 ,即序列x完全不可预测:
    g r = 2 g x g y -g x -g y + 1 = 2/2 g y -1/2-g y +1 = g y -g y + 1/2 = 1/2
    也就是说,添加任何其他序列不会损害主序列的完全不可预测性。
  • g y = 1/2 :与前一个类似。 添加一个完全不可预测的额外序列会使结果完全不可预测。

为了证明在主序列上添加一个附加序列不会对攻击者有所帮助,我们需要找出在什么条件下g r可能大于g x ,即

2 g x g y -g x -g y + 1> g x

将g x从右侧移到左侧,将g y和1移动到右侧:

2 g x g y -g x -g x > g y -1
2 g x g y -2 g x > g y -1
将2g x放在左括号中:
2 g x (g y -1)> g y -1
由于我们的g y小于1(我们已经考虑过g y = 1的极限情况),因此我们将g y -1变为1-g y ,而不必忘记将“更多”更改为“更少”:
2 g x (1- g y )<1- g y

减少“ 1- g y ”,并得到增加附加序列将改善攻击者猜测情况的条件:

2克x <1
x <1/2

也就是说,只有在猜测主序列比硬币差的情况下, g r才能大于g x 。 然后,当我们的预测变量参与有意识的破坏活动时。

有关熵的其他一些注意事项。

  1. 熵是一个极其神话的概念。 信息-包括。 这非常令人不安。 通常,信息熵被表示为一种客观存在于数据中的微妙物质。 实际上,信息熵不是信号本身中存在的信息,而是对消息接收者关于消息本身的先验意识的定量评估。 即,不仅与信号有关,而且与接收者有关。 如果接收者事先对信号一无所知,则无论如何接收信号和接收到什么信号,发送的二进制单位的信息熵都恰好是1位。
  2. 我们有一个熵加定理,根据该定理,独立源的总熵等于这些源的熵之和。 如果我们通过连接将主序列与附加序列组合在一起,我们将保留源的熵,但是会得到不好的结果,因为在我们的任务中,我们需要用单独的位来评估总熵而不是总熵。 源的级联给我们提供的结果的特定熵等于源的熵的算术平均值,而熵弱的附加序列自然会使结果恶化。 XOR运算的应用导致以下事实:我们损失了一些熵,但可以保证所得的熵不劣于项的最大熵。
  3. 密码学家有一个教条:使用伪随机数生成器是不可原谅的傲慢。 因为这些生成器具有较小的比熵。 但是我们发现,如果一切正确,熵就会变成一桶蜂蜜,不会被任何数量的焦油所破坏。
  4. 如果我们只有10个字节的实际熵,并且散布在一个千字节的数据上,那么从形式上看,我们只有1%的特定熵,这是非常糟糕的。 但是,如果定性地涂抹了这10个字节,并且除了蛮力之外,就没有办法计算这10个字节,那么一切看起来都不会那么糟糕。 10个字节是2 80 ,如果我们每秒的蛮力搜索一万亿个选项,我们将平均需要19000年的时间来学习如何猜测下一个字符。

如上所述,信息熵是一个相对值。 对于一个主题,特定的熵为1,而对于另一个主题,特定的熵很可能为0。此外,一个为1的熵可能无法知道事务的真实状态。 系统RNG产生的流对于我们来说与真正的随机性是无法区分的,但是我们只能希望它对每个人来说都是真正的随机性。 并相信。 如果偏执狂暗示主要RNG的质量可能突然不令人满意,那么在附加RNG的帮助下进行套期保值是有意义的。

在Python中实现汇总RNG


from random import Random, SystemRandom from random import BPF as _BPF, RECIP_BPF as _RECIP_BPF from functools import reduce as _reduce from operator import xor as _xor class CompoundRandom(SystemRandom): def __new__(cls, *sources): """Positional arguments must be descendants of Random""" if not all(isinstance(src, Random) for src in sources): raise TypeError("all the sources must be descendants of Random") return super().__new__(cls) def __init__(self, *sources): """Positional arguments must be descendants of Random""" self.sources = sources super().__init__() def getrandbits(self, k): """getrandbits(k) -> x. Generates an int with k random bits.""" ########         : return _reduce(_xor, (src.getrandbits(k) for src in self.sources), 0) def random(self): """Get the next random number in the range [0.0, 1.0).""" ########  ,   SystemRandom   .  ... return self.getrandbits(_BPF) * _RECIP_BPF 

用法示例:

 >>> import random_xe # <<<    >>> from random import Random, SystemRandom >>> #  : >>> myrandom1 = random_xe.CompoundRandom(SystemRandom(), Random()) >>> #    Random: >>> myrandom1.random() 0.4092251189581082 >>> myrandom1.randint(100, 200) 186 >>> myrandom1.gauss(20, 10) 19.106991205743107 

被认为是正确的SystemRandom被用作主流,而作为辅助流-标准PRNG Random。 当然,这并不是很重要。 标准PRNG绝对不是值得开始的那种补充。 相反,您可以将两个系统RNG结合在一起:

 >>> myrandom2 = random_xe.CompoundRandom(SystemRandom(), SystemRandom()) 

从某种意义上讲,这方面的道理甚至更少(尽管出于某种原因,布鲁斯·施耐尔(Bruce Schneier)在“应用密码学”中建议这样做是出于某种原因),因为上述计算仅对独立来源有效。 如果系统的RNG被破坏,结果也将被破坏。 原则上,寻找额外熵的源头的花式飞行不受任何限制(在我们的世界中,无序比顺序更普遍),但是作为一个简单的解决方案,我将提供HashRandom PRSP,它也可以在random_xe库中实现。

基于流循环哈希的PRSP


在最简单的情况下,您可以采用相对少量的初始数据(例如,要求用户敲击键盘),计算其哈希值,然后将哈希值循环添加到哈希算法的输入中,并采用以下哈希值。 可以用以下方式表示:



此过程的加密强度基于两个假设:

  1. 从哈希值恢复原始数据的任务非常复杂。
  2. 使用哈希值,不可能恢复哈希算法的内部状态。

在咨询了内部偏执狂之后,他认为第二个假设是不必要的,因此,在PRNG的最终实施中,该计划有些复杂:



现在,如果攻击者设法获得“哈希2r”值,那么他将无法计算跟随其的“哈希2r”值,因为他没有一个不计算“反对羊毛”哈希函数就无法识别的“哈希2h”值。 因此,该方案的密码强度与所使用的哈希算法的密码强度相对应。

用法示例:

 >>> #  ,  HashRandom     '123': >>> myrandom3 = random_xe.CompoundRandom(SystemRandom(), random_xe.HashRandom('123')) >>> #    Random: >>> myrandom3.random() 0.8257149881148604 

默认情况下,使用SHA-256算法。 如果您还需要其他东西,则可以使用第二个参数将所需的哈希算法类型传递给构造函数。 例如,让我们制作一个复合RNG,将以下内容总结为一个堆:

1.系统性RNG(这是神圣的)。
2. SHA3-512算法处理的用户输入。
3. SHA-256处理此输入所花费的时间。

 >>> from getpass import getpass >>> from time import perf_counter >>> from hashlib import sha3_512 #    : >>> def super_myrandom(): t_start = perf_counter() return random_xe.CompoundRandom(SystemRandom(), random_xe.HashRandom( getpass('  :'), sha3_512), random_xe.HashRandom(perf_counter() - t_start)) >>> myrandom4 = super_myrandom()   : >>> myrandom4.random() 0.35381173716740766 

结论:

  1. 如果我们不确定随机数生成器,则可以轻松,便宜地解决此问题。
  2. 解决这个问题,我们不能做得更糟。 只有更好。 并且它在数学上得到了证明。
  3. 我们一定不要忘记尝试确保所使用的熵源是独立的。

库资源在GitHub上

Source: https://habr.com/ru/post/zh-CN423093/


All Articles