1"""The 9-step local-collision pattern cancels in the linearised model, and the vectorised step equals the reference."""2import pathlib, random, sys3import numpy as np4ROOT = pathlib.Path(__file__).resolve().parents[1]5sys.path.insert(0, str(ROOT / "src")); sys.path.insert(0, str(ROOT / "experiments" / "reduced_round_sha256"))6from wp34 import sha256 as S7import local_collision as L8910def test_pattern_cancels_for_all_single_bits_and_random_words():11 for b in range(32):12 assert L.verify_linear(1 << b)[0]13 rng = random.Random(5)14 for _ in range(10):15 assert L.verify_linear(rng.getrandbits(32))[0]161718def test_wrong_pattern_does_not_cancel():19 d = 1 << 720 A, B = L.linear_step_matrices()21 x = np.zeros(256, dtype=np.uint8)22 pat = L.pattern(d); pat[5] = 0 # drop one correction23 for dw in pat:24 x = (A @ x + B @ L.vec(dw)) % 225 assert x.any()262728def test_vectorised_step_matches_reference():29 rng = np.random.default_rng(1)30 st = [rng.integers(0, 2**32, 64, dtype=np.uint32) for _ in range(8)]31 w = rng.integers(0, 2**32, 64, dtype=np.uint32)32 out = L.np_step(st, S.K[3], w)33 for i in range(64):34 ref = S.step(tuple(int(x[i]) for x in st), S.K[3], int(w[i]))35 assert tuple(int(x[i]) for x in out) == ref36