aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJ08nY2025-11-04 17:51:10 +0100
committerJ08nY2025-11-04 17:51:10 +0100
commita89cc36a0d7e976488f22bef6328be90292d40af (patch)
treef0bcf32a038bdd05f50064c2e02baa7304d4b7c3
parentc22bce41b09ae9018cc4c7ac271eeac0b67b140c (diff)
downloadECTester-a89cc36a0d7e976488f22bef6328be90292d40af.tar.gz
ECTester-a89cc36a0d7e976488f22bef6328be90292d40af.tar.zst
ECTester-a89cc36a0d7e976488f22bef6328be90292d40af.zip
-rw-r--r--analysis/scalarmults/visualize.ipynb593
1 files changed, 366 insertions, 227 deletions
diff --git a/analysis/scalarmults/visualize.ipynb b/analysis/scalarmults/visualize.ipynb
index a77ba9d..b198060 100644
--- a/analysis/scalarmults/visualize.ipynb
+++ b/analysis/scalarmults/visualize.ipynb
@@ -20,18 +20,27 @@
"import glob\n",
"import gc\n",
"import random\n",
+ "import sys\n",
"\n",
"import matplotlib\n",
"import matplotlib.pyplot as plt\n",
"import numpy as np\n",
"\n",
+ "from copy import copy, deepcopy\n",
"from tqdm.auto import tqdm, trange\n",
"from statsmodels.stats.proportion import proportion_confint\n",
"\n",
"from pyecsca.ec.mult import *\n",
- "from pyecsca.misc.utils import TaskExecutor\n",
+ "from pyecsca.ec.countermeasures import *\n",
"\n",
- "from common import *\n",
+ "from epare.config import all_configs, Config, MultIdent, CountermeasureIdent\n",
+ "from epare.prob_map import ProbMap\n",
+ "from epare.error_model import ErrorModel\n",
+ "\n",
+ "if sys.version_info >= (3, 14):\n",
+ " from compression import zstd\n",
+ "else:\n",
+ " from backports import zstd\n",
"\n",
"%matplotlib ipympl"
]
@@ -52,26 +61,8 @@
"metadata": {},
"outputs": [],
"source": [
- "# Setup the ticks and colors deterministically.\n",
- "mult_klasses = sorted(list(set(map(lambda mult: mult.klass, all_mults))), key=lambda klass: klass.__name__)\n",
- "mult_kwarg_map = {klass: 0 for klass in mult_klasses}\n",
- "mult_cm_map = {mult: 0 for mult in all_mults}\n",
- "mult_colors = matplotlib.cm.tab20(range(len(mult_klasses)))\n",
- "mult_styles = ['-', '--', '-.', ':', (5, (10, 3)), (0, (5, 1)), (0, (3, 1, 1, 1, 1, 1)), (0, (3, 1, 1, 1)), (0, (1, 1)), (0, (3, 10, 1, 10))]\n",
- "mult_markers = [None, \"o\", \"+\", \"*\", \"^\", \"s\"]\n",
- "colors = {}\n",
- "styles = {}\n",
- "markers = {}\n",
- "for mult in all_mults:\n",
- " color = mult_colors[mult_klasses.index(mult.klass) % len(mult_colors)]\n",
- " style = mult_styles[mult_kwarg_map[mult.klass] % len(mult_styles)]\n",
- " mult_kwarg_map[mult.klass] += 1\n",
- " for cm in (None, \"gsr\", \"additive\", \"multiplicative\", \"euclidean\", \"bt\"):\n",
- " mwc = mult.with_countermeasure(cm)\n",
- " colors[mwc] = color\n",
- " styles[mwc] = style\n",
- " markers[mwc] = mult_markers[mult_cm_map[mult] % len(mult_markers)]\n",
- " mult_cm_map[mult] += 1\n",
+ "# mult_styles = ['-', '--', '-.', ':', (5, (10, 3)), (0, (5, 1)), (0, (3, 1, 1, 1, 1, 1)), (0, (3, 1, 1, 1)), (0, (1, 1)), (0, (3, 10, 1, 10))]\n",
+ "# mult_markers = [None, \"o\", \"+\", \"*\", \"^\", \"s\"]\n",
"\n",
"majticks = np.arange(0, 1, 0.1)\n",
"minticks = np.arange(0, 1, 0.05)"
@@ -93,141 +84,415 @@
"metadata": {},
"outputs": [],
"source": [
- "from common import divisor_map\n",
+ "from epare.divisors import divisor_map\n",
"for d, ds in divisor_map.items():\n",
" print(f\"{d:<27}\", ds[:3], \"...\", ds[-1:])"
]
},
{
+ "cell_type": "markdown",
+ "id": "8b008248-a0aa-41fa-933c-f325f8eec31b",
+ "metadata": {},
+ "source": [
+ "## Loading\n",
+ "Load the merged probability maps."
+ ]
+ },
+ {
"cell_type": "code",
"execution_count": null,
- "id": "638f8634-1f6e-4844-a796-096611dfbac2",
+ "id": "19d986ab-5fe7-4dd6-b5b5-4e75307217d6",
"metadata": {},
"outputs": [],
"source": [
- "bits = 256\n",
- "num_workers = 28"
+ "with zstd.open(\"merged.zpickle\", \"rb\") as f:\n",
+ " config_map = pickle.load(f)"
]
},
{
"cell_type": "markdown",
- "id": "8b008248-a0aa-41fa-933c-f325f8eec31b",
+ "id": "3afb10e0-383b-443b-a164-2670c606c146",
"metadata": {},
"source": [
- "## Configuration\n",
- "Select the mults you want to compute the prob-maps for here as well as a set of divisors. It is good to set `all` here, compute the prob-maps for all the divisors, save them and they continue with visualizing them on subsets of divisors."
+ "## Plots"
]
},
{
- "cell_type": "code",
- "execution_count": null,
- "id": "4d2a0f19-8275-4db8-b3fc-c930d8ba2177",
+ "cell_type": "markdown",
+ "id": "7f6c5506-8636-4570-824b-701eec5fbaa7",
"metadata": {},
- "outputs": [],
"source": [
- "selected_mults = all_mults\n",
- "divisor_name = \"all\"\n",
- "showci = False\n",
- "selected_divisors = divisor_map[divisor_name]\n",
- "show_error_model = ErrorModel({}, \"all\", True)"
+ "### 1. Error models\n",
+ "First, lets plot the effect different error models have on the error probability given the same multiplier and countermeasure."
]
},
{
"cell_type": "code",
"execution_count": null,
- "id": "19d986ab-5fe7-4dd6-b5b5-4e75307217d6",
+ "id": "8736fb1d-9af0-4173-902c-1124e6729956",
"metadata": {},
"outputs": [],
"source": [
- "with open(f\"merged.pickle\", \"rb\") as f:\n",
- " distributions_mults = pickle.load(f)"
+ "plot_configs = []\n",
+ "plot_divisors = divisor_map[\"small_primes\"]\n",
+ "\n",
+ "# Here are several useful filters when playing around with the data. We want to select a single multiplier and countereasure combination.\n",
+ "only_ltr_example = lambda config: config.mult.klass == LTRMultiplier and not config.mult.kwargs[\"always\"] and not config.mult.kwargs[\"complete\"]\n",
+ "only_rtl_example = lambda config: config.mult.klass == RTLMultiplier and not config.mult.kwargs[\"always\"] and not config.mult.kwargs[\"complete\"]\n",
+ "only_sliding_example = lambda config: config.mult.klass == SlidingWindowMultiplier and config.mult.kwargs[\"width\"] == 4 and config.mult.kwargs[\"recoding_direction\"] == ProcessingDirection.LTR\n",
+ "only_comb_example = lambda config: config.mult.klass == CombMultiplier and config.mult.kwargs[\"width\"] == 4 and config.mult.kwargs[\"always\"] == True\n",
+ "single_layer_ctr = lambda config: all(map(lambda ident: isinstance(ident, MultIdent), config.composition.args))\n",
+ "single_type_ctr = lambda config: all(map(lambda ident: isinstance(ident, MultIdent) or ident.klass == config.composition.klass, config.composition.args))\n",
+ "single_type_ctr_full = lambda config: all(map(lambda ident: ident.klass == config.composition.klass, config.composition.args))\n",
+ "\n",
+ "groups = {}\n",
+ "for config, probmap in config_map.items():\n",
+ " if config.composition.klass == GroupScalarRandomization and single_layer_ctr(config) and only_rtl_example(config):\n",
+ " plot_configs.append(config)\n",
+ " pmap = deepcopy(probmap)\n",
+ " pmap.narrow(plot_divisors)\n",
+ " group = groups.setdefault(pmap.id(), [])\n",
+ " group.append(config)\n",
+ "print(f\"Plotting {len(plot_configs)} configs in {len(groups)} groups:\")\n",
+ "inverse_groups = {}\n",
+ "for i, group in groups.items():\n",
+ " for c in group:\n",
+ " inverse_groups[c] = i\n",
+ " print(c.error_model)\n",
+ " print()\n",
+ "\n",
+ "L = len(plot_divisors)\n",
+ "N = len(plot_mults)\n",
+ "x = list(range(L))\n",
+ "\n",
+ "fig = plt.figure(figsize=(20, 10))\n",
+ "ax = plt.subplot(111)\n",
+ "colors = matplotlib.cm.tab10(range(8))\n",
+ "color_map = {\n",
+ " \"affine\": 0,\n",
+ " \"affine,equal_multiples\": 1,\n",
+ " \"affine,divides\": 2,\n",
+ " \"affine,half_add\": 3,\n",
+ " \"affine,divides,equal_multiples\": 4,\n",
+ " \"affine,equal_multiples,half_add\": 5,\n",
+ " \"affine,divides,half_add\": 6,\n",
+ " \"affine,divides,equal_multiples,half_add\": 7\n",
+ "}\n",
+ "\n",
+ "style_map = {}\n",
+ "for i, config in enumerate(plot_configs):\n",
+ " probmap = config_map[config]\n",
+ " y_values = [probmap[l] for l in plot_divisors]\n",
+ " # Use the same style for several entries that are fully overlapping (in the same group)\n",
+ " group = inverse_groups[config]\n",
+ " if group in style_map:\n",
+ " style = style_map[group]\n",
+ " else:\n",
+ " style = dict(color=colors[color_map[\",\".join(sorted(config.error_model.checks))]],\n",
+ " marker=\"o\" if config.error_model.precomp_to_affine else \"\",\n",
+ " linestyle=\"-\" if config.error_model.check_condition == \"all\" else \"--\")\n",
+ " style_map[group] = style\n",
+ " ax.plot(x, y_values, **style, label=str(config.error_model))\n",
+ "\n",
+ "ax.set_xlabel(\"divisor\")\n",
+ "ax.set_ylabel(\"error probability\")\n",
+ "ax.set_ylim((-0.05, 1.05))\n",
+ "ax.set_yticks(majticks)\n",
+ "ax.set_yticks(minticks, minor=True)\n",
+ "ax.set_xticks(x, plot_divisors, rotation=90)\n",
+ "\n",
+ "ax.grid(axis=\"y\", which=\"major\", alpha=0.7)\n",
+ "ax.grid(axis=\"y\", which=\"minor\", alpha=0.3)\n",
+ "ax.grid(axis=\"x\", alpha=0.7)\n",
+ "#plt.tight_layout()\n",
+ "box = ax.get_position()\n",
+ "ax.set_position([box.x0-0.08, box.y0, box.width, box.height+0.08])\n",
+ "\n",
+ "ax.legend(loc='center left', bbox_to_anchor=(1.0, 0.5))\n",
+ "\n",
+ "fig.savefig(\"error_models.pdf\")\n",
+ "plt.close();"
]
},
{
"cell_type": "markdown",
- "id": "ef5b7a43-74b4-4e72-a3a1-955e175f5297",
+ "id": "c9daec59-b75c-432d-a543-ddac7ef9ec2d",
"metadata": {},
"source": [
- "Now, go over all the divisor sets and visualize them (without the combs) into PNGs in the graphs/ directory."
+ "### 2. Countermeasures\n",
+ "Next up, we can have a look at how the countermeasure(s) used change the error probability, given a single multiplier and error model."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "5b3e3d65-815b-4a2d-afce-53069f7a7daf",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "plot_configs = []\n",
+ "plot_divisors = divisor_map[\"small_primes\"]\n",
+ "\n",
+ "# Here are several useful filters when playing around with the data. We want to select a single multiplier and error model.\n",
+ "only_ltr_example = lambda config: config.mult.klass == LTRMultiplier and not config.mult.kwargs[\"always\"] and not config.mult.kwargs[\"complete\"]\n",
+ "only_rtl_example = lambda config: config.mult.klass == RTLMultiplier and not config.mult.kwargs[\"always\"] and not config.mult.kwargs[\"complete\"]\n",
+ "only_sliding_example = lambda config: config.mult.klass == SlidingWindowMultiplier and config.mult.kwargs[\"width\"] == 4 and config.mult.kwargs[\"recoding_direction\"] == ProcessingDirection.LTR\n",
+ "only_comb_example = lambda config: config.mult.klass == CombMultiplier and config.mult.kwargs[\"width\"] == 4 and config.mult.kwargs[\"always\"] == True\n",
+ "\n",
+ "fixed_error_model = lambda config: config.error_model == ErrorModel({\"divides\"}, \"all\", True)\n",
+ "single_layer_ctr = lambda config: all(map(lambda ident: isinstance(ident, MultIdent), config.composition.args))\n",
+ "single_type_ctr = lambda config: all(map(lambda ident: isinstance(ident, MultIdent) or ident.klass == config.composition.klass, config.composition.args))\n",
+ "single_type_ctr_full = lambda config: all(map(lambda ident: ident.klass == config.composition.klass, config.composition.args))\n",
+ "\n",
+ "groups = {}\n",
+ "for config, probmap in config_map.items():\n",
+ " if fixed_error_model(config) and single_layer_ctr(config) and only_ltr_example(config):\n",
+ " plot_configs.append(config)\n",
+ " pmap = deepcopy(probmap)\n",
+ " pmap.narrow(plot_divisors)\n",
+ " group = groups.setdefault(pmap.id(), [])\n",
+ " group.append(config)\n",
+ "print(f\"Plotting {len(plot_configs)} configs in {len(groups)} groups:\")\n",
+ "inverse_groups = {}\n",
+ "for i, group in groups.items():\n",
+ " for c in group:\n",
+ " inverse_groups[c] = i\n",
+ " print(c)\n",
+ " print()\n",
+ "\n",
+ "L = len(plot_divisors)\n",
+ "N = len(plot_mults)\n",
+ "x = list(range(L))\n",
+ "\n",
+ "fig = plt.figure(figsize=(20, 10))\n",
+ "ax = plt.subplot(111)\n",
+ "colors = matplotlib.cm.tab10(range(len(groups)))\n",
+ "color_map = {group: colors[i] for i, group in enumerate(groups)}\n",
+ "\n",
+ "style_map = {}\n",
+ "for i, config in enumerate(plot_configs):\n",
+ " probmap = config_map[config]\n",
+ " y_values = [probmap[l] for l in plot_divisors]\n",
+ " # Use the same style for several entries that are fully overlapping (in the same group)\n",
+ " group = inverse_groups[config]\n",
+ " if group in style_map:\n",
+ " style = style_map[group]\n",
+ " else:\n",
+ " style = dict(color=color_map[group],\n",
+ " marker=\"o\",\n",
+ " linestyle=\"-\")\n",
+ " style_map[group] = style\n",
+ " ax.plot(x, y_values, **style, label=str(config.composition.klass.__name__))\n",
+ "\n",
+ "ax.set_xlabel(\"divisor\")\n",
+ "ax.set_ylabel(\"error probability\")\n",
+ "ax.set_ylim((-0.05, 1.05))\n",
+ "ax.set_yticks(majticks)\n",
+ "ax.set_yticks(minticks, minor=True)\n",
+ "ax.set_xticks(x, plot_divisors, rotation=90)\n",
+ "\n",
+ "ax.grid(axis=\"y\", which=\"major\", alpha=0.7)\n",
+ "ax.grid(axis=\"y\", which=\"minor\", alpha=0.3)\n",
+ "ax.grid(axis=\"x\", alpha=0.7)\n",
+ "#plt.tight_layout()\n",
+ "box = ax.get_position()\n",
+ "ax.set_position([box.x0-0.08, box.y0, box.width, box.height+0.08])\n",
+ "\n",
+ "ax.legend(loc='center left', bbox_to_anchor=(1.0, 0.5))\n",
+ "\n",
+ "fig.savefig(\"countermeasures.pdf\")\n",
+ "plt.close();"
]
},
{
"cell_type": "markdown",
- "id": "9b6f169b-07b3-4b27-ba36-8b90418cd072",
+ "id": "7ee79c41-44c7-4882-9f7c-27f619a0d01b",
"metadata": {},
"source": [
- "## Plots (nocomb)\n",
- "Let's visualize all the divisor groups while looking at the multipliers and countermeasures except the comb-like ones."
+ "### 3. Multipliers (small primes)\n",
+ "We can also have a look at how different scalar multipliers influence the error probability."
]
},
{
"cell_type": "code",
"execution_count": null,
- "id": "906b5d78-b3a4-4cbb-8051-092d411ba735",
+ "id": "7bb99570-d417-4121-b5ef-aeafb6f823b4",
"metadata": {},
"outputs": [],
"source": [
- "for divisor_name in divisor_map:\n",
- " plot_mults = list(filter(lambda mult: mult in distributions_mults and mult.klass not in (CombMultiplier, BGMWMultiplier), distributions_mults))\n",
- " print(divisor_name, \"nocomb\")\n",
- " plot_divisors = sorted(divisor_map[divisor_name])\n",
- " L = len(plot_divisors)\n",
- " N = len(plot_mults)\n",
- " x = list(range(L))\n",
- " \n",
- " fig = plt.figure(figsize=(L/4+10, 24))\n",
- " ax = plt.subplot(111)\n",
- " \n",
- " vals = np.zeros((N, L))\n",
- " n_samples = 0\n",
- " for i, mult in enumerate(plot_mults):\n",
- " clear_mult = mult.with_error_model(None)\n",
- " probmap = distributions_mults[mult]\n",
- " y_values = [probmap[l] for l in plot_divisors]\n",
- " vals[i,] = y_values\n",
- " ax.plot(x, y_values,\n",
- " color=colors[clear_mult],\n",
- " linestyle=styles[clear_mult],\n",
- " marker=markers[clear_mult],\n",
- " label=str(mult) if mult.countermeasure is None and mult.error_model == show_error_model else \"_nolegend_\")\n",
- " if showci:\n",
- " cis = [conf_interval(p, probmap.samples) for p in y_values]\n",
- " ci_low = [ci[0] for ci in cis]\n",
- " ci_high = [ci[1] for ci in cis]\n",
- " ax.fill_between(x, ci_low, ci_high, color=\"black\", alpha=0.1)\n",
- " n_samples += probmap.samples\n",
- " \n",
- " ax.set_title(f\"{divisor_name}\\nSamples: \" + str(n_samples//N))\n",
- " \n",
- " #var = np.var(vals, axis=0)\n",
- " #ax.plot(x, var / np.max(var), label=\"cross-mult variance (normalized)\", ls=\"--\", lw=2, color=\"black\")\n",
- " \n",
- " ax.set_xlabel(\"divisors\")\n",
- " ax.set_ylabel(\"error probability\")\n",
- " ax.set_yticks(majticks)\n",
- " ax.set_yticks(minticks, minor=True)\n",
- " ax.set_xticks(x, plot_divisors, rotation=90)\n",
- " \n",
- " ax.grid(axis=\"y\", which=\"major\", alpha=0.7)\n",
- " ax.grid(axis=\"y\", which=\"minor\", alpha=0.3)\n",
- " ax.grid(axis=\"x\", alpha=0.7)\n",
- " plt.tight_layout()\n",
- " box = ax.get_position()\n",
- " ax.set_position([box.x0, box.y0, box.width * 0.9, box.height])\n",
- " \n",
- " ax.legend(loc='center left', bbox_to_anchor=(1, 0.5))\n",
+ "plot_configs = []\n",
+ "plot_divisors = divisor_map[\"small_primes\"]\n",
"\n",
- " fig.savefig(f\"graphs/{divisor_name}-nocomb{'+ci' if showci else ''}.pdf\");\n",
- " plt.close()"
+ "# Here are several useful filters when playing around with the data. We want to select a single countermeasure config and error_model\n",
+ "only_ltrs = lambda config: config.mult.klass == LTRMultiplier\n",
+ "only_rtls = lambda config: config.mult.klass == RTLMultiplier\n",
+ "only_slidings = lambda config: config.mult.klass == SlidingWindowMultiplier\n",
+ "only_combs = lambda config: config.mult.klass == CombMultiplier\n",
+ "no_combs = lambda config: config.mult.klass not in (CombMultiplier, BGMWMultiplier)\n",
+ "\n",
+ "fixed_error_model = lambda config: config.error_model == ErrorModel({\"divides\"}, \"all\", True)\n",
+ "fixed_no_countermeasure = lambda config: isinstance(config.composition, MultIdent)\n",
+ "fixed_gsr_countermeasure = lambda config: config.composition.klass == GroupScalarRandomization\n",
+ "\n",
+ "groups = {}\n",
+ "for config, probmap in config_map.items():\n",
+ " if fixed_error_model(config) and fixed_no_countermeasure(config) and no_combs(config):\n",
+ " plot_configs.append(config)\n",
+ " pmap = deepcopy(probmap)\n",
+ " pmap.narrow(plot_divisors)\n",
+ " group = groups.setdefault(pmap.id(), [])\n",
+ " group.append(config)\n",
+ "print(f\"Plotting {len(plot_configs)} configs in {len(groups)} groups:\")\n",
+ "inverse_groups = {}\n",
+ "for i, group in groups.items():\n",
+ " for c in group:\n",
+ " inverse_groups[c] = i\n",
+ " print(c.mult)\n",
+ " print()\n",
+ "\n",
+ "L = len(plot_divisors)\n",
+ "N = len(plot_mults)\n",
+ "x = list(range(L))\n",
+ "\n",
+ "fig = plt.figure(figsize=(20, 10))\n",
+ "ax = plt.subplot(111)\n",
+ "colors = matplotlib.cm.tab20(range(12))\n",
+ "color_map = {\n",
+ " LTRMultiplier: 0,\n",
+ " RTLMultiplier: 1,\n",
+ " CoronMultiplier: 2,\n",
+ " BinaryNAFMultiplier: 3,\n",
+ " WindowNAFMultiplier: 4,\n",
+ " FixedWindowLTRMultiplier: 5,\n",
+ " SlidingWindowMultiplier: 6,\n",
+ " WindowBoothMultiplier: 7,\n",
+ " SimpleLadderMultiplier: 8,\n",
+ " BGMWMultiplier: 9,\n",
+ " CombMultiplier: 10,\n",
+ " FullPrecompMultiplier: 11\n",
+ "}\n",
+ "\n",
+ "label_map = {}\n",
+ "for i, config in enumerate(plot_configs):\n",
+ " probmap = config_map[config]\n",
+ " y_values = [probmap[l] for l in plot_divisors]\n",
+ " style = dict(color=colors[color_map[config.mult.klass]],\n",
+ " marker=\"o\",\n",
+ " linestyle=\"-\")\n",
+ " if config.mult.klass in label_map:\n",
+ " label = \"__nolegend__\"\n",
+ " else:\n",
+ " label = config.mult.klass.__name__\n",
+ " label_map[config.mult.klass] = label\n",
+ " ax.plot(x, y_values, **style, label=label)\n",
+ "\n",
+ "ax.set_xlabel(\"divisor\")\n",
+ "ax.set_ylabel(\"error probability\")\n",
+ "ax.set_ylim((-0.05, 1.05))\n",
+ "ax.set_yticks(majticks)\n",
+ "ax.set_yticks(minticks, minor=True)\n",
+ "ax.set_xticks(x, plot_divisors, rotation=90)\n",
+ "\n",
+ "ax.grid(axis=\"y\", which=\"major\", alpha=0.7)\n",
+ "ax.grid(axis=\"y\", which=\"minor\", alpha=0.3)\n",
+ "ax.grid(axis=\"x\", alpha=0.7)\n",
+ "#plt.tight_layout()\n",
+ "box = ax.get_position()\n",
+ "ax.set_position([box.x0-0.08, box.y0, box.width, box.height+0.08])\n",
+ "\n",
+ "ax.legend(loc='center left', bbox_to_anchor=(1.0, 0.5))\n",
+ "\n",
+ "fig.savefig(\"multipliers_small_primes.pdf\")\n",
+ "plt.close();"
]
},
{
"cell_type": "markdown",
- "id": "4068e7d0-addb-45d0-ba87-e572d4c82fbd",
+ "id": "ffd2dfc7-7ad3-4dc1-a860-21a76fd1275a",
"metadata": {},
"source": [
- "## Plots (allmults)\n",
- "Now, lets also do plots with allmults for all divisor groups."
+ "### 4. Multiplier options (small primes)\n",
+ "Scalar multipliers are often parametrizable, we can examine how parameters like \"width\" in a window-based multiplier influence the error rate, given a single error model and no countermeasures."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "ad44583f-8052-44d9-a0d7-1335aa707817",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "plot_configs = []\n",
+ "plot_divisors = divisor_map[\"small_primes\"]\n",
+ "\n",
+ "# Here are several useful filters when playing around with the data. We want to select a single countermeasure config and error_model\n",
+ "only_ltrs = lambda config: config.mult.klass == LTRMultiplier\n",
+ "only_rtls = lambda config: config.mult.klass == RTLMultiplier\n",
+ "only_slidings = lambda config: config.mult.klass == SlidingWindowMultiplier\n",
+ "only_combs = lambda config: config.mult.klass == CombMultiplier\n",
+ "\n",
+ "fixed_error_model = lambda config: config.error_model == ErrorModel({\"divides\"}, \"all\", True)\n",
+ "fixed_no_countermeasure = lambda config: isinstance(config.composition, MultIdent)\n",
+ "fixed_gsr_countermeasure = lambda config: config.composition.klass == GroupScalarRandomization\n",
+ "\n",
+ "groups = {}\n",
+ "for config, probmap in config_map.items():\n",
+ " if fixed_error_model(config) and fixed_no_countermeasure(config) and only_slidings(config):\n",
+ " plot_configs.append(config)\n",
+ " pmap = deepcopy(probmap)\n",
+ " pmap.narrow(plot_divisors)\n",
+ " group = groups.setdefault(pmap.id(), [])\n",
+ " group.append(config)\n",
+ "print(f\"Plotting {len(plot_configs)} configs in {len(groups)} groups:\")\n",
+ "inverse_groups = {}\n",
+ "for i, group in groups.items():\n",
+ " for c in group:\n",
+ " inverse_groups[c] = i\n",
+ " print(c.mult)\n",
+ " print()\n",
+ "\n",
+ "L = len(plot_divisors)\n",
+ "N = len(plot_mults)\n",
+ "x = list(range(L))\n",
+ "\n",
+ "fig = plt.figure(figsize=(20, 10))\n",
+ "ax = plt.subplot(111)\n",
+ "colors = matplotlib.cm.tab10(range(len(groups)))\n",
+ "color_map = {group: colors[i] for i, group in enumerate(groups)}\n",
+ "\n",
+ "label_map = {}\n",
+ "for i, config in enumerate(plot_configs):\n",
+ " probmap = config_map[config]\n",
+ " y_values = [probmap[l] for l in plot_divisors]\n",
+ " # Use the same style for several entries that are fully overlapping (in the same group)\n",
+ " group = inverse_groups[config]\n",
+ " if group in style_map:\n",
+ " style = style_map[group]\n",
+ " else:\n",
+ " style = dict(color=color_map[group],\n",
+ " marker=\"o\",\n",
+ " linestyle=\"-\")\n",
+ " style_map[group] = style\n",
+ " ax.plot(x, y_values, **style, label=str(config.mult))\n",
+ "\n",
+ "ax.set_xlabel(\"divisor\")\n",
+ "ax.set_ylabel(\"error probability\")\n",
+ "ax.set_ylim((-0.05, 1.05))\n",
+ "ax.set_yticks(majticks)\n",
+ "ax.set_yticks(minticks, minor=True)\n",
+ "ax.set_xticks(x, plot_divisors, rotation=90)\n",
+ "\n",
+ "ax.grid(axis=\"y\", which=\"major\", alpha=0.7)\n",
+ "ax.grid(axis=\"y\", which=\"minor\", alpha=0.3)\n",
+ "ax.grid(axis=\"x\", alpha=0.7)\n",
+ "#plt.tight_layout()\n",
+ "box = ax.get_position()\n",
+ "ax.set_position([box.x0-0.08, box.y0, box.width, box.height+0.08])\n",
+ "\n",
+ "ax.legend(loc='center left', bbox_to_anchor=(1.0, 0.5))\n",
+ "\n",
+ "fig.savefig(\"multiplier_options_small_primes.pdf\")\n",
+ "plt.close();"
]
},
{
@@ -289,132 +554,6 @@
" fig.savefig(f\"graphs/{kind}-kind/{divisor_name}-allmults{'+ci' if showci else ''}.pdf\")\n",
" plt.close()"
]
- },
- {
- "cell_type": "markdown",
- "id": "df2e236a-4540-4677-a7f1-563c4cc37a3e",
- "metadata": {},
- "source": [
- "## Interactive plot\n",
- "Below you can choose a concrete divisor set and visualize it with all the mults, or just some to your liking."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "b464865d-b169-446e-a9e7-0cead699aee1",
- "metadata": {},
- "outputs": [],
- "source": [
- "#divisor_name = \"powers_of_2_large\"\n",
- "single_mult = random.choice(list(distributions_mults.keys())).with_error_model(None)\n",
- "divisor_name = \"all_integers\"\n",
- "plot_mults = list(filter(lambda mult: mult.with_error_model(None) == single_mult, distributions_mults))\n",
- "plot_divisors = divisor_map[divisor_name]\n",
- "#plot_divisors = (61, 65, 111, 165, 1536, 12288) \n",
- "#plot_divisors = (55, 65, 165, 248, 3072)\n",
- "L = len(plot_divisors)\n",
- "N = len(plot_mults)\n",
- "x = list(range(L))\n",
- "\n",
- "colors = plt.get_cmap('tab20').colors +plt.get_cmap('tab20b').colors[:12]\n",
- "\n",
- "fig = plt.figure(figsize=(L/4+15, 24))\n",
- "ax = plt.subplot(111)\n",
- "\n",
- "vals = np.zeros((N, L))\n",
- "n_samples = 0\n",
- "groups = {}\n",
- "for i, mult in enumerate(plot_mults):\n",
- "\n",
- " clear_mult = mult.with_error_model(None)\n",
- " probmap = distributions_mults[mult]\n",
- " y_values = [probmap[l] for l in plot_divisors]\n",
- " y_tup = tuple(y_values)\n",
- " group = groups.setdefault(y_tup, set())\n",
- " group.add(mult)\n",
- " vals[i,] = y_values\n",
- " offset = (i - N/2) * 0.0001\n",
- " ax.plot(x,[v + offset for v in y_values],\n",
- " color=colors[i],\n",
- " linestyle=styles[clear_mult],\n",
- " marker=markers[clear_mult],\n",
- " label=str(mult))\n",
- " if showci:\n",
- " cis = [conf_interval(p, probmap.samples) for p in y_values]\n",
- " ci_low = [ci[0] for ci in cis]\n",
- " ci_high = [ci[1] for ci in cis]\n",
- " ax.fill_between(x, ci_low, ci_high, color=\"black\", alpha=0.1)\n",
- " n_samples += probmap.samples\n",
- "\n",
- "ax.set_title(f\"{divisor_name}\\nSamples(avg): \" + str(n_samples//N))\n",
- "\n",
- "#var = np.var(vals, axis=0)\n",
- "#ax.plot(x, var / np.max(var), label=\"cross-mult variance (normalized)\", ls=\"--\", lw=2, color=\"black\")\n",
- "\n",
- "ax.set_xlabel(\"divisors\")\n",
- "ax.set_ylabel(\"error probability\")\n",
- "ax.set_yticks(majticks)\n",
- "ax.set_yticks(minticks, minor=True)\n",
- "ax.set_xticks(x, plot_divisors, rotation=90)\n",
- "\n",
- "ax.grid(axis=\"y\", which=\"major\", alpha=0.7)\n",
- "ax.grid(axis=\"y\", which=\"minor\", alpha=0.3)\n",
- "ax.grid(axis=\"x\", alpha=0.7)\n",
- "plt.tight_layout()\n",
- "box = ax.get_position()\n",
- "ax.set_position([box.x0, box.y0, box.width * 0.7, box.height])\n",
- "\n",
- "# Put a legend to the right of the current axis\n",
- "ax.legend(loc='center left', bbox_to_anchor=(1, 0.5));\n",
- "for _, group in groups.items():\n",
- " print(group)\n",
- " print()"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "bf6a5acb-2836-445b-a877-c29ed0f03bf7",
- "metadata": {},
- "outputs": [],
- "source": [
- "divisor_name = \"all\"\n",
- "plot_divisors = divisor_map[divisor_name]\n",
- "ngroups = []\n",
- "for mult in all_mults_with_ctr:\n",
- " groups = {}\n",
- " for error_model in all_error_models:\n",
- " full = mult.with_error_model(error_model)\n",
- " probmap = distributions_mults[full]\n",
- " y_values = [probmap[l] for l in plot_divisors]\n",
- " y_tup = tuple(y_values)\n",
- " group = groups.setdefault(y_tup, set())\n",
- " group.add(mult)\n",
- " ngroups.append(len(groups))\n",
- "print(np.min(ngroups))\n",
- "print(np.mean(ngroups))\n",
- "print(np.median(ngroups))\n",
- "print(np.max(ngroups))"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "9c41722a-45b1-40f0-afc4-1aadc882fcc0",
- "metadata": {},
- "outputs": [],
- "source": [
- "plt.close(\"all\")"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "e7d7e614-467d-4e7d-874b-0495ef4dcf27",
- "metadata": {},
- "outputs": [],
- "source": []
}
],
"metadata": {