/*
	tripartie Diffie-Hellman
*/
#include <iostream>
#include <fstream>
#include <cybozu/random_generator.hpp>
#include <mcl/bn256.hpp>
#include <cybozu/option.hpp>

static cybozu::RandomGenerator rg;

const std::string skSuf = ".sk.txt";
const std::string pkSuf = ".pk.txt";

using namespace mcl::bn256;

void keygen(const std::string& user)
{
	if (user.empty()) {
		throw cybozu::Exception("keygen:user is empty");
	}
	const char *aa = "12723517038133731887338407189719511622662176727675373276651903807414909099441";
	const char *ab = "4168783608814932154536427934509895782246573715297911553964171371032945126671";
	const char *ba = "13891744915211034074451795021214165905772212241412891944830863846330766296736";
	const char *bb = "7937318970632701341203597196594272556916396164729705624521405069090520231616";


	initPairing();
	G2 Q(Fp2(aa, ab), Fp2(ba, bb));
	G1 P(-1, 1);

	Fr s;
	s.setRand(rg);
	G1::mul(P, P, s);
	G2::mul(Q, Q, s);
	{
		std::string name = user + skSuf;
		std::ofstream ofs(name.c_str(), std::ios::binary);
		ofs << s << std::endl;
	}
	{
		std::string name = user + pkSuf;
		std::ofstream ofs(name.c_str(), std::ios::binary);
		ofs << P << std::endl;
		ofs << Q << std::endl;
	}
}

void load(G1& P, G2& Q, const std::string& fileName)
{
	std::ifstream ifs(fileName.c_str(), std::ios::binary);
	ifs >> P >> Q;
}

void share(const std::string& skFile, const std::string& pk1File, const std::string& pk2File)
{
	initPairing();
	Fr s;
	G1 P1, P2;
	G2 Q1, Q2;
	{
		std::ifstream ifs(skFile.c_str(), std::ios::binary);
		ifs >> s;
	}
	load(P1, Q1, pk1File);
	load(P2, Q2, pk2File);
	Fp12 e;
	pairing(e, P1, Q2);
	{
		// verify(not necessary)
		Fp12 e2;
		pairing(e2, P2, Q1);
		if (e != e2) {
			throw cybozu::Exception("share:bad public key file") << e << e2;
		}
	}
	Fp12::pow(e, e, s);
	std::cout << "share key:\n" << e << std::endl;
}

int main(int argc, char *argv[])
	try
{
	if (argc == 3 && strcmp(argv[1], "keygen") == 0) {
		keygen(argv[2]);
	} else if (argc == 5 && strcmp(argv[1], "share") == 0) {
		share(argv[2], argv[3], argv[4]);
	} else {
		fprintf(stderr, "tri-dh.exe keygen <user name>\n");
		fprintf(stderr, "tri-dh.exe share <secret key file> <public key1 file> <public key2 file>\n");
		return 1;
	}
} catch (std::exception& e) {
	printf("ERR %s\n", e.what());
	return 1;
}