Exemple #1
0
def attack(outputs, modulus=None, multiplier=None, increment=None):
    """
    Recovers the parameters from a linear congruential generator.
    If no modulus is provided, attempts to recover the modulus from the outputs (may require many outputs).
    If no multiplier is provided, attempts to recover the multiplier from the outputs (requires at least 3 outputs).
    If no increment is provided, attempts to recover the increment from the outputs (requires at least 2 outputs).
    :param outputs: the sequential output values obtained from the LCG
    :param modulus: the modulus of the LCG (can be None)
    :param multiplier: the multiplier of the LCG (can be None)
    :param increment: the increment of the LCG (can be None)
    :return: a tuple containing the modulus, multiplier, and the increment
    """
    if modulus is None:
        assert len(
            outputs
        ) >= 4, "At least 4 outputs are required to recover the modulus"
        for i in range(len(outputs) - 3):
            d0 = outputs[i + 1] - outputs[i]
            d1 = outputs[i + 2] - outputs[i + 1]
            d2 = outputs[i + 3] - outputs[i + 2]
            g = d2 * d0 - d1 * d1
            modulus = g if modulus is None else gcd(g, modulus)

        assert is_prime_power(
            modulus
        ), "Modulus must be a prime power, try providing more outputs"

    gf = GF(modulus)
    if multiplier is None:
        assert len(
            outputs
        ) >= 3, "At least 3 outputs are required to recover the multiplier"
        x0 = gf(outputs[0])
        x1 = gf(outputs[1])
        x2 = gf(outputs[2])
        multiplier = int((x2 - x1) / (x1 - x0))

    if increment is None:
        assert len(
            outputs
        ) >= 2, "At least 2 outputs are required to recover the multiplier"
        x0 = gf(outputs[0])
        x1 = gf(outputs[1])
        increment = int(x1 - multiplier * x0)

    return modulus, multiplier, increment
# set_seed(SEED + 306)
# X = [random.randint(-100, 100) for _ in range(20)] + [random.randint(100, 1_000_000_000) for _ in range(20)]
# Z = [0,]*len(X)
# for i in range(len(X)):
#     x = X[i]
#     z = is_prime(x)
#     Z[i] = bool(z)
# d = {"X": X, "Z": Z}
# save_pickle(d, FOLDER, "is_composite.pkl")

set_seed(SEED + 307)
X = [random.randint(-256, 257) for _ in range(20)] + [random.randint(100, 1_000_000_000) for _ in range(20)]
Z = [0,]*len(X)
for i in range(len(X)):
    x = X[i]
    z = is_prime_power(x)
    Z[i] = bool(z)
d = {"X": X, "Z": Z}
save_pickle(d, FOLDER, "is_prime_power.pkl")

set_seed(SEED + 308)
X = list(range(-256, 257)) + [random.randint(100, 1_000_000_000) for _ in range(20)]
Z = [0,]*len(X)
for i in range(len(X)):
    x = X[i]
    z = Integer(x).is_perfect_power()
    Z[i] = bool(z)
d = {"X": X, "Z": Z}
save_pickle(d, FOLDER, "is_perfect_power.pkl")

set_seed(SEED + 309)
Exemple #3
0
def elliptic_curve_search(info, query):
    parse_rational_to_list(info, query, 'jinv', 'j-invariant')
    parse_ints(info, query, 'conductor')
    if info.get('conductor_type'):
        if info['conductor_type'] == 'prime':
            query['num_bad_primes'] = 1
            query['semistable'] = True
        elif info['conductor_type'] == 'prime_power':
            query['num_bad_primes'] = 1
        elif info['conductor_type'] == 'squarefree':
            query['semistable'] = True
        elif info['conductor_type'] == 'divides':
            if not isinstance(query.get('conductor'), int):
                err = "You must specify a single conductor"
                flash_error(err)
                raise ValueError(err)
            else:
                query['conductor'] = {'$in': integer_divisors(ZZ(query['conductor']))}
    parse_signed_ints(info, query, 'discriminant', qfield=('signD', 'absD'))
    parse_ints(info,query,'rank')
    parse_ints(info,query,'sha','analytic order of Ш')
    parse_ints(info,query,'num_int_pts','num_int_pts')
    parse_ints(info,query,'class_size','class_size')
    if info.get('class_deg'):
        parse_ints(info,query,'class_deg','class_deg')
        if not isinstance(query.get('class_deg'), int):
            err = "You must specify a single isogeny class degree"
            flash_error(err)
            raise ValueError(err)
    parse_floats(info,query,'regulator','regulator')
    parse_floats(info, query, 'faltings_height', 'faltings_height')
    if info.get('reduction'):
        if info['reduction'] == 'semistable':
            query['semistable'] = True
        elif info['reduction'] == 'not semistable':
            query['semistable'] = False
        elif info['reduction'] == 'potentially good':
            query['potential_good_reduction'] = True
        elif info['reduction'] == 'not potentially good':
            query['potential_good_reduction'] = False
    if info.get('torsion'):
        if info['torsion'][0] == '[':
            parse_bracketed_posints(info,query,'torsion',qfield='torsion_structure',maxlength=2,check_divisibility='increasing')
        else:
            parse_ints(info,query,'torsion')
    # speed up slow torsion_structure searches by also setting torsion
    #if 'torsion_structure' in query and not 'torsion' in query:
    #    query['torsion'] = reduce(mul,[int(n) for n in query['torsion_structure']],1)
    if 'cm' in info:
        if info['cm'] == 'noCM':
            query['cm'] = 0
        elif info['cm'] == 'CM':
            query['cm'] = {'$ne' : 0}
        else:
            parse_ints(info,query,field='cm',qfield='cm')
    parse_element_of(info,query,'isogeny_degrees',split_interval=200,contained_in=get_stats().isogeny_degrees)
    parse_primes(info, query, 'nonmax_primes', name='non-maximal primes',
                 qfield='nonmax_primes', mode=info.get('nonmax_quantifier'), radical='nonmax_rad')
    parse_primes(info, query, 'bad_primes', name='bad primes',
                 qfield='bad_primes',mode=info.get('bad_quantifier'))
    parse_primes(info, query, 'sha_primes', name='sha primes',
                 qfield='sha_primes',mode=info.get('sha_quantifier'))
    if info.get('galois_image'):
        labels = [a.strip() for a in info['galois_image'].split(',')]
        elladic_labels = [a for a in labels if elladic_image_label_regex.fullmatch(a) and is_prime_power(elladic_image_label_regex.match(a)[1])]
        modell_labels = [a for a in labels if modell_image_label_regex.fullmatch(a) and is_prime(modell_image_label_regex.match(a)[1])]
        if len(elladic_labels)+len(modell_labels) != len(labels):
            err = "Unrecognized Galois image label, it should be the label of a subgroup of GL(2,Z_ell), such as %s, or the label of a subgroup of GL(2,F_ell), such as %s, or a list of such labels"
            flash_error(err, "13.91.3.2", "13S4")
            raise ValueError(err)
        if elladic_labels:
            query['elladic_images'] = {'$contains': elladic_labels}
        if modell_labels:
            query['modell_images'] = {'$contains': modell_labels}
        if 'cm' not in query:
            query['cm'] = 0
            info['cm'] = "noCM"
        if query['cm']:
            # try to help the user out if they specify the normalizer of a Cartan in the CM case (these are either maximal or impossible
            if any(a.endswith("Nn") for a in modell_labels) or any(a.endswith("Ns") for a in modell_labels):
                err = "To search for maximal images, exclude non-maximal primes"
                flash_error(err)
                raise ValueError(err)
        else:
            # if the user specifies full mod-ell image with ell > 3, automatically exclude nonmax primes (if possible)
            max_labels = [a for a in modell_labels if a.endswith("G") and int(modell_image_label_regex.match(a)[1]) > 3]
            if max_labels:
                if info.get('nonmax_primes') and info['nonmax_quantifier'] != 'exclude':
                    err = "To search for maximal images, exclude non-maximal primes"
                    flash_error(err)
                    raise ValueError(err)
                else:
                    modell_labels = [a for a in modell_labels if a not in max_labels]
                    max_primes = [modell_image_label_regex.match(a)[1] for a in max_labels]
                    if info.get('nonmax_primes'):
                        max_primes += [l.strip() for l in info['nonmax_primes'].split(',') if not l.strip() in max_primes]
                    max_primes.sort(key=int)
                    info['nonmax_primes'] = ','.join(max_primes)
                    info['nonmax_quantifier'] = 'exclude'
                    parse_primes(info, query, 'nonmax_primes', name='non-maximal primes',
                                 qfield='nonmax_primes', mode=info.get('nonmax_quantifier'), radical='nonmax_rad')
                    info['galois_image'] = ','.join(modell_labels + elladic_labels)
                query['modell_images'] = { '$contains': modell_labels }

    # The button which used to be labelled Optimal only no/yes"
    # (default: no) has been renamed "Curves per isogeny class
    # all/one" (default: all).  When this option is "one" we only list
    # one curve in each class, currently choosing the curve with
    # minimal Faltings heights, which is conjecturally the
    # Gamma_1(N)-optimal curve.
    if 'optimal' in info and info['optimal'] == 'on':
        query["__one_per__"] = "lmfdb_iso"

    info['curve_ainvs'] = lambda dbc: str([ZZ(ai) for ai in dbc['ainvs']])
    info['curve_url_LMFDB'] = lambda dbc: url_for(".by_triple_label", conductor=dbc['conductor'], iso_label=split_lmfdb_label(dbc['lmfdb_iso'])[1], number=dbc['lmfdb_number'])
    info['iso_url_LMFDB'] = lambda dbc: url_for(".by_double_iso_label", conductor=dbc['conductor'], iso_label=split_lmfdb_label(dbc['lmfdb_iso'])[1])
    info['cremona_bound'] = CREMONA_BOUND
    info['curve_url_Cremona'] = lambda dbc: url_for(".by_ec_label", label=dbc['Clabel'])
    info['iso_url_Cremona'] = lambda dbc: url_for(".by_ec_label", label=dbc['Ciso'])
    info['FH'] = lambda dbc: RealField(20)(dbc['faltings_height'])