Beispiel #1
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
Beispiel #2
0
    def preprocess_cycles(self):
        from graph import cycle

        self.obf_cir.wire_objs = read_verilog_wires(self.args.o, 'generic')
        cycles_list = cycle.find_cycles(self.args, self.obf_cir.wire_objs)
        wires = self.obf_cir.wire_objs
        constraints = ""

        # for lat based circuits
        if self.config.enable_async:
            lats_list = []
            for cycle in cycles_list:
                has_ff = False
                for w in cycle:
                    if wires[w].type == Wire.DFF:
                        has_ff = True
                        break
                if not has_ff:
                    tmp = []
                    for w in cycle:
                        if wires[w].type == Wire.LAT:
                            tmp.append(w)
                    lats_list.append(tmp)

            for lats in lats_list:
                tmp = []
                for l in lats:
                    tmp.append("({{{}, {}}} == 2'b00)".format(
                        wires[l].operands[0], wires[l].operands[1]))
                tmp = ' || '.join(tmp)
                constraints += 'assume(({}) || (({}) && ({})) );\n'.format(
                    tmp, tmp.replace('00', '01'), tmp.replace('00', '10'))
            self.key_constraints = constraints
            self.key_constraints = self.key_constraints.replace(
                'keyinput', 'k1') + self.key_constraints.replace(
                    'keyinput', 'k2')
        else:
            # for mux based cycles (original cycsat)
            # TODO: to be implemented
            for cycle in cycles_list:
                for w in cycle:
                    if w.type == 'MUX2x1':
                        continue
            self.key_constraints = constraints
Beispiel #3
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
Beispiel #4
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
Beispiel #5
0
def verilog2bench(args):
    tmp_circuit = verilog2circuit(args.b)
    wires = read_verilog_wires(args.b)

    inputs = []
    bench_file = ""
    for p in tmp_circuit.input_wires:
        if tmp_circuit.input_wires[p] > 1:
            for i in range(tmp_circuit.input_wires[p]):
                inputs.append(sanitize_name('{}[{}]'.format(p, i)))
        else:
            inputs.append(sanitize_name('{}'.format(p)))
    for p in inputs:
        bench_file += 'INPUT({})\n'.format(p)

    outputs = []
    for p in tmp_circuit.output_wires:
        if tmp_circuit.output_wires[p] > 1:
            for i in range(tmp_circuit.output_wires[p]):
                outputs.append(sanitize_name('{}[{}]'.format(p, i)))
        else:
            outputs.append(sanitize_name('{}'.format(p)))
    for p in outputs:
        bench_file += 'OUTPUT({})\n'.format(p)

    for p in wires:
        operands = ''
        if len(wires[p].operands) > 1:
            for o in wires[p].operands:
                operands += sanitize_name(o) + ', '
            operands = operands[:-2]
        else:
            operands = sanitize_name(wires[p].operands[0])
            if "1'b0" in operands:
                operands = 'zero'
            elif "1'b1" in operands:
                operands = 'one'
        output = sanitize_name(p)
        bench_file += '{} = {}( {} )\n'.format(output, wires[p].type, operands)

    # add zero and one for 1'b0 and 1'b1
    bench_file += 'not_tmp = not( {} )\n'.format(inputs[0])
    bench_file += 'one = or( not_tmp,{} )\n'.format(inputs[0])
    bench_file += 'zero = and( not_tmp,{} )\n'.format(inputs[0])

    # check ports
    missing_vars = []
    for p in inputs:
        if not re.search(r'= .*\(.*{}.*\)'.format(p), bench_file):
            missing_vars.append(p)
    logging.warning('these inputs have not been used: {}'.format(missing_vars))

    missing_vars = []
    for p in outputs:
        if not re.search(r'{} = '.format(p), bench_file):
            missing_vars.append(p)
    logging.warning('these outputs are not driven: {}'.format(missing_vars))

    new_path = args.b.replace('.v', '.bench')
    design = open(new_path, "w")
    design.write(bench_file)
    exit()