Skip to content

Instantly share code, notes, and snippets.

@honwen
Last active December 28, 2017 18:48
Show Gist options
  • Save honwen/c6eb4ada5187cf208a131dfa7d1d6eb0 to your computer and use it in GitHub Desktop.
Save honwen/c6eb4ada5187cf208a131dfa7d1d6eb0 to your computer and use it in GitHub Desktop.

随机数生成器评估 - 以NIST为标准

小结: 通读NIST的文档,大致明白其中随机性的检测的原理。

NIST

测试项目与原理

  1. Frequency (Monobit) Test:
    频数测试: 二进制中的0和1出现的次数应该基本一样

  2. Frequency Test within a Block:
    块内频数测试: 非重叠的区块(M bit)中1出现的次数应该接近一半(M/2)

  3. Runs Test:
    游程测试: 0序列的长度与1序列的长度是否随机

  4. Test for the Longest Run of Ones in a Block:
    块内游程测试: 非重叠的区块(M bit)中0序列的长度与1序列的长度是否随机

  5. Binary Matrix Rank Test:
    矩阵秩的测试: 转化为矩阵, 求秩, 判断固定长度的的子串的相关性

  6. Discrete Fourier Transform (Spectral) Test:
    离散傅里叶变换测试: 做离散傅里叶变换, 看峰高的差异: 判断是否有周期性特征

  7. Non-overlapping Template Matching Test:
    非重叠模板匹配测试: 做模板匹配测试: (不重叠)搜索重复出现的相同序列

  8. Overlapping Template Matching Test:
    重叠模板匹配测试: 搜索重复出现的特定长度的1的序列

  9. Maurer’s “Universal Statistical” Test:
    可压缩性测试: 可压缩率与随机性负相关

  10. Linear Complexity Test:
    线性复杂度测试: 与随机性负相关

  11. Serial Test:
    连续性测试: m-bit的序列在2^m bit内的唯一性

  12. Approximate Entropy Test:
    近似熵测试: m-bit的序列在2^m bit的所有区块出现的频度

  13. Cumulative Sums (Cusum) Test:
    部分和测试: 区块累加, 然后左右平移, 看累加值变化

  14. Random Excursions Test:
    随机游走测试: 某个特定状态出现的次数是否远远超过真随机序列中的情况

  15. Random Excursions Variant Test:
    随机游走变量测试: 某一特定状态在一个游机游程中出现次数与真随机序列的偏离程度

测试工具的使用

参考资料:

最小Binary数据:

  • 128KiB (以/dev/urandom测试得出)

TestU01

测试项目

主要提供了三个大类别的测试模式

  • Small Crush (大约10种测试的组合)
  • Crush (大约60种测试的组合)
  • Big Crush (大约45种测试的组合)

参考资料:


测试脚本 for Binary with NIST (Skip Random Excursions and Universal Statistical)

package main

import (
	"bytes"
	"errors"
	"fmt"
	"os"
	"os/exec"
	"regexp"
	"strconv"
	"strings"

	"github.com/urfave/cli"
)

var (
	errSTFail = errors.New("Statistical Testing Failed")

	cmdPath  = `test.sh`
	cmdShell = `
#! /bin/sh

bitRNG=$1

LEN=100000
BITSTREAM=10

rm -rf ./experiments/AlgorithmTesting/finalAnalysisReport.txt

  ./assess $LEN <<-EOF 2>&1 | grep 'Statistical Testing'
0
$bitRNG
0
111111111010011
0
$BITSTREAM
1
EOF

cat ./experiments/AlgorithmTesting/finalAnalysisReport.txt
`
)

func main() {
	app := cli.NewApp()
	app.Name = "rank"
	app.Usage = "Rank RNG"
	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:  "file, f",
			Usage: "RNG Date Path",
		},
	}
	app.Action = func(c *cli.Context) error {
		dataPath := c.String("file")
		if 0 == len(dataPath) {
			cli.ShowAppHelp(c)
		} else {
			fout, err := os.Create(cmdPath)
			if err != nil {
				return err
			}
			defer fout.Close()
			defer os.Remove(cmdPath)
			fout.Write([]byte(cmdShell))
			if err := os.Chmod(cmdPath, 0755); err != nil {
				return err
			}

			cmd := exec.Command("/bin/sh", cmdPath, dataPath)
			var cmdOut bytes.Buffer

			cmd.Stdout = &cmdOut
			if err = cmd.Run(); err != nil {
				return errSTFail
			}

			result := cmdOut.String()
			if !strings.Contains(result, "Statistical Testing Complete") ||
				!strings.Contains(result, fmt.Sprintf("generator is <%s>", dataPath)) {
				return errSTFail
			}
			fraction := regexp.MustCompile(".*[^0-9]([0-9]+/[0-9]+).*").ReplaceAllString(result, "$1")
			// fmt.Printf("%+v", fraction)
			fractions := regexp.MustCompile("([0-9]+/[0-9]+)").FindAllString(fraction, -1)
			// fmt.Printf("%+v", fractions)

			extract := regexp.MustCompile("([0-9]+)/([0-9]+)")
			numeratorSUM, denominatorSUM := 0, 0
			for _, str := range fractions {
				numerator, _ := strconv.Atoi(extract.ReplaceAllString(str, "$1"))
				numeratorSUM += numerator
				denominator, _ := strconv.Atoi(extract.ReplaceAllString(str, "$2"))
				denominatorSUM += denominator
			}

			fmt.Printf("Rank: %.8f (%d of %d NIST-Test Passed!)\n",
				float64(numeratorSUM)/float64(denominatorSUM),
				numeratorSUM, denominatorSUM,
			)
		}
		return nil
	}
	if err := app.Run(os.Args); err != nil {
		fmt.Println(err)
	}
}

测试样例 (以 /dev/urandom 为例)

~/sts-2.1.2 » dd if=/dev/urandom of=./data/urandom bs=128K count=1
1+0 records in
1+0 records out
131072 bytes (131 kB, 128 KiB) copied, 0.000853436 s, 154 MB/s

~//sts-2.1.2 » go run rank.go -f data/urandom
Rank: 0.98633540 (1588 of 1610 NIST-Test Passed!)

测试脚本 for LCG(线性同余) with TestU01

#include "unif01.h"
#include "ulcg.h"
#include "bbattery.h"
#include <stddef.h>
int main (void) {
	unif01_Gen *gen1, *gen2, *gen3;
	gen1 = ulcg_CreateLCG (2147483543, 10064, 0, 12345);
	gen2 = ulcg_CreateLCG (2147483563, 16493, 0, 12345);
	gen3 = unif01_CreateCombAdd2 (gen1, gen2,"My Combination of LCGs");
	bbattery_SmallCrush (gen3);
	unif01_DeleteCombGen (gen3);
	ulcg_DeleteGen (gen1);
	ulcg_DeleteGen (gen2);
	return 0;
}

TO-DO

研究近年Paper:

  • Faster Randomness Testing with the NIST Statistical Test Suite
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment