Andy has published his program but is reporting some problems in recreating the original tables--the values generated by his program are XORed with a constant value when compared with the original table.
I have just verified that this doesn't happen to me, so I presume this is due to a different method we used to reconstruct the Feistel function for the first two rounds.
Let's recap how this was done. The fundamental idea was published by Andy:
since R4 = L3 XOR F4(L4), if you pick (E,D) and (E',D') such that L4 = L'4, then
R'4 = L'3 XOR F4(L'4) = L'3 XOR F4(L4) = L'3 XOR R4 XOR L3
L3 XOR L'3 = R4 XOR R'4
Now if we pick (E,D) and (E',D') such that L4 = L'4 and E and E' differ by only one bit, we can see how flipping a single bit in the input changes the output after the third round. Andy's fundamental discovery was that flipping certain bits never affects certain other bits.
That knowledge can easily be used to determine F4. Take (E,D) and (E',D'), where E and E' differ only by one bit which we know doesn't affect bit b in L3. Then we know that
Bb(L3 XOR L'3) = 0
where Bb(x) gives me the value of bit b of x.
Bb(R4 XOR F4(L4) XOR R'4 XOR F4(L'4)) = 0
Bb(F4(L4) XOR F4(L'4)) = Bb(R4 XOR R'4)
Do that for all b and for all E, E' pairs, and you quickly reconstruct the whole F4 structure. I'm saying its structure and not F4 itself, because it's all done through XOR so you need to set F4(0) arbitrarily, then all the others are derived from it through XOR.
After F4 is reconstructed, it can be used to undo the fourth round of the encryption. Then you repeat exactly the same process to reconstruct F3 (still XOR an arbitrary value). Then use F3 to undo the third round, and you are left with just two rounds.
Now things get really simple, because by definition
L2 = L0 XOR F1(R0)
R2 = R0 XOR F2(L2)
and since you know all of L0, R0, L2, and R2, F1 and F2 are immediately derived as
F1(R0) = L0 XOR L2
F2(L2) = R0 XOR R2
Note that here we derive F1 and F2 explicitly, not XOR an arbitrary value.