Beispiel #1
0
def factorize(n, M, m, t):
    """
    Recovers the prime factors from a modulus using the ROCA method.
    More information: Nemec M. et al., "The Return of Coppersmith’s Attack: Practical Factorization of Widely Used RSA Moduli"
    :param n: the modulus
    :param M: the primorial used to generate the primes
    :param m: the m parameter for Coppersmith's method
    :param t: the t parameter for Coppersmith's method
    :return: a tuple containing the prime factors
    """
    logging.debug("Generating M'...")
    M_ = _greedy_find_M_(n, M)
    ZmodM_ = Zmod(M_)
    e = ZmodM_(65537)
    c_ = ZmodM_(n).log(e)
    ord_ = e.multiplicative_order()

    x = Zmod(n)["x"].gen()
    X = int(2 * n**0.5 // M_)
    logging.debug("Starting exhaustive a' search...")
    for a_ in range(c_ // 2, (c_ + ord_) // 2 + 1):
        f = M_ * x + int(e**a_)
        for k_ in modular_univariate(f, n, m, t, X):
            p = int(f(k_))
            if n % p == 0:
                return p, n // p
Beispiel #2
0
def build_matrix(P, M, c=1000):
    factors_M = factor(M)
    rows = []

    # add logarithms
    for p in P:
        row = []
        for q, e in factors_M:
            row.extend(Zmod(q**e)(p).generalised_log()
                       )  # generalised_log() uses unit_gens() generators
        row = [c * x
               for x in row]  # multiply logs by a large constant to help LLL
        rows.append(row)

    height = len(rows)
    width = len(rows[0])

    # add unit matrix
    for i, row in enumerate(rows):
        row.extend([1 if j == i else 0 for j in range(0, height)])

    # add group orders
    generators_M = [g for q, e in factors_M for g in Zmod(q**e).unit_gens()]
    for i, g in enumerate(generators_M):
        rows.append([
            g.multiplicative_order() * c if j == i else 0
            for j in range(0, width + height)
        ])

    return Matrix(rows)
Beispiel #3
0
def roca(n):

    keySize = n.bit_length()

    if keySize <= 960:
        M_prime = 0x1B3E6C9433A7735FA5FC479FFE4027E13BEA
        m = 5

    elif 992 <= keySize <= 1952:
        M_prime = (
            0x24683144F41188C2B1D6A217F81F12888E4E6513C43F3F60E72AF8BD9728807483425D1E
        )
        m = 4
        print("Have you several days/months to spend on this ?")

    elif 1984 <= keySize <= 3936:
        M_prime = 0x16928DC3E47B44DAF289A60E80E1FC6BD7648D7EF60D1890F3E0A9455EFE0ABDB7A748131413CEBD2E36A76A355C1B664BE462E115AC330F9C13344F8F3D1034A02C23396E6
        m = 7
        print("You'll change computer before this scripts ends...")

    elif 3968 <= keySize <= 4096:
        print("Just no.")
        return None

    else:
        print("Invalid key size: {}".format(keySize))
        return None

    beta = 0.1
    a3 = Zmod(M_prime)(n).log(65537)
    order = Zmod(M_prime)(65537).multiplicative_order()
    inf = a3 >> 1
    sup = (a3 + order) >> 1
    # Upper bound for the small root x0
    XX = floor(2 * n ** 0.5 / M_prime)
    invmod_Mn = inverse_mod(M_prime, n)
    # Create the polynom f(x)
    F = PolynomialRing(Zmod(n), implementation="NTL", names=("x",))
    (x,) = F._first_ngens(1)
    # Search 10 000 values at a time, using multiprocess
    # too big chunks is slower, too small chunks also
    chunk_size = 10000
    for inf_a in range(inf, sup, chunk_size):
        # create an array with the parameter for the solve function
        inputs = [
            ((M_prime, n, a, m, XX, invmod_Mn, F, x, beta), {})
            for a in range(inf_a, inf_a + chunk_size)
        ]
        # the sage builtin multiprocessing stuff
        from sage.parallel.multiprocessing_sage import parallel_iter
        from multiprocessing import cpu_count

        for k, val in parallel_iter(cpu_count(), solve, inputs):
            if val:
                p = val[0]
                q = val[1]
                print("{}:{}".format(p, q))
                return val
        return "Fail"
Beispiel #4
0
def attack(n, e, c, bitsize, msb_known, msb, lsb_known, lsb, m_start=1):
    """
    Recovers the plaintext from the ciphertext if some bits of the plaintext are known, using Coppersmith's method.
    :param n: the modulus
    :param e: the public exponent (should be "small": 3, 5, or 7 work best)
    :param c: the encrypted message
    :param bitsize: the amount of bits of the plaintext
    :param msb_known: the amount of known most significant bits of the plaintext
    :param msb: the known most significant bits of the plaintext
    :param lsb_known: the amount of known least significant bits of the plaintext
    :param lsb: the known least significant bits of the plaintext
    :param m_start: the m value to start at for the Howgrave-Graham small roots method (default: 1)
    :return: the plaintext
    """
    x = Zmod(n)["x"].gen()
    f = (msb * 2**(bitsize - msb_known) + x * 2**lsb_known + lsb)**e - c
    bound = 2**(bitsize - msb_known - lsb_known) - 1
    m = m_start
    while True:
        t = m
        logging.debug(f"Trying m = {m}, t = {t}...")
        for root in modular_univariate(f, n, m, t, bound):
            return msb * 2**(bitsize - msb_known) + root * 2**lsb_known + lsb

        m += 1
Beispiel #5
0
def neg_fdd_div(D):
    s = 0
    for d in divisors(D):
        if is_fundamental_discriminant(-d):
            if Zmod(d)(D / d).is_square():
                s += 1
    return s
Beispiel #6
0
def compute_max_M_(M, ord_):
    for p in _prime_power_divisors(M):
        ordp = Zmod(p)(65537).multiplicative_order()
        if ord_ % ordp != 0:
            M //= p

    return M
Beispiel #7
0
def CMorbits(D):
    s = sum([
        2**(len(prime_divisors(old_div(D, d))))
        for d in divisors(D) if is_fundamental_discriminant(-d) and Zmod(d)
        (old_div(D, d)).is_square()
    ]) + 1
    return s
    def __init__(self,
                 ec,
                 P=None,
                 dmap=None,
                 order=None,
                 pairing="weil",
                 k=None,
                 seed=None):
        self.ec = ec
        self.P = P

        self.distortion = self._deco(dmap)
        if dmap == None:
            self.distortion = self._ext

        if order == None:
            self.order = P.order()
        else:
            self.order = order

        self.pairing = pairing

        ord = self.ec.base_ring().cardinality()
        if k == None:
            k = Zmod(self.order)(ord).multiplicative_order()
        self.k = k

        random.seed(seed)
        self.t = random.randint(2, self.order - 1)

        base = FiniteField(ord**self.k, 'b')
        self.hom = Hom(self.ec.base_ring(),
                       base)(base.gen()**((ord**self.k - 1) / (ord - 1)))
        self.ec2 = EllipticCurve(map(int,
                                     self.ec.a_invariants())).change_ring(base)
Beispiel #9
0
 def decrypt(c, d, n):
     n = int(n)
     size = n.bit_length() // 2
     c_high, c_low = c
     b = (c_low**2 - c_high**3) % n
     EC = EllipticCurve(Zmod(n), [0, b])
     m_high, m_low = (EC((c_high, c_low)) * d).xy()
     m_high, m_low = int(m_high), int(m_low)
     return (m_high << size) | m_low
Beispiel #10
0
def compare_formulas_2a(D, k):
    d1 = dimension_new_cusp_forms(kronecker_character(D), k)
    if D < 0:
        D = -D
    d2 = RR(1 / pi * sqrt(D) * sum([
        log(d) * sigma(D / d, 0) for d in divisors(D)
        if Zmod(d)(D / d).is_square() and is_fundamental_discriminant(-d)
    ]))
    return d1 - d2
def _polynomial_gcd_crt(a, b, modulus):
    gs = []
    ps = []
    for p, _ in factor(modulus):
        zmodp = Zmod(p)
        gs.append(_polynomial_gcd(a.change_ring(zmodp), b.change_ring(zmodp)).change_ring(ZZ))
        ps.append(p)

    return gs[0] if len(gs) == 1 else crt(gs, ps)
Beispiel #12
0
def factorize(n, D):
    """
    Recovers the prime factors from a modulus using Cheng's elliptic curve complex multiplication method.
    More information: Sedlacek V. et al., "I want to break square-free: The 4p - 1 factorization method and its RSA backdoor viability"
    :param n: the modulus
    :param D: the discriminant to use to generate the Hilbert polynomial
    :return: a tuple containing the prime factors
    """
    assert D % 8 == 3, "D should be square-free"

    zmodn = Zmod(n)
    pr = zmodn["x"]

    H = pr(hilbert_class_polynomial(-D))
    Q = pr.quotient(H)
    j = Q.gen()

    try:
        k = j * _polynomial_inverse((1728 - j).lift(), H)
    except ArithmeticError as err:
        # If some polynomial was not invertible during XGCD calculation, we can factor n.
        p = gcd(int(err.args[1].lc()), n)
        return int(p), int(n // p)

    E = EllipticCurve(Q, [3 * k, 2 * k])
    while True:
        x = zmodn.random_element()

        logging.debug(f"Calculating division polynomial of Q{x}...")
        z = E.division_polynomial(n, x=Q(x))

        try:
            d, _, _ = _polynomial_xgcd(z.lift(), H)
        except ArithmeticError as err:
            # If some polynomial was not invertible during XGCD calculation, we can factor n.
            p = gcd(int(err.args[1].lc()), n)
            return int(p), int(n // p)

        p = gcd(int(d), n)
        if 1 < p < n:
            return int(p), int(n // p)
Beispiel #13
0
def search_global_symbols(n, D):
    rank = 2 + n
    sign = 2 - n
    csymbols = list()  # a list of canonical symbols to avoid duplicates
    D = (-1)**n * D
    symbols = all_symbols(sign, rank, D)
    global_symbols = []
    for sym in symbols:
        #print sym
        for p in sym.keys():
            prank = sum([s[1] for s in sym[p]])
            v = sum([s[0] * s[1] for s in sym[p]])
            Dp = D // (p**v)
            if prank != rank:
                eps = (Dp * Integer(prod([s[2] for s in sym[p]]))).kronecker(p)
                if p == 2:
                    if eps == -1:
                        eps = 3
                    sym[p].insert(0, [0, rank - prank, eps, 0, 0])
                else:
                    if eps == -1:
                        for x in Zmod(p):
                            if not x.is_square():
                                eps = x
                                break
                    sym[p].insert(0, [0, rank - prank, eps])
        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()
        ]
        symbol._signature = (2, n)
        #print symbol._local_symbols
        isglob = is_GlobalGenus(symbol)
        if isglob:
            #print "GLOBAL SYMBOL:"
            #print symbol._local_symbols
            #return symbol
            #for s in symbol._local_symbols:
            #    s = s.canonical_symbol()
            append = True
            for j, s in enumerate(symbol._local_symbols):
                if s._prime == 2:
                    sc = deepcopy(symbol)
                    sc._local_symbols[j] = sc._local_symbols[
                        j].canonical_symbol()
                    if csymbols.count(sc) > 0:
                        append = False
                    else:
                        csymbols.append(sc)
                    break
            if append:
                global_symbols.append(symbol)
    return global_symbols
def _recover_modulus_and_multiplier(polynomials, modulus_bitsize, modulus=None, multiplier=None):
    for combination in combinations(polynomials, 3):
        P0 = combination[0]
        P1 = combination[1]
        P2 = combination[2]
        possible_modulus = gcd(P0.resultant(P1), P1.resultant(P2), P0.resultant(P2))
        if (modulus is None and possible_modulus.bit_length() == modulus_bitsize) or possible_modulus == modulus:
            if multiplier is None:
                g = _polynomial_gcd_crt(P0, _polynomial_gcd_crt(P1, P2, possible_modulus), possible_modulus)
                for possible_multiplier in g.change_ring(Zmod(possible_modulus)).roots(multiplicities=False):
                    yield int(possible_modulus), int(possible_multiplier)
            else:
                yield int(possible_modulus), multiplier
Beispiel #15
0
def attack(n, e, c1, c2, f1, f2):
    """
    Recovers the shared secret from two plaintext messages encrypted with the same modulus.
    :param n: the modulus
    :param e: the public exponent
    :param c1: the ciphertext of the first encryption
    :param c2: the ciphertext of the second encryption
    :param f1: the function encoding the shared secret into the first plaintext
    :param f2: the function encoding the shared secret into the second plaintext
    :return: the shared secret
    """
    x = Zmod(n)["x"].gen()
    g1 = f1(x)**e - c1
    g2 = f2(x)**e - c2
    g = -_polynomial_gcd(g1, g2).monic()
    return g[0]
Beispiel #16
0
def _greedy_find_M_(n, M):
    ord = Zmod(M)(65537).multiplicative_order()
    while True:
        best_r = 0
        best_ord_ = ord
        best_M_ = M
        for p in _prime_power_divisors(ord):
            ord_ = ord // p
            M_ = compute_max_M_(M, ord_)
            r = (log2(ord) - log2(ord_)) / (log2(M) - log2(M_))
            if r > best_r:
                best_r = r
                best_ord_ = ord_
                best_M_ = M_

        if log2(best_M_) < log2(n) / 4:
            return M

        ord = best_ord_
        M = best_M_
Beispiel #17
0
def attack(n, e, bitsize, lsb_known=0, lsb=0, delta=0.25, m_start=1):
    """
    Recovers the prime factors if the private exponent is too small.
    More information: Boneh D., Durfee G., "Cryptanalysis of RSA with Private Key d Less than N^0.292"
    This implementation exploits knowledge of least significant bits of prime factors, if available.
    :param n: the modulus
    :param e: the public exponent
    :param bitsize: the amount of bits of the prime factors
    :param lsb_known: the amount of known least significant bits of one of the prime factors
    :param lsb: the known least significant bits of one of the prime factors
    :param delta: a predicted bound on the private exponent (d < n^delta) (default: 0.25)
    :param m_start: the m value to start at for the Herrmann-May small roots method (default: 1)
    :return: a tuple containing the prime factors
    """
    x, y = Zmod(e)["x, y"].gens()

    # Use additional information about factors to speed up Boneh-Durfee
    p_lsb = lsb
    q_lsb = (pow(lsb, -1, 2**lsb_known) * (n % 2**lsb_known)) % (2**lsb_known)
    a = ((n >> lsb_known) + pow(2, -lsb_known, e) *
         (p_lsb * q_lsb - p_lsb - q_lsb + 1))
    f = x * (a + y) + pow(2, -lsb_known, e)

    xbound = int(e**RealNumber(delta))
    ybound = int(2**(bitsize - lsb_known + 1))
    m = m_start
    while True:
        t = int(m * (1 - 2 * delta))
        logging.debug(f"Trying m = {m}, t = {t}...")
        for xroot, yroot in modular_bivariate(f, e, m, t, xbound, ybound):
            z = xroot * (a + yroot) + pow(2, -lsb_known, e)
            if z % e == 0:
                s = (n + 1 + pow(xroot, -1, e)) % e
                p = ZZ["p"].gen()
                f = p**2 - s * p + n
                for proot, _ in f.roots():
                    proot = int(proot)
                    if n % proot == 0:
                        return proot, n // proot

        m += 1
Beispiel #18
0
def solve(M, n, a, m):
    # I need to import it in the function otherwise multiprocessing doesn't find it in its context
    from sage_functions import coppersmith_howgrave_univariate

    base = int(65537)
    # the known part of p: 65537^a * M^-1 (mod N)
    known = int(pow(base, a, M) * inverse_mod(M, n))
    # Create the polynom f(x)
    F = PolynomialRing(Zmod(n), implementation="NTL", names=("x",))
    (x,) = F._first_ngens(1)
    pol = x + known
    beta = 0.1
    t = m + 1
    # Upper bound for the small root x0
    XX = floor(2 * n ** 0.5 / M)
    # Find a small root (x0 = k) using Coppersmith's algorithm
    roots = coppersmith_howgrave_univariate(pol, n, beta, m, t, XX)
    # There will be no roots for an incorrect guess of a.
    for k in roots:
        # reconstruct p from the recovered k
        p = int(k * M + pow(base, a, M))
        if n % p == 0:
            return p, n // p
def attack(n, e, bitsize, lsb_known, lsb, m_start=1):
    """
    Recovers the prime factors of a modulus and the private exponent using Coppersmith's method if part of the private exponent is known.
    More information: Boneh D., Durfee G., Frankel Y., "An Attack on RSA Given a Small Fraction of the Private Key Bits"
    :param n: the modulus
    :param e: the public exponent (should be "small": 3, 5, or 7 work best)
    :param bitsize: the amount of bits of the prime factors
    :param lsb_known: the amount of known least significant bits of the private exponent
    :param lsb: the known least significant bits of the private exponent
    :param m_start: the m value to start at for the Howgrave-Graham small roots method (default: 1)
    :return: a tuple containing the prime factors of the modulus and the private exponent
    """
    logging.debug("Generating solutions for k candidates...")
    x = var("x")
    solutions = []
    for k in range(1, e + 1):
        solutions += solve_mod(
            k * x**2 + (e * lsb - k * (n + 1) - 1) * x + k * n == 0,
            2**lsb_known)

    x = Zmod(n)["x"].gen()
    bound = 2**(bitsize - lsb_known) - 1
    m = m_start
    while True:
        t = m
        logging.debug(f"Trying m = {m}, t = {t}...")
        for s in solutions:
            p_lsb = int(s[0])
            f = x * 2**lsb_known + p_lsb
            for root in modular_univariate(f, n, m, t, bound):
                p = root * 2**lsb_known + p_lsb
                if p != 0 and n % p == 0:
                    q = n // p
                    return p, q, pow(e, -1, (p - 1) * (q - 1))

        m += 1
Beispiel #20
0
def is_global(M, r, s, return_symbol=False):
    r"""
    Test if the FiniteQuadraticModule M can be represented by a Z-lattice
    of signature ``(r,s)``.

    INPUT:

        -``M`` -- FiniteQuadraticModule
        - ``r`` -- positive integer
        - ``s`` -- positive integer
        
    OUTPUT:
        - boolean
    """

    J = M.jordan_decomposition()
    symbols = {}
    n = r + s
    sig = r - s
    for A in J:
        p = A[1][0]
        if p not in symbols:
            symbols[p] = list()
        sym = list(A[1][1:len(A[1])])
        if p == 2:
            if len(A[1]) == 4:
                sym.append(0)
                sym.append(0)
            else:
                if sym[3].kronecker(2) == sym[2]:
                    det = sym[3] % 8
                else:
                    if sym[2] == -1:
                        det = 3
                    else:
                        det = 1
                sym = [sym[0], sym[1], det, 1, sym[3] % 8]
                #print sym
                #if sym[1]==1:
                #    if  sym[2].kronecker(2)==sym[4].kronecker(2):
                #        sym[2]=sym[4]
                #    else:
                #        return False
        #print p, sym
        symbols[p].append(sym)
    D = M.order() * (-1)**s
    for p in symbols.keys():
        prank = sum([sym[1] for sym in symbols[p]])
        v = sum([sym[0] * sym[1] for sym in symbols[p]])
        Dp = D // (p**v)
        if prank != n:
            eps = (Dp * Integer(prod([sym[2]
                                      for sym in symbols[p]]))).kronecker(p)
            if p == 2:
                if eps == -1:
                    eps = 3
                symbols[p].append([0, n - prank, eps, 0, 0])
            else:
                if eps == -1:
                    for x in Zmod(p):
                        if not x.is_square():
                            eps = x
                            break
                symbols[p].append([0, n - prank, eps])
    symbol = GenusSymbol_global_ring(MatrixSpace(ZZ, r + s, r + s).one())
    symbol._local_symbols = [
        Genus_Symbol_p_adic_ring(p, syms) for p, syms in symbols.items()
    ]
    symbol._signature = (r, s)
    #print r,s, symbol._local_symbols
    isglob = is_GlobalGenus(symbol)
    if return_symbol:
        return symbol, isglob
    else:
        return isglob
Beispiel #21
0
def compare_formulas_2(D, k):
    d1 = RR(abs(D)) / RR(6)
    if D < 0:
        D = -D
    s1 = RR(
        sqrt(abs(D)) * sum([
            log(d) for d in divisors(D)
            if is_fundamental_discriminant(-d) and kronecker(-d, D / d) == 1
        ]))
    d2 = RR((2 / (sqrt(3) * pi)) * s1)
    return d1 - d2, d2, RR(2 * sqrt(D) * log(D) / pi)


A3 = lambda N: sum(
    [kronecker(-N, x) for x in Zmod(N) if x**2 + x + Zmod(N)(1) == 0])


def compare_formulas_2a(D, k):
    d1 = dimension_new_cusp_forms(kronecker_character(D), k)
    if D < 0:
        D = -D
    d2 = RR(1 / pi * sqrt(D) * sum([
        log(d) * sigma(D / d, 0) for d in divisors(D)
        if Zmod(d)(D / d).is_square() and is_fundamental_discriminant(-d)
    ]))
    return d1 - d2


def compare_formulas_3(D, k):
    d1 = dimension_cusp_forms(kronecker_character(D), k)
Beispiel #22
0
from sage.all import EllipticCurve, GF, Zmod, ZZ
import socketserver
import os
import signal
from Crypto.Util.number import bytes_to_long
from hashlib import sha256

# Dual_EC_Drbg parameters taken from:
# https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-90a.pdf
# Section A.1.1
EC = EllipticCurve(
    GF(0xffffffff00000001000000000000000000000000ffffffffffffffffffffffff),
    [-3, 0x5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b])
n = 0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551
assert EC.cardinality() == n
Zn = Zmod(n)
G = EC((0x6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296,
        0x4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5))
P = G
Q = EC((0xc97445f45cdef9f0d3e05e1e585fc297235b82b5be8ff3efca67c59852018192,
        0xb28ef557ba31dfcbdd21ac46e2a91e3c304f44cb87058ada2cb815151e610046))


class DualEcDrbg(object):
    """
    Dual Elliptic Curve Deterministic Random Bit Generator
    """
    def __init__(self, seed):
        self.s = ZZ(bytes_to_long(seed))

    def next_bits(self):
Beispiel #23
0
def search_global_symbols(n, D):
    rank = 2 + n
    sign = 2 - n
    csymbols = list()  # a list of canonical symbols to avoid duplicates
    symbols = list()
    #print D
    D = (-1)**n * D
    fac = Integer(D).factor()
    symbols = list()
    for p, v in fac:
        psymbols = list()
        parts = partitions(v)
        Dp = D // (p**v)
        for vs in parts:
            #print "partition:", vs
            l = list()  # list of p-symbols corresponding to the partition vs
            if len(vs) <= rank:
                exponents = Set(list(vs))
                # now we set up a list ll for each vv in the partition vs
                # that contains an entry for each possibility
                # and then update l with ll (see below)
                if p == 2:
                    for vv in exponents:
                        mult = vs.count(vv)
                        ll = list()
                        for t in [0, 1]:  # even(0) or odd(1) type
                            for det in [1, 3, 5,
                                        7]:  # the possible determinants
                                if mult % 2 == 0 and t == 0:
                                    ll.append([vv, mult, det, 0, 0])
                                if mult == 1:
                                    odds = [det]
                                elif mult == 2:
                                    if det in [1, 7]:
                                        odds = [0, 2, 6]
                                    else:
                                        odds = [2, 4, 6]
                                else:
                                    odds = [
                                        o for o in range(8)
                                        if o % 2 == mult % 2
                                    ]
                                for oddity in odds:
                                    if t == 1:
                                        ll.append([vv, mult, det, 1, oddity])
                                    #else:
                                    #ll.append([vv,1,det,0,0])
                                    #if mult % 2 == 0 and mult>2:
                                    #    for x in range(1,Integer(mult)/Integer(2)):
                                    #        if mult-2*x==2 and det in [1,7] and oddity not in [0,2,6]:
                                    #            continue
                                    #        elif mult-2*x==2 and det in [3,5] and oddity not in [2,4,6]:
                                    #            continue
                                    #        ll.append([[vv,2*x,det,0,0],[vv,mult-2*x,det,1,oddity]])
                        #print "ll:\n",ll
                        if len(l) == 0:
                            for t in ll:
                                if type(t[0]) == list:
                                    l.append({p: t})
                                else:
                                    l.append({p: [t]})
                        else:
                            newl = list()
                            for t in ll:
                                for sym in l:
                                    newsym = deepcopy(sym)
                                    #print newsym
                                    if type(t[0]) == list:
                                        newsym[p] = newsym[p] + t
                                    else:
                                        newsym[p].append(t)
                                    #print newsym
                                    newl.append(newsym)
                                    #print l
                            l = newl
                        #print "l:\n",l
                else:
                    for vv in exponents:
                        ll = [[vv, vs.count(vv), 1], [vv, vs.count(vv), -1]]
                        if len(l) == 0:
                            for t in ll:
                                l.append({p: [t]})
                        else:
                            newl = list()
                            for t in ll:
                                for sym in l:
                                    sym[p].append(t)
                                    newl.append(sym)
                            l = newl
                #print "l=\n",l
                #print "psymbols=\n",psymbols
                #print psymbols+l
                psymbols = psymbols + l
        if len(symbols) == 0:
            symbols = psymbols
        else:
            symbols_new = list()
            for sym in symbols:
                for psym in psymbols:
                    newsym = deepcopy(sym)
                    newsym.update(psym)
                    symbols_new.append(newsym)
            symbols = symbols_new
    global_symbols = []
    for sym in symbols:
        #print sym
        for p in sym.keys():
            prank = sum([s[1] for s in sym[p]])
            v = sum([s[0] * s[1] for s in sym[p]])
            Dp = D // (p**v)
            if prank != rank:
                eps = (Dp * Integer(prod([s[2] for s in sym[p]]))).kronecker(p)
                if p == 2:
                    if eps == -1:
                        eps = 3
                    sym[p].insert(0, [0, rank - prank, eps, 0, 0])
                else:
                    if eps == -1:
                        for x in Zmod(p):
                            if not x.is_square():
                                eps = x
                                break
                    sym[p].insert(0, [0, rank - prank, eps])
        symbol = GenusSymbol_global_ring(MatrixSpace(ZZ, rank, rank).one())
        symbol._local_symbols = [
            Genus_Symbol_p_adic_ring(p, syms) for p, syms in sym.items()
        ]
        symbol._signature = (2, n)
        #print symbol._local_symbols
        isglob = is_GlobalGenus(symbol)
        if isglob:
            #print "GLOBAL SYMBOL:"
            #print symbol._local_symbols
            #return symbol
            #for s in symbol._local_symbols:
            #    s = s.canonical_symbol()
            append = True
            for j, s in enumerate(symbol._local_symbols):
                if s._prime == 2:
                    sc = deepcopy(symbol)
                    sc._local_symbols[j] = sc._local_symbols[
                        j].canonical_symbol()
                    if csymbols.count(sc) > 0:
                        append = False
                    else:
                        csymbols.append(sc)
                    break
            if append:
                global_symbols.append(symbol)
    return global_symbols