Beispiel #1
0
def verify_1(n, m, sig, uid, pk, MPK):
    print("sig: {}".format(sig))
    # parsing sig
    e = sig[0]
    z = sig[1]
    z1, z2, z1a, z2a = z[0], z[1], z[2], z[3]

    # restore e
    vev1 = add_zq(add_zq(z1, mul_zq(z2, MPK)), mul_zq(uid, neg(e)))
    vec2 = add_zq(add_zq(z1a, mul_zq(z2a, MPK)), mul_zq(pk, neg(e)))
    e_check = H1(n, vev1, vec2, m)
    #print('e from sig: {}'.format(e))
    #print('e resttored: {}'.format(e_check))
    return e == e_check
Beispiel #2
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
Beispiel #3
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
Beispiel #4
0
    def verify(self, message, signature):
        """Verify a signature."""
        # Unpack the salt and the short polynomial s1
        salt = signature[:SALT_LEN]
        enc_s = signature[SALT_LEN:]
        s1 = decompress(enc_s, self.sig_bytelen - SALT_LEN, self.n)

        # Check that the encoding is valid
        if (s1 is False):
            print("Invalid encoding")
            return False

        # Compute s0 and normalize its coefficients in (-q/2, q/2]
        hashed = self.hash_to_point(message, salt)
        s0 = sub_zq(hashed, mul_zq(s1, self.h))
        s0 = [(coef + (q >> 1)) % q - (q >> 1) for coef in s0]

        # Check that the (s0, s1) is short
        norm_sign = sum(coef**2 for coef in s0)
        norm_sign += sum(coef**2 for coef in s1)
        if norm_sign > self.signature_bound:
            print("Squared norm of signature is too large:", norm_sign)
            return False

        # If all checks are passed, accept
        return True
Beispiel #5
0
def test_ntt(n, q, iterations=10):
    """Test the NTT."""
    for i in range(iterations):
        f = [randint(0, q - 1) for j in range(n)]
        g = [randint(0, q - 1) for j in range(n)]
        h = mul_zq(f, g, q)
        try:
            k = div_zq(h, f, q)
            if k != g:
                print("(f * g) / f =", k)
                print("g =", g)
                print("mismatch")
                return False
        except ZeroDivisionError:
            continue
    return True
Beispiel #6
0
def test_module_ntru_gen(d, m, iterations):
    q = q_12289
    for _ in range(iterations):
        A, B, inv_B, sqr_gsnorm = module_ntru_gen(d, q, m)
        # Check that the determinant of B is q
        if (my_det(B) != [q] + [0] * (d - 1)):
            print("det(B) != q")
            return False
        # Check that B * A = 0 mod q
        C = [None] * (m + 1)
        for i in range(m + 1):
            elt = [0] * d
            for j in range(m + 1):
                elt = add_zq(elt, mul_zq(B[i][j], A[j], q), q)
            C[i] = elt
        if any(elt != [0] * d for elt in C):
            print("Error: A and B are not orthogonal")
            return False
        # If all the checks passed, return True
    return True
Beispiel #7
0
 def verify(self, message, signature):
     """Verify a signature."""
     r, s = signature
     """1. hashes a message to a point of Z[x] mod (Phi,q"""
     hashed = self.hash_to_point(message, r)
     """2. Computes s0 + s1*h."""
     result = add_zq(s[0], mul_zq(s[1], self.h))
     """3. Verifies that the s0 + s1*h = hashed."""
     # print "h =", self.h
     # print "r =", r
     if any(result[i] != hashed[i] for i in range(self.n)):
         print("The signature does not correspond to the hash!")
         return False
     """4. Verifies that the norm is small"""
     norm_sign = sum(sum(elt**2 for elt in part) for part in s)
     # print "signature bound   = ", self.signature_bound
     # print "norm of signature = ", norm_sign
     if norm_sign > self.signature_bound:
         print("The squared norm of the signature is too big:", norm_sign)
         return False
     """5. If the previous steps did not fail, accept."""
     return True
Beispiel #8
0
    def verify(self, message, signature):
        """
        Verify a signature.

        Input:
        self        The private key
        message     The message to sign
        signature   The signature (r, s)

        Output:
        True        If (s * A == H(r||message)) and (s is short)
        False       Otherwise
        """
        A = self.A
        q = self.q
        d = self.d
        m = self.m
        r, t = signature
        s = decompress(t, self.d, self.rate)
        # The message is hashed to a point of Z_q[x] / (x ** d + 1)
        hashed = self.hash_to_point(message, r)
        # One compute result = s * A
        result = [0] * d
        for i in range(m + 1):
            result = add_zq(result, mul_zq(s[i], A[i], q), q)
        # Check that the hashed point == result
        if any(result[i] != hashed[i] for i in range(d)):
            print("The signature does not correspond to the hash!")
            return False
        # Check that the norm is small
        norm_sign = sum(sum(elt**2 for elt in part) for part in s)
        if norm_sign > self.signature_bound:
            print("The squared norm of the signature is too big:", norm_sign)
            return False
        # If the two checks passed, accept
        return True
Beispiel #9
0
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