Repository navigation
Fix missing flip-flop edges in DANA and S-box location and identification in HAWKEYE - #682
Open
julianspeith wants to merge 4 commits into
Open
julianspeith wants to merge 4 commits into
julianspeith wants to merge 4 commits into
Conversation
identify_successors_predecessors shares its per-net caches across the traversals of all target gates, but a traversal does not push a net it has visited before. With reconvergent fanout, the nets on the second path to such a net never got its targets, so their cache entries stayed incomplete, and every later traversal that hit them lost those edges. On two synthesized AES netlists (about 850 flip-flops, 20k edges), 178 and 202 edges were missing, which split a 128-bit register into 120 + 8 bits in the steered analysis. Hand the cache entry of a visited net to the nets of the current path, unless it lies on the path itself (a combinational loop, still being explored). The same applies to the predecessor cache of known net groups. The flip-flop graph now matches the one of NetlistTraversalDecorator::get_next_sequential_gates_map on both netlists. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ersion class
lookup_sbox reduced surplus outputs by a linear elimination that reused
pivot outputs for later rows, so it miscounted the rank (too high in
about a fifth of random tests). It also treated a complemented copy of
an output as independent, although identify_sbox holds key inputs at 0,
which turns a key addition (XOR/XNOR) into exactly such a copy. Use a
proper echelon-form elimination with the constant function in the basis
first, and keep the outputs as they are (the database does not care
about output constants). On a synthesized AES netlist, this identifies
all 16 S-boxes instead of 6.
SBoxDatabase::lookup gave up as soon as the canonical form search ran out
of budget, assuming that this happens for every output constant alike.
It does not: a table that maps 0 to 0 takes a search of its own, which
exhausts the budget for the inversion class, i.e., for every
AES-equivalent table with T(0) = 0. Skip that constant and go on with
the others in lookup, and leave the entry out in add instead of failing,
so that SBoxDatabase().add("AES", ...) works again.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
locate_sboxes accepted every split of a component into equal groups of more than one flip-flop, while whole components need at least 3. When synthesis starts the S-boxes with 2-to-4 predecoders on pairs of input bits, the round function splits into groups of 2 first, which produced 64 bogus 2-bit S-boxes (384 of 816 located ones) on an AES netlist. Use one minimum for both cases. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…rm search SBoxDatabase::lookup computes a canonical form for every output constant beta, which takes about 20 seconds for an 8-bit table that matches no entry. With the corrected output reduction, such tables now reach the lookup more often, e.g., two 4-bit S-boxes side by side that HAWKEYE locates as one 8-bit S-box in LED, which made the ASIC LED benchmark go from 2 to 53 seconds. Affine equivalence and XORing constants only permute the entries of the difference distribution table, so compare the spectrum of the table with those of the entries of the database first and give up right away if none matches. Rejecting a non-matching 8-bit table now takes 0.03 seconds; every representative stored in the shipped database is still found. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This PR fixes one bug in DANA and three problems in HAWKEYE. I found them on two synthesized AES-128 netlists (Synopsys DC, LSI10k, about 850 flip-flops each). On those netlists, DANA lost flip-flop edges, and HAWKEYE identified only 6 of the 16 S-boxes on one netlist and reported 64 bogus 2-bit S-boxes on the other.
Changes
DANA: missing flip-flop edges (8bd08f4)
identify_successors_predecessorsshares its per-net caches across the traversals of all target gates, but a traversal never pushes a net it has already visited. With reconvergent fanout, the nets on the second path to such a net therefore never received its targets. Their cache entries stayed incomplete, and every later traversal that hit them lost those edges. On the two netlists, 202 of 20,016 and 178 of 19,982 edges were missing. In the steered analysis this split a 128-bit register into 120 + 8 bits.The fix hands the cache entry of an already visited net to the nets of the current path, unless that net lies on the path itself (a combinational loop, still being explored). The predecessor cache of known net groups gets the same fix. A Python re-implementation of the old routine reproduces DANA's old graph edge for edge. After the fix, the graph equals the one from
NetlistTraversalDecorator::get_next_sequential_gates_mapon both netlists.HAWKEYE: identification with surplus outputs and for the inversion class (ec8f9f8)
lookup_sboxreduced surplus outputs by a linear elimination that reused pivot outputs for later rows, so it got the rank wrong (too high in about a fifth of random tests). It also counted a complemented copy of an output as independent.identify_sboxholds key inputs at 0, which turns a key addition (XOR/XNOR) into exactly such a copy. The elimination is now a proper echelon-form elimination with the constant function in the basis first, and the selected outputs are kept unchanged (the database does not care about output constants). On the affected netlist, all 16 S-boxes are identified instead of 6.SBoxDatabase::lookupgave up as soon as the canonical form search ran out of budget, assuming this happens for all output constants alike. It does not: a table that maps 0 to 0 takes a search of its own, which runs out of budget for the inversion class, i.e., for every AES-equivalent table with T(0) = 0.lookupnow skips that one constant and goes on with the others.addleaves that entry out instead of failing, soSBoxDatabase().add("AES", ...)works again.HAWKEYE: minimum S-box size when splitting a component (e258778)
locate_sboxesaccepted every split of a component into equal groups of more than one flip-flop, while whole components need at least 3. When synthesis starts the S-boxes with 2-to-4 predecoders on pairs of input bits, the round function first splits into groups of 2. On one netlist this produced 64 bogus 2-bit S-boxes (384 of 816 located ones). Both cases now use the same minimum,MIN_SBOX_BITS = 3.HAWKEYE: differential spectrum prefilter in
SBoxDatabase::lookup(bbad8ce)The canonical form search runs once per output constant and takes about 20 s for an 8-bit table that matches no entry. With the corrected output reduction, such tables reach the lookup more often, e.g., two 4-bit S-boxes side by side that HAWKEYE locates as one 8-bit S-box in LED. This made the ASIC LED benchmark go from 2 s to 53 s. Affine equivalence and XORing constants only permute the entries of the difference distribution table, so
lookupnow first compares the spectrum of the table with those of the database entries and gives up right away if none matches. Rejecting a non-matching 8-bit table now takes 0.03 s.Testing
Regression against the 65 benchmarks of the HAWKEYE artifact (Crypto'24), running
masterand this branch side by side:plugins/hawkeye/scripts/characterize.pygives identical output for all 65 benchmarks: same candidates, round functions, and S-boxes, gate by gate.run_isolated_benchmarks.pyandrun_soc_benchmarks.pyto theCipherCandidateAPI (not part of this PR) gives the same 130 summary lines (candidates, true/false positives, identified S-box) on both.identify_sboxesidentifies more S-boxes per candidate: LED-64 on FPGA 16 instead of 8 (both methods), CRAFT on ASIC with method 2 14 instead of 10. No benchmark gets worse. The whole run takes 982 s, against 988 s onmaster.Not part of this PR
netlist_preprocessing.simplify_lut_initsthrowsbad_variant_accesson the FPGA noise benchmarkscpu_edgeandcpu_ibex_risc-v. This happens onmasteras well; for the regression, I skipped the failing step on both sides.masterdeviates on 29 ASIC lines. All 29 disappear with thelsi_10k.hglfrom before 3145cb7, so they come from the corrected pin types, not from HAWKEYE. The only other deviation (cpu_ibex_risc-von FPGA, 774 instead of 775 flip-flops) is probably due to the skipped preprocessing step.🤖 Generated with Claude Code