import random
import z3

_ROL_ = lambda x, i : ((x << i) | (x >> (N-i))) & (2**N - 1)


N = 128

def parity(x):
    res = 0
    while x:
        res ^= x & 1
        x >>= 1
    return res


while True:
    x = random.randint(0, 2**128)
    if parity(x) == 0:
        break

# Compute y and c, such that y ^ _ROL_(y,c) == x
# Hint: to implement _ROL_, z3 already has the function z3.RotateLeft
def compute_yc(x):
    s = z3.Solver()
    y = z3.BitVec("y", N)
    c = z3.BitVec("c", N)
    s.add((y ^ z3.RotateLeft(y,c)) == x)
    s.check()
    m = s.model()

    return m[y].as_long(), m[c].as_long()


y, c = compute_yc(x)

print(f'{y=}, {c=}')
print(f'{x=}, {y ^ _ROL_(y, c)=}')
print(f'{x==y ^ _ROL_(y, c)=}')
