改进硬件随机数生成器


53

您的任务是使用您所使用的任何硬件即兴使用硬件随机数生成器。

挑战

编写具有以下属性的程序:

  1. 它会打印01(或仅打印其他内容)。
  2. 输出取决于物理过程,而不仅取决于计算机的内部状态。
  3. 后续运行的输出(相隔一分钟)之间没有关系。
  4. 任何现实的努力都无法预测输出。
  5. 输出的概率0在0.2到0.8之间。
  6. 它在不到一分钟的时间内运行的可能性相当高。

您必须说明为什么程序不具有这些属性(如果不明显)。

澄清和限制

以下内容似乎对流行性竞赛有很多限制,但最终只能确保程序保持在问题的实质范围内,在一定程度上可行,并避免由于完全过高而普遍使用的解决方案,但最终我宁愿无聊的待着。

  • 系统时间不算作物理过程。
  • 您可以使用任何喜欢的消费级硬件,从8英寸的软盘驱动器到USB火箭发射器再到耳机-除非用于随机数生成。如果一件硬件是批量生产的,且成本低于1000美元/€/£ 则它是消费级的,因此您不能使用射电望远镜,CERN,MRI或家用粒子探测器。
  • 您只能对硬件的状态和对齐方式做出最基本的假设,例如打开电源(如果有电源开关)以及正确安装和运行。例如,您可以假定CD驱动器通常能够读取磁盘并且不会被阻塞,但是您不能假定CD驱动器可以打开或关闭或包含磁盘。在另一个示例中,您不能假设要对齐两个硬件以进行特殊的交互,但是可以假设它们在同一个房间中。
  • 除非破坏硬件,否则您可以使其处于任何状态。
  • 您可以并且必须假定硬件在自然环境中,但仅此而已。例如,您可以假定硬件未放置在液态氦的储罐中,既不隔音又不透光的房间中也不不在空间中。但是,您不能假定存在任何声音和光源,除非那些声音和光源只能通过激进的努力才能避免。
  • 您的程序必须在具有您选择的非神秘操作系统的标准台式计算机上运行。您可以使用任何不是专门为随机数生成设计的软件。
  • 您不能假设可以访问Internet。
  • 您不能假设没有人在场,但是您可以假设没有人有意干扰您的程序,例如,通过手动停止风扇或运行一个程序,该程序除了尽可能多地关闭麦克风外什么也不做。
  • 您只能对软件设置做出最基本的假设。例如,您可以假定要安装和激活驱动程序,但必须准备使声音静音。
  • 您可以根据需要将软件设置保持为任何状态。

奖金

一项特别短暂的解决方案被授予特别赏金。确切地说,它是通过指令的数量而不是字符来实现的。获奖者是(按照我的标准并列):

我只能授予一个答案,而Tejas Kale的答案却很幸运。


2
像在新型智能手机和笔记本电脑中发现的那样,陀螺仪是否被视为消费类硬件?
Nzall 2014年

@NateKerkhofs:是的。
Wrzlprmft

其实,我们能否得到“消费级硬件”的定义?“您可以在本地计算机商店以低于500美元的价格购买任何东西,或者可以从1000美元的机器中获得的任何东西”是否可以接受?
Nzall 2014年

1
@SebastianNegraszus:已经有了答案。
Wrzlprmft

1
让我在这里插入一些琐事,在澳大利亚国立大学有一个基于量子力学的实数随机发生器。看一下:qrng.anu.edu.au/index.php
Alexandre Teles

Answers:


28

贝壳

从麦克风流中读取单个样本并打印其最低有效位,该位应以噪声为主。

编辑:更改为取消静音麦克风...以及其他所有内容!

# Warning - unmutes EVERYTHING!
for DEV in `amixer | grep Simple | sed -e "s/.*'\(.*\)'.*/\\1/" -e "s/ /~/g"`
do
    amixer -q -- sset "`echo $DEV | sed 's/~/ /g'`" unmute 100% 2>/dev/null
done

echo $(( `od -N1 -d < /dev/dsp | head -n1 | sed 's/.* //'` & 1 ))

如果我将麦克风静音了怎么办?这不是完美的沉默吗?
yeti 2014年

3
@yeti:好的,当然。但是我们可以假定“硬件已打开且功能正常”,我认为涵盖了这一点。
2014年

3
对我来说,取消一切静音对“伪随机”二进制生成器来说是一个很大的(而且很烦人)的副作用,^^
Olivier Dulac

1
您可以尝试使用来向扬声器提供一些数据cat /dev/urandom > /dev/dsp,以防万一计算机位于隔音室/室/箱/箱/空间中。
伊斯梅尔·米格尔

就是我想做的!
shortstheory 2014年

26

重击

echo $[`ping -qc1 127.1|sed 's/[^1-9]/+/g'`0&1]

从单个ping到localhost的响应时间收集熵。

请注意,响应时间在以下输出中恰好出现三次ping -qc1

PING 127.1 (127.0.0.1) 56(84) bytes of data.

--- 127.1 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.044/0.044/0.044/0.000 ms

所有其他数字都是常数,而且更重要的是与响应时间无关。

sed 's/[^1-9]/+/g'将每个零和非数字转换为加号,并echo $[...0&1]打印所得和的奇偶校验。


1
它总是打印1对我来说:CYGWIN_NT-6.2-WOW64 work 1.7.28(0.271/5/3) 2014-02-09 21:06 i686 Cygwin- ping既没有-q-c在这里。
rr-

2
使用Windows ping确认。我很惊讶。
rr- 2014年

1
@JamesSnell:那就是问题所在。Windows Ping没有足够的精度。它将始终显示1毫秒的时间...
丹尼斯

6
似乎违反了限制2:ping localhost完全取决于计算机的内部状态。
tophyr

2
很难说。@丹尼斯:您知道波动的来源吗?
Wrzlprmft

25

JavaScript + HTML5 DeviceMotion

var hash = function(x) {
    var h = 0
    for (var i = 0; i < x.length; i++) {
        h += x.charCodeAt(i)
        h ^= h << 5
        h ^= h >> 3
        h ^= h << 13
        h &= 0xffff
    }
    return h
}
var listener = function(e) {
    var accelerationString = JSON.stringify(e.acceleration)
    var hashed = hash(accelerationString)
    alert(hashed % 2)
    window.removeEventListener("devicemotion", listener, true)
}
window.addEventListener("devicemotion", listener, true);

JSFiddle 在这里

在受支持的设备(主要是移动设备)上使用HTML5 DeviceMotion API。它将结果acceleration对象转换为JSON,对其进行哈希处理,然后将余数取模2。

大多数代码是哈希函数(该死的JavaScript,以及您完全缺乏标准库的功能)。它可能会更短一些,但是我很喜欢一个好的哈希函数。


40
“请摇动设备以生成新密码。”
PTwr 2014年

21

Python +网络摄像头

使用从此处偷来的代码,使用网络摄像头进行快照,对数据进行哈希处理,然后打印最低有效位。

#!/usr/bin/python
import pygame.camera, hashlib

pygame.camera.init()
cam = pygame.camera.Camera(pygame.camera.list_cameras()[0])
cam.start()
raw = cam.get_raw()
cam.stop()
pygame.camera.quit()

h = hashlib.sha256()
h.update(raw)
print ord(h.digest()[-1]) % 2

8
良好的哈希中没有“最低有效位”。是的,我知道您的意思
ni子手

11
@ 11684,相机中可能存在足够的热噪声等,以防止产生相同的结果
g小鸟

2
光线应该有很大的波动(外部光线向上/向下,当然,计算机可能发出的任何“闪烁”)
Olivier Dulac

7
这是基于我的一个朋友所做的事情。他对利用放射性衰变产生真正的随机数感兴趣。他拆除了一个摄像头和一个烟雾报警器,将同位素放在CCD旁边,并编写了一些代码以将检测到的β发射的位置输入到/ dev / random中。但是,我们发现,即使我们封闭了所有来自外部的光,尽管仍可以检测到β辐射,但CCD上仍有相当数量的背景噪声。
James_pic 2014年


15

佩尔

通过计时三个操作来检查硬盘的响应时间:

  • 阅读自己的资料
  • 删除自己
  • 再写一次

最后,将花费的时间打包为浮点数,并使用第11个最高有效位(尾数的第二个最高有效位)。

use Time::HiRes qw(time);

$t1 = time;
open SELF, "<$0";
read SELF, $_, $^H;
close SELF;

unlink $0;

open SELF, ">$0";
print SELF $_;
close SELF;

print 1&unpack(xB3, pack(f, time-$t1))

1
我只能想象一个由perl或python程序员执行的删除并写入磁盘的程序。很棒的主意!
iFreilicht 2014年

在VM中运行时,这看起来不会碰到任何硬件,并且具有确定性,这是很常见的情况。
彼得斯(Peteris)2014年

1
您希望刷新磁盘以使其依赖于磁盘而不是缓存(这是计算机状态,规则2)
MSalters 2014年

14

重击

echo $[`sensors|sed 's/[^1-9]/+/g'`0&1]

sensors 打印当前系统温度以及风扇速度。

acpitz-virtual-0
Adapter: Virtual device
temp1:        +52.0°C  (crit = +98.0°C)

thinkpad-isa-0000
Adapter: ISA adapter
fan1:        3510 RPM

coretemp-isa-0000
Adapter: ISA adapter
Physical id 0:  +54.0°C  (high = +86.0°C, crit = +100.0°C)
Core 0:         +51.0°C  (high = +86.0°C, crit = +100.0°C)
Core 1:         +46.0°C  (high = +86.0°C, crit = +100.0°C)

sed 's/[^1-9]/+/g'将每个零和非数字转换为加号,然后echo $[...0&1]打印所得和的奇偶校验。

正则表达式和奇偶校验计算借鉴了丹尼斯的答案。


该答案因特别短的解决方案而获得了特别赏金(以防万一,有人知道)。根据我的标准,它与弗兰基的答案并列,并以抽签方式获胜。
Wrzlprmft

12

重击

(echo -en "ibase=16;";(find /proc/[0-9]*/s* -type f -maxdepth 2 ; find /sys /proc/[^0-9]* -type f) 2>&1 | xargs -n1 sha256sum  2>&1 | sha256sum | tr abcdef ABCDEF | sed 's/  -/%2/' )| bc

使用一切,以防万一...

取决于

  • 大多数硬件传感器的传感器读数(几乎全部以某种方式在/sys或中的某个位置公开其值/proc
  • 系统上所有进程的数量,内存布局和运行时(可能被视为“系统状态”,但通常它们本身取决于硬件的时序)
  • 根据系统的不同,/proc/<pid>/s*(例如sched / schedstat)中的各种值取决于使这些进程生效所需的硬件速度。
  • 这些文件中也提供了我可能没有想到的内容。

我的系统上的运行时间约为10秒,但可能相差很大。特别是不要以root用户身份运行它,或者至少对其进行修改以排除/proc/kcore(除非您愿意花费很多时间来包含其中包含的熵,否则可能真的包含了所有内容)


9

外壳+ Wi-Fi

sudo airmon-ng start wlan0 > /dev/null && sudo dumpcap -a duration:30 -i mon0 -w out.cap > /dev/null && sha512sum out.cap | grep -c "^[0-7]" && sudo airmon-ng stop mon0 > /dev/null

将Wi-Fi卡置于监控器模式,转储接收到的30秒的数据包(包括来自相邻网络的不可读的加密数据),对数据包数据进行sha512哈希,如果哈希的第一个字母为0-7,则返回1 。假设您的Wi-Fi卡为wlan0,并且您当前没有mon0设备。

如果附近没有Wi-Fi设备,则输出将是可预测的,因为每次输出都相同。


1
嗯,我不会指望缺少wi-fi设备如此不自然,以至于您可以忽略它。
Wrzlprmft

3
@Wrzlprmft这取决于您在哪里。在拥挤的市区中没有wifi网络是不自然的。从普遍的角度来看,不是处于接近完全真空的状态不是一个公平的假设,也不限于地球是否可以将计算机浸没在水中也算是公平的。
伊恩·斯科特

1
@ IanD.Scott:好吧,对我来说,下一个无无线网络的区域实际上是在地窖中(不要问我为什么知道这一点)。而且我不住在虚无的地方。无论如何,在没有wifi的环境中,计算机的数量肯定比在水或真空中的(工作)计算机的数量高几个数量级。(我想这
全都取决于

8

英特尔制造的现代8086兼容处理器包含易于访问的外围设备,可产生适当的随机性。使用该rdrand指令来驱动该外设,如果该外设不可用或超出熵,则该指令会生成随机位模式或设置进位标志。

以下针对80386 Linux的简短程序通过cpuid指令检查外围设备是否可用,并尝试生成随机数。如果没有外围设备或随机数,则程序将以状态终止1。如果可以生成一个随机数,则打印出a 1或a 0,并且程序以退出状态终止0

另存为rand.s并组装

as --32 -o rand.o rand.s
ld -melf_i386 -o rand rand.o

这是整个程序集:

        .globl _start
        .type _start,@function
_start:
        # check if the cpuid instruction is available by trying to
        # toggle the id flag in the eflags register
        pushfl
        mov (%esp),%eax
        btc $21,%eax    # toggle id bit
        push %eax
        popfl           # check if id bit was saved
        pushfl
        pop %eax        # load new flags
        pop %ecx        # load original flags
        xor %ecx,%eax   # difference is in %eax
        bt $21,%eax     # check if bit was flipped
        jnc .Lfailure

        # if we reach this part, we have a cpuid instruction
        # next, check if rdrand exists
        mov $1,%eax     # load cpuid leaf 1
        cpuid
        bt $30,%ecx     # is rdrnd available?
        jnc .Lfailure

        # let's try to get some random data
        rdrand %ax      # don't waste randomness; one bit would suffice
        jnc .Lfailure   # no randomness available
        and $1,%eax     # isolate one bit of randomness
        add $0x30,%al   # 0x30 = '0'
        push %eax
        mov $4,%eax     # prepare a write system call
        mov $1,%ebx
        mov %esp,%ecx   # where we placed the data before
        mov %ebx,%edx   # one byte
        int $0x80

        # okay, we're done here. Let's exit
        mov %ebx,%eax   # do an exit system call with status 0
        xor %ebx,%ebx
        int $0x80

.Lfailure:
        mov $1,%eax     # do an exit system call with status 1
        mov %eax,%ebx
        int $0x80

        .size _start,.-_start

并转储产生的77个字节的机器代码:

08048098 <_start>:
 8048098:   9c                      pushf  
 8048099:   8b 04 24                mov    (%esp),%eax
 804809c:   0f ba f8 15             btc    $0x15,%eax
 80480a0:   50                      push   %eax
 80480a1:   9d                      popf   
 80480a2:   9c                      pushf  
 80480a3:   58                      pop    %eax
 80480a4:   59                      pop    %ecx
 80480a5:   31 c8                   xor    %ecx,%eax
 80480a7:   0f ba e0 15             bt     $0x15,%eax
 80480ab:   73 2f                   jae    80480dc <_start+0x44>
 80480ad:   b8 01 00 00 00          mov    $0x1,%eax
 80480b2:   0f a2                   cpuid  
 80480b4:   0f ba e1 1e             bt     $0x1e,%ecx
 80480b8:   73 22                   jae    80480dc <_start+0x44>
 80480ba:   66 0f c7 f0             rdrand %ax
 80480be:   73 1c                   jae    80480dc <_start+0x44>
 80480c0:   83 e0 01                and    $0x1,%eax
 80480c3:   04 30                   add    $0x30,%al
 80480c5:   50                      push   %eax
 80480c6:   b8 04 00 00 00          mov    $0x4,%eax
 80480cb:   bb 01 00 00 00          mov    $0x1,%ebx
 80480d0:   89 e1                   mov    %esp,%ecx
 80480d2:   89 da                   mov    %ebx,%edx
 80480d4:   cd 80                   int    $0x80
 80480d6:   89 d8                   mov    %ebx,%eax
 80480d8:   31 db                   xor    %ebx,%ebx
 80480da:   cd 80                   int    $0x80
 80480dc:   b8 01 00 00 00          mov    $0x1,%eax
 80480e1:   89 c3                   mov    %eax,%ebx
 80480e3:   cd 80                   int    $0x80

12
除非可以用于随机数生成,否则您可以使用任何[…]硬件[…] 。” –目标是简化硬件随机数生成器,而不使用一个。
Wrzlprmft

18
@Wrzlprmft rdrand不是随机数生成器。这是NSA与人们的加密技术相混淆的外围设备。
FUZxxl 2014年

1
实际上,在编写此程序之前,我没有注意到该句子。我的错。
FUZxxl 2014年

7

重击

瞄准最不必要的昂贵的随机数收集方法。将emacs生成一百万次所花费的时间,然后使用Dennis的技巧将花费的时间变成一个布尔值(在我的机器上花费大约7秒)。

$[`(time (seq 1000000 | xargs -P1000 emacs  >/dev/null 2>&1)) |& sed 's/[^1-9]/+/g'`0&1]

1
平均而言,偏差可能很小……
Sarge Borsch 2014年

7

Arduino Mega1280

编辑:更新版本,可以防止将任何东西插入图钉。该想法基于ATMega1280使用独立的内部振荡器作为看门狗振荡器的事实。我只是简单地设置了一个看门狗中断,该中断设置了一个标志,有一个基于系统时钟的计数器(在Arduino上,这是一个16MHz的外部晶体),并允许时钟抖动/方差起作用。

#include <avr/interrupt.h>

int time;
volatile bool wdt_ran;

// watchdog interrupt handler
ISR(WDT_vect, ISR_BLOCK)
{
  wdt_ran = true;
}

void setup()  
{
  // setup watchdog interrupt
  cli();
  MCUSR &= ~(1 << WDRF);
  WDTCSR |= (1<<WDCE) | (1<<WDE);
  WDTCSR = (1<<WDIE) | (1<<WDP2) | (1<<WDP1) | (1<<WDP0);
  sei();
  // Open serial communications and wait for port to open:
  Serial.begin(57600);
}

void loop()
{
  if(wdt_ran)
  {
    Serial.println(abs(time%2));
    wdt_ran = false;
  }
  ++time;
}

5

Java脚本

http://jsfiddle.net/prankol57/9a6s0gmv/

进行视频输入。

您可以看到用于计算随机数的屏幕截图。

var m = (navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia);

var constraints = {
  video: {
    mandatory: {
      maxWidth: 350,
      maxHeight: 350
    }
  },
  audio: false
};

var video = document.querySelector("video"), canvas = document.createElement("canvas");
document.body.appendChild(canvas);
canvas.width = 350;
canvas.height = 350;

function start() {
    m.call(navigator, constraints, function (stream) {
        video.src = window.URL.createObjectURL(stream);
    }, function() {
        alert("An error occured. Did you deny permission?");
    });
}

if (m) {
    start();
} else {
    alert('getUserMedia() is not supported in your browser');
}

function getRandomData() {
    var ctx = canvas.getContext("2d");
    ctx.drawImage(video, 0, 0);
    var data = ctx.getImageData(0, 0, 350, 350).data;
    var total = 0;
    for (var i = 0; i < data.length; ++i) {
        total += data[i];
        total %= 2;
    }
    alert("The random number is " + total);
}

document.querySelector("button").onclick = getRandomData;

1
我只是在FF中发现一个错误,“停止共享”不会关闭网络摄像头!
2014年

3

Linux上的Shell

测量硬盘驱动器的读取速度+此磁盘上布局经常无法预测的频繁更新目录的访问时间。

# Set this to the device node of whatever drive you want to measure
DRIVE_DEVICE=sda
# This must be a path that is
# a) on device "/dev/$DRIVE_PATH"
# b) frequently updated to add additional access time randomization due to
#    less-predictable disk layout due to less-predictable time, amount and
#    ordering uf updates, like logfile directories, maybe cache directories.
FIND_PATH=/var/log
# Better than using 'sync' - sync only the disk that we actually read from
# also sync both internal drive and system buffers
hdparm -f -F "/dev/$DRIVE_DEVICE"
# Note: bash's built-in time command doesn't support formats :/
# Note: the result is only going to be as good as the system's time command,
#       which isn't necessarily equally good on other U*ICes
t=$(command time -f '%e' -- find "$FIND_PATH" -printf '' 2>&1)
echo $((${t#*.}&1))

要求:

1) read and execute access to every directory under "$FIND_PATH"
2) sending (flush) control commands to a hard drive via a device node.
   Requires root access per default, but can be delegated to a less privileged user
   either by using sudo on this script or by applying
       chgrp 'some_system_group' "$DRIVE_DEVICE" &&
       chmod g+rx "$DRIVE_DEVICE"
   if this is acceptable on your system.

这种方法的优点是不修改系统上的任何数据,并且不需要perl优于primo的数据。


3

贝壳

在Linux上进行了测试,但是也许您的U * IX也具有/ proc / stat?

这仅启动一个附加过程,仅读取一个附加文件(甚至不读取光盘上的文件),并且长度为37个字符。它也非常快。

t=1`sum /proc/stat`;echo $[${t% *}&1]

可能有人认为这是由所有内核和用户态进程状态决定的,但事实并非如此,因为/ proc / stat还包括IO等待时间,服务硬件中断的时间,在空闲任务上花费的时间以及所有其他取决于外部硬件输入。


根据我的标准,这个答案与悬赏挂钩,特别是简短的答案,但很多都输了。
Wrzlprmft

2

Matlab的

麦克风解决方案:

recObj=audiorecorder;recordblocking(recObj,10);rem(sum(getaudiodata(recObj)<0),2)

记录10秒钟的声音,查找记录中的负采样数,如果该数字为偶数,则输出0,如果为奇数,则输出1。因此0为50%的概率。该方法意味着,即使是静音录音中不可避免的少量杂音,也足以产生随机输出。随后的稍长一些的代码通过使用较短的记录(由较高的比特率补偿)来加快数字发生器的速度,从而产生更多的噪声。

recObj=audiorecorder(8000,16,1);recordblocking(recObj,0.1);rem(sum(getaudiodata(recObj)<0),2)

在安静条件下的测试中,我发现在100次运行的后一代码中,该代码输出零51次。在嘈杂的条件下运行100次会产生40次零。

编辑:感谢Emil指出原始代码中的缺陷:-)


1
如果记录不是静音且没有非零样本,会发生什么?
埃米尔(Emil)2014年

1
好问题。无论如何,总是会弹出一些零,因为这些值会在零附近振荡(声音振动),并且小数位数有限。但是,既然您提到它,它当然应该是“ <0”而不是〜= 0,以便我计算负样本的数量。:-]这也是随机的。
Abulafia 2014年


0

占用计算机加速计的最低有效位(需要hdapsLinux模块):

#!/usr/bin/env python
import re
m = re.search('([-\d]+),([-\d]+)',
              open('/sys/devices/platform/hdaps/position', 'r').read())
print((int(m.group(1)) ^ int(m.group(2))) & 1)

这基本上可以测量传感器的噪声。


0

SmileBASIC

XON MOTION 'enable motion sensor
ACCEL OUT ,,Z 'get Z acceleration (up/down)
PRINT Z<-1 'if Z is less than -1, output 1, otherwise 0.

使用3DS的运动传感器。加速度计的Z轴通常约为-1(由于重力),并且由于随机噪声,有时可能会高于或低于Z轴。

这是使用麦克风的一种:

XON MIC 'enable microphone
DIM REC%[0] 'make array
MICSTART 0,3,1 'start recording. 0=8180Hz, 3=8 bit unsigned, 1=1 second
WAIT 1 'delay (1 frame is enough since we only check the first sample)
MICSAVE MIC 'save recording
PRINT MIC[0]>0 'if the first sample isn't negative, output 1

-3

重击

我接受了Soham的建议(使用top):

echo $[`top -bn1|sed 's/[^1-9]/+/g'`0&1]

编辑:它的工作方式与Soham相同。它将top输出中的所有非数字字符转换为“ +”,然后评估结果字符串的奇偶校验。

top的'b'标志以批处理模式运行它,以便它报告所有进程,而不仅仅是第一个屏幕,而'n1'则说只运行top的1次迭代。


您和Soham的计划之间真的有什么区别吗?
clismique
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.