"""passlib.crypto._blowfish.unrolled - unrolled loop implementation of bcrypt,
autogenerated by _gen_files.py

currently this override the encipher() and expand() methods
with optimized versions, and leaves the other base.py methods alone.
"""

# pkg
from passlib.crypto._blowfish.base import BlowfishEngine as _BlowfishEngine

# local
__all__ = [
    "BlowfishEngine",
]


class BlowfishEngine(_BlowfishEngine):
    def encipher(self, l, r):
        """blowfish encipher a single 64-bit block encoded as two 32-bit ints"""

        (
            p0,
            p1,
            p2,
            p3,
            p4,
            p5,
            p6,
            p7,
            p8,
            p9,
            p10,
            p11,
            p12,
            p13,
            p14,
            p15,
            p16,
            p17,
        ) = self.P
        S0, S1, S2, S3 = self.S

        l ^= p0

        # Feistel substitution on left word (round 0)
        r ^= (
            (
                ((S0[l >> 24] + S1[(l >> 16) & 0xFF]) ^ S2[(l >> 8) & 0xFF])
                + S3[l & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p1

        # Feistel substitution on right word (round 1)
        l ^= (
            (
                ((S0[r >> 24] + S1[(r >> 16) & 0xFF]) ^ S2[(r >> 8) & 0xFF])
                + S3[r & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p2
        # Feistel substitution on left word (round 2)
        r ^= (
            (
                ((S0[l >> 24] + S1[(l >> 16) & 0xFF]) ^ S2[(l >> 8) & 0xFF])
                + S3[l & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p3

        # Feistel substitution on right word (round 3)
        l ^= (
            (
                ((S0[r >> 24] + S1[(r >> 16) & 0xFF]) ^ S2[(r >> 8) & 0xFF])
                + S3[r & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p4
        # Feistel substitution on left word (round 4)
        r ^= (
            (
                ((S0[l >> 24] + S1[(l >> 16) & 0xFF]) ^ S2[(l >> 8) & 0xFF])
                + S3[l & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p5

        # Feistel substitution on right word (round 5)
        l ^= (
            (
                ((S0[r >> 24] + S1[(r >> 16) & 0xFF]) ^ S2[(r >> 8) & 0xFF])
                + S3[r & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p6
        # Feistel substitution on left word (round 6)
        r ^= (
            (
                ((S0[l >> 24] + S1[(l >> 16) & 0xFF]) ^ S2[(l >> 8) & 0xFF])
                + S3[l & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p7

        # Feistel substitution on right word (round 7)
        l ^= (
            (
                ((S0[r >> 24] + S1[(r >> 16) & 0xFF]) ^ S2[(r >> 8) & 0xFF])
                + S3[r & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p8
        # Feistel substitution on left word (round 8)
        r ^= (
            (
                ((S0[l >> 24] + S1[(l >> 16) & 0xFF]) ^ S2[(l >> 8) & 0xFF])
                + S3[l & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p9

        # Feistel substitution on right word (round 9)
        l ^= (
            (
                ((S0[r >> 24] + S1[(r >> 16) & 0xFF]) ^ S2[(r >> 8) & 0xFF])
                + S3[r & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p10
        # Feistel substitution on left word (round 10)
        r ^= (
            (
                ((S0[l >> 24] + S1[(l >> 16) & 0xFF]) ^ S2[(l >> 8) & 0xFF])
                + S3[l & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p11

        # Feistel substitution on right word (round 11)
        l ^= (
            (
                ((S0[r >> 24] + S1[(r >> 16) & 0xFF]) ^ S2[(r >> 8) & 0xFF])
                + S3[r & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p12
        # Feistel substitution on left word (round 12)
        r ^= (
            (
                ((S0[l >> 24] + S1[(l >> 16) & 0xFF]) ^ S2[(l >> 8) & 0xFF])
                + S3[l & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p13

        # Feistel substitution on right word (round 13)
        l ^= (
            (
                ((S0[r >> 24] + S1[(r >> 16) & 0xFF]) ^ S2[(r >> 8) & 0xFF])
                + S3[r & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p14
        # Feistel substitution on left word (round 14)
        r ^= (
            (
                ((S0[l >> 24] + S1[(l >> 16) & 0xFF]) ^ S2[(l >> 8) & 0xFF])
                + S3[l & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p15

        # Feistel substitution on right word (round 15)
        l ^= (
            (
                ((S0[r >> 24] + S1[(r >> 16) & 0xFF]) ^ S2[(r >> 8) & 0xFF])
                + S3[r & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p16

        return r ^ p17, l

    def expand(self, key_words):
        """unrolled version of blowfish key expansion"""
        ##assert len(key_words) >= 18, "size of key_words must be >= 18"

        P, S = self.P, self.S
        S0, S1, S2, S3 = S
        p0 = P[0] ^ key_words[0]
        p1 = P[1] ^ key_words[1]
        p2 = P[2] ^ key_words[2]
        p3 = P[3] ^ key_words[3]
        p4 = P[4] ^ key_words[4]
        p5 = P[5] ^ key_words[5]
        p6 = P[6] ^ key_words[6]
        p7 = P[7] ^ key_words[7]
        p8 = P[8] ^ key_words[8]
        p9 = P[9] ^ key_words[9]
        p10 = P[10] ^ key_words[10]
        p11 = P[11] ^ key_words[11]
        p12 = P[12] ^ key_words[12]
        p13 = P[13] ^ key_words[13]
        p14 = P[14] ^ key_words[14]
        p15 = P[15] ^ key_words[15]
        p16 = P[16] ^ key_words[16]
        p17 = P[17] ^ key_words[17]

        # ------------------------------------------------
        # update P[0] and P[1]
        # ------------------------------------------------
        l, r = p0, 0

        # Feistel substitution on left word (round 0)
        r ^= (
            (
                ((S0[l >> 24] + S1[(l >> 16) & 0xFF]) ^ S2[(l >> 8) & 0xFF])
                + S3[l & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p1

        # Feistel substitution on right word (round 1)
        l ^= (
            (
                ((S0[r >> 24] + S1[(r >> 16) & 0xFF]) ^ S2[(r >> 8) & 0xFF])
                + S3[r & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p2
        # Feistel substitution on left word (round 2)
        r ^= (
            (
                ((S0[l >> 24] + S1[(l >> 16) & 0xFF]) ^ S2[(l >> 8) & 0xFF])
                + S3[l & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p3

        # Feistel substitution on right word (round 3)
        l ^= (
            (
                ((S0[r >> 24] + S1[(r >> 16) & 0xFF]) ^ S2[(r >> 8) & 0xFF])
                + S3[r & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p4
        # Feistel substitution on left word (round 4)
        r ^= (
            (
                ((S0[l >> 24] + S1[(l >> 16) & 0xFF]) ^ S2[(l >> 8) & 0xFF])
                + S3[l & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p5

        # Feistel substitution on right word (round 5)
        l ^= (
            (
                ((S0[r >> 24] + S1[(r >> 16) & 0xFF]) ^ S2[(r >> 8) & 0xFF])
                + S3[r & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p6
        # Feistel substitution on left word (round 6)
        r ^= (
            (
                ((S0[l >> 24] + S1[(l >> 16) & 0xFF]) ^ S2[(l >> 8) & 0xFF])
                + S3[l & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p7

        # Feistel substitution on right word (round 7)
        l ^= (
            (
                ((S0[r >> 24] + S1[(r >> 16) & 0xFF]) ^ S2[(r >> 8) & 0xFF])
                + S3[r & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p8
        # Feistel substitution on left word (round 8)
        r ^= (
            (
                ((S0[l >> 24] + S1[(l >> 16) & 0xFF]) ^ S2[(l >> 8) & 0xFF])
                + S3[l & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p9

        # Feistel substitution on right word (round 9)
        l ^= (
            (
                ((S0[r >> 24] + S1[(r >> 16) & 0xFF]) ^ S2[(r >> 8) & 0xFF])
                + S3[r & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p10
        # Feistel substitution on left word (round 10)
        r ^= (
            (
                ((S0[l >> 24] + S1[(l >> 16) & 0xFF]) ^ S2[(l >> 8) & 0xFF])
                + S3[l & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p11

        # Feistel substitution on right word (round 11)
        l ^= (
            (
                ((S0[r >> 24] + S1[(r >> 16) & 0xFF]) ^ S2[(r >> 8) & 0xFF])
                + S3[r & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p12
        # Feistel substitution on left word (round 12)
        r ^= (
            (
                ((S0[l >> 24] + S1[(l >> 16) & 0xFF]) ^ S2[(l >> 8) & 0xFF])
                + S3[l & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p13

        # Feistel substitution on right word (round 13)
        l ^= (
            (
                ((S0[r >> 24] + S1[(r >> 16) & 0xFF]) ^ S2[(r >> 8) & 0xFF])
                + S3[r & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p14
        # Feistel substitution on left word (round 14)
        r ^= (
            (
                ((S0[l >> 24] + S1[(l >> 16) & 0xFF]) ^ S2[(l >> 8) & 0xFF])
                + S3[l & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p15

        # Feistel substitution on right word (round 15)
        l ^= (
            (
                ((S0[r >> 24] + S1[(r >> 16) & 0xFF]) ^ S2[(r >> 8) & 0xFF])
                + S3[r & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p16

        p0, p1 = l, r = r ^ p17, l

        # ------------------------------------------------
        # update P[2] and P[3]
        # ------------------------------------------------
        l ^= p0

        # Feistel substitution on left word (round 0)
        r ^= (
            (
                ((S0[l >> 24] + S1[(l >> 16) & 0xFF]) ^ S2[(l >> 8) & 0xFF])
                + S3[l & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p1

        # Feistel substitution on right word (round 1)
        l ^= (
            (
                ((S0[r >> 24] + S1[(r >> 16) & 0xFF]) ^ S2[(r >> 8) & 0xFF])
                + S3[r & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p2
        # Feistel substitution on left word (round 2)
        r ^= (
            (
                ((S0[l >> 24] + S1[(l >> 16) & 0xFF]) ^ S2[(l >> 8) & 0xFF])
                + S3[l & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p3

        # Feistel substitution on right word (round 3)
        l ^= (
            (
                ((S0[r >> 24] + S1[(r >> 16) & 0xFF]) ^ S2[(r >> 8) & 0xFF])
                + S3[r & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p4
        # Feistel substitution on left word (round 4)
        r ^= (
            (
                ((S0[l >> 24] + S1[(l >> 16) & 0xFF]) ^ S2[(l >> 8) & 0xFF])
                + S3[l & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p5

        # Feistel substitution on right word (round 5)
        l ^= (
            (
                ((S0[r >> 24] + S1[(r >> 16) & 0xFF]) ^ S2[(r >> 8) & 0xFF])
                + S3[r & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p6
        # Feistel substitution on left word (round 6)
        r ^= (
            (
                ((S0[l >> 24] + S1[(l >> 16) & 0xFF]) ^ S2[(l >> 8) & 0xFF])
                + S3[l & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p7

        # Feistel substitution on right word (round 7)
        l ^= (
            (
                ((S0[r >> 24] + S1[(r >> 16) & 0xFF]) ^ S2[(r >> 8) & 0xFF])
                + S3[r & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p8
        # Feistel substitution on left word (round 8)
        r ^= (
            (
                ((S0[l >> 24] + S1[(l >> 16) & 0xFF]) ^ S2[(l >> 8) & 0xFF])
                + S3[l & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p9

        # Feistel substitution on right word (round 9)
        l ^= (
            (
                ((S0[r >> 24] + S1[(r >> 16) & 0xFF]) ^ S2[(r >> 8) & 0xFF])
                + S3[r & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p10
        # Feistel substitution on left word (round 10)
        r ^= (
            (
                ((S0[l >> 24] + S1[(l >> 16) & 0xFF]) ^ S2[(l >> 8) & 0xFF])
                + S3[l & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p11

        # Feistel substitution on right word (round 11)
        l ^= (
            (
                ((S0[r >> 24] + S1[(r >> 16) & 0xFF]) ^ S2[(r >> 8) & 0xFF])
                + S3[r & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p12
        # Feistel substitution on left word (round 12)
        r ^= (
            (
                ((S0[l >> 24] + S1[(l >> 16) & 0xFF]) ^ S2[(l >> 8) & 0xFF])
                + S3[l & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p13

        # Feistel substitution on right word (round 13)
        l ^= (
            (
                ((S0[r >> 24] + S1[(r >> 16) & 0xFF]) ^ S2[(r >> 8) & 0xFF])
                + S3[r & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p14
        # Feistel substitution on left word (round 14)
        r ^= (
            (
                ((S0[l >> 24] + S1[(l >> 16) & 0xFF]) ^ S2[(l >> 8) & 0xFF])
                + S3[l & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p15

        # Feistel substitution on right word (round 15)
        l ^= (
            (
                ((S0[r >> 24] + S1[(r >> 16) & 0xFF]) ^ S2[(r >> 8) & 0xFF])
                + S3[r & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p16
        p2, p3 = l, r = r ^ p17, l

        # ------------------------------------------------
        # update P[4] and P[5]
        # ------------------------------------------------
        l ^= p0

        # Feistel substitution on left word (round 0)
        r ^= (
            (
                ((S0[l >> 24] + S1[(l >> 16) & 0xFF]) ^ S2[(l >> 8) & 0xFF])
                + S3[l & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p1

        # Feistel substitution on right word (round 1)
        l ^= (
            (
                ((S0[r >> 24] + S1[(r >> 16) & 0xFF]) ^ S2[(r >> 8) & 0xFF])
                + S3[r & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p2
        # Feistel substitution on left word (round 2)
        r ^= (
            (
                ((S0[l >> 24] + S1[(l >> 16) & 0xFF]) ^ S2[(l >> 8) & 0xFF])
                + S3[l & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p3

        # Feistel substitution on right word (round 3)
        l ^= (
            (
                ((S0[r >> 24] + S1[(r >> 16) & 0xFF]) ^ S2[(r >> 8) & 0xFF])
                + S3[r & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p4
        # Feistel substitution on left word (round 4)
        r ^= (
            (
                ((S0[l >> 24] + S1[(l >> 16) & 0xFF]) ^ S2[(l >> 8) & 0xFF])
                + S3[l & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p5

        # Feistel substitution on right word (round 5)
        l ^= (
            (
                ((S0[r >> 24] + S1[(r >> 16) & 0xFF]) ^ S2[(r >> 8) & 0xFF])
                + S3[r & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p6
        # Feistel substitution on left word (round 6)
        r ^= (
            (
                ((S0[l >> 24] + S1[(l >> 16) & 0xFF]) ^ S2[(l >> 8) & 0xFF])
                + S3[l & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p7

        # Feistel substitution on right word (round 7)
        l ^= (
            (
                ((S0[r >> 24] + S1[(r >> 16) & 0xFF]) ^ S2[(r >> 8) & 0xFF])
                + S3[r & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p8
        # Feistel substitution on left word (round 8)
        r ^= (
            (
                ((S0[l >> 24] + S1[(l >> 16) & 0xFF]) ^ S2[(l >> 8) & 0xFF])
                + S3[l & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p9

        # Feistel substitution on right word (round 9)
        l ^= (
            (
                ((S0[r >> 24] + S1[(r >> 16) & 0xFF]) ^ S2[(r >> 8) & 0xFF])
                + S3[r & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p10
        # Feistel substitution on left word (round 10)
        r ^= (
            (
                ((S0[l >> 24] + S1[(l >> 16) & 0xFF]) ^ S2[(l >> 8) & 0xFF])
                + S3[l & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p11

        # Feistel substitution on right word (round 11)
        l ^= (
            (
                ((S0[r >> 24] + S1[(r >> 16) & 0xFF]) ^ S2[(r >> 8) & 0xFF])
                + S3[r & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p12
        # Feistel substitution on left word (round 12)
        r ^= (
            (
                ((S0[l >> 24] + S1[(l >> 16) & 0xFF]) ^ S2[(l >> 8) & 0xFF])
                + S3[l & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p13

        # Feistel substitution on right word (round 13)
        l ^= (
            (
                ((S0[r >> 24] + S1[(r >> 16) & 0xFF]) ^ S2[(r >> 8) & 0xFF])
                + S3[r & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p14
        # Feistel substitution on left word (round 14)
        r ^= (
            (
                ((S0[l >> 24] + S1[(l >> 16) & 0xFF]) ^ S2[(l >> 8) & 0xFF])
                + S3[l & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p15

        # Feistel substitution on right word (round 15)
        l ^= (
            (
                ((S0[r >> 24] + S1[(r >> 16) & 0xFF]) ^ S2[(r >> 8) & 0xFF])
                + S3[r & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p16
        p4, p5 = l, r = r ^ p17, l

        # ------------------------------------------------
        # update P[6] and P[7]
        # ------------------------------------------------
        l ^= p0

        # Feistel substitution on left word (round 0)
        r ^= (
            (
                ((S0[l >> 24] + S1[(l >> 16) & 0xFF]) ^ S2[(l >> 8) & 0xFF])
                + S3[l & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p1

        # Feistel substitution on right word (round 1)
        l ^= (
            (
                ((S0[r >> 24] + S1[(r >> 16) & 0xFF]) ^ S2[(r >> 8) & 0xFF])
                + S3[r & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p2
        # Feistel substitution on left word (round 2)
        r ^= (
            (
                ((S0[l >> 24] + S1[(l >> 16) & 0xFF]) ^ S2[(l >> 8) & 0xFF])
                + S3[l & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p3

        # Feistel substitution on right word (round 3)
        l ^= (
            (
                ((S0[r >> 24] + S1[(r >> 16) & 0xFF]) ^ S2[(r >> 8) & 0xFF])
                + S3[r & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p4
        # Feistel substitution on left word (round 4)
        r ^= (
            (
                ((S0[l >> 24] + S1[(l >> 16) & 0xFF]) ^ S2[(l >> 8) & 0xFF])
                + S3[l & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p5

        # Feistel substitution on right word (round 5)
        l ^= (
            (
                ((S0[r >> 24] + S1[(r >> 16) & 0xFF]) ^ S2[(r >> 8) & 0xFF])
                + S3[r & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p6
        # Feistel substitution on left word (round 6)
        r ^= (
            (
                ((S0[l >> 24] + S1[(l >> 16) & 0xFF]) ^ S2[(l >> 8) & 0xFF])
                + S3[l & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p7

        # Feistel substitution on right word (round 7)
        l ^= (
            (
                ((S0[r >> 24] + S1[(r >> 16) & 0xFF]) ^ S2[(r >> 8) & 0xFF])
                + S3[r & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p8
        # Feistel substitution on left word (round 8)
        r ^= (
            (
                ((S0[l >> 24] + S1[(l >> 16) & 0xFF]) ^ S2[(l >> 8) & 0xFF])
                + S3[l & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p9

        # Feistel substitution on right word (round 9)
        l ^= (
            (
                ((S0[r >> 24] + S1[(r >> 16) & 0xFF]) ^ S2[(r >> 8) & 0xFF])
                + S3[r & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p10
        # Feistel substitution on left word (round 10)
        r ^= (
            (
                ((S0[l >> 24] + S1[(l >> 16) & 0xFF]) ^ S2[(l >> 8) & 0xFF])
                + S3[l & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p11

        # Feistel substitution on right word (round 11)
        l ^= (
            (
                ((S0[r >> 24] + S1[(r >> 16) & 0xFF]) ^ S2[(r >> 8) & 0xFF])
                + S3[r & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p12
        # Feistel substitution on left word (round 12)
        r ^= (
            (
                ((S0[l >> 24] + S1[(l >> 16) & 0xFF]) ^ S2[(l >> 8) & 0xFF])
                + S3[l & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p13

        # Feistel substitution on right word (round 13)
        l ^= (
            (
                ((S0[r >> 24] + S1[(r >> 16) & 0xFF]) ^ S2[(r >> 8) & 0xFF])
                + S3[r & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p14
        # Feistel substitution on left word (round 14)
        r ^= (
            (
                ((S0[l >> 24] + S1[(l >> 16) & 0xFF]) ^ S2[(l >> 8) & 0xFF])
                + S3[l & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p15

        # Feistel substitution on right word (round 15)
        l ^= (
            (
                ((S0[r >> 24] + S1[(r >> 16) & 0xFF]) ^ S2[(r >> 8) & 0xFF])
                + S3[r & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p16
        p6, p7 = l, r = r ^ p17, l

        # ------------------------------------------------
        # update P[8] and P[9]
        # ------------------------------------------------
        l ^= p0

        # Feistel substitution on left word (round 0)
        r ^= (
            (
                ((S0[l >> 24] + S1[(l >> 16) & 0xFF]) ^ S2[(l >> 8) & 0xFF])
                + S3[l & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p1

        # Feistel substitution on right word (round 1)
        l ^= (
            (
                ((S0[r >> 24] + S1[(r >> 16) & 0xFF]) ^ S2[(r >> 8) & 0xFF])
                + S3[r & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p2
        # Feistel substitution on left word (round 2)
        r ^= (
            (
                ((S0[l >> 24] + S1[(l >> 16) & 0xFF]) ^ S2[(l >> 8) & 0xFF])
                + S3[l & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p3

        # Feistel substitution on right word (round 3)
        l ^= (
            (
                ((S0[r >> 24] + S1[(r >> 16) & 0xFF]) ^ S2[(r >> 8) & 0xFF])
                + S3[r & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p4
        # Feistel substitution on left word (round 4)
        r ^= (
            (
                ((S0[l >> 24] + S1[(l >> 16) & 0xFF]) ^ S2[(l >> 8) & 0xFF])
                + S3[l & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p5

        # Feistel substitution on right word (round 5)
        l ^= (
            (
                ((S0[r >> 24] + S1[(r >> 16) & 0xFF]) ^ S2[(r >> 8) & 0xFF])
                + S3[r & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p6
        # Feistel substitution on left word (round 6)
        r ^= (
            (
                ((S0[l >> 24] + S1[(l >> 16) & 0xFF]) ^ S2[(l >> 8) & 0xFF])
                + S3[l & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p7

        # Feistel substitution on right word (round 7)
        l ^= (
            (
                ((S0[r >> 24] + S1[(r >> 16) & 0xFF]) ^ S2[(r >> 8) & 0xFF])
                + S3[r & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p8
        # Feistel substitution on left word (round 8)
        r ^= (
            (
                ((S0[l >> 24] + S1[(l >> 16) & 0xFF]) ^ S2[(l >> 8) & 0xFF])
                + S3[l & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p9

        # Feistel substitution on right word (round 9)
        l ^= (
            (
                ((S0[r >> 24] + S1[(r >> 16) & 0xFF]) ^ S2[(r >> 8) & 0xFF])
                + S3[r & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p10
        # Feistel substitution on left word (round 10)
        r ^= (
            (
                ((S0[l >> 24] + S1[(l >> 16) & 0xFF]) ^ S2[(l >> 8) & 0xFF])
                + S3[l & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p11

        # Feistel substitution on right word (round 11)
        l ^= (
            (
                ((S0[r >> 24] + S1[(r >> 16) & 0xFF]) ^ S2[(r >> 8) & 0xFF])
                + S3[r & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p12
        # Feistel substitution on left word (round 12)
        r ^= (
            (
                ((S0[l >> 24] + S1[(l >> 16) & 0xFF]) ^ S2[(l >> 8) & 0xFF])
                + S3[l & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p13

        # Feistel substitution on right word (round 13)
        l ^= (
            (
                ((S0[r >> 24] + S1[(r >> 16) & 0xFF]) ^ S2[(r >> 8) & 0xFF])
                + S3[r & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p14
        # Feistel substitution on left word (round 14)
        r ^= (
            (
                ((S0[l >> 24] + S1[(l >> 16) & 0xFF]) ^ S2[(l >> 8) & 0xFF])
                + S3[l & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p15

        # Feistel substitution on right word (round 15)
        l ^= (
            (
                ((S0[r >> 24] + S1[(r >> 16) & 0xFF]) ^ S2[(r >> 8) & 0xFF])
                + S3[r & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p16
        p8, p9 = l, r = r ^ p17, l

        # ------------------------------------------------
        # update P[10] and P[11]
        # ------------------------------------------------
        l ^= p0

        # Feistel substitution on left word (round 0)
        r ^= (
            (
                ((S0[l >> 24] + S1[(l >> 16) & 0xFF]) ^ S2[(l >> 8) & 0xFF])
                + S3[l & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p1

        # Feistel substitution on right word (round 1)
        l ^= (
            (
                ((S0[r >> 24] + S1[(r >> 16) & 0xFF]) ^ S2[(r >> 8) & 0xFF])
                + S3[r & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p2
        # Feistel substitution on left word (round 2)
        r ^= (
            (
                ((S0[l >> 24] + S1[(l >> 16) & 0xFF]) ^ S2[(l >> 8) & 0xFF])
                + S3[l & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p3

        # Feistel substitution on right word (round 3)
        l ^= (
            (
                ((S0[r >> 24] + S1[(r >> 16) & 0xFF]) ^ S2[(r >> 8) & 0xFF])
                + S3[r & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p4
        # Feistel substitution on left word (round 4)
        r ^= (
            (
                ((S0[l >> 24] + S1[(l >> 16) & 0xFF]) ^ S2[(l >> 8) & 0xFF])
                + S3[l & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p5

        # Feistel substitution on right word (round 5)
        l ^= (
            (
                ((S0[r >> 24] + S1[(r >> 16) & 0xFF]) ^ S2[(r >> 8) & 0xFF])
                + S3[r & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p6
        # Feistel substitution on left word (round 6)
        r ^= (
            (
                ((S0[l >> 24] + S1[(l >> 16) & 0xFF]) ^ S2[(l >> 8) & 0xFF])
                + S3[l & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p7

        # Feistel substitution on right word (round 7)
        l ^= (
            (
                ((S0[r >> 24] + S1[(r >> 16) & 0xFF]) ^ S2[(r >> 8) & 0xFF])
                + S3[r & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p8
        # Feistel substitution on left word (round 8)
        r ^= (
            (
                ((S0[l >> 24] + S1[(l >> 16) & 0xFF]) ^ S2[(l >> 8) & 0xFF])
                + S3[l & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p9

        # Feistel substitution on right word (round 9)
        l ^= (
            (
                ((S0[r >> 24] + S1[(r >> 16) & 0xFF]) ^ S2[(r >> 8) & 0xFF])
                + S3[r & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p10
        # Feistel substitution on left word (round 10)
        r ^= (
            (
                ((S0[l >> 24] + S1[(l >> 16) & 0xFF]) ^ S2[(l >> 8) & 0xFF])
                + S3[l & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p11

        # Feistel substitution on right word (round 11)
        l ^= (
            (
                ((S0[r >> 24] + S1[(r >> 16) & 0xFF]) ^ S2[(r >> 8) & 0xFF])
                + S3[r & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p12
        # Feistel substitution on left word (round 12)
        r ^= (
            (
                ((S0[l >> 24] + S1[(l >> 16) & 0xFF]) ^ S2[(l >> 8) & 0xFF])
                + S3[l & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p13

        # Feistel substitution on right word (round 13)
        l ^= (
            (
                ((S0[r >> 24] + S1[(r >> 16) & 0xFF]) ^ S2[(r >> 8) & 0xFF])
                + S3[r & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p14
        # Feistel substitution on left word (round 14)
        r ^= (
            (
                ((S0[l >> 24] + S1[(l >> 16) & 0xFF]) ^ S2[(l >> 8) & 0xFF])
                + S3[l & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p15

        # Feistel substitution on right word (round 15)
        l ^= (
            (
                ((S0[r >> 24] + S1[(r >> 16) & 0xFF]) ^ S2[(r >> 8) & 0xFF])
                + S3[r & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p16
        p10, p11 = l, r = r ^ p17, l

        # ------------------------------------------------
        # update P[12] and P[13]
        # ------------------------------------------------
        l ^= p0

        # Feistel substitution on left word (round 0)
        r ^= (
            (
                ((S0[l >> 24] + S1[(l >> 16) & 0xFF]) ^ S2[(l >> 8) & 0xFF])
                + S3[l & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p1

        # Feistel substitution on right word (round 1)
        l ^= (
            (
                ((S0[r >> 24] + S1[(r >> 16) & 0xFF]) ^ S2[(r >> 8) & 0xFF])
                + S3[r & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p2
        # Feistel substitution on left word (round 2)
        r ^= (
            (
                ((S0[l >> 24] + S1[(l >> 16) & 0xFF]) ^ S2[(l >> 8) & 0xFF])
                + S3[l & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p3

        # Feistel substitution on right word (round 3)
        l ^= (
            (
                ((S0[r >> 24] + S1[(r >> 16) & 0xFF]) ^ S2[(r >> 8) & 0xFF])
                + S3[r & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p4
        # Feistel substitution on left word (round 4)
        r ^= (
            (
                ((S0[l >> 24] + S1[(l >> 16) & 0xFF]) ^ S2[(l >> 8) & 0xFF])
                + S3[l & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p5

        # Feistel substitution on right word (round 5)
        l ^= (
            (
                ((S0[r >> 24] + S1[(r >> 16) & 0xFF]) ^ S2[(r >> 8) & 0xFF])
                + S3[r & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p6
        # Feistel substitution on left word (round 6)
        r ^= (
            (
                ((S0[l >> 24] + S1[(l >> 16) & 0xFF]) ^ S2[(l >> 8) & 0xFF])
                + S3[l & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p7

        # Feistel substitution on right word (round 7)
        l ^= (
            (
                ((S0[r >> 24] + S1[(r >> 16) & 0xFF]) ^ S2[(r >> 8) & 0xFF])
                + S3[r & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p8
        # Feistel substitution on left word (round 8)
        r ^= (
            (
                ((S0[l >> 24] + S1[(l >> 16) & 0xFF]) ^ S2[(l >> 8) & 0xFF])
                + S3[l & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p9

        # Feistel substitution on right word (round 9)
        l ^= (
            (
                ((S0[r >> 24] + S1[(r >> 16) & 0xFF]) ^ S2[(r >> 8) & 0xFF])
                + S3[r & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p10
        # Feistel substitution on left word (round 10)
        r ^= (
            (
                ((S0[l >> 24] + S1[(l >> 16) & 0xFF]) ^ S2[(l >> 8) & 0xFF])
                + S3[l & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p11

        # Feistel substitution on right word (round 11)
        l ^= (
            (
                ((S0[r >> 24] + S1[(r >> 16) & 0xFF]) ^ S2[(r >> 8) & 0xFF])
                + S3[r & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p12
        # Feistel substitution on left word (round 12)
        r ^= (
            (
                ((S0[l >> 24] + S1[(l >> 16) & 0xFF]) ^ S2[(l >> 8) & 0xFF])
                + S3[l & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p13

        # Feistel substitution on right word (round 13)
        l ^= (
            (
                ((S0[r >> 24] + S1[(r >> 16) & 0xFF]) ^ S2[(r >> 8) & 0xFF])
                + S3[r & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p14
        # Feistel substitution on left word (round 14)
        r ^= (
            (
                ((S0[l >> 24] + S1[(l >> 16) & 0xFF]) ^ S2[(l >> 8) & 0xFF])
                + S3[l & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p15

        # Feistel substitution on right word (round 15)
        l ^= (
            (
                ((S0[r >> 24] + S1[(r >> 16) & 0xFF]) ^ S2[(r >> 8) & 0xFF])
                + S3[r & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p16
        p12, p13 = l, r = r ^ p17, l

        # ------------------------------------------------
        # update P[14] and P[15]
        # ------------------------------------------------
        l ^= p0

        # Feistel substitution on left word (round 0)
        r ^= (
            (
                ((S0[l >> 24] + S1[(l >> 16) & 0xFF]) ^ S2[(l >> 8) & 0xFF])
                + S3[l & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p1

        # Feistel substitution on right word (round 1)
        l ^= (
            (
                ((S0[r >> 24] + S1[(r >> 16) & 0xFF]) ^ S2[(r >> 8) & 0xFF])
                + S3[r & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p2
        # Feistel substitution on left word (round 2)
        r ^= (
            (
                ((S0[l >> 24] + S1[(l >> 16) & 0xFF]) ^ S2[(l >> 8) & 0xFF])
                + S3[l & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p3

        # Feistel substitution on right word (round 3)
        l ^= (
            (
                ((S0[r >> 24] + S1[(r >> 16) & 0xFF]) ^ S2[(r >> 8) & 0xFF])
                + S3[r & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p4
        # Feistel substitution on left word (round 4)
        r ^= (
            (
                ((S0[l >> 24] + S1[(l >> 16) & 0xFF]) ^ S2[(l >> 8) & 0xFF])
                + S3[l & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p5

        # Feistel substitution on right word (round 5)
        l ^= (
            (
                ((S0[r >> 24] + S1[(r >> 16) & 0xFF]) ^ S2[(r >> 8) & 0xFF])
                + S3[r & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p6
        # Feistel substitution on left word (round 6)
        r ^= (
            (
                ((S0[l >> 24] + S1[(l >> 16) & 0xFF]) ^ S2[(l >> 8) & 0xFF])
                + S3[l & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p7

        # Feistel substitution on right word (round 7)
        l ^= (
            (
                ((S0[r >> 24] + S1[(r >> 16) & 0xFF]) ^ S2[(r >> 8) & 0xFF])
                + S3[r & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p8
        # Feistel substitution on left word (round 8)
        r ^= (
            (
                ((S0[l >> 24] + S1[(l >> 16) & 0xFF]) ^ S2[(l >> 8) & 0xFF])
                + S3[l & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p9

        # Feistel substitution on right word (round 9)
        l ^= (
            (
                ((S0[r >> 24] + S1[(r >> 16) & 0xFF]) ^ S2[(r >> 8) & 0xFF])
                + S3[r & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p10
        # Feistel substitution on left word (round 10)
        r ^= (
            (
                ((S0[l >> 24] + S1[(l >> 16) & 0xFF]) ^ S2[(l >> 8) & 0xFF])
                + S3[l & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p11

        # Feistel substitution on right word (round 11)
        l ^= (
            (
                ((S0[r >> 24] + S1[(r >> 16) & 0xFF]) ^ S2[(r >> 8) & 0xFF])
                + S3[r & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p12
        # Feistel substitution on left word (round 12)
        r ^= (
            (
                ((S0[l >> 24] + S1[(l >> 16) & 0xFF]) ^ S2[(l >> 8) & 0xFF])
                + S3[l & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p13

        # Feistel substitution on right word (round 13)
        l ^= (
            (
                ((S0[r >> 24] + S1[(r >> 16) & 0xFF]) ^ S2[(r >> 8) & 0xFF])
                + S3[r & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p14
        # Feistel substitution on left word (round 14)
        r ^= (
            (
                ((S0[l >> 24] + S1[(l >> 16) & 0xFF]) ^ S2[(l >> 8) & 0xFF])
                + S3[l & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p15

        # Feistel substitution on right word (round 15)
        l ^= (
            (
                ((S0[r >> 24] + S1[(r >> 16) & 0xFF]) ^ S2[(r >> 8) & 0xFF])
                + S3[r & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p16
        p14, p15 = l, r = r ^ p17, l

        # ------------------------------------------------
        # update P[16] and P[17]
        # ------------------------------------------------
        l ^= p0

        # Feistel substitution on left word (round 0)
        r ^= (
            (
                ((S0[l >> 24] + S1[(l >> 16) & 0xFF]) ^ S2[(l >> 8) & 0xFF])
                + S3[l & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p1

        # Feistel substitution on right word (round 1)
        l ^= (
            (
                ((S0[r >> 24] + S1[(r >> 16) & 0xFF]) ^ S2[(r >> 8) & 0xFF])
                + S3[r & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p2
        # Feistel substitution on left word (round 2)
        r ^= (
            (
                ((S0[l >> 24] + S1[(l >> 16) & 0xFF]) ^ S2[(l >> 8) & 0xFF])
                + S3[l & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p3

        # Feistel substitution on right word (round 3)
        l ^= (
            (
                ((S0[r >> 24] + S1[(r >> 16) & 0xFF]) ^ S2[(r >> 8) & 0xFF])
                + S3[r & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p4
        # Feistel substitution on left word (round 4)
        r ^= (
            (
                ((S0[l >> 24] + S1[(l >> 16) & 0xFF]) ^ S2[(l >> 8) & 0xFF])
                + S3[l & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p5

        # Feistel substitution on right word (round 5)
        l ^= (
            (
                ((S0[r >> 24] + S1[(r >> 16) & 0xFF]) ^ S2[(r >> 8) & 0xFF])
                + S3[r & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p6
        # Feistel substitution on left word (round 6)
        r ^= (
            (
                ((S0[l >> 24] + S1[(l >> 16) & 0xFF]) ^ S2[(l >> 8) & 0xFF])
                + S3[l & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p7

        # Feistel substitution on right word (round 7)
        l ^= (
            (
                ((S0[r >> 24] + S1[(r >> 16) & 0xFF]) ^ S2[(r >> 8) & 0xFF])
                + S3[r & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p8
        # Feistel substitution on left word (round 8)
        r ^= (
            (
                ((S0[l >> 24] + S1[(l >> 16) & 0xFF]) ^ S2[(l >> 8) & 0xFF])
                + S3[l & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p9

        # Feistel substitution on right word (round 9)
        l ^= (
            (
                ((S0[r >> 24] + S1[(r >> 16) & 0xFF]) ^ S2[(r >> 8) & 0xFF])
                + S3[r & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p10
        # Feistel substitution on left word (round 10)
        r ^= (
            (
                ((S0[l >> 24] + S1[(l >> 16) & 0xFF]) ^ S2[(l >> 8) & 0xFF])
                + S3[l & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p11

        # Feistel substitution on right word (round 11)
        l ^= (
            (
                ((S0[r >> 24] + S1[(r >> 16) & 0xFF]) ^ S2[(r >> 8) & 0xFF])
                + S3[r & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p12
        # Feistel substitution on left word (round 12)
        r ^= (
            (
                ((S0[l >> 24] + S1[(l >> 16) & 0xFF]) ^ S2[(l >> 8) & 0xFF])
                + S3[l & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p13

        # Feistel substitution on right word (round 13)
        l ^= (
            (
                ((S0[r >> 24] + S1[(r >> 16) & 0xFF]) ^ S2[(r >> 8) & 0xFF])
                + S3[r & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p14
        # Feistel substitution on left word (round 14)
        r ^= (
            (
                ((S0[l >> 24] + S1[(l >> 16) & 0xFF]) ^ S2[(l >> 8) & 0xFF])
                + S3[l & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p15

        # Feistel substitution on right word (round 15)
        l ^= (
            (
                ((S0[r >> 24] + S1[(r >> 16) & 0xFF]) ^ S2[(r >> 8) & 0xFF])
                + S3[r & 0xFF]
            )
            & 0xFFFFFFFF
        ) ^ p16
        p16, p17 = l, r = r ^ p17, l

        # ------------------------------------------------
        # save changes to original P array
        # ------------------------------------------------
        P[:] = (
            p0,
            p1,
            p2,
            p3,
            p4,
            p5,
            p6,
            p7,
            p8,
            p9,
            p10,
            p11,
            p12,
            p13,
            p14,
            p15,
            p16,
            p17,
        )

        for box in S:
            j = 0
            while j < 256:
                l ^= p0

                # Feistel substitution on left word (round 0)
                r ^= (
                    (
                        ((S0[l >> 24] + S1[(l >> 16) & 0xFF]) ^ S2[(l >> 8) & 0xFF])
                        + S3[l & 0xFF]
                    )
                    & 0xFFFFFFFF
                ) ^ p1

                # Feistel substitution on right word (round 1)
                l ^= (
                    (
                        ((S0[r >> 24] + S1[(r >> 16) & 0xFF]) ^ S2[(r >> 8) & 0xFF])
                        + S3[r & 0xFF]
                    )
                    & 0xFFFFFFFF
                ) ^ p2
                # Feistel substitution on left word (round 2)
                r ^= (
                    (
                        ((S0[l >> 24] + S1[(l >> 16) & 0xFF]) ^ S2[(l >> 8) & 0xFF])
                        + S3[l & 0xFF]
                    )
                    & 0xFFFFFFFF
                ) ^ p3

                # Feistel substitution on right word (round 3)
                l ^= (
                    (
                        ((S0[r >> 24] + S1[(r >> 16) & 0xFF]) ^ S2[(r >> 8) & 0xFF])
                        + S3[r & 0xFF]
                    )
                    & 0xFFFFFFFF
                ) ^ p4
                # Feistel substitution on left word (round 4)
                r ^= (
                    (
                        ((S0[l >> 24] + S1[(l >> 16) & 0xFF]) ^ S2[(l >> 8) & 0xFF])
                        + S3[l & 0xFF]
                    )
                    & 0xFFFFFFFF
                ) ^ p5

                # Feistel substitution on right word (round 5)
                l ^= (
                    (
                        ((S0[r >> 24] + S1[(r >> 16) & 0xFF]) ^ S2[(r >> 8) & 0xFF])
                        + S3[r & 0xFF]
                    )
                    & 0xFFFFFFFF
                ) ^ p6
                # Feistel substitution on left word (round 6)
                r ^= (
                    (
                        ((S0[l >> 24] + S1[(l >> 16) & 0xFF]) ^ S2[(l >> 8) & 0xFF])
                        + S3[l & 0xFF]
                    )
                    & 0xFFFFFFFF
                ) ^ p7

                # Feistel substitution on right word (round 7)
                l ^= (
                    (
                        ((S0[r >> 24] + S1[(r >> 16) & 0xFF]) ^ S2[(r >> 8) & 0xFF])
                        + S3[r & 0xFF]
                    )
                    & 0xFFFFFFFF
                ) ^ p8
                # Feistel substitution on left word (round 8)
                r ^= (
                    (
                        ((S0[l >> 24] + S1[(l >> 16) & 0xFF]) ^ S2[(l >> 8) & 0xFF])
                        + S3[l & 0xFF]
                    )
                    & 0xFFFFFFFF
                ) ^ p9

                # Feistel substitution on right word (round 9)
                l ^= (
                    (
                        ((S0[r >> 24] + S1[(r >> 16) & 0xFF]) ^ S2[(r >> 8) & 0xFF])
                        + S3[r & 0xFF]
                    )
                    & 0xFFFFFFFF
                ) ^ p10
                # Feistel substitution on left word (round 10)
                r ^= (
                    (
                        ((S0[l >> 24] + S1[(l >> 16) & 0xFF]) ^ S2[(l >> 8) & 0xFF])
                        + S3[l & 0xFF]
                    )
                    & 0xFFFFFFFF
                ) ^ p11

                # Feistel substitution on right word (round 11)
                l ^= (
                    (
                        ((S0[r >> 24] + S1[(r >> 16) & 0xFF]) ^ S2[(r >> 8) & 0xFF])
                        + S3[r & 0xFF]
                    )
                    & 0xFFFFFFFF
                ) ^ p12
                # Feistel substitution on left word (round 12)
                r ^= (
                    (
                        ((S0[l >> 24] + S1[(l >> 16) & 0xFF]) ^ S2[(l >> 8) & 0xFF])
                        + S3[l & 0xFF]
                    )
                    & 0xFFFFFFFF
                ) ^ p13

                # Feistel substitution on right word (round 13)
                l ^= (
                    (
                        ((S0[r >> 24] + S1[(r >> 16) & 0xFF]) ^ S2[(r >> 8) & 0xFF])
                        + S3[r & 0xFF]
                    )
                    & 0xFFFFFFFF
                ) ^ p14
                # Feistel substitution on left word (round 14)
                r ^= (
                    (
                        ((S0[l >> 24] + S1[(l >> 16) & 0xFF]) ^ S2[(l >> 8) & 0xFF])
                        + S3[l & 0xFF]
                    )
                    & 0xFFFFFFFF
                ) ^ p15

                # Feistel substitution on right word (round 15)
                l ^= (
                    (
                        ((S0[r >> 24] + S1[(r >> 16) & 0xFF]) ^ S2[(r >> 8) & 0xFF])
                        + S3[r & 0xFF]
                    )
                    & 0xFFFFFFFF
                ) ^ p16

                box[j], box[j + 1] = l, r = r ^ p17, l
                j += 2
