from sage.crypto.block_cipher.sdes import SimplifiedDES
from tqdm.auto import tqdm # il s'agit d'un module très utile pour afficher une barre de progression

F2 = GF(2)
bin = BinaryStrings()


# Dictionnaire de conversion sûr : '0'/'1' (StringMonoidElement) -> GF(2)
# Évite : TypeError: int() argument must be ... not 'StringMonoidElement'
bin_to_GF2 = {bin("0"): F2(0), bin("1"): F2(1)}


class doubleSdes(SimplifiedDES):
    """
    Double S-DES avec deux clés indépendantes K1 et K2.

    Définition :
        C = E_{K2}( E_{K1}(P) )
    """
    def encrypt(self, P, K1, K2):
        return super().encrypt(super().encrypt(P, K1), K2)

    def decrypt(self, C, K1, K2):
        return super().decrypt(super().decrypt(C, K2), K1)

    def random_key(self):
        return super().random_key(), super().random_key()



class tripleSdes(SimplifiedDES):
   """
    Triple S-DES avec trois clés indépendantes K1, K2, K3.

    Définition :
        C = E_{K3}( D_{K2}( E_{K1}(P) ) )

    C’est l’analogue jouet de 3DES (EDE).
    """

   def encrypt(self, P, K1, K2, K3):
       return super().encrypt(super().decrypt(super().encrypt(P, K1), K2), K3)

   def decrypt(self, C, K1, K2, K3):
       return super().decrypt(super().encrypt(super().decrypt(C, K3), K2), K1)

   def random_key(self):
       return super().random_key(), super().random_key(), super().random_key()


tSdes = tripleSdes()


# ---------------------------------------------------------------------------
# Génération de trois clés aléatoires, puis conversion explicite vers GF(2).
# - random_key() renvoie des listes de '0'/'1' (StringMonoidElement)
# - on applique bin_to_GF2 pour obtenir des éléments de GF(2)
# ---------------------------------------------------------------------------

K1, K2, K3 = tSdes.random_key()
K1 = [bin_to_GF2[bin(str(k1))] for k1 in K1]
K2 = [bin_to_GF2[bin(str(k2))] for k2 in K2]
K3 = [bin_to_GF2[bin(str(k3))] for k3 in K3]


NombrePaires = 10

P = [[bin(str(randint(0, 1))) for _ in range(8)] for _ in range(NombrePaires)]
C = list(map(lambda x: tSdes.encrypt(x, K1, K2, K3), P))
PC = list(zip(P, C))


# ---------------------------------------------------------------------------
# Vérifications rapides
# ---------------------------------------------------------------------------
# # 1) Déchiffrer la première paire : doit rendre le clair original
# assert tSdes.decrypt(C[0], K1, K2, K3) == P[0]
#
# # 2) Visualiser un exemple de formats (pour l’explication des types)
# print("Exemple P[0] (8 bits GF(2)) :", P[0])
# print("Exemple C[0] (8 bits GF(2)) :", C[0])
# print("Clés (10 bits GF(2))        :", K1, K2, K3)
#
