The Challenge
The binary validates the flag character by character: each byte c must satisfy c² - k*c == -k²/4 for a per-position constant k. Equivalently, the equation has two roots — only one of them is a valid printable ASCII character.
Approach
Looking at the constraints, each one is flag[i]² - coeff[i] * flag[i] == constant[i]. These are independent one-variable quadratic equations, so they have at most two integer solutions each. One will be a printable ASCII code, the other either negative or out of range.
Z3 handles this trivially: declare 20 Int variables, add 20 constraints, solve. The model gives the integer value for each character; cast to bytes with .to_bytes(1, "little") and decode.
Solution
|
|
Each constraint is x² - kx + k²/4 == 0, which factors as (x - k/2)² == 0, giving x == k/2. The constants in each equation encode half the ASCII value of the corresponding character — but Z3 solves it without needing to spot the pattern.
What I Learned
When the binary validates each character independently with a polynomial equation, there’s no need to reverse the math by hand. Z3 handles polynomial constraints natively. The key signal is independent per-character checks — if they don’t mix characters, each variable is solvable in isolation.