import struct
R = 0xE1000000000000000000000000000000
MASK128 = (1 << 128) - 1
def gf128_mul(x, y):
z = 0
v = x & MASK128
for i in range(128):
if (y >> i) & 1:
z ^= v
msb = (v >> 127) & 1
v = (v << 1) & MASK128
if msb:
v ^= R
return z & MASK128
def ghash(H_bytes, aad, ct):
H = int.from_bytes(H_bytes, "big")
len_block = struct.pack(">QQ", len(aad) * 8, len(ct) * 8)
data = aad + ct + len_block
Y = 0
for i in range(0, len(data), 16):
block = data[i:i+16]
if len(block) < 16:
block = block + b"\x00" * (16 - len(block))
X = int.from_bytes(block, "big")
Y = gf128_mul(Y ^ X, H)
return Y.to_bytes(16, "big")
# Данные из твоего вывода:
GLOBAL_H = bytes.fromhex("044419fccd60e5ce1b9f1659fb1831e9")
FLAG_CT = bytes.fromhex("18930f5ebd9e497b1d511181817de1a7c05d54281447ee3c8f97f1d86a04606b1fe7ae2fc5")
known = bytes.fromhex("3a49b67dcfd2e6afa091835adb1d8000")
G0_real = bytes.fromhex("de97a6094a79f37f5d1779c242dc4dce")
AAD_PREFIX = b"user-aad-prefix:"
print(f"FLAG_CT len = {len(FLAG_CT)}")
# G0 через нашу функцию
G0 = ghash(GLOBAL_H, AAD_PREFIX + b"\x00" * 16, FLAG_CT)
print(f"G0 (локально) = {G0.hex()}")
print(f"G0 (с сервера) = {G0_real.hex()}")
print(f"G0 совпадает: {G0 == G0_real}")
print()
# Проверим разные X
def test_X(X):
return ghash(GLOBAL_H, AAD_PREFIX + X, FLAG_CT)
G0 = test_X(b"\x00" * 16)
G1 = test_X(b"\x00" * 15 + b"\x01")
G2 = test_X(b"\x00" * 15 + b"\x02")
G3 = test_X(b"\x00" * 15 + b"\x03")
d1 = int.from_bytes(bytes(a ^ b for a, b in zip(G1, G0)), "big")
d2 = int.from_bytes(bytes(a ^ b for a, b in zip(G2, G0)), "big")
d3 = int.from_bytes(bytes(a ^ b for a, b in zip(G3, G0)), "big")
print(f"d1 = G1^G0 = {d1:032x}")
print(f"d2 = G2^G0 = {d2:032x}")
print(f"d3 = G3^G0 = {d3:032x}")
print(f"d2 == 2*d1: {d2 == gf128_mul(2, d1)}")
print(f"d3 == 3*d1: {d3 == gf128_mul(3, d1)}")
print()
# Ищем k: d1 == H^k
H = int.from_bytes(GLOBAL_H, "big")
H_k = 1
for k in range(0, 30):
if H_k == d1:
print(f"*** d1 == H^{k} ***")
break
H_k = gf128_mul(H_k, H)
else:
print("d1 != H^k для k=0..29")