From 3892d994470b181f950703fabf719a9c963d1c20 Mon Sep 17 00:00:00 2001 From: J08nY Date: Thu, 20 Feb 2020 20:41:29 +0100 Subject: Add full implementation tests. --- .travis.yml | 1 + docs/commands.rst | 10 +- pyecsca/codegen/asn1/asn1.c | 9 +- pyecsca/codegen/builder.py | 28 ++--- pyecsca/codegen/client.py | 32 +++-- pyecsca/codegen/templates/main.c | 7 +- pyecsca/codegen/templates/mult_ltr.c | 4 +- pyecsca/codegen/templates/mult_rtl.c | 4 +- test/test_impl.py | 228 ++++++++++++++++++++++++++++++----- 9 files changed, 256 insertions(+), 67 deletions(-) diff --git a/.travis.yml b/.travis.yml index 050f8a2..401fb62 100644 --- a/.travis.yml +++ b/.travis.yml @@ -19,6 +19,7 @@ install: - cd ../ - git clone https://github.com/J08nY/pyecsca - cd pyecsca + - git submodule update --init --recursive - pip install -e . - cd ../.. - pip install -e ".[test, typecheck]" diff --git a/docs/commands.rst b/docs/commands.rst index 9954832..c8bdfdc 100644 --- a/docs/commands.rst +++ b/docs/commands.rst @@ -153,7 +153,7 @@ Verify with ECDSA Verify a message signature with ECDSA. -- Character: :code:`v` +- Character: :code:`r` - Payload: Encoded. - :code:`d` The message to verify. @@ -174,5 +174,13 @@ Send back the implementation configuration (model and coordinate system). - :code:`d` The model shortname and coordinate system name, ASCII, comma-separated. +Check version +------------- +ChipWhisperer command. + +- Character: :code:`v` +- Payload: none +- Response: :code:`z00` always. + .. _ChipWhisperer: https://github.com/newaetech/chipwhisperer .. _XKCP: https://github.com/XKCP/XKCP \ No newline at end of file diff --git a/pyecsca/codegen/asn1/asn1.c b/pyecsca/codegen/asn1/asn1.c index 3fd1f5f..13bfa5c 100644 --- a/pyecsca/codegen/asn1/asn1.c +++ b/pyecsca/codegen/asn1/asn1.c @@ -7,8 +7,8 @@ uint8_t *asn1_der_encode(const bn_t *r, const bn_t *s, size_t *result_len) { uint8_t s_len = (uint8_t) bn_to_bin_size(s); // Pad with one zero byte in case most-significant bit of top byte is one. - uint8_t r_length = r_len + (bn_get_bit(r, r_len * 8) ? 1 : 0); - uint8_t s_length = s_len + (bn_get_bit(s, s_len * 8) ? 1 : 0); + uint8_t r_length = r_len + (bn_get_bit(r, (r_len * 8) - 1) ? 1 : 0); + uint8_t s_length = s_len + (bn_get_bit(s, (s_len * 8) - 1) ? 1 : 0); // R and S are < 128 bytes, so 1 byte tag + 1 byte len + len bytes value size_t seq_value_len = 2 + r_length + 2 + s_length; @@ -29,6 +29,7 @@ uint8_t *asn1_der_encode(const bn_t *r, const bn_t *s, size_t *result_len) { whole_len += 1; uint8_t *data = malloc(whole_len); + *result_len = whole_len; size_t i = 0; data[i++] = 0x30; // SEQUENCE if (seq_value_len < 128) { @@ -41,14 +42,14 @@ uint8_t *asn1_der_encode(const bn_t *r, const bn_t *s, size_t *result_len) { } data[i++] = 0x02; //INTEGER data[i++] = r_length; - if (bn_get_bit(r, r_len * 8)) { + if (bn_get_bit(r, (r_len * 8) - 1)) { data[i++] = 0; } bn_to_bin(r, data + i); i += r_len; data[i++] = 0x02; //INTEGER data[i++] = s_length; - if (bn_get_bit(s, s_len * 8)) { + if (bn_get_bit(s, (s_len * 8) - 1)) { data[i++] = 0; } bn_to_bin(s, data + i); diff --git a/pyecsca/codegen/builder.py b/pyecsca/codegen/builder.py index b9f9708..bf8e6be 100644 --- a/pyecsca/codegen/builder.py +++ b/pyecsca/codegen/builder.py @@ -73,16 +73,6 @@ def get_multiplier(ctx: click.Context, param, value: Optional[str]) -> Optional[ return mult -def get_ecdsa(ctx: click.Context, param, value: bool) -> bool: - if not value: - return False - ctx.ensure_object(dict) - formulas = ctx.obj["formulas"] - if not any(isinstance(formula, AdditionFormula) for formula in formulas): - raise click.BadParameter("ECDSA needs an addition formula. None was supplied.") - return value - - @click.group(context_settings={"help_option_names": ["-h", "--help"]}) @click.version_option() @public @@ -118,12 +108,15 @@ def main(): type=click.Choice(Reduction.names()), callback=wrap_enum(Reduction), help="Modular reduction algorithm to use.") -@click.option("--keygen/--no-keygen", help="Whether to enable keygen.", is_flag=True, default=True, show_default=True) -@click.option("--ecdh/--no-ecdh", help="Whether to enable ECDH.", is_flag=True, default=True, show_default=True) +@click.option("--keygen/--no-keygen", help="Whether to enable keygen.", is_flag=True, default=True, + show_default=True) +@click.option("--ecdh/--no-ecdh", help="Whether to enable ECDH.", is_flag=True, default=True, + show_default=True) @click.option("--ecdsa/--no-ecdsa", help="Whether to enable ECDSA.", is_flag=True, default=True, - callback=get_ecdsa, show_default=True) + show_default=True) @click.option("--strip", help="Whether to strip the binary or not.", is_flag=True) -@click.option("--remove/--no-remove", help="Whether to remove the dir.", is_flag=True, default=True, show_default=True) +@click.option("--remove/--no-remove", help="Whether to remove the dir.", is_flag=True, default=True, + show_default=True) @click.option("-v", "--verbose", count=True) @click.argument("model", required=True, type=click.Choice(["shortw", "montgom", "edwards", "twisted"]), @@ -135,8 +128,9 @@ def main(): @click.argument("scalarmult", required=True, callback=get_multiplier) @click.argument("outdir") +@click.pass_context @public -def build_impl(platform, hash, rand, mul, sqr, red, keygen, ecdh, ecdsa, strip, remove, +def build_impl(ctx, platform, hash, rand, mul, sqr, red, keygen, ecdh, ecdsa, strip, remove, verbose, model, coords, formulas, scalarmult, outdir): """This command builds an ECC implementation. @@ -147,6 +141,10 @@ def build_impl(platform, hash, rand, mul, sqr, red, keygen, ecdh, ecdsa, strip, SCALARMULT: The scalar multiplication algorithm to use. OUTDIR: The output directory for files with the built impl. """ + ctx.ensure_object(dict) + formulas = ctx.obj["formulas"] + if ecdsa and not any(isinstance(formula, AdditionFormula) for formula in formulas): + raise click.BadParameter("ECDSA needs an addition formula. None was supplied.") config = DeviceConfiguration(model, coords, formulas, scalarmult, hash, rand, mul, sqr, red, platform, keygen, ecdh, ecdsa) diff --git a/pyecsca/codegen/client.py b/pyecsca/codegen/client.py index 197c703..cd4cff7 100644 --- a/pyecsca/codegen/client.py +++ b/pyecsca/codegen/client.py @@ -68,16 +68,16 @@ def cmd_init_prng(seed: bytes) -> str: @public -def cmd_set_params(group: DomainParameters) -> str: +def cmd_set_params(params: DomainParameters) -> str: data = { - "p": encode_scalar(group.curve.prime), - "n": encode_scalar(group.order), - "h": encode_scalar(group.cofactor) + "p": encode_scalar(params.curve.prime), + "n": encode_scalar(params.order), + "h": encode_scalar(params.cofactor) } - for param, value in group.curve.parameters.items(): + for param, value in params.curve.parameters.items(): data[param] = encode_scalar(value) - data["g"] = encode_point(group.generator.to_affine()) - data["i"] = encode_point(group.neutral) + data["g"] = encode_point(params.generator.to_affine()) + data["i"] = encode_point(params.curve.neutral) return "c" + hexlify(encode_data(None, data)).decode() @@ -113,7 +113,7 @@ def cmd_ecdsa_sign(data: bytes) -> str: @public def cmd_ecdsa_verify(data: bytes, sig: bytes) -> str: - return "v" + hexlify(encode_data(None, {"d": data, "s": sig})).decode() + return "r" + hexlify(encode_data(None, {"d": data, "s": sig})).decode() @public @@ -173,7 +173,7 @@ class ImplTarget(SerialTarget): def scalar_mult(self, scalar: int) -> Point: self.write(cmd_scalar_mult(scalar).encode()) result = self.read(1)[1:-1] - plen = (self.params.curve.prime + 7) // 8 + plen = ((self.params.curve.prime.bit_length() + 7) // 8) * 2 self.read(1) params = {var: Mod(int(result[i * plen:(i + 1) * plen], 16), self.params.curve.prime) for i, var in enumerate(self.coords.variables)} @@ -209,10 +209,12 @@ class ImplTarget(SerialTarget): class BinaryTarget(ImplTarget): binary: str process: Optional[Popen] + debug_output: bool - def __init__(self, binary: str, model: CurveModel, coords: CoordinateModel): + def __init__(self, binary: str, model: CurveModel, coords: CoordinateModel, debug_output: bool = False): super().__init__(model, coords) self.binary = binary + self.debug_output = debug_output def connect(self): self.process = Popen([self.binary], stdin=subprocess.PIPE, stdout=subprocess.PIPE, @@ -221,20 +223,26 @@ class BinaryTarget(ImplTarget): def write(self, data: bytes): if self.process is None: raise ValueError + if self.debug_output: + print(">>", data.decode()) self.process.stdin.write(data.decode() + "\n") self.process.stdin.flush() def read(self, timeout: int) -> bytes: if self.process is None: raise ValueError - return self.process.stdout.readline().encode() + read = self.process.stdout.readline().encode() + if self.debug_output: + print("<<", read.decode(), end="") + return read def disconnect(self): if self.process is None: return self.process.stdin.close() self.process.stdout.close() - self.process.kill() + self.process.terminate() + self.process.wait() @click.group(context_settings={"help_option_names": ["-h", "--help"]}) diff --git a/pyecsca/codegen/templates/main.c b/pyecsca/codegen/templates/main.c index ae36bfd..b0f81f1 100644 --- a/pyecsca/codegen/templates/main.c +++ b/pyecsca/codegen/templates/main.c @@ -325,12 +325,17 @@ static uint8_t cmd_ecdsa_sign(uint8_t *data, uint16_t len) { bn_t r; bn_init(&r); point_to_affine(p, curve, &r, NULL); bn_mod(&r, &curve->n, &r); + // r = ([k]G).x mod n bn_t s; bn_init(&s); bn_copy(&privkey, &s); + // s = x bn_mod_mul(&s, &r, &curve->n, &s); + // s = rx mod n bn_mod_add(&s, &h, &curve->n, &s); + // s = rx + H(m) mod n bn_mod_div(&s, &k, &curve->n, &s); + // s = k^(-1)*(rx + H(m)) mod n size_t result_len = 0; uint8_t *result = asn1_der_encode(&r, &s, &result_len); @@ -444,7 +449,7 @@ int main(void) { {%- endif %} {%- if ecdsa %} simpleserial_addcmd('a', MAX_SS_LEN, cmd_ecdsa_sign); - simpleserial_addcmd('v', MAX_SS_LEN, cmd_ecdsa_verify); + simpleserial_addcmd('r', MAX_SS_LEN, cmd_ecdsa_verify); {%- endif %} simpleserial_addcmd('d', MAX_SS_LEN, cmd_debug); diff --git a/pyecsca/codegen/templates/mult_ltr.c b/pyecsca/codegen/templates/mult_ltr.c index dbd4704..5b08b80 100644 --- a/pyecsca/codegen/templates/mult_ltr.c +++ b/pyecsca/codegen/templates/mult_ltr.c @@ -19,10 +19,10 @@ void scalar_mult(bn_t *scalar, point_t *point, curve_t *curve, point_t *out) { for (int i = nbits; i >= 0; i--) { point_dbl(r, curve, r); if (bn_get_bit(scalar, i) == 1) { - point_add(q, r, curve, r); + point_add(r, q, curve, r); } else { {%- if scalarmult.always %} - point_add(q, r, curve, dummy); + point_add(r, q, curve, dummy); {%- endif %} } } diff --git a/pyecsca/codegen/templates/mult_rtl.c b/pyecsca/codegen/templates/mult_rtl.c index 01d42a5..ba40a66 100644 --- a/pyecsca/codegen/templates/mult_rtl.c +++ b/pyecsca/codegen/templates/mult_rtl.c @@ -14,10 +14,10 @@ void scalar_mult(bn_t *scalar, point_t *point, curve_t *curve, point_t *out) { while (!bn_is_0(©)) { if (bn_get_bit(©, 0) == 1) { - point_add(q, r, curve, r); + point_add(r, q, curve, r); } else { {%- if scalarmult.always %} - point_add(q, r, curve, dummy); + point_add(r, q, curve, dummy); {%- endif %} } point_dbl(q, curve, q); diff --git a/test/test_impl.py b/test/test_impl.py index 8a2bfde..267fc6b 100644 --- a/test/test_impl.py +++ b/test/test_impl.py @@ -1,15 +1,20 @@ +from binascii import hexlify +from copy import copy from os.path import join from unittest import TestCase from click.testing import CliRunner from pyecsca.ec.curves import get_params +from pyecsca.ec.key_agreement import ECDH_SHA1 from pyecsca.ec.mult import LTRMultiplier, RTLMultiplier, CoronMultiplier, BinaryNAFMultiplier +from pyecsca.ec.point import Point +from pyecsca.ec.signature import ECDSA_SHA1, SignatureResult from pyecsca.codegen.builder import build_impl from pyecsca.codegen.client import BinaryTarget -class KeyGenerationTests(TestCase): +class ImplTests(TestCase): def setUp(self): self.secp128r1 = get_params("secg", "secp128r1", "projective") @@ -20,10 +25,13 @@ class KeyGenerationTests(TestCase): self.base25519 = self.curve25519.generator self.coords25519 = self.curve25519.curve.coordinate_model - def do_basic_test(self, runner, params, mult_class, formulas, mult_name, **mult_kwargs): + def do_basic_test(self, callback, runner, params, mult_class, formulas, mult_name, + ecdsa, ecdh, **mult_kwargs): with runner.isolated_filesystem() as tmpdir: runner.invoke(build_impl, - ["--platform", "HOST", "--no-ecdsa", "--no-ecdh", + ["--platform", "HOST", + "--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())})", @@ -33,51 +41,211 @@ class KeyGenerationTests(TestCase): params.curve.coordinate_model) target.connect() target.set_params(params) - priv, pub = target.generate() - self.assertTrue(params.curve.is_on_curve(pub)) formula_instances = [params.curve.coordinate_model.formulas[formula] for formula in formulas] mult = mult_class(*formula_instances, **mult_kwargs) mult.init(params, params.generator) - expected = mult.multiply(priv).to_affine() - self.assertEqual(pub, expected) + callback(target, mult, params) target.disconnect() + +class PRNGTests(ImplTests): + + def test_init(self): + runner = CliRunner() + + def callback(target, mult, params): + target.init_prng(bytes([0x12, 0x34, 0x56, 0x78])) + + self.do_basic_test(callback, runner, self.secp128r1, LTRMultiplier, + ["add-1998-cmo", "dbl-1998-cmo"], "ltr", False, False, complete=False) + + +class SetupTests(ImplTests): + + def test_setup(self): + runner = CliRunner() + + def callback(target, mult, params): + priv = 57 + pub = mult.multiply(priv).to_affine() + target.set_privkey(priv) + target.set_pubkey(pub) + + self.do_basic_test(callback, runner, self.secp128r1, LTRMultiplier, + ["add-1998-cmo", "dbl-1998-cmo"], "ltr", False, False, complete=False) + + def test_debug(self): + runner = CliRunner() + def callback(target, mult, params): + model, coords = target.debug() + self.assertEqual(model, params.curve.model.shortname) + self.assertEqual(coords, params.curve.coordinate_model.name) + self.do_basic_test(callback, runner, self.secp128r1, LTRMultiplier, + ["add-1998-cmo", "dbl-1998-cmo"], "ltr", False, False, complete=False) + +class KeyGenerationTests(ImplTests): + + def do_keygen_test(self, runner, params, mult_class, formulas, mult_name, **mult_kwargs): + def callback(target, mult, params): + for _ in range(10): + priv, pub = target.generate() + self.assertTrue(params.curve.is_on_curve(pub)) + expected = mult.multiply(priv).to_affine() + self.assertEqual(pub, expected) + + self.do_basic_test(callback, runner, params, mult_class, formulas, mult_name, False, False, + **mult_kwargs) + def test_ltr(self): runner = CliRunner() - self.do_basic_test(runner, self.secp128r1, LTRMultiplier, ["add-1998-cmo", "dbl-1998-cmo"], - "ltr", - complete=False) - self.do_basic_test(runner, self.secp128r1, LTRMultiplier, ["add-1998-cmo", "dbl-1998-cmo"], - "ltr", - complete=True) - self.do_basic_test(runner, self.secp128r1, LTRMultiplier, ["add-1998-cmo", "dbl-1998-cmo"], - "ltr", - always=True, complete=False) - self.do_basic_test(runner, self.secp128r1, LTRMultiplier, ["add-1998-cmo", "dbl-1998-cmo"], - "ltr", - always=True, complete=True) + self.do_keygen_test(runner, self.secp128r1, LTRMultiplier, ["add-1998-cmo", "dbl-1998-cmo"], + "ltr", complete=False) + self.do_keygen_test(runner, self.secp128r1, LTRMultiplier, ["add-1998-cmo", "dbl-1998-cmo"], + "ltr", complete=True) + self.do_keygen_test(runner, self.secp128r1, LTRMultiplier, ["add-1998-cmo", "dbl-1998-cmo"], + "ltr", always=True, complete=False) + self.do_keygen_test(runner, self.secp128r1, LTRMultiplier, ["add-1998-cmo", "dbl-1998-cmo"], + "ltr", always=True, complete=True) def test_rtl(self): runner = CliRunner() - self.do_basic_test(runner, self.secp128r1, RTLMultiplier, ["add-1998-cmo", "dbl-1998-cmo"], - "rtl", - always=False) - self.do_basic_test(runner, self.secp128r1, RTLMultiplier, ["add-1998-cmo", "dbl-1998-cmo"], - "rtl", - always=True) + self.do_keygen_test(runner, self.secp128r1, RTLMultiplier, ["add-1998-cmo", "dbl-1998-cmo"], + "rtl", always=False) + self.do_keygen_test(runner, self.secp128r1, RTLMultiplier, ["add-1998-cmo", "dbl-1998-cmo"], + "rtl", always=True) def test_coron(self): runner = CliRunner() - self.do_basic_test(runner, self.secp128r1, CoronMultiplier, - ["add-1998-cmo", "dbl-1998-cmo"], "coron") + self.do_keygen_test(runner, self.secp128r1, CoronMultiplier, + ["add-1998-cmo", "dbl-1998-cmo"], "coron") def test_bnaf(self): runner = CliRunner() - self.do_basic_test(runner, self.secp128r1, BinaryNAFMultiplier, - ["add-1998-cmo", "dbl-1998-cmo", "neg"], "bnaf") + self.do_keygen_test(runner, self.secp128r1, BinaryNAFMultiplier, + ["add-1998-cmo", "dbl-1998-cmo", "neg"], "bnaf") # def test_ladder(self): # runner = CliRunner() - # self.do_basic_test(runner, self.curve25519, LadderMultiplier, ["ladd-1987-m", "dbl-1987-m"], "ldr") + # self.do_keygen_test(runner, self.curve25519, LadderMultiplier, ["ladd-1987-m", "dbl-1987-m"], "ldr") # # TODO: what about coords where generator is not affine? + + +class ScalarMultiplicationTests(ImplTests): + + def do_mult_test(self, runner, params, mult_class, formulas, mult_name, **mult_kwargs): + values = [15, 2355498743, 3253857901321912443757746] + + def callback(target, mult, params): + for value in values: + result = target.scalar_mult(value) + expected = mult.multiply(value) + self.assertEqual(result, expected) + + self.do_basic_test(callback, runner, params, mult_class, formulas, mult_name, False, False, + **mult_kwargs) + + def test_ltr(self): + runner = CliRunner() + self.do_mult_test(runner, self.secp128r1, LTRMultiplier, ["add-1998-cmo", "dbl-1998-cmo"], + "ltr", complete=False) + self.do_mult_test(runner, self.secp128r1, LTRMultiplier, ["add-1998-cmo", "dbl-1998-cmo"], + "ltr", complete=True) + self.do_mult_test(runner, self.secp128r1, LTRMultiplier, ["add-1998-cmo", "dbl-1998-cmo"], + "ltr", complete=False, always=True) + self.do_mult_test(runner, self.secp128r1, LTRMultiplier, ["add-1998-cmo", "dbl-1998-cmo"], + "ltr", complete=True, always=True) + + def test_rtl(self): + runner = CliRunner() + self.do_mult_test(runner, self.secp128r1, RTLMultiplier, ["add-1998-cmo", "dbl-1998-cmo"], + "rtl", always=False) + self.do_mult_test(runner, self.secp128r1, RTLMultiplier, ["add-1998-cmo", "dbl-1998-cmo"], + "rtl", always=True) + + def test_coron(self): + runner = CliRunner() + self.do_mult_test(runner, self.secp128r1, CoronMultiplier, + ["add-1998-cmo", "dbl-1998-cmo"], "coron") + + def test_bnaf(self): + runner = CliRunner() + self.do_mult_test(runner, self.secp128r1, BinaryNAFMultiplier, + ["add-1998-cmo", "dbl-1998-cmo", "neg"], "bnaf") + + +class ECDHTests(ImplTests): + def do_ecdh_test(self, runner, params, mult_class, formulas, mult_name, **mult_kwargs): + 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() + self.assertEqual(result, expected) + + self.do_basic_test(callback, runner, params, mult_class, formulas, mult_name, False, True, + **mult_kwargs) + + def test_ltr(self): + runner = CliRunner() + self.do_ecdh_test(runner, self.secp128r1, LTRMultiplier, ["add-1998-cmo", "dbl-1998-cmo"], + "ltr", complete=False) + self.do_ecdh_test(runner, self.secp128r1, LTRMultiplier, ["add-1998-cmo", "dbl-1998-cmo"], + "ltr", complete=True) + self.do_ecdh_test(runner, self.secp128r1, LTRMultiplier, ["add-1998-cmo", "dbl-1998-cmo"], + "ltr", complete=False, always=True) + self.do_ecdh_test(runner, self.secp128r1, LTRMultiplier, ["add-1998-cmo", "dbl-1998-cmo"], + "ltr", complete=True, always=True) + + def test_rtl(self): + runner = CliRunner() + self.do_ecdh_test(runner, self.secp128r1, RTLMultiplier, ["add-1998-cmo", "dbl-1998-cmo"], + "rtl", always=False) + self.do_ecdh_test(runner, self.secp128r1, RTLMultiplier, ["add-1998-cmo", "dbl-1998-cmo"], + "rtl", always=True) + + def test_coron(self): + runner = CliRunner() + self.do_ecdh_test(runner, self.secp128r1, CoronMultiplier, + ["add-1998-cmo", "dbl-1998-cmo"], "coron") + + def test_bnaf(self): + runner = CliRunner() + self.do_ecdh_test(runner, self.secp128r1, BinaryNAFMultiplier, + ["add-1998-cmo", "dbl-1998-cmo", "neg"], "bnaf") + + +class ECDSATests(ImplTests): + def do_ecdsa_test(self, runner, params, mult_class, formulas, mult_name, **mult_kwargs): + data = b"something" + + def callback(target, mult, params): + priv, pub = target.generate() + ecdsa = ECDSA_SHA1(copy(mult), params, mult.formulas["add"], + Point.from_affine(params.curve.coordinate_model, pub), priv) + + + signature_data = target.ecdsa_sign(data) + result = SignatureResult.from_DER(signature_data) + self.assertTrue(ecdsa.verify_data(result, data)) + + expected = ecdsa.sign_data(data).to_DER() + self.assertTrue(target.ecdsa_verify(data, expected)) + + self.do_basic_test(callback, runner, params, mult_class, formulas, mult_name, True, + False, **mult_kwargs) + + def test_ltr(self): + runner = CliRunner() + self.do_ecdsa_test(runner, self.secp128r1, LTRMultiplier, ["add-1998-cmo", "dbl-1998-cmo"], + "ltr", complete=False) + self.do_ecdsa_test(runner, self.secp128r1, LTRMultiplier, ["add-1998-cmo", "dbl-1998-cmo"], + "ltr", complete=True) + self.do_ecdsa_test(runner, self.secp128r1, LTRMultiplier, ["add-1998-cmo", "dbl-1998-cmo"], + "ltr", complete=False, always=True) + self.do_ecdsa_test(runner, self.secp128r1, LTRMultiplier, ["add-1998-cmo", "dbl-1998-cmo"], + "ltr", complete=True, always=True) -- cgit v1.3.1