From 249e5cb1e18fc25a215f160568b02510dbfbd809 Mon Sep 17 00:00:00 2001 From: Sam Hadow Date: Tue, 9 Jun 2026 10:16:12 +0200 Subject: [PATCH] exhaustive 2 bits XOR search --- src/tea3/cli.py | 20 ++++++++++++++++++-- src/tea3/variable_xor.py | 38 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+), 2 deletions(-) diff --git a/src/tea3/cli.py b/src/tea3/cli.py index cfdca7f..dd4d9e1 100644 --- a/src/tea3/cli.py +++ b/src/tea3/cli.py @@ -3,7 +3,7 @@ from tea3.cliutils import prompt_int, prompt_choice, prompt_list from tea3.tea3model import Tea3Model from tea3.variable_search import run_exhaustive from tea3.sbox import run_sbox -from tea3.variable_xor import run_variable_xor +from tea3.variable_xor import run_variable_xor, run_exhaustive_two_bit_xor from tea3.f31f32 import run_f31f32 @@ -70,6 +70,19 @@ def run_variable_xor_cli(): print("\n" + "=" * 50) print("Done.") +def run_exhaustive_two_bit_xor_cli(): + print("\nR registers are indexed 0–7; bits within each register are 0–7.") + print("This mode checks all 2-bit XOR pairs and prints the best one(s) at each step.") + + steps = prompt_int("How many steps? (1–100): ", 1, 100) + target_reg = prompt_int("Target register (0–7): ", 0, 7) + + print("-" * 50) + run_exhaustive_two_bit_xor(steps, target_reg) + + print("\n" + "=" * 50) + print("Done.") + def main(): @@ -83,8 +96,9 @@ def main(): print(" 3) S box analysis") print(" 4) variable XOR") print(" 5) F31, F32 analysis") + print(" 6) Exhaustive 2-bit XOR search") - mode = prompt_choice("Your choice (1, 2, 3, 4 or 5): ", {1, 2, 3, 4, 5}) + mode = prompt_choice("Your choice (1, 2, 3, 4, 5 or 6): ", {1, 2, 3, 4, 5, 6}) if mode == 1: run_classic_cli() @@ -96,6 +110,8 @@ def main(): run_variable_xor_cli() elif mode == 5: run_f31f32() + elif mode == 6: + run_exhaustive_two_bit_xor_cli() main() diff --git a/src/tea3/variable_xor.py b/src/tea3/variable_xor.py index d8538ce..febdbf0 100644 --- a/src/tea3/variable_xor.py +++ b/src/tea3/variable_xor.py @@ -1,6 +1,11 @@ +from itertools import combinations + from tea3.tea3model import Tea3Model from tea3.pretty_print import pretty_print +def monomial_count(poly): + return len(poly.monomials()) + def run_variable_xor(steps, target_reg, bits_to_xor): model = Tea3Model() @@ -23,3 +28,36 @@ def run_variable_xor(steps, target_reg, bits_to_xor): print(f"XOR of R_bits[{target_reg}][{bits_to_xor}] =") print(pretty_print(xor_poly)) print() + + +def run_exhaustive_two_bit_xor(steps, target_reg, bit_indices=range(8)): + model = Tea3Model() + + bit_pairs = list(combinations(bit_indices, 2)) + + print(f"Target register: R{target_reg}") + print(f"Searching all 2-bit XORs among bits: {list(bit_indices)}") + print("-" * 50) + + for i in range(steps): + model.step() + + best_count = None + best_pairs = [] + best_poly = None + + for b1, b2 in bit_pairs: + xor_poly = model.R_bits[target_reg][b1] + model.R_bits[target_reg][b2] + count = monomial_count(xor_poly) + + if best_count is None or count < best_count: + best_count = count + best_pairs = [(b1, b2)] + best_poly = xor_poly + elif count == best_count: + best_pairs.append((b1, b2)) + + print(f"\n[Step {i + 1}]") + print(f"Best XOR(s) with {best_count} total monomials:") + for b1, b2 in best_pairs: + print(f" bits XORed: ({b1}, {b2})")