= 0) && (A[index][i] == 0) ) + index--; + if ( index >= 0 ) + row_op = swap_rows(i, index, Q, A); + } + + return row_op; +} + +int +swap_rows(int i, int index, int Q, BitSequence **A) +{ + int p; + BitSequence temp; + + for ( p=0; p+#include "include/utilities.h" +#include "include/stat_fncs.h" +#include "mesa_sts.h" + +int mesa_statistical_test_suite(void* data,unsigned int datalen, struct sts_result* result) +{ + TP tp; + tp.n = datalen; + tp.blockFrequencyBlockLength = 128; + tp.nonOverlappingTemplateBlockLength = 9; + tp.overlappingTemplateBlockLength = 9; + tp.approximateEntropyBlockLength = 10; + tp.serialBlockLength = 16; + tp.linearComplexitySequenceLength = 500; + tp.numOfBitStreams = 1; + tp.PokerDetectMLength = 8; + tp.BinaryDerivateKLength = 3; + tp.SelfCorrelationDLength = 8; + + BitSequence* epsilon = (BitSequence *)calloc(tp.n,sizeof(BitSequence)); + int done, num_0s, num_1s, bitsRead; + num_0s = 0; + num_1s = 0; + bitsRead = 0; + done = 0; + done = convertToBits((BYTE*)data,datalen,tp.n,&num_0s,&num_1s,&bitsRead,epsilon); + result->frequency = Frequency(tp.n,epsilon); + result->block_frequency = BlockFrequency(tp.blockFrequencyBlockLength, tp.n,epsilon); + result->cumulative_sums = CumulativeSums(tp.n,epsilon); + result->runs = Runs(tp.n,epsilon); + result->longest_run = LongestRunOfOnes(tp.n,epsilon); + result->rank = Rank(tp.n,epsilon); + //result->discrete_fourier_transform = DiscreteFourierTransform(tp.n,epsilon);//cost too much time + result->non_overlapping_template_matching = NonOverlappingTemplateMatchings(tp.nonOverlappingTemplateBlockLength, tp.n,epsilon); + result->overlapping_template_matching = OverlappingTemplateMatchings(tp.overlappingTemplateBlockLength, tp.n,epsilon); + result->universal = Universal(tp.n,epsilon); + //result->approximate_entropy = ApproximateEntropy(tp.approximateEntropyBlockLength, tp.n,epsilon);//cost too much time + result->random_excursions = RandomExcursions(tp.n,epsilon); + result->random_excursions_variant = RandomExcursionsVariant(tp.n,epsilon); + //result->serial = Serial(tp.serialBlockLength,tp.n,epsilon);//cost too much time + //sresult->linear_complexity = LinearComplexity(tp.linearComplexitySequenceLength, tp.n,epsilon);//cost too much time + result->poker_detect = PokerDetect(tp.PokerDetectMLength,tp.n,epsilon); + result->runs_distribution = RunsDistribution(tp.n,epsilon); + result->self_correlation = SelfCorrelation(tp.SelfCorrelationDLength,tp.n,epsilon); + result->binary_derivative = BinaryDerivate(tp.BinaryDerivateKLength,tp.n,epsilon,tp.n);//this function will change the value of epsilon, must be the last one + + free(epsilon); + epsilon = NULL; + + return 0; +} \ No newline at end of file diff --git a/src/nonOverlappingTemplateMatchings.c b/src/nonOverlappingTemplateMatchings.c new file mode 100644 index 0000000..7f5d24b --- /dev/null +++ b/src/nonOverlappingTemplateMatchings.c @@ -0,0 +1,131 @@ +#include+#include +#include +#include +#include "include/externs.h" +#include "include/cephes.h" + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + N O N O V E R L A P P I N G T E M P L A T E T E S T + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +int +NonOverlappingTemplateMatchings(int m, int n, BitSequence *epsilon) +{ + int ret = 0; + int numOfTemplates[100] = {0, 0, 2, 4, 6, 12, 20, 40, 74, 148, 284, 568, 1116, + 2232, 4424, 8848, 17622, 35244, 70340, 140680, 281076, 562152}; + /*---------------------------------------------------------------------------- + NOTE: Should additional templates lengths beyond 21 be desired, they must + first be constructed, saved into files and then the corresponding + number of nonperiodic templates for that file be stored in the m-th + position in the numOfTemplates variable. + ----------------------------------------------------------------------------*/ + unsigned int bit, W_obs, nu[6], *Wj = NULL; + FILE *fp = NULL; + double sum, chi2, p_value, lambda, pi[6], varWj; + int i, j, jj, k, match, SKIP, M, N, K = 5; + char directory[100]; + BitSequence *sequence = NULL; + + N = 8; + M = n/N; + + if ( (Wj = (unsigned int*)calloc(N, sizeof(unsigned int))) == NULL ) { + return 0; + } + lambda = (M-m+1)/pow(2, m); + varWj = M*(1.0/pow(2.0, m) - (2.0*m-1.0)/pow(2.0, 2.0*m)); + sprintf(directory, "templates/template%d", m); + + if ( ((isNegative(lambda)) || (isZero(lambda))) || + ((fp = fopen(directory, "r")) == NULL) || + ((sequence = (BitSequence *) calloc(m, sizeof(BitSequence))) == NULL) ) { + goto end; + } + else { + if ( numOfTemplates[m] < MAXNUMOFTEMPLATES ) + SKIP = 1; + else + SKIP = (int)(numOfTemplates[m]/MAXNUMOFTEMPLATES); + numOfTemplates[m] = (int)numOfTemplates[m]/SKIP; + + sum = 0.0; + for ( i=0; i<2; i++ ) { /* Compute Probabilities */ + pi[i] = exp(-lambda+i*log(lambda)-cephes_lgam(i+1)); + sum += pi[i]; + } + pi[0] = sum; + for ( i=2; i<=K; i++ ) { /* Compute Probabilities */ + pi[i-1] = exp(-lambda+i*log(lambda)-cephes_lgam(i+1)); + sum += pi[i-1]; + } + pi[K] = 1 - sum; + + for( jj=0; jj 1 ) + fseek(fp, (long)(SKIP-1)*2*m, SEEK_CUR); +// fprintf(results[TEST_NONPERIODIC], "%f\n", p_value); fflush(results[TEST_NONPERIODIC]); + if (p_value < ALPHA) { + goto end; + } + } + } + + ret = 1; +// fprintf(stats[TEST_NONPERIODIC], "\n"); fflush(stats[TEST_NONPERIODIC]); + + end: + if (Wj != NULL) { + free(Wj); + } + if (fp != NULL) { + fclose(fp); + } + if (sequence != NULL) { + free(sequence); + } + return ret; +} diff --git a/src/overlappingTemplateMatchings.c b/src/overlappingTemplateMatchings.c new file mode 100644 index 0000000..70eabdf --- /dev/null +++ b/src/overlappingTemplateMatchings.c @@ -0,0 +1,97 @@ +#include +#include +#include +#include +#include "include/externs.h" +#include "include/cephes.h" + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + O V E R L A P P I N G T E M P L A T E T E S T + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ +double Pr(int u, double eta); + +int +OverlappingTemplateMatchings(int m, int n, BitSequence *epsilon) +{ + int ret = 0; + int i, k, match; + double W_obs, eta, sum, chi2, p_value, lambda; + int M, N, j, K = 5; + unsigned int nu[6] = { 0, 0, 0, 0, 0, 0 }; + double pi[6] = { 0.143783, 0.139430, 0.137319, 0.124314, 0.106209, 0.348945 }; + BitSequence *sequence; + + M = 1032; + N = n/M; + + if ( (sequence = (BitSequence *) calloc(m, sizeof(BitSequence))) == NULL ) { + return 0; + } + else { + for (i = 0; i < m; i++) + sequence[i] = 1; + } + + lambda = (double)(M-m+1)/pow(2,m); + eta = lambda/2.0; + sum = 0.0; + for ( i=0; i +#include +#include "include/stat_fncs.h" +#include "include/cephes.h" + +typedef struct _PokerNi { + unsigned int flag; + unsigned int count; +} PokerNi; + +unsigned char toByte(BitSequence *subEpsilon, int M) +{ + int i = 0; + unsigned char result = 0; + for (i = 0; i < M; ++i) { + result |= (subEpsilon[i] << (M - i - 1)); + } + return result; +} + +int findIndex(PokerNi *tab, int tabSize, unsigned int flag) +{ + int i = 0; + for (i = 0; i < tabSize; ++i) { + if (tab[i].flag == flag) { + return i; + } + } + return -1; +} + +int PokerDetect(int M, int n, BitSequence *epsilon) +{ + int ret = 0; + int i = 0, j = 0, N = n / M, index = 0, c = 0; + int maxElements = (int) pow(2, M); + double p_value = 0.0, sum_ni = 0.0, mp = 0.0, V = 0.0; + unsigned int flag = 0; + PokerNi *tab = NULL; + + if (M > 8) { + return 0; + } + + tab = (PokerNi *)calloc(maxElements, sizeof(PokerNi)); + if (NULL == tab) { + return 0; + } + for (i = 0; i < maxElements; ++i) { + tab[i].flag = (unsigned int) i; + tab[i].count = 0; + } + + for (i = 0, j = 0; j < N; ++j, i += M) { + flag = toByte(epsilon + i, M); + index = findIndex(tab, maxElements, flag); + if (-1 == index) { + goto end; + } + tab[index].count += 1; + } + + for (i = 0; i < maxElements; ++i) { + sum_ni += pow(tab[i].count, 2); + } + mp = (double)maxElements / N; + V = mp * sum_ni - N; + + p_value = cephes_igamc((double)(maxElements - 1) / 2, V / 2); + if (p_value < ALPHA) { + goto end; + } + + ret = 1; + + end: + free(tab); + return ret; +} \ No newline at end of file diff --git a/src/randomExcursions.c b/src/randomExcursions.c new file mode 100644 index 0000000..135396d --- /dev/null +++ b/src/randomExcursions.c @@ -0,0 +1,116 @@ +#include +#include +#include +#include +#include "include/externs.h" +#include "include/cephes.h" + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + R A N D O M E X C U R S I O N S T E S T + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +int +RandomExcursions(int n, BitSequence *epsilon) +{ + int ret = 0; + int b, i, j, k, J, x; + int cycleStart, cycleStop, *cycle = NULL, *S_k = NULL; + const int stateX[8] = { -4, -3, -2, -1, 1, 2, 3, 4 }; + int counter[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; + double p_value, sum, constraint, nu[6][8]; + double pi[5][6] = { {0.0000000000, 0.00000000000, 0.00000000000, 0.00000000000, 0.00000000000, 0.0000000000}, + {0.5000000000, 0.25000000000, 0.12500000000, 0.06250000000, 0.03125000000, 0.0312500000}, + {0.7500000000, 0.06250000000, 0.04687500000, 0.03515625000, 0.02636718750, 0.0791015625}, + {0.8333333333, 0.02777777778, 0.02314814815, 0.01929012346, 0.01607510288, 0.0803755143}, + {0.8750000000, 0.01562500000, 0.01367187500, 0.01196289063, 0.01046752930, 0.0732727051} }; + + if ( ((S_k = (int *)calloc(n, sizeof(int))) == NULL) || + ((cycle = (int *)calloc(MAX(1000, n/100), sizeof(int))) == NULL) ) { + printf("Random Excursions Test: Insufficent Work Space Allocated.\n"); + if ( S_k != NULL ) + free(S_k); + if ( cycle != NULL ) + free(cycle); + return 0; + } + + J = 0; /* DETERMINE CYCLES */ + S_k[0] = 2*(int)epsilon[0] - 1; + for( i=1; i MAX(1000, n/100) ) { + printf("ERROR IN FUNCTION randomExcursions: EXCEEDING THE MAX NUMBER OF CYCLES EXPECTED\n."); + goto end; + } + cycle[J] = i; + } + } + if ( S_k[n-1] != 0 ) + J++; + cycle[J] = n; + + constraint = MAX(0.005*pow(n, 0.5), 500); + if (J < constraint) { + ret = 1; //TODO + goto end; + } + else { + cycleStart = 0; + cycleStop = cycle[1]; + for ( k=0; k<6; k++ ) + for ( i=0; i<8; i++ ) + nu[k][i] = 0.; + for ( j=1; j<=J; j++ ) { /* FOR EACH CYCLE */ + for ( i=0; i<8; i++ ) + counter[i] = 0; + for ( i=cycleStart; i = 1 && S_k[i] <= 4) || (S_k[i] >= -4 && S_k[i] <= -1) ) { + if ( S_k[i] < 0 ) + b = 4; + else + b = 3; + counter[S_k[i]+b]++; + } + } + cycleStart = cycle[j]+1; + if ( j < J ) + cycleStop = cycle[j+1]; + + for ( i=0; i<8; i++ ) { + if ( (counter[i] >= 0) && (counter[i] <= 4) ) + nu[counter[i]][i]++; + else if ( counter[i] >= 5 ) + nu[5][i]++; + } + } + + for ( i=0; i<8; i++ ) { + x = stateX[i]; + sum = 0.; + for ( k=0; k<6; k++ ) + sum += pow(nu[k][i] - J*pi[(int)fabs(x)][k], 2) / (J*pi[(int)fabs(x)][k]); + p_value = cephes_igamc(2.5, sum/2.0); + + if ( isNegative(p_value) || isGreaterThanOne(p_value) ) { +// fprintf(stats[TEST_RND_EXCURSION], "WARNING: P_VALUE IS OUT OF RANGE.\n"); + goto end; + } + +// fprintf(stats[TEST_RND_EXCURSION], "%s\t\tx = %2d chi^2 = %9.6f p_value = %f\n", +// p_value < ALPHA ? "FAILURE" : "SUCCESS", x, sum, p_value); +// fprintf(results[TEST_RND_EXCURSION], "%f\n", p_value); fflush(results[TEST_RND_EXCURSION]); + if (p_value < ALPHA) { + goto end; + } + } + } +// fprintf(stats[TEST_RND_EXCURSION], "\n"); fflush(stats[TEST_RND_EXCURSION]); + ret = 1; + + end: + free(S_k); + free(cycle); + return ret; +} diff --git a/src/randomExcursionsVariant.c b/src/randomExcursionsVariant.c new file mode 100644 index 0000000..447ddf6 --- /dev/null +++ b/src/randomExcursionsVariant.c @@ -0,0 +1,61 @@ +#include +#include +#include +#include +#include "include/externs.h" +#include "include/cephes.h" + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + R A N D O M E X C U R S I O N S V A R I A N T T E S T + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +int +RandomExcursionsVariant(int n, BitSequence *epsilon) +{ + int ret = 0; + int i, p, J, x, constraint, count, *S_k = NULL; + const int stateX[18] = { -9, -8, -7, -6, -5, -4, -3, -2, -1, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + double p_value; + + if ( (S_k = (int *)calloc(n, sizeof(int))) == NULL ) { + return 0; + } + J = 0; + S_k[0] = 2*(int)epsilon[0] - 1; + for ( i=1; i +#include +#include +#include +#include "include/externs.h" +#include "include/cephes.h" +#include "include/matrix.h" + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + R A N K T E S T + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +int +Rank(int n, BitSequence *epsilon) +{ + int ret = 0; + int N, i, k, r; + double p_value, product, chi_squared, arg1, p_32, p_31, p_30, R, F_32, F_31, F_30; + BitSequence **matrix = create_matrix(32, 32); + + N = n/(32*32); + if ( isZero(N) ) { + p_value = 0.00; + } + else { + r = 32; /* COMPUTE PROBABILITIES */ + product = 1; + for ( i=0; i<=r-1; i++ ) + product *= ((1.e0-pow(2, i-32))*(1.e0-pow(2, i-32)))/(1.e0-pow(2, i-r)); + p_32 = pow(2, r*(32+32-r)-32*32) * product; + + r = 31; + product = 1; + for ( i=0; i<=r-1; i++ ) + product *= ((1.e0-pow(2, i-32))*(1.e0-pow(2, i-32)))/(1.e0-pow(2, i-r)); + p_31 = pow(2, r*(32+32-r)-32*32) * product; + + p_30 = 1 - (p_32+p_31); + + F_32 = 0; + F_31 = 0; + for ( k=0; k +#include +#include +#include +#include "include/externs.h" +#include "include/cephes.h" + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + R U N S T E S T + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +int +Runs(int n, BitSequence *epsilon) +{ + int S, k; + double pi, V, erfc_arg, p_value; + + S = 0; + for ( k=0; k (2.0 / sqrt(n)) ) { + p_value = 0.0; + } + else { + + V = 1; + for ( k=1; k +#include +#include "include/stat_fncs.h" +#include "include/cephes.h" + +int RunsDistribution(int n, BitSequence *epsilon) +{ + int ret = 0; + int i = 0, j = 0, k = 0; + unsigned char runFlag = 0x00; + double p_value = 0.0, sum_bi = 0.0, sum_gi = 0.0, V = 0.0; + double *bi = NULL, *gi = NULL, *e = NULL; + double bit = 0.0, git = 0.0, et = 0.0; + + bi = (double *)calloc(n, sizeof(double)); + if (NULL == bi) { + goto end; + } + gi = (double *)calloc(n, sizeof(double)); + if (NULL == gi) { + goto end; + } + e = (double *)calloc(n, sizeof(double)); + if (NULL == e) { + goto end; + } + + for (i = 1; i <= n; ++i) { + e[i - 1] = (double)(n - i + 3) / pow(2, i + 2); + if (e[i - 1] >= 5) { + k = i; + } + } + + runFlag = epsilon[0]; + j = 1; + for (i = 1; i < n; ++i) { + if (epsilon[i] != runFlag) { + if (runFlag == 0x00) { + gi[j - 1] += 1; + } else if (runFlag == 0x01) { + bi[j - 1] += 1; + } + runFlag = epsilon[i]; + j = 1; + } else { + ++j; + } + } + + for (i = 0; i < k; ++i) { + bit = bi[i]; + et = e[i]; + sum_bi += pow(bit - et, 2) / et; + } + for (i = 0; i < k; ++i) { + git = gi[i]; + et = e[i]; + sum_gi += pow(git - et, 2) / et; + } + V = sum_bi + sum_gi; + + p_value = cephes_igamc(k - 1, V / 2); + if (p_value < ALPHA) { + goto end; + } + + ret = 1; + + end: + if (NULL != bi) { + free(bi); + } + if (NULL != gi) { + free(gi); + } + if (NULL != e) { + free(e); + } + return ret; +} + diff --git a/src/selfCorrelation.c b/src/selfCorrelation.c new file mode 100644 index 0000000..d47a67b --- /dev/null +++ b/src/selfCorrelation.c @@ -0,0 +1,25 @@ +#include +#include "include/stat_fncs.h" + +int SelfCorrelation(int d, int n, BitSequence *epsilon) +{ + int i = 0; + int n_d = n - d; + int Ad = 0; + double V = 0.0, p_value = 0.0, sqrt2 = 1.41421356237309504880; + + for (i = 0; i < n_d - 1; ++i) { + Ad += (epsilon[i] ^ epsilon[i + d]); + } + + V = 2 * ((double)Ad - ((double)n_d / 2)) / sqrt(n_d); + + p_value = erfc(fabs(V) / sqrt2); + + if (p_value < ALPHA) { + return 0; + } else { + return 1; + } +} + diff --git a/src/serial.c b/src/serial.c new file mode 100644 index 0000000..3d37272 --- /dev/null +++ b/src/serial.c @@ -0,0 +1,65 @@ +#include +#include +#include +#include +#include "include/externs.h" +#include "include/cephes.h" + +double psi2(int m, int n, BitSequence *epsilon); + +int +Serial(int m, int n, BitSequence *epsilon) +{ + double p_value1, p_value2, psim0, psim1, psim2, del1, del2; + + psim0 = psi2(m, n, epsilon); + psim1 = psi2(m - 1, n, epsilon); + psim2 = psi2(m - 2, n, epsilon); + del1 = psim0 - psim1; + del2 = psim0 - 2.0*psim1 + psim2; + p_value1 = cephes_igamc(pow(2, m-1)/2, del1/2.0); + p_value2 = cephes_igamc(pow(2, m-2)/2, del2/2.0); + + if (p_value1 < ALPHA || p_value2 < ALPHA) { + return 0; + } else { + return 1; + } +} + +double +psi2(int m, int n, BitSequence *epsilon) +{ + int i, j, k, powLen; + double sum, numOfBlocks; + unsigned int *P; + + if ( (m == 0) || (m == -1) ) + return 0.0; + numOfBlocks = n; + powLen = (int)pow(2, m+1)-1; + if ( (P = (unsigned int*)calloc(powLen,sizeof(unsigned int)))== NULL ) { +// fprintf(stats[TEST_SERIAL], "Serial Test: Insufficient memory available.\n"); +// fflush(stats[TEST_SERIAL]); + return 0.0; + } + for ( i=1; i +#include +#include +#include +#include "include/externs.h" +#include "include/cephes.h" + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + U N I V E R S A L T E S T + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +int +Universal(int n, BitSequence *epsilon) +{ + int ret = 0; + int i, j, p, L, Q, K; + double arg, sqrt2, sigma, phi, sum, p_value, c; + long *T, decRep; + const double expected_value[17] = { 0, 0, 0, 0, 0, 0, 5.2177052, 6.1962507, 7.1836656, + 8.1764248, 9.1723243, 10.170032, 11.168765, + 12.168070, 13.167693, 14.167488, 15.167379 }; + const double variance[17] = { 0, 0, 0, 0, 0, 0, 2.954, 3.125, 3.238, 3.311, 3.356, 3.384, + 3.401, 3.410, 3.416, 3.419, 3.421 }; + + /* * * * * * * * * ** * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * THE FOLLOWING REDEFINES L, SHOULD THE CONDITION: n >= 1010*2^L*L * + * NOT BE MET, FOR THE BLOCK LENGTH L. * + * * * * * * * * * * ** * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + L = 5; + if ( n >= 387840 ) L = 6; + if ( n >= 904960 ) L = 7; + if ( n >= 2068480 ) L = 8; + if ( n >= 4654080 ) L = 9; + if ( n >= 10342400 ) L = 10; + if ( n >= 22753280 ) L = 11; + if ( n >= 49643520 ) L = 12; + if ( n >= 107560960 ) L = 13; + if ( n >= 231669760 ) L = 14; + if ( n >= 496435200 ) L = 15; + if ( n >= 1059061760 ) L = 16; + + Q = 10*(int)pow(2, L); + K = (int) (floor(n/L) - (double)Q); /* BLOCKS TO TEST */ + + p = (int)pow(2, L); + if ( (L < 6) || (L > 16) || ((double)Q < 10*pow(2, L)) || + ((T = (long *)calloc(p, sizeof(long))) == NULL) ) { + return 0; + } + + /* COMPUTE THE EXPECTED: Formula 16, in Marsaglia's Paper */ + c = 0.7 - 0.8/(double)L + (4 + 32/(double)L)*pow(K, -3/(double)L)/15; + sigma = c * sqrt(variance[L]/(double)K); + sqrt2 = sqrt(2); + sum = 0.0; + for ( i=0; i +#include
+#include +#include +#include "include/utilities.h" + +int +convertToBits(BYTE *x, int xBitLength, int bitsNeeded, int *num_0s, int *num_1s, int *bitsRead, BitSequence* epsilon) +{ + 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; +} + diff --git a/src/version.map b/src/version.map new file mode 100644 index 0000000..d4433ce --- /dev/null +++ b/src/version.map @@ -0,0 +1,6 @@ +{ + global: + mesa_statistical_test_suite; + GIT_VERSION*; + local: *; +}; \ No newline at end of file diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt new file mode 100644 index 0000000..7a89809 --- /dev/null +++ b/test/CMakeLists.txt @@ -0,0 +1,15 @@ +cmake_minimum_required (VERSION 2.8) + +include_directories(${CMAKE_SOURCE_DIR}/inc) +include_directories(/opt/MESA/include/MESA/) +include_directories(/opt/MESA/include) +include_directories(/usr/include/) +include_directories(${PROJECT_SOURCE_DIR}/src/) + +link_directories(/opt/MESA/lib) +link_directories("${CMAKE_BINARY_DIR}") + +add_executable(gtest_mesa gtest_mesa_sts.cpp) +target_link_libraries(gtest_mesa gtest gtest_main pcap pthread mesa_sts) + +file(COPY pcap DESTINATION ./) \ No newline at end of file diff --git a/test/gtest_mesa_sts.cpp b/test/gtest_mesa_sts.cpp new file mode 100644 index 0000000..d16b8d1 --- /dev/null +++ b/test/gtest_mesa_sts.cpp @@ -0,0 +1,257 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "gtest/gtest.h" + +extern "C" { +#include "mesa_sts.h" +} + +#define MAX_PKT_CNT 1 + +static int read_pcap_and_judge_randomness(const char* pcap_file, struct sts_result* result) +{ + pcap_t *handle; + struct pcap_pkthdr *header; // pcap报文头部结构 + const u_char *packet; // 报文数据指针 + char errbuf[PCAP_ERRBUF_SIZE]; + char content[2048] = {0}; + int content_len = 0; + int payload_len; + char *payload; + int pkt_cnt = 0; + + handle = pcap_open_offline(pcap_file, errbuf); + while (pcap_next_ex(handle, &header, &packet) > 0) { + unsigned short eth_type = ntohs(*(unsigned short *)(packet + 12)); + if (eth_type == ETH_P_IP) { + int l4_proto = *(unsigned char *)(packet + sizeof(struct ethhdr) + 9); + if (l4_proto == IPPROTO_TCP) { + payload_len = header->caplen - sizeof(struct ethhdr) - sizeof(struct iphdr) - sizeof(struct tcphdr); + payload = (char *)packet + sizeof(struct ethhdr) + sizeof(struct iphdr) + sizeof(struct tcphdr); + } else if (l4_proto == IPPROTO_UDP) { + payload_len = header->caplen - sizeof(struct ethhdr) - sizeof(struct iphdr) - sizeof(struct udphdr); + payload = (char *)packet + sizeof(struct ethhdr) + sizeof(struct iphdr) + sizeof(struct udphdr); + } else { + continue; + } + + } else if (eth_type == ETH_P_IPV6) { + int l4_proto = *(unsigned char *)(packet + sizeof(struct ethhdr) + 6); + if (l4_proto == IPPROTO_TCP) { + payload_len = header->caplen - sizeof(struct ethhdr) - sizeof(struct ip6_hdr) - sizeof(struct tcphdr); + payload = (char *)packet + sizeof(struct ethhdr) + sizeof(struct ip6_hdr) + sizeof(struct tcphdr); + } else if (l4_proto == IPPROTO_UDP) { + payload_len = header->caplen - sizeof(struct ethhdr) - sizeof(struct ip6_hdr) - sizeof(struct udphdr); + payload = (char *)packet + sizeof(struct ethhdr) + sizeof(struct ip6_hdr) + sizeof(struct udphdr); + } else { + continue; + } + } + + if (payload_len < 100) { + continue; + } + + memcpy(content + content_len, payload, payload_len); + content_len += payload_len; + pkt_cnt++; + if (pkt_cnt == MAX_PKT_CNT) { + break; + } + } + + mesa_statistical_test_suite(content, content_len, result); + + pcap_close(handle); + + return 0; +} + +TEST(random_looking, telegram_mtproto_ipv4_key1) +{ + struct sts_result result; + read_pcap_and_judge_randomness("pcap/telegram_mtproto_ipv4_key_1.pcap", &result); + + EXPECT_EQ(result.frequency, 1); + EXPECT_EQ(result.block_frequency, 1); + EXPECT_EQ(result.cumulative_sums, 1); + EXPECT_EQ(result.runs, 1); + EXPECT_EQ(result.longest_run, 1); + EXPECT_EQ(result.rank, 0); + EXPECT_EQ(result.non_overlapping_template_matching, 0); + EXPECT_EQ(result.overlapping_template_matching, 1); + EXPECT_EQ(result.universal, 0); + EXPECT_EQ(result.random_excursions, 1); + EXPECT_EQ(result.random_excursions_variant, 1); + EXPECT_EQ(result.poker_detect, 1); + EXPECT_EQ(result.runs_distribution, 1); + EXPECT_EQ(result.self_correlation, 1); + EXPECT_EQ(result.binary_derivative, 1); +} + +TEST(random_looking, telegram_mtproto_ipv4_key2) +{ + struct sts_result result; + read_pcap_and_judge_randomness("pcap/telegram_mtproto_ipv4_key_2_dd.pcap", &result); + + EXPECT_EQ(result.frequency, 1); + EXPECT_EQ(result.block_frequency, 1); + EXPECT_EQ(result.cumulative_sums, 1); + EXPECT_EQ(result.runs, 1); + EXPECT_EQ(result.longest_run, 1); + EXPECT_EQ(result.rank, 0); + EXPECT_EQ(result.non_overlapping_template_matching, 0); + EXPECT_EQ(result.overlapping_template_matching, 1); + EXPECT_EQ(result.universal, 0); + EXPECT_EQ(result.random_excursions, 1); + EXPECT_EQ(result.random_excursions_variant, 1); + EXPECT_EQ(result.poker_detect, 1); + EXPECT_EQ(result.runs_distribution, 1); + EXPECT_EQ(result.self_correlation, 1); + EXPECT_EQ(result.binary_derivative, 1); +} + +TEST(random_looking, telegram_mtproto_ipv4_key3) +{ + struct sts_result result; + read_pcap_and_judge_randomness("pcap/telegram_mtproto_ipv4_key_3_ee.pcap", &result); + + EXPECT_EQ(result.frequency, 1); + EXPECT_EQ(result.block_frequency, 0); + EXPECT_EQ(result.cumulative_sums, 1); + EXPECT_EQ(result.runs, 0); + EXPECT_EQ(result.longest_run, 1); + EXPECT_EQ(result.rank, 0); + EXPECT_EQ(result.non_overlapping_template_matching, 0); + EXPECT_EQ(result.overlapping_template_matching, 1); + EXPECT_EQ(result.universal, 0); + EXPECT_EQ(result.random_excursions, 1); + EXPECT_EQ(result.random_excursions_variant, 1); + EXPECT_EQ(result.poker_detect, 0); + EXPECT_EQ(result.runs_distribution, 1); + EXPECT_EQ(result.self_correlation, 1); + EXPECT_EQ(result.binary_derivative, 1); +} + +TEST(random_looking, telegram_mtproto_ipv6_key1) +{ + struct sts_result result; + read_pcap_and_judge_randomness("pcap/telegram_mtproto_ipv6_key_1.pcap", &result); + + EXPECT_EQ(result.frequency, 1); + EXPECT_EQ(result.block_frequency, 1); + EXPECT_EQ(result.cumulative_sums, 1); + EXPECT_EQ(result.runs, 1); + EXPECT_EQ(result.longest_run, 1); + EXPECT_EQ(result.rank, 0); + EXPECT_EQ(result.non_overlapping_template_matching, 0); + EXPECT_EQ(result.overlapping_template_matching, 1); + EXPECT_EQ(result.universal, 0); + EXPECT_EQ(result.random_excursions, 1); + EXPECT_EQ(result.random_excursions_variant, 1); + EXPECT_EQ(result.poker_detect, 1); + EXPECT_EQ(result.runs_distribution, 1); + EXPECT_EQ(result.self_correlation, 1); + EXPECT_EQ(result.binary_derivative, 1); +} + +TEST(random_looking, telegram_mtproto_ipv6_key2) +{ + struct sts_result result; + read_pcap_and_judge_randomness("pcap/telegram_mtproto_ipv6_key_2_dd.pcap", &result); + + EXPECT_EQ(result.frequency, 1); + EXPECT_EQ(result.block_frequency, 1); + EXPECT_EQ(result.cumulative_sums, 1); + EXPECT_EQ(result.runs, 1); + EXPECT_EQ(result.longest_run, 1); + EXPECT_EQ(result.rank, 0); + EXPECT_EQ(result.non_overlapping_template_matching, 0); + EXPECT_EQ(result.overlapping_template_matching, 1); + EXPECT_EQ(result.universal, 0); + EXPECT_EQ(result.random_excursions, 1); + EXPECT_EQ(result.random_excursions_variant, 1); + EXPECT_EQ(result.poker_detect, 1); + EXPECT_EQ(result.runs_distribution, 1); + EXPECT_EQ(result.self_correlation, 1); + EXPECT_EQ(result.binary_derivative, 1); +} + +TEST(random_looking, telegram_mtproto_ipv6_key3) +{ + struct sts_result result; + read_pcap_and_judge_randomness("pcap/telegram_mtproto_ipv6_key_3_ee.pcap", &result); + + EXPECT_EQ(result.frequency, 1); + EXPECT_EQ(result.block_frequency, 0); + EXPECT_EQ(result.cumulative_sums, 1); + EXPECT_EQ(result.runs, 1); + EXPECT_EQ(result.longest_run, 1); + EXPECT_EQ(result.rank, 0); + EXPECT_EQ(result.non_overlapping_template_matching, 0); + EXPECT_EQ(result.overlapping_template_matching, 1); + EXPECT_EQ(result.universal, 0); + EXPECT_EQ(result.random_excursions, 1); + EXPECT_EQ(result.random_excursions_variant, 1); + EXPECT_EQ(result.poker_detect, 0); + EXPECT_EQ(result.runs_distribution, 1); + EXPECT_EQ(result.self_correlation, 1); + EXPECT_EQ(result.binary_derivative, 1); +} + +TEST(non_random_looking, wechat_voice_call) +{ + struct sts_result result; + read_pcap_and_judge_randomness("pcap/202202161604_win_wifi_30M_pure_wechat_wechat3.5.0.46_voice-call_120s_2_multinat.pcap", &result); + + EXPECT_EQ(result.frequency, 0); + EXPECT_EQ(result.block_frequency, 1); + EXPECT_EQ(result.cumulative_sums, 0); + EXPECT_EQ(result.runs, 0); + EXPECT_EQ(result.longest_run, 0); + EXPECT_EQ(result.rank, 0); + EXPECT_EQ(result.non_overlapping_template_matching, 0); + EXPECT_EQ(result.overlapping_template_matching, 1); + EXPECT_EQ(result.universal, 0); + EXPECT_EQ(result.random_excursions, 1); + EXPECT_EQ(result.random_excursions_variant, 1); + EXPECT_EQ(result.poker_detect, 1); + EXPECT_EQ(result.runs_distribution, 0); + EXPECT_EQ(result.self_correlation, 0); + EXPECT_EQ(result.binary_derivative, 1); +} + +TEST(non_random_looking, http) +{ + struct sts_result result; + read_pcap_and_judge_randomness("pcap/xingongsuo_kouling_http_C2S.pcap", &result); + + EXPECT_EQ(result.frequency, 0); + EXPECT_EQ(result.block_frequency, 0); + EXPECT_EQ(result.cumulative_sums, 0); + EXPECT_EQ(result.runs, 1); + EXPECT_EQ(result.longest_run, 0); + EXPECT_EQ(result.rank, 1); + EXPECT_EQ(result.non_overlapping_template_matching, 0); + EXPECT_EQ(result.overlapping_template_matching, 1); + EXPECT_EQ(result.universal, 0); + EXPECT_EQ(result.random_excursions, 1); + EXPECT_EQ(result.random_excursions_variant, 1); + EXPECT_EQ(result.poker_detect, 0); + EXPECT_EQ(result.runs_distribution, 0); + EXPECT_EQ(result.self_correlation, 0); + EXPECT_EQ(result.binary_derivative, 1); +} + +int main(int argc, char **argv) +{ + testing::InitGoogleTest(&argc, argv); + //testing::GTEST_FLAG(filter) = "random_looking.telegram_mtproto_ipv6_key1"; + return RUN_ALL_TESTS(); +} \ No newline at end of file diff --git a/test/pcap/202202161604_win_wifi_30M_pure_wechat_wechat3.5.0.46_voice-call_120s_2_multinat.pcap b/test/pcap/202202161604_win_wifi_30M_pure_wechat_wechat3.5.0.46_voice-call_120s_2_multinat.pcap new file mode 100644 index 0000000..63787b7 Binary files /dev/null and b/test/pcap/202202161604_win_wifi_30M_pure_wechat_wechat3.5.0.46_voice-call_120s_2_multinat.pcap differ diff --git a/test/pcap/telegram_mtproto_ipv4_key_1.pcap b/test/pcap/telegram_mtproto_ipv4_key_1.pcap new file mode 100644 index 0000000..7b966dd Binary files /dev/null and b/test/pcap/telegram_mtproto_ipv4_key_1.pcap differ diff --git a/test/pcap/telegram_mtproto_ipv4_key_2_dd.pcap b/test/pcap/telegram_mtproto_ipv4_key_2_dd.pcap new file mode 100644 index 0000000..59eb480 Binary files /dev/null and b/test/pcap/telegram_mtproto_ipv4_key_2_dd.pcap differ diff --git a/test/pcap/telegram_mtproto_ipv4_key_3_ee.pcap b/test/pcap/telegram_mtproto_ipv4_key_3_ee.pcap new file mode 100644 index 0000000..8c70a1b Binary files /dev/null and b/test/pcap/telegram_mtproto_ipv4_key_3_ee.pcap differ diff --git a/test/pcap/telegram_mtproto_ipv6_key_1.pcap b/test/pcap/telegram_mtproto_ipv6_key_1.pcap new file mode 100644 index 0000000..e0b3144 Binary files /dev/null and b/test/pcap/telegram_mtproto_ipv6_key_1.pcap differ diff --git a/test/pcap/telegram_mtproto_ipv6_key_2_dd.pcap b/test/pcap/telegram_mtproto_ipv6_key_2_dd.pcap new file mode 100644 index 0000000..0659281 Binary files /dev/null and b/test/pcap/telegram_mtproto_ipv6_key_2_dd.pcap differ diff --git a/test/pcap/telegram_mtproto_ipv6_key_3_ee.pcap b/test/pcap/telegram_mtproto_ipv6_key_3_ee.pcap new file mode 100644 index 0000000..03a3678 Binary files /dev/null and b/test/pcap/telegram_mtproto_ipv6_key_3_ee.pcap differ diff --git a/test/pcap/xingongsuo_kouling_http_C2S.pcap b/test/pcap/xingongsuo_kouling_http_C2S.pcap new file mode 100644 index 0000000..cd05da7 Binary files /dev/null and b/test/pcap/xingongsuo_kouling_http_C2S.pcap differ diff --git a/vendor/CMakeLists.txt b/vendor/CMakeLists.txt new file mode 100644 index 0000000..0035fd9 --- /dev/null +++ b/vendor/CMakeLists.txt @@ -0,0 +1,36 @@ +# CMakeFiles for 3rd vendor library + +include(ExternalProject) +# libgtest +ExternalProject_Add(libgtest PREFIX libgtest + URL ${CMAKE_SOURCE_DIR}/vendor/googletest-release-1.10.0.tar.gz + URL_MD5 ecd1fa65e7de707cd5c00bdac56022cd + CMAKE_ARGS -DCMAKE_INSTALL_PREFIX= -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}) +ExternalProject_Get_Property(libgtest INSTALL_DIR) +file(MAKE_DIRECTORY ${INSTALL_DIR}/include) +add_library(gtest-static STATIC IMPORTED GLOBAL) +add_dependencies(gtest-static libgtest) +if(CMAKE_BUILD_TYPE STREQUAL "Debug") + set_property(TARGET gtest-static PROPERTY IMPORTED_LOCATION ${INSTALL_DIR}/lib64/libgtestd.a) +else() + set_property(TARGET gtest-static PROPERTY IMPORTED_LOCATION ${INSTALL_DIR}/lib64/libgtest.a) +endif() +set_property(TARGET gtest-static PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${INSTALL_DIR}/include) +set_property(TARGET gtest-static PROPERTY INTERFACE_LINK_LIBRARIES pthread) + +# # libmsgpackc +# ExternalProject_Add(libmsgpackc PREFIX libmsgpackc +# URL ${CMAKE_SOURCE_DIR}/vendor/msgpack-c-6.0.0.tar.gz +# URL_MD5 adc08f48550ce772fe24c0b41166b0de +# CMAKE_ARGS -DCMAKE_INSTALL_PREFIX= -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} +# -DMSGPACK_BUILD_TESTS=OFF -DMSGPACK_USE_BOOST=OFF) +# ExternalProject_Get_Property(libmsgpackc INSTALL_DIR) +# file(MAKE_DIRECTORY ${INSTALL_DIR}/include) +# add_library(msgpackc-static STATIC IMPORTED GLOBAL) +# add_dependencies(msgpackc-static libmsgpackc) + +# set_property(TARGET msgpackc-static PROPERTY IMPORTED_LOCATION ${INSTALL_DIR}/lib/libmsgpack-c.a) +# set_property(TARGET msgpackc-static PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${INSTALL_DIR}/include) + + + diff --git a/vendor/googletest-release-1.10.0.tar.gz b/vendor/googletest-release-1.10.0.tar.gz new file mode 100644 index 0000000..ab10868 Binary files /dev/null and b/vendor/googletest-release-1.10.0.tar.gz differ