aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorJ08nY2019-11-27 20:34:58 +0100
committerJ08nY2019-11-27 20:34:58 +0100
commit32a4874abfbaff8cb4ee2d31fe71bcc3499e52dc (patch)
tree1203a322d7488ef51b4de2d34c6e0c2871ea68a5
parentbb00fee9702155586e674b9d6a3b838bd54baac2 (diff)
downloadpyecsca-codegen-32a4874abfbaff8cb4ee2d31fe71bcc3499e52dc.tar.gz
pyecsca-codegen-32a4874abfbaff8cb4ee2d31fe71bcc3499e52dc.tar.zst
pyecsca-codegen-32a4874abfbaff8cb4ee2d31fe71bcc3499e52dc.zip
Reorganize files, implement proper main.
-rw-r--r--pyecsca/codegen/Makefile8
-rw-r--r--pyecsca/codegen/__init__.py44
-rw-r--r--pyecsca/codegen/asn1/asn1.c (renamed from pyecsca/codegen/asn1.c)0
-rw-r--r--pyecsca/codegen/asn1/asn1.h (renamed from pyecsca/codegen/asn1.h)0
-rw-r--r--pyecsca/codegen/bn.c81
-rw-r--r--pyecsca/codegen/bn.h35
-rw-r--r--pyecsca/codegen/bn/bn.c119
-rw-r--r--pyecsca/codegen/bn/bn.h51
-rw-r--r--pyecsca/codegen/coords.h19
-rw-r--r--pyecsca/codegen/curve.h10
-rw-r--r--pyecsca/codegen/defs.h18
-rw-r--r--pyecsca/codegen/ecdh.c0
-rw-r--r--pyecsca/codegen/ecdsa.c0
-rw-r--r--pyecsca/codegen/fat.h6
-rw-r--r--pyecsca/codegen/formulas.h21
-rw-r--r--pyecsca/codegen/hash/hash.h2
-rw-r--r--pyecsca/codegen/hash/none.c4
-rw-r--r--pyecsca/codegen/hash/sha1.c4
-rw-r--r--pyecsca/codegen/hash/sha2.c4
-rw-r--r--pyecsca/codegen/main.c79
-rw-r--r--pyecsca/codegen/prng/prng.c2
-rw-r--r--pyecsca/codegen/simpleserial/simpleserial.c6
-rw-r--r--pyecsca/codegen/templates/coords.c32
-rw-r--r--pyecsca/codegen/templates/coords.h33
-rw-r--r--pyecsca/codegen/templates/curve.c39
-rw-r--r--pyecsca/codegen/templates/curve.h14
-rw-r--r--pyecsca/codegen/templates/main.c358
-rw-r--r--pyecsca/codegen/templates/ops.c4
28 files changed, 685 insertions, 308 deletions
diff --git a/pyecsca/codegen/Makefile b/pyecsca/codegen/Makefile
index 13122d0..d0dab03 100644
--- a/pyecsca/codegen/Makefile
+++ b/pyecsca/codegen/Makefile
@@ -1,12 +1,12 @@
TARGET = pyecsca-codegen
-SRC += main.c bn.c ecdh.c ecdsa.c asn1.c hash/hash.c mult/mult.c prng/prng.c
+SRC += main.c bn/bn.c asn1/asn1.c hash/hash.c mult/mult.c prng/prng.c
-CDEFS += -DHASH=HASH_SHA224
+CDEFS += -DHASH=HASH_SHA224 -DMOD_RAND=MOD_RAND_SAMPLE
-MKDIR_LIST += hash prng mult
+MKDIR_LIST += hash prng mult asn1 bn
-EXTRAINCDIRS += hash prng mult ../../ext/libtommath/
+EXTRAINCDIRS += hash prng mult asn1 bn ../../ext/libtommath/
LDFLAGS += ../../ext/libtommath/libtommath.a
diff --git a/pyecsca/codegen/__init__.py b/pyecsca/codegen/__init__.py
index 33320ac..104b43f 100644
--- a/pyecsca/codegen/__init__.py
+++ b/pyecsca/codegen/__init__.py
@@ -6,7 +6,7 @@ from pyecsca.ec.coordinates import CoordinateModel
from pyecsca.ec.formula import (Formula, AdditionFormula, DoublingFormula, TriplingFormula,
NegationFormula, ScalingFormula, DifferentialAdditionFormula,
LadderFormula)
-from pyecsca.ec.model import CurveModel, MontgomeryModel
+from pyecsca.ec.model import CurveModel, ShortWeierstrassModel
from pyecsca.ec.op import CodeOp
env = Environment(
@@ -45,7 +45,7 @@ def render_coords_definition(coords: CoordinateModel):
def transform_ops(ops: List[CodeOp], parameters: List[str], outputs: Set[str],
renames: Mapping[str, str] = None):
def rename(name: str):
- if renames is not None:
+ if renames is not None and name not in outputs:
return renames.get(name, name)
return name
@@ -55,7 +55,7 @@ def transform_ops(ops: List[CodeOp], parameters: List[str], outputs: Set[str],
operations = []
frees = []
for op in ops:
- if op.result not in allocations and op.result not in outputs:
+ if op.result not in allocations:
allocations.append(op.result)
frees.append(op.result)
for param in op.parameters:
@@ -69,11 +69,16 @@ def transform_ops(ops: List[CodeOp], parameters: List[str], outputs: Set[str],
const_mapping[const] = name
frees.append(name)
operations.append((op.operator, op.result, rename(op.left), rename(op.right)))
+ returns = {}
+ if renames:
+ for r_from, r_to in renames.items():
+ if r_from in outputs:
+ returns[r_from] = r_to
return dict(allocations=allocations,
initializations=initializations,
const_mapping=const_mapping, operations=operations,
- frees=frees)
+ frees=frees, returns=returns)
def render_ops(ops: List[CodeOp], parameters: List[str], outputs: Set[str],
@@ -89,9 +94,18 @@ def render_coords_impl(coords: CoordinateModel):
ops.append(CodeOp(s))
except:
pass
- transform_ops(ops, coords.curve_model.parameter_names, coords.curve_model.coordinate_names)
- # TODO: do point_from_affine, and point_to_affine
- return env.get_template("coords.c").render(variables=coords.variables)
+ renames = {"x": "out_x", "y": "out_y"}
+ for variable in coords.variables:
+ renames[variable] = "point->{}".format(variable)
+ namespace = transform_ops(ops, coords.curve_model.parameter_names,
+ coords.curve_model.coordinate_names, renames)
+ returns = namespace["returns"]
+ namespace["returns"] = {}
+ frees = namespace["frees"]
+ namespace["frees"] = {}
+
+ return env.get_template("coords.c").render(variables=coords.variables, **namespace,
+ to_affine_rets=returns, to_affine_frees=frees)
def render_formula_impl(formula: Formula):
@@ -123,13 +137,17 @@ def render_formula_impl(formula: Formula):
var = output[0]
num = int(output[1:]) - formula.output_index
renames[output] = "{}->{}".format(outputs[num], var)
- namespace = transform_ops(formula.code, formula.coordinate_model.curve_model.parameter_names, formula.outputs, renames)
+ namespace = transform_ops(formula.code, formula.coordinate_model.curve_model.parameter_names,
+ formula.outputs, renames)
return template.render(namespace)
+def render_main(model: CurveModel, coords: CoordinateModel):
+ return env.get_template("main.c").render(curve_variables=coords.variables,
+ curve_parameters=model.parameter_names)
+
+
if __name__ == "__main__":
- mont = MontgomeryModel()
- mcoords = mont.coordinates["xz"]
- dbl = mcoords.formulas["dbl-1987-m"]
- t = transform_ops(dbl.code, mont.parameter_names, dbl.outputs)
- print(render_formula_impl(dbl))
+ model = ShortWeierstrassModel()
+ coords = model.coordinates["projective"]
+ print(render_coords_impl(coords))
diff --git a/pyecsca/codegen/asn1.c b/pyecsca/codegen/asn1/asn1.c
index 3fd1f5f..3fd1f5f 100644
--- a/pyecsca/codegen/asn1.c
+++ b/pyecsca/codegen/asn1/asn1.c
diff --git a/pyecsca/codegen/asn1.h b/pyecsca/codegen/asn1/asn1.h
index 691755c..691755c 100644
--- a/pyecsca/codegen/asn1.h
+++ b/pyecsca/codegen/asn1/asn1.h
diff --git a/pyecsca/codegen/bn.c b/pyecsca/codegen/bn.c
deleted file mode 100644
index aa33124..0000000
--- a/pyecsca/codegen/bn.c
+++ /dev/null
@@ -1,81 +0,0 @@
-#include "bn.h"
-
-bn_err bn_init(bn_t *bn) {
- return mp_init(bn);
-}
-
-void bn_copy(bn_t *from, bn_t *to) {
- mp_copy(from, to);
-}
-
-void bn_clear(bn_t *bn) {
- mp_clear(bn);
-}
-
-int bn_from_bin(const uint8_t *data, size_t size, bn_t *out) {
- return mp_from_ubin(out, data, size);
-}
-
-int bn_from_hex(const char *data, bn_t *out) {
- return mp_read_radix(out, data, 16);
-}
-
-int bn_from_int(uint64_t value, bn_t *out) {
- mp_set_u64(out, value);
- return MP_OKAY;
-}
-
-void bn_to_binpad(const bn_t *one, uint8_t *data, size_t size) {
- size_t ubin_size = mp_ubin_size(one);
- size_t offset = size - ubin_size;
- mp_to_ubin(one, data + offset, ubin_size, NULL);
-}
-
-void bn_to_bin(const bn_t *one, uint8_t *data) {
- mp_to_ubin(one, data, mp_ubin_size(one), NULL);
-}
-
-size_t bn_to_bin_size(const bn_t *one) {
- return mp_ubin_size(one);
-}
-
-void bn_mod_add(bn_t *one, bn_t *other, bn_t *mod, bn_t *out) {
- mp_addmod(one, other, mod, out);
-}
-
-void bn_mod_sub(bn_t *one, bn_t *other, bn_t *mod, bn_t *out) {
- mp_submod(one, other, mod, out);
-}
-
-void bn_mod_mul(bn_t *one, bn_t *other, bn_t *mod, bn_t *out) {
- mp_mulmod(one, other, mod, out);
-}
-
-void bn_mod_sqr(bn_t *one, bn_t *mod, bn_t *out) {
- mp_sqrmod(one, mod, out);
-}
-
-void bn_mod_div(bn_t *one, bn_t *other, bn_t *mod, bn_t *out) {
- bn_t inv;
- mp_init(&inv);
- mp_invmod(other, mod, &inv);
- mp_mulmod(one, &inv, mod, out);
- mp_clear(&inv);
-}
-
-void bn_mod_inv(bn_t *one, bn_t *mod, bn_t *out) {
- mp_invmod(one, mod, out);
-}
-
-int bn_get_bit(bn_t *bn, int which) {
- int which_digit = which / (sizeof(mp_digit) * 8);
- int which_bit = which % (sizeof(mp_digit) * 8);
- if (bn->used <= which_digit) {
- return 0;
- }
- return (bn->dp[which_digit] >> which_bit) & 1;
-}
-
-int bn_bit_length(bn_t *bn) {
- return mp_count_bits(bn);
-} \ No newline at end of file
diff --git a/pyecsca/codegen/bn.h b/pyecsca/codegen/bn.h
deleted file mode 100644
index 0690310..0000000
--- a/pyecsca/codegen/bn.h
+++ /dev/null
@@ -1,35 +0,0 @@
-#ifndef BN_H_
-#define BN_H_
-
-#include <tommath.h>
-
-#define bn_t mp_int
-#define bn_err mp_err
-
-typedef struct {
- char name;
- bn_t value;
-} named_bn_t;
-
-bn_err bn_init(bn_t *bn);
-void bn_copy(bn_t *from, bn_t *to);
-void bn_clear(bn_t *bn);
-
-int bn_from_bin(const uint8_t *data, size_t size, bn_t *out);
-int bn_from_hex(const char *data, bn_t *out);
-int bn_from_int(uint64_t value, bn_t *out);
-
-void bn_to_binpad(const bn_t *one, uint8_t *data, size_t size);
-void bn_to_bin(const bn_t *one, uint8_t *data);
-size_t bn_to_bin_size(const bn_t *one);
-
-void bn_mod_add(bn_t *one, bn_t *other, bn_t *mod, bn_t *out);
-void bn_mod_sub(bn_t *one, bn_t *other, bn_t *mod, bn_t *out);
-void bn_mod_mul(bn_t *one, bn_t *other, bn_t *mod, bn_t *out);
-void bn_mod_sqr(bn_t *one, bn_t *mod, bn_t *out);
-void bn_mod_div(bn_t *one, bn_t *other, bn_t *mod, bn_t *out);
-void bn_mod_inv(bn_t *one, bn_t *mod, bn_t *out);
-int bn_get_bit(bn_t *bn, int which);
-int bn_bit_length(bn_t *bn);
-
-#endif //BN_H_ \ No newline at end of file
diff --git a/pyecsca/codegen/bn/bn.c b/pyecsca/codegen/bn/bn.c
new file mode 100644
index 0000000..9b805d1
--- /dev/null
+++ b/pyecsca/codegen/bn/bn.c
@@ -0,0 +1,119 @@
+#include "bn.h"
+
+bn_err bn_init(bn_t *bn) {
+ return mp_init(bn);
+}
+
+void bn_copy(const bn_t *from, bn_t *to) {
+ mp_copy(from, to);
+}
+
+void bn_clear(bn_t *bn) {
+ mp_clear(bn);
+}
+
+int bn_from_bin(const uint8_t *data, size_t size, bn_t *out) {
+ return mp_from_ubin(out, data, size);
+}
+
+int bn_from_hex(const char *data, bn_t *out) {
+ return mp_read_radix(out, data, 16);
+}
+
+int bn_from_int(uint64_t value, bn_t *out) {
+ mp_set_u64(out, value);
+ return MP_OKAY;
+}
+
+void bn_to_binpad(const bn_t *one, uint8_t *data, size_t size) {
+ size_t ubin_size = mp_ubin_size(one);
+ size_t offset = size - ubin_size;
+ mp_to_ubin(one, data + offset, ubin_size, NULL);
+}
+
+void bn_to_bin(const bn_t *one, uint8_t *data) {
+ mp_to_ubin(one, data, mp_ubin_size(one), NULL);
+}
+
+size_t bn_to_bin_size(const bn_t *one) {
+ return mp_ubin_size(one);
+}
+
+void bn_rand_mod_sample(bn_t *out, const bn_t *mod) {
+ int mod_len = bn_bit_length(mod);
+
+ bn_t mask; bn_init(&mask);
+ mp_2expt(&mask, mod_len + 1);
+ mp_decr(&mask);
+ while (1) {
+ mp_rand(out, (mod_len / (sizeof(mp_digit) * 8)) + 1);
+ mp_and(out, &mask, out);
+ if (mp_cmp_mag(out, mod) == MP_LT) {
+ bn_clear(&mask);
+ break;
+ }
+ }
+}
+
+void bn_rand_mod_reduce(bn_t *out, const bn_t *mod) {
+ int mod_len = bn_bit_length(mod);
+ mp_rand(out, (mod_len / (sizeof(mp_digit) * 8)) + 2);
+ mp_mod(out, mod, out);
+}
+
+void bn_mod_add(const bn_t *one, const bn_t *other, const bn_t *mod, bn_t *out) {
+ mp_addmod(one, other, mod, out);
+}
+
+void bn_mod_sub(const bn_t *one, const bn_t *other, const bn_t *mod, bn_t *out) {
+ mp_submod(one, other, mod, out);
+}
+
+void bn_mod_mul(const bn_t *one, const bn_t *other, const bn_t *mod, bn_t *out) {
+ mp_mulmod(one, other, mod, out);
+}
+
+void bn_mod_sqr(const bn_t *one, const bn_t *mod, bn_t *out) {
+ mp_sqrmod(one, mod, out);
+}
+
+void bn_mod_div(const bn_t *one, const bn_t *other, const bn_t *mod, bn_t *out) {
+ bn_t inv;
+ mp_init(&inv);
+ mp_invmod(other, mod, &inv);
+ mp_mulmod(one, &inv, mod, out);
+ mp_clear(&inv);
+}
+
+void bn_mod_inv(const bn_t *one, const bn_t *mod, bn_t *out) {
+ mp_invmod(one, mod, out);
+}
+
+void bn_mod(const bn_t *one, const bn_t *mod, bn_t *out) {
+ mp_mod(one, mod, out);
+}
+
+void bn_lsh(const bn_t *one, int amount, bn_t *out) {
+ mp_mul_2d(one, amount, out);
+}
+
+void bn_rsh(const bn_t *one, int amount, bn_t *out) {
+ mp_div_2d(one, amount, out, NULL);
+}
+
+bool bn_eq(const bn_t *one, const bn_t *other) {
+ return mp_cmp_mag(one, other) == MP_EQ;
+}
+
+int bn_get_bit(const bn_t *bn, int which) {
+ int which_digit = which / (sizeof(mp_digit) * 8);
+ int which_bit = which % (sizeof(mp_digit) * 8);
+ if (bn->used <= which_digit) {
+ return 0;
+ }
+ return (bn->dp[which_digit] >> which_bit) & 1;
+}
+
+int bn_bit_length(const bn_t *bn) {
+ return mp_count_bits(bn);
+} \ No newline at end of file
diff --git a/pyecsca/codegen/bn/bn.h b/pyecsca/codegen/bn/bn.h
new file mode 100644
index 0000000..2ff723f
--- /dev/null
+++ b/pyecsca/codegen/bn/bn.h
@@ -0,0 +1,51 @@
+#ifndef BN_H_
+#define BN_H_
+
+#include <tommath.h>
+
+#define bn_t mp_int
+#define bn_err mp_err
+
+typedef struct {
+ char name;
+ bn_t value;
+} named_bn_t;
+
+bn_err bn_init(bn_t *bn);
+void bn_copy(const bn_t *from, bn_t *to);
+void bn_clear(bn_t *bn);
+
+int bn_from_bin(const uint8_t *data, size_t size, bn_t *out);
+int bn_from_hex(const char *data, bn_t *out);
+int bn_from_int(uint64_t value, bn_t *out);
+
+void bn_to_binpad(const bn_t *one, uint8_t *data, size_t size);
+void bn_to_bin(const bn_t *one, uint8_t *data);
+size_t bn_to_bin_size(const bn_t *one);
+
+void bn_rand_mod_sample(bn_t *out, const bn_t *mod);
+void bn_rand_mod_reduce(bn_t *out, const bn_t *mod);
+
+#if MOD_RAND == MOD_RAND_SAMPLE
+#define bn_rand_mod bn_rand_mod_sample
+#elif MOD_RAND == MOD_RAND_REDUCE
+#define bn_rand_mod bn_rand_mod_reduce
+#endif
+
+void bn_mod_add(const bn_t *one, const bn_t *other, const bn_t *mod, bn_t *out);
+void bn_mod_sub(const bn_t *one, const bn_t *other, const bn_t *mod, bn_t *out);
+void bn_mod_mul(const bn_t *one, const bn_t *other, const bn_t *mod, bn_t *out);
+void bn_mod_sqr(const bn_t *one, const bn_t *mod, bn_t *out);
+void bn_mod_div(const bn_t *one, const bn_t *other, const bn_t *mod, bn_t *out);
+void bn_mod_inv(const bn_t *one, const bn_t *mod, bn_t *out);
+void bn_mod(const bn_t *one, const bn_t *mod, bn_t *out);
+
+void bn_lsh(const bn_t *one, int amount, bn_t *out);
+void bn_rsh(const bn_t *one, int amount, bn_t *out);
+
+bool bn_eq(const bn_t *one, const bn_t *other);
+
+int bn_get_bit(const bn_t *bn, int which);
+int bn_bit_length(const bn_t *bn);
+
+#endif //BN_H_ \ No newline at end of file
diff --git a/pyecsca/codegen/coords.h b/pyecsca/codegen/coords.h
deleted file mode 100644
index 6a1af7e..0000000
--- a/pyecsca/codegen/coords.h
+++ /dev/null
@@ -1,19 +0,0 @@
-#ifndef COORDS_H_
-#define COORDS_H_
-
-#include "bn.h"
-#include "defs.h"
-
-point_t *point_new(void);
-
-point_t *point_copy(const point_t *from);
-
-void point_set(const point_t *from, point_t *out);
-
-void point_free(point_t *point);
-
-int point_to_affine(point_t *point, const char coord, curve_t *curve, bn_t *out);
-
-int point_from_affine(bn_t *x, bn_t *y, curve_t *curve, point_t *out);
-
-#endif //COORDS_H_ \ No newline at end of file
diff --git a/pyecsca/codegen/curve.h b/pyecsca/codegen/curve.h
deleted file mode 100644
index ab962e7..0000000
--- a/pyecsca/codegen/curve.h
+++ /dev/null
@@ -1,10 +0,0 @@
-#ifndef CURVE_H_
-#define CURVE_H_
-
-#include "defs.h"
-
-curve_t* curve_new(const named_bn_t **params, int num_params);
-
-void curve_free(curve_t *curve);
-
-#endif //CURVE_H_ \ No newline at end of file
diff --git a/pyecsca/codegen/defs.h b/pyecsca/codegen/defs.h
deleted file mode 100644
index df81226..0000000
--- a/pyecsca/codegen/defs.h
+++ /dev/null
@@ -1,18 +0,0 @@
-#ifndef DEFS_H_
-#define DEFS_H_
-#include "bn.h"
-
-//point_t definition is variable
-typedef struct {
- bn_t X;
- bn_t Y;
- bn_t Z;
-} point_t;
-
-//curve_t definition is variable
-typedef struct {
- bn_t n;
- point_t *neutral;
-} curve_t;
-
-#endif //DEFS_H_ \ No newline at end of file
diff --git a/pyecsca/codegen/ecdh.c b/pyecsca/codegen/ecdh.c
deleted file mode 100644
index e69de29..0000000
--- a/pyecsca/codegen/ecdh.c
+++ /dev/null
diff --git a/pyecsca/codegen/ecdsa.c b/pyecsca/codegen/ecdsa.c
deleted file mode 100644
index e69de29..0000000
--- a/pyecsca/codegen/ecdsa.c
+++ /dev/null
diff --git a/pyecsca/codegen/fat.h b/pyecsca/codegen/fat.h
new file mode 100644
index 0000000..e9fe3bd
--- /dev/null
+++ b/pyecsca/codegen/fat.h
@@ -0,0 +1,6 @@
+typedef struct {
+ size_t len;
+ void *value;
+} fat_t;
+
+#define fat_empty {0, NULL} \ No newline at end of file
diff --git a/pyecsca/codegen/formulas.h b/pyecsca/codegen/formulas.h
deleted file mode 100644
index a2278bb..0000000
--- a/pyecsca/codegen/formulas.h
+++ /dev/null
@@ -1,21 +0,0 @@
-#ifndef FORMULAS_H_
-#define FORMULAS_H_
-
-#include "coords.h"
-#include "defs.h"
-
-int point_add(const point_t *one, const point_t *other, const curve_t *curve, point_t *out_one);
-
-int point_dbl(const point_t *one, const curve_t *curve, point_t *out_one);
-
-int point_tpl(const point_t *one, const curve_t *curve, point_t *out_one);
-
-int point_neg(const point_t *one, const curve_t *curve, point_t *out_one);
-
-int point_scl(const point_t *one, const curve_t *curve, point_t *out_one);
-
-int point_dadd(const point_t *one, const point_t *other, const point_t *diff, const curve_t *curve, point_t *out_one);
-
-int point_ladd(const point_t *one, const point_t *other, const point_t *diff, const curve_t *curve, point_t *out_one, point_t *out_other);
-
-#endif //FORMULAS_H_ \ No newline at end of file
diff --git a/pyecsca/codegen/hash/hash.h b/pyecsca/codegen/hash/hash.h
index 9e79b61..7121cd4 100644
--- a/pyecsca/codegen/hash/hash.h
+++ b/pyecsca/codegen/hash/hash.h
@@ -18,4 +18,6 @@ void hash_init(void *ctx);
void hash_final(void *ctx, int size, const uint8_t *msg, uint8_t *digest);
+void hash_free_ctx(void *ctx);
+
#endif //HASH_H_ \ No newline at end of file
diff --git a/pyecsca/codegen/hash/none.c b/pyecsca/codegen/hash/none.c
index 79690e8..b40adc3 100644
--- a/pyecsca/codegen/hash/none.c
+++ b/pyecsca/codegen/hash/none.c
@@ -17,4 +17,8 @@ void hash_init(void *ctx) {
void hash_final(void *ctx, int size, const uint8_t *msg, uint8_t *digest) {
memcpy(digest, msg, size);
+}
+
+void hash_free_ctx(void *ctx) {
+
} \ No newline at end of file
diff --git a/pyecsca/codegen/hash/sha1.c b/pyecsca/codegen/hash/sha1.c
index cf6ca3e..213ed11 100644
--- a/pyecsca/codegen/hash/sha1.c
+++ b/pyecsca/codegen/hash/sha1.c
@@ -187,3 +187,7 @@ void hash_final(void *ctx, int size, const uint8_t *msg, uint8_t *digest) {
sha1_lastBlock(ctx, msg, length);
sha1_ctx2hash(digest, ctx);
}
+
+void hash_free_ctx(void *ctx) {
+ free(ctx);
+}
diff --git a/pyecsca/codegen/hash/sha2.c b/pyecsca/codegen/hash/sha2.c
index d2ddf6f..2b7f11d 100644
--- a/pyecsca/codegen/hash/sha2.c
+++ b/pyecsca/codegen/hash/sha2.c
@@ -334,4 +334,8 @@ void hash_final(void* ctx, int size, const uint8_t* msg, uint8_t* digest) {
}
sha2_lastBlock(ctx, msg, length_b);
sha2_ctx2hash(digest, ctx);
+}
+
+void hash_free_ctx(void *ctx) {
+ free(ctx);
} \ No newline at end of file
diff --git a/pyecsca/codegen/main.c b/pyecsca/codegen/main.c
deleted file mode 100644
index a1d43da..0000000
--- a/pyecsca/codegen/main.c
+++ /dev/null
@@ -1,79 +0,0 @@
-#include <stdint.h>
-#include <stdlib.h>
-
-#include "hal/hal.h"
-#include "simpleserial/simpleserial.h"
-#include "hash/hash.h"
-#include "bn.h"
-#include "prng.h"
-#include "defs.h"
-#include <stdlib.h>
-
-static point_t *pubkey;
-static bn_t privkey;
-
-static curve_t *curve;
-
-static uint8_t cmd_init_prng(uint8_t *data, uint16_t len) {
- prng_seed(data, len);
- return 0;
-}
-
-static uint8_t cmd_set_curve(uint8_t *data, uint16_t len) {
- // need p, [params], gx, gy, n
- return 0;
-}
-
-static uint8_t cmd_generate(uint8_t *data, uint16_t len) {
- // generate a keypair, export privkey and affine pubkey
- return 0;
-}
-
-static uint8_t cmd_set_privkey(uint8_t *data, uint16_t len) {
- // set the current privkey
- return 0;
-}
-
-static uint8_t cmd_set_pubkey(uint8_t *data, uint16_t len) {
- // set the current pubkey
- return 0;
-}
-
-static uint8_t cmd_scalar_mult(uint8_t *data, uint16_t len) {
- // perform base point scalar mult with supplied scalar, return affine point.
- return 0;
-}
-
-static uint8_t cmd_ecdh(uint8_t *data, uint16_t len) {
- //perform ECDH with provided point (and current privkey), output shared secret
- return 0;
-}
-
-static uint8_t cmd_ecdsa_sign(uint8_t *data, uint16_t len) {
- //perform ECDSA signature on supplied data, output signature
- return 0;
-}
-
-static uint8_t cmd_ecdsa_verify(uint8_t *data, uint16_t len) {
- //perform ECDSA verification on supplied data (and current pubkey), output status
- return 0;
-}
-
-int main(void) {
- platform_init();
- prng_init();
- init_uart();
- trigger_setup();
- simpleserial_init();
- simpleserial_addcmd('i', 32, cmd_init_prng);
- simpleserial_addcmd('c', MAX_SS_LEN, cmd_set_curve);
- simpleserial_addcmd('g', 0, cmd_generate);
- simpleserial_addcmd('s', MAX_SS_LEN, cmd_set_privkey);
- simpleserial_addcmd('w', MAX_SS_LEN, cmd_set_pubkey);
- simpleserial_addcmd('m', MAX_SS_LEN, cmd_scalar_mult);
- simpleserial_addcmd('e', MAX_SS_LEN, cmd_ecdh);
- simpleserial_addcmd('a', MAX_SS_LEN, cmd_ecdsa_sign);
- simpleserial_addcmd('v', MAX_SS_LEN, cmd_ecdsa_verify);
- while(simpleserial_get());
- return 0;
-} \ No newline at end of file
diff --git a/pyecsca/codegen/prng/prng.c b/pyecsca/codegen/prng/prng.c
index 934fe72..e3cb755 100644
--- a/pyecsca/codegen/prng/prng.c
+++ b/pyecsca/codegen/prng/prng.c
@@ -14,7 +14,7 @@ mp_err prng_mp_rand(void *out, size_t size) {
void prng_init(void) {
KeccakWidth200_SpongePRG_Initialize(&keccak, 70);
- mp_rand_source(prng_mp_rand);
+ mp_rand_source(&prng_mp_rand);
}
int prng_get(uint8_t *out, size_t size) {
diff --git a/pyecsca/codegen/simpleserial/simpleserial.c b/pyecsca/codegen/simpleserial/simpleserial.c
index d15b309..4d73ebb 100644
--- a/pyecsca/codegen/simpleserial/simpleserial.c
+++ b/pyecsca/codegen/simpleserial/simpleserial.c
@@ -28,10 +28,10 @@ int hex_decode(int len, char* ascii_buf, uint8_t* data_buf)
if (len % 2 != 0)
return 1;
- for(int i = 0; i < len; i+=2)
+ for(int i = 0; i < len/2; i++)
{
- char n_hi = ascii_buf[i];
- char n_lo = ascii_buf[i+1];
+ char n_hi = ascii_buf[i*2];
+ char n_lo = ascii_buf[i*2+1];
if(n_lo >= '0' && n_lo <= '9')
data_buf[i] = n_lo - '0';
diff --git a/pyecsca/codegen/templates/coords.c b/pyecsca/codegen/templates/coords.c
index 98ab86f..016dc36 100644
--- a/pyecsca/codegen/templates/coords.c
+++ b/pyecsca/codegen/templates/coords.c
@@ -1,3 +1,5 @@
+#include "coords.h"
+
point_t *point_new(void) {
point_t *result = malloc(sizeof(point_t));
{%- for variable in variables %}
@@ -26,10 +28,34 @@ void point_free(point_t *point) {
free(point);
}
-int point_to_affine(point_t *point, const char coord, curve_t *curve, bn_t *out) {
-
+int point_to_affine(point_t *point, curve_t *curve, bn_t *out_x, bn_t *out_y) {
+ {%- include "ops.c" %}
+ {%- if "x" in allocations %}
+ if (out_x) {
+ bn_copy(&x, out_x);
+ }
+ {%- endif %}
+ {%- if "y" in allocations %}
+ if (out_y) {
+ bn_copy(&y, out_y);
+ }
+ {%- endif %}
+ {%- for free in to_affine_frees %}
+ bn_clear(&{{ free }});
+ {%- endfor %}
}
int point_from_affine(bn_t *x, bn_t *y, 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") %}
+ bn_copy({{ variable | lower }}, &out->{{ variable }});
+ {%- endif %}
+ {%- if variable == "Z" %}
+ bn_from_int(1, &out->Z);
+ {%- endif %}
+ {%- if variable == "T" %}
+ bn_mod_mul(x, y, &curve->p, &out->T);
+ {%- endif %}
+ {%- endfor %}
}
diff --git a/pyecsca/codegen/templates/coords.h b/pyecsca/codegen/templates/coords.h
index 6890c11..91b6626 100644
--- a/pyecsca/codegen/templates/coords.h
+++ b/pyecsca/codegen/templates/coords.h
@@ -1,5 +1,36 @@
+#ifndef POINT_H_
+#define POINT_H_
+
typedef struct {
{%- for variable in variables %}
bn_t {{ variable }};
{%- endfor %}
-} point_t; \ No newline at end of file
+} point_t;
+
+point_t *point_new(void);
+
+point_t *point_copy(const point_t *from);
+
+void point_set(const point_t *from, point_t *out);
+
+void point_free(point_t *point);
+
+int point_to_affine(point_t *point, curve_t *curve, bn_t *out_x, bn_t *out_y);
+
+int point_from_affine(bn_t *x, bn_t *y, curve_t *curve, point_t *out);
+
+int point_add(const point_t *one, const point_t *other, const curve_t *curve, point_t *out_one);
+
+int point_dbl(const point_t *one, const curve_t *curve, point_t *out_one);
+
+int point_tpl(const point_t *one, const curve_t *curve, point_t *out_one);
+
+int point_neg(const point_t *one, const curve_t *curve, point_t *out_one);
+
+int point_scl(const point_t *one, const curve_t *curve, point_t *out_one);
+
+int point_dadd(const point_t *one, const point_t *other, const point_t *diff, const curve_t *curve, point_t *out_one);
+
+int point_ladd(const point_t *one, const point_t *other, const point_t *diff, const curve_t *curve, point_t *out_one, point_t *out_other);
+
+#endif //POINT_H_ \ No newline at end of file
diff --git a/pyecsca/codegen/templates/curve.c b/pyecsca/codegen/templates/curve.c
index 3d98571..425bf2d 100644
--- a/pyecsca/codegen/templates/curve.c
+++ b/pyecsca/codegen/templates/curve.c
@@ -1,31 +1,32 @@
-curve_t* curve_new(const named_bn_t **params, int num_params) {
+curve_t* curve_new() {
curve_t *result = malloc(sizeof(curve_t));
- bn_init(&result->p);
- {%- for param in params %}
+ {%- for param in params + ["p", "n", "h"] %}
bn_init(&result->{{ param }});
{%- endfor %}
- bn_init(&result->n);
- result->neutral = NULL;
+ result->generator = point_new();
+ result->neutral = point_new();
- for (int i = 0; i < num_params; ++i) {
- switch (params[i]->name) {
- {%- for param in params %}
- case '{{ param }}': bn_copy(params[i]->value, result->{{ param }});
- break;
- {%- endfor %}
- default:
- curve_free(result);
- return NULL;
- }
- }
return result;
}
void curve_free(curve_t *curve) {
- bn_clear(&curve->p);
- {%- for param in params %}
+ {%- for param in params + ["p", "n", "h"] %}
bn_clear(&curve->{{ param }});
{%- endfor %}
- bn_clear(&curve->n);
+ if (curve->generator) {
+ point_free(curve->generator);
+ }
+ if (curve->neutral) {
+ point_free(curve->neutral);
+ }
free(curve);
+}
+
+void curve_set_param(curve_t *curve, char name, const bn_t *value) {
+ switch (name) {
+ {%- for param in params + ["p", "n", "h"] %}
+ case '{{ param }}': bn_copy(value, &curve->{{ param }});
+ break;
+ {%- endfor %}
+ }
} \ No newline at end of file
diff --git a/pyecsca/codegen/templates/curve.h b/pyecsca/codegen/templates/curve.h
index e901304..f9b1507 100644
--- a/pyecsca/codegen/templates/curve.h
+++ b/pyecsca/codegen/templates/curve.h
@@ -1,3 +1,6 @@
+#ifndef CURVE_H_
+#define CURVE_H_
+
typedef struct {
bn_t p;
{%- for param in params %}
@@ -5,5 +8,14 @@ typedef struct {
{%- endfor %}
bn_t n;
bn_t h;
+ point_t *generator;
point_t *neutral;
-} curve_t; \ No newline at end of file
+} curve_t;
+
+curve_t* curve_new();
+
+void curve_free(curve_t *curve);
+
+void curve_set_param(curve_t *curve, char name, const bn_t *value);
+
+#endif //CURVE_H_ \ No newline at end of file
diff --git a/pyecsca/codegen/templates/main.c b/pyecsca/codegen/templates/main.c
new file mode 100644
index 0000000..a3051f1
--- /dev/null
+++ b/pyecsca/codegen/templates/main.c
@@ -0,0 +1,358 @@
+#include "hal/hal.h"
+#include "simpleserial/simpleserial.h"
+#include "hash/hash.h"
+#include "bn.h"
+#include "prng.h"
+#include "defs.h"
+#include "fat.h"
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+
+static point_t *pubkey;
+static bn_t privkey;
+
+static curve_t *curve;
+
+static size_t parse_data(const uint8_t *data, size_t len, const char *path, void(*callback)(const char *path, const uint8_t *data, size_t len, void *arg), void *callback_arg) {
+ size_t parsed = 0;
+ while (parsed < len) {
+ char name = (char) data[parsed];
+ bool recurse = false;
+ if (name & 0x80) {
+ name = name & 0x7f;
+ recurse = true;
+ }
+
+ uint8_t value_len = data[parsed + 1];
+ size_t path_len = strlen(path);
+ char new_path[path_len + 1 + 1];
+ strcpy(new_path, path);
+ new_path[path_len] = name;
+ new_path[path_len + 1] = '\0';
+
+ if (recurse) {
+ parsed += parse_data(data + parsed + 2, value_len, new_path, callback, callback_arg) + 2;
+ } else {
+ if (callback)
+ callback(new_path, data + parsed + 2, value_len, callback_arg);
+ parsed += value_len + 2;
+ }
+ }
+ return parsed;
+}
+
+static void parse_init_prng(const char *path, const uint8_t *data, size_t len, void *arg) {
+ prng_seed(data, len);
+}
+
+static uint8_t cmd_init_prng(uint8_t *data, uint16_t len) {
+ parse_data(data, len, "", parse_init_prng, NULL);
+ return 0;
+}
+
+static void parse_set_curve(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 }});
+ return;
+ }
+ {%- endfor %}
+ {%- for variable in curve_variables %}
+ if (strcmp(path, "g{{ variable }}") == 0) {
+ bn_from_bin(data, len, &curve->generator->{{ variable }});
+ return;
+ }
+ if (strcmp(path, "i{{ variable }}") == 0) {
+ bn_from_bin(data, len, &curve->neutral->{{ variable }});
+ return;
+ }
+ {%- endfor %}
+}
+
+static uint8_t cmd_set_curve(uint8_t *data, uint16_t len) {
+ // need p, [params], n, h, g[variables], i[variables]
+ parse_data(data, len, "", parse_set_curve, NULL);
+ return 0;
+}
+
+static uint8_t cmd_generate(uint8_t *data, uint16_t len) {
+ // generate a keypair, export privkey and affine pubkey
+ bn_init(&privkey);
+ bn_rand_mod(&privkey, &curve->n);
+ size_t priv_size = bn_to_bin_size(&privkey);
+ size_t coord_size = bn_to_bin_size(&curve->p);
+
+ scalar_mult(&privkey, curve->generator, curve, pubkey);
+
+ uint8_t priv[priv_size];
+ bn_to_bin(&privkey, priv);
+ simpleserial_put('s', priv_size, priv);
+ uint8_t pub[coord_size * {{ curve_parameters | length }}];
+ {%- for variable in curve_variables %}
+ bn_to_binpad(pubkey->{{ variable }}, pub + coord_size * {{ loop.index0 }}, coord_size);
+ {%- endfor %}
+ simpleserial_put('w', coord_size * {{ curve_parameters | length }}, pub);
+ return 0;
+}
+
+static void parse_set_privkey(const char *path, const uint8_t *data, size_t len, void *arg) {
+ if (strcmp(path, "s") == 0) {
+ bn_from_bin(data, len, &privkey);
+ return;
+ }
+}
+
+static uint8_t cmd_set_privkey(uint8_t *data, uint16_t len) {
+ // set the current privkey
+ parse_data(data, len, "", parse_set_privkey, NULL);
+ return 0;
+}
+
+static void parse_set_pubkey(const char *path, const uint8_t *data, size_t len, void *arg) {
+ {%- for variable in curve_variables %}
+ if (strcmp(path, "w{{ variable }}") == 0) {
+ bn_from_bin(data, len, &pubkey->{{ variable }});
+ return;
+ }
+ {%- endfor %}
+}
+
+static uint8_t cmd_set_pubkey(uint8_t *data, uint16_t len) {
+ // set the current pubkey
+ parse_data(data, len, "", parse_set_pubkey, NULL);
+ return 0;
+}
+
+static void parse_scalar_mult(const char *path, const uint8_t *data, size_t len, void *arg) {
+ bn_t *scalar = (bn_t *)arg;
+ if (strcmp(path, "s") == 0) {
+ bn_from_bin(data, len, scalar);
+ return;
+ }
+}
+
+static uint8_t cmd_scalar_mult(uint8_t *data, uint16_t len) {
+ // perform base point scalar mult with supplied scalar, return affine point.
+ bn_t scalar; bn_init(&scalar);
+ parse_data(data, len, "", parse_scalar_mult, (void *) &scalar);
+
+ point_t *result = point_new();
+
+ scalar_mult(&scalar, curve->generator, curve, result);
+
+ uint8_t res[coord_size * {{ curve_parameters | length }}];
+ {%- for variable in curve_variables %}
+ bn_to_binpad(result->{{ variable }}, res + coord_size * {{ loop.index0 }}, coord_size);
+ {%- endfor %}
+ simpleserial_put('w', coord_size * {{ curve_parameters | length }}, res);
+ bn_clear(&scalar);
+ point_free(&result);
+ return 0;
+}
+
+static void parse_ecdh(const char *path, const uint8_t *data, size_t len, void *arg) {
+ point_t *other = (point_t *) arg;
+ {%- for variable in curve_variables %}
+ if (strcmp(path, "w{{ variable }}") == 0) {
+ bn_from_bin(data, len, &other->{{ variable }});
+ return;
+ }
+ {%- endfor %}
+}
+
+static uint8_t cmd_ecdh(uint8_t *data, uint16_t len) {
+ //perform ECDH with provided point (and current privkey), output shared secret
+ point_t *other = point_new();
+ parse_data(data, len, "", parse_ecdh, (void *) other);
+
+ point_t *result = point_new();
+
+ scalar_mult(&privkey, other, curve, result);
+
+ bn_t x; bn_init(&x);
+ bn_t y; bn_init(&y);
+
+ point_to_affine(result, curve, &x, &y);
+
+ size_t size = bn_to_bin_size(&curve->p);
+
+ uint8_t x_raw[size];
+ bn_to_binpad(x, x_raw, size);
+
+ size_t h_size = hash_size(size);
+ void *h_ctx = hash_new_ctx();
+ hash_init(h_ctx);
+ uint8_t h_out[h_size];
+ hash_final(h_ctx, size, x_raw, h_out);
+ hash_free_ctx(h_ctx);
+
+ simpleserial_put('r', h_size, h_out);
+ bn_clear(&x);
+ bn_clear(&y);
+ point_free(result);
+ point_free(other);
+ return 0;
+}
+
+static void parse_ecdsa_msg(const char *path, const uint8_t *data, size_t len, void *arg) {
+ fat_t *dest = (fat_t *)arg;
+ if (strcmp(path, "d") == 0) {
+ dest->len = len;
+ dest->value = malloc(len);
+ memcpy(dest->value, data, len);
+ return;
+ }
+}
+
+static void parse_ecdsa_sig(const char *path, const uint8_t *data, size_t len, void *arg) {
+ fat_t *dest = (fat_t *)arg;
+ if (strcmp(path, "s") == 0) {
+ dest->len = len;
+ dest->value = malloc(len);
+ memcpy(dest->value, data, len);
+ return;
+ }
+}
+
+static uint8_t cmd_ecdsa_sign(uint8_t *data, uint16_t len) {
+ //perform ECDSA signature on supplied data, output signature
+ fat_t data = fat_empty;
+ parse_data(data, len, "", parse_ecdsa_msg, (void *) &data);
+
+ size_t h_size = hash_size(data.len);
+ void *h_ctx = hash_new_ctx();
+ hash_init(h_ctx);
+ uint8_t h_out[h_size];
+ hash_final(h_ctx, data.len, data.value, h_out);
+ hash_free_ctx(h_ctx);
+ free(data.value);
+
+ bn_t h; bn_init(&h);
+ bn_from_bin(h_out, h_size, &h);
+
+ int mod_len = bn_bit_length(&curve->n)
+
+ if (h_size * 8 > mod_len) {
+ bn_rsh(&h, (h_size * 8) - mod_len, &h);
+ }
+
+ bn_t k; bn_init(&k);
+ bn_rand_mod(&k, &curve->n);
+
+ point_t *p = point_new();
+
+ scalar_mult(&k, curve->generator, curve, p);
+
+ bn_t r; bn_init(&r);
+ point_to_affine(p, curve, &r, NULL);
+ bn_mod(&r, &curve->n, &r);
+
+ bn_t s; bn_init(&s);
+ bn_copy(&privkey, s);
+ bn_mul_mod(&s, &r, &curve->n, &s);
+ bn_add_mod(&s, &h, &curve->n, &s);
+ bn_div_mod(&s, &k, &curve->n, &s);
+
+ size_t result_len = 0;
+ uint8_t *result = as1n_der_encode(&r, &s, &result_len);
+
+ simpleserial_put('s', result_len, result);
+ free(result);
+ point_free(p);
+ bn_clear(&r);
+ bn_clear(&s);
+ bn_clear(&k);
+ bn_clear(&h);
+ return 0;
+}
+
+static uint8_t cmd_ecdsa_verify(uint8_t *data, uint16_t len) {
+ //perform ECDSA verification on supplied data and signature (and current pubkey), output status
+ fat_t data = fat_empty;
+ parse_data(data, len, "", parse_ecdsa_msg, (void *) &data);
+ fat_t sig = fat_empty;
+ parse_data(data, len, "", parse_ecdsa_sig, (void *) &sig);
+
+ size_t h_size = hash_size(data.len);
+ void *h_ctx = hash_new_ctx();
+ hash_init(h_ctx);
+ uint8_t h_out[h_size];
+ hash_final(h_ctx, data.len, data.value, h_out);
+ hash_free_ctx(h_ctx);
+ free(data.value);
+
+ bn_t h; bn_init(&h);
+ bn_from_bin(h_out, h_size, &h);
+
+ int mod_len = bn_bit_length(&curve->n)
+
+ if (h_size * 8 > mod_len) {
+ bn_rsh(&h, (h_size * 8) - mod_len, &h);
+ }
+
+ bn_t r; bn_init(&r);
+ bn_t s; bn_init(&s);
+ if (!asn1_der_decode(sig.value, sig.len, &r, &s)) {
+ simpleserial_put('v', 1, "\0");
+ bn_clear(&r);
+ bn_clear(&s);
+ bn_clear(&h);
+ free(sig.value);
+ return 0;
+ }
+ bn_t orig_r; bn_init(&orig_r);
+ bn_copy(&r, &orig_r);
+
+ bn_inv_mod(&s, &curve->n, &s);
+ bn_mul_mod(&r, &s, &curve->n, &r); //r = u2
+ bn_mul_mod(&h, &s, &curve->n, &h); //h = u1
+
+ point_t *p1 = point_new();
+ point_t *p2 = point_new();
+ scalar_mult(&h, curve->generator, curve, p1);
+ scalar_mult(&r, pubkey, curve, p2);
+
+ point_add(p1, p2, curve, p1);
+ bn_t x; bn_init(&x);
+ point_to_affine(p1, curve, &x, NULL);
+ bn_mod(&x, &curve->n, &x);
+
+ bool result = bn_eq(&orig_r, &x);
+ uint8_t res_data[1] = {(uint8_t) result};
+
+ simpleserial_put('v', 1, res_data);
+ point_free(p1);
+ point_free(p2);
+ bn_clear(&x);
+ bn_clear(&orig_r);
+ bn_clear(&h);
+ bn_clear(&r);
+ bn_clear(&s);
+ free(sig.value);
+ return 0;
+}
+
+int main(void) {
+ platform_init();
+ prng_init();
+ init_uart();
+ trigger_setup();
+
+ curve = curve_new();
+ pubkey = point_new();
+ bn_init(&privkey);
+
+ simpleserial_init();
+ simpleserial_addcmd('i', MAX_SS_LEN, cmd_init_prng);
+ simpleserial_addcmd('c', MAX_SS_LEN, cmd_set_curve);
+ simpleserial_addcmd('g', 0, cmd_generate);
+ simpleserial_addcmd('s', MAX_SS_LEN, cmd_set_privkey);
+ simpleserial_addcmd('w', MAX_SS_LEN, cmd_set_pubkey);
+ simpleserial_addcmd('m', MAX_SS_LEN, cmd_scalar_mult);
+ simpleserial_addcmd('e', MAX_SS_LEN, cmd_ecdh);
+ simpleserial_addcmd('a', MAX_SS_LEN, cmd_ecdsa_sign);
+ simpleserial_addcmd('v', MAX_SS_LEN, cmd_ecdsa_verify);
+ while(simpleserial_get());
+ return 0;
+} \ No newline at end of file
diff --git a/pyecsca/codegen/templates/ops.c b/pyecsca/codegen/templates/ops.c
index 96aa6ee..b6c22ba 100644
--- a/pyecsca/codegen/templates/ops.c
+++ b/pyecsca/codegen/templates/ops.c
@@ -10,6 +10,10 @@
{{ render_op(op, result, left, right, "curve->p")}}
{%- endfor %}
+{%- for src, dst in returns.items() %}
+ bn_copy(&{{ src }}, &{{ dst }});
+{%- endfor %}
+
{%- for free in frees %}
bn_clear(&{{ free }});
{%- endfor %} \ No newline at end of file