def finite_field(): """ Create a random finite field with degree at most 20 and prime at most 10^6. OUTPUT: a finite field EXAMPLES: sage: sage.rings.tests.finite_field() Finite Field in a of size 161123^4 """ from sage.all import ZZ, GF p = ZZ.random_element(x=2, y=10**6-18).next_prime() d = ZZ.random_element(x=1, y=20) return GF(p**d,'a')
def finite_field(): """ Create a random finite field with degree at most 20 and prime at most 10^6. OUTPUT: a finite field EXAMPLES: sage: sage.rings.tests.finite_field() Finite Field in a of size 161123^4 """ from sage.all import ZZ, GF p = ZZ.random_element(x=2, y=10**6 - 18).next_prime() d = ZZ.random_element(x=1, y=20) return GF(p**d, 'a')
def rsa(bits): # only prove correctness up to 1024bits proof = (bits <= 1024) p = next_prime(ZZ.random_element(2**(bits // 2 + 1)), proof=proof) q = next_prime(ZZ.random_element(2**(bits // 2 + 1)), proof=proof) n = p * q phi_n = (p - 1) * (q - 1) while True: e = ZZ.random_element(1, phi_n) if gcd(e, phi_n) == 1: break d = lift(Mod(e, phi_n)**(-1)) return e, d, n
def encap(cls, pk, seed=None): """IND-CCA encapsulation sans compression or extra hash :param cls: Kyber class, inherit and change constants to change defaults :param pk: public key :param seed: seed used for random sampling if provided .. note :: Resembles Algorithm 4 of the Kyber paper. """ n = cls.n if seed is not None: set_random_seed(seed) m = random_vector(GF(2), n) m.set_immutable() set_random_seed(hash(m)) # NOTE: this is obviously not faithful K_ = random_vector(GF(2), n) K_.set_immutable() r = ZZ.random_element(0, 2**n-1) c = cls.enc(pk, m, r) K = hash((K_, c)) # NOTE: this obviously isn't a cryptographic hash return c, K
def decap(cls, sk, pk, c): """IND-CCA decapsulation :param cls: Kyber class, inherit and change constants to change defaults :param sk: secret key :param pk: public key :param c: ciphertext .. note :: Resembles Algorithm 5 of the Kyber paper. """ n = cls.n m = cls.dec(sk, c) m.set_immutable() set_random_seed(hash(m)) # NOTE: this is obviously not faithful K_ = random_vector(GF(2), n) K_.set_immutable() r = ZZ.random_element(0, 2**n-1) c_ = cls.enc(pk, m, r) if c == c_: return hash((K_, c)) # NOTE: this obviously isn't a cryptographic hash else: return hash(c) # NOTE ignoring z
def rings1(): """ Return an iterator over random rings. Return a list of pairs (f, desc), where f is a function that outputs a random ring that takes a ring and possibly some other data as constructor. RINGS:: - polynomial ring in one variable over a rings0() ring. - polynomial ring over a rings1() ring. - multivariate polynomials EXAMPLES:: sage: import sage.rings.tests sage: type(sage.rings.tests.rings0()) <type 'list'> """ v = rings0() X = random_rings(level=0) from sage.all import PolynomialRing, ZZ v = [(lambda : PolynomialRing(next(X), names='x'), 'univariate polynomial ring over level 0 ring'), (lambda : PolynomialRing(next(X), abs(ZZ.random_element(x=2,y=10)), names='x'), 'multivariate polynomial ring in between 2 and 10 variables over a level 0 ring')] return v
def random_element(self, x=None, y=None, distribution=None): """ Return a random integer in Pari. NOTE: The given arguments are passed to ``ZZ.random_element(...)``. INPUT: - `x`, `y` -- optional integers, that are lower and upper bound for the result. If only `x` is provided, then the result is between 0 and `x-1`, inclusive. If both are provided, then the result is between `x` and `y-1`, inclusive. - `distribution` -- optional string, so that ``ZZ`` can make sense of it as a probability distribution. EXAMPLE:: sage: R = PariRing() sage: R.random_element() -8 sage: R.random_element(5,13) 12 sage: [R.random_element(distribution="1/n") for _ in range(10)] [0, 1, -1, 2, 1, -95, -1, -2, -12, 0] """ from sage.all import ZZ return self(ZZ.random_element(x,y,distribution))
def PointMinusInfinity(self, P, sign = 0): # Creates a divisor class of P- \inty_{(-1)**sign} maxlower = self.lower assert self.f.degree() == 2*self.g + 2; sqrtan = (-1)**sign * self.Rextraprec( sqrt( self.Rdoubleextraprec(self.an)) ); xP, yP = self.Rextraprec(P[0]),self.Rextraprec(P[1]) assert (self.f(xP) - yP**2).abs() <= (yP**2).abs() * self.almostzero if xP != 0 and self.a0 != 0: x0 = self.Rextraprec(0); else: x0 = xP while x0 == xP: x0 = self.Rextraprec(ZZ.random_element()) y0 = self.Rextraprec( sqrt( self.Rdoubleextraprec( self.f( x0 )))) # P0 = (x0, y0) WP1 = Matrix(self.Rextraprec, self.nZ, 3 * self.g + 6) # H0(3D0 - P0 - g \infty) = H0(3D0 - P0 - g(\infty_{+} + \infty_{-})) EvP = Matrix(self.Rextraprec, 1, 3 * self.g + 6) # the functions of H0(3D0-P0-g \infty) at P B = Matrix(self.Rextraprec, self.nZ, 3 * self.g + 5) # H0(3D0 - \infty_{sign} - P0 - g\infty) # adds the functions x - x0, (x - x0)**1, ..., (x - x0)**(2g+2) to it for j in xrange(2 * self.g + 2 ): for i, (x, y) in enumerate( self.Z ): WP1[ i, j] = B[ i, j] = (x - x0) ** (j + 1) EvP[ 0, j] = (xP - x0) ** (j + 1) # adds y - y0 for i, (x, y) in enumerate( self.Z ): WP1[ i, 2 * self.g + 2 ] = B[ i, 2 * self.g + 2] = y - y0 EvP[ 0, 2 * self.g + 2] = yP - y0 # adds (x - x0) * y ... (x-x0)**(g+1)*y for j in range(1, self.g + 2): for i, (x,y) in enumerate( self.Z ): WP1[ i, 2 * self.g + 2 + j ] = B[ i, 2 * self.g + 2 + j] = (x-x0)**j * y EvP[ 0, 2 * self.g + 2 + j] = (xP - x0)**j * yP # adds (x - x0)**(2g + 3) and y * (x - x0)**(g + 2) for i,(x,y) in enumerate(self.Z): WP1[ i, 3 * self.g + 4 ] = (x - x0)**( 2 * self.g + 3) WP1[ i, 3 * self.g + 5 ] = y * (x - x0)**(self.g + 2) B[ i, 3 * self.g + 4 ] = (x - x0)**( self.g + 2) * ( y - sqrtan * x**(self.g + 1) ) EvP[ 0, 3 * self.g + 4] = (xP - x0) ** ( 2 * self.g + 3) EvP[ 0, 3 * self.g + 5] = yP * (xP - x0)**(self.g + 2) # A = functions in H0(3D0-P0-g \infty) that vanish at P # = H**0(3D0 - P0 - P -g \infty) K, upper, lower = Kernel(EvP, EvP.ncols() - (3 * self.g + 5)) assert self.threshold_check(upper, lower), "upper = %s lower = %s" % (RealField(35)(upper), RealField(35)(lower)) maxlower = max(maxlower, lower); A = WP1 * K # A - B = P0 + P + g \infty - (\infty_{+} + P0 + g\infty) = P - \inty_{+} res, lower = self.Sub(A,B) maxlower = max(maxlower, lower); return res.change_ring(self.R), maxlower;
def relative_number_field(n=2, maxdeg=2): """ Return a tower of at most n extensions each of degree at most maxdeg. EXAMPLES:: sage: import sage.rings.tests sage: sage.rings.tests.relative_number_field(3) Number Field in aaa with defining polynomial x^2 - 15*x + 17 over its base field """ from sage.all import ZZ K = absolute_number_field(maxdeg) n -= 1 var = 'aa' R = ZZ['x'] while n >= 1: while True: f = R.random_element(degree=ZZ.random_element(x=1, y=maxdeg), x=-100, y=100) if f.degree() <= 0: continue f = f * f.denominator() # bug trac #4781 f = f + R.gen()**maxdeg # make monic if f.is_irreducible(): break K = K.extension(f, var) var += 'a' n -= 1 return K
def relative_number_field(n=2, maxdeg=2): """ Return a tower of at most n extensions each of degree at most maxdeg. EXAMPLES: sage: sage.rings.tests.relative_number_field(3) Number Field in aaa with defining polynomial x^2 - 15*x + 17 over its base field """ from sage.all import ZZ K = absolute_number_field(maxdeg) n -= 1 var = 'aa' R = ZZ['x'] while n >= 1: while True: f = R.random_element(degree=ZZ.random_element(x=1,y=maxdeg),x=-100,y=100) if f.degree() <= 0: continue f = f * f.denominator() # bug trac #4781 f = f + R.gen()**maxdeg # make monic if f.is_irreducible(): break K = K.extension(f,var) var += 'a' n -= 1 return K
def rings1(): """ Return an iterator over random rings. Return a list of pairs (f, desc), where f is a function that outputs a random ring that takes a ring and possibly some other data as constructor. RINGS: - polynomial ring in one variable over a rings0() ring. - polynomial ring over a rings1() ring. - multivariate polynomials EXAMPLES:: sage: import sage.rings.tests sage: type(sage.rings.tests.rings0()) <type 'list'> """ v = rings0() X = random_rings(level=0) from sage.all import PolynomialRing, ZZ v = [ (lambda: PolynomialRing(next(X), names='x'), 'univariate polynomial ring over level 0 ring'), (lambda: PolynomialRing( next(X), abs(ZZ.random_element(x=2, y=10)), names='x'), 'multivariate polynomial ring in between 2 and 10 variables over a level 0 ring' ) ] return v
def sample(self, m=2, klen_list=None, seed=None, errors=0.0): """ Sample `m` leaky signatures. :param m: :param klen_list: :param seed: :param errors: fraction of signatures that are 1 bit longer than ``klen_list`` specifies """ if klen_list is None: klen_list = [128] * m import ecdsa as ecdsam from ecdsa.util import PRNG if seed is not None: rng = PRNG(seed) else: rng = None sk = ecdsam.SigningKey.generate(curve=self.curve, entropy=rng) d = btoi(sk.to_string()) vk = sk.get_verifying_key() lines = [] k_list = [] for i in range(m): h = ZZ.random_element(2 ** self.nbits) hb = itob(h, self.baselen) if errors > 0 and random() < errors: k, sss = self.sign(hb, sk, klen=klen_list[i] + 1, return_k=True) else: k, sss = self.sign(hb, sk, klen=klen_list[i], return_k=True) k_list.append(k) lines.append("%s %s %s %s" % (str(klen_list[i]), bytes.hex(hb), bytes.hex(sss), bytes.hex(vk.to_string()))) return lines, k_list, d
def random_element(self, x=None, y=None, distribution=None): """ Return a random integer in Pari. NOTE: The given arguments are passed to ``ZZ.random_element(...)``. INPUT: - `x`, `y` -- optional integers, that are lower and upper bound for the result. If only `x` is provided, then the result is between 0 and `x-1`, inclusive. If both are provided, then the result is between `x` and `y-1`, inclusive. - `distribution` -- optional string, so that ``ZZ`` can make sense of it as a probability distribution. EXAMPLE:: sage: R = PariRing() sage: R.random_element() -8 sage: R.random_element(5,13) 12 sage: [R.random_element(distribution="1/n") for _ in range(10)] [0, 1, -1, 2, 1, -95, -1, -2, -12, 0] """ from sage.all import ZZ return self(ZZ.random_element(x, y, distribution))
def benchmark(nlen, klen, m, e, algorithm, flavor, tasks, jobs, parallelism, seed, dimension, params, loglvl="DEBUG"): """ Generate random instances and report solving statistics. Fractional nonce lengths (`-k`) are interpreted as a fraction of larger nonces. For example `252.2` means `0.2⋅m` nonces of size `2^{253}` and `0.8⋅m` of size `2^{252}`. """ logging.basicConfig(level=loglvl, format="%(message)s") install_mp_handler() from ecdsa_hnp import benchmark as run_hnp from sage.all import ZZ if klen >= nlen: raise ValueError("{klen:.2f} ≥ {nlen}".format(klen=klen, nlen=nlen)) if params is None: params = tuple() if params: params = dict([(x, eval(y)) for x, y in params]) else: params = {} if algorithm == tuple(): algorithm = (None, ) if seed is None: seed = ZZ.random_element(x=0, y=2**64) for alg in algorithm: run_hnp( nlen=nlen, klen=klen, m=m, e=e, tasks=tasks, algorithm=alg, flavor=flavor, d=dimension, jobs=jobs, parallelism=parallelism, seed=seed, solver_params=params, )
def integer_mod_ring(): """ Return a random ring of integers modulo n with n at most 50000. EXAMPLES: sage: sage.rings.tests.integer_mod_ring() Ring of integers modulo 30029 """ from sage.all import ZZ, IntegerModRing n = ZZ.random_element(x=2,y=50000) return IntegerModRing(n)
def integer_mod_ring(): """ Return a random ring of integers modulo n with n at most 50000. EXAMPLES: sage: sage.rings.tests.integer_mod_ring() Ring of integers modulo 30029 """ from sage.all import ZZ, IntegerModRing n = ZZ.random_element(x=2, y=50000) return IntegerModRing(n)
def prime_finite_field(): """ Create a random prime finite field with cardinality at most 10^20. OUTPUT: a prime finite field EXAMPLES: sage: sage.rings.tests.prime_finite_field() Finite Field of size 64748301524082521489 """ from sage.all import ZZ, GF return GF(ZZ.random_element(x=2, y=10**20 - 12).next_prime())
def quadratic_number_field(): """ Return a quadratic extension of QQ. EXAMPLES: sage: sage.rings.tests.quadratic_number_field() Number Field in a with defining polynomial x^2 - 61099 """ from sage.all import ZZ, QuadraticField while True: d = ZZ.random_element(x=-10**5, y=10**5) if not d.is_square(): return QuadraticField(d, 'a')
def test_eigenvalues(prec=100,nmax=10,dimmax=10): r""" Test the eigenvalue computations for some random matrices. """ F = MPComplexField(prec) dim = ZZ.random_element(2,dimmax) M = MatrixSpace(F,dim) for n in range(nmax): A,U,l=random_matrix_eigenvalues(F,dim) ev = A.eigenvalues() ev.sort(); l.sort() test = max([abs(ev[j]-l[j]) for j in range(len(ev))]) assert test < A.eps()*100
def quadratic_number_field(): """ Return a quadratic extension of QQ. EXAMPLES: sage: sage.rings.tests.quadratic_number_field() Number Field in a with defining polynomial x^2 - 61099 """ from sage.all import ZZ, QuadraticField while True: d = ZZ.random_element(x=-10**5, y=10**5) if not d.is_square(): return QuadraticField(d,'a')
def test_eigenvalues(prec=100, nmax=10, dimmax=10): r""" Test the eigenvalue computations for some random matrices. """ F = MPComplexField(prec) dim = ZZ.random_element(2, dimmax) M = MatrixSpace(F, dim) for n in range(nmax): A, U, l = random_matrix_eigenvalues(F, dim) ev = A.eigenvalues() ev.sort() l.sort() test = max([abs(ev[j] - l[j]) for j in range(len(ev))]) assert test < A.eps() * 100
def absolute_number_field(maxdeg=10): """ Return an absolute extension of QQ of degree at most 10. EXAMPLES: sage: sage.rings.tests.absolute_number_field() Number Field in a with defining polynomial x^5 + 82*x^4 - 46*x^3 + 39*x^2 - x - 41 """ from sage.all import ZZ, NumberField R = ZZ['x'] while True: f = R.random_element(degree=ZZ.random_element(x=1,y=maxdeg),x=-100,y=100) if f.degree() <= 0: continue f = f + R.gen()**(f.degree()+1) # make monic if f.is_irreducible(): return NumberField(f, 'a')
def small_finite_field(): """ Create a random finite field with cardinality at most 2^16. OUTPUT: a finite field EXAMPLES: sage: sage.rings.tests.small_finite_field() Finite Field of size 30029 """ from sage.all import ZZ, GF while True: q = ZZ.random_element(x=2, y=2**16) if q.is_prime_power(): return GF(q, 'a')
def small_finite_field(): """ Create a random finite field with cardinality at most 2^16. OUTPUT: a finite field EXAMPLES: sage: sage.rings.tests.small_finite_field() Finite Field of size 30029 """ from sage.all import ZZ, GF while True: q = ZZ.random_element(x=2,y=2**16) if q.is_prime_power(): return GF(q,'a')
def absolute_number_field(maxdeg=10): """ Return an absolute extension of QQ of degree at most 10. EXAMPLES:: sage: import sage.rings.tests sage: sage.rings.tests.absolute_number_field() Number Field in a with defining polynomial x^5 + 82*x^4 - 46*x^3 + 39*x^2 - x - 41 """ from sage.all import ZZ, NumberField R = ZZ['x'] while True: f = R.random_element(degree=ZZ.random_element(x=1,y=maxdeg),x=-100,y=100) if f.degree() <= 0: continue f = f + R.gen()**(f.degree()+1) # make monic if f.is_irreducible(): return NumberField(f, 'a')
def attack(base, multiplication_result): """ Solves the discrete logarithm problem using Smart's attack. More information: Smart N. P., "The discrete logarithm problem on elliptic curves of trace one" :param base: the base point :param multiplication_result: the point multiplication result :return: l such that l * base == multiplication_result """ curve = base.curve() gf = curve.base_ring() p = gf.order() assert curve.trace_of_frobenius() == 1, f"Curve should have trace of Frobenius = 1." lift_curve = EllipticCurve(Qp(p), list(map(lambda a: int(a) + p * ZZ.random_element(1, p), curve.a_invariants()))) lifted_base = p * _lift(lift_curve, base, gf) lifted_multiplication_result = p * _lift(lift_curve, multiplication_result, gf) lb_x, lb_y = lifted_base.xy() lmr_x, lmr_y = lifted_multiplication_result.xy() return int(gf((lmr_x / lmr_y) / (lb_x / lb_y)))
def sign(self, h, sk, klen=256, return_k=False): """ Sign ``h`` and signing key ``sk`` :param h: "hash" :param sk: signing key :param klen: number of bits in the nonce. :param return_k: """ d = btoi(sk.to_string()) hi = btoi(h) k = ZZ.random_element(2 ** klen) r = Integer((self.GG * k).xy()[0]) s = lift(inverse_mod(k, self.n) * mod(hi + d * r, self.n)) sig = itob(r, self.baselen) + itob(s, self.baselen) if return_k: return k, sig return sig
verbose = False prec = ceil(log(10) / log(2) * digits) iaj = InvertAJglobal(g, prec, verbose) CCap = iaj.C Pic = iaj.Pic y0 = 0 while y0 == 0: x0 = 1 #ZZ.random_element() y0 = sqrt(g(x0)) print "\tPi = (%s, -/+%s)" % (x0, y0) P0, P1 = vector(CCap, (x0, y0)), vector(CCap, (x0, -y0)) y0 = 0 while y0 == 0 or x0 == P0[0]: x0 = ZZ.random_element() y0 = sqrt(g(x0)) print "\tQi = (%s, -/+%s)" % (x0, y0) Q0, Q1 = vector(CCap, (x0, y0)), vector(CCap, (x0, -y0)) points = [P0, P1, Q0, Q1] pairs = [[P0, Q0], [P0, Q1], [P1, Q0], [P1, Q1]] print "\tTesting P -> Divisor(P, {0,1} ) -> Divisor(P, {0,1}).compute_coordinates() = P - \inf_{(-1)^{0,1}}?" for i, P in enumerate(points): for sign in range(2): #point - \infty_{ (-1)^sign} ~ # point + \inty_{ (-1)^{sign + 1} } - D0 DP = Divisor(Pic, [P], sign) R0, R1 = DP.compute_coordinates() R0 = vector(R0)
def Newforms_v2(N, k, chi_number, dmax=20, nan=100, Detail=0): t0 = time.time() G = pari(N).znstar(1) chi_dc = char_orbit_index_to_DC_number(N, chi_number) chi_gp = G.znconreylog(chi_dc) chi_order = ZZ(G.charorder(chi_gp)) if Detail: print("Decomposing space {}:{}:{}".format(N, k, chi_number)) NK = [N, k, [G, chi_gp]] pNK = pari(NK) if Detail > 1: print("NK = {} (gp character = {})".format(NK, chi_gp)) SturmBound = pNK.mfsturm() Snew = pNK.mfinit(0) total_dim = Snew.mfdim( ) # this is the relative dimension i.e. degree over Q(chi) # Get the character polynomial # Note that if the character order is 2*m with m odd then Pari uses the # m'th cyclotomic polynomial and not the 2m'th (e.g. for a # character of order 6 it uses t^2+t+1 and not t^2-t+1). chi_order_2 = chi_order // 2 if chi_order % 4 == 2 else chi_order chipoly = cyclotomic_polynomial(chi_order_2, 't') chi_degree = chipoly.degree() assert chi_degree == euler_phi(chi_order) == euler_phi(chi_order_2) t05 = time.time() if Detail: print( "Computed newspace {}:{}:{} in {:0.3f}, dimension={}*{}={}, now splitting into irreducible subspaces" .format(N, k, chi_number, t05 - t0, chi_degree, total_dim, chi_degree * total_dim)) if Detail > 1: print("Sturm bound = {}".format(SturmBound)) print("character order = {}".format(chi_order)) if total_dim == 0: if Detail: print("The space {}:{}:{} is empty".format(N, k, chi_number)) return [] # First just compute Hecke matrices one at a time, to find a splitting operator def Hecke_op_iter(): p = ZZ(1) while True: p = p.next_prime() # while p.divides(N): # p=p.next_prime() #print("Computing T_{}".format(p)) yield p, Snew.mfheckemat(p) Tp_iter = Hecke_op_iter() p, op = Tp_iter.next() s1 = time.time() if Detail: print("testing T_{}".format(p)) ok = is_semisimple_modular(op, chi_order_2) # f = op.charpoly() # ok = f.issquarefree() if ok: if Detail: print("Lucky first time: semisimple. Finding char poly") f = op.charpoly() ops = [(p, op)] while not ok: pi, opi = Tp_iter.next() if Detail: print("testing T_{}".format(pi)) ok = is_semisimple_modular(op, chi_order_2) # f = opi.charpoly() # ok = f.issquarefree() if ok: if Detail: print("success using T_{}. Finding char poly".format(pi)) op = opi f = op.charpoly() break else: #ops.append((pi,opi)) ops += [(pi, opi)] if Detail: print("T_{} not semisimple".format(pi)) print("testing combinations...") for j in range(5): co = [ZZ.random_element(-5, 5) for _ in ops] while not co: co = [ZZ.random_element(-5, 5) for _ in ops] if Detail: print("Testing lin comb of {} ops with coeffs {}".format( len(co), co)) op = sum([ci * opj[1] for ci, opj in zip(co, ops)]) ok = is_semisimple_modular(op, chi_order_2) # f=op.charpoly() # ok = f.issquarefree() if ok: if Detail: print( "success using {}-combo of T_p for p in {}. Finding char poly" .format(co, [opj[0] for opj in ops])) f = op.charpoly() break if not ok: raise RuntimeError( "failed to find a 0,1-combination of Tp which is semisimple") ffac = f.factor() nnf = ffac.matsize()[0] gp_pols = pari_col1(ffac) pols = [pol for pol in gp_pols] reldims = [pol.poldegree() for pol in pols] dims = [d * chi_degree for d in reldims] # We'll need the coefficients an, if any newforms have dimension >1 and <=dmax. an_needed = [ i for i, d in enumerate(dims) if d > 1 and (dmax == 0 or d <= dmax) ] if Detail: print("Need to compute a_n for {} newforms: {}".format( len(an_needed), an_needed)) s2 = time.time() if Detail: print("Computed splitting in {:0.3f}, # newforms = {}".format( s2 - s1, nnf)) print("relative dims = {}, absolute dims = {}".format(reldims, dims)) # Compute AL-matrices if character is trivial: if chi_order == 1: Qlist = [(pr, pr**e) for pr, e in ZZ(N).factor()] ALs = [Snew.mfatkininit(Q[1])[1] for Q in Qlist] if Detail: print("AL-matrices:") for Q, AL in zip(Qlist, ALs): print("W_{}={}".format(Q[1], AL)) if nnf == 1 and dims[0] > dmax and dmax > 0: if Detail: print( "Only one newform and dim={}, so use traceform to get traces". format(dims[0])) traces = pNK.mftraceform().mfcoefs(nan) if Detail > 1: print("raw traces: {}".format(traces)) if chi_degree > 1: # This is faster than the more simple # traces = [c.trace() for c in traces] gptrace = pari_trace(chi_degree) traces = pari.apply(gptrace, traces) if Detail > 1: print("traces to QQ: {}".format(traces)) traces = gen_to_sage(traces)[1:] traces[0] = dims[0] if Detail > 1: print("final traces: {}".format(traces)) traces = [traces] else: # >1 newform, or just one but its absolute dim is <=dmax hs = [f / fi for fi in pols] if Detail > 1: print("fs: {}".format(pols)) print("hs: {}".format(hs)) print(" with degrees {}".format([h.poldegree() for h in hs])) if Detail > 1: print("Starting to compute gcds") As = [(hi * (fi.gcdext(hi)[2])).subst(pari_x, op) for fi, hi in zip(pols, hs)] if Detail: print("Computed idempotent matrix decomposition") ims = [A.matimage() for A in As] U = pari.matconcat(ims) Uinv = U**(-1) if Detail: print("Computed U and U^-1") starts = [1 + sum(d for d in reldims[:i]) for i in range(len(reldims))] stops = [sum(d for d in reldims[:i + 1]) for i in range(len(reldims))] slicers = [pari_row_slice(r1, r2) for r1, r2 in zip(starts, stops)] ums = [slice(Uinv) for slice in slicers] imums = [imA * umA for imA, umA in zip(ims, ums)] s3 = time.time() if Detail: print("Computed projectors in {:0.3f}".format(s3 - s2)) print("Starting to compute {} Hecke matrices T_n".format(nan)) heckemats = Snew.mfheckemat(pari(range(1, nan + 1))) s4 = time.time() if Detail: print("Computed {} Hecke matrices in {:0.3f}s".format( nan, s4 - s3)) # If we are going to compute any a_n then we now compute # umA*T*imA for all Hecke matrices T, whose traces give the # traces and whose first columns (or any row or column) give # the coefficients of the a_n with respect to some # Q(chi)-basis for the Hecke field. # But if we only need the traces then it is faster to # precompute imA*umA=imAumA and then the traces are # trace(imAumA*T). NB trace(UMV)=trace(VUM)! if Detail: print("Computing traces") # Note that computing the trace of a matrix product is faster # than first computing the product and then the trace: gptrace = pari( 'c->if(type(c)=="t_POLMOD",trace(c),c*{})'.format(chi_degree)) traces = [[ gen_to_sage(gptrace(pari_trace_product(T, imum))) for T in heckemats ] for imum in imums] s4 = time.time() if Detail: print("Computed traces to Z in {:0.3f}".format(s4 - s3)) for tr in traces: print(tr[:20]) ans = [None for _ in range(nnf)] bases = [None for _ in range(nnf)] if an_needed: if Detail: print("...computing a_n...") for i in an_needed: dr = reldims[i] if Detail: print("newform #{}/{}, relative dimension {}".format( i, nnf, dr)) # method: for each irreducible component we have matrices # um and im (sizes dr x n and n x dr where n is the # relative dimension of the whole space) such that for # each Hecke matrix T, its restriction to the component is # um*T*im. To get the eigenvalue in a suitable basis all # we need do is take any one column (or row): we choose # the first column. So the computation can be done as # um*(T*im[,1]) (NB the placing of parentheses). imsicol1 = pari_col1(ims[i]) umsi = ums[i] ans[i] = [(umsi * (T * imsicol1)).Vec() for T in heckemats] if Detail: print("ans done") if Detail > 1: print("an: {}...".format(ans[i])) # Now compute the bases (of the relative Hecke field over # Q(chi) w.r.t which these coefficients are given. Here # we use e1 because we picked the first column just now. B = ums[i] * op * ims[i] e1 = pari_e1(dr) cols = [e1] while len(cols) < dr: cols.append(B * cols[-1]) W = pari.matconcat(cols) bases[i] = W.mattranspose()**(-1) if Detail > 1: print("basis = {}".format(bases[i].lift())) # Compute AL-eigenvalues if character is trivial: if chi_order == 1: ALeigs = [[[Q[0], gen_to_sage((umA * (AL * (pari_col1(imA))))[0])] for Q, AL in zip(Qlist, ALs)] for umA, imA in zip(ums, ims)] if Detail > 1: print("ALeigs: {}".format(ALeigs)) else: ALeigs = [[] for _ in range(nnf)] Nko = (N, k, chi_number) #print("len(traces) = {}".format(len(traces))) #print("len(newforms) = {}".format(len(newforms))) #print("len(pols) = {}".format(len(pols))) #print("len(ans) = {}".format(len(ans))) #print("len(ALeigs) = {}".format(len(ALeigs))) pari_nfs = [{ 'Nko': Nko, 'SB': SturmBound, 'chipoly': chipoly, 'poly': pols[i], 'ans': ans[i], 'basis': bases[i], 'ALeigs': ALeigs[i], 'traces': traces[i], } for i in range(nnf)] # We could return these as they are but the next processing step # will fail if the underlying gp process has quit, so we do the # processing here. # This processing returns full data but the polynomials have not # yet been polredbested and the an coefficients have not been # optimized (or even made integral): #return pari_nfs t1 = time.time() if Detail: print("{}: finished constructing pari newforms (time {:0.3f})".format( Nko, t1 - t0)) nfs = [process_pari_nf(nf, dmax, Detail) for nf in pari_nfs] if len(nfs) > 1: nfs.sort(key=lambda f: f['traces']) t2 = time.time() if Detail: print( "{}: finished first processing of newforms (time {:0.3f})".format( Nko, t2 - t1)) if Detail > 2: for nf in nfs: if 'eigdata' in nf: print(nf['eigdata']['ancs']) nfs = [bestify_newform(nf, dmax, Detail) for nf in nfs] t3 = time.time() if Detail: print("{}: finished bestifying newforms (time {:0.3f})".format( Nko, t3 - t2)) if Detail > 2: for nf in nfs: if 'eigdata' in nf: print(nf['eigdata']['ancs']) nfs = [integralify_newform(nf, dmax, Detail) for nf in nfs] t4 = time.time() if Detail: print("{}: finished integralifying newforms (time {:0.3f})".format( Nko, t4 - t3)) if Detail > 2: for nf in nfs: if 'eigdata' in nf: print(nf['eigdata']['ancs']) print("Total time for space {}: {:0.3f}".format(Nko, t4 - t0)) return nfs
def benchmark( nlen=256, klen=128, m=2, e=0.0, tasks=8, algorithm=None, flavor="plain", d=None, jobs=1, parallelism=1, seed=None, solver_params=None, ): """ :param nlen: number of bits in the ECDSA key :param klen: number of known bits of the key :param m: number of available samples :param e: fraction of errors :param tasks: number of experiments to run :param algorithm: algorithm to use, see ``usvp.solvers`` :param flavor: higher-level strategy to use, see ``usvp.flavors`` :param d: lattice dimension (default: `m+1`) :param jobs: number of experiments to run in parallel :param parallelism: parallelism to use per experiment :param seed: randomness seed """ from usvp_prec_hack import usvp_pred_cut_n_sieve_solve from usvp import solvers if nlen > 384: logging.warning("% hotpatching with slower but more numerically stable `usvp_pred_cut_n_sieve_solve`.") solvers["sieve_pred"] = usvp_pred_cut_n_sieve_solve klen_list = make_klen_list(klen, m) tag = ZZ.random_element(x=0, y=2 ** 64) # we tag all outputs for easier matching if seed is None: seed = ZZ.random_element(x=0, y=2 ** 64) logging.warning( ( "% {t:s} {h:s} 0x{tag:016x} :: nlen: {nlen:3d}, m: {m:2d}, klen: {klen:.3f}, e: {e:.2f}, " "alg: {alg:s}, seed: 0x{seed:016x}, params: {params}" ).format( t=str(datetime.datetime.now()), h=socket.gethostname(), nlen=nlen, e=e, m=m, klen=float(mean(klen_list)), alg=str(algorithm), seed=seed, tag=tag, params=solver_params, ) ) pool = Pool(jobs) J = [ ComputeKernelParams( i=i, nlen=nlen, m=m, e=e, klen_list=klen_list, seed=seed + i, algorithm=algorithm, flavor=flavor, d=d, threads=parallelism, params=solver_params, tag=tag, ) for i in range(tasks) ] if jobs > 1: r = list(pool.imap_unordered(compute_kernel, J)) else: r = list(map(compute_kernel, J)) ecdsa = ECDSA(nbits=nlen) expected_target = ECDSASolver.evf(m, max(klen_list), prec=nlen // 2) expected_b0 = ECDSASolver.ghf(m, ecdsa.n, klen_list, prec=nlen // 2) successes = 0 B0 = [] eB0 = [] work = [] cputime = [] walltime = [] for key, res, targetvector_norm in r: successes += int(res.success) B0.append(float(targetvector_norm / res.b0)) eB0.append(float(expected_target / res.b0)) work.append(int(res.ntests)) cputime.append(float(res.cputime)) walltime.append(float(res.walltime)) logging.warning( ( "% {tm:s} {h:s} 0x{tag:016x} :: sr: {sr:3.0f}%, v/b[0]: {b0ratio:.3f}, " "E|v|/|b[0]|: {eb0r:.3f}, E|v|/E|b[0]|: {eveb:.3f}, work: {wk:d}, " "t: {t:.1f}s, w: {w:.1f}s" ).format( tm=str(datetime.datetime.now()), h=socket.gethostname(), sr=100 * float(successes / tasks), b0ratio=median(B0), eb0r=median(eB0), eveb=float(expected_target / expected_b0), wk=int(median(work)), t=median(cputime), w=median(walltime), tag=tag, ) ) return r
def search(info): """ query processing for Sato-Tate groups -- returns rendered results page """ if 'jump' in info: return redirect(url_for('.by_label', label=info['jump']), 301) if 'label' in info: return redirect(url_for('.by_label', label=info['label']), 301) search_type = info.get("search_type", info.get("hst", "List")) template_kwds = { 'bread': [('Sato-Tate Groups', url_for('.index')), ('Search Results', '.')], 'credit': credit_string, 'learnmore': learnmore_list() } title = 'Sato-Tate Group Search Results' err_title = 'Sato-Tate Groups Search Input Error' count = parse_count(info, 50) start = parse_start(info) # if user clicked refine search always restart at 0 if 'refine' in info: start = 0 ratonly = (info.get('include_irrational', 'no').strip().lower() == 'no') if search_type == "Random" and not ratonly: info['err'] = err = 'Cannot select random irrational Sato-Tate group' flash_error(err) return render_template('st_results.html', info=info, title=err_title, **template_kwds) query = {'rational': True} if ratonly else {} try: parse_ints(info, query, 'weight', 'weight') if 'weight' in query: weight_list = parse_ints_to_list_flash(info.get('weight'), 'weight') parse_ints(info, query, 'degree', 'degree') if 'degree' in query: degree_list = parse_ints_to_list_flash(info.get('degree'), 'degree') if info.get('identity_component'): query['identity_component'] = info['identity_component'] parse_ints(info, query, 'components', 'components') if 'components' in query: components_list = parse_ints_to_list_flash(info.get('components'), 'components') parse_rational(info, query, 'trace_zero_density', 'trace zero density') except ValueError as err: info['err'] = str(err) return render_template('st_results.html', info=info, title=err_title, **template_kwds) # Check mu(n) groups first (these are not stored in the database) results = [] if ((not 'weight' in query or 0 in weight_list) and (not 'degree' in query or 1 in degree_list) and (not 'identity_component' in query or query['identity_component'] == 'SO(1)') and (not 'trace_zero_density' in query or query['trace_zero_density'] == '0')): if not 'components' in query: components_list = range(1, 3 if ratonly else start + count + 1) elif ratonly: components_list = [n for n in range(1, 3) if n in components_list] nres = len( components_list) if 'components' in query or ratonly else INFINITY if search_type == "Random" and nres > 0: # Need to return mu(1) and mu(2) sometimes otherlen = db.gps_sato_tate.count(query) r = ZZ.random_element(nres + otherlen) if r < nres: return redirect( url_for(".by_label", label="0.1.%d" % components_list[r]), 307) for n in itertools.islice(components_list, start, start + count): results.append(mu_info(n)) else: nres = 0 if 'result_count' in info: nres += db.gps_sato_tate.count(query) return jsonify({"nres": str(nres)}) if search_type == "Random": label = db.gps_sato_tate.random(query, "label") if label is not None: return redirect(url_for(".by_label", label=label), 307) # Now lookup other (rational) ST groups in database if nres != INFINITY: start2 = start - nres if start > nres else 0 proj = [ 'label', 'weight', 'degree', 'real_dimension', 'identity_component', 'name', 'pretty', 'components', 'component_group', 'trace_zero_density', 'moments' ] try: res = db.gps_sato_tate.search(query, proj, limit=max(count - len(results), 0), offset=start2, info=info) except QueryCanceledError as err: ctx = ctx_proc_userdata() flash_error( 'The search query took longer than expected! Please help us improve by reporting this error <a href="%s" target=_blank>here</a>.' % ctx['feedbackpage']) info['err'] = str(err) return render_template('st_results.html', info=info, title=err_title, **template_kwds) info['number'] += nres if start < info['number'] and len(results) < count: for v in res: v['identity_component'] = st0_pretty(v['identity_component']) v['component_group'] = sg_pretty(v['component_group']) v['trace_moments'] = trace_moments(v['moments']) results.append(v) else: info['number'] = 'infinity' info['start'] = start info['count'] = count info['st0_list'] = st0_list info['st0_dict'] = st0_dict info['results'] = results info['stgroup_url'] = lambda dbc: url_for('.by_label', label=dbc['label']) return render_template('st_results.html', info=info, title=title, **template_kwds)
def search(info): """ query processing for Sato-Tate groups -- returns rendered results page """ if 'jump' in info: return redirect(url_for('.by_label', label=info['jump']), 301) if 'label' in info: return redirect(url_for('.by_label', label=info['label']), 301) search_type = info.get("search_type", info.get("hst", "List")) template_kwds = { 'bread': get_bread("Search results"), 'credit': credit_string, 'learnmore': learnmore_list() } title = 'Sato-Tate group search results' err_title = 'Sato-Tate group search input error' count = parse_count(info, 50) start = parse_start(info) # if user clicked refine search always restart at 0 if 'refine' in info: start = 0 ratonly = (info.get('include_irrational', 'no').strip().lower() == 'no') if search_type == "Random" and not ratonly: info['err'] = err = 'Cannot select random irrational Sato-Tate group' flash_error(err) return render_template('st_results.html', info=info, title=err_title, **template_kwds) query = {'rational': True} if ratonly else {} try: parse_ints(info, query, 'weight', 'weight') if 'weight' in query: weight_list = parse_ints_to_list_flash(info.get('weight'), 'weight') parse_ints(info, query, 'degree', 'degree') if 'degree' in query: degree_list = parse_ints_to_list_flash(info.get('degree'), 'degree') if info.get('identity_component'): query['identity_component'] = info['identity_component'] parse_ints(info, query, 'components', 'components') def refine_components(current, condition): if current is None: return condition return [x for x in condition if x in current] # The following are used to constraint which mu(n) will show up in search results components_list = None ommitted = set() if 'components' in query: components_list = parse_ints_to_list_flash(info.get('components'), 'components') parse_component_group(info, query) gps = query.get("component_group") if gps: if isinstance(gps, dict): gps = gps["$in"] else: gps = [gps] if not ratonly: cyclic_labels = set( db.gps_small.search({"cyclic": True}, "label")) irrat = [] for code in gps: if code in cyclics: irrat.append(cyclics[code]) elif re.match(cyclicre, code): irrat.append(int(code[1:])) elif not ratonly and code in cyclic_labels: irrat.append(int(code.split(".")[0])) components_list = refine_components(components_list, irrat) parse_rational(info, query, 'trace_zero_density', 'trace zero density') parse_ints(info, query, 'second_trace_moment') parse_ints(info, query, 'fourth_trace_moment') for name, ones in [('second_trace_moment', [1, 2]), ('fourth_trace_moment', [1, 2, 4])]: if name in query: # E(x^2) for mu(1) and mu(2) are 1; others are 0 # E(x^4) for mu(1), mu(2) and mu(4) are 1; others are 0 E = parse_ints_to_list_flash(info.get(name), name.replace("_", " ")) if 0 not in E: components_list = refine_components(components_list, ones) if 1 not in E: ommitted.update(ones) parse_ints(info, query, 'first_a2_moment') parse_bool(info, query, 'maximal') if "first_a2_moment" in query or query.get("maximal"): # mu(n) do not have a2 moments and none are maximal components_list = [] except ValueError as err: info['err'] = str(err) return render_template('st_results.html', info=info, title=err_title, **template_kwds) # Check mu(n) groups first (these are not stored in the database) results = [] if ((not 'weight' in query or 0 in weight_list) and (not 'degree' in query or 1 in degree_list) and (not 'identity_component' in query or query['identity_component'] == 'SO(1)') and (not 'trace_zero_density' in query or query['trace_zero_density'] == '0')): nres = None if components_list is None: components_list = range( 1, 3 if ratonly else (start + count + 1 + len(ommitted))) nres = None if ratonly else INFINITY elif ratonly: components_list = [n for n in range(1, 3) if n in components_list] components_list = [n for n in components_list if n not in ommitted] if nres is None: nres = len(components_list) if search_type == "Random" and nres > 0: # Need to return mu(1), mu(2) or mu(4) sometimes otherlen = db.gps_sato_tate.count(query) r = ZZ.random_element(nres + otherlen) if r < nres: return redirect( url_for(".by_label", label="0.1.%d" % components_list[r]), 307) for n in itertools.islice(components_list, start, start + count): results.append(mu_info(n)) else: nres = 0 if 'result_count' in info: nres += db.gps_sato_tate.count(query) return jsonify({"nres": str(nres)}) if search_type == "Random": label = db.gps_sato_tate.random(query, "label") if label is not None: return redirect(url_for(".by_label", label=label), 307) # Now lookup other (rational) ST groups in database if nres != INFINITY: start2 = start - nres if start > nres else 0 proj = [ 'label', 'weight', 'degree', 'real_dimension', 'identity_component', 'name', 'pretty', 'components', 'component_group', 'trace_zero_density', 'moments' ] try: res = db.gps_sato_tate.search(query, proj, limit=max(count - len(results), 0), offset=start2, info=info) except QueryCanceledError as err: ctx = ctx_proc_userdata() flash_error( 'The search query took longer than expected! Please help us improve by reporting this error <a href="%s" target=_blank>here</a>.' % ctx['feedbackpage']) info['err'] = str(err) return render_template('st_results.html', info=info, title=err_title, **template_kwds) info['number'] += nres if start < info['number'] and len(results) < count: for v in res: v['identity_component'] = st0_pretty(v['identity_component']) v['component_group'] = sg_pretty(v['component_group']) v['trace_moments'] = trace_moments(v['moments']) results.append(v) else: info['number'] = 'infinity' info['start'] = start info['count'] = count info['st0_list'] = st0_list info['st0_dict'] = st0_dict info['results'] = results info['stgroup_url'] = lambda dbc: url_for('.by_label', label=dbc['label']) return render_template('st_results.html', info=info, title=title, **template_kwds)