Files
2026-05-27 23:03:00 +08:00

220 lines
4.3 KiB
Go

//go:build ignore
// +build ignore
package main
import (
"flag"
"fmt"
"io/ioutil"
"math"
"os"
"path"
"runtime"
"sync"
"xdx.jelly/xgcl/grand/statistics"
)
var suit = []struct {
name string
fn func([]byte) bool
}{
{
name: "单比特频数检测 ",
fn: statistics.Frequency,
},
{
name: "块内频数检测 ",
fn: statistics.BlockFrequency,
},
{
name: "扑克检测, m=4 ",
fn: statistics.Poker4,
},
{
name: "扑克检测, m=8 ",
fn: statistics.Poker8,
},
{
name: "重叠子序列检测, m=2",
fn: statistics.Serial2,
},
{
name: "重叠子序列检测, m=5",
fn: statistics.Serial5,
},
{
name: "游程总数检测 ",
fn: statistics.Runs,
},
{
name: "游程分布检测 ",
fn: statistics.RunsDistribution,
},
{
name: "二元推导检测, k=3 ",
fn: statistics.BinaryDerivative3,
},
{
name: "二元推导检测, k=7 ",
fn: statistics.BinaryDerivative7,
},
{
name: "自相关检测, d=1 ",
fn: statistics.Autocorrelation1,
},
{
name: "自相关检测, d=2 ",
fn: statistics.Autocorrelation2,
},
{
name: "自相关检测, d=8 ",
fn: statistics.Autocorrelation8,
},
{
name: "自相关检测, d=16 ",
fn: statistics.Autocorrelation16,
},
{
name: "矩阵秩检测 ",
fn: statistics.Rank,
},
{
name: "累加和检测 ",
fn: statistics.CumulativeSums,
},
{
name: "近似熵检测 ",
fn: statistics.ApproximateEntropy,
},
{
name: "线性复杂度检测 ",
fn: statistics.LinearComplexity,
},
{
name: "Maurer通用统计检测 ",
fn: statistics.Universal,
},
{
name: "离散傅立叶检测 ",
fn: statistics.DiscreteFourierTransform,
},
}
type payload struct {
e []byte
fn func([]byte) bool
}
func worker(in chan *payload, out chan bool, done chan struct{}) {
for {
select {
case p := <-in:
out <- p.fn(p.e) // fn may panic
case <-done:
return
}
}
}
func main() {
dataDir := flag.String("d", "./data", "The directory of random data, default is \"./data\"")
flag.Parse()
fmt.Println("=======================================================")
fmt.Println(" 测试文件夹:", *dataDir)
epsilons := make([][]byte, 0)
fs, err := ioutil.ReadDir(*dataDir)
if err != nil {
fmt.Println("文件夹读取错误: ", err)
return
}
for _, file := range fs {
if !file.IsDir() {
epsilon, err := readFile(path.Join(*dataDir, file.Name()))
if err != nil {
fmt.Println("文件读取错误: ", err)
return
}
epsilons = append(epsilons, epsilon)
}
}
fmt.Printf(" 共有随机数文件%d个,每个文件%d比特\n", len(epsilons), len(epsilons[0]))
bound := lowerBound(len(epsilons))
fmt.Printf(" 每组检测通过的样本数必须不小于: %d\n", bound)
fmt.Println("=======================================================")
threads := runtime.NumCPU()
in := make(chan *payload, threads)
out := make(chan bool, threads)
done := make(chan struct{})
for i := 0; i < threads; i++ {
go worker(in, out, done)
}
// for {
for _, t := range suit {
// for _, t := range suit[len(suit)-1:] {
sum := 0
var wg sync.WaitGroup
wg.Add(len(epsilons))
go func() {
for _, e := range epsilons {
in <- &payload{
e: e,
fn: t.fn,
}
}
}()
go func() {
for i := 0; i < len(epsilons); i++ {
b := <-out
if b {
sum += 1
}
wg.Done()
}
}()
wg.Wait()
if sum < bound {
fmt.Printf("[x] %s 【失败】: %d / %d\n", t.name, sum, len(epsilons))
} else {
fmt.Printf("[o] %s 【通过】: %d / %d\n", t.name, sum, len(epsilons))
}
}
// }
}
// readFile read from fileName and convert each bit to byte
func readFile(fileName string) ([]byte, error) {
content, err := os.ReadFile(fileName)
if err != nil {
return nil, err
}
bits := make([]byte, 0, len(content)*8)
for _, c := range content {
bits = append(bits, (c>>7)&1)
bits = append(bits, (c>>6)&1)
bits = append(bits, (c>>5)&1)
bits = append(bits, (c>>4)&1)
bits = append(bits, (c>>3)&1)
bits = append(bits, (c>>2)&1)
bits = append(bits, (c>>1)&1)
bits = append(bits, (c>>0)&1)
}
return bits, nil
}
const alpha float64 = 0.01
func lowerBound(samples int) int {
return int(math.Ceil((1 - alpha - 3*math.Sqrt((alpha*(1-alpha))/float64(samples))) * float64(samples)))
}