コード例 #1
0
def test_covariance(d, m, q, iterations=100):
    """
    Compute the covariance matrix of the signatures distribution.

    For an isotropic Gaussian, the covariance matrix is
    proportional to the identity matrix.
    """
    sk = SecretKey(d, m, q)
    dim = (m + 1) * d
    liste_sig = []
    mean = [0] * dim
    Cov = [[0 for _ in range(dim)] for _ in range(dim)]
    for i in range(iterations):
        message = "0"
        r, t = sk.sign(message)
        s = decompress(t, sk.d, sk.rate)
        s = sum([elt for elt in s], [])
        mean = add(mean, s)
        liste_sig += [s]
    # print("mean = {mean}".format(mean=mean))
    for s in liste_sig:
        s = [iterations * elt for elt in s]
        s = [(s[i] - mean[i]) for i in range(dim)]
        M = make_matrix(s)
        for i in range(dim):
            Cov[i] = add(Cov[i], M[i])
    # We normalize only at the end to work with integers as long as possible
    for i in range(dim):
        for j in range(dim):
            Cov[i][j] /= (iterations**3)
            Cov[i][j] = int(round(Cov[i][j]))
コード例 #2
0
def test_covariance(n, iterations=100):
    """
    Compute the covariance matrix of the signatures distribution.

    For an isotropic Gaussian, the covariance matrix is
    proportional to the identity matrix.
    """
    sk = SecretKey(n)
    liste_sig = []
    mean = [0] * (2 * n)
    Cov = [[0 for _ in range(2 * n)] for _ in range(2 * n)]
    for i in range(iterations):
        message = "0"
        r, s = sk.sign(message)
        s = s[0] + s[1]
        mean = add(mean, s)
        liste_sig += [s]
    # mean = [elt / iterations for elt in mean]
    # print(liste_sig)
    print("mean = {mean}".format(mean=mean))
    for s in liste_sig:
        s = [iterations * elt for elt in s]
        s = [(s[i] - mean[i]) for i in range(2 * n)]
        M = make_matrix(s)
        for i in range(2 * n):
            Cov[i] = add(Cov[i], M[i])
    for i in range(2 * n):
        for j in range(2 * n):
            Cov[i][j] /= (iterations**3)
    print(Cov)
    return Cov
コード例 #3
0
def vecvecmul(u, v, integer=False, modulus=None):
    """
    Compute the product u * (v^t), u and v are row vectors, and v^t denotes the transose of v.

    Input:
    u           A row vector
    v           A row vector
    integer     This flag should be set (to True) iff the elements are in Z[x] / (x ** n + 1)
    modulus     This flag should be set (to q) iff the elements are in Z_q[x] / (x ** n + 1)

    Output:
    rep         The product u * (v^t) = sum(u[i] * v[i] for i in range(len(u)))

    Format:     Coefficient
    """
    m = len(u)
    deg = len(u[0])
    assert (len(u) == len(v))
    rep = [0 for k in range(deg)]
    if modulus is not None:
        for i in range(m):
            rep = add_zq(rep, mul_zq(u[i], v[i], modulus), modulus)
        return rep
    else:
        for i in range(m):
            rep = add(rep, mul(u[i], v[i]))
        if integer is True:
            rep = [int(round(elt)) for elt in rep]
        return rep
コード例 #4
0
def vecmatmul(t, B, integer=False, modulus=None):
    """
    Compute the product t * B, where t is a vector and B is a square matrix.

    Input:
    t           A row vector
    B           A matrix
    integer     This flag should be set (to True) iff the elements are in Z[x] / (x ** n + 1)
    modulus     This flag should be set (to q) iff the elements are in Z_q[x] / (x ** n + 1)

    Output:
    v           The row vector t * B

    Format:     Coefficient
    """
    nrows = len(B)
    ncols = len(B[0])
    deg = len(B[0][0])
    assert (len(t) == nrows)
    v = [[0 for k in range(deg)] for j in range(ncols)]
    if modulus is not None:
        for j in range(ncols):
            for i in range(nrows):
                v[j] = add_zq(v[j], mul_zq(t[i], B[i][j], modulus), modulus)
        return v
    else:
        for j in range(ncols):
            for i in range(nrows):
                v[j] = add(v[j], mul(t[i], B[i][j]))
        if integer is True:
            v = [[int(round(elt)) for elt in poly] for poly in v]
        return v
コード例 #5
0
ファイル: ntrugen.py プロジェクト: tprest/ModFalcon
def my_det(M):
    """
    Compute the determinant of M.
    If M has coefficients in a ring R, then the determinant is in R.
    This determinant is computed using Cramer's rule: this is less efficient
    than other methods but allows to do all operations in R.

    Input:
    M               A matrix

    Output:
    determinant     The determinant of M

    Format:         Coefficient
    """
    nrow = len(M)
    ncol = len(M[0])
    d = len(M[0][0])
    assert (nrow == ncol)
    if (nrow == 1):
        return M[0][0]
    else:
        determinant = [0] * d
        for i in range(nrow):
            Mp = submatrix(M, i, 0)
            det_Mp = my_det(Mp)
            if (i & 1):
                det_Mp = [- elt for elt in det_Mp]
            determinant = add(determinant, karamul(M[i][0], det_Mp))
    return determinant
コード例 #6
0
ファイル: ffsampling.py プロジェクト: tprest/ModFalcon
def ffnp(t, T):
    """
    Compute the FFNP reduction of t, using T as auxilary information.

    Input:
    t           A vector
    T           The LDL decomposition tree of an (implicit) matrix G

    Output:
    z           An integer vector such that (t - z) * B is short

    Format:     Coefficient
    """
    m = len(t)
    n = len(t[0])
    z = [None] * m
    # General case
    if (n > 1):
        L = T[0]
        for i in range(m - 1, -1, -1):
            # t[i] is "corrected", taking into accounts the t[j], z[j] (j > i)
            tib = t[i][:]
            for j in range(m - 1, i, -1):
                tib = add(tib, mul(sub(t[j], z[j]), L[j][i]))
            # Recursive call
            z[i] = merge(ffnp(split(tib), T[i + 1]))
        return z
    # Bottom case: round each coefficient in parallel
    elif (n == 1):
        z[0] = [round(t[0][0])]
        z[1] = [round(t[1][0])]
        return z
コード例 #7
0
def gs_norm(f, g, q):
    """Compute the squared Gram-Schmidt norm of the NTRU matrix generated by f, g.

    This matrix is [[g, - f], [G, - F]].
    This algorithm is equivalent to line 9 of algorithm 5 (NTRUGen).
    """
    sqnorm_fg = sqnorm([f, g])
    ffgg = add(mul(f, adj(f)), mul(g, adj(g)))
    Ft = div(adj(g), ffgg)
    Gt = div(adj(f), ffgg)
    sqnorm_FG = (q**2) * sqnorm([Ft, Gt])
    return max(sqnorm_fg, sqnorm_FG)
コード例 #8
0
def gram(B):
    """Compute the Gram matrix of B.

    Args:
        B: a matrix

    Format: coefficient
    """
    rows = range(len(B))
    ncols = len(B[0])
    deg = len(B[0][0])
    G = [[[0 for coef in range(deg)] for j in rows] for i in rows]
    for i in rows:
        for j in rows:
            for k in range(ncols):
                G[i][j] = add(G[i][j], mul(B[i][k], adj(B[j][k])))
    return G
コード例 #9
0
def vecmatmul(t, B):
    """Compute the product t * B, where t is a vector and B is a square matrix.

    Args:
        B: a matrix

    Format: coefficient
    """
    nrows = len(B)
    ncols = len(B[0])
    deg = len(B[0][0])
    assert(len(t) == nrows)
    v = [[0 for k in range(deg)] for j in range(ncols)]
    for j in range(ncols):
        for i in range(nrows):
            v[j] = add(v[j], mul(t[i], B[i][j]))
    return v
コード例 #10
0
def gram(B):
    """
    Compute the Gram matrix of B.

    Input:
    B           A matrix

    Output:
    G           The Gram matrix of B: G = B * (B*)

    Format:     Coefficient
    """
    rows = range(len(B))
    ncols = len(B[0])
    deg = len(B[0][0])
    G = [[[0 for coef in range(deg)] for j in rows] for i in rows]
    for i in rows:
        for j in rows:
            for k in range(ncols):
                G[i][j] = add(G[i][j], mul(B[i][k], adj(B[j][k])))
    return G
コード例 #11
0
def ffnp(t, T):
    """Compute the ffnp reduction of t, using T as auxilary information.

    Args:
        t: a vector
        T: a ldl decomposition tree

    Format: coefficient
    """
    n = len(t[0])
    z = [None, None]
    if (n > 1):
        l10, T0, T1 = T
        z[1] = merge(ffnp(split(t[1]), T1))
        t0b = add(t[0], mul(sub(t[1], z[1]), l10))
        z[0] = merge(ffnp(split(t0b), T0))
        return z
    elif (n == 1):
        z[0] = [round(t[0][0])]
        z[1] = [round(t[1][0])]
        return z
コード例 #12
0
ファイル: ntrugen.py プロジェクト: tprest/ModFalcon
def module_ntru_gen(d, q, m):
    """
    Take as input system parameters, and output two "module-NTRU" matrices A and B such that:
    - B * A = 0 [mod q]
    - B has small polynomials
    - A is in Hermite normal form
    Also compute the inverse of B (over the field K = Q[x] / (x ** d + 1)).

    Input:
    d           The degree of the underlying ring R = Z[x] / (x ** d + 1)
    q           An integer
    m           An integer

    Output:
    A           A matrix in R ^ ((m + 1) x 1)
    B           A matrix in R ^ ((m + 1) x (m + 1))
    inv_B       A matrix in K ^ ((m + 1) x (m + 1))
    sq_gs_norm  A real number, the square of the Gram-Schmidt norm of B

    Format:     Coefficient
    """
    if m == 1:
        magic_constant = [1.15]
        gs_slack = 1.17
    elif m == 2:
        magic_constant = [1.07, 1.14]
        gs_slack = 1.17
    elif m == 3:
        magic_constant = [1.21, 1.10, 1.06]
        gs_slack = 1.24
    else:
        print("No parameters implemented yet for m = {m}".format(m=m))
        return
    max_gs_norm = gs_slack * (q ** (1 / (m + 1)))
    while True:
        # We generate all rows of B except the last
        B = [[None for j in range(m + 1)] for i in range(m + 1)]
        for i in range(m):
            for j in range(m + 1):
                # Each coefficient B[i][j] is a polynomial
                sigma = magic_constant[i] * (q ** (1 / (m + 1))) # ==> ||bi~|| = gs_slack * q^(1/(m+1))
                sig = sqrt(1 / (d * (m + 1 - i))) * sigma        # sig = stdv. dev. des coef de bi
                B[i][j] = [int(round(gauss(0, sig))) for k in range(d)]
        # We check that the GS norm is not larger than tolerated
        Bp_fft = [[fft(poly) for poly in row] for row in B[:-1]]
        Gp = gram_fft(Bp_fft)
        [Lp_fft, Dp_fft] = ldl_fft(Gp)
        Dp = [[[0] * d for col in range(m)] for row in range(m)]
        for i in range(m):
            Dp[i][i] = ifft(Dp_fft[i][i])
        prod_di = [1] + [0] * (d - 1)
        for i in range(m):
            prod_di = mul(prod_di, Dp[i][i])
        last = div([q ** 2] + [0] * (d - 1), prod_di)
        norms = [Dp[i][i][0] for i in range(m)] + [last[0]]
        # If the GS norm is too large, restart
        if sqrt(max(norms)) > max_gs_norm:
            continue
        # Try to solve the module-NTRU equation
        f = submatrix(B, m, 0)
        f = [[neg(elt) for elt in row] for row in f]
        g = [B[j][0] for j in range(m)]
        fp = my_det(f)
        adjf = my_adjugate(f)
        gp = [0] * d
        for i in range(m):
            gp = add(gp, karamul(adjf[0][i], g[i]))
        try:
            # Compute f^(-1) mod q
            fp_q = [elt % q for elt in fp]
            inv_f = [[elt[:] for elt in row] for row in adjf]
            for i in range(m):
                for j in range(m):
                    inv_f[i][j] = [elt % q for elt in inv_f[i][j]]
                    inv_f[i][j] = div_zq(inv_f[i][j], fp_q, q)
            # Compute h = f^(-1) * g mod q and A = [1 | h]
            h = [None] * m
            for i in range(m):
                elt = [0] * d
                for j in range(m):
                    elt = add_zq(elt, mul_zq(inv_f[i][j], g[j], q), q)
                h[i] = elt
            one = [1] + [0 for _ in range(1, d)]
            A = [one] + h
            Fp, Gp = ntru_solve(fp, gp, q)
            B[m][0] = Gp
            B[m][1] = [- coef for coef in Fp]
            for i in range(2, m + 1):
                B[m][i] = [0 for _ in range(d)]
            # Compute the inverse of B
            det_B = my_det(B)
            inv_B = my_adjugate(B)
            inv_B = [[div(poly, det_B) for poly in row] for row in inv_B]
            return A, B, inv_B, max(norms)
        # If any step failed, restart
        except (ZeroDivisionError, ValueError):
            continue