{ "cells": [ { "cell_type": "markdown", "id": "bafc2f4e-05a3-4120-bcd6-5d1f5fb91cd9", "metadata": {}, "source": [ "# Distinguishing countermeasures by output" ] }, { "cell_type": "code", "execution_count": 2, "id": "33ee6084-2ac3-4f95-9610-0fbc06026538", "metadata": {}, "outputs": [], "source": [ "import io\n", "import random\n", "import itertools\n", "import cypari2\n", "\n", "from matplotlib import pyplot as plt\n", "from collections import Counter\n", "from tqdm.auto import tqdm, trange\n", "\n", "from pyecsca.misc.utils import TaskExecutor\n", "from pyecsca.ec.mod import mod, RandomModAction\n", "from pyecsca.ec.point import Point\n", "from pyecsca.ec.model import ShortWeierstrassModel\n", "from pyecsca.ec.params import load_params_ectester\n", "from pyecsca.ec.mult import LTRMultiplier\n", "from pyecsca.ec.context import local, DefaultContext\n", "from pyecsca.ec.countermeasures import GroupScalarRandomization, AdditiveSplitting, MultiplicativeSplitting, EuclideanSplitting, BrumleyTuveri\n", "\n", "%matplotlib ipympl" ] }, { "cell_type": "code", "execution_count": 3, "id": "b1b9596c-1eba-4ace-af84-8cb279d84cc2", "metadata": {}, "outputs": [], "source": [ "model = ShortWeierstrassModel()\n", "coords = model.coordinates[\"projective\"]" ] }, { "cell_type": "code", "execution_count": 4, "id": "b0afb195-8390-44c5-931e-75a70ccd4e9e", "metadata": {}, "outputs": [], "source": [ "add = coords.formulas[\"add-2015-rcb\"]\n", "dbl = coords.formulas[\"dbl-2015-rcb\"]\n", "mult = LTRMultiplier(add, dbl, complete=False)" ] }, { "cell_type": "code", "execution_count": 5, "id": "52c877e1-5021-4ec2-9daa-dd20bec6bcb2", "metadata": {}, "outputs": [], "source": [ "gsr = GroupScalarRandomization(mult)\n", "asplit = AdditiveSplitting(mult)\n", "msplit = MultiplicativeSplitting(mult)\n", "esplit = EuclideanSplitting(mult)\n", "bt = BrumleyTuveri(mult)" ] }, { "cell_type": "markdown", "id": "27626337-dcbc-497c-a54e-02d50e2b8f34", "metadata": {}, "source": [ "## 3n test" ] }, { "cell_type": "code", "execution_count": 208, "id": "c3088419-161b-4193-a1b6-6f623f217fcd", "metadata": {}, "outputs": [], "source": [ "key3n = 0x20959f2b437de1e522baf6d814911938157390d3ea5118660b852ab0d5387006\n", "params3n = load_params_ectester(io.BytesIO(b\"0xc381bb0394f34b5ed061c9107b66974f4d0a8ec89b9fe73b98b6d1368c7d974d,0x5ca6c5ee0a10097af291a8f125303fb1a3e35e8100411902245d691e0e5cb497,0x385a5a8bb8af94721f6fd10b562606d9b9df931f7fd966e96859bb9bd7c05836,0x4616af1898b92cac0f902a9daee24bbae63571cead270467c6a7886ced421f5e,0x34e896bdb1337e0ae5960fa3389fb59c2c8d6c7dbfd9aac33a844f8f98e433ef,0x412b3e5686fbc3ca4575edb0292232702ae721a7d4a230cc170a5561aa70e00f,0x01\"), \"projective\")\n", "bits3n = params3n.full_order.bit_length()\n", "point3n = Point(X=mod(0x4a48addb2e471767b7cd0f6f1d4c27fe46f4a828fc20f950bd1f72c939b36a84, params3n.curve.prime),\n", " Y=mod(0x13384d38c353f862832c0f067e46a3e510bb6803c20745dfb31929f4a18d890d, params3n.curve.prime),\n", " Z=mod(1, params3n.curve.prime), model=coords)" ] }, { "cell_type": "code", "execution_count": 209, "id": "a8dde7e6-cd48-4f99-9677-23a19e4c2e5b", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "prime:\t0xc381bb0394f34b5ed061c9107b66974f4d0a8ec89b9fe73b98b6d1368c7d974d\n", "a:\t0x5ca6c5ee0a10097af291a8f125303fb1a3e35e8100411902245d691e0e5cb497\n", "b:\t0x385a5a8bb8af94721f6fd10b562606d9b9df931f7fd966e96859bb9bd7c05836\n", "G:\t[0x4616af1898b92cac0f902a9daee24bbae63571cead270467c6a7886ced421f5e,\n", "\t 0x34e896bdb1337e0ae5960fa3389fb59c2c8d6c7dbfd9aac33a844f8f98e433ef]\n", "n:\t0x412b3e5686fbc3ca4575edb0292232702ae721a7d4a230cc170a5561aa70e00f\n", "3n:\t0xc381bb0394f34b5ed061c9107b66975080b564f77de69264451f0024ff52a02d\n", "\n", "P:\t[0x4a48addb2e471767b7cd0f6f1d4c27fe46f4a828fc20f950bd1f72c939b36a84,\n", "\t 0x13384d38c353f862832c0f067e46a3e510bb6803c20745dfb31929f4a18d890d]\n" ] } ], "source": [ "print(f\"prime:\\t0x{params3n.curve.prime:x}\")\n", "print(f\"a:\\t0x{params3n.curve.parameters['a']:x}\")\n", "print(f\"b:\\t0x{params3n.curve.parameters['b']:x}\")\n", "print(f\"G:\\t[0x{params3n.generator.X:x},\\n\\t 0x{params3n.generator.Y:x}]\")\n", "print(f\"n:\\t0x{params3n.order:x}\")\n", "print(f\"3n:\\t0x{3 * params3n.order:x}\")\n", "print(f\"\\nP:\\t[0x{point3n.X:x},\\n\\t 0x{point3n.Y:x}]\")" ] }, { "cell_type": "code", "execution_count": 210, "id": "cd6f8500-7509-45b0-8b23-471ee5014f42", "metadata": {}, "outputs": [], "source": [ "def generate_scalars_mod3(rem, samples):\n", " scalars = []\n", " while True:\n", " scalar = random.randint(0, params3n.full_order)\n", " if scalar % 3 == rem:\n", " scalars.append(scalar)\n", " if len(scalars) == samples:\n", " break\n", " return scalars\n", "\n", "def test_3n(countermeasure, scalars):\n", " ctr = Counter()\n", " for k in tqdm(scalars, leave=False):\n", " mult.init(params3n, point3n)\n", " kP = mult.multiply(k).to_affine()\n", " mult.init(params3n, point3n)\n", " knP = mult.multiply(k + params3n.full_order).to_affine()\n", " mult.init(params3n, point3n)\n", " k2nP = mult.multiply(k + 2 * params3n.full_order).to_affine()\n", "\n", " countermeasure.init(params3n, point3n)\n", " res = countermeasure.multiply(k)\n", " aff = res.to_affine()\n", " if aff.equals(kP):\n", " ctr[\"k\"] += 1\n", " elif aff.equals(knP):\n", " ctr[\"k + 1n\"] += 1\n", " elif aff.equals(k2nP):\n", " ctr[\"k + 2n\"] += 1\n", " else:\n", " ctr[aff] += 1\n", " for name, count in sorted(ctr.items()):\n", " print(f\"{name}:\\t{count}\")\n", "\n", "def test_3n_fixed_scalar(countermeasure, samples):\n", " test_3n(countermeasure, [key3n for _ in range(samples)])\n", "\n", "def test_3n_random_scalar(countermeasure, samples):\n", " test_3n(countermeasure, [random.randint(0, params3n.full_order) for _ in range(samples)])\n", "\n", "def test_3n_random_scalar_projected(countermeasure, samples):\n", " print(\"k = 0 mod 3\")\n", " test_3n(countermeasure, generate_scalars_mod3(0, samples))\n", " print()\n", " print(\"k = 1 mod 3\")\n", " test_3n(countermeasure, generate_scalars_mod3(1, samples))\n", " print()\n", " print(\"k = 2 mod 3\")\n", " test_3n(countermeasure, generate_scalars_mod3(2, samples))" ] }, { "cell_type": "markdown", "id": "46b8f74a-433d-48c9-b5b9-6bb7d2731246", "metadata": {}, "source": [ "### Fixed scalar experiments" ] }, { "cell_type": "markdown", "id": "fc82d4b9-91cd-423c-83aa-89721efa1ae9", "metadata": {}, "source": [ "#### Group scalar randomization" ] }, { "cell_type": "code", "execution_count": 211, "id": "86532d50-2db7-4370-b449-c545b330a852", "metadata": {}, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "b0a80fc9b8f14b2992f10c7bb66a9a83", "version_major": 2, "version_minor": 0 }, "text/plain": [ " 0%| | 0/1000 [00:00 t:\n", " candidates.add(divisor)\n", " #print(f\"Candidates: {len(candidates)}, {r in candidates}\")\n", " candidate_amounts.append(len(candidates))\n", " if len(candidates) == 1:\n", " candidate = candidates.pop()\n", " print(\"Only one candidate, we got the mask:\", candidate, candidate == r)\n", " else:\n", " if len(candidate_amounts) > 10:\n", " # Do not print everything\n", " continue\n", " print(\"Several candidates for r\")\n", " print(f\"true r = {r}\")\n", " print(f\"t = {t}\")\n", " print(f\"full = k + t (n + 92) = {full}\")\n", " print(\"-----\")\n", " for candidate in candidates:\n", " print(f\"candidate = {candidate}\") \n", " candidate_inverse = mod(candidate, real_n + 92).inverse() \n", " print(f\"candidate^-1 = {candidate_inverse}\")\n", " multiplied = candidate * int(candidate_inverse * key)\n", " print(f\"(key * candidate^-1)_mod(n+92) * candidate = {multiplied}\")\n", " print(f\"above == full? {multiplied == full}\")\n", " print(\"-----\")\n", " print(\"---------------------\")\n", " #print(\"--\")\n", "print(f\"Total recovered masks: {len(list(filter(lambda a: a == 1, candidate_amounts)))} out of {tries}\")" ] }, { "cell_type": "code", "execution_count": 36, "id": "6274ff91-325f-4c6b-a4d7-d66b994d730f", "metadata": {}, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "aba07231a8d44a2f92c75ef741f73f50", "version_major": 2, "version_minor": 0 }, "image/png": "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s7O1b98+SVLnzp118803X4+yAAAAqIBDA2BhYaHuv/9+bd26VY0bN5YknT59WrfffrtWr16tZs2aObI8AAAAKuDQTwGPHz9eZ86c0VdffaUffvhBP/zwg/bu3avi4mJNmDDBkaUBAABQCYfuAKanp2vz5s3q2LGjra1Tp05asmSJBgwY4MjSAAAAqIRDdwCtVqtcXV0va3d1dZXVanVkaQAAAFTCoQHwjjvu0MSJE3X8+HFb27FjxzR58mT179/fkaUBAABQCYcGwMWLF6u4uFihoaFq06aN2rRpo1atWqm4uFiLFi2q1lhLlixRaGioPDw8FB0drZ07d16x/9q1a9WhQwd5eHgoPDxc77///mV99u3bpyFDhsjHx0cNGzZUjx49lJeXV615AQAA1DcOvQYwKChIOTk52rx5s7755htJUseOHRUbG1utcdasWaOkpCQtW7ZM0dHRSk1NVVxcnPbv3y8/P7/L+m/btk0jRoxQSkqK7rrrLq1atUrx8fHKyclRly5dJEmHDh1Snz59NGbMGM2ZM0fe3t766quv5OHhce0LBwAAqMMshmEYtT2Jq4mOjlaPHj20ePFiSb9eWxgUFKTx48dr6tSpl/VPSEhQSUmJNmzYYGu75ZZbFBERoWXLlkmS7r//frm6uuqNN96o8byKi4vl4+OjoqIieXt7V+mY0Kkba1zPbL6bO9jhNRz987geawAAVE9NXr9vNA59C1iSMjIydNddd9neAr7rrru0efPmKh9//vx5ZWdnl9s1dHJyUmxsrLKysio8Jisr67Jdxri4OFt/q9WqjRs3ql27doqLi5Ofn5+io6OVlpZW/QUCAADUMw4NgH/5y180cOBAeXl5aeLEiZo4caK8vb115513asmSJVUa49SpUyorK5O/v3+5dn9/f+Xn51d4TH5+/hX7FxYW6uzZs5o7d64GDhyojz76SEOHDtW9996rzMzMSudSWlqq4uLicg8AAID6xqHXAD7zzDN64YUXNG7cOFvbhAkT1Lt3bz3zzDMaO3asI8tX6uItaO655x5NnjxZkhQREaFt27Zp2bJl6tevX4XHpaSkaM6cOddtngAAAI7g0B3A06dPa+DAgZe1DxgwQEVFRVUaw9fXV87OziooKCjXXlBQoICAgAqPCQgIuGJ/X19fubi4qFOnTuX6dOzY8YqfAp42bZqKiopsj6NH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nTt32nX8Tz75RHfffbcCAwNlsVhsv8PYXlJSUtSjRw95eXnJz89P8fHx2r9/v11rLF26VF27drXdzDMmJkYffPCBXWtcau7cubZb/NjLk08+KYvFUu7RoUMHu40vSceOHdNvf/tbNW3aVJ6engoPD9euXbvsNn5oaOhla7BYLBo7dqzdapSVlWnmzJlq1aqVPD091aZNGz311FN2/12bZ86c0aRJkxQSEiJPT0/16tVLX3zxRY3Hu9q5ZhiGZs2apebNm8vT01OxsbE6ePCg3cZ/5513NGDAADVt2lQWi0W5ubl2XcOFCxc0ZcoUhYeHq2HDhgoMDNSoUaN0/Phxu9WQfj1POnTooIYNG+qmm25SbGysduzYYdca/+3RRx+VxWJRamqqXWs8+OCDl50nAwcOtOsa9u3bpyFDhsjHx0cNGzZUjx49lJeXZ7caFZ3rFotFzz33nN1qnD17VuPGjVPLli3l6empTp06admyZVUevyo1CgoK9OCDDyowMFANGjTQwIEDq3XuVeV17ueff9bYsWPVtGlTNWrUSMOGDbvsl0jcqAiANbBmzRolJSVp9uzZysnJUbdu3RQXF6fCwkK71SgpKVG3bt20ZMkSu4353zIzMzV27Fht375dmzZt0oULFzRgwACVlJTYrUbLli01d+5cZWdna9euXbrjjjt0zz336KuvvrJbjf/2xRdf6KWXXlLXrl3tPnbnzp114sQJ2+Ozzz6z29g//vijevfuLVdXV33wwQf6+uuvNX/+fN100012q/HFF1+Um/+mTZskScOHD7dbjWeffVZLly7V4sWLtW/fPj377LOaN2+eFi1aZLcakvTwww9r06ZNeuONN7Rnzx4NGDBAsbGxOnbsWI3Gu9q5Nm/ePL344otatmyZduzYoYYNGyouLk4///yzXcYvKSlRnz599Oyzz9Zo/lerce7cOeXk5GjmzJnKycnRO++8o/3792vIkCF2qyFJ7dq10+LFi7Vnzx599tlnCg0N1YABA3Ty5Em71bho3bp12r59uwIDA6u1hqrWGDhwYLnz5a233rLb+IcOHVKfPn3UoUMHbd26Vf/85z81c+bMKt9+rCo1/nvuJ06c0CuvvCKLxaJhw4bZrUZSUpLS09P15ptvat++fZo0aZLGjRun9evX26WGYRiKj4/Xv/71L7377rvavXu3QkJCFBsbW+XXqaq8zk2ePFnvvfee1q5dq8zMTB0/flz33ntvlddQrxmotp49expjx461fV1WVmYEBgYaKSkpDqknyVi3bp1Dxr6osLDQkGRkZmY6tM5NN91kvPzyy3Yf98yZM0ZYWJixadMmo1+/fsbEiRPtNvbs2bONbt262W28S02ZMsXo06ePw8avyMSJE402bdoYVqvVbmMOHjzYeOihh8q13XvvvcbIkSPtVuPcuXOGs7OzsWHDhnLt3bt3N5544olrHv/Sc81qtRoBAQHGc889Z2s7ffq04e7ubrz11lvXPP5/O3z4sCHJ2L17d7XHrWqNi3bu3GlIMo4cOeKwGkVFRYYkY/PmzXat8e9//9to0aKFsXfvXiMkJMR44YUXajR+ZTUSExONe+65p8ZjXm38hIQE47e//a1dxq+sxqXuuece44477rBrjc6dOxt/+tOfyrVdy3l4aY39+/cbkoy9e/fa2srKyoxmzZoZK1asqFGNS1/nTp8+bbi6uhpr16619dm3b58hycjKyqpRjfqEHcBqOn/+vLKzsxUbG2trc3JyUmxsrLKysmpxZtemqKhIkhz2i7HLysq0evVqlZSUOORX7Y0dO1aDBw8u93Oxp4MHDyowMFCtW7fWyJEjq/V2zdWsX79eUVFRGj58uPz8/HTzzTdrxYoVdhv/UufPn9ebb76phx56SBaLxW7j9urVSxkZGTpw4IAk6csvv9Rnn32mQYMG2a3GL7/8orKysst2Szw9Pe26K3vR4cOHlZ+fX+7/Kx8fH0VHR9f7891isahx48YOGf/8+fNavny5fHx81K1bN7uNa7Va9cADDyg5OVmdO3e227iX2rp1q/z8/NS+fXv9/ve/1/fff2+Xca1WqzZu3Kh27dopLi5Ofn5+io6OtvslPv+toKBAGzdu1JgxY+w6bq9evbR+/XodO3ZMhmFoy5YtOnDggAYMGGCX8UtLSyWp3Lnu5OQkd3f3Gp/rl77OZWdn68KFC+XO7w4dOig4OLhen99VRQCsplOnTqmsrMz2G0gu8vf3V35+fi3N6tpYrVZNmjRJvXv3LvebUuxhz549atSokdzd3fXoo49q3bp16tSpk11rrF69Wjk5ObZfA2hv0dHReu2115Senq6lS5fq8OHDuvXWW3XmzBm7jP+vf/1LS5cuVVhYmD788EP9/ve/14QJE/TXv/7VLuNfKi0tTadPn9aDDz5o13GnTp2q+++/Xx06dJCrq6tuvvlmTZo0SSNHjrRbDS8vL8XExOipp57S8ePHVVZWpjfffFNZWVk6ceKE3epcdPGcvpHO959//llTpkzRiBEj5O3tbdexN2zYoEaNGsnDw0MvvPCCNm3aJF9fX7uN/+yzz8rFxUUTJkyw25iXGjhwoF5//XVlZGTo2WefVWZmpgYNGqSysrJrHruwsFBnz57V3LlzNXDgQH300UcaOnSo7r33XmVmZtph9pf761//Ki8vL7u/rblo0SJ16tRJLVu2lJubmwYOHKglS5aob9++dhn/YhCbNm2afvzxR50/f17PPvus/v3vf9foXK/odS4/P19ubm6X/UOoPp/f1VFvfhUcHGfs2LHau3evQ3ZQ2rdvr9zcXBUVFenvf/+7EhMTlZmZabcQePToUU2cOFGbNm2q1jU01fHfO1hdu3ZVdHS0QkJC9Pbbb9vlX9VWq1VRUVF65plnJEk333yz9u7dq2XLlikxMfGax7/UypUrNWjQoBpdP3Ulb7/9tv72t79p1apV6ty5s3JzczVp0iQFBgbadR1vvPGGHnroIbVo0ULOzs7q3r27RowYoezsbLvVuFFduHBB9913nwzD0NKlS+0+/u23367c3FydOnVKK1as0H333acdO3bIz8/vmsfOzs7WwoULlZOTY9ed60vdf//9tj+Hh4era9euatOmjbZu3ar+/ftf09hWq1WSdM8992jy5MmSpIiICG3btk3Lli1Tv379rmn8irzyyisaOXKk3f9+XLRokbZv367169crJCREn3zyicaOHavAwEC7vBPj6uqqd955R2PGjFGTJk3k7Oys2NhYDRo0qEYfLHPk61x9xQ5gNfn6+srZ2fmyTwkVFBQoICCglmZVc+PGjdOGDRu0ZcsWtWzZ0u7ju7m5qW3btoqMjFRKSoq6deumhQsX2m387OxsFRYWqnv37nJxcZGLi4syMzP14osvysXFxS7/ar9U48aN1a5dO3377bd2Ga958+aXBeKOHTva9W3mi44cOaLNmzfr4YcftvvYycnJtl3A8PBwPfDAA5o8ebLdd2bbtGmjzMxMnT17VkePHtXOnTt14cIFtW7d2q51JNnO6RvhfL8Y/o4cOaJNmzbZffdPkho2bKi2bdvqlltu0cqVK+Xi4qKVK1faZexPP/1UhYWFCg4Otp3rR44c0WOPPabQ0FC71KhI69at5evra5fz3dfXVy4uLtftfP/000+1f/9+u5/vP/30k6ZPn64FCxbo7rvvVteuXTVu3DglJCTo+eeft1udyMhI5ebm6vTp0zpx4oTS09P1/fffV/tcr+x1LiAgQOfPn9fp06fL9a+P53dNEACryc3NTZGRkcrIyLC1Wa1WZWRkOOTaNkcxDEPjxo3TunXr9PHHH6tVq1bXpa7VarVd22EP/fv31549e5Sbm2t7REVFaeTIkcrNzZWzs7Pdal109uxZHTp0SM2bN7fLeL17977s1gQHDhxQSEiIXcb/b6+++qr8/Pw0ePBgu4997tw5OTmV/yvF2dnZtuthbw0bNlTz5s31448/6sMPP9Q999xj9xqtWrVSQEBAufO9uLhYO3bsqFfn+8Xwd/DgQW3evFlNmza9LnXteb4/8MAD+uc//1nuXA8MDFRycrI+/PBDu9SoyL///W99//33djnf3dzc1KNHj+t2vq9cuVKRkZF2vQ5T+vX/pwsXLly3893Hx0fNmjXTwYMHtWvXriqf61d7nYuMjJSrq2u583v//v3Ky8urV+d3TfEWcA0kJSUpMTFRUVFR6tmzp1JTU1VSUqLRo0fbrcbZs2fL/Yvz8OHDys3NVZMmTRQcHHzN448dO1arVq3Su+++Ky8vL9v1Dj4+PvL09Lzm8SVp2rRpGjRokIKDg3XmzBmtWrVKW7dutetf1l5eXpddt9iwYUM1bdrUbtcz/vGPf9Tdd9+tkJAQHT9+XLNnz5azs7NGjBhhl/EnT56sXr166ZlnntF9992nnTt3avny5Vq+fLldxr/IarXq1VdfVWJiolxc7H/q33333Xr66acVHByszp07a/fu3VqwYIEeeughu9b58MMPZRiG2rdvr2+//VbJycnq0KFDjc+/q51rkyZN0p///GeFhYWpVatWmjlzpgIDAxUfH2+X8X/44Qfl5eXZ7st3MRwEBARUeRfiSjWaN2+u3/zmN8rJydGGDRtUVlZmO9+bNGkiNze3a67RtGlTPf300xoyZIiaN2+uU6dOacmSJTp27Fi1bjV0te/VpcHV1dVVAQEBat++vV1qNGnSRHPmzNGwYcMUEBCgQ4cO6fHHH1fbtm0VFxdnlzUkJycrISFBffv21e2336709HS999572rp1q13WcPH1obi4WGvXrtX8+fOrPG51avTr10/Jycny9PRUSEiIMjMz9frrr2vBggV2q7F27Vo1a9ZMwcHB2rNnjyZOnKj4+Pgqf9Dkaq9zPj4+GjNmjJKSktSkSRN5e3tr/PjxiomJ0S233FLlddRbtfkR5Pps0aJFRnBwsOHm5mb07NnT2L59u13H37JliyHpskdiYqJdxq9obEnGq6++apfxDcMwHnroISMkJMRwc3MzmjVrZvTv39/46KOP7DZ+Zex9G5iEhASjefPmhpubm9GiRQsjISHB+Pbbb+02vmEYxnvvvWd06dLFcHd3Nzp06GAsX77cruMbhmF8+OGHhiRj//79dh/bMAyjuLjYmDhxohEcHGx4eHgYrVu3Np544gmjtLTUrnXWrFljtG7d2nBzczMCAgKMsWPHGqdPn67xeFc716xWqzFz5kzD39/fcHd3N/r371+t7+HVxn/11VcrfH727Nl2qXHx9jIVPbZs2WKXGj/99JMxdOhQIzAw0HBzczOaN29uDBkyxNi5c2eVx6/K9+pSNbkNzJVqnDt3zhgwYIDRrFkzw9XV1QgJCTEeeeQRIz8/365rWLlypdG2bVvDw8PD6Natm5GWlma3NVz00ksvGZ6enjU+N65W48SJE8aDDz5oBAYGGh4eHkb79u2N+fPnV+vWUlersXDhQqNly5aGq6urERwcbMyYMaNaf59U5XXup59+Mv7whz8YN910k9GgQQNj6NChxokTJ6pcoz6zGIadb9MPAACAOo1rAAEAAEyGAAgAAGAyBEAAAACTIQACAACYDAEQAADAZAiAAAAAJkMABAAAMBkCIIB647bbbtOkSZNsX4eGhio1NfWKx1gsFqWlpTl0XnVJVb4nAMCvggNQb33xxRdq2LChXcd88sknlZaWptzcXLuOCwB1CQEQQL3VrFmz2p4CANRLvAUMoNqsVqvmzZuntm3byt3dXcHBwXr66adtz0+ZMkXt2rVTgwYN1Lp1a82cOVMXLlywPf/kk08qIiJCb7zxhkJDQ+Xj46P7779fZ86csfUpKSnRqFGj1KhRIzVv3rzCX2p/6dudBw8eVN++feXh4aFOnTpp06ZNlx1zpbm99tprmjNnjr788ktZLBZZLBa99tprkqTTp0/r4YcfVrNmzeTt7a077rhDX375ZaXfo++++04Wi0Vvv/22br31Vnl6eqpHjx46cOCAvvjiC0VFRalRo0YaNGiQTp48aTvuiy++0P/8z//I19dXPj4+6tevn3JycmzPG4ahJ598UsHBwXJ3d1dgYKAmTJhQ6TxefvllNW7cWBkZGZKkv//97woPD5enp6eaNm2q2NhYlZSUVHo8gBsTO4AAqm3atGlasWKFXnjhBfXp00cnTpzQN998Y3vey8tLr732mgIDA7Vnzx498sgj8vLy0uOPP27rc+jQIaWlpWnDhg368ccfdd9992nu3Lm2IJmcnKzMzEy9++678vPz0/Tp05WTk6OIiIgK52S1WnXvvffK399fO3bsUFFRUbnrBasyt4SEBO3du1fp6enavHmzJMnHx0eSNHz4cHl6euqDDz6Qj4+PXnrpJfXv318HDhxQkyZNKv1ezZ49W6mpqQoODtZDDz2k//3f/5WXl5cWLlyoBg0a6L777tOsWbO0dOlSSdKZM2eUmJioRYsWyTAMzZ8/X3feeacOHjwoLy8v/eMf/9ALL7yg1atXq3PnzsrPz680iM6bN0/z5s3TRx99pJ49e+rEiRMaMWKE5s2bp6FDh+rMmTP69NNPxa+EB0zIAIBqKC4uNtzd3Y0VK1ZU+ZjnnnvOiIyMtH09e/Zso0GDBkZxcbGtLTk52YiOjjYMwzDOnDljuLm5GW+//bbt+e+//97w9PQ0Jk6caGsLCQkxXnjhBcMwDOPDDz80XFxcjGPHjtme/+CDDwxJxrp166o1t27dupXr8+mnnxre3t7Gzz//XK69TZs2xksvvVThuIcPHzYkGS+//LKt7a233jIkGRkZGba2lJQUo3379pXOr6yszPDy8jLee+89wzAMY/78+Ua7du2M8+fPV9j/4vfk8ccfN5o3b27s3bvX9lx2drYhyfjuu+8qrQfAHNgBBFAt+/btU2lpqfr3719pnzVr1ujFF1/UoUOHdPbsWf3yyy/y9vYu1yc0NFReXl62r5s3b67CwkJJv+4Onj9/XtHR0bbnmzRpovbt219xXkFBQQoMDLS1xcTE1Ghul/ryyy919uxZNW3atFz7Tz/9pEOHDl3x2K5du9r+7O/vL0kKDw8v13Zx3ZJUUFCgGTNmaOvWrSosLFRZWZnOnTunvLw8Sb/uRKampqp169YaOHCg7rzzTt19991ycfnPX+fz589XSUmJdu3apdatW9vau3Xrpv79+ys8PFxxcXEaMGCAfvOb3+imm2664hoA3Hi4BhBAtXh6el7x+aysLI0cOVJ33nmnNmzYoN27d+uJJ57Q+fPny/VzdXUt97XFYpHVarX7fGsyt0udPXtWzZs3V25ubrnH/v37lZycfMVj/3udFoulwrb/XndiYqJyc3O1cOFCbdu2Tbm5uWratKltjkFBQdq/f7/+8pe/yNPTU3/4wx/Ut2/fctdY3nrrrSorK9Pbb79dbi7Ozs7atGmTPvjgA3Xq1EmLFi1S+/btdfjw4at85wDcaAiAAKolLCxMnp6etg8VXGrbtm0KCQnRE088oaioKIWFhenIkSPVqtGmTRu5urpqx44dtrYff/xRBw4cqPSYjh076ujRozpx4oStbfv27dWem5ubm8rKysq1de/eXfn5+XJxcVHbtm3LPXx9fau1tqv5/PPPNWHCBN15553q3Lmz3N3dderUqXJ9PD09dffdd+vFF1/U1q1blZWVpT179tie79mzpz744AM988wzev7558sda7FY1Lt3b82ZM0e7d++Wm5ub1q1bZ9c1AKj7eAsYQLV4eHhoypQpevzxx+Xm5qbevXvr5MmT+uqrrzRmzBiFhYUpLy9Pq1evVo8ePbRx48ZqB4xGjRppzJgxSk5OVtOmTeXn56cnnnhCTk6V/5s1NjZW7dq1U2Jiop577jkVFxfriSeeKNenKnMLDQ3V4cOHlZubq5YtW8rLy0uxsbGKiYlRfHy85s2bp3bt2un48ePauHGjhg4dqqioqGqt70rCwsL0xhtvKCoqSsXFxUpOTi636/raa6+prKxM0dHRatCggd588015enoqJCSk3Di9evXS+++/r0GDBsnFxUWTJk3Sjh07lJGRoQEDBsjPz087duzQyZMn1bFjR7vNH0D9wA4ggGqbOXOmHnvsMc2aNUsdO3ZUQkKC7Tq2IUOGaPLkyRo3bpwiIiK0bds2zZw5s9o1nnvuOd166626++67FRsbqz59+igyMrLS/k5OTlq3bp1++ukn9ezZUw8//HC5W9NUdW7Dhg3TwIEDdfvtt6tZs2Z66623ZLFY9P7776tv374aPXq02rVrp/vvv19HjhyxXddnLytXrtSPP/6o7t2764EHHtCECRPk5+dne75x48ZasWKFevfura5du2rz5s167733Lrs+UZL69OmjjRs3asaMGVq0aJG8vb31ySef6M4771S7du00Y8YMzZ8/X4MGDbLrGgDUfRbD4PP/AAAAZsIOIAAAgMkQAAEAAEyGAAgAAGAyBEAAAACTIQACAACYDAEQAADAZAiAAAAAJkMABAAAMBkCIAAAgMkQAAEAAEyGAAgAAGAyBEAAAACT+X/vy2kjNTMj9AAAAABJRU5ErkJggg==", "text/html": [ "\n", "
\n", "
\n", " Figure\n", "
\n", " \n", "
\n", " " ], "text/plain": [ "Canvas(toolbar=Toolbar(toolitems=[('Home', 'Reset original view', 'home', 'home'), ('Back', 'Back to previous …" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "max_amount = max(candidate_amounts)\n", "fig = plt.subplots()\n", "plt.hist(candidate_amounts, range=(1, max_amount), align=\"left\", density=True, bins=range(1, max_amount))#, bins=list(range(20)) + list(range(20, 100, 5)) + list(range(100, max(candidate_amounts), 10)))\n", "plt.xlabel(\"candidate masks\")\n", "plt.ylabel(\"proportion\")\n", "plt.xticks(range(max_amount))\n", "plt.xlim(0, 20);\n", "plt.show()" ] }, { "cell_type": "code", "execution_count": 37, "id": "9f22ca9d-bdc2-4ea5-b2bc-249a256bb8ad", "metadata": {}, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "7aebc586f3684a8dbc8977aa2bcb8c38", "version_major": 2, "version_minor": 0 }, "image/png": "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krRp0yZnvY+PjwYMGKB9+/a51Ozfv1/dunVrdC6+vr4KDAx0eQEAAHgat34F3Lt3b82ePVtbt251hq8dO3bo/fff12OPPaaFCxc6ay/1t4EzMzOVnp6u+Ph4JSQkKDc3V7W1tcrIyJAkjRkzRl26dFFOTo4kadKkSRo8eLDmz5+v4cOHKy8vT7t27dLy5cudfWZlZSktLU133HGHfvSjH2njxo164403tHXrVjf8JgAAAFoPtz4GJioq6somYbPp008/vWTN4sWLNW/ePFVWVio2NlYLFy5UYmKiJOnOO+9UZGSkVq5c6axfs2aNpk+frkOHDik6Olpz587VsGHDXPp8/vnnlZOTo//7v//TzTffrFmzZunee++94vXxGBgAADwPj4HxkOcAtlYEQAAAPA8BsBmeA3iBZVkiawIAALQ8twfAF198UTExMfL395e/v7/69ev3nf76BgAAAL4bt94EsmDBAmVnZ2v8+PEaNGiQJOm9997TI488ohMnTjifwQcAAIDm49YAuGjRIi1dulRjxoxxto0YMUJ9+vTRU089RQAEAABoAW79CvjYsWMaOHDgRe0DBw7UsWPH3Dk0AAAAGuHWANi9e3e9+uqrF7WvXr1a0dHR7hwaAAAAjXDrV8CzZs1SWlqa/v73vzuvAXz//fdVUFDQYDAEAACA+7n1DOD999+v4uJihYSEKD8/X/n5+QoJCVFxcbHuu+8+dw4NAACARrjtDOD58+f13//938rOztbLL7/srmEAAABwldx2BrBt27b661//6q7uAQAAcI3c+hVwamqq8vPz3TkEAAAArpJbbwKJjo7Wb3/7W73//vuKi4vTdddd57J94sSJ7hweAAAADXBrAPzzn/+s4OBglZSUqKSkxGWbzWYjAAIAALQAtwbAgwcPOn+2LEvS18EPAAAALcet1wBKX58F7Nu3r/z8/OTn56e+ffvqT3/6k7uHBQAAQCPcegZwxowZWrBggSZMmKCkpCRJUmFhoR599FFVVFTot7/9rTuHBwAAQAPcGgCXLl2qFStWaNSoUc62ESNGqF+/fpowYQIBEAAAoAW49Svg8+fPKz4+/qL2uLg4ffXVV+4cGgAAAI1wawB86KGHtHTp0ovaly9frtGjR7tzaAAAADTCrV8BS1/fBPL222/rtttukyQVFRWpoqJCY8aMUWZmprNuwYIF7p4KAAAA5OYAWF5erltvvVWS9Mknn0iSQkJCFBISovLycmcdj4YBAABoPm4NgFu2bHFn9wAAALgGbn8OIL67yCnrW3oKAADge4QACAAAYBgCIAAAgGEIgAAAAIYhAAIAABiGAAgAAGAYAiAAAIBhCIAAAACGIQACAAAYhgAIAABgGAIgAACAYQiAAAAAhiEAAgAAGIYACAAAYBgCIAAAgGEIgAAAAIYhAAIAABiGAAgAAGAYAiAAAIBhCIAAAACGIQACAAAYhgAIAABgGAIgAACAYQiAAAAAhiEAAgAAGIYACAAAYBiPCoBLlixRZGSk/Pz8lJiYqOLi4kvWr1mzRj179pSfn59iYmK0YcOGRmsfeeQR2Ww25ebmNvGsAQAAWhePCYCrV69WZmamZs6cqdLSUvXv318pKSmqrq5usH779u0aNWqUxo4dq927dys1NVWpqakqLy+/qHbt2rXasWOHOnfu7O5lAAAAtDiPCYALFizQww8/rIyMDPXu3VvLli1Tu3bt9PzzzzdY/9xzz2no0KHKyspSr1699Lvf/U633nqrFi9e7FJ35MgRTZgwQa+88oratm3bHEsBAABoUR4RAM+dO6eSkhIlJyc727y8vJScnKzCwsIG9yksLHSpl6SUlBSXeofDoYceekhZWVnq06fPZedRV1cnu93u8nK3yCnr3T4GAAAwi0cEwBMnTqi+vl5hYWEu7WFhYaqsrGxwn8rKysvW/8///I+8vb01ceLEK5pHTk6OgoKCnK+IiIirXAkAAEDL84gA6A4lJSV67rnntHLlStlstivaZ+rUqaqpqXG+Dh8+7OZZAgAAND2PCIAhISFq06aNqqqqXNqrqqoUHh7e4D7h4eGXrH/33XdVXV2trl27ytvbW97e3vrss8/02GOPKTIyssE+fX19FRgY6PICAADwNB4RAH18fBQXF6eCggJnm8PhUEFBgZKSkhrcJykpyaVekjZt2uSsf+ihh/SPf/xDZWVlzlfnzp2VlZWlt956y32LAQAAaGHeLT2BK5WZman09HTFx8crISFBubm5qq2tVUZGhiRpzJgx6tKli3JyciRJkyZN0uDBgzV//nwNHz5ceXl52rVrl5YvXy5J6tixozp27OgyRtu2bRUeHq6bb765eRcHAADQjDwmAKalpen48eOaMWOGKisrFRsbq40bNzpv9KioqJCX179P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/vz5Vo8ePaxz5841WH/hd/L4449bnTp1ssrLy53bSkpKLEnWoUOHGh0PgBk4Awjgqnz88ceqq6vTXXfd1WjN6tWrtXDhQn3yySc6c+aMvvrqKwUGBrrUREZGKiAgwPm+U6dOqq6ulvT12cFz584pMTHRub1Dhw66+eabLzmviIgIde7c2dmWlJR0TXP7tg8++EBnzpxRx44dXdq/+OILffLJJ5fct1+/fs6fw8LCJEkxMTEubRfWLUlVVVWaPn26tm7dqurqatXX1+vs2bOqqKiQ9PWZyNzcXN14440aOnSohg0bpp/85Cfy9v73f87nz5+v2tpa7dq1SzfeeKOzvX///rrrrrsUExOjlJQUDRkyRD/72c/0gx/84JJrAPD9wzWAAK6Kv7//JbcXFhZq9OjRGjZsmNatW6fdu3frySef1Llz51zq2rZt6/LeZrPJ4XA0+XyvZW7fdubMGXXq1EllZWUur3379ikrK+uS+35znTabrcG2b647PT1dZWVleu6557R9+3aVlZWpY8eOzjlGRERo3759+sMf/iB/f3/95je/0R133OFyjeUPf/hD1dfX69VXX3WZS5s2bbRp0ya9+eab6t27txYtWqSbb75ZBw8evMxvDsD3DQEQwFWJjo6Wv7+/86aCb9u+fbu6deumJ598UvHx8YqOjtZnn312VWPcdNNNatu2rYqKipxtn3/+ufbv39/oPr169dLhw4d17NgxZ9uOHTuuem4+Pj6qr693abv11ltVWVkpb29vde/e3eUVEhJyVWu7nPfff18TJ07UsGHD1KdPH/n6+urEiRMuNf7+/vrJT36ihQsXauvWrSosLNSHH37o3J6QkKA333xTTz/9tJ555hmXfW02mwYNGqRZs2Zp9+7d8vHx0dq1a5t0DQBaP74CBnBV/Pz89MQTT+jxxx+Xj4+PBg0apOPHj2vPnj0aO3asoqOjVVFRoby8PA0YMEDr16+/6oDRvn17jR07VllZWerYsaNCQ0P15JNPysur8f/PmpycrB49eig9PV3z5s2T3W7Xk08+6VJzJXOLjIzUwYMHVVZWphtuuEEBAQFKTk5WUlKSUlNTNXfuXPXo0UNHjx7V+vXrdd999yk+Pv6q1ncp0dHReumllxQfHy+73a6srCyXs64rV65UfX29EhMT1a5dO7388svy9/dXt27dXPoZOHCgNmzYoLvvvlve3t6aPHmyioqKVFBQoCFDhig0NFRFRUU6fvy4evXq1WTzB+AZOAMI4KplZ2frscce04wZM9SrVy+lpaU5r2MbMWKEHn30UY0fP16xsbHavn27srOzr3qMefPm6Yc//KF+8pOfKDk5Wbfffrvi4uIarffy8tLatWv1xRdfKCEhQb/85S9dHk1zpXO7//77NXToUP3oRz/S9ddfr7/85S+y2WzasGGD7rjjDmVkZKhHjx4aOXKkPvvsM+d1fU3lz3/+sz7//HPdeuuteuihhzRx4kSFhoY6twcHB2vFihUaNGiQ+vXrp82bN+uNN9646PpESbr99tu1fv16TZ8+XYsWLVJgYKD+/ve/a9iwYerRo4emT5+u+fPn6+67727SNQBo/WyWxf3/AAAAJuEMIAAAgGEIgAAAAIYhAAIAABiGAAgAAGAYAiAAAIBhCIAAAACGIQACAAAYhgAIAABgGAIgAACAYQiAAAAAhiEAAgAAGIYACAAAYJj/D1eQsoxETxFtAAAAAElFTkSuQmCC", "text/html": [ "\n", "
\n", "
\n", " Figure\n", "
\n", " \n", "
\n", " " ], "text/plain": [ "Canvas(toolbar=Toolbar(toolitems=[('Home', 'Reset original view', 'home', 'home'), ('Back', 'Back to previous …" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "max_amount = max(candidate_amounts)\n", "fig = plt.subplots()\n", "plt.hist(candidate_amounts, range=(1, max_amount), align=\"left\", density=True, bins=range(1, max_amount))#, bins=list(range(20)) + list(range(20, 100, 5)) + list(range(100, max(candidate_amounts), 10)))\n", "plt.xlabel(\"candidate masks\")\n", "plt.ylabel(\"proportion\")\n", "plt.show()" ] }, { "cell_type": "code", "execution_count": null, "id": "1009372d-08af-4dbd-9382-be1f02b4ad42", "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.12.3" } }, "nbformat": 4, "nbformat_minor": 5 }