#include <iostream>
#include <time.h>
#include <gmpxx.h>

using namespace std;

unsigned long seed = time(NULL);   //inicializace generatoru nah.cisel

mpz_class prime(unsigned int bits)
{

	gmp_randclass generator(gmp_randinit_default);

	generator.seed(seed);


	mpz_class rand = generator.get_z_bits(bits);
	mpz_nextprime(rand.get_mpz_t(), rand.get_mpz_t());

	return rand;
}


mpz_class GCD(mpz_class a, mpz_class b) {

  mpz_t ans;
  mpz_init (ans);

  mpz_gcd(ans, a.get_mpz_t(), b.get_mpz_t());


  mpz_class ans2;
  ans2 = mpz_class(ans);


  mpz_clear(ans);

  return ans2;
}


int main() {

    cout << "------------------------------------------------------" << endl;
    cout << "KRYPTOGRAFICKY ALGORITMUS RSA   by Jaroslav VALENTA" << endl;
    cout << "------------------------------------------------------" << endl;
    cout << "Zadejte delku klice v bitech" << endl;
    int key;
    cin >> key;
    mpz_class p=prime(key/2);
    seed = time(NULL)+time(NULL);  //inicializace generatoru nah.cisel
    mpz_class q=prime(key/2);
    seed = time(NULL)+time(NULL);  //inicializace generatoru nah.cisel
//vypocet modulu
    mpz_class n=p*q;
//vypocet fii
    mpz_class fii=(p-1)*(q-1);
//vypocet e
    mpz_class e = 65537;
//vypocet d
    mpz_t d;
    mpz_init (d);
    mpz_invert (d, e.get_mpz_t(), fii.get_mpz_t());

    cout << "\n"<<"Prvocisla" << endl;
    cout << "---------" << endl;
    cout << "  p = "<< p<< endl;
    cout << "\n"<<"  q = "<< q<< endl;
    cout << "\n"<<"Verejny klic" << endl;
    cout << "------------" << endl;
    cout << "  n = "<< n<< endl;
    cout << "\n"<<"  e = "<< e<< endl;
    cout << "\n"<<"Soukromy klic" << endl;
    cout << "-------------" << endl;
    cout << "  n = "<< n<< endl;
    cout << "\n"<<"  d = "<< d<< endl;

 //sifrovani
    cout << "\n"<<"Zadejte vstupni data(ciselna)" << endl;
//mpz_class vstup;
    mpz_t vstup;
    mpz_init (vstup);
    cin >> vstup;
    cout << "\n"<<"Zadana vstupni data" << endl;
    cout << "-----------" << endl;
    cout << "  data = "<< vstup<< endl;
    mpz_t crypt;
    mpz_init (crypt);
    mpz_t decrypt;
    mpz_init (decrypt);
// sifrovani crypt = data^e mod n
    mpz_powm(crypt,vstup,e.get_mpz_t(),n.get_mpz_t());
// sifrovani crypt = data^e mod n
    mpz_powm(decrypt,crypt,d,n.get_mpz_t());
    cout << "\n"<<"Zasifrovana data (c = data^e mod n)" << endl;
    cout << "------------------------------------" << endl;
    cout << "  c = "<< crypt<< endl;
    cout << "\n"<<"Desifrovana data (data' = c^d mod n)" << endl;
    cout << "------------------------------------" << endl;
    cout << "  data' = "<< decrypt<< endl;
    mpz_clear(d);
    mpz_clear(crypt);
    mpz_clear(decrypt);
    mpz_clear(vstup);
    cin.get();
    getchar();
return 0;
}
