""" Tests pour les primitives cryptographiques. """ import pytest from src.crypto.encryption import ElGamalEncryption, HomomorphicEncryption from src.crypto.signatures import DigitalSignature from src.crypto.zk_proofs import ZKProofProtocol from src.crypto.hashing import SecureHash class TestElGamalEncryption: """Tests du chiffrement ElGamal""" def setup_method(self): self.eg = ElGamalEncryption() def test_keygen(self): """Tester la génération de clés""" pub, priv = self.eg.generate_keypair() assert pub.p == self.eg.p assert pub.g == self.eg.g assert pub.h > 0 assert priv.x > 0 def test_encrypt_decrypt(self): """Tester le chiffrement et déchiffrement""" pub, priv = self.eg.generate_keypair() message = 5 # Chiffrer ciphertext = self.eg.encrypt(pub, message) assert ciphertext.c1 > 0 assert ciphertext.c2 > 0 # Déchiffrer decrypted = self.eg.decrypt(priv, ciphertext, pub.p) assert decrypted == message def test_multiple_encryptions_different(self): """Vérifier que deux chiffrements du même message sont différents""" pub, _ = self.eg.generate_keypair() message = 3 ct1 = self.eg.encrypt(pub, message) ct2 = self.eg.encrypt(pub, message) # Les ciphertexts doivent être différents (probabiliste) assert (ct1.c1, ct1.c2) != (ct2.c1, ct2.c2) def test_homomorphic_addition(self): """Tester l'addition homomorphe ElGamal""" pub, priv = self.eg.generate_keypair() # Votes: 1 pour A, 0 pour B, 1 pour C votes = [1, 0, 1] # Chiffrer les votes encrypted_votes = [self.eg.encrypt(pub, v) for v in votes] # Additionner les votes chiffrés hom = HomomorphicEncryption() total_encrypted = hom.sum_encrypted_votes(encrypted_votes, pub.p) # Déchiffrer le résultat result = self.eg.decrypt(priv, total_encrypted, pub.p) # Devrait égaler la somme des votes assert result == sum(votes) class TestDigitalSignature: """Tests des signatures numériques""" def setup_method(self): self.sig = DigitalSignature(key_size=2048) def test_sign_verify(self): """Tester la signature et vérification""" priv_key, pub_key = self.sig.generate_keypair() message = b"Vote pour Alice" signature = self.sig.sign(priv_key, message) assert self.sig.verify(pub_key, message, signature) def test_signature_tampering_detected(self): """Vérifier que la modification d'un message est détectée""" priv_key, pub_key = self.sig.generate_keypair() message = b"Vote pour Alice" signature = self.sig.sign(priv_key, message) # Modifier le message tampered_message = b"Vote pour Bob" assert not self.sig.verify(pub_key, tampered_message, signature) def test_signature_tampering_signature_detected(self): """Vérifier que la modification d'une signature est détectée""" priv_key, pub_key = self.sig.generate_keypair() message = b"Vote pour Alice" signature = self.sig.sign(priv_key, message) # Modifier la signature tampered_signature = bytes([b ^ 1 for b in signature[:10]]) + signature[10:] assert not self.sig.verify(pub_key, message, tampered_signature) class TestZKProofs: """Tests des preuves de connaissance zéro""" def test_fiat_shamir_proof(self): """Tester le protocole Fiat-Shamir""" p = 23 g = 5 secret = 7 public_key = pow(g, secret, p) message = b"Vote valide" # Générer la preuve proof = ZKProofProtocol.fiat_shamir_proof( secret, public_key, message, p, g ) # Vérifier la preuve valid = ZKProofProtocol.verify_proof( proof.commitment, proof.challenge, proof.response, public_key, p, g ) assert valid def test_proof_with_wrong_secret(self): """Vérifier qu'une preuve échoue avec le mauvais secret""" p = 23 g = 5 secret = 7 public_key = pow(g, secret, p) message = b"Vote valide" # Générer une preuve avec un secret incorrect wrong_secret = 3 proof = ZKProofProtocol.fiat_shamir_proof( wrong_secret, public_key, message, p, g ) # La vérification devrait échouer valid = ZKProofProtocol.verify_proof( proof.commitment, proof.challenge, proof.response, public_key, p, g ) # Vrai ou faux dépend de la probabilité, mais généralement échoue # (test stochastique) class TestSecureHash: """Tests du hachage cryptographique""" def test_sha256_deterministic(self): """Verifier que SHA-256 est deterministe""" data = "Vote electronique".encode('utf-8') hash1 = SecureHash.sha256(data) hash2 = SecureHash.sha256(data) assert hash1 == hash2 assert len(hash1) == 32 # 256 bits = 32 bytes def test_sha256_avalanche(self): """Verifier l'effet d'avalanche""" data1 = b"Vote pour Alice" data2 = b"Vote pour Bob" hash1 = SecureHash.sha256(data1) hash2 = SecureHash.sha256(data2) # Les hashes doivent être très différents differences = sum(bin(a ^ b).count('1') for a, b in zip(hash1, hash2)) assert differences > 100 # Au moins 100 bits différents def test_derive_key(self): """Tester la dérivation de clé PBKDF2""" password = b"my_secure_password" key1, salt1 = SecureHash.derive_key(password) key2, salt2 = SecureHash.derive_key(password) # Les clés doivent être identiques avec le même salt key3, _ = SecureHash.derive_key(password, salt1) assert key1 == key3 # Mais les salts doivent être aléatoires assert salt1 != salt2 def test_hash_bulletin(self): """Tester le hash du bulletin""" hash1 = SecureHash.hash_bulletin(1, 10, 1234567890) hash2 = SecureHash.hash_bulletin(1, 10, 1234567890) hash3 = SecureHash.hash_bulletin(1, 11, 1234567890) assert hash1 == hash2 assert hash1 != hash3