diff options
| author | J08nY | 2025-04-16 11:51:22 +0200 |
|---|---|---|
| committer | J08nY | 2025-04-16 11:51:22 +0200 |
| commit | ba6e1218096bb47d8816d809293416c24196ce58 (patch) | |
| tree | 51ee6a1af130818d1e48da403441a6b016e14b18 /analysis/plot_dsa.ipynb | |
| parent | 8fa738d40fe7b905d12b90dbe9229a3a7d02a9a1 (diff) | |
| download | ECTester-ba6e1218096bb47d8816d809293416c24196ce58.tar.gz ECTester-ba6e1218096bb47d8816d809293416c24196ce58.tar.zst ECTester-ba6e1218096bb47d8816d809293416c24196ce58.zip | |
Diffstat (limited to 'analysis/plot_dsa.ipynb')
| -rw-r--r-- | analysis/plot_dsa.ipynb | 743 |
1 files changed, 743 insertions, 0 deletions
diff --git a/analysis/plot_dsa.ipynb b/analysis/plot_dsa.ipynb new file mode 100644 index 0000000..abd6531 --- /dev/null +++ b/analysis/plot_dsa.ipynb @@ -0,0 +1,743 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Analysis of signature data" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "ExecuteTime": { + "end_time": "2019-03-22T09:04:46.257111Z", + "start_time": "2019-03-22T09:04:43.955081Z" + } + }, + "outputs": [], + "source": [ + "%matplotlib notebook\n", + "import numpy as np\n", + "from scipy.stats import describe\n", + "from scipy.stats import norm as norm_dist\n", + "from scipy.stats.mstats import mquantiles\n", + "from math import log, sqrt\n", + "import matplotlib.pyplot as plt\n", + "from matplotlib import ticker, colors, gridspec\n", + "from copy import deepcopy\n", + "from utils import plot_hist, moving_average, hw, time_scale, hist_size_func, recompute_nonces\n", + "from binascii import unhexlify\n", + "from IPython.display import display, HTML\n", + "from ipywidgets import interact, interactive, fixed, interact_manual\n", + "import ipywidgets as widgets\n", + "import tabulate" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Settings\n", + "Enter your input below." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "ExecuteTime": { + "end_time": "2019-03-22T09:05:02.399284Z", + "start_time": "2019-03-22T09:05:02.391509Z" + } + }, + "outputs": [], + "source": [ + "# File name with output from ECTesterReader or ECTesterStandalone signatures.\n", + "fname = \"filename.csv\"\n", + "\n", + "# A hash algorithm used\n", + "hash_algo = \"SHA1\" # e.g. \"SHA1\" or None for no hash, raw data signatures\n", + "\n", + "# A curve name or a path to curve file, used to recompute the random nonces used in signing, if they are not present\n", + "# in the file. (ECTester was not able to recompute them for some reason)\n", + "curve = None # e.g. \"secg/secp256r1\" or \"secp256r1.csv\" or None for no curve.\n", + "\n", + "# The time unit used in displaying the plots. One of \"milli\", \"micro\", \"nano\".\n", + "# WARNING: Using nano might lead to very large plots/histograms and to the\n", + "# notebook to freeze or run out of memory, as well as bad visualization\n", + "# quality, due to noise and low density.\n", + "sign_unit = \"milli\"\n", + "verify_unit = \"milli\"\n", + "# A number which will be used to divide the time into sub-units, e.g. for 5, time will be in fifths of units\n", + "scaling_factor = 1\n", + "\n", + "# The amount of entries skipped from the beginning of the file, as they are usually outliers.\n", + "skip_first = 10\n", + "\n", + "# Whether to plot things in logarithmic scale or not.\n", + "log_scale = False\n", + "\n", + "# Whether to trim the time data outside the 1 - 99 percentile range (adjust below). Quite useful.\n", + "trim = True\n", + "\n", + "# How much to trim? Either a number in [0,1] signifying a quantile, or an absolute value signifying a threshold\n", + "trim_low = 0.01\n", + "trim_high = 0.99\n", + "\n", + "# Graphical (matplotlib) style name\n", + "style = \"ggplot\"\n", + "\n", + "# Color map to use, and what color to assign to \"bad\" values (necessary for log_scale)\n", + "color_map = plt.cm.viridis\n", + "color_map_bad = \"black\"\n", + "\n", + "# What function to use to calculate number of histogram bins of time\n", + "# one of \"sqrt\", \"sturges\", \"rice\", \"scott\" and \"fd\" or a number specifying the number of bins\n", + "hist_size = \"sturges\"" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Data processing" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "ExecuteTime": { + "end_time": "2019-03-22T09:05:04.270940Z", + "start_time": "2019-03-22T09:05:03.059822Z" + } + }, + "outputs": [], + "source": [ + "# Setup plot style\n", + "\n", + "plt.style.use(style)\n", + "\n", + "cmap = deepcopy(color_map)\n", + "cmap.set_bad(color_map_bad)\n", + "\n", + "# Normalization, linear or log.\n", + "if log_scale:\n", + " norm = colors.LogNorm()\n", + "else:\n", + " norm = colors.Normalize()\n", + "\n", + "# Read the header line.\n", + "\n", + "with open(fname, \"r\") as f:\n", + " header = f.readline()\n", + "header_names = header.split(\";\")\n", + "if len(header_names) != 9:\n", + " print(\"Bad data?\")\n", + " exit(1)\n", + "\n", + "# Load the data\n", + "\n", + "hx = lambda x: int(x, 16)\n", + "data = np.genfromtxt(fname, delimiter=\";\", skip_header=1, converters={3: unhexlify, 4: unhexlify,\n", + " 5: hx, 6: unhexlify, 7: hx,\n", + " 8: lambda b: bool(int(b))},\n", + " dtype=np.dtype([(\"index\", \"u4\"), (\"sign_time\", \"u4\"), (\"verify_time\", \"u4\"),\n", + " (\"data\", \"O\"), (\"pub\", \"O\"), (\"priv\", \"O\"), (\"signature\", \"O\"),\n", + " (\"nonce\", \"O\"), (\"valid\", \"b\")]))\n", + "# Skip first (outliers?)\n", + "\n", + "data = data[skip_first:]\n", + "\n", + "# Setup the data\n", + "\n", + "# Convert time data\n", + "orig_sign_unit = header_names[1].split(\"[\")[1][:-1]\n", + "orig_verify_unit = header_names[2].split(\"[\")[1][:-1]\n", + "sign_disp_unit = time_scale(data[\"sign_time\"], orig_sign_unit, sign_unit, scaling_factor)\n", + "verify_disp_unit = time_scale(data[\"verify_time\"], orig_verify_unit, verify_unit, scaling_factor)\n", + "\n", + "if np.any(data[\"nonce\"] == None):\n", + " recompute_nonces(data, curve, hash_algo)\n", + "\n", + "# Trim times\n", + "quant_low_bound = trim_low if 0 <= trim_low <= 1 else 0.01\n", + "quant_high_bound = trim_high if 0 <= trim_high <= 1 else 0.95\n", + "quantiles_sign = mquantiles(data[\"sign_time\"], prob=(quant_low_bound, 0.25, 0.5, 0.75, quant_high_bound))\n", + "if trim:\n", + " low_bound = quantiles_sign[0] if 0 <= trim_low <= 1 else trim_low\n", + " high_bound = quantiles_sign[4] if 0 <= trim_high <= 1 else trim_high\n", + " data_trimmed = data[np.logical_and(data[\"sign_time\"] >= low_bound,\n", + " data[\"sign_time\"] <= high_bound)]\n", + " quantiles_sign_trim = mquantiles(data_trimmed[\"sign_time\"], prob=(quant_low_bound, 0.25, 0.5, 0.75, quant_high_bound))\n", + "else:\n", + " low_bound = None\n", + " high_bound = None\n", + " data_trimmed = data\n", + " quantiles_sign_trim = quantiles_sign\n", + "\n", + "description_sign = describe(data[\"sign_time\"])\n", + "description_sign_trim = describe(data_trimmed[\"sign_time\"])\n", + "\n", + "max_sign_time = description_sign.minmax[1]\n", + "min_sign_time = description_sign.minmax[0]\n", + "bit_size = len(bin(max(data[\"priv\"]))) - 2\n", + "byte_size = (bit_size + 7) // 8\n", + "bit_size = byte_size * 8\n", + "\n", + "hist_size_sign_time = hist_size_func(hist_size)(description_sign.nobs, min_sign_time, max_sign_time, description_sign.variance, quantiles_sign[1], quantiles_sign[3])\n", + "hist_size_sign_time_trim = hist_size_func(hist_size)(description_sign_trim.nobs, description_sign_trim.minmax[0], description_sign_trim.minmax[1], description_sign_trim.variance, quantiles_sign_trim[1], quantiles_sign_trim[3])\n", + "\n", + "if hist_size_sign_time < 30:\n", + " hist_size_sign_time = max_sign_time - min_sign_time\n", + "if hist_size_sign_time_trim < 30:\n", + " hist_size_sign_time_trim = description_sign_trim.minmax[1] - description_sign_trim.minmax[0]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Analysis" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Summary" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "ExecuteTime": { + "end_time": "2019-03-22T09:05:04.817352Z", + "start_time": "2019-03-22T09:05:04.804639Z" + } + }, + "outputs": [], + "source": [ + "display(\"Raw\")\n", + "desc = [(\"N\", \"min, max\", \"mean\", \"variance\", \"skewness\", \"kurtosis\"),\n", + " description_sign]\n", + "display(HTML(tabulate.tabulate(desc, tablefmt=\"html\")))\n", + "display(\"Trimmed\")\n", + "desc = [(\"N\", \"min, max\", \"mean\", \"variance\", \"skewness\", \"kurtosis\"),\n", + " description_sign_trim]\n", + "display(HTML(tabulate.tabulate(desc, tablefmt=\"html\")))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Selected quantiles" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "ExecuteTime": { + "end_time": "2019-03-22T09:05:06.106323Z", + "start_time": "2019-03-22T09:05:06.090706Z" + } + }, + "outputs": [], + "source": [ + "tbl = [(quant_low_bound, \"0.25\", \"0.5\", \"0.75\", quant_high_bound),\n", + " list(map(lambda x: \"{} {}\".format(x, sign_disp_unit), quantiles_sign))]\n", + "display(HTML(tabulate.tabulate(tbl, tablefmt=\"html\")))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Info" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "ExecuteTime": { + "end_time": "2019-03-22T09:05:06.799992Z", + "start_time": "2019-03-22T09:05:06.790754Z" + } + }, + "outputs": [], + "source": [ + "display(\"Bitsize:\", bit_size)\n", + "display(\"Histogram time bins: {}\".format(hist_size_sign_time))\n", + "display(\"Histogram time bins(trimmed): {}\".format(hist_size_sign_time_trim))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Plots" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Nonce MSB vs signature time heatmap\n", + "The heatmap should show uncorrelated variables." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "ExecuteTime": { + "end_time": "2019-03-22T09:05:08.567129Z", + "start_time": "2019-03-22T09:05:07.948181Z" + } + }, + "outputs": [], + "source": [ + "fig_nonce = plt.figure(figsize=(10.5, 8), dpi=90)\n", + "axe_nonce = fig_nonce.add_subplot(1, 1, 1, title=\"Nonce MSB vs signature time\")\n", + "nonce_msb = np.array(list(map(lambda x: x >> (bit_size - 8), data_trimmed[\"nonce\"])), dtype=np.dtype(\"u1\"))\n", + "max_msb = max(nonce_msb)\n", + "min_msb = min(nonce_msb)\n", + "heatmap, xedges, yedges = np.histogram2d(nonce_msb, data_trimmed[\"sign_time\"],\n", + " bins=[max_msb - min_msb + 1, hist_size_sign_time_trim])\n", + "extent = [min_msb, max_msb, yedges[0], yedges[-1]]\n", + "im = axe_nonce.imshow(heatmap.T, extent=extent, aspect=\"auto\", cmap=cmap, origin=\"low\",\n", + " interpolation=\"nearest\", norm=norm)\n", + "axe_nonce.set_xlabel(\"nonce MSB value\")\n", + "axe_nonce.set_ylabel(\"signature time ({})\".format(sign_disp_unit))\n", + "fig_nonce.colorbar(im, ax=axe_nonce)\n", + "\n", + "fig_nonce.tight_layout()\n", + "del nonce_msb" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Nonce Hamming Weight vs signature time heatmap\n", + "The heatmap should show uncorrelated variables.\n", + "\n", + "Also contains a nonce Hamming Weight histogram, which should be binomially distributed." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "ExecuteTime": { + "end_time": "2019-03-22T09:05:17.416586Z", + "start_time": "2019-03-22T09:05:16.928355Z" + } + }, + "outputs": [], + "source": [ + "fig_nonce_hist = plt.figure(figsize=(10.5, 12), dpi=90)\n", + "gs = gridspec.GridSpec(2, 1, height_ratios=[2.5, 1])\n", + "axe_nonce_hist = fig_nonce_hist.add_subplot(gs[0], title=\"Nonce Hamming weight vs signature time\")\n", + "axe_nonce_hist_hw = fig_nonce_hist.add_subplot(gs[1], sharex=axe_nonce_hist, title=\"Nonce Hamming weight\")\n", + "nonce_hw = np.array(list(map(hw, data_trimmed[\"nonce\"])), dtype=np.dtype(\"u2\"))\n", + "h, xe, ye = np.histogram2d(nonce_hw, data_trimmed[\"sign_time\"], bins=[max(nonce_hw) - min(nonce_hw), hist_size_sign_time_trim])\n", + "im = axe_nonce_hist.imshow(h.T, origin=\"low\", cmap=cmap, aspect=\"auto\", extent=[xe[0], xe[-1], ye[0], ye[-1]], norm=norm)\n", + "axe_nonce_hist.axvline(x=bit_size//2, alpha=0.7, linestyle=\"dotted\", color=\"white\", label=str(bit_size//2) + \" bits\")\n", + "axe_nonce_hist.set_xlabel(\"nonce Hamming weight\")\n", + "axe_nonce_hist.set_ylabel(\"signature time ({})\".format(sign_disp_unit))\n", + "axe_nonce_hist.legend(loc=\"best\")\n", + "\n", + "plot_hist(axe_nonce_hist_hw, nonce_hw, \"nonce Hamming weight\", log_scale, True, True)\n", + "\n", + "param = norm_dist.fit(nonce_hw)\n", + "pdf_range = np.arange(min(nonce_hw), max(nonce_hw))\n", + "norm_pdf = norm_dist.pdf(pdf_range, *param[:-2], loc=param[-2], scale=param[-1]) * description_sign_trim.nobs\n", + "axe_nonce_hist_hw.plot(pdf_range, norm_pdf, label=\"fitted normal distribution\")\n", + "axe_nonce_hist_hw.legend(loc=\"best\")\n", + "\n", + "\n", + "display(HTML(\"<b>Nonce Hamming weight fitted with normal distribution:</b>\"))\n", + "display(HTML(tabulate.tabulate([(\"Mean\", \"Variance\"), param], tablefmt=\"html\")))\n", + "\n", + "fig_nonce_hist.tight_layout()\n", + "fig_nonce_hist.colorbar(im, ax=[axe_nonce_hist, axe_nonce_hist_hw])\n", + "del nonce_hw" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Signature time histogram" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "ExecuteTime": { + "end_time": "2019-03-21T16:18:48.188494Z", + "start_time": "2019-03-21T16:18:39.850301Z" + } + }, + "outputs": [], + "source": [ + "fig_sig_hist = plt.figure(figsize=(10.5, 8), dpi=90)\n", + "axe_hist_full = fig_sig_hist.add_subplot(2, 1, 1, title=\"Signature time\")\n", + "axe_hist_trim = fig_sig_hist.add_subplot(2, 1, 2, title=\"Signature time (trimmed)\")\n", + "plot_hist(axe_hist_full, data[\"sign_time\"], \"signature time ({})\".format(sign_disp_unit), log_scale, hist_size_sign_time);\n", + "plot_hist(axe_hist_trim, data_trimmed[\"sign_time\"], \"signature time ({})\".format(sign_disp_unit), log_scale, hist_size_sign_time_trim);\n", + "fig_sig_hist.tight_layout()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Verification time histogram" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "ExecuteTime": { + "end_time": "2019-03-21T16:19:05.618320Z", + "start_time": "2019-03-21T16:18:53.161932Z" + } + }, + "outputs": [], + "source": [ + "fig_vrfy_hist = plt.figure(figsize=(10.5, 5), dpi=90)\n", + "axe_hist_full = fig_vrfy_hist.add_subplot(1, 1, 1, title=\"Verification time\")\n", + "plot_hist(axe_hist_full, data[\"verify_time\"], \"verification time ({})\".format(verify_disp_unit), log_scale, hist_size_sign_time);\n", + "fig_vrfy_hist.tight_layout()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Moving averages of signature and verification times" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "ExecuteTime": { + "end_time": "2019-03-22T09:05:24.311923Z", + "start_time": "2019-03-22T09:05:24.063585Z" + } + }, + "outputs": [], + "source": [ + "fig_avg = plt.figure(figsize=(10.5, 8), dpi=90)\n", + "axe_sign_avg = fig_avg.add_subplot(2, 1, 1, title=\"Moving average of signature time\")\n", + "axe_vrfy_avg = fig_avg.add_subplot(2, 1, 2, sharex=axe_sign_avg, title=\"Moving average of verification time\")\n", + "avg_sign_100 = moving_average(data[\"sign_time\"], 100)\n", + "avg_sign_1000 = moving_average(data[\"sign_time\"], 1000)\n", + "axe_sign_avg.plot(avg_sign_100, label=\"window = 100\")\n", + "axe_sign_avg.plot(avg_sign_1000, label=\"window = 1000\")\n", + "if low_bound is not None:\n", + " axe_sign_avg.axhline(y=low_bound, alpha=0.7, linestyle=\"dotted\", color=\"green\", label=\"Low trim bound = {}\".format(low_bound))\n", + "if high_bound is not None:\n", + " axe_sign_avg.axhline(y=high_bound, alpha=0.7, linestyle=\"dotted\", color=\"orange\", label=\"Hight trim bound = {}\".format(high_bound))\n", + "axe_sign_avg.set_ylabel(\"signature time ({})\".format(sign_disp_unit))\n", + "axe_sign_avg.set_xlabel(\"index\")\n", + "axe_sign_avg.legend(loc=\"best\")\n", + "\n", + "avg_vrfy_100 = moving_average(data[\"verify_time\"], 100)\n", + "avg_vrfy_1000 = moving_average(data[\"verify_time\"], 1000)\n", + "axe_vrfy_avg.plot(avg_vrfy_100, label=\"window = 100\")\n", + "axe_vrfy_avg.plot(avg_vrfy_1000, label=\"window = 1000\")\n", + "axe_vrfy_avg.set_ylabel(\"verification time ({})\".format(verify_disp_unit))\n", + "axe_vrfy_avg.set_xlabel(\"index\")\n", + "axe_vrfy_avg.legend(loc=\"best\")\n", + "\n", + "fig_avg.tight_layout()\n", + "\n", + "del avg_sign_100, avg_sign_1000, avg_vrfy_100, avg_vrfy_1000" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Nonce MSB and LSB histograms\n", + "Expected to be uniform over [0, 255]." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "ExecuteTime": { + "end_time": "2019-03-22T09:05:29.427210Z", + "start_time": "2019-03-22T09:05:28.768399Z" + } + }, + "outputs": [], + "source": [ + "fig_nonce_hists = plt.figure(figsize=(10.5, 8), dpi=90)\n", + "nonce_msb = np.array(list(map(lambda x: x >> (bit_size - 8), data[\"nonce\"])), dtype=np.dtype(\"u1\"))\n", + "nonce_lsb = np.array(list(map(lambda x: x & 0xff, data[\"nonce\"])), dtype=np.dtype(\"u1\"))\n", + "axe_msb_n_hist = fig_nonce_hists.add_subplot(2, 1, 1, title=\"Nonce MSB\")\n", + "axe_lsb_n_hist = fig_nonce_hists.add_subplot(2, 1, 2, title=\"Nonce LSB\")\n", + "plot_hist(axe_msb_n_hist, nonce_msb, \"nonce MSB\", log_scale, False, False)\n", + "plot_hist(axe_lsb_n_hist, nonce_lsb, \"nonce LSB\", log_scale, False, False)\n", + "\n", + "fig_nonce_hists.tight_layout()\n", + "del nonce_msb, nonce_lsb" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Nonce bit length vs signature time heatmap\n", + "Also contains nonce bit length histogram, which is expected to be axis flipped geometric distribution with $p = \\frac{1}{2}$ peaking at the bit size of the order of the curve." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "ExecuteTime": { + "end_time": "2019-03-22T09:06:00.061206Z", + "start_time": "2019-03-22T09:05:59.817227Z" + } + }, + "outputs": [], + "source": [ + "fig_bl = plt.figure(figsize=(10.5, 12), dpi=90)\n", + "gs = gridspec.GridSpec(2, 1, height_ratios=[2.5, 1])\n", + "axe_bl_heat = fig_bl.add_subplot(gs[0], title=\"Nonce bit length vs signature time\")\n", + "axe_bl_hist = fig_bl.add_subplot(gs[1], sharex=axe_bl_heat, title=\"Nonce bit length\")\n", + "bl_data = np.array(list(map(lambda x: x.bit_length(), data_trimmed[\"nonce\"])), dtype=np.dtype(\"u2\"))\n", + "\n", + "h, xe, ye = np.histogram2d(bl_data, data_trimmed[\"sign_time\"], bins=[max(bl_data) - min(bl_data), hist_size_sign_time_trim])\n", + "im = axe_bl_heat.imshow(h.T, origin=\"low\", cmap=cmap, aspect=\"auto\", extent=[xe[0], xe[-1], ye[0], ye[-1]], norm=norm)\n", + "axe_bl_heat.set_xlabel(\"nonce bit length\")\n", + "axe_bl_heat.set_ylabel(\"signature time ({})\".format(sign_disp_unit))\n", + "\n", + "plot_hist(axe_bl_hist, bl_data, \"nonce bit length\", log_scale, align=\"right\")\n", + "\n", + "fig_bl.tight_layout()\n", + "fig_bl.colorbar(im, ax=[axe_bl_heat, axe_bl_hist])\n", + "\n", + "del bl_data" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Nonce bit length histogram given time\n", + "Interactively shows the histogram of nonce bit length given a selected time range centered around `center` of width `width`. Ideally, the means of these conditional distributions are equal, while the variances can vary." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "ExecuteTime": { + "end_time": "2019-03-22T09:06:16.571781Z", + "start_time": "2019-03-22T09:06:16.336312Z" + }, + "scrolled": false + }, + "outputs": [], + "source": [ + "fig_bl_time = plt.figure(figsize=(10.5, 5), dpi=90)\n", + "axe_bl_time = fig_bl_time.add_subplot(111)\n", + "axe_bl_time.set_autoscalex_on(False)\n", + "def f(center, width):\n", + " lower_bnd = center - width/2\n", + " upper_bnd = center + width/2\n", + " values = data_trimmed[np.logical_and(data_trimmed[\"sign_time\"] <= upper_bnd,\n", + " data_trimmed[\"sign_time\"] >= lower_bnd)]\n", + " axe_bl_time.clear()\n", + " axe_bl_time.set_title(\"Nonce bit length, given signature time $\\in ({}, {})$ {}\".format(int(lower_bnd), int(upper_bnd), sign_disp_unit))\n", + " bl_data = np.array(list(map(lambda x: x.bit_length(), values[\"nonce\"])), dtype=np.dtype(\"u2\"))\n", + " plot_hist(axe_bl_time, bl_data, \"nonce bit length\", bins=11, range=(bit_size-10, bit_size+1), align=\"left\")\n", + " axe_bl_time.set_xlim((bit_size-10, bit_size))\n", + " fig_bl_time.tight_layout()\n", + "\n", + "center_w = widgets.IntSlider(min=min(data_trimmed[\"sign_time\"]),\n", + " max=max(data_trimmed[\"sign_time\"]),\n", + " step=1,\n", + " value=description_sign_trim.mean,\n", + " continuous_update=False,\n", + " description=\"center {}\".format(sign_disp_unit))\n", + "width_w = widgets.IntSlider(min=1, max=100, continuous_update=False,\n", + " description=\"width {}\".format(sign_disp_unit))\n", + "w = interactive(f, center=center_w,\n", + " width=width_w)\n", + "display(w)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Validation\n", + "Perform some tests on the produced data and compare to expected results.\n", + "\n", + "\n", + "This requires some information about the used curve, enter it below." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "ExecuteTime": { + "end_time": "2019-03-21T15:24:57.397880Z", + "start_time": "2019-03-21T15:24:37.395614Z" + } + }, + "outputs": [], + "source": [ + "p_str = input(\"The prime specifying the finite field:\")\n", + "p = int(p_str, 16) if p_str.startswith(\"0x\") else int(p_str)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "ExecuteTime": { + "end_time": "2019-03-21T15:25:05.137250Z", + "start_time": "2019-03-21T15:24:59.218945Z" + } + }, + "outputs": [], + "source": [ + "r_str = input(\"The order of the curve:\")\n", + "r = int(r_str, 16) if r_str.startswith(\"0x\") else int(r_str)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "All of the following tests should pass (e.g. be true), given a large enough sample." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "ExecuteTime": { + "end_time": "2019-03-21T16:23:08.618543Z", + "start_time": "2019-03-21T16:23:08.451827Z" + }, + "scrolled": true + }, + "outputs": [], + "source": [ + "max_priv = max(data[\"priv\"])\n", + "max_nonce = max(data[\"nonce\"])\n", + "un = len(np.unique(data[\"priv\"])) != 1\n", + "if un:\n", + " print(\"Private keys are smaller than order:\\t\\t\\t\" + str(max_priv < r))\n", + " print(\"Private keys are larger than prime(if order > prime):\\t\" + str(r <= p or max_priv > p))\n", + "print(\"Nonces are smaller than order:\\t\\t\\t\\t\" + str(max_nonce < r))\n", + "print(\"Nonces are larger than prime(if order > prime):\\t\\t\" + str(r <= p or max_nonce > p))\n", + "if un:\n", + " print(\"Private keys reach full bit length of order:\\t\\t\" + str(max_priv.bit_length() == r.bit_length()))\n", + "print(\"Nonces reach full bit length of order:\\t\\t\\t\" + str(max_nonce.bit_length() == r.bit_length()))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "ExecuteTime": { + "end_time": "2019-03-21T16:23:09.355514Z", + "start_time": "2019-03-21T16:23:09.315702Z" + } + }, + "outputs": [], + "source": [ + "if un:\n", + " print(\"Private key bit length (min, max):\" + str(min(data[\"priv\"]).bit_length()) + \", \" + str(max(data[\"priv\"]).bit_length()))\n", + "print(\"Nonce bit length (min, max):\" + str(min(data[\"nonce\"]).bit_length()) + \", \" + str(max(data[\"nonce\"]).bit_length()))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "print(\"Nonce uniqueness (no duplicates):\" + str(len(np.unique(data[\"nonce\"])) == len(data[\"nonce\"])))" + ] + } + ], + "metadata": { + "@webio": { + "lastCommId": "a38f080b9a044da08882846212c38d91", + "lastKernelId": "4cad5b27-583d-4c4e-947c-f47bdf2d4754" + }, + "hide_input": false, + "kernelspec": { + "display_name": "Python 3", + "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.7.4" + }, + "latex_envs": { + "LaTeX_envs_menu_present": true, + "autoclose": false, + "autocomplete": true, + "bibliofile": "biblio.bib", + "cite_by": "apalike", + "current_citInitial": 1, + "eqLabelWithNumbers": true, + "eqNumInitial": 1, + "hotkeys": { + "equation": "Ctrl-E", + "itemize": "Ctrl-I" + }, + "labels_anchors": false, + "latex_user_defs": false, + "report_style_numbering": false, + "user_envs_cfg": false + }, + "toc": { + "base_numbering": 1, + "nav_menu": {}, + "number_sections": true, + "sideBar": true, + "skip_h1_title": false, + "title_cell": "Table of Contents", + "title_sidebar": "Contents", + "toc_cell": false, + "toc_position": {}, + "toc_section_display": true, + "toc_window_display": false + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} |
