//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))) }