From b320ef0be12884ae43cf9d292e0fb785c414c94d Mon Sep 17 00:00:00 2001 From: Thomas Coratger <60488569+tcoratger@users.noreply.github.com> Date: Thu, 21 May 2026 00:02:07 +0200 Subject: [PATCH] refactor(poseidon1): build circulant MDS via np.roll Replace the nested Python loop in _build_circulant_mds with a single numpy comprehension. Row i of a circulant matrix is the first row rolled right by i positions, so the matrix is built as a stack of rolled rows reduced mod p. Verified element-wise equivalent against the width-16 and width-24 spec rows and a value crossing the modulus. Co-Authored-By: Claude Opus 4.7 (1M context) --- src/lean_spec/subspecs/poseidon1/permutation.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/lean_spec/subspecs/poseidon1/permutation.py b/src/lean_spec/subspecs/poseidon1/permutation.py index 994ac40a8..1055e8f05 100644 --- a/src/lean_spec/subspecs/poseidon1/permutation.py +++ b/src/lean_spec/subspecs/poseidon1/permutation.py @@ -30,12 +30,10 @@ def _build_circulant_mds(first_row: list[int], n: int, p: int) -> NDArray[np.int A circulant matrix C defined by first row [r0, r1, ..., rn-1]: C[i][j] = r[(j - i) mod n] + + Row i is the first row rolled right by i positions. """ - matrix = np.zeros((n, n), dtype=np.int64) - for i in range(n): - for j in range(n): - matrix[i][j] = first_row[(j - i) % n] % p - return matrix + return np.array([np.roll(first_row, i) for i in range(n)], dtype=np.int64) % p @njit(cache=True)