aboutsummaryrefslogtreecommitdiffhomepage
path: root/pyecsca/codegen/render.py
diff options
context:
space:
mode:
Diffstat (limited to 'pyecsca/codegen/render.py')
-rw-r--r--pyecsca/codegen/render.py42
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: