#!/usr/bin/env python3
from Cryptotools.Groups.cyclic import Cyclic
from Cryptotools.Numbers.primeNumber import getPrimeNumber
from random import randint, choice
from math import log, log10

"""
    Here, we will try to understand why we need to have a generator when we encrypt data for Diffie-Hellman
    https://crypto.stackexchange.com/questions/25489/why-does-diffie-hellman-need-be-a-cyclic-group
"""
def operation(a, b, n):
    return (a ** b) % n

def getGenerator(gr, p):
    index = 1
    for g in range(2, p):
        z = list()
        for entry in range(1, p):
            res = operation(g, index, p)
            #if res not in z:
            z.append(res)
            index = index + 1
        print(f"{g}: {sorted(z)}")

def getGenerator2(gr, p, g):
    index = 1
    z = list()
    for entry in range(1, p):
        res = operation(g, index, p)
        if res not in z:
            z.append(res)
            index = index + 1
    return z
    

def computePublicKey(key, p, g):
    return (g ** key) % p

def computeEphemeralKey(public, secret, p):
    return (public ** secret) % p

gr = list()
# Public value
p = 43
g = 0
for i in range(1, p):
    gr.append(i)

print(f"p = {p}")
print(f"G = {gr}")
# We try with a generator which is not in list
cyclic = Cyclic(gr, p, operation)
generators = cyclic.getGenerators()
print(f"All generators: {generators}")

g = 3 # In the group
print(f"g = {g}")

# We can compute with the secret key
secretKeyA = 5
secretKeyB = 10
publicKeyA = computePublicKey(secretKeyA, p, g)
publicKeyB = computePublicKey(secretKeyB, p, g)
print(f"Public key A: {publicKeyA}")
print(f"Public key B: {publicKeyB}\n")

# Here, g is in the generator, we need to compute all values until that match with publicKeyA
for a in range(1, p):
    res = operation(g, a, p)
    if res == publicKeyA:
        print(f"Brute forced secret key of A: {a}")

for a in range(1, p):
    res = operation(g, a, p)
    if res == publicKeyB:
        print(f"Brute forced secret key of B: {a}")

print()

#for a in generators:
#    print(a)
#
#print()

# Here, we generate all key withthe same generator
keys = list()
for a in range(1, p):
    keys.append(operation(g, a, p))

print((keys))
print(sorted(keys))

print()

print(f"Keys with g = 4: {sorted(getGenerator2(gr, p, 4))}")

# Do the same, but g is not a generator
g = 4 # Not in the generator group
publicKeyA = computePublicKey(secretKeyA, p, g)
publicKeyB = computePublicKey(secretKeyB, p, g)
print(f"Public key A: {publicKeyA}")
print(f"Public key B: {publicKeyB}")

keys = list()
for a in range(1, p):
    keys.append(operation(g, a, p))
print(keys)

# Eve sniff the traffic and knows p, g and publicKeyA and B
# Eve, knows p and g, because it's public
# Eve need to guess the secretKey of A.
# For doing that, we iterate all posibility until that match with the publicKeyA

#for a in range(1, 4):
#    res = operation(g, a, p)
#    print(res)
