t = If(t < 0, t + 65537, t); t = If(t > 65536, t - 65537, t)
return If(t == 65536, BitVecVal(0, 16), Extract(15, 0, t))
function badd(x, y): # modular addition (mod 2^16)
return Extract(15, 0, simplify(ZeroExt(16, x) + ZeroExt(16, y)))
function IdeaOneRoundEqu(A, B, C, D, z): # round r with subkeys z0..z5
A = bmul(A, z0); B = badd(B, z1); C = badd(C, z2); D = bmul(D, z3)
T0 = C; T1 = B
C = bmul(C ^ A, z4); B = bmul(badd(B ^ D, C), z5)
C = badd(C, B); A = A ^ B; D = D ^ C; B = B ^ T0; C = C ^ T1
return (A, B, C, D)
function OutTransform(A, B, C, D, z): # output transformation
A = bmul(A, z[0]); C = badd(C, z[1]); B = badd(B, z[2]); D = bmul(D, z[3])
return (A, C, B, D)
# --- construct the SMT formula ---
K0, ..., K7 := BitVec("K0") ... BitVec("K7") # 8 x 16-bit unknowns
K := Concat(K0, K1, ..., K7)
EK := schedule(K) # 52 subkeys via 25-bit rotation
X := PT; for r in 1 .. rounds: X := IdeaOneRoundEqu(X, EK[6(r-1)..6r-1])
Y := OutTransform(X, EK[6*rounds .. 6*rounds+3])
s := SolverFor("QF_BV")
for every disclosed key bit position b: s.add(Extract(b, b, K) == known_bit)
for i in 0..3: s.add(Y[i] == CT[i])
# --- solve and verify ---
if s.check() == sat:
candidate := s.model()
key := Concat(model[K0], ..., model[K7])
verify: re-encrypt PT with key and compare against CT
record wall-clock time and solver seed
return key
else: return unsat
end procedure
5. Results and discussion
5.1 Experimental setup and results
The experiments recover the 128-bit master key from one known plaintext-ciphertext pair at r = 4 through 8.
We use PT = (0x0000, 0x0000, 0x0000, 0x0000) and K = 0x00010002000300040005000600070008. The
integer reference path generates the ciphertexts below, which are then imposed as symbolic equalities.
Round 4: CT = (0x1deb, 0x20c9, 0xe92f, 0xb4af)
Round 5: CT = (0xb51d, 0xb935, 0x417a, 0x5a1a)
Round 6: CT = (0xe95e, 0xfc74, 0x48b5, 0xad36)
Round 7: CT = (0x8c2b, 0xb895, 0x5a8d, 0x49dd)
Round 8: CT = (0x28d3, 0x2d26, 0x0fec, 0x0309)
The reference ciphertexts agree with the canonical test-vector chain. Each current measured cell uses a warm-
up solve followed by repeated seeded runs; Table 3 reports the median, observed range, and verification result,
while results.csv stores the underlying values and solver statistics. The experiments used an Intel Core i7
processor with 16 GB of RAM, Ubuntu 20.10, Python 3.8, and Z3 4.8.12. Runs were distributed across available
cores. The 96-known/32-unknown values are archival measurements without raw logs or known repetition
counts and are not presented as a replicated sample.
Table 3: Key-recovery results on the reduced-round IDEA (PT = all zeros)