forked from stevenang/randomness_testsuite
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Serial.py
69 lines (57 loc) · 3.3 KB
/
Serial.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
from numpy import zeros as zeros
from scipy.special import gammaincc as gammaincc
class Serial:
@staticmethod
def serial_test(binary_data:str, verbose=False, pattern_length=16):
"""
From the NIST documentation http://csrc.nist.gov/publications/nistpubs/800-22-rev1a/SP800-22rev1a.pdf
The focus of this test is the frequency of all possible overlapping m-bit patterns across the entire
sequence. The purpose of this test is to determine whether the number of occurrences of the 2m m-bit
overlapping patterns is approximately the same as would be expected for a random sequence. Random
sequences have uniformity; that is, every m-bit pattern has the same chance of appearing as every other
m-bit pattern. Note that for m = 1, the Serial test is equivalent to the Frequency test of Section 2.1.
:param binary_data: a binary string
:param verbose True to display the debug message, False to turn off debug message
:param pattern_length: the length of the pattern (m)
:return: ((p_value1, bool), (p_value2, bool)) A tuple which contain the p_value and result of serial_test(True or False)
"""
length_of_binary_data = len(binary_data)
binary_data += binary_data[:(pattern_length -1):]
# Get max length one patterns for m, m-1, m-2
max_pattern = ''
for i in range(pattern_length + 1):
max_pattern += '1'
# Step 02: Determine the frequency of all possible overlapping m-bit blocks,
# all possible overlapping (m-1)-bit blocks and
# all possible overlapping (m-2)-bit blocks.
vobs_01 = zeros(int(max_pattern[0:pattern_length:], 2) + 1)
vobs_02 = zeros(int(max_pattern[0:pattern_length - 1:], 2) + 1)
vobs_03 = zeros(int(max_pattern[0:pattern_length - 2:], 2) + 1)
for i in range(length_of_binary_data):
# Work out what pattern is observed
vobs_01[int(binary_data[i:i + pattern_length:], 2)] += 1
vobs_02[int(binary_data[i:i + pattern_length - 1:], 2)] += 1
vobs_03[int(binary_data[i:i + pattern_length - 2:], 2)] += 1
vobs = [vobs_01, vobs_02, vobs_03]
# Step 03 Compute for ψs
sums = zeros(3)
for i in range(3):
for j in range(len(vobs[i])):
sums[i] += pow(vobs[i][j], 2)
sums[i] = (sums[i] * pow(2, pattern_length - i) / length_of_binary_data) - length_of_binary_data
# Cimpute the test statistics and p values
#Step 04 Compute for ∇
nabla_01 = sums[0] - sums[1]
nabla_02 = sums[0] - 2.0 * sums[1] + sums[2]
# Step 05 Compute for P-Value
p_value_01 = gammaincc(pow(2, pattern_length - 1) / 2, nabla_01 / 2.0)
p_value_02 = gammaincc(pow(2, pattern_length - 2) / 2, nabla_02 / 2.0)
if verbose:
print('Serial Test DEBUG BEGIN:')
print("\tLength of input:\t", length_of_binary_data)
print('\tValue of Sai:\t\t', sums)
print('\tValue of Nabla:\t\t', nabla_01, nabla_02)
print('\tP-Value 01:\t\t\t', p_value_01)
print('\tP-Value 02:\t\t\t', p_value_02)
print('DEBUG END.')
return ((p_value_01, p_value_01 >= 0.01), (p_value_02, p_value_02 >= 0.01))