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) in0xorin2rr = rotr(in0xorin2, 8, wordsize) r = "BVXOR({0}, BVXOR({1}, {2}))".format(in0xorin2lr, in0xorin2, in0xorin2rr) command += "ASSERT({0}[31:0] = BVXOR({1}[31:0], {2}[31:0]));\n".format( out0, in0, l) command += "ASSERT({0}[31:0] = BVXOR({1}[31:0], {2}[31:0]));\n".format( out1, in1, r) command += "ASSERT({0}[31:0] = BVXOR({1}[31:0], {2}[31:0]));\n".format( out2, in2, l) command += "ASSERT({0}[31:0] = BVXOR({1}[31:0], {2}[31:0]));\n".format( out3, in3, r) return command
def setupChasKeyRound(self, stp_file, rnd, v0_in, v1_in, v2_in, v3_in, v0_out, v1_out, v2_out, v3_out, w0, w1, wordsize): """ Half a round of ChasKey a0 = (v1 + v0) <<< 32 a1 = (v1 + v0) ^ (v1 <<< 13) a2 = (v2 + v3) a3 = (v2 + v3) ^ (v3 <<< 16) """ command = "" if (rnd % 2) == 0: rot_one = self.rot_v1_up rot_two = self.rot_v3_up rot_three = self.rot_v0_up else: rot_one = self.rot_v1_down rot_two = self.rot_v3_down rot_three = self.rot_v0_down #Assert intermediate values #Rotate right to get correct output value #v0_out command += "ASSERT(" command += stpcommands.getStringAdd(v2_in, v3_in, v0_out, wordsize) command += ");\n" #v1_out command += "ASSERT({} = BVXOR({}, {}));\n".format( v1_out, rotl(v1_in, rot_one, wordsize), rotr(v2_out, rot_three, wordsize)) #v2_out command += "ASSERT(" command += stpcommands.getStringAdd(v1_in, v0_in, rotr(v2_out, rot_three, wordsize), wordsize) command += ");\n" #v3_out command += "ASSERT({} = BVXOR({}, {}));\n".format( v3_out, rotl(v3_in, rot_two, wordsize), v0_out) # Compute Weights for modular addition # Lipmaa and Moriai command += "ASSERT({0} = ~".format(w0) command += stpcommands.getStringEq(v1_in, v0_in, rotr(v2_out, rot_three, wordsize)) command += ");\n" command += "ASSERT({0} = ~".format(w1) command += stpcommands.getStringEq(v2_in, v3_in, v0_out) command += ");\n" stp_file.write(command) return
def setupChasKeyRound( self, stp_file, rnd, v0_in, v1_in, v2_in, v3_in, v0_out, v1_out, v2_out, v3_out, w0, w1, wordsize ): """ Half a round of ChasKey a0 = (v1 + v0) <<< 32 a1 = (v1 + v0) ^ (v1 <<< 13) a2 = (v2 + v3) a3 = (v2 + v3) ^ (v3 <<< 16) """ command = "" if (rnd % 2) == 0: rot_one = 5 rot_two = 8 else: rot_one = 7 rot_two = 13 # Assert intermediate values # Rotate right to get correct output value # v0_out command += "ASSERT(" command += stpcommands.getStringAdd(v2_in, v3_in, v0_out, wordsize) command += ");\n" # v1_out command += "ASSERT({} = BVXOR({}, {}));\n".format( v1_out, rotl(v1_in, rot_one, wordsize), rotr(v2_out, 16, wordsize) ) # v2_out command += "ASSERT(" command += stpcommands.getStringAdd(v1_in, v0_in, rotr(v2_out, 16, wordsize), wordsize) command += ");\n" # v3_out command += "ASSERT({} = BVXOR({}, {}));\n".format(v3_out, rotl(v3_in, rot_two, wordsize), v0_out) # Compute Weights for modular addition # Lipmaa and Moriai command += "ASSERT({0} = ~".format(w0) command += stpcommands.getStringEq(v1_in, v0_in, rotr(v2_out, 16, wordsize)) command += ");\n" command += "ASSERT({0} = ~".format(w1) command += stpcommands.getStringEq(v2_in, v3_in, v0_out) command += ");\n" stp_file.write(command) return
def setupQuarterRound(self, stp_file, a, tmp, c, w, wordsize): """ ChaCha quarter round: (c0, c1, c2, c3) = Quarterround(a0, a1, a2, a3) """ command = "" # a += b command += "ASSERT({});\n".format( stpcommands.getStringAdd(a[0], a[1], tmp[0], wordsize)) command += "ASSERT({} = ~{});\n".format(w[0], stpcommands.getStringEq(a[0], a[1], tmp[0])) # d ^= a; d <<<= 16; (a = tmp[0] after last step) d = rotl("BVXOR({}, {})".format(tmp[0], a[3]), 16, wordsize) # c += d; command += "ASSERT({});\n".format( stpcommands.getStringAdd(a[2], d, tmp[1], wordsize)) command += "ASSERT({} = ~{});\n".format(w[1], stpcommands.getStringEq(a[2], d, tmp[1])) # b ^= c; b <<<= 12; (c = tmp[1] after last step) b = rotl("BVXOR({}, {})".format(a[1], tmp[1]), 12, wordsize) # a += b; command += "ASSERT({});\n".format( stpcommands.getStringAdd(tmp[0], b, tmp[2], wordsize)) command += "ASSERT({} = ~{});\n".format(w[2], stpcommands.getStringEq(tmp[0], b, tmp[2])) # d ^= a; d <<<= 8; (a = tmp[2] after last step) d = rotl("BVXOR({}, {})".format(tmp[2], d), 8, wordsize) # c += d command += "ASSERT({});\n".format( stpcommands.getStringAdd(tmp[1], d, tmp[3], wordsize)) command += "ASSERT({} = ~{});\n".format(w[1], stpcommands.getStringEq(tmp[1], d, tmp[3])) # b ^= c; b <<<= 7; (c = tmp[3] after last step) b = rotl("BVXOR({}, {})".format(b, tmp[3]), 7, wordsize) # Output command += "ASSERT({} = {});\n".format(c[0], tmp[2]) command += "ASSERT({} = {});\n".format(c[1], b) command += "ASSERT({} = {});\n".format(c[2], tmp[3]) command += "ASSERT({} = {});\n".format(c[3], d) stp_file.write(command) return
def setupKeccakRound(self, stp_file, rnd, s, a, b, c, d, wordsize): """ Model for one round of Keccak. """ command = "" #Compute Parity for each column for i in range(5): command += "ASSERT({} = BVXOR({}, BVXOR({}, BVXOR({}, BVXOR({}, {})))));\n".format( c[i + 5 * rnd], s[i + 5 * 0 + 25 * rnd], s[i + 5 * 1 + 25 * rnd], s[i + 5 * 2 + 25 * rnd], s[i + 5 * 3 + 25 * rnd], s[i + 5 * 4 + 25 * rnd]) #Compute intermediate values for i in range(5): command += "ASSERT({} = BVXOR({}, {}));\n".format( d[i + 5 * rnd], c[(i - 1) % 5 + 5 * rnd], rotl(c[(i + 1) % 5 + 5 * rnd], 1, wordsize)) #Rho and Pi for x in range(5): for y in range(5): #x + 5*y + 25*rnd -> y + 5*((2*x + 3*y) % 5) + 25*rnd new_b_index = y + 5 * ((2 * x + 3 * y) % 5) + 25 * rnd tmp_xor = "BVXOR({}, {})".format(s[x + 5 * y + 25 * rnd], d[x + 5 * rnd]) command += "ASSERT({} = {});\n".format( b[new_b_index], rotl(tmp_xor, self.RO[x][y], wordsize)) #Chi for x in range(5): for y in range(5): chiTmp = "BVXOR({}, ~{} & {})".format( b[(x + 0) % 5 + 5 * y + 25 * rnd], b[(x + 1) % 5 + 5 * y + 25 * rnd], b[(x + 2) % 5 + 5 * y + 25 * rnd]) command += "ASSERT({} = {});\n".format(a[x + 5 * y + 25 * rnd], chiTmp) #Add rnd constant for x in range(5): for y in range(5): if x == 0 and y == 0: command += "ASSERT({} = BVXOR({}, {}));\n".format( s[25 * (rnd + 1)], a[25 * rnd], self.RC[rnd]) else: command += "ASSERT({} = {});\n".format( s[x + 5 * y + 25 * (rnd + 1)], a[x + 5 * y + 25 * rnd]) stp_file.write(command) return
def pi1(self, in0, in1, in2, in3, out0, out1, out2, out3, wordsize): """ Model for the Pi1 function in NOEKEON - which is the inverse of pi2 """ command = "" command += "ASSERT({0}[31:0] = {1}[31:0]);\n".format(in0, out0) command += "ASSERT({0}[31:0] = {1}[31:0]);\n".format( rotl(in1, 1, wordsize), out1) command += "ASSERT({0}[31:0] = {1}[31:0]);\n".format( rotl(in2, 5, wordsize), out2) command += "ASSERT({0}[31:0] = {1}[31:0]);\n".format( rotl(in3, 2, wordsize), out3) return command
def setupQuarterRound(self, stp_file, a, b, c, w, wordsize): """ Salsa quarter round: (c0, c1, c2, c3) = Quarterround(a0, a1, a2, a3) b0, b1, b2 and b3 are used for the modular addition. """ command = "" # First addition command += "ASSERT({});\n".format( stpcommands.getStringAdd(a[0], a[3], b[0], wordsize)) command += "ASSERT({} = ~{});\n".format(w[0], stpcommands.getStringEq(a[0], a[3], b[0])) # Second addition tmp_xor0 = "BVXOR({}, {})".format(rotl(b[0], 7, wordsize), a[1]) command += "ASSERT({});\n".format( stpcommands.getStringAdd(a[0], tmp_xor0, b[1], wordsize)) command += "ASSERT({} = ~{});\n".format(w[1], stpcommands.getStringEq(a[0], tmp_xor0, b[1])) # Third addition tmp_xor1 = "BVXOR({}, {})".format(rotl(b[1], 9, wordsize), a[2]) command += "ASSERT({});\n".format( stpcommands.getStringAdd(tmp_xor0, tmp_xor1, b[2], wordsize)) command += "ASSERT({} = ~{});\n".format(w[2], stpcommands.getStringEq(tmp_xor0, tmp_xor1, b[2])) # Fourth addition tmp_xor2 = "BVXOR({}, {})".format(rotl(b[2], 13, wordsize), a[3]) command += "ASSERT({});\n".format( stpcommands.getStringAdd(tmp_xor1, tmp_xor2, b[3], wordsize)) command += "ASSERT({} = ~{});\n".format(w[3], stpcommands.getStringEq(tmp_xor1, tmp_xor2, b[3])) # Outputs command += "ASSERT({} = BVXOR({}, {}));\n".format(c[0], a[0], rotl(b[3], 18, wordsize)) command += "ASSERT({} = {});\n".format(c[1], tmp_xor0) command += "ASSERT({} = {});\n".format(c[2], tmp_xor1) command += "ASSERT({} = {});\n".format(c[3], tmp_xor2) stp_file.write(command) return
def L(self, x0l_in, x0r_in, x1l_in, x1r_in, x0l_out, x0r_out, x1l_out, x1r_out): """ Model for the L' function in SPARX-128. L' is the Feistel function """ command = "" # (x_in xor y_in) xor_x0 = "BVXOR(" + x0l_in + " , " + x0r_in + ")" xor_x1 = "BVXOR(" + x1l_in + " , " + x1r_in + ")" xor_x0_x1 = "BVXOR(" + xor_x0 + " , " + xor_x1 + ")" #(x_in xor y_in) <<< 8) rot_x0_x1 = rotl(xor_x0_x1, 8, 16) # exchange x0l_out and x1l_out command += "ASSERT(" + x1l_out + " = " command += "BVXOR(" + x0l_in + " , " + rot_x0_x1 + "));\n" command += "ASSERT(" + x0r_out + " = " command += "BVXOR(" + x0r_in + " , " + rot_x0_x1 + "));\n" command += "ASSERT(" + x0l_out + " = " command += "BVXOR(" + x1l_in + " , " + rot_x0_x1 + "));\n" command += "ASSERT(" + x1r_out + " = " command += "BVXOR(" + x1r_in + " , " + rot_x0_x1 + "));\n" return command
def setupSPECKEYRound(self, stp_file, x_in, y_in, x_out, y_out, w, wordsize): """ Model for the ARX box (round) function of SPARX which is the same as SPECKEY. """ command = "" #Assert((x_in >>> 7) + y_in = x_out) command += "ASSERT(" command += stpcommands.getStringAdd(rotr(x_in, 7, wordsize), y_in, x_out, wordsize) command += ");\n" #Assert(x_out xor (y_in <<< 2) = y_out) command += "ASSERT(" + y_out + " = " command += "BVXOR(" + x_out + "," command += rotl(y_in, 2, wordsize) command += "));\n" #For weight computation command += "ASSERT({0} = ~".format(w) command += stpcommands.getStringEq(rotr(x_in, 7, wordsize), y_in, x_out) command += ");\n" stp_file.write(command) return
def A(self, x_in, y_in, x_out, y_out, w, wordsize): """ Model for the ARX box (round) function of SPARX. A^a denotes a rounds of SPECKEY. """ command = "" #Assert((x_in >>> 7) + y_in = x_out) command += "ASSERT(" command += stpcommands.getStringAdd(rotr(x_in, 7, wordsize), y_in, x_out, wordsize) command += ");\n" #Assert(x_out xor (y_in <<< 2) = y_out) command += "ASSERT(" + y_out + " = " command += "BVXOR(" + x_out + "," command += rotl(y_in, 2, wordsize) command += "));\n" #For weight computation command += "ASSERT({0} = ~".format(w) command += stpcommands.getStringEq(rotr(x_in, 7, wordsize), y_in, x_out) command += ");\n" return command
def setupSpeckRound(self, stp_file, x_in, y_in, x_out, y_out, w, wordsize): """ Model for differential behaviour of one round SPECK """ command = "" #Assert(x_in >>> self.rot_alpha + y_in = x_out) command += "ASSERT(" command += stpcommands.getStringAdd( rotr(x_in, self.rot_alpha, wordsize), y_in, x_out, wordsize) command += ");\n" #Assert(x_out xor (y_in <<< self.rot_beta) = x_in) command += "ASSERT(" + y_out + " = " command += "BVXOR(" + x_out + "," command += rotl(y_in, self.rot_beta, wordsize) command += "));\n" #For weight computation command += "ASSERT({0} = ~".format(w) command += stpcommands.getStringEq( rotr(x_in, self.rot_alpha, wordsize), y_in, x_out) command += ");\n" stp_file.write(command) return
def setupSpeckRound(self, stp_file, x_in, y_in, x_out, y_out, w, wordsize): """ Model for differential behaviour of one round SPECK """ command = "" #Assert(x_in >>> self.rot_alpha + y_in = x_out) command += "ASSERT(" command += stpcommands.getStringAdd(rotr(x_in, self.rot_alpha, wordsize), y_in, x_out, wordsize) command += ");\n" #Assert(x_out xor (y_in <<< self.rot_beta) = x_in) command += "ASSERT(" + y_out + " = " command += "BVXOR(" + x_out + "," command += rotl(y_in, self.rot_beta, wordsize) command += "));\n" #For weight computation command += "ASSERT({0} = ~".format(w) command += stpcommands.getStringEq(rotr(x_in, self.rot_alpha, wordsize), y_in, x_out) command += ");\n" stp_file.write(command) return
def setupQuarterRound(self, stp_file, a, b, c, w, wordsize): """ Salsa quarter round: (c0, c1, c2, c3) = Quarterround(a0, a1, a2, a3) b0, b1, b2 and b3 are used for the modular addition. """ command = "" # First addition command += "ASSERT({});\n".format( stpcommands.getStringAdd(a[0], a[3], b[0], wordsize)) command += "ASSERT({} = ~{});\n".format( w[0], stpcommands.getStringEq(a[0], a[3], b[0])) # Second addition tmp_xor0 = "BVXOR({}, {})".format(rotl(b[0], 7, wordsize), a[1]) command += "ASSERT({});\n".format( stpcommands.getStringAdd(a[0], tmp_xor0, b[1], wordsize)) command += "ASSERT({} = ~{});\n".format( w[1], stpcommands.getStringEq(a[0], tmp_xor0, b[1])) # Third addition tmp_xor1 = "BVXOR({}, {})".format(rotl(b[1], 9, wordsize), a[2]) command += "ASSERT({});\n".format( stpcommands.getStringAdd(tmp_xor0, tmp_xor1, b[2], wordsize)) command += "ASSERT({} = ~{});\n".format( w[2], stpcommands.getStringEq(tmp_xor0, tmp_xor1, b[2])) # Fourth addition tmp_xor2 = "BVXOR({}, {})".format(rotl(b[2], 13, wordsize), a[3]) command += "ASSERT({});\n".format( stpcommands.getStringAdd(tmp_xor1, tmp_xor2, b[3], wordsize)) command += "ASSERT({} = ~{});\n".format( w[3], stpcommands.getStringEq(tmp_xor1, tmp_xor2, b[3])) # Outputs command += "ASSERT({} = BVXOR({}, {}));\n".format( c[0], a[0], rotl(b[3], 18, wordsize)) command += "ASSERT({} = {});\n".format(c[1], tmp_xor0) command += "ASSERT({} = {});\n".format(c[2], tmp_xor1) command += "ASSERT({} = {});\n".format(c[3], tmp_xor2) stp_file.write(command) return
def setupKeccakRound(self, stp_file, rnd, s, a, b, c, d, wordsize): """ Model for one round of Keccak. """ command = "" #Compute Parity for each column for i in range(5): command += "ASSERT({} = BVXOR({}, BVXOR({}, BVXOR({}, BVXOR({}, {})))));\n".format( c[i + 5*rnd], s[i + 5*0 + 25*rnd], s[i + 5*1 + 25*rnd], s[i + 5*2 + 25*rnd], s[i + 5*3 + 25*rnd], s[i + 5*4 + 25*rnd]) #Compute intermediate values for i in range(5): command += "ASSERT({} = BVXOR({}, {}));\n".format( d[i + 5*rnd], c[(i - 1) % 5 + 5*rnd], rotl(c[(i + 1) % 5 + 5*rnd], 1, wordsize)) #Rho and Pi for x in range(5): for y in range(5): #x + 5*y + 25*rnd -> y + 5*((2*x + 3*y) % 5) + 25*rnd new_b_index = y + 5*((2*x + 3*y) % 5) + 25*rnd tmp_xor = "BVXOR({}, {})".format(s[x + 5*y + 25*rnd], d[x + 5*rnd]) command += "ASSERT({} = {});\n".format( b[new_b_index], rotl(tmp_xor, self.RO[x][y], wordsize)) #Chi for x in range(5): for y in range(5): chiTmp = "BVXOR({}, ~{} & {})".format(b[(x + 0) % 5 + 5*y + 25*rnd], b[(x + 1) % 5 + 5*y + 25*rnd], b[(x + 2) % 5 + 5*y + 25*rnd]) command += "ASSERT({} = {});\n".format(a[x + 5*y + 25*rnd], chiTmp) #Add rnd constant for x in range(5): for y in range(5): if x == 0 and y == 0: command += "ASSERT({} = BVXOR({}, {}));\n".format( s[25*(rnd + 1)], a[25*rnd], self.RC[rnd]) else: command += "ASSERT({} = {});\n".format( s[x + 5*y + 25*(rnd + 1)], a[x + 5*y + 25*rnd]) stp_file.write(command) return
def setupRound(self, stp_file, xin, yin, zin, xout, yout, zout, xsb, ysb, zsb, w, wordsize): """ Gimli round: x = (x xor (z << 1) xor (y & z) << a) <<< d y = (y xor x xor (x | z) << b) <<< e z = (y xor z xor (x & y) << c) <<< f """ command = "" # Conditions for non-linear layer xnl = "({} & ~({}|{}))".format(xsb, yin, zin) ynl = "({} & ~({}|{}))".format(ysb, xin, zin) znl = "({} & ~({}|{}))".format(zsb, xin, yin) command += "ASSERT(({} | {} | {}) = 0x{});\n".format(xnl, ynl, znl, "0" * (wordsize // 4)) # Dependency between bits # (x & y & ~z) & ~(xout ^ yout) xcond = "(({} & {} & ~{}) & ~(BVXOR({}, {})))".format(xin, yin, zin, xsb, ysb) # (x & ~y & z) & (xout ^ zout) ycond = "(({} & ~{} & {}) & (BVXOR({}, {})))".format(xin, yin, zin, xsb, zsb) # (~x & y & z) & ~(yout ^ zout) zcond = "((~{} & {} & {}) & ~(BVXOR({}, {})))".format(xin, yin, zin, ysb, zsb) # (x & y & z) & (~(xout ^ yout ^ zout)) fcond = "(({} & {} & {}) & ~(BVXOR(BVXOR({}, {}), {})))".format(xin, yin, zin, xsb, ysb, zsb) command += "ASSERT(({} | {} | {} | {}) = 0x{});\n".format(xcond, ycond, zcond, fcond, "0" * (wordsize // 4)) xshift = "BVXOR({0}, BVXOR(({1} << 1)[{4}:0], ({2} << {3})[{4}:0]))".format(xin, zin, xsb, self.a, wordsize - 1) command += "ASSERT({} = {});\n".format(zout, rotl(xshift, self.d, wordsize)) yshift = "BVXOR({}, BVXOR({}, ({} << {})[{}:0]))".format(yin, xin, ysb, self.b, wordsize - 1) command += "ASSERT({} = {});\n".format(yout, rotl(yshift, self.e, wordsize)) zshift = "BVXOR({}, BVXOR({}, ({} << {})[{}:0]))".format(zin, yin, zsb, self.c, wordsize - 1) command += "ASSERT({} = {});\n".format(xout, rotl(zshift, self.f, wordsize)) # Probability wxtmp = "((((({0} | {1}) << {2})[{3}:0]) >> {2})[{3}:0])".format(yin, zin, self.a, wordsize - 1) wytmp = "((((({0} | {1}) << {2})[{3}:0]) >> {2})[{3}:0])".format(xin, zin, self.b, wordsize - 1) wztmp = "((((({0} | {1}) << {2})[{3}:0]) >> {2})[{3}:0])".format(xin, yin, self.c, wordsize - 1) command += "ASSERT({0} = ({1} | {2} | {3}));\n".format(w, wxtmp, wytmp, wztmp) stp_file.write(command) return
def setupSimonRound(self, stp_file, x_in, y_in, x_out, y_out, and_out, w, wordsize): """ Model for differential behaviour of one round SIMON y[i+1] = x[i] x[i+1] = (x[i] <<< 1) & (x[i] <<< 8) ^ y[i] ^ (x[i] << 2) This model is only correct if gcd(self.rot_alpha - self.rot_beta, wordsize) = 1 and self.rot_alpha > self.rot_beta """ command = "" #Assert(y_out = x_in) command += "ASSERT({} = {});\n".format(y_out, x_in) x_in_rotalpha = rotl(x_in, self.rot_alpha, wordsize) x_in_rotbeta = rotl(x_in, self.rot_beta, wordsize) #Deal with dependent inputs varibits = "({0} | {1})".format(x_in_rotalpha, x_in_rotbeta) doublebits = self.getDoubleBits(x_in, wordsize) #Check for valid difference firstcheck = "({} & ~{})".format(and_out, varibits) secondcheck = "(BVXOR({}, {}) & {})".format( and_out, rotl(and_out, self.rot_alpha - self.rot_beta, wordsize), doublebits) thirdcheck = "(IF {0} = 0x{1} THEN BVMOD({2}, {0}, 0x{3}2) ELSE 0x{4} ENDIF)".format( x_in, "f" * (wordsize // 4), wordsize, "0" * (wordsize // 4 - 1), "0" * (wordsize // 4)) command += "ASSERT(({} | {} | {}) = 0x{});\n".format( firstcheck, secondcheck, thirdcheck, "0" * (wordsize // 4)) #Assert XORs command += "ASSERT({} = BVXOR({}, BVXOR({}, {})));\n".format( x_out, rotl(x_in, self.rot_gamma, wordsize), y_in, and_out) #Weight computation command += "ASSERT({0} = (IF {1} = 0x{4} THEN BVSUB({5},0x{4},0x{6}1) \ ELSE BVXOR({2}, {3}) ENDIF));\n".format( w, x_in, varibits, doublebits, "f" * (wordsize // 4), wordsize, "0"*((wordsize // 4) - 1)) stp_file.write(command) return
def setupCHAMRound(self, stp_file, x0_in, x1_in, x2_in, x3_in, x0_out, x1_out, x2_out, x3_out, x0x1, rot_x0, rot_x1, w, wordsize): """ Model for differential behaviour of one round CHAM """ command = "" # even rounds: # X_{i+1}[3] = (X_{i}[0] + (X_{i}[1] << 1)) << 8 # odd rounds: # X_{i+1}[3] = (X_{i}[0] + (X_{i}[1] << 8)) << 1 command += "ASSERT(" command += stpcommands.getStringAdd( rotl(x1_in, rot_x1, wordsize), x0_in, x0x1, wordsize) command += ");\n" command += "ASSERT({0} = {1});\n".format(x3_out, rotl(x0x1, rot_x0, wordsize)) # X_{i+1}[2] = X_{i+1}[3] # X_{i+1}[1] = X_{i+1}[2] # X_{i+1}[0] = X_{i+1}[1] command += "ASSERT({0} = {1});\n".format(x2_out, x3_in) command += "ASSERT({0} = {1});\n".format(x1_out, x2_in) command += "ASSERT({0} = {1});\n".format(x0_out, x1_in) #For weight computation command += "ASSERT({0} = ~".format(w) command += stpcommands.getStringEq(x0_in, rotl(x1_in, rot_x1, wordsize), x0x1) command += ");\n" stp_file.write(command) return
def setupSimonRound(self, stp_file, x0_in, y0_in, x0_out, y0_out, and_out0, key, wordsize): """ Returns a string representing one round of Simon in STP. y[i+1] = x[i] x[i+1] = (x[i] <<< 1) & (x[i] <<< 8) ^ y[i] ^ (x[i] << 2) ^ key """ command = "" #Assert(y_out = x_in) command += "ASSERT({} = {});\n".format(y0_out, x0_in) #Assert AND Output command += "ASSERT({} = {} & {});\n".format(and_out0, rotl(x0_in, self.rot_beta, wordsize), rotl(x0_in, self.rot_alpha, wordsize)) #Assert x_out command += "ASSERT({} = BVXOR({}, BVXOR({}, BVXOR({}, {}))));\n".format( x0_out, y0_in, and_out0, key, rotl(x0_in, self.rot_gamma, wordsize)) stp_file.write(command) return
def setupSimonRound(self, stp_file, x0_in, y0_in, x0_out, y0_out, and_out0, key, wordsize): """ Returns a string representing one round of Simon in STP. y[i+1] = x[i] x[i+1] = (x[i] <<< 1) & (x[i] <<< 8) ^ y[i] ^ (x[i] << 2) ^ key """ command = "" #Assert(y_out = x_in) command += "ASSERT({} = {});\n".format(y0_out, x0_in) #Assert AND Output command += "ASSERT({} = {} & {});\n".format( and_out0, rotl(x0_in, self.rot_beta, wordsize), rotl(x0_in, self.rot_alpha, wordsize)) #Assert x_out command += "ASSERT({} = BVXOR({}, BVXOR({}, BVXOR({}, {}))));\n".format( x0_out, y0_in, and_out0, key, rotl(x0_in, self.rot_gamma, wordsize)) stp_file.write(command) return
def setupRound(self, stp_file, x_in, y_in, x_out, y_out, in_G0, in_G1, xor_G, perm_G, w, wordsize): """ Model for differential behaviour of one round """ command = "" # 1. y_out = x_in command += "ASSERT({} = {});\n".format(y_out, x_in) # 2. rotations x_in_rotalpha = rotl(x_in, self.rot_alpha, wordsize // 4) x_in_rotbeta = rotl(x_in, self.rot_beta, wordsize // 4) command += "ASSERT({} = {});\n".format(in_G0, x_in_rotalpha) command += "ASSERT({} = {});\n".format(in_G1, x_in_rotbeta) # 3. G0 ^ G1 = xor_G command += SatConstraints.PatternXorAssert(in_G0, in_G1, xor_G, wordsize // 4) # 4. xor_G PERM to perm_G for i in range(wordsize // 4): command += "ASSERT({0}[{1}:{1}] = {2}[{3}:{3}]);\n".format( perm_G, self.PERM[i], xor_G, i) # 5. perm_G ^ y_in = x_out command += SatConstraints.PatternXorAssert(y_in, perm_G, x_out, wordsize // 4) # 6. Weight computation sum_w_i = stpcommands.getWeightString([x_in], wordsize // 4, 0, w) sum_w_i += '\n' command += sum_w_i stp_file.write(command) return
def setupLBlockRound(self, stp_file, x_in, y_in, x_out, y_out, f_out, s_out, w, wordsize): """ Model for differential behaviour of one round LBlock y[i+1] = x[i] x[i+1] = P(S(x[i])) xor y[i] <<< 8 """ command = "" #Assert(y[i+1] = x[i]) command += "ASSERT({} = {});\n".format(y_out, x_in) y_in_rot = rotl(y_in, 8, wordsize) command += self.F(x_in, s_out, f_out, w) #Assert XOR command += "ASSERT({} = BVXOR({}, {}));\n".format(x_out, f_out, y_in_rot) stp_file.write(command) return
def L(self, x_in, y_in, x_out, y_out): """ Model for the L function in SPARX. L is the Feistel function and is borrowed from NOEKEON. """ command = "" # (x_in xor y_in) xor_x_y = "BVXOR(" + x_in + " , " + y_in + ")" #(x_in xor y_in) <<< 8) rot_x_y = rotl(xor_x_y, 8, 16) #Assert(x_out = x_in xor ((x_in xor y_in) <<< 8)) command += "ASSERT(" + x_out + " = " command += "BVXOR(" + x_in + " , " + rot_x_y + "));\n" #Assert(y_out = y_in xor ((x_in xor y_in) <<< 8)) command += "ASSERT(" + y_out + " = " command += "BVXOR(" + y_in + " , " + rot_x_y + "));\n" return command
def setupAsconRound(self, stp_file, rnd, s, a, b, c, wordsize, tmp, w, xin, xout, andout): """ Model for one round of Ascon. """ command = "" weight_sum = "" # Linear part in S-box command += "ASSERT({} = BVXOR({}, {}));\n".format(a[0 + 5*rnd], s[0 + 5*rnd], s[4 + 5*rnd]) command += "ASSERT({} = {});\n".format(a[1 + 5*rnd], s[1 + 5*rnd]) command += "ASSERT({} = BVXOR({}, {}));\n".format(a[2 + 5*rnd], s[2 + 5*rnd], s[1 + 5*rnd]) command += "ASSERT({} = {});\n".format(a[3 + 5*rnd], s[3 + 5*rnd]) command += "ASSERT({} = BVXOR({}, {}));\n".format(a[4 + 5*rnd], s[4 + 5*rnd], s[3 + 5*rnd]) # Model for the S-box for z in range(wordsize): # Construct S-box input command += "ASSERT({}={});\n".format( xin[z + 5*wordsize*rnd], a[0 + 5*rnd] + "[{0}:{0}]".format(z) + "@" + a[1 + 5*rnd] + "[{0}:{0}]".format(z) + "@" + a[2 + 5*rnd] + "[{0}:{0}]".format(z) + "@" + a[3 + 5*rnd] + "[{0}:{0}]".format(z) + "@" + a[4 + 5*rnd] + "[{0}:{0}]".format(z)) # Construct S-box output command += "ASSERT({}={});\n".format( xout[z + 5*wordsize*rnd], b[0 + 5*rnd] + "[{0}:{0}]".format(z) + "@" + b[1 + 5*rnd] + "[{0}:{0}]".format(z) + "@" + b[2 + 5*rnd] + "[{0}:{0}]".format(z) + "@" + b[3 + 5*rnd] + "[{0}:{0}]".format(z) + "@" + b[4 + 5*rnd] + "[{0}:{0}]".format(z)) xin_rotalpha = rotl(xin[z + 5*wordsize*rnd], 2, 5) xin_rotbeta = rotl(xin[z + 5*wordsize*rnd], 1, 5) #Deal with dependent inputs varibits = "({0} | {1})".format(xin_rotalpha, xin_rotbeta) doublebits = self.getDoubleBits(xin[z + 5*wordsize*rnd]) #Check for valid difference firstcheck = "({} & ~{})".format(andout[z + 5*wordsize*rnd], varibits) secondcheck = "(~BVXOR({}, {}) & {})".format( andout[z + 5*wordsize*rnd], rotl(andout[z + 5*wordsize*rnd], 2 - 1, 5), doublebits) thirdcheck = "(IF {0} = 0b{1} THEN BVMOD(5, {0}, 0b00010) ELSE 0b{2}ENDIF)".format( xin[z + 5*wordsize*rnd], "11111", "00000") command += "ASSERT(({} | {} | {}) = 0b{});\n".format(firstcheck, secondcheck, thirdcheck, "00000") #Assert XORs command += "ASSERT({} = BVXOR({},{}));\n".format( xout[z + 5*wordsize*rnd], xin[z + 5*wordsize*rnd], andout[z + 5*wordsize*rnd]) #Weight computation command += ("ASSERT({0} = (IF {1} = 0b{4} THEN BVSUB({5},0b{4},0b{6}1)" "ELSE BVXOR({2}, {3}) ENDIF));\n".format( tmp[z + 5*wordsize*rnd], xin[z + 5*wordsize*rnd], varibits, doublebits, "1"*5, 5, "0"*4)) weight_sum += ("0b{0}@(BVPLUS({1}, {2}[0:0], {2}[1:1], " "{2}[2:2],{2}[3:3], {2}[4:4])),".format("0"*11, 5, "0b0000@" + tmp[z + 5*wordsize*rnd])) command += "ASSERT({}=BVPLUS({},{}));\n".format(w[rnd], 16, weight_sum[:-1]) # Linear after S-box command += "ASSERT({} = BVXOR({}, {}));\n".format(c[0 + 5*rnd], b[0 + 5*rnd], b[4 + 5*rnd]) command += "ASSERT({} = BVXOR({}, {}));\n".format(c[1 + 5*rnd], b[0 + 5*rnd], b[1 + 5*rnd]) command += "ASSERT({} = {});\n".format(c[2 + 5*rnd], b[2 + 5*rnd]) command += "ASSERT({} = BVXOR({}, {}));\n".format(c[3 + 5*rnd], b[2 + 5*rnd], b[3 + 5*rnd]) command += "ASSERT({} = {});\n".format(c[4 + 5*rnd], b[4 + 5*rnd]) # Linear functions rot_constants = [[19, 28], [61, 39], [1, 6], [10, 17], [7, 41]] for row in range(5): command += "ASSERT({} = BVXOR({}, BVXOR({}, {})));\n".format( s[row + 5 * (rnd + 1)], c[row + 5*rnd], rotr(c[row + 5*rnd], rot_constants[row][0], wordsize), rotr(c[row + 5*rnd], rot_constants[row][1], wordsize), ) stp_file.write(command) return
def setupSimonRound(self, stp_file, x_in, y_in, x_out, y_out, and_out, b, c, abits, w, tmpWeight, sbits, pbits, wordsize): """ Model for linear behaviour of one round SIMON. y[i+1] = x[i] x[i+1] = (x[i] <<< 1) & (x[i] <<< 8) ^ y[i] ^ (x[i] << 2) This is a loop unrolled version of the model presented in http://eprint.iacr.org/2015/145 """ command = "" deltarot = self.rot_alpha - self.rot_beta lout = y_in lin = "BVXOR(BVXOR({}, {}), {})".format(x_in, rotr(lout, self.rot_gamma, wordsize), y_out) #lin = "BVXOR({}, {})".format(x_in, rotr(lout, self.rot_gamma, wordsize)) #Assert(y_out = x_in) command += "ASSERT({} = {});\n".format(x_out, y_in) #Assert for AND linear approximation tmp = "BVXOR(({0} | {1}), {2}) & {2}".format( rotr(lout, self.rot_alpha, wordsize), rotr(lout, self.rot_beta, wordsize), lin) command += "ASSERT({} = 0x{});\n".format(tmp, "0"*(wordsize // 4)) #Assert for y_out # command += "ASSERT({0} = BVXOR({1}, BVXOR({2}, BVXOR({3}, {4}))));\n".format( # y_out, x_in, rotr(lout, self.rot_alpha, wordsize), rotr(lout, self.rot_beta, wordsize), # rotr(x_out, self.rot_gamma, wordsize)) command += "ASSERT({0} = BVXOR({1}, BVXOR({2}, {3})));\n".format( y_out, x_in, rotr(x_out, self.rot_gamma, wordsize), lin) #For weight computation #Compute abits loutRotated = rotr(lout, deltarot, wordsize) command += "ASSERT({} = ({} & {}));\n".format(tmpWeight[0], lout, loutRotated) for i in range(1, wordsize): command += "ASSERT({} = ({} & {}));\n".format( tmpWeight[i], lout, rotr(tmpWeight[i - 1], deltarot, wordsize)) abits = "BVXOR({}, {})".format(lout, tmpWeight[0]) for i in range(1, wordsize): abits = "BVXOR({}, {})".format(tmpWeight[i], abits) #abits = y_in #only use weight #Weight computation #command += "ASSERT({0} = (IF {1} = 0x{3} THEN BVSUB({4},0x{3},0x{5}1) \ # ELSE {2} ENDIF));\n".format( # w, y_in, abits, "f"*(wordsize / 4), # wordsize, "0"*((wordsize / 4) - 1)) command += "ASSERT({} = {});\n".format(w, abits) #Parity Checks command += "ASSERT({} = {});\n".format( sbits[0], rotr("({} & ~{} & ~{})".format( rotr(lout, deltarot, wordsize), lout, rotr(abits, deltarot, wordsize)), 1, wordsize)) command += "ASSERT({} = {});\n".format( pbits[0], rotl("({} & {})".format(sbits[0], lin), 2*deltarot, wordsize)) for i in range(1, wordsize): command += "ASSERT({} = {});\n".format( sbits[i], rotl("({} & {})".format( rotl(sbits[i - 1], deltarot, wordsize), rotr(sbits[i-1], self.rot_beta, wordsize)), deltarot, wordsize) ) command += "ASSERT({} = {});\n".format( pbits[i], rotl("BVXOR({}, {} & {})".format( pbits[i - 1], sbits[i], lin), 2*deltarot, wordsize) ) command += "ASSERT({} = 0x{});\n".format(pbits[wordsize - 1], "0"*(wordsize // 4)) stp_file.write(command) return
def getStringForSipRound(self, v0_in, v1_in, v2_in, v3_in, a0, a1, a2, a3, v0_out, v1_out, v2_out, v3_out, w0, w1, w2, w3, wordsize): """ Returns a string representing SipRound in STP. a0 = (v1 + v0) <<< 32 a1 = (v1 + v0) ^ (v1 <<< 13) a2 = (v2 + v3) a3 = (v2 + v3) ^ (v3 <<< 16) v0_out = (a0 + a3) v1_out = (a2 + a1) ^ (a1 <<< 17) v2_out = (a2 + a1) <<< 32 v3_out = (a0 + a3) ^ (a3 <<< 21) """ command = "" #Assert intermediate values #Rotate right to get correct output value #a0 command += "ASSERT(" command += stpcommands.getStringAdd( v1_in, v0_in, rotr(a0, 32, wordsize), wordsize) command += ");\n" #a1 command += "ASSERT({} = BVXOR({}, {}));\n".format( a1, rotl(v1_in, 13, wordsize), rotr(a0, 32, wordsize)) #a2 command += "ASSERT(" command += stpcommands.getStringAdd(v2_in, v3_in, a2, wordsize) command += ");\n" #a3 command += "ASSERT({} = BVXOR({}, {}));\n".format( a3, rotl(v3_in, 16, wordsize), a2) #v0_out command += "ASSERT(" command += stpcommands.getStringAdd(a0, a3, v0_out, wordsize) command += ");\n" #v1_out command += "ASSERT({} = BVXOR({}, {}));\n".format( v1_out, rotl(a1, 17, wordsize), rotr(v2_out, 32, wordsize)) #v2_out command += "ASSERT(" command += stpcommands.getStringAdd( a2, a1, rotr(v2_out, 32, wordsize), wordsize) command += ");\n" #v3_out command += "ASSERT({} = BVXOR({}, {}));\n".format( v3_out, rotl(a3, 21, wordsize), v0_out) # Lipmaa and Moriai command += "ASSERT({0} = ~".format(w0) command += stpcommands.getStringEq( v1_in, v0_in, rotr(a0, 32, wordsize)) command += ");\n" command += "ASSERT({0} = ~".format(w1) command += stpcommands.getStringEq(v2_in, v3_in, a2) command += ");\n" command += "ASSERT({0} = ~".format(w2) command += stpcommands.getStringEq(a0, a3, v0_out) command += ");\n" command += "ASSERT({0} = ~".format(w3) command += stpcommands.getStringEq( a2, a1, rotr(v2_out, 32, wordsize)) command += ");\n" return command
def getDoubleBits(self, xin, rot_alpha, rot_beta): command = "({0} & ~{1} & {2})".format( rotl(xin, rot_beta, 5), rotl(xin, rot_alpha, 5), rotl(xin, 2*rot_alpha - rot_beta, 5)) return command
def setupKeccakRound(self, stp_file, rnd, s, a, b, c, d, wordsize, tmp, w, m, xin, xout, andOut): """ Model for one round of Keccak. """ command = "" #xor the state with the message for the first two words for x in range(5): for y in range(5): if(x == 0 and y == 0) or (x == 1 and y == 0): command += "ASSERT({}=BVXOR({},{}));\n".format( a[x + 5*y + 25*rnd], s[x + 5*y + 25*rnd], m[x + 2*rnd]) else: command += "ASSERT({}={});\n".format( a[x + 5*y + 25*rnd], s[x + 5*y + 25*rnd]) # Linear functions for i in range(5): command += "ASSERT({} = BVXOR({}, BVXOR({}, BVXOR({}, BVXOR({}, {})))));\n".format( c[i + 5*rnd], a[i + 5*0 + 25*rnd], a[i + 5*1 + 25*rnd], a[i + 5*2 + 25*rnd], a[i + 5*3 + 25*rnd], a[i + 5*4 + 25*rnd]) # Compute intermediate values for i in range(5): command += "ASSERT({} = BVXOR({}, {}));\n".format( d[i + 5*rnd], c[(i - 1) % 5 + 5*rnd], rotl(c[(i + 1) % 5 + 5*rnd], 1, wordsize)) # Rho and Pi for x in range(5): for y in range(5): new_b_index = y + 5*((2*x + 3*y) % 5) + 25*rnd tmp_xor = "BVXOR({}, {})".format(a[x + 5*y + 25*rnd], d[x + 5*rnd]) command += "ASSERT({} = {});\n".format( b[new_b_index], rotl(tmp_xor, self.RO[x][y], wordsize)) # Chi rot_alpha = 2 rot_beta = 1 weight_sum = "" for y in range(5): for z in range(wordsize): # Construct S-box input command += "ASSERT({}={});\n".format( xin[z + wordsize*y + 5*wordsize*rnd], b[0 + 5*y + 25*rnd] + "[{0}:{0}]".format(z) + "@" + b[1 + 5*y + 25*rnd] + "[{0}:{0}]".format(z) + "@" + b[2 + 5*y + 25*rnd] + "[{0}:{0}]".format(z) + "@" + b[3 + 5*y + 25*rnd] + "[{0}:{0}]".format(z) + "@" + b[4 + 5*y + 25*rnd] + "[{0}:{0}]".format(z)) # Construct S-box output command += "ASSERT({}={});\n".format( xout[z + wordsize*y + 5*wordsize*rnd], s[0 + 5*y + 25*(rnd+1)] + "[{0}:{0}]".format(z) + "@" + s[1 + 5*y + 25*(rnd+1)] + "[{0}:{0}]".format(z) + "@" + s[2 + 5*y + 25*(rnd+1)] + "[{0}:{0}]".format(z) + "@" + s[3 + 5*y + 25*(rnd+1)] + "[{0}:{0}]".format(z) + "@" + s[4 + 5*y + 25*(rnd+1)] + "[{0}:{0}]".format(z)) xin_rotalpha = rotl(xin[z + wordsize*y + 5*wordsize*rnd], rot_alpha, 5) xin_rotbeta = rotl(xin[z + wordsize*y + 5*wordsize*rnd], rot_beta, 5) #Deal with dependent inputs varibits = "({0} | {1})".format(xin_rotalpha, xin_rotbeta) doublebits = self.getDoubleBits(xin[z + wordsize*y + 5*wordsize*rnd], rot_alpha, rot_beta) #Check for valid difference firstcheck = "({} & ~{})".format(andOut[z + wordsize*y + 5*wordsize*rnd], varibits) secondcheck = "(~BVXOR({}, {}) & {})".format( andOut[z + wordsize*y + 5*wordsize*rnd], rotl(andOut[z + wordsize*y + 5*wordsize*rnd], rot_alpha - rot_beta, 5), doublebits) thirdcheck = "(IF {0} = 0b{1} THEN BVMOD(5, {0}, 0b00010) ELSE 0b{2}ENDIF)".format( xin[z + wordsize*y + 5*wordsize*rnd], "11111", "00000") command += "ASSERT(({} | {} | {}) = 0b{});\n".format(firstcheck, secondcheck, thirdcheck, "00000") #Assert XORs command += "ASSERT({} = BVXOR({},{}));\n".format( xout[z + wordsize*y + 5*wordsize*rnd], xin[z + wordsize*y + 5*wordsize*rnd], andOut[z + wordsize*y + 5*wordsize*rnd]) #Weight computation command += ("ASSERT({0} = (IF {1} = 0b{4} THEN BVSUB({5},0b{4},0b{6}1)" "ELSE BVXOR({2}, {3}) ENDIF));\n".format( tmp[z + wordsize*y + 5*wordsize*rnd], xin[z + wordsize*y + 5*wordsize*rnd], varibits, doublebits, "1"*5, 5, "0"*4)) weight_sum += ("0b{0}@(BVPLUS({1}, {2}[0:0], {2}[1:1], " "{2}[2:2],{2}[3:3], {2}[4:4])),".format( "0"*11, 5, "0b0000@" + tmp[z + wordsize*y + 5*wordsize*rnd])) command += "ASSERT({}=BVPLUS({},{}));\n".format(w[rnd], 16, weight_sum[:-1]) stp_file.write(command) return
def setupAsconRound(self, stp_file, rnd, s, a, b, c, wordsize, tmp, w, xin, xout, andout): """ Model for one round of Ascon. """ command = "" weight_sum = "" # Linear part in S-box command += "ASSERT({} = BVXOR({}, {}));\n".format( a[0 + 5 * rnd], s[0 + 5 * rnd], s[4 + 5 * rnd]) command += "ASSERT({} = {});\n".format(a[1 + 5 * rnd], s[1 + 5 * rnd]) command += "ASSERT({} = BVXOR({}, {}));\n".format( a[2 + 5 * rnd], s[2 + 5 * rnd], s[1 + 5 * rnd]) command += "ASSERT({} = {});\n".format(a[3 + 5 * rnd], s[3 + 5 * rnd]) command += "ASSERT({} = BVXOR({}, {}));\n".format( a[4 + 5 * rnd], s[4 + 5 * rnd], s[3 + 5 * rnd]) # Model for the S-box for z in range(wordsize): # Construct S-box input command += "ASSERT({}={});\n".format( xin[z + 5 * wordsize * rnd], a[0 + 5 * rnd] + "[{0}:{0}]".format(z) + "@" + a[1 + 5 * rnd] + "[{0}:{0}]".format(z) + "@" + a[2 + 5 * rnd] + "[{0}:{0}]".format(z) + "@" + a[3 + 5 * rnd] + "[{0}:{0}]".format(z) + "@" + a[4 + 5 * rnd] + "[{0}:{0}]".format(z)) # Construct S-box output command += "ASSERT({}={});\n".format( xout[z + 5 * wordsize * rnd], b[0 + 5 * rnd] + "[{0}:{0}]".format(z) + "@" + b[1 + 5 * rnd] + "[{0}:{0}]".format(z) + "@" + b[2 + 5 * rnd] + "[{0}:{0}]".format(z) + "@" + b[3 + 5 * rnd] + "[{0}:{0}]".format(z) + "@" + b[4 + 5 * rnd] + "[{0}:{0}]".format(z)) xin_rotalpha = rotl(xin[z + 5 * wordsize * rnd], 2, 5) xin_rotbeta = rotl(xin[z + 5 * wordsize * rnd], 1, 5) #Deal with dependent inputs varibits = "({0} | {1})".format(xin_rotalpha, xin_rotbeta) doublebits = self.getDoubleBits(xin[z + 5 * wordsize * rnd]) #Check for valid difference firstcheck = "({} & ~{})".format(andout[z + 5 * wordsize * rnd], varibits) secondcheck = "(~BVXOR({}, {}) & {})".format( andout[z + 5 * wordsize * rnd], rotl(andout[z + 5 * wordsize * rnd], 2 - 1, 5), doublebits) thirdcheck = "(IF {0} = 0b{1} THEN BVMOD(5, {0}, 0b00010) ELSE 0b{2}ENDIF)".format( xin[z + 5 * wordsize * rnd], "11111", "00000") command += "ASSERT(({} | {} | {}) = 0b{});\n".format( firstcheck, secondcheck, thirdcheck, "00000") #Assert XORs command += "ASSERT({} = BVXOR({},{}));\n".format( xout[z + 5 * wordsize * rnd], xin[z + 5 * wordsize * rnd], andout[z + 5 * wordsize * rnd]) #Weight computation command += ( "ASSERT({0} = (IF {1} = 0b{4} THEN BVSUB({5},0b{4},0b{6}1)" "ELSE BVXOR({2}, {3}) ENDIF));\n".format( tmp[z + 5 * wordsize * rnd], xin[z + 5 * wordsize * rnd], varibits, doublebits, "1" * 5, 5, "0" * 4)) weight_sum += ("0b{0}@(BVPLUS({1}, {2}[0:0], {2}[1:1], " "{2}[2:2],{2}[3:3], {2}[4:4])),".format( "0" * 11, 5, "0b0000@" + tmp[z + 5 * wordsize * rnd])) command += "ASSERT({}=BVPLUS({},{}));\n".format( w[rnd], 16, weight_sum[:-1]) # Linear after S-box command += "ASSERT({} = BVXOR({}, {}));\n".format( c[0 + 5 * rnd], b[0 + 5 * rnd], b[4 + 5 * rnd]) command += "ASSERT({} = BVXOR({}, {}));\n".format( c[1 + 5 * rnd], b[0 + 5 * rnd], b[1 + 5 * rnd]) command += "ASSERT({} = {});\n".format(c[2 + 5 * rnd], b[2 + 5 * rnd]) command += "ASSERT({} = BVXOR({}, {}));\n".format( c[3 + 5 * rnd], b[2 + 5 * rnd], b[3 + 5 * rnd]) command += "ASSERT({} = {});\n".format(c[4 + 5 * rnd], b[4 + 5 * rnd]) # Linear functions rot_constants = [[19, 28], [61, 39], [1, 6], [10, 17], [7, 41]] for row in range(5): command += "ASSERT({} = BVXOR({}, BVXOR({}, {})));\n".format( s[row + 5 * (rnd + 1)], c[row + 5 * rnd], rotr(c[row + 5 * rnd], rot_constants[row][0], wordsize), rotr(c[row + 5 * rnd], rot_constants[row][1], wordsize), ) stp_file.write(command) return
def getDoubleBits(self, xin): command = "({0} & ~{1} & {2})".format(rotl(xin, 1, 5), rotl(xin, 2, 5), rotl(xin, 2 * 2 - 1, 5)) return command
def getDoubleBits(self, xin, rot_alpha, rot_beta): command = "({0} & ~{1} & {2})".format( rotl(xin, rot_beta, 5), rotl(xin, rot_alpha, 5), rotl(xin, 2 * rot_alpha - rot_beta, 5)) return command
def getStringForSipRound(self, v0_in, v1_in, v2_in, v3_in, a0, a1, a2, a3, v0_out, v1_out, v2_out, v3_out, w0, w1, w2, w3, wordsize): """ Returns a string representing SipRound in STP. a0 = (v1 + v0) <<< 32 a1 = (v1 + v0) ^ (v1 <<< 13) a2 = (v2 + v3) a3 = (v2 + v3) ^ (v3 <<< 16) v0_out = (a0 + a3) v1_out = (a2 + a1) ^ (a1 <<< 17) v2_out = (a2 + a1) <<< 32 v3_out = (a0 + a3) ^ (a3 <<< 21) """ command = "" #Assert intermediate values #Rotate right to get correct output value #a0 command += "ASSERT(" command += stpcommands.getStringAdd(v1_in, v0_in, rotr(a0, 32, wordsize), wordsize) command += ");\n" #a1 command += "ASSERT({} = BVXOR({}, {}));\n".format( a1, rotl(v1_in, 13, wordsize), rotr(a0, 32, wordsize)) #a2 command += "ASSERT(" command += stpcommands.getStringAdd(v2_in, v3_in, a2, wordsize) command += ");\n" #a3 command += "ASSERT({} = BVXOR({}, {}));\n".format( a3, rotl(v3_in, 16, wordsize), a2) #v0_out command += "ASSERT(" command += stpcommands.getStringAdd(a0, a3, v0_out, wordsize) command += ");\n" #v1_out command += "ASSERT({} = BVXOR({}, {}));\n".format( v1_out, rotl(a1, 17, wordsize), rotr(v2_out, 32, wordsize)) #v2_out command += "ASSERT(" command += stpcommands.getStringAdd(a2, a1, rotr(v2_out, 32, wordsize), wordsize) command += ");\n" #v3_out command += "ASSERT({} = BVXOR({}, {}));\n".format( v3_out, rotl(a3, 21, wordsize), v0_out) # Lipmaa and Moriai command += "ASSERT({0} = ~".format(w0) command += stpcommands.getStringEq(v1_in, v0_in, rotr(a0, 32, wordsize)) command += ");\n" command += "ASSERT({0} = ~".format(w1) command += stpcommands.getStringEq(v2_in, v3_in, a2) command += ");\n" command += "ASSERT({0} = ~".format(w2) command += stpcommands.getStringEq(a0, a3, v0_out) command += ");\n" command += "ASSERT({0} = ~".format(w3) command += stpcommands.getStringEq(a2, a1, rotr(v2_out, 32, wordsize)) command += ");\n" return command
def setupKeccakRound(self, stp_file, rnd, s, b, c, d, wordsize, tmp, w, xin, xout, andOut): """ Model for one round of Keccak. """ command = "" # Linear functions for i in range(5): command += "ASSERT({} = BVXOR({}, BVXOR({}, BVXOR({}, BVXOR({}, {})))));\n".format( c[i + 5 * rnd], s[i + 5 * 0 + 25 * rnd], s[i + 5 * 1 + 25 * rnd], s[i + 5 * 2 + 25 * rnd], s[i + 5 * 3 + 25 * rnd], s[i + 5 * 4 + 25 * rnd]) # Compute intermediate values for i in range(5): command += "ASSERT({} = BVXOR({}, {}));\n".format( d[i + 5 * rnd], c[(i - 1) % 5 + 5 * rnd], rotl(c[(i + 1) % 5 + 5 * rnd], 1, wordsize)) # Rho and Pi for x in range(5): for y in range(5): new_b_index = y + 5 * ((2 * x + 3 * y) % 5) + 25 * rnd tmp_xor = "BVXOR({}, {})".format(s[x + 5 * y + 25 * rnd], d[x + 5 * rnd]) command += "ASSERT({} = {});\n".format( b[new_b_index], rotl(tmp_xor, self.RO[x][y], wordsize)) # Chi rot_alpha = 2 rot_beta = 1 weight_sum = "" for y in range(5): for z in range(wordsize): # Construct S-box input command += "ASSERT({}={});\n".format( xin[z + wordsize * y + 5 * wordsize * rnd], b[0 + 5 * y + 25 * rnd] + "[{0}:{0}]".format(z) + "@" + b[1 + 5 * y + 25 * rnd] + "[{0}:{0}]".format(z) + "@" + b[2 + 5 * y + 25 * rnd] + "[{0}:{0}]".format(z) + "@" + b[3 + 5 * y + 25 * rnd] + "[{0}:{0}]".format(z) + "@" + b[4 + 5 * y + 25 * rnd] + "[{0}:{0}]".format(z)) # Construct S-box output command += "ASSERT({}={});\n".format( xout[z + wordsize * y + 5 * wordsize * rnd], s[0 + 5 * y + 25 * (rnd + 1)] + "[{0}:{0}]".format(z) + "@" + s[1 + 5 * y + 25 * (rnd + 1)] + "[{0}:{0}]".format(z) + "@" + s[2 + 5 * y + 25 * (rnd + 1)] + "[{0}:{0}]".format(z) + "@" + s[3 + 5 * y + 25 * (rnd + 1)] + "[{0}:{0}]".format(z) + "@" + s[4 + 5 * y + 25 * (rnd + 1)] + "[{0}:{0}]".format(z)) xin_rotalpha = rotl(xin[z + wordsize * y + 5 * wordsize * rnd], rot_alpha, 5) xin_rotbeta = rotl(xin[z + wordsize * y + 5 * wordsize * rnd], rot_beta, 5) #Deal with dependent inputs varibits = "({0} | {1})".format(xin_rotalpha, xin_rotbeta) doublebits = self.getDoubleBits( xin[z + wordsize * y + 5 * wordsize * rnd], rot_alpha, rot_beta) #Check for valid difference firstcheck = "({} & ~{})".format( andOut[z + wordsize * y + 5 * wordsize * rnd], varibits) secondcheck = "(~BVXOR({}, {}) & {})".format( andOut[z + wordsize * y + 5 * wordsize * rnd], rotl(andOut[z + wordsize * y + 5 * wordsize * rnd], rot_alpha - rot_beta, 5), doublebits) thirdcheck = "(IF {0} = 0b{1} THEN BVMOD(5, {0}, 0b00010) ELSE 0b{2}ENDIF)".format( xin[z + wordsize * y + 5 * wordsize * rnd], "11111", "00000") command += "ASSERT(({} | {} | {}) = 0b{});\n".format( firstcheck, secondcheck, thirdcheck, "00000") #Assert XORs command += "ASSERT({} = BVXOR({},{}));\n".format( xout[z + wordsize * y + 5 * wordsize * rnd], xin[z + wordsize * y + 5 * wordsize * rnd], andOut[z + wordsize * y + 5 * wordsize * rnd]) #Weight computation if rnd != 3: command += ( "ASSERT({0} = (IF {1} = 0b{4} THEN BVSUB({5},0b{4},0b{6}1)" "ELSE BVXOR({2}, {3}) ENDIF));\n".format( tmp[z + wordsize * y + 5 * wordsize * rnd], xin[z + wordsize * y + 5 * wordsize * rnd], varibits, doublebits, "1" * 5, 5, "0" * 4)) else: command += ("ASSERT({0} = {1});\n".format( tmp[z + wordsize * y + 5 * wordsize * rnd], "0b00000")) weight_sum += ("0b{0}@(BVPLUS({1}, {2}[0:0], {2}[1:1], " "{2}[2:2],{2}[3:3], {2}[4:4])),".format( "0" * 11, 5, "0b0000@" + tmp[z + wordsize * y + 5 * wordsize * rnd])) command += "ASSERT({}=BVPLUS({},{}));\n".format( w[rnd], 16, weight_sum[:-1]) stp_file.write(command) return
def getDoubleBits(self, xin): command = "({0} & ~{1} & {2})".format( rotl(xin, 1, 5), rotl(xin, 2, 5), rotl(xin, 2*2 - 1, 5)) return command
def setupSimonRound(self, stp_file, x_in, y_in, x_out, y_out, and_out, b, c, abits, w, tmpWeight, sbits, pbits, wordsize): """ Model for linear behaviour of one round SIMON. y[i+1] = x[i] x[i+1] = (x[i] <<< 1) & (x[i] <<< 8) ^ y[i] ^ (x[i] << 2) This is a loop unrolled version of the model presented in http://eprint.iacr.org/2015/145 """ command = "" deltarot = self.rot_alpha - self.rot_beta lout = y_in lin = "BVXOR(BVXOR({}, {}), {})".format( x_in, rotr(lout, self.rot_gamma, wordsize), y_out) #lin = "BVXOR({}, {})".format(x_in, rotr(lout, self.rot_gamma, wordsize)) #Assert(y_out = x_in) command += "ASSERT({} = {});\n".format(x_out, y_in) #Assert for AND linear approximation tmp = "BVXOR(({0} | {1}), {2}) & {2}".format( rotr(lout, self.rot_alpha, wordsize), rotr(lout, self.rot_beta, wordsize), lin) command += "ASSERT({} = 0x{});\n".format(tmp, "0" * (wordsize // 4)) #Assert for y_out # command += "ASSERT({0} = BVXOR({1}, BVXOR({2}, BVXOR({3}, {4}))));\n".format( # y_out, x_in, rotr(lout, self.rot_alpha, wordsize), rotr(lout, self.rot_beta, wordsize), # rotr(x_out, self.rot_gamma, wordsize)) command += "ASSERT({0} = BVXOR({1}, BVXOR({2}, {3})));\n".format( y_out, x_in, rotr(x_out, self.rot_gamma, wordsize), lin) #For weight computation #Compute abits loutRotated = rotr(lout, deltarot, wordsize) command += "ASSERT({} = ({} & {}));\n".format(tmpWeight[0], lout, loutRotated) for i in range(1, wordsize): command += "ASSERT({} = ({} & {}));\n".format( tmpWeight[i], lout, rotr(tmpWeight[i - 1], deltarot, wordsize)) abits = "BVXOR({}, {})".format(lout, tmpWeight[0]) for i in range(1, wordsize): abits = "BVXOR({}, {})".format(tmpWeight[i], abits) #abits = y_in #only use weight #Weight computation #command += "ASSERT({0} = (IF {1} = 0x{3} THEN BVSUB({4},0x{3},0x{5}1) \ # ELSE {2} ENDIF));\n".format( # w, y_in, abits, "f"*(wordsize / 4), # wordsize, "0"*((wordsize / 4) - 1)) command += "ASSERT({} = {});\n".format(w, abits) #Parity Checks command += "ASSERT({} = {});\n".format( sbits[0], rotr( "({} & ~{} & ~{})".format(rotr(lout, deltarot, wordsize), lout, rotr(abits, deltarot, wordsize)), 1, wordsize)) command += "ASSERT({} = {});\n".format( pbits[0], rotl("({} & {})".format(sbits[0], lin), 2 * deltarot, wordsize)) for i in range(1, wordsize): command += "ASSERT({} = {});\n".format( sbits[i], rotl( "({} & {})".format( rotl(sbits[i - 1], deltarot, wordsize), rotr(sbits[i - 1], self.rot_beta, wordsize)), deltarot, wordsize)) command += "ASSERT({} = {});\n".format( pbits[i], rotl("BVXOR({}, {} & {})".format(pbits[i - 1], sbits[i], lin), 2 * deltarot, wordsize)) command += "ASSERT({} = 0x{});\n".format(pbits[wordsize - 1], "0" * (wordsize // 4)) stp_file.write(command) return
def getDoubleBits(self, x_in, wordsize): command = "({0} & ~{1} & {2})".format( rotl(x_in, self.rot_beta, wordsize), rotl(x_in, self.rot_alpha, wordsize), rotl(x_in, 2 * self.rot_alpha - self.rot_beta, wordsize)) return command
def setupRound(self, stp_file, x_in, y_in, x_out, y_out, out_G0, out_G1, rot_G0, rot_G1, xor_G, perm_G, act_flag, w, wordsize): """ Model for differential behaviour of one round """ command = "" # 1. y_out = x_in command += "ASSERT({} = {});\n".format(y_out, x_in) # 2. pass SSb: x -> out_G0, out_G1 for i in range(wordsize // 4): s_in_4_bit = "{0}[{1}:{1}]@{0}[{2}:{2}]@" \ "{0}[{3}:{3}]@{0}[{4}:{4}]".format( x_in, wordsize - 1 - 4 * i - 0, wordsize - 1 - 4 * i - 1, wordsize - 1 - 4 * i - 2, wordsize - 1 - 4 * i - 3, ) s_out_4_bit_G0 = "{0}[{1}:{1}]@{0}[{2}:{2}]@" \ "{0}[{3}:{3}]@{0}[{4}:{4}]".format( out_G0, wordsize - 1 - 4 * i - 0, wordsize - 1 - 4 * i - 1, wordsize - 1 - 4 * i - 2, wordsize - 1 - 4 * i - 3, ) s_out_4_bit_G1 = "{0}[{1}:{1}]@{0}[{2}:{2}]@" \ "{0}[{3}:{3}]@{0}[{4}:{4}]".format( out_G1, wordsize - 1 - 4 * i - 0, wordsize - 1 - 4 * i - 1, wordsize - 1 - 4 * i - 2, wordsize - 1 - 4 * i - 3, ) command += "ASSERT(SBOX[{}@{}@{}] = 0bin1);\n".format( s_in_4_bit, s_out_4_bit_G0, s_out_4_bit_G1) command += "ASSERT({1} = (IF {0} = 0bin0000 " \ "THEN 0bin0 " \ "ELSE 0bin1 ENDIF));\n".format( s_in_4_bit, "{0}[{1}:{1}]".format(act_flag, wordsize // 4 - 1 - i)) # 3. rot out_G0, out_G1 out_G0_rotalpha = rotl(out_G0, self.rot_alpha, wordsize) out_G1_rotbeta = rotl(out_G1, self.rot_beta, wordsize) command += "ASSERT({} = {});\n".format(rot_G0, out_G0_rotalpha) command += "ASSERT({} = {});\n".format(rot_G1, out_G1_rotbeta) # 4. G0 ^ G1 = xor_G command += "ASSERT({} = BVXOR({}, {}));\n".format( xor_G, rot_G0, rot_G1) # 4. xor_G PERM to perm_G for i in range(wordsize): command += "ASSERT({0}[{1}:{1}] = {2}[{3}:{3}]);\n".format( perm_G, self.PERM[i], xor_G, i) # 5. perm_G ^ y_in = x_out command += "ASSERT({} = BVXOR({}, {}));\n".format(y_in, perm_G, x_out) # 6. Weight computation sum_w_i = stpcommands.getWeightString([act_flag], wordsize // 4, 0, w) sum_w_i += '\n' command += sum_w_i stp_file.write(command) return