123 lines
3.0 KiB
Python

"""
Preuves de connaissance zéro (Zero-Knowledge Proofs).
Pour démontrer la validité d'un vote sans révéler le contenu.
"""
from dataclasses import dataclass
import random
from typing import Tuple
@dataclass
class ZKProofChallenge:
"""Défi pour une preuve ZK interactive"""
challenge: int
@dataclass
class ZKProofResponse:
"""Réponse à un défi ZK"""
response: int
@dataclass
class ZKProof:
"""Preuve de connaissance zéro complète"""
commitment: int
challenge: int
response: int
class ZKProofProtocol:
"""
Protocole de Fiat-Shamir pour preuves de connaissance zéro.
Cas d'usage dans le vote:
- Prouver qu'on a déjà voté sans révéler le vote
- Prouver la correctionction d'un bullettin
"""
@staticmethod
def generate_proof(secret: int, p: int, g: int) -> Tuple[int, int]:
"""
Générer un commitment (première étape du protocole).
Args:
secret: Le secret à prouver (ex: clé privée)
p: Module premier
g: Générateur
Returns:
(commitment, random_value)
"""
r = random.randint(2, p - 2)
commitment = pow(g, r, p)
return commitment, r
@staticmethod
def generate_challenge(p: int) -> int:
"""Générer un défi aléatoire"""
return random.randint(1, p - 2)
@staticmethod
def compute_response(
secret: int,
random_value: int,
challenge: int,
p: int
) -> int:
"""
Calculer la réponse au défi (non-interactif).
response = random_value + challenge * secret
"""
return (random_value + challenge * secret) % (p - 1)
@staticmethod
def verify_proof(
commitment: int,
challenge: int,
response: int,
public_key: int,
p: int,
g: int
) -> bool:
"""
Vérifier la preuve.
Vérifie que: g^response = commitment * public_key^challenge (mod p)
"""
left = pow(g, response, p)
right = (commitment * pow(public_key, challenge, p)) % p
return left == right
@staticmethod
def fiat_shamir_proof(
secret: int,
public_key: int,
message: bytes,
p: int,
g: int
) -> ZKProof:
"""
Générer une preuve Fiat-Shamir non-interactive.
"""
# Étape 1: commitment
commitment, r = ZKProofProtocol.generate_proof(secret, p, g)
# Étape 2: challenge généré via hash(commitment || message)
import hashlib
challenge_bytes = hashlib.sha256(
str(commitment).encode() + message
).digest()
challenge = int.from_bytes(challenge_bytes, 'big') % (p - 1)
# Étape 3: réponse
response = ZKProofProtocol.compute_response(
secret, r, challenge, p
)
return ZKProof(
commitment=commitment,
challenge=challenge,
response=response
)