aboutsummaryrefslogtreecommitdiff
path: root/analysis/countermeasures/combinations.ipynb
diff options
context:
space:
mode:
authorvojtechsu2025-06-25 16:32:09 +0200
committervojtechsu2025-06-25 16:32:09 +0200
commit73db8e437f5e7a894642742028b37698da8c02b1 (patch)
treeda4c29f498026f22d827a1635092746e86c30f2d /analysis/countermeasures/combinations.ipynb
parentd4169812fc1265192c8023a53578f5a54fb0320e (diff)
downloadECTester-73db8e437f5e7a894642742028b37698da8c02b1.tar.gz
ECTester-73db8e437f5e7a894642742028b37698da8c02b1.tar.zst
ECTester-73db8e437f5e7a894642742028b37698da8c02b1.zip
Diffstat (limited to 'analysis/countermeasures/combinations.ipynb')
-rw-r--r--analysis/countermeasures/combinations.ipynb1854
1 files changed, 1854 insertions, 0 deletions
diff --git a/analysis/countermeasures/combinations.ipynb b/analysis/countermeasures/combinations.ipynb
new file mode 100644
index 0000000..e54c5ab
--- /dev/null
+++ b/analysis/countermeasures/combinations.ipynb
@@ -0,0 +1,1854 @@
+{
+ "cells": [
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "50a9e566",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import io\n",
+ "import math\n",
+ "import random\n",
+ "import itertools\n",
+ "import warnings\n",
+ "\n",
+ "import cypari2\n",
+ "from cysignals.alarm import alarm, AlarmInterrupt\n",
+ "\n",
+ "from matplotlib import pyplot as plt\n",
+ "from collections import Counter\n",
+ "from tqdm.auto import tqdm, trange\n",
+ "\n",
+ "from pyecsca.misc.cfg import TemporaryConfig\n",
+ "from pyecsca.misc.utils import TaskExecutor\n",
+ "from pyecsca.ec.mod import mod, RandomModAction\n",
+ "from pyecsca.ec.point import Point\n",
+ "from pyecsca.ec.model import ShortWeierstrassModel\n",
+ "from pyecsca.ec.params import load_params_ectester, get_params\n",
+ "from pyecsca.ec.mult import LTRMultiplier, RTLMultiplier, ScalarMultiplicationAction\n",
+ "from pyecsca.ec.context import local, DefaultContext\n",
+ "from countermeasures import GroupScalarRandomization, AdditiveSplitting, MultiplicativeSplitting, EuclideanSplitting, BrumleyTuveri\n",
+ "from pyecsca.ec.formula import AdditionFormula\n",
+ "from pyecsca.ec.mod import Mod, mod\n",
+ "from pyecsca.ec.mult import ScalarMultiplier, ScalarMultiplicationAction\n",
+ "from pyecsca.ec.params import DomainParameters\n",
+ "from pyecsca.ec.point import Point\n",
+ "from countermeasures import *\n",
+ "from public import public\n",
+ "from abc import ABC, abstractmethod\n",
+ "from typing import Optional\n",
+ "# %matplotlib ipympl"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "39788eba",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# copy from simulation notebook\n",
+ "\n",
+ "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",
+ " \n",
+ " print(ctr)\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": "code",
+ "execution_count": null,
+ "id": "03ab7450",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "model = ShortWeierstrassModel()\n",
+ "coords = model.coordinates[\"projective\"]\n",
+ "add = coords.formulas[\"add-2007-bl\"]\n",
+ "dbl = coords.formulas[\"dbl-2007-bl\"]\n",
+ "ltr = LTRMultiplier(add, dbl, complete=False)\n",
+ "rtl = RTLMultiplier(add, dbl, complete=False)\n",
+ "mult = ltr\n",
+ "gsr = GroupScalarRandomization(mult)\n",
+ "gsr160 = GroupScalarRandomization(mult, 160)\n",
+ "asplit = AdditiveSplitting(mult)\n",
+ "msplit = MultiplicativeSplitting(mult)\n",
+ "esplit = EuclideanSplitting(mult,add)\n",
+ "bt = BrumleyTuveri(mult)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "ef143ca2",
+ "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": "markdown",
+ "id": "c7535814",
+ "metadata": {},
+ "source": [
+ "## GSR + Add"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "ae49446a",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "@public\n",
+ "class GSR_Add_1(ScalarMultiplierCountermeasure):\n",
+ " r\"\"\"\n",
+ " GSR with Add, option 1.\n",
+ " [k+rn-s]+[s]\n",
+ " \"\"\"\n",
+ "\n",
+ " rand_bits: int\n",
+ "\n",
+ " def __init__(self, mult: ScalarMultiplier, rand_bits: int = 32, add = None):\n",
+ " \"\"\"\n",
+ " :param mult: The multiplier to use.\n",
+ " :param rand_bits: How many random bits to sample.\n",
+ " \"\"\"\n",
+ " super().__init__(mult)\n",
+ " self.rand_bits = rand_bits\n",
+ " self.add = add\n",
+ " self.r = None\n",
+ " self.s = None\n",
+ "\n",
+ " def init(self, params: DomainParameters, point: Point):\n",
+ " self.params = params\n",
+ " self.point = point\n",
+ " self.mult.init(\n",
+ " self.params,\n",
+ " self.point,\n",
+ " bits=params.full_order.bit_length() + self.rand_bits,\n",
+ " )\n",
+ "\n",
+ " def multiply(self, scalar: int) -> Point:\n",
+ " if self.params is None or self.point is None:\n",
+ " raise ValueError(\"Not initialized.\")\n",
+ " with ScalarMultiplicationAction(self.point, self.params, scalar) as action:\n",
+ " order = self.params.order\n",
+ " r = int(Mod.random(1 << self.rand_bits)) if self.r is None else self.r\n",
+ " order = self.params.order\n",
+ " s = Mod.random(order) if self.s is None else self.s\n",
+ " gsr_scalar = scalar + r * order\n",
+ " m1 = self.mult.multiply(int(gsr_scalar-s))\n",
+ " m2 = self.mult.multiply(int(s))\n",
+ " if self.add is None:\n",
+ " res = self.mult._add(m1, m2) # noqa: This is OK.\n",
+ " else:\n",
+ " res = self.add(\n",
+ " self.params.curve.prime, m1, m2, **self.params.curve.parameters\n",
+ " )[0]\n",
+ " return action.exit(res)\n",
+ " \n",
+ "@public\n",
+ "class GSR_Add_2(ScalarMultiplierCountermeasure):\n",
+ " r\"\"\"\n",
+ " GSR with Add, option 2.\n",
+ " [k-s+r_1*n]+[s+r_2*n]\n",
+ " \"\"\"\n",
+ "\n",
+ " rand_bits: int\n",
+ "\n",
+ " def __init__(self, mult: ScalarMultiplier, rand_bits: int = 32, add = None):\n",
+ " \"\"\"\n",
+ " :param mult: The multiplier to use.\n",
+ " :param rand_bits: How many random bits to sample.\n",
+ " \"\"\"\n",
+ " super().__init__(mult)\n",
+ " self.rand_bits = rand_bits\n",
+ " self.add = add\n",
+ " self.r1 = None\n",
+ " self.r2 = None\n",
+ " self.s = None\n",
+ "\n",
+ " def init(self, params: DomainParameters, point: Point):\n",
+ " self.params = params\n",
+ " self.point = point\n",
+ " self.mult.init(\n",
+ " self.params,\n",
+ " self.point,\n",
+ " bits=params.full_order.bit_length() + self.rand_bits,\n",
+ " )\n",
+ "\n",
+ " def multiply(self, scalar: int) -> Point:\n",
+ " if self.params is None or self.point is None:\n",
+ " raise ValueError(\"Not initialized.\")\n",
+ " with ScalarMultiplicationAction(self.point, self.params, scalar) as action:\n",
+ " order = self.params.order\n",
+ " r1 = int(Mod.random(1 << self.rand_bits)) if self.r1 is None else self.r1\n",
+ " r2 = int(Mod.random(1 << self.rand_bits)) if self.r2 is None else self.r2\n",
+ " order = self.params.order\n",
+ " s = Mod.random(order) if self.s is None else self.s\n",
+ " add_scalar = scalar - s\n",
+ " \n",
+ " m1 = self.mult.multiply(int(add_scalar+r1*order))\n",
+ " m2 = self.mult.multiply(int(s+r2*order))\n",
+ " if self.add is None:\n",
+ " res = self.mult._add(m1, m2) # noqa: This is OK.\n",
+ " else:\n",
+ " res = self.add(\n",
+ " self.params.curve.prime, m1, m2, **self.params.curve.parameters\n",
+ " )[0]\n",
+ " return action.exit(res)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "7c0875b7",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "ga1 = GSR_Add_1(mult)\n",
+ "ga2 = GSR_Add_2(mult)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "acda2816",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "test_3n_random_scalar(ga1, 10)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "d3441ab5",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "test_3n_random_scalar(ga2, 10)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "c93eb468",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "test_3n_random_scalar_projected(ga1,10)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "b9a181a2",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "test_3n_random_scalar_projected(ga2, 10)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "4c81fbba",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "test_3n_fixed_scalar(ga1,10)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "f6a635ad",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "test_3n_fixed_scalar(ga2, 10)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "e532becf",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "gsrbits = 32\n",
+ "ga1 = GSR_Add_1(mult)\n",
+ "ga1.r1 = int(Mod.random(1 << gsrbits))\n",
+ "ga1.r2 = int(Mod.random(1 << gsrbits))\n",
+ "ga2 = GSR_Add_2(mult)\n",
+ "ga2.r1 = int(Mod.random(1 << gsrbits))\n",
+ "ga2.r2 = int(Mod.random(1 << gsrbits))"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "879e75a4",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "test_3n_random_scalar_projected(ga1,10)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "07b29e36",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "test_3n_random_scalar_projected(ga2,300)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "9ae7dd85",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "test_3n_random_scalar_projected(ga2,300)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "707b8b61",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "order = params3n.order\n",
+ "ga1 = GSR_Add_1(mult)\n",
+ "ga1.s = Mod.random(order)\n",
+ "ga2 = GSR_Add_2(mult)\n",
+ "ga2.s = Mod.random(order)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "4e217adf",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "test_3n_random_scalar_projected(ga1,300)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "b97290ac",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "test_3n_random_scalar_projected(ga2,300)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "32da4f70",
+ "metadata": {},
+ "source": [
+ "## GSR + Mult"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "cd9fa456",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "@public\n",
+ "class GSR_Mult_1(ScalarMultiplierCountermeasure):\n",
+ " r\"\"\"\n",
+ " GSR with Mult, option 1.\n",
+ " [ks^(-1)+rn][s]\n",
+ " \"\"\"\n",
+ "\n",
+ " rand_bits: int\n",
+ "\n",
+ " def __init__(self, mult: ScalarMultiplier, rand_bits_gsr: int = 32, rand_bits_mult: int = 32):\n",
+ " \"\"\"\n",
+ " :param mult: The multiplier to use.\n",
+ " :param rand_bits: How many random bits to sample.\n",
+ " \"\"\"\n",
+ " super().__init__(mult)\n",
+ " self.rand_bits_gsr = rand_bits_gsr\n",
+ " self.rand_bits_mult = rand_bits_mult\n",
+ " self.r = None\n",
+ " self.s = None\n",
+ " \n",
+ " def init(self, params: DomainParameters, point: Point):\n",
+ " self.params = params\n",
+ " self.point = point\n",
+ " self.mult.init(\n",
+ " self.params,\n",
+ " self.point,\n",
+ " bits=params.full_order.bit_length() + self.rand_bits_gsr,\n",
+ " )\n",
+ "\n",
+ " def multiply(self, scalar: int) -> Point:\n",
+ " if self.params is None or self.point is None:\n",
+ " raise ValueError(\"Not initialized.\")\n",
+ " with ScalarMultiplicationAction(self.point, self.params, scalar) as action:\n",
+ " order = self.params.order\n",
+ " r = Mod.random(1 << self.rand_bits_gsr) if self.r is None else self.r\n",
+ " s = Mod.random(1 << self.rand_bits_mult) if self.s is None else self.s\n",
+ " \n",
+ " S = self.mult.multiply(int(s))\n",
+ " self.mult.init(self.params, S)\n",
+ " \n",
+ " ks_inv = scalar * mod(int(s), order).inverse()\n",
+ " ks_inv_gsr = int(ks_inv) + int(r)*order\n",
+ " return action.exit(self.mult.multiply(int(ks_inv_gsr)))\n",
+ "\n",
+ "@public\n",
+ "class GSR_Mult_2(ScalarMultiplierCountermeasure):\n",
+ " r\"\"\"\n",
+ " GSR with Mult, option 2.\n",
+ " [ks^(-1)+r_1*n][s+r_2*n]\n",
+ " \"\"\"\n",
+ "\n",
+ " rand_bits: int\n",
+ "\n",
+ " def __init__(self, mult: ScalarMultiplier, rand_bits_gsr: int = 32, rand_bits_mult: int = 32):\n",
+ " \"\"\"\n",
+ " :param mult: The multiplier to use.\n",
+ " :param rand_bits: How many random bits to sample.\n",
+ " \"\"\"\n",
+ " super().__init__(mult)\n",
+ " self.rand_bits_gsr = rand_bits_gsr\n",
+ " self.rand_bits_mult = rand_bits_mult\n",
+ " self.s = None\n",
+ " self.r1 = None\n",
+ " self.r2 = None\n",
+ "\n",
+ " def multiply(self, scalar: int) -> Point:\n",
+ " if self.params is None or self.point is None:\n",
+ " raise ValueError(\"Not initialized.\")\n",
+ " with ScalarMultiplicationAction(self.point, self.params, scalar) as action:\n",
+ " order = self.params.order\n",
+ " r1 = Mod.random(1 << self.rand_bits_gsr) if self.r1 is None else self.r1\n",
+ " r2 = Mod.random(1 << self.rand_bits_gsr) if self.r2 is None else self.r2\n",
+ " s = Mod.random(1 << self.rand_bits_mult) if self.s is None else self.s\n",
+ " s_gsr = s+ r2*order \n",
+ " \n",
+ " S = self.mult.multiply(int(s_gsr))\n",
+ " self.mult.init(self.params, S)\n",
+ " \n",
+ " ks_inv = scalar * mod(int(s_gsr), order).inverse()\n",
+ " ks_inv_gsr = int(ks_inv) + int(r1)*order\n",
+ " return action.exit(self.mult.multiply(int(ks_inv_gsr)))\n",
+ " \n",
+ "\n",
+ "@public\n",
+ "class GSR_Mult_3(ScalarMultiplierCountermeasure):\n",
+ " r\"\"\"\n",
+ " GSR with Mult, option 2.\n",
+ " [ks^(-1)][s+r*n]\n",
+ " \"\"\"\n",
+ "\n",
+ " rand_bits: int\n",
+ "\n",
+ " def __init__(self, mult: ScalarMultiplier, rand_bits_gsr: int = 32, rand_bits_mult: int = 32):\n",
+ " \"\"\"\n",
+ " :param mult: The multiplier to use.\n",
+ " :param rand_bits: How many random bits to sample.\n",
+ " \"\"\"\n",
+ " super().__init__(mult)\n",
+ " self.rand_bits_gsr = rand_bits_gsr\n",
+ " self.rand_bits_mult = rand_bits_mult\n",
+ " self.r = None\n",
+ " self.s = None\n",
+ " \n",
+ " def init(self, params: DomainParameters, point: Point):\n",
+ " self.params = params\n",
+ " self.point = point\n",
+ " self.mult.init(\n",
+ " self.params,\n",
+ " self.point,\n",
+ " bits=params.full_order.bit_length() + self.rand_bits_gsr,\n",
+ " )\n",
+ "\n",
+ " def multiply(self, scalar: int) -> Point:\n",
+ " if self.params is None or self.point is None:\n",
+ " raise ValueError(\"Not initialized.\")\n",
+ " with ScalarMultiplicationAction(self.point, self.params, scalar) as action:\n",
+ " order = self.params.order\n",
+ " r = Mod.random(1 << self.rand_bits_gsr) if self.r is None else self.r\n",
+ " s = Mod.random(1 << self.rand_bits_mult) if self.s is None else self.s\n",
+ " s_gsr = s+ r*order \n",
+ " \n",
+ " S = self.mult.multiply(int(s_gsr))\n",
+ " self.mult.init(self.params, S)\n",
+ " \n",
+ " ks_inv = scalar * mod(int(s_gsr), order).inverse()\n",
+ " return action.exit(self.mult.multiply(int(ks_inv)))"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "567cfeb5",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "gm1 = GSR_Mult_1(mult)\n",
+ "gm2 = GSR_Mult_2(mult)\n",
+ "gm3 = GSR_Mult_3(mult)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "14b8e75a",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "test_3n_random_scalar(gm1, 10)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "978d91fe",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "test_3n_random_scalar(gm2, 10)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "4eff0e70",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "test_3n_random_scalar(gm3, 10)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "bbe3335a",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "test_3n_random_scalar_projected(gm1,10)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "d4810b30",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "test_3n_random_scalar_projected(gm2,10)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "0bc389aa",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "test_3n_random_scalar_projected(gm3,10)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "d495728b",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "test_3n_fixed_scalar(gm1,10)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "d6abc08b",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "test_3n_fixed_scalar(gm2,10)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "c9585053",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "test_3n_fixed_scalar(gm3,10)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "d204713a",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "r = Mod.random(32)\n",
+ "gm1 = GSR_Mult_1(mult)\n",
+ "gm1.r = r\n",
+ "gm2 = GSR_Mult_2(mult)\n",
+ "gm2.r = r\n",
+ "gm3 = GSR_Mult_3(mult)\n",
+ "gm3.r = r"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "f588c3a6",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "test_3n_random_scalar_projected(gm1,300)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "5f75f678",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "test_3n_random_scalar_projected(gm2,300)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "ba0b5b0a",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "test_3n_random_scalar_projected(gm3,300)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "7cbf5e3a",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "s = Mod.random(32)\n",
+ "gm1 = GSR_Mult_1(mult)\n",
+ "gm1.s = s\n",
+ "gm2 = GSR_Mult_2(mult)\n",
+ "gm2.s = s\n",
+ "gm3 = GSR_Mult_3(mult)\n",
+ "gm3.s = s"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "2d5e7a7c",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "test_3n_random_scalar_projected(gm1,300)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "08c1dd70",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "test_3n_random_scalar_projected(gm2,300)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "b96efcce",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "test_3n_random_scalar_projected(gm3,300)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "856a3f86",
+ "metadata": {},
+ "source": [
+ "### GSR + Euclid"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "3a525ad2",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "@public\n",
+ "class GSR_Eucl_1(ScalarMultiplierCountermeasure):\n",
+ " r\"\"\"\n",
+ " GSR with Eucl, option 1.\n",
+ " k+rn = k1+k2s\n",
+ " [k1]+[k2][s]\n",
+ " \"\"\"\n",
+ "\n",
+ " add: Optional[AdditionFormula]\n",
+ "\n",
+ " def __init__(self, mult: ScalarMultiplier, rand_bits_gsr: int = 32, add: Optional[AdditionFormula] = None):\n",
+ " \"\"\"\n",
+ " :param mult: The multiplier to use.\n",
+ " :param add: Addition formula to use, if None, the formula from the multiplier is used.\n",
+ " \"\"\"\n",
+ " super().__init__(mult)\n",
+ " self.add = add\n",
+ " self.rand_bits_gsr = rand_bits_gsr\n",
+ " self.r = None\n",
+ " self.s = None\n",
+ "\n",
+ " def init(self, params: DomainParameters, point: Point):\n",
+ " self.params = params\n",
+ " self.point = point\n",
+ " self.mult.init(\n",
+ " self.params,\n",
+ " self.point,\n",
+ " bits=params.full_order.bit_length() + self.rand_bits_gsr,\n",
+ " )\n",
+ " \n",
+ " def multiply(self, scalar: int) -> Point:\n",
+ " if self.params is None or self.point is None:\n",
+ " raise ValueError(\"Not initialized.\")\n",
+ " with ScalarMultiplicationAction(self.point, self.params, scalar) as action:\n",
+ " half_bits = self.params.order.bit_length() // 2\n",
+ " order = self.params.order\n",
+ " r = Mod.random(1 << self.rand_bits_gsr) if self.r is None else self.r\n",
+ " gsr = int(scalar)+int(r)*int(order)\n",
+ " s = Mod.random(1 << half_bits) if self.s is None else self.s\n",
+ " S = self.mult.multiply(int(s))\n",
+ " k1 = gsr % int(s)\n",
+ " k2 = gsr // int(s)\n",
+ " T = self.mult.multiply(k1)\n",
+ " self.mult.init(self.params, S)\n",
+ " R = self.mult.multiply(k2)\n",
+ " if self.add is None:\n",
+ " res = self.mult._add(R, T) # noqa: This is OK.\n",
+ " else:\n",
+ " res = self.add(\n",
+ " self.params.curve.prime, R, T, **self.params.curve.parameters\n",
+ " )[0]\n",
+ " return action.exit(res)\n",
+ " \n",
+ " \n",
+ "@public\n",
+ "class GSR_Eucl_2(ScalarMultiplierCountermeasure):\n",
+ " r\"\"\"\n",
+ " GSR with Eucl, option 2.\n",
+ " k = k1+k2s\n",
+ " [k1]+[k2][s+r*n]\n",
+ " \"\"\"\n",
+ "\n",
+ " add: Optional[AdditionFormula]\n",
+ "\n",
+ " def __init__(self, mult: ScalarMultiplier, rand_bits_gsr: int = 32, add: Optional[AdditionFormula] = None):\n",
+ " \"\"\"\n",
+ " :param mult: The multiplier to use.\n",
+ " :param add: Addition formula to use, if None, the formula from the multiplier is used.\n",
+ " \"\"\"\n",
+ " super().__init__(mult)\n",
+ " self.add = add\n",
+ " self.rand_bits_gsr = rand_bits_gsr\n",
+ " self.r = None\n",
+ " self.s = None\n",
+ " \n",
+ " def init(self, params: DomainParameters, point: Point):\n",
+ " self.params = params\n",
+ " self.point = point\n",
+ " self.mult.init(\n",
+ " self.params,\n",
+ " self.point,\n",
+ " bits=params.full_order.bit_length() + self.rand_bits_gsr,\n",
+ " )\n",
+ "\n",
+ " def multiply(self, scalar: int) -> Point:\n",
+ " if self.params is None or self.point is None:\n",
+ " raise ValueError(\"Not initialized.\")\n",
+ " with ScalarMultiplicationAction(self.point, self.params, scalar) as action:\n",
+ " half_bits = self.params.order.bit_length() // 2\n",
+ " order = self.params.order\n",
+ " r = Mod.random(1 << self.rand_bits_gsr) if self.r is None else self.r\n",
+ " s = Mod.random(1 << half_bits) if self.s is None else self.s\n",
+ " S = self.mult.multiply(int(s)+int(r)*order)\n",
+ " k1 = int(scalar) % int(s)\n",
+ " k2 = int(scalar) // int(s)\n",
+ " T = self.mult.multiply(k1)\n",
+ " self.mult.init(self.params, S)\n",
+ " R = self.mult.multiply(k2)\n",
+ " if self.add is None:\n",
+ " res = self.mult._add(R, T) # noqa: This is OK.\n",
+ " else:\n",
+ " res = self.add(\n",
+ " self.params.curve.prime, R, T, **self.params.curve.parameters\n",
+ " )[0]\n",
+ " return action.exit(res)\n",
+ " \n",
+ "@public\n",
+ "class GSR_Eucl_3(ScalarMultiplierCountermeasure):\n",
+ " r\"\"\"\n",
+ " GSR with Eucl, option 3.\n",
+ " k = k1+k2s\n",
+ " [k1+r1*n]+[k2+r2*n][s]\n",
+ " \"\"\"\n",
+ "\n",
+ " add: Optional[AdditionFormula]\n",
+ "\n",
+ " def __init__(self, mult: ScalarMultiplier, rand_bits_gsr: int = 32, add: Optional[AdditionFormula] = None):\n",
+ " \"\"\"\n",
+ " :param mult: The multiplier to use.\n",
+ " :param add: Addition formula to use, if None, the formula from the multiplier is used.\n",
+ " \"\"\"\n",
+ " super().__init__(mult)\n",
+ " self.add = add\n",
+ " self.rand_bits_gsr = rand_bits_gsr\n",
+ " self.r1 = None\n",
+ " self.r2 = None\n",
+ " self.s = None\n",
+ " \n",
+ " def init(self, params: DomainParameters, point: Point):\n",
+ " self.params = params\n",
+ " self.point = point\n",
+ " self.mult.init(\n",
+ " self.params,\n",
+ " self.point,\n",
+ " bits=params.full_order.bit_length() + self.rand_bits_gsr,\n",
+ " )\n",
+ "\n",
+ " def multiply(self, scalar: int) -> Point:\n",
+ " if self.params is None or self.point is None:\n",
+ " raise ValueError(\"Not initialized.\")\n",
+ " with ScalarMultiplicationAction(self.point, self.params, scalar) as action:\n",
+ " half_bits = self.params.order.bit_length() // 2\n",
+ " order = self.params.order\n",
+ " r1 = Mod.random(1 << self.rand_bits_gsr) if self.r1 is None else self.r1\n",
+ " r2 = Mod.random(1 << self.rand_bits_gsr) if self.r2 is None else self.r2\n",
+ " s = Mod.random(1 << half_bits) if self.s is None else self.s\n",
+ " S = self.mult.multiply(int(s))\n",
+ " k1 = int(scalar) % int(s)\n",
+ " k2 = int(scalar) // int(s)\n",
+ " T = self.mult.multiply(k1+int(r1)*order)\n",
+ " self.mult.init(self.params, S)\n",
+ " R = self.mult.multiply(k2+int(r2)*order)\n",
+ " if self.add is None:\n",
+ " res = self.mult._add(R, T) # noqa: This is OK.\n",
+ " else:\n",
+ " res = self.add(\n",
+ " self.params.curve.prime, R, T, **self.params.curve.parameters\n",
+ " )[0]\n",
+ " return action.exit(res)\n",
+ " \n",
+ "@public\n",
+ "class GSR_Eucl_4(ScalarMultiplierCountermeasure):\n",
+ " r\"\"\"\n",
+ " GSR with Eucl, option 4.\n",
+ " k = k1+k2s\n",
+ " [k1+r1*n]+[k2+r2*n][s+r3*n]\n",
+ " \"\"\"\n",
+ "\n",
+ " add: Optional[AdditionFormula]\n",
+ "\n",
+ " def __init__(self, mult: ScalarMultiplier, rand_bits_gsr: int = 32, add: Optional[AdditionFormula] = None):\n",
+ " \"\"\"\n",
+ " :param mult: The multiplier to use.\n",
+ " :param add: Addition formula to use, if None, the formula from the multiplier is used.\n",
+ " \"\"\"\n",
+ " super().__init__(mult)\n",
+ " self.add = add\n",
+ " self.rand_bits_gsr = rand_bits_gsr\n",
+ " self.r1 = None\n",
+ " self.r2 = None\n",
+ " self.r3 = None\n",
+ " self.s = None\n",
+ " \n",
+ " def init(self, params: DomainParameters, point: Point):\n",
+ " self.params = params\n",
+ " self.point = point\n",
+ " self.mult.init(\n",
+ " self.params,\n",
+ " self.point,\n",
+ " bits=params.full_order.bit_length() + self.rand_bits_gsr,\n",
+ " )\n",
+ "\n",
+ " def multiply(self, scalar: int) -> Point:\n",
+ " if self.params is None or self.point is None:\n",
+ " raise ValueError(\"Not initialized.\")\n",
+ " with ScalarMultiplicationAction(self.point, self.params, scalar) as action:\n",
+ " half_bits = self.params.order.bit_length() // 2\n",
+ " order = self.params.order\n",
+ " r1 = Mod.random(1 << self.rand_bits_gsr) if self.r1 is None else self.r1\n",
+ " r2 = Mod.random(1 << self.rand_bits_gsr) if self.r2 is None else self.r2\n",
+ " r3 = Mod.random(1 << self.rand_bits_gsr) if self.r3 is None else self.r3\n",
+ " s = Mod.random(1 << half_bits) if self.s is None else self.s\n",
+ " S = self.mult.multiply(int(s)+int(r3)*order)\n",
+ " k1 = int(scalar) % int(s)\n",
+ " k2 = int(scalar) // int(s)\n",
+ " T = self.mult.multiply(k1+int(r1)*order)\n",
+ " self.mult.init(self.params, S)\n",
+ " R = self.mult.multiply(k2+int(r2)*order)\n",
+ " if self.add is None:\n",
+ " res = self.mult._add(R, T) # noqa: This is OK.\n",
+ " else:\n",
+ " res = self.add(\n",
+ " self.params.curve.prime, R, T, **self.params.curve.parameters\n",
+ " )[0]\n",
+ " return action.exit(res)\n",
+ " \n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "ac043c0e",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "ge1 = GSR_Eucl_1(mult)\n",
+ "ge2 = GSR_Eucl_2(mult)\n",
+ "ge3 = GSR_Eucl_3(mult)\n",
+ "ge4 = GSR_Eucl_4(mult)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "7089521c",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "test_3n_random_scalar(ge1, 10)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "9b0f74fc",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "test_3n_random_scalar(ge2, 10)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "e2482dbd",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "test_3n_random_scalar(ge3, 10)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "1182264d",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "test_3n_random_scalar(ge4, 10)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "83df90c7",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "test_3n_random_scalar_projected(ge1,10)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "c11fe8ac",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "test_3n_random_scalar_projected(ge2,10)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "e8c93af4",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "test_3n_random_scalar_projected(ge3,1000)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "b1e49379",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "test_3n_random_scalar_projected(ge4,1000)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "f8a19a27",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "test_3n_fixed_scalar(ge1,1000)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "53eab763",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "test_3n_fixed_scalar(ge2,1000)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "b3bf92f9",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "test_3n_fixed_scalar(ge3,1000)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "b630dac1",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "test_3n_fixed_scalar(ge4,1000)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "538e547e",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "half_bits = params3n.order.bit_length() // 2\n",
+ "s = Mod.random(1 << half_bits)\n",
+ "ge1 = GSR_Eucl_1(mult)\n",
+ "ge1.s = s\n",
+ "ge2 = GSR_Eucl_2(mult)\n",
+ "ge2.s = s\n",
+ "ge3 = GSR_Eucl_3(mult)\n",
+ "ge3.s = s\n",
+ "ge4 = GSR_Eucl_4(mult)\n",
+ "ge4.s = s"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "1a513b67",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "test_3n_random_scalar_projected(ge1,1000)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "0bd86e62",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "test_3n_random_scalar_projected(ge2,1000)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "d0106770",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "test_3n_random_scalar_projected(ge3,1000)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "b54b176c",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "test_3n_random_scalar_projected(ge4,1000)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "d7af08bd",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "bits = 32\n",
+ "r1 = Mod.random(1 << bits)\n",
+ "r2 = Mod.random(1 << bits)\n",
+ "r3 = Mod.random(1 << bits)\n",
+ "\n",
+ "ge1 = GSR_Eucl_1(mult)\n",
+ "ge1.r1 = r1\n",
+ "ge1.r2 = r2\n",
+ "ge1.r3 = r3\n",
+ "ge2 = GSR_Eucl_2(mult)\n",
+ "ge2.r1 = r1\n",
+ "ge2.r2 = r2\n",
+ "ge2.r3 = r3\n",
+ "ge3 = GSR_Eucl_3(mult)\n",
+ "ge3.r1 = r1\n",
+ "ge3.r2 = r2\n",
+ "ge3.r3 = r3\n",
+ "ge4 = GSR_Eucl_4(mult)\n",
+ "ge4.r1 = r1\n",
+ "ge4.r2 = r2\n",
+ "ge4.r3 = r3"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "2cbcfb89",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "test_3n_random_scalar_projected(ge1,1000)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "e0f2ba16",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "test_3n_random_scalar_projected(ge2,1000)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "9ddb9c53",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "test_3n_random_scalar_projected(ge3,1000)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "d0d3daed",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "test_3n_random_scalar_projected(ge4,1000)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "a4d14a41",
+ "metadata": {},
+ "source": [
+ "### Add+Mul"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "cc2ea21f",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "@public\n",
+ "class Add_Mul_1(ScalarMultiplierCountermeasure):\n",
+ " r\"\"\"\n",
+ " Add with Mul, option 1.\n",
+ " [(k-r)s1^(-1)][s1]+[rs2^(-1)][s2]\n",
+ " \"\"\"\n",
+ "\n",
+ " add: Optional[AdditionFormula]\n",
+ "\n",
+ " def __init__(self, mult: ScalarMultiplier,rand_bits_mul=32, add: Optional[AdditionFormula] = None):\n",
+ " \"\"\"\n",
+ " :param mult: The multiplier to use.\n",
+ " :param add: Addition formula to use, if None, the formula from the multiplier is used.\n",
+ " \"\"\"\n",
+ " super().__init__(mult)\n",
+ " self.add = add\n",
+ " self.rand_bits_mul = rand_bits_mul\n",
+ " self.r = None\n",
+ " self.s1 = None\n",
+ " self.s2 = None\n",
+ "\n",
+ " def multiply(self, scalar: int) -> Point:\n",
+ " if self.params is None or self.point is None:\n",
+ " raise ValueError(\"Not initialized.\")\n",
+ " with ScalarMultiplicationAction(self.point, self.params, scalar) as action:\n",
+ " order = self.params.order\n",
+ " r = Mod.random(order) if self.r is None else self.r\n",
+ " s1 = Mod.random(1 << self.rand_bits_mul) if self.s1 is None else self.s1\n",
+ " s2 = Mod.random(1 << self.rand_bits_mul) if self.s2 is None else self.s2\n",
+ " kr = scalar - r\n",
+ " \n",
+ " kr_inv = kr * mod(int(s1), order).inverse()\n",
+ " r_inv = r * mod(int(s2), order).inverse()\n",
+ " \n",
+ " R = self.mult.multiply(int(s1))\n",
+ " self.mult.init(self.params, R)\n",
+ " R = self.mult.multiply(int(kr_inv))\n",
+ " \n",
+ " self.mult.init(self.params, self.point)\n",
+ " S = self.mult.multiply(int(s2))\n",
+ " self.mult.init(self.params, S)\n",
+ " S = self.mult.multiply(int(r_inv))\n",
+ " if self.add is None:\n",
+ " res = self.mult._add(R, S) # noqa: This is OK.\n",
+ " else:\n",
+ " res = self.add(\n",
+ " self.params.curve.prime, R, S, **self.params.curve.parameters\n",
+ " )[0]\n",
+ " return action.exit(res)\n",
+ "\n",
+ "@public\n",
+ "class Add_Mul_2(ScalarMultiplierCountermeasure):\n",
+ " r\"\"\"\n",
+ " Add with Mul, option 2.\n",
+ " ([ks^(-1)-r]+[r])[s]\n",
+ " \"\"\"\n",
+ "\n",
+ " add: Optional[AdditionFormula]\n",
+ "\n",
+ " def __init__(self, mult: ScalarMultiplier,rand_bits_mul=32, add: Optional[AdditionFormula] = None):\n",
+ " \"\"\"\n",
+ " :param mult: The multiplier to use.\n",
+ " :param add: Addition formula to use, if None, the formula from the multiplier is used.\n",
+ " \"\"\"\n",
+ " super().__init__(mult)\n",
+ " self.add = add\n",
+ " self.rand_bits_mul = rand_bits_mul\n",
+ " self.r = None\n",
+ " self.s = None\n",
+ "\n",
+ " def multiply(self, scalar: int) -> Point:\n",
+ " if self.params is None or self.point is None:\n",
+ " raise ValueError(\"Not initialized.\")\n",
+ " with ScalarMultiplicationAction(self.point, self.params, scalar) as action:\n",
+ " order = self.params.order\n",
+ " r = Mod.random(order) if self.r is None else self.r\n",
+ " s = Mod.random(1 << self.rand_bits_mul) if self.s is None else self.s\n",
+ " \n",
+ " ks_inv = scalar * mod(int(s), order).inverse()\n",
+ " \n",
+ " S = self.mult.multiply(int(s))\n",
+ " self.mult.init(self.params, S)\n",
+ " \n",
+ " R = self.mult.multiply(int(ks_inv-r))\n",
+ " S = self.mult.multiply(int(r))\n",
+ "\n",
+ " if self.add is None:\n",
+ " res = self.mult._add(R, S) # noqa: This is OK.\n",
+ " else:\n",
+ " res = self.add(\n",
+ " self.params.curve.prime, R, S, **self.params.curve.parameters\n",
+ " )[0]\n",
+ " return action.exit(res)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "626a183b",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "am1 = Add_Mul_1(mult)\n",
+ "am2 = Add_Mul_2(mult)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "f1cb0716",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "test_3n_random_scalar(am1, 10)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "a24caf02",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "test_3n_random_scalar(am2, 1000)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "64e2cc97",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "test_3n_random_scalar_projected(am1, 1000)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "b1b5c2d7",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "test_3n_random_scalar_projected(am2, 1000)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "c4ffd67c",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "test_3n_fixed_scalar(am1,1000)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "29337718",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "test_3n_fixed_scalar(am2,1000)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "82876bb4",
+ "metadata": {},
+ "source": [
+ "### Add + Eucl"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "5ab887c5",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ " \n",
+ "@public\n",
+ "class Add_Eucl_1(ScalarMultiplierCountermeasure):\n",
+ " r\"\"\"\n",
+ " Add with Eucl, option 1.\n",
+ " k-r = k1+k2s1\n",
+ " r = l1+l2s2\n",
+ " [k1]+[k2][s1]+[l1]+[l2][s2]\n",
+ " \"\"\"\n",
+ "\n",
+ " add: Optional[AdditionFormula]\n",
+ "\n",
+ " def __init__(self, mult: ScalarMultiplier, add: Optional[AdditionFormula] = None):\n",
+ " \"\"\"\n",
+ " :param mult: The multiplier to use.\n",
+ " :param add: Addition formula to use, if None, the formula from the multiplier is used.\n",
+ " \"\"\"\n",
+ " super().__init__(mult)\n",
+ " self.add = add\n",
+ " self.r = None\n",
+ " self.s1 = None\n",
+ " self.s2 = None\n",
+ "\n",
+ " def multiply(self, scalar: int) -> Point:\n",
+ " if self.params is None or self.point is None:\n",
+ " raise ValueError(\"Not initialized.\")\n",
+ " with ScalarMultiplicationAction(self.point, self.params, scalar) as action:\n",
+ " half_bits = self.params.order.bit_length() // 2\n",
+ " order = self.params.order\n",
+ " r = Mod.random(order) if self.r is None else self.r\n",
+ " s1 = Mod.random(1 << half_bits) if self.s1 is None else self.s1\n",
+ " s2 = Mod.random(1 << half_bits) if self.s2 is None else self.s2\n",
+ " k_r = int(scalar-r)\n",
+ " k1 = k_r % int(s1)\n",
+ " k2 = k_r // int(s1)\n",
+ " \n",
+ " l1 = int(r) % int(s2)\n",
+ " l2 = int(r) // int(s2)\n",
+ " \n",
+ " \n",
+ " S1 = self.mult.multiply(int(s1))\n",
+ " S2 = self.mult.multiply(int(s2))\n",
+ " K1 = self.mult.multiply(int(k1))\n",
+ " L1 = self.mult.multiply(int(l1))\n",
+ " \n",
+ " self.mult.init(self.params, S1)\n",
+ " K2 = self.mult.multiply(int(k2))\n",
+ " self.mult.init(self.params, S2)\n",
+ " L2 = self.mult.multiply(int(l2))\n",
+ " \n",
+ " if self.add is None:\n",
+ " res = self.mult._add(K1, K2)\n",
+ " res = self.mult._add(res, L1)\n",
+ " res = self.mult._add(res, L2)\n",
+ " else:\n",
+ " res = self.add(\n",
+ " self.params.curve.prime, K1, K2, **self.params.curve.parameters\n",
+ " )[0]\n",
+ " res = self.add(\n",
+ " self.params.curve.prime, res, L1, **self.params.curve.parameters\n",
+ " )[0]\n",
+ " res = self.add(\n",
+ " self.params.curve.prime, res, L2, **self.params.curve.parameters\n",
+ " )[0]\n",
+ " return action.exit(res)\n",
+ " \n",
+ "\n",
+ " \n",
+ "@public\n",
+ "class Add_Eucl_2(ScalarMultiplierCountermeasure):\n",
+ " r\"\"\"\n",
+ " Add with Eucl, option 2.\n",
+ " k = k1+k2s\n",
+ " [k1-r1]+[r1]+([k2-r2]+[r2])[s]\n",
+ " \"\"\"\n",
+ "\n",
+ " add: Optional[AdditionFormula]\n",
+ "\n",
+ " def __init__(self, mult: ScalarMultiplier, add: Optional[AdditionFormula] = None):\n",
+ " \"\"\"\n",
+ " :param mult: The multiplier to use.\n",
+ " :param add: Addition formula to use, if None, the formula from the multiplier is used.\n",
+ " \"\"\"\n",
+ " super().__init__(mult)\n",
+ " self.add = add\n",
+ " self.r1 = None\n",
+ " self.r2 = None\n",
+ " self.s = None\n",
+ "\n",
+ " def multiply(self, scalar: int) -> Point:\n",
+ " if self.params is None or self.point is None:\n",
+ " raise ValueError(\"Not initialized.\")\n",
+ " with ScalarMultiplicationAction(self.point, self.params, scalar) as action:\n",
+ " half_bits = self.params.order.bit_length() // 2\n",
+ " order = self.params.order\n",
+ " r1 = Mod.random(order) if self.r1 is None else self.r1\n",
+ " r2 = Mod.random(order) if self.r2 is None else self.r2\n",
+ " s = Mod.random(1 << half_bits) if self.s is None else self.s\n",
+ " k1 = int(scalar) % int(s)\n",
+ " k2 = int(scalar) // int(s)\n",
+ " k1r1 = k1-r1\n",
+ " k2r2 = k2-r2\n",
+ " \n",
+ " \n",
+ " S = self.mult.multiply(int(s))\n",
+ " KR1 = self.mult.multiply(int(k1r1))\n",
+ " R1 = self.mult.multiply(int(r1))\n",
+ " \n",
+ " self.mult.init(self.params, S)\n",
+ " KR2 = self.mult.multiply(int(k2r2))\n",
+ " R2 = self.mult.multiply(int(r2))\n",
+ " \n",
+ " if self.add is None:\n",
+ " res = self.mult._add(KR1, R1)\n",
+ " res = self.mult._add(res, KR2)\n",
+ " res = self.mult._add(res, R2)\n",
+ " else:\n",
+ " res = self.add(\n",
+ " self.params.curve.prime, KR1, R1, **self.params.curve.parameters\n",
+ " )[0]\n",
+ " res = self.add(\n",
+ " self.params.curve.prime, res, KR2, **self.params.curve.parameters\n",
+ " )[0]\n",
+ " res = self.add(\n",
+ " self.params.curve.prime, res, R2, **self.params.curve.parameters\n",
+ " )[0]\n",
+ " return action.exit(res)\n",
+ " \n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "e70576c6",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "ae1 = Add_Eucl_1(mult)\n",
+ "ae2 = Add_Eucl_2(mult)\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "c2baaaef",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "test_3n_random_scalar(ae1, 10)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "8eae89c8",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "test_3n_random_scalar(ae2, 1000)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "e95c8c39",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "test_3n_random_scalar_projected(ae1, 1000)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "2d619d4f",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "test_3n_random_scalar_projected(ae2, 1000)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "a827e3fd",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "test_3n_fixed_scalar(ae1,1000)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "da2bcb55",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "test_3n_fixed_scalar(ae2,1000)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "3afaaa43",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ " \n",
+ "@public\n",
+ "class Mul_Eucl_1(ScalarMultiplierCountermeasure):\n",
+ " r\"\"\"\n",
+ " Mul with Eucl, option 1.\n",
+ " kr^(-1) = k1+k2s\n",
+ " ([k1]+[k2][s])[r]\n",
+ " \"\"\"\n",
+ "\n",
+ " add: Optional[AdditionFormula]\n",
+ "\n",
+ " def __init__(self, mult: ScalarMultiplier,rand_bits_mul=32, add: Optional[AdditionFormula] = None):\n",
+ " \"\"\"\n",
+ " :param mult: The multiplier to use.\n",
+ " :param add: Addition formula to use, if None, the formula from the multiplier is used.\n",
+ " \"\"\"\n",
+ " super().__init__(mult)\n",
+ " self.add = add\n",
+ " self.rand_bits_mul = rand_bits_mul\n",
+ " self.r = None\n",
+ " self.s = None\n",
+ "\n",
+ " def multiply(self, scalar: int) -> Point:\n",
+ " if self.params is None or self.point is None:\n",
+ " raise ValueError(\"Not initialized.\")\n",
+ " with ScalarMultiplicationAction(self.point, self.params, scalar) as action:\n",
+ " half_bits = self.params.order.bit_length() // 2\n",
+ " order = self.params.order\n",
+ " s = Mod.random(order) if self.s is None else self.s\n",
+ " r = Mod.random(1 << self.rand_bits_mul) if self.r is None else self.r\n",
+ " \n",
+ " kr_inv = scalar * mod(int(r), order).inverse()\n",
+ " \n",
+ " k1 = int(kr_inv) % int(s)\n",
+ " k2 = int(kr_inv) // int(s)\n",
+ " \n",
+ " R = self.mult.multiply(int(r))\n",
+ " self.mult.init(self.params, R)\n",
+ " \n",
+ " K1 = self.mult.multiply(int(k1))\n",
+ " \n",
+ " S = self.mult.multiply(int(s))\n",
+ " self.mult.init(self.params, S)\n",
+ " K2 = self.mult.multiply(int(k2))\n",
+ " \n",
+ " if self.add is None:\n",
+ " res = self.mult._add(K1, K2)\n",
+ " else:\n",
+ " res = self.add(\n",
+ " self.params.curve.prime, K1, K2, **self.params.curve.parameters\n",
+ " )[0]\n",
+ " return action.exit(res)\n",
+ " \n",
+ "\n",
+ " \n",
+ "@public\n",
+ "class Mul_Eucl_2(ScalarMultiplierCountermeasure):\n",
+ " r\"\"\"\n",
+ " Mul with Eucl, option 2.\n",
+ " [k1r1^(-1)][r1]+[k2r2^(-1)][r2][s]\n",
+ " \"\"\"\n",
+ "\n",
+ " add: Optional[AdditionFormula]\n",
+ "\n",
+ " def __init__(self, mult: ScalarMultiplier,rand_bits_mul=32, add: Optional[AdditionFormula] = None):\n",
+ " \"\"\"\n",
+ " :param mult: The multiplier to use.\n",
+ " :param add: Addition formula to use, if None, the formula from the multiplier is used.\n",
+ " \"\"\"\n",
+ " super().__init__(mult)\n",
+ " self.add = add\n",
+ " self.rand_bits_mul = rand_bits_mul\n",
+ " self.s = None\n",
+ " self.r1 = None\n",
+ " self.r2 = None\n",
+ "\n",
+ " def multiply(self, scalar: int) -> Point:\n",
+ " if self.params is None or self.point is None:\n",
+ " raise ValueError(\"Not initialized.\")\n",
+ " with ScalarMultiplicationAction(self.point, self.params, scalar) as action:\n",
+ " half_bits = self.params.order.bit_length() // 2\n",
+ " order = self.params.order\n",
+ " s = Mod.random(order) if self.s is None else self.s\n",
+ " \n",
+ " r1 = Mod.random(1 << self.rand_bits_mul) if self.r1 is None else self.r1\n",
+ " r2 = Mod.random(1 << self.rand_bits_mul) if self.r2 is None else self.r2\n",
+ " \n",
+ " k1 = int(scalar) % int(s)\n",
+ " k2 = int(scalar) // int(s)\n",
+ " \n",
+ " kr1_inv = k1 * mod(int(r1), order).inverse()\n",
+ " kr2_inv = k2 * mod(int(r2), order).inverse()\n",
+ " \n",
+ " R1 = self.mult.multiply(int(r1))\n",
+ " S = self.mult.multiply(int(s))\n",
+ " \n",
+ " self.mult.init(self.params, R1)\n",
+ " R1 = self.mult.multiply(int(kr1_inv))\n",
+ " \n",
+ " self.mult.init(self.params, S)\n",
+ " R2 = self.mult.multiply(int(r2))\n",
+ " \n",
+ " self.mult.init(self.params, R2)\n",
+ " R2 = self.mult.multiply(int(kr2_inv))\n",
+ " \n",
+ " \n",
+ " if self.add is None:\n",
+ " res = self.mult._add(R1, R2)\n",
+ " else:\n",
+ " res = self.add(\n",
+ " self.params.curve.prime, R1, R2, **self.params.curve.parameters\n",
+ " )[0]\n",
+ " return action.exit(res)\n",
+ " \n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "39c6abd4",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "me1 = Mul_Eucl_1(mult)\n",
+ "me2 = Mul_Eucl_2(mult)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "dd85d5e2",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "test_3n_random_scalar(me1, 10)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "228ad9c3",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "test_3n_random_scalar(me2, 1000)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "3ff4c1e6",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "test_3n_random_scalar_projected(me1, 1000)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "e0b3fe67",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "test_3n_random_scalar_projected(me2, 1000)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "34ad9676",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "test_3n_fixed_scalar(me1,1000)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "b7f69ff0",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "test_3n_fixed_scalar(me2,1000)"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "env",
+ "language": "python",
+ "name": "env"
+ },
+ "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
+}