aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--pyecsca/ec/curve.py18
-rw-r--r--pyecsca/ec/efd/edwards/coordinates1
-rw-r--r--pyecsca/ec/efd/montgom/coordinates1
-rw-r--r--pyecsca/ec/efd/shortw/coordinates1
-rw-r--r--pyecsca/ec/efd/twisted/coordinates1
-rw-r--r--pyecsca/ec/formula.py20
-rw-r--r--pyecsca/ec/model.py3
-rw-r--r--pyecsca/ec/op.py15
-rw-r--r--test/ec/test_context.py2
-rw-r--r--test/ec/test_curve.py7
10 files changed, 43 insertions, 26 deletions
diff --git a/pyecsca/ec/curve.py b/pyecsca/ec/curve.py
index 20b3902..4e41931 100644
--- a/pyecsca/ec/curve.py
+++ b/pyecsca/ec/curve.py
@@ -129,12 +129,13 @@ class EllipticCurve(object):
data = data[coord_len:]
return Point(self.coordinate_model, **coords)
elif encoded[0] in (0x02, 0x03):
- if isinstance(self.coordinate_model, AffineCoordinateModel) and isinstance(self.model, ShortWeierstrassModel):
+ if isinstance(self.coordinate_model, AffineCoordinateModel):
data = encoded[1:]
if len(data) != coord_len:
raise ValueError("Encoded point has bad length")
x = Mod(int.from_bytes(data, "big"), self.prime)
- rhs = x**3 + self.parameters["a"] * x + self.parameters["b"]
+ loc = {**self.parameters, "x": x}
+ rhs = eval(compile(self.model.ysquared, "", mode="eval"), loc)
if not rhs.is_residue():
raise ValueError("Point not on curve")
sqrt = rhs.sqrt()
@@ -149,6 +150,19 @@ class EllipticCurve(object):
else:
raise ValueError(f"Wrong encoding type: {hex(encoded[0])}, should be one of 0x04, 0x06, 0x02, 0x03 or 0x00")
+ def affine_random(self) -> Point:
+ """Generate a random affine point on the curve."""
+ while True:
+ x = Mod.random(self.prime)
+ loc = {**self.parameters, "x":x}
+ ysquared = eval(compile(self.model.ysquared, "", mode="eval"), loc)
+ if ysquared.is_residue():
+ y = ysquared.sqrt()
+ b = Mod.random(2)
+ if b == 1:
+ y = -y
+ return Point(AffineCoordinateModel(self.model), x=x, y=y)
+
def __eq__(self, other):
if not isinstance(other, EllipticCurve):
return False
diff --git a/pyecsca/ec/efd/edwards/coordinates b/pyecsca/ec/efd/edwards/coordinates
index dc85a7a..f70f3c8 100644
--- a/pyecsca/ec/efd/edwards/coordinates
+++ b/pyecsca/ec/efd/edwards/coordinates
@@ -4,6 +4,7 @@ parameter d
coordinate x
coordinate y
satisfying x^2+y^2 == c^2*(1+d*x^2*y^2)
+ysquared (x^2-c^2)/(c^2*d*x^2-1)
addition x = (x1*y2+y1*x2)/(c(1+d*x1*x2*y1*y2))
addition y = (y1*y2-x1*x2)/(c(1-d*x1*x2*y1*y2))
doubling x = (x1*y1+y1*x1)/(c(1+d*x1*x1*y1*y1))
diff --git a/pyecsca/ec/efd/montgom/coordinates b/pyecsca/ec/efd/montgom/coordinates
index 0821ec6..d3b7f4e 100644
--- a/pyecsca/ec/efd/montgom/coordinates
+++ b/pyecsca/ec/efd/montgom/coordinates
@@ -4,6 +4,7 @@ parameter b
coordinate x
coordinate y
satisfying b*y^2 == x^3 + a*x^2 + x
+ysquared (x^3+a*x^2+x)/b
addition x = b*(y2-y1)^2/(x2-x1)^2-a-x1-x2
addition y = (2*x1+x2+a)*(y2-y1)/(x2-x1)-b*(y2-y1)^3/(x2-x1)^3-y1
doubling x = b*(3*x1^2+2*a*x1+1)^2/(2*b*y1)^2-a-x1-x1
diff --git a/pyecsca/ec/efd/shortw/coordinates b/pyecsca/ec/efd/shortw/coordinates
index 683d86d..fa93043 100644
--- a/pyecsca/ec/efd/shortw/coordinates
+++ b/pyecsca/ec/efd/shortw/coordinates
@@ -4,6 +4,7 @@ parameter b
coordinate x
coordinate y
satisfying y^2 == x^3 + a*x + b
+ysquared x^3+a*x+b
addition x = (y2-y1)^2/(x2-x1)^2-x1-x2
addition y = (2*x1+x2)*(y2-y1)/(x2-x1)-(y2-y1)^3/(x2-x1)^3-y1
doubling x = (3*x1^2+a)^2/(2*y1)^2-x1-x1
diff --git a/pyecsca/ec/efd/twisted/coordinates b/pyecsca/ec/efd/twisted/coordinates
index 1a0d32d..bf62fff 100644
--- a/pyecsca/ec/efd/twisted/coordinates
+++ b/pyecsca/ec/efd/twisted/coordinates
@@ -4,6 +4,7 @@ parameter d
coordinate x
coordinate y
satisfying a*x^2+y^2 == 1+d*x^2*y^2
+ysquared (a*x^2-1)/(d*x^2-1)
addition x = (x1*y2+y1*x2)/(1+d*x1*x2*y1*y2)
addition y = (y1*y2-a*x1*x2)/(1-d*x1*x2*y1*y2)
doubling x = (x1*y1+y1*x1)/(1+d*x1*x1*y1*y1)
diff --git a/pyecsca/ec/formula.py b/pyecsca/ec/formula.py
index c10c79e..f3fdc4a 100644
--- a/pyecsca/ec/formula.py
+++ b/pyecsca/ec/formula.py
@@ -6,7 +6,7 @@ from typing import List, Set, Any, ClassVar, MutableMapping, Tuple, Union
from pkg_resources import resource_stream
from public import public
-from .context import ResultAction
+from .context import ResultAction, getcontext, NullContext
from .mod import Mod
from .op import CodeOp, OpType
@@ -55,6 +55,8 @@ class FormulaAction(ResultAction):
self.output_points = []
def add_operation(self, op: CodeOp, value: Mod):
+ if isinstance(getcontext(), NullContext):
+ return
parents: List[Union[Mod, OpResult]] = []
for parent in {*op.variables, *op.parameters}:
if parent in self.intermediates:
@@ -64,6 +66,8 @@ class FormulaAction(ResultAction):
self.intermediates[op.result] = OpResult(op.result, value, op.operator, *parents)
def add_result(self, point: Any, **outputs: Mod):
+ if isinstance(getcontext(), NullContext):
+ return
for k in outputs:
self.outputs[k] = self.intermediates[k]
self.output_points.append(point)
@@ -99,18 +103,16 @@ class Formula(ABC):
from .point import Point
if len(points) != self.num_inputs:
raise ValueError(f"Wrong number of inputs for {self}.")
- coords = {}
for i, point in enumerate(points):
if point.coordinate_model != self.coordinate_model:
raise ValueError(f"Wrong coordinate model of point {point}.")
for coord, value in point.coords.items():
- coords[coord + str(i + 1)] = value
- locals = {**coords, **params}
- with FormulaAction(self, *points, **locals) as action:
+ params[coord + str(i + 1)] = value
+ with FormulaAction(self, *points, **params) as action:
for op in self.code:
- op_result = op(**locals)
+ op_result = op(**params)
action.add_operation(op, op_result)
- locals[op.result] = op_result
+ params[op.result] = op_result
result = []
for i in range(self.num_outputs):
ind = str(i + self.output_index)
@@ -118,8 +120,8 @@ class Formula(ABC):
full_resulting = {}
for variable in self.coordinate_model.variables:
full_variable = variable + ind
- resulting[variable] = locals[full_variable]
- full_resulting[full_variable] = locals[full_variable]
+ resulting[variable] = params[full_variable]
+ full_resulting[full_variable] = params[full_variable]
point = Point(self.coordinate_model, **resulting)
action.add_result(point, **full_resulting)
diff --git a/pyecsca/ec/model.py b/pyecsca/ec/model.py
index a28e700..4832e3c 100644
--- a/pyecsca/ec/model.py
+++ b/pyecsca/ec/model.py
@@ -16,6 +16,7 @@ class CurveModel(object):
parameter_names: List[str]
coordinate_names: List[str]
equation: Expression
+ ysquared: Expression
base_addition: List[Module]
base_doubling: List[Module]
base_negation: List[Module]
@@ -70,6 +71,8 @@ class EFDCurveModel(CurveModel):
cls.coordinate_names.append(line[11:])
elif line.startswith("satisfying"):
cls.equation = format_eq(line[11:], mode="eval")
+ elif line.startswith("ysquared"):
+ cls.ysquared = format_eq(line[9:], mode="eval")
elif line.startswith("addition"):
cls.base_addition.append(format_eq(line[9:]))
elif line.startswith("doubling"):
diff --git a/pyecsca/ec/op.py b/pyecsca/ec/op.py
index d0cec58..d72716d 100644
--- a/pyecsca/ec/op.py
+++ b/pyecsca/ec/op.py
@@ -107,16 +107,5 @@ class CodeOp(object):
def __call__(self, *args, **kwargs: Mod) -> Mod:
"""Execute this operation with kwargs."""
- loc = dict(kwargs)
- exec(self.compiled, {}, loc)
- return loc[self.result]
-
-
-@public
-class OperationAction(ResultAction):
- """An operation."""
- operation: CodeOp
-
- def __init__(self, operation: CodeOp):
- super().__init__()
- self.operation = operation
+ exec(self.compiled, {}, kwargs)
+ return kwargs[self.result]
diff --git a/test/ec/test_context.py b/test/ec/test_context.py
index c3112d4..603369d 100644
--- a/test/ec/test_context.py
+++ b/test/ec/test_context.py
@@ -86,8 +86,6 @@ class ContextTests(TestCase):
with local(PathContext([0, 1, 7])) as ctx:
key_generator = KeyGeneration(self.mult, self.secp128r1, True)
key_generator.generate()
- print(ctx.value)
-
def test_str(self):
with local(DefaultContext()) as default:
diff --git a/test/ec/test_curve.py b/test/ec/test_curve.py
index f9e3387..a480bb0 100644
--- a/test/ec/test_curve.py
+++ b/test/ec/test_curve.py
@@ -70,6 +70,13 @@ class CurveTests(TestCase):
self.assertIsNone(self.curve25519.curve.affine_neutral)
self.assertIsNotNone(self.ed25519.curve.affine_neutral)
+ def test_affine_random(self):
+ for params in [self.secp128r1, self.curve25519, self.ed25519]:
+ for _ in range(20):
+ pt = params.curve.affine_random()
+ self.assertIsNotNone(pt)
+ self.assertTrue(params.curve.is_on_curve(pt))
+
def test_neutral_is_affine(self):
self.assertFalse(self.secp128r1.curve.neutral_is_affine)
self.assertFalse(self.curve25519.curve.neutral_is_affine)