aboutsummaryrefslogtreecommitdiffhomepage
path: root/test/test_impl.py
diff options
context:
space:
mode:
Diffstat (limited to 'test/test_impl.py')
-rw-r--r--test/test_impl.py583
1 files changed, 310 insertions, 273 deletions
diff --git a/test/test_impl.py b/test/test_impl.py
index 6c58315..da42c33 100644
--- a/test/test_impl.py
+++ b/test/test_impl.py
@@ -1,318 +1,355 @@
from copy import copy
from os.path import join
import pytest
+from click.testing import CliRunner
from pyecsca.ec.key_agreement import ECDH_SHA1
+from pyecsca.ec.mod import Mod
from pyecsca.ec.mult import (
LTRMultiplier,
RTLMultiplier,
CoronMultiplier,
BinaryNAFMultiplier,
+ WindowNAFMultiplier,
+ SlidingWindowMultiplier,
+ AccumulationOrder,
+ ProcessingDirection,
+ ScalarMultiplier,
+ FixedWindowLTRMultiplier,
+ FullPrecompMultiplier,
+ BGMWMultiplier,
+ CombMultiplier,
)
from pyecsca.ec.signature import ECDSA_SHA1, SignatureResult
from pyecsca.codegen.builder import build_impl
-from pyecsca.codegen.client import HostTarget
+from pyecsca.codegen.client import HostTarget, ImplTarget
-def do_basic_test(
- callback,
- runner,
- params,
- mult_class,
- formulas,
- mult_name,
- ecdsa,
- ecdh,
- **mult_kwargs,
-):
- other_args = [
- ("--mul", "KARATSUBA", "--sqr", "KARATSUBA"),
- ("--mul", "TOOM_COOK", "--sqr", "TOOM_COOK"),
- ("--red", "BARRETT"),
- ("--red", "MONTGOMERY"),
- ]
- for additional in other_args:
- with runner.isolated_filesystem() as tmpdir:
- runner.invoke(
- build_impl,
- [
- "--platform",
- "HOST",
- *additional,
- "--ecdsa" if ecdsa else "--no-ecdsa",
- "--ecdh" if ecdh else "--no-ecdh",
- params.curve.model.shortname,
- params.curve.coordinate_model.name,
- *formulas,
- f"{mult_name}({','.join(f'{key}={value}' for key, value in mult_kwargs.items())})",
- ".",
- ],
- )
- target = HostTarget(
- params.curve.model,
- params.curve.coordinate_model,
- binary=join(tmpdir, "pyecsca-codegen-HOST.elf"),
- )
- target.connect()
- target.set_params(params)
- formula_instances = [
- params.curve.coordinate_model.formulas[formula] for formula in formulas
- ]
- mult = mult_class(*formula_instances, **mult_kwargs)
- mult.init(params, params.generator)
- callback(target, mult, params)
- target.disconnect()
-
+@pytest.fixture(
+ scope="module",
+ params=[
+ pytest.param(("--mul", "KARATSUBA", "--sqr", "KARATSUBA"), id="Karatsuba"),
+ pytest.param(("--mul", "TOOM_COOK", "--sqr", "TOOM_COOK"), id="ToomCook"),
+ pytest.param(("--red", "BARRETT"), id="Barrett"),
+ pytest.param(("--red", "MONTGOMERY"), id="Montgomery"),
+ ],
+)
+def additional(request):
+ return request.param
-def test_init(cli_runner, secp128r1):
- def callback(target, mult, params):
- target.init_prng(bytes([0x12, 0x34, 0x56, 0x78]))
- do_basic_test(
- callback,
- cli_runner,
- secp128r1,
- LTRMultiplier,
- ["add-1998-cmo", "dbl-1998-cmo"],
- "ltr",
- False,
- False,
- )
+@pytest.fixture(
+ scope="module",
+ params=[
+ pytest.param(
+ (
+ LTRMultiplier,
+ "ltr",
+ ["add-1998-cmo", "dbl-1998-cmo"],
+ {"complete": False},
+ ),
+ id="LTR1",
+ ),
+ pytest.param(
+ (
+ LTRMultiplier,
+ "ltr",
+ ["add-1998-cmo", "dbl-1998-cmo"],
+ {"complete": True},
+ ),
+ id="LTR2",
+ ),
+ pytest.param(
+ (
+ LTRMultiplier,
+ "ltr",
+ ["add-1998-cmo", "dbl-1998-cmo"],
+ {"complete": False, "always": True},
+ ),
+ id="LTR3",
+ ),
+ pytest.param(
+ (
+ LTRMultiplier,
+ "ltr",
+ ["add-1998-cmo", "dbl-1998-cmo"],
+ {"complete": True, "always": True},
+ ),
+ id="LTR4",
+ ),
+ pytest.param(
+ (
+ LTRMultiplier,
+ "ltr",
+ ["add-1998-cmo", "dbl-1998-cmo"],
+ {"complete": False, "accumulation_order": AccumulationOrder.PeqRP},
+ ),
+ id="LTR5",
+ ),
+ pytest.param(
+ (RTLMultiplier, "rtl", ["add-1998-cmo", "dbl-1998-cmo"], {"always": False}),
+ id="RTL1",
+ ),
+ pytest.param(
+ (RTLMultiplier, "rtl", ["add-1998-cmo", "dbl-1998-cmo"], {"always": True}),
+ id="RTL2",
+ ),
+ pytest.param(
+ (CoronMultiplier, "coron", ["add-1998-cmo", "dbl-1998-cmo"], {}), id="Coron"
+ ),
+ pytest.param(
+ (
+ BinaryNAFMultiplier,
+ "bnaf",
+ ["add-1998-cmo", "dbl-1998-cmo", "neg"],
+ {"direction": ProcessingDirection.LTR},
+ ),
+ id="BNAF1",
+ ),
+ pytest.param(
+ (
+ BinaryNAFMultiplier,
+ "bnaf",
+ ["add-1998-cmo", "dbl-1998-cmo", "neg"],
+ {"direction": ProcessingDirection.RTL},
+ ),
+ id="BNAF2",
+ ),
+ pytest.param(
+ (
+ WindowNAFMultiplier,
+ "wnaf",
+ ["add-1998-cmo", "dbl-1998-cmo", "neg"],
+ {"width": 3},
+ ),
+ id="WNAF1",
+ ),
+ pytest.param(
+ (
+ WindowNAFMultiplier,
+ "wnaf",
+ ["add-1998-cmo", "dbl-1998-cmo", "neg"],
+ {"width": 3, "precompute_negation": True},
+ ),
+ id="WNAF2",
+ ),
+ pytest.param(
+ (
+ SlidingWindowMultiplier,
+ "sliding",
+ ["add-1998-cmo", "dbl-1998-cmo"],
+ {"width": 3},
+ ),
+ id="SLI1",
+ ),
+ pytest.param(
+ (
+ SlidingWindowMultiplier,
+ "sliding",
+ ["add-1998-cmo", "dbl-1998-cmo"],
+ {"width": 3, "recoding_direction": ProcessingDirection.RTL},
+ ),
+ id="SLI2",
+ ),
+ pytest.param(
+ (
+ FixedWindowLTRMultiplier,
+ "fixed",
+ ["add-1998-cmo", "dbl-1998-cmo"],
+ {"m": 4},
+ ),
+ id="FIX1",
+ ),
+ pytest.param(
+ (
+ FixedWindowLTRMultiplier,
+ "fixed",
+ ["add-1998-cmo", "dbl-1998-cmo"],
+ {"m": 5},
+ ),
+ id="FIX2",
+ ),
+ pytest.param(
+ (
+ FullPrecompMultiplier,
+ "precomp",
+ ["add-1998-cmo", "dbl-1998-cmo"],
+ {"direction": ProcessingDirection.LTR},
+ ),
+ id="PRE1",
+ ),
+ pytest.param(
+ (
+ FullPrecompMultiplier,
+ "precomp",
+ ["add-1998-cmo", "dbl-1998-cmo"],
+ {"direction": ProcessingDirection.RTL},
+ ),
+ id="PRE2",
+ ),
+ pytest.param(
+ (
+ BGMWMultiplier,
+ "bgmw",
+ ["add-1998-cmo", "dbl-1998-cmo"],
+ {"width": 3, "direction": ProcessingDirection.LTR},
+ ),
+ id="BGMW1",
+ ),
+ pytest.param(
+ (
+ BGMWMultiplier,
+ "bgmw",
+ ["add-1998-cmo", "dbl-1998-cmo"],
+ {"width": 5, "direction": ProcessingDirection.RTL},
+ ),
+ id="BGMW2",
+ ),
+ pytest.param(
+ (
+ CombMultiplier,
+ "comb",
+ ["add-1998-cmo", "dbl-1998-cmo"],
+ {"width": 3},
+ ),
+ id="Comb1",
+ ),
+ pytest.param(
+ (
+ CombMultiplier,
+ "comb",
+ ["add-1998-cmo", "dbl-1998-cmo"],
+ {"width": 5},
+ ),
+ id="Comb2",
+ ),
+ ],
+)
+def target(request, additional, secp128r1) -> ImplTarget:
+ mult_class, mult_name, formulas, mult_kwargs = request.param
+ runner = CliRunner()
+ with runner.isolated_filesystem() as tmpdir:
+ res = runner.invoke(
+ build_impl,
+ [
+ "--platform",
+ "HOST",
+ *additional,
+ "--ecdsa",
+ "--ecdh",
+ secp128r1.curve.model.shortname,
+ secp128r1.curve.coordinate_model.name,
+ *formulas,
+ f"{mult_name}({','.join(f'{key}={value}' for key, value in mult_kwargs.items())})",
+ ".",
+ ],
+ env={
+ "CFLAGS": "-fsanitize=address -fsanitize=undefined -fno-sanitize-recover=all"
+ },
+ )
+ assert res.exit_code == 0
+ target = HostTarget(
+ secp128r1.curve.model,
+ secp128r1.curve.coordinate_model,
+ binary=join(tmpdir, "pyecsca-codegen-HOST.elf"),
+ )
+ formula_instances = [
+ secp128r1.curve.coordinate_model.formulas[formula] for formula in formulas
+ ]
+ mult = mult_class(*formula_instances, **mult_kwargs)
+ target.mult = mult
+ yield target
-def test_setup(cli_runner, secp128r1):
- def callback(target, mult, params):
- priv = 57
- pub = mult.multiply(priv).to_affine()
- target.set_privkey(priv)
- target.set_pubkey(pub)
+@pytest.fixture(scope="module")
+def mult(target) -> ScalarMultiplier:
+ return target.mult # noqa
- do_basic_test(
- callback,
- cli_runner,
- secp128r1,
- LTRMultiplier,
- ["add-1998-cmo", "dbl-1998-cmo"],
- "ltr",
- False,
- False,
- )
+def test_init(target):
+ target.connect()
+ target.init_prng(bytes([0x12, 0x34, 0x56, 0x78]))
+ target.disconnect()
-def test_debug(cli_runner, secp128r1):
- def callback(target, mult, params):
- model, coords = target.debug()
- assert model == params.curve.model.shortname
- assert coords == params.curve.coordinate_model.name
- do_basic_test(
- callback,
- cli_runner,
- secp128r1,
- LTRMultiplier,
- ["add-1998-cmo", "dbl-1998-cmo"],
- "ltr",
- False,
- False,
- )
+def test_setup(target, mult, secp128r1):
+ priv = 57
+ mult.init(secp128r1, secp128r1.generator)
+ pub = mult.multiply(priv).to_affine()
+ target.connect()
+ target.set_privkey(priv)
+ target.set_pubkey(pub)
+ target.disconnect()
-@pytest.mark.parametrize(
- "mult_class,mult_name,formulas,mult_kwargs",
- [
- (LTRMultiplier, "ltr", ["add-1998-cmo", "dbl-1998-cmo"], {"complete": False}),
- (LTRMultiplier, "ltr", ["add-1998-cmo", "dbl-1998-cmo"], {"complete": True}),
- (
- LTRMultiplier,
- "ltr",
- ["add-1998-cmo", "dbl-1998-cmo"],
- {"complete": False, "always": True},
- ),
- (
- LTRMultiplier,
- "ltr",
- ["add-1998-cmo", "dbl-1998-cmo"],
- {"complete": True, "always": True},
- ),
- (RTLMultiplier, "rtl", ["add-1998-cmo", "dbl-1998-cmo"], {"always": False}),
- (RTLMultiplier, "rtl", ["add-1998-cmo", "dbl-1998-cmo"], {"always": True}),
- (CoronMultiplier, "coron", ["add-1998-cmo", "dbl-1998-cmo"], {}),
- (BinaryNAFMultiplier, "bnaf", ["add-1998-cmo", "dbl-1998-cmo", "neg"], {}),
- ],
-)
-def test_keygen(mult_class, mult_name, mult_kwargs, formulas, cli_runner, secp128r1):
- def callback(target, mult, params):
- for _ in range(10):
- priv, pub = target.generate()
- assert params.curve.is_on_curve(pub)
- expected = mult.multiply(priv).to_affine()
- assert pub == expected
+def test_debug(target, secp128r1):
+ target.connect()
+ model, coords = target.debug()
+ assert model == secp128r1.curve.model.shortname
+ assert coords == secp128r1.curve.coordinate_model.name
+ target.disconnect()
- do_basic_test(
- callback,
- cli_runner,
- secp128r1,
- mult_class,
- formulas,
- mult_name,
- False,
- False,
- **mult_kwargs,
- )
- # def test_ladder(self):
- # runner = CliRunner()
- # self.do_keygen_test(runner, self.curve25519, LadderMultiplier, ["ladd-1987-m", "dbl-1987-m"], "ldr")
- # # TODO: what about coords where generator is not affine?
+def test_keygen(target, mult, secp128r1):
+ target.connect()
+ target.set_params(secp128r1)
+ mult.init(secp128r1, secp128r1.generator)
+ for _ in range(10):
+ priv, pub = target.generate()
+ assert secp128r1.curve.is_on_curve(pub)
+ expected = mult.multiply(priv).to_affine()
+ assert pub == expected
+ target.disconnect()
-@pytest.mark.parametrize(
- "mult_class,mult_name,formulas,mult_kwargs",
- [
- (LTRMultiplier, "ltr", ["add-1998-cmo", "dbl-1998-cmo"], {"complete": False}),
- (LTRMultiplier, "ltr", ["add-1998-cmo", "dbl-1998-cmo"], {"complete": True}),
- (
- LTRMultiplier,
- "ltr",
- ["add-1998-cmo", "dbl-1998-cmo"],
- {"complete": False, "always": True},
- ),
- (
- LTRMultiplier,
- "ltr",
- ["add-1998-cmo", "dbl-1998-cmo"],
- {"complete": True, "always": True},
- ),
- (RTLMultiplier, "rtl", ["add-1998-cmo", "dbl-1998-cmo"], {"always": False}),
- (RTLMultiplier, "rtl", ["add-1998-cmo", "dbl-1998-cmo"], {"always": True}),
- (CoronMultiplier, "coron", ["add-1998-cmo", "dbl-1998-cmo"], {}),
- (BinaryNAFMultiplier, "bnaf", ["add-1998-cmo", "dbl-1998-cmo", "neg"], {}),
- ],
-)
-def test_scalarmult(
- mult_class, mult_name, mult_kwargs, formulas, cli_runner, secp128r1
-):
+def test_scalarmult(target, mult, secp128r1):
+ target.connect()
+ target.set_params(secp128r1)
+ mult.init(secp128r1, secp128r1.generator)
values = [15, 2355498743, 3253857901321912443757746]
+ for value in values:
+ result = target.scalar_mult(value, target.params.generator)
+ expected = mult.multiply(value)
+ assert result == expected
+ target.disconnect()
- def callback(target, mult, params):
- for value in values:
- result = target.scalar_mult(value, params.generator)
- expected = mult.multiply(value)
- assert result == expected
-
- do_basic_test(
- callback,
- cli_runner,
- secp128r1,
- mult_class,
- formulas,
- mult_name,
- False,
- False,
- **mult_kwargs,
- )
-
-@pytest.mark.parametrize(
- "mult_class,mult_name,formulas,mult_kwargs",
- [
- (LTRMultiplier, "ltr", ["add-1998-cmo", "dbl-1998-cmo"], {"complete": False}),
- (LTRMultiplier, "ltr", ["add-1998-cmo", "dbl-1998-cmo"], {"complete": True}),
- (
- LTRMultiplier,
- "ltr",
- ["add-1998-cmo", "dbl-1998-cmo"],
- {"complete": False, "always": True},
- ),
- (
- LTRMultiplier,
- "ltr",
- ["add-1998-cmo", "dbl-1998-cmo"],
- {"complete": True, "always": True},
- ),
- (RTLMultiplier, "rtl", ["add-1998-cmo", "dbl-1998-cmo"], {"always": False}),
- (RTLMultiplier, "rtl", ["add-1998-cmo", "dbl-1998-cmo"], {"always": True}),
- (CoronMultiplier, "coron", ["add-1998-cmo", "dbl-1998-cmo"], {}),
- (BinaryNAFMultiplier, "bnaf", ["add-1998-cmo", "dbl-1998-cmo", "neg"], {}),
- ],
-)
-def test_ecdh(mult_class, mult_name, mult_kwargs, formulas, cli_runner, secp128r1):
+def test_ecdh(target, mult, secp128r1):
+ target.connect()
+ target.set_params(secp128r1)
+ mult.init(secp128r1, secp128r1.generator)
other_privs = [15, 2355498743, 3253857901321912443757746]
-
- def callback(target, mult, params):
- for other_priv in other_privs:
- priv, pub = target.generate()
- other_pub = mult.multiply(other_priv)
- ecdh = ECDH_SHA1(copy(mult), params, other_pub, priv)
- result = target.ecdh(other_pub)
- expected = ecdh.perform()
- assert result == expected
-
- do_basic_test(
- callback,
- cli_runner,
- secp128r1,
- mult_class,
- formulas,
- mult_name,
- False,
- True,
- **mult_kwargs,
- )
+ for other_priv in other_privs:
+ priv, pub = target.generate()
+ other_pub = mult.multiply(other_priv)
+ ecdh = ECDH_SHA1(copy(mult), secp128r1, other_pub, Mod(priv, secp128r1.order))
+ result = target.ecdh(other_pub)
+ expected = ecdh.perform()
+ assert result == expected
+ target.disconnect()
-@pytest.mark.parametrize(
- "mult_class,mult_name,formulas,mult_kwargs",
- [
- (LTRMultiplier, "ltr", ["add-1998-cmo", "dbl-1998-cmo"], {"complete": False}),
- (LTRMultiplier, "ltr", ["add-1998-cmo", "dbl-1998-cmo"], {"complete": True}),
- (
- LTRMultiplier,
- "ltr",
- ["add-1998-cmo", "dbl-1998-cmo"],
- {"complete": False, "always": True},
- ),
- (
- LTRMultiplier,
- "ltr",
- ["add-1998-cmo", "dbl-1998-cmo"],
- {"complete": True, "always": True},
- ),
- (RTLMultiplier, "rtl", ["add-1998-cmo", "dbl-1998-cmo"], {"always": False}),
- (RTLMultiplier, "rtl", ["add-1998-cmo", "dbl-1998-cmo"], {"always": True}),
- (CoronMultiplier, "coron", ["add-1998-cmo", "dbl-1998-cmo"], {}),
- (BinaryNAFMultiplier, "bnaf", ["add-1998-cmo", "dbl-1998-cmo", "neg"], {}),
- ],
-)
-def test_ecdsa(mult_class, mult_name, mult_kwargs, formulas, cli_runner, secp128r1):
- data = b"something"
+def test_ecdsa(target, mult, secp128r1):
+ target.connect()
+ target.set_params(secp128r1)
+ mult.init(secp128r1, secp128r1.generator)
- def callback(target, mult, params):
+ messages = [b"something", b"something quite a bit longer than the hash thing"]
+ for message in messages:
priv, pub = target.generate()
ecdsa = ECDSA_SHA1(
copy(mult),
- params,
+ secp128r1,
mult.formulas["add"],
- pub.to_model(params.curve.coordinate_model, params.curve),
- priv,
+ pub.to_model(secp128r1.curve.coordinate_model, secp128r1.curve),
+ Mod(priv, secp128r1.order),
)
- signature_data = target.ecdsa_sign(data)
+ signature_data = target.ecdsa_sign(message)
result = SignatureResult.from_DER(signature_data)
- assert ecdsa.verify_data(result, data)
-
- expected = ecdsa.sign_data(data).to_DER()
- assert target.ecdsa_verify(data, expected)
+ assert ecdsa.verify_data(result, message)
- do_basic_test(
- callback,
- cli_runner,
- secp128r1,
- mult_class,
- formulas,
- mult_name,
- True,
- False,
- **mult_kwargs,
- )
+ expected = ecdsa.sign_data(message).to_DER()
+ assert target.ecdsa_verify(message, expected)
+ target.disconnect()