init: v1.0.0

This commit is contained in:
yaole
2026-05-27 23:03:00 +08:00
commit 8d97f750eb
466 changed files with 80067 additions and 0 deletions
+219
View File
@@ -0,0 +1,219 @@
//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)))
}
+45
View File
@@ -0,0 +1,45 @@
//go:build ignore
// +build ignore
package main
import (
"fmt"
"testing"
)
func TestLowerBound(t *testing.T) {
fmt.Println(lowerBound(1024))
}
func TestP(t *testing.T) {
tests := []string{
"Frequency",
"BlockFrequency",
"CumulativeSums",
"Runs",
"LongestRunOfOnes",
"Rank",
"DiscreteFourierTransform",
"Universal",
"ApproximateEntropy",
"LinearComplexity",
"Serial",
"Poker",
"Autocorrelation",
"BinaryDerivative",
"RunsDistribution",
}
for _, t := range tests {
fmt.Printf(`
sum = 0
for _, e := range epsilons {
if statistics.%s(e) {
sum += 1
}
}
if sum < bound {
fmt.Printf("%s Test Failed: \d/\d\n", sum, len(epsilons))
}
`, t, t)
}
}
+374
View File
@@ -0,0 +1,374 @@
#include "RandomTest.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <math.h>
// 记录有过失败的数据
//
int fileNo = 1;
int testNo = 1;
int failed[TEST_NUM+1][SAMPLE_NUM+1] = {0};
int main(int argc, char * argv[])
{
unsigned char *epsilon;
int pass[TEST_NUM + 1];
if ( (epsilon = (BitSequence *) calloc(SAMPLE_LEN, sizeof(BitSequence))) == NULL ) {
printf("BITSTREAM DEFINITION: Insufficient memory available.\n");
return -1;
}
int ret = 0;
int testVector[30] = {0};
FILE *fp;
char FileName[128] = {0};
double passmin = 0.0;
int loop = 1, passnum = 0;
bzero(pass, sizeof(pass));
printf("\n\n I N P U T B A S E D I R\n");
printf(" Make sure the test datas are ./data/Random_[x].bin\n");
printf(" Press enter to continue.");
getchar();
while (loop)
{
ChooseItems(&testVector[0]);
/* testVector[0] = 19;*/
if (testVector[0] == 0)
break;
// 一键测试
if (testVector[0] == 80)
{
passnum = 0;
fprintf(stdout,">> one key test start.");
for (int k=1; k<=TEST_NUM ; ++k )
{
testNo = k;
printf("\n");
pass[k] = 0;
// for (int i=1; i<=SAMPLE_NUM; i++)
for (int i = 0; i < SAMPLE_NUM;)
{
fileNo = i;
sprintf(FileName, "./data/Random_%d.txt", i+1);
if((fp = fopen(FileName,"rb")),!fp)
{
printf("\n打开文件失败\n");
ret = -1;
goto CLR;
}
// read file and test
readHexDigitsInBinaryFormat(fp,k, epsilon, pass);
// close file
if (EOF == fclose(fp))
{
printf("\n关闭文件失败\n");
ret = -1;
goto CLR;
}
i++;
if (0 == i%200)
{
printf("\n option %d: %d / %d pass.\n",k,pass[k],i);
}
if ( SAMPLE_NUM == i )
{
passmin = SAMPLE_NUM * (1 - ALPHA - 3 * sqrt( ALPHA*(1-ALPHA)/SAMPLE_NUM));
if (pass[k] >= passmin)
{
passnum++;
fprintf(stdout,"\n[O] option %d pass the test, result is %d / %d .", k, pass[k], SAMPLE_NUM);
}
else
{
fprintf(stdout,"\n[X] option %d fail the test, result is %d / %d .", k, pass[k], SAMPLE_NUM);
}
}
}
}
if (passnum == sizeof(pass)/sizeof(pass[0]))
{
fprintf(stdout,"\n\n>> one key test end, all options passed.");
}
else
{
fprintf(stdout,"\n\n>> one key test end, some one failed.");
}
}
else
{
printf("\n");
pass[testVector[0]] = 0;
testNo = testVector[0];
for (int i=0; i<SAMPLE_NUM;)
{
fileNo = i;
sprintf(FileName, "./data/random%03d.bin", i);
// open file
if((fp = fopen(FileName,"rb")),!fp)
{
printf("\n打开文件失败\n");
ret = -1;
goto CLR;
}
// read file and test
readHexDigitsInBinaryFormat(fp,testVector[0], epsilon, pass);
// close file
if (EOF == fclose(fp))
{
printf("\n关闭文件失败\n");
ret = -1;
goto CLR;
}
i++;
if (0 == i%200)
{
printf("\n option %d: %d / %d pass.\n",testVector[0],pass[testVector[0]],i);
}
if ( SAMPLE_NUM == i )
{
passmin = SAMPLE_NUM * (1 - ALPHA - 3 * sqrt( ALPHA*(1-ALPHA)/SAMPLE_NUM));
if (pass[testVector[0]] >= passmin)
{
fprintf(stdout,"\n[O] option %d pass the test, result is %d / %d .", testVector[0], pass[testVector[0]], SAMPLE_NUM);
}
else
{
fprintf(stdout,"\n[X] option %d fail the test, result is %d / %d .", testVector[0], pass[testVector[0]], SAMPLE_NUM);
}
}
}
}
printf("\n\n F A I L E D T E S T D E T A I L S\n");
int filePassResult[SAMPLE_NUM + 1] = {0};
for (int j = 1; j < SAMPLE_NUM+1; j++){
for (int i = 1; i <= TEST_NUM; i++){
if (failed[i][j]){
printf(" random%d.bin failed test %d\n", j, i);
filePassResult[j] = 1;
}
}
}
printf("\n\n F A I L E D T E S T S U M A R R Y\n");
printf(" The following files are failed in some test:\n");
for (int j = 1; j < SAMPLE_NUM+1; j++){
if (filePassResult[j]){
printf(" random%i.bin\n", j);
}
}
if (testVector[0] == 80){
break;
}else{
printf("\n\nPress any key to go on!\n");
getchar();
}
}
CLR:
free(epsilon);
return ret;
}
void ChooseItems(int *pChoice)
{
printf("\n\n R A N D O M N E S S T E S T S\n");
printf(" _________________________________\n\n");
printf(" [01] monobit frequency test (单比特频数检测)\n");
printf(" [02] frequency test with a block (块内频数检测)\n");
printf(" [03] poker test (扑克检测, m=4)\n");
printf(" [04] serial test (重叠子序列检测, m=2)\n");
printf(" [05] runs test (游程总数检测)\n");
printf(" [06] runs distribution test (游程分布检测)\n");
printf(" [07] test for the longest run of ones in a block\n");
printf(" (块内最大“1”游程检测)\n");
printf(" [08] binary derivative test (二元推导检测, k=3)\n");
printf(" [09] autocorrelation test (自相关检测, d=1)\n");
printf(" [10] binary matrix rank test (矩阵秩检测)\n");
printf(" [11] cumulative test (累加和检测)\n");
printf(" [12] approximate entropy test (近似熵检测)\n");
printf(" [13] linear complexity test (线性复杂度检测)\n");
printf(" [14] Maurer's \"Universal Test\" (Maurer通用统计检测)\n");
printf(" [15] discrete fourier transform test (离散傅立叶检测)\n\n");
printf(" [16] poker test (扑克检测, m=8)\n");
printf(" [17] serial test (重叠子序列检测, m=5)\n");
printf(" [18] binary derivative test (二元推导检测, k=7)\n");
printf(" [19] autocorrelation test (自相关检测, d=2)\n");
printf(" [20] autocorrelation test (自相关检测, d=8)\n");
printf(" [21] autocorrelation test (自相关检测, d=16)\n\n");
printf(" [80] One Key Test All\n");
printf(" [00] Quit\n\n");
printf("> Enter Choice: ");
scanf("%d", pChoice);
printf("\n");
}
void Test_Suite(unsigned char *epsilon, int n, int Choice, int *pass)
{
if (TEST_FREQUENCY == Choice)
pass[TEST_FREQUENCY] += Frequency(epsilon, n);
if (TEST_BLOCK_FREQUENCY == Choice)
pass[TEST_BLOCK_FREQUENCY] += BlockFrequency(epsilon, n);
if ( TEST_CUSUM == Choice )
pass[TEST_CUSUM] += CumulativeSums(epsilon, n);
if ( TEST_RUNS == Choice )
pass[TEST_RUNS] += Runs(epsilon, n);
if ( TEST_LONGEST_RUN == Choice)
pass[TEST_LONGEST_RUN] += LongestRunOfOnes(epsilon, n);
if ( TEST_RANK == Choice)
pass[TEST_RANK] += Rank(epsilon, n);
if ( TEST_FFT == Choice)
pass[TEST_FFT] += DiscreteFourierTransform(epsilon, n);
if ( TEST_UNIVERSAL == Choice)
pass[TEST_UNIVERSAL] += Universal(epsilon, n);
if ( TEST_APEN == Choice)
pass[TEST_APEN] += ApproximateEntropy(epsilon, n);
if ( TEST_SERIAL2 == Choice)
pass[TEST_SERIAL2] += Serial(epsilon, n, 2);
if ( TEST_LINEARCOMPLEXITY == Choice)
pass[TEST_LINEARCOMPLEXITY] += LinearComplexity(epsilon, n);
if (TEST_POKER4 == Choice)
pass[TEST_POKER4] += Poker(epsilon, n, 4);
if (TEST_AUTOCORRELATION1 == Choice)
pass[TEST_AUTOCORRELATION1] += Autocorrelation(epsilon, n, 1);
if (TEST_BINARYDERIVATION3 == Choice)
pass[TEST_BINARYDERIVATION3] += BinaryDerivative(epsilon, n, 3);
if (TEST_RUNSDISTRIBUTION == Choice)
pass[TEST_RUNSDISTRIBUTION] += RunsDistribution(epsilon, n);
if (TEST_POKER8 == Choice)
pass[TEST_POKER8] += Poker(epsilon, n, 8);
if (TEST_SERIAL5 == Choice)
pass[TEST_SERIAL5] += Serial(epsilon, n, 5);
if (TEST_BINARYDERIVATION7 == Choice)
pass[TEST_BINARYDERIVATION7] += BinaryDerivative(epsilon, n, 7);
if (TEST_AUTOCORRELATION2 == Choice)
pass[TEST_AUTOCORRELATION2] += Autocorrelation(epsilon, n, 2);
if (TEST_AUTOCORRELATION8 == Choice)
pass[TEST_AUTOCORRELATION8] += Autocorrelation(epsilon, n, 8);
if (TEST_AUTOCORRELATION16 == Choice)
pass[TEST_AUTOCORRELATION16] += Autocorrelation(epsilon, n, 16);
}
void readHexDigitsInBinaryFormat(FILE *fp,int choose, unsigned char *epsilon, int *pass)
{
int i, done, num_0s, num_1s, bitsRead;
BYTE buffer[4];
// printf(" Statistical Testing In Progress.........\n\n");
for ( i=0; i<1; i++ ) {
num_0s = 0;
num_1s = 0;
bitsRead = 0;
done = 0;
do {
if ( fread(buffer, sizeof(unsigned char), 4, fp) != 4 ) {
printf("READ ERROR: Insufficient data in file.\n");
free(epsilon);
return;
}
done = convertToBits(epsilon,buffer, 32,SAMPLE_LEN, &num_0s, &num_1s, &bitsRead);
} while ( !done );
// fprintf(freqfp, "\t\tBITSREAD = %d 0s = %d 1s = %d\n", bitsRead, num_0s, num_1s);
Test_Suite(epsilon, SAMPLE_LEN, choose, pass);
}
}
int convertToBits(unsigned char *epsilon, BYTE *x, int xBitLength, int bitsNeeded, int *num_0s, int *num_1s, int *bitsRead)
{
int i, j, count, bit;
BYTE mask;
int zeros, ones;
count = 0;
zeros = ones = 0;
for ( i=0; i<(xBitLength+7)/8; i++ ) {
mask = 0x80;
for ( j=0; j<8; j++ ) {
if ( *(x+i) & mask ) {
bit = 1;
(*num_1s)++;
ones++;
}
else {
bit = 0;
(*num_0s)++;
zeros++;
}
mask >>= 1;
epsilon[*bitsRead] = bit;
(*bitsRead)++;
if ( *bitsRead == bitsNeeded )
return 1;
if ( ++count == xBitLength )
return 0;
}
}
return 0;
}