# Path: parser/stpcommands.py
# def blockCharacteristic(stpfile, characteristic, wordsize):
# def setupQuery(stpfile):
# def setupVariables(stpfile, variables, wordsize):
# def assertVariableValue(stpfile, a, b):
# def getStringForVariables(variables, wordsize):
# def assertNonZero(stpfile, variables, wordsize):
# def getStringForNonZero(variables, wordsize):
# def limitWeight(stpfile, weight, p, wordsize, ignoreMSBs=0):
# def setupWeightComputationSum(stpfile, weight, p, wordsize, ignoreMSBs=0):
# def setupWeightComputation(stpfile, weight, p, wordsize, ignoreMSBs=0):
# def getWeightString(variables, wordsize, ignoreMSBs=0, weightVariable="weight"):
# def getStringEq(a, b, c):
# def getStringAdd(a, b, c, wordsize):
# def getStringForAndDifferential(a, b, c):
# def getStringLeftRotate(value, rotation, wordsize):
# def getStringRightRotate(value, rotation, wordsize):
# def add4bitSbox(sbox, variables):
#     DDT = [[0]*16 for i in range(16)]
# 
# Path: ciphers/cipher.py
# class AbstractCipher(object, metaclass=ABCMeta):
#     """
#     Abstract Class for Ciphers
#     """
# 
#     @abstractmethod
#     def createSTP(self, filename, cipherParameters):
#         """
#         Each cipher need to define how it creates an instance for the
#         SMT solver.
#         """
#         pass
# 
#     @abstractmethod
#     def getFormatString(self):
#         """
#         Each cipher needs to specify the format it should be printed.
#         """
#         pass
# 
# Path: parser/stpcommands.py
# def getStringRightRotate(value, rotation, wordsize):
#     if rotation % wordsize == 0:
#         return "{0}".format(value)
#     command = "((({0} >> {1})[{2}:0]) | (({0} << {3})[{2}:0]))".format(
#         value, (rotation % wordsize), wordsize - 1, (wordsize - rotation) % wordsize)
#     return command
# 
# Path: parser/stpcommands.py
# def getStringLeftRotate(value, rotation, wordsize):
#     if rotation % wordsize == 0:
#         return "{0}".format(value)
#     command = "((({0} << {1})[{2}:0]) | (({0} >> {3})[{2}:0]))".format(
#         value, (rotation % wordsize), wordsize - 1, (wordsize - rotation) % wordsize)
# 
#     return command


from parser import stpcommands
from ciphers.cipher import AbstractCipher
from parser.stpcommands import getStringRightRotate as rotr
from parser.stpcommands import getStringLeftRotate as rotl
                          gamma0, gamma1, gamma2, gamma3,
                          pi10, pi11, pi12, pi13,
                          pi20, pi21, pi22, pi23,
                          a0_out, a1_out, a2_out, a3_out,
                          w, wordsize):
        """
        Model for differential behaviour of one round NOEKEON
        """
        command = ""

        command += self.theta(a0_in, a1_in, a2_in, a3_in, theta0, theta1, theta2, theta3, wordsize)
        command += self.pi1(theta0, theta1, theta2, theta3, pi10, pi11, pi12, pi13, wordsize)
        command += self.gamma(pi10, pi11, pi12, pi13, gamma0, gamma1, gamma2, gamma3, w)
        command += self.pi2(gamma0, gamma1, gamma2, gamma3, a0_out, a1_out, a2_out, a3_out, wordsize)

        stp_file.write(command)
        return

    def theta(self, in0, in1, in2, in3, out0, out1, out2, out3, wordsize):
        """
        Model for the Theta function in NOEKEON
        """
        command = ""

        in1xorin3 = "BVXOR({0}[31:0], {1}[31:0])".format(in1, in3)
        in1xorin3lr = rotl(in1xorin3, 8, wordsize)
        in1xorin3rr = rotr(in1xorin3, 8, wordsize)
        l = "BVXOR({0}, BVXOR({1}, {2}))".format(in1xorin3lr, in1xorin3, in1xorin3rr)

        in0xorin2 = "BVXOR({0}[31:0], {1}[31:0])".format(in0, in2)

# Path: parser/stpcommands.py
# def blockCharacteristic(stpfile, characteristic, wordsize):
# def setupQuery(stpfile):
# def setupVariables(stpfile, variables, wordsize):
# def assertVariableValue(stpfile, a, b):
# def getStringForVariables(variables, wordsize):
# def assertNonZero(stpfile, variables, wordsize):
# def getStringForNonZero(variables, wordsize):
# def limitWeight(stpfile, weight, p, wordsize, ignoreMSBs=0):
# def setupWeightComputationSum(stpfile, weight, p, wordsize, ignoreMSBs=0):
# def setupWeightComputation(stpfile, weight, p, wordsize, ignoreMSBs=0):
# def getWeightString(variables, wordsize, ignoreMSBs=0, weightVariable="weight"):
# def getStringEq(a, b, c):
# def getStringAdd(a, b, c, wordsize):
# def getStringForAndDifferential(a, b, c):
# def getStringLeftRotate(value, rotation, wordsize):
# def getStringRightRotate(value, rotation, wordsize):
# def add4bitSbox(sbox, variables):
#     DDT = [[0]*16 for i in range(16)]
# 
# Path: ciphers/cipher.py
# class AbstractCipher(object, metaclass=ABCMeta):
#     """
#     Abstract Class for Ciphers
#     """
# 
#     @abstractmethod
#     def createSTP(self, filename, cipherParameters):
#         """
#         Each cipher need to define how it creates an instance for the
#         SMT solver.
#         """
#         pass
# 
#     @abstractmethod
#     def getFormatString(self):
#         """
#         Each cipher needs to specify the format it should be printed.
#         """
#         pass
# 
# Path: parser/stpcommands.py
# def getStringRightRotate(value, rotation, wordsize):
#     if rotation % wordsize == 0:
#         return "{0}".format(value)
#     command = "((({0} >> {1})[{2}:0]) | (({0} << {3})[{2}:0]))".format(
#         value, (rotation % wordsize), wordsize - 1, (wordsize - rotation) % wordsize)
#     return command
# 
# Path: parser/stpcommands.py
# def getStringLeftRotate(value, rotation, wordsize):
#     if rotation % wordsize == 0:
#         return "{0}".format(value)
#     command = "((({0} << {1})[{2}:0]) | (({0} >> {3})[{2}:0]))".format(
#         value, (rotation % wordsize), wordsize - 1, (wordsize - rotation) % wordsize)
# 
#     return command


# Path: ciphers/noekeon.py
from parser import stpcommands
from ciphers.cipher import AbstractCipher
from parser.stpcommands import getStringRightRotate as rotr
from parser.stpcommands import getStringLeftRotate as rotl

                          gamma0, gamma1, gamma2, gamma3,
                          pi10, pi11, pi12, pi13,
                          pi20, pi21, pi22, pi23,
                          a0_out, a1_out, a2_out, a3_out,
                          w, wordsize):
        """
        Model for differential behaviour of one round NOEKEON
        """
        command = ""

        command += self.theta(a0_in, a1_in, a2_in, a3_in, theta0, theta1, theta2, theta3, wordsize)
        command += self.pi1(theta0, theta1, theta2, theta3, pi10, pi11, pi12, pi13, wordsize)
        command += self.gamma(pi10, pi11, pi12, pi13, gamma0, gamma1, gamma2, gamma3, w)
        command += self.pi2(gamma0, gamma1, gamma2, gamma3, a0_out, a1_out, a2_out, a3_out, wordsize)

        stp_file.write(command)
        return

    def theta(self, in0, in1, in2, in3, out0, out1, out2, out3, wordsize):
        """
        Model for the Theta function in NOEKEON
        """
        command = ""

        in1xorin3 = "BVXOR({0}[31:0], {1}[31:0])".format(in1, in3)
        in1xorin3lr = rotl(in1xorin3, 8, wordsize)
        in1xorin3rr = rotr(in1xorin3, 8, wordsize)
        l = "BVXOR({0}, BVXOR({1}, {2}))".format(in1xorin3lr, in1xorin3, in1xorin3rr)

        in0xorin2 = "BVXOR({0}[31:0], {1}[31:0])".format(in0, in2)

        in0xorin2lr = rotl(in0xorin2, 8, wordsize)