def SW2TE(params: DomainParameters) -> DomainParameters: """ Convert a ShortWeierstrass curve to TwistedEdwards. :param params: The domain parameters to convert. :return: The converted domain parameters. """ if not isinstance( params.curve.model, ShortWeierstrassModel) or not isinstance( params.curve.coordinate_model, AffineCoordinateModel): raise ValueError ax = symbols("α") field = FF(params.curve.prime) rhs = Poly( ax**3 + field(int(params.curve.parameters["a"])) * ax + field(int(params.curve.parameters["b"])), ax, domain=field, ) roots = rhs.ground_roots() if not roots: raise ValueError( "Curve cannot be transformed to Montgomery model (x^3 + ax + b has no root)." ) alpha = Mod(int(next(iter(roots.keys()))), params.curve.prime) beta = (3 * alpha**2 + params.curve.parameters["a"]).sqrt() def map_parameters(a, b): a = 3 * alpha + 2 * beta d = 3 * alpha - 2 * beta return {"a": a, "d": d} def map_point(a, b, pt, aff): if params.curve.is_neutral(pt): u = Mod(0, params.curve.prime) v = Mod(1, params.curve.prime) elif pt.x == alpha and pt.y == 0: u = Mod(0, params.curve.prime) v = Mod(-1, params.curve.prime) else: u = (pt.x - alpha) / pt.y v = (pt.x - alpha - beta) / (pt.x - alpha + beta) return Point(aff, x=u, y=v) return __M_map(params, ("a", "b"), map_parameters, map_point, TwistedEdwardsModel())
def SW2M(params: DomainParameters) -> DomainParameters: """ Convert a ShortWeierstrass curve to Montgomery. :param params: The domain parameters to convert. :return: The converted domain parameters. """ if not isinstance( params.curve.model, ShortWeierstrassModel) or not isinstance( params.curve.coordinate_model, AffineCoordinateModel): raise ValueError ax = symbols("α") field = FF(params.curve.prime) rhs = Poly( ax**3 + field(int(params.curve.parameters["a"])) * ax + field(int(params.curve.parameters["b"])), ax, domain=field, ) roots = rhs.ground_roots() if not roots: raise ValueError( "Curve cannot be transformed to Montgomery model (x^3 + ax + b has no root)." ) alpha = Mod(int(next(iter(roots.keys()))), params.curve.prime) beta = (3 * alpha**2 + params.curve.parameters["a"]).sqrt() def map_parameters(a, b): A = (3 * alpha) / beta B = 1 / beta return {"a": A, "b": B} def map_point(a, b, pt, aff): u = (pt.x - alpha) / beta v = pt.y / beta return Point(aff, x=u, y=v) return __M_map(params, ("a", "b"), map_parameters, map_point, MontgomeryModel())
def _create_params(curve, coords, infty): if curve["field"]["type"] == "Binary": raise ValueError("Binary field curves are currently not supported.") if curve["field"]["type"] == "Extension": raise ValueError("Extension field curves are currently not supported.") # Get model and param names model: CurveModel field = int(curve["field"]["p"], 16) order = int(curve["order"], 16) cofactor = int(curve["cofactor"], 16) if curve["form"] == "Weierstrass": model = ShortWeierstrassModel() param_names = ["a", "b"] elif curve["form"] == "Montgomery": model = MontgomeryModel() param_names = ["a", "b"] elif curve["form"] == "Edwards": model = EdwardsModel() param_names = ["c", "d"] elif curve["form"] == "TwistedEdwards": model = TwistedEdwardsModel() param_names = ["a", "d"] else: raise ValueError("Unknown curve model.") params = { name: Mod(int(curve["params"][name]["raw"], 16), field) for name in param_names } # Check coordinate model name and assumptions coord_model: CoordinateModel if coords == "affine": coord_model = AffineCoordinateModel(model) else: if coords not in model.coordinates: raise ValueError("Coordinate model not supported for curve.") coord_model = model.coordinates[coords] for assumption in coord_model.assumptions: # Try to execute assumption, if it works, check with curve parameters # if it doesn't work, move all over to rhs and construct a sympy polynomial of it # then find roots and take first one for new value for new coordinate parameter. try: alocals: Dict[str, Union[Mod, int]] = {} compiled = compile(assumption, "", mode="exec") exec(compiled, None, alocals) for param, value in alocals.items(): if params[param] != value: raise_unsatisified_assumption( getconfig().ec. unsatisfied_coordinate_assumption_action, f"Coordinate model {coord_model} has an unsatisifed assumption on the {param} parameter (= {value}).", ) except NameError: k = FF(field) assumption_string = unparse(assumption) lhs, rhs = assumption_string.split(" = ") expr = sympify(f"{rhs} - {lhs}") for curve_param, value in params.items(): expr = expr.subs(curve_param, k(value)) if (len(expr.free_symbols) > 1 or (param := str(expr.free_symbols.pop())) not in coord_model.parameters): raise ValueError( f"This coordinate model couldn't be loaded due to an unsupported assumption ({assumption_string})." ) poly = Poly(expr, symbols(param), domain=k) roots = poly.ground_roots() for root in roots: params[param] = Mod(int(root), field) break else: raise UnsatisfiedAssumptionError( f"Coordinate model {coord_model} has an unsatisifed assumption on the {param} parameter (0 = {expr})." )
def __validate_assumptions(self, field, params): # Validate assumptions and compute formula parameters. # TODO: Should this also validate coordinate assumptions and compute their parameters? is_symbolic = any(isinstance(x, SymbolicMod) for x in params.values()) for assumption in self.assumptions: assumption_string = unparse(assumption)[1:-2] lhs, rhs = assumption_string.split(" == ") if lhs in params: # Handle an assumption check on value of input points. alocals: Dict[str, Union[Mod, int]] = {**params} compiled = compile(assumption, "", mode="eval") holds = eval(compiled, None, alocals) if not holds: # The assumption doesn't hold, see what is the current configured action and do it. raise_unsatisified_assumption( getconfig().ec.unsatisfied_formula_assumption_action, f"Unsatisfied assumption in the formula ({assumption_string}).", ) elif lhs in self.parameters and is_symbolic: # Handle a symbolic assignment to a new parameter. k = FF(field) expr = sympify(rhs, evaluate=False) for curve_param, value in params.items(): if isinstance(value, SymbolicMod): expr = expr.subs(curve_param, value.x) else: expr = expr.subs(curve_param, k(value)) params[lhs] = SymbolicMod(expr, field) else: k = FF(field) expr = sympify(f"{rhs} - {lhs}", evaluate=False) for curve_param, value in params.items(): if isinstance(value, SymbolicMod): expr = expr.subs(curve_param, value.x) else: expr = expr.subs(curve_param, k(value)) if (len(expr.free_symbols) > 1 or (param := str( expr.free_symbols.pop())) not in self.parameters): raise ValueError( f"This formula couldn't be executed due to an unsupported assumption ({assumption_string})." ) def resolve(expression): if not expression.args: return expression args = [] for arg in expression.args: if isinstance(arg, Rational): a = arg.p b = arg.q arg = k(a) / k(b) else: arg = resolve(arg) args.append(arg) return expression.func(*args) expr = resolve(expr) poly = Poly(expr, symbols(param), domain=k) roots = poly.ground_roots() for root in roots: params[param] = Mod(int(root), field) break else: raise UnsatisfiedAssumptionError( f"Unsatisfied assumption in the formula ({assumption_string}).\n" f"'{expr}' has no roots in the base field {k}.")