diff options
| -rw-r--r-- | pyecsca/ec/curve.py | 18 | ||||
| -rw-r--r-- | pyecsca/ec/efd/edwards/coordinates | 1 | ||||
| -rw-r--r-- | pyecsca/ec/efd/montgom/coordinates | 1 | ||||
| -rw-r--r-- | pyecsca/ec/efd/shortw/coordinates | 1 | ||||
| -rw-r--r-- | pyecsca/ec/efd/twisted/coordinates | 1 | ||||
| -rw-r--r-- | pyecsca/ec/formula.py | 20 | ||||
| -rw-r--r-- | pyecsca/ec/model.py | 3 | ||||
| -rw-r--r-- | pyecsca/ec/op.py | 15 | ||||
| -rw-r--r-- | test/ec/test_context.py | 2 | ||||
| -rw-r--r-- | test/ec/test_curve.py | 7 |
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) |
