I want to generate a keygen in python with z3. here is the validation function:
def f(a):
a = ord(a)
if a <= 47 or a > 57:
if a <= 64 or a > 98:
exit()
else:
return a - 55
else:
return a - 48
def validate(key):
if len(key) != 16:
return False
for k in key:
if f(k)%2== 0:
return False
return True
I tried to write a solver for this
from z3 import *
solver = Solver()
def f_z3(a):
return If(
Or(a<=47, a>57),
If(
Or(a<=64, a>98),
False, # exit()???
a -55
),
a -48
)
key = IntVector("key", 16)
for k in key:
solver.add(f_z3(k)%2==0)
solver.check()
print(solver.model())
and here is the output
[key__1 = 48,
key__10 = 48,
key__9 = 48,
key__15 = 48,
key__6 = 48,
key__8 = 48,
key__4 = 48,
key__0 = 48,
key__14 = 48,
key__11 = 48,
key__7 = 48,
key__5 = 48,
key__2 = 48,
key__12 = 48,
key__13 = 48,
key__3 = 48]
Which returns the key "0000000000000000", but validate("0000000000000000") return False.
I know that the problem is in the f_z3 function, I don't know how to express the exit() inside the if, I want something always False. But instead am just returning False.
Any idea how to solve this problem?
There are two issues with your code:
As you observed, the replacement of
exitwithFalseisn't right in thef_z3function. (The python version is just bizarre here that it would return a boolean in certain cases and just plain die in others. But that's beside the point.) In all other branches you're returning an integer, and in that one you're returning a boolean. In z3 you always want to return the same type; an integer. So pick something that will cause that case to produceFalseeventually. Since later on you're checking for evenness, any odd number will do. Say1; so modify it to produce1instead ofFalsewhenexitis called.While you're validating, the Python code returns
Falseif the result is even; so you need to assert that correctly. Currently you're doingsolver.add(f_z3(k)%2==0), instead you should require the modulus to be not-even, like this:solver.add(f_z3(k)%2!=0).With those two modifications, you'll have the following code:
When run, this produces:
which suggests the valid key
"1111111111111111".