def test_shanks_middle(numOfTests: int,
                       numOfBits: list,
                       randSeed=0,
                       centered=True):
    import matplotlib.pyplot as plt
    seed(randSeed)
    giant_steps_class_list, times_clasic = [], []
    giant_steps_centered_list, times_centered = [], []
    for bits in numOfBits:
        time_clas, time_cent = [], []
        giant_clas, giant_cent = [], []
        for iter in range(numOfTests):
            p, g, exp, h = gnp.logarithm_test_numbers(bits, centered)
            # print("iter:", iter)
            t = timer()
            x_c, _, giant_steps_c, _ = shanks_classic(g, h, p, p - 1)
            giant_clas.append(giant_steps_c)
            passed_time = (timer() - t) * 1000
            time_clas.append(passed_time)
            # print(f"C_passed x:{x_c}, exp:{exp}, sm:{small_steps_c}, gs:{giant_steps_c} time:{passed_time:.3f}")

            t = timer()
            x_m, _, giant_steps_m = shanks_centered(g, h, p, p - 1)
            giant_cent.append(giant_steps_m)
            passed_time = (timer() - t) * 1000
            time_cent.append(passed_time)
            # print(f"M_passed x:{x_c}, exp:{exp}, sm:{small_steps_m}, gs:{giant_steps_m} time:{passed_time:.3f} \n")
        print()
        giant_steps_class_list.append(avg(giant_clas))
        giant_steps_centered_list.append(avg(giant_cent))
        times_clasic.append(avg(time_clas))
        times_centered.append(avg(time_cent))
Beispiel #2
0
def test_pohlig_primes(bitlist: list,
                       algQe_type=pohlig_hellman_alg,
                       solver='shanks',
                       shanks_type='classic',
                       pollard_cycle='brent',
                       pollard_func='teske',
                       rand_seed=0):
    seed(rand_seed)
    if solver == 'shanks':
        Solver = partial(Shanks, type=shanks_type, r=2.25)
    else:
        Solver = partial(pollard_rho,
                         cycle=pollard_cycle,
                         func=pollard_func,
                         rand_seed=rand_seed)
    for ind, bits in enumerate(bitlist):
        p, g, exp, h = logarithm_test_numbers(bits, silvPohHell=True)
        print(list(factorint(p - 1).keys())[-1], countBits(p))
        t = timer()
        x = silver_pohlig_hellman_alg(g,
                                      h,
                                      p,
                                      fact=factorint,
                                      qeAlg=algQe_type,
                                      solver=Solver)
        if x != exp:
            print("WRONG!")
        print(f"Bits: {bits}, time: {(timer() - t) * 1000: .4f}")
def test_shanks(numOfTests: int, numOfBits: int, type: str, r=2):
    times = []
    for _ in range(numOfTests):
        p, g, e, h = gnp.logarithm_test_numbers(1, numOfBits)
        if type == 'c':
            t_start = time.time()
            x, small_steps, giant_steps = Shanks_ordin_cunoscut(
                g[0], h[0], p[0], p[0] - 1)
        elif type == 'g':
            t_start = time.time()
            x, small_steps, giant_steps = Shanks_general(
                g[0], h[0], p[0], p[0] - 1, r)
        else:
            l, m = optim_factors(p[0] - 1)
            t_start = time.time()
            x, small_steps, giant_steps = Shanks_factor(g[0], h[0], p[0], l, m)
        t_stop = time.time()
        if e[0] != x:
            print(f"e:{e[0]}  x:{x}")
        else:
            t = (t_stop - t_start) / 1000
            times.append(t)
            print(
                f"Test passed! p:{p[0]}, time:{t:.7f} ms, small_steps:{small_steps} giant_steps:{giant_steps}"
            )
    print(f"Avg time:{avg(times)}")
def test_pollard(numOfTests: int,
                 listOfBits: list,
                 contests: dict,
                 img_path: str,
                 rand_seeds=[0]):
    import matplotlib.pyplot as plt
    from matplotlib.lines import Line2D
    from itertools import cycle
    marker = cycle(rand.sample(Line2D.markers.keys(), len(contests)))
    plt.tight_layout(pad=0.05)

    times = [[[0 for _ in rand_seeds] for _ in contests] for _ in listOfBits]
    times_avg = [[0 for _ in contests] for _ in listOfBits]
    iterations = [[[0 for _ in rand_seeds] for _ in contests]
                  for _ in listOfBits]
    iterations_avg = [[0 for _ in contests] for _ in listOfBits]

    for ind_b, bits in enumerate(listOfBits):
        print("Bits: ", bits)
        tests = num_of_tests(bits, numOfTests)
        print("Nr of tests: ", tests)
        p_set = set()
        print("Seed: ", end='')
        for ind_s, seed in enumerate(rand_seeds):
            rand.seed(seed)
            print(seed, end=', ')
            distinct_primes = number_of_distinct_primes(bits)
            for _ in range(tests):
                p, g, exp, h = logarithm_test_numbers(bits, safe=False)
                p_iter = 0
                while p in p_set and len(
                        p_set) < distinct_primes - 1 and p_iter < 10**2:
                    p, g, exp, h = logarithm_test_numbers(bits, safe=False)
                    p_iter += 1
                p_set.add(p)

                bit_seed = rand.randint(1, seed)
                for ind_c, c in enumerate(contests):
                    t = timer()
                    x, iter = pollard_rho(g,
                                          h,
                                          p,
                                          cycle=c[0],
                                          func=c[1],
                                          rand_seed=bit_seed)
                    if x != exp:
                        print("WRONG " + c[0] + " " + c[1])
                    times[ind_b][ind_c][ind_s] += (timer() - t) * 1000
                    iterations[ind_b][ind_c][ind_s] += iter

            for ind_c, c in enumerate(contests):
                iterations[ind_b][ind_c][ind_s] /= tests
                times[ind_b][ind_c][ind_s] /= tests
        print()
        for ind_c, c in enumerate(contests):
            iterations_avg[ind_b][ind_c] = avg(
                iterations[ind_b][ind_c]) / ceil(sqrt(p))
            times_avg[ind_b][ind_c] = avg(times[ind_b][ind_c])
            print(
                f"Cycle: {c[0]}, function: {c[1]}, itertions: {iterations_avg[ind_b][ind_c]:.4f}, time: {times_avg[ind_b][ind_c]:.3f}"
            )
        print()

    plt.figure(0)
    for ind_c, c in enumerate(contests):
        the_times = [t[ind_c] for t in times_avg]
        plt.plot(listOfBits,
                 the_times,
                 marker=next(marker),
                 label=c[0] + '_' + c[1])
    plt.legend()
    plt.ylabel("Milisecunde")
    plt.xlabel("biti")
    # plt.ticklabel_format(style='sci', axis='y', scilimits=(0, 0))
    plt.yscale('log')
    plt.savefig(img_path + '/pollard_time.png', bbox_inches='tight')

    plt.figure(1)
    print("The avg number of iterations: ", end='')
    avgits = []
    for ind_c, c in enumerate(contests):
        the_iterations = [it[ind_c] for it in iterations_avg]
        avg_c = avg(the_iterations)
        print(c[0] + '-' + c[1] + f": {avg_c:.4f}", end=' ')
        avgits.append(avg_c)
        plt.plot(listOfBits,
                 the_iterations,
                 marker=next(marker),
                 label=c[0] + '_' + c[1])
    plt.legend()
    plt.ylabel("Iteratii")
    plt.xlabel("biti")
    # plt.ticklabel_format(style='sci', axis='y', scilimits=(0, 0))
    plt.yscale('log')
    plt.savefig(img_path + '/pollard_iter.png', bbox_inches='tight')
    plt.show()
    return avgits
def test_pollard_dellays(numOfTests: int,
                         listOfBits: list,
                         contests: dict,
                         img_path: str,
                         rand_seeds=[0]):
    iterations = [[[0 for _ in rand_seeds] for _ in contests]
                  for _ in listOfBits]
    iterations_avg = [[0 for _ in contests] for _ in listOfBits]

    lambs = [[[0 for _ in rand_seeds] for _ in contests] for _ in listOfBits]
    lambs_avg = [[0 for _ in contests] for _ in listOfBits]

    mus = [[[0 for _ in rand_seeds] for _ in contests] for _ in listOfBits]
    mus_avg = [[0 for _ in contests] for _ in listOfBits]

    for ind_b, bits in enumerate(listOfBits):
        print("Bits: ", bits)
        tests = num_of_tests(bits, numOfTests)
        print("Nr of tests: ", tests)
        p_set = set()
        print("Seed: ", end='')
        for ind_s, seed in enumerate(rand_seeds):
            rand.seed(seed)
            print(seed, end=', ')
            distinct_primes = number_of_distinct_primes(bits)
            for _ in range(tests):
                p, g, exp, h = logarithm_test_numbers(bits, safe=False)
                p_iter = 0
                while p in p_set and len(
                        p_set) < distinct_primes - 1 and p_iter < 10**2:
                    p, g, exp, h = logarithm_test_numbers(bits, safe=False)
                    p_iter += 1
                p_set.add(p)

                bit_seed = rand.randint(1, seed)
                for ind_c, c in enumerate(contests):
                    x, iter, lamb, mu = pollard_rho(g,
                                                    h,
                                                    p,
                                                    cycle=c[0],
                                                    func=c[1],
                                                    rand_seed=bit_seed)
                    if x != exp:
                        print("WRONG " + c[0] + " " + c[1])
                    iterations[ind_b][ind_c][ind_s] += iter
                    lambs[ind_b][ind_c][ind_s] += lamb
                    mus[ind_b][ind_c][ind_s] += mu

            for ind_c, c in enumerate(contests):
                iterations[ind_b][ind_c][ind_s] /= tests
                lambs[ind_b][ind_c][ind_s] /= tests
                mus[ind_b][ind_c][ind_s] /= tests
        print()
        for ind_c, c in enumerate(contests):
            iterations_avg[ind_b][ind_c] = avg(
                iterations[ind_b][ind_c]) / ceil(sqrt(p))
            lambs_avg[ind_b][ind_c] = avg(lambs[ind_b][ind_c]) / ceil(sqrt(p))
            mus_avg[ind_b][ind_c] = avg(mus[ind_b][ind_c]) / ceil(sqrt(p))
            print(
                f"Cycle: {c[0]}, function: {c[1]}, itertions: {iterations_avg[ind_b][ind_c]:.4f}, lambs: {lambs_avg[ind_b][ind_c]:.4f} mus: {mus_avg[ind_b][ind_c]:.4f}, "
                f"rho: {lambs_avg[ind_b][ind_c] + mus_avg[ind_b][ind_c]:.4f} delay: {iterations_avg[ind_b][ind_c]/(lambs_avg[ind_b][ind_c] + mus_avg[ind_b][ind_c]):.4f}"
            )
        print()

    for ind_c, c in enumerate(contests):
        the_iterations = avg([it[ind_c] for it in iterations_avg])
        the_lambs = [lamb[ind_c] for lamb in lambs_avg]
        the_mus = [mu[ind_c] for mu in mus_avg]
        the_rhos = avg([x + y for x, y in zip(the_lambs, the_mus)])
        print(
            f"Cycle: {c[0]}, function: {c[1]}, itertions_avg: {the_iterations:.4f}, rho: {the_rhos:.4f}, delays {the_iterations/the_rhos:.4f}"
        )
Beispiel #6
0
def test_qe_solver(listOfBits: list,
                   numOfTests: int,
                   contests: list,
                   rand_seeds=[0]):
    n = len(contests)
    times = [[[0 for _ in rand_seeds] for _ in range(n)] for _ in listOfBits]
    # iterations = [[[0 for _ in rand_seeds] for _ in range(n)] for _ in listOfBits]
    # iterations_avg = [[0 for _ in range(n)] for _ in listOfBits]
    times_avg = [[0 for _ in range(n)] for _ in listOfBits]

    for ind_b, bits in enumerate(listOfBits):
        tests = num_of_tests(bits, numOfTests)
        p_set = set()
        print("\nStarted bits: ", bits)
        print("Number of tests: ", tests)
        print("Seeds:", end=' ')
        for ind_s, s in enumerate(rand_seeds):
            print(s, end=', ')
            seed(s)
            i = 0
            distinct_primes = number_of_distinct_primes(bits)
            last_sum = 0
            while i < tests:
                p, g, exp, h = logarithm_test_numbers(bits, safe=False)
                p_iter = 0

                while (p in p_set or ceil(sqrt(p)) > 30000000
                       ) and len(p_set) < distinct_primes and p_iter < 10**2:
                    p, g, exp, h = logarithm_test_numbers(bits, safe=False)
                    p_iter += 1
                p_set.add(p)

                bit_seed = randint(1, s)
                for ind_c, c in enumerate(contests):

                    if c[0] == 'shoup':
                        qeAlg = partial(shoup_alg)
                    else:
                        qeAlg = partial(pohlig_hellman_alg)

                    if c[1] == 'shanks':
                        Solver = partial(Shanks, type=c[2], r=2.25)
                    else:
                        Solver = partial(pollard_rho,
                                         cycle=c[2],
                                         func=c[3],
                                         rand_seed=bit_seed)

                    t = timer()
                    x = silver_pohlig_hellman_alg(g,
                                                  h,
                                                  p,
                                                  fact=factorint,
                                                  qeAlg=qeAlg,
                                                  solver=Solver)
                    if x != exp:
                        print("WRONG " + c[0] + " " + c[1] + ' ' + c[2] + ' ' +
                              c[3])
                    times[ind_b][ind_c][ind_s] += (timer() - t) * 1000
                    # iterations[ind_b][ind_c][ind_s] += iter
                i += 1

        for ind_c, c in enumerate(contests):
            # iterations[ind_b][ind_c][ind_s] /= tests * ceil(sqrt(p))
            times[ind_b][ind_c][ind_s] /= tests
        print()
        for ind_c, c in enumerate(contests):
            # iterations_avg[ind_b][ind_c] = avg([it for it in iterations[ind_b][ind_c]]) {iterations_avg[ind_b][ind_c]:.4f},
            times_avg[ind_b][ind_c] = avg([it for it in times[ind_b][ind_c]])
            print(
                f"Qe_alg: {c[0]},  solver: {c[1]}: type: {c[2]}, function: {c[3]}, time: {times_avg[ind_b][ind_c]:.3f}"
            )
def test_shanks_vs_pollard(numOfTests: int,
                           listOfBits: list,
                           contests: list,
                           rand_seeds=[0]):
    n = len(contests) + 2
    times = [[[0 for _ in rand_seeds] for _ in range(n)] for _ in listOfBits]
    iterations = [[[0 for _ in rand_seeds] for _ in range(n)]
                  for _ in listOfBits]
    iterations_avg = [[0 for _ in range(n)] for _ in listOfBits]
    times_avg = [[0 for _ in range(n)] for _ in listOfBits]

    for ind_b, bits in enumerate(listOfBits):
        tests = num_of_tests(bits, numOfTests)
        p_set = set()
        print("\nStarted bits: ", bits)
        print("Number of tests: ", tests)
        print("Seeds:", end=' ')
        for ind_s, s in enumerate(rand_seeds):
            print(s, end=',\n')
            seed(s)
            i = 0
            distinct_primes = number_of_distinct_primes(bits)
            last_sum = 0
            while i < tests:
                p, g, exp, h = logarithm_test_numbers(bits, safe=False)
                p_iter = 0

                while (p in p_set or ceil(sqrt(p)) > 30000000
                       ) and len(p_set) < distinct_primes and p_iter < 10**2:
                    p, g, exp, h = logarithm_test_numbers(bits, safe=False)
                    p_iter += 1
                p_set.add(p)

                bit_seed = randint(1, s)
                print(f"sqrt(p): {ceil(sqrt(p))}")

                t = timer()
                x, iter = poll.pollard_simple(g, h, p, rand_seed=bit_seed)
                if x != exp:
                    if x == None:
                        continue
                    print("WRONG Pollard simplu")
                times[ind_b][n - 2][ind_s] += (timer() - t) * 1000
                iterations[ind_b][n - 2][ind_s] += iter
                # print("Poll simplu Done!:", (timer() - t) * 1000)

                t = timer()
                x, sm, gs, _ = shanks.shanks_classic(g, h, p, p - 1)
                if x != exp:
                    if x == None:
                        continue
                    print("WRONG Shanks clasic")
                times[ind_b][n - 1][ind_s] += (timer() - t) * 1000
                iterations[ind_b][n - 1][ind_s] += sm + gs
                # print("Shanks Done!", (timer() - t) * 1000)

                for ind_c, c in enumerate(contests):
                    t = timer()
                    x, iter = poll.pollard_rho(g,
                                               h,
                                               p,
                                               cycle=c[0],
                                               func=c[1],
                                               rand_seed=bit_seed)
                    if x != exp:
                        print("WRONG " + c[0] + " " + c[1])
                    times[ind_b][ind_c][ind_s] += (timer() - t) * 1000
                    iterations[ind_b][ind_c][ind_s] += iter
                    new_sum = sum([t[0] for t in times[ind_b][:]])
                print(f"Test {i} done, time: {new_sum - last_sum:.4f}")
                last_sum = new_sum
                i += 1

                # t = timer()
                # x, op, _ = shanks.shanks_two_grumpys_one_baby(g, h, p, p - 1)
                # if x != exp:
                #   print("WRONG Shanks clasic")
                # times[ind_b][n - 1][ind_s] += (timer() - t) * 1000
                # iterations[ind_b][n - 1][ind_s] += op

            for ind_c, c in enumerate(contests):
                iterations[ind_b][ind_c][ind_s] /= tests * ceil(sqrt(p))
                times[ind_b][ind_c][ind_s] /= tests
            iterations[ind_b][n - 2][ind_s] /= tests * ceil(sqrt(p))
            times[ind_b][n - 2][ind_s] /= tests
            iterations[ind_b][n - 1][ind_s] /= tests * ceil(sqrt(p))
            times[ind_b][n - 1][ind_s] /= tests
            # iterations[ind_b][n - 1][ind_s] /= tests * ceil(sqrt(p)); times[ind_b][n - 1][ind_s] /= tests
        print()
        for ind_c, c in enumerate(contests):
            iterations_avg[ind_b][ind_c] = avg(
                [it for it in iterations[ind_b][ind_c]])
            times_avg[ind_b][ind_c] = avg([it for it in times[ind_b][ind_c]])
            print(
                f"Cycle: {c[0]},  function: {c[1]}: itertions: {iterations_avg[ind_b][ind_c]:.4f}, time: {times_avg[ind_b][ind_c]:.3f}"
            )
        iterations_avg[ind_b][n - 2] = avg(
            [it for it in iterations[ind_b][n - 2]])
        times_avg[ind_b][n - 2] = avg([it for it in times[ind_b][n - 2]])
        print(
            f"Pollard simple: itertions: {iterations_avg[ind_b][n - 2] :.4f}, time: {times_avg[ind_b][n - 2]:.3f}"
        )
        iterations_avg[ind_b][n - 1] = avg(
            [it for it in iterations[ind_b][n - 1]])
        times_avg[ind_b][n - 1] = avg([it for it in times[ind_b][n - 1]])
        print(
            f"Shanks clasic: itertions: {iterations_avg[ind_b][n - 1] :.4f}, time: {times_avg[ind_b][n - 1]:.3f}"
        )
        # iterations_avg[ind_b][n - 1] = avg([it for it in iterations[ind_b][n - 1]])
        # times_avg[ind_b][n - 1] = avg([it for it in times[ind_b][n - 1]])
        # print(f"Two giants: itertions: {iterations_avg[ind_b][n - 1]:.4f}, time: {times_avg[ind_b][n - 1]:.3f}")

        print("Finished bits: ", bits)

    print("\nThe avg number of iterations: ", end='')
    avgits = []
    for ind_c, c in enumerate(contests):
        avg_c = avg([it[ind_c] for it in iterations_avg])
        print(c[0] + '-' + c[1] + f": {avg_c:.4f}", end=' ')
        avgits.append(avg_c)
    avg_c = avg([it[n - 2] for it in iterations_avg])
    print(f"pollard simple: {avg_c:.4f}", end=', ')
    avg_c = avg([it[n - 1] for it in iterations_avg])
    print(f"shanks clasic: {avg_c:.4f}", end=', ')
    # avg_c = avg([it[n - 1] for it in iterations_avg])
    # print(f"two giants: {avg_c:.4f}", end=' .')

    return iterations_avg


# def test_shanks_vs_pollard(numOfTests: int, listOfBits: list, contests: dict, rand_seeds = [0]):
#   n = len(contests) + 2
#   times = [[[0 for _ in rand_seeds] for _ in range(n)] for _ in listOfBits]
#   iterations = [[[0 for _ in rand_seeds] for _ in range(n)] for _ in listOfBits]
#   iterations_avg = [[0 for _ in range(n)] for _ in listOfBits]
#   times_avg = [[0 for _ in range(n)] for _ in listOfBits]
#   for ind_b, bits in enumerate(listOfBits):
#     tests = num_of_tests(bits, numOfTests)
#     p_set = set()
#     print("\nStarted bits: ", bits)
#     print("Seeds:", end = ' ')
#     for ind_s, s in enumerate(rand_seeds):
#       print(s, end=', ')
#       seed(s)
#       i = 0
#       distinct_primes = number_of_distinct_primes(bits)
#       while i < tests:
#         p, g, exp, h = logarithm_test_numbers(bits, safe=False)
#         p_iter = 0
#         while (p in p_set or ceil(sqrt(p)) > 30000000) and len(p_set) < distinct_primes and p_iter < 10**2:
#           p, g, exp, h = logarithm_test_numbers(bits, safe=False)
#           p_iter += 1
#         p_set.add(p)
#
#         bit_seed = randint(1, s)
#         # print(f"sqrt(p): {ceil(sqrt(p))}")
#
#         t = timer()
#         x, iter = poll.pollard_simple(g, h, p, rand_seed=bit_seed)
#         if x != exp:
#           if x == None:
#               continue
#           print("WRONG Pollard simplu")
#         times[ind_b][n - 2][ind_s] += (timer() - t) * 1000
#         iterations[ind_b][n - 2][ind_s] += iter
#         # print("Poll simplu Done!:", (timer() - t) * 1000)
#
#         t = timer()
#         x, sm, gs, _ = shanks.shanks_classic(g, h, p, p - 1)
#         if x != exp:
#           if x == None:
#               continue
#           print("WRONG Shanks clasic")
#         times[ind_b][n - 1][ind_s] += (timer() - t) * 1000
#         iterations[ind_b][n - 1][ind_s] += sm + gs
#         # print("Shanks Done!", (timer() - t) * 1000)
#
#
#         for ind_c, c in enumerate(contests):
#           t = timer()
#           x, iter = poll.pollard_rho(g, h, p, cycle=c[0], func=c[1], rand_seed=bit_seed)
#           if x != exp:
#             print("WRONG " + c[0] + " " + c[1])
#           times[ind_b][ind_c][ind_s] += (timer() - t) * 1000
#           iterations[ind_b][ind_c][ind_s] += iter
#         # print("Polls done")
#         i += 1
#
#         # t = timer()
#         # x, op, _ = shanks.shanks_two_grumpys_one_baby(g, h, p, p - 1)
#         # if x != exp:
#         #   print("WRONG Shanks clasic")
#         # times[ind_b][n - 1][ind_s] += (timer() - t) * 1000
#         # iterations[ind_b][n - 1][ind_s] += op
#
#       for ind_c, c in enumerate(contests):
#         iterations[ind_b][ind_c][ind_s] /= tests * ceil(sqrt(p))
#         times[ind_b][ind_c][ind_s] /= tests
#       iterations[ind_b][n - 2][ind_s] /= tests * ceil(sqrt(p)); times[ind_b][n - 2][ind_s] /= tests
#       iterations[ind_b][n - 1][ind_s] /= tests * ceil(sqrt(p)); times[ind_b][n - 1][ind_s] /= tests
#       # iterations[ind_b][n - 1][ind_s] /= tests * ceil(sqrt(p)); times[ind_b][n - 1][ind_s] /= tests
#     print()
#     for ind_c, c in enumerate(contests):
#       iterations_avg[ind_b][ind_c] = avg([it for it in iterations[ind_b][ind_c]])
#       times_avg[ind_b][ind_c] = avg([it for it in times[ind_b][ind_c]])
#       print(f"Cycle: {c[0]},  function: {c[1]}: itertions: {iterations_avg[ind_b][ind_c]:.4f}, time: {times_avg[ind_b][ind_c]:.3f}")
#     iterations_avg[ind_b][n - 2] = avg([it for it in iterations[ind_b][n - 2]])
#     times_avg[ind_b][n - 2] = avg([it for it in times[ind_b][n - 2]])
#     print(f"Pollard simple: itertions: {iterations_avg[ind_b][n - 2] :.4f}, time: {times_avg[ind_b][n - 2]:.3f}")
#     iterations_avg[ind_b][n - 1] = avg([it for it in iterations[ind_b][n - 1]])
#     times_avg[ind_b][n - 1] = avg([it for it in times[ind_b][n - 1]])
#     print(f"Shanks clasic: itertions: {iterations_avg[ind_b][n - 1] :.4f}, time: {times_avg[ind_b][n - 1]:.3f}")
#     # iterations_avg[ind_b][n - 1] = avg([it for it in iterations[ind_b][n - 1]])
#     # times_avg[ind_b][n - 1] = avg([it for it in times[ind_b][n - 1]])
#     # print(f"Two giants: itertions: {iterations_avg[ind_b][n - 1]:.4f}, time: {times_avg[ind_b][n - 1]:.3f}")
#
#     print("Finished bits: ", bits)
#
#   print("\nThe avg number of iterations: ", end='');
#   avgits = []
#   for ind_c, c in enumerate(contests):
#     avg_c = avg([it[ind_c] for it in iterations_avg])
#     print(c[0] + '-' + c[1] + f": {avg_c:.4f}", end=' ')
#     avgits.append(avg_c)
#   avg_c = avg([it[n - 2] for it in iterations_avg])
#   print(f"pollard simple: {avg_c:.4f}", end=', ')
#   avg_c = avg([it[n - 1] for it in iterations_avg])
#   print(f"shanks clasic: {avg_c:.4f}", end=', ')
#   # avg_c = avg([it[n - 1] for it in iterations_avg])
#   # print(f"two giants: {avg_c:.4f}", end=' .')
#
#   return iterations_avg

# if __name__ == "__main__":
#   numOfTests = 100
#   bits = [15]
#   seed(42)
#   rand_seeds = sample(range(0, 5000), 1)
#   contests = [('brent', 'pollard'), ('floyd', 'pollard'), ('teske', 'pollard')]
#   iters = test_shanks_vs_pollard(numOfTests, bits, contests, rand_seeds)
def test_shanks_clasic_inter_grumpy(numOfTests: int,
                                    numOfBits: list,
                                    randSeeds=[0]):
    total_steps_class_list, times_clasic_list, total_memory_clasic = [], [], []
    total_steps_inter_list, times_inter_list, total_memory_inter = [], [], []
    total_steps_grumpy_list, times_grumpy_list, total_memory_grumpy = [], [], []
    for bits in numOfBits:
        seed_steps_class_list, seed_times_clasic_list, seed_total_memory_clasic = [], [], []
        seed_steps_inter_list, seed_times_inter_list, seed_total_memory_inter = [], [], []
        seed_steps_grumpy_list, seed_times_grumpy_list, seed_total_memory_grumpy = [], [], []
        print("Started: ", bits)
        if bits >= 50:
            numOfTests = 50
        elif bits >= 40:
            numOfTests = 100
        elif bits >= 30:
            numOfTests = 500
        for s in randSeeds:
            seed(s)
            time_clas, time_inter, time_grumpy = [], [], []
            steps_clas, steps_inter, steps_grumpy = [], [], []
            mem_clas, mem_inter, mem_grumpy = [], [], []
            for iter in range(numOfTests):
                p, g, exp, h = gnp.logarithm_test_numbers(bits, False)
                t = timer()
                x_c, small_clas, giant_clas, mem_c = shanks_classic(
                    g, h, p, p - 1)
                steps_clas.append(small_clas + giant_clas)
                mem_clas.append(mem_c)
                passed_time = (timer() - t) * 1000
                time_clas.append(passed_time)

                t = timer()
                x_c, oper, mem_c = shanks_interleved(g, h, p, p - 1)
                if x_c != exp:
                    print("NI")
                steps_inter.append(oper)
                mem_inter.append(mem_c)
                passed_time = (timer() - t) * 1000
                time_inter.append(passed_time)

                t = timer()
                x_c, oper, mem_c = shanks_two_grumpys_one_baby(g, h, p, p - 1)
                if x_c != exp:
                    print("NG")
                steps_grumpy.append(oper)
                mem_grumpy.append(mem_c)
                passed_time = (timer() - t) * 1000
                time_grumpy.append(passed_time)
            seed_steps_class_list.append(avg(steps_clas) / ceil(sqrt(p)))
            seed_steps_inter_list.append(avg(steps_inter) / ceil(sqrt(p)))
            seed_steps_grumpy_list.append(avg(steps_grumpy) / ceil(sqrt(p)))
            seed_times_clasic_list.append(avg(time_clas))
            seed_times_inter_list.append(avg(time_inter))
            seed_times_grumpy_list.append(avg(time_grumpy))
            seed_total_memory_clasic.append(avg(mem_clas) / ceil(sqrt(p)))
            seed_total_memory_inter.append(avg(mem_inter) / ceil(sqrt(p)))
            seed_total_memory_grumpy.append(avg(mem_grumpy) / ceil(sqrt(p)))
        print(
            f"Avg steps clasic:{avg(seed_steps_class_list):.4f} -- Avg steps inter:{avg(seed_steps_inter_list):.4f} -- Avg steps grumpy:{avg(seed_steps_grumpy_list):.4f}"
        )
        print(
            f"Avg memory clasic:{avg(seed_total_memory_clasic):.4f} -- Avg memory inter:{avg(seed_total_memory_inter):.4f} -- Avg memory grumpy:{avg(seed_total_memory_grumpy):.4f}"
        )
        print(
            f"Avg time clasic:{avg(seed_times_clasic_list):.4f} -- Avg time inter:{avg(seed_times_inter_list):.4f} -- Avg time grumpy:{avg(seed_times_grumpy_list):.4f}"
        )
        total_steps_class_list.append(avg(seed_steps_class_list))
        total_steps_inter_list.append(avg(seed_steps_inter_list))
        total_steps_grumpy_list.append(avg(seed_steps_grumpy_list))
        times_clasic_list.append(avg(seed_times_clasic_list))
        times_inter_list.append(avg(seed_times_inter_list))
        times_grumpy_list.append(avg(seed_times_grumpy_list))
        total_memory_clasic.append(avg(seed_total_memory_clasic))
        total_memory_inter.append(avg(seed_total_memory_inter))
        total_memory_grumpy.append(avg(seed_total_memory_grumpy))
        print(f"Finished: {bits}\n")

    print(
        f"Avg steps clasic:{avg(total_steps_class_list):.4f} -- Avg steps inter:{avg(total_steps_inter_list):.4f} -- Avg steps grumpy:{avg(total_steps_grumpy_list):.4f}"
    )
    print(
        f"Avg memory clasic:{avg(total_memory_clasic):.4f} -- Avg memory inter:{avg(total_memory_inter):.4f} -- Avg memory grumpy:{avg(total_memory_grumpy):.4f}"
    )
    print(
        f"Avg time clasic:{avg(times_clasic_list):.4f} -- Avg time inter:{avg(times_inter_list):.4f} -- Avg time grumpy:{avg(times_grumpy_list):.4f}"
    )
def shakns_benchmark(numOfTests: int, maxBits: int, rand_seed=0):
    import matplotlib.pyplot as plt
    seed(rand_seed)
    times, small_steps_list, giant_steps_list, total_steps, list_sizes, bits, time_bin, list_sizes_bin = [], [], [], [], [], [], [], []
    for numOfBits in range(10, maxBits + 5, 5):
        time, small, giant, total, list_sz, tb, lb = 0, 0, 0, 0, 0, 0, 0
        bits.append(numOfBits)
        for _ in range(numOfTests):
            p, g, e, h = gnp.logarithm_test_numbers(numOfBits)
            t_start = timer()
            x, small_steps, giant_steps, list_size = shanks_classic(
                g, h, p, p - 1)
            time += (timer() - t_start) * 1000
            small += small_steps
            giant += giant_steps
            total += small_steps + giant_steps
            list_sz += list_size
            t_start = timer()
            x, small_steps, giant_steps, list_size = shanks_classic_binary_search(
                g, h, p, p - 1)
            tb += (timer() - t_start) * 1000
            lb += list_size
        times.append(time / numOfTests)
        time_bin.append(tb / numOfTests)
        small_steps_list.append(small / numOfTests)
        giant_steps_list.append(giant / numOfTests)
        total_steps.append(total / numOfTests)
        list_sizes.append(list_sz / numOfTests)
        list_sizes_bin.append(lb / numOfTests)

    next_xs = list(range(numOfBits + 5, numOfBits + 25, 5))
    plt.figure(1)
    plt.xlim(5, numOfBits + 25)
    next_ys = extrapolate(times, len(next_xs))
    next_ys_bin = extrapolate(time_bin, len(next_xs))
    plt.plot(np.append(bits, next_xs),
             np.append(times, next_ys),
             marker='o',
             color='b',
             linestyle='dashed',
             label='dispersie')
    plt.plot(bits, times, marker='o', c='b')
    plt.plot(np.append(bits, next_xs),
             np.append(time_bin, next_ys_bin),
             marker='s',
             c='r',
             linestyle='dashed',
             label='cautare binara')
    plt.plot(bits, time_bin, marker='s', c='r')
    plt.xlabel('biti')
    plt.ylabel('milisecunde')
    plt.yscale('log')
    plt.legend(loc="upper left")
    plt.grid(True)
    plt.savefig('imagini/shanks_classic_timp.png')

    plt.figure(2)
    plt.xlim(5, numOfBits + 25)
    next_ys = extrapolate(small_steps_list, len(next_xs))
    plt.plot(np.append(bits, next_xs), np.append(small_steps_list, next_ys),
             'b--')
    plt.plot(bits, small_steps_list, c='b')
    plt.xlabel('biti')
    plt.ylabel('pasi mici')
    plt.yscale('log')
    plt.grid(True)
    plt.savefig('imagini/shanks_classic_pasi_mici.png')

    plt.figure(3)
    plt.xlim(5, numOfBits + 25)
    next_ys = extrapolate(giant_steps_list, len(next_xs))
    plt.plot(np.append(bits, next_xs), np.append(giant_steps_list, next_ys),
             'b--')
    plt.plot(bits, giant_steps_list, c='b')
    plt.xlabel('biti')
    plt.ylabel('pasi giant')
    plt.yscale('log')
    plt.grid(True)
    plt.savefig('imagini/shanks_classic_pasi_mari.png')

    plt.figure(4)
    plt.xlim(5, numOfBits + 25)
    next_ys = extrapolate(total_steps, len(next_xs))
    plt.plot(np.append(bits, next_xs), np.append(total_steps, next_ys), 'b--')
    plt.plot(bits, total_steps, c='b')
    plt.xlabel('biti')
    plt.ylabel('pasi totali')
    plt.yscale('log')
    plt.grid(True)
    plt.savefig('imagini/shanks_classic_pasi_total.png')

    plt.figure(5)
    plt.xlim(5, numOfBits + 25)
    next_ys = extrapolate(list_sizes, len(next_xs))
    next_ys_bin = extrapolate(list_sizes_bin, len(next_xs))
    plt.plot(np.append(bits, next_xs),
             np.append(list_sizes, next_ys),
             marker='o',
             color='b',
             linestyle='dashed',
             label='dispersie')
    plt.plot(bits, list_sizes, marker='o', c='b')
    plt.plot(np.append(bits, next_xs),
             np.append(list_sizes_bin, next_ys_bin),
             marker='s',
             c='r',
             linestyle='dashed',
             label='cautare binara')
    plt.plot(bits, list_sizes_bin, marker='s', c='r')
    plt.xlabel('biti')
    plt.ylabel('bytes')
    plt.yscale('log')
    plt.legend(loc="upper left")
    plt.grid(True)
    plt.savefig('imagini/shanks_classic_memory.png')

    plt.show()
            exponents = None
    # dictionary of bases and exponents
    return exponents[-1] % (p - 1), t_cong, it


if __name__ == '__main__':
    i = 0
    ts, tts = [], []
    its = []
    seed(42)
    for q in range(5):
        for _ in range(500):
            ok = 1
            while ok:
                ok = 0
                p, g, exponent, h = logarithm_test_numbers(15, safe=False)
            x = 2**ceil(log2(p - 1))
            B = ceil(exp(1 / sqrt(2) * sqrt(log(x) * log(log(x)))) / 2)
            # print(L(p), shanks_complex(p))
            primesB = primes_up_to_B(B)
            max_equations = primes_upto(B) + 5
            # print(B, max_equations, p)
            t = timer()
            x, ta, it = SELD_lect11(g, h, p, B, max_equations, primesB, 42)
            ts.append((timer() - t) * 1000)
            its.append(it)
            if x == exponent:
                # print("DA")
                i += 1
            else:
                if pow(g, x, p) != h: