Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 47 additions & 0 deletions lab_2/RandomGenerator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import java.io.FileWriter;
import java.io.IOException;
import java.util.Random;

public class RandomGenerator {

/**
* Generates a random binary sequence of 128 bit
*
* @return Generated binary sequence as a string
*/
public static String generate_seq() {
Random rand = new Random();
StringBuilder sequence = new StringBuilder();

for (int i = 0; i < 128; ++i) {
sequence.append(rand.nextInt(2));
}

return sequence.toString();
}

/**
* Saves a sequence to the specified file
*
* @param filename Path to the file to save
* @param sequence Sequence to save
*/
public static void save_seq(String filename, String sequence) {
try (FileWriter writer = new FileWriter(filename)) {
writer.write(sequence + "\n");
}
catch (IOException e) {
System.err.println(e.getMessage());
}
}

/**
* Main method of the program
*
* @param args Command line arguments (not used)
*/
public static void main(String[] args) {
String sequence = generate_seq();
save_seq("sequence_java.txt", sequence);
}
}
53 changes: 53 additions & 0 deletions lab_2/random.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
#include <fstream>
#include <iostream>
#include <random>
#include <string>

/**
* Generates a random binary sequence of 128 bit
*
* @return Generated binary sequence as a string
*/
std::string generate_seq() {
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_int_distribution number(0, 1);

std::string sequence;

for (size_t i = 0; i < 128; ++i) {
sequence += std::to_string(number(gen));
}

return sequence;
}

/**
* Saves a sequence to the specified file
*
* @param filename Path to the file to save
* @param sequence Sequence to save
*/
void save_seq(const std::string& filename, const std::string& sequence) {
try {
std::ofstream out;
out.open(filename);

if (!out.is_open()) {
throw std::runtime_error("Failed to open file " + filename);
}

out << sequence << std::endl;
out.close();
}
catch (const std::exception& e) {
std::cerr << e.what() << std::endl;
}
}

int main() {
std::string sequence = generate_seq();
save_seq("sequence_cpp.txt", sequence);

return 0;
}
14 changes: 14 additions & 0 deletions lab_2/results.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"cpp": {
"sequence": "10001111101110111111001001001100101000101110100101001111000001010011001000001011111000011110110110110001110101100100010001000001",
"frequency_bit_test": 0.8596837951986662,
"identical_consecutive_bits_test": 0.7256806886581656,
"longest_sequence_in_block_test": 0.9693053066778472
},
"java": {
"sequence": "00111101111000001011100110110011000110101101111010101100111100110001011000101011111111001111000110011010111010101010111111010011",
"frequency_bit_test": 0.05182992721790971,
"identical_consecutive_bits_test": 0.5985061525910559,
"longest_sequence_in_block_test": 0.07923339282255983
}
}
1 change: 1 addition & 0 deletions lab_2/sequence_cpp.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
10001111101110111111001001001100101000101110100101001111000001010011001000001011111000011110110110110001110101100100010001000001
1 change: 1 addition & 0 deletions lab_2/sequence_java.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
00111101111000001011100110110011000110101101111010101100111100110001011000101011111111001111000110011010111010101010111111010011
6 changes: 6 additions & 0 deletions lab_2/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"CPP": "sequence_cpp.txt",
"JAVA": "sequence_java.txt",
"RESULTS": "results.json",
"PI": [0.2148, 0.3672, 0.2305, 0.1875]
}
138 changes: 138 additions & 0 deletions lab_2/tests.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
import math
from scipy.special import gammaincc
from utility_file import *


def frequency_bit_test(sequence: str) -> float:
"""
Выполняет частотный побитовый тест NIST.
:param sequence: бинарная последовательность
:return: P-значение теста
"""
if not sequence:
raise ZeroDivisionError("Sequence is empty")

if not all(bit in '01' for bit in sequence):
raise ValueError("Sequence must include only '0' and '1'")

s_n = abs(sequence.count('1') - sequence.count('0')) / math.sqrt(len(sequence))
p_value = math.erfc(s_n / math.sqrt(2))
Comment on lines +18 to +19

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

добавить обработку исключений


return p_value


def identical_consecutive_bits_test(sequence: str) -> float:
"""
Выполняет тест на одинаковые подряд идущие биты.
:param sequence: бинарная последовательность
:return: P-значение теста
"""
if not sequence:
raise ZeroDivisionError("Sequence is empty")

if not all(bit in '01' for bit in sequence):
raise ValueError("Sequence must include only '0' and '1'")

n = len(sequence)
zeta = sequence.count('1') / n

if abs(zeta - 0.5) >= 2 /math.sqrt(n):
return 0.0

v_n = sum(1 if sequence[i] != sequence[i + 1] else 0 for i in range(n - 1))
p_value = math.erfc(abs(v_n - 2 * n * zeta * (1 - zeta)) / (2 * math.sqrt(2 * n) * zeta * (1 - zeta)))

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

добавить обработку исключений


return p_value


def longest_sequence_in_block_test(sequence: str, pi: list[float], block_size: int = 8) -> float:
"""
Выполняет тест на самую длинную последовательность единиц в блоке.
:param sequence: бинарная последовательность
:param pi: список вероятностных констант
:param block_size: размер блока (по умолчанию 8)
:return: P-значение теста
"""
if block_size <= 0:
raise ValueError("Block size must be a positive integer number")

if len(sequence) % block_size:
raise ValueError("Sequence length must be a multiple of the block size")

if not pi:
raise ValueError("List of probabilities is empty")

if not all(0 < p < 1 for p in pi):
raise ValueError("List of probabilities isn't correct")

if not sequence:
raise ValueError("Sequence is empty")

if not all(bit in '01' for bit in sequence):
raise ValueError("Sequence must include only '0' and '1'")

blocks = [sequence[i:i + block_size] for i in range(0, len(sequence), block_size)]
num_blocks = len(sequence) // block_size
v = [0] * len(pi)

for block in blocks:
max_len = 0
cur_len = 0

for bit in block:
if bit == '1':
cur_len += 1
max_len = max(max_len, cur_len)
else:
cur_len = 0

match max_len:
case x if x <= 1:
v[0] += 1
case 2:
v[1] += 1
case 3:
v[2] += 1
case _:
v[3] += 1

chi2 = sum(((v[i] - num_blocks * pi[i]) ** 2) / (num_blocks * pi[i]) for i in range(len(pi)))
p_value = gammaincc((len(pi) - 1) / 2, chi2 / 2)

return p_value


def analyze_sequence(sequence: str, pi: list[float]) -> dict:
"""
Выполняет тесты NIST для данной последовательности.
:param sequence: бинарная последовательность
:param pi: список вероятностных констант
:return: словарь с результатами тестов
"""
return {
"sequence": sequence,
"frequency_bit_test": frequency_bit_test(sequence),
"identical_consecutive_bits_test": identical_consecutive_bits_test(sequence),
"longest_sequence_in_block_test": longest_sequence_in_block_test(sequence, pi)
}


def main():
try:
source = load_json("settings.json")
cpp_seq = read_txt(source["CPP"])
java_seq = read_txt(source["JAVA"])

results = {
"cpp": analyze_sequence(cpp_seq, source["PI"]),
"java": analyze_sequence(java_seq, source["PI"])
}

write_json(results, source["RESULTS"])
print(f"Результаты сохранены в {source["RESULTS"]}")
except Exception as e:
print(f"Error: {e}")


if __name__ == "__main__":
main()
46 changes: 46 additions & 0 deletions lab_2/utility_file.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import json


def read_txt(filename: str) -> str:
"""
Читает содержимое текстового файла.
:param filename: путь к файлу
:return: строка с содержимым файла
"""
try:
with open(filename, "r", encoding="utf-8") as file:
return file.read().strip()
except FileNotFoundError:
print(f"File {filename} not found")
except Exception as e:
print(f"An error occurred while reading the file {filename}: {e}")


def load_json(filename: str) -> dict:
"""
Загружает данные из json-файла.
:param filename: путь к файлу
:return: словарь с содержимым файла
"""
try:
with open(filename, "r", encoding="utf-8") as file:
return json.load(file)
except FileNotFoundError:
print(f"File {filename} not found")
except json.JSONDecodeError:
print(f"File {filename} isn't correct JSON")
except Exception as e:
print(f"An error occurred while reading the file {filename}: {e}")


def write_json(data: dict, filename: str) -> None:
"""
Записывает данные в json-файл.
:param data: словарь с данными для записи
:param filename: путь к файлу, в который будут записаны данные
"""
try:
with open(filename, "w", encoding="utf-8") as file:
json.dump(data, file, indent=4, ensure_ascii=False)
except Exception as e:
print(f"An error occurred while saving the file {filename}: {e}")