コード例 #1
0
def to_weierstrass(pt, curve):
    """Given a point P and an Montgomery Curve it is on, computes the equivalent point and curve
    in weierstrass form.

    Note: Multiple calls for same curve with different P will produce different output curves.
    This is due to y-coordinates being omitted in the representation. Without the ability to
    square-root y (mod n) by fixing B, the natural thing to do is to fix y and calculate B.
    So different point P produces different B.

    Args:
        pt (tuple(int, int)): Point P in XZ form.
        curve (tuple(int, int, int)): Curve in Montgomery form.

    Returns:
        tuple(tuple(int, int), tuple(int, int, int)): (Point, Curve), where

         -  Point = (t, v) in XY form.
         -  Curve = (a, b, n) representing the Elliptic Curve y**2 = x**3 + a*x + b (mod n).

    """
    x, z = pt
    A, _s, n = curve
    y_norm = 1
    x_norm = x * inv(z, n)
    B = (x_norm**3 + A * x_norm**2 + x_norm) % n
    assert B * y_norm**2 % n == (x_norm**3 + A * x_norm**2 + x_norm) % n
    B_inv = inv(B, n)
    three_inv = inv(3, n)
    t = (x_norm * B_inv + A * three_inv * B_inv) % n
    v = (y_norm * B_inv) % n
    a = (3 - A**2) * three_inv * B_inv * B_inv % n
    b = (2 * A**3 - 9 * A) * (three_inv * B_inv % n)**3 % n
    assert v**2 % n == (t**3 + a * t + b) % n
    return (t, v), (a, b, n)
コード例 #2
0
def get_curve_a(x, A, n):
    """Given parameters x and A, generate an Elliptic Curve (mod n) and a point on it.

    Args:
        x (int): Desired x coordinate of the point.
        A (int): Parameter A of Montgomery Curve.
        n (int): Modulus.

    Raises:
        CurveInitFail: Thrown when the curve generated by the given parameters fails the
            necessary conditions.

    Returns:
        tuple(tuple(int, int), tuple(int, int, int)): (Point, Curve), where

         -  Point = (x0, z0) in projective coordinates ignoring y.
         -  Curve = (A, s, n),
            representing B * (y/z) ** 2 == (x/z) ** 3 + A * (x/z) ** 2 + (x/z) (mod n),
            ignoring B and y.

             -  s = (A+2)/4 % n is precomputed for point doubling.

    """
    if A % n in (n - 2, 2):
        raise CurveInitFail()
    x0 = x % n
    z0 = 1
    s = (A + 2) * inv(4, n) % n
    # For completeness...
    # x0_norm = x0
    # y0_norm = 2
    # B = (x0_norm ** 3 + A * x0_norm ** 2 + x0_norm) * inv(y0_norm ** 2, n) % n
    # assert B * y0_norm ** 2 % n == (x0_norm ** 3 + A * x0_norm ** 2 + x0_norm) % n
    return (x0, z0), (A, s, n)
コード例 #3
0
 def test_inv_multi_error(self):
     n = 65537 * 65539
     element_list = range(60000, 65538)
     with self.assertRaises(InverseNotFound) as cm_target:
         _target = {element: inv(element, n) for element in element_list}
     with self.assertRaises(InverseNotFound) as cm_actual:
         _actual = inv_multi(element_list, n)
     self.assertEqual(gcd(cm_target.exception.x, n), 65537)
     self.assertEqual(gcd(cm_actual.exception.x, n), 65537)
コード例 #4
0
def get_curve_suyama(sigma, n):
    """Given parameter sigma, generate an Elliptic Curve (mod n) and a point on it using
    Suyama's parametrization.

    The constructed curve's group order is a multiple of 12, compared to 4 guaranteed for
    Montgomery Curves.

    Args:
        sigma (int): The sigma parameter.
        n (int): Modulus.

    Raises:
        CurveInitFail: Thrown when the curve generated by the given parameters fails the
            necessary conditions.

    Returns:
        tuple(tuple(int, int), tuple(int, int, int)): (Point, Curve), where

         -  Point = (x0, z0) in projective coordinates ignoring y.
         -  Curve = (A, s, n),
            representing B * (y/z) ** 2 == (x/z) ** 3 + A * (x/z) ** 2 + (x/z) (mod n),
            ignoring B and y.

             -  s = (A+2)/4 % n is precomputed for point doubling.

    """
    if sigma % n in (n - 5, n - 3, n - 1, 0, 1, 3,
                     5) or sigma * 3 % n in (n - 5, 5):
        raise CurveInitFail()
    u = sigma**2 - 5 % n
    v = 4 * sigma % n
    x0 = u**3 % n
    z0 = v**3 % n
    A = ((v - u)**3 * (3 * u + v) * inv(4 * u**3 * v, n) - 2) % n
    if A in (n - 2, 2):
        raise CurveInitFail()
    s = (A + 2) * inv(4, n) % n
    # For completeness...
    # B = u * inv(z0, n) % n
    # y = (sigma ** 2 - 1) * (sigma ** 2 - 25) * (sigma ** 4 - 25) % n
    # x0_norm = (x0 * inv(z0, n)) % n
    # y0_norm = (y * inv(z0, n)) % n
    # assert B * y0_norm ** 2 % n == (x0_norm ** 3 + A * x0_norm ** 2 + x0_norm) % n
    return (x0, z0), (A, s, n)
コード例 #5
0
def add_pt_exn(pt1, pt2, curve):
    """Adds two points pt1 and pt2 on curve.

    Args:
        pt1 (tuple(int, int)): Point (x1, y1). Use (None, None) for point at infinity.
        pt2 (tuple(int, int)): Point (x2, y2). Use (None, None) for point at infinity.
        curve (tuple(int, int, int)): (a, b, n) representing the
            Elliptic Curve y**2 = x**3 + a*x + b (mod n).

    Raises:
        InverseNotFound: Throws InverseNotFound when the sum is the point at infinity.

    Returns:
        tuple(int, int): Point pt1 + pt2.
    """
    _a, _b, n = curve
    gen = add_pt_gen(pt1, pt2, curve)
    inv_req = gen.send(None)
    if inv_req is None:
        return gen.send(None)
    else:
        return gen.send(inv(inv_req, n))
コード例 #6
0
 def test_inv_multi_normal(self):
     n = 65537 * 65539
     element_list = range(1, 65537)
     target = {element: inv(element, n) for element in element_list}
     actual = inv_multi(element_list, n)
     self.assertEqual(target, actual)
コード例 #7
0
def ecm(n, rounds, b1, b2):
    """Elliptic Curve Factorization Method. In each round, the following steps are performed:

        0. Generate random point and curve.
        1. Repeatedly multiply the current point by small primes raised to some power, determined
           by b1.
        2. Repeatedly try to multiply the point from step 1 by primes (with wheel of 2310)
           between b1 and b2.

    Returns when a non-trivial factor is found.

    Args:
        n (int): Number to be factorized. n >= 12.
        rounds (int): Number of random curves to try.
        b1 (int): Bound for primes used in step 1.
        b2 (int): Bound for primes searched for in step 2. b1 < b2.

    Raises:
        ValueError: Thrown when n < 12.

    Returns:
        int: Non-trivial factor if found, otherwise returns None.
    """
    if n < 12:
        raise ValueError
    wheel = 2310
    st = time.time()
    j_list, prime_array = init_wheel(b1, b2, wheel)
    print("Init time: {:.2f}".format(time.time() - st))
    for round_i in range(rounds):
        st = time.time()
        print("Round {}...".format(round_i))
        count = 0
        success = False
        while not success and count < 20:
            try:
                count += 1
                sigma = random.randint(6, n - 6)
                pt, curve = get_curve_suyama(sigma, n)
                success = True
            except InverseNotFound as e:
                res = gcd(e.x, n)
                if 1 < res < n:
                    return res
            except CurveInitFail:
                pass
        if not success:
            print(" - Curve Init Failed.")
            break
        try:
            # Step 1
            print("{:>5.2f}: Step 1".format(time.time() - st))
            for p in PRIME_GEN(b1):
                for _ in range(int(np.log(b1) / np.log(p))):
                    pt = mul_pt_exn(pt, curve, p)
            # Step 2
            print("{:>5.2f}: Step 2".format(time.time() - st))
            q = pt
            mq = mul_pt_exn(q, curve, wheel)
            xj_list = []
            for j in j_list:
                xj, zj = mul_pt_exn(q, curve, j)
                xj_list.append(xj * inv(zj, n) % n)
            c1 = b1 // wheel
            c2 = b2 // wheel + 2
            c = 0
            cq = mul_pt_exn(q, curve, c1 * wheel)
            cq_ = mul_pt_exn(q, curve, (c1 - 1) * wheel)
            while c < c2 - c1:
                s = 1
                for xj, is_prime in zip(
                        xj_list,
                        np.unpackbits(prime_array[c, :], bitorder="little")):
                    if is_prime:
                        t = (xj * cq[1] - cq[0]) % n
                        if t != 0:
                            s = s * t % n
                res = gcd(s, n)
                if 1 < res < n:
                    return res
                elif res == n:
                    for xj in xj_list:
                        res = gcd(xj * cq[1] - cq[0], n)
                        if 1 < res < n:
                            return res
                    # s is a multiple of n while each of {(xj *  cq[1] - cq[0]) % n} is not.
                    # There must be at least 2 non-trivial factors. The function should have returned.
                    assert False
                c += 1
                cq, cq_ = add_pt_exn(cq, mq, cq_, curve), cq
            print("{:>5.2f}: End".format(time.time() - st))
        except InverseNotFound as e:
            res = gcd(e.x, n)
            if 1 < res < n:
                return res
    return None