golang真伪随机数

伪随机

伪随机性是一个过程似乎是随机的,但实际上并不是。例如伪随机数是使用一个确定性的算法计算出来的似乎是随机的数序,因此伪随机数实际上并不随机。在计算伪随机数时假如使用的开始值不变的话,那么伪随机数的数序也不变。伪随机数的随机性可以用它的统计特性来衡量,其主要特征是每个数出现的可能性和它出现时与数序中其它数的关系。伪随机数的优点是它的计算比较简单,而且只使用少数数值很难推算出计算它的算法。一般人们使用一个假的随机数,比如电脑上的时间作为计算伪随机数的开始值。

package main

import (
  "fmt"
  "math/rand"
  "time"
)

func main() {
  rand.Seed(int64(time.Now().UnixNano()))

  fmt.Println(rand.Int())
}

真随机

随机数据生成器也可以创建在“随机”的宏观过程基础上,比如基于掷硬币、骰子、轮盘和彩票摇奖机。这些现象中的不可预测性可由动力系统和混沌理论证明。虽然在经典力学中宏观过程都是决定论的,但一个设计良好的此类设备是无法在现实生活中被预测的,因为它的每次使用都依赖于敏感的初始条件。

package main

import (
  "crypto/rand"
  "fmt"
  "math/big"
)

func main() {
    result, _ := rand.Int(rand.Reader, big.NewInt(10))
    fmt.Println(result)
  
}

讨论点

其实伪随机没什么可讨论的,知道初始值,往里面套公式,就可以算出随机值
关键是golang的这个真随机,之前知道有个网站,专门提供真随机的api
https://www.random.org/

那golang是如何实现的呢

看了下文档,是这么描述的:
第一个传入的参数
rand.Reader是加密安全随机数生成器的全局共享实例。

在Linux和FreeBSD上,Reader使用getrandom(2)(如果可用),否则使用/dev/urandom。在OpenBSD上,Reader使用getentropy(2)。在其他类unix系统上,Reader从/dev/urandom读取数据。在Windows系统中,Reader使用CryptGenRandom API。在Wasm上,Reader使用Web Crypto API。

其中在linux下 getrandom()在Linux内核的3.17版才加入的
如果没有则通过 /dev/urandom去获取真随机源

其中/dev/random & /dev/urandom
这两个特殊设备都是字符型设备。我们可以在用户空间通过read系统调用读这两个设备文件以此获取随机数。这两个设备文件的区别在于:如果内核熵池的估计值为0时,

/dev/random将被阻塞,而/dev/urandom不会有这个限制。

熵池

计算机本身是可预测的系统,因此,用计算机算法不可能产生真正的随机数。但是机器的环境中充满了各种各样的噪声,如硬件设备发生中断的时间,用户点击鼠标的时间间隔等是完全随机的,事先无法预测。Linux内核实现的随机数产生器正是利用系统中的这些随机噪声来产生高质量随机数序列。
内核维护了一个熵池用来收集来自设备驱动程序和其它来源的环境噪音。理论上,熵池中的数据是完全随机的,可以实现产生真随机数序列。为跟踪熵池中数据的随机性,内核在将数据加入池的时候将估算数据的随机性,这个过程称作熵估算。熵估算值描述池中包含的随机数位数,其值越大表示池中数据的随机性越好。

总结

一般直接只用伪随机就好了,需要安全系数高,则采用真随机,但是真随机性能不如伪随机好。

添加新评论