def solve_gf2_linear(H_k, D):
"""
Решает X * H_k = D в GF(2^128).
Строит матрицу 128x128 и решает Гауссом.
"""
# Столбцы: H_k * e_i для i=0..127
# e_i = 1 << i
cols = [gf128_mul(H_k, 1 << i) for i in range(128)]
# Строим систему: для каждого бита j (0..127):
# sum_i X_i * cols[i][j] = D[j]
# где cols[i][j] = (cols[i] >> j) & 1
# Матрица строк: row j = (биты cols[0..127][j], D[j])
rows = []
for j in range(128):
row = 0
for i in range(128):
if (cols[i] >> j) & 1:
row |= (1 << i)
if (D >> j) & 1:
row |= (1 << 128)
rows.append(row)
# Гаусс
pivot_row = 0
pivot_cols = []
for col in range(128):
pivot = -1
for r in range(pivot_row, 128):
if (rows[r] >> col) & 1:
pivot = r
break
if pivot == -1:
continue
rows[pivot_row], rows[pivot] = rows[pivot], rows[pivot_row]
for r in range(128):
if r != pivot_row and ((rows[r] >> col) & 1):
rows[r] ^= rows[pivot_row]
pivot_cols.append(col)
pivot_row += 1
# Проверяем решение
X = 0
for r in range(pivot_row):
for col in range(128):
if (rows[r] >> col) & 1:
if (rows[r] >> 128) & 1:
X |= (1 << col)
break
# Проверка
check = 0
for i in range(128):
if (X >> i) & 1:
check ^= cols[i]
if check != D:
return None
return X