HAWKEYE
Automated tool to locate arbitrary symmetric cryptographic implementations in gate-level netlists.
- hawkeye.identify_sbox(output_functions: List[hal_py.BooleanFunction], db: hawkeye.SBoxDatabase) Optional[str]
Try to identify an S-box given as one Boolean function per output bit by matching it against a database of known S-boxes under affine equivalence.
Evaluates the Boolean functions into a truth table and looks that up in the database, so it works on functions that do not come from a netlist at all. Every variable occurring in them is taken as an input bit of the S-box, so substitute anything that is not one beforehand.
Note that an S-box which simply does not match anything in the database is not an error: in that case an empty string is returned.
Noneis only returned if the S-box could not be analyzed at all.- Parameters
output_functions (list[hal_py.BooleanFunction]) – The Boolean functions of the S-box, one per output bit. Their order does not matter, as affine equivalence absorbs a permutation of the output bits.
db (hawkeye.SBoxDatabase) – The database of known S-boxes.
- Returns
The name of the matching S-box, or an empty string if no S-box of the database matched.
Noneon error.- Return type
- class hawkeye.DetectionConfiguration
This class holds important parameters that configure the candidate search of HAWKEYE, see
CipherCandidate.detect.- __init__(self: hawkeye.DetectionConfiguration) None
Constructs a default DetectionConfiguration.
- class Components
This enum specifies whether SCC detection should be used to refine the results of neighborhood discovery. If SCC detection is used, the exploration only stops if the size of the largest discovered SCC saturates. Specifically, it does no longer require the size of the entire neighborhood to saturate.
Members:
NONE : Do not use SCC detection and instead resort to the simple neighborhood discovery algorithm.
CHECK_SCC : Use SCC detection within the currently explored neighborhood of a start flip-flop.
- property name
- class Control
This enum specifies the checks that are to be performed on the flip-flops of the netlist to determine whether there should be an edge between two flip-flops or not.
Members:
CHECK_FF : If two flip-flops
ff1andff2are connected through combinational logic, an edge is added such that(ff1,ff2)is part of the graph.CHECK_TYPE : If two flip-flops
ff1andff2are connected through combinational logic and are of the same gate type, an edge is added such that(ff1,ff2)is part of the graph.CHECK_PINS : If two flip-flops
ff1andff2are connected through combinational logic and are controlled through the same input pins, an edge is added such that(ff1,ff2)is part of the graph.CHECK_NETS : If two flip-flops
ff1andff2are connected through combinational logic and are controlled through the same input nets, an edge is added such that(ff1,ff2)is part of the graph.- property name
- property components
Determines whether to use SCC detection as part of neighborhood discovery.
- property control
Checks to be performed on flip-flop control inputs during candidate search.
- property equivalent_types
A list of a list of gate types that are treated as identical types by the candidate search, i.e., when checking equality of the types of two gates that are different but declared equivalent,
Trueis returned.
- property min_register_size
Minimum number of flip-flops of a register for a candidate to be created from it.
- Type
- class hawkeye.CipherCandidate
A candidate for a symmetric cryptographic implementation within a netlist.
A candidate is discovered by
detectin stages and is filled in as the analysis proceeds: detection only establishes the state register,build_round_functionadds the combinational logic computing the next state, andlocate_sboxesadds the S-boxes within that logic. Usehas_round_functionandget_sboxesto find out how far a candidate has been analyzed.All gates and nets of a candidate belong to the netlist it was detected in, so they can be inspected and grouped into modules directly.
- __init__(*args, **kwargs)
Overloaded function.
__init__(self: hawkeye.CipherCandidate) -> None
Default constructor for
CipherCandidate.__init__(self: hawkeye.CipherCandidate, round_reg: Set[hal_py.Gate]) -> None
Construct a round-based candidate, i.e., one whose input and output register are the same.
- param set[hal_py.Gate] round_reg
The state register of the candidate.
__init__(self: hawkeye.CipherCandidate, in_reg: Set[hal_py.Gate], out_reg: Set[hal_py.Gate]) -> None
Construct a candidate from an input and an output register. The candidate is round-based if both registers are equal.
- param set[hal_py.Gate] in_reg
The input register of the candidate.
- param set[hal_py.Gate] out_reg
The output register of the candidate.
- build_round_function(self: hawkeye.CipherCandidate) bool
Determine the round function of the candidate, i.e., the combinational logic computing the next state.
Determines the state logic between the input and the output register together with the state, control, and other inputs of the candidate, and builds the graph that
locate_sboxesoperates on. Discards any S-boxes located so far, as they are derived from the round function, which invalidates all S-boxes previously returned bylocate_sboxesandget_sboxes.Recomputes the round function on every call, which only makes a difference if the netlist changed in the meantime.
- Returns
Trueon success,Falseotherwise.- Return type
- clear_sboxes(self: hawkeye.CipherCandidate) None
Discard the S-boxes located so far.
Invalidates all S-boxes previously returned by
locate_sboxesandget_sboxes.
- create_modules(self: hawkeye.CipherCandidate) hal_py.Module
Write the candidate back into the netlist as a module hierarchy.
Creates one module holding the entire candidate, a submodule holding its state register, and one submodule per identified S-box holding its combinational gates. S-boxes that were not identified are skipped, as are identified S-boxes that overlap an S-box module already created, since a gate belongs to exactly one module. Every skipped S-box is reported to the log.
- Returns
The module holding the candidate on success,
Noneotherwise.- Return type
- static detect(nl: hal_py.Netlist, configs: List[hawkeye.DetectionConfiguration], min_state_size: int = 40, start_ffs: List[hal_py.Gate] = []) Optional[List[hawkeye.CipherCandidate]]
Attempt to locate candidates for symmetric cryptographic SPN, Feistel, and ARX implementations within a gate-level netlist.
Operates on an abstraction of the netlist that holds only the flip-flops as vertices and their connections through combinational logic as edges. Computes the k-neighborhood of every flip-flop for
k = 1, ..., config.timeoutand stops once the size of the neighborhood saturates, at which point a candidate is created if the neighborhood is larger thanconfig.min_register_size. Depending on theconfig, further criteria narrow down the search, seeDetectionConfiguration.ControlandDetectionConfiguration.Components. The candidates found are then reduced by discarding those smaller thanmin_state_sizeas well as those that fully contain a smaller candidate.The returned candidates only know their state register, call
build_round_functionon a candidate to analyze it further.- Parameters
nl (hal_py.Netlist) – The netlist to operate on.
configs (list[hawkeye.DetectionConfiguration]) – The configurations of the detection approaches to be executed one after another on each start flip-flop.
min_state_size (int) – The minimum size of a candidate to be considered a cryptographic state register. Defaults to
40.start_ffs (list[hal_py.Gate]) – The flip-flops to analyze. Defaults to an empty list, i.e., all flip-flops of the netlist are analyzed.
- Returns
A list of candidates on success,
Noneotherwise.- Return type
- get_control_inputs(self: hawkeye.CipherCandidate) Set[hal_py.Net]
Get the control inputs of the round function.
- Returns
The control inputs of the candidate.
- Return type
- get_gates(self: hawkeye.CipherCandidate) List[hal_py.Gate]
Get all gates of the candidate, i.e., its registers together with its round function, ordered by gate ID.
- Returns
The gates of the candidate.
- Return type
- get_graph(self: hawkeye.CipherCandidate) graph_algorithm.NetlistGraph
Get the graph of the round function, in which the gates of the state register are represented by a primary and a shadow vertex so that the feedback of a round-based candidate does not close a cycle.
- Returns
The graph of the round function,
Noneif the round function has not been computed yet.- Return type
- get_input_ffs_of_gate(self: hawkeye.CipherCandidate) Dict[hal_py.Gate, Set[hal_py.Gate]]
Get a dict from each gate of the round function to the input flip-flops it depends on.
- Returns
A dict from gates to sets of input flip-flops.
- Return type
- get_input_reg(self: hawkeye.CipherCandidate) List[hal_py.Gate]
Get the input register of the candidate, ordered by gate ID.
- Returns
The input register of the candidate.
- Return type
- get_longest_distance_to_gate(self: hawkeye.CipherCandidate) Dict[int, Set[hal_py.Gate]]
Get a dict from a distance to all gates reachable within at most that distance from any input flip-flop.
- Returns
A dict from longest distance to a set of gates.
- Return type
- get_netlist(self: hawkeye.CipherCandidate) hal_py.Netlist
Get the netlist that the candidate belongs to.
- Returns
The netlist of the candidate.
- Return type
- get_other_inputs(self: hawkeye.CipherCandidate) Set[hal_py.Net]
Get the remaining inputs of the round function.
- Returns
The other inputs of the candidate.
- Return type
- get_output_reg(self: hawkeye.CipherCandidate) List[hal_py.Gate]
Get the output register of the candidate, ordered by gate ID. Equal to the input register for a round-based candidate.
- Returns
The output register of the candidate.
- Return type
- get_round_logic(self: hawkeye.CipherCandidate) List[hal_py.Gate]
Get the combinational logic computing the next state, ordered by gate ID.
- Returns
The round function of the candidate, empty if it has not been computed yet.
- Return type
- get_sboxes(self: hawkeye.CipherCandidate) List[hawkeye.SBox]
Get the S-boxes located within the round function of the candidate.
- Returns
The S-boxes of the candidate, empty if they have not been located yet.
- Return type
- get_size(self: hawkeye.CipherCandidate) int
Get the size of the candidate, i.e., the width of its state register.
- Returns
The size of the candidate.
- Return type
- get_state_inputs(self: hawkeye.CipherCandidate) Set[hal_py.Net]
Get the state inputs of the round function.
- Returns
The state inputs of the candidate.
- Return type
- get_state_outputs(self: hawkeye.CipherCandidate) Set[hal_py.Net]
Get the state outputs of the round function.
- Returns
The state outputs of the candidate.
- Return type
- has_round_function(self: hawkeye.CipherCandidate) bool
Check whether the round function of the candidate has been computed, see
build_round_function.- Returns
Trueif the round function has been computed,Falseotherwise.- Return type
- identify_sbox(self: hawkeye.CipherCandidate, sbox: hawkeye.SBox, db: hawkeye.SBoxDatabase) Optional[str]
Try to identify a single S-box of this candidate by matching it against a database of known S-boxes under affine equivalence.
Tries every assignment of the control inputs that the S-box reads, as the round function computes the S-box for one of them and something else for the others, and the right one is not known in advance. The remaining inputs are held at
0.Does not annotate the S-box, use
identify_sboxesfor that.Note that an S-box which simply does not match anything in the database is not an error: in that case an empty string is returned.
Noneis only returned if the S-box could not be analyzed at all.- Parameters
sbox (hawkeye.SBox) – The S-box to identify. Must be one of the S-boxes of this candidate.
db (hawkeye.SBoxDatabase) – The database of known S-boxes.
- Returns
The name of the matching S-box, or an empty string if no S-box of the database matched.
Noneon error.- Return type
- identify_sboxes(self: hawkeye.CipherCandidate, db: hawkeye.SBoxDatabase) Optional[int]
Try to identify all S-boxes of the candidate by matching them against a database of known S-boxes.
Annotates every S-box with the outcome, see
SBox.statusandSBox.identified_as. An S-box that is not contained in the database is not an error.Since the exact outputs of an S-box are not known in advance,
locate_sboxesproduces many variants of the same S-box that differ only in which of the surplus gates are taken as its outputs but all read the same input flip-flops. Variants are therefore identified as a group, and the group is left as soon as one of them matches, marking the remaining onessuperseded.- Parameters
db (hawkeye.SBoxDatabase) – The database of known S-boxes.
- Returns
The number of identified S-boxes on success,
Noneotherwise.- Return type
- is_round_based(self: hawkeye.CipherCandidate) bool
Check whether the candidate is round-based, i.e., whether its input and output register are the same.
- Returns
Trueif the candidate is round-based,Falseif it is pipelined.- Return type
- locate_sboxes(self: hawkeye.CipherCandidate) Optional[List[hawkeye.SBox]]
Try to locate S-boxes within the round function of the candidate.
Computes an initial set of connected components within the round function. If these components are reasonably small and their input and output sizes match, they are turned into S-boxes right away. Otherwise, iteratively considers more combinational gates starting from the components’ input gates and searches for sub-components.
Returns the S-boxes located by an earlier call unchanged instead of locating them again. Call
clear_sboxesto locate them anew.- Returns
The S-boxes of the candidate on success,
Noneotherwise.- Return type
list[hawkeye.SBox] or None
- class hawkeye.SBox
An S-box located within the round function of a
CipherCandidate.Owned by the candidate it was located in, which also owns every gate it refers to, so an S-box is only valid for as long as its candidate is.
The exact size and shape of an S-box is not known in advance, so the search deliberately produces more S-boxes than the round function actually contains, among them smaller ones nested inside larger ones. Identification resolves that, see
SBoxStatus.- property component
The gates of the connected component that the S-box was located in, including its input flip-flops.
- Type
- get_combinational_gates(self: hawkeye.SBox) List[hal_py.Gate]
Get the combinational gates computing the outputs of the S-box from its input flip-flops.
Walks back from the output gates within the component and stops at the flip-flops, so the result is the logic of this S-box alone rather than that of the whole component, which several S-boxes may share.
- Returns
The combinational gates of the S-box, ordered by gate ID.
- Return type
- property identified_as
The name of the S-box in the database it was identified as, empty unless
statusisidentified.- Type
- property input_gates
The input flip-flops of the S-box, ordered by gate ID.
These are the flip-flops of the state register that the S-box reads, and hence the only link between the identified S-box and the state bits it operates on. They are not ordered by S-box input bit: the database matches under affine equivalence, which absorbs any permutation of the input and output bits, so no bit correspondence is established during identification.
- Type
- property output_gates
The output gates of the S-box, ordered by gate ID. Usually combinational gates feeding the linear layer.
- Type
- property status
The outcome of trying to identify the S-box,
unidentifieduntilidentify_sboxesran.- Type
- class hawkeye.SBoxStatus
The outcome of trying to identify an S-box, see
CipherCandidate.identify_sboxes.Members:
unidentified : Identification ran but the S-box is not contained in the database.
identified : Identification ran and matched, see
SBox.identified_as.superseded : Identification did not run, another variant of the same S-box was identified before.
- property name
- class hawkeye.SBoxDatabase
This class holds and manages known S-boxes and allows to perform efficient S-box lookups in the database.
- __init__(*args, **kwargs)
Overloaded function.
__init__(self: hawkeye.SBoxDatabase) -> None
Construct an empty S-box database.
__init__(self: hawkeye.SBoxDatabase, sboxes: Dict[str, List[int]]) -> None
Construct an S-box database from the given S-boxes.
- param dict[str,list[int]] sboxes
A dict from S-box name to the respective S-box.
- add(*args, **kwargs)
Overloaded function.
add(self: hawkeye.SBoxDatabase, name: str, sbox: List[int]) -> bool
Add an S-box to the database.
- param str name
The name of the S-box.
- patam list[int] sbox
The S-box.
- returns
Trueon success,Falseotherwise.- rtype
bool
add(self: hawkeye.SBoxDatabase, sboxes: Dict[str, List[int]]) -> bool
Add multiple S-boxes to the database.
- param dict[str,list[int]] sboxes
A dict from S-box name to the respective S-box.
- returns
Trueon success,Falseotherwise.- rtype
bool
- static compute_linear_representative(sbox: List[int]) List[int]
Compute the linear representative of the given S-box.
- static from_file(file_path: os.PathLike) Optional[hawkeye.SBoxDatabase]
Construct an S-box database from file.
- Parameters
file_path (pathlib.Path) – The path from which to load the S-box database file.
- Returns
The S-box database on success,
Noneotherwise.- Return type
- load(self: hawkeye.SBoxDatabase, file_path: os.PathLike, overwrite: bool = False) bool
Load S-boxes from a file and add them to the existing database.
- Parameters
file_path (pathlib.Path) – The path from which to load the S-box database file.
overwrite (bool) – Set
Trueto overwrite existing database,Falseotherwise. Defaults toFalse.
- Returns
Trueon success,Falseotherwise.- Return type
- lookup(self: hawkeye.SBoxDatabase, sbox: List[int]) Optional[str]
Attempt to look up an S-box in the database.
- print(self: hawkeye.SBoxDatabase) None
Print the database.
- store(self: hawkeye.SBoxDatabase, file_path: os.PathLike) bool
Store the S-box database to a database file.
- Parameters
file_path (pathlib.Path) – The path to where to store the S-box database file.
- Returns
Trueon success,Falseotherwise.- Return type
- class hawkeye.HawkeyePlugin
This class provides an interface to integrate the HAWKEYE tool as a plugin within the HAL framework.
- get_dependencies(self: hawkeye.HawkeyePlugin) Set[str]
Get a set of plugin names that this plugin depends on.
- get_description(self: hawkeye.HawkeyePlugin) str
Get the description of the plugin.
- Returns
The description of the plugin.
- Return type
- get_name(self: hawkeye.HawkeyePlugin) str
Get the name of the plugin.
- Returns
The name of the plugin.
- Return type
- get_version(self: hawkeye.HawkeyePlugin) str
Get the version of the plugin.
- Returns
The version of the plugin.
- Return type