github.com/platonnetwork/platon-go@v0.7.6/cases/tool/win/bls_win/include/mcl/she.hpp (about)

     1  #pragma once
     2  /**
     3  	@file
     4  	@brief somewhat homomorphic encryption with one-time multiplication, based on prime-order pairings
     5  	@author MITSUNARI Shigeo(@herumi)
     6  	see https://github.com/herumi/mcl/blob/master/misc/she/she.pdf
     7  	@license modified new BSD license
     8  	http://opensource.org/licenses/BSD-3-Clause
     9  */
    10  #include <cmath>
    11  #include <vector>
    12  #include <iosfwd>
    13  #ifndef MCLBN_FP_UNIT_SIZE
    14  	#define MCLBN_FP_UNIT_SIZE 4
    15  #endif
    16  #if MCLBN_FP_UNIT_SIZE == 4
    17  #include <mcl/bn256.hpp>
    18  #elif MCLBN_FP_UNIT_SIZE == 6
    19  #include <mcl/bn384.hpp>
    20  #elif MCLBN_FP_UNIT_SIZE == 8
    21  #include <mcl/bn512.hpp>
    22  #else
    23  	#error "MCLBN_FP_UNIT_SIZE must be 4, 6, or 8"
    24  #endif
    25  
    26  #include <mcl/window_method.hpp>
    27  #include <cybozu/endian.hpp>
    28  #include <cybozu/serializer.hpp>
    29  
    30  namespace mcl { namespace she {
    31  
    32  using namespace mcl::bn;
    33  
    34  namespace local {
    35  
    36  #ifndef MCLSHE_WIN_SIZE
    37  	#define MCLSHE_WIN_SIZE 10
    38  #endif
    39  static const size_t winSize = MCLSHE_WIN_SIZE;
    40  static const size_t defaultTryNum = 2048;
    41  
    42  struct KeyCount {
    43  	uint32_t key;
    44  	int32_t count; // power
    45  	bool operator<(const KeyCount& rhs) const
    46  	{
    47  		return key < rhs.key;
    48  	}
    49  	bool isSame(const KeyCount& rhs) const
    50  	{
    51  		return key == rhs.key && count == rhs.count;
    52  	}
    53  };
    54  
    55  template<class G, bool = true>
    56  struct InterfaceForHashTable : G {
    57  	static G& castG(InterfaceForHashTable& x) { return static_cast<G&>(x); }
    58  	static const G& castG(const InterfaceForHashTable& x) { return static_cast<const G&>(x); }
    59  	void clear() { clear(castG(*this)); }
    60  	void normalize() { normalize(castG(*this)); }
    61  	static bool isOdd(const G& P) { return P.y.isOdd(); }
    62  	static bool isZero(const G& P) { return P.isZero(); }
    63  	static bool isSameX(const G& P, const G& Q) { return P.x == Q.x; }
    64  	static uint32_t getHash(const G& P) { return uint32_t(*P.x.getUnit()); }
    65  	static void clear(G& P) { P.clear(); }
    66  	static void normalize(G& P) { P.normalize(); }
    67  	static void dbl(G& Q, const G& P) { G::dbl(Q, P); }
    68  	static void neg(G& Q, const G& P) { G::neg(Q, P); }
    69  	static void add(G& R, const G& P, const G& Q) { G::add(R, P, Q); }
    70  	template<class INT>
    71  	static void mul(G& Q, const G& P, const INT& x) { G::mul(Q, P, x); }
    72  };
    73  
    74  /*
    75  	treat Fp12 as EC
    76  	unitary inverse of (a, b) = (a, -b)
    77  	then b.a.a or -b.a.a is odd
    78  */
    79  template<class G>
    80  struct InterfaceForHashTable<G, false> : G {
    81  	static G& castG(InterfaceForHashTable& x) { return static_cast<G&>(x); }
    82  	static const G& castG(const InterfaceForHashTable& x) { return static_cast<const G&>(x); }
    83  	void clear() { clear(castG(*this)); }
    84  	void normalize() { normalize(castG(*this)); }
    85  	static bool isOdd(const G& x) { return x.b.a.a.isOdd(); }
    86  	static bool isZero(const G& x) { return x.isOne(); }
    87  	static bool isSameX(const G& x, const G& Q) { return x.a == Q.a; }
    88  	static uint32_t getHash(const G& x) { return uint32_t(*x.getFp0()->getUnit()); }
    89  	static void clear(G& x) { x = 1; }
    90  	static void normalize(G&) { }
    91  	static void dbl(G& y, const G& x) { G::sqr(y, x); }
    92  	static void neg(G& Q, const G& P) { G::unitaryInv(Q, P); }
    93  	static void add(G& z, const G& x, const G& y) { G::mul(z, x, y); }
    94  	template<class INT>
    95  	static void mul(G& z, const G& x, const INT& y) { G::pow(z, x, y); }
    96  };
    97  
    98  template<class G>
    99  char GtoChar();
   100  template<>char GtoChar<bn::G1>() { return '1'; }
   101  template<>char GtoChar<bn::G2>() { return '2'; }
   102  template<>char GtoChar<bn::GT>() { return 'T'; }
   103  
   104  /*
   105  	HashTable<EC, true> or HashTable<Fp12, false>
   106  */
   107  template<class G, bool isEC = true>
   108  class HashTable {
   109  	typedef InterfaceForHashTable<G, isEC> I;
   110  	typedef std::vector<KeyCount> KeyCountVec;
   111  	KeyCountVec kcv_;
   112  	G P_;
   113  	mcl::fp::WindowMethod<I> wm_;
   114  	G nextP_;
   115  	G nextNegP_;
   116  	size_t tryNum_;
   117  	void setWindowMethod()
   118  	{
   119  		const size_t bitSize = G::BaseFp::BaseFp::getBitSize();
   120  		wm_.init(static_cast<const I&>(P_), bitSize, local::winSize);
   121  	}
   122  public:
   123  	HashTable() : tryNum_(local::defaultTryNum) {}
   124  	bool operator==(const HashTable& rhs) const
   125  	{
   126  		if (kcv_.size() != rhs.kcv_.size()) return false;
   127  		for (size_t i = 0; i < kcv_.size(); i++) {
   128  			if (!kcv_[i].isSame(rhs.kcv_[i])) return false;
   129  		}
   130  		return P_ == rhs.P_ && nextP_ == rhs.nextP_;
   131  	}
   132  	bool operator!=(const HashTable& rhs) const { return !operator==(rhs); }
   133  	/*
   134  		compute log_P(xP) for |x| <= hashSize * tryNum
   135  	*/
   136  	void init(const G& P, size_t hashSize, size_t tryNum = local::defaultTryNum)
   137  	{
   138  		if (hashSize == 0) {
   139  			kcv_.clear();
   140  			return;
   141  		}
   142  		if (hashSize >= 0x80000000u) throw cybozu::Exception("HashTable:init:hashSize is too large");
   143  		P_ = P;
   144  		tryNum_ = tryNum;
   145  		kcv_.resize(hashSize);
   146  		G xP;
   147  		I::clear(xP);
   148  		for (int i = 1; i <= (int)kcv_.size(); i++) {
   149  			I::add(xP, xP, P_);
   150  			I::normalize(xP);
   151  			kcv_[i - 1].key = I::getHash(xP);
   152  			kcv_[i - 1].count = I::isOdd(xP) ? i : -i;
   153  		}
   154  		nextP_ = xP;
   155  		I::dbl(nextP_, nextP_);
   156  		I::add(nextP_, nextP_, P_); // nextP = (hasSize * 2 + 1)P
   157  		I::neg(nextNegP_, nextP_); // nextNegP = -nextP
   158  		/*
   159  			ascending order of abs(count) for same key
   160  		*/
   161  		std::stable_sort(kcv_.begin(), kcv_.end());
   162  		setWindowMethod();
   163  	}
   164  	void setTryNum(size_t tryNum)
   165  	{
   166  		this->tryNum_ = tryNum;
   167  	}
   168  	/*
   169  		log_P(xP)
   170  		find range which has same hash of xP in kcv_,
   171  		and detect it
   172  	*/
   173  	int basicLog(G xP, bool *pok = 0) const
   174  	{
   175  		if (pok) *pok = true;
   176  		if (I::isZero(xP)) return 0;
   177  		typedef KeyCountVec::const_iterator Iter;
   178  		KeyCount kc;
   179  		I::normalize(xP);
   180  		kc.key = I::getHash(xP);
   181  		kc.count = 0;
   182  		std::pair<Iter, Iter> p = std::equal_range(kcv_.begin(), kcv_.end(), kc);
   183  		G Q;
   184  		I::clear(Q);
   185  		int prev = 0;
   186  		/*
   187  			check range which has same hash
   188  		*/
   189  		while (p.first != p.second) {
   190  			int count = p.first->count;
   191  			int abs_c = std::abs(count);
   192  			assert(abs_c >= prev); // assume ascending order
   193  			bool neg = count < 0;
   194  			G T;
   195  //			I::mul(T, P, abs_c - prev);
   196  			mulByWindowMethod(T, abs_c - prev);
   197  			I::add(Q, Q, T);
   198  			I::normalize(Q);
   199  			if (I::isSameX(Q, xP)) {
   200  				bool QisOdd = I::isOdd(Q);
   201  				bool xPisOdd = I::isOdd(xP);
   202  				if (QisOdd ^ xPisOdd ^ neg) return -count;
   203  				return count;
   204  			}
   205  			prev = abs_c;
   206  			++p.first;
   207  		}
   208  		if (pok) {
   209  			*pok = false;
   210  			return 0;
   211  		}
   212  		throw cybozu::Exception("HashTable:basicLog:not found");
   213  	}
   214  	/*
   215  		compute log_P(xP)
   216  		call basicLog at most 2 * tryNum
   217  	*/
   218  	int64_t log(const G& xP, bool *pok = 0) const
   219  	{
   220  		bool ok;
   221  		int c = basicLog(xP, &ok);
   222  		if (ok) {
   223  			if (pok) *pok = true;
   224  			return c;
   225  		}
   226  		G posP = xP, negP = xP;
   227  		int64_t posCenter = 0;
   228  		int64_t negCenter = 0;
   229  		int64_t next = (int64_t)kcv_.size() * 2 + 1;
   230  		for (size_t i = 1; i < tryNum_; i++) {
   231  			I::add(posP, posP, nextNegP_);
   232  			posCenter += next;
   233  			c = basicLog(posP, &ok);
   234  			if (ok) {
   235  				if (pok) *pok = true;
   236  				return posCenter + c;
   237  			}
   238  			I::add(negP, negP, nextP_);
   239  			negCenter -= next;
   240  			c = basicLog(negP, &ok);
   241  			if (ok) {
   242  				if (pok) *pok = true;
   243  				return negCenter + c;
   244  			}
   245  		}
   246  		if (pok) {
   247  			*pok = false;
   248  			return 0;
   249  		}
   250  		throw cybozu::Exception("HashTable:log:not found");
   251  	}
   252  	/*
   253  		remark
   254  		tryNum is not saved.
   255  	*/
   256  	template<class OutputStream>
   257  	void save(OutputStream& os) const
   258  	{
   259  		cybozu::save(os, BN::param.cp.curveType);
   260  		cybozu::writeChar(os, GtoChar<G>());
   261  		cybozu::save(os, kcv_.size());
   262  		cybozu::write(os, &kcv_[0], sizeof(kcv_[0]) * kcv_.size());
   263  		P_.save(os);
   264  	}
   265  	size_t save(void *buf, size_t maxBufSize) const
   266  	{
   267  		cybozu::MemoryOutputStream os(buf, maxBufSize);
   268  		save(os);
   269  		return os.getPos();
   270  	}
   271  	/*
   272  		remark
   273  		tryNum is not set
   274  	*/
   275  	template<class InputStream>
   276  	void load(InputStream& is)
   277  	{
   278  		int curveType;
   279  		cybozu::load(curveType, is);
   280  		if (curveType != BN::param.cp.curveType) throw cybozu::Exception("HashTable:bad curveType") << curveType;
   281  		char c = 0;
   282  		if (!cybozu::readChar(&c, is) || c != GtoChar<G>()) throw cybozu::Exception("HashTable:bad c") << (int)c;
   283  		size_t kcvSize;
   284  		cybozu::load(kcvSize, is);
   285  		kcv_.resize(kcvSize);
   286  		cybozu::read(&kcv_[0], sizeof(kcv_[0]) * kcvSize, is);
   287  		P_.load(is);
   288  		I::mul(nextP_, P_, (kcvSize * 2) + 1);
   289  		I::neg(nextNegP_, nextP_);
   290  		setWindowMethod();
   291  	}
   292  	size_t load(const void *buf, size_t bufSize)
   293  	{
   294  		cybozu::MemoryInputStream is(buf, bufSize);
   295  		load(is);
   296  		return is.getPos();
   297  	}
   298  	const mcl::fp::WindowMethod<I>& getWM() const { return wm_; }
   299  	/*
   300  		mul(x, P, y);
   301  	*/
   302  	template<class T>
   303  	void mulByWindowMethod(G& x, const T& y) const
   304  	{
   305  		wm_.mul(static_cast<I&>(x), y);
   306  	}
   307  };
   308  
   309  template<class G>
   310  int log(const G& P, const G& xP)
   311  {
   312  	if (xP.isZero()) return 0;
   313  	if (xP == P) return 1;
   314  	G negT;
   315  	G::neg(negT, P);
   316  	if (xP == negT) return -1;
   317  	G T = P;
   318  	for (int i = 2; i < 100; i++) {
   319  		T += P;
   320  		if (xP == T) return i;
   321  		G::neg(negT, T);
   322  		if (xP == negT) return -i;
   323  	}
   324  	throw cybozu::Exception("she:log:not found");
   325  }
   326  
   327  } // mcl::she::local
   328  
   329  template<size_t dummyInpl = 0>
   330  struct SHET {
   331  	class SecretKey;
   332  	class PublicKey;
   333  	class PrecomputedPublicKey;
   334  	// additive HE
   335  	class CipherTextA; // = CipherTextG1 + CipherTextG2
   336  	class CipherTextGT; // multiplicative HE
   337  	class CipherText; // CipherTextA + CipherTextGT
   338  
   339  	static G1 P_;
   340  	static G2 Q_;
   341  	static GT ePQ_; // e(P, Q)
   342  	static std::vector<Fp6> Qcoeff_;
   343  	static local::HashTable<G1> PhashTbl_;
   344  	static local::HashTable<G2> QhashTbl_;
   345  	static mcl::fp::WindowMethod<G2> Qwm_;
   346  	typedef local::InterfaceForHashTable<GT, false> GTasEC;
   347  	static local::HashTable<GT, false> ePQhashTbl_;
   348  	static bool useDecG1ViaGT_;
   349  	static bool useDecG2ViaGT_;
   350  	static bool isG1only_;
   351  private:
   352  	template<class G>
   353  	class CipherTextAT : public fp::Serializable<CipherTextAT<G> > {
   354  		G S_, T_;
   355  		friend class SecretKey;
   356  		friend class PublicKey;
   357  		friend class PrecomputedPublicKey;
   358  		friend class CipherTextA;
   359  		friend class CipherTextGT;
   360  		bool isZero(const Fr& x) const
   361  		{
   362  			G xT;
   363  			G::mul(xT, T_, x);
   364  			return S_ == xT;
   365  		}
   366  	public:
   367  		const G& getS() const { return S_; }
   368  		const G& getT() const { return T_; }
   369  		void clear()
   370  		{
   371  			S_.clear();
   372  			T_.clear();
   373  		}
   374  		static void add(CipherTextAT& z, const CipherTextAT& x, const CipherTextAT& y)
   375  		{
   376  			/*
   377  				(S, T) + (S', T') = (S + S', T + T')
   378  			*/
   379  			G::add(z.S_, x.S_, y.S_);
   380  			G::add(z.T_, x.T_, y.T_);
   381  		}
   382  		static void sub(CipherTextAT& z, const CipherTextAT& x, const CipherTextAT& y)
   383  		{
   384  			/*
   385  				(S, T) - (S', T') = (S - S', T - T')
   386  			*/
   387  			G::sub(z.S_, x.S_, y.S_);
   388  			G::sub(z.T_, x.T_, y.T_);
   389  		}
   390  		// INT = int64_t or Fr
   391  		template<class INT>
   392  		static void mul(CipherTextAT& z, const CipherTextAT& x, const INT& y)
   393  		{
   394  			G::mul(z.S_, x.S_, y);
   395  			G::mul(z.T_, x.T_, y);
   396  		}
   397  		static void neg(CipherTextAT& y, const CipherTextAT& x)
   398  		{
   399  			G::neg(y.S_, x.S_);
   400  			G::neg(y.T_, x.T_);
   401  		}
   402  		void add(const CipherTextAT& c) { add(*this, *this, c); }
   403  		void sub(const CipherTextAT& c) { sub(*this, *this, c); }
   404  		template<class InputStream>
   405  		void load(bool *pb, InputStream& is, int ioMode = IoSerialize)
   406  		{
   407  			S_.load(pb, is, ioMode); if (!*pb) return;
   408  			T_.load(pb, is, ioMode);
   409  		}
   410  		template<class OutputStream>
   411  		void save(bool *pb, OutputStream& os, int ioMode = IoSerialize) const
   412  		{
   413  			const char sep = *fp::getIoSeparator(ioMode);
   414  			S_.save(pb, os, ioMode); if (!*pb) return;
   415  			if (sep) {
   416  				cybozu::writeChar(pb, os, sep);
   417  				if (!*pb) return;
   418  			}
   419  			T_.save(pb, os, ioMode);
   420  		}
   421  		template<class InputStream>
   422  		void load(InputStream& is, int ioMode = IoSerialize)
   423  		{
   424  			bool b;
   425  			load(&b, is, ioMode);
   426  			if (!b) throw cybozu::Exception("she:CipherTextA:load");
   427  		}
   428  		template<class OutputStream>
   429  		void save(OutputStream& os, int ioMode = IoSerialize) const
   430  		{
   431  			bool b;
   432  			save(&b, os, ioMode);
   433  			if (!b) throw cybozu::Exception("she:CipherTextA:save");
   434  		}
   435  		friend std::istream& operator>>(std::istream& is, CipherTextAT& self)
   436  		{
   437  			self.load(is, fp::detectIoMode(G::getIoMode(), is));
   438  			return is;
   439  		}
   440  		friend std::ostream& operator<<(std::ostream& os, const CipherTextAT& self)
   441  		{
   442  			self.save(os, fp::detectIoMode(G::getIoMode(), os));
   443  			return os;
   444  		}
   445  		bool operator==(const CipherTextAT& rhs) const
   446  		{
   447  			return S_ == rhs.S_ && T_ == rhs.T_;
   448  		}
   449  		bool operator!=(const CipherTextAT& rhs) const { return !operator==(rhs); }
   450  	};
   451  	/*
   452  		g1 = millerLoop(P1, Q)
   453  		g2 = millerLoop(P2, Q)
   454  	*/
   455  	static void doubleMillerLoop(GT& g1, GT& g2, const G1& P1, const G1& P2, const G2& Q)
   456  	{
   457  #if 1
   458  		std::vector<Fp6> Qcoeff;
   459  		precomputeG2(Qcoeff, Q);
   460  		precomputedMillerLoop(g1, P1, Qcoeff);
   461  		precomputedMillerLoop(g2, P2, Qcoeff);
   462  #else
   463  		millerLoop(g1, P1, Q);
   464  		millerLoop(g2, P2, Q);
   465  #endif
   466  	}
   467  	static void finalExp4(GT out[4], const GT in[4])
   468  	{
   469  		for (int i =  0; i < 4; i++) {
   470  			finalExp(out[i], in[i]);
   471  		}
   472  	}
   473  	static void tensorProductML(GT g[4], const G1& S1, const G1& T1, const G2& S2, const G2& T2)
   474  	{
   475  		/*
   476  			(S1, T1) x (S2, T2) = (ML(S1, S2), ML(S1, T2), ML(T1, S2), ML(T1, T2))
   477  		*/
   478  		doubleMillerLoop(g[0], g[2], S1, T1, S2);
   479  		doubleMillerLoop(g[1], g[3], S1, T1, T2);
   480  	}
   481  	static void tensorProduct(GT g[4], const G1& S1, const G1& T1, const G2& S2, const G2& T2)
   482  	{
   483  		/*
   484  			(S1, T1) x (S2, T2) = (e(S1, S2), e(S1, T2), e(T1, S2), e(T1, T2))
   485  		*/
   486  		tensorProductML(g,S1, T1, S2,T2);
   487  		finalExp4(g, g);
   488  	}
   489  	template<class Tag, size_t n>
   490  	struct ZkpT : public fp::Serializable<ZkpT<Tag, n> > {
   491  		Fr d_[n];
   492  		template<class InputStream>
   493  		void load(bool *pb, InputStream& is, int ioMode = IoSerialize)
   494  		{
   495  			for (size_t i = 0; i < n; i++) {
   496  				d_[i].load(pb, is, ioMode); if (!*pb) return;
   497  			}
   498  		}
   499  		template<class OutputStream>
   500  		void save(bool *pb, OutputStream& os, int ioMode = IoSerialize) const
   501  		{
   502  			const char sep = *fp::getIoSeparator(ioMode);
   503  			d_[0].save(pb, os, ioMode); if (!*pb) return;
   504  			for (size_t i = 1; i < n; i++) {
   505  				if (sep) {
   506  					cybozu::writeChar(pb, os, sep);
   507  					if (!*pb) return;
   508  				}
   509  				d_[i].save(pb, os, ioMode);
   510  			}
   511  		}
   512  		template<class InputStream>
   513  		void load(InputStream& is, int ioMode = IoSerialize)
   514  		{
   515  			bool b;
   516  			load(&b, is, ioMode);
   517  			if (!b) throw cybozu::Exception("she:ZkpT:load");
   518  		}
   519  		template<class OutputStream>
   520  		void save(OutputStream& os, int ioMode = IoSerialize) const
   521  		{
   522  			bool b;
   523  			save(&b, os, ioMode);
   524  			if (!b) throw cybozu::Exception("she:ZkpT:save");
   525  		}
   526  		friend std::istream& operator>>(std::istream& is, ZkpT& self)
   527  		{
   528  			self.load(is, fp::detectIoMode(Fr::getIoMode(), is));
   529  			return is;
   530  		}
   531  		friend std::ostream& operator<<(std::ostream& os, const ZkpT& self)
   532  		{
   533  			self.save(os, fp::detectIoMode(Fr::getIoMode(), os));
   534  			return os;
   535  		}
   536  	};
   537  	struct ZkpBinTag;
   538  	struct ZkpEqTag; // d_[] = { c, sp, ss, sm }
   539  	struct ZkpBinEqTag; // d_[] = { d0, d1, sp0, sp1, ss, sp, sm }
   540  public:
   541  	/*
   542  		Zkp for m = 0 or 1
   543  	*/
   544  	typedef ZkpT<ZkpBinTag, 4> ZkpBin;
   545  	/*
   546  		Zkp for decG1(c1) == decG2(c2)
   547  	*/
   548  	typedef ZkpT<ZkpEqTag, 4> ZkpEq;
   549  	/*
   550  		Zkp for (m = 0 or 1) and decG1(c1) == decG2(c2)
   551  	*/
   552  	typedef ZkpT<ZkpBinEqTag, 7> ZkpBinEq;
   553  
   554  	typedef CipherTextAT<G1> CipherTextG1;
   555  	typedef CipherTextAT<G2> CipherTextG2;
   556  
   557  	static void init(const mcl::CurveParam& cp = mcl::BN254, size_t hashSize = 1024, size_t tryNum = local::defaultTryNum)
   558  	{
   559  		initPairing(cp);
   560  		hashAndMapToG1(P_, "0");
   561  		hashAndMapToG2(Q_, "0");
   562  		pairing(ePQ_, P_, Q_);
   563  		precomputeG2(Qcoeff_, Q_);
   564  		setRangeForDLP(hashSize);
   565  		useDecG1ViaGT_ = false;
   566  		useDecG2ViaGT_ = false;
   567  		isG1only_ = false;
   568  		setTryNum(tryNum);
   569  	}
   570  	static void init(size_t hashSize, size_t tryNum = local::defaultTryNum)
   571  	{
   572  		init(mcl::BN254, hashSize, tryNum);
   573  	}
   574  	/*
   575  		standard lifted ElGamal encryption
   576  	*/
   577  	static void initG1only(const mcl::EcParam& para, size_t hashSize = 1024, size_t tryNum = local::defaultTryNum)
   578  	{
   579  		Fp::init(para.p);
   580  		Fr::init(para.n);
   581  		G1::init(para.a, para.b);
   582  		const Fp x0(para.gx);
   583  		const Fp y0(para.gy);
   584  		P_.set(x0, y0);
   585  
   586  		setRangeForG1DLP(hashSize);
   587  		useDecG1ViaGT_ = false;
   588  		useDecG2ViaGT_ = false;
   589  		isG1only_ = true;
   590  		setTryNum(tryNum);
   591  	}
   592  	/*
   593  		set range for G1-DLP
   594  	*/
   595  	static void setRangeForG1DLP(size_t hashSize)
   596  	{
   597  		PhashTbl_.init(P_, hashSize);
   598  	}
   599  	/*
   600  		set range for G2-DLP
   601  	*/
   602  	static void setRangeForG2DLP(size_t hashSize)
   603  	{
   604  		QhashTbl_.init(Q_, hashSize);
   605  	}
   606  	/*
   607  		set range for GT-DLP
   608  	*/
   609  	static void setRangeForGTDLP(size_t hashSize)
   610  	{
   611  		ePQhashTbl_.init(ePQ_, hashSize);
   612  	}
   613  	/*
   614  		set range for G1/G2/GT DLP
   615  		decode message m for |m| <= hasSize * tryNum
   616  		decode time = O(log(hasSize) * tryNum)
   617  	*/
   618  	static void setRangeForDLP(size_t hashSize)
   619  	{
   620  		setRangeForG1DLP(hashSize);
   621  		setRangeForG2DLP(hashSize);
   622  		setRangeForGTDLP(hashSize);
   623  	}
   624  	static void setTryNum(size_t tryNum)
   625  	{
   626  		PhashTbl_.setTryNum(tryNum);
   627  		QhashTbl_.setTryNum(tryNum);
   628  		ePQhashTbl_.setTryNum(tryNum);
   629  	}
   630  	static void useDecG1ViaGT(bool use = true)
   631  	{
   632  		useDecG1ViaGT_ = use;
   633  	}
   634  	static void useDecG2ViaGT(bool use = true)
   635  	{
   636  		useDecG2ViaGT_ = use;
   637  	}
   638  	/*
   639  		only one element is necessary for each G1 and G2.
   640  		this is better than David Mandell Freeman's algorithm
   641  	*/
   642  	class SecretKey : public fp::Serializable<SecretKey> {
   643  		Fr x_, y_;
   644  		void getPowOfePQ(GT& v, const CipherTextGT& c) const
   645  		{
   646  			/*
   647  				(s, t, u, v) := (e(S, S'), e(S, T'), e(T, S'), e(T, T'))
   648  				s v^(xy) / (t^y u^x) = s (v^x / t) ^ y / u^x
   649  				= e(P, Q)^(mm')
   650  			*/
   651  			GT t, u;
   652  			GT::unitaryInv(t, c.g_[1]);
   653  			GT::unitaryInv(u, c.g_[2]);
   654  			GT::pow(v, c.g_[3], x_);
   655  			v *= t;
   656  			GT::pow(v, v, y_);
   657  			GT::pow(u, u, x_);
   658  			v *= u;
   659  			v *= c.g_[0];
   660  		}
   661  	public:
   662  		void setByCSPRNG()
   663  		{
   664  			x_.setRand();
   665  			if (!isG1only_) y_.setRand();
   666  		}
   667  		/*
   668  			set xP and yQ
   669  		*/
   670  		void getPublicKey(PublicKey& pub) const
   671  		{
   672  			pub.set(x_, y_);
   673  		}
   674  #if 0
   675  		// log_x(y)
   676  		int log(const GT& x, const GT& y) const
   677  		{
   678  			if (y == 1) return 0;
   679  			if (y == x) return 1;
   680  			GT inv;
   681  			GT::unitaryInv(inv, x);
   682  			if (y == inv) return -1;
   683  			GT t = x;
   684  			for (int i = 2; i < 100; i++) {
   685  				t *= x;
   686  				if (y == t) return i;
   687  				GT::unitaryInv(inv, t);
   688  				if (y == inv) return -i;
   689  			}
   690  			throw cybozu::Exception("she:dec:log:not found");
   691  		}
   692  #endif
   693  		int64_t dec(const CipherTextG1& c, bool *pok = 0) const
   694  		{
   695  			if (useDecG1ViaGT_) return decViaGT(c);
   696  			/*
   697  				S = mP + rxP
   698  				T = rP
   699  				R = S - xT = mP
   700  			*/
   701  			G1 R;
   702  			G1::mul(R, c.T_, x_);
   703  			G1::sub(R, c.S_, R);
   704  			return PhashTbl_.log(R, pok);
   705  		}
   706  		int64_t dec(const CipherTextG2& c, bool *pok = 0) const
   707  		{
   708  			if (useDecG2ViaGT_) return decViaGT(c);
   709  			G2 R;
   710  			G2::mul(R, c.T_, y_);
   711  			G2::sub(R, c.S_, R);
   712  			return QhashTbl_.log(R, pok);
   713  		}
   714  		int64_t dec(const CipherTextA& c, bool *pok = 0) const
   715  		{
   716  			return dec(c.c1_, pok);
   717  		}
   718  		int64_t dec(const CipherTextGT& c, bool *pok = 0) const
   719  		{
   720  			GT v;
   721  			getPowOfePQ(v, c);
   722  			return ePQhashTbl_.log(v, pok);
   723  //			return log(g, v);
   724  		}
   725  		int64_t decViaGT(const CipherTextG1& c, bool *pok = 0) const
   726  		{
   727  			G1 R;
   728  			G1::mul(R, c.T_, x_);
   729  			G1::sub(R, c.S_, R);
   730  			GT v;
   731  			pairing(v, R, Q_);
   732  			return ePQhashTbl_.log(v, pok);
   733  		}
   734  		int64_t decViaGT(const CipherTextG2& c, bool *pok = 0) const
   735  		{
   736  			G2 R;
   737  			G2::mul(R, c.T_, y_);
   738  			G2::sub(R, c.S_, R);
   739  			GT v;
   740  			pairing(v, P_, R);
   741  			return ePQhashTbl_.log(v, pok);
   742  		}
   743  		int64_t dec(const CipherText& c, bool *pok = 0) const
   744  		{
   745  			if (c.isMultiplied()) {
   746  				return dec(c.m_, pok);
   747  			} else {
   748  				return dec(c.a_, pok);
   749  			}
   750  		}
   751  		bool isZero(const CipherTextG1& c) const
   752  		{
   753  			return c.isZero(x_);
   754  		}
   755  		bool isZero(const CipherTextG2& c) const
   756  		{
   757  			return c.isZero(y_);
   758  		}
   759  		bool isZero(const CipherTextA& c) const
   760  		{
   761  			return c.c1_.isZero(x_);
   762  		}
   763  		bool isZero(const CipherTextGT& c) const
   764  		{
   765  			GT v;
   766  			getPowOfePQ(v, c);
   767  			return v.isOne();
   768  		}
   769  		bool isZero(const CipherText& c) const
   770  		{
   771  			if (c.isMultiplied()) {
   772  				return isZero(c.m_);
   773  			} else {
   774  				return isZero(c.a_);
   775  			}
   776  		}
   777  		template<class InputStream>
   778  		void load(bool *pb, InputStream& is, int ioMode = IoSerialize)
   779  		{
   780  			x_.load(pb, is, ioMode); if (!*pb) return;
   781  			if (!isG1only_) y_.load(pb, is, ioMode);
   782  		}
   783  		template<class OutputStream>
   784  		void save(bool *pb, OutputStream& os, int ioMode = IoSerialize) const
   785  		{
   786  			const char sep = *fp::getIoSeparator(ioMode);
   787  			x_.save(pb, os, ioMode); if (!*pb) return;
   788  			if (isG1only_) return;
   789  			if (sep) {
   790  				cybozu::writeChar(pb, os, sep);
   791  				if (!*pb) return;
   792  			}
   793  			y_.save(os, ioMode);
   794  		}
   795  		template<class InputStream>
   796  		void load(InputStream& is, int ioMode = IoSerialize)
   797  		{
   798  			bool b;
   799  			load(&b, is, ioMode);
   800  			if (!b) throw cybozu::Exception("she:SecretKey:load");
   801  		}
   802  		template<class OutputStream>
   803  		void save(OutputStream& os, int ioMode = IoSerialize) const
   804  		{
   805  			bool b;
   806  			save(&b, os, ioMode);
   807  			if (!b) throw cybozu::Exception("she:SecretKey:save");
   808  		}
   809  		friend std::istream& operator>>(std::istream& is, SecretKey& self)
   810  		{
   811  			self.load(is, fp::detectIoMode(Fr::getIoMode(), is));
   812  			return is;
   813  		}
   814  		friend std::ostream& operator<<(std::ostream& os, const SecretKey& self)
   815  		{
   816  			self.save(os, fp::detectIoMode(Fr::getIoMode(), os));
   817  			return os;
   818  		}
   819  		bool operator==(const SecretKey& rhs) const
   820  		{
   821  			return x_ == rhs.x_ && (isG1only_ || y_ == rhs.y_);
   822  		}
   823  		bool operator!=(const SecretKey& rhs) const { return !operator==(rhs); }
   824  	};
   825  private:
   826  	/*
   827  		simple ElGamal encryptionfor G1 and G2
   828  		(S, T) = (m P + r xP, rP)
   829  		Pmul.mul(X, a) // X = a P
   830  		xPmul.mul(X, a) // X = a xP
   831  		use *encRand if encRand is not null
   832  	*/
   833  	template<class G, class INT, class MulG, class I>
   834  	static void ElGamalEnc(G& S, G& T, const INT& m, const mcl::fp::WindowMethod<I>& Pmul, const MulG& xPmul, const Fr *encRand = 0)
   835  	{
   836  		Fr r;
   837  		if (encRand) {
   838  			r = *encRand;
   839  		} else {
   840  			r.setRand();
   841  		}
   842  		Pmul.mul(static_cast<I&>(T), r);
   843  		xPmul.mul(S, r); // S = r xP
   844  		if (m == 0) return;
   845  		G C;
   846  		Pmul.mul(static_cast<I&>(C), m);
   847  		S += C;
   848  	}
   849  	/*
   850  		https://github.com/herumi/mcl/blob/master/misc/she/nizkp.pdf
   851  
   852  		encRand is a random value used for ElGamalEnc()
   853  		d[1-m] ; rand
   854  		s[1-m] ; rand
   855  		R[0][1-m] = s[1-m] P - d[1-m] T
   856  		R[1][1-m] = s[1-m] xP - d[1-m] (S - (1-m) P)
   857  		r ; rand
   858  		R[0][m] = r P
   859  		R[1][m] = r xP
   860  		c = H(S, T, R[0][0], R[0][1], R[1][0], R[1][1])
   861  		d[m] = c - d[1-m]
   862  		s[m] = r + d[m] encRand
   863  	*/
   864  	template<class G, class I, class MulG>
   865  	static void makeZkpBin(ZkpBin& zkp, const G& S, const G& T, const Fr& encRand, const G& P, int m, const mcl::fp::WindowMethod<I>& Pmul, const MulG& xPmul)
   866  	{
   867  		if (m != 0 && m != 1) throw cybozu::Exception("makeZkpBin:bad m") << m;
   868  		Fr *s = &zkp.d_[0];
   869  		Fr *d = &zkp.d_[2];
   870  		G R[2][2];
   871  		d[1-m].setRand();
   872  		s[1-m].setRand();
   873  		G T1, T2;
   874  		Pmul.mul(static_cast<I&>(T1),  s[1-m]); // T1 = s[1-m] P
   875  		G::mul(T2, T, d[1-m]);
   876  		G::sub(R[0][1-m], T1, T2); // s[1-m] P - d[1-m]T
   877  		xPmul.mul(T1, s[1-m]); // T1 = s[1-m] xP
   878  		if (m == 0) {
   879  			G::sub(T2, S, P);
   880  			G::mul(T2, T2, d[1-m]);
   881  		} else {
   882  			G::mul(T2, S, d[1-m]);
   883  		}
   884  		G::sub(R[1][1-m], T1, T2); // s[1-m] xP - d[1-m](S - (1-m) P)
   885  		Fr r;
   886  		r.setRand();
   887  		Pmul.mul(static_cast<I&>(R[0][m]), r); // R[0][m] = r P
   888  		xPmul.mul(R[1][m], r); // R[1][m] = r xP
   889  		char buf[sizeof(G) * 2];
   890  		cybozu::MemoryOutputStream os(buf, sizeof(buf));
   891  		S.save(os);
   892  		T.save(os);
   893  		R[0][0].save(os);
   894  		R[0][1].save(os);
   895  		R[1][0].save(os);
   896  		R[1][1].save(os);
   897  		Fr c;
   898  		c.setHashOf(buf, os.getPos());
   899  		d[m] = c - d[1-m];
   900  		s[m] = r + d[m] * encRand;
   901  	}
   902  	/*
   903  		R[0][i] = s[i] P - d[i] T ; i = 0,1
   904  		R[1][0] = s[0] xP - d[0] S
   905  		R[1][1] = s[1] xP - d[1](S - P)
   906  		c = H(S, T, R[0][0], R[0][1], R[1][0], R[1][1])
   907  		c == d[0] + d[1]
   908  	*/
   909  	template<class G, class I, class MulG>
   910  	static bool verifyZkpBin(const G& S, const G& T, const G& P, const ZkpBin& zkp, const mcl::fp::WindowMethod<I>& Pmul, const MulG& xPmul)
   911  	{
   912  		const Fr *s = &zkp.d_[0];
   913  		const Fr *d = &zkp.d_[2];
   914  		G R[2][2];
   915  		G T1, T2;
   916  		for (int i = 0; i < 2; i++) {
   917  			Pmul.mul(static_cast<I&>(T1), s[i]); // T1 = s[i] P
   918  			G::mul(T2, T, d[i]);
   919  			G::sub(R[0][i], T1, T2);
   920  		}
   921  		xPmul.mul(T1, s[0]); // T1 = s[0] xP
   922  		G::mul(T2, S, d[0]);
   923  		G::sub(R[1][0], T1, T2);
   924  		xPmul.mul(T1, s[1]); // T1 = x[1] xP
   925  		G::sub(T2, S, P);
   926  		G::mul(T2, T2, d[1]);
   927  		G::sub(R[1][1], T1, T2);
   928  		char buf[sizeof(G) * 2];
   929  		cybozu::MemoryOutputStream os(buf, sizeof(buf));
   930  		S.save(os);
   931  		T.save(os);
   932  		R[0][0].save(os);
   933  		R[0][1].save(os);
   934  		R[1][0].save(os);
   935  		R[1][1].save(os);
   936  		Fr c;
   937  		c.setHashOf(buf, os.getPos());
   938  		return c == d[0] + d[1];
   939  	}
   940  	/*
   941  		encRand1, encRand2 are random values use for ElGamalEnc()
   942  	*/
   943  	template<class G1, class G2, class INT, class I1, class I2, class MulG1, class MulG2>
   944  	static void makeZkpEq(ZkpEq& zkp, G1& S1, G1& T1, G2& S2, G2& T2, const INT& m, const mcl::fp::WindowMethod<I1>& Pmul, const MulG1& xPmul, const mcl::fp::WindowMethod<I2>& Qmul, const MulG2& yQmul)
   945  	{
   946  		Fr p, s;
   947  		p.setRand();
   948  		s.setRand();
   949  		ElGamalEnc(S1, T1, m, Pmul, xPmul, &p);
   950  		ElGamalEnc(S2, T2, m, Qmul, yQmul, &s);
   951  		Fr rp, rs, rm;
   952  		rp.setRand();
   953  		rs.setRand();
   954  		rm.setRand();
   955  		G1 R1, R2;
   956  		G2 R3, R4;
   957  		ElGamalEnc(R1, R2, rm, Pmul, xPmul, &rp);
   958  		ElGamalEnc(R3, R4, rm, Qmul, yQmul, &rs);
   959  		char buf[sizeof(G1) * 4 + sizeof(G2) * 4];
   960  		cybozu::MemoryOutputStream os(buf, sizeof(buf));
   961  		S1.save(os);
   962  		T1.save(os);
   963  		S2.save(os);
   964  		T2.save(os);
   965  		R1.save(os);
   966  		R2.save(os);
   967  		R3.save(os);
   968  		R4.save(os);
   969  		Fr& c = zkp.d_[0];
   970  		Fr& sp = zkp.d_[1];
   971  		Fr& ss = zkp.d_[2];
   972  		Fr& sm = zkp.d_[3];
   973  		c.setHashOf(buf, os.getPos());
   974  		Fr::mul(sp, c, p);
   975  		sp += rp;
   976  		Fr::mul(ss, c, s);
   977  		ss += rs;
   978  		Fr::mul(sm, c, m);
   979  		sm += rm;
   980  	}
   981  	template<class G1, class G2, class I1, class I2, class MulG1, class MulG2>
   982  	static bool verifyZkpEq(const ZkpEq& zkp, const G1& S1, const G1& T1, const G2& S2, const G2& T2, const mcl::fp::WindowMethod<I1>& Pmul, const MulG1& xPmul, const mcl::fp::WindowMethod<I2>& Qmul, const MulG2& yQmul)
   983  	{
   984  		const Fr& c = zkp.d_[0];
   985  		const Fr& sp = zkp.d_[1];
   986  		const Fr& ss = zkp.d_[2];
   987  		const Fr& sm = zkp.d_[3];
   988  		G1 R1, R2, X1;
   989  		G2 R3, R4, X2;
   990  		ElGamalEnc(R1, R2, sm, Pmul, xPmul, &sp);
   991  		G1::mul(X1, S1, c);
   992  		R1 -= X1;
   993  		G1::mul(X1, T1, c);
   994  		R2 -= X1;
   995  		ElGamalEnc(R3, R4, sm, Qmul, yQmul, &ss);
   996  		G2::mul(X2, S2, c);
   997  		R3 -= X2;
   998  		G2::mul(X2, T2, c);
   999  		R4 -= X2;
  1000  		char buf[sizeof(G1) * 4 + sizeof(G2) * 4];
  1001  		cybozu::MemoryOutputStream os(buf, sizeof(buf));
  1002  		S1.save(os);
  1003  		T1.save(os);
  1004  		S2.save(os);
  1005  		T2.save(os);
  1006  		R1.save(os);
  1007  		R2.save(os);
  1008  		R3.save(os);
  1009  		R4.save(os);
  1010  		Fr c2;
  1011  		c2.setHashOf(buf, os.getPos());
  1012  		return c == c2;
  1013  	}
  1014  	/*
  1015  		encRand1, encRand2 are random values use for ElGamalEnc()
  1016  	*/
  1017  	template<class G1, class G2, class I1, class I2, class MulG1, class MulG2>
  1018  	static void makeZkpBinEq(ZkpBinEq& zkp, G1& S1, G1& T1, G2& S2, G2& T2, int m, const mcl::fp::WindowMethod<I1>& Pmul, const MulG1& xPmul, const mcl::fp::WindowMethod<I2>& Qmul, const MulG2& yQmul)
  1019  	{
  1020  		if (m != 0 && m != 1) throw cybozu::Exception("makeZkpBinEq:bad m") << m;
  1021  		Fr *d = &zkp.d_[0];
  1022  		Fr *spm = &zkp.d_[2];
  1023  		Fr& ss = zkp.d_[4];
  1024  		Fr& sp = zkp.d_[5];
  1025  		Fr& sm = zkp.d_[6];
  1026  		Fr p, s;
  1027  		p.setRand();
  1028  		s.setRand();
  1029  		ElGamalEnc(S1, T1, m, Pmul, xPmul, &p);
  1030  		ElGamalEnc(S2, T2, m, Qmul, yQmul, &s);
  1031  		d[1-m].setRand();
  1032  		spm[1-m].setRand();
  1033  		G1 R1[2], R2[2], X1;
  1034  		Pmul.mul(static_cast<I1&>(R1[1-m]), spm[1-m]);
  1035  		G1::mul(X1, T1, d[1-m]);
  1036  		R1[1-m] -= X1;
  1037  		if (m == 0) {
  1038  			G1::sub(X1, S1, P_);
  1039  			G1::mul(X1, X1, d[1-m]);
  1040  		} else {
  1041  			G1::mul(X1, S1, d[1-m]);
  1042  		}
  1043  		xPmul.mul(R2[1-m], spm[1-m]);
  1044  		R2[1-m] -= X1;
  1045  		Fr rpm, rp, rs, rm;
  1046  		rpm.setRand();
  1047  		rp.setRand();
  1048  		rs.setRand();
  1049  		rm.setRand();
  1050  		ElGamalEnc(R2[m], R1[m], 0, Pmul, xPmul, &rpm);
  1051  		G1 R3, R4;
  1052  		G2 R5, R6;
  1053  		ElGamalEnc(R4, R3, rm, Pmul, xPmul, &rp);
  1054  		ElGamalEnc(R6, R5, rm, Qmul, yQmul, &rs);
  1055  		char buf[sizeof(Fp) * 12];
  1056  		cybozu::MemoryOutputStream os(buf, sizeof(buf));
  1057  		S1.save(os);
  1058  		T1.save(os);
  1059  		R1[0].save(os);
  1060  		R1[1].save(os);
  1061  		R2[0].save(os);
  1062  		R2[1].save(os);
  1063  		R3.save(os);
  1064  		R4.save(os);
  1065  		R5.save(os);
  1066  		R6.save(os);
  1067  		Fr c;
  1068  		c.setHashOf(buf, os.getPos());
  1069  		Fr::sub(d[m], c, d[1-m]);
  1070  		Fr::mul(spm[m], d[m], p);
  1071  		spm[m] += rpm;
  1072  		Fr::mul(sp, c, p);
  1073  		sp += rp;
  1074  		Fr::mul(ss, c, s);
  1075  		ss += rs;
  1076  		Fr::mul(sm, c, m);
  1077  		sm += rm;
  1078  	}
  1079  	template<class G1, class G2, class I1, class I2, class MulG1, class MulG2>
  1080  	static bool verifyZkpBinEq(const ZkpBinEq& zkp, const G1& S1, const G1& T1, const G2& S2, const G2& T2, const mcl::fp::WindowMethod<I1>& Pmul, const MulG1& xPmul, const mcl::fp::WindowMethod<I2>& Qmul, const MulG2& yQmul)
  1081  	{
  1082  		const Fr *d = &zkp.d_[0];
  1083  		const Fr *spm = &zkp.d_[2];
  1084  		const Fr& ss = zkp.d_[4];
  1085  		const Fr& sp = zkp.d_[5];
  1086  		const Fr& sm = zkp.d_[6];
  1087  		G1 R1[2], R2[2], X1;
  1088  		for (int i = 0; i < 2; i++) {
  1089  			Pmul.mul(static_cast<I1&>(R1[i]), spm[i]);
  1090  			G1::mul(X1, T1, d[i]);
  1091  			R1[i] -= X1;
  1092  		}
  1093  		xPmul.mul(R2[0], spm[0]);
  1094  		G1::mul(X1, S1, d[0]);
  1095  		R2[0] -= X1;
  1096  		xPmul.mul(R2[1], spm[1]);
  1097  		G1::sub(X1, S1, P_);
  1098  		G1::mul(X1, X1, d[1]);
  1099  		R2[1] -= X1;
  1100  		Fr c;
  1101  		Fr::add(c, d[0], d[1]);
  1102  		G1 R3, R4;
  1103  		G2 R5, R6;
  1104  		ElGamalEnc(R4, R3, sm, Pmul, xPmul, &sp);
  1105  		G1::mul(X1, T1, c);
  1106  		R3 -= X1;
  1107  		G1::mul(X1, S1, c);
  1108  		R4 -= X1;
  1109  		ElGamalEnc(R6, R5, sm, Qmul, yQmul, &ss);
  1110  		G2 X2;
  1111  		G2::mul(X2, T2, c);
  1112  		R5 -= X2;
  1113  		G2::mul(X2, S2, c);
  1114  		R6 -= X2;
  1115  		char buf[sizeof(Fp) * 12];
  1116  		cybozu::MemoryOutputStream os(buf, sizeof(buf));
  1117  		S1.save(os);
  1118  		T1.save(os);
  1119  		R1[0].save(os);
  1120  		R1[1].save(os);
  1121  		R2[0].save(os);
  1122  		R2[1].save(os);
  1123  		R3.save(os);
  1124  		R4.save(os);
  1125  		R5.save(os);
  1126  		R6.save(os);
  1127  		Fr c2;
  1128  		c2.setHashOf(buf, os.getPos());
  1129  		return c == c2;
  1130  	}
  1131  	/*
  1132  		common method for PublicKey and PrecomputedPublicKey
  1133  	*/
  1134  	template<class T>
  1135  	struct PublicKeyMethod {
  1136  		/*
  1137  			you can use INT as int64_t and Fr,
  1138  			but the return type of dec() is int64_t.
  1139  		*/
  1140  		template<class INT>
  1141  		void enc(CipherTextG1& c, const INT& m) const
  1142  		{
  1143  			static_cast<const T&>(*this).encG1(c, m);
  1144  		}
  1145  		template<class INT>
  1146  		void enc(CipherTextG2& c, const INT& m) const
  1147  		{
  1148  			static_cast<const T&>(*this).encG2(c, m);
  1149  		}
  1150  		template<class INT>
  1151  		void enc(CipherTextA& c, const INT& m) const
  1152  		{
  1153  			enc(c.c1_, m);
  1154  			enc(c.c2_, m);
  1155  		}
  1156  		template<class INT>
  1157  		void enc(CipherTextGT& c, const INT& m) const
  1158  		{
  1159  			static_cast<const T&>(*this).encGT(c, m);
  1160  		}
  1161  		template<class INT>
  1162  		void enc(CipherText& c, const INT& m, bool multiplied = false) const
  1163  		{
  1164  			c.isMultiplied_ = multiplied;
  1165  			if (multiplied) {
  1166  				enc(c.m_, m);
  1167  			} else {
  1168  				enc(c.a_, m);
  1169  			}
  1170  		}
  1171  		/*
  1172  			reRand method is for circuit privacy
  1173  		*/
  1174  		template<class CT>
  1175  		void reRandT(CT& c) const
  1176  		{
  1177  			CT c0;
  1178  			static_cast<const T&>(*this).enc(c0, 0);
  1179  			CT::add(c, c, c0);
  1180  		}
  1181  		void reRand(CipherTextG1& c) const { reRandT(c); }
  1182  		void reRand(CipherTextG2& c) const { reRandT(c); }
  1183  		void reRand(CipherTextGT& c) const { reRandT(c); }
  1184  		void reRand(CipherText& c) const
  1185  		{
  1186  			if (c.isMultiplied()) {
  1187  				reRandT(c.m_);
  1188  			} else {
  1189  				reRandT(c.a_);
  1190  			}
  1191  		}
  1192  		/*
  1193  			convert from CipherTextG1 to CipherTextGT
  1194  		*/
  1195  		void convert(CipherTextGT& cm, const CipherTextG1& c1) const
  1196  		{
  1197  			/*
  1198  				Enc(1) = (S, T) = (Q + r yQ, rQ) = (Q, 0) if r = 0
  1199  				cm = c1 * (Q, 0) = (S, T) * (Q, 0) = (e(S, Q), 1, e(T, Q), 1)
  1200  			*/
  1201  			precomputedMillerLoop(cm.g_[0], c1.getS(), Qcoeff_);
  1202  			finalExp(cm.g_[0], cm.g_[0]);
  1203  			precomputedMillerLoop(cm.g_[2], c1.getT(), Qcoeff_);
  1204  			finalExp(cm.g_[2], cm.g_[2]);
  1205  
  1206  			cm.g_[1] = cm.g_[3] = 1;
  1207  		}
  1208  		/*
  1209  			convert from CipherTextG2 to CipherTextGT
  1210  		*/
  1211  		void convert(CipherTextGT& cm, const CipherTextG2& c2) const
  1212  		{
  1213  			/*
  1214  				Enc(1) = (S, T) = (P + r xP, rP) = (P, 0) if r = 0
  1215  				cm = (P, 0) * c2 = (e(P, S), e(P, T), 1, 1)
  1216  			*/
  1217  			pairing(cm.g_[0], P_, c2.getS());
  1218  			pairing(cm.g_[1], P_, c2.getT());
  1219  			cm.g_[2] = cm.g_[3] = 1;
  1220  		}
  1221  		void convert(CipherTextGT& cm, const CipherTextA& ca) const
  1222  		{
  1223  			convert(cm, ca.c1_);
  1224  		}
  1225  		void convert(CipherText& cm, const CipherText& ca) const
  1226  		{
  1227  			if (ca.isMultiplied()) throw cybozu::Exception("she:PublicKey:convertCipherText:already isMultiplied");
  1228  			cm.isMultiplied_ = true;
  1229  			convert(cm.m_, ca.a_);
  1230  		}
  1231  	};
  1232  public:
  1233  	class PublicKey : public fp::Serializable<PublicKey,
  1234  		PublicKeyMethod<PublicKey> > {
  1235  		G1 xP_;
  1236  		G2 yQ_;
  1237  		friend class SecretKey;
  1238  		friend class PrecomputedPublicKey;
  1239  		template<class T>
  1240  		friend struct PublicKeyMethod;
  1241  		template<class G>
  1242  		struct MulG {
  1243  			const G& base;
  1244  			MulG(const G& base) : base(base) {}
  1245  			template<class INT>
  1246  			void mul(G& out, const INT& m) const
  1247  			{
  1248  				G::mul(out, base, m);
  1249  			}
  1250  		};
  1251  		void set(const Fr& x, const Fr& y)
  1252  		{
  1253  			G1::mul(xP_, P_, x);
  1254  			if (!isG1only_) G2::mul(yQ_, Q_, y);
  1255  		}
  1256  		template<class INT>
  1257  		void encG1(CipherTextG1& c, const INT& m) const
  1258  		{
  1259  			const MulG<G1> xPmul(xP_);
  1260  			ElGamalEnc(c.S_, c.T_, m, PhashTbl_.getWM(), xPmul);
  1261  		}
  1262  		template<class INT>
  1263  		void encG2(CipherTextG2& c, const INT& m) const
  1264  		{
  1265  			const MulG<G2> yQmul(yQ_);
  1266  			ElGamalEnc(c.S_, c.T_, m, QhashTbl_.getWM(), yQmul);
  1267  		}
  1268  public:
  1269  		void encWithZkpBin(CipherTextG1& c, ZkpBin& zkp, int m) const
  1270  		{
  1271  			Fr encRand;
  1272  			encRand.setRand();
  1273  			const MulG<G1> xPmul(xP_);
  1274  			ElGamalEnc(c.S_, c.T_, m, PhashTbl_.getWM(), xPmul, &encRand);
  1275  			makeZkpBin(zkp, c.S_, c.T_, encRand, P_, m,  PhashTbl_.getWM(), xPmul);
  1276  		}
  1277  		void encWithZkpBin(CipherTextG2& c, ZkpBin& zkp, int m) const
  1278  		{
  1279  			Fr encRand;
  1280  			encRand.setRand();
  1281  			const MulG<G2> yQmul(yQ_);
  1282  			ElGamalEnc(c.S_, c.T_, m, QhashTbl_.getWM(), yQmul, &encRand);
  1283  			makeZkpBin(zkp, c.S_, c.T_, encRand, Q_, m,  QhashTbl_.getWM(), yQmul);
  1284  		}
  1285  		bool verify(const CipherTextG1& c, const ZkpBin& zkp) const
  1286  		{
  1287  			const MulG<G1> xPmul(xP_);
  1288  			return verifyZkpBin(c.S_, c.T_, P_, zkp, PhashTbl_.getWM(), xPmul);
  1289  		}
  1290  		bool verify(const CipherTextG2& c, const ZkpBin& zkp) const
  1291  		{
  1292  			const MulG<G2> yQmul(yQ_);
  1293  			return verifyZkpBin(c.S_, c.T_, Q_, zkp, QhashTbl_.getWM(), yQmul);
  1294  		}
  1295  		template<class INT>
  1296  		void encWithZkpEq(CipherTextG1& c1, CipherTextG2& c2, ZkpEq& zkp, const INT& m) const
  1297  		{
  1298  			const MulG<G1> xPmul(xP_);
  1299  			const MulG<G2> yQmul(yQ_);
  1300  			makeZkpEq(zkp, c1.S_, c1.T_, c2.S_, c2.T_, m, PhashTbl_.getWM(), xPmul, QhashTbl_.getWM(), yQmul);
  1301  		}
  1302  		bool verify(const CipherTextG1& c1, const CipherTextG2& c2, const ZkpEq& zkp) const
  1303  		{
  1304  			const MulG<G1> xPmul(xP_);
  1305  			const MulG<G2> yQmul(yQ_);
  1306  			return verifyZkpEq(zkp, c1.S_, c1.T_, c2.S_, c2.T_, PhashTbl_.getWM(), xPmul, QhashTbl_.getWM(), yQmul);
  1307  		}
  1308  		void encWithZkpBinEq(CipherTextG1& c1, CipherTextG2& c2, ZkpBinEq& zkp, int m) const
  1309  		{
  1310  			const MulG<G1> xPmul(xP_);
  1311  			const MulG<G2> yQmul(yQ_);
  1312  			makeZkpBinEq(zkp, c1.S_, c1.T_, c2.S_, c2.T_, m, PhashTbl_.getWM(), xPmul, QhashTbl_.getWM(), yQmul);
  1313  		}
  1314  		bool verify(const CipherTextG1& c1, const CipherTextG2& c2, const ZkpBinEq& zkp) const
  1315  		{
  1316  			const MulG<G1> xPmul(xP_);
  1317  			const MulG<G2> yQmul(yQ_);
  1318  			return verifyZkpBinEq(zkp, c1.S_, c1.T_, c2.S_, c2.T_, PhashTbl_.getWM(), xPmul, QhashTbl_.getWM(), yQmul);
  1319  		}
  1320  		template<class INT>
  1321  		void encGT(CipherTextGT& c, const INT& m) const
  1322  		{
  1323  			/*
  1324  				(s, t, u, v) = ((e^x)^a (e^y)^b (e^-xy)^c e^m, e^b, e^a, e^c)
  1325  				s = e(a xP + m P, Q)e(b P - c xP, yQ)
  1326  			*/
  1327  			Fr ra, rb, rc;
  1328  			ra.setRand();
  1329  			rb.setRand();
  1330  			rc.setRand();
  1331  			GT e;
  1332  
  1333  			G1 P1, P2;
  1334  			G1::mul(P1, xP_, ra);
  1335  			if (m != 0) {
  1336  //				G1::mul(P2, P, m);
  1337  				PhashTbl_.mulByWindowMethod(P2, m);
  1338  				P1 += P2;
  1339  			}
  1340  //			millerLoop(c.g[0], P1, Q);
  1341  			precomputedMillerLoop(c.g_[0], P1, Qcoeff_);
  1342  //			G1::mul(P1, P, rb);
  1343  			PhashTbl_.mulByWindowMethod(P1, rb);
  1344  			G1::mul(P2, xP_, rc);
  1345  			P1 -= P2;
  1346  			millerLoop(e, P1, yQ_);
  1347  			c.g_[0] *= e;
  1348  			finalExp(c.g_[0], c.g_[0]);
  1349  #if 1
  1350  			ePQhashTbl_.mulByWindowMethod(c.g_[1], rb);
  1351  			ePQhashTbl_.mulByWindowMethod(c.g_[2], ra);
  1352  			ePQhashTbl_.mulByWindowMethod(c.g_[3], rc);
  1353  #else
  1354  			GT::pow(c.g_[1], ePQ_, rb);
  1355  			GT::pow(c.g_[2], ePQ_, ra);
  1356  			GT::pow(c.g_[3], ePQ_, rc);
  1357  #endif
  1358  		}
  1359  	public:
  1360  		template<class InputStream>
  1361  		void load(bool *pb, InputStream& is, int ioMode = IoSerialize)
  1362  		{
  1363  			xP_.load(pb, is, ioMode); if (!*pb) return;
  1364  			if (!isG1only_) yQ_.load(pb, is, ioMode);
  1365  		}
  1366  		template<class OutputStream>
  1367  		void save(bool *pb, OutputStream& os, int ioMode = IoSerialize) const
  1368  		{
  1369  			const char sep = *fp::getIoSeparator(ioMode);
  1370  			xP_.save(pb, os, ioMode); if (!*pb) return;
  1371  			if (isG1only_) return;
  1372  			if (sep) {
  1373  				cybozu::writeChar(pb, os, sep);
  1374  				if (!*pb) return;
  1375  			}
  1376  			yQ_.save(pb, os, ioMode);
  1377  		}
  1378  		template<class InputStream>
  1379  		void load(InputStream& is, int ioMode = IoSerialize)
  1380  		{
  1381  			bool b;
  1382  			load(&b, is, ioMode);
  1383  			if (!b) throw cybozu::Exception("she:PublicKey:load");
  1384  		}
  1385  		template<class OutputStream>
  1386  		void save(OutputStream& os, int ioMode = IoSerialize) const
  1387  		{
  1388  			bool b;
  1389  			save(&b, os, ioMode);
  1390  			if (!b) throw cybozu::Exception("she:PublicKey:save");
  1391  		}
  1392  		friend std::istream& operator>>(std::istream& is, PublicKey& self)
  1393  		{
  1394  			self.load(is, fp::detectIoMode(G1::getIoMode(), is));
  1395  			return is;
  1396  		}
  1397  		friend std::ostream& operator<<(std::ostream& os, const PublicKey& self)
  1398  		{
  1399  			self.save(os, fp::detectIoMode(G1::getIoMode(), os));
  1400  			return os;
  1401  		}
  1402  		bool operator==(const PublicKey& rhs) const
  1403  		{
  1404  			return xP_ == rhs.xP_ && (isG1only_ || yQ_ == rhs.yQ_);
  1405  		}
  1406  		bool operator!=(const PublicKey& rhs) const { return !operator==(rhs); }
  1407  	};
  1408  
  1409  	class PrecomputedPublicKey : public fp::Serializable<PrecomputedPublicKey,
  1410  		PublicKeyMethod<PrecomputedPublicKey> > {
  1411  		typedef local::InterfaceForHashTable<GT, false> GTasEC;
  1412  		typedef mcl::fp::WindowMethod<GTasEC> GTwin;
  1413  		template<class T>
  1414  		friend struct PublicKeyMethod;
  1415  		GT exPQ_;
  1416  		GT eyPQ_;
  1417  		GT exyPQ_;
  1418  		GTwin exPQwm_;
  1419  		GTwin eyPQwm_;
  1420  		GTwin exyPQwm_;
  1421  		mcl::fp::WindowMethod<G1> xPwm_;
  1422  		mcl::fp::WindowMethod<G2> yQwm_;
  1423  		template<class T>
  1424  		void mulByWindowMethod(GT& x, const GTwin& wm, const T& y) const
  1425  		{
  1426  			wm.mul(static_cast<GTasEC&>(x), y);
  1427  		}
  1428  		template<class INT>
  1429  		void encG1(CipherTextG1& c, const INT& m) const
  1430  		{
  1431  			ElGamalEnc(c.S_, c.T_, m, PhashTbl_.getWM(), xPwm_);
  1432  		}
  1433  		template<class INT>
  1434  		void encG2(CipherTextG2& c, const INT& m) const
  1435  		{
  1436  			ElGamalEnc(c.S_, c.T_, m, QhashTbl_.getWM(), yQwm_);
  1437  		}
  1438  		template<class INT>
  1439  		void encGT(CipherTextGT& c, const INT& m) const
  1440  		{
  1441  			/*
  1442  				(s, t, u, v) = (e^m e^(xya), (e^x)^b, (e^y)^c, e^(b + c - a))
  1443  			*/
  1444  			Fr ra, rb, rc;
  1445  			ra.setRand();
  1446  			rb.setRand();
  1447  			rc.setRand();
  1448  			GT t;
  1449  			ePQhashTbl_.mulByWindowMethod(c.g_[0], m); // e^m
  1450  			mulByWindowMethod(t, exyPQwm_, ra); // (e^xy)^a
  1451  			c.g_[0] *= t;
  1452  			mulByWindowMethod(c.g_[1], exPQwm_, rb); // (e^x)^b
  1453  			mulByWindowMethod(c.g_[2], eyPQwm_, rc); // (e^y)^c
  1454  			rb += rc;
  1455  			rb -= ra;
  1456  			ePQhashTbl_.mulByWindowMethod(c.g_[3], rb);
  1457  		}
  1458  	public:
  1459  		void init(const PublicKey& pub)
  1460  		{
  1461  			const size_t bitSize = Fr::getBitSize();
  1462  			xPwm_.init(pub.xP_, bitSize, local::winSize);
  1463  			if (isG1only_) return;
  1464  			yQwm_.init(pub.yQ_, bitSize, local::winSize);
  1465  			pairing(exPQ_, pub.xP_, Q_);
  1466  			pairing(eyPQ_, P_, pub.yQ_);
  1467  			pairing(exyPQ_, pub.xP_, pub.yQ_);
  1468  			exPQwm_.init(static_cast<const GTasEC&>(exPQ_), bitSize, local::winSize);
  1469  			eyPQwm_.init(static_cast<const GTasEC&>(eyPQ_), bitSize, local::winSize);
  1470  			exyPQwm_.init(static_cast<const GTasEC&>(exyPQ_), bitSize, local::winSize);
  1471  		}
  1472  		void encWithZkpBin(CipherTextG1& c, ZkpBin& zkp, int m) const
  1473  		{
  1474  			Fr encRand;
  1475  			encRand.setRand();
  1476  			ElGamalEnc(c.S_, c.T_, m, PhashTbl_.getWM(), xPwm_, &encRand);
  1477  			makeZkpBin(zkp, c.S_, c.T_, encRand, P_, m,  PhashTbl_.getWM(), xPwm_);
  1478  		}
  1479  		void encWithZkpBin(CipherTextG2& c, ZkpBin& zkp, int m) const
  1480  		{
  1481  			Fr encRand;
  1482  			encRand.setRand();
  1483  			ElGamalEnc(c.S_, c.T_, m, QhashTbl_.getWM(), yQwm_, &encRand);
  1484  			makeZkpBin(zkp, c.S_, c.T_, encRand, Q_, m,  QhashTbl_.getWM(), yQwm_);
  1485  		}
  1486  		bool verify(const CipherTextG1& c, const ZkpBin& zkp) const
  1487  		{
  1488  			return verifyZkpBin(c.S_, c.T_, P_, zkp, PhashTbl_.getWM(), xPwm_);
  1489  		}
  1490  		bool verify(const CipherTextG2& c, const ZkpBin& zkp) const
  1491  		{
  1492  			return verifyZkpBin(c.S_, c.T_, Q_, zkp, QhashTbl_.getWM(), yQwm_);
  1493  		}
  1494  		template<class INT>
  1495  		void encWithZkpEq(CipherTextG1& c1, CipherTextG2& c2, ZkpEq& zkp, const INT& m) const
  1496  		{
  1497  			makeZkpEq(zkp, c1.S_, c1.T_, c2.S_, c2.T_, m, PhashTbl_.getWM(), xPwm_, QhashTbl_.getWM(), yQwm_);
  1498  		}
  1499  		bool verify(const CipherTextG1& c1, const CipherTextG2& c2, const ZkpEq& zkp) const
  1500  		{
  1501  			return verifyZkpEq(zkp, c1.S_, c1.T_, c2.S_, c2.T_, PhashTbl_.getWM(), xPwm_, QhashTbl_.getWM(), yQwm_);
  1502  		}
  1503  		void encWithZkpBinEq(CipherTextG1& c1, CipherTextG2& c2, ZkpBinEq& zkp, int m) const
  1504  		{
  1505  			makeZkpBinEq(zkp, c1.S_, c1.T_, c2.S_, c2.T_, m, PhashTbl_.getWM(), xPwm_, QhashTbl_.getWM(), yQwm_);
  1506  		}
  1507  		bool verify(const CipherTextG1& c1, const CipherTextG2& c2, const ZkpBinEq& zkp) const
  1508  		{
  1509  			return verifyZkpBinEq(zkp, c1.S_, c1.T_, c2.S_, c2.T_, PhashTbl_.getWM(), xPwm_, QhashTbl_.getWM(), yQwm_);
  1510  		}
  1511  	};
  1512  	class CipherTextA {
  1513  		CipherTextG1 c1_;
  1514  		CipherTextG2 c2_;
  1515  		friend class SecretKey;
  1516  		friend class PublicKey;
  1517  		friend class CipherTextGT;
  1518  		template<class T>
  1519  		friend struct PublicKeyMethod;
  1520  	public:
  1521  		void clear()
  1522  		{
  1523  			c1_.clear();
  1524  			c2_.clear();
  1525  		}
  1526  		static void add(CipherTextA& z, const CipherTextA& x, const CipherTextA& y)
  1527  		{
  1528  			CipherTextG1::add(z.c1_, x.c1_, y.c1_);
  1529  			CipherTextG2::add(z.c2_, x.c2_, y.c2_);
  1530  		}
  1531  		static void sub(CipherTextA& z, const CipherTextA& x, const CipherTextA& y)
  1532  		{
  1533  			CipherTextG1::sub(z.c1_, x.c1_, y.c1_);
  1534  			CipherTextG2::sub(z.c2_, x.c2_, y.c2_);
  1535  		}
  1536  		static void mul(CipherTextA& z, const CipherTextA& x, int64_t y)
  1537  		{
  1538  			CipherTextG1::mul(z.c1_, x.c1_, y);
  1539  			CipherTextG2::mul(z.c2_, x.c2_, y);
  1540  		}
  1541  		static void neg(CipherTextA& y, const CipherTextA& x)
  1542  		{
  1543  			CipherTextG1::neg(y.c1_, x.c1_);
  1544  			CipherTextG2::neg(y.c2_, x.c2_);
  1545  		}
  1546  		void add(const CipherTextA& c) { add(*this, *this, c); }
  1547  		void sub(const CipherTextA& c) { sub(*this, *this, c); }
  1548  		template<class InputStream>
  1549  		void load(bool *pb, InputStream& is, int ioMode = IoSerialize)
  1550  		{
  1551  			c1_.load(pb, is, ioMode); if (!*pb) return;
  1552  			c2_.load(pb, is, ioMode);
  1553  		}
  1554  		template<class OutputStream>
  1555  		void save(bool *pb, OutputStream& os, int ioMode = IoSerialize) const
  1556  		{
  1557  			const char sep = *fp::getIoSeparator(ioMode);
  1558  			c1_.save(pb, os, ioMode); if (!*pb) return;
  1559  			if (sep) {
  1560  				cybozu::writeChar(pb, os, sep);
  1561  				if (!*pb) return;
  1562  			}
  1563  			c2_.save(pb, os, ioMode);
  1564  		}
  1565  		template<class InputStream>
  1566  		void load(InputStream& is, int ioMode = IoSerialize)
  1567  		{
  1568  			bool b;
  1569  			load(&b, is, ioMode);
  1570  			if (!b) throw cybozu::Exception("she:CipherTextA:load");
  1571  		}
  1572  		template<class OutputStream>
  1573  		void save(OutputStream& os, int ioMode = IoSerialize) const
  1574  		{
  1575  			bool b;
  1576  			save(&b, os, ioMode);
  1577  			if (!b) throw cybozu::Exception("she:CipherTextA:save");
  1578  		}
  1579  		friend std::istream& operator>>(std::istream& is, CipherTextA& self)
  1580  		{
  1581  			self.load(is, fp::detectIoMode(G1::getIoMode(), is));
  1582  			return is;
  1583  		}
  1584  		friend std::ostream& operator<<(std::ostream& os, const CipherTextA& self)
  1585  		{
  1586  			self.save(os, fp::detectIoMode(G1::getIoMode(), os));
  1587  			return os;
  1588  		}
  1589  		bool operator==(const CipherTextA& rhs) const
  1590  		{
  1591  			return c1_ == rhs.c1_ && c2_ == rhs.c2_;
  1592  		}
  1593  		bool operator!=(const CipherTextA& rhs) const { return !operator==(rhs); }
  1594  	};
  1595  
  1596  	class CipherTextGT : public fp::Serializable<CipherTextGT> {
  1597  		GT g_[4];
  1598  		friend class SecretKey;
  1599  		friend class PublicKey;
  1600  		friend class PrecomputedPublicKey;
  1601  		friend class CipherTextA;
  1602  		template<class T>
  1603  		friend struct PublicKeyMethod;
  1604  	public:
  1605  		void clear()
  1606  		{
  1607  			for (int i = 0; i < 4; i++) {
  1608  				g_[i].setOne();
  1609  			}
  1610  		}
  1611  		static void neg(CipherTextGT& y, const CipherTextGT& x)
  1612  		{
  1613  			for (int i = 0; i < 4; i++) {
  1614  				GT::unitaryInv(y.g_[i], x.g_[i]);
  1615  			}
  1616  		}
  1617  		static void add(CipherTextGT& z, const CipherTextGT& x, const CipherTextGT& y)
  1618  		{
  1619  			/*
  1620  				(g[i]) + (g'[i]) = (g[i] * g'[i])
  1621  			*/
  1622  			for (int i = 0; i < 4; i++) {
  1623  				GT::mul(z.g_[i], x.g_[i], y.g_[i]);
  1624  			}
  1625  		}
  1626  		static void sub(CipherTextGT& z, const CipherTextGT& x, const CipherTextGT& y)
  1627  		{
  1628  			/*
  1629  				(g[i]) - (g'[i]) = (g[i] / g'[i])
  1630  			*/
  1631  			GT t;
  1632  			for (size_t i = 0; i < 4; i++) {
  1633  				GT::unitaryInv(t, y.g_[i]);
  1634  				GT::mul(z.g_[i], x.g_[i], t);
  1635  			}
  1636  		}
  1637  		static void mulML(CipherTextGT& z, const CipherTextG1& x, const CipherTextG2& y)
  1638  		{
  1639  			/*
  1640  				(S1, T1) * (S2, T2) = (ML(S1, S2), ML(S1, T2), ML(T1, S2), ML(T1, T2))
  1641  			*/
  1642  			tensorProductML(z.g_, x.S_, x.T_, y.S_, y.T_);
  1643  		}
  1644  		static void finalExp(CipherTextGT& y, const CipherTextGT& x)
  1645  		{
  1646  			finalExp4(y.g_, x.g_);
  1647  		}
  1648  		/*
  1649  			mul(x, y) = mulML(x, y) + finalExp
  1650  			mul(c11, c12) + mul(c21, c22)
  1651  			= finalExp(mulML(c11, c12) + mulML(c21, c22)),
  1652  			then one finalExp can be reduced
  1653  		*/
  1654  		static void mul(CipherTextGT& z, const CipherTextG1& x, const CipherTextG2& y)
  1655  		{
  1656  			/*
  1657  				(S1, T1) * (S2, T2) = (e(S1, S2), e(S1, T2), e(T1, S2), e(T1, T2))
  1658  			*/
  1659  			mulML(z, x, y);
  1660  			finalExp(z, z);
  1661  		}
  1662  		static void mul(CipherTextGT& z, const CipherTextA& x, const CipherTextA& y)
  1663  		{
  1664  			mul(z, x.c1_, y.c2_);
  1665  		}
  1666  		template<class INT>
  1667  		static void mul(CipherTextGT& z, const CipherTextGT& x, const INT& y)
  1668  		{
  1669  			for (int i = 0; i < 4; i++) {
  1670  				GT::pow(z.g_[i], x.g_[i], y);
  1671  			}
  1672  		}
  1673  		void add(const CipherTextGT& c) { add(*this, *this, c); }
  1674  		void sub(const CipherTextGT& c) { sub(*this, *this, c); }
  1675  		template<class InputStream>
  1676  		void load(bool *pb, InputStream& is, int ioMode = IoSerialize)
  1677  		{
  1678  			for (int i = 0; i < 4; i++) {
  1679  				g_[i].load(pb, is, ioMode); if (!*pb) return;
  1680  			}
  1681  		}
  1682  		template<class OutputStream>
  1683  		void save(bool *pb, OutputStream& os, int ioMode = IoSerialize) const
  1684  		{
  1685  			const char sep = *fp::getIoSeparator(ioMode);
  1686  			g_[0].save(pb, os, ioMode); if (!*pb) return;
  1687  			for (int i = 1; i < 4; i++) {
  1688  				if (sep) {
  1689  					cybozu::writeChar(pb, os, sep);
  1690  					if (!*pb) return;
  1691  				}
  1692  				g_[i].save(pb, os, ioMode); if (!*pb) return;
  1693  			}
  1694  		}
  1695  		template<class InputStream>
  1696  		void load(InputStream& is, int ioMode = IoSerialize)
  1697  		{
  1698  			bool b;
  1699  			load(&b, is, ioMode);
  1700  			if (!b) throw cybozu::Exception("she:CipherTextGT:load");
  1701  		}
  1702  		template<class OutputStream>
  1703  		void save(OutputStream& os, int ioMode = IoSerialize) const
  1704  		{
  1705  			bool b;
  1706  			save(&b, os, ioMode);
  1707  			if (!b) throw cybozu::Exception("she:CipherTextGT:save");
  1708  		}
  1709  		friend std::istream& operator>>(std::istream& is, CipherTextGT& self)
  1710  		{
  1711  			self.load(is, fp::detectIoMode(G1::getIoMode(), is));
  1712  			return is;
  1713  		}
  1714  		friend std::ostream& operator<<(std::ostream& os, const CipherTextGT& self)
  1715  		{
  1716  			self.save(os, fp::detectIoMode(G1::getIoMode(), os));
  1717  			return os;
  1718  		}
  1719  		bool operator==(const CipherTextGT& rhs) const
  1720  		{
  1721  			for (int i = 0; i < 4; i++) {
  1722  				if (g_[i] != rhs.g_[i]) return false;
  1723  			}
  1724  			return true;
  1725  		}
  1726  		bool operator!=(const CipherTextGT& rhs) const { return !operator==(rhs); }
  1727  	};
  1728  
  1729  	class CipherText : public fp::Serializable<CipherText> {
  1730  		bool isMultiplied_;
  1731  		CipherTextA a_;
  1732  		CipherTextGT m_;
  1733  		friend class SecretKey;
  1734  		friend class PublicKey;
  1735  		template<class T>
  1736  		friend struct PublicKeyMethod;
  1737  	public:
  1738  		CipherText() : isMultiplied_(false) {}
  1739  		void clearAsAdded()
  1740  		{
  1741  			isMultiplied_ = false;
  1742  			a_.clear();
  1743  		}
  1744  		void clearAsMultiplied()
  1745  		{
  1746  			isMultiplied_ = true;
  1747  			m_.clear();
  1748  		}
  1749  		bool isMultiplied() const { return isMultiplied_; }
  1750  		static void add(CipherText& z, const CipherText& x, const CipherText& y)
  1751  		{
  1752  			if (x.isMultiplied() && y.isMultiplied()) {
  1753  				z.isMultiplied_ = true;
  1754  				CipherTextGT::add(z.m_, x.m_, y.m_);
  1755  				return;
  1756  			}
  1757  			if (!x.isMultiplied() && !y.isMultiplied()) {
  1758  				z.isMultiplied_ = false;
  1759  				CipherTextA::add(z.a_, x.a_, y.a_);
  1760  				return;
  1761  			}
  1762  			throw cybozu::Exception("she:CipherText:add:mixed CipherText");
  1763  		}
  1764  		static void sub(CipherText& z, const CipherText& x, const CipherText& y)
  1765  		{
  1766  			if (x.isMultiplied() && y.isMultiplied()) {
  1767  				z.isMultiplied_ = true;
  1768  				CipherTextGT::sub(z.m_, x.m_, y.m_);
  1769  				return;
  1770  			}
  1771  			if (!x.isMultiplied() && !y.isMultiplied()) {
  1772  				z.isMultiplied_ = false;
  1773  				CipherTextA::sub(z.a_, x.a_, y.a_);
  1774  				return;
  1775  			}
  1776  			throw cybozu::Exception("she:CipherText:sub:mixed CipherText");
  1777  		}
  1778  		static void neg(CipherText& y, const CipherText& x)
  1779  		{
  1780  			if (x.isMultiplied()) {
  1781  				y.isMultiplied_ = true;
  1782  				CipherTextGT::neg(y.m_, x.m_);
  1783  				return;
  1784  			} else {
  1785  				y.isMultiplied_ = false;
  1786  				CipherTextA::neg(y.a_, x.a_);
  1787  				return;
  1788  			}
  1789  		}
  1790  		static void mul(CipherText& z, const CipherText& x, const CipherText& y)
  1791  		{
  1792  			if (x.isMultiplied() || y.isMultiplied()) {
  1793  				throw cybozu::Exception("she:CipherText:mul:mixed CipherText");
  1794  			}
  1795  			z.isMultiplied_ = true;
  1796  			CipherTextGT::mul(z.m_, x.a_, y.a_);
  1797  		}
  1798  		static void mul(CipherText& z, const CipherText& x, int64_t y)
  1799  		{
  1800  			if (x.isMultiplied()) {
  1801  				CipherTextGT::mul(z.m_, x.m_, y);
  1802  			} else {
  1803  				CipherTextA::mul(z.a_, x.a_, y);
  1804  			}
  1805  		}
  1806  		void add(const CipherText& c) { add(*this, *this, c); }
  1807  		void sub(const CipherText& c) { sub(*this, *this, c); }
  1808  		void mul(const CipherText& c) { mul(*this, *this, c); }
  1809  		template<class InputStream>
  1810  		void load(bool *pb, InputStream& is, int ioMode = IoSerialize)
  1811  		{
  1812  			cybozu::writeChar(pb, isMultiplied_ ? '0' : '1', is); if (!*pb) return;
  1813  			if (isMultiplied()) {
  1814  				m_.load(pb, is, ioMode);
  1815  			} else {
  1816  				a_.load(pb, is, ioMode);
  1817  			}
  1818  		}
  1819  		template<class OutputStream>
  1820  		void save(bool *pb, OutputStream& os, int ioMode = IoSerialize) const
  1821  		{
  1822  			char c;
  1823  			if (!cybozu::readChar(&c, os)) return;
  1824  			if (c == '0' || c == '1') {
  1825  				isMultiplied_ = c == '0';
  1826  			} else {
  1827  				*pb = false;
  1828  				return;
  1829  			}
  1830  			if (isMultiplied()) {
  1831  				m_.save(pb, os, ioMode);
  1832  			} else {
  1833  				a_.save(pb, os, ioMode);
  1834  			}
  1835  		}
  1836  		template<class InputStream>
  1837  		void load(InputStream& is, int ioMode = IoSerialize)
  1838  		{
  1839  			bool b;
  1840  			load(&b, is, ioMode);
  1841  			if (!b) throw cybozu::Exception("she:CipherText:load");
  1842  		}
  1843  		template<class OutputStream>
  1844  		void save(OutputStream& os, int ioMode = IoSerialize) const
  1845  		{
  1846  			bool b;
  1847  			save(&b, os, ioMode);
  1848  			if (!b) throw cybozu::Exception("she:CipherText:save");
  1849  		}
  1850  		friend std::istream& operator>>(std::istream& is, CipherText& self)
  1851  		{
  1852  			self.load(is, fp::detectIoMode(G1::getIoMode(), is));
  1853  			return is;
  1854  		}
  1855  		friend std::ostream& operator<<(std::ostream& os, const CipherText& self)
  1856  		{
  1857  			self.save(os, fp::detectIoMode(G1::getIoMode(), os));
  1858  			return os;
  1859  		}
  1860  		bool operator==(const CipherTextGT& rhs) const
  1861  		{
  1862  			if (isMultiplied() != rhs.isMultiplied()) return false;
  1863  			if (isMultiplied()) {
  1864  				return m_ == rhs.m_;
  1865  			}
  1866  			return a_ == rhs.a_;
  1867  		}
  1868  		bool operator!=(const CipherTextGT& rhs) const { return !operator==(rhs); }
  1869  	};
  1870  };
  1871  typedef local::HashTable<G1> HashTableG1;
  1872  typedef local::HashTable<G2> HashTableG2;
  1873  typedef local::HashTable<Fp12, false> HashTableGT;
  1874  
  1875  template<size_t dummyInpl> G1 SHET<dummyInpl>::P_;
  1876  template<size_t dummyInpl> G2 SHET<dummyInpl>::Q_;
  1877  template<size_t dummyInpl> Fp12 SHET<dummyInpl>::ePQ_;
  1878  template<size_t dummyInpl> std::vector<Fp6> SHET<dummyInpl>::Qcoeff_;
  1879  template<size_t dummyInpl> HashTableG1 SHET<dummyInpl>::PhashTbl_;
  1880  template<size_t dummyInpl> HashTableG2 SHET<dummyInpl>::QhashTbl_;
  1881  template<size_t dummyInpl> HashTableGT SHET<dummyInpl>::ePQhashTbl_;
  1882  template<size_t dummyInpl> bool SHET<dummyInpl>::useDecG1ViaGT_;
  1883  template<size_t dummyInpl> bool SHET<dummyInpl>::useDecG2ViaGT_;
  1884  template<size_t dummyInpl> bool SHET<dummyInpl>::isG1only_;
  1885  typedef mcl::she::SHET<> SHE;
  1886  typedef SHE::SecretKey SecretKey;
  1887  typedef SHE::PublicKey PublicKey;
  1888  typedef SHE::PrecomputedPublicKey PrecomputedPublicKey;
  1889  typedef SHE::CipherTextG1 CipherTextG1;
  1890  typedef SHE::CipherTextG2 CipherTextG2;
  1891  typedef SHE::CipherTextGT CipherTextGT;
  1892  typedef SHE::CipherTextA CipherTextA;
  1893  typedef CipherTextGT CipherTextGM; // old class
  1894  typedef SHE::CipherText CipherText;
  1895  typedef SHE::ZkpBin ZkpBin;
  1896  typedef SHE::ZkpEq ZkpEq;
  1897  typedef SHE::ZkpBinEq ZkpBinEq;
  1898  
  1899  inline void init(const mcl::CurveParam& cp = mcl::BN254, size_t hashSize = 1024, size_t tryNum = local::defaultTryNum)
  1900  {
  1901  	SHE::init(cp, hashSize, tryNum);
  1902  }
  1903  inline void initG1only(const mcl::EcParam& para, size_t hashSize = 1024, size_t tryNum = local::defaultTryNum)
  1904  {
  1905  	SHE::initG1only(para, hashSize, tryNum);
  1906  }
  1907  inline void init(size_t hashSize, size_t tryNum = local::defaultTryNum) { SHE::init(hashSize, tryNum); }
  1908  inline void setRangeForG1DLP(size_t hashSize) { SHE::setRangeForG1DLP(hashSize); }
  1909  inline void setRangeForG2DLP(size_t hashSize) { SHE::setRangeForG2DLP(hashSize); }
  1910  inline void setRangeForGTDLP(size_t hashSize) { SHE::setRangeForGTDLP(hashSize); }
  1911  inline void setRangeForDLP(size_t hashSize) { SHE::setRangeForDLP(hashSize); }
  1912  inline void setTryNum(size_t tryNum) { SHE::setTryNum(tryNum); }
  1913  inline void useDecG1ViaGT(bool use = true) { SHE::useDecG1ViaGT(use); }
  1914  inline void useDecG2ViaGT(bool use = true) { SHE::useDecG2ViaGT(use); }
  1915  inline HashTableG1& getHashTableG1() { return SHE::PhashTbl_; }
  1916  inline HashTableG2& getHashTableG2() { return SHE::QhashTbl_; }
  1917  inline HashTableGT& getHashTableGT() { return SHE::ePQhashTbl_; }
  1918  
  1919  inline void add(CipherTextG1& z, const CipherTextG1& x, const CipherTextG1& y) { CipherTextG1::add(z, x, y); }
  1920  inline void add(CipherTextG2& z, const CipherTextG2& x, const CipherTextG2& y) { CipherTextG2::add(z, x, y); }
  1921  inline void add(CipherTextGT& z, const CipherTextGT& x, const CipherTextGT& y) { CipherTextGT::add(z, x, y); }
  1922  inline void add(CipherText& z, const CipherText& x, const CipherText& y) { CipherText::add(z, x, y); }
  1923  
  1924  inline void sub(CipherTextG1& z, const CipherTextG1& x, const CipherTextG1& y) { CipherTextG1::sub(z, x, y); }
  1925  inline void sub(CipherTextG2& z, const CipherTextG2& x, const CipherTextG2& y) { CipherTextG2::sub(z, x, y); }
  1926  inline void sub(CipherTextGT& z, const CipherTextGT& x, const CipherTextGT& y) { CipherTextGT::sub(z, x, y); }
  1927  inline void sub(CipherText& z, const CipherText& x, const CipherText& y) { CipherText::sub(z, x, y); }
  1928  
  1929  inline void neg(CipherTextG1& y, const CipherTextG1& x) { CipherTextG1::neg(y, x); }
  1930  inline void neg(CipherTextG2& y, const CipherTextG2& x) { CipherTextG2::neg(y, x); }
  1931  inline void neg(CipherTextGT& y, const CipherTextGT& x) { CipherTextGT::neg(y, x); }
  1932  inline void neg(CipherText& y, const CipherText& x) { CipherText::neg(y, x); }
  1933  
  1934  template<class INT>
  1935  inline void mul(CipherTextG1& z, const CipherTextG1& x, const INT& y) { CipherTextG1::mul(z, x, y); }
  1936  template<class INT>
  1937  inline void mul(CipherTextG2& z, const CipherTextG2& x, const INT& y) { CipherTextG2::mul(z, x, y); }
  1938  template<class INT>
  1939  inline void mul(CipherTextGT& z, const CipherTextGT& x, const INT& y) { CipherTextGT::mul(z, x, y); }
  1940  template<class INT>
  1941  inline void mul(CipherText& z, const CipherText& x, const INT& y) { CipherText::mul(z, x, y); }
  1942  
  1943  inline void mul(CipherTextGT& z, const CipherTextG1& x, const CipherTextG2& y) { CipherTextGT::mul(z, x, y); }
  1944  inline void mul(CipherText& z, const CipherText& x, const CipherText& y) { CipherText::mul(z, x, y); }
  1945  
  1946  } } // mcl::she
  1947