#ifndef __BGN_PRIVATEKEY_HPP
#define __BGN_PRIVATEKEY_HPP

#include <iostream>
#include <unordered_map>

#include "Scalar.hpp"
#include "Bipoint.hpp"
#include "Quadripoint.hpp"
#include "PublicKey.hpp"
#include "pairing.hpp"

class BGNPrivateKey
{
    public:
        BGNPrivateKey(const BGNPrivateKey& other);
        
        Scalar decrypt(const CurveBipoint& ciphertext);
        Scalar decrypt(const TwistBipoint& ciphertext);
        Scalar decrypt(const Quadripoint & ciphertext);

        friend std::ostream& operator<<(std::ostream& os, const BGNPrivateKey& output);
        friend std::istream& operator>>(std::istream& is, BGNPrivateKey& input);
    
    private:
        BGNPrivateKey();
        friend class BGN;
        void set(const BGNPublicKey& pub_key, const Scalar& a1, const Scalar& b1, const Scalar& c1, const Scalar& d1, const Scalar& a2, const Scalar& b2, const Scalar& c2, const Scalar& d2);

        CurveBipoint pi_1(const CurveBipoint& input) const;
        TwistBipoint pi_2(const TwistBipoint& input) const;
        Quadripoint  pi_T(const Quadripoint & input) const;

        Scalar a1, b1, c1, d1, a2, b2, c2, d2;

        CurveBipoint pi_1_curvegen;
        TwistBipoint pi_2_twistgen;
        Quadripoint  pi_T_pairgen;

        std::unordered_map<CurveBipoint, Scalar, CurveBipointHash> curve_memoizer;
        std::unordered_map<TwistBipoint, Scalar, TwistBipointHash> twist_memoizer;
        std::unordered_map<Quadripoint, Scalar, QuadripointHash> pair_memoizer;
        Scalar curve_max_checked, twist_max_checked, pair_max_checked;
};

#endif