init: v1.0.0
This commit is contained in:
@@ -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)))
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
Reference in New Issue
Block a user