#!/usr/bin/python
# -*- coding: utf-8 -*-

from math import log
from copy import copy
from time import time
from fractions import gcd
from random import SystemRandom
rand = SystemRandom()
import time
from random import randint

def hex2int(hexString):
    return int(''.join(hexString.replace(':', '').split()), 16)


def half_extended_gcd(aa, bb):
    (lastrem, rem) = (abs(aa), abs(bb))
    (x, lastx) = (0, 1)
    while rem:
        (lastrem, (quotient, rem)) = (rem, divmod(lastrem, rem))
        (x, lastx) = (lastx - quotient * x, x)
    return (lastrem, lastx)


def modular_inverse(a, m):
    (g, x) = half_extended_gcd(a, m)
    if g != 1:
        raise ValueError
    return x % m


class ECcurve:

    def __init__(self):
        return

    def field_mul(self, a, b):
        return a * b % self.p

    def field_div(self, num, den):
        inverse_den = modular_inverse(den % self.p, self.p)
        return self.field_mul(num % self.p, inverse_den)

    def field_exp(self, num, power):
        return pow(num % self.p, power, self.p)

    def identity(self):
        return ECpoint(self, self.p, 0)

    def touches(self, Q):
        y2 = self.field_exp(Q.y, 2)
        x3ab = (self.field_mul(Q.x * Q.x % self.p + self.a, Q.x)
                + self.b) % self.p
        return y2 == x3ab

    def tangent(self, Q):
        return self.field_div(Q.x * Q.x * 3 + self.a, Q.y * 2)

    def line_intersect(
        self,
        Q1,
        Q2,
        m,
        ):

        v = (Q1.y + self.p - m * Q1.x % self.p) % self.p
        x = (m * m + self.p - Q1.x + self.p - Q2.x) % self.p
        y = (self.p - m * x % self.p + self.p - v) % self.p
        return ECpoint(self, x, y)

    def double(self, Q):
        if Q.x == self.p:
            return Q
        return self.line_intersect(Q, Q, self.tangent(Q))

    def add(self, Q1, Q2):

        if Q1.x == self.p:
            return Q2
        if Q2.x == self.p:
            return Q1

        if Q1.x == Q2.x:
            if Q1.y == Q2.y:
                return self.double(Q1)
            else:
                return self.identity()

        m = self.field_div(Q1.y + self.p - Q2.y, Q1.x + self.p - Q2.x)
        return self.line_intersect(Q1, Q2, m)

    def mul(self, Q, m):
        R = self.identity()
        while m != 0:
            if m & 1:
                R = self.add(R, Q)
            m = m >> 1
            if m != 0:
                Q = self.double(Q)
        return R


class ECpoint:

    def __init__(
        self,
        curve,
        x,
        y,
        ):

        self.curve = curve
        self.x = x
        self.y = y
        if not x == curve.p and not curve.touches(self):
            print (' ECpoint left curve: ', x, ',', y)

    def add(self, Q2):
        return self.curve.add(self, Q2)

    def mul(self, m):
        return self.curve.mul(self, m)

    def __str__(self):
        if self.x == self.curve.p:
            return 'identity_point'
        else:
            return '(' + str(self.x) + ', ' + str(self.y) + ')'


# definice krivek........

#brainpoolP160r1
brainpoolP160r1=ECcurve()
brainpoolP160r1.p=hex2int("E95E4A5F737059DC60DFC7AD95B3D8139515620F");
brainpoolP160r1.a=hex2int("340E7BE2A280EB74E2BE61BADA745D97E8F7C300");
brainpoolP160r1.b=hex2int("1E589A8595423412134FAA2DBDEC95C8D8675E58");
brainpoolP160r1.n=hex2int("E95E4A5F737059DC60DF5991D45029409E60FC09");

brainpoolP160r1.G=ECpoint(curve=brainpoolP160r1,
        x = hex2int("BED5AF16EA3F6A4F62938C4631EB5AF7BDBCDBC3"),
        y = hex2int("1667CB477A1A8EC338F94741669C976316DA6321")
);

#brainpoolP192r1
brainpoolP192r1=ECcurve()
brainpoolP192r1.p=hex2int("C302F41D932A36CDA7A3463093D18DB78FCE476DE1A86297");
brainpoolP192r1.a=hex2int("6A91174076B1E0E19C39C031FE8685C1CAE040E5C69A28EF");
brainpoolP192r1.b=hex2int("469A28EF7C28CCA3DC721D044F4496BCCA7EF4146FBF25C9");
brainpoolP192r1.n=hex2int("C302F41D932A36CDA7A3462F9E9E916B5BE8F1029AC4ACC1");

brainpoolP192r1.G=ECpoint(curve=brainpoolP192r1,
        x = hex2int("C0A0647EAAB6A48753B033C56CB0F0900A2F5C4853375FD6"),
        y = hex2int("14B690866ABD5BB88B5F4828C1490002E6773FA2FA299B8F")
);

#brainpoolP224r1
brainpoolP224r1=ECcurve()
brainpoolP224r1.p=hex2int("D7C134AA264366862A18302575D1D787B09F075797DA89F57EC8C0FF");
brainpoolP224r1.a=hex2int("68A5E62CA9CE6C1C299803A6C1530B514E182AD8B0042A59CAD29F43");
brainpoolP224r1.b=hex2int("2580F63CCFE44138870713B1A92369E33E2135D266DBB372386C400B");
brainpoolP224r1.n=hex2int("D7C134AA264366862A18302575D0FB98D116BC4B6DDEBCA3A5A7939F");

brainpoolP224r1.G=ECpoint(curve=brainpoolP224r1,
        x = hex2int("0D9029AD2C7E5CF4340823B2A87DC68C9E4CE3174C1E6EFDEE12C07D"),
        y = hex2int("58AA56F772C0726F24C6B89E4ECDAC24354B9E99CAA3F6D3761402CD")
);

#brainpoolP256r1
brainpoolP256r1=ECcurve()
brainpoolP256r1.p=hex2int("A9FB57DBA1EEA9BC3E660A909D838D726E3BF623D52620282013481D1F6E5377");
brainpoolP256r1.a=hex2int("7D5A0975FC2C3057EEF67530417AFFE7FB8055C126DC5C6CE94A4B44F330B5D9");
brainpoolP256r1.b=hex2int("26DC5C6CE94A4B44F330B5D9BBD77CBF958416295CF7E1CE6BCCDC18FF8C07B6");
brainpoolP256r1.n=hex2int("A9FB57DBA1EEA9BC3E660A909D838D718C397AA3B561A6F7901E0E82974856A7");

brainpoolP256r1.G=ECpoint(curve=brainpoolP256r1,
        x = hex2int("8BD2AEB9CB7E57CB2C4B482FFC81B7AFB9DE27E1E3BD23C23A4453BD9ACE3262"),
        y = hex2int("547EF835C3DAC4FD97F8461A14611DC9C27745132DED8E545C1D54C72F046997")
);

#brainpoolP320r1
brainpoolP320r1=ECcurve()
brainpoolP320r1.p=hex2int("D35E472036BC4FB7E13C785ED201E065F98FCFA6F6F40DEF4F92B9EC7893EC28FCD412B1F1B32E27");
brainpoolP320r1.a=hex2int("3EE30B568FBAB0F883CCEBD46D3F3BB8A2A73513F5EB79DA66190EB085FFA9F492F375A97D860EB4");
brainpoolP320r1.b=hex2int("520883949DFDBC42D3AD198640688A6FE13F41349554B49ACC31DCCD884539816F5EB4AC8FB1F1A6");
brainpoolP320r1.n=hex2int("D35E472036BC4FB7E13C785ED201E065F98FCFA5B68F12A32D482EC7EE8658E98691555B44C59311");

brainpoolP320r1.G=ECpoint(curve=brainpoolP320r1,
        x = hex2int("43BD7E9AFB53D8B85289BCC48EE5BFE6F20137D10A087EB6E7871E2A10A599C710AF8D0D39E20611"),
        y = hex2int("14FDD05545EC1CC8AB4093247F77275E0743FFED117182EAA9C77877AAAC6AC7D35245D1692E8EE1")
);

#brainpoolP384r1
brainpoolP384r1=ECcurve()
brainpoolP384r1.p=hex2int("8CB91E82A3386D280F5D6F7E50E641DF152F7109ED5456B412B1DA197FB71123ACD3A729901D1A71874700133107EC53");
brainpoolP384r1.a=hex2int("7BC382C63D8C150C3C72080ACE05AFA0C2BEA28E4FB22787139165EFBA91F90F8AA5814A503AD4EB04A8C7DD22CE2826");
brainpoolP384r1.b=hex2int("04A8C7DD22CE28268B39B55416F0447C2FB77DE107DCD2A62E880EA53EEB62D57CB4390295DBC9943AB78696FA504C11");
brainpoolP384r1.n=hex2int("8CB91E82A3386D280F5D6F7E50E641DF152F7109ED5456B31F166E6CAC0425A7CF3AB6AF6B7FC3103B883202E9046565");

brainpoolP384r1.G=ECpoint(curve=brainpoolP384r1,
        x = hex2int("1D1C64F068CF45FFA2A63A81B7C13F6B8847A3E77EF14FE3DB7FCAFE0CBD10E8E826E03436D646AAEF87B2E247D4AF1E"),
        y = hex2int("8ABE1D7520F9C2A45CB1EB8E95CFD55262B70B29FEEC5864E19C054FF99129280E4646217791811142820341263C5315")
);

#brainpoolP512r1
brainpoolP512r1=ECcurve()
brainpoolP512r1.p=hex2int("AADD9DB8DBE9C48B3FD4E6AE33C9FC07CB308DB3B3C9D20ED6639CCA703308717D4D9B009BC66842AECDA12AE6A380E62881FF2F2D82C68528AA6056583A48F3");
brainpoolP512r1.a=hex2int("7830A3318B603B89E2327145AC234CC594CBDD8D3DF91610A83441CAEA9863BC2DED5D5AA8253AA10A2EF1C98B9AC8B57F1117A72BF2C7B9E7C1AC4D77FC94CA");
brainpoolP512r1.b=hex2int("3DF91610A83441CAEA9863BC2DED5D5AA8253AA10A2EF1C98B9AC8B57F1117A72BF2C7B9E7C1AC4D77FC94CADC083E67984050B75EBAE5DD2809BD638016F723");
brainpoolP512r1.n=hex2int("AADD9DB8DBE9C48B3FD4E6AE33C9FC07CB308DB3B3C9D20ED6639CCA70330870553E5C414CA92619418661197FAC10471DB1D381085DDADDB58796829CA90069");

brainpoolP512r1.G=ECpoint(curve=brainpoolP512r1,
        x = hex2int("81AEE4BDD82ED9645A21322E9C4C6A9385ED9F70B5D916C1B43B62EEF4D0098EFF3B1F78E2D0D48D50D1687B93B97D5F7C6D5047406A5E688B352209BCB9F822"),
        y = hex2int("7DDE385D566332ECC0EABFA9CF7822FDF209F70024A57B1AA000C55B881F8111B2DCDE494A5F485E5BCA4BD88A2763AED1CA2B2FA8F0540678CD1E0F3AD80892")
);

#vypocet pro krivku brainpoolP160r1
curve=brainpoolP160r1

start = time.time()

for i in range(1, 1001):
    A = rand.getrandbits(randint(1, 160)) % curve.p
    B = curve.mul(curve.G, A)

end = time.time()

#zobraz nazev krivky a vysledny cas alias celkovy cas / 1000 * 1000 [ms]

print ('brainpoolP160r1;', end - start)

#vypocet pro krivku brainpoolP192r1
curve=brainpoolP192r1

start = time.time()

for i in range(1, 1001):
    A = rand.getrandbits(randint(1, 192)) % curve.p
    B = curve.mul(curve.G, A)

end = time.time()

#zobraz nazev krivky a vysledny cas alias celkovy cas / 1000 * 1000 [ms]

print ('brainpoolP192r1;', end - start)

#vypocet pro krivku brainpoolP224r1
curve=brainpoolP224r1

start = time.time()

for i in range(1, 1001):
    A = rand.getrandbits(randint(1, 224)) % curve.p
    B = curve.mul(curve.G, A)

end = time.time()

#zobraz nazev krivky a vysledny cas alias celkovy cas / 1000 * 1000 [ms]

print ('brainpoolP224r1;', end - start)

#vypocet pro krivku brainpoolP256r1
curve=brainpoolP256r1

start = time.time()

for i in range(1, 1001):
    A = rand.getrandbits(randint(1, 256)) % curve.p
    B = curve.mul(curve.G, A)

end = time.time()

#zobraz nazev krivky a vysledny cas alias celkovy cas / 1000 * 1000 [ms]

print ('brainpoolP256r1;', end - start)

#vypocet pro krivku brainpoolP320r1
curve=brainpoolP320r1

start = time.time()

for i in range(1, 1001):
    A = rand.getrandbits(randint(1, 320)) % curve.p
    B = curve.mul(curve.G, A)

end = time.time()

#zobraz nazev krivky a vysledny cas alias celkovy cas / 1000 * 1000 [ms]

print ('brainpoolP320r1;', end - start)

#vypocet pro krivku brainpoolP384r1
curve=brainpoolP384r1

start = time.time()

for i in range(1, 1001):
    A = rand.getrandbits(randint(1, 384)) % curve.p
    B = curve.mul(curve.G, A)

end = time.time()

#zobraz nazev krivky a vysledny cas alias celkovy cas / 1000 * 1000 [ms]

print ('brainpoolP384r1;', end - start)

#vypocet pro krivku brainpoolP512r1
curve=brainpoolP512r1

start = time.time()

for i in range(1, 1001):
    A = rand.getrandbits(randint(1, 512)) % curve.p
    B = curve.mul(curve.G, A)

end = time.time()

#zobraz nazev krivky a vysledny cas alias celkovy cas / 1000 * 1000 [ms]

print ('brainpoolP512r1;', end - start)

