Beispiel #1
1
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')
Beispiel #2
0
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')
Beispiel #3
0
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
Beispiel #4
0
    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
Beispiel #5
0
    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
Beispiel #6
0
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
Beispiel #7
0
    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;
Beispiel #9
0
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
Beispiel #10
0
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
Beispiel #11
0
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
Beispiel #12
0
    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
Beispiel #13
0
    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))
Beispiel #14
0
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,
        )
Beispiel #15
0
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)
Beispiel #16
0
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)
Beispiel #17
0
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())
Beispiel #18
0
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')
Beispiel #19
0
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
Beispiel #20
0
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())
Beispiel #21
0
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')
Beispiel #22
0
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
Beispiel #23
0
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')
Beispiel #24
0
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')
Beispiel #25
0
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')
Beispiel #26
0
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')
Beispiel #27
0
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)))
Beispiel #28
0
    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)
Beispiel #30
0
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
Beispiel #31
0
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
Beispiel #32
0
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)
Beispiel #33
0
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)