def small_B_twist(E): """ Description: Finds a curve isogenous to E that has small B in the curve equation y^2 = x^3 + A*x + B Input: E - elliptic curve Output: E' - elliptic curve isogenous to E that has small B in the curve equation y^2 = x^3 + A*x + B """ b = E.ainvs()[4] q = E.base_field().order() b = power_mod(Integer(b), -1, q) d = 0 s = Mod(1, q) bool = True while bool: try: d = (s * b) d = d.nth_root(3) d = Integer(d) bool = False except ValueError as e: s += 1 pass ainvs = [i for i in E.ainvs()] ainvs[3] *= d**2 ainvs[4] *= d**3 return EllipticCurve(E.base_field(), ainvs)
def local_data(self, E, n, prec=64): import re R = PolynomialRing(RationalField(), 'x') if prec > 64: raise ValueError("prec (=%s) must be at most 64" % prec) if prec < 1: raise ValueError("prec (=%s) must be at least 1" % prec) if n % 2 != 1: v = self('-sp %sp%s -local %s' % (n, prec, self._curve_str(E))) else: v = self('-sp %sp%sd0 -local %s' % (n, prec, self._curve_str(E))) vv = v.split('\n') bad_primes_l = [i for i in vv if re.match(r'sp %d: Euler' % n, i)] bad_primes = [(Integer(i.split()[5]), R(i.split()[7]).coefficients(sparse=False)) for i in bad_primes_l] cond_rootn_string = [i for i in vv if re.search('conductor', i)].pop() cond_rootn_string = cond_rootn_string.replace(',', ' ') conductor, root = Integer(cond_rootn_string.split()[5]), Integer( cond_rootn_string.split()[-1]) return bad_primes, conductor, root
def __str__(self): S = 'Toric datum\n'\ 'Base ring: ' + str(self.ring) + '\n\n'\ 'Polyhedron: ' + str(self.polyhedron) + '\n' +\ str(self.polyhedron.cdd_Hrepresentation()) + '\n'\ 'Integrand: t^(y * ' + str(self.integrand[0]) + ') * q^(y * ' + str(self.integrand[1]) + ')\n' if len(self.cc) == 0: return S + 'No divisibility conditions.' width = max( map(lambda f: len([i for i in f.exponents()[0] if i > 0]), self.lhs)) * 4 + 2 for i in range(len(self.cc)): if self.initials[i] is None: S += ('(%2d ) %' + str(width) + 's || %s\n') % (i, str(self.lhs[i]), str(self.rhs[i])) else: S += ('(%2d ) %' + str(width) + 's || <<%s>>') % ( i, str(self.lhs[i]), str(self.initials[i])) rem = self.rhs[i] - self.initials[i] if rem.lc() > Integer(0): S += ' + ' + str(rem) elif rem.lc() < Integer(0): S += ' ' + str(rem) S += '\n' return S
def gen_params_from_r(r, k): """ Description: Finds a fundamental discriminant D to use as input to the Cocks-Pinch method Input: r - prime such that r % k == 1 k - embedding degree Output: r - prime such that r % k == 1 k - embedding degree D - (negative) fundamental discriminant where D is a square mod r """ D = -Integer(Mod(int(random() * (1000)), r)) i = 0 while not kronecker( D, r) == 1: # expected number of iterations of the while loop is 2 D = -Integer(Mod(int(random() * (1000)), r)) i += 1 D = fundamental_discriminant(D) if not (kronecker(D, r) == 1): return r, k, 0 return r, k, D
def FZ_kappa_factor(L,sigma): nv = len(L) mmm = max((0,)+sigma) sigma_grouped = [0 for i in range(mmm)] for i in sigma: sigma_grouped[i-1] += 1 S_list = [] for i in sigma_grouped: S_list.append(IntegerVectors(i,nv)) S = itertools.product(*S_list) kappa_factors = {} for parity in itertools.product(*((0,1) for i in range(nv))): kappa_factors[tuple(parity)] = 0 for assignment in S: assigned_sigma = [[] for j in range(nv)] for i in range(mmm): for j in range(nv): for k in range(assignment[i][j]): assigned_sigma[j].append(i+1) sigma_auts = Integer(1) parity = [0 for i in range(nv)] kappa_factor = Integer(1) for j in range(nv): sigma_auts *= aut(assigned_sigma[j]) parity[j] += sum(assigned_sigma[j]) parity[j] %= 2 kappa_factor *= kappa_coeff(assigned_sigma[j],L[j][0],L[j][1]) kappa_factors[tuple(parity)] += kappa_factor/sigma_auts return kappa_factors
def is_quotient(M, sym, rank): symbol = GenusSymbol_global_ring(MatrixSpace(ZZ, rank, rank).one()) symbol._local_symbols = [ Genus_Symbol_p_adic_ring(p, syms) for p, syms in sym.iteritems() ] s = get_symbol_string(symbol) print s N = FiniteQuadraticModule(s) t = N.order() / M.order() if not Integer(t).is_square(): return False else: t = sqrt(t) for p in Integer(N.order()).prime_factors(): if not N.signature(p) == M.signature(p): return False # if not N.signature() == M.signature(): # return False for G in N.subgroups(): if G.order() == t and G.is_isotropic(): Q = G.quotient() if Q.is_isomorphic(M): print Q return N else: del Q del N return False
def get_weil_polys(res_field, ordinary=False): """Used to compute all characteristic polynomial of Frobenius of elliptic curves over the given residue field""" # If res characteristic is 2 or 3, one can easily check that # all possible Weil polynomials are realised if res_field.characteristic() == 2: frob_polys = R.weil_polynomials(2, Integer(2)) elif res_field.characteristic() == 3: frob_polys = R.weil_polynomials(2, Integer(3)) else: frob_polys = set() for A, B in list(product(res_field, res_field)): if (4 * A ** 3 + 27 * B ** 2) != 0: E = EllipticCurve([A, B]) frob_poly = E.frobenius_polynomial() frob_polys = frob_polys.union({frob_poly}) frob_polys = list(frob_polys) if ordinary: q, _ = res_field.cardinality().perfect_power() frob_polys = [f for f in frob_polys if f[1] % q != 0] return frob_polys
def __init__(self, signature=0, weight=2, level_limit=34, rank_limit=4, primes=None, simple_color=None, nonsimple_color=None, reduction=True, bound=0): """ Initialize a SimpleModulesGraph containing finite quadratic modules of signature ``signature``. They are checked for being ``weight``-simple if their minimal number of generators is at most `rank_limit`. INPUT: - ``signature``: the signature of the modules - ``weight``: check for cusp forms of weight ``weight`` - ``level_limit``: only check for anisotropic modules with level smaller than ``level_limit`` - ``rank_limit``: an upper bound for the minimal number of generators - ``bound``: upper bound for the dimension (for considered being simple), default=0 OUTPUT: A SimpleModulesGraph object. No computations are done after initialization. Start the computation using the method ``compute()``. """ ########################### # basic parameters ########################### self._level_limit = Integer(level_limit) self._rank_limit = Integer(rank_limit) self._signature = Integer(signature) % 8 self._weight = QQ(weight) self._reduction = reduction self._bound = bound ######################################################### # Initialize the primes that need to be checked # According to Theorem 4.21 in [BEF], # in the worst case, we need to check primes p for which # prime_pol_simple(p, weight) <= bound. ######################################################### if primes is None: p = 2 while True: if prime_pol_simple(p, weight) > self._bound: primes = list(prime_range(p)) break else: p = next_prime(p) self._primes = primes self._simple_color = colors.darkred.rgb( ) if simple_color is None else simple_color self._nonsimple_color = colors.darkgreen.rgb( ) if nonsimple_color is None else nonsimple_color self._vertex_colors = dict() self._vertex_colors[self._simple_color] = list() self._vertex_colors[self._nonsimple_color] = list() self._heights = dict() # a height function for plotting self._simple = list() # will contain the list of k-simple modules super(SimpleModulesGraph, self).__init__()
def encrypt(self, message, pubkey, seed=None, text=False): random.seed(seed) tmp = None if not text: tmp = Integer(message).digits(2) else: tmp = 0 for let in message: tmp = tmp * 256 tmp = (tmp + ord(let)) tmp = Integer(tmp).digits(2) tmp.reverse() r = random.randint(2, self.order - 1) if self.pairing == "tate": pair = self._ext(pubkey[0]).tate_pairing( self.distortion(pubkey[1]), self.order, self.k, self.ec2.base_ring().cardinality()) else: pair = self._ext(pubkey[0]).weil_pairing( self.distortion(pubkey[1]), self.order) print "Sin cifrar", tmp return r * self.P, self._mask(tmp, pair**r)
def __init__(self, modulus, number): assert gcd(modulus, number) == 1 self.modulus = Integer(modulus) self.number = Integer(number) self.G = Pari("znstar({},1)".format(modulus)) self.chi_pari = pari("znconreylog(%s,%d)" % (self.G, self.number)) self.chi_0 = None self.indlabel = None
def weight_one_half_dim(FQM, use_reduction=True, proof=False, debug=0, local=True): N = Integer(FQM.level()) if not N % 4 == 0: return 0 m = Integer(N / Integer(4)) d = 0 for l in m.divisors(): if is_squarefree(m / l): if debug > 1: print "l = {0}".format(l) TM = FiniteQuadraticModule([2 * l], [-1 / Integer(4 * l)]) if local: dd = [0, 0] # eigenvalue 1, -1 multiplicity for p, n in lcm(FQM.level(), 4 * l).factor(): N = None TN = None J = FQM.jordan_decomposition() L = TM.jordan_decomposition() for j in xrange(1, n + 1): C = J.constituent(p**j)[0] D = L.constituent(p**j)[0] if debug > 1: print "C = {0}, D = {1}".format(C, D) if N == None and C.level() != 1: N = C elif C.level() != 1: N = N + C if TN == None and D.level() != 1: TN = D elif D.level() != 1: TN = TN + D dd1 = invariants_eps(N, TN, use_reduction, proof, debug) if debug > 1: print "dd1 = {}".format(dd1) if dd1 == [0, 0]: # the result is multiplicative # a single [0,0] as a local result # yields [0,0] in the end # and we're done here dd = [0, 0] break if dd == [0, 0]: # this is the first prime dd = dd1 else: # some basic arithmetic ;-) # 1 = 1*1 = (-1)(-1) # -1 = 1*(-1) = (-1)*1 ddtmp = copy(dd) ddtmp[0] = dd[0] * dd1[0] + dd[1] * dd1[1] ddtmp[1] = dd[0] * dd1[1] + dd[1] * dd1[0] dd = ddtmp if debug > 1: print "dd = {0}".format(dd) d += dd[0] else: d += invariants_eps(FQM, TM, use_reduction, proof, debug)[0] return d
def id_dirichlet(fun, N, n): N = Integer(N) if N == 1: return (1, 1) p2 = valuation(N, 2) N2 = 2**p2 Nodd = N // N2 Nfact = list(factor(Nodd)) #print "n = "+str(n) #for j in range(20): # print "chi(%d) = e(%d/%d)"%(j+2, fun(j+2,n), n) plist = [z[0] for z in Nfact] ppows = [z[0]**z[1] for z in Nfact] ppows2 = list(ppows) idems = [1 for z in Nfact] proots = [primitive_root(z) for z in ppows] # Get CRT idempotents if p2 > 0: ppows2.append(N2) for j in range(len(plist)): exps = [1 for z in idems] if p2 > 0: exps.append(1) exps[j] = proots[j] idems[j] = crt(exps, ppows2) idemvals = [fun(z, n) for z in idems] # now normalize to right root of unity base idemvals = [ idemvals[j] * euler_phi(ppows[j]) / n for j in range(len(idemvals)) ] ans = [ Integer(mod(proots[j], ppows[j])**idemvals[j]) for j in range(len(proots)) ] ans = crt(ans, ppows) # There are cases depending on 2-part of N if p2 == 0: return (N, ans) if p2 == 1: return (N, crt([1, ans], [2, Nodd])) if p2 == 2: my3 = crt([3, 1], [N2, Nodd]) if fun(my3, n) == 0: return (N, crt([1, ans], [4, Nodd])) else: return (N, crt([3, ans], [4, Nodd])) # Final case 2^3 | N my5 = crt([5, 1], [N2, Nodd]) test1 = fun(my5, n) * N2 / 4 / n test1 = Integer(mod(5, N2)**test1) minusone = crt([-1, 1], [N2, Nodd]) test2 = (fun(minusone, n) * N2 / 4 / n) % (N2 / 4) if test2 > 0: test1 = Integer(mod(-test1, N2)) return (N, crt([test1, ans], [N2, Nodd]))
def wiener(e, n): m = 12345 c = pow(m, e, n) list1 = continued_fraction(Integer(e) / Integer(n)) conv = list1.convergents() for i in conv: d = int(i.denominator()) m1 = pow(c, d, n) if m1 == m: return d
def test_dimension_jacobi(N, k): from nils.jacobiforms.dimension_jac_forms import dimension_jac_cusp_forms N = Integer(N) dj = dimension_jac_cusp_forms(k + Integer(1) / Integer(2), N) M = FiniteQuadraticModule([2 * N], [1 / (4 * N)]) s = GenusSymbol(M.jordan_decomposition().genus_symbol()) dv = s.dimension_cusp_forms(k, reduction=True) if not dj == dv: print "Error: ", N, dj, dv return False return True
def simple_gamma0_genus_symbols(r=range(1, 500), precomputed=None): if isinstance(precomputed, list): l = precomputed comp = False res = [] for s in l: if Integer(4).divides(s.level()): if s.defines_isomorphic_module( gamma0_N_genus_symbol(s.level() / Integer(4))): res.append(s) print s return res, filter(lambda x: x not in res, l)
def _kappaSR_monom_to_X(expr): X = StrataGraph.Xvar if expr in ZZ: return expr elif expr.operator() == None: ka_subscript = Integer(str(expr)[2:]) return X**ka_subscript elif expr.operator() == operator.pow: ops = expr.operands() expon = ops[1] ka = ops[0] ka_subscript = Integer(str(ka)[2:]) return expon * X**ka_subscript
def __calculate_rank(self): # this will work once the lattice class is used and Nils's # implementation of the module class if self._L != None: L = self._L o_inv = L.o_invariant() V2 = L.bullet_vectors_of_order_2() return L.det() + Integer( len(V2) * (-1)**(self.__par + o_inv)).divide_knowing_divisible_by(2) else: # stupid... just for testing purposes return Integer(1)
def __init__(self, A, use_genus_symbols=False, aniso_formula=False, use_reduction=False): try: from sfqm.fqm.genus_symbol import GenusSymbol except ImportError as e: print(e) use_genus_symbols = False print("Not using genus symbols.") self._use_reduction = use_reduction if use_genus_symbols: if isinstance(A, str): g = GenusSymbol(A) else: try: g = GenusSymbol(A.jordan_decomposition().genus_symbol()) except: raise ValueError self._g = g n2 = self._n2 = g.torsion(2) self._v2 = g.two_torsion_values() self._M = None self._aniso_formula = aniso_formula else: self._M = FiniteQuadraticModule(A) self._g = None self._level = self._M.level() self._aniso_formula = False if is_odd(self._M.order()): self._n2 = n2 = 1 self._v2 = {0: 1} else: self._M2 = M2 = self._M.kernel_subgroup(2).as_ambient()[0] self._n2 = n2 = self._M2.order() self._v2 = list(self._M2.values()) if use_genus_symbols: self._signature = g.signature() m = g.order() else: self._signature = self._M.signature() m = self._M.order() self._m = m d = Integer(1) / Integer(2) * (m + n2) # |discriminant group/{+/-1}| self._d = d self._alpha3 = None self._alpha4 = None
def compute(self, p=None, cut_nonsimple_aniso=True, fast=1): args = list() for N in range(1, self._level_limit): v2 = Integer(N).valuation(2) N2 = 2**v2 if v2 in [0, 1, 2, 3] and is_squarefree(Integer(N) / N2): s = anisotropic_symbols(N, self._signature) if len(s) == 0: continue args = args + s logger.debug('args = {0}'.format(args)) logger.info('starting with {} anisotropic modules'.format(len(args))) self.compute_from_startpoints(args, p, cut_nonsimple_aniso, fast) return self._simple
def make_curve(num_bits, num_curves=1): """ Description: Finds num_curves Barreto-Naehrig curves with a prime order that is at least 2^num_bits. Input: num_bits - number of bits for the prime order of the curve num_curves - number of curves to find Output: curves - list of the first num_curves BN curves each of prime order at least 2^num_bits; each curve is represented as a tuple (q,t,r,k,D) """ def P(y): x = Integer(y) return 36*pow(x,4) + 36*pow(x,3) + 24*pow(x,2) + 6*x + 1 x = Integer(floor(pow(2, (num_bits)/4.0)/(sqrt(6)))) q = 0 r = 0 t = 0 curve_num = 0 curves = [] while curve_num < num_curves or (log(q).n()/log(2).n() < 2*num_bits and not (utils.is_suitable_q(q) and utils.is_suitable_r(r) and utils.is_suitable_curve(q,t,r,12,-3,num_bits))): t = Integer(6*pow(x,2) + 1) q = P(-x) r = q + 1 - t b = utils.is_suitable_q(q) and utils.is_suitable_r(r) and utils.is_suitable_curve(q,t,r,12,-3,num_bits) if b: try: assert floor(log(r)/log(2)) + 1 >= num_bits, 'Subgroup not large enough' curves.append((q,t,r,12,-3)) curve_num += 1 except AssertionError as e: pass if curve_num < num_curves or not b: q = P(x) r = q+1-t if (utils.is_suitable_q(q) and utils.is_suitable_r(r) and utils.is_suitable_curve(q,t,r,12,-3,num_bits)): try: assert floor(log(r)/log(2)) + 1 >= num_bits, 'Subgroup not large enough' curves.append((q,t,r,12,-3)) curve_num += 1 except AssertionError as e: pass x += 1 return curves
def _method_pt1(num_bits, k, D, y): a = Integer(-D * y**2) R = PolynomialRing(ZZ, 'x') f = R.cyclotomic_polynomial(k)(x - 1).polynomial(base_ring=R) g = (a + (x - 2)**2).polynomial(base_ring=R) r = Integer(f.resultant(g)) if (Mod(r, k) == 1) and r > 2**(num_bits - 1) and utils.is_suitable_r( r): # found a valid r, so use it F = GF(r) f = f.change_ring(F) g = g.change_ring(F) t = Integer(f.gcd(g).any_root()) return t, r else: return 0, 0
def test_list_freitag(m=-1): all = True if m == -1 else False for n, symbols in list_freitag.items(): if all or n == m: for symbol in symbols: M = FiniteQuadraticModule(symbol) V = VectorValuedModularForms(M) k = Integer(2 + n) / Integer(2) glob = is_global(M, 2, n) if glob: d = V.dimension_cusp_forms(k) else: d = "?" print("n = {0} {1}: Dimension({2}) = {3}, {4}, |M|={5}".format( n, symbol, str(k), d, glob, M.order()))
def __init__(self, data, weight=None, prec=3, dual=False): if isinstance(data, dict): #print "dict" self._coeff_dict = data elif isinstance(data, str): #print "str" try: if data == '': F = FiniteQuadraticModule(matrix(2, 2, [0, 1, 1, 0])) else: F = FiniteQuadraticModule(data) if dual: F = F.twist(Integer(-1)) J = F.jordan_decomposition() L = LocalSpaceByJordanData(J._jordan_decomposition_data()) except: jd = genus_symbol_dict_to_jd(GenusSymbol(data)._symbol_dict) L = LocalSpaceByJordanData(jd) self._coeff_dict = L.eisenstein_series(weight, prec=prec) else: #print "else" L = Lattice(data) if dual: L = L(-1) self._coeff_dict = L.eisenstein_series(weight, prec=prec)
def string2number(s): # a start to replace p2sage (used for the paramters in the FE) strs = str(s).replace(' ','') try: if 'e' in strs: # check for e(m/n) := exp(2*pi*i*m/n), used by Dirichlet characters, for example r = re.match(r'^\$?e\\left\(\\frac\{(?P<num>\d+)\}\{(?P<den>\d+)\}\\right\)\$?$',strs) if not r: r = re.match(r'^e\((?P<num>\d+)/(?P<den>\d+)\)$',strs) if r: q = Rational(r.groupdict()['num'])/Rational(r.groupdict()['den']) return CDF(exp(2*pi*I*q)) if 'I' in strs: return CDF(strs) elif (type(s) is list or type(s) is tuple) and len(s) == 2: return CDF(tuple(s)) elif '/' in strs: return Rational(strs) elif strs=='0.5': # Temporary fix because 0.5 in db for EC return Rational('1/2') elif '.' in strs: return float(strs) else: return Integer(strs) except: return s
def polynomial_conjugacy_class_matcher_fn(input): """ Given an input of the form [{"RootOf":["0","1"], "ConjugacyClass":3}, {"RootOf":["-7","1"], "ConjugacyClass":4}] returns a function that - takes an argument alpha - matches alpha as a root to one of the 'RootsOf' - returns the value in the corresponding 'ConjugacyClass' """ P = PolynomialRing(Integers(), "x") fn_cc_pairs = [] for d in input: pol = P([Integer(int_val) for int_val in d["RootOf"]]) fn_cc_pairs.append((pol, d["ConjugacyClass"])) def polynomial_conjugacy_class_matcher(alpha): """ A function that has an internal list of pairs (pol, return_val). Given alpha, finds the pol that it is a root of and returns the associated return_val """ for pol_fn, conjugacy_class_index in fn_cc_pairs: if pol_fn(alpha) == 0: return conjugacy_class_index raise AssertionError("alpha = %s is supposed to be root of one of %s" % (alpha, input)) return polynomial_conjugacy_class_matcher
def test_curve(q, t, r, k, D, E): """ Description: Tests that E is an elliptic curve over F_q with trace t, a subgroup of order r with embedding degree k, and fundamental discriminant D Input: q - size of prime field t - trace of Frobenius r - size of prime order subgroup k - embedding degree D - (negative) fundamental discriminant Output: bool - true iff E is an elliptic curve over F_q with trace t, a subgroup of order r with embedding degree k, and fundamental discriminant D """ bool = True bool = bool and (power_mod(q, k, r) == 1) #q^k -1 ==0 mod r bool = bool and (E.trace_of_frobenius() == t) bool = bool and (kronecker( (t * t - 4 * q) * Integer(D).inverse_mod(q), q) == 1) bool = bool and (E.cardinality() == q + 1 - t) bool = bool and (E.cardinality() % r == 0) return bool
def get_factor_over_nf(curve, prime_ideal, prime_number, conductor, accuracy): """ Returns the inverse of the factor corresponding to the given prime ideal in the Euler product expansion of the L-function at prime_ideal. Unless the accuracy doesn't need this expansion, and then returns 1 in power series ring. """ P = PowerSeriesRing(ZZ, 'T') T = P.gen() q = prime_ideal.norm() inertial_deg = Integer(q).ord(prime_number) if inertial_deg > accuracy: return P(1) if prime_ideal.divides(conductor): a = curve.local_data(prime_ideal).bad_reduction_type() L = 1 - a * (T**inertial_deg) else: discriminant = curve.discriminant() if prime_ideal.divides(discriminant): a = q + 1 - curve.local_minimal_model(prime_ideal).reduction( prime_ideal).count_points() else: a = q + 1 - curve.reduction(prime_ideal).count_points() L = 1 - a * (T**inertial_deg) + q * (T**(2 * inertial_deg)) return L
def small_A_twist(E): """ Description: Finds a curve isogenous to E that has small A in the curve equation y^2 = x^3 + A*x + B Input: E - elliptic curve Output: E' - elliptic curve isogenous to E that has small A in the curve equation y^2 = x^3 + A*x + B """ a = E.ainvs()[3] q = E.base_field().order() a = power_mod(Integer(a), -1, q) if kronecker(a, q) == -1: b = 2 while kronecker(b, q) == 1: b += 1 a = a * b assert kronecker(a, q) == 1 d = Mod(a, q).sqrt() ainvs = [i for i in E.ainvs()] ainvs[3] *= d**2 ainvs[4] *= d**3 return EllipticCurve(E.base_field(), ainvs)
def bad_primes(self): try: return self._bad_primes except AttributeError: from sage.rings.all import Integer self._bad_primes = [Integer(str(x)) for x in self._data["BadPrimes"]] return self._bad_primes
def type_2_primes(K, embeddings, bound=None): """Compute a list containing the type 2 primes""" logger.debug("Starting Type 2 computation ...") # First compute the superset of type 2 primes which are not of Momose Type 2 output = get_type_2_not_momose(K, embeddings) logger.debug("Type 2 not Momose = {}".format(sorted(output))) # Now deal with Momose Type 2 # First get the bound if bound is None: bound = get_type_2_bound(K) logger.info("type_2_bound = {}".format(bound)) # We need to include all primes up to 25 # see Larson/Vaintrob's proof of Theorem 6.4 output = output.union(set(prime_range(25))) for p in pari.primes(25, bound): p_int = Integer(p) if p_int % 4 == 3: # Type 2 primes necessarily congruent to 3 mod 4 if satisfies_condition_CC(K, p_int): output.add(p_int) output = list(output) output.sort() return output