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
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]))
def test_compress(d, q, iterations): """Test compression and decompression.""" sigma = 1.5 * sqrt(q) for i in range(iterations): initial = [[int(round(gauss(0, sigma))) for coef in range(d)]] for rate in range(6, 9): compressed = compress(initial, rate=rate) decompressed = decompress(compressed, degree=d, rate=rate) if decompressed != initial: return False return True
def test_compress(n, iterations): """Test compression and decompression.""" sigma = 1.5 * sqrt(q) for i in range(iterations): initial = [int(round(gauss(0, sigma))) for coef in range(n)] compressed = compress(initial) decompressed = decompress(compressed) # print compressed if decompressed != initial: return False return True
def test_compress(n, iterations): """Test compression and decompression.""" try: sigma = 1.5 * sqrt(q) slen = Params[n]["sig_bytelen"] - SALT_LEN except KeyError: return True for i in range(iterations): while(1): initial = [int(round(gauss(0, sigma))) for coef in range(n)] compressed = compress(initial, slen) if compressed is not False: break decompressed = decompress(compressed, slen, n) if decompressed != initial: return False return True
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