From 1f7e7d968ea1827459f7092abcf48ca83fe25a79 Mon Sep 17 00:00:00 2001 From: Ryan Rueger Date: Wed, 30 Apr 2025 18:26:40 +0200 Subject: Bugfixes and Refactoring MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Pierrick Dartois Co-Authored-By: Jonathan Komada Eriksen Co-Authored-By: Jonathan Komada Eriksen Co-Authored-By: Arthur Herlédan Le Merdy Co-Authored-By: Riccardo Invernizzi Co-Authored-By: Damien Robert Co-Authored-By: Ryan Rueger Co-Authored-By: Frederik Vercauteren Co-Authored-By: Benjamin Wesolowski --- basis_sampling.py | 113 +++++++ coin.py | 748 +++++++++++++++++--------------------------- const_precomp.py | 629 +++++++++++++++++++++++++++++++++++++ dim1_isogenies.py | 207 ++++++++++++ elkies.py | 268 ++++++++-------- generate_params.py | 119 +++++++ ideal_to_kernel.py | 234 ++++++++++++++ ideals.py | 103 +++--- independent-verification.py | 79 +++++ lcsidh.py | 297 ++++++++++-------- pegasis.py | 617 +++--------------------------------- temp_test.py | 51 +++ time_pegasis.py | 4 +- utilities.py | 137 ++++++++ uv_params.py | 16 +- 15 files changed, 2298 insertions(+), 1324 deletions(-) create mode 100644 basis_sampling.py create mode 100644 dim1_isogenies.py create mode 100644 generate_params.py create mode 100644 ideal_to_kernel.py create mode 100644 independent-verification.py create mode 100644 temp_test.py create mode 100644 utilities.py diff --git a/basis_sampling.py b/basis_sampling.py new file mode 100644 index 0000000..275e81d --- /dev/null +++ b/basis_sampling.py @@ -0,0 +1,113 @@ +#!/usr/bin/env python3 + +import logging +from time import time + +from xonly import xPoint, MontgomeryA + +logger = logging.getLogger(__name__) +logger.setLevel(logging.WARNING) +logger_sh = logging.StreamHandler() +logger_sh.setLevel(logging.WARNING) +formatter = logging.Formatter("%(name)s [%(levelname)s] %(message)s") +logger_sh.setFormatter(formatter) +logger.addHandler(logger_sh) + + +def find_Ts(E, only_T0 = False): + r""" + Given a curve E, finds and marks the non-trivial + 2-torsion points according to Lemma D.1 + """ + A = MontgomeryA(E) + F = E.base_field() + R = F["X"] + X = R.gens()[0] + f = X**2 + A*X + 1 + logger.debug(" > root finding") + lam1, lam2 = f.roots(multiplicities=False) + + R1 = E(lam1, 0) + R2 = E(lam2, 0) + R3 = E(0, 0) + + #Find T0 + Rs = [R1, R2] + for T in Rs: + if T.tate_pairing(T, 2, 1) != 1: + T0 = T + Rs.remove(T) + break + + assert T0 + if only_T0: + return T0 + + assert T0.tate_pairing(T0, 2, 1) == -1 + Rs.append(R3) + for T in Rs: + if T.tate_pairing(T0, 2, 1) == 1: + Tm1 = T + Rs.remove(T) + break + + assert Tm1 + T1 = Rs[0] + assert T1.tate_pairing(T0, 2, 1) != 1 + + return T0, Tm1, T1 + + +def TwoTorsBasis(E, e): + r""" + Fast sampling of a basis P, Q of E[2**e], such that x(P) and x(Q) are both defined over Fp + Input: + - E: Elliptic curve over Fp + - e: Exponent + Output: + - P, Q: Basis of E[2**e] so that P is in E(Fp), and Q is in E^t(Fp) for an Fp-twist of E. + """ + logger.debug(" > Finding TwoTorsionBasis") + tstart = time() + + T0, Tm1, T1 = find_Ts(E) + + A = MontgomeryA(E) + F = E.base_field() + R = F["X"] + X = R.gens()[0] + f = X**2 + A*X + 1 + + logger.debug(f" > Done, have used {time()-tstart} sec") + + logger.debug(" > sample xP") + xT0 = T0.x() + xP = xT0 + F.random_element()**2 + while not (f(xP)*xP).is_square() or (xP-Tm1.x()).is_square(): + xP = xT0 + F.random_element()**2 + + logger.debug(" > sample xQ") + xQ = xT0 - F.random_element()**2 + while (f(xQ)*xQ).is_square() or not ((xQ-T1.x()).is_square()): + xQ = xT0 - F.random_element()**2 + + logger.debug(f" > Done, have used {time()-tstart} sec") + #print(T0.tate_pairing(E.lift_x(xP), 2, 1)) + + P = xPoint(xP, E) + Q = xPoint(xQ, E) + + assert (E.base_field().characteristic()+1) % 2**(e+1) == 0 + cofac = (E.base_field().characteristic()+1)/2**(e+1) + P = P.xMUL(cofac) + Q = Q.xMUL(cofac) + + assert P.xMUL(2**(e-1)) + assert not P.xMUL(2**e) + assert Q.xMUL(2**(e-1)) + assert not Q.xMUL(2**e) + assert Q.xMUL(2**(e-1)) != P.xMUL(2**(e-1)) + + logger.debug(f" > Total time for 2-tors basis finding: {time()-tstart}") + + return P, Q diff --git a/coin.py b/coin.py index b6aec22..0c4f688 100644 --- a/coin.py +++ b/coin.py @@ -1,500 +1,332 @@ -from sage.all import ( - xgcd, - ceil, floor, - log, -) -from sage.all import gcd, is_pseudoprime, two_squares, Factorization, ZZ -from sage.all import isqrt -from sage.rings.finite_rings.integer_mod import Mod - -small_squares = { - 5: (1, 2), 13: (2, 3), 17: (1, 4), 29: (2, 5), 37: (1, 6), 41: (4, 5), - 53: (2, 7), 61: (5, 6), 73: (3, 8), 89: (5, 8), 97: (4, 9), - 101: (1, 10), 109: (3, 10), 113: (7, 8), 137: (4, 11), 149: (7, 10), - 157: (6, 11), 173: (2, 13), 181: (9, 10), 193: (7, 12), 197: (1, 14), - 229: (2, 15), 233: (8, 13), 241: (4, 15), 257: (1, 16), 269: (10, 13), - 277: (9, 14), 281: (5, 16), 293: (2, 17), 313: (12, 13), 317: (11, 14), - 337: (9, 16), 349: (5, 18), 353: (8, 17), 373: (7, 18), 389: (10, 17), - 397: (6, 19), 401: (1, 20), 409: (3, 20), 421: (14, 15), 433: (12, 17), - 449: (7, 20), 457: (4, 21), 461: (10, 19), 509: (5, 22), 521: (11, 20), - 541: (10, 21), 557: (14, 19), 569: (13, 20), 577: (1, 24), 593: (8, 23), - 601: (5, 24), 613: (17, 18), 617: (16, 19), 641: (4, 25), 653: (13, 22), - 661: (6, 25), 673: (12, 23), 677: (1, 26), 701: (5, 26), 709: (15, 22), - 733: (2, 27), 757: (9, 26), 761: (19, 20), 769: (12, 25), 773: (17, 22), - 797: (11, 26), 809: (5, 28), 821: (14, 25), 829: (10, 27), 853: (18, 23), - 857: (4, 29), 877: (6, 29), 881: (16, 25), 929: (20, 23), 937: (19, 24), - 941: (10, 29), 953: (13, 28), 977: (4, 31), 997: (6, 31), 1009: (15, 28), - 1013: (22, 23), 1021: (11, 30), 1033: (3, 32), 1049: (5, 32), 1061: (10, 31), - 1069: (13, 30), 1093: (2, 33), 1097: (16, 29), 1109: (22, 25), 1117: (21, 26), - 1129: (20, 27), 1153: (8, 33), 1181: (5, 34), 1193: (13, 32), 1201: (24, 25), - 1213: (22, 27), 1217: (16, 31), 1229: (2, 35), 1237: (9, 34), 1249: (15, 32), - 1277: (11, 34), 1289: (8, 35), 1297: (1, 36), 1301: (25, 26), 1321: (5, 36), - 1361: (20, 31), 1373: (2, 37), 1381: (15, 34), 1409: (25, 28), 1429: (23, 30), - 1433: (8, 37), 1453: (3, 38), 1481: (16, 35), 1489: (20, 33), 1493: (7, 38), - 1549: (18, 35), 1553: (23, 32), 1597: (21, 34), 1601: (1, 40), 1609: (3, 40), - 1613: (13, 38), 1621: (10, 39), 1637: (26, 31), 1657: (19, 36), 1669: (15, 38), - 1693: (18, 37), 1697: (4, 41), 1709: (22, 35), 1721: (11, 40), 1733: (17, 38), - 1741: (29, 30), 1753: (27, 32), 1777: (16, 39), 1789: (5, 42), 1801: (24, 35), - 1861: (30, 31), 1873: (28, 33), 1877: (14, 41), 1889: (17, 40), 1901: (26, 35), - 1913: (8, 43), 1933: (13, 42), 1949: (10, 43), 1973: (23, 38), 1993: (12, 43), - 1997: (29, 34), 2017: (9, 44), 2029: (2, 45), 2053: (17, 42), 2069: (25, 38), - 2081: (20, 41), 2089: (8, 45), 2113: (32, 33), 2129: (23, 40), 2137: (29, 36), - 2141: (5, 46), 2153: (28, 37), 2161: (15, 44), 2213: (2, 47), 2221: (14, 45), - 2237: (11, 46), 2269: (30, 37), 2273: (8, 47), 2281: (16, 45), 2293: (23, 42), - 2297: (19, 44), 2309: (10, 47), 2333: (22, 43), 2341: (15, 46), 2357: (26, 41), - 2377: (21, 44), 2381: (34, 35), 2389: (25, 42), 2393: (32, 37), 2417: (4, 49), - 2437: (6, 49), 2441: (29, 40), 2473: (13, 48), 2477: (19, 46), 2521: (35, 36), - 2549: (7, 50), 2557: (21, 46), 2593: (17, 48), 2609: (20, 47), 2617: (4, 51), - 2621: (11, 50), 2633: (28, 43), 2657: (16, 49), 2677: (34, 39), 2689: (33, 40), - 2693: (22, 47), 2713: (3, 52), 2729: (5, 52), 2741: (25, 46), 2749: (30, 43), - 2753: (7, 52), 2777: (29, 44), 2789: (17, 50), 2797: (14, 51), 2801: (20, 49), - 2833: (23, 48), 2837: (34, 41), 2857: (16, 51), 2861: (19, 50), 2897: (31, 44), - 2909: (10, 53), 2917: (1, 54), 2953: (12, 53), 2957: (29, 46), 2969: (37, 40), - 3001: (20, 51), 3037: (11, 54), 3041: (4, 55), 3049: (32, 45), 3061: (6, 55), - 3089: (8, 55), 3109: (30, 47), 3121: (39, 40), 3137: (1, 56), 3169: (12, 55), - 3181: (34, 45), 3209: (20, 53), 3217: (9, 56), 3221: (14, 55), 3229: (27, 50), - 3253: (2, 57), 3257: (11, 56), 3301: (30, 49), 3313: (8, 57), 3329: (25, 52), - 3361: (15, 56), 3373: (3, 58), 3389: (5, 58), 3413: (7, 58), 3433: (27, 52), - 3449: (40, 43), 3457: (39, 44), 3461: (31, 50), 3469: (38, 45), 3517: (6, 59), - 3529: (35, 48), 3533: (13, 58), 3541: (25, 54), 3557: (34, 49), 3581: (10, 59), - 3593: (28, 53), 3613: (42, 43), 3617: (41, 44), 3637: (39, 46), 3673: (37, 48), - 3677: (14, 59), 3697: (36, 49), 3701: (26, 55), 3709: (30, 53), 3733: (22, 57), - 3761: (25, 56), 3769: (13, 60), 3793: (33, 52), 3797: (41, 46), 3821: (10, 61), - 3833: (32, 53), 3853: (3, 62), 3877: (31, 54), 3881: (20, 59), 3889: (17, 60), - 3917: (14, 61), 3929: (35, 52), 3989: (25, 58), 4001: (40, 49), 4013: (13, 62), - 4021: (39, 50), 4049: (32, 55), 4057: (24, 59), 4073: (37, 52), 4093: (27, 58), - 4129: (23, 60), 4133: (17, 62), 4153: (43, 48), 4157: (26, 59), 4177: (9, 64), - 4201: (40, 51), 4217: (11, 64), 4229: (2, 65), 4241: (4, 65), 4253: (38, 53), - 4261: (6, 65), 4273: (32, 57), 4289: (8, 65), 4297: (24, 61), 4337: (44, 49), - 4349: (43, 50), 4357: (1, 66), 4373: (23, 62), 4397: (26, 61), 4409: (40, 53), - 4421: (14, 65), 4441: (29, 60), 4457: (19, 64), 4481: (16, 65), 4493: (2, 67), - 4513: (47, 48), 4517: (46, 49), 4549: (18, 65), 4561: (31, 60), 4597: (41, 54), - 4621: (30, 61), 4637: (34, 59), 4649: (5, 68), 4657: (39, 56), 4673: (7, 68), - 4721: (25, 64), 4729: (45, 52), 4733: (37, 58), 4789: (42, 55), 4793: (13, 68), - 4801: (24, 65), 4813: (18, 67), 4817: (41, 56), 4861: (10, 69), 4877: (34, 61), - 4889: (20, 67), 4909: (3, 70), 4933: (33, 62), 4937: (29, 64), 4957: (14, 69), - 4969: (37, 60), 4973: (22, 67), 4993: (32, 63), 5009: (28, 65), 5021: (11, 70), - 5077: (6, 71), 5081: (40, 59), 5101: (50, 51), 5113: (48, 53), 5153: (23, 68), - 5189: (17, 70), 5197: (29, 66), 5209: (5, 72), 5233: (7, 72), 5237: (14, 71), - 5261: (19, 70), 5273: (28, 67), 5281: (41, 60), 5297: (16, 71), 5309: (50, 53), - 5333: (2, 73), 5381: (34, 65), 5393: (8, 73), 5413: (38, 63), 5417: (44, 59), - 5437: (26, 69), 5441: (20, 71), 5449: (43, 60), 5477: (1, 74), 5501: (5, 74), - 5521: (36, 65), 5557: (9, 74), 5569: (40, 63), 5573: (47, 58), 5581: (35, 66), - 5641: (4, 75), 5653: (18, 73), 5657: (44, 61), 5669: (38, 65), 5689: (8, 75), - 5693: (43, 62), 5701: (15, 74), 5717: (26, 71), 5737: (51, 56), 5741: (29, 70), - 5749: (50, 57), 5801: (5, 76), 5813: (22, 73), 5821: (14, 75), 5849: (35, 68), - 5857: (9, 76), 5861: (31, 70), 5869: (45, 62), 5881: (16, 75), 5897: (11, 76), - 5953: (52, 57), 5981: (50, 59), 6029: (10, 77), 6037: (41, 66), 6053: (47, 62), - 6073: (12, 77), 6089: (40, 67), 6101: (25, 74), 6113: (28, 73), 6121: (45, 64), - 6133: (7, 78), 6173: (53, 58), 6197: (34, 71), 6217: (21, 76), 6221: (50, 61), - 6229: (30, 73), 6257: (4, 79), 6269: (37, 70), 6277: (6, 79), 6301: (26, 75), - 6317: (29, 74), 6329: (20, 77), 6337: (36, 71), 6353: (32, 73), 6361: (40, 69), - 6373: (17, 78), 6389: (55, 58), 6397: (54, 59), 6421: (39, 70), 6449: (7, 80), - 6469: (50, 63), 6473: (43, 68), 6481: (9, 80), 6521: (11, 80), 6529: (48, 65), - 6553: (37, 72), 6569: (13, 80), 6577: (4, 81), 6581: (41, 70), 6637: (54, 61), - 6653: (53, 62), 6661: (10, 81), 6673: (52, 63), 6689: (17, 80), 6701: (35, 74), - 6709: (25, 78), 6733: (3, 82), 6737: (31, 76), 6761: (19, 80), 6781: (34, 75), - 6793: (48, 67), 6829: (30, 77), 6833: (47, 68), 6841: (21, 80), 6857: (56, 61), - 6869: (55, 62), 6917: (26, 79), 6949: (15, 82), 6961: (20, 81), 6977: (44, 71), - 6997: (39, 74), 7001: (35, 76), 7013: (17, 82), 7057: (1, 84), 7069: (38, 75), - 7109: (47, 70), 7121: (55, 64), 7129: (27, 80), 7177: (11, 84), 7193: (52, 67), - 7213: (18, 83), 7229: (2, 85), 7237: (26, 81), 7253: (23, 82), 7297: (39, 76), - 7309: (35, 78), 7321: (60, 61), 7333: (58, 63), 7349: (25, 82), 7369: (12, 85), - 7393: (47, 72), 7417: (19, 84), 7433: (53, 68), 7457: (41, 76), 7477: (9, 86), - 7481: (16, 85), 7489: (33, 80), 7517: (11, 86), 7529: (40, 77), 7537: (36, 79), - 7541: (50, 71), 7549: (18, 85), 7561: (44, 75), 7573: (2, 87), 7577: (59, 64), - 7589: (58, 65), 7621: (15, 86), 7649: (55, 68), 7669: (10, 87), 7673: (28, 83), - 7681: (25, 84), 7717: (34, 81), 7741: (46, 75), 7753: (3, 88), 7757: (19, 86), - 7789: (30, 83), 7793: (7, 88), 7817: (61, 64), 7829: (50, 73), 7841: (40, 79), - 7853: (58, 67), 7873: (57, 68), 7877: (49, 74), 7901: (26, 85), 7933: (43, 78), - 7937: (4, 89), 7949: (35, 82), 7993: (53, 72), 8009: (28, 85), 8017: (31, 84), - 8053: (22, 87), 8069: (62, 65), 8081: (41, 80), 8089: (60, 67), 8093: (37, 82), - 8101: (1, 90), 8117: (14, 89), 8161: (40, 81), 8209: (55, 72), 8221: (11, 90), - 8233: (48, 77), 8237: (29, 86), 8269: (13, 90), 8273: (23, 88), 8293: (47, 78), - 8297: (4, 91), 8317: (6, 91), 8329: (52, 75), 8353: (28, 87), 8369: (25, 88), - 8377: (51, 76), 8389: (17, 90), 8429: (50, 77), 8461: (19, 90), 8501: (55, 74), - 8513: (7, 92), 8521: (36, 85), 8537: (16, 91), 8573: (43, 82), 8581: (65, 66), - 8597: (26, 89), 8609: (47, 80), 8629: (23, 90), 8641: (60, 71), 8669: (38, 85), - 8677: (46, 81), 8681: (20, 91), 8689: (15, 92), 8693: (58, 73), 8713: (8, 93), - 8737: (41, 84), 8741: (50, 79), 8753: (17, 92), 8761: (56, 75), 8821: (30, 89), - 8837: (1, 94), 8849: (65, 68), 8861: (5, 94), 8893: (53, 78), 8929: (60, 73), - 8933: (47, 82), 8941: (29, 90), 8969: (35, 88), 9001: (51, 80), 9013: (38, 87), - 9029: (2, 95), 9041: (4, 95), 9049: (20, 93), 9109: (55, 78), 9133: (22, 93), - 9137: (64, 71), 9157: (54, 79), 9161: (44, 85), 9173: (62, 73), 9181: (30, 91), - 9209: (53, 80), 9221: (14, 95), 9241: (5, 96), 9257: (59, 76), 9277: (21, 94), - 9281: (16, 95), 9293: (58, 77), 9337: (11, 96), 9341: (46, 85), 9349: (18, 95), - 9377: (56, 79), 9397: (66, 71), 9413: (2, 97), 9421: (45, 86), 9433: (28, 93), - 9437: (34, 91), 9461: (25, 94), 9473: (8, 97), 9497: (61, 76), 9521: (40, 89), - 9533: (53, 82), 9601: (24, 95), 9613: (3, 98), 9629: (5, 98), 9649: (57, 80), - 9661: (69, 70), 9677: (29, 94), 9689: (35, 92), 9697: (56, 81), 9721: (64, 75), - 9733: (18, 97), 9749: (55, 82), 9769: (45, 88), 9781: (41, 90), 9817: (4, 99), - 9829: (15, 98), 9833: (37, 92), 9857: (44, 89), 9901: (10, 99), 9929: (52, 85), - 9941: (70, 71), 9949: (43, 90), 9973: (57, 82)} +#!/usr/bin/env python3 + +from copy import copy + +from sage.arith.misc import is_pseudoprime, xgcd +from sage.functions.other import floor, ceil +from sage.misc.functional import isqrt, log +from sage.rings.integer_ring import ZZ +from sage.rings.integer import Integer +from sage.misc.misc_c import prod + +from utilities import remove_common_factors, two_squares_factored, remove_primes # Primes 1 mod 4 / 3 mod 4 -from const_precomp import ( - good_prime_prod_10k, bad_prime_prod_10k, - good_prime_prod_100k, bad_prime_prod_100k, - good_prime_prod_500k, bad_prime_prod_500k -) +from const_precomp import good_prime_prod_10k, bad_prime_prod_10k + good_prime_prod = good_prime_prod_10k bad_prime_prod = bad_prime_prod_10k -def coin_pair_generator(n1, n2, e, exp_bound=None): - """ - Find all pairs (u, v) s.t. u*n1 + v*n2 = 2^t for t <= e. - If exp_bound is set, stop returning solution for t > t0 + exp_bound, where - t0 is the minimum t for which a solution is found. + +def coins(n1, n2, e, exp_bound=None): + """Yield pairs (u, v) s.t. u*n1 + v*n2 = 2^t for t <= e + + Arguments: + - n1, n2: Integers + - e: Largest 2-power exponent + - exp_bound (optional): Stop searching when t > t_min + exp_bound. + Where t_min is the smallest 2-power for which + there is a solution. """ - one, a, b = xgcd(n1, n2) - # Assuming (a, b) = 1 - if gcd is 2^i we can divide before - if one != 1: + + g, a, b = xgcd(n1, n2) + + if g != 1: raise ValueError(f"{n1 = } and {n2 = } are not coprime") - a, b, n1, n2 = map(int, [a, b, n1, n2]) - t0 = None - for t in range(floor(log(min(n1, n2), 2)), e+1): - if exp_bound and t0 and t > t0 + exp_bound: + # Smallest t for which we have found a solution + t_min = None + + for t in range(floor(log(min(n1, n2), 2)), e + 1): + + if t_min and exp_bound and t > t_min + exp_bound: break - l = 2**t - if l < max(n1, n2): - continue - if a < 0: - k = ((-l*a - 1) // n2) + 1 # = ceil(-l*a / n2) - k_max = l*b // n1 # = floor(l*b / n1) - while k <= k_max: - u = l*a + k*n2 - v = l*b - k*n1 - - k += 1 - if u % 2 == v % 2 == 0: - continue # Skip if both even (already included) - if not t0: - t0 = t - yield (ZZ(u), ZZ(v), ZZ(t)) - - elif b < 0: - k = ((-l*b - 1) // n1) + 1 # = ceil(-l*b / n1) - k_max = l*a // n2 # = floor(l*a / n2) - while k <= k_max: - u = l*a - k*n2 - v = l*b + k*n1 - - k += 1 - if u % 2 == v % 2 == 0: - continue - if not t0: - t0 = t - yield (ZZ(u), ZZ(v), ZZ(t)) - - -def two_squares_factored(factors): - """ - This is the function `two_squares` from sage, except we give it the - factorisation of n already. + + N = 2**t + + # Find conditions for u > 0 and v > 0 and solve for k + # (using definitions as below) + for k in range(ceil(-N * a / n2), floor(N * b / n1) + 1): + + if not t_min: + # Found minimal solution + t_min = t + + # u * n1 + v * n2 = N * (a * n1 + b * n2) = g * N = N + u = N * a + k * n2 + v = N * b - k * n1 + + if u % 2 == 0 and v % 2 == 0: + # We have seen this solution for a previous power of 2 + continue + + assert u > 0 + assert v > 0 + assert u * n1 + v * n2 == 2**t + + yield u, v, t + + +def is_sum_of_2_squares(numbers, early_abort=False): + """Determine whether every number in numbers is sum of (two) squares + + We know that n can be written as the sum of two squares if and only if every + prime p dividing n that is 3 mod 4 divides n with even multiplicity + + If any of the numbers cannot be written as sum of squares, we try to abort + as soon as possible. + + Input: + - numbers: List of ints/Integers + + Note: Also accepts a single int/Integer n (you do not need to cast + single element to singleton list [n]) + + Output: + - List [(success, pseudo_factorization), ...] one entry for every number + in numbers + + Note: If numbers is just an int, or Integer, then just a tuple + (success, partial_factorization) + is returned, not a singleton + [(success, pseudo_factorization)]. + + For the i-th entry (success, pseudo_factorization) in output list + + - success (True/False) tells us whether i-th number in numbers can be + written as sum of two squares + + - pseudo_factorization is a list of tuples [(p_1, e_1), (p_2, e_2), ...] + where p_j divides the i-th number in numbers with multiplicity e_j + + Every p_j is a prime number, with the exception of the last one, which + is only checked for pseudoprimality """ - F = factors - for (p,e) in F: - if e % 2 == 1 and p % 4 == 3: - raise ValueError("%s is not a sum of 2 squares"%n) - - n = factors.expand() - if n == 0: - return (0, 0) - a = ZZ.one() - b = ZZ.zero() - for (p,e) in F: - if p == 1: + + single = False + if isinstance(numbers, (int, Integer)): + single = True + numbers = [ZZ(numbers)] + + # List of pairs (status, factorizations) for every number + # - status is one of [-1, 0, 1], where + # * -1 = do not know + # * 0 = failure + # * 1 = success + # + # we need three status codes (more than success/failure), becuase we + # want to be able to abort early and so we need an "I don't know" option + # + # - factorizations is a list of (partial) factorizations of the numbers + # If there is an early abort, it is possible that the factorization is + # only partial + + result = [[-1, []] for _ in numbers] + + # Numbers with factors removed (Iteratively updated throughout) + # Must perform copy to prevent changing numbers outside function call as + # python essentially passes mutable types by reference + reduced_numbers = copy(numbers) + + for i, n in enumerate(reduced_numbers): + # Any power of two is the sum of two squares, we know this for free + v2 = n.valuation(2) + remainder = n // (2**v2) + # Update factorization + result[i][1] += [(2, v2)] + + if remainder % 4 == 3: + # n cannot be written as sum of two squares + # Tell later steps not to operate further + result[i][0] = 0 + + if early_abort: + # If there is only one number, do not return list + return result[0] if single else result + + # Update list of numbers + reduced_numbers[i] = remainder + + for i, n in enumerate(reduced_numbers): + if result[i] == 0: + # Previous step has determined that this number cannot be written as + # sum of two squares continue - if e >= 2: - m = p ** (e//2) - a *= m - b *= m - if e % 2 == 1: - if p == 2: - # (a + bi) *= (1 + I) - a,b = a - b, a + b - else: # p = 1 mod 4 - if p in small_squares: - r,s = small_squares[p] - else: - # Find a square root of -1 mod p. - # If y is a non-square, then y^((p-1)/4) is a square root of -1. - y = Mod(2,p) - while True: - s = y**((p-1)/4) - if not s*s + 1: - s = s.lift() - break - y += 1 - # Apply Cornacchia's algorithm to write p as r^2 + s^2. - r = p - while s*s > p: - r,s = s, r % s - r %= s - - # Multiply (a + bI) by (r + sI) - a,b = a*r - b*s, b*r + a*s - - a = a.abs() - b = b.abs() - assert a*a + b*b == n - if a <= b: - return (a,b) - else: - return (b,a) - -def rep_gcd(a, b): - """ - Given a and b returns (a1, g) where a1*g = a and g contains - the factors in common between a and b - """ - out = 1 - g = gcd(a, b) - while g != 1: - out *= g - a /= g - g = gcd(a, g) - return a, out + # Get product of all "bad" primes that divide n + remainder, bad_part = remove_common_factors(n, bad_prime_prod) -def sum_of_squares_friendly(n): - """ - We can write any n = x^2 + y^2 providing that there - are no prime power factors p^k | n such that - p = 3 mod 4 and k odd. - """ - # We consider the odd part of n and try and determine if there are bad factors - n_val = n.valuation(2) - n_odd = n // (2**n_val) - fact = [(2, n_val)] + # Check whether bad_part is a square + bad_part_isqrt = isqrt(bad_part) + if bad_part_isqrt**2 == bad_part: + # Update the factorization + result[i][1] += [(bad_part_isqrt, 2)] + else: + # n cannot be written as sum of two squares + # Tell later steps not to operate further + result[i][0] = 0 - if n_odd % 4 == 3: - return False, fact + if early_abort: + # If there is only one number, do not return list + return result[0] if single else result - n_odd, bad_cof = rep_gcd(n_odd, bad_prime_prod) + # Update list of numbers + reduced_numbers[i] = remainder - sbf = isqrt(bad_cof) - if sbf**2 == bad_cof: - fact.append((sbf, 2)) - else: - return False, fact + for i, n in enumerate(reduced_numbers): + if result[i] == 0: + # Previous step has told us, that this number is not sum of two + # squares we skip further processing + continue - # Good primes 1 mod 4 - n_odd, good_cof = rep_gcd(n_odd, good_prime_prod) - good_cof = ZZ(good_cof) + # Get product of all "good" primes that divide n + remainder, good_part = remove_common_factors(n, good_prime_prod) - if n_odd == 1: - return True, Factorization([*fact, *good_cof.factor()]) + # Update factorization + # Cast Factorization instance to list so we can append + result[i][1] += list(ZZ(good_part).factor()) + [(remainder, 1)] - else: - return is_pseudoprime(n_odd), Factorization([*fact, *good_cof.factor(), (n_odd, 1)]) + # If not successful + if not is_pseudoprime(remainder): + # n cannot be written as sum of two squares + result[i][0] = 0 -def sum_of_squares_friendly_pair(n1, n2): - """ - sum_of_squares_friendly applied directly to a pair - to minimize primality testing with early rejection - """ - # We consider the odd part of n and try and determine if there are bad factors - n1_val = n1.valuation(2) - n1_odd = n1 // (2**n1_val) - fact1 = [(2, n1_val)] - n2_val = n2.valuation(2) - n2_odd = n2 // (2**n2_val) - fact2 = [(2, n2_val)] - - if n1_odd % 4 == 3 or n2_odd % 4 == 3: - return False, fact, False, fact - - n1_odd, bad_cof1 = rep_gcd(n1_odd, bad_prime_prod) - sbf1 = isqrt(bad_cof1) - if sbf1**2 == bad_cof1: - fact1.append((sbf1, 2)) - else: - return False, fact1, False, fact2 - - n2_odd, bad_cof2 = rep_gcd(n2_odd, bad_prime_prod) - sbf2 = isqrt(bad_cof2) - if sbf2**2 == bad_cof2: - fact2.append((sbf2, 2)) - else: - return False, fact1, False, fact2 - - # Good primes 1 mod 4 - n1_odd, good_cof1 = rep_gcd(n1_odd, good_prime_prod) - good_cof1 = ZZ(good_cof1) - if n1_odd != 1 and not is_pseudoprime(n1_odd): - return False, fact1, False, fact2 - - n2_odd, good_cof2 = rep_gcd(n2_odd, good_prime_prod) - good_cof2 = ZZ(good_cof2) - if n2_odd != 1 and not is_pseudoprime(n2_odd): - return False, fact1, False, fact2 - - return True, Factorization([*fact1, *good_cof1.factor(), (n1_odd, 1)]), True, Factorization([*fact2, *good_cof2.factor(), (n2_odd, 1)]) - - -def sum_of_squares(n): - """ - Attempts to compute x,y such that n = x^2 + y^2 - """ - n = ZZ(n) + if early_abort: + # If there is only one number, do not return list + return result[0] if single else result + else: + # n can be written as sum of two squares + result[i][0] = 1 - b, fact = sum_of_squares_friendly(n) - if not b: - return [] - return two_squares_factored(fact) + # Update list of numbers + reduced_numbers[i] = remainder + # Verify factorizations are correct + # Disabled when python is called with -O flag + if __debug__: + for i, (success, factorization) in enumerate(result): + if success == 1: + assert prod([p**e for p, e in factorization]) == numbers[i] -def sum_of_squares_pair(n1, n2): - """ - Sum of squares for both n1 and n2 - """ - n1 = ZZ(n1) - n2 = ZZ(n2) + # If there is only one number, do not return list + return result[0] if single else result - b1, fact1, b2, fact2 = sum_of_squares_friendly_pair(n1, n2) - if not (b1 and b2): - return [], [] - return two_squares_factored(fact1), two_squares_factored(fact2) +def sum_of_2_squares(numbers, early_abort=False): + """Write every number in numbers as sum of two squares if possible + If any of the numbers cannot be written as sum of squares, we try to abort + as soon as possible. + + See also: is_sum_of_2_squares -def sos_pair_generator(n1, n2, e, n_squares=1, exp_bound=None): - """ - Compute pairs (u, v) such that u*n1 + v*n2 = 2^t, with t <= e - and u or v (or both) sum of squares. Input: - - n1 and n2: starting values - - e: target exponent of 2 - - n_squares: how many of u and v must be sum of squares - (1 or 2, default 1) - - exp_bound: (optional) exp_bound argument to pass to - coin_pair_generator - Output: a triple (u, v, t) where - - t is such that u*n1 + v*n2 = 2^t, t <= e - - the non s.o.s. among u and v (if any) is an integer - - the s.o.s. are returned as a pair (x, y) such that - x^2 + y^2 = u - """ + - numbers: List of ints/Integers - for u, v, t in coin_pair_generator(n1, n2, e, exp_bound): - if n_squares == 1: - dec = sum_of_squares(u) - if dec != []: - yield [dec, v, t] - dec = sum_of_squares(v) - if dec != []: - yield [u, dec, t] - - elif n_squares == 2: - dec_u = sum_of_squares(u) - if dec_u == []: - continue - dec_v = sum_of_squares(v) - if dec_v != []: - yield [dec_u, dec_v, t] + Note: Also accepts a single int/Integer n (you do not need to cast + single element to singleton list [n]) - else: - raise ValueError("n_squares must be 1 or 2") + Output: + - Tuple (success, list_of_pairs) - return false + Where + - success (True/False) tells us whether + - List [(success, pseudo_factorization), ...] one entry for every number + in numbers -def remove_primes(u, primes): - """ - Remove odd exponents of primes from u. - Returns (x, g) such that x*g = u, and g contains - the odd exponents of `primes` in u. - """ - g = 1 - for pi in primes: - val_i = u.valuation(pi) % 2 - g *= pi**val_i - u /= pi**val_i + Note: If numbers is just an int, or Integer, then just a tuple + (success, partial_factorization) + is returned, not a singleton + [(success, pseudo_factorization)]. - return u, g + For the i-th entry (success, pseudo_factorization) in output list -def xsos_pair_generator(n1, n2, e, allowed_primes, n_squares=1, exp_bound=None): + - success (True/False) tells us whether i-th number in numbers can be + written as sum of two squares + + - pseudo_factorization is a list of tuples [(p_1, e_1), (p_2, e_2), ...] + where p_j divides the i-th number in numbers with multiplicity e_j + + Every p_j is a prime number, with the exception of the last one, which + is only checked for pseudoprimality """ - Compute pairs (u, v) such that u*n1 + v*n2 = 2^t, with t <= e and u or v - (or both) sum of squares. + + single = False + if isinstance(numbers, (int, Integer)): + single = True + numbers = [ZZ(numbers)] + + are_sos = is_sum_of_2_squares(numbers, early_abort=early_abort) + + result = [] + for success, factorization in are_sos: + if success == 1: + x, y = two_squares_factored(factorization) + result += [(True, x, y)] + else: + result += [(False, 0, 0)] + + # If there is only one number, do not return list + return result[0] if single else result + + +def sos_coins(n1, n2, e, allowed_primes, n_squares=1, exp_bound=None): + """Yield tuples to solve norm equation u * n1 + v * n2 = 2 ** t + Input: - - n1 and n2: starting values - - e: target exponent of 2 - - n_squares: how many of u and v must be sum of squares (1 or 2, - default 1) - - allowed primes: a list of primes that can be removed from u and v - when checking for sum of squares, e.g. u = u'*3 with u' sum of - squares and 3 allowed prime - - exp_bound: (optional) argument to pass to coin_pair_generator - Output: a triple (u, v, t) where - - t is such that u*n1 + v*n2 = 2^t, t <= e - - the non s.o.s. among u and v (if any) is an integer - - the s.o.s. are returned as a triple (x, y, g) such that g*(x^2 + y^2) - = u + - n1, n2: int/Integer + - e: Maximal two-exponent t to return for + - n_squares: How many of u and v must be sum of squares (1 or 2, + default 1) + - allowed primes: List of primes that can be removed from u and v + when checking for sum of squares + e.g. u = 3 * (x_u ** 2 + y_y ** 2) + - exp_bound: (optional) Argument to pass to coin_pair_generator + + Output: + Tuple ((success_u, x_u, y_u, g_u), (success_v, x_v, y_v, g_v), t) + + Such that with + + u = | g_u * (x_u ** 2 + y_u ** 2) if u/g_u is sum of two squares + | u else + + v = | g_v * (x_v ** 2 + y_v ** 2) if v/g_v is sum of two squares + | v else + + we have + + u * n1 + v * n2 = 2^t + + with t <= e + + In both cases, g_{u, v} is a product of primes in allowed_primes with + multiplicity at most 1 + + If n_squares = 1, it is possible that only one of u/g_u, v/g_v is sum of + two squares. + If n_squares = 2, both must be. """ - for u, v, t in coin_pair_generator(n1, n2, e, exp_bound): - if n_squares == 1: - uu, gu = remove_primes(u, allowed_primes) - dec = sum_of_squares(uu) - if dec != []: - x, y = dec - yield [(x, y, gu), v, t] - - vv, gv = remove_primes(v, allowed_primes) - dec = sum_of_squares(vv) - if dec != []: - x, y = dec - yield [u, (x, y, gv), t] - - elif n_squares == 2: - uu, gu = remove_primes(u, allowed_primes) - vv, gv = remove_primes(v, allowed_primes) - - if (uu % 4 == 3) or (vv % 4 == 3): - continue - dec_u, dec_v = sum_of_squares_pair(uu, vv) - if dec_u == [] or dec_v == []: - continue + early_abort = True if n_squares == 2 else False - xu, yu = dec_u - xv, yv = dec_v - yield [(xu, yu, gu), (xv, yv, gv), t] + for u, v, t in coins(n1, n2, e, exp_bound): - else: - raise ValueError("n_squares must be 1 or 2") - - return False - - -if __name__ == '__main__': - from sage.all import set_random_seed, randint - _r = randint(1, 1000) - set_random_seed(_r) - print(f'random seed: {_r}') - - # benchmarking for p = 2**lambda - lb = 1500 - k = lb//2 - d1 = randint(2**k-2**(k//2), 2**k+2**(k//2)) - d2 = d1 - while gcd(d1, d2) != 1: - d2 = randint(2**k-2**(k-1), 2**k+2**(k-1)) - print(f'{d1*d2}\n{2**lb}') - - import time - tic = time.time() - res = sos_pair_generator(d1, d2, lb, n_squares=1) - print(f'time 1: {time.time() - tic:.3f}') - print(f'{res = }') - - if res: - u, v, t = res - if not u in zz: - u = u[0]**2 + u[1]**2 - if not v in zz: - v = v[0]**2 + v[1]**2 - assert u*d1 + v*d2 == 2**t and t <= lb + u, g_u = remove_primes(u, allowed_primes, odd_parity_only=True) + v, g_v = remove_primes(v, allowed_primes, odd_parity_only=True) + + (success_u, x_u, y_u), (success_v, x_v, y_v) = sum_of_2_squares([u, v], early_abort=early_abort) + + if n_squares == 1 and (success_u or success_v): + raise NotImplementedError("n_squares = 1 is not implemented yet") + elif n_squares == 2 and (success_u and success_v): + # In the n_squares = 2 case, we know that both u, v are sums of two + # squares, so success_{u, v} are redudant + # ...however, when we implement n_squares = 1, the caller will want + # to know which one of u, v are sum of two squares, and so we will + # need some sort of success variable + # To keep a stable api, we leave the succcess_{u, v} variables here + # for now + yield (success_u, x_u, y_u, g_u), (success_v, x_v, y_v, g_v), t diff --git a/const_precomp.py b/const_precomp.py index ed08bb6..5dd6c03 100644 --- a/const_precomp.py +++ b/const_precomp.py @@ -1,6 +1,635 @@ +#!/usr/bin/env python3 + +# Numbers produced with the following code +# +# def good_bad_primes(N): +# good_prod = 1 +# bad_prod = 1 +# for p in Primes(): +# if p > N: +# break +# if p % 4 == 1: +# good_prod *= p +# if p % 4 == 3: +# bad_prod *= p +# return good_prod, bad_prod + good_prime_prod_10k = 678831692590323346796807762934726038890633874182421565870094868859746393339032372967983025537545214448295714340531909395683479295599172896314863651481470665904729481848658047394468423142798712722879313943982400498738528895615360648879640351352393994566809940400025768061248633898249050368635545274212045675085896421359019724731014256209326154083426232965342440150182720061492394975866239113918959579935489884857264791298642713339616150882449324383184121660773179743535683126345418834682360842251087399480662663527693084265621491228607794537975121791979302542334007232326331268223048355658104288517940845077779804550565860647190882904822953254000138882674715580843566825988657221301613248895805090013138308675514335356584908745970810648641449130884443511607478799136477618327722457451234253147997821110181664872679340020360693204369305442489988488782627657578743062714119444521202357497028930918979994478039073046237934686385297144760565448085473240367067256124612163302360684729913903239285393991656267569816989816591995633451410141700533647130311788608548475343769417129386052430434801687985259217816738125461340480074656302848684435724216533927343335280863755341290616260518747733252217286539729175516659332648565475858148393417784713628138184179647803839261185737408798527162369342261660039397096628975556719946153372025373671929969886881955700673791218633543016315553504743454561856404733090673002211694540000386773667057121302759035800751751573781819918356744750363300191644890845174451727042742615186770846269437649485196656607019949723323181010637791468215247128577972467609221071660968031783731011832478178468759633797340519540164784564044540431801127671967802502107489485063655513813623507237218785944756834616838585656923523256190256458609084283928970638913017593547529727098427210792319075828287586212071893475419371338681729739147353843282906689150604273293806475516269719858507854843499001722410095448095152152612893328702098162811439244595470247494558386426343910752526677429760084497481469017507167310186622376199980789152977116251690068936930574701591221983010990007895488243803742356701696868090296084458815292294886945 bad_prime_prod_10k = 43818431158532702980213044238377202797867929740599566868300971988291926835547782569838749043132426141436231131056569179877114157737279067571922703651709270899619608578252161183425584256904877786238738141818564527444211368187875843274878586941662833975895223543491228785714379008459362310030343463916916455350839885310648330817037583039332287772641769313455581668948926998650777423890419666132241750580427056366573455685435932086313294671349081286800955300338900646319461696926544648378387504554503041786959692181721488616300775739307691340221814307510526978185555574882375585117695894927867122076062952587196030910249335730502398882303705655101178524722518180840695375928470516855216416603918024581248964984009820591928620440073599629883078982108706864026754556243680572018659324729736829874458638395631150103828354427105466435288749107091610166799000613393639676891476246306745461069306190223352999672599190054172211653533977055900355293047317941715241280169636488240529962771969385895459326401323150521017169890874333166211423205811035260422372979169171696473405030669655887961885108305478417735844464983891300685417211469508441731635768923944278944806775061591736315441260348598895619917726064195530069374231205486035949647091979622409108310943198439418617449526806931619024021322924071007973712067579358138212717237199180796155208591891519998432584748852314871997078630519432440049903843464907360349931352392997297451636575550495882658564935959408036964276414397532970331094735939917334709240801321417884457139474010492908684519712176292024374239837440512399014225683055989793921493484951621535719600222334895666121220412064708340537505742235055788291939774404232512238240830499902201002900371341372734780386472370092240743241741103501526043922594642813149076844701536446633948536113597708233358609438091018464739798653060141217998751246123901582724207651225727305530895310288390170993082119597808417194694045188271070196694849545617933624035153954838636798418821046740620430344891747740797321873506081502825847951049488719951329578813090191171124076699283764498988358382067017106668007281330534184192655353044168668594050900929227558485273225187394205408339 good_prime_prod_100k = 47310855547175036743506709264392765244245630790736190281434356259523357717977961729860438358080277398556424790453980509588281167464487112307488799034785105144169756039124966749608211628624846417198002391262304788584865022624418669167839386014099639270015505299402366987787002690013358274099157216651810611444390735081452396086339608836949714305088036323360126998673196191208178354360747003245261083110304225361249618242213594026280938843489553231764491123574496354320853552890492411193586788656784583127816677554362811790306764590409168072109972412116497066509177951509729273164457758527857971661956389140662386096814094722435838862952907236921073188464314551832972341148185174146906079291820295273888382244389102138483316763085228033334715039552537207191829875902741840827733006217032746020862542973034165118649313444065356892286140778957887832468675273749766056198931771963722515212021304278077184937630935297348009808654514672011680656851153079869115156452018286453247002017955491725231289309964045538194676406111440712543929628587658043101993145433253390199410670231669600100232518901290048338608084443366297384223810941306235371560893499157053636026037601758695072583820357863971549575564524564124407349122435253214394519091313440962364582328801864445463384933426737066254434472932209906353435972713895817870058444888800642907190721949035251238523097793887798181298060654052103910593005362045631341273793691390394396585730863994315006632536628478323604055965818253856814171601954301776577717865850623076088470593439213622945788667128898819669597263432186274807739129358696285874311972133300179525545383876326199429983119980861448043806930783033535952582745878255504634996554664018229663655421562009501008048257085149662688129041736370219487778783601251321047206698238659730054338793819292333941892599478316915535488059675881146235417716813151388789496440348058369635107530362748009731095039326117847415091504735269056399647328690504412280321795596208146064835995768231005156592865573253578201403918945023574761338167622239134170202047955706589920388086769995710769224396875571118964952310261458064827005699691432350235693779664755865002656205604470773232135043491198722292304293819539477639531580397888632046222025496025161810233056287002088465244667202973275819493380696854360288575880157883216533423472632493642161264257699148630027603274200267705998742406733064770020376258729596583216027350100085322293870053193770746593141233852845361805547183695984526347703508294258646689197410923353673078044269275662826419122918739308040062121421229065041657496661885145623464364830462692089007609575967871549522510853399516348432143331159876428431450829788950850248584134873596087575278553536461365497058319306556265090816235563600134922442641428421564390097752566766269822017802482815153499161810508919632827045701472162674919644663222381870358904419776389730122053256233949336090952045901907919542264656507706726683272937372778027122626014847686146021000634346108969289998911852412643573199935335533881051566728529739054653091190340796357526150292591370082742207503473644023242590090122938154704475763703781141771442976558707005577574652640343589667841392861616722991881686077335754358031874087720245977812275161306668058138256825321354374996042127343799723119724406639778121221619066066272919548814597175588443349465682706834941234111236080024287940992418015963557709055472532712893896468142724801169656753667183228424034390105903496810090535385742802867019735977592068901326789805917697232086089119584058230305744168620923082397531492928462345016491413509900675547320926521520438566773653632211270117404474852599535817146880897382374098440594579216854061920933719562811702139152518257758294065137223420567370630807320431831116636845934227114627906485694968012188554986091462158108930920339056128976979317779916395606543227712661306493622459325372084356528337984565099789419331246299713516151015201937757299268676450458762192612098349657829292465870582969501401096905613021479989860133220718690697975245428334832812554719982528490127097253997114362094998824746023754509270997072826026335964821399572868423960388134987168024322070660655551831568959181160558980780490960920724918332325892063423503179261731596072322434239999551732426040289786857058217130760527584480379678386825992663372353917489983978728159195630710311871321214632088613057675588681140691031342945018888689515684761771697791257145433424460271466345715967580983971612404168900705791012774619285116707677466791838345241534530658960905436120686488515793089530795265815335877965437856283133509122042207321517986093851263204553900410978570560234524598606350446488485708463510167153086394910595653086691218716173708690669933446908458989013167295095870760416416976433219928282022309568755039317017614721768848330425513813454328575737658919991619767864530106429948943260218240181507481573767217746592090702329307666015136962522047924296126083655655450402262865809765915694777990091481191021235125509733408076986766632330160795559316285722037345806907255394672303677886668607328787415136110340907715446673766786640532761274213879172437859424234180605600505958185595689328535839218588023834418228466505968904296628980503391167089190856984266061645429116524179901318094902759998638831907395692681826745596760314747879689311331508658661735700605352231362006621384668344765744103391068641826440811842148917276383512307483972924387866329077813016080504781919707578557929151337467566668025023832340520272132711722443936933708533241493578920218022744596284724234165472035293794156721186647008907588229319361791930793251087619858386842544162162088886373400500574200657924236639004843686998973139840723473135639605741766537914953132891825509115474220022012068518694770119428116106402071324004549834288873762044830115758336414264533039775505647264207058209312025396359827912341792746708031146729396532565736957803476542475943033844887331416581938731882432035358006950328837687396414281071557622321299698750335170614886555409818310626599110367143646476121656078355840455219072222774485600114861753920030585073949494063534045145173664500875389100321359349652626652458587913989630731525724660942930770037624647329176309930869762718664381703179743931352172125526722508357057549479523597950395029572653886709993401352628462712940304612973467677310654457239566535792995965271613225747252272919287223715131309057103433368718173754735410609398140957171174539830523469304771091197652562295282987852676304625935786760072253356556179547075710212221640856637784033714009675709193359175494464140906617489576639734101479017340189589339960943875990535563462766754870323202988716499482938059050878400551910566623149447247517162923364555785212749802371220796279099832696257394768471458833502723557986769847782806667252518942754116873911780442942143206740874583544572235150407964120552916851934825121770594966688344682721684971097120735944496607216432271686198085951476565852320283374823758021888824466568506557743200614814404223162006009203788255336759000675358175872883408417869722292610858955391769223910043204349764259599595729672846468256465825035601333540758882284723022228909612530237815735613774553010265423731557076526369915762616005020416670058784612727557435849265596871795950913981533919884246947798242596568856301660494091810201392586778729412036169814350787009894022864744790276683359355618650409083365621494632518405719186958966532050977496390261456391306530453442453994530279905434201758525271875928512605952951951608886788656380129143082780729027759787200694768884701106986403851132798940970652590320920629378842525752967037751016650626823600461433059238793285256604847501884423703825212287324938699754886130238596337902526703956145524343019220514621668130570630134924580266948944276424702071769425496159213724073850969796483877265548638223653916260520402336009753467735321691130876559078391232523777791928923144497784769971800433052026628771801771289261831665870255408297427316410576554346121636815717359491378170439613924395485805314952108743171771285839710791314605442301293067950275046392987816282377614197102124106889716374784907048084708149728898264557675590276549884404108528366526123757652319163501234009247712049792472510334509857057704010357207192602035446074592554564805262165885606613483522631571487957315141011600309152497192840828049551037232439950269089283771588486565697956055348380101750292287758725433917631679770330614062044295447295601633898615778660930778819956472300983632118991512999916403345151080696755673212612808945542392395125655212867939642237578633818958086559625600779151005202870904134348719389029594025826246806973173355509864427775614196040601941913650185847184442855004808059841930825314715014967322448683963338460616561653765671261947748988470237167462238186616020402473126115399001908541677495241006066013171347311946184909264843281029229831912386931453623811586794257354579004180888289283356153517701441397886729829204479536793033735547340836539889600823015776794832371597239229867298107725085000387699808469258577973327531930730474881979988763763737008014450581464908918973576059958747578931633803101478829554670757222738293526616011889708837704775327461138317891763612601478024334207613151909605918208040370437392940855980792009318312634138506178264868878450407973696345451437749443804762733296914848496781320699766808474383475552460713187119120167383181586826334766607120555380236745686036389877236012142782936301923445344667670006483441268477638366264596294750718596580673714640862288547644058081896031079920428565620648197084843440388658718419451432915813753445429921553776176876258952015601499328920000283724053067562627322589376035634708784003925909805755419544498172228351789985953232876116168887902216262822874046637237434072313574576108055008862212003288996096019025337237155699257600502109039259327581842524180543887813035082051649489113080909861579775821733648715361017290655585779047017545901635543483544524761631793490424816637116266625851181348913148477880593494893410294759194933039383057679542705414169484664507885381015555163999246899201788536221591187084257418862331453582062585636645357687795347722227218396649989283695960329148218909737982276977347360462259743717410434311042194638949236224959947316890963862336565666452779844674094052427947469166877662637336758108000907921733169108453885207976831972141437731300322916595435320546976937761264021495468573504301608958885198908603089043770522019552827595617980248270438612876971360673211673902518303927398726454884687501872121629569642613058662542314229173118308015543402195832219169351940827962356738432094367970215648398037882564002283751183269528196831633384918469050315127118779706821089827595347711146744946709793077113363631479815666728535582260759937252805519291252624882490354706704099456012540480164539898173291238135705596705549709839050756843216845850571463942232971955953256036564399682818145250317164996814137364521865400193638327268162098181042639963881644200522281205962953570290746391371943424910391924709603073184732477297973342041068866235404112550966492957219597069172477913180072115280736325945811876699189168758621301836127129080423862053626878040158581871208192049415606225688409064671423973815260591633322466104968780820843107566413880776950437402881258199024384841770230157924864980084187806536581666834938183445712345522415400094476120289104155906369528791925767513647660280124275162382643414278395717964486102830413393600010329954337281241472947003415484016564366711617942067599250163571667686990937947767281709000229427787185415132048342899016293179585131915833692922162245321797353204438009161085301675007912947011202424916891886096155156380818239482847938185841138188017168602675668628207263537619722083646809120789778653387670479654305091248486620070925780081293743830695506195935719309975366520859364204815352363854233261634694308465572773098865924755923698426156922565030463708914359427105225765029310095452255313624824439133627501247619616318599476746410268727134865679843058249908796608635626485262889570665010885001157172214331955574829907904229303420885605992856330918268390142781384035709269450996522667596607640430245938096215869915309265086918355092189280471807654150233331691601748628726112773867089010016070415368863335129156471862270298949330553718383999652743067997914690778969478827496941413734986005249724369426522494842461855241052379184494351574918942834301932412877873759400650054970021800379469175529173178937125022798247799624268559606357837068260066536082357644866706348911639773599096130181784668408853315001873409787285366295927185324727551676611810422850918896520342245754314758927084102163143919930627134734631989778711536941464334696190333788239132112232542637502444292457770739464544688590935868818114667307706165322150327608431611444715094223409273777394125261842895331497213076827195876713852437498669238280343972361738200212057673709643797352316736417779793796784789902318941645171493034321750969815564085041920640824927822456960217983673803687670927382108758320668780498901710254576783326921515047930784957016846729128339866595401129420614756473742913545374285644154389862235782505529077059270930795074180757769319028507448044868478820094163223095322257870351694347453033215795026691775580855707529645734114518831080221469994933994380895799367380854484819412193561438130117814427039979669987343042335176759034939425807611496780118936514767982820802374917024156699650960200891656135914145468554813323972668346252552607067876701756770136754426579040307480935559557278004091873426398897982466429836735326310780938115476620290243260317480022581787893012607238581602925012846934103210600706881670809344171396849139171105510352345975676675223829397728595180857348983773939937272401493703773741515255589820605965735547261777763384861067906486777712607240773135672817920313447721882378367566926452288658619750839608607814979309061990352442972978386151849678381329595086738903777315397880992605029929112234018926372574660486637866314315860501832141828179867993636855558722158258080532275507538090846607279039325308560893639395405875082982941013383736532867902942349825791417579080281913539783258553708080360504578251017675643738682854170072749164135674181738966787454660110605409310336736727895425560882277932829307881608465640265369239224985334683818291384481246470791349368728201023275477667296628057177870412905096878168839257375342323581026064207539998637320564403682747075190212112232961612852305774965593785687252102349222885916525227383250976716274317123033091102046198323101409113501224719375894375230162320727086819388018401176762375436849065830182332801577961148405977337223418373038834638592036232329441595286560704290759881079045552421280587529990403510634364524795577426737347540744574107799062593764164671204682165420814677494202755300802957017183704655744975803985420870490763407360177147921722175240449945620962915869055964497397373245600541314707727647597537463115516342250686774636329186417041008276591462298511786009103653104691799395118865081707551002921525259553402035921523090644708035247641941071002813815473275968607730255411810577852213254073711250771613749375096646800787172399909714033878927301076822249405434192092130341831438201364039622861376536998336493605687841083052560267488650116613047520234360765894103771525186956591960481052373254061476242858855139476980495280287797987303917055000660382008615048432231796328228979240020801493892981627569639190694461793992164770436692022057380009470267052586953352529761484116163174242622643580329890680107858292402983159688809703806455651203742605781370360043542395942191350244807068068299264342614195077181535383706732206614757430002793946296415355025902096439941540909702504872164871227663691420954617301693876507655777631396048825541713539648289411350217001979671767708542677727892239555316545024822278237715282179858429520025857979589163147436264831093430035027278209351469456099662116384902645799620803944007074735854481766746275214703431963849698161832861143741411322331604605706992658853199599488770241564416051847583735705919873067719735157027616223528383965045017898831871379272435004138776598928842621500995746395625856202754894552296602298130212585388633732852378903395300610124883097498982674440176454134459293500970771793200667951146700080120761646068599657623953950981407579833044915788985919198150504288657264622453158100678267964259214761271343603075647214889979400086295510656225387223513986489394993897361232047097099184751556565292584515685134983600703976377979804705711104972438619574923261840504523618491398987367910023506972805211191124358731007537619988143586766844990931435830461254316529926849495272737679887960526189660709810583981423763939863582340856526968725521122802474356401080995611020318553067911086578589106951916823544448112658249594605019891162548826214585438598494452136562272561434039267884873799497331203560187386509426361895853777561844510972014976276995956319217082214559972552670361894467024168065548858470519971085256151511546196335890236025087466422535451568451851929847463883448936446367528691457108576573756507988284309609949868979842701035334719374266921337965094058245700229458413155010921405060830292616798240652551593742024693351670377798096989809280907805407278119246736039964489726104035512815974304732814918332527367671366162500779321014825498953079003594033506975815719108437491901712335375479814483171609192628447194485755443312106846710334187338012433291230510229099017524006858935717024751247038134089567333709294341251324297821215147843537633383457378678705806690182835572509975222499935492895220483348048701274664127952871266877138098467832626681674297398239285058995785406572909768280143764279134409954527357137645136758697146659285878668853680349128798159485227283827827264172920939718764088821200982010062715900219132205840648162140381580287108140196606168407880823909616537330477237199528788909062034266520731802828306525282952232605445326377602434065416088479352625866473294972814384638512406912687201829006693981188064230029500331492520193959495866415444465801556623419158430739732224738366561332232141234742027845022463943317255629021387110725187811948305732254336446112188978456465624825867144093655813148984000237610427632889423203736723341533596974476275017529730407374253542571522083130877324034802178752529291193549244021287149360898191832208337809310977344827501272068238375530093734927745749290858016327518002277439402316151139275979337269262432902383410992750737957929282024533194417804135746639312572942267775587571302663798256050240598722588920836153573921804934623440901317204753169169570093918915412349581888899073927962273294601239653616612341598748960742853005860270374241970913996789618505042779708885669215964609930360294476895928001169511881214143997957743324973709583686932746311396862680133530361866883756047916554837946200638917842183467693771023864190271257320654243240709840245234959932638565214347422288148347932709512313550717052831666536042200323361948708656631566546752240671891911717778956836585500624423625401098060143096540961654884472161785037642772402774494591401955398298265125713296504133754639971669550871261269292525678624775979155415330379781733508060094801125110333018594033756851317752684408414921787996670347952852579747364357102670747236776350726215155926569112603097218876839093531869470324529727256568100550405233769473579040501413380694410897657598875891702091482746390898654453609669272841257064145430660569066758918574726347039550844171380059203919672679005066602557562771525316020144491248827677543294679651165913446758648539916084960175012615786540357225899259200731435189747915431825750076188659527357622621677093524170814143721095804047976667550948362646505076285438143246591258199212831027671839829629475765828100784115172000503008134190368693872070939367817521150522653132179136237799635404726567643256214525337495290425595876856380867298027412034389020932129508128771226264156740079887996515356599099878387283762528781850693451009413922667451742660242634587060988519009256400130659467133525383139578894039287082772290151982178916815989642692187595607896274264163911352657656051436675089226066000142412033387495354650806415344067193661770670780637816356312619520800463742623655317647592230202526267498971542275118335417427727231402828980412856986119503005952485118648309368128164524217712263265039542413414719304970872480463232074972130469664902596622539495793857888202858259244872943014967296772012405170308051682879763747193585127237277542381501054507922736862421159696338223277108714085024840840137960832616829110320118811934134849832219381519360045660137804522965808439054170503949599623002904497955480517906341958005825001535130674773819518458807971149255813609372389977158335771426741607700836621885118913364139403660088514643978562138864017478640489714294393404417096689654554351008949336986439217661643320044641975325201744448528260558471032531544702534796867309572965027590984555473790206452288282165624600226560970012989355386106206839579039444378499315581372134682289332041925741561732412915646117094581773246395943464235331653378773040302307107252495778115864920051806526961153052286527724814682766051831165871774090030226207977065967009908347901872691999467520637390354420587815547603557938056596393059321189918377411862357608948994210819076833350990524174428905038264497526710734074057400679302790857597833802701438267748181435075372480616856653487216535909013412799356927375828180336033778727456261555338784917828347476305315254985139189284596189603939611332950458372403241258303008308910567757983429781484514962940869762086270449779900247865816745644455299947419908615837338086475856360965 bad_prime_prod_100k = 6894375583796955808152870940250887241411398356569451048283495762999677927809573014691363690123464535630208842011563796049758765263851113156072053227399249625329964813352136118550563301715658785153650041614403874919760768797431569318202908568001653922227279099889430489320513395253320265938140204306578749870588937716432335616077983159343684676677754561400532960660998766435239072121947012329335249507721723202790141972441262321069745835891796103469190025721496146039388594170446622322891361583238763111906320421068549736258463881088928103913191068429546132809948845761466618873924024501286066985051532888911470368864148754629995918889593913712785934369865247516805152358415557880619684063525244023053606042199127077179247324942702079645484152050681655573169965516178428744735223909961971104547460611018107885431285225105872552030507153149789504558774833246654723971579395574072732640110074085312297835564341641512906665207324658206446444882760251312408115165422417760437389850955585257856965369667355127494632320794671396408198302560074410976457591437421614505898359004164177127078548202043846699259795625917240062394213756019487123826764567805472954105334086618821577971381291476780340086517701543807292875873173459115676206464495192144290070170058955490803716248671464712830489109250349180976710142081692710297118275260438851917720392981037127838332253689977779463055474442998591762193412131965415639703492611734948322034643289547182665877338873644144010262007597918440203980869340261407276578344410580693807644181544179243388210977340449213825270486278029645612141335385031636571675509511203844689936362726795701446494658571277566626629969544712049925507814451698995271266308837845764592917325856333994129654792622165402860491623175787017681081406099867692283646586001062762257465818977354653628453981783000330823825678306304088931076821211482752186776375274875005248408228077382527339664910848910030729838883724451173341022318353372509760068285534127453245342702283274280472422500541152487776510031910672910375754136549043955781904244414100700120044210888879679585903792356800096976864615640151786515088822885823109085930271659176803019525355132083353650630981312459520804835153364576122830574170892535780627088272149536814089025663478127889351338303335562649800996028064371563599521854255813659029432087133974826216867555426850219873905473262260448521308228026611472361615416688023271108182210303440110417407047559202232571417382814985170738307365537333810214489151977739479490679671718061642102773833864740967614121201574661807792454042361271454425562137721245979076454566972817546848850805876873294016887273311630560470268739155717778128460324603227350613153368181125854096294922081325430744971721357399516599353904809288668257152300905722674091628467828309201946052853178242418366491992795697181141887133906799262128330585162478651347093214160970192276646395324246065605524757460759196087286642220999237067733063356561622352291228990069511455981528403610124350488992201836775995381936686549227359317414396589995755102207541966428192877804528152834120285704648272421990744135640403933588927351230997420151133816745195544767744465148421537775512849126308309403342947273839180959703838870073448621008297728243842558747661954165307274935459253478427773735112773894454657691108955010329525170699652259377165842742491130656132933195891757167671606855785952536288905223643150562685049896089849466467885363274859625024534495009239821080454576599644167029024708612268941902901921738252867634944387799420448785226657019183790955557622303130355951811584145346542568429987500310604666813181323166654892866069770263400744143892676912798701466083773643726597766783637412311463936221444877078362592477557545100178025343388071397424519669080700335045869255184414219809307469608053549748653621468902396457788565405762602407212406012814375146352331366606822344708789354879504152106713977768991665726157305267331767329265721217437205250787265698177480536203950721043335772461972376785336898562711413880152032406484644572874023416528454048227563964804098107359066571012658496220108475091760581126093425082521088099311618299795039768465936538571288000306374471183988327878612522303906616629072590099924080048541289057432140144138881857183128644439019824578885938280144136983558316921004042072684863194663880044629517629397248809741399606869620839394122662991473671142766620008695404099013808606585295682906902258473008579152092826790040436104221598391961432725425452215011315828683846316301710117202357564913729912816957626479750638061540428412101442878292795316317449726185636198682466207299638373237725024088026526723699815657034721606572537806271216559454083616739147983404774616467557664684094608102249293591401561739765825562491312980381467003021764945491172961625428155561530721364474171743997268988443391751355903034273041972046232612335235515697066476121244177976767943785551995535070969890779818513641029065092810129197641753479861956510175665365923964104958931023490609843866842004133602553104911423199794248165477711675931620797727997862917268899301040143169486312570081329195778939859666890979856456526679752264990501104727067457085361849598939344134607131660352713613929661972689183344184281897732817647495110998001201818375244873691817245240711029230773688509688933407024761710936849527938617287435727104109371956475340674086446365924230977803304965027348802700839316480411082385701753827465788712707164879111955361444928797852174917152766637382127187387580178774576368157929876402767219290483066940696176226667856865544063235523950537317641121883319016312814407395742457120703744057409834659732313881942503794023877139651361754347252135735728151090835356853514306834428261265486300655610619959152267662221526834662703261245391177619298676208385173974065368401345186339331311256996451264871903645297850320516802127776959679107048072647905322950445579705302611808221334929215465572708767620198960283820710376211626636853197716995989144634650725407029641959613524873385008630467910802716176931394502925964983914768896582105749071901108832743526653002308332095106862601648013409838290342797723660163843105213379950123890495567253383614303980377019955405717746684611496952311196040819128745988435222461703666203682450538930564012522041726440040394888161172390430144815485886180086024037317924982801235462110339381640769532028902468924217727104294664464424424494192978537762050909365323978849803401789788245553727761284105618637438923113428804602374299036206248284904658603877061606978539877984325518877855225660151771861204588132312080913894302233406319009301085848440761084113712726678485896526028456667014628809618697909994495100317370729595909484929893856277928789374858171266444160156445757936380070719712524753451000541770957651748017688923624573749108085380414033710988259782788741133191407178222632561485447116297715833382353256416599389556529000078915192183088962154058105731217547623345116748770740882148789666013105894815494272951227242501080654794134628743724521160524853543819142409305594065660104270041278840240883144993460287654386998245802403281936565510332891759584518280654386671277468883650250847813287752700743081628651714885198724619297943392066696746798039598485966655781145396683109942938934566986619372481675041084641886329105944493754692778735531290240954529667769644244493474755226670255455357121422762314902011945440321357181117276219432892188464402187631074398143493603075830973892250574889368185262738715801803047729922433728042738958283172705850593213431983535088291447303952192902938450588420087632422068215408586303318660699646147611438192020421758531468692123075590483449427921637770919681353336691263095352968475050289064842008845709362515210269941134080079414819051177571833060611186524966835916663913844138411501043172433150749919719026516071234299048801205304637949002346723184905995711909910801918216725944328843551094317959493873241449547113940739867924870709836484085511600940582272260333324746572036280995521661938001080532793143623584778971988891611981734013217236166217727899187222274998127072508402623415449977787166639938978124928553813243973603111923853839472231850341180474338486445577776879591512015877077686533120695225470041859837046559683132332957600114265037494175481045038518661710659232449314920421060646967936802637712360285202816919816984406744810078305759183116085491530317321440129353116446426389896945576012941888176037989482768755245138813921837614064811994751871303500304447746459348733626537243838545828769490572094661876855666177386943353404007896952795938190470350876356046240295490041903707373464424574069791924539985833347509569520226846156166967777098276181998656349382629166539529782448144227424145348743462092003346708808796845048345666994053949956237495162842316472975181319098389753029318651387448931516224965303080975175661916835740425398235840033805769297913929248366050918971331608692046197711953317916975240989556551694191757331747045391996211279093387492800727279318859886675779499327530764093678526178615429770921051813523031690718143729793344227923893205800693966246112257842299499853189134727503274889485234333788331885873277856351321460503844466756187494275390929955976057702260470979579514327997457708321723570672288164749164522600154438275349413459010789094013368063569880314560361226663835443509830305211496082213754188592649049544722156374985294181254858952844641821370789082853783298702231470315037012155262172427647138078784024547966894813987654427256206529635404044402376528241419779466088153673813840845144776214075025198143353871867719611845787618163403537688444615107396341670268229686610635169109306973849299156840843932844540402038302985786976037734133305085495446841045466757313986561465630577612476154308626474866184278970727522322204585816620220766353277520031761374485380403150886462620295970071010794081196699709224181239913198903646693694012951481371570066795448773847738825459440179997907819877154559937748352921067537437459166050731891517550012048756738037895997262979066084797567805526127516970694415545335697930454664297523830282863804197962134167801194957209686251243640838306216345835028244735416766453677708451511425580954497201152564284052073374518172964007265691840073808770509599075957664178239884237554308528619640100774797104426872727527501068881872516201250864683679975595190601826462871570461110703648248716816667620483963798760544679907551135176726431400250305704038312190936468909640823693017469949138384065399944428490013376716973388912842576973935389582457358146390625644079800751646089581755308791161588391624777310242362302543478504044497184906957580664845082307766786214790985089756555873276853016502287028453507555698391975938007098803657789635367954018367674576666399073131291687751677728547981421845772096557304945639336948173540245307016050277866245490069576638723269615801598456847527166659492914255586719666031486415730418097563913315412985962749976175962651140072332355659009798077665576892426910424762673798870395551722711025592508834506213752024675523988637409202381833545721677718224304005750420806308108780375381356957035827680914090654801719090369738487748998194588456148785776876077906549285797469050511350446165464025941801266634999316953513514402048679522939258266454342432684768000789536729438318005653409812813180237725408958320875731637963137308111485875450725946282566015483164385256384497700669536812796002464642771694424413704916919110360967594177976044230526393230344278928979985657809624134731145440176661807782911983657145448846090241946561608466868975324966103821729192950301432390915352103329674739707898304498987340461948452858532463601396071172018203200880037821401135359804057911970052148146733035782256574012783740549329985068438831390496132084927677411066366863751820155245819600905104814111320668726279414645117584150955778014180313272074749465753951210964614441133025547223935870891315524167808963312512535742309083138511603109282239133383688349467825732060194857218286559726500503308479789465631623164876929874807665700052858416705424755398720214709975644592012316109459523365346082170295016904685920338433659304495327739343953720180055866681175537951984004305323166613021496743565291292467969489267273134163035148219062398474551861573832150798141932798248724062460364649389339756848122550607267080777307567628497676722668697827447763063420982587343408330049300959211556062769699812975845401144313912800035771298405416479219498597190050278064313305592117944719072204294264065622232045730323584555951655836827409011814626435570657946525049491028652248294614062882188028331208288079757316551292330947788499535388342258248090460206189595344356649197677971675823658545116393090602795455647231103250133415015105548542451603235673647509256334001995180297113684746479646354161471128352327527636978376661208819807535382210461573736577576902634908727297647690693564916002215983271948601631425617534548009383093694798298117810422346318342326048923251791503694655755405915324404609186220597654738358781539712394110273806678907332812295096849477902067693948907702694461836673597972671133018028125390759684776510793880968128321845527946060864181382107719825751424248354120622558042957831997750046187164463463809517683234634085883123574435109716682054225350470802474138787243499867747888556562185277336660841369414254967998804702879603819345629922831323411980584228935741675421572088142479421234534437047115865706555612210629736295454790473572001846229751568916620529618393302490641014562517820305636715205485217685946921386497651205476658506089342485154129877490678659511074663211366399547666927235870921230832204685199715755567419770396321768408331258314468367486197384867794349165846660816241565885998762806458549601556445108850178270868611087990278151229149883000950432465606611370181623991311305492100272014103220724344872003645951464051699993874428196553144006136770336815298203928481966312927435196305450909493297971843980560507463183495224227984717901102381452187720082229144390410416438777247104982230466816400143668895073665546230646949067248227471118887915869271302746015464125117699997013014086787149277684402250202444381706880340516454107112586054447206001216873468375599762877328679317435277631353300417850711065281774550151483333234946704895310656123381722246190041803637476499736380668575595128923102404820915103499334303241155329711764933570307195273089764157831495059602743382527747614682719139224007401290855110714047540464594232605635730878699448646593089527083980114623228363798876801810308996538494510037192064424079592666757909587038133507432440644416034497612902187648798955577995874087179514555114321462596733191199736139784109474009318534136005196608828249984380520436651601649077003364228577943667812722455015819335692570369442264699649803276514406792040176085767771127580404171535557088823447141928391671719013073315962857094623228456457445878394900944855865145119710394552304113527924728246267432044061324400351040578852220576455708692696640095392770022641239893502927582168935363253897040126010671686362912995122819305775619187434592175246191078102445413417011141639893029740267375473245697277207456455125279680615876211662042842605684867322753256413718623987163605563139496437302330223764647821555015330742316246201575571137062152817933678474215737328467673478733091164894570007679284552662927128880043741012956542687803598929492512717043423597864721168372031973941411884881675488210846061637204855751022394729957596043696688064767291587506430253974653693021415576356560886102484035511181210842893651136686753679358662864961426084268068938033044953850805021325434074270555250056422425548996526919945065605399149494465914644967598683469673841125382904594825434925719415449786910057755077103279254638162190378513016628655437653129158870535812560487340033070100630423066668203298315551560743919701492246021135595034109512164326381531229616097544053975941089848562684713162630498429392068001749139765278000317134182036113858396919547981326622924579313242754847419907458379949658700198045324279291972742875819639273602060283792282648069213807950466747606401892362392493596582425760374229760697751204280126222436408164253746437472645340832606648894247785660745477138739402897103305771102185683168829504555444730990474012421172037363063056020567052269126746570373226363384384464659417754836669749029768946420433505343992116657007571380203814749182144529473565131543851278085906289390519031595611872987493214698905405298775449583419127805594284235026912620177222549910065372487137860101353428416332112597082868796128571938924201139535080243833434645419153952216863067430078159022206816638144733021596072657007378099819220555995631960072341617686116852202361239914909257399801450067505742732467253698314724075480558042505146720906560197620253554061930871636282609295170613538699718557254859207225249631967912027643391666758340286038865495596537804420457566793948475187440534934944951513035191632858132605408648266710628228399524358510325570362006564959082172174327939403309516681321749803697320347687029249207920846698165943856734356468095280975110475001938977832273569506401324849914783517456791069770640146380420655658189103463426425873708274733452083376653679420348826465656403069269965395430046140837904388342984831185210288374122997783631663924048752402619803853836235971328418484828821993454943908929405916109654073327483149410082433590586959849848696398095181149407573441028736932458833090641205271011820904911521891163673083495497397370330653754914854531211309309347690843684063836335516300612827909823519834156617657818319541852934289685420387431431553982351279912466292623371989165003255170311324283760242664995972985373153302116054351303189733395866677861240082637716259212064352952337979943483604055061463671236262970542032316906104061134728691378613758484552527380156528156336895085538878375796160634349208124131724609482172121541291744473780721723017653844950558159808349417895898338778441254994218447951248166891964585609251308826051209895400537313926156972790987770773767048730932505288030784540684471903946412182800102412241875436429576104162712675728097777184105166951180591150047373372028489416099284027434243655743666826363813653540724682103651678460877599086969117038128676792566752400861350609102476534530222192023489517062468647686917447383809986639420133097261017028628877970137554765937200381531151509249084449332425314518462243588634973876275855170197567751342109307333162310168777677817973620600132366259636212246555706886867620103429182738571155380402315340243270444963106490047109603131625197279105077389667834997103237701782245795553471321561612537347764825220047798544978394966633196052756974729698447504530631439770102820381148215738845036635118081147156253698982122250694322985429433564934729458316514092586424732096710716314330673019044721187684746396644757775863053117361751202909098719054388636109465148924864406336281209190615031209342735699313587150110951230674609081116309976268308415454977606245309056599441140999321367376289170092193674900040522109424417035990085448776860881723871102571247463018343002870325809950541468706293460504102740594481008585782756352729800134543979559549586004702635211566093315172444259989226360118649051341645025417105199983031374622280607254407680449954309191026773875075358541257899132481799379995435214619806247200227977563385516441375594664726799793765062513830022915565701564031537897012234696965224546803260939027813888915323250157210442308033431622807144997092327337294685250923515984859586065210097285377702002786839311189748589090454346366986075240650427548006823358008403427111668448931172637016817992251058029767639674797177023922600112836966174998960198681809318409434629839222279388813339724545636221295729217952756322963940998400914965556926582685745791668982732133308531459575305379623570432774352414175391472556581093468727477856980795605384900995002061180498779128930141345633485490767863121779665472494366123389981664953169134180389907820115228091260886788264483496506979341935811446114473086917237183031630512017036529721708182242654798756936099649077609061560496522091303911654308358908947711260312797352002054992779288038620307742186646144784695129386213900608680621157223987659533330341640438709327762730070613454851283891531423919131620526609913528410282056342793227622967784626038295467643978161936101538790026080794841226887553209457764679322055424544105440074710981527528005445106877093531596130446030786448599431375722379234761783619730170864035111364738414995955994684198946335443227103732407881309017532807634483240309003084225031864707495532696984082403960835281169579746492568328815687768838621754442003862525005055348362901620042867793702438324311952442367516062486543671346504807835301082958065895764324548972860168558256554736935736719860828105822057047829109766308450394459923848635121262251633341136398919330492678329381700619561286243123682948471084118083018286735399460045700480210642288598852389190737007298477723513384323925704707746427599484888212922458202808054685419882865570523593908304435507499022188896399981883450676016139665795897331926152861537536129320855231026279329600428932237914948310699378102184884740214410079574937813421080115525240151679014269019002097305180843535086675183362729166481573916202504410096074144845628651277010030851921649171442944581026605746697589647599563236247101477495297935331698787117877252988698769091246904838571317861570465014595897850428893893261682105798831006359857561174707791043520361795855463456097129569566620199694582109078207920369940473134468665044746727469779273548406054198949334522490441139322354831327574063759002534552336029435053637142198941899137557363705149980691722507829056484281084397510627250382103204540444270101535177407329080910589007357163250702500228446629 good_prime_prod_500k = 12802943032179060539314909162954057799384345722705615557259862500460983550132748972232242467404513060948409383748340704136983267707221127862550095569103921875939703172102836485248003386881738609894877089359342239270145617470925320144135124895056183521933042359964244913107417197391061652418602302489638675778051151572263369460746262541811664778570148984794706382960145829236052100625680006625693281790258341927550984820004142563799677591319873992550800917630059850556052663166490220104476926793056773212241235514388659419484007502328582631080376981413548314295400605812572710503541772578066828948996913475880020268379220169901388362281328040250325984853691135964199829659552940850822319507765386966580305992589093920772542009108064620723105177782729324427825218337972377979144007556961233489865126456231568993797522561015631632912011479579940620637475041445477611616685336863610076458521339071173923682862625168660865691059320787481037988182013078519737879019968674404777337822175754181841412078125841323016371932503420902401193767723555639678459438584927355195231356164685964581038078528348399329891859383454540560092358175601920889064316247810517246335090247664804974568286961079690780663972570605254936262655264023583860535277794397181839163375422641864950872024725982539381705361736788754641137367503440016387875997556781146799188776633648653043296332205517894931990694651574607423949922658977999898668855028752081978682045269148795542809800143670525229389217900466577844571679255415300821913947052610617663679463656190119793664558951947621700146977684037910390041861876566902131212644269363010099815819992388101532521119425450806814243756240468521576975704896906486672696986032803722502001888985030583575383827870276597178440479024167274504407147636732978466253771284594773851157931093175938641346534497495758114269407588602082692719400456063652650356471416213326037125288182971904198484416462433645975711236755964882001070760007871894247182543291608640029496488801054352967095236349444391251090728382813924423912438338842982441176458491457097102936337991130561521774766725016929774055824381556116810319327707985122383800585114199246258392315871119755127602573707932829586997811144360479484170902787901898217959441689562167122601739707131797044034532685152918174026643719812995298476937678409706487028291979986830428357504096499543953059234729555153522514289931381731135566913167588013677973979390662125883315352471609426104207907671678774330871324075317496704333041266382380865091027271637472196739875676681948527431547429312468931606576269961034474201832709261106821593743430746666910143899043660880005970678734056310846509094719353382207348760141987377338072140380798500630434686791486989919463330913496704266406229529949743615285491825303323875154314572494175163494097448552980439323404519664242971649408132659403415261625024289585775662932398433257094046167877874862017005607875408845175639049777742484815873210448271033000069907838383008393847068303930323526923201305302937475051283808996338116526851179223686427724887815330648169311217349795466230590029933722756091729855912081473100147591161889248362305739650212291343427069055539185932676907600258060432646070532518512187759451881534304246967960060844932080746767200211113241373077169711471058082633807705674023352243471054132831892082220920406510397104523189016387733138297069129398110989727926186757685592289418315150023071195287732319196773849478545225400058387087296765995604069632629434632982344767303422444235732354437274331763518753898581155233571494270370876960744196959211434933657188790404353243793592684991471491607729778599619460178383310344812952782630208710082001063782442506692596908805430459012070137493619752373614053689149366895388377461774656865976394899840101387373271291352110691816848397867827670821489774551468699854419528747105043084678932275611066431139633122738044287052084002881417892859417705922863390264329762220797728726185686929871295420116501751357261872133862145586923671950521736489864827094598793399076721102136116199453979979329432503444205165986148038377494624308953259336049064376365758978155291798197244401429924661671036906936992033368334059157516830401924283333675258395772244369700789759852307769433809525948734082572301308555733278728562106563194771398336275709249329750417170723926244073513906856940048246194148402903832438105275716574477066538447102989427391117726723656015433684853714884402233001477706617711589353044607001834557435438918308378620095957937267337948082145067464737031866250707610287664981128068155323658427743429957834922229189122284184135205723009958003766056568121102371491427386695810521856866666238429174959265987407140320714451945768240428384309095310136270954122627162675936078863416430836232417207527623920639451890836016147970181835196935485210304448640494000197722689314675956277864382641927860044329400628468858678934384488041742479815387931235747901433101134683027538004341031851533228256677569243321710177216749503447533698592016231176694934760702204645329407928746219840556015006774634263541899599131661063784962022474194221883820124692080604490974694268733808242678207866257299087870998389021359132693483397176079098633139370745779755053434037991734606954536829460962751970915341747734304289813689219284564506948074071486822130203410312670154051076903796045309239543682678619302925144017786307787033511832678512491376499858707813458741138891394612916437655173907673313404276088189156182335723015565885473485286164856288208305153517207218529379895179334722718663034351186528484725806865870962900066389726270120980944277917040401962532924658858580230122525371839924523426649093707104454445936906514553158921936767427549663648587660997648886738673701452600645342698881999733015674690033787271744384580716417789559812168369912325137423613341454814990519750303767204867533360089345078221874912257159797596669328417465834580103067942927391161193379384224851715756455474558218975551793721971148938831286093817182960594415746924723170670515367767402901333306999074138671383391423022109557266711191902371366383935487819352401128243429306420086160123285773940101611946474813585751399536133850120703022541926966798435006134143365103415293253699649563898369456602069821802793011563026098480523754902630167627067785959473455283665047427180832572723117208672348614069312423170645716999976412076041326245631151676247729788914516488064478081215876789572637272085297535830118056592673387466608416850860343290659629046246700061881402051143786863407650178664012064681973703356921253471000882670979100155662443999102959360923698373713329143285096450987083907440087789901820178821521143687185969643817063940751676355279058518150813066859138885169838961963722425886738493398241753040978116337248810143649588282713891897781562450944903885278421603258309392487628237291950195554103824342087588889585277803543856392050837325178798042326767636345666121914478276441931212106156045302638134985478100975831707889906923951665772653769158125784722161644900601242445675108207119468463386167042881669730508128151442374540075172049481164910968889882615129872298216440612867994880447480718663851596526577657772999279612861291342162392781524296404803170541500404713969346206078726911463698057996106369084609257303315656690629466568874912139344529409245504575816941416628335321019771264724511279229562035961091771261341262490411544122404792442490747099891264497235684232432309989541902656224344980282868209297339569037779046800216364232080089543189358023303122278121009253650224382735732716420838303725286717961075649688871514569485929607971218718213587628993066940109565746887115228326150776459162333341702332958322161518777663258149681648892248987003032830435105951220057964127844554589277018163831888348601462490563742756586229618716892646204826064566161738089355427907369594611145499424067219894767571348560841585133776478763918777191463756173289346968222351350035708840990660238151443975952511074922696812392491449404732197289087345520013480664208556222599148376452811010356916243001349420731355322333334805654082867414640302313659445296137535675500471594244697381697637891480443368288980264453787538708148490993012886051925382209177233405829280432499034056055833247136056202825064283006881553952306674000995484493698185218458023804476200156116839112537561039170188647301657968847856316951657983526645596592301206852807838038634879000553246908328531422618689455392614324785121269284026176702494664154092716732951083872021946307061553034493604737598882091485132899503572515336458254028368064890893429921757259633452885375554511385940186843523769289852984009622703742649316199015857860755851096691314967569776793899093574779106639191349709445001408087701530699957840736630120284868155182131423312059003746405345388562561658194721011603481148920148356264666456937703581223027677199246453761961834462697811883493904099913615854673463329047984278402981615312102951422996532078411141584746743502574451768002715050818495596241170835556117320086119752566906626000537975672913307141584270436995170927762034432892932636498661962392866255637327244840008143734577254339739960885529019245992870968853777142149578467406416380095519912258797463872563943242295435151374178346922648167997681614838256278497468037210382791801818202560290895447908631861160897624713361914892974615583604267968795178278384066345562615753366869069698222723460608094027985734444297601332529028776161970316223812710796277169627939233082519329491556597013351863050067565572553093007377266887963390512778373227140323519675775032615666879413601511440894645992831070595287674163752144914781530393774794711065070344215877118776930258446989177363630653919578821753896554635867251445897162007097896857964274705992901756336596204434090486113961813805596170840384933723888577636580209716761815878601512688633827725822829313819415754149699444753802419391128679579741459362477113989495066750955195326110338177332611414448103722433212762970979776955808191251280000384996703342941184061829848158668584424776533849152625321031064062133918868066476406201801553485430844324124128358667751797275900073654630351815930904483852082429558649070806887501968083564272672501394668644575029586872382991990574140777135529209549007156452583063198973180927814113344863647996891680331367645404797430953764973472212057479730211631611350753807838538605907130658375089029867577994012486251520034309227360394194727095386326447103869647522551816529336478537591997846265084079361813332095623191337415255711982360981367292805830273749943559742228292301968614441216934470038549476579586340183102533269676294728071109639942884819307341201553873673941592947326588555407011008027236253049057180972718585679130779017502842927246474438654683976542414065912081387774506576620896961282676382084845195824535014864494504773992683035486742447620028452922428972932814619371212500624410156689047251238317137353931283396860326075407514449567411326713722360623642286583532985817099225631875965960493693492987985636350974618811289229706742788921458707363385517489582776369675087464512747733539017273003321062992490017599441798373483797772821506486277729841794987935951244598903280879557267748500158715424028787047786967273965149924329603050243389968896726834137691470154340031567611631215277923684372158281547529716447375068400634438802600895556949604152077711482308929210398463658822028246264380498407342836073906930688118707065089651776004029719365611909162004794241661267498333788075896606505671713585599633927336404227694374686161997773229630030835214426029036563463548265347879758564741942573727895273317231010387628201323367505272396768123174467455090950168648694524112731164537854908328599839639765706455095191278367969983808267279363632040682179717746315975053707483895328725404381505816626326643926874847049880738444734931468917243863594350521004434157093041640938560643020390270083209547555205726209600943209699896147271290114517015443349091005257808007110103691330733183999522716581574578832323089677764670047435877423333830621054098997429261802213327451716384654147598021904636455772655607657208857254282504768911077563920125562493827199082429538359025526477503561996777465894085372607987234302133177488534787128564511741080419582047671633415853115616628826681596120312177102457582970512756064522206876253597216345668124954695387927959144917145204106610575047105588152590022900718382303803054353266663833517785492836393393554116780951154416873163760327995715142443168203217131165074890019351634684157671144009956751796109164108289081679205714256336428251816859379089649318712460142172598312867582412085914072326792394145670534722054097294701491332326939560798291535309978840501351648097184956944801528701197591722821275263355779287826237270945159106391054234262863628599651659540138956614522667174987008995136598478697290561661669018198116734027681399629965088591668749807492438087748664784514155430387147188452566901775696472309032093638927321718435219597743865854082719222071071304213118921432973129666536071205391857844103314956541969232339902545145005250597522591124763765230298449731541907258357914616411259580867056801863304951758205977026726515928382029797539477261052952268831788100252046314213467456663602142183274559887608728879451219553800928608406537833116581162269894479904250385245518825516830128883849563788622479384637509547625254221468181708949962633582057907338189213479754813170990214778599120413144148764472090563250811286142917256304558976233353493046374272619245881890504408267332513304254710694536640247743461367240541815663580835116098875696937607483184311705798988926668483744235999295352068134291948558645484324112093882585100186204083539153821592007064183751269951642930455931146439623459130764848608825506088682741506377105760412302478231511681525817769523120664201294260816610740929448596937954790292920738570632281238714177162577359895540040451022572742312543243680629590805914643990266682749406281623677995083405800492861988883809003628689928357618575422786087208023856571849859250035023127043278026938683268639603589044175803417033007482937839954369313153625395022422994794794326731526993811261740904092087335619544149913999544402267854224575593165035658241087447202182119950876706032913947998928325983327475837756880942145312244492527381928495325499065083416860913322398420739493863068265243213650662799418736272638489637676839064119812185672517225838466332329449555356224311995003322862374312655796193560465347603517679830654069024431933870180332195574588740237672100803008125770851841026021201205162092833355045948517382320527079230666951666500935794686614924060621854418701043468975493576876043542413667842060469025863686435371034607779399219583414470409070407533913564122999689707543235544018804353216863430036654939942921663734113753763442637365655515805609103216455761362605561644695701567637655419803577172488552921924788645815912379111516594330485542354269671542662549744515846621354162374845441415109309605357942805971163635550435601022595402236859766921265943774787212781214060092219092165972742059964555365582347054524995716643784480510387118585036088324181164165127670125724397248409637815692568878783417029625363947815289889472078284991527078262056577467532375483796174101465548136439880521795631304345849819718760279721699406181162616948788992346979372423109055491827872668118041304052804421803134227965866429965068619701759465045421757989231264965933514839746456544525584176900301521153949571365160858545123710784231229122557085266877183280354435356438528629472456320158392520910262542988498531301395649403656783425941815773310613213997790815531022135965758318326301612704290029614238410170731116449569691376154481766150425083561301927223831220265998335511491314620405163337140137571944959141119169651650682740642343825402880196220371421578210569878549568714835445439736777798741485414787215980649134193965339453400854761791361050918430522883751113833234302741181742074983772106411633311164625930411888214379646336563613241794930798546022690071093969051391259729799866313176881225181178091446042723720688748931507782300621351925868690754581376148463655497794936909066746473260815559433718644226425437937507341099112835698467635392647515982137903973233806576934591237562599104601585305353221948830704821919340194415387766069487017258268117717810625893672886529891448338927662912749047682594979064713627225394953735069981341625462220635450338614116722359919020460014037859397867942913324920259461952216158701085370151233369940631628133843942903537565682198803843705903126585178012131568292655235391630930332375923893505199838935364117832305938054746782316569334206140920417818214116604221109394657384999351184083072983475372224959688093941738896617006066032957660273880921197730385740334044991658163077186900722917278287632422499074505865821821413789832188402665201372944666752416730710976687782465602908362281069509829091598628697015665843276433614194112962499359251205627511912595115605243882025359342968781242943266677193493169943126100134161010554305151737849896168820774551904107685211521249099413975729972711172364151280043524055010765095637394792908618525521738912407988597628788223693992833413307775458278901985472766618749633054095344794127189707320660249116108856570372281875601116132796099565202442271256581286917889237760057528602798892359801655522667355560194647644440108479687852802971202891265721594212135855020102438151212027468882661630439479306415867646660301954635879802668736419149048583253393009439963165552555594676887329309088059470300877249271901286011021512276311898061679861727182637243250526901219369404744143780818224997816126202461173847560113873808997792287187324860697550072865781477416451001194447548819119800259438895322853234310962450475751913511978213789612467136240830776380355452066492072034029789759286228874878690319399990370053500373252554349697069195307405816869748914650304512222786221202245969945448832983067395380304034248148396266519159986999583777467996612198185822599322967700985556499172111924455458278252734892936035488825011928345021209701245142959330928744739866634661531465870470103407197449005827989308464850304589536030682329087255707222873725574066314054875897894637379972025792577032226622997186414490943847374663098444233868743872596741860177995428149927838983197849267946016433692673142657469520048660050623008410368560408418152714415441125976999619398277872252374417906109135517830933378612769184613245491264311365269252401354471283309066904670351589955978534242753420300544321103223509937442301131317436672489910632607204357420862689739748519109596539595990587684403567554279738821710163501787347722542492984783090710766833739164437116933619110325967114511844728451317952466095487994256550360260850003181019205754566382584617119146166805907265763292625075662920189013387391152721557541496768824822619991084400440646442468929920431028935087546509515266297036035217480829593195846749324881074489485650532680143751660048853630565746211564147771564117520296551550455932963867265923727449968439244612032811595391410915103509664186375279774169738484863281272338311086805314878025066484010967622771590068816922087432286883444260203042743847555311442223309030334302693613285587428289679428184898522138921603257970515039262732232158904838000303088828831098068625856814860575562624221741955242285028746336779214635290151359960322707318237507025560428955812929240791301791299423088115558331210271647764492482057464392844269584087650889243173817484621098996588362104481114025119033385842406252977407806705247729944569085843666714316735957749275222384565905032287284313916518314174605626008596046738168440961895099251612425662579130671162642087447254316773561412749317790874005536366463691483232399198132521891738365191358809349606685400255084527669969532498939662599792498367974867435140118759626417632037160167740134711497143938445617978840522403530557898342682767724646208839255856966721580119527770263304239069406048879044648207790710277464387998693768288075969890394963427526582044058475188168567906749823761940342160908432938777728174733253083069495450928821965726379333616547577595813242440323134916435807525565759536421228765834908584187779781736253736864901742848308627254905600224410051631496483795549924402979680280830328369006869632928479707312996280016090032815577736533338688515660733129219661534078351974319436278853803696741120215680120069382988079979366417721699526486971868763522293444637093444490797066301032873796744087327960084946305783012188148799002537189809536021040872718963813033752314931690345052401427674765800696801744412962037406148770262532743798030039904622027441912815275221537554833499418884051549577256819354815203347235269481304154897392513849357097153110360466062206569622574049946578270168533194945432532079641669552056542444340621151563925123560555494546955561753131973656252037393315506877328754204489827140481816950496888433993765014251525096669710394472556597659222217631535397415031982447847074646638790644477971478106009134190037894435160264076349222962524035734855498476910071408875410810882603762299211663527728449783901912912397778382222540193997351537433496610619466918200663429981451010412069650548229136517458256329313336560029812875855728431362691000303206168171620094924354339400053551794878812036092214341162825425349472067306274435992953704062983542737773980996732044239554461522974744403733785332026922931762131070601597594137103543846245782152609025834457962658148789114888145045903001011722485576421375871428500558216539382608218063368058258318534076287809509175896575225120472137650432183262828573129398267546990561809514100120422804779845317608248704869032706056989834274500904915632993735993422457076420112321268652024117041065890539936533984028520674497271366951105617929986785448510545310875006677486835307584480385164105034896902721108584588611112582215698878477917894167907646865682202218715597058660130897781529007752961296351272701191273858864874950372928765460873835306355383640554554132395392387706752748658886057633090772629722011614610903654146920554446556200960365659114210292213163668893633696151138286193792172342400554311366480794839506716770266959944252558618738336193084210120620912358325235631444665688329193147657401443010829932614499385608184813960844938476062181127611534083133546201645740587752703405551751860984389259385570935040256822031984791170334910288122813275907904907405145750536983328304423266276195799694076133460963663238565451999424129854353553265427431828549668329649712463166892726381705472395186845746903889333307713387021901833529698724611075308022562638402811376250296991731312098636627267631660613241475516843058921272565170634936785000669014889465940877765912517269284452406214851152808059530293475332405800362141854742757423303087172277614006770888336397426478449936243464709106579606587068277986622451630392247487166127424997814493786684921783770222219632614192499757794813705513306986622726524266469909834789483549508267320888103857377167454437013984804611137582043246908385314581423942059169085212726371373108309443119550766193597434806159835887433284018961755863876835434941577349813115213344937651882570592108914485502754199754407689513465595082063947470645835034886256860689017309991001774733528664838122343688098904824496651804276741288724370121344358294634329346514141461618671555370460491330245141076699660392540726558919496933492895935977254368975705931581481829116136576964283466363056529906646628071120184746799123622560747254119978424956706879474172035266781119754831002647459209867140121307356711904416096519563830325772381703592507764176798706279198149861956422457618290222252686625302923779075313546316563557415748922720679103834652696377838440690036939221089777163655169007193587446158054414488794328289833738992468763578139341355676950478461528809832358077105606683555805000287893941851002085330717057399111763010760383124757527839594780352044225538068898234714864638097534448348299859590001566871301418919014366629879831695948693684842266133025575589262456015946495353439175876406063046736323963765886202151660253312448627365277182316440894114792296668055027273214253876449296973182003847667015300459838247256125831540106499917556871928950724910571559320401113156361808218182322969082977192492778833604480074135510190811563431066846776124370456339362442846335117434262437359221920386624687529222910749750981132725209472688485529514056946425538219345667075286797598042157242541151481941396666835330943304421768765473261828023095021103900786479153696792044829423717391968956603154630353704952718238316306921608871255857300574685628286206853834386379266848171031712377364782949695546619148425188651737610593398801970500906204667549147416264696453985411713874977407424254124868240052370737767801243728866201556238208217706252435313310611677991261973917874325900944534959415512846577890760408614698171575081098616562117121961202647978258606873658032809396129966800380301431302522871913346816961196514156120283032109901515031017358614128646468860733297195134077580167545089636372694015484094398096895355658442892456659451905449674047623544464647767028293494102412115002772314268366457923544526344665391905031965096983601421154886230410104454895810017674449690071782826716685065017563125138955659184678911002665835584698380344835898243294422419354906509252132335424364090884757538868696039476354981567429741798679423130393366055759535497819826050050149840951679504891169383561075097807652171351151211406447723750725886216605130697431785101505827141963982774657752983651436371347665351565096414689851376408946524907654201159749435209987146946759202596450713778277078537060638880323621685510028196202302247941265599893659428159650929336329512573422742059822948242859603558259482807513166502059135188122595578121685943399922878228627522746422201514719465786472508719514911025704251603138928732546427532915579787764223824057070964307098546335371356903835159045449451040264181528932148778615380173213754890827589799055477519138515028888208812845699511783116017184112088755357399513719811957056185543335369116303298843248884204801037562963504316626936698203847849281369949349888205258683930465810150909132441897399772371348654924931741939014942549048676358897801833926976739834854344966180915929402896426053215749578871029310342220364120070683161577882786259296425890152992367477273222957145267379605679591819191538454850455005733973242693889657801933113356133296198385517809710060309800078839255037874112898681556060857071356474911239099648236188044263750027925201050417524144882972538140666599710338809333998614223231829522860354126277007065751023912591790215852402299796044929306880515552073799541353793531675876705512912040736330184997833458216348118469375559413356910218055701395542117824998429831868738015488050179618449388032675216214530044420666468458370700806291265246749128868837499260221564734497108677567116575169902600010367235483930073325878098671078058418687564654005527583189285616064213887443783314786782874278296605385739191126923535004427600209400723658211819942319369277130656541354087868215088442212397248424934607849732259314046841376749989804118833417563577990846072888398408743688693553903865689374449982970818461134798183784254956915467581213695263747167275404607356685198079178118615579582923019630382770915997810165522156378584468833530830492503833806786637214568960440884783859364837270902064049548244061885335611772642396877144495290199071925765651386422731148468131213847731416513582401463358376342171450456381797637817614414245132104699973349492269339621897126120380140140518412512434771965828679947177194579006274607715068969097821409053147821555134345262768520222248779476395622242939395667327272234199316670917811408613185466886514172966291592101425391692511627373916643198674347098786466053186940420502472686214511819853034733713560554946506615227129959293863307107812331435994257114511935140215966352215297605589936183851318917190879282727249797852094639922156588664311379000739875883194590043529124074989782834867286195560234113187136883820133997015438091416683705330635621919293510858975655115127261032581087938195617883093150667550669765535495325675241019922656776727493433093847754360781847643837132535399387306772362388829751036906073911953418301738985556499659133648664298093947938913943733257049191974533032856099541218024432850842700298747959829809396559880771807952264794228180422925183268398661955069559452483557652177565000482436458567659935166059314188017090998108187128897702524322279944154431380996646738341463917292953866101072618425327561982260756351479492888492362681952855217594767219694067992699616957282435767186738917593426757608791989204675485189097139985690710835325351829894603638499410588710525964274517697441814115675686953310296663943347623090881527903515224687584163030992162906588123477197761389994392681484611625838053075375964935318551820541504356821553065929996156268615832407652779206004164135815494694205225308295593901008646677305202183762506110708757601386491105419925614321148739051036095479635533024838389790768529608178067774336331578090173661963819036778373734648243154517275783002942164987686351899210019068710305031006177765218931935897928805797664137821365329982474073492154311602954017279410836849079656336622216760601115150901713831993264293851168424450638023234858037451642357005114119724462729513255697900441318635407147732183057987338750037264792895487480024968225660317751259039329102241462643722841018372005551080137855357808851049854258161160755898519817914345634265029357119023830139727574076296280441851526596844195674153259443023115552528028348249975561163258527115644044075476723264313812970303596904584352457886414876180815901621431117565002872206433236521385171860312539238871184937437452172023210875828848689082726894192279685442771091866594613326839489858065661295246295236563599472660837476426965867320666116057165360748745197513817001385235645465277924192736746166617304883012806678958350448855808342384492753620809690516807281138567048925942362797049323333124939812867839666728561068930614338919845793723197092815791838992839695513717114413342063858713655025710979337302231664264473112852586332109373540949857153121003221099986727155921052023115803544500032958448437187083618319471160913115746590846657874793700942188468975407496424372249429275710501844337463687151157078016504850318560407917477894639411943064777086533087742188307727389052171073089759492252275717735421127884796680976184533012010306006922761471347357139270345835945184734788597270001394781501590699355364814475143267192634977359822810616822714049184476074776332627283216681802081019718434210452656274170332579547756955187226315611149842768640111311061048620529558859765372255071799865395559816479814548440153948310476735116476411686292021882699057525088135194212131268700800711532968013199986656020014769957090159084730171383669462224104106348705163963471408873466113202205101820599830783961278546612644550761238892889932417528815474219342489606864678602217850170468641847272360332974660913206206323463488005323058938113034019659192316840004409960081831706665884469996075127597976701775277614699274919116016621525090037667582879300575933737049657623647565008273668156216133623172961533389614943877814564289619587616521913701494508339978343054615506477237309513450907494953458884410844571679272959801564936678808675236450374380361907807568567970607300148344295834060547928284035414707619358533694220310401414007415957288527850035608223332925182880938084155451863325593545474577367308725825579728755269503561922511037067316921344441514368744893824365133730258893894659120343029115302117550612491339813279018964582424110326287555028172262497958212001833342972859171891085330560898072483590309499395255562780991704445781383321597168137339920484765829496124795374915905097115661271839278394049857698984171492596411658321829395925007578527891342372606133558390618641196469629481509879334768868549395721882038673473831333438576320238934239520717018445745465963364722342410776991752608392562677319867249345273392541456408020488501124880108332676958201427174432440610449338151145026672125089508384356183999002107644218787069658456645284427014130760689673631313684554400260167642809543026097781846089706182996039790068949787596436502011826938628310429872751311592351024553096752508207647034771477719477925226842006244285553228966771087273429604117887495726156707842829673540086185866455050479818344284393476013524738898858935511066707056267329788598599594323324770389437098012187902853978615415444725978946512220327311826692303164807604242886323774195043736664677413659729563990855534774231527224539754326070688349216388646832222156393028603238269882482584780258501477224400364827745676258386575641222405340813129796389556534143463460202839324432845977357741322092359898400356579705418646555407246348191344629021524777299944666597119115841690808988023197140950607190113402478347624022451384684008300081572810358289501149972904361368029207343000940027254949598663599449615363298299996309208409415946813779362795378128732440484175312134742618239547600743019371590946515832790072145499711505482458167033550960050602579000451090210549088185837005891455602522340326831933554902494249358961240308330808262589234432392618043387159377074761161518405422372703048305177205764828376274928458654753520100648938901998115398052417302827470820335185018798417267301146344042023086490140039827474516264164171274841220647439709150679034175349024767441237111681514994670053204836380519204023739856502526533818886566643066766123710672738658339843081036750138855411526998229251910169162192106619749603738746156637476943061496835805544696646605627018721212953678636174919643120874794138619254990465317455585985089425474359643194648553793273484561774701267061732753912212103716103706359319085634047707332101012471977084620864625693056166474494002974431814530154819130573935569561729314237252894120421088727556651313352147235252366050518714549845996333445360703321416117057219866719332583092169597805959169023076384353557140902485486779622991956187624233316119970748779769112818058029200942269720755906394953888625368872917499741315965814041674919689065201952591108288175890340320917103276577467484898968698478317959926823883137850179557920619667508337186012269592972038478812307603757661034159994604434627527973755399820734293764843379238352863992004234621661542920818574754428794706467711605444375598808667354433897168655487807836958851007333685417349599101638780227474967610035303485358825295047966151059682798210279984053198865324758233359939776215438529918102101500856026557477293351178402448226681292203216899248681552244080497560899190512490527454230571897050393037595131899740365538385616735801169079520171006933889262656418935780765697487242625000834715119384385859948794941505033152268336185001356258717011289112065181822842702733726162665939295684991853721828837656150924578751283560055196502854673527801673319998012132405680758369931365979085791410561502738964524001441582997259984722879019600460887915910721885136425723136613571521711062071170870617576737434154648277902912339201098826692683419870315934264739783060649986188027814154355122608479717330566111423055841343650781180175357469735921005959412488605886535375389735682184790577955545387467836552119005450958405694943958716829542661025909596221195108701351735306338755696095875244336830529793775390546155337186403876904302049372189349205881220129279503265903188721218735408634541457931181672096033529385710743558033992137800567944558122699074592895546868451037945486533281360756530982613885733713173212617504221777749806036351931739921278173338339671767843525620109566472956266798081111819244468341121453457684097332053027914723461488467028162302825301435157651961841024439604089859680058024921502366539896389461286985385194473492024465766505470027312220423569334207974556029713926797819904772423232938413358930257764151666241982270379047641759335639318861800743640242267841894116148540633528762256128527822866733311737383179072099783223705164074349186537916483290232492670392026115078565324597016546124898956762121190361843371603530188817542793013963844897841623756561193316526238600380658789625355329704501390583403752580785286851050658619190357966668503363463892577766838223258321776001223782429753768213193139258514888255621333578899699329091199745375595638513445550499127444413026571254809049011384555532615210432192711745901979674490989988480334755626173361049150148784408161351858295373359346260946700138987146416156230964618403016553940275996908073394605302062908582632772184789794458937882411887587449796772822984839120390668780542947730780558655076120470630483317745747056948993248260107538441321913691048391410207733052011420970655069541074058847736680033680152063630450176570697992503297354933248472996136098626615362915189979998728665809482636000818330825992652631627953548076244631606154237667660595048920560746429419314605709220877677256363141819420425458720995632954404461829966128809985661040179602250369161544710388469271700954102148742054687108253787842236503701762172421269968378867159144233906365003052739962480219206098096030131159630354635543492274636316931660863904933530220515084006193503755290824813982539181394748721845395695354560596332380882667995706588080460114038995644960793295916364230715633594333649801083645572006189348589627192424208721625190495081705217500850239213099067716316356861376060955979413088189197718844686810016739173208520315250454215328971792497214735198090178069588091855883539718193958372973894139293426446959187639566754957066017188974499585814199530707274003484027469742275344848872257962483880676635672793298531929694938883165945269183525273742107715140543589261842639548014696134752277656466869821479649511732229607446913653626936403082434373869460442603657448700932167996731940339658989504836715153648677556048788572945717969497665328635334186063102782808400173069464147132987302418663249945381772670983637474217627253880938036473394529435478279039360445750017388419752526183512068733145310835283494879412405742000622306464343246628079345808181716880719766677213854486896129373248715504470610624111931025659991214039958512724950262277405734988179727564593202975220371187806357348184799464373382496494210970908133675934549069094805255928017498573981564582381911613408748178441646675490487204433117516395612760583240310850215331248346312683929397151816131556617030163733758846196717872035401852725714385149522065080458570036514112036411226997113676978470591251980023759288334257793528339090281627721604466537363543473017379745986631132585954806891525469750282345902902460231873885325131482111550348256411532482733305450800715947251365484534131594461235639899994764139396745173218030443520331551279359985151243342417352083058355538578828155967848882734780665775241455278738947792783445974885987878738706853241753151365315718396323904874495057246073363981994537000902533072193739288188535254107154583633109464952537006980268470898587968497391271901024762841681027699735633290552102270206922970803300656961117607124495121893839665242787185796692376288403382053717088721214367453951818638585228237293941846348134579250696401883407726295497662503451330212564290445659319879236073740185385144525697527740369372461416858788449480053551660655794907646460979600089239778021535418792342806415718708274128260344477203152385967009635898526178645054842687586528819639052713040903010487516494741930655727042724378673623630464014353022850019293663877578200223762377429925463460296823597417979844450956979472674958015506206206032939669631356215635584767804987561660946522371014656004254708660417650476053689992610227808006901389254791374607391281356223070131073919917501213235297214962186358970490993870467438061167011557167771013655770738093011448930608976005038875018277922466511706206902771626898704209102602740116021252131986042269678788503936550066427189933625922038318220776392092489425191410078271331716265942360751320767589530505325872788438239021499337584858810115886847865031954009290484463639427356975209364171046425237003248732561485179073439302334119177553071971147849770225753396991226963234092722152467113254287781873010720276452539294347479742419668740975824381893680350773582919387215815202494836404420399161201763566887814355775976756256515982259513379839623409576238045957390544864321231436325824921426569430646738422182062254409603703281027840011010867754924904328955930700773034587705747686151568089332677212291624501802555511583363254020780612729350240094415281150079551934831003901182979578158727176200823730337378198591608601181941599687030147519239608495043307154283390941752075972445371498370240401874664169935546778010640797833037413417177003302738746411600064124358087220505149445393150344202616276083013177638210685939678601156268576195220148185249599491280929936788415341394314214356013369846802779910498127709475299205483366430842728978213059268207891464523799882316200543069438750360162594765564501561965423560608812657345382735086700192260739151952996039544207756228152499050245524192151746638407514666465201753889456624182757173566943506358866032662263279607288997946257681488691115992126909608192972211947129923692860617795306566438078961901043204144324103721270568981481527412902867881480099830381070580823315111423486550284312939792851021654945661668724705525766539515535714394939586602913629996867668831327330490482318050607872684755490546209121655556546839568013309111064419503685118705738544666954080351425477482650884157987219998455160611915246092599242456578477944754287844380193356675604246127534748997173274601274804042341504343705349648586667224035906849624221513411815015364293161018203807806505440950138528614404162057638478366357008909518355786132532129838891106955118416496602566651331648431389761837037272937585287444766220906933820087123627583776550530041462137279695334118285418116657883925170114855050092466244919392390034031093581260888307789525343544764524188250962454672258271899334336407685232432011140924943768470699236927661786583883579392057614893263009549309952829138262593002095172898909851056088142448669935191162657692385514996849770983378263595787724445773529800469733315162068324763601205609047411094341971339638519505478024777736752633818157421465422273951019748536971226980095989205013582631444028156355926110828050354025222660833035322229486182154666837776244139373898622581874243687965066118633574699598203435846959347240827503239164561809886027114270284135570708916337653223227843270572899430240036318080167468483201369930561227822337947705336692268088142891270976912748038419423550539285224744747484405823162573939262272561348587050150139652903165050929015373878079002091770503534101599732595013650799344193726270504484484224700390471902666239036479304383191089524702057704010498471337977731022610956487997046408101409453658771890326338165106643727970785011598691530086553452463214747467248499861067999463023212016325296814805862817661841677335315892253166413268642181975829180013744607262481051939561584880944557613203168737583657754794828430731199577490421600461811312617586654464639540979799752016269227455046468666986807979147330347252650290977007653495403473621633556723845826416180988544230071941754712637499274160978190191349951224767355718061908292034527552697019223805322897380953235592225741460369697294173840540439076521582349552012114868229212081948859794142901535778008663732114563091825107630476512229298513524416267570985126768940335508423359682210498594122942656623584556256063844798799540175263532526024408642727043214586048054191212608057686364708481792660756891730325740331621182711005742182439312933779871917391208457621783759736732713150633974272675230089350560590344515423480997681980797901412027540969056695987025645746481611910498787408745950554179817035832013421031721195694002731511330246266711412064845438045675188857650496095604538731496027317039532064020798918434481912884853209282056710654940328281564609561826196412982878236457416092174667611858351632237462309371614256413651265905724196538728624320166284894638663412213088714612993096900281405835699025979298444484493624382425936396321174568212337027920238315954295026390642646491763817167932408721834412731815665047841859933521496911661032809758580698705583106091370823612365671137854889110854663979192027664630280648080056007595860275176445710576087164627948434936193678272872035778008004818087038927306684821501353759757514252852859174445188010381279400149731766450399053968369085464807008350835739609657065734405895303241457391099467181301321647055572225259247177460367780825918120243959348942674061236993553953868705497810369350535706697747244681507756642113365852516391003636465449987666093045719613018748623387662827021309417799555850841431875427959593305047744820665127257938783432644671822279252223582141732467601717780154258770803324955474657794227891147070233041024913191652499971540990656102020059184670532597167060776752996206442411491865652258319767459703806660323337083849764692861595667658362192856771245470893121130480125590924286777828244318026615989217105676736243465785700537477355884896383521228426846755563828694428199231155820919279782691881319475930547716812140934941124746778539545901555927446941758210455608087598488793113591322880516550167630336555124352660132017043476812303800080479563169225908496404204625840443056006145944754766530016486641350036542226399959471799006959969639310804638389033122289155471068913570550927537971099192864528470156559463584434353238932235841789317269889052279522836672928633320723505339386050990426558678830883689857924109427870341380585244255777369919161408158358104574317630667918184759098900612622050128304589935339528972738036931772362817051450549747103164903223072157618066758447540402468413528495018144611938781252523779221416018255919993695447774311492455751000258648333102886128669353719022886316615964590450878624173251956051727573452572977823561268002813244277984161515272455852216565248096751834290742534649620365806261584924389444320096424434205729381549128716671223178738953360488177757055220135005574255078778670094166033478029728973422037113092147122145244987642566002397020992642027821616201771285910969032371870305935342204621409474110291788264384638309230075406618848149416867507260535350858952214634075688447845698735564421081338513737178652857529961071807409139716849453563175317314979444666712422646756585268573657436465781073308176251280079535614020826659852144545331796496494618919161790968241937221889706411082880539809310218512047856128895705508744833718988436370226923019174746086717710601773269364734010711100440507456725536863586498074097380539530657336110902630909929284671972437317308379371309389994862985469619912458956119931759759740212061667672040755700784635377495220155329187869753047250260769345016554548606137989382187197007901804929982139566421605458481453177908336124891010428648725913995973499488112587005625855173238194902806643949662593145993197578290560578399604547717463198265506465472852216742951771389056450568079652190956887768252908981946283591496585069370740563594464699420074920318179075050585649443431153817042277468996869512792087940717469059100147889262755030335003472796284274285344947166508564306781540785285434906750118266723565839282914035329919369472702521558767077642268484127012684761717832445568738910589899247164329803417716702914806623349677141596915769075783433413297500023498344684786801942579076038643673569355584359987646057319707981192873063916222475460075210993248807081365956466916942654695839803332956944621435923989914803870316178261696260449759899486122562706228081056440533733884825988080163021515434672604139814661005763121131129473819612955427622796684445175140946381688309604022968942862517345173972102595475596432436159148961994656682961949470573837341512142640586267326540347902568905429290197616422743920748510539495643349351827610196042739960314625244558129347842398413748196193085709303901178909133402647325878229633080212036277893677336034932473407541199544176879912417270442055755378528513691090844076800024499361859655732930029918610099725738330098630501967721879341178747237010742571806297365592094710853142864162402565059570005672532184075889408043279316252049363584329276209062003228528830792206512144156418878840954478688817225040413937511565207140388609462954806102847624834352179297468193853786493020713877623492736896665786286958252288234090926162793330007248244291328050257044401153905226204781718763195275586023869842661037393468083602720174849716676378212042645936940526359846579384577348310574826557255377063658534058721857359576127707251482224566744914646257303884016909080454549274612174940191998782921696332684441486078579759037288274026946087642901111744997595952364823799769888055062538488461824059170030845494039509171710802202658565470328790323887087583258470650546173618256647266922100111149221115626106063047431328730010964937022601531038434124819481481006329654080797668863371724875074975288090593676034066257005461770668977683948543064821326067384642816950117960616381748407992671713964427444382063686609153547776551772947573878339732095439582360221477733410263664647083313969174425006243925903888050848182659677665762683393796244534996515627361937049760058895522068413581805212540561755217652343181229037448191921245711580422621354400665127801024477491203565784839464230915058670205879027315233001140978241743272637014519163200014908059752325864157799483881331236562892852267928178706243141026431714116313308658041912680351494849605037030366176493580800157617759515103312664785282470460714118737730978556971302588916667260636090703215682870624715969855460313826242902699418647014787633521395678445826324462232778831493021397462532929938460698664103126717723695031510648707921078402796775867618846458236290265463542738796177821921452682884740023066651826436187538255707656404403962198100790030732352124130727649966672317094124476685464439046642403316804901474207863771749414352416860261496928975732670661986381539849331658768730922935864599891900445025893013528888712685177045893530225548055938670411477482908566345136548723771435885659001767032461178116018632026781353194771826623871669408087898369829614869773194285238732352328895919034498118260733676243883692835259291988534731215464990140719335754362914552759619180375745497790752776225421460787765911171229363430319436393994844004128156823476531919096454937659611054073120654028400283757874539285714507874172355121265324887235180943396562327199697449680479328236664894282473591013600559797906471427969806880811502608816944164666127069339972168784962977513914965495781075246522822063603609087960793539761190590897012403139035256794680962266069993046078055100267179246472725708346407870934238680185687355418470996594229906881171168908600193175298699033232303535360589708957425980169779919996397207425917024954398155881478436011395147857338592022702293177587408362009407527707009554532436449873297612502277380553357697066740206734272640143703358381849797190764074358234569900174936511977716086816602189557482423578149856256643624773974831752149109638983843653881529184390519733671178476471236807349731081480196332568771383627634665779119740738374835757410381312788291847931893464832027394528960615759202407000937817468514259990911698882461771985751160962158008346402883461596648854547114206700481595163706859525287602683194529809368676777710987498397598811031307436146721027669130241027897684213315994469084116803839780829418755518670177649762588561590438754060667344332328057081536201530581231067477872027402646175370116380027257785300157867460462488600600523740504328094162500246179457755453239690045458972852637229005882136882223371370846136539731809210959936622856011900511696519286949968907657808811994993166882170114960972207432139172786265169435069172908791882183637318887203910628216494352784413688394104130193663082151682914385662180112064733407791337223604115800074648932363177215824139543009542141054574812382768307153873761196108888785639241435206542066667406270953809390825869715582839904709772185783355301075553969530716308926172289349419589475616418851940106496730532924986367741246894200125286486652512633955846848668492875451553520624776842038581617131028363087840228361569310830942066949068214384453405326896029031849988743116987264825312313220047214279432555286009978820072376286010073891052088657886930600491654199313434884247949632163244670051103957849411234867888886065886803287092898829612925511311426114144213631494206953369904453774871740545896336472577503061540866765149513081474677794298804194056947882165229988870024664956846968404865131579517244149631167152788555662938775658014642982838620108997473243668978143996454603457047600462227770593380844617959457783707692098146322161408139259306199110450622303277747146625491465734082596294487591548198525593065887665723394401409725595341919742611790092693474047052789034026408125623272465429280485972330564427888365201648353500765323381433690743120449739070334355033553463695345167877601941496019811255355050256379959695887796112422887096689529857538697466970190744713355660724736040750187935842323844733286093683452265493895966368619603827986699052200012632557000345189939992012575746493740309954772133259467207815334732720532516414849137641392759131312771297181736572943946537655391075230196415790424649446118933352872651329649557729593808932455304369239345769001419912230754820786084435278557158581733588525708888065066200442001523333035784438994302667347470647910933249688502216993936312132553490508776976716003061568124743547824909230963262700495346091596913560744913970122016825599443940044548581436479486784230914585602148473633026891496584908004481722828619706350781849340282471352241012138983960433360828805768904250271296278185872246954522233183328765402574372050807214253764259359924689965070762425027747529077227968073772223475387447772954216260706507895622709489822652799943494541877913192612397157547739830774109653038424633446205188380798527677679754597136380591321583700886560505561733004108781790224562584701953658543769971669919533992141283629614282519574184383888149019506394843971509322565677018241499309977778515483596670669323923547861742267631606932035160289935352980507617236677237470515812699621826285700381141709271482527909911208784706325688639385178021602393837554885955342085615601704944749071941284831157240235404392621675657985284577653922227451888581987199261100789716745122218161035424017396592619422564914280814864315488591712135720424097248514214914738284478069654366928922916238018117303702597786857270391073037033692551781423126415909656444159293024037401915094297588337926698919221448480405567951057920470557059115484063322150499638032000679233213506800457192673220864472433539564178124985158059350661826511769913042068049981424498488944418180226063144423057720562319471020575327699045882100676429176971251976094216341234499486921335184389316048110905529804515141679011810916306244635504358887313317568978354186700575661059384614008166090538022280142458081251758241003830479040022256385316972863518788567198791469257812978689817108121272340438995219554164465972929376837776309886699604795931865381196288307562086803813593380997045209463117292487495805027261825792767389902821158306889823707002331242449231633077900275799888597002506425423375859670846915599045857719002729982096234505671004578942596986439186329489086650360457403930350711389881470663330249032897709013931647678655585568569494656235320146098661201275991128732346956063295814757813106433438556214967161302966560076562346299377100212760309357434606076936196587228921336003839131924277474557434850146469904403152056650062522860407394940670951575596732708584102936280290742886373397696436741593220059704222867584143150672438083482102745064230575579937180818909642243386329471006640729811457738671434049810271989892086317284725878337302890162366492706922948671792889816847349066457549607435399610353670385282617403064523928432321048216936008280515614930092697626461778354890637569868864041008150998601812335720093744111546490260815630985199290454701349948392435104208103502333392647139098287797931599675633790419898733699095064616608695605693994660331862495212033747381442066078759785633877552949456947207752160480618169287792734208692897249432572440781769509583169449614402304509434500040553773842959364022276371702652210083070197059247865162997390650289922683290267455562935488731021602485215763904012897138363063645852384092477756184372274150012327792347407344988856963982104020220755034105407141778150405893530803745251535983005864316028343763668427247852837063397119463737608146193886155720602599065033172730430090272754402183504717449847239954860963702707880598312192134112717928114025176898383142346072496735596218591043887000003936238306710909562034818453552845766024813784076581097796096492421527795055304472248254718776359188959160879702034260773335339641159394962875473372965994420537462996718234344595666519539467797105178853418241797625040149613297272168501016682849474682307919562233874077759771523239919192676219636918618670734074836460050482831028104367897440661986112780432253036601973272633723406585491295689522614970534610646560051388979916232183737116533292994602713511744993771119457688552689079190430292404270831468974793085705031153529495520029388167239220913104879050199972036854691704817244213405265135217423241475961727125103932944699412526750819617279978228910490258557447803387759756025341468072102446687838689562148967514533498059330926503496522913598979424385495083293800208208317984908992774925698353490967089847890367218884779285140191058914179530041899779043444744133199037025269122109061324451986136375198182476988404403241287147883363940872607026822839519350764711304298251534428949265296718211984296072922569907722946938360216329189677338168353500059515089438175321847872459834739989306313868966628051852968552009355353338757403868526835391872608665323658381804855873525841211518305969171107703908156727172314872047879334852628603887633347433903057351848903057183134307901976153858111013654318822472512598736109765002340986155746601345146031630884849337336426705168403064357732774307415503445191276753032481093514687521228443099627017564099191274994320787591664724243556136281881578309087866272861083049945117315427354272143842349815830398353413818858661755635873797685559800926316712735284284246691055558959133980603289331017094571600287650709979702562838498620534409187854906035384455439075019917115290279933886362380922046826455356477644498993065530149179533537064294707107611514312098206716935928096874621536812713754016870803992973676878963759886808524514321485625740212979014264666890123740506743419936783420496150935778146275322585981884579257633089143564003659677702366171336496161065050962155120763989211698514608283624625521662947784803804594973348983976667171704916447486486581666966808374096473006227610610306173331025734148761616726356763063842623644469698381451911100446635594763864585405464966359901154294696078732289881804343999249946939055174627270576028134566130127535990634750369454182115273161845923260453294090427012618909336583305131388318151978780249246089642446803907602702198522651333080326892731365210397648528329453789239421704885571843472237903930725255745346346366142180352813700343346305764092730603420896618646333424777586477657571454478284436714814775299165195282490113184984575689225565858350045254330263281211887733194989088050644209881268745488214217643224037030048620871737970938367293328753080400017343222376059791432498286072659452659519039895789414369909107647666725663071082228476083311039289884466395462657784926845119344466016921665510579317806839096182628717016516086999622007900276495017277889464617157090528590628822083368118630517168857909478969473354397140340604563845478702889315073737584660777567385506238663265899155610731341848541268879132484852851198386560291865593929181513615855435138747156245394332082448981120574010308602948196064394404916157589182577840529575775141098963434329981675507668035207545074204363611496818442902407724585293188180844448027318858363287360614715265804772743197115144047067100715525157726752920302918934505322888077855499526479556441878166677634223242965509336431983600562380057695218436965691624271987907697688780941563830591368965959370373309155261781476786804365966765473522324812047117591606938009649959568138006383253668609410078002913223192188418454285446651935485563437607678658482661741197147748609972994622867223166421601866780459759110657941482059621626912001659724250799643000854467686746503359519725165031810061957187852423941808326669631561485307180747703159095199269957585626675982855721275261138641238874888430497507602134276160465542413121882228357271926273224823634744711433185958663230433318569155101219633867111923718865927375676623629948669243010173830844169574248487918528954602118615155865526677148732970094669865767156321357608544168308391302259429656759836782768277601241139368093361236609223733033955491108041057681644897279083783587112789957362596355794123625725808019250122596650267795485543987856308995579042174561045474540287085236075083038507517587776291444018611300459461030467601238101944818888343566046245573344606739541531962787107874395260637781961584037052418903902156870011955113808701902449544587550648392107008703593533592431668662330775611122618977014372918627388846681997099662380223250492313170747157486939943543424955600541961265530887305771340719784185548181827265671966496060221372595298038228339974604186619414833233395244533139756864543272901252921132346292558752138863402263717585740337417751254842232705553040465886286062855286157440869528056343370512724596578448975950517617115054868798987174174083777584717490326784096144936865102547957924085398100739021583158704364760646613597863182935760222883842161299720350324155595753170631156902677470671173762296369357723376550462626376625639770368854344482021789805208092682120972172252322608472407935206601252751311429361140548537452666936763646412061971653861635323939949349305807695935078688281814765064671914488510974949803480542752763501788271006755847262579303783613382220371067066831773927184705153262220373219313981001220761294259959404253201425147300185477574711997989025305536257686685217019952969604844601671676915362933508968195380822233676325781004467911405173699608794123790627280394636301533598147755946206279518627229589848918987812576046553555529270912767779185222207456429804476813882751160982539224264755857734838125565167082689040114151242654549138689594001769610851983737746346818296694678020498831031827390977104966709789419065603051177283187542574203444190918668334030655595216461835904490149569432120784136005991853457566685416513312658169157700484659510839341221568042559994015209390210487957818173799331558166593561190948590636616402550160671108098584644380412006151277096344843319421538833602333546710421212120666779656637688231973855972507953400922200242067072833726280711079189343039848180229922141236584695994073433760073583363530943209772170282039687742716951448273520289542127726893968228307904518638034867325049887114607626393335194572339457322219233660313962018090309013224240426523786640256664236956983179853372904300858560856559570021390711985585499863670873145636881538586752322931179806305548278983014157174455988305244731270056631925305869494464388471029345013379102177714875672136938941853637870008999276788234113746701918732010808497148806588688311981454364198518152186539510915615780757787795742100542078352591077350176028634316313365441710440891666388191766320643747836653395964438501770637140189384307502144131633448133681466906818355228976211625155553434884252148544214513951064000741642969607443402235376686211753872488215709290698498839230545635040485711063244825443105211446375148853490559840576421472377726522382110613334106526287307627374878260485414403348215193114261696548862033996789016989220669187085922657538002870725648990161757603165887400483699112772520154623171807085359854399754421014074239103693322213949528796039437798574567858326496448288366148653252872544338794798115705731216809072776694571479359845489625723936570481774220416956303088127163446327589257993588321302530452744449501895414627299366744313135468464212859500859864147073709496601118370063073610336317250807099745591613433129445088868739594115725816631800479992296414782986985232888967902516964545341866569811221273740592984381672897131598796224476214088624305573343317227579299678651018878350822434753258161586161916676932046597137532608112637574448205865433018336952743212598791359550396108050105907085783798788442151569748376933609286612309782653601934741807682609599847422605155076708367902024773829472841205095860741149072791281426333067614406505814573691905642552277792277446179334749759931584041746906543161479608540779208624235250245164368566218514771889069972876584353401532408227755200941642001169391293303894654409890957709454958344220196135263382671863612722154995057305711235834584066641332702220790652851070878896806007544920695008594499024149053404098937596358327456272969532735866451826687598021791984215807498498057501377009459180655741473076743214899411697576099391704077801957209704066628250446952094192785570904214915337919710889209898911686507836949332070681577508460959663315554598669345828952070036099308942850951746286909422825317027070139833179288391886578862460167312891892162414414803500344394704890567059072135304533588176558998695046166398082200047016895008170950729227453786915439538150757086273579384491958132960759316962897491799259548870870600423788386503612470250297269709235611625798414557092513484545807686731569944425250614623189822266724756678572347934862904379988350760036666952962153383777809837872731381088364626656562365489649258227441234323427721524768241251622498883459063558266301613274373356198245208680837780631638243975208122703843500386445114332755991471179575244160428600991870809976663205955476788913814548031352332825403219966520516899202738838027728082759738282622148536220992715481520409680168359021456542629441179308757413913847070495547561330122341602107920049658382698338985224972166801516650635215450989962902611777458562516142016696997609505304519023699460029161198469935657427451734295641860082540735597138302720718257621906315630363566202510107927457344845746477975678152441308838254816038149284231067197572327896686968475207820224820014259715740376636901879617045786025745245047128850277567470111688629359399014292571722078505363296104897461671345057140938490231509964211204757529478454490382245389249256545509789175858587855540168226655118288406244133630237632791589768905199778940329067757040200718181896940376072654393611218416536103528876978536257756045886320337871724409974811701739192877568792048359360540109049800640164263367292205170856049868962603026469337248210818097133930915852315094500959938141886957164876325203886847182613528435688574269836811065989770483627744812468841272229519878922773807736204278807359314377160847460574313817033995914416803458501542663274674950732270069504761678954931619569422063455049141499929549528747444587404112061163527650223193801311728005084225488697619284412131703965523130929891838628478302995620599809249568477145539091626786629088170066869111026237629628281947630546542103155083915050056943590199312590816838233855860794105083927976117408625350865271239918002868714457445242070461564619472716642742892369953902612422381675488867446712989704392194099364035669976013882799619481738376712073943108329322122050894843718121947086005340050203269051992466144317237881497854144241392266194017444010253437076917885921475077422117994368078037728558258909488645999802903947726990690149673261788422989119537032144297309390962069177272003845507960829910136359547787863530503465556729010484330682909319669305108815565495614182642334466859641213876583296766686467675418465104073699750828028791195467226476783173823252208562602220258309088125519496236830757530757866126059171830589361278857278053494433231953685999282755187264276354583282994857717826549569952708208960257948523065891766404787511515221684311766312534734784639182207197463441100847086469654653147978620809200338933093050616099576732692768340515897757382724478604836928565012662305560443614498570966271626445943388035902833278510395325612658554349834945935535455790606124985904131460044279818699247330405956651904154082398255684466935306778375968887194745174750234022049191235772407730360476788794493986589114634687283784352765231454967996632901015727865181058112886016381743528840611012009650063747854909762869727980695828832159603904710038470413758155441445496400762329303850507704863059477184585812108515579413214748282623406315824813168424039282751251521050176104652846468263959510456685203804017549551626384163874945333205193926191838618519483131666369330569835183374936352488408044280071395954114637426493364381842124139571200806304770270293231122230538873904578887559285682169832816716924104708453517347577286115331932725774296718843077447578683571737250862305576943443392933618092895325938599046691929193777357405260124249165305254796055531895599618781930855945624160770428875012976583994671002848111955538109087919019393332912786078783457644690081905106966433764829838334612071321579455450188507419586690879155859628059663107720601770084284705858168023360372853734330480758488715216624084274114653592311482051184028918997058049036342270409838771943680021481108857076026514917985844919522203880508304983518669471976147277260083352180686739280079271089243765034271440021953980594513546335485283072426888268702430615130729900334050937780190749259865445606340697792021105152275682929187553507306179813535042452297832594117296630041795933719722013292896885360214038943313983841099409559548323741043954209611158719250715353085962446034166197377806331468626447590662776708844694761067478900319486173625015902580148686944233443173293290088784499370759005994490031025632437450922994506482222590114954307785079494632436748585968062657228598945466596039158164399076358470332869148927188773265681876690934101756495296041438683239122788889354578693419934874730918936364063843460934496986124378635852579372679537898037004093224337536882716704715230418945228849815206390799117407804124829888890420356360258059581237523286262180429380846560431776532989018734755587871012947671833103380894165575508938669072306629705213536994226159824131660761329671516395175363519440964373716911172633073135991311180143798293823123265056383807079252361470593352982706592958772539860802066660631637420320468231674030668966594335849477157067526127150019306405771000460112562620432080426906344690025917424789056172540334536370336978129805622264299105173768127413691898835224681356638618502077560610826135085592070489998255597481538174255527603612284207065522332373483773394326866887562236320466142683155602041445942563641637847490664027108609329724301610487142321017751027152808728540404650084949649201425259814784745671845154639972420347720318375062680955012232504101098383657982052682550327010743287908999833625951121874017129491870881927932455089301326113608308779415229079634563142503353589436718052973094473446832298842076005000345678584325194655213955902148679646502401738384102551180257383589467923475429756894154733211241633148583837445613906027066091123148291504162458373305031628152286242168759339019080170603195037569430379969912415669946617445754226137688540004267504520090702885143063386446279711707809043877885390309731124646279218652658675678796459529909514884362256157383661914432288794187966010810335141765619999758292014153543582361417146207045659221466894380424727690989248630071095588441799558121760733518302795955359937004362870570879181153529516499030062125909778550181237516372780497556327607147468079797269445187119114710630461301020177888848895932868083995750786178479137555541955365236995073828603233844428081660628426907347909560301816316284127891403810283281592161756693304412968104017214782562839106638661533468770481992206948920548156266622132832752306988249093141913379471509412463152458621418474683485650920859797486099340723840022870968313075556871819754765959749142263151566975118352013089647275398185608868414492347168903106422839895729078427157701407615360808146373144729594268825424883882936482749499883298092642033400694298250505413281387798999899853052384575751889803915107462411759631282424690051651199783959047341090859645432899037300156647841995539387128733626767429965576976359998048165217684774627598079838532131907710547048103073939573760593660291609898832418775812831861818741410234519332573907445698793990608500159358691754241227453953568931292595223083570716900006761512337226801457942659864433179408974790984869290509596436110616325681905067178687881753210462144819082663019438446418658726138390166818777853220235954285477372149894634260951070443755381026619186594161561343979336880682767555061288306645219150008376193638117937746901328182805196195025876026553716401230207133128107204050917707681257999980508288453322511312511042327956375155468118720336505284706973868497152867606415051272925403742875176146170877365208872318299348058394760025697365189062734927653864062914938910343628357374647608015988493552725575279350727050610343248782831537471034059393381042504063617220057674479536949332033503096316616774328248272602439071269922775545328682589448424062711992192756415258578286334790826126926064495455203070347365591567910726869511922625955874829265429655540674963127445111431242843638245967394677101017393445961963385413942716616440600098096412386041390458443369773559109057355241282920523545759545063737210279890364101191658173959727387920517611223479033246442874536177736300459504277452798072277327519598472653567651194328746975744096272096720298261924337991647080212627905178313315576821856958782060296802946493786181989541267204330147513173547982000254579503612829095193188165079623754639473170435648825513070471574383433558483712579721526268214375124320962485431916988059529525283739129326194415414465210288070255206674323581333014754508344297397212967674321817268180637990902909639766214927383126412324622990839126453953584280520336702388611206688044676919525083467624080737003165802924000452766480195058219500395299058934541133750392663198862087369772370681818877640906447135034068941207563331424410887190563041454104865575249536505433036578365416011837599620191344452376886881635848815377821443467745907576193364969713914979450584217932742165535380164125552196447881432990409224930705334015731450866965435649698885254624003100312002509851957816185761862191458901966024674785332826890859250190825810782727630805658552651547437771476222895109717800836311075142646784293186709188011333670791642603156597387920748677779713399219409916660501235818915537991351873327012775965573988810013520414630569329073794572454398426452708783728162235823920480522891021502082901505527941959568304009592427406521339986570094784059561001405676180909138055705157076970243321135803904033343256283731287733648072705627926505255671347797511345725076108702049979420744936297841980654350291605316632614348927575396255364609537391901256473480365001705901748885615763452827236039792464079176553015760573153320082809280113017790519868399297643518767706623480916851199193511288498520945090628377849641761297333220643103911798097102993454937444853398052591034097117053893293041171367636247131765657986175999923043972421138636621727051699751891427405548709900798249096803187350314917647609779705114739738403845170084918040561977160033223948831160655570430535497759845379317721582502166989951456301439398991965716227188172164264282454882045849857351535313766542795984535955392143170481284612825084665065677791813687304907427363985839342386010840741569457877687031271846933922358648560521393462401107774866142919534230830260327955035038027474734295570064618093409988038227066454102738223183625281020117560574949212534171178159224067892139552754804367558822571659919296944477803120610802847636106583734183514356527026620635586302579304397156985872668073287138304249122550918886402690558098359620176411401424148304471332117454787803947935060822795633921248786460072959477607804397405830399895486084412134555131669726219919478202608380665161446250278044954474614888535748462020800031142001727250316020664315428980909245213601675336676835640304971427327484728053660723084759364663545843339955208189563232429622826465860255272762516210345376329308885068744597458600879258537631953549692606014515335126298228767716445765547683905956591129124545880303368721842492838143098846447672471951965504426745908713890297124525393727724255470503074010622572123852654561447382832997902818707607860291474102441540050543804066220165249529212901858544785336143933099227497143745225418150059890162743329011201581933480524431428382265556116528657615157787805894279923028303742770314596663074464017249345836588351005628038401257288072061091685209478053061946002175877866641840766285053527889457320969483221735764935664346275649940244225977144608205322692609644625893790045664684250788965017378324314967855042382748572282673914668698508435666957180189729572462070554042481550306816714998316318941293043554575469738569471718515637674646836917482656564782118983584549219681852618442085167162317200279383320060025850541661446796721954250841012368808461375348386311358242139218009481837241382761994843979975280027449539456648585877392826485254510364522951422951781100688200798686635864354764118953187568263018726213417814827742020643408034376474806719746202317149602173221424533799185788520928055371492382859039200922600050508697206973082479777923371312915745127446028327440409247059375583399146602553960065990328540024596703608038836157932454801386361802400265905357370933328135091514266648459347755545532428296644072844994799907583662588402444226025233017219283952316669110009745024201720209934787817992934501147513665447500343277795670576049585953037777420107282874058448928830683635397078452147696103827576940079075132145958969103507588526683954271604273162015592189359160354009865288326613903190808191912911011653595227966590161005816853958714564412868238705253190148693832603536758488837017486923141491593002332860389956077345299906187978606771251072427686847535687803250442377287888773512779099415289233342303470271927031731346087326285545916152379216173345102481305756763463228908986922165789258519276620908461630653234693391145159294591679910876908831905078830043451663444458423803853710551076089845989183030037785498042948759392362741642508742978908448257728425835400185080096520825658633505920846245194770638130448077292345329840262160835496469231229366662261878751532557464816934652774814057562774754522346709678260075751347983500389767012914499316102104801360443924363552638159858376548096851098702403401122961670382745674097053159994969558419807802547252346822834822354658542671610305763557164968672763969600355753502644751484031378100708831356079879671037625972221199196446052765347883778248020604768308528320694575839944257975994003354091007441655166903787968996020877853628571167563341203217135186073106985359371633399234689139082572883572396967180359940498878708428579494259100825718837848795361930737618189297729469808583687820523885526420679501680270655941659745358109272840677900596609022936550774580650750978137351355632030801080478152637340492433953090598740226990849799393652183400679784413744005678995851569966374809308768059309849935119139243304634073504787596879080880773264582492344274771616557067273445876249386669294010072014839894978081802924321688978464823244354946850885517894981082409885832333877077957148420360306816817972614662560639103554959241457441265067142995643557336779612093213546480789238795396160489162088524758732731907158740363547438892374297882401474650086549934785602988623199981556699013398396498195859200899982406881604890703742563112182932532791621375052554500461717230347459139851222544753697115277971903516453607012458562993034393552325829869012092750144455143753607600279514859885268435509361602739871952156219535429998444101941648056106349366763024561473601333600403229642602331955680687742319011150923495163308217602238801546333241060570768818552651415375064351657368482894421765253059072604874318733665400128795242100679950884922483644405309970569336391522525949327374539042851314470195537230925442418849283421770259924796363104641328201383071356234045314864407738698749068542889863055135044369633785487895350425400006424200221180219438966750430769320443999538004149458809263969997002048927102329946144226327230838177229020695499162158329054663577881525452465983089078584061776500730054785655966804712508363822077498774551855053282770148389417988062572798353646590862365188943679527570675558651214952235536675674753564567740583901483605102386772910331776544689253532995913627954792614845542420288240221007582008996356055058589005445339886464173832176239395239755883064734745120729403982931431176607933700036080386143173743153817640403343311497511441763466065877300358991094351431519016151371468385490347913136561220853753420761010794887014606418182668649914693388785796146438791542111013800493947032869217627558363519552105205246717318157072764381410661199563475415998136730155109111532318503326353678372072260922305704839663611013211373604584006028996687606245641363913988660658509898229530514707399451575176448334477535405409850764713129985495463698753291571140335518232662850470401150006980389940386143648463298445054073162249331308167367313687282499209803069190059725470273010391057225875481482478834805288501836216779791892315392225412111196584068201503579466276557335405223400193600695260355457745547406081906821515933251889367020954762647670334030714553500366339685011220498139434517919945063122544580222905914253127358120704066318031892645904304131358334893732694719416190133335397999272269199094252599534112348679903918988869578322369561143632085976679309395432460092751415579413552973487217297942528830298071964666408092523259053322096350130906785128537474521753950994325128618615350610682923685565074046454828121005519440674982092846758939128064347398182203928708350927600730951136102360616533529981054572592609474640254715195186317074221382505846601842407999770629880429255219908469847897134416292344223506950809446997258936420276875847195953584648861295514378085685474721184065093846443408099781816933710497261285952491049023078429749856042121879669644498102893536026019480124415550777482035753500120940879804380641405496409456595562580018945765963715804169867162970171116283139188256671110384238438282247501357913069378432002851815049424884403663155232560470203288328544267555429784695980552190130887828098060105358627647083774634100698712425036206639021263175038711277136547479075107581351473025571888919014459318531371845198516645676304733593428441320160704548628154057949230896993212410537991632771655099441462774459467721199402975722156639154777473996604357465414941674337692899730550499566929265071896620713197253187063065185237734877154749765021140507561612849872333106716682325628279785570976777759781392479162647113470335499215356358178139345876433858290430446769017838138547349981261015856343712594142775455796958556020156785384711359317344743406053554023148646422890170376865411009773597645294182325356125953344434702866390679732642428492010178461781055199266677435939976393017839449876219824876488511299544870513697581162410995774298610309612893605146130315806020749724356796836512688889631492215095494264150097915055440304814543995414924704546252212689375441224008031097895423111574435526130907368207854622466939470207739504348358181524511761435006745544164167354536380732078635167768279025200017585228538920384742853915280226664777312497528395529790261960914001051532338939594153488129554929867737675719326023140456858263875021555133077184631054338426018905027421874660157035636901365299258095973416380739845698226590865019624461754054566830186432235205676553494609776979604614287672648263616597434323892362215091065153296055948821082185956441071147361543099358326714920688341016936937851883184684372714655664484423625193979552909823384275763460383514527397457822200990693847104026438834907921306124759352728077741696242372196385984496341972871004615055029043035899902457311560344577704245264187667427118090242521761503461254336241942625975352091224273235506111876611824788201513332699652336775510070392190388248873815547961451964422715414687469982189048301053198724494173520784808452701853741098576166839167646579496941655814983803028382373102514581478205024265386969761061208620115682308966105019321134411001681607215750474782108330588738692403281769733449648948315474059253451308419858863131046209773237609232022719741241382048491736268918015750621214365069398294230498911161708355956971396311501345502462800902394452207001540345486311113139905444571874514660694102022918425557704220084979514928571549072516860303619948182797737452477778224333603558937858006395131789072559966878833219827333633488104835638353759840829292434500812886658087965429747922408031858779180590834542805626059560671749898732953868604606011557497430888236791665689374754028771946605223567802071097966661100561348615598385021490153233168172898962831137296371840453736156032057150878599457080722140191605058315374098715085538985455576448202696182180996412985145929898207872247849538646436139080791606555917673310175189912754467252100853177710201719784459234133024540636535711070095096121450917211044319963532198966358762377422328535175250753750318622428828877044962712177287792531289568013408544115371888157067880114348562705195911008789481854968926122865965291566231817932891033729940870571326771393680725862816553985573245697428983747677698749820984410184388048207332786163845768555807161790670572277869455867115229863562444693456863393053931462667808530206584918839080453080461891148911690383910122877332135149069052468534439166306317731798342279169678069384758014528194945559293061558735542162213602730633508639314019939540971880856358906852849391150448366773226546076250648979399425406012943035693741313371604503696634017653509525961738595354506603584750241617017690210648757910196157225714865285868518717323316530778850051321321223971789258361585264331007161171105822864845784068821460421972214964003772694643954211883590476934648052222920431882974400476224982081388923808365504920923841577964202064125422690684466285060360921059551762892953266584272420806041550524872512273117223430763838244708438546726988931468031061785175902767921400216926773855647966425162419500587999260916174458176680626280172854991846806622836837521435057225220499616107821012439204667251616466831234486093664088764909901372003948558718370660478433786594749324813748600804336274625429323372962682936849106427118296783046660535164215200107540262410846536558427465895673618319429480063508094741103546351598696037520272389087195822213043012213117701238944440616123179099979700858202602799024987296173096077542333916835987409587908403275395285884523871517715657720871056279149818948595424215588276242470809125546254060232298006196616650282458143852399236174186854082551111686264158891167278998681546843609787453096722538910769316510990050613207732829651763685762792807778353771451533096553685671014793672106319014565488215201151201521935986797891584506283030893462597078222482210662723065487449843895745358827743746043812448090646621493182390409971806713480776213863808294980253464275728830931447044197066488549063344753042859101168956956851054747501744063585209991891668464530858463790946630184686774590119533454388598903114453632303852504708466274865502822698845985159710670030222017348771731583723634486807170303728974489517055995644471368865184542166971959900387755139284747228151951498926027180836474201942309715513612455586018892333474175155699514145833089265336881668023293353326470080739333616921692104334790511969146298916625048842121108706880994841070102868074276189458836123905360320971784221122461143959911095291590541457446988598262658508824993369519426438334298980559219288391480190066647844178788955285018549383996961415059780907332978290379251383114965471183572915286225090603608615056992262709577936094205344044618250015143598682044834781066119166640471192727171937512678212991324410274268735903266425774902887156378855057405396928278573614810856095300952642642947459396599098407994959700345681877467434248884376174935901888044472570505359474921684978053213506951122129134916230078112719555134494857944886956714849933541108681477386572271328600377675319871327000355129049346127204841548888753106950598424905965512387539085879446270782701650864466180268502560229096701380031434399653251519607605576764371111437459328900660618523990147119340080735284938862797573859718721771751199294844972921464642971396051247666799649922376843901607776545960407691049281716066513565858973101307534159519862417932668179839717697166748399720519674608545813781154639908295914983460133235331448722303002930787645337055896112830214779477822749123151212913357371543954883436403776780055472293673804490049276479542789414796102272906963486587419159958380436833915699053289558462182699367344064917725717451405135327026370996205806399705839484592857815628154462554309665872758551013260984154972395198221341479101455910664476471475938556382750034918908755399649367617406162195533387455498125752096265981619333740955937913022356250198463848469179206508728839222962398610508941665300084604167902344582333973508927716474355056482349770408193106482871148991567305274485036418028246101842172161933354297863459363260980123668054402940276800085555256716459022765781127698405143458415211048155283800754974775822603402736549331667051555717988298124170384564386083629902950243804377767461294507757825788209034536058746979189176406643212407816790318139115849128764310081710168278708530424093881677794488291789619480819079456220027831653821187980597460754215074181020842571668985217046222257130689074108060899286206603942746077895730851356574262462029004975602279174232865582221904164798469960216857300060529830944511762300287046751017670086312882108304121560206380696126452109023739984955507310185937592464927089121460337915118134328873021767660838198670084133821085657494197749625285789258873750446541611502074461019394761503634539950157196545063540156964813543688185272451117708565063586075148687232939098429685774273214297817411362331503288025750490825291877840830677789204666959012028924652685573678786884335202913258654374521343750962344695098470905981822269729307391791965156893723450428197554869214956338657657268493105833196160236087609783454718841994745268122727900629878834932180398237941635515921167186064908555242341402238511074158188762826487952006876526865220660740042482378288086439441871855390869564216917762407962246799294962267081768193494201021103647505154199349960475191719414018404975168343187336392400567764128250762468089893376638511999520688955647534697525576858864025087474960285716653509992810055343199608572398534057951404388652496714790000890290788086299699672986416901382611048052349249080186767782770485528046682960480451917521564067662211629021956062526719324930012143970610329713658684469177447605159650492118972071694021011607267987393410967653543693306446630775303680959161324160759184221447974796603258532090441083689194821864408578938732267031598774110003159773123968088693724001036835170646704808371883789686783771854514321968566091484660253696479186021438019591561872945449891225821680361540446161194827185749738457939392787328304175108685428500721826264402691937133146671457218605900267641916264009137409025740884613262283614646814046452924057209865867918476054502671656318451787302112482569590732033043470886936296037462529517716285802010381866613355642843771069093826724340769677449066662441178633936032829042874417543540156170057054161125826536004716480346701275332010912764999402608502675595208264397021316852797221955362580360670248479716506906905010343777684841337885888514051176423721309073873691743904535149775391322093906242673461913687372195334331841679311024700892471810979585664337412391785816400027710741485758938502751670444591800703974081881578232274945018561653274298943609935509498409230253662359208535111487462273438569813452060320797329277111555404971535516553956589816584315705124569809943637125794856451841855830689406601318953795764709862463801340406806742404831934591754266197587564260377395075737670588187408738374835072018261368818870758281942540286514274868711009841703631725419543099843034435359345411516565429128549339221139481305400276084350201982585256020044972624447522872469583819091265571835628309380813627887537715117204096681035100400984700530456682232016575521686946907173614901562995938254228139134164690671569618023664659297125141632079019916585225533866416931721578143470813245537052685575951537520249335802388414688123260137125117428892706206374170160616748711669874348653251967410989809922906390372770071132529918565929782970004394407658600195247839890170666250461766116557933615457368292653641285492293826269388380011988105136644887804306882085100553619613139590653834722732004730051425312372343263881879795424404563040463227548778144017764717243179093987492921488102694874698601472351626595886891383760586314386136338659313635582446921923444138492059925590302359458584900381461756187619993885301159501124397795160160623119938679037274100194559522864621527422096590577126718082021036921572028312352271419541649203086828096418243547337674487688126479818497089195351665407523377449967858148852691716561083781765389191281092968769709643738919478029766720296897097690301481829899575011794779794562462723813668154425877588884377320418081795185718108621271407446787651028681212793275101305549536022754213985038276530153234347168398476212467324749627480306658620487944944002733355331398501315328289454452394784605762012445261226260653351594957397156115378208253585156263271571755873978075226463662905340000860160452078209907684025886349970303007329670645820321426421779811616540910494515749869374562115686974315113631171295280064324567479239465640630133805308361830422825433566447820469117475995454014388386708510777402870167089772790895190436226053381738933600828039675300422916052113867838078798162374604135050707869029140977266556194082973996256807392119254976546994938968798371761234460304867423576493006575854125292370316291723837820030803465358596321098488694419084061978833302384846586158798771405721645213046479048273952075964845035700194120199235961324999890443587170900544008987014615668987007383089447241693237997374459530883013363711051309285192090143148180824936995369789186303798799266171571288803013350102335122886308085850540828401794925787281258184214751547530056893654676094253063239192064740309037737954460455560947264639965414684791946156442946953731681707502620618003184731708225306474718851936753188254672066928379813808265097335380139761123938016846742642113163490745356349603362366810973014717440117564119957313306744727610039299968504978175789488276726946348296608557967459419939699251149879690955298722811713242823378345436474044962441426679530858382824788845590676964988476211568810970596010924244561015148796149022676045427537617705437935294166377700187142657049012180130478805518180668205227066179802381415773036671667213417416978838846489078902958589782084075800876833672627795689651284135970852275943835799514209893144686504148523215323885961395593106400276437552383391703987634525740314786667123212461636699552501499532850952834706255619584817487536986053206312249245683155488215304526443087854261050182746220285713092687237244346876527550264143472388624946549472500127680323383251308974666544255584150534398260340063887959394684927632790732511972471669684475096656102402373539087229976631837675673069364736469656977844128922194404068513326850622409177576922876534377993488656446662734950630555533775405903134792058273056863811329952756575373253825913434290281484420431380694640798939416042441481506221622149571293181062812339621254452555702001806345439597620265870433600878438889712041500714786573069707061335444004274000875339060928127893569687704934213335037812484789727402995666480478747548272858974826856164202781031162177168359908110873549542923258246483446179382110289338146068642722390431536451790525498513770904153319810202903850077691285947241687059732467701554560533758318771722650844846127458991807176342000030791211934268247715252535086354615740108714034603616145520085805308179562788047247506305593477574915663933272234608449031167008902689347632376155294052956821405741047262538286864310822080774920763356648554317755843320623739664428753304078778776871003111016104605020850150290909542173423140644786822743584383244468474840272819660522457010304650003112250692124501737959475309994780308602064746995131104043895495745097288198000852136978249846396105059118429439605102331448145536919792084021598742457765013997005368873149130378397260066741146799836968076866915853968821929820364239000005609409366125108769626916229551470035428410312751821387820864376926060666157995503658084074270804623505306103044275970552991679057450528158338659345172098435932916127639390724142177437507211539494989239887183218634453826604363065713098145268650501577271247261056587812388062578784602564061227430878579830941980454862728111542784779144895893310705414535243959004396535878026251324817769153764068016164901754033100654252080382630957982010882505153539006060518657854708770495698374878107695397429077835604043428258986106212713046350672805241678024828270021120444689753904183073098640850853679583203935583701397108144135019351357944782724646987461925743265732906790800842927070452742539062691422767616969223511464569711644948339130868127468870333985996155962222731939376039728339861960657809632480243106262106003232422172062281056837305968250399223859497786128351281573293722746262777099410042943047345554872754550336033688167625785012759473289007420839693258970893320771305302538695549212296879995769015298248136181665314174913159164190466221119003714792644938114225233659153616954617475826168512992752925671914345332656640837851685874718536119755627137073413071402250607066558602404995325323099325378378666825312147078641208433484414044568619585288750778774547348976752833445731890763374717158801563162282654540540810449761127707361733726554435674788424506757452864460013824486881027845443461898394710395981247754717687456266469922771097596216636280517622016190104159179515469565526807256595289423078472025153705622413608776653636869622287062705877568521766148898678369039253550928787896966484318813100996350566236184932975403048313815150580622140690754824479511028590425131847535795443079199947377568385539750349894095857441246256892816127567549665176429956815411716510124105723080974020686261538840805090713249236061629270980987231739469918469671878861688517874935636185598225021221881387870505033432208059383165906927833962206263673321491494453328094716998900668325213352992463136773374658024550383180471662070652662396125943701378454063502626712782990570959303601446935898573599947221985402883928324807459146510574595606924505820881547331810043335984657962988600566259410462186229890149815256405396300725198656311874832832780603411072505435208617544865152014528504619045049728043426750991896335480697667321954985733875393690219009736309284185517791985779420794454046296117938075766430212440106660357256810515774537554000977820988083281423615383608463532053476731897526404699994990709069362888173188252765330432204876565014708805183239679082191024780973693365847557032011587156511029761129258158894627012594741426624549828861141614699669439037999098863979233126752568495838571015851490604187189403426688418692961289184150926459502620079104897361683475286807152060821539290091619720604315408532061285678698926393453319596716198027727278192020942865849239387693865823848074656188796490801436682788307181744901467157416306212227912259275921885421078223285739509463558742671554934473101278125449569193329438350892649801029973009953968973962825279384661050724321186514825899715638545530474298332782376588771250515353600053781944435320739785692205755142462633746978963681678002638045934235934680256492278324658952089017908315946553713828512762812958912432884383610253871647648327629289684599401605167409269225270890119986526564562022346344998080831264723634313905426625239368306281594305368677720896028863273010744441044242114828918069680265516674111486428567633096483183351128352528133107915583221156085999055064044428222545117643609011083539615986910482676569682295108456928412975481656088637246284494794475804602072427038940319705753193688643270768755040483743351825934148115331611562167547459249344230572622143467051462382844411956493088990228641879669590037699447566406936951533637336629054652989937715264232885147863406705620402346263611799448041447166030791853426159861787337632614033410350957237646305143668119431600892894911661646699791725621887110265568672621385618960804849419555932654031651629891309129570346211640141948375803881814885498587893407973260900070670286489920694549717105162716990069309400931018521298120691396840756554274657541635385664911362452211376703965626197024474682630428101135211891807991641428089439053353261870328240132712020060476561811730342119336900948688190324607273251355361350242144235053592681716164242658544209091451143914530627375491360306142278806406481662785368960007348124580858765656204694653943710806153638764950834105002185178983381085017860281365431132671035759845435722149004059033779294661504974270665745043311704906026264411344320805169417002643255354849992380577514545488332816616981404411729653801504625557868405828249339515705811066308844743406092758835889051354369120035734245485393399938599092612952476177657825193727063420780566924527057757895271639695038258243561333245489518358099666607976102757454021463829394171083366310312374464487318414375135357215009910746483198415708777984663133380204356772222958160273985389619386946946777609447166111757645865059066599785904633385648129758672119084981542797609595210571551642274178257625764079019448963144669100754221846240091398900906564966257218997076231227283469347734200238247018921465285030993039821748630101399781107600228032051096361483603852469805887250968622704062544705265932868748101908710019529105919359145853420174308601442516254826780437018121765216369023755843133844189764440388655301185388849988286134026893591905257227992766832601725247681865508578188971345430352802204686757546431814890702882869763729956299272541556339670539611616292813951645585135645202290572408746987147567037448105512561643139377346409110378623961824786648803398208032313297001990848237750748779790085450602548751517251337781546514335270571373441732827928394765255333976630711218621997399184843898546468374020951490370977309129728275828388900376662939303484079072429346923211500723576412373622514215629449836712419459269620389361504752689271365013199705293277387296103339570504897002972043631244831500682763358057614950085132139345338817559427628433362299619847465482138812537833431737524103443193399321353855613383184547416603159397989750073817034168602922419910061865589913538037047922931608599448063252406821128031895509950325440409281315623782667747325320383281021687490493686922985827752982473244881607982018191014681210738083874603026899368277610116976552824314338930941304944644620921974973345663330182575226836398899102843783777081867125201974331097077534706216382138227002957248532422482322911838021679955593374526618874368181959863874180308499947032219340337686865514392600828957781787876711863616838562962012547672329471051626778106191508495020188555433931324343242800765685821177152967786112545384952530071136902842874394950992643670893161913640653734962447168463856069716945890254652316927516229941969057905957668044586193580448445701589000173436717598035685476536703088431723362430885088169035202688133590499425527469142652630326120514870923199126716305238737807240589484362142689268369687783080347541590606024113019681913121260220371025009096064551289604396349680878959569790045489023673376332367679799384164813756640718909927563137343252627626155076156476431361377444413653605423496094212220275825593618250864341590157245774956040801141779029933852924072594529728707152580611663937832139913526026269574888168178616962830288303860728362392575392421557774022763859694779491685193336760315739385092205346141270860851548326821496773833748664518038408435057982587108861013979763693671472211859362415633977801222602377496773077309061301546394791952224277518097540426601611229096808664935799374309550425054980647780303902956218419069306526186268365426021314523445269673256074939852619294075622838836904714914819494785634521644935396912056862697041500046193245977408434435173072188300339780511683151044885945854717004828860259952837249707634650909031248842444536290391873083768505178960331711193777627449591678329468636191247165858296154796501215007325822494108519761386107057631331442807221797352791812225412303969664428980869026509965457958021963628659245238541159936330373585639424124607942041708263183282024918873180876862881608716043273574567388076151035551757214034674881030519356756018220182024125667627420544272794789543958257442216726854644783690901295046902101088307566022001496370696562345564451896776924257928337562105364261392195063948192154894856885706528106903370470991434923648110097818695717408742694846565580316757265548477467312987149648768975590199658457397916929895599188260219459558911804632275033335678482387309019152204546115256158564019619727569454151581952796338894408424167898674448685095109368762457280142145818363647908523930817800347786370026946586637471086815414578901053117061085094632845544300288131898543391794740827191376504574028609386604997304631499766951450256649354231622143247455741889134120413345214978429386169355603679519529315373827871950960969222913623732334855512809611163139564093444816848459519313097783039900855180491737786753335205316648351724652860023522183740747346915294227320391579109919244453504893105872297927699010455329274923848996763849719668834592293330415979859426428613393249490258157804477438327372032617271290053872747927598423346571499837792985302045229384577014571821723861369464535362546923537882437867706935564556462957110916295939533563310266285362299126059916764015963172332955184641214176870029115424302932442208739460307336245385756283278460413875834828566906983024287122733945449636685251590585756144785197761468484447501619988867609029854119494304011946821087470229410598632073020707382512029701310432549670617718002022746379739280154803409910216322878607384929025285508749844670893807907603757103750519783009171773301465430717563654569465877542157543715147701285711707704157676949961098735226739460723175378544937494881237979269581359746394815783669572813920097260960887018510671428771747485275144722613050159929535114938576176678190472976315949903420322140267497207950058209622044997538226866916956268381186783564048588288412729077265531651946158562677755019532058808324739119843206003521462184144920978379212461758830118450492146816759621853696196055841402361657616345149026676916304298483602870398041079259378682071526947238435752393159551061661958992935955629135020485646534994550334779159168445140873801182134098987217301338014560792048103129805526862138536892091193697268023413717244030556713584468870128124648585605372279295805836061521868846510620243064336066025285706004656100534221603827800231468915523823232140983117744530562973314153567239271599525086046952438842394875995700398967863988079253585932957335983461005631404380843269000579107153365096081593973895354206614012786792668926046049165140700550840587155153515571677795750644913916373981879033683656811608234503721615000139562436044920947570508863895480522091892488775335842492284784359963974402934329931764502328304028870568353823689833329436461394367336005227558999959302713184731675054303758245125546188058325301727017715648282760672264627310692458049332355122131079404047267470750020727959799495668760716837759332641971924386929672474223872225326191911939698966135345106659783022618020012819632593132665304001358490939276512659412535167789935060825404971530705121016817618314259839907532167011548963545471377465317293950879576429926609796318427508057065151245327782774719004103123979859127615422809888227575131454671291265503699099289761695636021501401888673825435548829972055347555565446313902541388402285587290243183807005558939940007380133725330905177917292745765258556505758700114627654475375535327208824533953628398898463171202012406181694126067394934790837300227249208410088137764304844402599045 bad_prime_prod_500k = 4963612076075916453952366022099490594324293395095011483628207608536618847951318760963979794509066920116400634582756228296840944355320042649017239614381091995955455073994100403560896239806307339879307228937831758997737925128646738541832868671475185849370155327872658490401567929394929114567388064501206013895927488882773030009126200521386592248935262305549779870920257170141423151564046319175991523133744029089799911150093679676704992336907274707983689198469543964761365753124784527257820912550964032289971910467558896528357452045645489256354411612009486636684120429980600084502616655543724915395825423420482010816043296302419847284680911802315043461160306317864701183636620559026591864035742332952658531888826994178155200323176808984934047998195328188590139679735830213784248162375989400344606528753775093171948902894252140307241765635767972887997473080883583499098461320486158419676620692461113666084671898579102091989573324179095532551438905697210586131954814713821530084440712927635879248187001016163526641688397220660185402873714065422067607303881156132608944970554697667766642566650930173871877996975695740372645860150107981525136154247303723289298542155225368633420630890132379838637627710438504934579296979580302697613456686792462364958520714059806034281147950314418473101081443608044910473299156340768443234058454019809281593523658172300152726256409230900202460153369918831029480060342448052612641232495340416075957028251097970446993239914013869408974562066052366551540846115379939924084146791430101681025962663641517138814623338434373505760753220933192867568341936630095372119233087731767929936725725911691245082056984252794524516194167448274416626356847472837898061358258207765509189934235402991339517530735438696215011177839596682971768677625486975231894433171927086104182199137134839172337700159542069491340230732342686004416415115813526601900745283898325535687932425176921942900390889743578461859968924605304935837153946428819197538073684658019703053577941300687952462046082608567226149718500413140926270457067858874294812950503264712100596416559515051592599827756267480301997599871509046198879557357275871210211873108973458560448653303519418822977404089748000980826170910463108536995980449297211898450960484524982974470685700481780096847578105656962853646283047329069074483980265613335240940976826091917836863908898910443235685144917331629187076739228046511128939552304064536937537155263286534623135128815596765114118361781744862773310669488336652467370262636657550317390189111669082802881513590783881145936554835993712065816571936178804346421768129168502214700509757676029959653896600160899400010828096630639042113184358041268712614586684113520003663516010277949725130154819461672673188047654320636867605218070306928966532716218373632461819531368406558292219808943759976982869275139848178716984876600803242723911107870947305173255480558482983962459174733140480596511680825757656341269366762705347996583924978009815450897333866954665658493017404322781755144716615812448428894244628178955739708995003687661096040294079637840588618473450313742137568620029230850203860842486881723883010508973651715588476459535831846109652624071078415837108972379613876991144736158869421395697425085887279425583850229369963510536713743195646430204394194166312193671622884384677879971301466050785221065185774189019900294246016530788001315463871934636686646206571731093061315671308813777867780329335081475617577360754598555268092421322141058223154539677859994516800844426210751781561695747904573234221788393085613671691195658727065136704341661765516966219572795877447863411810712924976318597202889266555559217585198735046140750745430999561403200575191573013371344304871191460843025890950636974338677629959521473524130510518468660518402593961896529639817170208927099191918643140721926633867410924687300663356450708939869462324551502271775519258572480504916906137934383796192890071881729060189291535635435723133233668572215311294477072847552528462948643190051922214201150058284937649188328248808231180644280588612201210730169757759459437505590936934830523457672790066680438521034506061917903404462709720555195003573314580934651828709695779904181818678466769940331226120420563662103066460322150087834846331325198467269194054359729638983384384085500491370200894259177329971713924365821585043235969791831828999397322916440076744368860433069461833530650399757744053022219949271850955681325058384421527830854804683391714059446492394546164428145348419928815098602905688629289781827168294413933650909772795462465878863205488123595095139844469029001208764300481791038502408239682715519610772461554694829623716613029722112073859341108396172778403227492398340745132922084957209320181097421845355230495906148722988203034014253568553728500684376614275857656348307187039706455824231554260049709800158807044307157226563959865301112925262407483739429033723155794263254663514908108946490045117295147803151924670912645858822736631537586929771751391128723415503164358903054391576063906960292824841959183927811069304464723228719986419021467747559446138267401600763944273155858367129749007849036365087876377216147959629247851745907057459824701188492250777745487037904263838839440659189047013600150243869220085195160040616625414631235935693060410519710768002880045456717580850569306157680753187187833682812981976378530527041676111749185543322459614648575895155606116953171504121512157198216316955370350143408521435849599981591160027240335496199880377285870162789861071989372316893223931912417444259859592064359419324234735286821862744020441576348607763600676061995833511224755570452018922565226488937008793467046734069446651023731737379011834992815591635864268944590073749275680340208866589548787165882285903794656574943866437853192901498991807149962678489437855275048662957730463663332863972557002432047321861330403906262567650867802236439687138998327321284469778681692143457679794274722192199532322255264333023025250260316181177038069181463907325298717879186445378172510529498880349193425108945027813048209161779468737861293530948108404406925316446100167540379865143396356665753270525163771822155875769753279895719458908569776982151737967899632887829805100539483209202173409913315002164538622337387302565353060436873371380879657006626921582919021825126410115606647531186823125905707214012037081139936381118421019992511412453318668175610480089455536421248226772023133970827418334599850213918167690204710515521796614436097665844271861366474425847485572126209461099058089667202220665426202615905578474642587997858624734837647707789511915422961714217855994650442302044336967836685015762788790211606717420115450419882450660678271531721355311918673869740508510919946735729706724499683544941520210490841027417727910585592214425139157594136559296563843580023339459745900792529224914038324882205474908881445357944952854553541997972118182826179511657808194716678428883508878989022039961989324476415880439109760551129654345193864832470929080179710301261646871313924159246037120815384224028008764544518581807921375302361845211396812096133277056154609491664904427919169403426435317514620024297197557824348242458976936426766257120148293741580810085752270271200034951558352311379866054117473832735286571201480884364005632563555088621425105592505428472079471242554706162261414249726037330362821030091477599346477624271454142460578245614952277920321211692827974036754122526439717278009357198361964745879072814506678731195639296369237213737551737299782313660352906988786863770975447288637631217783826907506218613884631304863072297111608008536503796057760742264029428438735131819040047337076285154408590700247638136702133279933877092301253284861019962833647754821144879790005959160452725208496045093236205596178607152600671238172621847804809538405387751460405653184743135495911707802506704124380134158741342329615942257722107911135880666325691662841490942248616557890402258254738864425333414120896964150360576928602958880629891537097697158071903760678493514653014442233055379095458369358732724385992488872493585693081619013311856727760353768127753355406323653541612664892452963121997042901647634877229076145129913596956025080890617793750918908688895688687833425073321161904530323243214668263336853884168805628580862012225731140592441052010275823918627978717785727509170832056429365006812836366833585107406880641941777751439569471275127126372730408195345865949832616273170145024502208533111741512474540423318060946444777837555544170022486142983591637389969932898649912493230891376177058751745128128478407395287519541732933190005296285798422448182834455489579004772162904692565697670194674411703737555305122613738963760613631565843493804840482160702221778822301247294983670211200219072882313005534551280220479440757294842866223942086546968902933212018592412376917074075312057360859787997143254649912809165055871730690823064082442508687865644893283003061435965067435960637198437607044916872259969586481865259410794766734223923777203252673117563683001632544630049586082678911205092051276497738235721618144431986603049586019209910961815821825120766037055898060250245592817531238707758520546840485053947702432665154586001402901274641414991656497805121924343948159021727281902588445302111326086861703185106384432918212439250518483731888069136446274760202324368882059068420302691584533867529094965569553835052033767965935890969928451918619534879880629935089185577427603881096253605587624375185959222809049527957146644413629487311324512274924856852190353005405196905790091672997436713959266528204846052568188070357077298296175297210813859812397674209475777821537078867008726419873766284902884932394624869894819228892576302635269565821798976874706240926700366771591451542446284052693581755736829358071460819149090163826140686191579533237837429683187643929185059284127566590290131082137649852380928873299232431129928955024044836954169725030162904727559169497652572001054269698392546198228288512018725809927086230298618896901759387177482932609602400283813607227331259639862485613820980130974054741837482123601549670883438072597059052530290581323026953367421658912034682676038064485302146597648402823250212529575845658711623300662049649704994107377186501022250875347564528661505515577411895746487649893254310081397089057704989425282483131328148261464063557267494465186072198043902034134710712924508359576795157592332715812335711180754945750379329445773678366047902108283385791587459518293928472126224222999082356414853666122057954686386870262573774398173743387655160565596819614444050925077956600292620628845436433645315012255465128756324644487830900067955261866420253078002366129279434455061362071070091493067847535523427343845138870667737391904744694078901606009191709061863176673618077959904335923737534771728031787376052490953933025712995218942744522862556104494158128654535131472506817028096319129239976328277397369268830824448662712901187689803157197544329699867786256978004661473870429772224897018098269901950590205460779661149531814322861915959659672663513086173775954473820186431726102894381441325312433857170394806719207905316621509783846811226223337643023595373750427079161561675632291316039480836169107623313384260250424921954242910784384363106260718986129122494593037378772113125505715019269746387022286732215565353177289566661669510395886227194270385859588145934547204385734823504657650692958175435659412383887240530951478804430516255996969549052886688454337371769591610171206272565125475153641718262578727936665306702616155166393898301704543505276416836485317303727363394196032262025012445611189172130292614259154197235609287428366946834896959276435969811376726404153964969305706308252627010312949037208073913461361803892096561055793124018051420422949200669634981079260762587101660235117483427953892861557057314691541901090367873157601411923984715928279716700137622969999111170313000496763546191308675657609530416336134656318306014168429821324044645802418621244455206361761624706146202919154265707872388966528926849934730533618740414114749781530786477187356141370955976227122704495667064203010583006448712868268243353538655007692616234118563060966916385716359781129308321412857948940714274879405829535872021140195382565433504903603176078335461961503806156090003928746754067122886250323254790517205622754863934041070139050518954538157766224378698759696752017422926102541568669206518994193966281329762398012989851055131493897332366941683803442444660627563912701106230504026511874059290165311070653611040524841393952297537367111036633780654248693778570086750601285216452349261580522239883839655536779707045761494664734079767738368677456715116169897462094697905560175245567753767620569908565792615310406583662194765843245267947644094281976600755686801971330736846753318673351588482399429108294636750568829142303679214105216876556643661474886524391416331165015006408709330069654263009724826756528672738707035438241852704934980799528631965135317345661023195140097867871639164042188155314168882300785546602251583517206663191915038944226306499124077170381999746531731280550382867953597739416908037190390452619159255832546451427084578045726427165085474048630479711747893958204633834255478293680210912974583559461807732464800976875121315611082442169272810920800697223449875117648184945835547616172375103091341345268177915596591495082474209924123290021683076118813676599114713458442107297018266240148590855806968974701569901939902861613307142429359282847653285964854996095482684130619579322498134869433035870675052628749381760238516904823530901401768161055445100468751495432426627448678266491179731546711806636882091998677551898054513186231493755742859143870236392981412552653749999115837948366689565195443688260580724975650901290423200705990657128675874243488357035153233255679039691498299435594498860883605818287571756555843276995871529156148231432990687296110781860355923062692412531767960219178183958725277506815199448117961490887318165684586743541204402665731776127470617686897333719933942283293014117241216148946004308529443964439186597250634392470159834978389846211278031582235911966500478375149657855075449774014032394605129871407937103922535234638997690485730290722003398283356797729168730926670229734398119696904833711981988488206129133758281364282026294190642514091410360347571911435111367293510529561925664909773141881542075485079582412717717102870655583801704822849053304458280063234708306244621559422150023489257077066106071245537287236859333114392465145906173797108807736931028013587648963628440269167678809543238921028820236591361089747501138090768450314323320977533835213172943015502921490032229164031308649868217296045863867517761165499139058627345975607836074581208402545287278131382753946748965594421752614051409591164245581312230987758805472829125228355112488666873839212496095907497262065833795921387736608463937184752806661598667098457461614591472329203969641162375563400097401909440487409206959736970692314555407169843106695885419880331715027202372177045367791473161937035229436691616798024126054049461660129955821722549850585322996766817121776232475589125543618981423962832560024340575580992458416701387059419571692781026388250928494197911758751348019386729633894075875704601725249341724042463430317379190782348763352419180587492161258113063882681291630462152108823684450257934034406048012202776300826112125434878299088467895491204465473660937688479031221849240676599389568896594175634077463200665224283386219774668289977245603760275402075934521555535521411847329278321037039938407260376431350994444138775950168462502301908273644895919895444687680905559729056737560391953573763750320528446688603954142411521194255280640338466633462486290234376738666282014988378441933282547612373984851283412656146442057925232092501892508351311407988091341021228178480378341267094498474887945520794122538836873591262429955667079025659891300613759101753257319944814754350561992904141639476425307372418138264063931147913197462167342875596971760915692279443834626656504234877237583167448210511803567739885049061215399465890043973517163140765036454552204161337762473388296870901646479433941083496031014271239079431349818680979846171938478958117989746362782517115081088861912453447944209296581872337386158760572468713858469562812088142749974231163801718742337664325251559024205215730506459507076300854437113116511961971952871599409157614964251538952969241013896420422326957382766797416883558863307461229038663513052762032152407948099282381656552730715568370892658150390623894499730596974254413033281328662213206051312348149273392092203343526120459291260904159842855957263643523488834760289993272920388186527406823015296833090698596524548647862032544041674600009643364053075096898703310247891042067436078399995800185163969129127347941166128472991237173735046542310730598119723740610567554908445130258786980481424897776562197999376953859467217820896053759715192104969659367741817798335562898011609840905868979389283725902297744670834517391398304901281153107766108880982819859700413911753911928462990437052675326944551051472900804789663169697977532552213036692224402963700437342876378524190096870657128776956871439758572298581913793171888405437509161006864709874990413926560680866076962001170140056938528300011194933761912754628905446917204762216218816719566179865897578986282030092726386369600777912129840780731258434986667952586246802876934014313096649285423165305528500100245005134699347115213800458790313372704554860551655132083969846194128506565160868249878953312397926719104574185551126625454584555335757685633450352457403799908034018519040760603015585298809640060854956009899965309865804485931363144981291483422432050708761759577768628325049202786716681703801341803268028295755229385247410971554005874855812106563269668003149746743746735064755022440969492452748987068386533904725024448135117509412601981884223550935650668862207994079496351952935052088300118983406968241245918558612986505071277511103154930721040334323258834769082906948891731935290227324559328032305006831895100587646844603308348079486769119579660912996759495913647277196283608259870241898414881737517589763129201206857068578081725473854213213285168344883653007586395680033197297022901218016010984884357167592919566552260566098151650664290116363861374414533839261247859975081858861071676953337130687552656228038932077207109201612987692145227237213585708724604965831076142172932102002169164044647756147348905664835780524457469875313084214057945672263576906450773071473918813859060285013624761102398217581315287088587897891518706969940504154109190615527010614364870752595256369278942296147183648843906238034950649909356616023971734665844574210973672412861834234274589544168406103623769632556948599564764932577235205805145805375959789400753918149147501236605147189059881280464348620808847098039054749986773338274524473960754476748090719253784359130080247308755986452394414531557650059158248700333959985674852415767932851069809321717740983839802956528181239839998311062210112170292914741633343892592661020799588480616142305821845004068345781603825801122789718062512094563817394740411222000526420304507661410871488381790626743056113839881677061882157656506113405735743519980911730805843285292573729906560251299402241604023734830408044689114972519777556197364378793157509860440876212726108909307693029663417351242467798886223190409756197984947331781072198999590876022003890272374173621701781657600755740475350717962074059014204778143633536929328722720049691001634414355629068653676838593250808531000352055985028644358313316650522881997116094167617745805774552720404538461931551000916538403195745455703040510673153400544665376933073373837871581072115851475106001668147298390742283935884583503185624532496380038824634812998452039735281224587772165297764897282417801031004974850318293113079803464305654225125534791252761086661473433715427789109973286683956021362502191114808120012487079668713388545617012760636869513203795041735393062071234222188220622958744235647846708356023963165351274277668440293407134915072660162381103183070560639204397431873135204553778278358112862745919824016945180312888763043180700717110790083917288967622805841861084930054259436830670617391803362926765389224786903425495100216007913178968276408731776971520402707806802840240676158666390891658028530127558689362329193818231466631141610236635327589914174050236394628982393873701227489563752565677464858953027968841057902468946797539051953786133740952850141553443284352189090485606010169943489014475103094664038129567400201471932262330307557561718765163084873066286746526783456348391510656345977162437920593790399395829750060217161858291620595051328355515182886035278165192315687406042117024907469517581653250452817530401271851358492173477281437229443910026133355918022557649911836512527792908519500500192289260610728587662319207977992758019667931509485528286848774573838965530229878239950360461411020363186397746216543330666886302926765753960998601175947530580264325363474132530190709459884111774508868908501049554683847775673937319382558215703885579995204348483012775215349673591829353883621091784823921317266327416357045354094500715320403213535010783290867790674474958286665789336886978516638426524790545460721782181199363653416032033354391076852894571467545830447297379535599535983610680106651903206718821814158267397806232713164797396172693837645047244014219800272423376220134367662529340322834414029251718790512075469712696390352589928706730861352069118942928536962711418264921708794997042811503063866547298124986392217886126889157404346782035322149578518339819602483190856999474522969647620380491992278074771930558173389475769803299210890825343155366728324917001253162360913830834907687903384858544293428575887272813138136639477009761206991486367255266227600911440191106171247002458036120650989112621823045255045316090465369483763499619009196554488495987182525866417366189257589264184103817155641369357915169631491160778892422326986602740856532674660631651040842685542668535238875815712735647475445273748762090392664065355261249000881523741788016278796245062462591353063776296339796105265038523210497545719023052316335729523367474847634945304630861742416085396244177121453565101949373416067017339647903947025526021236408613939048358835547228198980088293857632868816416578627307593338083203584281570533478548205101230987760930742436359492337848224897136225977845582916923244647673767212917141269862532901827865100943649177519912475760638129769773698939671034426037890647339196933909119470896825541947302488745547818378094412796924455775923886359033001988950420947146872028612814339527298830147326075194828366824663266202074895256412042187503421990933672321820513822423072194861098087873950813502984872341403431962910868994469149581837263294196908544485595305124672005415501802907143380977255423198252961519261015239702801034383828455337922672920850377223735614149227827112022973794776384434930863992958064413964159912846284137478806452031444727473645080273703669553545949750776335100586150025495208048748405911458463533784566964560865239507210686354575164142155672172248914104430567895315470646225670289252124806834197192819557013240564173662674766339808585212991460261707158366950465476557862273944154357233810990898824581819427018658027817224090322261303264026123130953355363754073025935416431508553128630655192958241974505181609942951189063151460334515196509091504454287197394229611283514264084866822464354706538339651185394003024915738191562560244069036868805276103421377718617738347423894521607362693899578392442243958697262467987862854168305851273403874267003983670701286804056737969009062290637883164705159045262278220447035640143147407232282894157592463686104777208799844688576798216892008207610556521864460053710460746427630707007417309589419820064906429987955384706698594898282557839116253165648347601913134520234583315660128022916240580212728732528491324810088036735941579796547359420378255760410214275443889237277843300660190990452751391386895640561166479278613834258555829517561029735791483910765641160020623033124935548406050815441276832903947894899057394718356730176536540732217286505665365843609772906081440539002019669834574409159242515355850151462483046960879654172079360174055479419117552661283571536024648796306244399234800735699828562885507825884914819815573592280394180426898999850415894414158541403374607726345747129365491675256819361625527893013346103210165924091125596314626861980846905485627343157871307013796116755853413189146070733367129591282532454538601768007525203253947118987406895774009666742235052531455699121021312532107868258647719519710131648843051969269446853665347147721913328434233067364422478172512317619290502972954007094956568191414755581241740400760908628654991867647036090350819457350080357299895615929385232012262715771957388037424575470991699108173622344865695258988794527220705196436072375894748421456308530865909955349692589403782889467416934649757035291062408916016274284099395140261847508218252712475009685385708443503524709650653474595020614773725881638365778685063505271139444627178852267316211055604667286522750007655007624281909206555124356745303774823073039872743845810010770625328753349684017391880752491417014078443013619764139234199780448548382412999108691095839931154864355053877341718849471799590218086546074612128199143542559799488633781596262750756322239400553844735330955092676178194406471406637386498078599026341486006539009560304693182561652227982444061382235409717142715497136054845256794567885949153229515296797314976391158884797928586069896370752810326567565286818298749057229141396613760340478210705656828988966397446178114538369617559951157641676226696311363467647263049696222901173817451019470733459727107237079886432404547150800508091723676326696343356853472609889745730087370478934256802853542471744141093508854641754232248399094369906093851304550608019828316997779286751923765890855958941882964266657357857771882453877184202653441214274405385537616436554706213674304096470895802390689784078789269403550501055118992571680769091210613543291560390431376321713463454605008831573636567685061240351250523597476599314194929438716074436042636793242699522011253314028305938538597685658511478320929743002906768391160929121404995541940951465373027474004429520055574659566854290385761846470619117755060233909840049535928912174350709326411484889045708676894819511395871916417287577074604044830500671325047089597524035843029610884895177146564704998383132671905750718245288173591922418196234186982619070108739613823240820457642352001105639286830490951343893565644098074024092029258781955190904070368053719311503208283036454772218471255526853362667501097373685861393746117787538541137518815943376978147884291592606706456091794240333250888320136996718350129414329034731383758195328440724492301754777681515012732023443544563216717185880665873751499497085264413590304471292556943433820177708242802834528624921859275708164805762179847971002900271865589236789911900442368145648752134073974539902362965684849842619327735324922668858772112576862217015178599552376831722760107263365623474667297032187735351439290828250114501268092080171642455671372603036621615649372157981811235108668767083916824511778330992624013875933951059777117130330424411302361281414827741609510945641826966936017394072223996792882037622087974453492796040284094119232014798427456347662485208842481026182460751170881759769035598324563501041621145602562510353204984534458155934392779583915581666939359411718025003256567802218215943074176560969377365657435219730700182735924175579688024635698705339597411582022671807407628537347177898434609562568800693615117914564363342115359491800770421217589448728208061908808530542786759665099321228764974417011714962580185741564098897623084072833101811331935066239208167863911118628987773856181593812312366917254356062270845980629219422399974473147415742845799112519665324273763929960423250311000571051792688204362591986002028704086813118971809891255024179446510406244565866970272299937037168800124730181529335799126251326190014707711145610723302296733084727449024723461331965996688754847286305418656293516536850123987459479662079161357481211914101752649211340108169655622227651051240513386417907831975541209901302964440935877945548992437376925214998683545187341127078312576194777328132142536073421134072481759894205715073531317931732632341563883756963817663218597451771404996687010881498782044892969759290226296760798052716205550925478097374746001678264541285782398995822678957882631827572966177793475810249263030324958140802698595145148742123784890098147813544922196199395654723276341377988331652106375481012289651136067383585759067260519988936117698952468682441491687049953319697697400239720912598596887017365996135843700777079843225946864146436638234425805311606406986081956519789705189695680281040616534327182010859696836409460958124096020694620938699701463924668643225378143833157137246988790110370343269764563921144730537988337372305528635251217752661646670117260067477662507748381825078077554821292566981083260062059229997735438489414902437012913875023530416045456361787480360017343963759920877269035518133199893521270893369756714071023925859342641854086503300526220254612223357708354967753731370097977285245227020692837316040171938845619612752314031065445282251417849925545703833664155852209810144220856873583318652104449076722942075543477407459498773466322823864882918765098308836266503486856223764624076330635823297988373819909022156948628380600620716887594571949028568372846003949309534105230189670225638526483201133146137480953103338456585384150443437943999772094808805835493261642710890217804414959122797437733835548039044285144465777102113039917876886709016935123061713482407510236615700004137678435721051351534702401548259394740449044190851318442534224595483486469755703184522941934162312262629749010129934767399647231808483050828080455313911527066781816773583060988553378981987213265843517851050343318705464651043728443023583725548732617005882739999119543593922898723081671764363485749749757585570458462830205419786018710292612724845556285104529440047479793693394930941648696026191592354902191838780451333303950511007239099991233269634356432517019480935013508436107753323374575400924884262220162530427915783053002132644971375522120059375890894900427453633832210613651106622349878780130877604969608192782735281782173726998017004219788482886793085345005961535005991547964798650465540435231690592446532077838951403342381860889855687278158027901957525943265534044489869556349697528116253081097428421195027305736387174562083743490697238698186608273102164381212165074892908606140172248796150616118597044596891602998873176985540034487017267201380371210328774464636843822655936942581581152227601480750169189487792174322041708171702979130315887719645162546065542812173358342883738393416647369215539894436987320383929694441506045266505019881413098430308414592407407611933032622485841914400911189071569846168422515860694179661885230856735316111705525183362198736579086913015862075065166744183131671403574895827267654440443213400340156114483697862157045950981136488838805661907902878079287095057444241582483476597529172845634302531146970363839640155107224452937904994376997527863746553757566262053406208965717509218856676494201112747298727975277470819875281234049034597701611739937049121428601582437887243236659144428386477238674974139018808447760227178564225471508030632576078155430629203769540480230476127806044137571988310091961026876145506253276080487835741918543673099116592087624349786389193854359103915882131394918586673647205992766699024217835303658544541798506555926817860387346448671992469038328863088884302127374266689817974538236082039758300319681988603759691069809178582119394050988213849023860267430163801156068221593589592536629442143716099719357197855917385118500612809989987856586954680687375263608276152520764896407592091642810883172439869294329749062684120335172485476567410573155187503141306564060026052014195691843165740372234386908155563884444877766614769655481744098540485125538290482712374795832418682598808328669827097861011093437172248175657687840496423504776015621517967318921010804315984452046658109509089464546734156585891395549567489850350237607089485850431432553297237753428871136667631527683049719283412993749751239411191045939674849913921481902397807183776287913804724485020520784306481726394821517160342908672086220117414428873637564802758527615460521720721691676009995689616652397946343592320887746191171166414339482115710008192481247483361391811280891971235785653427305809217189314557529117732153553336064299109452140892262425922761677502484274638565179073186619043842962728927551085500407397553280128056236244880119107518501182417627635426969790485309242934817079577221151620939001801788382687488414606276040026480016635848208045791890570047810423373961248485619459281794611967328278151851130756780495672525382301694517366884813762608933624675457666983159592653215120215056389868104787294270038198578844376226937942851793450926802595195031001521847381472551846195930081335211965630291128810395322527938236150640327017664191979917548565555904062431557719206233241272039379770376921694004699892192054919386546466839866439326600163217093450203142560354476887267532894500019497027601219927798140750470689438298526276068525457683875540882224001784305975095199125171409252710225094879497669011503418576074453398153496116130732072109622897452543428015678384064230115417908807691068317549499817926591812442051526594746799416474245750748549243552047050310954019779151193521930750739956624590075385603305114471637409598829124524453681037531300737116482844460342897211856802585315595651816810488484792070170962050444856101289117581617842228305711369688054539418700725765286212562035405311632779039463702183742519341701081631126704314986020677878304919891008051412727744367502371475356092391426217647906151151164719401022868946376993997267736926870899674102595982766718779531650979810913622460979818760280887434330601434945018526682959251098531156510526013849178901408710487618865639902281382659575276201571133959882307898932236393206010005647845220621729212668401224915380555708064997404687935127151172175417497224906270720290651232587844350705005263409730042315569018984685527387286765321995607613177942781383231179375987801575529791432585086243203747204864521692026588072245671420853850547080859484341927490779345821624034587539774473630194093090695067745738910732459850573561955789744287935523461414333660108701346532038717166646628733448652084490604407899881828473776756883576249074672444817674836825989498508218597210165745717365991204229421619858102965004819180481640431594670525952195001699214148883631782517584597493612615768504563287018256385616800963047716145468104788256426705454561310493532451014221159599601228563948891930533236284817936706937157123105571581925871868308631392971643252944087318656430932627609850888584808506070608680615137990949809492401328234296316276829697957826574227131474754077329979072294287605044652488391987210638950612905236129304688230143062124690116818407640738007510236508261429933279909476044715074438598205425212865435154706957309492107481353140166286603375209737889622821868375934487736849984324749600999908626775714234668579657066713549576217556243935936343144330770333015076505913035419927521635529763112349273321449558554617340910241850747867551691085055815483761141411716983340114985933557370680699844340610381792510986751661530732159295686170942692982462223778300325471777067215978765071777650605726462261575783236983484257030832400137350569701496568193460826583042614750399629988301236345344351471869229332468250460641389688758544686089162624185756784054702806095369303249820777411773784055483816688572220979455406509987620129911585662027230757934472755210898167357375142828459516821302897022059277959822991147950895016120757030902594797286479979939077375005038313708263056231956957386852573298914203685123709731933280958282914384057623728098046695522971657335839578766426480918677777839419919771361480384520835308042105864745975901721186836485975461623005290509300098877109714282706788308222499508790618494450278138010936817314071573649588888470842633143771834385872685598452554408161667077309295692239655190496703862743290234464109873957077582207122781553126224851050205136910550269245195618579979208710562942803111000057803463102031347237737820015737133477227661435235478551673041566756899602301071666809602981377043207310057855487514323975864166670870388380379708858901166808595596682364929626279368272193904322172274012018570439493837458747198902929917196248129739766725158575432035148573961031003757696521227538863999048315250479394484441624879290058314721693482900653105596807566045534912482314835328381331701996876219092643315892296283439700208107476662817454046661807680699662939642577972473549005131849610952745434993865179565080193363747849197849273552901288538757165920531575613458771483371960378479360637645283434910580530028842196485898305285860106818903114936448528034347999726421574907425315028924765155030866669984847695787990212670282759032750964400962410082743078558244770756527234724535194499372351875739473181948968964646760410116236000936612492467978847158953150098820668945642636842431222037707045934501420615830157254709371442133076446468548853442109872850373693551725565867930158829170213989935717512303290070701645445833325286085793285214752833233907053234674694290853587340326268408257693489307550647576972922420277405406668909597330981029755018203739074403234597600072292304991962599074316193639546851395379322673243804272859987545806189288493358128529573795391020853958602187824448383922986034118426573335577436095004692454915153260854299918896254394557834487264347809074838397447316425546653890322106714795925541652572988925152733104187469194224993390303814730937422878856556423150358389003444587046545288049413704158676435302551827475837009022924031240443135216595024803904851393868396424288036670639112464834314916269004641292800688080522710020397590291915347037557466501967056740023767445514319720852727940080008633009731407959088525001082627994791431259415170693950057080938979208560325653205052723780883291544346799897892716058093382978429151693830800941659407943618662636209162473310441472050484589351421550772775189599325199236709069155275548875358239366462864417509243746116325547172182604616235867937944658642758384031085481820759368900194468757499019195154704544677644881922523923239408063235782940276392455067060668746785275726129989985212468913865068293673207292340509696128085320172417847569353332499611713764035961112256841625413425798913370223558609759768601120267116897225543527626663751661142399187912170365087010148784639193631122018182317092636459278368185666507301118396211656702047387437603298958271992601838360856632622801347982062588300869549559357961019912554607690357468741221833599439314279420250368454749416273593973100652086273701071336147737520652091649768543890604684490530612611864637719006645094112944041066017318941846686624394943717060890036049486236672186641517400415302577543646542589762099507994982635894581748719889438489652641090043491444745077565362519407430567096706590710613491872047285609531356720662377838997877798142064300648545265497991748040261521622794066454570842815155541985903289365230484203495838086793729025964519097750507966056632018886207241138753246212433976422649891584726793140798502631486612202010551550709115010174547689225816154090862719347456420205481823969122035462364984357200807804497225059256100883226561936216697475172628442451422524764426749131037827585855022775816967178841064212901738227983975200333603101392646700733130855911824350887297966439262863668952057980574103491477559475017530257427314015941257733690259992678292373143597751797106682358183362313857734253506496191638060132002511985836213800403095032658811903095826002176314535162989486728722851695836018481349814420015814109540488841250817975838213950378762469067828924885455827782450526894746200724121583060371839226591386711950958942091796627767417747817955133047918100794121452079778237664893910778638513050830449620491133548960385461472216944919728985734504956717301546432268581765488047695210150032209132827424254247531706816984494004690179715832095888127813651776583944934006959525968986698425711072768238100568133432874779221172028266232149215384177594876404649113095962389440330711317645014480852848881618461963330602836757899906764029208290164364763773265237466240511043991624801222028063237071970445641027502195473697327552370135544402038865876768247545915004128154448126674431185621129492296413638974924724145429442410504473809437761506794370261040262057523856692908718991884931307337825314249351539199837033011100353845862837833154070934583337614292205251754768083948003610409725823678954648835491130119959006311506589322820878023577270213201462344932585802945578259363225090453744686598226802304751385673837069334375905703290691654478938010961557149541034783554702243257977580974599440831152586107451376453674717084371566273044689844184161723831833881994275736244150466523047355454924958618451558268443226714021911920884467574768562036781238780187577122937033942587783230267618646087012018093574406855777491199387311071838293186579713119800427997842976992623211699878262690427659578005274010781161892987604520493061868435316234581831036636794781733363788048949166209295876034024017592735779133033058602025881130804275048810955712687745795832418747525544521068159493102473588167286238142351255402251474268388011241055113220332645456955382393871585277011351200565443857280736024784832579758303544060198419684225179823413311220232600566894031959759970449635354771418542315584336770502349204477201728460798576077752468091906066026670634977802023529585146323700923705351065643532959429794717970872196788128145881439295976921302377311376628560212395525860925072618095133792433237350265308399503853586616136753259960504879608423411712606429824149018167233049878808777088307461972358609840386656034385438065454344143843763470172085586079414655068262775338899581313058914491568965130382519370700371064446996942058047006696255107156547222018197228267811936646405708481039956425425165521725187131194817248397028444902348006762538233810005490559365435389375163008287540588037870017041231435718092286619810828448446042439163386810974289132773345190230469129647467678159018155429533435365147932367417236745967304533936068318421966234112555125877558256235056329293516473356190681345303292942971812983703929681236680438352011710321629513321230852516372335332236642230814712786146780892948259015385855812427900444195269242494068632568590150528993897417914463709806741255596382811882434550723204667004130617466979755032064278475712498499859881258651136624980131611861970675441999132714917132228906283966501122276719850683795914676300418912996071290549010382077134419313475036380011561971767483239647494624211427805112761230350390121238149842548325509655277396597263421915931472845143465673587794350791475987524253246991369256047232745764164094406825361907373491377647025691033989622912292833427561026929448450272852956834275860252434636929572304761521107843795240214238616403642951023360625290469948006057495800082478387583842135684639596261137950624427930484866477185154897148706488032049458682520728117955651917081698542771601676858565956497053834619924295596700351875749067839774648699486901132470180866396842632000865909889235482912015216555509600756651941766434003869668796747642000590666706103170885467990329538007595748956708823847742099065520299247987739384968680388488771609351716196960987361660949686691247678636537924967565909715866102094879834938127299774244705873443790614581648145446376327655068907260243042864391328228890738849333330733298277085275993908355472268181722432961966887737245208398584035501833115852979321723610380048073944614809789476939975011465484809117602408147387436151908001524046228317202863844952145584266540265666180321073646001306753492417990859137250844817276623614700848338441204931271680996523896919355702292334918096050384314423625791966006995143516818681310963411081420575638659064370646823908708756475788876710511756484417917178361331638105538370675666080615007522308183344997376545591329795327816772529178105130361382704848562867639410532139685779315519746936424132926495689690279752468695659906766361469049973055641569023834010125519802335487532737288787580571337471090692773755343513825235215062297711684543422272468117786581270984378341298514231424685211971422778416941444554622771957651029559122882574824220830656411815843095442623530119577226609842255219327846594105715633715293724488693694269261885778987099875614549756758088425525416843184868130300807910075113892782336079777463097880803957899216539214639439454546820144556524468066157581821354297550242382822179302013209486093273640519683924124838457379933770729580949060500627920934103697858534316405140352985232033593468175498571731111383662582157638883565734462736612360543175411649776515560129174839013790665471930695625818483963365196452334629141102302896228552832052467390168467716222937143022632660945666287537813919831098009464551701883145297108307482198489464901673790353853221090883812828254935739502875468983489627823893637526287027105153954968101175281054413104541868368015953424388914848720256068240385228498678096658324665555999836769562285600717899228141199496638088081200594339708893276961597851839504214616349118271215013802909418104567916544381939723202007652722906582766191831560677340165587332049658647518712177214992755635555603206987908207891569424690147416356953171099275711090870541714837166328710757687767782504011664424767829109253348337896386316652981327681921400507261110010442664623125838627618338602119541676564428726313181069589992189105076295304117901525500840786516543230752692661975904759478619760629175136524560732402626385915795717275011807555946229021878809646839657974725949032354932810803537677101375806515138987284229272176919610690841420839456178897485334586942826498479807787318978195954559121029244037916554694764857435382564354074467545463444144742934949332738280928841882516608608421449404976524636780487894462664458946643104818909843219218121399262348051377781901050194562505146902632225405263479332366834386318269684938425601344614411728611817729158783112835827477153341739284725573788561623113160308046100532151240987108689255704980811286242103141389794822514579749496205050262641898158952171444479152090027924907006966610069641143607754117227794153708810989060630140890287868997991782206309832422063885051956099467253885059972602877919485490196912981084195459278792591203625419275919557368085781747288625812794292788194732920736800031738348989552798337440881511032738711297065009478368096435478995453610619031073565995183227889523907838251972530446784405049464275528486054259617952986871440881499725612317395256280926335354240453580782152996501309243522533143919276027173077551764238253027334619175988955093650684434337747344463957408447167006118494574685881461431758963207633583924193608035360543817617452451835424495997613357383136445026223164467091669296285163600153289059771053358592222723736375961900958801689260425788599605231587726947087369329597487492407730030358771133549299899152569437257416894423217347133517297116660322836296353456885890095821611243271267915318959040020388292255436603526087688990897474448860362272193450602050860492796598169327676618251516890645670165326346200291895765079607015534268134815899376875627689927308570257690604798453065165929044210111836403734197953987042319192849864703983152221634410412649945242483258565489973543331583671740422601437790085585591199331964066632260679428124461579818309914051605889998031104109562297267520134921400831630978154767221995662232153139643343149073772757247508744046882309332258532067400491247382761241937745276691058472639326322190822237872218222598349259328435038773561542967540639871309318480594379828024721904698356402123575957472578325637172003799832175911642668497139867446191044894532504518823576857796576125890937611162264412692135847876202206108695989966765718519353868792679975928446523836669200773832859499563767517168790336525622313234788871334710598721505883337827972022135479994244994024893572448842777858446863163468218792519983459850339725573567492023465334713223019350604450268899889624305127910455880227848743914997859586382123679713446290779061093344596602293441404352905086177665530602570542636004931810258964477776597204731853547867813313974297819144699963992000630762408775894275913132821625128606249794447081497954963106332273782602736359614402326363078062884648920126116717094860335713406086998146516566542788322448321686388337996853163254194611720787305700718677238442884630205350077493102633864375002302882983263555198939462963339474521194451491679853134425102650717392648074281722946705248129294622101277358505214040166957092171288396613267312100812478076606895984904002995040889921394164414548583323057832690662777211972373188501897295244101366266078595296709284901403205898163983611758135877586226266473916773713195296979508859053492047382272497758819391665294750466917214204029511010530260450096804133238993904630695273964339200751131039540331782605478541970856497697305726487894561396814092579719256776496456823928624660218481101321936202939692331838613948761362119812386549167637834934289355877002660812173730604830041044567508150386839943588783115814771707431625104546895458052153577242590764480962576906416604094343649939099637458757058869361674638620476734331929577411756788988744198320188406725105875783089682836237060090853602244566283358605843132406415921945410386494921695555081548834862583813420960129995379458727628690344345643261684275041615103980396196089133506878099237292265562007611167585753496025226814100085795412427435251540888649315857018348258590591168391777734953860787446368833330876289621597141053313968608949504506764923323329753185115451843017184071036178760426053033989834445612691912294259920469243020392453237574293504634290108281413638127861671990053088487763412437744461882303136757906192426841322244620111405266848316958844048266025625419862050540802542674701424696536411269526041536071763917598762869431669942820384662400496083593601005178200889206618526922591434105271685373886544694073289120117532342828750446660510497075441515331978373324263737657738645125161387245158997890461201252094880253436436300607123791828943140033481010667161004020614224588202601753898001400207527787259022720223094598293747378378624761781797667717574159491993526926965728193094862895219598039657704834248469879743100711852603421419973325377211381556404671813915128419508393995220166340359388161616363638436352969023333383857646317262080506566512600051033035487038446054039224776413023043974301885065226645762337849442605190390443258878082722456221765425760239896868164380161963453858346320102269803220415434607540549502463285640923807209894770118019624422615878647435118385141593804664406015977685896596279023050424516257064693381191835614802847560394734421709893547640633726977647391377700327035551712017791378017129440893534165915540152877162035683499970499332918067895828271538073502523358128638986993110546444479454151776490935806592473460814101333769611664294848131409637361048754693600199882381093465898831695062366979240743465791444611393213565031028304064379699016125722059766127699548722502654646701969295242559591151094886732929375782472292748652050160376783303466699391130981862553807785809114688498285636338334501331594789959264863629034013660872262806042208786273066929791990548639211361353340693894778996033155233695322466262776814418437846926788757686250840299278453887231017241955385980884506813095759693766661769602826979743522959217417213919688916392005909552809563747168831901025923192669987817394046872312073027179197437928402107319544681753764289897161315122877727090239908245545032021710029027606788624093792760681588523844373852837115451166249691213085816677698672972272772740457042348033981036277581452320209886415085770175284740612880104586815954905922676211354969482225686553002945221649848945358385412698546901018386796950943757388894237128000313111089720267791799583289507073517123842746068927237978565617129197451794187440153696910929588913775835822010959877622763716029484406597252247433123163847236364386503644810526143330508936610149944277832789111679734759154384363248434094796918749636436940983430054484435992529279116740411883503113264458319087624260784103899352218546558532341470090836410213125762498610518886863451593280281932165168819525263926392114639186269846468356890220376878984839181751493848221898183265619261592446731886056905257746399695502853187036775283646088959675427158273412826661670927886837466238933527817811087055679701693454638849470499125709574741436759674618233626058586543555333271019484275029125111189767014661399717298101185306471302686234105532574049543210212294614433224349029708908042540001738832746795629347922516097060304712178427226613347977379965933622214813800711197920359166511671212816641015274762818378690374025108276485928376893590283928821979481537028616670324345900895066490751130115807157115174984172095963909182926584147407782564100659787604063377230435467882142971777590603071535435465304647761435734525010717974519547419649167528559283102294598133845389596649230709692841684265352421641419359112108984089945200736021450131546593288091325434791356551126722169617210224224433208089295258625764425027872328079971493979020160484838252360852358062620489903207919210043411668204146729436373776454653348614515653887110853217678724859141594003099512652824864849183643507409689876436782567777183643620755012092391167682503511567096424502442552734848590950647772971860572430911707650176675965308257876391796609627915282322883342825804832319237208044750369098305170050439976722415787784604918763323139245920591905811474532043467100362303120001998717116082972378653598024604479634779771105909186477868268153204335621819363500715727899097451549908352576983599807119231925980348816767467811061050402255333099180565304100939637915672797574501036763122833467522317677600349901544138955861902026799636689304116911811669093463978758157868943638978420009601082001202554978942724430269813432825865659219042889584979019627860991417230398558259226071262489595718018261471437601968435937645328758285812621876582434423527835526108822212523218251764473575841681605293228308993723806776973324153958908374152899271563187798908706033442672339738462726478282342179117509829246423801806518194666878076899475041126282173949094680225459382140951836789576576504722761101333520989806019145742502125030761388350669232305267577842502630271017340311653327146008950622756729625451512286038959559925559510877223042502685714954084407772103035619478046462625624038450737119463810792053023267504617999112894825409593703458817222232383194707818293913680287405685875083809166355297752451946383621510113284332810416725905575187327025641863841702669585947314621476061196601243166205697064272124649296369298346158613370259996225169900678104792667235072677750589915084574411815677734121254948784209240958242899255235530918281276037736281434634365733765991319331490563363904454161736460945895239070266381103959303233206314026747712722189103438193168780573806757351278345273552560405687642450563155105975445358531255465897306212709100731359254018310538450556724353191680610575080037495501706885095671535781604161988177378126164193450487732688303204974010805284011616463088057011949978392296116500042115942649901451158566195987050073942797193175235625287154655330831441871211323311573319160192653674441321011082301366919884782208255796998200817238176456716376125940109197822681860807373382242782959944000318790445178512727164144761443842095358110117500666670530539027162105214940572022571249218452435352819892429749355110304852104549777757953316918612063461293149020998573160911714229747796035418645927327722580007473334242263237465762548701916208970170723433470600258561056764327014446892493633261069293742249564965481139022379339573128405080400168697728616071953515614833595118677888593506305605330236302075703033068361138908348221935007011842917166281955071530024305012657477860450170702417781480068989695898451368082687004567457051871821043303279561380525091907921097928894448832718445194708217546390078242835225536455242622322910910357862993346886200101015168596696061833020532428307371237200867338171838173955480619514935237269715171647039484452222090099742688823345016619908694998323218043072196007479256793834209170956679348411700183460695347182947961679258893424693389430789486735223497283997284357736368319099962489007477985802984056809528352600539704755558894178491641513198190121619809272153549946447029047729943901888511921535200046796799599684463787265300195707748647870227488611649179175734994747292661716178473609266344489584972448805443824054287995750424517574932639905956520275811307041824564979154899008856731669446547570621584261313759293486994856961860894394074543230749349608011979581542566813140859314047846065103505296471100589109206598784440296076775876591867042353185806172929268384267313840108888096920842353857529816752146283322573536826613478758635371571387199788465160158180184784578866027308451427422656320365272393337123519789215330681360313509812649939141289239225922524490771129298910211101030462171985030473055177792235435125816873468376364379825048790515086811091139282119851491627057604666166227111379533606948350686398581070336352245855534138122591371894548997971867170957568094809074684975872153490510880621412830183880867651517753391959504407988007798401544596602656153874423532912435094880462683832518977571792379817887130833839965382030417738182103552419410748515949311239239801783159221241410181989937430853964062349218395262061803882017974188399730856338069195551918705350757780146086523723472337303968519905174739081086227082217135034124035571403754120028189085379526322275957904382199014303703268505335442329607233185074899562675042891520565946547629907460268713596616405467665670123905044872352190206358831570584407515670403739743229849486405108274020239810132539873731205803959166117490999945814370447892578707519207495096865426150142464794850530890795548292890322748723446278800285050769359692538604601604791671863008818622287331539353896422600074135930784953895814512805900905010588510082330914386521455222670835275322994200456520761281029544918575250678997602473897282377220507601467323157980238621353245923992575215994626828083427766623583841453648113542072800094769475711468028494722336132192447926760544231605656121190526061486245127516595468196125397205012736281671990645984947528190253116214754869235252706481384167828665900389335222982039235208244674039379485686337667268761589590357088248022337155334058713838101939254974899189559288501104596098377283920870292853459391509403196527270401489957792531136514734505960964529762102920524344148457788677709726297547797378337547519636256136112549376000745682953507213011539256829362189431361698581510986888461225095261617715170072691805061270895174388376460554763720043085083739752335789543059649837100093254948526465019442775301476418212594304683280786023054239844243481127673573482377452777579952607140303159570518410038503778464086409240528861649491549903956833984446302406912992900725504309191721893046291270791651124563225444650640813842559591969746125330875398593741713360242420449632274676134733362464317701934650346537788461469338830025722538737568642703980331226910547372136434748990946915622999338854440963271413071313097313415339908986742546858762415977244657139149332312520095679952157611536272840304488226371751699311226124835549487644773964902081182190742855058294265766902702367824038840495714947583208181189090833872373898701363770257803920602983260267073085373378919699667602145077434823202229944866907856327574794356779644752492871245959728228792345296367987557112040949787907268988465606069289348302934738588062480020015333327803864796418762350708769750154785061900517022114497962518314615381961883011141302720807048368037043703913215012471050683971675853330169180000912292335233111306925437641028702507467814962571985957359315946156037479780742139556560443844818712175924569239934476816476395333788285514566293074713860970766731482677445839938299083303673833810136622421935116392826542825111293536559117407135275994395141273500103283602793106228693045854918249294488221211065766785927535723710094746483833771497608722396993598853983651032862365065227890312295756391928303896428785024452020121453745742818850696199074560387493118194094908187216738627429602463034496594323581219063109819277517584186514009128889956681057273073648390937490551041764416000338426294326253367224730883918495408870337077149126610072669493749774595667659488767679994092892354281287095049377711572350951094857498345029694819001884738795186868692042207792406855623483815417554187346576567318178698614004160173968565033237791839118507665242941241118102317733812211924932340613237650066574137921498052827783694768165262157406720116739901144639570272073460530615662007380600703098412655213798279179333954941856858956089406526276551009734272390764369956781654365820793821636536413031444992967746015380170251473486299271401193440964370418071818642344932233580542811939955896360586771435338288246193056900841801096947477502383319741267752906550131527340382707362565125582619627406168513395506960109184298590855908064703403870892242724524311230477952157933387873773996225699194272571594325193709287035229367488568819312657132795002210327027083345979535758369674936523103787556232420450057189530954048571475569420724518116236937727853188220739509523666655034318387820853261352476675394150735158767124458423142356190681463602968155749000245942587945798473544001646495593804760806433892103331148107583152370398210108622166627532584422969126781095879601879031527112801135536111594202322149323130791292999793033564242665813394812010817828986697775667483138268891892232725967262121680407170167037288607947729784235098373102505117919214436752188403507613745560410237837784676522007458418806575663075173182194576077068722528812419894287735453280981538564516373428467664366595951733821242507674047338403525367598099346193489526661605964857757530800925270772950486794971454322958267845320930566817625577088677693544863681417444507923438261384366138542989021763232840313609052546885180774993871325984360825556759842961414684048645204965890753147721359661743136090876661985659136152822920720323581296749849393629669316073325391301479077858007611813989396914511040684081993966472586244256093935313434978555500629093088336429164474699488427053332041430478618398764230547461583168164351088319339277371554206474783164239692503872445613190697112400387524843318005696955751679847220718479935187437896489589789752117243862598276691478393607270167433959043589227200556197177342168376028603903666553298153788997791175285005399386860851715179010529883496892418081715334737249945924935537300682385390323277427054199433541260844355221568158052465760285872730129721006581162267659165334189007603869398512532110237805289663088202780886871626927567022671844454250649437395152002370856991099868441496695416781459193716800281058408991969839283308610668193598745519802199901549264600958917042859823006580791633743677357535723616185791525975941381138981302694304959636375345589910651258415839716147305455368935865509182672615412999083965946841660910315819062404602671014144848893038971219931699432666397680437726627999250205936309808649779069670508784857666850170344316342401647572910107374346952259185538291232883986003018036405526010813662672796410455379354241013388358972319636056893456200322873158958150248465083833176055303236852052466185909016804979642778744459316112501314023616951895092187339505633545809052822809273119415946325571528879068567729163430325641273825477564300403483636340736926130205497693943629035605423380921854027647401483761643973090829086251401401858542027333485549304646080520032752323712904116254733358293173600980824875266509657064112826507257301803285488474336344875199042676234239472694161482060279974943052915428399150180498158176121879418988673025962755974815086096413689277694624821919843128383435689311476357500700939823071199051196830413923973095259979666149406688505884984977872414032823180953056323156738702857677290271873398257239330541528565945183744795290309046916253446047075909653678105387109235554789934635171998262882076945279913638347882031303900549846548453637256474926281386822127441267407983594708761341794327834332977281577528230059002002871155989049452679138019579068001306747539735582231960242490588070479528088446691601681951756003741721341006547747550633643838589803861224466550485692965418641540437226957015837377704717236670339474035042380330415497343110786669251150334204370989072501807183866979048026881630678744343913733401191079138218996061032354401111354904742895040634570566011130532858318704987678603914101471343317665868585814383499128643555660675895172274712782615627083180384563051682205750915342568973111294339436353045682647319011545500271451563758075885803472251248162784489791450245046925489182153195534253012775648975711762521797348525090026649635681754783179667378695509405606551165745690163924073424333242296391205864298307404266339669998537002205822357497532771704440139647764781185867720065274631080812740274561939098892284196984399891623875334779838762941748552137955964900250889322665598919749253030883159086222399396942946100443961920833211001992756439454861213376556859550351526848852464866209884516577678208711837413675268166611083333608446086698265080150494550316589468079476209853075855400909280840770306411205333581022037282678020520760684126172821772873101604060914717768598359147101873351541894105526412773424810698504076068199368947411409813799717217152133850047649305800533689529717216097548931870755780288156156684155012975137040179036449997765968536140517833619871921593842056251736734215105653904170238545695981504061605478816475529681423021520803410135385680791790505719801953474092909058663516714465284069079429319531710015901103095267381564480036123177503181905154042159230671885903907530282727356102538596315059605043891347305618679662744170447227984265885668481781357118585053724085869781165078948545373268444467424184473718588909046164267965665272285956671285622229599536478476682528295978464599421719219155862244959326489328602425499022818064499201240848686482882330044726208391494554573356052638175509812206163446187384883913258652118526758966941277403380354710137660423456022371947079425476584769606371109452263637815841591030379303337382722770807344580564451906504902100304715269263211215347823608702102628137847130966499446640229086399753610676241371217691159678602287889231121437342468029400734206544883259639345858102772077831260368059374216412111359522990900336544169885778605788174951134330322890283725274823684865752845960325992638179994556171182119013149594628935811940525807123439899720627041738814733056587373962647499410380563304362169648585476778835285371271504805455722351797214562094620621656796421005795720554203337548646199217895111414753208650478294865620154602262155549871749004519812980306283315694594404916669167649059263147093535322473206402971123245503461073734511540061130003555885341107554887706571011083132603246501919250369208195428657596790829578039002059852686069685757729787347529288276979444444859557137211132097889266921406455409034115991211669182868679165335750692330966001664844948276060120568271266787904296116538451707003642696366224350794877621718820302836359465500649858708549121832345171598526906442039236563051654757803336209640840800198827371639597404641858020802846435146951197789701406483942751259746580879070771692222955249138758838593035223361643166991600635859740270058278737605573852128076069836617371457219803721128666415566552341487649550235120797193747116567674439487244057781299817738292841966086917808468403832302358839757617201443643311206056491494076447465564969369868761433735101283030448201462934990190812284651377382480084993656353525427495830469130652456501398760247486302289574052280332603056119816573224880989156946814885465633855389289443930827578108084620271415231779283272810094677633402741530860411862255990308717487434807976179005648438615912410971545069369949804035777756455505204381429667145325481678455668520338687445604651251036057546075406474622674972185389552272813498850897466983597093862727758994186038717486643086869373915565566835952584121096687425640868944231992938244246714121936762925730147512778733698306398884440945566220846011445225496126388324170776730413311889900326492065575708749079618756550590585314079817487737520278939474660314318894255210555024178494457199971019635672064703593092458433469718726789148645841599868200200359324584637406091135142142758615581569103458628885872324528929615870851689832526002457051037985989232644491677779650717018940989575869028639972529193483411189557777010151544478569170447354106126752940651324694039800949615079196925946869821552501425868737007232258058617556290892541045642963343920184091146560959203060381478059571020593370884169140181552582307730654414799240948224749114177724865263770842180094447997893282889212082425398755280444248183161248276179251463587988978681339993938635532310864880335224194611188969141076475799498154266556142237936593489900710834037005923002664431474065205978390231497200124568157961146642000925111953063628824109557827137003663464631569251088706127963934770503580198471481704266705614975534061628733600297339809431831223594203973748792790295625938216653541563300488057368145946435624173144428038738530270679507073104810194972581898511760590291705676293012913622781939703011964413503668000287145041783381771478760874143007450751179134304943718022398398252171239280116726386935379240444671515198315672859311657321480072864908019734933662651224162228821466249874853197065062237803570668394994507034023705908955260392559097562274799526337373518746712639516087998162907422522621221246666242456269175974612765681161476755281893065476445722619224763517902295564231342213968167917320392052408945320565634204752648577462902952715947539677045499240525360887961642128290982423718480178826919030992124193554502193565993991566721329292441032352424779048550246969881818258605966945043832531736298369306830725150974465016998452741027076058715576079068110852365642997222867608593399391563482296734443474106349066438227247519946375694428251055329135827716742522866288770491063109714267071271372810145203273801655990885420388062347102060681593422855018977199625943653296957301174827353766579318067418889771598921769945146802030864499686901275711824772870663975653873092206767669917907862725722967657241933335331869200469107614852488179535970708115998559121630196514527486255995650178047906437012950281949481679391840145384385317732819668580303187599333782958700124551244963894276872909765526692987022554873179432449995334379339744313127577904458886675686919637964961396458071977482692608119818395208677246756639397964611716904877715747151508925665195783846820893341412213871741882115435356623655552914603792236481608549031779063672318749291589188134900854941103789750051913263047160988007327934677755887193850638416855311826613866665918337503221890365481039042681984127915445429601065777561500703505312938454461359071002598297437243970820982975866840194856532124041988245834059045114658079706435710235194248877388838773300238423809671365270545908954990977234113514415093786250453760177380001936433552639475198704372916181232047616527579440874578053515855153450711269692502908553921311616548437686379097957313768125118989164359689707907595037342819000832168949826726905114556037687945150181905244774204735640199517986562427757405363390490765123663471479844997067717937071532270295156814818596515450786481605171382295843159976626413932010106598612477560526680798678127379660300988416491313266852547327782233683529795336867208365451755565100080491426159904287788410795594305590321798822961709092549818683435025848970744396880209982629827110680674220392972843475059119010265158876725183007604706952301680298652794026956976048867408045215962673259237894813559811435775088383857593466016316172467414080922198965547441733727146563034578411358119394489795207050824015547253674527904496053684439320071140890030529224313994016153851579307337429691606491240783951304400058302595093809956657502574867961907686114162573056983743731024156696407977621206482177026327185383433721837735097175487035350249341575800468979010467736300428637706222555216586048826760469509815224304315477648232831346233487899532295806279254152817379453885830918715780191101280292721500624025035397471557185093867999353961236117161153688541076943312628543746915027432127325424425025625646977684652529341563290835747169220020178473283648182301470414463549302882168036071700939102259435565914390469278648879496316377049538319644278901130044879388557774183194229266517813111045988145869832070082662766042747782801423179517627418136403391205132171145050354660707496610549785274876339170189654305872496611683105748012229024605650859606191993560948423855726315147620440808505782804598050702438898376396738398821953887817508402192542414261251446032045292930341966908970105074835921784916308807489332178167833788849395217857111973979393503629719560233043410033680358180768052890916989367548190685434656887346738241052054858326668392834537073473186935011265807138922597875903514702239954429639384588131730274928513277971899654129067001883767773336129033262915288160110170386083311302747003409500933624935707643552083183047252614837265587442229483970313592558269949569519021833433519805791708077161934259482702416532485414608314533964778285369550085130946459214101003894671956236643797400338314292478023949980371284693210347159266364185462053579892400162075950874663116529423984224906699118656044060646342745526028315458197669692975553112848366399858155857154228033201617276499146120942787001788222158262133308185893215568350588876641294026332948656173286011076828949945551623003560327808077237485808211031805894138370781699165466065951753055369668272134445181164019356933234219536217406475586942564799889715404167098039251926756027708967544376062896059108488343681114460097184235700668481376570122658339571304666243018885871726757038494634722004203486076927176757043149302648885151093636418500936222043218821311930466274781051565545105557581739281350856012890263520862558998449761710472370523348891706627446384854050820093329322807869825435347016902925891623313396804601747039364721774661431152383666427627078750172067176436836792731775248212642725192228124557460421694968030264718787428420151477319662534617790762365552206191232626676716887664345958711868000170088809041763877657214226318914534969008905232141162855084267878823625477085020237713551912191995043439388296240816631891363376100156110873768351985613906544169898290391740987463357670046219745629096668376073430928936677403860955664131887340785004488280123625363326551280969361357190133485920448128484595218553758123366179447744294264237099810016404800026240411147195624033705847775546111393224582595691976851931569755410499390223227316594813935381448129431744578891567807328923238202213523949845690331863018197417623602774564637970244511350388949953807960154842430781319228465545177195869303812285879875499657074195778493162274899404844207415814904238715158862540483597634575615947520798104686474970961199470451318810541659259196843015501905729422400842152206196033595083294363770177761069032328589481941451442960160010655897390060733490536557659666600790852390754647909966921954364225915526722892838882005325936319815467188816209171843335115153753707918128543442065412625532917310534708691109170664331665045002721548726443271099737934741043300517246834560670435510962836110889311366662147273554919657631616216227581404943229615430621295095549750186108835004924824132968523747072668187500568561247297538516318435111336281982384031334684676588617242562626608386341322384349827589642281891350252552385569171750375781770502832575658904907863480617602123847584354028163099175378326688487883382200510862599223777172371819426595331351309341808633705759730139973158392574014002646762169167798203995001961036754228442942486780267788701765353764467838660035906157835031256742804346566846737687428220733317137074243381112445173856400724679928695986316731033721909132354067395976562821067311540174961692374162037703411355465899438183747915675885177716053844194862285285742989728328011353393693065506747014660188626627913483343504115939426172921093255387634361424794410777500286091945395788415301750764965603654086654274106335961104673367379596282154830737043473821211676107714840225862062689144555744949613805363173935054759732201625834434076163925943693516620889663231736280249402729654058699516068434092188350840997972941109999914581857331970167280528626189448955688522213545124853789171056164356917928406161069283644034823409068083737793343673888903860318896331630952740835075670195590541500980542964170415940084327104372257187406278139566967847364166952072165277545477013729811291737444665504481910101455660437562568412325982499735253075493761456480772790328729598662555667141588657867760568269776352046939886171694417569806167370918808669553848666122898739692781807913870312161806626135902121802093855207239717693714872646070651753055532384211536692741823856463849737744726020616369806330589951947455174475681048165095024054401663928878292332900426909484856004422522110786206443841607731507834102329188089112168350416087440761362076542146601048513346226224597918492452353075135836249138101047385290863863217854677051593307137879287390561826178900647790334444789019027753640247899854634273073936576257169655874700122765583766889376556699869170609094479294687745393000736484248947959670296157446995595283224581544151167103570658995331887081556066373419966808178135412538420659817816643004936246291595664956827662399908897594984354130248081137528087062227129292151788160101875951571307312164654270958437765525479956544522996165988712059532797162455380730433695804864513313010508828039175488166082325859746675659281337826341590954596962630634083224662860527387978852641641663716357188516238538494119979004599473634978262510444615549645755152789921125958473211673896585367198404246494372478726754075011242368062791695928606419378290365861069793820182710722464151896494694199923233846654257691719431972641158404947896265877226160342500644403865579295979641237457087425402773350340743113371414135770844919312343078989394853235849727344607000922907457493672552680062127982644663003664100599617201850761446538425902829484379317217970956827115928090102095456343230934930756068850423524974522350516856010854721110354432468703953671138436821527545727528500876631262002273411930843100065036326376142703805399512957872450496667951192980989555586111298169529695692793210363726903896272268269138048689042198195771023688992608944328461275354316233230045956819935290715948418676167911322895446138825179409080876204499402840271754782736096533187426340133971850493201160982196425107729176395883347756260384828709294140342720263211544336118953106898340069182545994773752633934098218852031889243491220533248129823734678250386494121164136749496616214633749246926623991129947590133250803126238320459468273714390123224410626676406579446482011216233881554085006932033078388701845875081429883524057810287514682273517834984147196042711195506583226371913324722315208101303930869134364148111324490462050943857916998248405824677171523667492347813425251640434877213539147294741341078495075258836874909430891002118022960922989551521867665026036731036102255554801574787286101343712485288504756101914554800791154012042048930992060490317458568374888795603871822239891419452430803248401309449964403482312022208515131460117348307821220245609044217626402135428394655859751454467967731677025799509217398741398483523077746596640371449362645278358570613811993718422104853588314572254290548236344508749090447626589780982031907531009678555002084532999420122977496003876119839301688648044396995838394683296912445627225794849390368200750097199665984141055258439527118512697064362392358114833205825771931231149496596682401012363665558789763163852827880969462365765433499953546690621242998223769651473977887899313029898006132427863850994946826992757227560291434884761915343479331390890189572072162661133565960770593678965705536041121410114936049416099342430814483027067087647622607518944594412492234320214927407088123495685573498772516463057750554101774121632064425693233830413009601264273932419363527943250461344915619324980017908706490162391100511079231944007730716490878592699811078759896803566680165899182840033161078242503428008361394712406826208770581608384127086097148461135660715215383177564900504734722343718535912851206682680431310307323334280893680351658756053268370954617489262220093304502956920724946127246458673405252541851906200719146296598764903354137432246190388306456439222142110321479268331534037215875271129763080898438777981053079810712569409002655094358552110374643626654081744381437524516415982277340213611780952753214850285013512840365695690964523234228483796755899131637537491843881303546921784961744404808340495882348976685360305994652969423301356546994102931686376586878982696990801510684551705180027038432164241808758951025021428453447779797558952705601304372037429618429044444191122658419540664096617159350937881291863959395926750275129352874767837182885082495303721132215389355559282634632362157220476287672272046860403365020035678732056795638672879195224185069001728558946192378917592235808094429863744419431818167121607749262176399645001705243482889344434408802738085369892078802377110102733714080857859933566173026390692772267646836089175850794989655762565312132665985645164352183677739475966653936912008166836928121141037942947823419326709789402869865874043571144099265830527630979672390652874495403715084771119242609734296104256652877963836300790886044743286999731416136511708594602280743183129509594228184276973028177376426012696553919769391975960821390945697004861772638757637869101618901093086144339606300635337622720722599364993093521488169252047586798853878330322282893958447297700214898261850090473382821717481089092653536475597218385592066398225665965907461359653836584172373839235645012818508492246008734589212808093155988681243070511827905096251840778100649942408717158165596478638819337853792863286707104376649470157709393534806805267310276765523254165242610881688934884946289249218363765957019323276798378096709173727350447962355222010138983524342355318180505920977839118616351841165551495976021502212595638457295984341842479870044374787968464353123965449959351554607713112176694237311962263572649068085783239390536350545565106088642293143460734356408904683404067248234174157633436435986180681708194678004522774817059770708491177234467772270074420497567168572283330756121019597373194517142055322772546658514765444737275784927553405109976422151483284540227839192808838558670530915653451455037126216785993396081943096183697751916294572654803323686413369607446568090073228814506042420737006238434777679503080899339975631532811952597744646422362535543159188792828364983306229319255475471035941705405743613662664991239608141267880595427875032215642557312139353819912047380728358943934751304148762471670795493459124713264262241190406544571523479306046220673834648659413467469005719901142620819251489724928118643907406613678228722142701036208291950850236783624749808313105070275962890061896446786677909228632950967819980511891409243422388751646563953993151950700078979255845854036656253173711672283667497948975483517651587909629679728379705906060485662073853325737169779465236471757943790880607731635622563120135750876344099546570339386257120134072125407936898055139619165189915488777119920349642062065269801591002824514656577120582955051552476109975944489912015191209393459120066139256849869600538730746116309420296797516790713130818198312046031107960686444433294988445978163182437234628527629440702668628396298233754375167069959393305391042675953967502832453016446974781435018047006868430818954351010771025410569884619810096158704876015341544395750999007351903971013085877876766993616063920842386698984247111393589920946445184259941912017895623354084174682606328215641705600586099376539086124309715529861448051571205939883086970148340936091767216175716966249643809574344721234522646568601170254413200310920302808638276008684860149076116176423904193598472290307409108342482893519194624198066220097127559563948572633941521387173465792075993076174374573173486148557746436365572206351219110374278634583666915992920507012588386607588292010059255527943218399136302588647718236043873002331988124305661381938983043059496794723776112662245992642545882784089358725701802963157191364317050119483815916373220531285964292751791872029162002106550435258006991345766913072395525878319293464479049027433037714261286127019344410333912257745264118658099447570491243300098830148264643153447915335624906623105954681456258778211772106357407257972510380506563301838150121087578294490896943625097599698261101296981600711823588038438882929302012060852866702590981131522233961266919548533055752039777240185397085714495010637058191630482193790774565003189276357466089581991431352199188612460788105862639163865687163323293625230426071392638594464841863085710497841237752165111791849420887658581323734775482559199987393829118521393822700507741157300092002595890758558529981016357355495086533504947499214776505040358501036765202246745441901225233160864325203899509816352596588335709759246042531011886997323704022430231710866718214136505934977072081828598480273206186869834347252031200845562567832012203793217938110236037334440513023810352654749208199988641692843115114886766055816218824522779767880051020030030084518315220085304349307889698792628481781710154597739697995305919650598196339944469603789418520718050829273266853082238898720252019507457692615054298238384159316985210648871450518894930190638329513623624773074762931533630874163204361193512934409344584670482359002603178157254874939303801997102675766357217257245671539820319471797687064130249505216860671428537038923340874240895265500463241282365875737445827059466028330168643148653344127180004010824338498484141442877405531023029070123553661659892721886567918620892385573014509018851764699876886224520398601078342180625696801641689053477394310480705271203705748788267742498498642504329639027405547170298994140713053948069222926174836918709036923446149860850078133632739032970112512130141335995648720198600774206915554669488768528586671399421658610535504430644378554561459325547289770427941997454564654782162967002144906578440259009960649475593841938388644061257586491237693086774971038469937540100283323041338595937446158049612544828454597780475456157047137730395618543999968495684627411520395307867700458194546239048229406830834554409693998378018477834707914446906494438779086584882789784398479852571653851428989642330983705839018285518442273044721775097760211136099205343717184959045482052379992583366614083592457924921671723775345184352764645433419913456862097942751585236474244067393407099776126082228341755161742398285059485302587768149842951093173127317023104885662657071634051813445252824222902787834855800701904067697950470640910344662416244839140523213558107653253280555101870407595302364741972480592254352723904732635365677339778199838875575942909854952997055271987311441763062622476539914306808205450823970283171035090112959041657605169170405766414357219921448305249699437975648400474212780045888416586668156557937549949783123464855361938914585124909190932104746070624991561103898339513851589217157430668552527162222390556003885682963115410890957824856753385922722974115595479386361598789264586535072203559764960917232003817121889073363099823802555367943685121681318670899484363597990876027776474876195821552444560616030362419838021567295546844525781296124727527014558983269782577625592235924845021802000038560600972136023446123873335865979459114016783944919418048467227498762180586124310274697333296111361676846694599209418220745544501569953155189064887613637061343564305829895520326500572679070749065315133582367345096091584149382797784605232545347167890471629455815257906001306594940650595245016877477308732131890918952282788501900674491275390259512700795349013848823232515143382539813898084062058373386684466517166671916874853303682670004109966771905196152798124429505169977925312221177244704575859638169913817071032558937441238036622262212099816404032158045841713795778009841876557242839402400269327570612507796352517140779207641443298700250038159328111010611759484995731548636539083231387639461739996745619705573758874205374666753844832337926477074311931531657879309221893941364470388879643264037781169944721141998888191672806768257441187224544149243589625234667875984310911037010531207736678484795220502663034859362516943916463467397365915482999826897380687210963013244183001791308963087349198637331018035238108846927139638354579170374936008544353852779512919235827446328319206781719479509362076131319128520932633114285962476173092518139193274431828722455372096834150438736187273719421259548491115918760659125186139948659968527233393839465574769739863584907935314196842137305970697391710286987163265899803056047698864488139710716092306797976930724078293029257197551346169434422456389579487576696899383965185037099557874828352570336802889908181558561995372052364649988182711088826844756036404616419486862318212825769954508631261367632624477182922887051732241068552783234620752391933676557531307071142847995750637149798866144492218507626342434528427282338253366918954103473182111064879114616895467784914421978399148193705908170347034328532700806470777952109117489919167234599474760076236704083399136941543601883717795051930384361995175632855613274552104838946287284678698985495718682608039389902437639973561809432207858068032453688342884407536650948803395629368105073748063260260054766068529896768638790218203681634573266119516025228993837137743688815190451016780345725202549655685040720924385013450553426994229420638600804044175905413322643929815634340270283473570717526458250199952619718615751258596542461438233232769256531858882099810413198505063676761969705305156217079868526919611307420450425734100068565984834426474473162882069487924382067181247503537961528580272596371630898680111368511502481174778385817001647201929705838352058466956104653959440286382729497549041686685350107755446480834193223395740711012738839072670957942893821769830076033201992394461390304595459568314698959495985164015956594636636138894716450394246346105289927590967601450338079027519108808372110057424779199935769758132155287658002412762192125141477369541098724018770127596816156284575460273350296764377046356639755051671211337802064923955325534969057429247614451332914575869761958339865381705673969569461195982677171546035443837201626248937430379809741370296271001978917038465535626414291956163553235293866798326270747560009328502475124206954217051797780806865288127284184936254586359464395500681343589207754650879431591995079931182866247716325779618844475255149536330062197285777149398296770849504717102796884744761382403730823089667776682002541776498916282190737233660564502780737024367449663175862949912758711646226701363639092494311800569841711706373644225840546391480482291322219437709242494949389772274664265502923871933304393128010730186593204285892748016212322139180273270258990364339202510216953772685614438778081124091327135252434199837097430118499918548040680834382457031084861176869922550354564819525692678397558149339641715397359521638764521965070908236807696636266575616896708744463448466648142897889576288424079040381948689872848552602553576283360862275116888966625146048067281015661780019169049298982459293409142462129175879193685704511327275422576342754597726352145637708293019196329713579196671072567329243757294035506569286508723078203652570195515595306699134820945626666790223070422851601897977109283896792086531645651736093277092197799987887169544462288267219156795275615127330699266013466150983183863706811577779310364802739067109837832257597777089875265743377681539060704088673264600789265794587953616586190646695898538279975231361376528920255608239231069103648366590612059865396491215771267302835046085526962188099724406606264321391496085151351744022696825606623674065448783962298429859628743940004660407532249468093122756860696146121369427505727440417141730580852392713075095900950420467142241731061291628517061010754547472671337634254271954728498030602187534350398712028540415334150830741081823156983188359450979721385744527853489434951824793677165532195112574774711054690593284225896394754005530995913832125059024816769560969608488733982337989499469648324066118864305518254623478446454656562713970086421804810076005964108041459738886835100453771593559807434172557008865178776661568340272890117531565598993592360613911587255998370876709202056891827028935194052626741051641840231783783488667333212336195476165822812162493568285425002060728041006853401637114963896472464721314704427677981232970107361260451867214564620385930909754338345992020654594309388475418360100402325317000335862190086163884906036607501988002446290248804162204179587991034460397784329541212434095714596830342232559128782025138223325666532733381414389554240722947681930331836781985884626415416397990900181420746086106927396476230282280072746064798340684150241440281173903090278666805639802332268933885250079154236087707472719830991215682319654123128466048255221076388439468427743732179965842295408720072225515219303213365855751379474841818808133067808039534655048365320495691805618199413941137406160706857917590045104248277538896782076872065344952958109185329495211186133881146657140286771084142379108408603315010088528611413449445738245547895761317606171178694526699100267270168419274283386819346800771569858393632139356684485551503771418458279519099541422687712241865234356633313855378129050042968932442175556417837180685838741557722420693106386747399488489188464655815819316820094900836871933349277571940082903963150307218495114700518549625719880479880492135611093094728176149381473733056081054810525776887117832339998875342611189699080635748831144939816476823776603529606664796109490771337331638675919473064321738379629625120286977330994831875688022264537299012901827702305500849029866472000837426512187312383565914936343162524453373574811373307392757377652101134087208657149199360440740112217081586556490856600562729890328896134606859059780093617710131774191797342648958185499708073709664443201368589086339518440796620388546076453830912358765826080493395091636714424542717029858855751454712521985216949112467689374330492657998780939921219848832382021200062536104096240147178298637860523623791955754212445301244798833551981103612154082221377954917326891193250078597527408771758518206164308445902916827671346042537152440888607087941992649538438117263356089832439133026554175958242447545797820344723524093513145428613250628275493717289338685045815222801276772292140770254783428404855160086441795663651607097017625775065560351198428693692695657336791931967154793328203741580859938805125017159380166146459279335326870718709104785421791951150336266851950499351096614111633090207046975633453838163991561956142909739845296641770456837502705202218969397033854102277735773030029924245250361578667888212030190396741888048960442580353703544035649641202442815373527221446441877539501620433267178800649053409789957555926485881362369600727279637820045921140596665131203404657136651882142409395232754904663273510349112643224555695457524572018942942714530478002076092243647639674144352800124530019354050665187012343050772010511216082686365573087276248021568718651332516109933530098556946516759049173744670006827287910405653154805333374371961070801490739167930889659904480425747149864744445228598791514532362952965585787116172650328203111989110988947094698857555201990719311160567860563153177625963556130356293365284778338220000111700368135377874335340036383936762406956209307092919059246205292808764078505178019170384801896183422935556965583000542572330365561815604011210855934974621788107315293806655841001958985599836508418898186760381008976059660674959242165720965369016366403744285501632213876747728427916093673081919952483548936026157697803911976434442459506833096247108335463606042545921166928856465148571853062639962313482999575237315476835428736688622708591690305031895647281378589881033724093040069606907028680650857073808782730571010121069854170261508626031463777811656307377249740750014825392517762757616741441126378896662802501042103148274550514410273844162027640756062794078205237819208248997575718179884541837267941027732953472915211697240261143116155625208736280909064106272974525862980122280260597643697627981469292715125962924990900097882092417660064510198265969156922283894576955206459326388249704777478467631195380390329475682968664293285255242551537999121900994554177137910604294782455685235436965495430069090962217433013023226446698175471132262304943241408527078186788360786024596501308721277047665535583300295506144657734745909331606628022906253105112173741285175693044474519688428048842371260754873903563612161983248041652171373650381441313061066075807011092970862936450462735936241289589599863344274265374812920033785109114179243089790109138061729103754920197908920205534313541986244180278007548185040089606104717480842523262457453386517180912096359328593102354084224722653087894078653974548088669315024903419912027008612238594933933754823014124599027730994373453339885627695143617065604490873150006123695202278150693583672522695208923148482334945330341147740706021443673778833167888031644167740797003854844132744364333222899289048742407867508625975225953057770947018720754571304817767689188340293127054373575948289867682863973276519402616763269500585652543388388150319529170524220435688301293043390543322244748096715820171138766518913393957528580469914738998159164417653657902298023125379166036674536448385733544863049694483490726305806434799286685587228925266605494399172255090034954039768885192183772962117844749897472686848658389342921308423433986291853932105780312236861965645788632096564085120456129534368972268676620602693942543267675029102643812202280910106996970640329715401040201201562124849641112009174236540652443523334353473543875407707518506651149210486550296652795866170655255209762458213627100656472415291156561064008813301695284342634714901850410724341054172347923479033850713540267608959007752819075586663161478983058762296683806040999435377793304236367081631897041494386734209100917388355236379506659699317727483684403792185687220427539397189190451252526438482841094827611158027062047537306463586441022849080259845796434045033835454404099191086296977925211200965354947729871715339784084181160434615744049100049170472411919033332578721288191099377065973326726446771252417225725791271984289242992559140025947912551320400674369046678312866786654808081717763605843216165270283498943610702512747901080302870171000349865562595023685977664420120559223602040863089642393029364744576408247015283335389081241544216673884087160327065076951795126277643646306787759647085759087525008561186995192340329903019285104061070720935156478732319340790677824621950355704096042842104090166478420797017567076527224914279236993588130078594853698393396371355875151576835291452497330526740737108083788572236518222350207127821804979087235596023363995034375377739030987476106997101911543588945151967220110008948267743301563591838438882349977544326163756979311914519040759378518152017588032711594207010649004442149125557187180666623240897328882869781926418038236284365885963222818370635779011851708326157069609897087451990559080049512828907668490253784314116196245066395038226092009757069542042356638580842788141341022295312180482544220719506614502387089645884194075505342788173207531306793374658132196771712960147836821837473401868229726694658558129700869472382588695588866299642603819764835816383634489147255701617617335875944452154675088901483402409034504755090585211776720019342927709511043534019874558200371011137618168019729321768287985886270561902632605852568950255740054887935823401496617192097396390200125557030021908717649669873640822765380595738561733451217116065254133070726526806183193000519955367686090975666117032807870604160657408942549374229445097770788845848191603994624677439666108916408452686965105699659902836418371243410358872786502396825610823326419996730403567284353742898173096208418943022940461360623175831382129063391705102811601783641354675921463401848675937955781032063386644448630931245323555666754704133316098742141640655950168180905966925719476271969745118613615648753813706892905574280401701070095295048161030813128207767887995928445438061965334955895949375951692125746911277397860502348820536915278588296248594836880932965154930069512505736770731731649653134718278361992319636799833611203087673788742048696952140639423652099303151241393330365793169126820990403862794929886217859194355121929801765283425770647037618149216574790485009300168455698684285592635423564615350173987850210107843992283285297449081312036820462781485223833933615309440792754747831966914582020544900863247116728493177752782537471978502065177831783831284787700254250639129621603275270549565001764644544742682588801141993251117892270549831559985841240388855886577703154267164875585197655423571670480035442955905584519981838642529767543753768853363920550799781917121882217543557971142426771906055814737348898843497747876031203580917020776396541157776192242967488453160279503891839580903465422217234079700379961259759909919403744256346846609961138442284635823708076402851040027138116113680149960185171942686610858398338869865376940631319608506260067375506282175889174120766052588915110684754610879803970751484060392518523146793435533742434014443122008918952045674682994292164655996357567781886251354306737574489229121684398636375007875415403044763544922340177056578456157524129435818853996206667083128334130553149370790896146125684810282715041665393824116441966284615807232680977969844859313349486121023937769561679484781102684399861242611877887879060508594680484787247530246145764380433305195021120045756355761115131573149076143235218874220653662486237748716863494488275104275703233456621652274502509147772318687492733832076832040175134769781929150861206561471085155768253240382721346083844474321011986901642240434408205621205584534922828457392165954963027425488014190785682373199502297610324846256035754089491143268132422887362006165159923983167200112673238206424942528195581082937121191554308305788670836020076555326048276954596668006963018673823162250139508276035009087953692114169175857978952826317596901865042999824747527250067350206612186911300450626098360685296012708198922479181806538996264415781665388113286891216016320260911531627810437202607371496216764863819321258443042617644190331175017601477723372018203705727318956548575676029205540699910992522937388915025247163338511330616866560089092520984322947336181000856264148492635062420376430573064819266619441237836043438849801935726596580503276619350750648868612012258338095668788336582386378610473723735616741486570414190431592189831792353095596097962276317502229505597436352383475159860218846861262513114777979033380851531692059232288140749421407381920444749245468672305073553687132266101483154153554830609129589435365135064478029826485841347089676581618121505887464819170678999086100282594985105158823114191807922050594528447008922276126426921556242379608447751037934966594356289729462154289171069002838690108961161369923844903895309154188497111170878949389228328094389875810643526290121051877449746577235906622958524490616420650658654461481689439357919595188442041918223279396261991129120149922445220121794458393963522177161916645795516196241017490589632467375330764655497470680529581828900037606727454629340934921064522953324125757769711622084980110463140229940120205498073159801957118806222533573795482403771758917690565733039210310557276060467467771672693420958509368323297358649379534844773222763972143250160284510560725243853015778881722408402172835845054452628751999804905236469512686600412393768648635988630560950985283936784583140319376672266986454239847221483023096218463042760854406487062027985093577273259679925664628609333182889712287074779179393447742283080036016854905951164297217902445708611298923870252796733549553084491255289109512468995393829830887989647928084260567720364840014412382659968202816798110620417357097593381494500674903267234881450848757686611071963761620385207897034038310488555952083553929805410531431584130495655702492594277250882905051377409306078985361875289262692696572069830228094937314576679965681632765899141703871419771978519121382017219604561826793424637392903430385817784518779783575117086010231072630537828125281624919653247124690599326775827004220657581019726414480994332684834354974943674326742418895918697524846656074243647766961263038870662026663533993445624280457092933840913904568245188104977815206954446836711494719411206793379993086486054825680937602552151684824211185548469804185616594503891167733199759225433767941820369777073405484767315640568085173996169420127317207246755138002362521574291873139779791533242496127242699132558411403639878029222792810957397944228306574419086513189930372478198568033299574669297186807883233743938359328301070384725043529676997557349610512769554588776573185772744719838261667267954352956338960969086617771884922450499984188790370000856610734170903726306810911887442393088104778189932613242847725936314224723620301422158634008993143073606662222515743472483107342071830351341053091374617740463984915241051831762288595597378070441628013929165804142339883856205818094231424506653600310410079154656840325199667299820689175825896433457907658459273709321570913983953800909715261231487527164036304276904623568014289253939792396787253021662387281847889810472100429086003769172917330887257375201968723344140735877104238855658307931623869010582750213413840962623653022680689657742765367602072798175182624546095027463959352152422228956315451199866441620868208284541370353941878078260739008442257034065029253415986728443220910482290730162357726391133439535637134871444027717984356799826625911229807818026674992618281490440691200828831135967361067727824597303895703728791652085739516470038538714976975462514514948297953611535971708364896344050289512665069456749587505147673456687416954011942114882015245449527456705501221309753761290217737136974673546819498676157208037009467598291969129098497148305731946618987052926951837697761489365465129196638233427657546719362537664482833561469219877775647873421647450147736914645561910909581996730053512187761432916207499371038719225647499883884045074112437550615275326689095187706544361843736856848935186962983839222798136850306309761018069133034947394709986810181965768956371877199420895083893082818986457580258959501925417742614469581625115586949867714574369342865874888430201810267307208251306738017046468901813902492931919987603835103410652555496375413933379306270008226576711045929247971690720486537690730269045549702243099239844412931515726769893450507208818796723250587336729971114244891339996839819084469183134073634012860468720943864539166010321995226356829663276630606163638935846213933185492550996660821914079199131148366068841559416715121309803628108389292283496725964186026694823984947266965094959465528874287466953664737184583706354198112326741682118013089443781110803402899741346220142817309508520460538927877540615267938431215763170688596593307184763196775271856107468045818402082264544601807588076673160808248666449341720637564002368924663668607906177633536140306762970741490772808698676103659611640614855554928209045625981236883047500344060443061844425656850470162680679147535931723888934538114101761579286967000224372477754401819528089176554620744969862598751477390283451907205181421458580903463466243364559049463398561415393606546424589041337765634272381844556522694276767282247948003217435055073557393854424278608257013035585644534226288543212893682718123202999651953695739698806484999733504418439247965755794281836157626029746008201736880456115131459547704626542020849295301847469398381011948389945323875337120447709244917057415895473299511568790693658412258190177700182088385425669926843301490759042289919011033444066191567276911925036989481273326144240137115650687092005426720135653899668927648057464793525020544125436446794703143202654289622380187706296260370635854531846112744655253630593585834784575111489032468503013137931202045856040750532837964573748584598835524724202536100583880552500386658950204479697206059512484347069117564161580027248191559403657568839220850951893888726299538170384579354622299235705053909401242897875680507684538173700800936485826541710544707663331203216981145585897133801929205910131321833328209658311396913424354614218119920624523479233840146797048748646089746132079605766510003692773480026593126194354206278594866108780235817590646551174765834380543929352927709438977006430217 + +# Small sums of (two) squares +small_sos = { + 5: (1, 2), + 13: (2, 3), + 17: (1, 4), + 29: (2, 5), + 37: (1, 6), + 41: (4, 5), + 53: (2, 7), + 61: (5, 6), + 73: (3, 8), + 89: (5, 8), + 97: (4, 9), + 101: (1, 10), + 109: (3, 10), + 113: (7, 8), + 137: (4, 11), + 149: (7, 10), + 157: (6, 11), + 173: (2, 13), + 181: (9, 10), + 193: (7, 12), + 197: (1, 14), + 229: (2, 15), + 233: (8, 13), + 241: (4, 15), + 257: (1, 16), + 269: (10, 13), + 277: (9, 14), + 281: (5, 16), + 293: (2, 17), + 313: (12, 13), + 317: (11, 14), + 337: (9, 16), + 349: (5, 18), + 353: (8, 17), + 373: (7, 18), + 389: (10, 17), + 397: (6, 19), + 401: (1, 20), + 409: (3, 20), + 421: (14, 15), + 433: (12, 17), + 449: (7, 20), + 457: (4, 21), + 461: (10, 19), + 509: (5, 22), + 521: (11, 20), + 541: (10, 21), + 557: (14, 19), + 569: (13, 20), + 577: (1, 24), + 593: (8, 23), + 601: (5, 24), + 613: (17, 18), + 617: (16, 19), + 641: (4, 25), + 653: (13, 22), + 661: (6, 25), + 673: (12, 23), + 677: (1, 26), + 701: (5, 26), + 709: (15, 22), + 733: (2, 27), + 757: (9, 26), + 761: (19, 20), + 769: (12, 25), + 773: (17, 22), + 797: (11, 26), + 809: (5, 28), + 821: (14, 25), + 829: (10, 27), + 853: (18, 23), + 857: (4, 29), + 877: (6, 29), + 881: (16, 25), + 929: (20, 23), + 937: (19, 24), + 941: (10, 29), + 953: (13, 28), + 977: (4, 31), + 997: (6, 31), + 1009: (15, 28), + 1013: (22, 23), + 1021: (11, 30), + 1033: (3, 32), + 1049: (5, 32), + 1061: (10, 31), + 1069: (13, 30), + 1093: (2, 33), + 1097: (16, 29), + 1109: (22, 25), + 1117: (21, 26), + 1129: (20, 27), + 1153: (8, 33), + 1181: (5, 34), + 1193: (13, 32), + 1201: (24, 25), + 1213: (22, 27), + 1217: (16, 31), + 1229: (2, 35), + 1237: (9, 34), + 1249: (15, 32), + 1277: (11, 34), + 1289: (8, 35), + 1297: (1, 36), + 1301: (25, 26), + 1321: (5, 36), + 1361: (20, 31), + 1373: (2, 37), + 1381: (15, 34), + 1409: (25, 28), + 1429: (23, 30), + 1433: (8, 37), + 1453: (3, 38), + 1481: (16, 35), + 1489: (20, 33), + 1493: (7, 38), + 1549: (18, 35), + 1553: (23, 32), + 1597: (21, 34), + 1601: (1, 40), + 1609: (3, 40), + 1613: (13, 38), + 1621: (10, 39), + 1637: (26, 31), + 1657: (19, 36), + 1669: (15, 38), + 1693: (18, 37), + 1697: (4, 41), + 1709: (22, 35), + 1721: (11, 40), + 1733: (17, 38), + 1741: (29, 30), + 1753: (27, 32), + 1777: (16, 39), + 1789: (5, 42), + 1801: (24, 35), + 1861: (30, 31), + 1873: (28, 33), + 1877: (14, 41), + 1889: (17, 40), + 1901: (26, 35), + 1913: (8, 43), + 1933: (13, 42), + 1949: (10, 43), + 1973: (23, 38), + 1993: (12, 43), + 1997: (29, 34), + 2017: (9, 44), + 2029: (2, 45), + 2053: (17, 42), + 2069: (25, 38), + 2081: (20, 41), + 2089: (8, 45), + 2113: (32, 33), + 2129: (23, 40), + 2137: (29, 36), + 2141: (5, 46), + 2153: (28, 37), + 2161: (15, 44), + 2213: (2, 47), + 2221: (14, 45), + 2237: (11, 46), + 2269: (30, 37), + 2273: (8, 47), + 2281: (16, 45), + 2293: (23, 42), + 2297: (19, 44), + 2309: (10, 47), + 2333: (22, 43), + 2341: (15, 46), + 2357: (26, 41), + 2377: (21, 44), + 2381: (34, 35), + 2389: (25, 42), + 2393: (32, 37), + 2417: (4, 49), + 2437: (6, 49), + 2441: (29, 40), + 2473: (13, 48), + 2477: (19, 46), + 2521: (35, 36), + 2549: (7, 50), + 2557: (21, 46), + 2593: (17, 48), + 2609: (20, 47), + 2617: (4, 51), + 2621: (11, 50), + 2633: (28, 43), + 2657: (16, 49), + 2677: (34, 39), + 2689: (33, 40), + 2693: (22, 47), + 2713: (3, 52), + 2729: (5, 52), + 2741: (25, 46), + 2749: (30, 43), + 2753: (7, 52), + 2777: (29, 44), + 2789: (17, 50), + 2797: (14, 51), + 2801: (20, 49), + 2833: (23, 48), + 2837: (34, 41), + 2857: (16, 51), + 2861: (19, 50), + 2897: (31, 44), + 2909: (10, 53), + 2917: (1, 54), + 2953: (12, 53), + 2957: (29, 46), + 2969: (37, 40), + 3001: (20, 51), + 3037: (11, 54), + 3041: (4, 55), + 3049: (32, 45), + 3061: (6, 55), + 3089: (8, 55), + 3109: (30, 47), + 3121: (39, 40), + 3137: (1, 56), + 3169: (12, 55), + 3181: (34, 45), + 3209: (20, 53), + 3217: (9, 56), + 3221: (14, 55), + 3229: (27, 50), + 3253: (2, 57), + 3257: (11, 56), + 3301: (30, 49), + 3313: (8, 57), + 3329: (25, 52), + 3361: (15, 56), + 3373: (3, 58), + 3389: (5, 58), + 3413: (7, 58), + 3433: (27, 52), + 3449: (40, 43), + 3457: (39, 44), + 3461: (31, 50), + 3469: (38, 45), + 3517: (6, 59), + 3529: (35, 48), + 3533: (13, 58), + 3541: (25, 54), + 3557: (34, 49), + 3581: (10, 59), + 3593: (28, 53), + 3613: (42, 43), + 3617: (41, 44), + 3637: (39, 46), + 3673: (37, 48), + 3677: (14, 59), + 3697: (36, 49), + 3701: (26, 55), + 3709: (30, 53), + 3733: (22, 57), + 3761: (25, 56), + 3769: (13, 60), + 3793: (33, 52), + 3797: (41, 46), + 3821: (10, 61), + 3833: (32, 53), + 3853: (3, 62), + 3877: (31, 54), + 3881: (20, 59), + 3889: (17, 60), + 3917: (14, 61), + 3929: (35, 52), + 3989: (25, 58), + 4001: (40, 49), + 4013: (13, 62), + 4021: (39, 50), + 4049: (32, 55), + 4057: (24, 59), + 4073: (37, 52), + 4093: (27, 58), + 4129: (23, 60), + 4133: (17, 62), + 4153: (43, 48), + 4157: (26, 59), + 4177: (9, 64), + 4201: (40, 51), + 4217: (11, 64), + 4229: (2, 65), + 4241: (4, 65), + 4253: (38, 53), + 4261: (6, 65), + 4273: (32, 57), + 4289: (8, 65), + 4297: (24, 61), + 4337: (44, 49), + 4349: (43, 50), + 4357: (1, 66), + 4373: (23, 62), + 4397: (26, 61), + 4409: (40, 53), + 4421: (14, 65), + 4441: (29, 60), + 4457: (19, 64), + 4481: (16, 65), + 4493: (2, 67), + 4513: (47, 48), + 4517: (46, 49), + 4549: (18, 65), + 4561: (31, 60), + 4597: (41, 54), + 4621: (30, 61), + 4637: (34, 59), + 4649: (5, 68), + 4657: (39, 56), + 4673: (7, 68), + 4721: (25, 64), + 4729: (45, 52), + 4733: (37, 58), + 4789: (42, 55), + 4793: (13, 68), + 4801: (24, 65), + 4813: (18, 67), + 4817: (41, 56), + 4861: (10, 69), + 4877: (34, 61), + 4889: (20, 67), + 4909: (3, 70), + 4933: (33, 62), + 4937: (29, 64), + 4957: (14, 69), + 4969: (37, 60), + 4973: (22, 67), + 4993: (32, 63), + 5009: (28, 65), + 5021: (11, 70), + 5077: (6, 71), + 5081: (40, 59), + 5101: (50, 51), + 5113: (48, 53), + 5153: (23, 68), + 5189: (17, 70), + 5197: (29, 66), + 5209: (5, 72), + 5233: (7, 72), + 5237: (14, 71), + 5261: (19, 70), + 5273: (28, 67), + 5281: (41, 60), + 5297: (16, 71), + 5309: (50, 53), + 5333: (2, 73), + 5381: (34, 65), + 5393: (8, 73), + 5413: (38, 63), + 5417: (44, 59), + 5437: (26, 69), + 5441: (20, 71), + 5449: (43, 60), + 5477: (1, 74), + 5501: (5, 74), + 5521: (36, 65), + 5557: (9, 74), + 5569: (40, 63), + 5573: (47, 58), + 5581: (35, 66), + 5641: (4, 75), + 5653: (18, 73), + 5657: (44, 61), + 5669: (38, 65), + 5689: (8, 75), + 5693: (43, 62), + 5701: (15, 74), + 5717: (26, 71), + 5737: (51, 56), + 5741: (29, 70), + 5749: (50, 57), + 5801: (5, 76), + 5813: (22, 73), + 5821: (14, 75), + 5849: (35, 68), + 5857: (9, 76), + 5861: (31, 70), + 5869: (45, 62), + 5881: (16, 75), + 5897: (11, 76), + 5953: (52, 57), + 5981: (50, 59), + 6029: (10, 77), + 6037: (41, 66), + 6053: (47, 62), + 6073: (12, 77), + 6089: (40, 67), + 6101: (25, 74), + 6113: (28, 73), + 6121: (45, 64), + 6133: (7, 78), + 6173: (53, 58), + 6197: (34, 71), + 6217: (21, 76), + 6221: (50, 61), + 6229: (30, 73), + 6257: (4, 79), + 6269: (37, 70), + 6277: (6, 79), + 6301: (26, 75), + 6317: (29, 74), + 6329: (20, 77), + 6337: (36, 71), + 6353: (32, 73), + 6361: (40, 69), + 6373: (17, 78), + 6389: (55, 58), + 6397: (54, 59), + 6421: (39, 70), + 6449: (7, 80), + 6469: (50, 63), + 6473: (43, 68), + 6481: (9, 80), + 6521: (11, 80), + 6529: (48, 65), + 6553: (37, 72), + 6569: (13, 80), + 6577: (4, 81), + 6581: (41, 70), + 6637: (54, 61), + 6653: (53, 62), + 6661: (10, 81), + 6673: (52, 63), + 6689: (17, 80), + 6701: (35, 74), + 6709: (25, 78), + 6733: (3, 82), + 6737: (31, 76), + 6761: (19, 80), + 6781: (34, 75), + 6793: (48, 67), + 6829: (30, 77), + 6833: (47, 68), + 6841: (21, 80), + 6857: (56, 61), + 6869: (55, 62), + 6917: (26, 79), + 6949: (15, 82), + 6961: (20, 81), + 6977: (44, 71), + 6997: (39, 74), + 7001: (35, 76), + 7013: (17, 82), + 7057: (1, 84), + 7069: (38, 75), + 7109: (47, 70), + 7121: (55, 64), + 7129: (27, 80), + 7177: (11, 84), + 7193: (52, 67), + 7213: (18, 83), + 7229: (2, 85), + 7237: (26, 81), + 7253: (23, 82), + 7297: (39, 76), + 7309: (35, 78), + 7321: (60, 61), + 7333: (58, 63), + 7349: (25, 82), + 7369: (12, 85), + 7393: (47, 72), + 7417: (19, 84), + 7433: (53, 68), + 7457: (41, 76), + 7477: (9, 86), + 7481: (16, 85), + 7489: (33, 80), + 7517: (11, 86), + 7529: (40, 77), + 7537: (36, 79), + 7541: (50, 71), + 7549: (18, 85), + 7561: (44, 75), + 7573: (2, 87), + 7577: (59, 64), + 7589: (58, 65), + 7621: (15, 86), + 7649: (55, 68), + 7669: (10, 87), + 7673: (28, 83), + 7681: (25, 84), + 7717: (34, 81), + 7741: (46, 75), + 7753: (3, 88), + 7757: (19, 86), + 7789: (30, 83), + 7793: (7, 88), + 7817: (61, 64), + 7829: (50, 73), + 7841: (40, 79), + 7853: (58, 67), + 7873: (57, 68), + 7877: (49, 74), + 7901: (26, 85), + 7933: (43, 78), + 7937: (4, 89), + 7949: (35, 82), + 7993: (53, 72), + 8009: (28, 85), + 8017: (31, 84), + 8053: (22, 87), + 8069: (62, 65), + 8081: (41, 80), + 8089: (60, 67), + 8093: (37, 82), + 8101: (1, 90), + 8117: (14, 89), + 8161: (40, 81), + 8209: (55, 72), + 8221: (11, 90), + 8233: (48, 77), + 8237: (29, 86), + 8269: (13, 90), + 8273: (23, 88), + 8293: (47, 78), + 8297: (4, 91), + 8317: (6, 91), + 8329: (52, 75), + 8353: (28, 87), + 8369: (25, 88), + 8377: (51, 76), + 8389: (17, 90), + 8429: (50, 77), + 8461: (19, 90), + 8501: (55, 74), + 8513: (7, 92), + 8521: (36, 85), + 8537: (16, 91), + 8573: (43, 82), + 8581: (65, 66), + 8597: (26, 89), + 8609: (47, 80), + 8629: (23, 90), + 8641: (60, 71), + 8669: (38, 85), + 8677: (46, 81), + 8681: (20, 91), + 8689: (15, 92), + 8693: (58, 73), + 8713: (8, 93), + 8737: (41, 84), + 8741: (50, 79), + 8753: (17, 92), + 8761: (56, 75), + 8821: (30, 89), + 8837: (1, 94), + 8849: (65, 68), + 8861: (5, 94), + 8893: (53, 78), + 8929: (60, 73), + 8933: (47, 82), + 8941: (29, 90), + 8969: (35, 88), + 9001: (51, 80), + 9013: (38, 87), + 9029: (2, 95), + 9041: (4, 95), + 9049: (20, 93), + 9109: (55, 78), + 9133: (22, 93), + 9137: (64, 71), + 9157: (54, 79), + 9161: (44, 85), + 9173: (62, 73), + 9181: (30, 91), + 9209: (53, 80), + 9221: (14, 95), + 9241: (5, 96), + 9257: (59, 76), + 9277: (21, 94), + 9281: (16, 95), + 9293: (58, 77), + 9337: (11, 96), + 9341: (46, 85), + 9349: (18, 95), + 9377: (56, 79), + 9397: (66, 71), + 9413: (2, 97), + 9421: (45, 86), + 9433: (28, 93), + 9437: (34, 91), + 9461: (25, 94), + 9473: (8, 97), + 9497: (61, 76), + 9521: (40, 89), + 9533: (53, 82), + 9601: (24, 95), + 9613: (3, 98), + 9629: (5, 98), + 9649: (57, 80), + 9661: (69, 70), + 9677: (29, 94), + 9689: (35, 92), + 9697: (56, 81), + 9721: (64, 75), + 9733: (18, 97), + 9749: (55, 82), + 9769: (45, 88), + 9781: (41, 90), + 9817: (4, 99), + 9829: (15, 98), + 9833: (37, 92), + 9857: (44, 89), + 9901: (10, 99), + 9929: (52, 85), + 9941: (70, 71), + 9949: (43, 90), + 9973: (57, 82) +} diff --git a/dim1_isogenies.py b/dim1_isogenies.py new file mode 100644 index 0000000..8c38627 --- /dev/null +++ b/dim1_isogenies.py @@ -0,0 +1,207 @@ +#!/usr/bin/env python3 + +import logging + +from xonly import xPoint, isWeierstrass, translate_by_T +from basis_sampling import find_Ts +from elkies import Elkies + +from sage.arith.misc import factor +from sage.rings.integer import Integer +from sage.arith.misc import kronecker_symbol +from sage.rings.finite_rings.finite_field_constructor import GF + +logger = logging.getLogger(__name__) +logger.setLevel(logging.WARNING) +logger_sh = logging.StreamHandler() +logger_sh.setLevel(logging.WARNING) +formatter = logging.Formatter("%(name)s [%(levelname)s] %(message)s") +logger_sh.setFormatter(formatter) +logger.addHandler(logger_sh) + + +def ideal_above_2_action(E, P, Q, basis_order, ideal, w): + r"""Computes the action of a power of an ideal above 2 using Velu + + Input: + - E: Elliptic curve over Fp + - P, Q: Basis of E[2^basis_order], + Here, P is in E(Fp) and Q is in Et(Fp) for a quadratic twist Et + - basis_order: Such that 2^basis_order is the order of P, Q + - ideal: Power of an ideal above 2 + Output: + Tuple (phi, E_ideal) + + - phi: The isogeny corresponding to ideal + - E_ideal: The curve obtained by the action of the ideal on E + """ + _, v2 = factor(ideal.norm())[0] + + left = 0 + right = 0 + if (w - 1) / 2 in ideal: + K = P + left = v2 + else: + assert (w + 1) / 2 in ideal + K = Q + right = v2 + + K = K.xMUL(2 ** (basis_order - v2)) + + assert K.xMUL(2 ** (v2 - 1)) + assert not K.xMUL(2**v2) + + phi_2 = K.xMUL(2 ** (v2 - 1)).xISOG(E, 2) + phi = phi_2 + + for step in range(1, v2): + E = phi.codomain() + K = K.push(phi_2) + + assert K.xMUL(2 ** (v2 - step - 1)) + assert not K.xMUL(2 ** (v2 - step)) + + phi_2 = K.xMUL(2 ** (v2 - step - 1)).xISOG(E, 2) + phi = phi_2 * phi + + E_out = phi.codomain().montgomery_model() + + return phi.codomain().isomorphism_to(E_out) * phi, E_out, left, right + + +def small_prime_ideal_action(E, ell, lam=None, prev_j=None): + r"""Computes action of a ideal with prime norm using Elkies + + Input: + - E: Elliptic curve over Fp IN WEIERSTRASS FORM + - ell: A small prime, split in the quadratic order + - lam: (optional) Eigenvalue determining the ideal + - prev_j: (optional) The j-invariant of the WRONG ell-isogenous curve + + Both lam and prev_j are passed to Elkies + + Output: + - phi: Isogeny corresponding to an ideal above ell + """ + # Fix later, but Elkies uses short Weierstrass + # Change ring stuff is messy, but needed to actually compute the rational model + assert isWeierstrass(E) + + h = Elkies(E, ell, E.base_field(), lam=lam, prev_j=prev_j) + phi = E.isogeny(h) + + return phi + + +def smooth_ideal_action(E, norm, ideal, w, max_order): + r"""Computes action of a an ideal with odd smooth norm using successive Elkies + + Input: + - E: Elliptic curve over Fp + - norm: Norm of ideal + - ideal: An ideal + + Output: Tuple (isogenies, E_ideal) + - isogenies: A list of isogenies, forming a chain from E to E_out + - E_ideal: The curve obtained by the action of the ideal on E + """ + + p = E.base_field().characteristic() + + isogenies = [] + E1 = E.short_weierstrass_model() + isogenies += [E.isomorphism_to(E1)] + + if norm > 1: + for ell, e in factor(norm): + + lam = Integer(GF(ell)(-p).sqrt()) + if not (w - lam) in (ideal + ell * max_order): + # In this case, we want the other one + lam = ell - lam + + assert (w - lam) in (ideal + ell * max_order) + + prev_j = None + for _ in range(e): + logger.debug(f"Starting Elkies step of degree {ell}") + phi = small_prime_ideal_action(E1, ell, lam, prev_j) + prev_j = E1.j_invariant() + E1 = phi.codomain() + isogenies.append(phi) + + E_ideal = isogenies[-1].codomain().montgomery_model() + isogenies += [isogenies[-1].codomain().isomorphism_to(E_ideal)] + + return isogenies, E_ideal + + +def random_smooth_isogeny(E, g): + r""" + Returns a random isogeny of smooth degree g from E + Input: + - E: Elliptic curve over Fp + - g: Smooth number + Output: + - phi : An isogeny from E of degree g + - E_out : phi(E) + """ + p = E.base_field().characteristic() + # Random smooth odd norm isogeny + isogs = [] + if g > 1: + E1 = E.short_weierstrass_model() + pre_isom = E.isomorphism_to(E1) + isogs.append(pre_isom) + logger.debug(f"Extra isogeny for g = {factor(g)}") + # Do elkies first, to stay over Fp + g_elkies = [] + for ell, e in factor(g): + if kronecker_symbol(-p, ell) == 1: + g_elkies.append((ell, e)) + for ell, e in g_elkies: + prev_j = None + for _ in range(e): + phi_ell = small_prime_ideal_action(E1, ell, prev_j=prev_j) + prev_j = E1.j_invariant() + E1 = phi_ell.codomain() + isogs.append(phi_ell) + + E_out = isogs[-1].codomain().montgomery_model() + post_isom = isogs[-1].codomain().isomorphism_to(E_out) + isogs.append(post_isom) + + return isogs, E_out + else: + return [], E + + +def eval_endomorphism(rho, P, twist, max): + r""" + Evaluates an element of End(E) on a point P. + P is assumed to be Fp rational on either E or on a twist + """ + a, b = list(rho) # write as a + b*pi + n = rho.denominator() + if twist: + # a + b*pi = a - b, since pi(P) = -P + m = Integer(a - b) + else: + # a + b*pi = a + b, since pi(P) = P + m = Integer(a + b) + if max and (n == 2): # See Appendix D.2 + mP = P.xMUL(m) + E = P.curve + + T0 = find_Ts(E, only_T0=True) + + # Already know which point to choose, Remark D.2 + assert (P.X - T0.x()).is_square() != twist + + T = xPoint(T0.x(), E) + + return translate_by_T(mP, T) + + else: + return P.xMUL(m) diff --git a/elkies.py b/elkies.py index aa6e8d3..592d596 100644 --- a/elkies.py +++ b/elkies.py @@ -1,8 +1,15 @@ -from sage.all import * -import random -from xonly import xPoint +#!/usr/bin/env python3 -def Elkies(E, ell, Fp, lam = None, prev_j = None): +import sage.all +from sage.schemes.elliptic_curves.mod_poly import classical_modular_polynomial +from sage.calculus.functional import derivative +from sage.rings.power_series_ring import PowerSeriesRing +from sage.arith.misc import kronecker_symbol +from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing +from sage.functions.other import binomial + + +def Elkies(E, ell, Fp, lam=None, prev_j=None): """ Elkies algorithm for computing isogenies as detailed in [BSS - Elliptic Curves in Cryptography, Chapter VII]. @@ -18,20 +25,20 @@ def Elkies(E, ell, Fp, lam = None, prev_j = None): Output: - the kernel polynomial hc """ - #TODO maybe we want montomery curves later + # TODO maybe we want montomery curves later p = Fp.characteristic() assert ell > 2 - d = (ell-1)/2 + d = (ell - 1) / 2 j = Fp(E.j_invariant()) _, _, _, a, b = [Fp(c) for c in E.a_invariants()] - R = Fp['X,Y'] + R = Fp["X,Y"] X, Y = R._first_ngens(2) - E4 = -48*a - E6 = 864*b + E4 = -48 * a + E6 = 864 * b - jp = -E6*j/E4 + jp = -E6 * j / E4 phi_ell = R(classical_modular_polynomial(ell)) X, Y = phi_ell.variables() @@ -48,181 +55,178 @@ def Elkies(E, ell, Fp, lam = None, prev_j = None): phi_ell_eval = phi_ell_eval // (x - prev_j) # print(f"Finding j: {time()-tstart}") if prev_j: - j_ells = [phi_ell_eval.any_root()] #There is only one root in this case! - #assert len(j_ells) == 1, f"j_ells was {j_ells}, and prev_j was {prev_j}" + j_ells = [phi_ell_eval.any_root()] # There is only one root in this case! + # assert len(j_ells) == 1, f"j_ells was {j_ells}, and prev_j was {prev_j}" else: - j_ells = [r for r,e in phi_ell_eval.roots()] + j_ells = [r for r, e in phi_ell_eval.roots()] assert len(j_ells) == 2, f"j_ells was {j_ells}" - #print(j_ells) + # print(j_ells) jt = j_ells[0] assert jt != 0 and jt != 1728, "encountered E0" - hc = _derive_hc(Fp, a, b, ell, d, j, jt, jp, E4, E6, phi_ellx, phi_ellxx, - phi_ellxy, phi_elly, phi_ellyy) + hc = _derive_hc(Fp, a, b, ell, d, j, jt, jp, E4, E6, phi_ellx, phi_ellxx, phi_ellxy, phi_elly, phi_ellyy) if lam and not prev_j: if not CheckElkies(E, ell, hc, lam): - #Do the other one + # Do the other one assert j_ells[1] != 0 and j_ells[1] != 1728, "encountered E0" - hc = _derive_hc(Fp, a, b, ell, d, j, j_ells[1], jp, E4, E6, phi_ellx, phi_ellxx, phi_ellxy, phi_elly, phi_ellyy) + hc = _derive_hc( + Fp, a, b, ell, d, j, j_ells[1], jp, E4, E6, phi_ellx, phi_ellxx, phi_ellxy, phi_elly, phi_ellyy + ) + if lam: + assert CheckElkies(E, ell, hc, lam) return hc -def WeierstrassP(a,b,d): + +def WeierstrassP(a, b, d): # Weierstrass p up to degree d in w=z^2 - coefs = [-a/5, -b/7] + coefs = [-a / 5, -b / 7] for k in range(2, d): ck = 0 - for j in range (k-1): - ck = ck + coefs[j]*coefs[k-2-j] - ck = ck*3/((k-1)*(2*(k+1)+3)) + for j in range(k - 1): + ck = ck + coefs[j] * coefs[k - 2 - j] + ck = ck * 3 / ((k - 1) * (2 * (k + 1) + 3)) coefs.append(ck) return coefs def _derive_hc(Fp, a, b, ell, d, j, jt, jp, E4, E6, phi_ellx, phi_ellxx, phi_ellxy, phi_elly, phi_ellyy): - jtp = -jp*phi_ellx(j, jt)/(ell*phi_elly(j, jt)) - at = -jtp**2/(48*jt*(jt-1728)) - bt = -jtp**3/(864*jt**2*(jt-1728)) - - E4t = -48*at - E6t = 864*bt - - fracjs = -(jp**2*phi_ellxx(j, jt) + 2*ell*jp*jtp*phi_ellxy(j, jt) + (ell*jtp)**2*phi_ellyy(j, jt))/ (jp*phi_ellx(j, jt)) - p1 = ell*fracjs/2 + (Fp(ell)/4)*(E4**2/E6 - ell*E4t**2/E6t) + (Fp(ell)/3)*(E6/E4 - ell*E6t/E4t) - - c = WeierstrassP(a,b,d) - ckst = WeierstrassP(ell**4*at, ell**6*bt, d) - ct = [ckst[i] - ell*c[i] for i in range(len(c))] # difference in formula VII.23 + jtp = -jp * phi_ellx(j, jt) / (ell * phi_elly(j, jt)) + at = -(jtp**2) / (48 * jt * (jt - 1728)) + bt = -(jtp**3) / (864 * jt**2 * (jt - 1728)) + + E4t = -48 * at + E6t = 864 * bt + + fracjs = -( + jp**2 * phi_ellxx(j, jt) + 2 * ell * jp * jtp * phi_ellxy(j, jt) + (ell * jtp) ** 2 * phi_ellyy(j, jt) + ) / (jp * phi_ellx(j, jt)) + p1 = ( + ell * fracjs / 2 + + (Fp(ell) / 4) * (E4**2 / E6 - ell * E4t**2 / E6t) + + (Fp(ell) / 3) * (E6 / E4 - ell * E6t / E4t) + ) + + c = WeierstrassP(a, b, d) + ckst = WeierstrassP(ell**4 * at, ell**6 * bt, d) + ct = [ckst[i] - ell * c[i] for i in range(len(c))] # difference in formula VII.23 # Computing the coefficients of VII.23 and store as A[i] - Fpw, w = PowerSeriesRing(Fp, 'w', default_prec=d+1).objgen() - evp = -(p1/2)*w - sum(w**(i+1)*ct[i-1] / ((2*i+1)*(2*i+2)) for i in range(1,d)) - exp_evp = evp.exp(d+1) + Fpw, w = PowerSeriesRing(Fp, "w", default_prec=d + 1).objgen() + evp = -(p1 / 2) * w - sum(w ** (i + 1) * ct[i - 1] / ((2 * i + 1) * (2 * i + 2)) for i in range(1, d)) + exp_evp = evp.exp(d + 1) A = exp_evp.coefficients() - C = sum(c[i-1]*w**i for i in range(1, d+1)) + C = sum(c[i - 1] * w**i for i in range(1, d + 1)) # Computing all powers of C starting with zeroth power - Cpow = [Fpw(1), C]; - for i in range(2, d+1): - Cpow.append(C*Cpow[-1]) + Cpow = [Fpw(1), C] + for i in range(2, d + 1): + Cpow.append(C * Cpow[-1]) # Now doing recurrence relation VII.24 - hc = [1, -p1/2] - for i in range(2, d+1): + hc = [1, -p1 / 2] + for i in range(2, d + 1): newcoeff = A[i] - for k in range(1, i+1): + for k in range(1, i + 1): insum = 0 - for j in range(k+1): - insum += Fp(binomial(d-i+k, k-j))*Cpow[k-j][j] - newcoeff -= insum*hc[i-k] + for j in range(k + 1): + insum += Fp(binomial(d - i + k, k - j)) * Cpow[k - j][j] + newcoeff -= insum * hc[i - k] hc.append(newcoeff) - Rx, x = PolynomialRing(Fp, 'x').objgen() + Rx, x = PolynomialRing(Fp, "x").objgen() hc = Rx(hc[::-1]) return hc -def CheckElkies(E, ell, h, lam): - p = E.base_field().characteristic() - if kronecker_symbol(-p, ell) != 1: - assert False, "not Elkies" - _, _, _, a, b = E.a_invariants() - f = h.parent()([b, a, 0, 1]) +def CheckElkies(E, ell, kernel_polynomial, lam): + r"""Given a kernel polynomial, verify it corresponds to the correct eigenvalue - B = pow(f, (p-1)/2, h) - check_wrong = False - if lam > ell//2: - lam = ell-lam - check_wrong = True + If the multiplication-by-lambda map has the following standard form in + rational maps (c.f. Sutherland's lectures) - if lam == 1: - if check_wrong: - return B != 1 - else: - return B == 1 - - # Stupid way for now, no sage function for directly computing mod h - RR = h.parent().quotient_ring(h) - y_coord = E.multiplication_by_m(lam)[1] - y_coord_num = y_coord.numerator() - x, y = y_coord_num.variables() - y_coord_den = y_coord.denominator() - - if check_wrong: - return RR(B)*RR(y_coord_den) != RR(y_coord_num(x, 1).univariate_polynomial()) - else: - return RR(B)*RR(y_coord_den) == RR(y_coord_num(x, 1).univariate_polynomial()) + [\lambda] = (u(x)/v(x), r(x, y)/s(x)) + then the eigenvalue is correct, if -def NonElkiesIsogeny(E, ell, Fp2): - # For u, v, when not elkies prime. - # Make that either ell divides p+1, the other way works... + \pi(P) = \lambda P - E = E.change_ring(Fp2) - #print(factor(E.division_polynomial(ell))) - # Make sure these are the only cases... - h_ell = factor(E.division_polynomial(ell))[0][0] + on all points in the kernel of the isogeny defined by kernel_polynomial. - m = (ell-1)//(2*h_ell.degree()) - if m == 1: - return h_ell + Note that r(x, y) = r(x, 1) * y, by the standard form of isogenies. So, if + P = (x, y), this is equivalent to - #Deuring for the people <3 - from sage.schemes.elliptic_curves.isogeny_small_degree import _least_semi_primitive - a = _least_semi_primitive(ell) - fs = [h_ell] - Fbig = Fp2.extension(h_ell) - x = Fbig.gens()[0] - xi = xPoint(x, E.change_ring(Fbig)) - for _ in range(1, m): - xi = xi.mul(a) - fs.append(xi.X.minpoly()) + (x^p, y^p) = (u(x)/v(x), r(x, 1)/s(x) * y) - h_ell = prod(fs) - assert h_ell.degree() == (ell-1)/2, f"Degree : {h_ell.degree()}, shouldve been {(ell-1)/2}" - return h_ell + for points in ker(\varphi) + Verifying the first component is easy. To verify the second, we note that + y^p = r(x, 1)/s(x) * y + <=> y^{p-1} = r(x, 1)/s(x) + <=> f(x)^{(p-1)/2} = r(x, 1)/s(x) + <=> f(x)^{(p-1)/2} * s(x) = r(x, 1) -### This is way slower for now :(( -def ElkiesDirect(E, ell, lam = None): - psi_x = E.division_polynomial(ell) - Fp = E.base_field() - p = Fp.characteristic() - if not lam: - F_ell = GF(ell) - lam = F_ell(-p).sqrt() + where f(x) is the defining equation of the curve E: y^2 = f(x). + """ - R = psi_x.parent() - x = psi_x.variables()[0] - RR = R.quotient_ring(psi_x) + p = E.base_field().characteristic() + E = E.short_weierstrass_model() - X = RR._first_ngens(1)[0] + assert kronecker_symbol(-p, ell) == 1, f"{ell} not Elkies" - check_wrong = False - if lam > ell//2: - lam = ell-lam - check_wrong = True + # Defining equation of E: y^2 + g(x)y = f(x) + f, g = E.hyperelliptic_polynomials() - if lam == 1: - h_sq_bar = X**p - X + # Must be true, because E is in Weierstrass form + assert g == 0 + + # Disabled when python is called with -O flag + if __debug__: + # @todo: Can be deleted later. Sanity check. + # Verify that this is really the same as previous method of getting the + # defining equation + # This must be equal, because E is in short weierstrass form + assert f == kernel_polynomial.parent()([E.a6(), E.a4(), 0, 1]) + + # For efficiency: replace lambda with -lambda if -lambda has smaller + # absolute value + # If we switch, then we need to multiply the isogeny with -1 + # (which is multiplication by -1 on the y-coordinate) + + if lam > ell - lam: + lam = ell - lam + sign = -1 else: - mult_by_lam = E.multiplication_by_m(lam)[0] - mult_by_lam_num = mult_by_lam.numerator().univariate_polynomial() - mult_by_lam_denom = mult_by_lam.denominator().univariate_polynomial() - h_sq_bar = X**p*mult_by_lam_denom(X) - mult_by_lam_num(X) + sign = 1 + + if lam == 1: + Y = pow(f, (p - 1) / 2, kernel_polynomial) + return sign * Y == 1 + + # Build extension over which the x-coordinates of the kernel are defined + extension = kernel_polynomial.parent().quotient_ring(kernel_polynomial) + + # Get rational functions of multiplication-by-lambda + # x = u/v, y = r/x as in the description in the docstring + x, y = E.multiplication_by_m(lam)[:2] + u = extension(x.numerator()) + v = extension(x.denominator()) + # Overwrite r(x, y) with r(x, 1) + r = y.numerator() + r = extension(r(r.variables()[0], 1).univariate_polynomial()) + s = extension(y.denominator()) - h_sq = 0 - x_pow = x**0 - for ai in list(h_sq_bar): - h_sq += ai*x_pow - x_pow *= x - h_sq = gcd(psi_x, h_sq) - #print(h_sq) - #print(factor(h_sq)) + # x^p in the extension + Xp = extension(pow(kernel_polynomial.parent().gens()[0], p, kernel_polynomial)) - #print(Elkies(E, ell, Fp)) + # Verify u(x)/v(x) = x^p + if u != Xp * v: + return False + Y = extension(pow(f, (p - 1) / 2, kernel_polynomial)) + # Verify y^{p-1} = f(x)^{(p-1)/2} = sign * r(x, 1)/s(x) + return Y * s == sign * r diff --git a/generate_params.py b/generate_params.py new file mode 100644 index 0000000..3bfbd67 --- /dev/null +++ b/generate_params.py @@ -0,0 +1,119 @@ +#!/usr/bin/env python3 + +from argparse import ArgumentParser, RawDescriptionHelpFormatter +from itertools import product +from random import choice +from textwrap import dedent + +import sage.all +from sage.rings.finite_rings.finite_field_constructor import GF +from sage.arith.misc import is_prime +from sage.arith.misc import kronecker_symbol +from sage.schemes.elliptic_curves.constructor import EllipticCurve +from sage.schemes.elliptic_curves.mod_poly import classical_modular_polynomial +from sage.sets.primes import Primes +from sage.rings.fast_arith import prime_range + +# Arguments +parser = ArgumentParser( + formatter_class=RawDescriptionHelpFormatter, + epilog=dedent( + """ + CONTROLLING ELKIES PRIMES + So that we have small elkies primes, we search for a prime so that there + are ELKIES elkies primes of size at most MAX_ELKIES. + + FINDING STARTING CURVE + To find a starting curve, we must be sufficiently far away from j=1728. + We achieve this by doing a random walk starting at j=1728*. + For each elkies prime up to WALK_MAX_ELKIES we do WALK_STEPS number of + steps of that size. + + *There is a small caveat: we want a curve on the surface, so our first step + is a 2-isogeny step to land on the surface. +""" + ), +) +parser.add_argument("-p", "--prime", type=int, help="Prime size in bits (Default: 512 bits)", default=512) +parser.add_argument("-e", "--elkies", type=int, help="Minmal number of small elkies primes", default=4) +parser.add_argument("-m", "--max-elkies", type=int, help="Maximal elkies primes to consider small", default=23) +parser.add_argument("-s", "--walk-steps", type=int, help="Steps per elkies prime in random walk", default=20) +parser.add_argument("-w", "--walk-max-elkies", type=int, help="Largest elkies prime used in random walk", default=None) +args = parser.parse_args() + + +print(f":: Finding parameters for") +print(f" => log(p) = {args.prime}") +print(f" => With at least {args.elkies} odd elkies primes of size at most {args.max_elkies}") +print(f" => Doing random walks of length {args.walk_steps} for every prime up to {args.prime}") +print() + + +def small_elkies_primes(p): + elkies_primes = [] + for ell in Primes(proof=False): + if ell == 2: + continue + if ell >= args.max_elkies: + return elkies_primes + if kronecker_symbol(-p, ell) == 1: + elkies_primes += [ell] + return [] + + +def random_elkies(j, ell): + return choice(list(set(classical_modular_polynomial(ell, j=j).roots(GF(p), multiplicities=False)) - set([j]))) + + +def walk(j, p): + # Do some walking in the graph, to get away from j=1728 + for ell in prime_range(3, args.walk_max_elkies): + print(f"Walking {args.walk_steps} times for prime {ell}") + for _ in range(args.walk_steps): + if kronecker_symbol(-p, ell) == 1: + j = random_elkies(j, ell) + return j + + +p = None +for e, f in product(range(args.prime, 2 * args.prime), range(1, 10 * args.prime)): + p = f * 2**e - 1 + if is_prime(p): + j = GF(p)(1728) + if len(small_elkies_primes(p)) > args.elkies: + if not on_surface(EllipticCurve(j=j)): + j = random_elkies(j, 2) + assert on_surface(EllipticCurve(j=j)) + break + +if p is None: + print("Failure") + exit() + +print(f":: Found prime p = {f} * 2**{e} - 1") +print(f" => Corresponding elkies primes = {small_elkies_primes(p)}") +print() + +if args.walk_max_elkies is None: + args.walk_max_elkies = args.prime + +A = None + +while True: + print() + j = walk(j, p) + for E in EllipticCurve(j=j).twists(): + E = E.montgomery_model() + + assert E.is_supersingular() + assert E.base_field() == GF(E.base_field().characteristic()) + assert on_surface(E) + + A = E.a2() + + print() + print(f"self.f = {f}") + print(f"self.e = {e}") + print(f"self.p = self.f * 2**self.e - 1") + print(f"self.A = {A}") + print(f"self.allowed_primes = {small_elkies_primes(p)}") diff --git a/ideal_to_kernel.py b/ideal_to_kernel.py new file mode 100644 index 0000000..a18435d --- /dev/null +++ b/ideal_to_kernel.py @@ -0,0 +1,234 @@ +#!/usr/bin/env python3 + +from time import time +import logging + +from sage.arith.misc import valuation, inverse_mod +from sage.calculus.var import var +from sage.rings.finite_rings.finite_field_constructor import GF +from sage.rings.integer import Integer +from sage.rings.integer_ring import ZZ + +from ideals import ideal_to_sage, conjugate, principal_generator +from basis_sampling import TwoTorsBasis +from dim1_isogenies import ideal_above_2_action, smooth_ideal_action, eval_endomorphism, random_smooth_isogeny + +logger = logging.getLogger(__name__) +logger.setLevel(logging.WARNING) +logger_sh = logging.StreamHandler() +formatter = logging.Formatter("%(name)s [%(levelname)s] %(message)s") +logger_sh.setFormatter(formatter) +logger.addHandler(logger_sh) + + +def ideal_to_kernel(E, uv, frak_bc, max_order, w, e): + r""" + Following sec. 5.4, prepare the data necessary for the 4D isogeny. + Input: + - E: starting curve + - uv: the decomposition of u and v as cof + sum of squares + - frak_bc: the ideals b and c as output of UVSolver + - e: the torsion we want to use + + Output: + - N1, N2, x_u, y_u, g_u, x_v, y_u, g_v e s.t. + N1*g_u*(x_u^2 + y_u^2) + N2*g_v*(x_v^2 + y_v^2) == 2^e + - P_u, Q_u, P_v, Q_v: image points on E_u, Ev as described + in sec 5.4 + """ + p = E.base_field().characteristic() + Fp2 = GF((p, 2), name="i", modulus=var("x") ** 2 + 1) + + # First recover the numbers + tstart = time() + if type(uv[0]) == tuple: + (x_u, y_u, g_u) = uv[0] + else: + x_u = None + y_u = None + g_u = 1 + + if type(uv[1]) == tuple: + (x_v, y_v, g_v) = uv[1] + else: + x_v = None + y_v = None + g_v = 1 + + # (x_u, y_u, g_u), (x_v, y_v, g_v) = uv + b_list, c_list = frak_bc + + N1, b_cof, b_twopower, frak_b_list = b_list + N2, c_cof, c_twopower, frak_c_list = c_list + + # assert N1 * g_u * (x_u**2 + y_u**2) + N2 * g_v * (x_v**2 + y_v**2) == 2**e + + def div_by_n(ideal, n): + generators = [gi / n for gi in ideal.gens()] + return sum([max_order * gi for gi in generators]) + + frak_b = ideal_to_sage(frak_b_list, max_order) + frak_c = ideal_to_sage(frak_c_list, max_order) + + if b_twopower > 1: # factors through two + frak_b = div_by_n(frak_b, 2) + if c_twopower > 1: + frak_c = div_by_n(frak_c, 2) + + # The part thats the same for b and c + frak_bc_same = frak_b + frak_c + + # We only want the "unique" part of b and c + frak_b = div_by_n(frak_b * conjugate(max_order, frak_bc_same), frak_bc_same.norm()) + frak_c = div_by_n(frak_c * conjugate(max_order, frak_bc_same), frak_bc_same.norm()) + + frak_b_2 = frak_b + max_order * ((2 ** frak_b.norm().valuation(2))) + frak_c_2 = frak_c + max_order * ((2 ** frak_c.norm().valuation(2))) + + odd_part = Integer(frak_bc_same.norm()).prime_to_m_part(2) + pow2_part = frak_bc_same.norm() / odd_part + frak_bc_same_2 = frak_bc_same + max_order * pow2_part + frak_bc_same_odd = frak_bc_same + max_order * odd_part + + b_cof = b_cof / odd_part + c_cof = c_cof / odd_part + + # First step to the starting curve given by same direction steps + ee = valuation(p + 1, 2) - 1 + logger.debug("Walking to starting point (i.e. steps that are same for b and c)...") + if frak_bc_same.norm() > 1: + if pow2_part > 1: + P_temp, Q_temp = TwoTorsBasis(E, ee) + # P_temp, Q_temp = TwoTorsBasis(E, two_pow) + _, E, _, _ = ideal_above_2_action(E, P_temp, Q_temp, ee, frak_bc_same_2, w) + if odd_part > 1: + _, E = smooth_ideal_action(E, odd_part, frak_bc_same_odd, w, max_order) + logger.debug(f"Done! Have used {time() - tstart}") + P, Q = TwoTorsBasis(E, ee) + # P, Q = TwoTorsBasis(E, ee) + + # Doing the Elkies steps for b + logger.debug("odd Elkies steps for b") + isogs_cof, E1 = smooth_ideal_action(E, b_cof, frak_b, w, max_order) + P1, Q1 = P, Q + for phi in isogs_cof: + P1 = P1.push(phi) + Q1 = Q1.push(phi) + logger.debug(f"Done! Have used {time() - tstart}") + + # Even Elkies steps for b + if frak_b_2.norm() > 1: + phi_2, E1, left_b, right_b = ideal_above_2_action(E1, P1, Q1, ee, frak_b_2, w) + P1 = P1.push(phi_2) + Q1 = Q1.push(phi_2) + else: + left_b = 0 + right_b = 0 + + # Adjust the order + P1, Q1 = P1.xMUL(2 ** (ee - left_b - (e + 2))), Q1.xMUL(2 ** (ee - right_b - (e + 2))) + + assert P1.xMUL(2 ** (e + 1)) + assert not P1.xMUL(2 ** (e + 2)) + assert Q1.xMUL(2 ** (e + 1)) + assert not Q1.xMUL(2 ** (e + 2)) + # At this point, P1, Q1 are the "starting points" + + logger.debug("Doing g_u isogeny") + g_u_isogs, Eu = random_smooth_isogeny(E1, g_u) + Pu, Qu = P1, Q1 + for phi_gu in g_u_isogs: + Pu = Pu.push(phi_gu) + Qu = Qu.push(phi_gu) + logger.debug(f"Done! Have used {time() - tstart}") + + # Now the second part + # Evaluating the endomorphism + logger.debug("Evaluating the endomorphism frak_b*frac_c_bar") + rho_bc = principal_generator(frak_b * conjugate(max_order, frak_c)) + rho_bc_val_2 = rho_bc.norm().valuation(2) + + # assert (frak_b*frak_c).norm() == rho_bc.norm() + # assert rho_bc in frak_b + # assert rho_bc.conjugate() in frak_c + + # adjust_2 = 0 + # if rho_bc_val_2 > 0: #Here we really need to clear denominators to evaluate the endomorphism + # rho_bc *= 2 + # adjust_2 = 1 + + # print("!!!!!!!!!") + # print(ee-(rho_bc_val_2)) + # print(e+2) + # assert ee-(rho_bc_val_2 + adjust_2) >= e+2, "NotImplemented: We can drop adjust_2 if we allow extension-fields" + # print(f"Evaluating {rho_bc}") + max = ee - rho_bc_val_2 == e + 2 + + Pc = P + Qc = Q + # Then apply endomorphism + Pc = eval_endomorphism(rho_bc, Pc, False, max) + Qc = eval_endomorphism(rho_bc, Qc, True, max) + + # Act with 2-ideals above c + logger.debug("Acting with 2-part of frak_c") + E2 = E + frak_c_2_norm = frak_c_2.norm() + if frak_c_2_norm > 1: + phi_2, E2, _, _ = ideal_above_2_action(E2, P, Q, ee, frak_c_2, w) + Pc = Pc.push(phi_2) + Qc = Qc.push(phi_2) + c_2_part = ZZ(frak_c_2_norm).valuation(2) + else: + c_2_part = 0 + + # Finally, odd part of c + isogs_cof, E2 = smooth_ideal_action(E2, c_cof, frak_c, w, max_order) + for phi in isogs_cof: + Pc = Pc.push(phi) + Qc = Qc.push(phi) + + inverse_norms = inverse_mod(c_cof, 2**ee) + assert (inverse_norms * c_cof) % 2**ee == 1 + + logger.debug(f"Done! Have used {time() - tstart}") + P2 = Pc.xMUL(2 ** (ee - c_2_part - left_b - (e + 2)) * inverse_norms) + Q2 = Qc.xMUL(2 ** (ee - c_2_part - right_b - (e + 2)) * inverse_norms) + + assert P2.xMUL(2 ** (e + 1)) + assert not P2.xMUL(2 ** (e + 2)) + assert Q2.xMUL(2 ** (e + 1)) + assert not Q2.xMUL(2 ** (e + 2)) + + logger.debug("Doing g_v isogeny") + Pv, Qv = P2, Q2 + + g_v_isogs, Ev = random_smooth_isogeny(E2, g_v) + + for phi_gv in g_v_isogs: + Pv = Pv.push(phi_gv) + Qv = Qv.push(phi_gv) + logger.debug(f"Done! Have used {time() - tstart}") + + Ev = Pv.curve.change_ring(Fp2) + Eu = Pu.curve.change_ring(Fp2) + + Pv = Ev.lift_x(Pv.X) + Qv = Ev.lift_x(Qv.X) + + Pu = Eu.lift_x(Pu.X) + Qu = Eu.lift_x(Qu.X) + + # Make sure to lift correctly + if Pu.weil_pairing(Qu, 2 ** (e + 2)) ** (g_v * N1 * N2) != Pv.weil_pairing(Qv, 2 ** (e + 2)) ** (g_u): + Qv = -Qv + + # Double check full order + assert Pu.weil_pairing(Qu, 2 ** (e + 2)) ** (2 ** (e + 2)) == 1 + assert Pu.weil_pairing(Qu, 2 ** (e + 2)) ** (2 ** (e + 1)) != 1 + assert Pv.weil_pairing(Qv, 2 ** (e + 2)) ** (2 ** (e + 2)) == 1 + assert Pv.weil_pairing(Qv, 2 ** (e + 2)) ** (2 ** (e + 1)) != 1 + # Weil pairing check + assert Pu.weil_pairing(Qu, 2 ** (e + 2)) ** (g_v * N1 * N2) == Pv.weil_pairing(Qv, 2 ** (e + 2)) ** (g_u) + + return N1, N2, x_u, y_u, g_u, x_v, y_v, g_v, Pu, Qu, Pv, Qv diff --git a/ideals.py b/ideals.py index 7065c2e..722653c 100644 --- a/ideals.py +++ b/ideals.py @@ -1,40 +1,58 @@ -from sage.all import * +#!/usr/bin/env python3 + import itertools as itt -from time import time +from random import randint + +from sage.arith.misc import next_prime +from sage.matrix.constructor import Matrix +from sage.misc.functional import isqrt +from sage.arith.misc import kronecker +from sage.rings.integer import Integer +from sage.rings.rational_field import QQ +from sage.rings.finite_rings.finite_field_constructor import GF +from sage.rings.integer_ring import ZZ + -def NormEl(el, p): - return el[0]**2 + p*el[1]**2 +def element_norm(el, p): + return el[0] ** 2 + p * el[1] ** 2 -def MulEl(el1, el2, p): + +def element_multiply(el1, el2, p): a1, b1 = el1 a2, b2 = el2 - return [a1*a2 - p*b1*b2, a1*b2 + b1*a2] + return [a1 * a2 - p * b1 * b2, a1 * b2 + b1 * a2] + -def ScaleEl(el, scal): +def element_scale(el, scal): a, b = el - return [a/scal, b/scal] + return [a / scal, b / scal] + def _norm(v): return sum([x**2 for x in v]) + def _add(a, b): - return [ia + ib for ia, ib in zip(a,b)] + return [ia + ib for ia, ib in zip(a, b)] + def _mul(v, n): - return [x*n for x in v] + return [x * n for x in v] + def _is_zero(v): return all([x == 0 for x in v]) -def ShortVectors(L, B, cf_b=15): + +def short_vectors(L, B, cf_b=15): """ Enumerate vectors in L with norm bounded by B. Tries linear combinations with coefficients up to cf_b """ sv = {} - assert len(L) == 2 # Avoiding sign repeats + assert len(L) == 2 # Avoiding sign repeats for cff in itt.product(range(-cf_b, cf_b), range(0, cf_b)): - # for cff in itt.product(range(-cf_b, cf_b), repeat=len(L)): + # for cff in itt.product(range(-cf_b, cf_b), repeat=len(L)): v = [0 for _ in range(len(L[0]))] for i in range(len(L)): v = _add(v, _mul(L[i], cff[i])) @@ -45,7 +63,8 @@ def ShortVectors(L, B, cf_b=15): sv.sort() return sv -def ShortIdeals(I, N, B, p, spr=None, cf_b=15): + +def short_ideals(ideal, ideal_norm, norm_bound, p, spr=None, cf_b=15): """ For a given ideal returns the shortest vectors (or equivalently the smallest equivalent ideals). @@ -62,35 +81,35 @@ def ShortIdeals(I, N, B, p, spr=None, cf_b=15): and ideal I1 equivalent to I, n is the norm of I1 and c is the short element in I sending I to I1 """ + gens = [list(gen) for gen in ideal.gens()] + if not spr: spr = isqrt(p) - L = Matrix(ZZ, 2,[ - I[0][0], spr*I[0][1], - I[1][0], spr*I[1][1] - ]) + L = Matrix(ZZ, 2, [gens[0][0], spr * gens[0][1], gens[1][0], spr * gens[1][1]]) L = L.LLL() L = [L[0], L[1]] res = [] - sv2 = ShortVectors(L, N*B, cf_b=cf_b) + sv2 = short_vectors(L, ideal_norm * norm_bound, cf_b=cf_b) for _, sh in sv2: - cshel = [sh[0], -sh[1]/spr] + cshel = [sh[0], -sh[1] / spr] if sh[1] % spr != 0: - print('Non divisible') - idl = [ScaleEl(MulEl(I[0], cshel, p), N), ScaleEl(MulEl(I[1], cshel, p), N), cshel] - res.append((NormEl(cshel, p)/N, idl)) + print("Non divisible") + idl = [element_scale(element_multiply(gens[0], cshel, p), ideal_norm), element_scale(element_multiply(gens[1], cshel, p), ideal_norm), cshel] + res.append((element_norm(cshel, p) / ideal_norm, idl)) return res -def ReducedBasis(I_basis): - #LLL is way overkill here, change later + +def reduced_basis(I_basis): + # LLL is way overkill here, change later def _matrix_to_gens(M, B): return [sum(c * g for c, g in zip(row, B)) for row in M] def gram_matrix(basis): M = [] for a in basis: - M.append([(a*b.conjugate()).trace() for b in basis]) + M.append([(a * b.conjugate()).trace() for b in basis]) return Matrix(QQ, M) G = gram_matrix(I_basis) @@ -98,39 +117,44 @@ def ReducedBasis(I_basis): reduced_basis_elements = _matrix_to_gens(U, I_basis) return reduced_basis_elements -def PrincipalGenerator(frak_a): + +def principal_generator(frak_a): N = frak_a.norm() assert len(frak_a.gens()) == 2, "The ideal has only one generator (which is not really an issue)" - for gen in ReducedBasis(frak_a.gens()): + for gen in reduced_basis(frak_a.gens()): if gen.norm() == N: return gen assert False, "WARNING: Not a principal ideal" -def Conjugate(order, frak_a): + +def conjugate(order, frak_a): a, b = frak_a.gens_two() - return order*a.conjugate() + order*b.conjugate() + return order * a.conjugate() + order * b.conjugate() -def RandomDegreeOnePrimeIdeal(order, gen, p): - ell = next_prime(randint(-order.discriminant(), -10*order.discriminant())) + +def random_degree_one_ideal(order, gen, p): + ell = next_prime(randint(-order.discriminant(), -10 * order.discriminant())) while kronecker(-p, ell) != 1: - ell = next_prime(randint(-order.discriminant(), -10*order.discriminant())) + ell = next_prime(randint(-order.discriminant(), -10 * order.discriminant())) lam = Integer(GF(ell)(-p).sqrt()) - frak_ell = order*ell + order*(gen-lam) + frak_ell = order * ell + order * (gen - lam) assert frak_ell.norm() == ell return ell, frak_ell -def RandomFixedPrimeIdeal(order, gen, p, ell): + +def random_fixed_prime_ideal(order, gen, p, ell): lam = Integer(GF(ell)(-p).sqrt()) - frak_ell = order*ell + order*(gen-lam) + frak_ell = order * ell + order * (gen - lam) assert frak_ell.norm() == ell return ell, frak_ell + def ideal_to_sage(I, O): """ Converts an ideal as a list of lists into @@ -141,7 +165,6 @@ def ideal_to_sage(I, O): pi = O.gens()[1] - g1 = I[0][0] + pi*I[0][1] - g2 = I[1][0] + pi*I[1][1] - return O*g1 + O*g2 - + g1 = I[0][0] + pi * I[0][1] + g2 = I[1][0] + pi * I[1][1] + return O * g1 + O * g2 diff --git a/independent-verification.py b/independent-verification.py new file mode 100644 index 0000000..62b0588 --- /dev/null +++ b/independent-verification.py @@ -0,0 +1,79 @@ +#!/usr/bin/env python3 + +from logging import getLogger + +from sage.arith.misc import kronecker_symbol +from sage.rings.finite_rings.finite_field_constructor import GF +from sage.rings.integer import Integer +from sage.schemes.elliptic_curves.mod_poly import classical_modular_polynomial +from sage.rings.fast_arith import prime_range + +from multiprocessing import Process, Queue, cpu_count + +from pegasis import PEGASIS + +pegasis_logger = getLogger("pegasis") +pegasis_logger.setLevel("WARNING") + +SENTINEL = None + + +def test(ell): + EGA = PEGASIS(500) + + ideal = ell * EGA.order + (EGA.w - Integer(GF(ell)(-EGA.p).sqrt())) * EGA.order + + E = EGA.action(EGA.E_start, ideal) + + modular_polynomial = classical_modular_polynomial(ell, j=EGA.E_start.j_invariant()) + + return (modular_polynomial(E.j_invariant()) == 0, ell) + + +def __test(q_in, q_out): + while True: + ell = q_in.get() + + if ell is SENTINEL: + q_out.put((SENTINEL, SENTINEL)) + return + + q_out.put(test(ell)) + + +if __name__ == "__main__": + EGA = PEGASIS(500) + good_ells = [ell for ell in prime_range(2, 2**16) if kronecker_symbol(-EGA.p, ell) == 1] + + q_in = Queue() + q_out = Queue() + + for ell in good_ells: + q_in.put(ell) + + processes = [Process(target=__test, args=(q_in, q_out)) for _ in range(cpu_count() - 1)] + + for process in processes: + process.start() + + sentinels = 0 + finished = False + tries = 0 + success = 0 + max_ell_computed = 0 + + while sentinels < cpu_count() - 1: + + result, ell = q_out.get() + + if result is SENTINEL: + sentinels += 1 + continue + + tries += 1 + if result: + success += 1 + + max_ell_computed = max(max_ell_computed, ell) + + print(f"Success rate {success / tries * 100:.1f}% of {tries:>4} attempts (Max ell: {max_ell_computed})") diff --git a/lcsidh.py b/lcsidh.py index 30ff6ce..9e2d91e 100644 --- a/lcsidh.py +++ b/lcsidh.py @@ -1,195 +1,242 @@ -from sage.all import( - isqrt, sqrt, floor, prod, - randint, - log, - proof, - next_prime, - kronecker, - GF, ZZ, QQ, - Matrix, - gcd, xgcd, valuation, -) - -from coin import sos_pair_generator, xsos_pair_generator -from ideals import ideal_to_sage, ShortIdeals -import time +#!/usr/bin/env python3 + +from sage.all import proof +from sage.arith.misc import gcd, valuation + +from coin import sos_coins +from ideals import ideal_to_sage, short_ideals +from utilities import remove_common_factors import logging + logger = logging.getLogger(__name__) logger.setLevel(logging.WARNING) logger_sh = logging.StreamHandler() logger_sh.setLevel(logging.WARNING) -formatter = logging.Formatter('%(name)s [%(levelname)s] %(message)s') +formatter = logging.Formatter("%(name)s [%(levelname)s] %(message)s") logger_sh.setFormatter(formatter) logger.addHandler(logger_sh) proof.all(False) -def generate_combs(n): - """ - Generate pairs (i, j) sorted by L1-norm. - """ - i_start = 1 - while i_start < n: - i = i_start - j = 0 - while i > j: - yield i, j - j += 1 - i -= 1 - i_start += 1 - - -def eval_sol(vals, allowed_primes): - """ - Given a list vals of Elkies isogenies of degrees contained in - allowed_primes, estimate the total cost of such isogeny. The cost of a - single step is assumed to be linear in the degree. +def ascending_combinations(max_norm): + """Sequence of distinct non-negative integer pairs in ascending L1-norm up to permutation + + The pairs returned (x, y) satisfy x >= y + + Arguments: + - max_norm: Return pairs with L1 norm strictly less than max_norm + + Note: We return pairs with L1-norm up to (but not including) max_norm for compatibility with previous + implementatation. """ - costs = {} - for li in allowed_primes: - cost_li = 0 - for vi in vals: - cost_li += valuation(vi, li) - costs[li] = cost_li - return sum(li * costs[li] for li in allowed_primes) + norm = 0 + while norm < max_norm: + for i in range(norm): + # Pair `norm - i, i` has L1-norm `norm` + # We want pairs up to permutation, so we only return if `norm - i < i` + if norm - i > i: + yield norm - i, i + norm += 1 -def UVSolver(R, N_R, uv_params): +def two_signature(ideal, twoval, uv_params): + """Return signature of norm-2-ideals contained in ideal + + Input: + - ideal: Ideal as list of generators, where a generator is + a pair of numbers [a, b] representing the element a + ib + - twoval: The 2-valuation of the norm of the input ideal + - uv_params: Instance of uv_params class for ambient order information + + Ouput: Tuple of integers + + (left - min(left, right), right - min(left, right)) + + Where two_left**left divides ideal and two_right**right divides ideal + + Note: One entry of the output tuple is zero. """ - Given an ideal R try to find two equivalent ideals I_1 and I_2 such that, + + ideal_sage = ideal_to_sage(ideal, uv_params.max_order) + + # Compute common part + ideal_common_two_left = ideal_sage + uv_params.two_left**twoval + ideal_common_two_right = ideal_sage + uv_params.two_right**twoval + + # Get the power that actually was common + twoval_left = valuation(ideal_common_two_left.norm(), 2) + twoval_right = valuation(ideal_common_two_right.norm(), 2) + + # Now we know two_left divides ideal twoval_left times (same for right) + # If both two_left and two_right divides ideal, then ideal contains the + # ideal corresponding to multiplication_by_two + # We assume this will be factored later on, so we remove it from our + # signature + mult_by_two = min(twoval_left, twoval_right) + + return twoval_left - mult_by_two, twoval_right - mult_by_two + + +def UVSolver(ideal, ideal_norm, uv_params): + """Solve UV equation for given ideal + + Given an ideal ideal try to find two equivalent ideals I_1 and I_2 such that, after writing n(I_1) = N1*cof1 and n(I_2) = N2*cof2 we can solve the equation u*N1 + v*N2 = 2^e for u and v sums of two squares. Input: - - R: the input ideal as a list of generators, where a generator is a pair - of numbers [a, b] representing the element a + ib; - - N_R: the (ideal) norm of R; - - uv_params: an instance of uv_params.UV_params containing the parameters - for the algorithm, as described in the UV_params class. + - ideal: the input ideal as sage ideal + - ideal_norm: the (ideal) norm of ideal; + - uv_params: an instance of uv_params.UV_params containing the parameters + for the algorithm, as described in the UV_params class. + + Note: e from the 2^e in the norm equation above is given by + uv_params Output: - - u, v, ids[i], ids[j], sig_1, sig_2, t + - u, v, I_1, I_2, sig_1, sig_2, t + where - - u, v are written as (x_u, y_u, g_u) such that g_u*(x_u^2 + y_2^2)=u - - ids[i], ids[j] are ideals represented as (norm, cofactor, 2-valuation, - gens); norm * cofactor * 2**(2-valuation) is the norm if the ideal - generated by gens; - - setting n1=ids[i][0], n2 = ids[j][0] (the cofactor-free norms) it holds - 2**t == u*n1 + v*n2; in general t <= uv_params.e, but they do not need to - be equal; - - sig_1, sig_2 are the ideals over 2 that are left in ids[i], ids[j] - respectively after multiplications by two are removed, as a pair (left, - right); one between left and right must be zero; if they point in the - same direction (e. g. (e_1, 0) and (e_2, 0)) the algorithm assumes that - the common part is computed in advance and removed by the ideals. - - if uv_params.n_squares=1, only one among u and v is decomposed as sum of - squares + - u, v are written as + (x_u, y_u, g_u) + such that g_u*(x_u^2 + y_2^2)=u + + Note: if uv_params.n_squares=1, only one among u and v is decomposed as + sum of squares. + + - I_1, I_2 are ideals represented as + (norm, cofactor, 2-valuation, gens) + where + norm * cofactor * 2**(2-valuation) + is the norm of the ideal generated by gens; + + - setting + n1 = I_1[0], n2 = I_2[0] (the cofactor-free norms) + it holds + 2**t == u*n1 + v*n2 + in general t <= uv_params.e, but they do not need to be equal; + + - sig_1, sig_2 are the ideals over 2 that are left in I_1, I_2 + respectively after multiplications-by-two are removed, as a pair (left, + right). + + One of `left` and `right` must be zero; if they point in the same + direction (e. g. (e_1, 0) and (e_2, 0)) the algorithm assumes that the + common part is computed in advance and removed by the ideals. """ - # Look for short vectors # Elements of L are of the form (norm, [elements]) p, spr = uv_params.p, uv_params.spr norm_bound = uv_params.norm_bound - L = ShortIdeals(R, N_R, norm_bound*spr, p, spr, uv_params.norm_cff_bound) - logger.info(f'{len(L) = }') + L = short_ideals(ideal, ideal_norm, norm_bound * spr, p, spr, uv_params.norm_cff_bound) + logger.info(f"{len(L) = }") # Remove allowed primes - ids = {} + ideals = {} for nI, I in L: + if gcd(nI, ideal_norm) > 1: + continue # Even exponents v2 = nI.valuation(2) nI //= 2**v2 - k = nI / gcd(nI, uv_params.allowed_primes_prod) - while gcd(k, uv_params.allowed_primes_prod) != 1: - k /= gcd(k, uv_params.allowed_primes_prod) + smooth_part, rough_cofactor = remove_common_factors(nI, uv_params.allowed_primes_prod) - cof = nI/k - if k in ids and cof*2**v2 >= ids[k][0]*2**ids[k][1]: + if smooth_part in ideals and rough_cofactor * 2**v2 >= ideals[smooth_part][0] * 2 ** ideals[smooth_part][1]: # Multiple of a previous vector continue - ids[k] = (cof, v2, I) + ideals[smooth_part] = (rough_cofactor, v2, I) # Short vectors sorted by cofactor-free norm - ids = [(j,) + ids[j] for j in ids] - ids.sort() + ideals = [(j,) + ideals[j] for j in ideals] + ideals.sort() - two_parts = {} - two_left = ideal_to_sage([[2, 0], [-1/2, 1/2]], uv_params.max_order) - two_right = ideal_to_sage([[2, 0], [1/2, 1/2]], uv_params.max_order) + cached_two_signatures = {} # Keep track of the best solution found so far best_sol = None best_cost = None - sol_cnt = 0 - - def compute_two_sig(id_i, v2_i): - id_sage = ideal_to_sage(id_i, uv_params.max_order) - id_l = id_sage + two_left**v2_i - id_r = id_sage + two_right**v2_i - v2_l = valuation(id_l.norm(), 2) - v2_r = valuation(id_r.norm(), 2) - mul2 = min(v2_l, v2_r) - sig_i = (v2_l - mul2, v2_r - mul2) - return sig_i + sol_count = 0 # Try pairs to solve the coin equation - for i, j in generate_combs(min(len(ids), uv_params.comb_bound)): + for i, j in ascending_combinations(min(len(ideals), uv_params.comb_bound)): - if uv_params.sol_bound and sol_cnt >= uv_params.sol_bound: + if uv_params.sol_bound and sol_count >= uv_params.sol_bound: break - n1, cof1, v2_1, id1 = ids[i] - n2, cof2, v2_2, id2 = ids[j] - if gcd(n1, n2) != 1: + + norm_1, _, v2_1, ideal_1 = ideals[i] + norm_2, _, v2_2, ideal_2 = ideals[j] + + if gcd(norm_1, norm_2) != 1: continue # Compute the part above two of the ideals - if i in two_parts: - sig_1 = two_parts[i] + if i in cached_two_signatures: + signature_1 = cached_two_signatures[i] else: - sig_1 = compute_two_sig(id1, v2_1) - two_parts[i] = sig_1 + signature_1 = two_signature(ideal_1, v2_1, uv_params) + # Update cache + cached_two_signatures[i] = signature_1 - if j in two_parts: - sig_2 = two_parts[j] + if j in cached_two_signatures: + signature_2 = cached_two_signatures[j] else: - sig_2 = compute_two_sig(id2, v2_2) - two_parts[j] = sig_2 + signature_2 = two_signature(ideal_2, v2_2, uv_params) + # Update cache + cached_two_signatures[j] = signature_2 - # Compute the remeaning torsion - used_torsion = abs(sig_1[0] - sig_2[0]) + abs(sig_1[1] - sig_2[1]) - av_torsion = uv_params.uv_e - used_torsion + # Compute the remaining torsion + used_torsion = abs(signature_1[0] - signature_2[0]) + abs(signature_1[1] - signature_2[1]) + remaining_torsion = uv_params.uv_e - used_torsion # Avoid generating too many combinations for a single pair - local_sol_ncnt = 0 - for u, v, t in xsos_pair_generator(n1, n2, av_torsion, - uv_params.sos_allowed_primes, - n_squares=uv_params.n_squares): - sol_cnt += 1 - local_sol_ncnt += 1 + local_sol_count = 0 + + for (_, x_u, y_u, g_u), (_, x_v, y_v, g_v), t in sos_coins( + norm_1, norm_2, remaining_torsion, uv_params.sos_allowed_primes, n_squares=uv_params.n_squares + ): + + assert g_u * (x_u ** 2 + y_u ** 2) * norm_1 + g_v * (x_v ** 2 + y_v ** 2) * norm_2 == 2**t + + sol_count += 1 + local_sol_count += 1 if uv_params.sol_bound == 1: - return u, v, ids[i], ids[j], sig_1, sig_2, t + return (x_u, y_u, g_u), (x_v, y_v, g_v), ideals[i], ideals[j], signature_1, signature_2, t # Cost estimate for best solution - elkies_vals = [ids[i][1], ids[j][1]] - if type(u) in [tuple, list]: - elkies_vals.append(u[2]) - if type(v) in [tuple, list]: - elkies_vals.append(v[2]) - elkies_cost = eval_sol(elkies_vals, uv_params.allowed_primes) - if not best_sol or elkies_cost < best_cost: - best_sol = u, v, ids[i], ids[j], sig_1, sig_2, t + elkies_steps = [] + + # Append cost of elkies steps + # Recall: ideals[i] is a tuple (norm, cofactor, twoval, ideal) + # The cofactor is smooth, and constains the product of norms of elkies steps + elkies_steps.append(ideals[i][1]) + elkies_steps.append(ideals[j][1]) + + elkies_steps.append(g_u) + elkies_steps.append(g_v) + + # Recall: Elkies steps of norm prime are done for all primes in uv_params.allowed_primes + # We assume cost to be linear in the size of the prime + # We count the number of steps required by getting the sum of valuations for each ideal + elkies_cost = sum( + [prime * sum([valuation(value, prime) for value in elkies_steps]) for prime in uv_params.allowed_primes] + ) + + if not best_sol or not best_cost or elkies_cost < best_cost: + best_sol = (x_u, y_u, g_u), (x_v, y_v, g_v), ideals[i], ideals[j], signature_1, signature_2, t best_cost = elkies_cost - if sol_cnt >= uv_params.sol_bound: + + if sol_count >= uv_params.sol_bound: break - if local_sol_ncnt > 3: # TODO: this is completely arbitrary + + # @TODO: this is completely arbitrary + if local_sol_count > 3: break return best_sol - diff --git a/pegasis.py b/pegasis.py index 38384e6..315e626 100644 --- a/pegasis.py +++ b/pegasis.py @@ -1,13 +1,17 @@ from time import time import logging -from sage.all import * +from sage.rings.integer import Integer +from sage.arith.misc import kronecker_symbol +from sage.rings.finite_rings.finite_field_constructor import GF -from xonly import xPoint, random_xPoint, MontgomeryA, isWeierstrass, translate_by_T +from xonly import xPoint from lcsidh import UVSolver from uv_params import UV_params -from ideals import ideal_to_sage, PrincipalGenerator, Conjugate, RandomDegreeOnePrimeIdeal -from elkies import Elkies +from ideals import random_degree_one_ideal +from dim1_isogenies import small_prime_ideal_action +from ideals import ideal_to_sage +from ideal_to_kernel import ideal_to_kernel #from theta_lib.isogenies.Kani_clapoti import KaniClapotiIsog from Theta_dim4.Theta_dim4_sage.pkg.isogenies.Kani_clapoti import KaniClapotiIsog @@ -15,15 +19,16 @@ from Theta_dim4.Theta_dim4_sage.pkg.isogenies.Kani_clapoti import KaniClapotiIso logger = logging.getLogger(__name__) logger.setLevel(logging.WARNING) logger_sh = logging.StreamHandler() -formatter = logging.Formatter('%(name)s [%(levelname)s] %(message)s') +formatter = logging.Formatter("%(name)s [%(levelname)s] %(message)s") logger_sh.setFormatter(formatter) logger.addHandler(logger_sh) + class PEGASIS: def __init__(self, level, params=None): r""" Main Clapoti class. Takes as input the security level - (500|1000|1500|2000|4000) and generates the necessary parameters and + (100|500|1000|1500|2000|4000) and generates the necessary parameters and structures to solve the norm equation and run the Clapoti algorithm. Additional parameters can be supplied as a dictionary. """ @@ -62,11 +67,11 @@ class PEGASIS: if kronecker_symbol(-self.p, ell) == 1: self.lam = Integer(GF(ell)(-self.p).sqrt()) self.small_ell = ell - self.frak_ell = self.order*ell + self.order*(self.w-self.lam) + self.frak_ell = self.order * ell + self.order * (self.w - self.lam) assert self.frak_ell.norm() == ell break - def action(self, E, frak_a, verb_return = False): + def action(self, E, frak_a, verb_return=False): r""" Function for computes the class action of any ideal. Input: @@ -76,27 +81,22 @@ class PEGASIS: - frak_a * E - Optional: Extra data for measuring performance """ - compensate = 0 + rerandomizations = 0 logger.info("") - logger.info("="*50) + logger.info("=" * 50) logger.info("Starting UV Solver....") - logger.info("="*50) + logger.info("=" * 50) # Step 1: find u and v _t0 = time() - _rerand_cnt = 0 uv_output = None while not uv_output: - uv_output = UVSolver( - [list(beta) for beta in frak_a.gens()], frak_a.norm(), - self.uv_params) + uv_output = UVSolver(frak_a, frak_a.norm(), self.uv_params) if not uv_output: - _rerand_cnt += 1 - frak_a = frak_a*self.frak_ell - compensate += 1 + rerandomizations += 1 + frak_a = frak_a * self.frak_ell logger.debug("Rerandomising!") - continue _t1 = time() logger.info(f"Used {_t1 - _t0} seconds") @@ -106,41 +106,49 @@ class PEGASIS: _n1, _cof1, _v21, _gens1 = b_list _n2, _cof2, _v22, _gens2 = c_list - if compensate > 0: - E = E.short_weierstrass_model() - prev_j = None - for _ in range(compensate): - logger.debug("Compensation step") - E_prev = E - E = self.small_prime_ideal_action(E, self.small_ell, self.small_ell - self.lam, prev_j).codomain() - prev_j = E_prev.j_invariant() - E = E.montgomery_model() + N1, b_cof, b_twopower, frak_b_list = b_list + N2, c_cof, c_twopower, frak_c_list = c_list + frak_b = ideal_to_sage(frak_b_list, self.order) + frak_c = ideal_to_sage(frak_c_list, self.order) + assert frak_b.is_equivalent(frak_a) + assert frak_c.is_equivalent(frak_a) + + E = E.short_weierstrass_model() + prev_j = None + for _ in range(rerandomizations): + logger.debug("Compensation step") + E_prev = E + E = small_prime_ideal_action(E, self.small_ell, self.small_ell - self.lam, prev_j).codomain() + prev_j = E_prev.j_invariant() + E = E.montgomery_model() logger.info("") - logger.info("="*50) + logger.info("=" * 50) logger.info("Starting Ideal Action....") - logger.info("="*50) - N1, N2, x_u, y_u, g_u, x_v, y_v, g_v, Pu, Qu, Pv, Qv = self.ideal_to_kernel(E, [u,v], [b_list, c_list], t) + logger.info("=" * 50) + N1, N2, x_u, y_u, g_u, x_v, y_v, g_v, Pu, Qu, Pv, Qv = ideal_to_kernel( + E, [u, v], [b_list, c_list], self.max_order, self.w, t + ) _t2 = time() logger.info(f"Used {_t2 - _t1} seconds") # Sanity checks - assert all([not R*2**(t+2) for R in [Pu, Qu, Pv, Qv]]) - assert all([bool(R*2**(t+1)) for R in [Pu, Qu, Pv, Qv]]) - assert Pu.weil_pairing(Qu, 2**(t+2))**(g_v*N1*N2) == Pv.weil_pairing(Qv, 2**(t+2))**(g_u) - assert N1*g_u*(x_u**2 + y_u**2) + N2*g_v*(x_v**2 + y_v**2) == 2**t + assert all([not R * 2 ** (t + 2) for R in [Pu, Qu, Pv, Qv]]) + assert all([bool(R * 2 ** (t + 1)) for R in [Pu, Qu, Pv, Qv]]) + assert Pu.weil_pairing(Qu, 2 ** (t + 2)) ** (g_v * N1 * N2) == Pv.weil_pairing(Qv, 2 ** (t + 2)) ** (g_u) + assert N1 * g_u * (x_u**2 + y_u**2) + N2 * g_v * (x_v**2 + y_v**2) == 2**t # Step 3 : 4d iso logger.info("") - logger.info("="*50) + logger.info("=" * 50) logger.info(f"Starting 4D isog") - logger.info("="*50) + logger.info("=" * 50) logger.debug("Starting product: ") logger.debug(Pu.curve()) logger.debug(Qv.curve()) - F = KaniClapotiIsog([Pu,Qu,Pv,Qv],[g_u,x_u,y_u,g_v,x_v,y_v,N1,N2,t]) + F = KaniClapotiIsog([Pu, Qu, Pv, Qv], [g_u, x_u, y_u, g_v, x_v, y_v, N1, N2, t]) logger.debug(f"Change of coordinates: {F.iso_type} Twist={F.twist}") _t3 = time() @@ -152,7 +160,7 @@ class PEGASIS: "time_step2": _t2 - _t1, "time_step3": _t3 - _t2, "time_total": _t3 - _t0, - "rerandomizations": _rerand_cnt, + "rerandomizations": rerandomizations, "u": u, "v": v, "g_u": g_u, @@ -167,7 +175,7 @@ class PEGASIS: "_cof2": _cof2, "_v21": _v21, "_v22": _v22, - "t": t + "t": t, } if verb_return: @@ -175,531 +183,8 @@ class PEGASIS: return F.Ea.change_ring(self.Fp) - - def ideal_to_kernel(self, E, uv, frak_bc, e): - r""" - Following sec. 5.4, prepare the data necessary for the 4D isogeny. - Input: - - E: starting curve - - uv: the decomposition of u and v as cof + sum of squares - - frak_bc: the ideals b and c as output of UVSolver - - e: the torsion we want to use - - Output: - - N1, N2, x_u, y_u, g_u, x_v, y_u, g_v e s.t. - N1*g_u*(x_u^2 + y_u^2) + N2*g_v*(x_v^2 + y_v^2) == 2^e - - P_u, Q_u, P_v, Q_v: image points on E_u, Ev as described - in sec 5.4 - """ - # First recover the numbers - tstart = time() - if type(uv[0]) == tuple: - (x_u, y_u, g_u) = uv[0] - else: - x_u = None - y_u = None - g_u = 1 - - if type(uv[1]) == tuple: - (x_v, y_v, g_v) = uv[1] - else: - x_v = None - y_v = None - g_v = 1 - - # (x_u, y_u, g_u), (x_v, y_v, g_v) = uv - b_list, c_list = frak_bc - - N1, b_cof, b_twopower, frak_b_list = b_list - N2, c_cof, c_twopower, frak_c_list = c_list - - # assert N1 * g_u * (x_u**2 + y_u**2) + N2 * g_v * (x_v**2 + y_v**2) == 2**e - - def div_by_n(ideal, n): - generators = [gi / n for gi in ideal.gens()] - return sum([self.max_order * gi for gi in generators]) - - frak_b = ideal_to_sage(frak_b_list, self.max_order) - frak_c = ideal_to_sage(frak_c_list, self.max_order) - - if b_twopower > 1: # factors through two - frak_b = div_by_n(frak_b, 2) - if c_twopower > 1: - frak_c = div_by_n(frak_c, 2) - - #The part thats the same for b and c - frak_bc_same = frak_b + frak_c - - #We only want the "unique" part of b and c - frak_b = div_by_n(frak_b * Conjugate(self.max_order, frak_bc_same), frak_bc_same.norm()) - frak_c = div_by_n(frak_c * Conjugate(self.max_order, frak_bc_same), frak_bc_same.norm()) - - frak_b_2 = frak_b + self.max_order*((2**frak_b.norm().valuation(2))) - frak_c_2 = frak_c + self.max_order*((2**frak_c.norm().valuation(2))) - - odd_part = Integer(frak_bc_same.norm()).prime_to_m_part(2) - pow2_part = frak_bc_same.norm()/odd_part - frak_bc_same_2 = frak_bc_same + self.max_order*pow2_part - frak_bc_same_odd = frak_bc_same + self.max_order*odd_part - - b_cof = b_cof/odd_part - c_cof = c_cof/odd_part - - #First step to the starting curve given by same direction steps - ee = valuation(self.p+1, 2) - 1 - logger.debug("Walking to starting point (i.e. steps that are same for b and c)...") - if frak_bc_same.norm() > 1: - if pow2_part > 1: - P_temp, Q_temp = self.TwoTorsBasis(E, ee) - #P_temp, Q_temp = TwoTorsBasis(E, two_pow) - _, E = self.ideal_above_2_action(E, P_temp, Q_temp, ee, frak_bc_same_2) - if odd_part > 1: - _, E = self.smooth_ideal_action(E, odd_part, frak_bc_same_odd) - logger.debug(f"Done! Have used {time() - tstart}") - P, Q = self.TwoTorsBasis(E, ee) - #P, Q = TwoTorsBasis(E, ee) - - # Doing the Elkies steps for b - logger.debug("odd Elkies steps for b and conjugate of c") - # These are really different directions, so we can - isogs_cof, E1 = self.smooth_ideal_action(E, b_cof*c_cof, frak_b*Conjugate(self.max_order, frak_c)) - P1, Q1 = P, Q - for phi in isogs_cof: - P1 = P1.push(phi) - Q1 = Q1.push(phi) - logger.debug(f"Done! Have used {time() - tstart}") - - #Adjust the order - P1, Q1 = P1.xMUL(2**(ee - (e+2))), Q1.xMUL(2**(ee - (e+2))) - - assert P1.xMUL(2**(e+1)) - assert not P1.xMUL(2**(e+2)) - assert Q1.xMUL(2**(e+1)) - assert not Q1.xMUL(2**(e+2)) - #At this point, P1, Q1 are the "starting points" - - logger.debug("Doing g_u isogeny") - g_u_isogs, Eu = self.random_smooth_isogeny(E1, g_u) - Pu, Qu = P1, Q1 - for phi_gu in g_u_isogs: - Pu = Pu.push(phi_gu) - Qu = Qu.push(phi_gu) - logger.debug(f"Done! Have used {time() - tstart}") - - # Now the second part - # Evaluating the endomorphism - logger.debug("Evaluating the endomorphism frak_b*frac_c_bar") - rho_bc = PrincipalGenerator(frak_b*Conjugate(self.max_order, frak_c)) - rho_bc_val_2 = rho_bc.norm().valuation(2) - - #assert (frak_b*frak_c).norm() == rho_bc.norm() - #assert rho_bc in frak_b - #assert rho_bc.conjugate() in frak_c - - #adjust_2 = 0 - #if rho_bc_val_2 > 0: #Here we really need to clear denominators to evaluate the endomorphism - # rho_bc *= 2 - # adjust_2 = 1 - - #print("!!!!!!!!!") - #print(ee-(rho_bc_val_2)) - #print(e+2) - #assert ee-(rho_bc_val_2 + adjust_2) >= e+2, "NotImplemented: We can drop adjust_2 if we allow extension-fields" - #print(f"Evaluating {rho_bc}") - max = (ee - rho_bc_val_2 == e+2) - Pc = self.eval_endomorphism(rho_bc, P, False, max) - Qc = self.eval_endomorphism(rho_bc, Q, True, max) - - logger.debug(f"Done! Have used {time() - tstart}") - - # Act with 2-ideals right away. - logger.debug("Acting with 2-part of frak_b and frak_c") - #print(f"!!!! {frak_c_2.norm(), frak_b_2.norm()}") - #print(f"!!!? {rho_bc_val_2}") - if frak_c_2.norm() > 1 or frak_b_2.norm() > 1: - frak_bc_2 = frak_c_2*Conjugate(self.max_order, frak_b_2) - phi_2, E = self.ideal_above_2_action(E, P, Q, ee, frak_bc_2) - Pc = Pc.push(phi_2) - Qc = Qc.push(phi_2) - - logger.debug(f"Done! Have used {time() - tstart}") - P2 = Pc.xMUL(2**(ee - (e+2) - (rho_bc_val_2))) - Q2 = Qc.xMUL(2**(ee - (e+2) - (rho_bc_val_2))) - - assert P2.xMUL(2**(e+1)) - assert not P2.xMUL(2**(e+2)) - assert Q2.xMUL(2**(e+1)) - assert not Q2.xMUL(2**(e+2)) - E2 = E - - logger.debug("Doing g_v isogeny") - Pv, Qv = P2, Q2 - - g_v_isogs, Ev = self.random_smooth_isogeny(E2, g_v) - - for phi_gv in g_v_isogs: - Pv = Pv.push(phi_gv) - Qv = Qv.push(phi_gv) - logger.debug(f"Done! Have used {time() - tstart}") - - Ev = Pv.curve.change_ring(self.Fp2) - Eu = Pu.curve.change_ring(self.Fp2) - - Pv = Ev.lift_x(Pv.X) - Qv = Ev.lift_x(Qv.X) - - Pu = Eu.lift_x(Pu.X) - Qu = Eu.lift_x(Qu.X) - - #Make sure to lift correctly - if Pu.weil_pairing(Qu, 2**(e+2))**(g_v*N1*N2) != Pv.weil_pairing(Qv, 2**(e+2))**(g_u): - Qv = -Qv - - # Double check full order - assert Pu.weil_pairing(Qu, 2**(e+2))**(2**(e+2)) == 1 - assert Pu.weil_pairing(Qu, 2**(e+2))**(2**(e+1)) != 1 - assert Pv.weil_pairing(Qv, 2**(e+2))**(2**(e+2)) == 1 - assert Pv.weil_pairing(Qv, 2**(e+2))**(2**(e+1)) != 1 - # Weil pairing check - assert Pu.weil_pairing(Qu, 2**(e+2))**(g_v*N1*N2) == Pv.weil_pairing(Qv, 2**(e+2))**(g_u) - - return N1, N2, x_u, y_u, g_u, x_v, y_v, g_v, Pu, Qu, Pv, Qv - - def sample_ideal(self): - r""" - Samples a random ideal of End(E) + r"""Sample a random ideal of the class group """ - N_a, frak_a = RandomDegreeOnePrimeIdeal(self.order, self.w, self.p) - return frak_a - - def ideal_above_2_action(self, E, P, Q, basis_ord, frak_a): - r""" - Computes the action of a power of an ideal above 2 using Velu. - Input: - - E: Elliptic curve over Fp - - P, Q: Basis of E[2^basis_ord], where P is in E(Fp) and Q is in Et(Fp) for a quadratic twist Et - - basis_ord: The order of P, Q (log_2) - - frak_a: A power of an ideal above 2 - Output: - - phi : The isogeny corresponding to frak_a - - frak_a * E - """ - _, val_2_frak_a = factor(frak_a.norm())[0] - - if (self.w - 1)/2 in frak_a: - K = P - else: - assert (self.w + 1)/2 in frak_a - K = Q - - K = K.xMUL(2**(basis_ord - val_2_frak_a)) - assert K.xMUL(2**(val_2_frak_a - 1)) - assert not K.xMUL(2**val_2_frak_a) - - phi_2 = K.xMUL(2**(val_2_frak_a-1)).xISOG(E, 2) - phi = phi_2 - for steps in range(1, val_2_frak_a): - E = phi.codomain() - K = K.push(phi_2) - assert K.xMUL(2**(val_2_frak_a-1-steps)) - assert not K.xMUL(2**(val_2_frak_a-steps)) - phi_2 = K.xMUL(2**(val_2_frak_a-1-steps)).xISOG(E, 2) - phi = phi_2 * phi - - E_out = phi.codomain().montgomery_model() - - return phi.codomain().isomorphism_to(E_out) * phi, E_out - - - def small_prime_ideal_action(self, E, ell, lam=None, prev_j=None): - r""" - Computes the action of a an ideal above ell using Elkies algorithm. - Input: - - E: Elliptic curve over Fp IN WEIERSTRASS FORM - - ell: A small prime, split in End(E) - - lam (optional): The eigenvalue determining the ideal frak_l = (ell, pi - lam) - - prev_j (optional): The j-invariant of the WRONG ell-isogenous curve - Output: - - phi : The isogeny corresponding to an ideal above ell - """ - # Fix later, but Elkies uses short Weierstrass - # Change ring stuff is messy, but needed to actually compute the rational model - assert isWeierstrass(E) - h = Elkies(E, ell, self.Fp, lam=lam, prev_j=prev_j) - phi = E.isogeny(h) - return phi - - - def small_prime_degree_isogeny(self, E, ell): - r""" - Computes an (unspecified) isogeny of degree ell - Input: - - E: Elliptic curve over Fp - - ell: A small prime, not necessarily split in End(E) - Output: - - phi : An isogeny from E of degree ell - """ - # Just a random isogeny of degree ell - # Not (necessarily) oriented (if prime is Elkies, we should use the other) - Fbig, k, ontwist = self.ell_to_Fpk[ell] - Ebig = E.change_ring(Fbig) - if ontwist: - Ebig_ord = self.p**k + (-1)**k - else: - Ebig_ord = self.p**k - (-1)**k - assert not Ebig_ord % ell, f"ehh {(self.p**k + (-1)**k) % ell}, {(self.p**k - (-1)**k) % ell}" - - cof = Ebig_ord//ell - - # Picking point smarter makes this easier - K = None - while not K: - K = random_xPoint(Ebig, Fbig, ontwist) - # TODO: Clear some cofactors by working in trace 0 part - K = K.xMUL(cof) - - phi = K.xISOG(E, ell) - return phi - - - def _adjust_2_tors_order(self, P, Q, e, return_scalars = False): - r""" - Multiplies P, Q by suitable cofactors so they form a basis of E[2**e] - Input: - - P, Q, points of order at least 2**e, so that E[2**e] \subseteq - - e: Exponent of 2. - Output: - - Pm, Qm: Basis of E[2**e] - - Optional: The scalars a, b so that Pm = a*P, Qm = b*Q - """ - assert P.xMUL((2**(e-1))) - assert Q.xMUL((2**(e-1))) - P_small = P.xMUL(2**e) - scal_1 = 1 - scal_2 = 1 - while P_small: - P = P.xMUL(2) - P_small = P_small.xMUL(2) - scal_1 *= 2 - Q_small = Q.xMUL(2**e) - while Q_small: - Q = Q.xMUL(2) - Q_small = Q_small.xMUL(2) - scal_2 *= 2 - if return_scalars: - return P, Q, scal_1, scal_2 - return P, Q - - - def smooth_ideal_action(self, E, cof, frak): - r""" - Computes the action of a an ideal of odd, smooth norm using Elkies algorithm repeatedly. - Input: - - E: Elliptic curve over Fp - - cof: norm of frak - - frak: An ideal of End(E) - Output: - - phi : The isogeny corresponding to frak - - frak * E - """ - # Evaluate a smooth, odd normed ideal - isogs = [] - E1 = E.short_weierstrass_model() - pre_isom = E.isomorphism_to(E1) - isogs.append(pre_isom) - if cof > 1: - for ell_cof, e_cof in factor(cof): - lam = Integer(GF(ell_cof)(-self.p).sqrt()) - if not self.w - lam in frak + ell_cof*self.max_order: - # In this case, we want the other one - lam = ell_cof - lam - assert self.w - lam in frak + ell_cof*self.max_order - prev_j = None - for _ in range(e_cof): - logger.debug(f'Starting Elkies step of degree {ell_cof}') - phi_part = self.small_prime_ideal_action(E1, ell_cof, lam, prev_j) - prev_j = E1.j_invariant() - E1 = phi_part.codomain() - isogs.append(phi_part) - - E_out = isogs[-1].codomain().montgomery_model() - post_isom = isogs[-1].codomain().isomorphism_to(E_out) - isogs.append(post_isom) - return isogs, E_out - - - def random_smooth_isogeny(self, E, g): - r""" - Returns a random isogeny of smooth degree g from E - Input: - - E: Elliptic curve over Fp - - g: Smooth number - Output: - - phi : An isogeny from E of degree g - - E_out : phi(E) - """ - # Random smooth odd norm isogeny - isogs = [] - if g > 1: - E1 = E.short_weierstrass_model() - pre_isom = E.isomorphism_to(E1) - isogs.append(pre_isom) - logger.debug(f"Extra isogeny for g = {factor(g)}") - # Do elkies first, to stay over Fp - g_elkies = [] - g_non_elkies = [] - for ell, e in factor(g): - if kronecker_symbol(-self.p, ell) == 1: - g_elkies.append((ell, e)) - else: - g_elkies.append((ell, e)) - for ell, e in g_elkies: - prev_j = None - for _ in range(e): - phi_ell = self.small_prime_ideal_action(E1, ell, prev_j = prev_j) - prev_j = E1.j_invariant() - E1 = phi_ell.codomain() - isogs.append(phi_ell) - - E_out = isogs[-1].codomain().montgomery_model() - post_isom = isogs[-1].codomain().isomorphism_to(E_out) - isogs.append(post_isom) - - for ell, e in g_non_elkies: - for _ in range(e): - phi_ell = self.small_prime_degree_isogeny(E_out, ell) - E_out = phi_ell.codomain() - isogs.append(phi_ell) - - return isogs, E_out - else: - return [], E - - - def eval_endomorphism(self, rho, P, twist, max): - r""" - Evaluates an element of End(E) on a point P. - P is assumed to be Fp rational on either E or on a twist - """ - a, b = list(rho) #write as a + b*pi - n = rho.denominator() - if twist: - #a + b*pi = a - b, since pi(P) = -P - m = Integer(a - b) - else: - #a + b*pi = a + b, since pi(P) = P - m = Integer(a + b) - if max and (n == 2): #See Appendix D.2 - mP = P.xMUL(m) - E = P.curve - - T0 = self.find_Ts(E, only_T0 = True) - - #Already know which point to choose, Remark D.2 - assert (P.X - T0.x()).is_square() != twist - - T = xPoint(T0.x(), E) - - return translate_by_T(mP, T) - - else: - return P.xMUL(m) - - - def TwoTorsBasis(self, E, e): - r""" - Fast sampling of a basis P, Q of E[2**e], such that x(P) and x(Q) are both defined over Fp - Input: - - E: Elliptic curve over Fp - - e: Exponent - Output: - - P, Q: Basis of E[2**e] so that P is in E(Fp), and Q is in E^t(Fp) for an Fp-twist of E. - """ - logger.debug(" > Finding TwoTorsionBasis") - tstart = time() - - T0, Tm1, T1 = self.find_Ts(E) - - A = MontgomeryA(E) - F = E.base_field() - R = F["X"] - X = R.gens()[0] - f = X**2 + A*X + 1 - - logger.debug(f" > Done, have used {time()-tstart} sec") - - logger.debug(" > sample xP") - xT0 = T0.x() - xP = xT0 + F.random_element()**2 - while not (f(xP)*xP).is_square() or (xP-Tm1.x()).is_square(): - xP = xT0 + F.random_element()**2 - - logger.debug(" > sample xQ") - xQ = xT0 - F.random_element()**2 - while (f(xQ)*xQ).is_square() or not ((xQ-T1.x()).is_square()): - xQ = xT0 - F.random_element()**2 - - logger.debug(f" > Done, have used {time()-tstart} sec") - #print(T0.tate_pairing(E.lift_x(xP), 2, 1)) - - P = xPoint(xP, E) - Q = xPoint(xQ, E) - - assert (self.p+1) % 2**(e+1) == 0 - cofac = (self.p+1)/2**(e+1) - P = P.xMUL(cofac) - Q = Q.xMUL(cofac) - - assert P.xMUL(2**(e-1)) - assert not P.xMUL(2**e) - assert Q.xMUL(2**(e-1)) - assert not Q.xMUL(2**e) - assert Q.xMUL(2**(e-1)) != P.xMUL(2**(e-1)) - - logger.debug(f" > Total time for 2-tors basis finding: {time()-tstart}") - - return P, Q - - def find_Ts(self, E, only_T0 = False): - r""" - Given a curve E, finds and marks the non-trivial - 2-torsion points according to Lemma D.1 - """ - A = MontgomeryA(E) - F = E.base_field() - R = F["X"] - X = R.gens()[0] - f = X**2 + A*X + 1 - logger.debug(" > root finding") - lam1, lam2 = f.roots(multiplicities=False) - - R1 = E(lam1, 0) - R2 = E(lam2, 0) - R3 = E(0, 0) - - #Find T0 - Rs = [R1, R2] - for T in Rs: - if T.tate_pairing(T, 2, 1) != 1: - T0 = T - Rs.remove(T) - break - - assert T0 - if only_T0: - return T0 - - assert T0.tate_pairing(T0, 2, 1) == -1 - Rs.append(R3) - for T in Rs: - if T.tate_pairing(T0, 2, 1) == 1: - Tm1 = T - Rs.remove(T) - break - - assert Tm1 - T1 = Rs[0] - assert T1.tate_pairing(T0, 2, 1) != 1 - - return T0, Tm1, T1 + _, ideal = random_degree_one_ideal(self.order, self.w, self.p) + return ideal diff --git a/temp_test.py b/temp_test.py new file mode 100644 index 0000000..a468e19 --- /dev/null +++ b/temp_test.py @@ -0,0 +1,51 @@ +from sage.all import * +from pegasis import PEGASIS, Conjugate + +EGA = PEGASIS(500) +order = EGA.order +generator = EGA.w + +e = 245 +ell = next_prime(randint(0, 2**e)) +while kronecker_symbol(-EGA.p, ell) != 1: + ell = next_prime(randint(0, 2**e)) + +ideal = ell * order + (generator - Integer(GF(ell)(-EGA.p).sqrt())) * order +assert ideal.norm() == ell +#ideal = EGA.sample_ideal() + + + +E = EGA.action(EGA.E_start, ideal) + +print("DONE WITH FIRST.....") +#alpha = frak_a.random_element() +#while not is_pseudoprime(ZZ(alpha.norm()/frak_a.norm())): +# alpha = frak_a.random_element() +#gen_1, gen_2 = frak_a.gens_two() +#frak_a = EGA.order*(gen_1*alpha.conjugate()/frak_a.norm()) + EGA.order*(gen_2*alpha.conjugate()/frak_a.norm()) +#assert is_pseudoprime(frak_a.norm()) + +E2 = EGA.action(E, Conjugate(EGA.order, ideal)) + +print("-------------") +print(f"original: {EGA.E_start.j_invariant()}") +print(f"new: {E2.j_invariant()}") + +""" +E2 = E2.short_weierstrass_model() +prev_j = None +F = E2 +for idx in range(5): + F = EGA.small_prime_ideal_action(F, EGA.small_ell, EGA.lam, prev_j).codomain() + print(f"left_{idx}: {F.j_invariant()}") + if truth == F.j_invariant(): + print("!!!!!!!!!!! WOW") + +F = E2 +for idx in range(5): + F = EGA.small_prime_ideal_action(F, EGA.small_ell, EGA.small_ell-EGA.lam, prev_j).codomain() + print(f"right_{idx}: {F.j_invariant()}") + if truth == F.j_invariant(): + print("!!!!!!!!!!! WOW") +""" \ No newline at end of file diff --git a/time_pegasis.py b/time_pegasis.py index c81c745..3ce605d 100644 --- a/time_pegasis.py +++ b/time_pegasis.py @@ -27,12 +27,12 @@ if __name__ == "__main__": # Arguments parser = argparse.ArgumentParser() - parser.add_argument("-p", type=int, help="Prime size", choices=(500, 1000, 1500, 2000, 4000), default=500) + parser.add_argument("-p", type=int, help="Prime size", choices=(100, 500, 1000, 1500, 2000, 4000), default=500) parser.add_argument("--nruns", type=int, help="Number of runs", default=5) parser.add_argument("--runname", type=str, help="Run name", default="run") parser.add_argument("--precompute", action=argparse.BooleanOptionalAction) args = parser.parse_args() - assert args.p in [500, 1000, 1500, 2000, 4000] + assert args.p in [100, 500, 1000, 1500, 2000, 4000] EGA = PEGASIS(args.p) if args.precompute: diff --git a/utilities.py b/utilities.py new file mode 100644 index 0000000..784f254 --- /dev/null +++ b/utilities.py @@ -0,0 +1,137 @@ +#!/usr/bin/env python3 + +from sage.arith.misc import gcd +from sage.rings.integer_ring import ZZ +from sage.structure.factorization import Factorization +from sage.rings.finite_rings.integer_mod import Mod + +from const_precomp import small_sos + + +def remove_common_factors(n, r): + r"""Remove all primes dividing r from n + + If n = \prod_i p_i^e_i and r = \prod_i p_i^f_i, returns + tuple + (remainder, common_factors) + where + common_factors = \prod_i p_i^{min(e_i, f_i)} + and + remainder = n / common_factors + """ + + common_factors = 1 + remainder = n + + while (g := gcd(remainder, r)) != 1: + common_factors *= g + remainder /= g + + assert common_factors * remainder == n + + return remainder, common_factors + + +def remove_primes(n, primes, odd_parity_only=True): + """Remove all powers of primes in primes from n + + Input: + - n: int/Integer + - primes: List of prime numbers + - odd_parity_only: (optional) For every prime p in primes, remove only as + many powers of p until p has even multiplicity in n + + Output: + - Tuple (remainder, prime_powers_contained) + + Where remainder is n with all the power of primes removed, and + prime_powers_contained the product of all primes and their + multiplicities in n. In other words + + n == remainder * prime_powers_contained + """ + remainder = ZZ(n) + prime_powers_contained = 1 + + for prime in primes: + val = remainder.valuation(prime) + + if odd_parity_only: + val = val % 2 + + prime_powers_contained *= prime ** val + remainder /= prime ** val + + assert prime_powers_contained * remainder == n + + return remainder, prime_powers_contained + + +def two_squares_factored(factors): + """ + This is the function `two_squares` from sage, except we give it the + factorisation of n already. + """ + F = Factorization(factors) + for p, e in F: + if e % 2 == 1 and p % 4 == 3: + raise ValueError("%s is not a sum of 2 squares" % n) + + n = F.expand() + if n == 0: + return (0, 0) + a = ZZ.one() + b = ZZ.zero() + for p, e in F: + if p == 1: + continue + if e >= 2: + m = p ** (e // 2) + a *= m + b *= m + if e % 2 == 1: + if p == 2: + # (a + bi) *= (1 + I) + a, b = a - b, a + b + else: # p = 1 mod 4 + if p in small_sos: + r, s = small_sos[p] + else: + # Find a square root of -1 mod p. + # If y is a non-square, then y^((p-1)/4) is a square root of -1. + y = Mod(2, p) + while True: + s = y ** ((p - 1) / 4) + if not s * s + 1: + s = s.lift() + break + y += 1 + # Apply Cornacchia's algorithm to write p as r^2 + s^2. + r = p + while s * s > p: + r, s = s, r % s + r %= s + + # Multiply (a + bI) by (r + sI) + a, b = a * r - b * s, b * r + a * s + + a = a.abs() + b = b.abs() + assert a * a + b * b == n + if a <= b: + return (a, b) + else: + return (b, a) + + +def on_surface(E): + try: + E.torsion_basis(2) + except ValueError: + return False + try: + E.torsion_basis(4) + except ValueError: + return True + + return False diff --git a/uv_params.py b/uv_params.py index c651347..e93d8ff 100644 --- a/uv_params.py +++ b/uv_params.py @@ -2,6 +2,7 @@ from sage.all import * import coin import const_precomp +from ideals import ideal_to_sage class UV_params: """ @@ -49,7 +50,9 @@ class UV_params: def __init__(self, level, params=None): level = int(level) - if level == 500: + if level == 100: + self.init_100() + elif level == 500: self.init_500() elif level == 1000: self.init_1000() @@ -86,11 +89,22 @@ class UV_params: self.n_squares = 2 self.sol_bound = 1 + self.two_left = ideal_to_sage([[2, 0], [-1 / 2, 1 / 2]], self.max_order) + self.two_right = ideal_to_sage([[2, 0], [1 / 2, 1 / 2]], self.max_order) + # Optional parameter update if params: for p_key, p_val in params.items(): setattr(self,p_key,p_value) + def init_100(self): + self.f = 77 + self.e = 100 + self.p = self.f * 2**self.e - 1 + self.A = 86576444069281248423336823187435 + allowed_primes = [5, 7, 11] + self.allowed_primes = [ZZ(li) for li in allowed_primes] + def init_500(self): self.f = 33 self.e = 503 -- cgit v1.2.3-70-g09d2