diff options
| author | Ján Jančár | 2023-10-08 21:12:06 +0200 |
|---|---|---|
| committer | GitHub | 2023-10-08 21:12:06 +0200 |
| commit | ffbaa1ae62095eb644eda67571aa8845aa6fb09d (patch) | |
| tree | dfdfbf9a12acd1662cba56b46b30d8337ae81918 /test | |
| parent | 9c6acdd2409c49c2ae64a8c41df315a1eca3eea7 (diff) | |
| parent | 1c2e383d8e8df323b4cebb302869fc15599961a0 (diff) | |
| download | pyecsca-codegen-ffbaa1ae62095eb644eda67571aa8845aa6fb09d.tar.gz pyecsca-codegen-ffbaa1ae62095eb644eda67571aa8845aa6fb09d.tar.zst pyecsca-codegen-ffbaa1ae62095eb644eda67571aa8845aa6fb09d.zip | |
Merge pull request #4 from J08nY/feat/more-mults
More scalar multipliers
Diffstat (limited to 'test')
| -rw-r--r-- | test/Makefile | 3 | ||||
| -rw-r--r-- | test/test_bn.c | 91 | ||||
| -rw-r--r-- | test/test_impl.py | 583 | ||||
| -rw-r--r-- | test/test_simulator.py | 6 |
4 files changed, 410 insertions, 273 deletions
diff --git a/test/Makefile b/test/Makefile new file mode 100644 index 0000000..d13b487 --- /dev/null +++ b/test/Makefile @@ -0,0 +1,3 @@ + +test_bn: test_bn.c ../pyecsca/codegen/bn/bn.c + gcc -o $@ $^ -fsanitize=address -fsanitize=undefined -I ../pyecsca/codegen/ -I ../pyecsca/codegen/tommath/ -L ../pyecsca/codegen/tommath/ -l:libtommath-HOST.a
\ No newline at end of file diff --git a/test/test_bn.c b/test/test_bn.c new file mode 100644 index 0000000..66de22f --- /dev/null +++ b/test/test_bn.c @@ -0,0 +1,91 @@ +#include <stdio.h> +#include <stdlib.h> +#include "bn/bn.h" + +int test_wsliding_ltr() { + printf("test_wsliding_ltr: "); + bn_t bn; + bn_init(&bn); + bn_from_int(181, &bn); + wsliding_t *ws = bn_wsliding_ltr(&bn, 3); + if (ws == NULL) { + printf("NULL\n"); + return 1; + } + if (ws->length != 6) { + printf("Bad length (%li instead of 6)\n", ws->length); + return 1; + } + uint8_t expected[6] = {5, 0, 0, 5, 0, 1}; + for (int i = 0; i < 6; i++) { + if (ws->data[i] != expected[i]) { + printf("Bad data (%i instead of %i)\n", ws->data[i], expected[i]); + return 1; + } + } + printf("OK\n"); + bn_clear(&bn); + free(ws->data); + free(ws); + return 0; +} + +int test_wsliding_rtl() { + printf("test_wsliding_rtl: "); + bn_t bn; + bn_init(&bn); + bn_from_int(181, &bn); + wsliding_t *ws = bn_wsliding_rtl(&bn, 3); + if (ws == NULL) { + printf("NULL\n"); + return 1; + } + if (ws->length != 8) { + printf("Bad length (%li instead of 8)\n", ws->length); + return 1; + } + uint8_t expected[8] = {1, 0, 0, 3, 0, 0, 0, 5}; + for (int i = 0; i < 8; i++) { + if (ws->data[i] != expected[i]) { + printf("Bad data (%i instead of %i)\n", ws->data[i], expected[i]); + return 1; + } + } + printf("OK\n"); + bn_clear(&bn); + free(ws->data); + free(ws); + return 0; +} + +int test_convert_base() { + printf("test_convert_base: "); + bn_t bn; + bn_init(&bn); + bn_from_int(11, &bn); + small_base_t *bs = bn_convert_base_small(&bn, 2); + if (bs == NULL) { + printf("NULL\n"); + return 1; + } + if (bs->length != 4) { + printf("Bad length (%li instead of 4)\n", bs->length); + return 1; + } + uint8_t expected[4] = {1, 1, 0, 1}; + for (int i = 0; i < 4; i++) { + if (bs->data[i] != expected[i]) { + printf("Bad data (%i insead of %i)\n", bs->data[i], expected[i]); + return 1; + } + } + printf("OK\n"); + bn_clear(&bn); + free(bs->data); + free(bs); + return 0; +} + +int main(void) { + return test_wsliding_ltr() + test_wsliding_rtl() + test_convert_base(); +} 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() diff --git a/test/test_simulator.py b/test/test_simulator.py index e5a1c9d..89819b1 100644 --- a/test/test_simulator.py +++ b/test/test_simulator.py @@ -5,6 +5,7 @@ import pytest from pyecsca.ec.key_agreement import ECDH_SHA1 from pyecsca.ec.mult import LTRMultiplier, RTLMultiplier from pyecsca.ec.signature import ECDSA_SHA1, SignatureResult +from rainbow import TraceConfig, HammingWeight from pyecsca.codegen.builder import build_impl from pyecsca.codegen.client import SimulatorTarget @@ -46,6 +47,10 @@ def do_basic_test( "STM32F3", "--ecdsa" if ecdsa else "--no-ecdsa", "--ecdh" if ecdh else "--no-ecdh", + "--red", + "MONTGOMERY", + "-D", + "BN_NON_CONST", params.curve.model.shortname, params.curve.coordinate_model.name, *formulas, @@ -193,6 +198,7 @@ def test_ecdh(mult_name, mult_class, cli_runner, curve32): ) +@pytest.mark.xfail(reason="Simulator bug #3") @pytest.mark.parametrize( "mult_name,mult_class", [("ltr", LTRMultiplier), ("rtl", RTLMultiplier)] ) |
