Exemplo n.º 1
0
def product_tree(poly_list, n):
    """Product Tree Algorithm. Multiply a list of polynomials, poly_list.

    The leaf nodes are populated by polynomials in poly_list. If the length of poly_list is not
    a power of 2, the remaining leaf nodes are takes the value of the polynomial f(x) = 1.
    The value of each internal node is the product of its children.

    Args:
        poly_list (list(Polynomial)): List of polynomials to multiply.
        n (int): Modulus.

    Returns:
        list(Polynomial): The Product Tree, a complete binary tree in list form.
        The root node is at position 0 of the list. The children of node i are
        node 2*i+1 and node 2*i+2.
    """
    poly_num = len(poly_list)
    k = 1
    while k < poly_num:
        k *= 2
    res = [None for _ in range(k * 2 - 1)]
    for i in range(poly_num):
        res[k + i - 1] = poly_list[i]
    for i in range(poly_num, k):
        res[k + i - 1] = Polynomial([1], n)
    while k > 1:
        for i in range(k // 2 - 1, k - 1):
            res[i] = res[2 * i + 1] * res[2 * i + 2]
        k //= 2
    return res
Exemplo n.º 2
0
 def test_sub(self):
     n = 4
     a = [0]
     b = [3]
     c = [1]
     self.assertEqual(Polynomial(a, n) - Polynomial(b, n), Polynomial(c, n))
     n = 4
     a = [0, 1, 2, 3, 0, 1]
     b = [3, 3, 2, 2, 1, 1]
     c = [1, 2, 0, 1, 3]
     self.assertEqual(Polynomial(a, n) - Polynomial(b, n), Polynomial(c, n))
     n = 5
     a = [0, 1, 2, 3]
     b = [3, 3, 2, 2, 1, 1]
     c = [2, 3, 0, 1, 4, 4]
     self.assertEqual(Polynomial(a, n) - Polynomial(b, n), Polynomial(c, n))
Exemplo n.º 3
0
 def test_add(self):
     n = 4
     a = [0]
     b = [3]
     c = [3]
     self.assertEqual(Polynomial(a, n) + Polynomial(b, n), Polynomial(c, n))
     n = 4
     a = [0, 1, 2, 3, 3]
     b = [3, 3, 2, 2, 1]
     c = [3, 0, 0, 1]
     self.assertEqual(Polynomial(a, n) + Polynomial(b, n), Polynomial(c, n))
     n = 4
     a = [0, 1, 2, 3]
     b = [3, 3, 2, 2, 1]
     c = [3, 0, 0, 1, 1]
     self.assertEqual(Polynomial(a, n) + Polynomial(b, n), Polynomial(c, n))
Exemplo n.º 4
0
 def test_mul(self):
     random.seed(2)
     n = 5
     a = [3]
     b = [4]
     c = mul(a, b, n)
     self.assertEqual(Polynomial(a, n) * Polynomial(b, n), Polynomial(c, n))
     n = 5
     a = [4 for _ in range(10)]
     b = [4 for _ in range(100)]
     c = mul(a, b, n)
     self.assertEqual(Polynomial(a, n) * Polynomial(b, n), Polynomial(c, n))
     n = 97
     a = [random.randint(0, n - 1) for _ in range(100)]
     b = [random.randint(0, n - 1) for _ in range(1000)]
     c = mul(a, b, n)
     self.assertEqual(Polynomial(a, n) * Polynomial(b, n), Polynomial(c, n))
Exemplo n.º 5
0
 def test_divmod(self):
     random.seed(2)
     n = 5
     a = [3]
     b = [4]
     q, r = divmod(Polynomial(a, n), Polynomial(b, n))
     self.assertEqual(len(r.coeff), 1)
     self.assertEqual(len(q.coeff), 1)
     self.assertEqual(q * Polynomial(b, n) + r, Polynomial(a, n))
     n = 5
     a = [4 for _ in range(100)]
     b = [4 for _ in range(10)]
     q, r = divmod(Polynomial(a, n), Polynomial(b, n))
     self.assertLess(len(r.coeff), len(b))
     self.assertEqual(len(q.coeff), len(a) - len(b) + 1)
     self.assertEqual(q * Polynomial(b, n) + r, Polynomial(a, n))
     n = 97
     a = [random.randint(0, n - 1) for _ in range(1000)]
     b = [random.randint(0, n - 1) for _ in range(100)]
     q, r = divmod(Polynomial(a, n), Polynomial(b, n))
     self.assertLess(len(r.coeff), len(b))
     self.assertEqual(len(q.coeff), len(a) - len(b) + 1)
     self.assertEqual(q * Polynomial(b, n) + r, Polynomial(a, n))
Exemplo n.º 6
0
 def test_mod_with_recip(self):
     n = 5
     a1 = Polynomial([3], n)
     a2 = Polynomial([2], n)
     b = Polynomial([4], n)
     b_recip = b.recip()
     self.assertEqual(divmod(a1, b)[1], a1.mod_with_recip(b, b_recip))
     self.assertEqual(divmod(a2, b)[1], a2.mod_with_recip(b, b_recip))
     n = 5
     a1 = Polynomial(list(range(5)) * 20, n)
     a2 = Polynomial(list(range(5)) * 10, n)
     b = Polynomial([1, 2, 3, 1], n)
     b_recip = b.recip()
     self.assertEqual(divmod(a1, b)[1], a1.mod_with_recip(b, b_recip))
     self.assertEqual(divmod(a2, b)[1], a2.mod_with_recip(b, b_recip))
Exemplo n.º 7
0
 def test_recip(self):
     random.seed(2)
     n = 5
     a = [3]
     self.assertEqual(Polynomial(recip(a, n), n), Polynomial(a, n).recip())
     n = 5
     a = [4 for _ in range(100)]
     self.assertEqual(Polynomial(recip(a, n), n), Polynomial(a, n).recip())
     n = 97
     a = [random.randint(0, n - 1) for _ in range(1000)]
     self.assertEqual(Polynomial(recip(a, n), n), Polynomial(a, n).recip())
     n = 97
     a = [random.randint(0, n - 1) for _ in range(63)]
     self.assertEqual(Polynomial(recip(a, n), n), Polynomial(a, n).recip())
     n = 97
     a = [random.randint(0, n - 1) for _ in range(64)]
     self.assertEqual(Polynomial(recip(a, n), n), Polynomial(a, n).recip())
     n = 97
     a = [random.randint(0, n - 1) for _ in range(65)]
     self.assertEqual(Polynomial(recip(a, n), n), Polynomial(a, n).recip())
Exemplo n.º 8
0
def ecm(n, rounds, b1, b2, wheel=2310, output=True):
    """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. Standard continuation from b1 to b2 with Brent-Suyama's Extension and Polyeval.

    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.
        wheel (int, optional): Wheel, where only numbers coprime to wheel will be considered in
            step 2. Defaults to 2310.
        output (bool, optional): Whether to print progress to stdout. Defaults to True.

    Raises:
        ValueError: Thrown when n < 12.

    Returns:
        int: Non-trivial factor if found, otherwise returns None.
    """
    if n < 12:
        raise ValueError
    j_list = [j for j in range(1, wheel // 2) if gcd(j, wheel) == 1]
    block_size = 1 << (len(j_list) - 1).bit_length() - 1
    for round_i in range(rounds):
        if output:
            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)
                mnt_pt, mnt_curve = mnt.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
            if output:
                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))):
                    mnt_pt = mnt.mul_pt_exn(mnt_pt, mnt_curve, p)
            # Step 2
            if output:
                print("{:>5.2f}: Step 2".format(time.time() - st))
            polynomial = (2, 0, 9, 0, 6, 0, 1)  # f(x) = x^6 + 6x^4 + 9x^2 + 2
            q, wst_curve = mnt.to_weierstrass(mnt_pt, mnt_curve)
            c1 = b1 // wheel
            c2 = b2 // wheel + 2
            c = 0
            k_ls = [apply_polynomial(polynomial, j) for j in j_list
                    ] + get_difference_seq(polynomial, c1 * wheel, wheel)
            mul_res = wst.mul_pt_multi(q, wst_curve, k_ls)
            xj_list = []
            for i in range(len(j_list)):
                xj_list.append(mul_res[i][0])
            cq_list = mul_res[len(j_list):]
            f_tree = product_tree(
                [Polynomial([n - xj, 1], n) for xj in xj_list], n)
            f_recip_tree = recip_tree(f_tree)
            H = Polynomial([1], n)
            g_poly_list = []
            while c < c2 - c1:
                for _ in range(min(block_size, c2 - c1 - c)):
                    g_poly_list.append(Polynomial([n - cq_list[0][0], 1], n))
                    step_difference_seq_exn(cq_list, wst_curve)
                    c += 1
                G = product_tree(g_poly_list, n)[0]
                H = (H * G).mod_with_recip(f_tree[0], f_recip_tree[0])
                g_poly_list.clear()
            rem_tree = remainder_tree(H, f_tree, f_recip_tree, n)
            res = gcd(rem_tree[0], n)
            if 1 < res < n:
                return res
            elif res == n:
                for rem in rem_tree[len(rem_tree) // 2:]:
                    res = gcd(rem, n)
                    if 1 < res < n:
                        return res
                assert False
            if output:
                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