Esempio n. 1
0
def rnd_obf(args, ast):
    ast_mgr = ASTWrapper(ast, args.b)
    circuit = ast_mgr.get_circuit(req_fanout=True, correct_order=False)
    wires = circuit.wire_objs

    i = 0
    obf_gates = []
    new_wires = []
    rep_wire_names = []
    rep_instances = []
    key_list = ""
    while i < args.k:
        rnd_w = wires[randint(0, len(wires) - 1)]
        if (rnd_w.type != Wire.INPUT) and (rnd_w.fanout != 0) and (
                rnd_w.instance not in rep_instances):
            key_val = randint(0, 1)
            key_list += str(key_val)
            if key_val == 0:
                gate_type = "xor"
            else:
                gate_type = "xnor"

            logging.warning(rnd_w.name + " is selected for obfuscation")

            new_w_name = rnd_w.name + "_obf"
            new_wires.append(new_w_name)
            rep_wire_names.append({rnd_w.name: new_w_name})
            rep_instances.append(rnd_w.instance)
            key_ports = Wire("keyinput" + str(i), "inp", [], 0)
            obf_gates.append(Wire(rnd_w.name, gate_type, [rnd_w, key_ports],
                                  0))
            rnd_w.name = new_w_name
            i = i + 1

    # old wire names should be replaced in their instances (for example G13 to G13_obf)
    ast_mgr.replace_wire_names(rep_wire_names, rep_instances)
    for i in range(args.k):
        ast_mgr.add_ports('keyinput{}'.format(i), 0, 'input')
    ast_mgr.add_wires(new_wires)
    ast_mgr.add_instances(obf_gates)
    ast_mgr.change_module_name(circuit.name + "_obf")

    bench_address = circuit.path
    bench_folder = bench_address[0:bench_address.
                                 rfind("/", 0, bench_address.rfind("/"))] + "/"
    output_folder = bench_folder + args.m + "/"
    obf_file_name = circuit.name + "_" + str(args.k) + ".v"
    write_verilog(ast_mgr.ast, obf_file_name, output_folder)

    key_list = key_list[::-1]
    key_list = "// key=" + key_list
    with open(output_folder + obf_file_name, 'r+') as f:
        content = f.read()
        f.seek(0, 0)
        f.write(key_list.rstrip('\r\n') + '\n' + content)
    return
Esempio n. 2
0
def rnd_obf(args):
    circuit = verilog2circuit(args.b)
    circuit.wire_objs = read_verilog_wires(args.b, 'generic')
    wires = circuit.wire_objs

    i = 0
    obf_gates = {}
    rep_instances = []
    key_list = ""
    while i < args.k:
        rnd_w = circuit.get_random_wire()
        if (rnd_w not in rep_instances) and (wires[rnd_w].type != Wire.DFF) and \
                (wires[rnd_w] != Wire.INPUT) and (rnd_w not in circuit.output_wires):
            logging.warning(rnd_w + " is selected for obfuscation")
            key_val = randint(0, 1)
            if key_val == 0:
                gate_type = "xor"
                key_list += '0'
            else:
                gate_type = "xnor"
                key_list += '1'

            rep_instances.append(rnd_w)
            w_tmp = rnd_w + '_obf'
            obf_gates[rnd_w] = Wire(rnd_w, gate_type, ['keyinput[{}]'.format(i), w_tmp])
            obf_gates[w_tmp] = Wire(w_tmp, wires[rnd_w].type, wires[rnd_w].operands)
            obf_gates[w_tmp].tag = wires[rnd_w].tag
            i = i + 1

    # old wire names should be replaced in their instances (e.g., G13 to G13_obf)
    for w in rep_instances:
        del wires[w]
    for w in obf_gates:
        wires[w] = obf_gates[w]

    circuit.input_wires['keyinput'] = i
    circuit.port_defs.append('keyinput')

    bench_address = circuit.folder_path
    output_folder = bench_address[0: bench_address.rfind("/", 0, bench_address.rfind("/"))] + "/{}/".format(args.m)
    obf_file_name = circuit.name + "_" + str(args.k) + ".v"
    verilog_text = circuit2verilog(circuit, circuit.name + "_obf")

    key_list = key_list[::-1]
    key_list = "// key=" + key_list
    with open(output_folder + obf_file_name, 'w') as f:
        f.write(key_list.rstrip('\r\n') + '\n\n')
        f.write(verilog_text)
    return
Esempio n. 3
0
def create_wire(type, in_port, out_port):
    w = None
    if 'nand' in type:
        assert len(in_port) > 1
        w = Wire(out_port, 'nand', in_port)
    elif 'and' in type:
        assert len(in_port) > 1
        w = Wire(out_port, 'and', in_port)
    elif 'xnor' in type:
        assert len(in_port) > 1
        w = Wire(out_port, 'xnor', in_port)
    elif 'xor' in type:
        assert len(in_port) > 1
        w = Wire(out_port, 'xor', in_port)
    elif 'nor' in type:
        assert len(in_port) > 1
        w = Wire(out_port, 'nor', in_port)
    elif 'or' in type:
        assert len(in_port) > 1
        w = Wire(out_port, 'or', in_port)
    elif ('inv' in type) or ('not' in type):
        assert len(in_port) == 1
        w = Wire(out_port, 'not', in_port)
    elif 'buf' in type:
        assert len(in_port) == 1
        w = Wire(out_port, 'buf', in_port)
    elif 'mx2' in type:
        assert len(in_port) > 1
        w = Wire(out_port, 'mux', in_port)
    elif 'mux' in type:
        assert len(in_port) > 1
        w = Wire(out_port, 'mux', in_port)
    else:
        logging.critical('undefined gate type: {}'.format(type))
        exit()
    return w
Esempio n. 4
0
def read_dffwrst_wires(path):
    # for designs with ffs with rst port
    try:
        with open(path, "r") as f:
            design = f.read()
            line = ''.join(design)
    except EnvironmentError:
        logging.critical('{} not found'.format(path))
        exit()

    wires = {}
    # match assign
    assigns = re.findall(r'assign (.*?) = (.*?);', line)
    for a in assigns:
        wires[a[0]] = Wire(a[0], 'buf', 1)
        wires[a[0]].operands = [a[1]]

    # match gates
    # g[0]: gate type; g[1]: gate tag; g[2]: gate ports
    gates = re.findall(r'^\s*(\S*?)\s*(\S*?)\s*\(([\s\S]*?)\);', line,
                       re.MULTILINE)
    for g in gates:
        ports = g[2].replace(' ', '').replace('\n', '').split(',')
        type = g[0].lower()
        if 'dff' in type:
            in_port = ports[4]
            q_port = ports[1]
            wires[q_port] = Wire(q_port, 'dff', 1)
            wires[q_port].operands = [in_port]
            wires[q_port].tag = g[1]
        else:
            if 'module' not in type:
                out_port = ports[0]
                in_port = ports[1:]
                wires[out_port] = create_wire(type, in_port, out_port)
                wires[out_port].operands = in_port
                wires[out_port].tag = g[1]
    return wires
Esempio n. 5
0
def lbll_obf(args):
    # latch-based obfuscation
    circuit = verilog2circuit(args.b)
    circuit.wire_objs = read_verilog_wires(args.b, 'generic')
    wires = circuit.wire_objs

    i = 0
    obf_gates = {}
    rep_instances = []
    key_list = ""
    while i <= args.k:
        r = randint(0, 2)
        if r == 0:
            for w in wires:
                if (w not in rep_instances) and (wires[w].type == Wire.DFF):
                    logging.warning(w + " is selected as modified FF")
                    rep_instances.append(w)
                    w_tmp = w + '_obf'
                    obf_gates[w_tmp] = Wire(w_tmp, 'lat', ['keyinput[{}]'.format(i), 'keyinput[{}]'.format(i+1), wires[w].operands[0]])
                    obf_gates[w] = Wire(w, 'lat', ['keyinput[{}]'.format(i+2), 'keyinput[{}]'.format(i+3), w_tmp])
                    key_list += '1001'
                    i = i + 4
                    break
        elif r == 1:
            for w in wires:
                if (w not in rep_instances) and (wires[w].type != Wire.DFF):
                    logging.warning(w + " is selected as path delay decoy")
                    rep_instances.append(w)
                    w_tmp = w + '_obf'
                    obf_gates[w_tmp] = wires[w]
                    obf_gates[w_tmp].name = w_tmp
                    obf_gates[w] = Wire(w, 'lat', ['keyinput[{}]'.format(i), 'keyinput[{}]'.format(i+1), w_tmp])
                    key_list += '11'
                    i = i + 2
                    break
        else:
            # continue
            for w1 in wires:
                if (w1 not in rep_instances) and (wires[w1].type != Wire.DFF):
                    for w2 in wires:
                        if (w2 not in rep_instances) and (wires[w2].type != Wire.DFF) and (w2 != w1):
                            logging.warning(w1 + " is selected as logic decoy")
                            rep_instances.append(w1)
                            w_tmp = w1 + '_obf'
                            obf_gates[w_tmp] = wires[w1]
                            obf_gates[w_tmp].name = w_tmp
                            lat_tmp = 'w_lat{}'.format(i)
                            obf_gates[lat_tmp] = Wire(lat_tmp, 'lat', ['keyinput[{}]'.format(i), 'keyinput[{}]'.format(i + 1), w2])
                            obf_gates[w1] = Wire(w1, 'or', [w_tmp, lat_tmp])
                            key_list += '00'
                            i = i + 2
                            break
                    break

    for w in rep_instances:
        del wires[w]
    for w in obf_gates:
        wires[w] = obf_gates[w]

    circuit.input_wires['keyinput'] = i
    circuit.port_defs.append('keyinput')

    bench_address = circuit.folder_path
    output_folder = bench_address[0: bench_address.rfind("/", 0, bench_address.rfind("/"))] + "/{}/".format(args.m)
    obf_file_name = circuit.name + "_" + str(args.k) + ".v"
    verilog_text = circuit2verilog(circuit, circuit.name + "_obf")

    key_list = key_list[::-1]
    key_list = "// key=" + key_list
    with open(output_folder + obf_file_name, 'w') as f:
        f.write(key_list.rstrip('\r\n') + '\n\n')
        f.write(verilog_text)
    return
Esempio n. 6
0
def bench2circuit(path):
    try:
        with open(path, "r") as f:
            bench_file = f.read()
    except EnvironmentError:
        logging.critical('{} not found'.format(path))
        exit()

    inputs = re.findall(r'INPUT\((.*?)\)', bench_file)
    outputs = re.findall(r'OUTPUT\((.*?)\)', bench_file)
    gates_match = re.findall(r'(.*?) = (.*?)\((.*?)\)', bench_file)

    wires = {}
    for g in gates_match:
        in_port = g[2].replace(' ', '').replace('\n', '').split(',')
        out_port = g[0]
        gate_type = g[1].lower()

        if 'dff' in gate_type:
            assert len(in_port) == 1
            wires[out_port] = Wire(out_port, 'dff', in_port)
        elif 'nand' in gate_type:
            assert len(in_port) > 1
            wires[out_port] = Wire(out_port, 'nand', in_port)
        elif 'and' in gate_type:
            assert len(in_port) > 1
            wires[out_port] = Wire(out_port, 'and', in_port)
        elif 'xnor' in gate_type:
            assert len(in_port) > 1
            wires[out_port] = Wire(out_port, 'xnor', in_port)
        elif 'xor' in gate_type:
            assert len(in_port) > 1
            wires[out_port] = Wire(out_port, 'xor', in_port)
        elif 'nor' in gate_type:
            assert len(in_port) > 1
            wires[out_port] = Wire(out_port, 'nor', in_port)
        elif 'or' in gate_type:
            assert len(in_port) > 1
            wires[out_port] = Wire(out_port, 'or', in_port)
        elif 'not' in gate_type:
            assert len(in_port) == 1
            wires[out_port] = Wire(out_port, 'not', in_port)
        elif 'buf' in gate_type:
            assert len(in_port) == 1
            wires[out_port] = Wire(out_port, 'buf', in_port)
        elif 'mux' in gate_type:
            assert len(in_port) == 3
            wires[out_port] = Wire(out_port, 'mux', in_port)
        else:
            logging.critical('undefined gate type: {}'.format(gate_type))
            exit()
        wires[out_port].operands = in_port

    for w in wires:
        for o in wires[w].operands:
            if (o in wires) or (o in inputs):
                continue
            else:
                logging.critical(
                    'wire {} is used but is not connected to anywhere'.format(
                        o))
                exit()

    keys = []
    for i in inputs:
        if 'keyinput' in i:
            keys.append(i)

    for k in keys:
        inputs.remove(k)

    circuit = Circuit(path[path.rfind("/") + 1:path.rfind(".")])
    circuit.folder_path = path[:path.rfind("/") + 1]
    circuit.file_name = path[path.rfind("/") + 1:]
    circuit.input_wires = inputs
    circuit.output_wires = outputs
    circuit.wire_objs = wires
    circuit.key_wires = keys

    logging.warning(
        'circuit: {}, inputs: {}, outputs: {}, keyinputs: {}'.format(
            circuit.name, len(circuit.input_wires), len(circuit.output_wires),
            len(keys)))
    return circuit
Esempio n. 7
0
    def __init__(self, orcl_cir, obf_cir):
        self.orcl_cir = orcl_cir
        self.obf_cir = obf_cir
        self.key_subs = [{}, {}]
        self.dip_ckt0 = []
        self.dip_ckt1 = []
        self.dip_ckt0_frame = []
        self.dip_ckt1_frame = []
        self.oracle_ckt_frame = []

        # generate solver formulas
        gen_wire_formulas(self.orcl_cir)
        gen_wire_formulas(self.obf_cir)

        # create symbols for primary outputs and next state wires
        orcl_wires = self.orcl_cir.wire_objs
        obf_wires = self.obf_cir.wire_objs

        for w in self.orcl_cir.output_wires:
            orcl_wires[w].formula = Iff(Symbol(w), orcl_wires[w].formula)

        for w in set(orcl_cir.next_state_wires):
            if w in orcl_cir.input_wires:
                # TODO: test for the next states that are connecting to the inputs
                print(w)
                orcl_wires[w] = Wire(w, Wire.INPUT, [])
                orcl_wires[w].formula = Symbol(w)
            else:
                orcl_wires[w].formula = Iff(Symbol(w), orcl_wires[w].formula)

        for w in self.obf_cir.output_wires:
            obf_wires[w].formula = Iff(Symbol(w), obf_wires[w].formula)

        for w in set(obf_cir.next_state_wires):
            if w not in obf_cir.output_wires:
                if w in obf_cir.input_wires:
                    obf_wires[w] = Wire(w, Wire.INPUT, [])
                    obf_wires[w].formula = Symbol(w)
                else:
                    obf_wires[w].formula = Iff(Symbol(w), obf_wires[w].formula)

        # 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
        for w in self.obf_cir.output_wires:
            self.dip_ckt0.append(
                substitute(obf_wires[w].formula, self.key_subs[0]))
            self.dip_ckt1.append(
                substitute(obf_wires[w].formula, self.key_subs[1]))

        # converted to set to ignore duplicate next_state_wires
        for w in self.obf_cir.next_state_wires:
            self.dip_ckt0.append(
                substitute(obf_wires[w].formula, self.key_subs[0]))
            self.dip_ckt1.append(
                substitute(obf_wires[w].formula, self.key_subs[1]))

        # key inequality circuit
        key_xors = []
        for w in self.obf_cir.key_wires:
            key_xors.append(
                Xor(Symbol('{}_0'.format(w)), Symbol('{}_1'.format(w))))
        self.key_inequality_ckt = Or(key_xors)
Esempio n. 8
0
def build_ce(cir):
    # ce_netlist = copy.copy(obf_cir.raw_netlist)
    rep_wire_names = {}
    seq_elements = []
    count = 0
    # cir = obf_cir
    cir.wire_objs = read_verilog_wires(cir.folder_path + cir.file_name,
                                       'generic')

    added_wires = {}
    for w in cir.wire_objs:
        if cir.wire_objs[w].type == 'dff':
            Q = w
            D = cir.wire_objs[w].operands[0]
            rep_wire_names[str(Q)] = "state[" + str(count) + "]"
            if ("'b" in D) or (D in cir.input_wires) or (D[:D.rfind('[')]
                                                         in cir.input_wires):
                # for constant 1'b1 and 1'b0 inputs
                r = "next_state[{}]".format(count)
                added_wires[r] = Wire(r, 'buf', [str(D)])
            else:
                rep_wire_names[str(D)] = "next_state[{}]".format(count)
            seq_elements.append(w)
            count = count + 1
    cir.wire_objs = {**cir.wire_objs, **added_wires}

    for w in cir.wire_objs:
        if cir.wire_objs[w].type == 'lat':
            Q = w
            D = cir.wire_objs[w].operands[0]
            rst = cir.wire_objs[w].operands[1]
            rep_wire_names[str(Q)] = "state[" + str(count) + "]"
            rep_wire_names[str(D)] = "next_state[" + str(count) + "]"
            rep_wire_names[str(rst)] = "next_state[" + str(count + 1) + "]"
            seq_elements.append(w)
            count = count + 2

    # remove dffs/lats
    for w in seq_elements:
        cir.wire_objs.pop(w)

    # change dff input/output wires to next_state/state
    for r in rep_wire_names:
        if r in cir.wire_objs:
            cir.wire_objs[rep_wire_names[r]] = cir.wire_objs[r]
            cir.wire_objs.pop(r)
        for w in cir.wire_objs:
            if r in cir.wire_objs[w].operands:
                cir.wire_objs[w].operands[cir.wire_objs[w].operands.index(
                    r)] = rep_wire_names[r]

    # add new buf gates for replaced outputs
    for r in rep_wire_names:
        if r in cir.output_wires:
            cir.wire_objs[r] = Wire(r, 'buf', [rep_wire_names[r]])
    # for vectorized wires
    for r in rep_wire_names:
        if r[:r.rfind('[')] in cir.output_wires:
            cir.wire_objs[r] = Wire(r, 'buf', [rep_wire_names[r]])

    # add ports
    cir.port_defs = cir.port_defs + ['state', 'next_state']
    cir.input_wires['state'] = count
    cir.output_wires['next_state'] = count

    verilog_text = circuit2verilog(cir, cir.name + '_ce')
    return verilog_text, count
Esempio n. 9
0
def read_cadence_verilog_wires(path):
    try:
        with open(path, "r") as f:
            design = f.read()
            line = ''.join(design)
    except EnvironmentError:
        logging.critical('{} not found'.format(path))
        exit()

    wires = {}
    # match assign
    assigns = re.findall(r'assign (.*?) = (.*?);', line)
    for a in assigns:
        wires[a[0]] = Wire(a[0], 'buf', 1)
        wires[a[0]].operands = [a[1]]

    # match gates
    # g[0]: gate type; g[1]: gate tag; g[2]: gate ports
    gates = re.findall(r'^\s*(\S*?)\s*(\S*?)\s*\(([\s\S]*?)\);', line,
                       re.MULTILINE)
    for g in gates:
        ports = g[2].replace(' ', '').replace('\n', '')
        gate_ports = re.findall(r'\.(.*?)\s*\((.*?)\)', ports)
        type = g[0].lower()
        if 'dff' in type:
            in_port = ''
            q_port = ''
            qn_port = ''
            for p in gate_ports:
                if p[0] == 'D':
                    in_port = p[1]
                elif p[0] == 'Q':
                    q_port = p[1]
                elif p[0] == 'QN':
                    qn_port = p[1]

            if q_port and qn_port:
                wires[q_port] = Wire(q_port, 'dff', 1)
                wires[q_port].operands = [in_port]
                wires[qn_port] = Wire(qn_port, 'not', 1)
                wires[qn_port].operands = [q_port]
            elif q_port:
                wires[q_port] = Wire(q_port, 'dff', 1)
                wires[q_port].operands = [in_port]
            elif qn_port:
                q_tmp = 'tmp_' + qn_port
                wires[q_tmp] = Wire(q_tmp, 'dff', 1)
                wires[q_tmp].operands = [in_port]
                wires[qn_port] = Wire(qn_port, 'not', 1)
                wires[qn_port].operands = [q_tmp]
            else:
                logging.critical('undefined dff definition: {}'.format(g[1]))
                exit()
        else:
            if 'module' not in type:
                in_port = []
                out_port = ''
                for p in gate_ports:
                    if p[0] == 'Y':
                        out_port = p[1]
                    elif p[0] == 'S0':
                        in_port.insert(0, p[1])
                    else:
                        in_port.append(p[1])
                wires[out_port] = create_wire(type, in_port, out_port)
                wires[out_port].operands = in_port
    return wires