Tests an die Verwendung von Bytes angepasst

main
Gideon Regehr 2023-05-15 15:40:10 +02:00
parent fe08489de2
commit 4f6e19311a
1 changed files with 67 additions and 76 deletions

View File

@ -8,28 +8,31 @@ from scipy.special import gammaincc as gammaincc
class TotOnline: class TotOnline:
@staticmethod
def total_failure_test(binary_data: str, pattern_length=10):
length_of_binary_data = len(binary_data) @staticmethod
def total_failure_test(binary_data: bytes, pattern_length=10):
length_of_binary_data = len(binary_data) * 8
# Convert bytes to binary string representation
binary_data_str = ''
for byte in binary_data:
binary_data_str += format(byte, '08b')
# Augment the n-bit sequence to create n overlapping m-bit sequences by appending m-1 bits # 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. # from the beginning of the sequence to the end of the sequence.
binary_data += binary_data[:pattern_length + 1:] binary_data_str += binary_data_str[:pattern_length + 1]
# Get max length one patterns for m, m-1, m-2 # Get max length one patterns for m, m-1, m-2
max_pattern = '' max_pattern = '1' * (pattern_length + 2)
for i in range(pattern_length + 2):
max_pattern += '1'
# Keep track of each pattern's frequency (how often it appears) # Keep track of each pattern's frequency (how often it appears)
vobs_01 = zeros(int(max_pattern[0:pattern_length:], 2) + 1) vobs_01 = zeros(int(max_pattern[0:pattern_length], 2) + 1)
vobs_02 = zeros(int(max_pattern[0:pattern_length + 1:], 2) + 1) vobs_02 = zeros(int(max_pattern[0:pattern_length + 1], 2) + 1)
for i in range(length_of_binary_data): for i in range(length_of_binary_data):
# Work out what pattern is observed # Work out what pattern is observed
vobs_01[int(binary_data[i:i + pattern_length:], 2)] += 1 vobs_01[int(binary_data_str[i:i + pattern_length], 2)] += 1
vobs_02[int(binary_data[i:i + pattern_length + 1:], 2)] += 1 vobs_02[int(binary_data_str[i:i + pattern_length + 1], 2)] += 1
# Calculate the test statistics and p values # Calculate the test statistics and p values
vObs = [vobs_01, vobs_02] vObs = [vobs_01, vobs_02]
@ -49,18 +52,19 @@ class TotOnline:
return p_value, (p_value >= 0.01) return p_value, (p_value >= 0.01)
@staticmethod @staticmethod
def monobit_test(binary_data: str): def monobit_test(binary_data: bytes):
length_of_bit_string = len(binary_data) * 8
length_of_bit_string = len(binary_data)
# Variable for S(n) # Variable for S(n)
count = 0 count = 0
# Iterate each bit in the string and compute for S(n)
for bit in binary_data: # Iterate each bit in the byte sequence and compute for S(n)
if bit == 48: for byte in binary_data:
for bit in range(8):
if (byte >> (7 - bit)) & 1 == 0:
# If bit is 0, then -1 from the S(n) # If bit is 0, then -1 from the S(n)
count -= 1 count -= 1
elif bit == 49: else:
# If bit is 1, then +1 to the S(n) # If bit is 1, then +1 to the S(n)
count += 1 count += 1
@ -74,45 +78,41 @@ class TotOnline:
return p_value, (p_value >= 0.01) return p_value, (p_value >= 0.01)
@staticmethod @staticmethod
def block_frequency_test(binary_data: str, block_size=128): def block_frequency_test(binary_data: bytes, block_size=128):
length_of_bit_string = len(binary_data) * 8
length_of_bit_string = len(binary_data)
if length_of_bit_string < block_size: if length_of_bit_string < block_size:
block_size = length_of_bit_string block_size = length_of_bit_string
# Compute the number of blocks based on the input given. Discard the remainder # Compute the number of blocks based on the input given. Discard the remainder
number_of_blocks = floor(length_of_bit_string / block_size) number_of_blocks = length_of_bit_string // block_size
if number_of_blocks == 1: if number_of_blocks == 1:
# For block size M=1, this test degenerates to test 1, the Frequency (Monobit) test. # For block size M=1, this test degenerates to test 1, the Frequency (Monobit) test.
return TotOnline.monobit_test(binary_data[0:block_size]) return TotOnline.monobit_test(binary_data[0:block_size])
# Initialized variables # Initialize variables
block_start = 0
block_end = block_size
proportion_sum = 0.0 proportion_sum = 0.0
# Create a for loop to process each block # Create a for loop to process each block
for counter in range(number_of_blocks): for counter in range(number_of_blocks):
# Partition the input sequence and get the data for block # Partition the input sequence and get the data for block
block_start = counter * block_size // 8
block_end = block_start + block_size // 8
block_data = binary_data[block_start:block_end] block_data = binary_data[block_start:block_end]
# Determine the proportion i of ones in each M-bit # Determine the proportion πi of ones in each M-bit
one_count = 0 one_count = 0
for bit in block_data: for byte in block_data:
if bit == 49: for bit in range(8):
if (byte >> (7 - bit)) & 1 == 1:
one_count += 1 one_count += 1
# compute π # Compute π
pi = one_count / block_size pi = one_count / (block_size * 8) * 8
# Compute Σ(πi -½)^2. # Compute Σ(πi -½)^2.
proportion_sum += pow(pi - 0.5, 2.0) proportion_sum += pow(pi - 0.5, 2.0)
# Next Block
block_start += block_size
block_end += block_size
# Compute 4M Σ(πi -½)^2. # Compute 4M Σ(πi -½)^2.
result = 4.0 * block_size * proportion_sum result = 4.0 * block_size * proportion_sum
@ -122,27 +122,30 @@ class TotOnline:
return p_value, (p_value >= 0.01) return p_value, (p_value >= 0.01)
@staticmethod @staticmethod
def run_test(binary_data: str): def run_test(binary_data: bytes):
vObs = 0 vObs = 0
length_of_binary_data = len(binary_data) length_of_binary_data = len(binary_data) * 8
# Predefined tau = 2 / sqrt(n) # Predefined tau = 2 / sqrt(n)
tau = 2 / sqrt(length_of_binary_data) tau = 2 / sqrt(length_of_binary_data)
# Step 1 - Compute the pre-test proportion π of ones in the input sequence: π = Σjεj / n # Step 1 - Compute the pre-test proportion π of ones in the input sequence: π = Σjεj / n
one_count = binary_data.count(49) one_count = 0
for byte in binary_data:
for bit in range(8):
if (byte >> (7 - bit)) & 1 == 1:
one_count += 1
pi = one_count / length_of_binary_data 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 # Step 2 - If it can be shown that the absolute value of (π - 0.5) is greater than or equal to tau,
# then the run test need not be performed. # then the run test need not be performed.
if abs(pi - 0.5) >= tau: if abs(pi - 0.5) >= tau:
return 0.0000 return 0.0000
else: else:
# Step 3 - Compute vObs # Step 3 - Compute vObs
for item in range(1, length_of_binary_data): for i in range(1, length_of_binary_data):
if binary_data[item] != binary_data[item - 1]: if ((binary_data[i // 8] >> (7 - (i % 8))) & 1) != ((binary_data[(i - 1) // 8] >> (7 - ((i - 1) % 8))) & 1):
vObs += 1 vObs += 1
vObs += 1 vObs += 1
@ -152,14 +155,10 @@ class TotOnline:
return p_value, (p_value > 0.01) return p_value, (p_value > 0.01)
@staticmethod @staticmethod
def longest_one_block_test(binary_data: str): def longest_one_block_test(binary_data: bytes):
length_of_binary_data = len(binary_data) * 8
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: if length_of_binary_data < 128:
# Not enough data to run this test
return 0.00000, 'Error: Not enough data to run this test' return 0.00000, 'Error: Not enough data to run this test'
elif length_of_binary_data < 6272: elif length_of_binary_data < 6272:
k = 3 k = 3
@ -172,7 +171,6 @@ class TotOnline:
v_values = [4, 5, 6, 7, 8, 9] v_values = [4, 5, 6, 7, 8, 9]
pi_values = [0.1174, 0.2430, 0.2493, 0.1752, 0.1027, 0.1124] pi_values = [0.1174, 0.2430, 0.2493, 0.1752, 0.1027, 0.1124]
else: else:
# If length_of_bit_string > 750000
k = 6 k = 6
m = 10000 m = 10000
v_values = [10, 11, 12, 13, 14, 15, 16] v_values = [10, 11, 12, 13, 14, 15, 16]
@ -182,19 +180,16 @@ class TotOnline:
block_start = 0 block_start = 0
block_end = m block_end = m
xObs = 0 xObs = 0
# This will initialize an array with a number of 0 you specified.
frequencies = zeros(k + 1) frequencies = zeros(k + 1)
# print('Number of Blocks: ', number_of_blocks)
for count in range(number_of_blocks): for count in range(number_of_blocks):
block_data = binary_data[block_start:block_end] block_data = binary_data[block_start // 8:block_end // 8]
max_run_count = 0 max_run_count = 0
run_count = 0 run_count = 0
# This will count the number of ones in the block for byte in block_data:
for bit in block_data: for bit in range(7, -1, -1):
if bit == 49: if (byte >> bit) & 1 == 1:
run_count += 1 run_count += 1
max_run_count = max(max_run_count, run_count) max_run_count = max(max_run_count, run_count)
else: else:
@ -203,7 +198,6 @@ class TotOnline:
max(max_run_count, run_count) max(max_run_count, run_count)
# print('Block Data: ', block_data, '. Run Count: ', max_run_count)
if max_run_count < v_values[0]: if max_run_count < v_values[0]:
frequencies[0] += 1 frequencies[0] += 1
for j in range(k): for j in range(k):
@ -214,13 +208,10 @@ class TotOnline:
block_start += m block_start += m
block_end += m block_end += m
# print("Frequencies: ", frequencies)
# Compute xObs
for count in range(len(frequencies)): for count in range(len(frequencies)):
xObs += pow((frequencies[count] - (number_of_blocks * pi_values[count])), 2.0) / ( xObs += pow((frequencies[count] - (number_of_blocks * pi_values[count])), 2.0) / (
number_of_blocks * pi_values[count]) number_of_blocks * pi_values[count])
p_value = gammaincc(float(k / 2), float(xObs / 2)) p_value = gammaincc(float(k / 2), float(xObs / 2))
return p_value, (p_value > 0.01) return p_value, (p_value > 0.01)