diff options
Diffstat (limited to 'pyecsca/codegen/render.py')
| -rw-r--r-- | pyecsca/codegen/render.py | 42 |
1 files changed, 28 insertions, 14 deletions
diff --git a/pyecsca/codegen/render.py b/pyecsca/codegen/render.py index d4d1d7f..19d395f 100644 --- a/pyecsca/codegen/render.py +++ b/pyecsca/codegen/render.py @@ -2,7 +2,6 @@ import os import shutil import subprocess import tempfile -from _ast import Pow from os import path from os import makedirs from typing import Optional, List, Set, Mapping, MutableMapping, Any, Tuple @@ -82,6 +81,13 @@ def render_curve_impl(model: CurveModel) -> str: def transform_ops(ops: List[CodeOp], parameters: List[str], outputs: Set[str], renames: Mapping[str, str] = None) -> MutableMapping[Any, Any]: + """ + Transform a list of CodeOps, parameters, outputs and renames into a mapping + that will be used by the ops template macros to render the ops. + + This tracks allocations and frees, also creates a mapping of constants + to variable names. + """ def rename(name: str): if renames is not None and name not in outputs: return renames.get(name, name) @@ -92,6 +98,11 @@ def transform_ops(ops: List[CodeOp], parameters: List[str], outputs: Set[str], const_mapping = {} operations = [] frees = [] + # Go over the ops, track allocations needed for intermediates and constants. + # There are two kinds of constants, encoded and not-encoded. The encoded + # ones are default, the non-encoded ones are only in the exponents, where + # you don't want to encode using the reduction object (i.e. Montgomery form). + # Also constructs a mapping from raw constants to their variable names. for op in ops: if op.result not in allocations: allocations.append(op.result) @@ -100,23 +111,32 @@ def transform_ops(ops: List[CodeOp], parameters: List[str], outputs: Set[str], if param not in allocations and param not in parameters: raise ValueError("Should be allocated or parameter: {}".format(param)) for const in op.constants: - name = "c" + str(const) + if op.operator == OpType.Pow: + name = "cu" + str(const) + encode = False + else: + name = "c" + str(const) + encode = True if name not in allocations: allocations.append(name) - initializations[name] = const - const_mapping[const] = name + initializations[name] = (const, encode) + const_mapping[(const, encode)] = name frees.append(name) operations.append((op.operator, op.result, rename(op.left), rename(op.right))) mapped = [] + # Go over the operations and map constants to their variable names, + # make sure the encoded/non-encoded version is used where appropriate. for op in operations: o2 = op[2] - if o2 in const_mapping: - o2 = const_mapping[o2] + if (o2, True) in const_mapping: + o2 = const_mapping[(o2, True)] o3 = op[3] - if o3 in const_mapping and not (isinstance(op[0], Pow) and o3 == 2): - o3 = const_mapping[o3] + o3_enc = op[0] != OpType.Pow + if (o3, o3_enc) in const_mapping: + o3 = const_mapping[(o3, o3_enc)] mapped.append((op[0], op[1], o2, o3)) returns = {} + # Handle renames in the returns. if renames: for r_from, r_to in renames.items(): if r_from in outputs: @@ -128,12 +148,6 @@ def transform_ops(ops: List[CodeOp], parameters: List[str], outputs: Set[str], frees=frees, returns=returns) -def render_ops(ops: List[CodeOp], parameters: List[str], outputs: Set[str], - renames: Mapping[str, str] = None) -> str: - namespace = transform_ops(ops, parameters, outputs, renames) - return env.get_template("ops.c").render(namespace) - - def render_coords_impl(coords: CoordinateModel) -> str: ops = [] for s in coords.satisfying: |
