Exemplo n.º 1
0
def ldl_fft(G):
    """
    Compute the LDL decomposition of G.

    Input:
    G           A self-adjoint matrix (i.e. G is equal to its conjugate transpose)

    Output:
    L, D        The LDL decomposition of G, that is G = L * D * (L*), where:
                - L is lower triangular with a diagonal of 1's
                - D is diagonal

    Format:     FFT
    """
    deg = len(G[0][0])
    dim = len(G)
    L = [[[0 for k in range(deg)] for j in range(dim)] for i in range(dim)]
    D = [[[0 for k in range(deg)] for j in range(dim)] for i in range(dim)]
    for i in range(dim):
        L[i][i] = [1 for j in range(deg)]
        D[i][i] = G[i][i]
        for j in range(i):
            L[i][j] = G[i][j]
            for k in range(j):
                L[i][j] = sub_fft(
                    L[i][j],
                    mul_fft(mul_fft(L[i][k], adj_fft(L[j][k])), D[k][k]))
            L[i][j] = div_fft(L[i][j], D[j][j])
            D[i][i] = sub_fft(
                D[i][i], mul_fft(mul_fft(L[i][j], adj_fft(L[i][j])), D[j][j]))
    return [L, D]
Exemplo n.º 2
0
def ldl_fft(G):
    """Compute the LDL decomposition of G.

	Args:
		G: a Gram matrix

	Format: FFT

	Corresponds to algorithm 14 (LDL) of Falcon's documentation.
	"""
    deg = len(G[0][0])
    dim = len(G)
    L = [[[0 for k in range(deg)] for j in range(dim)] for i in range(dim)]
    D = [[[0 for k in range(deg)] for j in range(dim)] for i in range(dim)]
    for i in range(dim):
        L[i][i] = [1 for j in range(deg)]
        D[i][i] = G[i][i]
        for j in range(i):
            L[i][j] = G[i][j]
            for k in range(j):
                L[i][j] = sub_fft(
                    L[i][j],
                    mul_fft(mul_fft(L[i][k], adj_fft(L[j][k])), D[k][k]))
            L[i][j] = div_fft(L[i][j], D[j][j])
            D[i][i] = sub_fft(
                D[i][i], mul_fft(mul_fft(L[i][j], adj_fft(L[i][j])), D[j][j]))
    return [L, D]
def ldl_fft(G):
    """
    Compute the LDL decomposition of G. Only works with 2 * 2 matrices.

    Args:
        G: a Gram matrix

    Format: FFT

    Corresponds to algorithm 8 (LDL*) of Falcon's documentation.
    """
    deg = len(G[0][0])
    dim = len(G)
    assert (dim == 2)
    assert (dim == len(G[0]))

    zero = [0] * deg
    one = [1] * deg
    D00 = G[0][0][:]
    L10 = div_fft(G[1][0], G[0][0])
    D11 = sub_fft(G[1][1], mul_fft(mul_fft(L10, adj_fft(L10)), G[0][0]))
    L = [[one, zero], [L10, one]]
    D = [[D00, zero], [zero, D11]]

    return [L, D]
def reduce(f, g, F, G):
    """
    Reduce (F, G) relatively to (f, g).

    This is done via Babai's reduction.
    (F, G) <-- (F, G) - k * (f, g), where k = round((F f* + G g*) / (f f* + g g*)).
    Corresponds to algorithm 7 (Reduce) of Falcon's documentation.
    """
    n = len(f)
    size = max(53, bitsize(min(f)), bitsize(max(f)), bitsize(min(g)),
               bitsize(max(g)))

    f_adjust = [elt >> (size - 53) for elt in f]
    g_adjust = [elt >> (size - 53) for elt in g]
    fa_fft = fft(f_adjust)
    ga_fft = fft(g_adjust)

    while (1):
        # Because we work in finite precision to reduce very large polynomials,
        # we may need to perform the reduction several times.
        Size = max(53, bitsize(min(F)), bitsize(max(F)), bitsize(min(G)),
                   bitsize(max(G)))
        if Size < size:
            break

        F_adjust = [elt >> (Size - 53) for elt in F]
        G_adjust = [elt >> (Size - 53) for elt in G]
        Fa_fft = fft(F_adjust)
        Ga_fft = fft(G_adjust)

        den_fft = add_fft(mul_fft(fa_fft, adj_fft(fa_fft)),
                          mul_fft(ga_fft, adj_fft(ga_fft)))
        num_fft = add_fft(mul_fft(Fa_fft, adj_fft(fa_fft)),
                          mul_fft(Ga_fft, adj_fft(ga_fft)))
        k_fft = div_fft(num_fft, den_fft)
        k = ifft(k_fft)
        k = [int(round(elt)) for elt in k]
        if all(elt == 0 for elt in k):
            break
        # The two next lines are the costliest operations in ntru_gen
        # (more than 75% of the total cost in dimension n = 1024).
        # There are at least two ways to make them faster:
        # - replace Karatsuba with Toom-Cook
        # - mutualized Karatsuba, see ia.cr/2020/268
        # For simplicity reasons, we didn't implement these optimisations here.
        fk = karamul(f, k)
        gk = karamul(g, k)
        for i in range(n):
            F[i] -= fk[i] << (Size - size)
            G[i] -= gk[i] << (Size - size)
    return F, G
Exemplo n.º 5
0
def reduce(f, g, F, G):
    """
    Reduce (F, G) relatively to (f, g).

    This is done via Babai's reduction.
    (F, G) <-- (F, G) - k * (f, g), where k = round((F f* + G g*) / (f f* + g g*)).
    Similar to algorithm Reduce of Falcon's documentation.

    Input:
    f, g, F, G      Four polynomials mod (x ** n + 1)

    Output:
    None            The inputs are reduced as detailed above.

    Format:         Coefficient
    """
    n = len(f)
    size = max(53, bitsize(min(f)), bitsize(max(f)), bitsize(min(g)), bitsize(max(g)))

    f_adjust = [elt >> (size - 53) for elt in f]
    g_adjust = [elt >> (size - 53) for elt in g]
    fa_fft = fft(f_adjust)
    ga_fft = fft(g_adjust)

    while(1):
        # Because we are working in finite precision to reduce very large polynomials,
        # we may need to perform the reduction several times.
        Size = max(53, bitsize(min(F)), bitsize(max(F)), bitsize(min(G)), bitsize(max(G)))
        if Size < size:
            break

        F_adjust = [elt >> (Size - 53) for elt in F]
        G_adjust = [elt >> (Size - 53) for elt in G]
        Fa_fft = fft(F_adjust)
        Ga_fft = fft(G_adjust)

        den_fft = add_fft(mul_fft(fa_fft, adj_fft(fa_fft)), mul_fft(ga_fft, adj_fft(ga_fft)))
        num_fft = add_fft(mul_fft(Fa_fft, adj_fft(fa_fft)), mul_fft(Ga_fft, adj_fft(ga_fft)))
        k_fft = div_fft(num_fft, den_fft)
        k = ifft(k_fft)
        k = [int(round(elt)) for elt in k]
        if all(elt == 0 for elt in k):
            break
        fk = karamul(f, k)
        gk = karamul(g, k)
        for i in range(n):
            F[i] -= fk[i] << (Size - size)
            G[i] -= gk[i] << (Size - size)
    return F, G