def __init__(self, oracle_cir, obf_cir): self.oracle_cir = oracle_cir self.obf_cir = obf_cir # generate solver formulas for w in self.oracle_cir.wire_objs: lst = [] for op in w.operands: lst.append(Symbol(op.name)) r = self.get_wire_formulas(w, lst) w.formula = Iff(Symbol(w.name), r) # generate formulas for two copies of obfuscated circuit ckt1 = self.gen_dip_chk('dc1', '_0', None) ckt2 = self.gen_dip_chk('dc2', '_1', None) output_xors = [] for w in self.obf_cir.output_wires: output_xors.append( Xor(Symbol(w.name + '@dc1'), Symbol(w.name + '@dc2'))) self.dip_gen_ckt = And(Or(output_xors), ckt1, ckt2) # key inequality circuit key_symbols1 = [] key_symbols2 = [] for w in self.obf_cir.wire_objs: if 'keyinput' in w.name: key_symbols1.append(Symbol(w.name + '_0')) key_symbols2.append(Symbol(w.name + '_1')) output_xors = [] for i in range(self.obf_cir.k_inputs): output_xors.append(Xor(key_symbols1[i], key_symbols2[i])) self.key_inequality_ckt = Or(output_xors)
def get_wire_formulas(w, lst): r = None if w.type == Wire.INPUT: r = Symbol(w.name) elif w.type == 'not': r = Not(lst[0]) elif w.type == 'buf': r = lst[0] elif w.type == 'buff': r = lst[0] elif w.type == 'and': r = And(lst) elif w.type == 'nand': r = And(lst) r = Not(r) elif w.type == 'or': r = Or(lst) elif w.type == 'nor': r = Or(lst) r = Not(r) elif w.type == 'xor': assert (len(lst) == 2) r = Xor(lst[0], lst[1]) elif w.type == 'xnor': assert (len(lst) == 2) r = Xor(lst[0], lst[1]) r = Not(r) elif w.type == 'mux': assert (len(lst) == 3) r = Or(And(Not(lst[0]), lst[1]), And(lst[0], lst[2])) else: logging.critical('unspecified gate type') exit() return r
def __init__(self, oracle_cir, obf_cir): self.orcl_cir = oracle_cir self.obf_cir = obf_cir self.key_subs = [{}, {}] orcl_wires = self.orcl_cir.wire_objs obf_wires = self.obf_cir.wire_objs # generate solver formulas self.gen_wire_formulas(self.orcl_cir) self.gen_wire_formulas(self.obf_cir) # create key substitution dictionary for w in self.obf_cir.key_wires: self.key_subs[0][Symbol(w)] = Symbol(w + '_0') self.key_subs[1][Symbol(w)] = Symbol(w + '_1') # generate formulas for two copies of obfuscated circuit ckt1 = [] ckt2 = [] for w in self.obf_cir.output_wires: ckt1.append(substitute(obf_wires[w].formula, self.key_subs[0])) ckt2.append(substitute(obf_wires[w].formula, self.key_subs[1])) output_xors = [] for i in range(len(self.obf_cir.output_wires)): output_xors.append(Xor(ckt1[i], ckt2[i])) self.dip_gen_ckt = Or(output_xors) # key inequality circuit key_symbols1 = [] key_symbols2 = [] for w in self.obf_cir.key_wires: key_symbols1.append(Symbol(w + '_0')) key_symbols2.append(Symbol(w + '_1')) output_xors = [] for i in range(len(key_symbols1)): output_xors.append(Xor(key_symbols1[i], key_symbols2[i])) self.key_inequality_ckt = Or(output_xors) # dip checker circuit self.dip_chk1 = [] self.dip_chk2 = [] for w in self.obf_cir.output_wires: self.dip_chk1.append(substitute(obf_wires[w].formula, self.key_subs[0])) self.dip_chk2.append(substitute(obf_wires[w].formula, self.key_subs[1]))
def gen_wire_formulas(self, circuit): wires = circuit.wire_objs for w in circuit.sorted_wires: wire = wires[w] lst = [] r = None for op in wire.operands: if op in (circuit.input_wires + circuit.key_wires): lst.append(Symbol(op)) else: lst.append(wires[op].formula) if wire.type == 'not': r = Not(lst[0]) elif wire.type == 'buf': r = lst[0] elif wire.type == 'and': r = And(lst) elif wire.type == 'nand': r = And(lst) r = Not(r) elif wire.type == 'or': r = Or(lst) elif wire.type == 'nor': r = Or(lst) r = Not(r) elif wire.type == 'xor': assert (len(lst) == 2) r = Xor(lst[0], lst[1]) # r = And(Or(lst[0], lst[1]), Not(And(lst[0], lst[1]))) elif wire.type == 'xnor': assert (len(lst) == 2) r = Xor(lst[0], lst[1]) # r = And(Or(lst[0], lst[1]), Not(And(lst[0], lst[1]))) r = Not(r) else: logging.critical('unspecified gate type: {}'.format(wire.type)) exit() wire.formula = r
def test_infix_extended(self): p, r, x, y = self.p, self.r, self.x, self.y get_env().enable_infix_notation = True self.assertEqual(Plus(p, Int(1)), p + 1) self.assertEqual(Plus(r, Real(1)), r + 1) self.assertEqual(Times(r, Real(1)), r * 1) self.assertEqual(Minus(p, Int(1)), p - 1) self.assertEqual(Minus(r, Real(1)), r - 1) self.assertEqual(Times(r, Real(1)), r * 1) self.assertEqual(Plus(r, Real(1.5)), r + 1.5) self.assertEqual(Minus(r, Real(1.5)), r - 1.5) self.assertEqual(Times(r, Real(1.5)), r * 1.5) self.assertEqual(Plus(r, Real(1.5)), 1.5 + r) self.assertEqual(Times(r, Real(1.5)), 1.5 * r) with self.assertRaises(TypeError): foo = p + 1.5 self.assertEqual(Not(x), ~x) self.assertEqual(Times(r, Real(-1)), -r) self.assertEqual(Times(p, Int(-1)), -p) self.assertEqual(Xor(x, y), x ^ y) self.assertEqual(And(x, y), x & y) self.assertEqual(Or(x, y), x | y) self.assertEqual(Or(x, TRUE()), x | True) self.assertEqual(Or(x, TRUE()), True | x) self.assertEqual(And(x, TRUE()), x & True) self.assertEqual(And(x, TRUE()), True & x) get_env().enable_infix_notation = False
def test_infix_extended(self): p, r, x, y = self.p, self.r, self.x, self.y get_env().enable_infix_notation = True self.assertEqual(Plus(p, Int(1)), p + 1) self.assertEqual(Plus(r, Real(1)), r + 1) self.assertEqual(Times(r, Real(1)), r * 1) self.assertEqual(Minus(p, Int(1)), p - 1) self.assertEqual(Minus(r, Real(1)), r - 1) self.assertEqual(Times(r, Real(1)), r * 1) self.assertEqual(Plus(r, Real(1.5)), r + 1.5) self.assertEqual(Minus(r, Real(1.5)), r - 1.5) self.assertEqual(Times(r, Real(1.5)), r * 1.5) self.assertEqual(Plus(r, Real(1.5)), 1.5 + r) self.assertEqual(Times(r, Real(1.5)), 1.5 * r) with self.assertRaises(PysmtTypeError): foo = p + 1.5 self.assertEqual(Not(x), ~x) self.assertEqual(Times(r, Real(-1)), -r) self.assertEqual(Times(p, Int(-1)), -p) self.assertEqual(Xor(x, y), x ^ y) self.assertEqual(And(x, y), x & y) self.assertEqual(Or(x, y), x | y) self.assertEqual(Or(x, TRUE()), x | True) self.assertEqual(Or(x, TRUE()), True | x) self.assertEqual(And(x, TRUE()), x & True) self.assertEqual(And(x, TRUE()), True & x) self.assertEqual(Iff(x, y), x.Iff(y)) self.assertEqual(And(x, y), x.And(y)) self.assertEqual(Or(x, y), x.Or(y)) self.assertEqual(Ite(x, TRUE(), FALSE()), x.Ite(TRUE(), FALSE())) with self.assertRaises(Exception): x.Ite(1, 2) self.assertEqual(6 - r, Plus(Times(r, Real(-1)), Real(6))) # BVs # BV_CONSTANT: We use directly python numbers # # Note: In this case, the width is implicit (yikes!) The # width of the constant is inferred by the use of a # symbol or operator that enforces a bit_width. # # This works in very simple cases. For complex # expressions it is advisable to create a shortcut for # the given BVType. const1 = 3 const2 = 0b011 const3 = 0x3 # Since these are python numbers, the following holds self.assertEqual(const1, const2) self.assertEqual(const1, const3) # However, we cannot use infix pySMT Equals, since const1 is a # python int!!! with self.assertRaises(AttributeError): const1.Equals(const2) # We use the usual syntax to build a constant with a fixed width const1_8 = self.mgr.BV(3, width=8) # In actual code, one can simply create a macro for this: _8bv = lambda v: self.mgr.BV(v, width=8) const1_8b = _8bv(3) self.assertEqual(const1_8, const1_8b) # Equals forces constants to have the width of the operand self.assertEqual(const1_8.Equals(const1), self.mgr.Equals(const1_8, const1_8b)) # Symbols bv8 = self.mgr.FreshSymbol(BV8) bv7 = self.mgr.FreshSymbol(BVType(7)) self.assertEqual(bv8.Equals(const1), bv8.Equals(const1_8)) # BV_AND, self.assertEqual(bv8 & const1, self.mgr.BVAnd(bv8, const1_8)) self.assertEqual(const1 & bv8, self.mgr.BVAnd(bv8, const1_8)) self.assertEqual(const1 & bv8, self.mgr.BVAnd(bv8, const1_8)) # BV_XOR, self.assertEqual(bv8 ^ const1, self.mgr.BVXor(bv8, const1_8)) self.assertEqual(const1 ^ bv8, self.mgr.BVXor(bv8, const1_8)) # BV_OR, self.assertEqual(bv8 | const1, self.mgr.BVOr(bv8, const1_8)) self.assertEqual(const1 | bv8, self.mgr.BVOr(bv8, const1_8)) # BV_ADD, self.assertEqual(bv8 + const1, self.mgr.BVAdd(bv8, const1_8)) self.assertEqual(const1 + bv8, self.mgr.BVAdd(bv8, const1_8)) # BV_SUB, self.assertEqual(bv8 - const1, self.mgr.BVSub(bv8, const1_8)) self.assertEqual(const1 - bv8, self.mgr.BVSub(const1_8, bv8)) # BV_MUL, self.assertEqual(bv8 * const1, self.mgr.BVMul(bv8, const1_8)) self.assertEqual(const1 * bv8, self.mgr.BVMul(bv8, const1_8)) # BV_NOT: # !!!WARNING!!! Cannot be applied to python constants!! # This results in a negative number with self.assertRaises(PysmtValueError): _8bv(~const1) # For symbols and expressions this works as expected self.assertEqual(~bv8, self.mgr.BVNot(bv8)) # BV_NEG -- Cannot be applied to 'infix' constants self.assertEqual(-bv8, self.mgr.BVNeg(bv8)) # BV_EXTRACT -- Cannot be applied to 'infix' constants self.assertEqual(bv8[0:7], self.mgr.BVExtract(bv8, 0, 7)) self.assertEqual(bv8[:7], self.mgr.BVExtract(bv8, end=7)) self.assertEqual(bv8[0:], self.mgr.BVExtract(bv8, start=0)) self.assertEqual(bv8[7], self.mgr.BVExtract(bv8, start=7, end=7)) # BV_ULT, self.assertEqual(bv8 < const1, self.mgr.BVULT(bv8, const1_8)) # BV_ULE, self.assertEqual(bv8 <= const1, self.mgr.BVULE(bv8, const1_8)) # BV_UGT self.assertEqual(bv8 > const1, self.mgr.BVUGT(bv8, const1_8)) # BV_UGE self.assertEqual(bv8 >= const1, self.mgr.BVUGE(bv8, const1_8)) # BV_LSHL, self.assertEqual(bv8 << const1, self.mgr.BVLShl(bv8, const1_8)) # BV_LSHR, self.assertEqual(bv8 >> const1, self.mgr.BVLShr(bv8, const1_8)) # BV_UDIV, self.assertEqual(bv8 / const1, self.mgr.BVUDiv(bv8, const1_8)) # BV_UREM, self.assertEqual(bv8 % const1, self.mgr.BVURem(bv8, const1_8)) # The following operators use the infix syntax left.Operator.right # These includes all signed operators # BVSLT, self.assertEqual(self.mgr.BVSLT(bv8, const1_8), bv8.BVSLT(const1_8)) #BVSLE, self.assertEqual(self.mgr.BVSLE(bv8, const1_8), bv8.BVSLE(const1_8)) #BVComp self.assertEqual(self.mgr.BVComp(bv8, const1_8), bv8.BVComp(const1_8)) #BVSDiv self.assertEqual(self.mgr.BVSDiv(bv8, const1_8), bv8.BVSDiv(const1_8)) #BVSRem self.assertEqual(self.mgr.BVSRem(bv8, const1_8), bv8.BVSRem(const1_8)) #BVAShr self.assertEqual(self.mgr.BVAShr(bv8, const1_8), bv8.BVAShr(const1_8)) #BVNand self.assertEqual(self.mgr.BVNand(bv8, const1_8), bv8.BVNand(const1_8)) #BVNor self.assertEqual(self.mgr.BVNor(bv8, const1_8), bv8.BVNor(const1_8)) #BVXnor self.assertEqual(self.mgr.BVXnor(bv8, const1_8), bv8.BVXnor(const1_8)) #BVSGT self.assertEqual(self.mgr.BVSGT(bv8, const1_8), bv8.BVSGT(const1_8)) #BVSGE self.assertEqual(self.mgr.BVSGE(bv8, const1_8), bv8.BVSGE(const1_8)) #BVSMod self.assertEqual(self.mgr.BVSMod(bv8, const1_8), bv8.BVSMod(const1_8)) #BVRol, self.assertEqual(self.mgr.BVRol(bv8, steps=5), bv8.BVRol(5)) #BVRor, self.assertEqual(self.mgr.BVRor(bv8, steps=5), bv8.BVRor(5)) #BVZExt, self.assertEqual(self.mgr.BVZExt(bv8, increase=4), bv8.BVZExt(4)) #BVSExt, self.assertEqual(self.mgr.BVSExt(bv8, increase=4), bv8.BVSExt(4)) #BVRepeat, self.assertEqual(self.mgr.BVRepeat(bv8, count=5), bv8.BVRepeat(5))
from pysmt.shortcuts import Symbol, is_sat, Xor Q = Symbol('Q') P = Symbol('P') prop1 = Xor(Q, P) print is_sat(prop1)