Esempio n. 1
0
def id_dirichlet(fun, N, n):
    N = Integer(N)
    if N == 1:
        return (1, 1)
    p2 = valuation(N, 2)
    N2 = 2**p2
    Nodd = N // N2
    Nfact = list(factor(Nodd))
    #print "n = "+str(n)
    #for j in range(20):
    #    print "chi(%d) = e(%d/%d)"%(j+2, fun(j+2,n), n)
    plist = [z[0] for z in Nfact]
    ppows = [z[0]**z[1] for z in Nfact]
    ppows2 = list(ppows)
    idems = [1 for z in Nfact]
    proots = [primitive_root(z) for z in ppows]
    # Get CRT idempotents
    if p2 > 0:
        ppows2.append(N2)
    for j in range(len(plist)):
        exps = [1 for z in idems]
        if p2 > 0:
            exps.append(1)
        exps[j] = proots[j]
        idems[j] = crt(exps, ppows2)
    idemvals = [fun(z, n) for z in idems]
    # now normalize to right root of unity base
    idemvals = [
        idemvals[j] * euler_phi(ppows[j]) / n for j in range(len(idemvals))
    ]
    ans = [
        Integer(mod(proots[j], ppows[j])**idemvals[j])
        for j in range(len(proots))
    ]
    ans = crt(ans, ppows)
    # There are cases depending on 2-part of N
    if p2 == 0:
        return (N, ans)
    if p2 == 1:
        return (N, crt([1, ans], [2, Nodd]))
    if p2 == 2:
        my3 = crt([3, 1], [N2, Nodd])
        if fun(my3, n) == 0:
            return (N, crt([1, ans], [4, Nodd]))
        else:
            return (N, crt([3, ans], [4, Nodd]))
    # Final case 2^3 | N

    my5 = crt([5, 1], [N2, Nodd])
    test1 = fun(my5, n) * N2 / 4 / n
    test1 = Integer(mod(5, N2)**test1)
    minusone = crt([-1, 1], [N2, Nodd])
    test2 = (fun(minusone, n) * N2 / 4 / n) % (N2 / 4)
    if test2 > 0:
        test1 = Integer(mod(-test1, N2))
    return (N, crt([test1, ans], [N2, Nodd]))
Esempio n. 2
0
def id_dirichlet(fun, N, n):
    N = Integer(N)
    if N == 1:
        return (1, 1)
    p2 = valuation(N, 2)
    N2 = 2 ** p2
    Nodd = N / N2
    Nfact = list(factor(Nodd))
    # print "n = "+str(n)
    # for j in range(20):
    #    print "chi(%d) = e(%d/%d)"%(j+2, fun(j+2,n), n)
    plist = [z[0] for z in Nfact]
    ppows = [z[0] ** z[1] for z in Nfact]
    ppows2 = list(ppows)
    idems = [1 for z in Nfact]
    proots = [primitive_root(z) for z in ppows]
    # Get CRT idempotents
    if p2 > 0:
        ppows2.append(N2)
    for j in range(len(plist)):
        exps = [1 for z in idems]
        if p2 > 0:
            exps.append(1)
        exps[j] = proots[j]
        idems[j] = crt(exps, ppows2)
    idemvals = [fun(z, n) for z in idems]
    # now normalize to right root of unity base
    idemvals = [idemvals[j] * euler_phi(ppows[j]) / n for j in range(len(idemvals))]
    ans = [Integer(mod(proots[j], ppows[j]) ** idemvals[j]) for j in range(len(proots))]
    ans = crt(ans, ppows)
    # There are cases depending on 2-part of N
    if p2 == 0:
        return (N, ans)
    if p2 == 1:
        return (N, crt([1, ans], [2, Nodd]))
    if p2 == 2:
        my3 = crt([3, 1], [N2, Nodd])
        if fun(my3, n) == 0:
            return (N, crt([1, ans], [4, Nodd]))
        else:
            return (N, crt([3, ans], [4, Nodd]))
    # Final case 2^3 | N

    my5 = crt([5, 1], [N2, Nodd])
    test1 = fun(my5, n) * N2 / 4 / n
    test1 = Integer(mod(5, N2) ** test1)
    minusone = crt([-1, 1], [N2, Nodd])
    test2 = (fun(minusone, n) * N2 / 4 / n) % (N2 / 4)
    if test2 > 0:
        test1 = Integer(mod(-test1, N2))
    return (N, crt([test1, ans], [N2, Nodd]))
def _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)
def _backtrack(s, bases, residues, moduli, i):
    if i == len(s):
        combined_modulus = 1
        for modulus in moduli:
            combined_modulus *= modulus

        return crt(residues, moduli), combined_modulus

    moduli.append(4 * bases[i])
    for residue in s[i]:
        residues.append(residue)
        try:
            crt(residues, moduli)
            ans = _backtrack(s, bases, residues, moduli, i + 1)
            if ans:
                return ans
        except ValueError:
            pass
        residues.pop()

    moduli.pop()
    return None, None
Esempio n. 5
0
def pohlighellman(g, h):
    phi = g.multiplicative_order()
    factors = factor(phi)
    chinese_pairs = []
    for pi, ei in factors:
        n = phi / (pi**ei)
        print("testing n = %s" % n)
        hn = h**n
        print(("Searching h^%d in subgroup "
               "g^%d using Baby-step giant-step") % (n, n))
        a = babystepgiantstep(g**n, hn)
        print("Found g^(%s * %s) == %s" % (n, a, hn))
        chinese_pairs.append([a, pi**ei])

    return crt(*map(list, zip(*chinese_pairs)))
Esempio n. 6
0
def attack(base, multiplication_result):
    """
    Solves the discrete logarithm problem using the MOV attack.
    :param base: the base point
    :param multiplication_result: the point multiplication result
    :return: l such that l * base == multiplication_result
    """
    curve = base.curve()
    p = curve.base_ring().order()
    n = base.order()

    assert gcd(
        n, p
    ) == 1, "GCD of curve base ring order and generator order should be 1."

    logging.debug("Calculating embedding degree...")

    # Embedding degree k.
    k = 1
    while (p**k - 1) % n != 0:
        k += 1

    logging.debug(
        f"Found embedding degree {k}, computing discrete logarithm...")

    pairing_curve = curve.base_extend(GF(p**k))
    pairing_base = pairing_curve(base)
    pairing_multiplication_result = pairing_curve(multiplication_result)

    ls = []
    ds = []
    while lcm(*ds) != n:
        rand = pairing_curve.random_point()
        o = rand.order()
        d = gcd(o, n)
        rand = (o // d) * rand
        assert rand.order() == d

        u = pairing_base.weil_pairing(rand, n)
        v = pairing_multiplication_result.weil_pairing(rand, n)
        logging.debug(f"Calculating ({v}).log({u}) modulo {d}")
        l = v.log(u)
        logging.debug(f"Found discrete log {l} modulo {d}")
        ls.append(int(l))
        ds.append(int(d))

    return ls[0] if len(ls) == 1 else int(crt(ls, ds))
def pohlighellman(g, h):
    phi = g.multiplicative_order()
    factors = factor(phi)
    chinese_pairs = []
    for pi, ei in factors:
        n = phi / (pi ** ei)
        print("testing n = %s" % n)
        hn = h ** n
        print("h^%s = %s" % (n, hn))
        for i in range(pi ** ei):
            print("Testing g^(%s * %s) == %s" % (i, n, hn))
            if g ** (n * i) == hn:
                print("Found x mod %s = %s" % (pi ** ei, i))
                chinese_pairs.append([i, pi ** ei])
                break

    return crt(*map(list, zip(*chinese_pairs)))
    x = X[i]
    b = B[i]
    z = log(Integer(x), b)
    Z[i] = int(z)
d = {"X": X, "B": B, "Z": Z}
save_pickle(d, FOLDER, "ilog.pkl")

set_seed(SEED + 108)
N = [random.randint(2, 6) for _ in range(40)]
X = [[random.randint(0, 1000) for _ in range(N[i])] for i in range(20)] + [[random.randint(0, 1_000_000) for _ in range(N[20 + i])] for i in range(20)]  # Remainder
Y = [[random.randint(10, 1000) for _ in range(N[i])] for i in range(20)] + [[random.randint(1000, 1_000_000) for _ in range(N[20 + i])] for i in range(20)]  # Modulus
Z = [0,]*len(X)  # The solution
for i in range(len(X)):
    X[i] = [X[i][j] % Y[i][j] for j in range(len(X[i]))]  # Ensure a is within [0, m)
    try:
        z = crt(X[i], Y[i])
        Z[i] = int(z)
    except:
        Z[i] = None
d = {"X": X, "Y": Y, "Z": Z}
save_pickle(d, FOLDER, "crt.pkl")


###############################################################################
# Number theory functions
###############################################################################

set_seed(SEED + 201)
X = [random.randint(1, 1_000_000_000) for _ in range(20)]
Z = [0,]*len(X)
for i in range(len(X)):
Esempio n. 9
0
def make_luts(field, sub_folder, seed, sparse=False):
    global FIELD, RING
    print(f"Making LUTs for {field}")

    ###############################################################################
    # Finite field arithmetic
    ###############################################################################
    folder = os.path.join(PATH, "fields", "data", sub_folder)
    if os.path.exists(folder):
        shutil.rmtree(folder)
    os.mkdir(folder)

    FIELD = field
    RING = PolynomialRing(field, names="x")
    characteristic = int(field.characteristic())
    order = int(field.order())
    dtype = np.int64 if order <= np.iinfo(np.int64).max else object
    alpha = field.primitive_element()
    # assert field.gen() == field.multiplicative_generator()

    d = {
        "characteristic": int(field.characteristic()),
        "degree": int(field.degree()),
        "order": int(field.order()),
        "primitive_element": I(field.primitive_element()),
        "irreducible_poly": [int(c) for c in field.modulus().list()[::-1]]
    }
    save_json(d, folder, "properties.json", indent=True)

    set_seed(seed + 1)
    X, Y, XX, YY, ZZ = io_2d(0, order, 0, order, sparse=sparse)
    for i in range(ZZ.shape[0]):
        for j in range(ZZ.shape[1]):
            ZZ[i, j] = I(F(XX[i, j]) + F(YY[i, j]))
    d = {"X": X, "Y": Y, "Z": ZZ}
    save_pickle(d, folder, "add.pkl")

    set_seed(seed + 2)
    X, Y, XX, YY, ZZ = io_2d(0, order, 0, order, sparse=sparse)
    for i in range(ZZ.shape[0]):
        for j in range(ZZ.shape[1]):
            ZZ[i, j] = I(F(XX[i, j]) - F(YY[i, j]))
    d = {"X": X, "Y": Y, "Z": ZZ}
    save_pickle(d, folder, "subtract.pkl")

    set_seed(seed + 3)
    X, Y, XX, YY, ZZ = io_2d(0, order, 0, order, sparse=sparse)
    for i in range(ZZ.shape[0]):
        for j in range(ZZ.shape[1]):
            ZZ[i, j] = I(F(XX[i, j]) * F(YY[i, j]))
    d = {"X": X, "Y": Y, "Z": ZZ}
    save_pickle(d, folder, "multiply.pkl")

    set_seed(seed + 4)
    X, Y, XX, YY, ZZ = io_2d(0, order, -order - 2, order + 3, sparse=sparse)
    for i in range(ZZ.shape[0]):
        for j in range(ZZ.shape[1]):
            ZZ[i, j] = I(F(XX[i, j]) * YY[i, j])
    d = {"X": X, "Y": Y, "Z": ZZ}
    save_pickle(d, folder, "scalar_multiply.pkl")

    set_seed(seed + 5)
    X, Y, XX, YY, ZZ = io_2d(0, order, 1, order, sparse=sparse)
    for i in range(ZZ.shape[0]):
        for j in range(ZZ.shape[1]):
            ZZ[i, j] = I(F(XX[i, j]) / F(YY[i, j]))
    d = {"X": X, "Y": Y, "Z": ZZ}
    save_pickle(d, folder, "divide.pkl")

    set_seed(seed + 6)
    X, Z = io_1d(0, order, sparse=sparse)
    for i in range(X.shape[0]):
        Z[i] = I(-F(X[i]))
    d = {"X": X, "Z": Z}
    save_pickle(d, folder, "additive_inverse.pkl")

    set_seed(seed + 7)
    X, Z = io_1d(1, order, sparse=sparse)
    for i in range(X.shape[0]):
        Z[i] = I(1 / F(X[i]))
    d = {"X": X, "Z": Z}
    save_pickle(d, folder, "multiplicative_inverse.pkl")

    set_seed(seed + 8)
    X, Y, XX, YY, ZZ = io_2d(1, order, -order - 2, order + 3, sparse=sparse)
    for i in range(ZZ.shape[0]):
        for j in range(ZZ.shape[1]):
            ZZ[i, j] = I(F(XX[i, j])**YY[i, j])
    d = {"X": X, "Y": Y, "Z": ZZ}
    save_pickle(d, folder, "power.pkl")

    set_seed(seed + 9)
    X, Z = io_1d(1, order, sparse=sparse)
    for i in range(Z.shape[0]):
        try:
            Z[i] = I(field.fetch_int(X[i]).log(alpha))
        except:
            Z[i] = I(log(F(X[i]), alpha))
    d = {"X": X, "Z": Z}
    save_pickle(d, folder, "log.pkl")

    set_seed(seed + 10)
    X, Z = io_1d(0, order, sparse=sparse)
    for i in range(X.shape[0]):
        Z[i] = int(F(X[i]).additive_order())
    d = {"X": X, "Z": Z}
    save_pickle(d, folder, "additive_order.pkl")

    set_seed(seed + 11)
    X, Z = io_1d(1, order, sparse=sparse)
    for i in range(X.shape[0]):
        Z[i] = int(F(X[i]).multiplicative_order())
    d = {"X": X, "Z": Z}
    save_pickle(d, folder, "multiplicative_order.pkl")

    set_seed(seed + 12)
    X, _ = io_1d(0, order, sparse=sparse)
    Z = []
    for i in range(len(X)):
        x = F(X[i])
        p = x.charpoly()
        z = poly_to_list(p)
        Z.append(z)
    d = {"X": X, "Z": Z}
    save_pickle(d, folder, "characteristic_poly_element.pkl")

    set_seed(seed + 13)
    shapes = [(2, 2), (3, 3), (4, 4), (5, 5), (6, 6)]
    X = []
    Z = []
    for i in range(len(shapes)):
        x = randint_matrix(0, order, shapes[i])
        X.append(x)
        x = matrix(FIELD, [[F(e) for e in row] for row in x])
        p = x.charpoly()
        z = poly_to_list(p)
        Z.append(z)
    d = {"X": X, "Z": Z}
    save_pickle(d, folder, "characteristic_poly_matrix.pkl")

    set_seed(seed + 14)
    X, _ = io_1d(0, order, sparse=sparse)
    Z = []
    for i in range(len(X)):
        x = F(X[i])
        p = x.minpoly()
        z = poly_to_list(p)
        Z.append(z)
    d = {"X": X, "Z": Z}
    save_pickle(d, folder, "minimal_poly_element.pkl")

    # set_seed(seed + 15)
    # shapes = [(2,2), (3,3), (4,4), (5,5), (6,6)]
    # X = []
    # Z = []
    # for i in range(len(shapes)):
    #     x = randint_matrix(0, order, shapes[i])
    #     X.append(x)
    #     x = matrix(FIELD, [[F(e) for e in row] for row in x])
    #     p = x.minpoly()
    #     z = np.array([I(e) for e in p.list()[::-1]], dtype=dtype).tolist()
    #     z = z if z != [] else [0]
    #     Z.append(z)
    # d = {"X": X, "Z": Z}
    # save_pickle(d, folder, "minimal_poly_matrix.pkl")

    set_seed(seed + 16)
    X, Z = io_1d(0, order, sparse=sparse)
    for i in range(X.shape[0]):
        z = F(X[i]).trace()
        Z[i] = int(z)
    d = {"X": X, "Z": Z}
    save_pickle(d, folder, "field_trace.pkl")

    set_seed(seed + 17)
    X, Z = io_1d(0, order, sparse=sparse)
    for i in range(X.shape[0]):
        z = F(X[i]).norm()
        Z[i] = int(z)
    d = {"X": X, "Z": Z}
    save_pickle(d, folder, "field_norm.pkl")

    ###############################################################################
    # Linear algebra
    ###############################################################################

    set_seed(seed + 201)
    X_shapes = [(2, 2), (2, 3), (3, 2), (3, 3), (3, 4)]
    Y_shapes = [(2, 2), (3, 3), (2, 4), (3, 3), (4, 5)]
    X = []
    Y = []
    Z = []
    for i in range(len(shapes)):
        x = randint_matrix(0, order, X_shapes[i])
        y = randint_matrix(0, order, Y_shapes[i])
        X.append(x)
        Y.append(y)
        x = matrix(FIELD, [[F(e) for e in row] for row in x])
        y = matrix(FIELD, [[F(e) for e in row] for row in y])
        z = x * y
        z = np.array([[I(e) for e in row] for row in z], dtype)
        Z.append(z)
    d = {"X": X, "Y": Y, "Z": Z}
    save_pickle(d, folder, "matrix_multiply.pkl")

    set_seed(seed + 202)
    shapes = [(2, 2), (2, 3), (3, 2), (3, 3), (3, 4)]
    X = []
    Z = []
    for i in range(len(shapes)):
        x = randint_matrix(0, order, shapes[i])
        X.append(x)
        x = matrix(FIELD, [[F(e) for e in row] for row in x])
        z = x.rref()
        z = np.array([[I(e) for e in row] for row in z], dtype)
        Z.append(z)
    d = {"X": X, "Z": Z}
    save_pickle(d, folder, "row_reduce.pkl")

    set_seed(seed + 203)
    shapes = [(2, 2), (2, 3), (3, 2), (3, 3), (3, 4), (4, 3), (4, 4), (4, 5),
              (5, 4), (5, 5), (5, 6), (6, 5), (6, 6)]
    X = []
    L = []
    U = []
    for i in range(len(shapes)):
        while True:
            # Ensure X has a PLU decomposition with P = I, which means it has an LU decomposition
            x = randint_matrix(0, order, shapes[i])
            x_orig = x.copy()
            x = matrix(FIELD, [[F(e) for e in row] for row in x])
            p, l, u = x.LU()
            if p == matrix.identity(FIELD, shapes[i][0]):
                break
        X.append(x_orig)
        l = np.array([[I(e) for e in row] for row in l], dtype)
        u = np.array([[I(e) for e in row] for row in u], dtype)
        L.append(l)
        U.append(u)
    d = {"X": X, "L": L, "U": U}
    save_pickle(d, folder, "lu_decompose.pkl")

    set_seed(seed + 204)
    shapes = [(2, 2), (2, 3), (3, 2), (3, 3), (3, 4), (4, 3), (4, 4), (4, 5),
              (5, 4), (5, 5), (5, 6), (6, 5), (6, 6)]
    X = []
    L = []
    U = []
    P = []
    for i in range(len(shapes)):
        x = randint_matrix(0, order, shapes[i])
        X.append(x)
        x = matrix(FIELD, [[F(e) for e in row] for row in x])
        p, l, u = x.LU()
        p = np.array([[I(e) for e in row] for row in p], dtype)
        l = np.array([[I(e) for e in row] for row in l], dtype)
        u = np.array([[I(e) for e in row] for row in u], dtype)
        P.append(p)
        L.append(l)
        U.append(u)
    d = {"X": X, "P": P, "L": L, "U": U}
    save_pickle(d, folder, "plu_decompose.pkl")

    set_seed(seed + 205)
    shapes = [(2, 2), (3, 3), (4, 4), (5, 5), (6, 6)]
    X = []
    Z = []
    for i in range(len(shapes)):
        while True:
            x = randint_matrix(0, order, shapes[i])
            x_orig = x.copy()
            x = matrix(FIELD, [[F(e) for e in row] for row in x])
            if x.rank() == shapes[i][0]:
                break
        X.append(x_orig)
        z = x.inverse()
        z = np.array([[I(e) for e in row] for row in z], dtype)
        Z.append(z)
    d = {"X": X, "Z": Z}
    save_pickle(d, folder, "matrix_inverse.pkl")

    set_seed(seed + 206)
    shapes = [(2, 2), (2, 2), (2, 2), (3, 3), (3, 3), (3, 3), (4, 4), (4, 4),
              (4, 4), (5, 5), (5, 5), (5, 5), (6, 6), (6, 6), (6, 6)]
    X = []
    Z = []
    for i in range(len(shapes)):
        x = randint_matrix(0, order, shapes[i])
        X.append(x)
        x = matrix(FIELD, [[F(e) for e in row] for row in x])
        z = I(x.determinant())
        Z.append(z)
    d = {"X": X, "Z": Z}
    save_pickle(d, folder, "matrix_determinant.pkl")

    set_seed(seed + 207)
    shapes = [(2, 2), (2, 2), (2, 2), (3, 3), (3, 3), (3, 3), (4, 4), (4, 4),
              (4, 4), (5, 5), (5, 5), (5, 5), (6, 6), (6, 6), (6, 6)]
    X = []
    Y = []
    Z = []
    for i in range(len(shapes)):
        while True:
            x = randint_matrix(0, order, shapes[i])
            x_orig = x.copy()
            x = matrix(FIELD, [[F(e) for e in row] for row in x])
            if x.rank() == shapes[i][0]:
                break
        X.append(x_orig)
        y = randint_matrix(0, order, shapes[i][1])  # 1-D vector
        Y.append(y)
        y = vector(FIELD, [F(e) for e in y])
        z = x.solve_right(y)
        z = np.array([I(e) for e in z], dtype)
        Z.append(z)
    d = {"X": X, "Y": Y, "Z": Z}
    save_pickle(d, folder, "matrix_solve.pkl")

    set_seed(seed + 208)
    shapes = [(2, 2), (2, 3), (2, 4), (3, 2), (4, 2), (3, 3)]
    X = []
    Z = []
    for i in range(len(shapes)):
        deg = shapes[i][1]  # The degree of the vector space

        # Random matrix
        x = randint_matrix(0, order, shapes[i])
        X.append(x)
        x = matrix(FIELD, [[F(e) for e in row] for row in x])
        z = x.row_space()
        if z.dimension() == 0:
            z = randint_matrix(0, 1, (0, deg))
        else:
            z = z.basis_matrix()
            z = np.array([[I(e) for e in row] for row in z], dtype)
        Z.append(z)

        # Reduce the row space by 1 by copying the 0th row to the jth row
        for j in range(1, shapes[i][0]):
            x = copy(x)
            x[j, :] = F(random.randint(0, order - 1)) * x[0, :]

            z = x.row_space()
            if z.dimension() == 0:
                z = randint_matrix(0, 1, (0, deg))
            else:
                z = z.basis_matrix()
                z = np.array([[I(e) for e in row] for row in z], dtype)
            X.append(np.array([[I(e) for e in row] for row in x], dtype))
            Z.append(z)

        # Zero matrix
        x = copy(x)
        x[:] = F(0)
        z = x.row_space()
        if z.dimension() == 0:
            z = randint_matrix(0, 1, (0, deg))
        else:
            z = z.basis_matrix()
            z = np.array([[I(e) for e in row] for row in z], dtype)
        X.append(np.array([[I(e) for e in row] for row in x], dtype))
        Z.append(z)

    d = {"X": X, "Z": Z}
    save_pickle(d, folder, "row_space.pkl")

    set_seed(seed + 209)
    shapes = [(2, 2), (2, 3), (2, 4), (3, 2), (4, 2), (3, 3)]
    X = []
    Z = []
    for i in range(len(shapes)):
        deg = shapes[i][0]  # The degree of the vector space

        # Random matrix
        x = randint_matrix(0, order, shapes[i])
        X.append(x)
        x = matrix(FIELD, [[F(e) for e in row] for row in x])
        z = x.column_space()
        if z.dimension() == 0:
            z = randint_matrix(0, 1, (0, deg))
        else:
            z = z.basis_matrix()
            z = np.array([[I(e) for e in row] for row in z], dtype)
        Z.append(z)

        # Reduce the column space by 1 by copying the 0th column to the jth column
        for j in range(1, shapes[i][1]):
            x = copy(x)
            x[:, j] = F(random.randint(0, order - 1)) * x[:, 0]

            z = x.column_space()
            if z.dimension() == 0:
                z = randint_matrix(0, 1, (0, deg))
            else:
                z = z.basis_matrix()
                z = np.array([[I(e) for e in row] for row in z], dtype)
            X.append(np.array([[I(e) for e in row] for row in x], dtype))
            Z.append(z)

        # Zero matrix
        x = copy(x)
        x[:] = F(0)
        z = x.column_space()
        if z.dimension() == 0:
            z = randint_matrix(0, 1, (0, deg))
        else:
            z = z.basis_matrix()
            z = np.array([[I(e) for e in row] for row in z], dtype)
        X.append(np.array([[I(e) for e in row] for row in x], dtype))
        Z.append(z)

    d = {"X": X, "Z": Z}
    save_pickle(d, folder, "column_space.pkl")

    set_seed(seed + 210)
    shapes = [(2, 2), (2, 3), (2, 4), (3, 2), (4, 2), (3, 3)]
    X = []
    Z = []
    for i in range(len(shapes)):
        deg = shapes[i][0]  # The degree of the vector space

        # Random matrix
        x = randint_matrix(0, order, shapes[i])
        X.append(x)
        x = matrix(FIELD, [[F(e) for e in row] for row in x])
        z = x.left_kernel()
        if z.dimension() == 0:
            z = randint_matrix(0, 1, (0, deg))
        else:
            z = z.basis_matrix()
            z = np.array([[I(e) for e in row] for row in z], dtype)
        Z.append(z)

        # Reduce the left null space by 1 by copying the 0th row to the jth row
        for j in range(1, shapes[i][0]):
            x = copy(x)
            x[j, :] = F(random.randint(0, order - 1)) * x[0, :]

            z = x.left_kernel()
            if z.dimension() == 0:
                z = randint_matrix(0, 1, (0, deg))
            else:
                z = z.basis_matrix()
                z = np.array([[I(e) for e in row] for row in z], dtype)
            X.append(np.array([[I(e) for e in row] for row in x], dtype))
            Z.append(z)

        # Zero matrix
        x = copy(x)
        x[:] = F(0)
        z = x.left_kernel()
        if z.dimension() == 0:
            z = randint_matrix(0, 1, (0, deg))
        else:
            z = z.basis_matrix()
            z = np.array([[I(e) for e in row] for row in z], dtype)
        X.append(np.array([[I(e) for e in row] for row in x], dtype))
        Z.append(z)

    d = {"X": X, "Z": Z}
    save_pickle(d, folder, "left_null_space.pkl")

    set_seed(seed + 211)
    shapes = [(2, 2), (2, 3), (2, 4), (3, 2), (4, 2), (3, 3)]
    X = []
    Z = []
    for i in range(len(shapes)):
        deg = shapes[i][1]  # The degree of the vector space

        # Random matrix
        x = randint_matrix(0, order, shapes[i])
        X.append(x)
        x = matrix(FIELD, [[F(e) for e in row] for row in x])
        z = x.right_kernel()
        if z.dimension() == 0:
            z = randint_matrix(0, 1, (0, deg))
        else:
            z = z.basis_matrix()
            z = np.array([[I(e) for e in row] for row in z], dtype)
        Z.append(z)

        # Reduce the null space by 1 by copying the 0th column to the jth column
        for j in range(1, shapes[i][1]):
            x = copy(x)
            x[:, j] = F(random.randint(0, order - 1)) * x[:, 0]

            z = x.right_kernel()
            if z.dimension() == 0:
                z = randint_matrix(0, 1, (0, deg))
            else:
                z = z.basis_matrix()
                z = np.array([[I(e) for e in row] for row in z], dtype)
            X.append(np.array([[I(e) for e in row] for row in x], dtype))
            Z.append(z)

        # Zero matrix
        x = copy(x)
        x[:] = F(0)
        z = x.right_kernel()
        if z.dimension() == 0:
            z = randint_matrix(0, 1, (0, deg))
        else:
            z = z.basis_matrix()
            z = np.array([[I(e) for e in row] for row in z], dtype)
        X.append(np.array([[I(e) for e in row] for row in x], dtype))
        Z.append(z)

    d = {"X": X, "Z": Z}
    save_pickle(d, folder, "null_space.pkl")

    ###############################################################################
    # Polynomial arithmetic
    ###############################################################################
    folder = os.path.join(PATH, "polys", "data", sub_folder)
    if os.path.exists(folder):
        shutil.rmtree(folder)
    os.mkdir(folder)

    MIN_COEFFS = 1
    MAX_COEFFS = 12

    set_seed(seed + 101)
    X = [random_coeffs(0, order, MIN_COEFFS, MAX_COEFFS) for i in range(20)]
    Y = [random_coeffs(0, order, MIN_COEFFS, MAX_COEFFS) for i in range(20)]
    Z = []
    for i in range(len(X)):
        x = list_to_poly(X[i])
        y = list_to_poly(Y[i])
        z = x + y
        z = poly_to_list(z)
        Z.append(z)
    d = {"X": X, "Y": Y, "Z": Z}
    save_pickle(d, folder, "add.pkl")

    set_seed(seed + 102)
    X = [random_coeffs(0, order, MIN_COEFFS, MAX_COEFFS) for i in range(20)]
    Y = [random_coeffs(0, order, MIN_COEFFS, MAX_COEFFS) for i in range(20)]
    Z = []
    for i in range(len(X)):
        x = list_to_poly(X[i])
        y = list_to_poly(Y[i])
        z = x - y
        z = poly_to_list(z)
        Z.append(z)
    d = {"X": X, "Y": Y, "Z": Z}
    save_pickle(d, folder, "subtract.pkl")

    set_seed(seed + 103)
    X = [random_coeffs(0, order, MIN_COEFFS, MAX_COEFFS) for i in range(20)]
    Y = [random_coeffs(0, order, MIN_COEFFS, MAX_COEFFS) for i in range(20)]
    Z = []
    for i in range(len(X)):
        x = list_to_poly(X[i])
        y = list_to_poly(Y[i])
        z = x * y
        z = poly_to_list(z)
        Z.append(z)
    d = {"X": X, "Y": Y, "Z": Z}
    save_pickle(d, folder, "multiply.pkl")

    set_seed(seed + 104)
    X = [random_coeffs(0, order, MIN_COEFFS, MAX_COEFFS) for i in range(20)]
    Y = [random.randint(1, 2 * characteristic) for i in range(20)]
    Z = []
    for i in range(len(X)):
        x = list_to_poly(X[i])
        y = Y[i]
        z = x * y
        z = poly_to_list(z)
        Z.append(z)
    d = {"X": X, "Y": Y, "Z": Z}
    save_pickle(d, folder, "scalar_multiply.pkl")

    set_seed(seed + 105)
    X = [random_coeffs(0, order, MIN_COEFFS, MAX_COEFFS) for i in range(20)]
    Y = [random_coeffs(0, order, MIN_COEFFS, MAX_COEFFS) for i in range(20)]
    # Add some specific polynomial types
    X.append([0]), Y.append(random_coeffs(0, order, MIN_COEFFS,
                                          MAX_COEFFS))  # 0 / y
    X.append(random_coeffs(0, order, MIN_COEFFS, MAX_COEFFS // 2)), Y.append(
        random_coeffs(0, order, MAX_COEFFS // 2,
                      MAX_COEFFS))  # x / y with x.degree < y.degree
    X.append(random_coeffs(0, order, 2, MAX_COEFFS)), Y.append(
        random_coeffs(0, order, 1, 2))  # x / y with y.degree = 0
    Q = []
    R = []
    for i in range(len(X)):
        x = list_to_poly(X[i])
        y = list_to_poly(Y[i])
        q = x // y
        r = x % y
        q = poly_to_list(q)
        Q.append(q)
        r = poly_to_list(r)
        R.append(r)
    d = {"X": X, "Y": Y, "Q": Q, "R": R}
    save_pickle(d, folder, "divmod.pkl")

    set_seed(seed + 106)
    X = [random_coeffs(0, order, MIN_COEFFS, MAX_COEFFS) for i in range(4)]
    X.append(random_coeffs(0, order, 1, 2))
    Y = [0, 1, 2, 3]
    Z = []
    for i in range(len(X)):
        x = list_to_poly(X[i])
        ZZ = []
        for j in range(len(Y)):
            y = Y[j]
            z = x**y
            z = poly_to_list(z)
            ZZ.append(z)
        Z.append(ZZ)
    d = {"X": X, "Y": Y, "Z": Z}
    save_pickle(d, folder, "power.pkl")

    set_seed(seed + 107)
    X = [random_coeffs(0, order, MIN_COEFFS, MAX_COEFFS) for i in range(20)]
    Y = arange(0, order, sparse=sparse)
    Z = np.array(np.zeros((len(X), len(Y))), dtype=dtype)
    for i in range(len(X)):
        for j in range(len(Y)):
            x = list_to_poly(X[i])
            y = F(Y[j])
            z = x(y)
            Z[i, j] = I(z)
    d = {"X": X, "Y": Y, "Z": Z}
    save_pickle(d, folder, "evaluate.pkl")

    set_seed(seed + 108)
    X = [random_coeffs(0, order, MIN_COEFFS, MAX_COEFFS) for i in range(20)]
    Y = [randint_matrix(0, order, (2, 2)) for i in range(20)]
    Z = []
    for i in range(len(X)):
        x = list_to_poly(X[i])
        y = matrix(FIELD, [[F(e) for e in row] for row in Y[i]])
        z = x(y)
        z = np.array([[I(e) for e in row] for row in z], dtype)
        Z.append(z)
    d = {"X": X, "Y": Y, "Z": Z}
    save_pickle(d, folder, "evaluate_matrix.pkl")

    ###############################################################################
    # Polynomial arithmetic methods
    ###############################################################################

    set_seed(seed + 301)
    X = [random_coeffs(0, order, MIN_COEFFS, MAX_COEFFS) for i in range(20)]
    Z = []
    for i in range(len(X)):
        x = list_to_poly(X[i])
        z = x.reverse()
        z = poly_to_list(z)
        Z.append(z)
    d = {"X": X, "Z": Z}
    save_pickle(d, folder, "reverse.pkl")

    set_seed(seed + 302)
    X = [random_coeffs(0, order, MIN_COEFFS, MAX_COEFFS) for i in range(20)]
    R = []
    M = []
    for i in range(len(X)):
        x = list_to_poly(X[i])
        roots = x.roots()
        RR, MM = [], []
        for root in roots:
            r = root[0]
            m = root[1]
            RR.append(I(r))
            MM.append(int(m))
        idxs = np.argsort(RR)  # Sort by ascending roots
        RR = (np.array(RR, dtype=dtype)[idxs]).tolist()
        MM = (np.array(MM, dtype=dtype)[idxs]).tolist()
        R.append(RR)
        M.append(MM)
    d = {"X": X, "R": R, "M": M}
    save_pickle(d, folder, "roots.pkl")

    set_seed(seed + 303)
    X = [
        random_coeffs(0, order, 2 * FIELD.degree(), 6 * FIELD.degree())
        for i in range(20)
    ]
    Y = [
        1,
    ] * 10 + [random.randint(2,
                             FIELD.degree() + 1) for i in range(10)]
    Z = []
    for i in range(len(X)):
        x = list_to_poly(X[i])
        z = x.derivative(Y[i])
        z = poly_to_list(z)
        Z.append(z)
    d = {"X": X, "Y": Y, "Z": Z}
    save_pickle(d, folder, "derivative.pkl")

    ###############################################################################
    # Polynomial arithmetic functions
    ###############################################################################

    set_seed(seed + 401)
    X = [random_coeffs(0, order, MIN_COEFFS, MAX_COEFFS) for i in range(20)]
    Y = [random_coeffs(0, order, MIN_COEFFS, MAX_COEFFS) for i in range(20)]
    D = []
    S = []
    T = []
    for i in range(len(X)):
        x = list_to_poly(X[i])
        y = list_to_poly(Y[i])
        d, s, t = xgcd(x, y)
        d = poly_to_list(d)
        s = poly_to_list(s)
        t = poly_to_list(t)
        D.append(d)
        S.append(s)
        T.append(t)
    d = {"X": X, "Y": Y, "D": D, "S": S, "T": T}
    save_pickle(d, folder, "egcd.pkl")

    set_seed(seed + 402)
    X = []
    Z = []
    for i in range(20):
        XX = [
            random_coeffs(0, order, MIN_COEFFS, MAX_COEFFS)
            for i in range(random.randint(2, 5))
        ]
        X.append(XX)
        xx = [list_to_poly(XXi) for XXi in XX]
        z = lcm(xx)
        z = poly_to_list(z)
        Z.append(z)
    d = {"X": X, "Z": Z}
    save_pickle(d, folder, "lcm.pkl")

    set_seed(seed + 403)
    X = []
    Z = []
    for i in range(20):
        XX = [
            random_coeffs(0, order, MIN_COEFFS, MAX_COEFFS)
            for i in range(random.randint(2, 5))
        ]
        X.append(XX)
        xx = [list_to_poly(XXi) for XXi in XX]
        z = prod(xx)
        z = poly_to_list(z)
        Z.append(z)
    d = {"X": X, "Z": Z}
    save_pickle(d, folder, "prod.pkl")

    set_seed(seed + 404)
    X = [random_coeffs(0, order, MIN_COEFFS, MAX_COEFFS) for i in range(20)]
    E = [random.randint(2, 10) for i in range(20)]
    M = [random_coeffs(0, order, MIN_COEFFS, MAX_COEFFS) for i in range(20)]
    Z = []
    for i in range(20):
        x = list_to_poly(X[i])
        e = E[i]
        m = list_to_poly(M[i])
        z = (x**e) % m
        z = poly_to_list(z)
        Z.append(z)
    d = {"X": X, "E": E, "M": M, "Z": Z}
    save_pickle(d, folder, "modular_power.pkl")

    set_seed(seed + 405)
    X = [
        0,
    ] * 20  # The remainder
    Y = [
        0,
    ] * 20  # The modulus
    Z = [
        0,
    ] * 20  # The solution
    for i in range(20):
        n = random.randint(2, 4)  # The number of polynomials
        x, y = [], []
        for j in range(n):
            d = random.randint(3, 5)
            x.append(random_coeffs(0, order, d, d + 1))
            y.append(random_coeffs(
                0, order, d + 1, d +
                2))  # Ensure modulus degree is greater than remainder degree
        X[i] = x
        Y[i] = y
        try:
            x = [list_to_poly(xx) for xx in x]
            y = [list_to_poly(yy) for yy in y]
            z = crt(x, y)
            Z[i] = poly_to_list(z)
        except:
            Z[i] = None
    d = {"X": X, "Y": Y, "Z": Z}
    save_pickle(d, folder, "crt.pkl")

    ###############################################################################
    # Special polynomials
    ###############################################################################

    set_seed(seed + 501)
    X = [random_coeffs(0, order, 1, 6) for _ in range(20)]
    Z = [
        False,
    ] * len(X)
    for i in range(len(X)):
        if random.choice(["one", "other"]) == "one":
            X[i][0] = 1
        x = list_to_poly(X[i])
        z = x.is_monic()
        Z[i] = bool(z)
    d = {"X": X, "Z": Z}
    save_pickle(d, folder, "is_monic.pkl")

    set_seed(seed + 502)
    IS = []
    IS_NOT = []
    if order <= 2**16:
        while len(IS) < 10:
            x = random_coeffs(0, order, 1, 6)
            f = list_to_poly(x)
            if f.is_irreducible():
                IS.append(x)
        while len(IS_NOT) < 10:
            x = random_coeffs(0, order, 1, 6)
            f = list_to_poly(x)
            if not f.is_irreducible():
                IS_NOT.append(x)
    d = {"IS": IS, "IS_NOT": IS_NOT}
    save_pickle(d, folder, "is_irreducible.pkl")

    set_seed(seed + 503)
    IS = []
    IS_NOT = []
    if order <= 2**16:
        while len(IS) < 10:
            x = random_coeffs(0, order, 1, 6)
            f = list_to_poly(x)
            # f = f / f.coefficients()[-1]  # Make monic
            # assert f.is_monic()
            if f.degree() == 1 and f.coefficients(sparse=False)[0] == 0:
                continue  # For some reason `is_primitive()` crashes on f(x) = a*x
            if not f.is_irreducible():
                continue  # Want to find an irreducible polynomial that is also primitive
            if f.is_primitive():
                IS.append(x)
        while len(IS_NOT) < 10:
            x = random_coeffs(0, order, 1, 6)
            f = list_to_poly(x)
            # f = f / f.coefficients()[-1]  # Make monic
            # assert f.is_monic()
            if f.degree() == 1 and f.coefficients(sparse=False)[0] == 0:
                continue  # For some reason `is_primitive()` crashes on f(x) = a*x
            if not f.is_irreducible():
                continue  # Want to find an irreducible polynomial that is not primitive
            if not f.is_primitive():
                IS_NOT.append(x)
    d = {"IS": IS, "IS_NOT": IS_NOT}
    save_pickle(d, folder, "is_primitive.pkl")

    set_seed(seed + 504)
    if order <= 2**16:
        X = [random_coeffs(0, order, 1, 6) for _ in range(20)]
        Z = [
            False,
        ] * len(X)
        for i in range(len(X)):
            x = list_to_poly(X[i])
            z = x.is_squarefree()
            Z[i] = bool(z)
    else:
        X = []
        Z = []
    d = {"X": X, "Z": Z}
    save_pickle(d, folder, "is_square_free.pkl")
Esempio n. 10
0
 def crack_by_pq(self):
     mp, mq = self.crack_by_p(), self.crack_by_q()
     return crt([mp, mq], [self.p, self.q])
Esempio n. 11
0
def _faulty_sign(m, p, q, d_p, d_q):
    s_p = pow(m, d_p, p)
    s_q = pow(m, d_q, q)
    s_q ^= 1
    return crt([s_p, s_q], [p, q])
Esempio n. 12
0
def test_SECCON_2020_crypto01():
    masked_flag = 8077275413285507538357977814283814136815067070436948406142717872478737670143034266458000767181162602217137657160614964831459653429727469965712631294123225
    ciphertexts = [
        (
            886775008733978973740257525650074677865489026053222554158847150065839924739525729402395428639350660027796013999414358689067171124475540042281892825140355436902197270317502862419355737833115120643020255177020178331283541002427279377648285229476212651491301857891044943211950307475969543789857568915505152189,
            428559018841948586040450870835405618958247103990365896475476359721456520823105336402250177610460462882418373365551361955769011150860740050608377302711322189733933012507453380208960247649622047461113987220437673085,
            (80103920082434941308951713928956232093682985133090231319482222058601362901404235742975739345738195056858602864819514638254604213654261535503537998613664606957411824998071339098079622119781772477940471338367084695408560473046701072890754255641388442248683562485936267601216704036749070688609079527182189924,
             842529568002033827493313169405480104392127700904794758022297608679141466431472390397211660887148306350328312067659313538964875094877785244888004725864621826211254824064492961341512012172365417791553455922872091302295614295785447354268009914265614957287377743897340475899980395298019735631787570231395791009
             ),
            59051335744243522933765175665,
        ),
        (
            37244493713246153778174562251362609960152354778990433088693945121840521598316370898923829767722653817418453309557995775960963654893571162621888675965423771020678918714406461976659339420718804301006282789714856197345257634581330970033427061846386874027391337895557558939538516456076874074642348992933600929747,
            152657520846237173082171645969128953029734435220247551748055538422696193261367413610113664730705318574898280226247526051526753570012356026049784218573767765351341949785570284026342156807244268439356037529507501666987,
            (14301224815357080657295611483943004076662022528706782110580690613822599700117720290144067866898573981166927919045773324162651193822888938569692341428439887892150361361566562459037438581637126808773605536449091609307652818862273375400935935851849153633881318435727224452416837785155763820052159016539063161774,
             711567521767597846126014317418558888899966530302382481896965868976010995445213619798358362850235642988939870722858624888544954189591439381230859036120045216842190726357421800117080884618285875510251442474167884705409694074544449959388473647082485564659040849556130494057742499029963072560315800049629531101
             ),
            56178670950277431873900982569,
        ),
        (
            6331516792334912993168705942035497262087604457828016897033541606942408964421467661323530702416001851055818803331278149668787143629857676822265398153269496232656278975610802921303671791426728632525217213666490425139054750899596417296214549901614709644307007461708968510489409278966392105040423902797155302293,
            2041454339352622193656627164408774503102680941657965640324880658919242765901541504713444825283928928662755298871656269360429687747026596290805541345773049732439830112665647963627438433525577186905830365395002284129,
            (4957181230366693742871089608567285130576943723414681430592899115510633732100117146460557849481224254840925101767808247789524040371495334272723624632991086495766920694854539353934108291010560628236400352109307607758762704896162926316651462302829906095279281186440520100069819712951163378589378112311816255944,
             2715356151156550887523953822376791368905549782137733960800063674240100539578667744855739741955125966795181973779300950371154326834354436541128751075733334790425302253483346802547763927140263874521376312837536602237535819978061120675338002761853910905172273772708894687214799261210445915799607932569795429868
             ),
            70953285682097151767648136059,
        ),
    ]
    HINTSIZE = 96

    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

    hintmod = 2**HINTSIZE
    todec = masked_flag
    for data in ciphertexts:
        n, e, c, hint = data
        c_high, c_low = c
        for f in (e / QQ(n)).continued_fraction().convergents():
            y = f.numerator()
            x = f.denominator()
            if is_prime(x) and is_prime(y):
                print("good", x, y)
                break

        plo = hint
        qlo = n * inverse_mod(plo, hintmod) % hintmod
        slo = (plo + qlo) % hintmod
        assert plo * qlo % hintmod == n % hintmod

        a = e * x - (n + 1) * y

        z_mod_y = (-a) % y
        z_mod_hintmod = (-a + slo * y) % hintmod
        midmod = hintmod * y
        zmid = crt([z_mod_y, z_mod_hintmod], [y, hintmod])

        aa = a - slo * y + zmid
        assert aa % midmod == 0
        aa //= midmod

        # shi = (p + q) // hintmod
        # zhi is ~216 bits
        # assert shi == aa + zhi

        sumpq = aa * hintmod
        eps = 2**216 * hintmod

        rsa = RSA(n)
        pbound, qbound = rsa.bound_primes_from_approximate_sum(
            sumpq - eps, 2 * eps)

        try:
            print("factor1")
            p, q = rsa.factor_with_prime_hint(low_mod=(plo, hintmod),
                                              bounds=pbound,
                                              beta=0.49)
        except RuntimeError:
            print("factor2")
            p, q = rsa.factor_with_prime_hint(low_mod=(qlo, hintmod),
                                              bounds=pbound,
                                              beta=0.49)
        print("ok!")
        d = inverse_mod(e, n + p + q + 1)
        mask = decrypt(c, d, n)
        todec ^= mask
    assert Bin(todec).bytes == b'SECCON{gut_poweeeeeeeeeeeeeer}'