aboutsummaryrefslogtreecommitdiff
path: root/epare/countermeasures.ipynb
diff options
context:
space:
mode:
Diffstat (limited to 'epare/countermeasures.ipynb')
-rw-r--r--epare/countermeasures.ipynb1131
1 files changed, 1131 insertions, 0 deletions
diff --git a/epare/countermeasures.ipynb b/epare/countermeasures.ipynb
new file mode 100644
index 0000000..1ee3dea
--- /dev/null
+++ b/epare/countermeasures.ipynb
@@ -0,0 +1,1131 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "bafc2f4e-05a3-4120-bcd6-5d1f5fb91cd9",
+ "metadata": {},
+ "source": [
+ "# Distinguishing countermeasures by output"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "33ee6084-2ac3-4f95-9610-0fbc06026538",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import io\n",
+ "import random\n",
+ "\n",
+ "from collections import Counter\n",
+ "from tqdm.auto import tqdm, trange\n",
+ "\n",
+ "from pyecsca.ec.mod import mod\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.countermeasures import GroupScalarRandomization, AdditiveSplitting, MultiplicativeSplitting, EuclideanSplitting, BrumleyTuveri"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "id": "b1b9596c-1eba-4ace-af84-8cb279d84cc2",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "model = ShortWeierstrassModel()\n",
+ "coords = model.coordinates[\"projective\"]"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "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": 4,
+ "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": 5,
+ "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": 6,
+ "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": 7,
+ "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": 8,
+ "id": "86532d50-2db7-4370-b449-c545b330a852",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "application/vnd.jupyter.widget-view+json": {
+ "model_id": "a645f19f86484d3f8154c39c2b851de2",
+ "version_major": 2,
+ "version_minor": 0
+ },
+ "text/plain": [
+ " 0%| | 0/1000 [00:00<?, ?it/s]"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "k:\t343\n",
+ "k + 1n:\t339\n",
+ "k + 2n:\t318\n"
+ ]
+ }
+ ],
+ "source": [
+ "test_3n_fixed_scalar(gsr, 1000)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "aba3e713-6246-435d-93af-2e8b42ee9582",
+ "metadata": {},
+ "source": [
+ "#### Additive splitting"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 9,
+ "id": "ad421630-606f-4666-9bbf-1a446eec1b59",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "application/vnd.jupyter.widget-view+json": {
+ "model_id": "1d3be2fca22c468c84b0c6fa179ba46c",
+ "version_major": 2,
+ "version_minor": 0
+ },
+ "text/plain": [
+ " 0%| | 0/1000 [00:00<?, ?it/s]"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "k:\t520\n",
+ "k + 1n:\t480\n"
+ ]
+ }
+ ],
+ "source": [
+ "test_3n_fixed_scalar(asplit, 1000)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "a1284a11-4ace-437d-9826-2035cce36756",
+ "metadata": {},
+ "source": [
+ "#### Multiplicative splitting"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 10,
+ "id": "3ed5d7f3-0ba1-4b62-9635-aeb492499175",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "application/vnd.jupyter.widget-view+json": {
+ "model_id": "758e44f09b0448ba9cd2e69cf7a16691",
+ "version_major": 2,
+ "version_minor": 0
+ },
+ "text/plain": [
+ " 0%| | 0/1000 [00:00<?, ?it/s]"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "k:\t219\n",
+ "k + 1n:\t554\n",
+ "k + 2n:\t227\n"
+ ]
+ }
+ ],
+ "source": [
+ "test_3n_fixed_scalar(msplit, 1000)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "5e40f8e9-d26f-41e7-adbf-a0fbdb680677",
+ "metadata": {},
+ "source": [
+ "#### Euclidean splitting"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 11,
+ "id": "314447c6-a1fb-4d3a-8988-b34c8912dd5e",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "application/vnd.jupyter.widget-view+json": {
+ "model_id": "3eec57b52cd647e7bfc37b577ac7b6b9",
+ "version_major": 2,
+ "version_minor": 0
+ },
+ "text/plain": [
+ " 0%| | 0/1000 [00:00<?, ?it/s]"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "k:\t1000\n"
+ ]
+ }
+ ],
+ "source": [
+ "test_3n_fixed_scalar(esplit, 1000)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "ff7185a2-3cd9-44d7-b1a9-982eaed561dc",
+ "metadata": {},
+ "source": [
+ "#### Brumley and Tuveri bit-length fixing"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 12,
+ "id": "f41dfc1d-1017-4aa0-bcd4-6569c53bf81e",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "application/vnd.jupyter.widget-view+json": {
+ "model_id": "cdb7d64c69f64a62b4b1357f06db1481",
+ "version_major": 2,
+ "version_minor": 0
+ },
+ "text/plain": [
+ " 0%| | 0/1000 [00:00<?, ?it/s]"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "k + 2n:\t1000\n"
+ ]
+ }
+ ],
+ "source": [
+ "test_3n_fixed_scalar(bt, 1000)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "28915553-b5e6-4108-bc23-e5844b6a63b8",
+ "metadata": {},
+ "source": [
+ "### Random scalar experiments"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "566ddd10-2d0e-4b32-9b27-60770ab68155",
+ "metadata": {},
+ "source": [
+ "#### Group scalar randomization"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 13,
+ "id": "7255321a-6ad6-4938-8ec9-dd8d977686db",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "application/vnd.jupyter.widget-view+json": {
+ "model_id": "828fecbd021a43b4a529e1261b4e5f5b",
+ "version_major": 2,
+ "version_minor": 0
+ },
+ "text/plain": [
+ " 0%| | 0/1000 [00:00<?, ?it/s]"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "k:\t315\n",
+ "k + 1n:\t330\n",
+ "k + 2n:\t355\n"
+ ]
+ }
+ ],
+ "source": [
+ "test_3n_random_scalar(gsr, 1000)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "376c0da8-b92d-4151-ac30-839ab5c0ceae",
+ "metadata": {},
+ "source": [
+ "#### Additive splitting"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 14,
+ "id": "b0146a9a-0803-43c4-ab29-8ba6e15934b5",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "application/vnd.jupyter.widget-view+json": {
+ "model_id": "5d9adb2b79254271872bdfe5c38a3983",
+ "version_major": 2,
+ "version_minor": 0
+ },
+ "text/plain": [
+ " 0%| | 0/1000 [00:00<?, ?it/s]"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "k:\t505\n",
+ "k + 1n:\t495\n"
+ ]
+ }
+ ],
+ "source": [
+ "test_3n_random_scalar(asplit, 1000)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "96823352-cd63-4cf8-8ab7-cf6e025837b9",
+ "metadata": {},
+ "source": [
+ "#### Multiplicative splitting"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 15,
+ "id": "5645ae6f-f5f4-419d-ba47-248532dc2114",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "application/vnd.jupyter.widget-view+json": {
+ "model_id": "e4073f552ae248269ab0785b701bd069",
+ "version_major": 2,
+ "version_minor": 0
+ },
+ "text/plain": [
+ " 0%| | 0/1000 [00:00<?, ?it/s]"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "k:\t345\n",
+ "k + 1n:\t327\n",
+ "k + 2n:\t328\n"
+ ]
+ }
+ ],
+ "source": [
+ "test_3n_random_scalar(msplit, 1000)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "1784d763-932a-4f66-a1da-d7ef51cbc88a",
+ "metadata": {},
+ "source": [
+ "#### Euclidean splitting"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 16,
+ "id": "c9fc4f35-1c25-4cac-bb63-8bd70263db47",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "application/vnd.jupyter.widget-view+json": {
+ "model_id": "529938c684364319be7d8ba15f68d79c",
+ "version_major": 2,
+ "version_minor": 0
+ },
+ "text/plain": [
+ " 0%| | 0/1000 [00:00<?, ?it/s]"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "k:\t1000\n"
+ ]
+ }
+ ],
+ "source": [
+ "test_3n_random_scalar(esplit, 1000)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "8917dfd5-1548-414b-846a-685857bfb427",
+ "metadata": {},
+ "source": [
+ "#### Brumley and Tuveri bit-length fixing"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 17,
+ "id": "4fd6b288-08a9-4dbe-9145-e96401805315",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "application/vnd.jupyter.widget-view+json": {
+ "model_id": "19bdafccd4f04b42ba188598567a1e8c",
+ "version_major": 2,
+ "version_minor": 0
+ },
+ "text/plain": [
+ " 0%| | 0/1000 [00:00<?, ?it/s]"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "k + 1n:\t35\n",
+ "k + 2n:\t965\n"
+ ]
+ }
+ ],
+ "source": [
+ "test_3n_random_scalar(bt, 1000)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "ee9e23f6-edd9-4fc2-9e7c-b5c176991071",
+ "metadata": {},
+ "source": [
+ "### Random scalar experiments projected to scalar divisor classes mod 3"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "e17fcb12-1e02-4bcf-a2b7-785c16c03028",
+ "metadata": {},
+ "source": [
+ "#### Group scalar randomization"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 18,
+ "id": "6c46fdbb-2ffb-4169-8e00-6d93b8407ee5",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "k = 0 mod 3\n"
+ ]
+ },
+ {
+ "data": {
+ "application/vnd.jupyter.widget-view+json": {
+ "model_id": "a65c045d5236432aba76108115266213",
+ "version_major": 2,
+ "version_minor": 0
+ },
+ "text/plain": [
+ " 0%| | 0/1000 [00:00<?, ?it/s]"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "k:\t349\n",
+ "k + 1n:\t300\n",
+ "k + 2n:\t351\n",
+ "\n",
+ "k = 1 mod 3\n"
+ ]
+ },
+ {
+ "data": {
+ "application/vnd.jupyter.widget-view+json": {
+ "model_id": "475dc945b4624296817e939a7e86ca14",
+ "version_major": 2,
+ "version_minor": 0
+ },
+ "text/plain": [
+ " 0%| | 0/1000 [00:00<?, ?it/s]"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "k:\t358\n",
+ "k + 1n:\t329\n",
+ "k + 2n:\t313\n",
+ "\n",
+ "k = 2 mod 3\n"
+ ]
+ },
+ {
+ "data": {
+ "application/vnd.jupyter.widget-view+json": {
+ "model_id": "a03a298fe08446b7849d02a2b7b217ca",
+ "version_major": 2,
+ "version_minor": 0
+ },
+ "text/plain": [
+ " 0%| | 0/1000 [00:00<?, ?it/s]"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "k:\t310\n",
+ "k + 1n:\t324\n",
+ "k + 2n:\t366\n"
+ ]
+ }
+ ],
+ "source": [
+ "test_3n_random_scalar_projected(gsr, 1000)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "b9d635c8-f788-4700-876b-ac48e89557a7",
+ "metadata": {},
+ "source": [
+ "#### Additive splitting"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 19,
+ "id": "344a4f90-3470-40e9-a75f-b925a88c2480",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "k = 0 mod 3\n"
+ ]
+ },
+ {
+ "data": {
+ "application/vnd.jupyter.widget-view+json": {
+ "model_id": "5c77bfdf86864a76ab849f5379f44248",
+ "version_major": 2,
+ "version_minor": 0
+ },
+ "text/plain": [
+ " 0%| | 0/1000 [00:00<?, ?it/s]"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "k:\t513\n",
+ "k + 1n:\t487\n",
+ "\n",
+ "k = 1 mod 3\n"
+ ]
+ },
+ {
+ "data": {
+ "application/vnd.jupyter.widget-view+json": {
+ "model_id": "e98ab853babf4a3ba962d72e19b69dd3",
+ "version_major": 2,
+ "version_minor": 0
+ },
+ "text/plain": [
+ " 0%| | 0/1000 [00:00<?, ?it/s]"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "k:\t484\n",
+ "k + 1n:\t516\n",
+ "\n",
+ "k = 2 mod 3\n"
+ ]
+ },
+ {
+ "data": {
+ "application/vnd.jupyter.widget-view+json": {
+ "model_id": "6e6ebc6372ad45758f30937a6ac3c291",
+ "version_major": 2,
+ "version_minor": 0
+ },
+ "text/plain": [
+ " 0%| | 0/1000 [00:00<?, ?it/s]"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "k:\t518\n",
+ "k + 1n:\t482\n"
+ ]
+ }
+ ],
+ "source": [
+ "test_3n_random_scalar_projected(asplit, 1000)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "78aaf83f-a689-40ad-ae88-58ab20e5e6f9",
+ "metadata": {},
+ "source": [
+ "#### Multiplicative splitting"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 20,
+ "id": "616a7726-01e6-4e9c-b7f2-fe8f14b60071",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "k = 0 mod 3\n"
+ ]
+ },
+ {
+ "data": {
+ "application/vnd.jupyter.widget-view+json": {
+ "model_id": "fcc70a8e56bc4e19baac2065827fe431",
+ "version_major": 2,
+ "version_minor": 0
+ },
+ "text/plain": [
+ " 0%| | 0/1000 [00:00<?, ?it/s]"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "k:\t564\n",
+ "k + 1n:\t213\n",
+ "k + 2n:\t223\n",
+ "\n",
+ "k = 1 mod 3\n"
+ ]
+ },
+ {
+ "data": {
+ "application/vnd.jupyter.widget-view+json": {
+ "model_id": "8401c46897fe47739342c17404fe0774",
+ "version_major": 2,
+ "version_minor": 0
+ },
+ "text/plain": [
+ " 0%| | 0/1000 [00:00<?, ?it/s]"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "k:\t216\n",
+ "k + 1n:\t209\n",
+ "k + 2n:\t575\n",
+ "\n",
+ "k = 2 mod 3\n"
+ ]
+ },
+ {
+ "data": {
+ "application/vnd.jupyter.widget-view+json": {
+ "model_id": "700a89093d19425d8b8a4d3418af215b",
+ "version_major": 2,
+ "version_minor": 0
+ },
+ "text/plain": [
+ " 0%| | 0/1000 [00:00<?, ?it/s]"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "k:\t231\n",
+ "k + 1n:\t564\n",
+ "k + 2n:\t205\n"
+ ]
+ }
+ ],
+ "source": [
+ "test_3n_random_scalar_projected(msplit, 1000)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "018c8f31-d7c3-497b-bdaf-580c6465753f",
+ "metadata": {},
+ "source": [
+ "#### Euclidean splitting"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 21,
+ "id": "adced4e4-37a7-43ed-97b5-01cb5d274d6b",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "k = 0 mod 3\n"
+ ]
+ },
+ {
+ "data": {
+ "application/vnd.jupyter.widget-view+json": {
+ "model_id": "c314c4a285634a6eaaabc93bbd7aa60f",
+ "version_major": 2,
+ "version_minor": 0
+ },
+ "text/plain": [
+ " 0%| | 0/1000 [00:00<?, ?it/s]"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "k:\t1000\n",
+ "\n",
+ "k = 1 mod 3\n"
+ ]
+ },
+ {
+ "data": {
+ "application/vnd.jupyter.widget-view+json": {
+ "model_id": "7134985a8cdf4d1f8cecce1bbfb31f9a",
+ "version_major": 2,
+ "version_minor": 0
+ },
+ "text/plain": [
+ " 0%| | 0/1000 [00:00<?, ?it/s]"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "k:\t1000\n",
+ "\n",
+ "k = 2 mod 3\n"
+ ]
+ },
+ {
+ "data": {
+ "application/vnd.jupyter.widget-view+json": {
+ "model_id": "45bc4b1be69c4d918f821e5c3cfde87f",
+ "version_major": 2,
+ "version_minor": 0
+ },
+ "text/plain": [
+ " 0%| | 0/1000 [00:00<?, ?it/s]"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "k:\t1000\n"
+ ]
+ }
+ ],
+ "source": [
+ "test_3n_random_scalar_projected(esplit, 1000)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "8d7b0a42-7be7-464d-932d-8386ad912034",
+ "metadata": {},
+ "source": [
+ "#### Brumley and Tuveri bit-length fixing"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 22,
+ "id": "fe8d8295-3e69-4b60-b8c3-5710deaeb0b3",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "k = 0 mod 3\n"
+ ]
+ },
+ {
+ "data": {
+ "application/vnd.jupyter.widget-view+json": {
+ "model_id": "8a13b1ee1a9e448cbcfc95b94efa4254",
+ "version_major": 2,
+ "version_minor": 0
+ },
+ "text/plain": [
+ " 0%| | 0/1000 [00:00<?, ?it/s]"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "k + 1n:\t51\n",
+ "k + 2n:\t949\n",
+ "\n",
+ "k = 1 mod 3\n"
+ ]
+ },
+ {
+ "data": {
+ "application/vnd.jupyter.widget-view+json": {
+ "model_id": "a7db0f83dcd54e92b9b7e3360e255aec",
+ "version_major": 2,
+ "version_minor": 0
+ },
+ "text/plain": [
+ " 0%| | 0/1000 [00:00<?, ?it/s]"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "k + 1n:\t39\n",
+ "k + 2n:\t961\n",
+ "\n",
+ "k = 2 mod 3\n"
+ ]
+ },
+ {
+ "data": {
+ "application/vnd.jupyter.widget-view+json": {
+ "model_id": "63a961fdb65e4223bde808fed8f4abbc",
+ "version_major": 2,
+ "version_minor": 0
+ },
+ "text/plain": [
+ " 0%| | 0/1000 [00:00<?, ?it/s]"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "k + 1n:\t37\n",
+ "k + 2n:\t963\n"
+ ]
+ }
+ ],
+ "source": [
+ "test_3n_random_scalar_projected(bt, 1000)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "b1b0bfd6-70f9-4822-b964-0c6ab097b498",
+ "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
+}