def sign(self, message, salt=None, verbose=False): """ Sign a message. Needs hash randomization to be secure. Input: self The private key message The message to sign salt The hashing salt (optional) verbose If this flag is set, the algorithm notifies each time it restarts Output: r, s A signature of the message: - s * A = H(r||message) - s is short """ # If no salt is provided, one is generated randomly if salt is None: salt = randint(0, (1 << 320) - 1) # The message is hashed into a point of Z_q[x] / (x ** d + 1) r = "" for i in range(320 // 8): r += chr((salt >> (8 * i)) & 0xff) hashed = self.hash_to_point(message, r) # A short pre-image of this point is determined while (1): s = self.sample_preimage_fft(hashed) # The norm of the signature is checked norm_sign = sum(sum(elt**2 for elt in part) for part in s) if norm_sign < self.signature_bound: return r, compress(s, rate=self.rate) elif verbose is True: print("redo")
def sign(self, message, randombytes=urandom): """ Sign a message. The message MUST be a byte string or byte array. Optionally, one can select the source of (pseudo-)randomness used (default: urandom). """ int_header = 0x30 + logn[self.n] header = int_header.to_bytes(1, "little") salt = randombytes(SALT_LEN) hashed = self.hash_to_point(message, salt) # We repeat the signing procedure until we find a signature that is # short enough (both the Euclidean norm and the bytelength) while (1): if (randombytes == urandom): s = self.sample_preimage(hashed) else: seed = randombytes(SEED_LEN) s = self.sample_preimage(hashed, seed=seed) norm_sign = sum(coef**2 for coef in s[0]) norm_sign += sum(coef**2 for coef in s[1]) # Check the Euclidean norm if norm_sign <= self.signature_bound: enc_s = compress(s[1], self.sig_bytelen - HEAD_LEN - SALT_LEN) # Check that the encoding is valid (sometimes it fails) if (enc_s is not False): return header + salt + enc_s
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 sign(self, message): """ Sign a message. The message MUST be a byte string or byte array. """ salt = randombytes(SALT_LEN) hashed = self.hash_to_point(message, salt) # We repeat the signing procedure until we find a signature that is # short enough (both the Euclidean norm and the bytelength) while (1): s = self.sample_preimage(hashed) norm_sign = sum(coef**2 for coef in s[0]) norm_sign += sum(coef**2 for coef in s[1]) # Check the Euclidean norm if norm_sign < self.signature_bound: enc_s = compress(s[1], self.sig_bytelen - SALT_LEN) # Check that the encoding is valid (sometimes it fails) if (enc_s is not False): return salt + enc_s