Skip to content

Commit 3aa8ba3

Browse files
committed
Add mult graphs visualization.
1 parent fb301e2 commit 3aa8ba3

4 files changed

Lines changed: 1232 additions & 39 deletions

File tree

analysis/scalarmults/epare/config.py

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from enum import Enum
44
from functools import total_ordering
55
from typing import Any, Optional, Type
6+
from anytree import Node
67

78
from pyecsca.ec.countermeasures import (
89
GroupScalarRandomization,
@@ -43,7 +44,11 @@ def mult(self):
4344
"""
4445
Extract the MultIdent out of the Composable.
4546
46-
We assume there is only one somewhere in the tree (at the leafs).
47+
We assume there is only one somewhere in the tree
48+
(in all the leafs). We also assume the Composable only has up to 3 layers:
49+
Countermeasure(Countermeasure(Mult)), or
50+
Countermeasure(Mult), or
51+
Mult
4752
"""
4853
if isinstance(self, MultIdent):
4954
return self
@@ -54,6 +59,30 @@ def mult(self):
5459
if isinstance(kwarg, Composable):
5560
return kwarg.mult
5661

62+
def walk(self, callback):
63+
"""
64+
Recursively walk the Composable, applying the callback.
65+
"""
66+
callback(self)
67+
for arg in self.args:
68+
if isinstance(arg, Composable):
69+
arg.walk(callback)
70+
for kwarg in self.kwargs.values():
71+
if isinstance(kwarg, Composable):
72+
kwarg.walk(callback)
73+
74+
def tree(self) -> Node:
75+
me = Node(self)
76+
children = []
77+
for arg in self.args:
78+
if isinstance(arg, Composable):
79+
children.append(arg.tree())
80+
for kwarg in self.kwargs.values():
81+
if isinstance(kwarg, Composable):
82+
children.append(kwarg.tree())
83+
me.children = children
84+
return me
85+
5786
def construct(self, *mult_args, **mult_kwargs):
5887
"""Recursively construct this composable."""
5988
args, kwargs = self._build_args_kwargs(mult_args, mult_kwargs)
@@ -242,6 +271,13 @@ def mult(self):
242271
def has_countermeasure(self):
243272
return isinstance(self.composition, CountermeasureIdent)
244273

274+
@property
275+
def countermeasures(self) -> set[CountermeasureIdent]:
276+
r = set()
277+
if not self.has_countermeasure:
278+
return r
279+
self.composition.walk(lambda c: r.add(c) if isinstance(c, CountermeasureIdent) else None)
280+
245281
@property
246282
def has_error_model(self):
247283
return self.error_model is not None
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
from pyecsca.ec.mult import LTRMultiplier, RTLMultiplier, SlidingWindowMultiplier, CombMultiplier, ProcessingDirection
2+
3+
from epare.error_model import ErrorModel
4+
from epare.config import MultIdent, Config
5+
6+
7+
def only_ltr_example(config: Config, always=False, complete=False):
8+
"""Select single LTRMultiplier example."""
9+
return config.mult.klass == LTRMultiplier and config.mult.kwargs["always"] == always and config.mult.kwargs["complete"] == complete
10+
11+
12+
def only_rtl_example(config: Config, always=False, complete=False):
13+
"""Select single RTLMultiplier example."""
14+
return config.mult.klass == RTLMultiplier and config.mult.kwargs["always"] == always and config.mult.kwargs["complete"] == complete
15+
16+
17+
def only_sliding_example(config: Config, width=4, recoding_direction=ProcessingDirection.LTR):
18+
"""Select single SlidingWindow example."""
19+
return config.mult.klass == SlidingWindowMultiplier and config.mult.kwargs["width"] == width and config.mult.kwargs["recoding_direction"] == recoding_direction
20+
21+
22+
def only_comb_example(config: Config, width=4, always=True):
23+
"""Select single Comb example."""
24+
return config.mult.klass == CombMultiplier and config.mult.kwargs["width"] == width and config.mult.kwargs["always"] == always
25+
26+
27+
def only_ltrs(config: Config):
28+
"""Select all LTRs."""
29+
return config.mult.klass == LTRMultiplier
30+
31+
32+
def only_rtls(config: Config):
33+
"""Select all RTLs."""
34+
return config.mult.klass == RTLMultiplier
35+
36+
37+
def only_slidingws(config: Config):
38+
"""Select all SlidingWindows."""
39+
return config.mult.klass == SlidingWindowMultiplier
40+
41+
42+
def only_combs(config: Config):
43+
"""Select all Combs (not BGMW)."""
44+
return config.mult.klass == CombMultiplier
45+
46+
47+
def no_combs(config: Config):
48+
"""Select all but Comb and BGMW."""
49+
return config.mult.klass not in (CombMultiplier, BGMWMultiplier)
50+
51+
52+
def single_layer_ctr(config: Config):
53+
"""Select configs with only a single countermeasure."""
54+
return all(map(lambda ident: isinstance(ident, MultIdent), config.composition.args))
55+
56+
57+
def single_type_ctr(config: Config):
58+
"""Select configs with only a single type of countermeasure (can be nested)."""
59+
return all(map(lambda ident: isinstance(ident, MultIdent) or ident.klass == config.composition.klass, config.composition.args))
60+
61+
62+
def single_type_ctr_full(config: Config):
63+
"""Select configs with only a single type of countermeasure that is fully nested."""
64+
return all(map(lambda ident: ident.klass == config.composition.klass, config.composition.args))
65+
66+
67+
def fixed_error_model(config: Config):
68+
"""Select a single example error model."""
69+
return config.error_model == ErrorModel({"divides"}, "all", True)
70+
71+
72+
def fixed_no_countermeasure(config: Config):
73+
"""Select configs with no countermeasures."""
74+
return not config.has_countermeasure
75+
76+
77+
def has_gsr(config: Config):
78+
"""Select configs with GSR."""
79+
return any(lambda ident: ident.klass == GroupScalarRandomization, config.countermeasures)
80+
81+
82+
83+
84+

analysis/scalarmults/graphs.ipynb

Lines changed: 1033 additions & 0 deletions
Large diffs are not rendered by default.

analysis/scalarmults/visualize.ipynb

Lines changed: 78 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
},
1111
{
1212
"cell_type": "code",
13-
"execution_count": null,
13+
"execution_count": 1,
1414
"id": "3232df80-2a65-47ce-bc77-6a64f44d2404",
1515
"metadata": {},
1616
"outputs": [],
@@ -36,6 +36,7 @@
3636
"from epare.config import all_configs, Config, MultIdent, CountermeasureIdent\n",
3737
"from epare.prob_map import ProbMap\n",
3838
"from epare.error_model import ErrorModel\n",
39+
"from epare.filters import *\n",
3940
"\n",
4041
"if sys.version_info >= (3, 14):\n",
4142
" from compression import zstd\n",
@@ -56,7 +57,7 @@
5657
},
5758
{
5859
"cell_type": "code",
59-
"execution_count": null,
60+
"execution_count": 2,
6061
"id": "e89e66dc-4a9b-4320-8612-a8fa9af04b69",
6162
"metadata": {},
6263
"outputs": [],
@@ -79,10 +80,32 @@
7980
},
8081
{
8182
"cell_type": "code",
82-
"execution_count": null,
83+
"execution_count": 3,
8384
"id": "bab2a086-8b3d-4e76-bf5c-46ea2b617708",
8485
"metadata": {},
85-
"outputs": [],
86+
"outputs": [
87+
{
88+
"name": "stdout",
89+
"output_type": "stream",
90+
"text": [
91+
"small_primes [3, 5, 7] ... [199]\n",
92+
"medium_primes [211, 223, 227] ... [397]\n",
93+
"large_primes [401, 409, 419] ... [997]\n",
94+
"all_primes [3, 5, 7] ... [997]\n",
95+
"all_integers [1, 2, 3] ... [399]\n",
96+
"all_even [2, 4, 6] ... [398]\n",
97+
"all_odd [1, 3, 5] ... [399]\n",
98+
"powers_of_2 [2, 4, 8] ... [524288]\n",
99+
"powers_of_2_large [2, 4, 8] ... [57896044618658097711785492504343953926634992332820282019728792003956564819968]\n",
100+
"powers_of_2_large_3 [6, 12, 24] ... [173688133855974293135356477513031861779904976998460846059186376011869694459904]\n",
101+
"powers_of_2_large_p1 [3, 5, 9] ... [57896044618658097711785492504343953926634992332820282019728792003956564819969]\n",
102+
"powers_of_2_large_m1 [1, 3, 7] ... [57896044618658097711785492504343953926634992332820282019728792003956564819967]\n",
103+
"powers_of_2_large_pmautobus [1, 2, 3] ... [57896044618658097711785492504343953926634992332820282019728792003956564819972]\n",
104+
"powers_of_3 [3, 9, 27] ... [1162261467]\n",
105+
"all [1, 2, 3] ... [173688133855974293135356477513031861779904976998460846059186376011869694459904]\n"
106+
]
107+
}
108+
],
86109
"source": [
87110
"from epare.divisors import divisor_map\n",
88111
"for d, ds in divisor_map.items():\n",
@@ -100,7 +123,7 @@
100123
},
101124
{
102125
"cell_type": "code",
103-
"execution_count": null,
126+
"execution_count": 4,
104127
"id": "19d986ab-5fe7-4dd6-b5b5-4e75307217d6",
105128
"metadata": {},
106129
"outputs": [],
@@ -137,13 +160,14 @@
137160
"plot_divisors = divisor_map[\"small_primes\"]\n",
138161
"\n",
139162
"# Here are several useful filters when playing around with the data. We want to select a single multiplier and countereasure combination.\n",
140-
"only_ltr_example = lambda config: config.mult.klass == LTRMultiplier and not config.mult.kwargs[\"always\"] and not config.mult.kwargs[\"complete\"]\n",
141-
"only_rtl_example = lambda config: config.mult.klass == RTLMultiplier and not config.mult.kwargs[\"always\"] and not config.mult.kwargs[\"complete\"]\n",
142-
"only_sliding_example = lambda config: config.mult.klass == SlidingWindowMultiplier and config.mult.kwargs[\"width\"] == 4 and config.mult.kwargs[\"recoding_direction\"] == ProcessingDirection.LTR\n",
143-
"only_comb_example = lambda config: config.mult.klass == CombMultiplier and config.mult.kwargs[\"width\"] == 4 and config.mult.kwargs[\"always\"] == True\n",
144-
"single_layer_ctr = lambda config: all(map(lambda ident: isinstance(ident, MultIdent), config.composition.args))\n",
145-
"single_type_ctr = lambda config: all(map(lambda ident: isinstance(ident, MultIdent) or ident.klass == config.composition.klass, config.composition.args))\n",
146-
"single_type_ctr_full = lambda config: all(map(lambda ident: ident.klass == config.composition.klass, config.composition.args))\n",
163+
"# See the filters module for more.\n",
164+
"# only_ltr_example\n",
165+
"# only_rtl_example\n",
166+
"# only_sliding_example\n",
167+
"# only_comb_example\n",
168+
"# single_layer_ctr\n",
169+
"# single_type_ctr\n",
170+
"# single_type_ctr_full\n",
147171
"\n",
148172
"groups = {}\n",
149173
"for config, probmap in config_map.items():\n",
@@ -234,15 +258,15 @@
234258
"plot_divisors = divisor_map[\"small_primes\"]\n",
235259
"\n",
236260
"# Here are several useful filters when playing around with the data. We want to select a single multiplier and error model.\n",
237-
"only_ltr_example = lambda config: config.mult.klass == LTRMultiplier and not config.mult.kwargs[\"always\"] and not config.mult.kwargs[\"complete\"]\n",
238-
"only_rtl_example = lambda config: config.mult.klass == RTLMultiplier and not config.mult.kwargs[\"always\"] and not config.mult.kwargs[\"complete\"]\n",
239-
"only_sliding_example = lambda config: config.mult.klass == SlidingWindowMultiplier and config.mult.kwargs[\"width\"] == 4 and config.mult.kwargs[\"recoding_direction\"] == ProcessingDirection.LTR\n",
240-
"only_comb_example = lambda config: config.mult.klass == CombMultiplier and config.mult.kwargs[\"width\"] == 4 and config.mult.kwargs[\"always\"] == True\n",
241-
"\n",
242-
"fixed_error_model = lambda config: config.error_model == ErrorModel({\"divides\"}, \"all\", True)\n",
243-
"single_layer_ctr = lambda config: all(map(lambda ident: isinstance(ident, MultIdent), config.composition.args))\n",
244-
"single_type_ctr = lambda config: all(map(lambda ident: isinstance(ident, MultIdent) or ident.klass == config.composition.klass, config.composition.args))\n",
245-
"single_type_ctr_full = lambda config: all(map(lambda ident: ident.klass == config.composition.klass, config.composition.args))\n",
261+
"# See the filters module for more.\n",
262+
"# only_ltr_example\n",
263+
"# only_rtl_example\n",
264+
"# only_sliding_example\n",
265+
"# only_comb_example\n",
266+
"# fixed_error_model\n",
267+
"# single_layer_ctr\n",
268+
"# single_type_ctr\n",
269+
"# single_type_ctr_full\n",
246270
"\n",
247271
"groups = {}\n",
248272
"for config, probmap in config_map.items():\n",
@@ -324,15 +348,18 @@
324348
"plot_divisors = divisor_map[\"small_primes\"]\n",
325349
"\n",
326350
"# Here are several useful filters when playing around with the data. We want to select a single countermeasure config and error_model\n",
327-
"only_ltrs = lambda config: config.mult.klass == LTRMultiplier\n",
328-
"only_rtls = lambda config: config.mult.klass == RTLMultiplier\n",
329-
"only_slidings = lambda config: config.mult.klass == SlidingWindowMultiplier\n",
330-
"only_combs = lambda config: config.mult.klass == CombMultiplier\n",
331-
"no_combs = lambda config: config.mult.klass not in (CombMultiplier, BGMWMultiplier)\n",
332-
"\n",
333-
"fixed_error_model = lambda config: config.error_model == ErrorModel({\"divides\"}, \"all\", True)\n",
334-
"fixed_no_countermeasure = lambda config: isinstance(config.composition, MultIdent)\n",
335-
"fixed_gsr_countermeasure = lambda config: config.composition.klass == GroupScalarRandomization\n",
351+
"# See the filters module for more.\n",
352+
"# only_ltrs\n",
353+
"# only_rtls\n",
354+
"# only_slidingws\n",
355+
"# only_combs\n",
356+
"# no_combs\n",
357+
"# fixed_error_model\n",
358+
"# fixed_no_countermeasure\n",
359+
"# single_layer_ctr\n",
360+
"# single_type_ctr\n",
361+
"# single_type_ctr_full\n",
362+
"# has_gsr\n",
336363
"\n",
337364
"groups = {}\n",
338365
"for config, probmap in config_map.items():\n",
@@ -426,18 +453,23 @@
426453
"plot_divisors = divisor_map[\"small_primes\"]\n",
427454
"\n",
428455
"# Here are several useful filters when playing around with the data. We want to select a single countermeasure config and error_model\n",
429-
"only_ltrs = lambda config: config.mult.klass == LTRMultiplier\n",
430-
"only_rtls = lambda config: config.mult.klass == RTLMultiplier\n",
431-
"only_slidings = lambda config: config.mult.klass == SlidingWindowMultiplier\n",
432-
"only_combs = lambda config: config.mult.klass == CombMultiplier\n",
456+
"# See the filters module for more.\n",
457+
"# only_ltrs\n",
458+
"# only_rtls\n",
459+
"# only_slidingws\n",
460+
"# only_combs\n",
461+
"# no_combs\n",
462+
"# fixed_error_model\n",
463+
"# fixed_no_countermeasure\n",
464+
"# single_layer_ctr\n",
465+
"# single_type_ctr\n",
466+
"# single_type_ctr_full\n",
467+
"# has_gsr\n",
433468
"\n",
434-
"fixed_error_model = lambda config: config.error_model == ErrorModel({\"divides\"}, \"all\", True)\n",
435-
"fixed_no_countermeasure = lambda config: isinstance(config.composition, MultIdent)\n",
436-
"fixed_gsr_countermeasure = lambda config: config.composition.klass == GroupScalarRandomization\n",
437469
"\n",
438470
"groups = {}\n",
439471
"for config, probmap in config_map.items():\n",
440-
" if fixed_error_model(config) and fixed_no_countermeasure(config) and only_slidings(config):\n",
472+
" if fixed_error_model(config) and fixed_no_countermeasure(config) and only_slidingws(config):\n",
441473
" plot_configs.append(config)\n",
442474
" pmap = deepcopy(probmap)\n",
443475
" pmap.narrow(plot_divisors)\n",
@@ -495,6 +527,14 @@
495527
"plt.close();"
496528
]
497529
},
530+
{
531+
"cell_type": "markdown",
532+
"id": "7995e2b5-550e-423e-b51c-f40f10c66cc3",
533+
"metadata": {},
534+
"source": [
535+
"## Misc (broken)"
536+
]
537+
},
498538
{
499539
"cell_type": "code",
500540
"execution_count": null,

0 commit comments

Comments
 (0)