Nicht Final, aber funktional
parent
220c64ae5d
commit
2f725cdde4
|
@ -0,0 +1,58 @@
|
||||||
|
from TotOnline import TotOnline
|
||||||
|
from StartUpTest import StartUPTest
|
||||||
|
|
||||||
|
|
||||||
|
class Main:
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
print("Main class instantiated")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
filename = "resources/SmallTest.txt"
|
||||||
|
with open(filename, "rb") as f:
|
||||||
|
binary_data = f.read().strip()
|
||||||
|
|
||||||
|
filename = "resources/data2.txt"
|
||||||
|
with open(filename, "rb") as f:
|
||||||
|
binary_data2 = f.read().strip()
|
||||||
|
|
||||||
|
# Call the StarUpTest
|
||||||
|
print("StartUp:")
|
||||||
|
result = StartUPTest.monobit_test(binary_data2)
|
||||||
|
print("p_value:", result[0])
|
||||||
|
print("test passed (p_value >= 0.01):", result[1])
|
||||||
|
|
||||||
|
result = StartUPTest.test5(binary_data2)
|
||||||
|
print("Z_tau:", result[0])
|
||||||
|
print("test passed (Z_tau > 2326 and Z_tau < 2674):", result[1])
|
||||||
|
|
||||||
|
# Call the TotalFailure-Test
|
||||||
|
|
||||||
|
print("Total Failure:")
|
||||||
|
result = TotOnline.total_failure(binary_data, pattern_length=10)
|
||||||
|
print("p_value:", result[0])
|
||||||
|
print("test passed (p_value >= 0.01):", result[1])
|
||||||
|
|
||||||
|
# Call the Online Test
|
||||||
|
print("Monobit:")
|
||||||
|
result = TotOnline.monobit_test(binary_data)
|
||||||
|
print("p_value:", result[0])
|
||||||
|
print("test passed (p_value >= 0.01):", result[1])
|
||||||
|
|
||||||
|
print("Block Frequency:")
|
||||||
|
result = TotOnline.block_frequency(binary_data)
|
||||||
|
print("p_value:", result[0])
|
||||||
|
print("test passed (p_value >= 0.01):", result[1])
|
||||||
|
|
||||||
|
print("Run:")
|
||||||
|
result = TotOnline.run_test(binary_data)
|
||||||
|
print("p_value:", result[0])
|
||||||
|
print("test passed (p_value >= 0.01):", result[1])
|
||||||
|
|
||||||
|
print("Longest Run:")
|
||||||
|
result = TotOnline.longest_one_block_test(binary_data)
|
||||||
|
print("p_value:", result[0])
|
||||||
|
print("test passed (p_value >= 0.01):", result[1])
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
Die Main Klasse fällt nacher weg und wird vollständig im restlichen Code zur Erstellung und Verarbeitung der Zufallszahlen integriert.
|
||||||
|
Aktuell werden die Daten für die Tests aus zwei verschiedenen Dateien eingelesen, da der Startup Test eine deutlich größere Menge an Zahlen benötigt (hier mindestens 20.000 Bits der Total Failure/Online Test nur mindestens 128 Bits)
|
|
@ -0,0 +1,88 @@
|
||||||
|
from math import fabs as fabs
|
||||||
|
from math import sqrt as sqrt
|
||||||
|
from scipy.special import erfc as erfc
|
||||||
|
|
||||||
|
|
||||||
|
class StartUPTest:
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def monobit_test(binary_data: str):
|
||||||
|
|
||||||
|
length_of_bit_string = len(binary_data)
|
||||||
|
|
||||||
|
# Variable for S(n)
|
||||||
|
count = 0
|
||||||
|
# Iterate each bit in the string and compute for S(n)
|
||||||
|
for bit in binary_data:
|
||||||
|
if bit == 48:
|
||||||
|
# If bit is 0, then -1 from the S(n)
|
||||||
|
count -= 1
|
||||||
|
elif bit == 49:
|
||||||
|
# If bit is 1, then +1 to the S(n)
|
||||||
|
count += 1
|
||||||
|
|
||||||
|
# Compute the test statistic
|
||||||
|
sObs = count / sqrt(length_of_bit_string)
|
||||||
|
|
||||||
|
# Compute p-Value
|
||||||
|
p_value = erfc(fabs(sObs) / sqrt(2))
|
||||||
|
|
||||||
|
# return a p_value and randomness result
|
||||||
|
return (p_value, (p_value >= 0.01))
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def test5(binary_data: str):
|
||||||
|
|
||||||
|
ShiftFeld = [0] * 5000
|
||||||
|
MaxKorrFeld = [0] * 5000
|
||||||
|
|
||||||
|
# Fill BitFeldB with data
|
||||||
|
|
||||||
|
for tau in range(1, 5001):
|
||||||
|
Z_tau = 0
|
||||||
|
for i in range(5000):
|
||||||
|
Z_tau += binary_data[i] ^ binary_data[i + tau]
|
||||||
|
ShiftFeld[tau - 1] = Z_tau
|
||||||
|
|
||||||
|
#Debugging
|
||||||
|
#for i in range(5000):
|
||||||
|
# print(ShiftFeld[i], end=' ')
|
||||||
|
|
||||||
|
# Find the index of the maximum deviation from 2500
|
||||||
|
max_deviation = 0
|
||||||
|
for tau in range(5000):
|
||||||
|
deviation = abs(ShiftFeld[tau] - 2500)
|
||||||
|
if deviation > max_deviation:
|
||||||
|
max_deviation = deviation
|
||||||
|
|
||||||
|
# Find all indices with the maximum deviation
|
||||||
|
j = 0
|
||||||
|
for tau in range(5000):
|
||||||
|
deviation = abs(ShiftFeld[tau] - 2500)
|
||||||
|
if deviation == max_deviation:
|
||||||
|
MaxKorrFeld[j] = tau
|
||||||
|
j += 1
|
||||||
|
|
||||||
|
print("Maximale Z_tau-Abweichung von 2500:", max_deviation)
|
||||||
|
print("Aufgetreten für Shifts:")
|
||||||
|
for k in range(j):
|
||||||
|
print("Shift:", MaxKorrFeld[k] + 1)
|
||||||
|
|
||||||
|
tau = MaxKorrFeld[0]
|
||||||
|
Z_tau = 0
|
||||||
|
for i in range(10000, 15000):
|
||||||
|
Z_tau += StartUPTest.charToInt(i, binary_data) ^ StartUPTest.charToInt(i + tau + 1, binary_data)
|
||||||
|
tau += 1
|
||||||
|
|
||||||
|
ok = Z_tau > 2326 and Z_tau < 2674
|
||||||
|
return (Z_tau, ok)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def charToInt(index, binary_data: str):
|
||||||
|
value = 0
|
||||||
|
if binary_data[index] == 49:
|
||||||
|
value = 1
|
||||||
|
else:
|
||||||
|
value = 0
|
||||||
|
return value
|
||||||
|
|
|
@ -0,0 +1,227 @@
|
||||||
|
from math import log as log
|
||||||
|
from numpy import zeros as zeros
|
||||||
|
from math import fabs as fabs
|
||||||
|
from math import floor as floor
|
||||||
|
from math import sqrt as sqrt
|
||||||
|
from scipy.special import erfc as erfc
|
||||||
|
from scipy.special import gammaincc as gammaincc
|
||||||
|
|
||||||
|
|
||||||
|
class TotOnline:
|
||||||
|
@staticmethod
|
||||||
|
def total_failure(binary_data: str, pattern_length=10):
|
||||||
|
|
||||||
|
length_of_binary_data = len(binary_data)
|
||||||
|
|
||||||
|
# Augment the n-bit sequence to create n overlapping m-bit sequences by appending m-1 bits
|
||||||
|
# from the beginning of the sequence to the end of the sequence.
|
||||||
|
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 + 2):
|
||||||
|
max_pattern += '1'
|
||||||
|
|
||||||
|
# Keep track of each pattern's frequency (how often it appears)
|
||||||
|
vobs_01 = zeros(int(max_pattern[0:pattern_length:], 2) + 1)
|
||||||
|
vobs_02 = zeros(int(max_pattern[0:pattern_length + 1:], 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
|
||||||
|
|
||||||
|
# Calculate the test statistics and p values
|
||||||
|
vobs = [vobs_01, vobs_02]
|
||||||
|
|
||||||
|
sums = zeros(2)
|
||||||
|
for i in range(2):
|
||||||
|
for j in range(len(vobs[i])):
|
||||||
|
if vobs[i][j] > 0:
|
||||||
|
sums[i] += vobs[i][j] * log(vobs[i][j] / length_of_binary_data)
|
||||||
|
sums /= length_of_binary_data
|
||||||
|
ape = sums[0] - sums[1]
|
||||||
|
|
||||||
|
xObs = 2.0 * length_of_binary_data * (log(2) - ape)
|
||||||
|
|
||||||
|
p_value = gammaincc(pow(2, pattern_length - 1), xObs / 2.0)
|
||||||
|
|
||||||
|
return (p_value, (p_value >= 0.01))
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def monobit_test(binary_data: str):
|
||||||
|
|
||||||
|
length_of_bit_string = len(binary_data)
|
||||||
|
|
||||||
|
# Variable for S(n)
|
||||||
|
count = 0
|
||||||
|
# Iterate each bit in the string and compute for S(n)
|
||||||
|
for bit in binary_data:
|
||||||
|
if bit == 48:
|
||||||
|
# If bit is 0, then -1 from the S(n)
|
||||||
|
count -= 1
|
||||||
|
elif bit == 49:
|
||||||
|
# If bit is 1, then +1 to the S(n)
|
||||||
|
count += 1
|
||||||
|
|
||||||
|
# Compute the test statistic
|
||||||
|
sObs = count / sqrt(length_of_bit_string)
|
||||||
|
|
||||||
|
# Compute p-Value
|
||||||
|
p_value = erfc(fabs(sObs) / sqrt(2))
|
||||||
|
|
||||||
|
# return a p_value and randomness result
|
||||||
|
return (p_value, (p_value >= 0.01))
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def block_frequency(binary_data: str, block_size=128):
|
||||||
|
|
||||||
|
length_of_bit_string = len(binary_data)
|
||||||
|
|
||||||
|
if length_of_bit_string < block_size:
|
||||||
|
block_size = length_of_bit_string
|
||||||
|
|
||||||
|
# Compute the number of blocks based on the input given. Discard the remainder
|
||||||
|
number_of_blocks = floor(length_of_bit_string / block_size)
|
||||||
|
|
||||||
|
if number_of_blocks == 1:
|
||||||
|
# For block size M=1, this test degenerates to test 1, the Frequency (Monobit) test.
|
||||||
|
return TotOnline.monobit_test(binary_data[0:block_size])
|
||||||
|
|
||||||
|
# Initialized variables
|
||||||
|
block_start = 0
|
||||||
|
block_end = block_size
|
||||||
|
proportion_sum = 0.0
|
||||||
|
|
||||||
|
# Create a for loop to process each block
|
||||||
|
for counter in range(number_of_blocks):
|
||||||
|
# Partition the input sequence and get the data for block
|
||||||
|
block_data = binary_data[block_start:block_end]
|
||||||
|
|
||||||
|
# Determine the proportion 蟺i of ones in each M-bit
|
||||||
|
one_count = 0
|
||||||
|
for bit in block_data:
|
||||||
|
if bit == 49:
|
||||||
|
one_count += 1
|
||||||
|
# compute π
|
||||||
|
pi = one_count / block_size
|
||||||
|
|
||||||
|
# Compute Σ(πi -½)^2.
|
||||||
|
proportion_sum += pow(pi - 0.5, 2.0)
|
||||||
|
|
||||||
|
# Next Block
|
||||||
|
block_start += block_size
|
||||||
|
block_end += block_size
|
||||||
|
|
||||||
|
# Compute 4M Σ(πi -½)^2.
|
||||||
|
result = 4.0 * block_size * proportion_sum
|
||||||
|
|
||||||
|
# Compute P-Value
|
||||||
|
p_value = gammaincc(number_of_blocks / 2, result / 2)
|
||||||
|
|
||||||
|
return (p_value, (p_value >= 0.01))
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def run_test(binary_data: str):
|
||||||
|
|
||||||
|
one_count = 0
|
||||||
|
vObs = 0
|
||||||
|
length_of_binary_data = len(binary_data)
|
||||||
|
|
||||||
|
# Predefined tau = 2 / sqrt(n)
|
||||||
|
tau = 2 / sqrt(length_of_binary_data)
|
||||||
|
|
||||||
|
# Step 1 - Compute the pre-test proportion πof ones in the input sequence: π = Σjεj / n
|
||||||
|
one_count = binary_data.count(49)
|
||||||
|
|
||||||
|
pi = one_count / length_of_binary_data
|
||||||
|
|
||||||
|
# Step 2 - If it can be shown that absolute value of (π - 0.5) is greater than or equal to tau
|
||||||
|
# then the run test need not be performed.
|
||||||
|
if abs(pi - 0.5) >= tau:
|
||||||
|
return (0.0000)
|
||||||
|
else:
|
||||||
|
# Step 3 - Compute vObs
|
||||||
|
for item in range(1, length_of_binary_data):
|
||||||
|
if binary_data[item] != binary_data[item - 1]:
|
||||||
|
vObs += 1
|
||||||
|
vObs += 1
|
||||||
|
|
||||||
|
# Step 4 - Compute p_value = erfc((|vObs − 2nπ * (1−π)|)/(2 * sqrt(2n) * π * (1−π)))
|
||||||
|
p_value = erfc(abs(vObs - (2 * (length_of_binary_data) * pi * (1 - pi))) / (2 * sqrt(2 * length_of_binary_data) * pi * (1 - pi)))
|
||||||
|
|
||||||
|
return (p_value, (p_value > 0.01))
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def longest_one_block_test(binary_data: str):
|
||||||
|
|
||||||
|
length_of_binary_data = len(binary_data)
|
||||||
|
# print('Length of binary string: ', length_of_binary_data)
|
||||||
|
|
||||||
|
# Initialized k, m. n, pi and v_values
|
||||||
|
if length_of_binary_data < 128:
|
||||||
|
# Not enough data to run this test
|
||||||
|
return (0.00000, 'Error: Not enough data to run this test')
|
||||||
|
elif length_of_binary_data < 6272:
|
||||||
|
k = 3
|
||||||
|
m = 8
|
||||||
|
v_values = [1, 2, 3, 4]
|
||||||
|
pi_values = [0.2148, 0.3672, 0.2305, 0.1875]
|
||||||
|
elif length_of_binary_data < 750000:
|
||||||
|
k = 5
|
||||||
|
m = 128
|
||||||
|
v_values = [4, 5, 6, 7, 8, 9]
|
||||||
|
pi_values = [0.1174, 0.2430, 0.2493, 0.1752, 0.1027, 0.1124]
|
||||||
|
else:
|
||||||
|
# If length_of_bit_string > 750000
|
||||||
|
k = 6
|
||||||
|
m = 10000
|
||||||
|
v_values = [10, 11, 12, 13, 14, 15, 16]
|
||||||
|
pi_values = [0.0882, 0.2092, 0.2483, 0.1933, 0.1208, 0.0675, 0.0727]
|
||||||
|
|
||||||
|
number_of_blocks = floor(length_of_binary_data / m)
|
||||||
|
block_start = 0
|
||||||
|
block_end = m
|
||||||
|
xObs = 0
|
||||||
|
# This will intialized an array with a number of 0 you specified.
|
||||||
|
frequencies = zeros(k + 1)
|
||||||
|
|
||||||
|
# print('Number of Blocks: ', number_of_blocks)
|
||||||
|
|
||||||
|
for count in range(number_of_blocks):
|
||||||
|
block_data = binary_data[block_start:block_end]
|
||||||
|
max_run_count = 0
|
||||||
|
run_count = 0
|
||||||
|
|
||||||
|
# This will count the number of ones in the block
|
||||||
|
for bit in block_data:
|
||||||
|
if bit == 49:
|
||||||
|
run_count += 1
|
||||||
|
max_run_count = max(max_run_count, run_count)
|
||||||
|
else:
|
||||||
|
max_run_count = max(max_run_count, run_count)
|
||||||
|
run_count = 0
|
||||||
|
|
||||||
|
max(max_run_count, run_count)
|
||||||
|
|
||||||
|
#print('Block Data: ', block_data, '. Run Count: ', max_run_count)
|
||||||
|
if max_run_count < v_values[0]:
|
||||||
|
frequencies[0] += 1
|
||||||
|
for j in range(k):
|
||||||
|
if max_run_count == v_values[j]:
|
||||||
|
frequencies[j] += 1
|
||||||
|
if max_run_count > v_values[k - 1]:
|
||||||
|
frequencies[k] += 1
|
||||||
|
|
||||||
|
block_start += m
|
||||||
|
block_end += m
|
||||||
|
|
||||||
|
# print("Frequencies: ", frequencies)
|
||||||
|
# Compute xObs
|
||||||
|
for count in range(len(frequencies)):
|
||||||
|
xObs += pow((frequencies[count] - (number_of_blocks * pi_values[count])), 2.0) / (
|
||||||
|
number_of_blocks * pi_values[count])
|
||||||
|
|
||||||
|
p_value = gammaincc(float(k / 2), float(xObs / 2))
|
||||||
|
|
||||||
|
return (p_value, (p_value > 0.01))
|
Loading…
Reference in New Issue