{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "3c944a8c",
   "metadata": {},
   "source": [
    "# FIPS References\n",
    "\n",
    "This notebook provides insights into the references of FIPS certificates."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "91a0cb1b",
   "metadata": {},
   "outputs": [],
   "source": [
    "import sys\n",
    "import pandas as pd\n",
    "import seaborn as sns\n",
    "import networkx as nx\n",
    "import matplotlib\n",
    "import matplotlib.pyplot as plt\n",
    "\n",
    "from sec_certs.utils.plot_utils import (\n",
    "    get_cert_property,\n",
    "    get_fips_cert_references_graph,\n",
    "    get_most_referenced_cert_graph,\n",
    "    get_most_referencing_cert_graph,\n",
    ")\n",
    "from sec_certs.dataset.fips import FIPSDataset\n",
    "\n",
    "from enum import Enum\n",
    "from collections import Counter\n",
    "from pprint import pprint\n",
    "\n",
    "# Typing imports\n",
    "from pandas.core.frame import DataFrame, Series\n",
    "\n",
    "#%matplotlib inline\n",
    "#matplotlib.use(\"pgf\")\n",
    "sns.set_theme(style='white')\n",
    "plt.rcParams[\"axes.linewidth\"] = 0.5\n",
    "plt.rcParams[\"legend.fontsize\"] = 6.5\n",
    "plt.rcParams[\"xtick.labelsize\"] = 8\n",
    "plt.rcParams[\"ytick.labelsize\"] = 8\n",
    "plt.rcParams[\"ytick.left\"] = True\n",
    "plt.rcParams[\"ytick.major.size\"] = 5\n",
    "plt.rcParams[\"ytick.major.width\"] = 0.5\n",
    "plt.rcParams[\"ytick.major.pad\"] = 0\n",
    "plt.rcParams[\"xtick.bottom\"] = True\n",
    "plt.rcParams[\"xtick.major.size\"] = 5\n",
    "plt.rcParams[\"xtick.major.width\"] = 0.5\n",
    "plt.rcParams[\"xtick.major.pad\"] = 0\n",
    "# plt.rcParams[\"pgf.texsystem\"] = \"pdflatex\"\n",
    "plt.rcParams[\"font.family\"] = \"serif\"\n",
    "# plt.rcParams[\"text.usetex\"] = True\n",
    "# plt.rcParams[\"pgf.rcfonts\"] = False\n",
    "plt.rcParams[\"axes.titlesize\"] = 10\n",
    "plt.rcParams[\"legend.handletextpad\"] = 0.3\n",
    "plt.rcParams[\"lines.markersize\"] = 4\n",
    "plt.rcParams[\"savefig.pad_inches\"] = 0.01\n",
    "sns.set_palette(\"deep\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "629aec45",
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Downloading FIPS Dataset: 100%|█████████████████████████████████████| 57.3M/57.3M [00:51<00:00, 1.16MB/s]\n"
     ]
    }
   ],
   "source": [
    "dset = FIPSDataset.from_web()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "96ad0831",
   "metadata": {},
   "outputs": [],
   "source": [
    "df = dset.to_pandas()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "b76653bd",
   "metadata": {},
   "outputs": [],
   "source": [
    "def get_references_count(references: set[str] | float) -> int:\n",
    "    return 0 if pd.isna(references) else len(references)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "8fd8e127",
   "metadata": {},
   "outputs": [],
   "source": [
    "df[\"outgoing_direct_references_count\"] = df[\"module_directly_referencing\"].apply(get_references_count)\n",
    "df[\"incoming_direct_references_count\"] = df[\"module_directly_referenced_by\"].apply(get_references_count)\n",
    "df[\"outgoing_indirect_references_count\"] = df[\"module_indirectly_referencing\"].apply(get_references_count)\n",
    "df[\"incoming_indirect_references_count\"] = df[\"module_indirectly_referenced_by\"].apply(get_references_count)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "eff29c58",
   "metadata": {},
   "source": [
    "## Analysis of FIPS references"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "6ceb86c7",
   "metadata": {},
   "outputs": [],
   "source": [
    "REFS_COLUMNS: list[str] = [\n",
    "    \"cert_id\",\n",
    "    \"status\",\n",
    "    \"standard\",\n",
    "    \"type\",\n",
    "    \"level\",\n",
    "    \"embodiment\",\n",
    "    \"year_from\",\n",
    "    \"related_cves\",\n",
    "    \"module_directly_referenced_by\",\n",
    "    \"module_indirectly_referenced_by\",\n",
    "    \"module_directly_referencing\",\n",
    "    \"module_indirectly_referencing\",\n",
    "    \"policy_directly_referenced_by\",\n",
    "    \"policy_indirectly_referenced_by\",\n",
    "    \"policy_directly_referencing\",\n",
    "    \"policy_indirectly_referencing\",\n",
    "    \"outgoing_direct_references_count\",\n",
    "    \"incoming_direct_references_count\",\n",
    "    \"outgoing_indirect_references_count\",\n",
    "    \"incoming_indirect_references_count\"\n",
    "]\n",
    "df = df[REFS_COLUMNS]"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9921ff15",
   "metadata": {},
   "source": [
    "### References EDA"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "12f546d4",
   "metadata": {},
   "source": [
    "#### Direct module references"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "9d3b4894",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Total ratio of referencing certs in dataset: 0.1\n"
     ]
    }
   ],
   "source": [
    "n_certs: int = df.shape[0]\n",
    "n_referencing_certs: int = df[df[\"outgoing_direct_references_count\"] > 0].shape[0]\n",
    "ratio: float = round(n_referencing_certs / n_certs, 2)\n",
    "\n",
    "print(f\"Total ratio of referencing certs in dataset: {ratio}\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "28037bec",
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "count    477.000000\n",
       "mean       1.322851\n",
       "std        0.799528\n",
       "min        1.000000\n",
       "25%        1.000000\n",
       "50%        1.000000\n",
       "75%        1.000000\n",
       "max        8.000000\n",
       "Name: outgoing_direct_references_count, dtype: float64"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "df[df[\"outgoing_direct_references_count\"] > 0][\"outgoing_direct_references_count\"].describe()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9276357b",
   "metadata": {},
   "source": [
    "#### Indirect module references"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "ba3e0d4d",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "count    477.000000\n",
       "mean       2.207547\n",
       "std        2.923554\n",
       "min        1.000000\n",
       "25%        1.000000\n",
       "50%        1.000000\n",
       "75%        2.000000\n",
       "max       27.000000\n",
       "Name: outgoing_indirect_references_count, dtype: float64"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "df[df[\"outgoing_indirect_references_count\"] > 0][\"outgoing_indirect_references_count\"].describe()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f7c8177f",
   "metadata": {},
   "source": [
    "#### Direct references per status"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "b374ad5b",
   "metadata": {
    "scrolled": false
   },
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 29916 characters]",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "refs_direct_eda_df: DataFrame = df[df[\"outgoing_direct_references_count\"] > 0]\n",
    "refs_direct_eda_df[\"status\"].value_counts().loc[lambda x: x > 0].plot.pie(autopct=\"%.1f%%\")\n",
    "\n",
    "plt.title(\"Status distribution among directly referencing certificates\")\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b78c8e28",
   "metadata": {},
   "source": [
    "#### Direct references per type\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "cd503dd3",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 43176 characters]",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "refs_direct_eda_df[\"type\"].value_counts().loc[lambda x: x > 0].plot.pie(autopct=\"%.1f%%\")\n",
    "\n",
    "plt.title(\"Certificate type distribution among directly referencing certificates\")\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f2640599",
   "metadata": {},
   "source": [
    "#### Direct references per level"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "571b537b",
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 32812 characters]",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "refs_direct_eda_df[\"level\"].value_counts().loc[lambda x: x > 0].plot.pie(autopct=\"%.1f%%\")\n",
    "\n",
    "plt.title(\"Certificate level distribution among directly referencing certificates\")\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c3954632",
   "metadata": {},
   "source": [
    "#### Direct references per embodiment"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "61a9b016",
   "metadata": {
    "scrolled": false
   },
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 42116 characters]",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "embodiment_counts_df = refs_direct_eda_df[\"embodiment\"].value_counts().loc[lambda x: x > 0].plot.pie(autopct=\"%.1f%%\")\n",
    "\n",
    "plt.title(\"Certificate embodiment distribution among directly referencing certificates\")\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d6eb6ba2",
   "metadata": {},
   "source": [
    "#### Time analysis of mean of references per years"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "id": "60ae26c1",
   "metadata": {
    "scrolled": false
   },
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 44508 characters]",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "referencing_df = df[df[\"outgoing_direct_references_count\"] > 0][\n",
    "    [\"year_from\", \"outgoing_direct_references_count\"]\n",
    "]\n",
    "refs_grouped_by = referencing_df.select_dtypes(include=[\"number\"]).groupby([\"year_from\"]).mean()\n",
    "refs_grouped_by = refs_grouped_by.reset_index()\n",
    "\n",
    "# Fill missing years\n",
    "dataset_years: set[int] = set(refs_grouped_by[\"year_from\"])\n",
    "years_interval: set[int] = set(range(min(dataset_years), max(dataset_years) + 1))\n",
    "missing_years: set[int] = years_interval - dataset_years\n",
    "\n",
    "for year in missing_years:\n",
    "    refs_grouped_by.loc[len(refs_grouped_by.index)] = (year, 0)\n",
    "\n",
    "line = sns.lineplot(data=refs_grouped_by, x=\"year_from\", y=\"outgoing_direct_references_count\")\n",
    "\n",
    "plt.title(\"Time analysis of references mean per year\")\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9a789e26",
   "metadata": {},
   "source": [
    "#### Distribution of total number of references per cert since 2016"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "id": "900a900b",
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 32236 characters]",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "YEAR: int = 2016\n",
    "modern_refs = df[df[\"year_from\"] >= YEAR]\n",
    "sns.histplot(modern_refs[\"outgoing_direct_references_count\"], kde=True)\n",
    "\n",
    "plt.title(f\"Histogram of references count since {YEAR}\")\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "84572319",
   "metadata": {},
   "source": [
    "#### Distribution of embodiments with assigned at least one CVE"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "id": "86f9e1d4",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 23080 characters]",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "cve_df: DataFrame = df[df[\"related_cves\"].notna()]\n",
    "embodiments_counts = cve_df[\"embodiment\"].value_counts()\n",
    "sns.barplot(x=embodiments_counts.index, y=embodiments_counts.values)\n",
    "\n",
    "plt.title(\"Distribution of embodiments of certificates with at least one CVE\")\n",
    "plt.xlabel(\"Embodiment\")\n",
    "plt.ylabel(\"Count\")\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "165041da",
   "metadata": {},
   "source": [
    "#### Distribution of levels with assigned at least one CVE"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "id": "f8dda3e9",
   "metadata": {},
   "outputs": [],
   "source": [
    "def normalize_value_counts(df: DataFrame, series: Series, column: str) -> Series | None:\n",
    "    \"\"\"\n",
    "    Function normalizes the value_counts in subdataset (e.g. cve_df)\n",
    "    compared to the general dataset (e.g. df)\n",
    "    \"\"\"\n",
    "    if column not in df.columns:\n",
    "        return None\n",
    "\n",
    "    data = []\n",
    "    indices = []\n",
    "\n",
    "    for tpl in series.items():\n",
    "        index = tpl[0]\n",
    "        count = tpl[1]\n",
    "        amount_in_category = df[df[column] == index].shape[0]\n",
    "        indices.append(index)\n",
    "        data.append(round(count / amount_in_category, 3))\n",
    "\n",
    "    return Series(index=indices, data=data)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "id": "fb0dad90",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 21376 characters]",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "level_counts = cve_df[\"level\"].value_counts()\n",
    "normalized_level_counts = normalize_value_counts(df, level_counts, \"level\")\n",
    "\n",
    "sns.barplot(x=normalized_level_counts.index, y=normalized_level_counts.values)\n",
    "\n",
    "plt.title(\"Relative counts of certificate levels with at least one assigned CVE\")\n",
    "plt.xlabel(\"Level\")\n",
    "plt.ylabel(\"Count\")\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6fe98617",
   "metadata": {},
   "source": [
    "#### Distribution of types with assigned at least one CVE"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "id": "b1e1fe59",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 32136 characters]",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "type_counts = cve_df[\"type\"].value_counts()\n",
    "normalized_type_counts = normalize_value_counts(df, type_counts, \"type\")\n",
    "\n",
    "sns.barplot(x=normalized_type_counts.index, y=normalized_type_counts.values)\n",
    "\n",
    "plt.title(\"Relative counts of certificate type with at least one assigned CVE\")\n",
    "plt.xlabel(\"Type\")\n",
    "plt.ylabel(\"Count\")\n",
    "plt.xticks(rotation=90)\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0adc5009",
   "metadata": {},
   "source": [
    "#### Distribution of statuses with assigned at least one CVE"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "id": "39e0c5ef",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 23376 characters]",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "status_counts = cve_df[\"status\"].value_counts()\n",
    "normalized_status_counts = normalize_value_counts(df, status_counts, \"status\")\n",
    "\n",
    "sns.barplot(x=normalized_status_counts.index, y=normalized_status_counts.values)\n",
    "\n",
    "plt.title(\"Relative counts of certificate statuses with at least one assigned CVE\")\n",
    "plt.xlabel(\"Status\")\n",
    "plt.ylabel(\"Count\")\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "480bc189",
   "metadata": {},
   "source": [
    "### Statistics how many certificates are referenced and have at least one CVE assigned"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "id": "678835dd",
   "metadata": {
    "scrolled": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Total number of certificates which are referenced by at least one certificate and have assigned at least one assigned CVE: 81\n"
     ]
    }
   ],
   "source": [
    "cve_ref_df: DataFrame = df[(df[\"related_cves\"].notna()) & (df[\"incoming_direct_references_count\"] > 0)]\n",
    "total_references: int = cve_ref_df[\"incoming_direct_references_count\"].sum()\n",
    "\n",
    "print(f\"Total number of certificates which are referenced by at least one certificate and have assigned at least one assigned CVE: {total_references}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2922d261",
   "metadata": {},
   "source": [
    "#### Potential vulnerable certificates "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "id": "14322ef7",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{'4176', '2162', '2446', '1817', '4136', '4146', '1807', '1933', '979', '2721', '2633', '3880', '3563', '1337', '3891', '3469', '1791', '4135', '1386', '1805', '1385', '2212', '3421', '1002', '3168', '2605', '1808', '2742', '3892', '2404', '2798', '4206', '2908', '3286', '3348', '1806', '1053', '3733', '2604', '1792', '4147', '3921', '3699', '4145', '3007', '1500', '4266', '1384', '3893', '2997', '2447', '1859', '3939', '2915', '2343', '2630', '4164', '4148', '3306', '2582', '1001', '3170', '1338', '2736', '3342', '1445', '1449', '1339', '1003'}\n"
     ]
    }
   ],
   "source": [
    "# NOTE: List of certificates IDs which reference at least one certificate with assigned CVE\n",
    "print(set.union(*cve_ref_df[\"module_directly_referenced_by\"]))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "15968ee7",
   "metadata": {},
   "source": [
    "#### The certificate with at least one CVE assigned and maximum of references from other certs"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "id": "3c17e838",
   "metadata": {
    "scrolled": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Maximum amount of references from the other certificates referencing the vulnerable certificate: 7\n"
     ]
    }
   ],
   "source": [
    "maximum_references: int = cve_ref_df[\"incoming_direct_references_count\"].max()\n",
    "print(f\"Maximum amount of references from the other certificates referencing the vulnerable certificate: {maximum_references}\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "id": "6ca75914",
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>cert_id</th>\n",
       "      <th>status</th>\n",
       "      <th>standard</th>\n",
       "      <th>type</th>\n",
       "      <th>level</th>\n",
       "      <th>embodiment</th>\n",
       "      <th>year_from</th>\n",
       "      <th>related_cves</th>\n",
       "      <th>module_directly_referenced_by</th>\n",
       "      <th>module_indirectly_referenced_by</th>\n",
       "      <th>module_directly_referencing</th>\n",
       "      <th>module_indirectly_referencing</th>\n",
       "      <th>policy_directly_referenced_by</th>\n",
       "      <th>policy_indirectly_referenced_by</th>\n",
       "      <th>policy_directly_referencing</th>\n",
       "      <th>policy_indirectly_referencing</th>\n",
       "      <th>outgoing_direct_references_count</th>\n",
       "      <th>incoming_direct_references_count</th>\n",
       "      <th>outgoing_indirect_references_count</th>\n",
       "      <th>incoming_indirect_references_count</th>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>dgst</th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>10acb87b3040f4e1</th>\n",
       "      <td>3616</td>\n",
       "      <td>historical</td>\n",
       "      <td>FIPS 140-2</td>\n",
       "      <td>Software</td>\n",
       "      <td>1.0</td>\n",
       "      <td>Multi-Chip Stand Alone</td>\n",
       "      <td>2020</td>\n",
       "      <td>{CVE-2016-1908, CVE-2016-2801, CVE-2016-5404, ...</td>\n",
       "      <td>{3893, 4164, 4147, 3921, 4146, 4135, 3699}</td>\n",
       "      <td>{3893, 4164, 4147, 3921, 4146, 4135, 3699}</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>{3699, 3893, 3921}</td>\n",
       "      <td>{3699, 3893, 3921}</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>0</td>\n",
       "      <td>7</td>\n",
       "      <td>0</td>\n",
       "      <td>7</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3c4ee858b268931a</th>\n",
       "      <td>1336</td>\n",
       "      <td>historical</td>\n",
       "      <td>FIPS 140-2</td>\n",
       "      <td>Software</td>\n",
       "      <td>1.0</td>\n",
       "      <td>Multi-Chip Stand Alone</td>\n",
       "      <td>2010</td>\n",
       "      <td>{CVE-2008-2250, CVE-2009-1216, CVE-2009-2526, ...</td>\n",
       "      <td>{2736, 1339, 1808, 1807, 1817, 1805, 1806}</td>\n",
       "      <td>{2736, 1339, 1808, 1807, 1817, 1805, 1806}</td>\n",
       "      <td>{1334}</td>\n",
       "      <td>{1333, 1334, 1321}</td>\n",
       "      <td>{1339, 1808, 1807, 1817, 1805, 1806}</td>\n",
       "      <td>{1339, 1808, 1807, 1817, 1805, 1806}</td>\n",
       "      <td>{1334}</td>\n",
       "      <td>{1333, 1334, 1321}</td>\n",
       "      <td>1</td>\n",
       "      <td>7</td>\n",
       "      <td>3</td>\n",
       "      <td>7</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "                  cert_id      status    standard      type  level  \\\n",
       "dgst                                                                 \n",
       "10acb87b3040f4e1     3616  historical  FIPS 140-2  Software    1.0   \n",
       "3c4ee858b268931a     1336  historical  FIPS 140-2  Software    1.0   \n",
       "\n",
       "                              embodiment  year_from  \\\n",
       "dgst                                                  \n",
       "10acb87b3040f4e1  Multi-Chip Stand Alone       2020   \n",
       "3c4ee858b268931a  Multi-Chip Stand Alone       2010   \n",
       "\n",
       "                                                       related_cves  \\\n",
       "dgst                                                                  \n",
       "10acb87b3040f4e1  {CVE-2016-1908, CVE-2016-2801, CVE-2016-5404, ...   \n",
       "3c4ee858b268931a  {CVE-2008-2250, CVE-2009-1216, CVE-2009-2526, ...   \n",
       "\n",
       "                               module_directly_referenced_by  \\\n",
       "dgst                                                           \n",
       "10acb87b3040f4e1  {3893, 4164, 4147, 3921, 4146, 4135, 3699}   \n",
       "3c4ee858b268931a  {2736, 1339, 1808, 1807, 1817, 1805, 1806}   \n",
       "\n",
       "                             module_indirectly_referenced_by  \\\n",
       "dgst                                                           \n",
       "10acb87b3040f4e1  {3893, 4164, 4147, 3921, 4146, 4135, 3699}   \n",
       "3c4ee858b268931a  {2736, 1339, 1808, 1807, 1817, 1805, 1806}   \n",
       "\n",
       "                 module_directly_referencing module_indirectly_referencing  \\\n",
       "dgst                                                                         \n",
       "10acb87b3040f4e1                         NaN                           NaN   \n",
       "3c4ee858b268931a                      {1334}            {1333, 1334, 1321}   \n",
       "\n",
       "                         policy_directly_referenced_by  \\\n",
       "dgst                                                     \n",
       "10acb87b3040f4e1                    {3699, 3893, 3921}   \n",
       "3c4ee858b268931a  {1339, 1808, 1807, 1817, 1805, 1806}   \n",
       "\n",
       "                       policy_indirectly_referenced_by  \\\n",
       "dgst                                                     \n",
       "10acb87b3040f4e1                    {3699, 3893, 3921}   \n",
       "3c4ee858b268931a  {1339, 1808, 1807, 1817, 1805, 1806}   \n",
       "\n",
       "                 policy_directly_referencing policy_indirectly_referencing  \\\n",
       "dgst                                                                         \n",
       "10acb87b3040f4e1                         NaN                           NaN   \n",
       "3c4ee858b268931a                      {1334}            {1333, 1334, 1321}   \n",
       "\n",
       "                  outgoing_direct_references_count  \\\n",
       "dgst                                                 \n",
       "10acb87b3040f4e1                                 0   \n",
       "3c4ee858b268931a                                 1   \n",
       "\n",
       "                  incoming_direct_references_count  \\\n",
       "dgst                                                 \n",
       "10acb87b3040f4e1                                 7   \n",
       "3c4ee858b268931a                                 7   \n",
       "\n",
       "                  outgoing_indirect_references_count  \\\n",
       "dgst                                                   \n",
       "10acb87b3040f4e1                                   0   \n",
       "3c4ee858b268931a                                   3   \n",
       "\n",
       "                  incoming_indirect_references_count  \n",
       "dgst                                                  \n",
       "10acb87b3040f4e1                                   7  \n",
       "3c4ee858b268931a                                   7  "
      ]
     },
     "execution_count": 24,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "cve_ref_df[cve_ref_df[\"incoming_direct_references_count\"] == maximum_references]"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "38e5b33d",
   "metadata": {},
   "source": [
    "### Active certificates which reference at least one historical cert"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "id": "2d3619d6",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Total active certificates referencing at least one historical: 13\n",
      "Total active certificates referencing at least one certificate: 131\n"
     ]
    }
   ],
   "source": [
    "active_certs_referencing_historical: list[int] = []\n",
    "# NOTE: \"cert_id\" field is represented as integer, however \"module_directly_referencing\" is set of strings\n",
    "historical_cert_ids: set[str] = set(df[df[\"status\"] == \"historical\"][\"cert_id\"].apply(str))\n",
    "active_referencing_certs: DataFrame = df[(df[\"status\"] == \"active\") & (df[\"outgoing_direct_references_count\"] > 0)]\n",
    "\n",
    "for _, rows in active_referencing_certs.iterrows():\n",
    "    referencing_ids = rows[\"module_directly_referencing\"]\n",
    "    intersection = referencing_ids & historical_cert_ids\n",
    "\n",
    "    if intersection:\n",
    "        active_certs_referencing_historical.append(rows.cert_id)\n",
    "\n",
    "print(f\"Total active certificates referencing at least one historical: {len(active_certs_referencing_historical)}\")\n",
    "print(f\"Total active certificates referencing at least one certificate: {len(active_referencing_certs)}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "39dcecd1",
   "metadata": {},
   "source": [
    "#### Active certificate referencing at least one historical certificate with assigned CVE"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "id": "f3402d08",
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Active certificate 3939 is referencing historical certificate 3860 with assigned CVE\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "[(3939, 3860)]"
      ]
     },
     "execution_count": 26,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "active_cert_referencing_historical_with_cves: list[tuple[int, int]] = []\n",
    "\n",
    "for _, cert in df[df[\"cert_id\"].isin(active_certs_referencing_historical)].iterrows():\n",
    "    cert_id = cert[\"cert_id\"]\n",
    "\n",
    "    for referenced_cert_id in cert[\"module_directly_referencing\"]:\n",
    "        referenced_cert_id_int = int(referenced_cert_id)\n",
    "        related_cves = get_cert_property(df, referenced_cert_id_int, \"related_cves\")\n",
    "\n",
    "        if not pd.isna(related_cves):\n",
    "            print(f\"Active certificate {cert_id} is referencing historical certificate {referenced_cert_id} with assigned CVE\")\n",
    "            active_cert_referencing_historical_with_cves.append((cert_id, referenced_cert_id_int))\n",
    "\n",
    "active_cert_referencing_historical_with_cves"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d343e55b",
   "metadata": {},
   "source": [
    "### Certificates with higher levels referencing certificates with lower levels"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "id": "b8225902",
   "metadata": {
    "scrolled": false
   },
   "outputs": [],
   "source": [
    "referencing_certs: DataFrame = df[df[\"outgoing_direct_references_count\"] > 0]\n",
    "cert_level_ids: dict[int, set[str]] = {}\n",
    "unique_levels: list[int] = df[\"level\"].apply(int).unique()\n",
    "\n",
    "for level in df[\"level\"].unique():\n",
    "    level_cert_ids: set[str] = set(df[df[\"level\"] == level][\"cert_id\"].apply(str))\n",
    "    cert_level_ids[int(level)] = level_cert_ids"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "id": "dfca806f",
   "metadata": {},
   "outputs": [],
   "source": [
    "def get_cert_ids_referencing_lower_level_cert(level_referencing_certs_df: DataFrame, lower_cert_ids: set[str]) -> list[int]:\n",
    "    cert_ids = []\n",
    "\n",
    "    for _, cert in level_referencing_certs_df.iterrows():\n",
    "        if cert[\"module_directly_referencing\"] & lower_cert_ids:\n",
    "            cert_ids.append(cert[\"cert_id\"])\n",
    "\n",
    "    return cert_ids"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0f04580e",
   "metadata": {},
   "source": [
    "#### Level 2 referencing at least one certificate of level 1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "id": "681996d3",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Total amount of certificates with level 2 referencing at least one certificate: 41\n",
      "Total amount of certicates with reference at least one certificate with lower level: 16\n"
     ]
    }
   ],
   "source": [
    "LEVEL2: int = 2\n",
    "below_level2_cert_ids: set[str] = cert_level_ids[1]\n",
    "level2_ref_certs = referencing_certs[referencing_certs[\"level\"] == LEVEL2]\n",
    "level2_referencing_lower_level = get_cert_ids_referencing_lower_level_cert(level2_ref_certs, below_level2_cert_ids)\n",
    "\n",
    "print(f\"Total amount of certificates with level {LEVEL2} referencing at least one certificate: {level2_ref_certs.shape[0]}\")\n",
    "print(f\"Total amount of certicates with reference at least one certificate with lower level: {len(level2_referencing_lower_level)}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "27d269a3",
   "metadata": {},
   "source": [
    "#### Level 3 referencing at least one certificate of level 1 or 2"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "id": "88351957",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Total amount of certificates with level 3 referencing at least one certificate: 27\n",
      "Total amount of certicates with reference at least one certificate with lower level: 1\n"
     ]
    }
   ],
   "source": [
    "LEVEL3: int = 3\n",
    "below_level3_cert_ids = below_level2_cert_ids | cert_level_ids[2]\n",
    "level3_ref_certs = referencing_certs[referencing_certs[\"level\"] == LEVEL3]\n",
    "level3_referencing_lower_level = get_cert_ids_referencing_lower_level_cert(level3_ref_certs, below_level3_cert_ids)\n",
    "\n",
    "print(f\"Total amount of certificates with level {LEVEL3} referencing at least one certificate: {level3_ref_certs.shape[0]}\")\n",
    "print(f\"Total amount of certicates with reference at least one certificate with lower level: {len(level3_referencing_lower_level)}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "679fa9c7",
   "metadata": {},
   "source": [
    "#### Level 4 referencing at least one certificate of level 1, 2 or 3"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "id": "91db647f",
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Total amount of certificates with level 4 referencing at least one certificate: 0\n"
     ]
    }
   ],
   "source": [
    "LEVEL4: int = 4\n",
    "below_level4_cert_ids = below_level3_cert_ids | cert_level_ids[3]\n",
    "level4_ref_certs = referencing_certs[referencing_certs[\"level\"] == LEVEL4]\n",
    "level4_referencing_lower_level = get_cert_ids_referencing_lower_level_cert(level4_ref_certs, below_level4_cert_ids)\n",
    "print(f\"Total amount of certificates with level {LEVEL4} referencing at least one certificate: {level4_ref_certs.shape[0]}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5c2fca19",
   "metadata": {},
   "source": [
    "### Distribution of references among embodiments"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "id": "34b5c83b",
   "metadata": {},
   "outputs": [],
   "source": [
    "def get_embodiment_references(df: DataFrame, embodiment: str) -> dict[str, int]:\n",
    "    result: dict[str, int] = {}\n",
    "    sub_df = df[(df[\"embodiment\"] == embodiment) & (df[\"outgoing_direct_references_count\"] > 0)]\n",
    "\n",
    "    for references in sub_df[\"module_directly_referencing\"]:\n",
    "        for cert_id in references:\n",
    "            referenced_embodiment: str = get_cert_property(df, cert_id, \"embodiment\")\n",
    "            result[referenced_embodiment] = result.get(referenced_embodiment, 0) + 1\n",
    "\n",
    "    return result"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "id": "6e69410d",
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{'Multi-Chip Embedded': {'Multi-Chip Embedded': 13, 'Single Chip': 2},\n",
      " 'Multi-Chip Stand Alone': {'Multi-Chip Embedded': 7,\n",
      "                            'Multi-Chip Stand Alone': 548,\n",
      "                            'Single Chip': 30},\n",
      " 'Single Chip': {'Multi-Chip Embedded': 2,\n",
      "                 'Multi-Chip Stand Alone': 1,\n",
      "                 'Single Chip': 28}}\n"
     ]
    }
   ],
   "source": [
    "final_embodiment_statistics: dict[str, dict[str, int]] = {}\n",
    "\n",
    "for embodiment in df[\"embodiment\"].unique():\n",
    "    final_embodiment_statistics[embodiment] = get_embodiment_references(df, embodiment)\n",
    "\n",
    "pprint(final_embodiment_statistics)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "id": "0737ca41",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 41596 characters]",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "embodiment_df = pd.DataFrame(final_embodiment_statistics).fillna(0).astype(int).transpose()\n",
    "embodiment_df.plot(kind=\"bar\", stacked=True)\n",
    "\n",
    "plt.xlabel(\"Referencing cert embodiment\")\n",
    "plt.ylabel(\"Number of referenced certificates\")\n",
    "plt.title(\"Direct references among FIPS embodiments\")\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d1743560",
   "metadata": {},
   "source": [
    "### Distribution of references among types"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "id": "72fb288b",
   "metadata": {},
   "outputs": [],
   "source": [
    "def get_type_references(df: DataFrame, cert_type: str) -> dict[str, int]:\n",
    "    result = {}\n",
    "    sub_df = df[(df[\"type\"] == cert_type) & (df[\"outgoing_direct_references_count\"] > 0)]\n",
    "\n",
    "    for references in sub_df[\"module_directly_referencing\"]:\n",
    "        for cert_id in references:\n",
    "            referenced_type: str = get_cert_property(df, cert_id, \"type\")\n",
    "            result[referenced_type] =result.get(referenced_type, 0) + 1\n",
    "\n",
    "    return result"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "id": "79c3b7c8",
   "metadata": {
    "scrolled": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{'Firmware': {'Firmware': 1, 'Hardware': 1},\n",
      " 'Firmware-Hybrid': {'Hardware': 2},\n",
      " 'Hardware': {'Firmware': 2,\n",
      "              'Firmware-Hybrid': 2,\n",
      "              'Hardware': 78,\n",
      "              'Software': 9},\n",
      " 'Hybrid': {},\n",
      " 'Software': {'Firmware': 1,\n",
      "              'Hardware': 1,\n",
      "              'Software': 504,\n",
      "              'Software-Hybrid': 3},\n",
      " 'Software hybrid': {},\n",
      " 'Software-Hybrid': {'Hardware': 5, 'Software': 6, 'Software-Hybrid': 16}}\n"
     ]
    }
   ],
   "source": [
    "final_type_statistics: dict[str, dict[str, int]] = {}\n",
    "\n",
    "for cert_type in df[\"type\"].unique():\n",
    "    final_type_statistics[cert_type] = get_type_references(df, cert_type)\n",
    "\n",
    "pprint(final_type_statistics)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "id": "6694e4cd",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 47152 characters]",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "cert_type_df = pd.DataFrame(final_type_statistics).fillna(0).astype(int).transpose()\n",
    "cert_type_df.plot(kind=\"bar\", stacked=True)\n",
    "\n",
    "plt.xlabel(\"Referencing cert type\")\n",
    "plt.ylabel(\"Number of referenced certificates\")\n",
    "plt.title(\"Direct references among FIPS certificate types\")\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c0bd6844",
   "metadata": {},
   "source": [
    "### Temporal evolution of referencing certificates amount displayed in percentages per year"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 38,
   "id": "366103d5",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 37840 characters]",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "def convert_refences_count_to_relative(number: int, n_issued_certs: int) -> float:\n",
    "    return 100 * number / n_issued_certs\n",
    "\n",
    "THRESHOLD_YEAR: int = 2023\n",
    "\n",
    "temporal_df: DataFrame = df[(df[\"outgoing_direct_references_count\"] > 0) & (df[\"year_from\"] < THRESHOLD_YEAR)]\n",
    "total_referencing_certs: int = temporal_df.shape[0]\n",
    "grouped_df: DataFrame = temporal_df.groupby(\"year_from\")\n",
    "converted_df: DataFrame = grouped_df.size().reset_index(name=\"year_references\")\n",
    "\n",
    "# Fill missing years\n",
    "dataset_years: set[int] = set(converted_df[\"year_from\"])\n",
    "years_interval: set[int] = set(range(min(dataset_years), max(dataset_years) + 1))\n",
    "missing_years: set[int] = years_interval - dataset_years\n",
    "\n",
    "for year in missing_years:\n",
    "    converted_df.loc[len(converted_df.index)] = (year, 0)\n",
    "\n",
    "converted_df[\"percentage\"] = converted_df[\"year_references\"].apply(convert_refences_count_to_relative, args=(total_referencing_certs,))\n",
    "line = sns.lineplot(data=converted_df, x=\"year_from\", y=\"percentage\")\n",
    "\n",
    "plt.title(\"Temporal evolution of referencing certificate in time (percentages)\")\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "258c803c",
   "metadata": {},
   "source": [
    "### Cross-references among certificates\n",
    "\n",
    "Certificate A directly references certificate B and at the same time certificate B directly references certificate A.\n",
    "In other words intersection of `module_directly_referenced_by` and `module_directly_referencing` results into discovery of cross references in the dataset."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 39,
   "id": "77a1db87",
   "metadata": {
    "scrolled": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[(3384, 3382), (3382, 3383), (63, 80)]\n"
     ]
    }
   ],
   "source": [
    "result: list[tuple[int, int]] = []\n",
    "cross_references_df: DataFrame = df[(df[\"incoming_direct_references_count\"] > 0) & (df[\"outgoing_direct_references_count\"] > 0)]\n",
    "\n",
    "\n",
    "for _, cert in cross_references_df.iterrows():\n",
    "    referenced_by = cert[\"module_directly_referenced_by\"]\n",
    "    referencing = cert[\"module_directly_referencing\"]\n",
    "    cert_id = cert[\"cert_id\"]\n",
    "\n",
    "    intersection: set[str] = referenced_by & referencing\n",
    "\n",
    "\n",
    "    for another_cert_id in intersection:\n",
    "        another_cert_id_int = int(another_cert_id)\n",
    "\n",
    "        if not (another_cert_id_int, cert_id) in result:\n",
    "            result.append((cert_id, int(another_cert_id)))\n",
    "\n",
    "print(result)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 40,
   "id": "bb8fed46",
   "metadata": {
    "scrolled": false
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>cert_id</th>\n",
       "      <th>status</th>\n",
       "      <th>standard</th>\n",
       "      <th>type</th>\n",
       "      <th>level</th>\n",
       "      <th>embodiment</th>\n",
       "      <th>year_from</th>\n",
       "      <th>related_cves</th>\n",
       "      <th>module_directly_referenced_by</th>\n",
       "      <th>module_indirectly_referenced_by</th>\n",
       "      <th>module_directly_referencing</th>\n",
       "      <th>module_indirectly_referencing</th>\n",
       "      <th>policy_directly_referenced_by</th>\n",
       "      <th>policy_indirectly_referenced_by</th>\n",
       "      <th>policy_directly_referencing</th>\n",
       "      <th>policy_indirectly_referencing</th>\n",
       "      <th>outgoing_direct_references_count</th>\n",
       "      <th>incoming_direct_references_count</th>\n",
       "      <th>outgoing_indirect_references_count</th>\n",
       "      <th>incoming_indirect_references_count</th>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>dgst</th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>6ef02a389c6415e7</th>\n",
       "      <td>3384</td>\n",
       "      <td>active</td>\n",
       "      <td>FIPS 140-2</td>\n",
       "      <td>Hardware</td>\n",
       "      <td>1.0</td>\n",
       "      <td>Multi-Chip Embedded</td>\n",
       "      <td>2019</td>\n",
       "      <td>NaN</td>\n",
       "      <td>{3382}</td>\n",
       "      <td>{3382, 3384, 3383}</td>\n",
       "      <td>{3382}</td>\n",
       "      <td>{3382, 3384, 3383}</td>\n",
       "      <td>{3382}</td>\n",
       "      <td>{3382, 3384, 3383}</td>\n",
       "      <td>{3382}</td>\n",
       "      <td>{3382, 3384, 3383}</td>\n",
       "      <td>1</td>\n",
       "      <td>1</td>\n",
       "      <td>3</td>\n",
       "      <td>3</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>a080dde530fce451</th>\n",
       "      <td>3382</td>\n",
       "      <td>active</td>\n",
       "      <td>FIPS 140-2</td>\n",
       "      <td>Hardware</td>\n",
       "      <td>1.0</td>\n",
       "      <td>Single Chip</td>\n",
       "      <td>2019</td>\n",
       "      <td>NaN</td>\n",
       "      <td>{3384, 3383}</td>\n",
       "      <td>{3382, 3384, 3383}</td>\n",
       "      <td>{3384, 3383}</td>\n",
       "      <td>{3382, 3384, 3383}</td>\n",
       "      <td>{3384, 3383}</td>\n",
       "      <td>{3382, 3384, 3383}</td>\n",
       "      <td>{3384, 3383}</td>\n",
       "      <td>{3382, 3384, 3383}</td>\n",
       "      <td>2</td>\n",
       "      <td>2</td>\n",
       "      <td>3</td>\n",
       "      <td>3</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>efb092e03612f568</th>\n",
       "      <td>3383</td>\n",
       "      <td>active</td>\n",
       "      <td>FIPS 140-2</td>\n",
       "      <td>Hardware</td>\n",
       "      <td>1.0</td>\n",
       "      <td>Multi-Chip Embedded</td>\n",
       "      <td>2019</td>\n",
       "      <td>NaN</td>\n",
       "      <td>{3382}</td>\n",
       "      <td>{3382, 3384, 3383}</td>\n",
       "      <td>{3382}</td>\n",
       "      <td>{3382, 3384, 3383}</td>\n",
       "      <td>{3382}</td>\n",
       "      <td>{3382, 3384, 3383}</td>\n",
       "      <td>{3382}</td>\n",
       "      <td>{3382, 3384, 3383}</td>\n",
       "      <td>1</td>\n",
       "      <td>1</td>\n",
       "      <td>3</td>\n",
       "      <td>3</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "                  cert_id  status    standard      type  level  \\\n",
       "dgst                                                             \n",
       "6ef02a389c6415e7     3384  active  FIPS 140-2  Hardware    1.0   \n",
       "a080dde530fce451     3382  active  FIPS 140-2  Hardware    1.0   \n",
       "efb092e03612f568     3383  active  FIPS 140-2  Hardware    1.0   \n",
       "\n",
       "                           embodiment  year_from related_cves  \\\n",
       "dgst                                                            \n",
       "6ef02a389c6415e7  Multi-Chip Embedded       2019          NaN   \n",
       "a080dde530fce451          Single Chip       2019          NaN   \n",
       "efb092e03612f568  Multi-Chip Embedded       2019          NaN   \n",
       "\n",
       "                 module_directly_referenced_by  \\\n",
       "dgst                                             \n",
       "6ef02a389c6415e7                        {3382}   \n",
       "a080dde530fce451                  {3384, 3383}   \n",
       "efb092e03612f568                        {3382}   \n",
       "\n",
       "                 module_indirectly_referenced_by module_directly_referencing  \\\n",
       "dgst                                                                           \n",
       "6ef02a389c6415e7              {3382, 3384, 3383}                      {3382}   \n",
       "a080dde530fce451              {3382, 3384, 3383}                {3384, 3383}   \n",
       "efb092e03612f568              {3382, 3384, 3383}                      {3382}   \n",
       "\n",
       "                 module_indirectly_referencing policy_directly_referenced_by  \\\n",
       "dgst                                                                           \n",
       "6ef02a389c6415e7            {3382, 3384, 3383}                        {3382}   \n",
       "a080dde530fce451            {3382, 3384, 3383}                  {3384, 3383}   \n",
       "efb092e03612f568            {3382, 3384, 3383}                        {3382}   \n",
       "\n",
       "                 policy_indirectly_referenced_by policy_directly_referencing  \\\n",
       "dgst                                                                           \n",
       "6ef02a389c6415e7              {3382, 3384, 3383}                      {3382}   \n",
       "a080dde530fce451              {3382, 3384, 3383}                {3384, 3383}   \n",
       "efb092e03612f568              {3382, 3384, 3383}                      {3382}   \n",
       "\n",
       "                 policy_indirectly_referencing  \\\n",
       "dgst                                             \n",
       "6ef02a389c6415e7            {3382, 3384, 3383}   \n",
       "a080dde530fce451            {3382, 3384, 3383}   \n",
       "efb092e03612f568            {3382, 3384, 3383}   \n",
       "\n",
       "                  outgoing_direct_references_count  \\\n",
       "dgst                                                 \n",
       "6ef02a389c6415e7                                 1   \n",
       "a080dde530fce451                                 2   \n",
       "efb092e03612f568                                 1   \n",
       "\n",
       "                  incoming_direct_references_count  \\\n",
       "dgst                                                 \n",
       "6ef02a389c6415e7                                 1   \n",
       "a080dde530fce451                                 2   \n",
       "efb092e03612f568                                 1   \n",
       "\n",
       "                  outgoing_indirect_references_count  \\\n",
       "dgst                                                   \n",
       "6ef02a389c6415e7                                   3   \n",
       "a080dde530fce451                                   3   \n",
       "efb092e03612f568                                   3   \n",
       "\n",
       "                  incoming_indirect_references_count  \n",
       "dgst                                                  \n",
       "6ef02a389c6415e7                                   3  \n",
       "a080dde530fce451                                   3  \n",
       "efb092e03612f568                                   3  "
      ]
     },
     "execution_count": 40,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "df[df[\"cert_id\"].isin([3382, 3383, 3384])]"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0bdcce5c",
   "metadata": {},
   "source": [
    "### Referenced certs, which are not referencing any other cert"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 41,
   "id": "8545977e",
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "In the dataset is total of 151 certificates which are referenced by at least one cert and not referencing any other certs.\n"
     ]
    }
   ],
   "source": [
    "not_referencing_df: DataFrame = df[(df[\"outgoing_direct_references_count\"] == 0) & (df[\"incoming_direct_references_count\"] > 0)]\n",
    "print(f\"In the dataset is total of {not_referencing_df.shape[0]} certificates which are referenced by at least one cert and not referencing any other certs.\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "79ad426b",
   "metadata": {},
   "source": [
    "#### Status of the certificates"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 42,
   "id": "a3026921",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 29488 characters]",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "not_referencing_df[\"status\"].value_counts().loc[lambda x: x > 0].plot.pie(autopct=\"%.0f%%\")\n",
    "\n",
    "plt.title(\"Distribution of statuses across referenced, not referencing certs\")\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "00fbae83",
   "metadata": {},
   "source": [
    "#### Histogram of most common CVEs of certificates which are not referencing any other certificate and are referenced by at least one "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 43,
   "id": "d1e45d14",
   "metadata": {
    "scrolled": false
   },
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 27088 characters]",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "number_of_cves: int = 10\n",
    "counter: Counter = Counter()\n",
    "\n",
    "for cve_set in not_referencing_df[\"related_cves\"]:\n",
    "    if pd.isna(cve_set):\n",
    "        continue\n",
    "    counter.update(cve_set)\n",
    "\n",
    "not_referencing_cve_df: DataFrame = pd.DataFrame.from_dict(counter, orient=\"index\").reset_index()\n",
    "not_referencing_cve_df.columns = (\"CVE\", \"count\")\n",
    "not_referencing_cve_df.sort_values(by=\"count\", ascending=False, inplace=True)\n",
    "sns.barplot(x=\"CVE\", y=\"count\", data=not_referencing_cve_df.head(number_of_cves))\n",
    "\n",
    "plt.title(f\"The most common {number_of_cves} CVEs of referenced, not referencing certs\")\n",
    "plt.xticks(rotation=90)\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7c8f743d",
   "metadata": {},
   "source": [
    "### Certificates which are referenced, but not referencing any other certificate"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 44,
   "id": "6930a9d7",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "There are total of 380 certs, which are referencing at least one other cert and referenced by no other cert\n"
     ]
    }
   ],
   "source": [
    "not_referenced_df: DataFrame = df[(df[\"outgoing_direct_references_count\"] > 0) & (df[\"incoming_direct_references_count\"] == 0)]\n",
    "print(f\"There are total of {not_referenced_df.shape[0]} certs, which are referencing at least one other cert and referenced by no other cert\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 45,
   "id": "4ebdcbd2",
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 28836 characters]",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "not_referenced_df[\"status\"].value_counts().loc[lambda x: x > 0].plot.pie(autopct=\"%.0f%%\")\n",
    "\n",
    "plt.title(\"Cert status distribution of referencing, no referenced by certs\")\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "670d6b80",
   "metadata": {},
   "source": [
    "#### Histogram of most common CVEs of certificates which are referencing at least one other certicate and are not referenced by any other one"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 46,
   "id": "c79ba9f2",
   "metadata": {
    "scrolled": false
   },
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 29508 characters]",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "number_of_cves: int = 10\n",
    "counter: Counter = Counter()\n",
    "cve_rich_certs_df: DataFrame = not_referenced_df[not_referenced_df[\"related_cves\"].notna()]\n",
    "\n",
    "for cve_set in cve_rich_certs_df[\"related_cves\"]:\n",
    "    counter.update(cve_set)\n",
    "\n",
    "not_referenced_by_df: DataFrame = pd.DataFrame.from_dict(counter, orient=\"index\").reset_index()\n",
    "not_referenced_by_df.columns = (\"CVE\", \"count\")\n",
    "not_referenced_by_df.sort_values(by=\"count\", ascending=False, inplace=True)\n",
    "\n",
    "sns.barplot(x=\"CVE\", y=\"count\", data=not_referenced_by_df.head(number_of_cves))\n",
    "\n",
    "plt.title(f\"The most common {number_of_cves} CVEs of referencing, not referenced certs\")\n",
    "plt.xticks(rotation=90)\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2811febc",
   "metadata": {},
   "source": [
    "### Certificate overview"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 47,
   "id": "07cc51e6",
   "metadata": {},
   "outputs": [],
   "source": [
    "COLOUR_MAPPING = {\n",
    "    \"chosen_cert_colour\": \"lightgreen\",\n",
    "    \"referencing_colour\": \"lightblue\",\n",
    "    \"referenced_colour\": \"red\",\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 48,
   "id": "a6f97708",
   "metadata": {
    "scrolled": false
   },
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 44072 characters]",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "cert_id: int = 4512 # Enter the certificate ID you are interested in\n",
    "\n",
    "graph, node_colors = get_fips_cert_references_graph(df, cert_id, COLOUR_MAPPING)\n",
    "pos = nx.circular_layout(graph)\n",
    "nx.draw(graph, pos, arrows=True, node_color=node_colors, with_labels=True, node_size=900)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 49,
   "id": "986e0f57",
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Certificate ID: 4512:\n",
      " - references the certificates dgst\n",
      "033581b0970477af    {4339, 4348, 4457}\n",
      "Name: module_directly_referencing, dtype: object\n",
      " - is referenced by certificates dgst\n",
      "033581b0970477af    {4536, 4537, 4538}\n",
      "Name: module_directly_referenced_by, dtype: object\n",
      " - its page is at https://seccerts.org/fips/033581b0970477af/\n"
     ]
    }
   ],
   "source": [
    "cert_id_series = df[df[\"cert_id\"] == cert_id]\n",
    "cert_dgst = cert_id_series.index[0]\n",
    "\n",
    "print(f\"Certificate ID: {cert_id}:\")\n",
    "print(f\" - references the certificates {cert_id_series['module_directly_referencing']}\")\n",
    "print(f\" - is referenced by certificates {cert_id_series['module_directly_referenced_by']}\")\n",
    "print(f\" - its page is at https://seccerts.org/fips/{cert_dgst}/\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d609cea7",
   "metadata": {},
   "source": [
    "### Graph of the most referenced certificate"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 50,
   "id": "23433698",
   "metadata": {},
   "outputs": [],
   "source": [
    "STATUS_TO_COLOUR_MAPPING: dict[str, str] = {\n",
    "    \"active\": \"lightblue\",\n",
    "    \"historical\": \"red\",\n",
    "    \"revoked\": \"blue\",\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 51,
   "id": "fd18154a",
   "metadata": {
    "scrolled": false
   },
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 299496 characters]",
      "text/plain": [
       "<Figure size 1500x1500 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "graph, node_colors = get_most_referenced_cert_graph(df, STATUS_TO_COLOUR_MAPPING)\n",
    "fig, ax = plt.subplots(figsize=(15, 15))\n",
    "pos = nx.circular_layout(graph)\n",
    "nx.draw(graph, pos, node_color=node_colors, arrows=True, with_labels=True, node_size=1000)\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ab332b30",
   "metadata": {},
   "source": [
    "### Graph of the most referencing certitificate"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 52,
   "id": "56d5a694",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 74980 characters]",
      "text/plain": [
       "<Figure size 1000x1000 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "graph, node_colors = get_most_referencing_cert_graph(df, STATUS_TO_COLOUR_MAPPING)\n",
    "fig, ax = plt.subplots(figsize=(10, 10))\n",
    "pos = nx.circular_layout(graph)\n",
    "nx.draw(graph, pos, node_color=node_colors, arrows=True, with_labels=True, node_size=1000)\n",
    "plt.show()"
   ]
  }
 ],
 "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.10.12"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
