diff --git a/.gitignore b/.gitignore index ea8c4bf..9be143b 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ /target +scripts/__pycache__/ diff --git a/gen_values.py b/gen_values.py deleted file mode 100644 index 1fa4602..0000000 --- a/gen_values.py +++ /dev/null @@ -1,28 +0,0 @@ -import sys -import random -import argparse - -def generate_test_file(noise_bits, number): - - p = random.randint(1000, 10000) - while p % 2 == 0: - p = random.randint(1000, 10000) - - max_noise = (1 << noise_bits) - 1 # 2^noise_bits - 1 - - a = [str(p * random.randint(1, 100) + random.randint(0, max_noise)) for _ in range(number)] - - print(noise_bits) - - for b in a: - print(b) - - print(f"// True p: {p}") - -if __name__ == "__main__": - parser = argparse.ArgumentParser(description='Generate test input for AGCD computation') - parser.add_argument('--noise-bits', type=int, default=5, help='Number of noise bits (default: 5)') - parser.add_argument('--number', type=int, default=20, help='Number of numbers to generate (default: 20)') - - args = parser.parse_args() - generate_test_file(args.noise_bits, args.number) diff --git a/scripts/gen_values.py b/scripts/gen_values.py new file mode 100644 index 0000000..af0e32a --- /dev/null +++ b/scripts/gen_values.py @@ -0,0 +1,47 @@ +import sys +import random +import argparse + +def generate_test_values(noise_bits, number, p_bits): + + p = random.randint(2**(p_bits-1), 2**p_bits) + while p % 2 == 0: + p = random.randint(2**(p_bits-1), 2**p_bits) + + max_noise = (1 << noise_bits) - 1 # 2^noise_bits - 1 + + a = [str(p * random.randint(1, 100) + random.randint(0, max_noise)) for _ in range(number)] + + return noise_bits, a, p + + +def generate_test_file(noise_bits, number, p_bits, filename): + noise_bits, a, p = generate_test_values(noise_bits, number, p_bits) + + with open(filename, 'w') as f: + f.write(f"{noise_bits}\n") + for b in a: + f.write(f"{b}\n") + f.write(f"// True p: {p}\n") + + return p + +def print_test_values(noise_bits, number, p_bits): + + _, a, p = generate_test_values(noise_bits, number, p_bits) + + print(noise_bits) + + for b in a: + print(b) + + print(f"// True p: {p}") + +if __name__ == "__main__": + parser = argparse.ArgumentParser(description='Generate test input for AGCD computation') + parser.add_argument('--noise-bits', type=int, default=5, help='Number of noise bits (default: 5)') + parser.add_argument('--p-bits', type=int, default=16, help='Number of key bits (default: 16)') + parser.add_argument('--number', type=int, default=20, help='Number of numbers to generate (default: 20)') + + args = parser.parse_args() + print_test_values(args.noise_bits, args.number, args.p_bits) diff --git a/scripts/script.py b/scripts/script.py new file mode 100644 index 0000000..952992f --- /dev/null +++ b/scripts/script.py @@ -0,0 +1,72 @@ +#!/bin/python3 +import argparse, subprocess, re, tempfile, os +import numpy as np +import matplotlib.pyplot as plt +from gen_values import generate_test_file + +def run_agcd(input_file): + cmd = ["./target/release/approximate-gcd", "agcd", input_file] + + try: + result = subprocess.run(cmd, capture_output=True, text=True, check=True) + output = result.stdout + + match = re.search(r"Recovered p: (\d+)", output) + return int(match.group(1)) if match else None + + except subprocess.CalledProcessError as e: + print(f"Error running command for input_file={input_file}: {e}") + return None + except (AttributeError, ValueError) as e: + print(f"Error parsing output for input_file={input_file}: {e}") + return None + + +def plot_curves(noise_bits, p_bits, test_numbers, successes): + plt.figure(figsize=(10, 6)) + plt.plot(test_numbers, successes, marker='o') + plt.xlabel('Number of Test Values') + plt.ylabel('Success (1 = Correct, 0 = Incorrect)') + plt.title(f'Success vs. Number of Test Values\n(noise_bits={noise_bits}, p_bits={p_bits})') + plt.grid(True) + plt.ylim(-0.1, 1.1) + plt.yticks([0, 1]) + plt.xticks(test_numbers) + plt.savefig('success_plot.png') + plt.show() + +def main(): + parser = argparse.ArgumentParser(description='Test AGCD with varying number of test values.') + parser.add_argument('--noise_bits', type=int, default=8, help='Number of noise bits') + parser.add_argument('--p_bits', type=int, default=128, help='Number of bits for p') + parser.add_argument('--min_values', type=int, default=2, help='Minimum number of test values') + parser.add_argument('--max_values', type=int, default=100, help='Maximum number of test values') + args = parser.parse_args() + + noise_bits = args.noise_bits + p_bits = args.p_bits + test_numbers = range(args.min_values, args.max_values + 1) + successes = [] + + for num_values in test_numbers: + # Create temporary test file + with tempfile.NamedTemporaryFile(mode='w', delete=False, suffix='.txt') as tmp_file: + true_p = generate_test_file(noise_bits, num_values, p_bits, tmp_file.name) + + # Run AGCD + recovered_p = run_agcd(tmp_file.name) + + # Check if recovery was successful + success = 1 if recovered_p != None and abs(recovered_p - true_p) <= 4 else 0 + successes.append(success) + + # Clean up + os.unlink(tmp_file.name) + + print(f"Number of values: {num_values}, Success: {'Yes' if success else 'No'}") + + # Plot the results + plot_curves(noise_bits, p_bits, test_numbers, successes) + +if __name__ == "__main__": + main()