From 5da1d167c203395103d220c450e29fece08f4198 Mon Sep 17 00:00:00 2001 From: J08nY Date: Wed, 19 Feb 2020 18:29:53 +0100 Subject: Flesh out client, add implementation tests. --- pyecsca/codegen/builder.py | 23 +++-- pyecsca/codegen/client.py | 191 ++++++++++++++++++++++++----------- pyecsca/codegen/common.py | 2 +- pyecsca/codegen/point.h | 6 +- pyecsca/codegen/render.py | 11 +- pyecsca/codegen/templates/main.c | 12 +-- pyecsca/codegen/templates/mult.c | 14 +-- pyecsca/codegen/templates/mult_ltr.c | 3 +- pyecsca/codegen/templates/point.c | 34 ++++++- 9 files changed, 201 insertions(+), 95 deletions(-) (limited to 'pyecsca/codegen') diff --git a/pyecsca/codegen/builder.py b/pyecsca/codegen/builder.py index b1a8816..b9f9708 100644 --- a/pyecsca/codegen/builder.py +++ b/pyecsca/codegen/builder.py @@ -4,7 +4,7 @@ import shutil import subprocess from copy import copy from os import path -from typing import List, Optional, Tuple +from typing import List, Optional, Tuple, Type, MutableMapping import click from public import public @@ -39,13 +39,13 @@ def get_multiplier(ctx: click.Context, param, value: Optional[str]) -> Optional[ if value is None: return None res = re.match( - "(?P[a-zA-Z\-]+)\((?P([a-zA-Z_]+ *= *[a-zA-Z0-9]+, )*?([a-zA-Z_]+ *= *[a-zA-Z0-9]+)*)\)", + "(?P[a-zA-Z\-]+)\((?P([a-zA-Z_]+ *= *[a-zA-Z0-9]+, ?)*?([a-zA-Z_]+ *= *[a-zA-Z0-9]+)*)\)", value) if not res: raise click.BadParameter("Couldn't parse multiplier spec: {}.".format(value)) name = res.group("name") args = res.group("args") - mult_class = None + mult_class: Type[ScalarMultiplier] = None for mult_def in MULTIPLIERS: if name in mult_def["name"]: mult_class = mult_def["class"] @@ -80,6 +80,7 @@ def get_ecdsa(ctx: click.Context, param, value: bool) -> bool: 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"]}) @@ -108,7 +109,7 @@ def main(): @click.option("--mul", envvar="MUL", default="BASE", show_default=True, type=click.Choice(Multiplication.names()), callback=wrap_enum(Multiplication), - help="Multiplier to use.") + help="Multiplication algorithm to use.") @click.option("--sqr", envvar="SQR", default="BASE", show_default=True, type=click.Choice(Squaring.names()), callback=wrap_enum(Squaring), @@ -117,12 +118,12 @@ 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 disable keygen.", is_flag=True, default=True) -@click.option("--ecdh/--no-ecdh", help="Whether to disable ECDH.", is_flag=True, default=True) -@click.option("--ecdsa/--no-ecdsa", help="Whether to disable ECDSA.", is_flag=True, default=True, - callback=get_ecdsa) +@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) @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) +@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"]), @@ -143,7 +144,7 @@ def build_impl(platform, hash, rand, mul, sqr, red, keygen, ecdh, ecdsa, strip, MODEL: The curve model to use. COORDS: The coordinate model to use. FORMULAS: The formulas to use. - MULT: The scalar multiplication algorithm to use. + SCALARMULT: The scalar multiplication algorithm to use. OUTDIR: The output directory for files with the built impl. """ @@ -196,7 +197,7 @@ def list_impl(model: Optional[CurveModel], coords: Optional[CoordinateModel], return if not formulas and coords: click.echo(coords) - types = {} + types: MutableMapping[Type, List] = {} for val in coords.formulas.values(): category = types.setdefault(val.__class__, []) category.append(val) diff --git a/pyecsca/codegen/client.py b/pyecsca/codegen/client.py index 81dca40..197c703 100644 --- a/pyecsca/codegen/client.py +++ b/pyecsca/codegen/client.py @@ -1,13 +1,16 @@ #!/usr/bin/env python3 import subprocess -from binascii import hexlify +from binascii import hexlify, unhexlify from os import path from subprocess import Popen -from typing import Mapping, Union, Optional +from typing import Mapping, Union, Optional, Tuple import click +from public import public +from pyecsca.ec.coordinates import CoordinateModel, AffineCoordinateModel from pyecsca.ec.curves import get_params from pyecsca.ec.mod import Mod +from pyecsca.ec.model import CurveModel from pyecsca.ec.params import DomainParameters from pyecsca.ec.point import Point, InfinityPoint from pyecsca.sca import SerialTarget @@ -20,6 +23,7 @@ def encode_scalar(val: Union[int, Mod]) -> bytes: return val.to_bytes((val.bit_length() + 7) // 8, "big") elif isinstance(val, Mod): return encode_scalar(int(val)) + return bytes() def encode_point(point: Point) -> Mapping: @@ -30,6 +34,8 @@ def encode_point(point: Point) -> Mapping: def encode_data(name: Optional[str], structure: Union[Mapping, bytes]) -> bytes: if isinstance(structure, bytes): + if name is None: + raise ValueError header = bytes([ord(name)]) + bytes([len(structure)]) return header + structure data = bytes() @@ -56,11 +62,13 @@ def decode_data(data: bytes) -> Mapping: return result +@public def cmd_init_prng(seed: bytes) -> str: return "i" + hexlify(seed).decode() -def cmd_set_curve(group: DomainParameters) -> str: +@public +def cmd_set_params(group: DomainParameters) -> str: data = { "p": encode_scalar(group.curve.prime), "n": encode_scalar(group.order), @@ -73,43 +81,137 @@ def cmd_set_curve(group: DomainParameters) -> str: return "c" + hexlify(encode_data(None, data)).decode() +@public def cmd_generate() -> str: return "g" +@public def cmd_set_privkey(privkey: int) -> str: return "s" + hexlify(encode_data(None, {"s": encode_scalar(privkey)})).decode() +@public def cmd_set_pubkey(pubkey: Point) -> str: return "w" + hexlify(encode_data(None, {"w": encode_point(pubkey.to_affine())})).decode() +@public def cmd_scalar_mult(scalar: int) -> str: return "m" + hexlify(encode_data(None, {"s": encode_scalar(scalar)})).decode() +@public def cmd_ecdh(pubkey: Point) -> str: return "e" + hexlify(encode_data(None, {"w": encode_point(pubkey.to_affine())})).decode() +@public def cmd_ecdsa_sign(data: bytes) -> str: return "a" + hexlify(encode_data(None, {"d": data})).decode() +@public def cmd_ecdsa_verify(data: bytes, sig: bytes) -> str: return "v" + hexlify(encode_data(None, {"d": data, "s": sig})).decode() +@public def cmd_debug() -> str: return "d" -class BinaryTarget(SerialTarget): +class ImplTarget(SerialTarget): + model: CurveModel + coords: CoordinateModel + seed: Optional[bytes] + params: Optional[DomainParameters] + privkey: Optional[int] + pubkey: Optional[Point] + + def __init__(self, model: CurveModel, coords: CoordinateModel): + self.model = model + self.coords = coords + self.seed = None + self.params = None + self.privkey = None + self.pubkey = None + + def init_prng(self, seed: bytes) -> None: + self.write(cmd_init_prng(seed).encode()) + self.read(1) + self.seed = seed + + def set_params(self, params: DomainParameters) -> None: + self.write(cmd_set_params(params).encode()) + self.read(1) + self.params = params + + def generate(self) -> Tuple[int, Point]: + self.write(cmd_generate().encode()) + priv = self.read(1).decode()[1:-1] + pub = self.read(1).decode()[1:-1] + self.read(1) + self.privkey = int(priv, 16) + pub_len = len(pub) + x = int(pub[:pub_len // 2], 16) + y = int(pub[pub_len // 2:], 16) + self.pubkey = Point(AffineCoordinateModel(self.model), x=Mod(x, self.params.curve.prime), + y=Mod(y, self.params.curve.prime)) + return self.privkey, self.pubkey + + def set_privkey(self, privkey: int) -> None: + self.write(cmd_set_privkey(privkey).encode()) + self.read(1) + self.privkey = privkey + + def set_pubkey(self, pubkey: Point) -> None: + self.write(cmd_set_pubkey(pubkey).encode()) + self.read(1) + self.pubkey = pubkey + + 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 + 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)} + return Point(self.coords, **params) + + def ecdh(self, other_pubkey: Point) -> bytes: + self.write(cmd_ecdh(other_pubkey).encode()) + result = self.read(1) + self.read(1) + return unhexlify(result[1:-1]) + + def ecdsa_sign(self, data: bytes) -> bytes: + self.write(cmd_ecdsa_sign(data).encode()) + signature = self.read(1) + self.read(1) + return unhexlify(signature[1:-1]) + + def ecdsa_verify(self, data: bytes, signature: bytes) -> bool: + self.write(cmd_ecdsa_verify(data, signature).encode()) + result = self.read(1) + self.read(1) + return unhexlify(result[1:-1])[0] == 1 + + def debug(self) -> Tuple[str, str]: + self.write(cmd_debug().encode()) + resp = self.read(1) + self.read(1) + model, coords = unhexlify(resp[1:-1]).decode().split(",") + return model, coords + + +@public +class BinaryTarget(ImplTarget): binary: str process: Optional[Popen] - def __init__(self, binary: str): + def __init__(self, binary: str, model: CurveModel, coords: CoordinateModel): + super().__init__(model, coords) self.binary = binary def connect(self): @@ -117,15 +219,22 @@ class BinaryTarget(SerialTarget): text=True, bufsize=1) def write(self, data: bytes): + if self.process is None: + raise ValueError self.process.stdin.write(data.decode() + "\n") self.process.stdin.flush() def read(self, timeout: int) -> bytes: - return self.process.stdout.readline() + if self.process is None: + raise ValueError + return self.process.stdout.readline().encode() def disconnect(self): - if self.process.poll() is not None: - self.process.terminate() + if self.process is None: + return + self.process.stdin.close() + self.process.stdout.close() + self.process.kill() @click.group(context_settings={"help_option_names": ["-h", "--help"]}) @@ -134,9 +243,15 @@ class BinaryTarget(SerialTarget): callback=wrap_enum(Platform), help="The target platform to use.") @click.option("--binary", help="For HOST target only. The binary to run.") +@click.argument("model", required=True, + type=click.Choice(["shortw", "montgom", "edwards", "twisted"]), + callback=get_model) +@click.argument("coords", required=True, + callback=get_coords) @click.version_option() @click.pass_context -def main(ctx, platform, binary): +@public +def main(ctx, platform, binary, model, coords): """ A tool for communicating with built and flashed ECC implementations. """ @@ -158,40 +273,7 @@ def main(ctx, platform, binary): if binary is None or not path.isfile(binary): click.secho("Binary is required if the target is the host.", fg="red", err=True) raise click.Abort - ctx.obj["target"] = BinaryTarget(binary) - # model = ShortWeierstrassModel() - # coords = model.coordinates["projective"] - # p = 0xffffffff00000001000000000000000000000000ffffffffffffffffffffffff - # curve = EllipticCurve(model, coords, - # p, - # {"a": 0xffffffff00000001000000000000000000000000fffffffffffffffffffffffc, - # "b": 0x5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b}) - # affine_g = Point(AffineCoordinateModel(model), - # x=Mod(0x6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296, p), - # y=Mod(0x4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5, p)) - # g = Point.from_affine(coords, affine_g) - # neutral = Point(coords, X=Mod(0, p), Y=Mod(1, p), Z=Mod(0, p)) - # group = AbelianGroup(curve, g, neutral, - # 0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551, 0x1) - # - # print(cmd_set_curve(group)) - # mul = LTRMultiplier(coords.formulas["add-1998-cmo"], coords.formulas["dbl-1998-cmo"], coords.formulas["z"]) - # mul.init(group, g) - # res = mul.multiply(0x2EF035DF6D0634C7422161D08BCC794B5312E042DDB32B0135A4DE6E6345A555) - # rx = Mod(0x77E3FF34C12571970845CBEB1BE0A79E3ECEE187510C2B8894BA800F8164C954, p) - # ry = Mod(0x408A6A05607F9ACA97BB9A34EA643B107AADE0C9BB5EDB930EADE3009666B9D1, p) - # rz = Mod(0xC66ECD687C335D63A7030434CA70351191BAFF1C206332EFEA39FA3003E91646, p) - # - # ox = Mod(0x3B1E7733E3250C97EB9D00AE0394F0768902DD337FEAAF7C4F6B9588462920DD, p) - # oy = Mod(0xBA718497596C964E77F9666506505B1E730EE69D254E85AD44727DFFB2C7063E, p) - # oz = Mod(0x0000000000000000000000000000000000000000000000000000000000000001, p) - # - # pt = Point(coords, X=rx, Y=ry, Z=rz) - # ot = Point(coords, X=ox, Y=oy, Z=oz) - # print(ot, res) - # print(pt.equals(res)) - # print(ot.equals(res)) - # print(ot == res) + ctx.obj["target"] = BinaryTarget(binary, model, coords) def get_curve(ctx: click.Context, param, value: Optional[str]) -> DomainParameters: @@ -204,37 +286,28 @@ def get_curve(ctx: click.Context, param, value: Optional[str]) -> DomainParamete @main.command("gen") -@click.argument("model", required=True, - type=click.Choice(["shortw", "montgom", "edwards", "twisted"]), - callback=get_model) -@click.argument("coords", required=True, - callback=get_coords) @click.argument("curve", required=True, callback=get_curve) @click.pass_context -def generate(ctx: click.Context, model, coords, curve): +@public +def generate(ctx: click.Context, curve): ctx.ensure_object(dict) - set_curve = cmd_set_curve(curve) - generate = cmd_generate() - target: SerialTarget = ctx.obj["target"] + target: ImplTarget = ctx.obj["target"] target.connect() - click.echo(set_curve) - target.write(set_curve.encode()) - click.echo(target.read(1)) - click.echo(generate) - target.write(generate.encode()) - click.echo(target.read(1)) - click.echo(target.read(1)) + target.set_params(curve) + click.echo(target.generate()) target.disconnect() @main.command("ecdh") @click.pass_context +@public def ecdh(ctx: click.Context): ctx.ensure_object(dict) @main.command("ecdsa") @click.pass_context +@public def ecdsa(ctx: click.Context): ctx.ensure_object(dict) diff --git a/pyecsca/codegen/common.py b/pyecsca/codegen/common.py index bd57ab6..917963e 100644 --- a/pyecsca/codegen/common.py +++ b/pyecsca/codegen/common.py @@ -105,4 +105,4 @@ def get_coords(ctx: click.Context, param, value: Optional[str]) -> Optional[Coor model.__class__.__name__)) coords = model.coordinates[value] ctx.obj["coords"] = coords - return coords \ No newline at end of file + return coords diff --git a/pyecsca/codegen/point.h b/pyecsca/codegen/point.h index 1b7e8e1..f85a818 100644 --- a/pyecsca/codegen/point.h +++ b/pyecsca/codegen/point.h @@ -13,9 +13,11 @@ void point_free(point_t *point); bool point_equals(const point_t *one, const point_t *other); -void point_to_affine(point_t *point, curve_t *curve, bn_t *out_x, bn_t *out_y); +bool point_equals_affine(const point_t *one, const point_t *other, const curve_t *curve); -void point_from_affine(bn_t *x, bn_t *y, curve_t *curve, point_t *out); +void point_to_affine(const point_t *point, const curve_t *curve, bn_t *out_x, bn_t *out_y); + +void point_from_affine(bn_t *x, bn_t *y, const curve_t *curve, point_t *out); void point_add(const point_t *one, const point_t *other, const curve_t *curve, point_t *out_one); diff --git a/pyecsca/codegen/render.py b/pyecsca/codegen/render.py index ead1470..6ea1e36 100644 --- a/pyecsca/codegen/render.py +++ b/pyecsca/codegen/render.py @@ -26,9 +26,9 @@ env = Environment( loader=PackageLoader("pyecsca.codegen") ) - env.globals["isinstance"] = isinstance + def render_op(op: OpType, result: str, left: str, right: str, mod: str) -> Optional[str]: if op == OpType.Add: return "bn_mod_add(&{}, &{}, &{}, &{});".format(left, right, mod, result) @@ -48,8 +48,10 @@ def render_op(op: OpType, result: str, left: str, right: str, mod: str) -> Optio print(op, result, left, right, mod) return None + env.globals["render_op"] = render_op + def render_defs(model: CurveModel, coords: CoordinateModel) -> str: return env.get_template("defs.h").render(params=model.parameter_names, variables=coords.variables) @@ -233,7 +235,7 @@ def render(config: DeviceConfiguration) -> Tuple[str, str, str]: @public def build(dir: str, elf_file: str, hex_file: str, outdir: str, strip: bool = False, - remove : bool = True) -> subprocess.CompletedProcess: + remove: bool = True) -> subprocess.CompletedProcess: """ :param dir: @@ -248,7 +250,8 @@ def build(dir: str, elf_file: str, hex_file: str, outdir: str, strip: bool = Fal if res.returncode != 0: raise ValueError("Build failed!") if strip: - subprocess.run(["strip", elf_file], cwd=dir) + s = subprocess.run(["strip", elf_file], cwd=dir) + s.returncode full_elf_path = path.join(dir, elf_file) full_hex_path = path.join(dir, hex_file) shutil.copy(full_elf_path, outdir) @@ -271,4 +274,4 @@ def render_and_build(config: DeviceConfiguration, outdir: str, strip: bool = Fal """ dir, elf_file, hex_file = render(config) res = build(dir, elf_file, hex_file, outdir, strip, remove) - return dir, elf_file, hex_file, res \ No newline at end of file + return dir, elf_file, hex_file, res diff --git a/pyecsca/codegen/templates/main.c b/pyecsca/codegen/templates/main.c index c2e250f..ab69858 100644 --- a/pyecsca/codegen/templates/main.c +++ b/pyecsca/codegen/templates/main.c @@ -56,7 +56,7 @@ static uint8_t cmd_init_prng(uint8_t *data, uint16_t len) { return 0; } -static void parse_set_curve(const char *path, const uint8_t *data, size_t len, void *arg) { +static void parse_set_params(const char *path, const uint8_t *data, size_t len, void *arg) { {%- for param in curve_parameters + ["p", "n", "h"] %} if (strcmp(path, "{{ param }}") == 0) { bn_from_bin(data, len, &curve->{{ param }}); @@ -90,10 +90,10 @@ static void parse_set_curve(const char *path, const uint8_t *data, size_t len, v {%- endfor %} } -static uint8_t cmd_set_curve(uint8_t *data, uint16_t len) { +static uint8_t cmd_set_params(uint8_t *data, uint16_t len) { // need p, [params], n, h, g[xy], i[variables] fat_t affine[2] = {fat_empty, fat_empty}; - parse_data(data, len, "", parse_set_curve, (void *) affine); + parse_data(data, len, "", parse_set_params, (void *) affine); bn_t x; bn_init(&x); bn_t y; bn_init(&y); bn_from_bin(affine[0].value, affine[0].len, &x); @@ -416,10 +416,10 @@ static uint8_t cmd_ecdsa_verify(uint8_t *data, uint16_t len) { } static uint8_t cmd_debug(uint8_t *data, uint16_t len) { - const char *debug_string = "{{ ','.join((model.shortname, coords.name))}}"; + char *debug_string = "{{ ','.join((model.shortname, coords.name))}}"; size_t debug_len = strlen(debug_string); - simpleserial_put('d', debug_len, debug_string); + simpleserial_put('d', debug_len, (uint8_t *) debug_string); return 0; } @@ -435,7 +435,7 @@ int main(void) { simpleserial_init(); simpleserial_addcmd('i', MAX_SS_LEN, cmd_init_prng); - simpleserial_addcmd('c', MAX_SS_LEN, cmd_set_curve); + simpleserial_addcmd('c', MAX_SS_LEN, cmd_set_params); {%- if keygen %} simpleserial_addcmd('g', 0, cmd_generate); {%- endif %} diff --git a/pyecsca/codegen/templates/mult.c b/pyecsca/codegen/templates/mult.c index 61ec825..6851b6b 100644 --- a/pyecsca/codegen/templates/mult.c +++ b/pyecsca/codegen/templates/mult.c @@ -2,17 +2,17 @@ #include "mult.h" {%- if isinstance(scalarmult, LTRMultiplier) -%} -{%- include "mult_ltr.c" %} +{% include "mult_ltr.c" %} {%- elif isinstance(scalarmult, RTLMultiplier) -%} -{%- include "mult_rtl.c" %} +{% include "mult_rtl.c" %} {%- elif isinstance(scalarmult, CoronMultiplier) -%} -{%- include "mult_coron.c" %} +{% include "mult_coron.c" %} {%- elif isinstance(scalarmult, LadderMultiplier) -%} -{%- include "mult_ldr.c" %} +{% include "mult_ldr.c" %} {%- elif isinstance(scalarmult, SimpleLadderMultiplier) -%} -{%- include "mult_simple_ldr.c" %} +{% include "mult_simple_ldr.c" %} {%- elif isinstance(scalarmult, DifferentialLadderMultiplier) -%} -{%- include "mult_diff_ldr.c" %} +{% include "mult_diff_ldr.c" %} {%- elif isinstance(scalarmult, BinaryNAFMultiplier) -%} -{%- include "mult_bnaf.c" %} +{% include "mult_bnaf.c" %} {%- endif -%} diff --git a/pyecsca/codegen/templates/mult_ltr.c b/pyecsca/codegen/templates/mult_ltr.c index 9b7d87e..dbd4704 100644 --- a/pyecsca/codegen/templates/mult_ltr.c +++ b/pyecsca/codegen/templates/mult_ltr.c @@ -7,8 +7,7 @@ void scalar_mult(bn_t *scalar, point_t *point, curve_t *curve, point_t *out) { point_t *r = point_copy(curve->neutral); int nbits = bn_bit_length(&curve->n) - 1; {%- else %} - point_t *q = point_new(); - point_dbl(point, curve, q); + point_t *q = point_copy(point); point_t *r = point_copy(point); int nbits = bn_bit_length(scalar) - 2; {%- endif %} diff --git a/pyecsca/codegen/templates/point.c b/pyecsca/codegen/templates/point.c index c12c50a..445bdc4 100644 --- a/pyecsca/codegen/templates/point.c +++ b/pyecsca/codegen/templates/point.c @@ -20,6 +20,7 @@ void point_set(const point_t *from, point_t *out) { {%- for variable in variables %} bn_copy(&from->{{ variable }}, &out->{{ variable }}); {%- endfor %} + out->infinity = from->infinity; } void point_free(point_t *point) { @@ -30,7 +31,7 @@ void point_free(point_t *point) { } bool point_equals(const point_t *one, const point_t *other) { - if (one->infinity && !other->infinity || other->infinity && !one->infinity) { + if ((one->infinity && !other->infinity) || (other->infinity && !one->infinity)) { return false; } if (one->infinity && other->infinity) { @@ -45,7 +46,34 @@ bool point_equals(const point_t *one, const point_t *other) { return true; } -void point_to_affine(point_t *point, curve_t *curve, bn_t *out_x, bn_t *out_y) { +bool point_equals_affine(const point_t *one, const point_t *other, const curve_t *curve) { + if ((one->infinity && !other->infinity) || (other->infinity && !one->infinity)) { + return false; + } + if (one->infinity && other->infinity) { + return true; + } + bool result = true; + bn_t ax; bn_init(&ax); + bn_t ay; bn_init(&ay); + bn_t bx; bn_init(&bx); + bn_t by; bn_init(&by); + point_to_affine(one, curve, &ax, &ay); + point_to_affine(other, curve, &bx, &by); + if (!bn_eq(&ax, &bx)) { + result = false; + } + if (!bn_eq(&ay, &by)) { + result = false; + } + bn_clear(&ax); + bn_clear(&ay); + bn_clear(&bx); + bn_clear(&by); + return result; +} + +void point_to_affine(const point_t *point, const curve_t *curve, bn_t *out_x, bn_t *out_y) { {%- include "ops.c" %} {%- if "x" in allocations %} if (out_x) { @@ -62,7 +90,7 @@ void point_to_affine(point_t *point, curve_t *curve, bn_t *out_x, bn_t *out_y) { {%- endfor %} } -void point_from_affine(bn_t *x, bn_t *y, curve_t *curve, point_t *out) { +void point_from_affine(bn_t *x, bn_t *y, const curve_t *curve, point_t *out) { {# XXX: This just works for the stuff currently in EFD. #} {%- for variable in variables %} {%- if variable in ("X", "Y") %} -- cgit v1.3.1