Module logiclocking.utils
Various utils for working with logic-locked circuits.
Expand source code
"""Various utils for working with logic-locked circuits."""
from ast import literal_eval
import circuitgraph as cg
def check_for_difference(oracle, locked_circuit, key):
"""
Check the correctness of a key.
Returns any differences between the oracle and a locked circuit
with a specific key applied.
Parameters
----------
oracle: circuitgraph.Circuit
The unlocked circuit to check against.
locked_circuit: circuitgraph.Circuit
The locked circuit to apply the key to.
key: dict of str:bool
The key to check
Returns
-------
False or dict of str:bool
False if there is no difference, otherwise the assignment that
produced a difference.
"""
m = cg.tx.miter(oracle, locked_circuit)
key = {f"c1_{k}": v for k, v in key.items()}
live = cg.sat.solve(m, assumptions=key)
if not live:
return True
return cg.sat.solve(m, assumptions={"sat": True, **key})
def locked_unroll(
locked_circuit,
key,
num_copies,
D="D",
Q="Q",
ignore_pins="CK",
initial_values=None,
remove_unloaded=True,
prefix="cg_unroll",
):
"""
Unrolls a sequential circuit to prepare for a combinational attack.
This can be used for locks applied on sequential circuits that prevent
scan-chain access.
Note that this function uses the `prefix` variable to identify unrolled
nodes, so choosing a prefix that is already used in nodes in the sequential
circuit can cause undefined behavior.
Parameters
----------
locked_circuit: circuitgraph.Circuit
The circuit to unroll
key: list of str or dict of str:bool
The key inputs. If a dictionary is passed in, this key is used
to construct an unrolled oracle and this is returned in addition
to the unrolled locked circuit
num_copies: int
The number of unrolled copies of the circuit to create
D: str
The name of the D pin of the sequential elements
Q: str
The name of the Q pin of the sequential elements
ignore_pins: str or list of str
The pins on the sequential elements to ignore
initial_values: str or dict of str:str
The initial values of the data ports for the first timestep.
If None, the ports will be added as primary inputs.
If a single value ('0', '1', or 'x'), every flop will get that value.
Can also pass in dict mapping flop names to values.
remove_unloaded: bool
If True, unloaded inputs will be removed after unrolling. This can remove
unused sequential signals such as the clock and reset.
prefix: str
The prefix to use for naming unrolled nodes.
Returns
-------
circuitgraph.Circuit, circuitgraph.Circuit, dict of str:list of str
The unrolled locked circuit, the unrolled oracle, and the io map.
"""
locked_circuit_unrolled, io_map = cg.tx.sequential_unroll(
locked_circuit,
num_copies,
D,
Q,
ignore_pins=ignore_pins,
initial_values=initial_values,
remove_unloaded=remove_unloaded,
prefix=prefix,
)
for k in key:
locked_circuit_unrolled.set_type(io_map[k], "buf")
locked_circuit_unrolled.add(k, "input", fanout=io_map[k])
del io_map[k]
oracle_unrolled = locked_circuit_unrolled.copy()
for k, v in key.items():
oracle_unrolled.set_type(k, str(int(v)))
return locked_circuit_unrolled, oracle_unrolled, io_map
def write_key(key, filename):
"""Write a key dictionary to a file."""
with open(filename, "w") as f:
f.write(str(key) + "\n")
def read_key(filename):
"""Read a key dictionary from a file."""
with open(filename) as f:
return literal_eval(f.read())
Functions
def check_for_difference(oracle, locked_circuit, key)
-
Check the correctness of a key.
Returns any differences between the oracle and a locked circuit with a specific key applied.
Parameters
oracle
:circuitgraph.Circuit
- The unlocked circuit to check against.
locked_circuit
:circuitgraph.Circuit
- The locked circuit to apply the key to.
key
:dict
ofstr:bool
- The key to check
Returns
False
ordict
ofstr:bool
- False if there is no difference, otherwise the assignment that produced a difference.
Expand source code
def check_for_difference(oracle, locked_circuit, key): """ Check the correctness of a key. Returns any differences between the oracle and a locked circuit with a specific key applied. Parameters ---------- oracle: circuitgraph.Circuit The unlocked circuit to check against. locked_circuit: circuitgraph.Circuit The locked circuit to apply the key to. key: dict of str:bool The key to check Returns ------- False or dict of str:bool False if there is no difference, otherwise the assignment that produced a difference. """ m = cg.tx.miter(oracle, locked_circuit) key = {f"c1_{k}": v for k, v in key.items()} live = cg.sat.solve(m, assumptions=key) if not live: return True return cg.sat.solve(m, assumptions={"sat": True, **key})
def locked_unroll(locked_circuit, key, num_copies, D='D', Q='Q', ignore_pins='CK', initial_values=None, remove_unloaded=True, prefix='cg_unroll')
-
Unrolls a sequential circuit to prepare for a combinational attack.
This can be used for locks applied on sequential circuits that prevent scan-chain access. Note that this function uses the
prefix
variable to identify unrolled nodes, so choosing a prefix that is already used in nodes in the sequential circuit can cause undefined behavior.Parameters
locked_circuit
:circuitgraph.Circuit
- The circuit to unroll
key
:list
ofstr
ordict
ofstr:bool
- The key inputs. If a dictionary is passed in, this key is used to construct an unrolled oracle and this is returned in addition to the unrolled locked circuit
num_copies
:int
- The number of unrolled copies of the circuit to create
D
:str
- The name of the D pin of the sequential elements
Q
:str
- The name of the Q pin of the sequential elements
ignore_pins
:str
orlist
ofstr
- The pins on the sequential elements to ignore
initial_values
:str
ordict
ofstr:str
- The initial values of the data ports for the first timestep. If None, the ports will be added as primary inputs. If a single value ('0', '1', or 'x'), every flop will get that value. Can also pass in dict mapping flop names to values.
remove_unloaded
:bool
- If True, unloaded inputs will be removed after unrolling. This can remove unused sequential signals such as the clock and reset.
prefix
:str
- The prefix to use for naming unrolled nodes.
Returns
circuitgraph.Circuit, circuitgraph.Circuit, dict
ofstr:list
ofstr
- The unrolled locked circuit, the unrolled oracle, and the io map.
Expand source code
def locked_unroll( locked_circuit, key, num_copies, D="D", Q="Q", ignore_pins="CK", initial_values=None, remove_unloaded=True, prefix="cg_unroll", ): """ Unrolls a sequential circuit to prepare for a combinational attack. This can be used for locks applied on sequential circuits that prevent scan-chain access. Note that this function uses the `prefix` variable to identify unrolled nodes, so choosing a prefix that is already used in nodes in the sequential circuit can cause undefined behavior. Parameters ---------- locked_circuit: circuitgraph.Circuit The circuit to unroll key: list of str or dict of str:bool The key inputs. If a dictionary is passed in, this key is used to construct an unrolled oracle and this is returned in addition to the unrolled locked circuit num_copies: int The number of unrolled copies of the circuit to create D: str The name of the D pin of the sequential elements Q: str The name of the Q pin of the sequential elements ignore_pins: str or list of str The pins on the sequential elements to ignore initial_values: str or dict of str:str The initial values of the data ports for the first timestep. If None, the ports will be added as primary inputs. If a single value ('0', '1', or 'x'), every flop will get that value. Can also pass in dict mapping flop names to values. remove_unloaded: bool If True, unloaded inputs will be removed after unrolling. This can remove unused sequential signals such as the clock and reset. prefix: str The prefix to use for naming unrolled nodes. Returns ------- circuitgraph.Circuit, circuitgraph.Circuit, dict of str:list of str The unrolled locked circuit, the unrolled oracle, and the io map. """ locked_circuit_unrolled, io_map = cg.tx.sequential_unroll( locked_circuit, num_copies, D, Q, ignore_pins=ignore_pins, initial_values=initial_values, remove_unloaded=remove_unloaded, prefix=prefix, ) for k in key: locked_circuit_unrolled.set_type(io_map[k], "buf") locked_circuit_unrolled.add(k, "input", fanout=io_map[k]) del io_map[k] oracle_unrolled = locked_circuit_unrolled.copy() for k, v in key.items(): oracle_unrolled.set_type(k, str(int(v))) return locked_circuit_unrolled, oracle_unrolled, io_map
def read_key(filename)
-
Read a key dictionary from a file.
Expand source code
def read_key(filename): """Read a key dictionary from a file.""" with open(filename) as f: return literal_eval(f.read())
def write_key(key, filename)
-
Write a key dictionary to a file.
Expand source code
def write_key(key, filename): """Write a key dictionary to a file.""" with open(filename, "w") as f: f.write(str(key) + "\n")