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

     1  #pragma once
     2  /**
     3  	@file
     4  	@brief lifted-ElGamal encryption
     5  	@author MITSUNARI Shigeo(@herumi)
     6  	@license modified new BSD license
     7  	http://opensource.org/licenses/BSD-3-Clause
     8  
     9  	original:
    10  	Copyright (c) 2014, National Institute of Advanced Industrial
    11  	Science and Technology All rights reserved.
    12  	This source file is subject to BSD 3-Clause license.
    13  */
    14  #include <string>
    15  #include <sstream>
    16  #include <cybozu/unordered_map.hpp>
    17  #ifndef CYBOZU_UNORDERED_MAP_STD
    18  #include <map>
    19  #endif
    20  #include <cybozu/exception.hpp>
    21  #include <cybozu/itoa.hpp>
    22  #include <cybozu/atoi.hpp>
    23  #include <mcl/window_method.hpp>
    24  
    25  namespace mcl {
    26  
    27  template<class _Ec, class Zn>
    28  struct ElgamalT {
    29  	typedef _Ec Ec;
    30  	struct CipherText {
    31  		Ec c1;
    32  		Ec c2;
    33  		CipherText()
    34  		{
    35  			clear();
    36  		}
    37  		/*
    38  			(c1, c2) = (0, 0) is trivial valid ciphertext for m = 0
    39  		*/
    40  		void clear()
    41  		{
    42  			c1.clear();
    43  			c2.clear();
    44  		}
    45  		/*
    46  			add encoded message with encoded message
    47  			input : this = Enc(m1), c = Enc(m2)
    48  			output : this = Enc(m1 + m2)
    49  		*/
    50  		void add(const CipherText& c)
    51  		{
    52  			Ec::add(c1, c1, c.c1);
    53  			Ec::add(c2, c2, c.c2);
    54  		}
    55  		/*
    56  			mul by x
    57  			input : this = Enc(m), x
    58  			output : this = Enc(m x)
    59  		*/
    60  		template<class N>
    61  		void mul(const N& x)
    62  		{
    63  			Ec::mul(c1, c1, x);
    64  			Ec::mul(c2, c2, x);
    65  		}
    66  		/*
    67  			negative encoded message
    68  			input : this = Enc(m)
    69  			output : this = Enc(-m)
    70  		*/
    71  		void neg()
    72  		{
    73  			Ec::neg(c1, c1);
    74  			Ec::neg(c2, c2);
    75  		}
    76  		template<class InputStream>
    77  		void load(InputStream& is, int ioMode = IoSerialize)
    78  		{
    79  			c1.load(is, ioMode);
    80  			c2.load(is, ioMode);
    81  		}
    82  		template<class OutputStream>
    83  		void save(OutputStream& os, int ioMode = IoSerialize) const
    84  		{
    85  			const char sep = *fp::getIoSeparator(ioMode);
    86  			c1.save(os, ioMode);
    87  			if (sep) cybozu::writeChar(os, sep);
    88  			c2.save(os, ioMode);
    89  		}
    90  		void getStr(std::string& str, int ioMode = 0) const
    91  		{
    92  			str.clear();
    93  			cybozu::StringOutputStream os(str);
    94  			save(os, ioMode);
    95  		}
    96  		std::string getStr(int ioMode = 0) const
    97  		{
    98  			std::string str;
    99  			getStr(str, ioMode);
   100  			return str;
   101  		}
   102  		void setStr(const std::string& str, int ioMode = 0)
   103  		{
   104  			cybozu::StringInputStream is(str);
   105  			load(is, ioMode);
   106  		}
   107  		friend inline std::ostream& operator<<(std::ostream& os, const CipherText& self)
   108  		{
   109  			self.save(os, fp::detectIoMode(Ec::getIoMode(), os));
   110  			return os;
   111  		}
   112  		friend inline std::istream& operator>>(std::istream& is, CipherText& self)
   113  		{
   114  			self.load(is, fp::detectIoMode(Ec::getIoMode(), is));
   115  			return is;
   116  		}
   117  		// obsolete
   118  		std::string toStr() const { return getStr(); }
   119  		void fromStr(const std::string& str) { setStr(str); }
   120  	};
   121  	/*
   122  		Zero Knowledge Proof
   123  		cipher text with ZKP to ensure m = 0 or 1
   124  		http://dx.doi.org/10.1587/transfun.E96.A.1156
   125  	*/
   126  	struct Zkp {
   127  		Zn c[2], s[2];
   128  		template<class InputStream>
   129  		void load(InputStream& is, int ioMode = IoSerialize)
   130  		{
   131  			c[0].load(is, ioMode);
   132  			c[1].load(is, ioMode);
   133  			s[0].load(is, ioMode);
   134  			s[1].load(is, ioMode);
   135  		}
   136  		template<class OutputStream>
   137  		void save(OutputStream& os, int ioMode = IoSerialize) const
   138  		{
   139  			const char sep = *fp::getIoSeparator(ioMode);
   140  			c[0].save(os, ioMode);
   141  			if (sep) cybozu::writeChar(os, sep);
   142  			c[1].save(os, ioMode);
   143  			if (sep) cybozu::writeChar(os, sep);
   144  			s[0].save(os, ioMode);
   145  			if (sep) cybozu::writeChar(os, sep);
   146  			s[1].save(os, ioMode);
   147  		}
   148  		void getStr(std::string& str, int ioMode = 0) const
   149  		{
   150  			str.clear();
   151  			cybozu::StringOutputStream os(str);
   152  			save(os, ioMode);
   153  		}
   154  		std::string getStr(int ioMode = 0) const
   155  		{
   156  			std::string str;
   157  			getStr(str, ioMode);
   158  			return str;
   159  		}
   160  		void setStr(const std::string& str, int ioMode = 0)
   161  		{
   162  			cybozu::StringInputStream is(str);
   163  			load(is, ioMode);
   164  		}
   165  		friend inline std::ostream& operator<<(std::ostream& os, const Zkp& self)
   166  		{
   167  			self.save(os, fp::detectIoMode(Ec::getIoMode(), os));
   168  			return os;
   169  		}
   170  		friend inline std::istream& operator>>(std::istream& is, Zkp& self)
   171  		{
   172  			self.load(is, fp::detectIoMode(Ec::getIoMode(), is));
   173  			return is;
   174  		}
   175  		// obsolete
   176  		std::string toStr() const { return getStr(); }
   177  		void fromStr(const std::string& str) { setStr(str); }
   178  	};
   179  
   180  	class PublicKey {
   181  		size_t bitSize;
   182  		Ec g;
   183  		Ec h;
   184  		bool enableWindowMethod_;
   185  		fp::WindowMethod<Ec> wm_g;
   186  		fp::WindowMethod<Ec> wm_h;
   187  		template<class N>
   188  		void mulDispatch(Ec& z, const Ec& x, const N& n, const fp::WindowMethod<Ec>& pw) const
   189  		{
   190  			if (enableWindowMethod_) {
   191  				pw.mul(z, n);
   192  			} else {
   193  				Ec::mul(z, x, n);
   194  			}
   195  		}
   196  		template<class N>
   197  		void mulG(Ec& z, const N& n) const { mulDispatch(z, g, n, wm_g); }
   198  		template<class N>
   199  		void mulH(Ec& z, const N& n) const { mulDispatch(z, h, n, wm_h); }
   200  	public:
   201  		PublicKey()
   202  			: bitSize(0)
   203  			, enableWindowMethod_(false)
   204  		{
   205  		}
   206  		void enableWindowMethod(size_t winSize = 10)
   207  		{
   208  			wm_g.init(g, bitSize, winSize);
   209  			wm_h.init(h, bitSize, winSize);
   210  			enableWindowMethod_ = true;
   211  		}
   212  		const Ec& getG() const { return g; }
   213  		void init(size_t bitSize, const Ec& g, const Ec& h)
   214  		{
   215  			this->bitSize = bitSize;
   216  			this->g = g;
   217  			this->h = h;
   218  			enableWindowMethod_ = false;
   219  			enableWindowMethod();
   220  		}
   221  		/*
   222  			encode message
   223  			input : m
   224  			output : c = (c1, c2) = (g^u, h^u g^m)
   225  		*/
   226  		void enc(CipherText& c, const Zn& m, fp::RandGen rg = fp::RandGen()) const
   227  		{
   228  			Zn u;
   229  			u.setRand(rg);
   230  			mulG(c.c1, u);
   231  			mulH(c.c2, u);
   232  			Ec t;
   233  			mulG(t, m);
   234  			Ec::add(c.c2, c.c2, t);
   235  		}
   236  		/*
   237  			encode message
   238  			input : m = 0 or 1
   239  			output : c (c1, c2), zkp
   240  		*/
   241  		void encWithZkp(CipherText& c, Zkp& zkp, int m, fp::RandGen rg = fp::RandGen()) const
   242  		{
   243  			if (m != 0 && m != 1) {
   244  				throw cybozu::Exception("elgamal:PublicKey:encWithZkp") << m;
   245  			}
   246  			Zn u;
   247  			u.setRand(rg);
   248  			mulG(c.c1, u);
   249  			mulH(c.c2, u);
   250  			Ec t1, t2;
   251  			Ec R1[2], R2[2];
   252  			zkp.c[1-m].setRand(rg);
   253  			zkp.s[1-m].setRand(rg);
   254  			mulG(t1, zkp.s[1-m]);
   255  			Ec::mul(t2, c.c1, zkp.c[1-m]);
   256  			Ec::sub(R1[1-m], t1, t2);
   257  			mulH(t1, zkp.s[1-m]);
   258  			if (m) {
   259  				Ec::add(c.c2, c.c2, g);
   260  				Ec::mul(t2, c.c2, zkp.c[0]);
   261  			} else {
   262  				Ec::sub(t2, c.c2, g);
   263  				Ec::mul(t2, t2, zkp.c[1]);
   264  			}
   265  			Ec::sub(R2[1-m], t1, t2);
   266  			Zn r;
   267  			r.setRand(rg);
   268  			mulG(R1[m], r);
   269  			mulH(R2[m], r);
   270  			std::ostringstream os;
   271  			os << R1[0] << R2[0] << R1[1] << R2[1] << c.c1 << c.c2 << g << h;
   272  			Zn cc;
   273  			cc.setHashOf(os.str());
   274  			zkp.c[m] = cc - zkp.c[1-m];
   275  			zkp.s[m] = r + zkp.c[m] * u;
   276  		}
   277  		/*
   278  			verify cipher text with ZKP
   279  		*/
   280  		bool verify(const CipherText& c, const Zkp& zkp) const
   281  		{
   282  			Ec R1[2], R2[2];
   283  			Ec t1, t2;
   284  			mulG(t1, zkp.s[0]);
   285  			Ec::mul(t2, c.c1, zkp.c[0]);
   286  			Ec::sub(R1[0], t1, t2);
   287  			mulH(t1, zkp.s[0]);
   288  			Ec::mul(t2, c.c2, zkp.c[0]);
   289  			Ec::sub(R2[0], t1, t2);
   290  			mulG(t1, zkp.s[1]);
   291  			Ec::mul(t2, c.c1, zkp.c[1]);
   292  			Ec::sub(R1[1], t1, t2);
   293  			mulH(t1, zkp.s[1]);
   294  			Ec::sub(t2, c.c2, g);
   295  			Ec::mul(t2, t2, zkp.c[1]);
   296  			Ec::sub(R2[1], t1, t2);
   297  			std::ostringstream os;
   298  			os << R1[0] << R2[0] << R1[1] << R2[1] << c.c1 << c.c2 << g << h;
   299  			Zn cc;
   300  			cc.setHashOf(os.str());
   301  			return cc == zkp.c[0] + zkp.c[1];
   302  		}
   303  		/*
   304  			rerandomize encoded message
   305  			input : c = (c1, c2)
   306  			output : c = (c1 g^v, c2 h^v)
   307  		*/
   308  		void rerandomize(CipherText& c, fp::RandGen rg = fp::RandGen()) const
   309  		{
   310  			Zn v;
   311  			v.setRand(rg);
   312  			Ec t;
   313  			mulG(t, v);
   314  			Ec::add(c.c1, c.c1, t);
   315  			mulH(t, v);
   316  			Ec::add(c.c2, c.c2, t);
   317  		}
   318  		/*
   319  			add encoded message with plain message
   320  			input : c = Enc(m1) = (c1, c2), m2
   321  			ouput : c = Enc(m1 + m2) = (c1, c2 g^m2)
   322  		*/
   323  		template<class N>
   324  		void add(CipherText& c, const N& m) const
   325  		{
   326  			Ec fm;
   327  			mulG(fm, m);
   328  			Ec::add(c.c2, c.c2, fm);
   329  		}
   330  		template<class InputStream>
   331  		void load(InputStream& is, int ioMode = IoSerialize)
   332  		{
   333  			std::string s;
   334  			mcl::fp::local::loadWord(s, is);
   335  			bitSize = cybozu::atoi(s);
   336  			g.load(is, ioMode);
   337  			h.load(is, ioMode);
   338  			init(bitSize, g, h);
   339  		}
   340  		template<class OutputStream>
   341  		void save(OutputStream& os, int ioMode = IoSerialize) const
   342  		{
   343  			std::string s = cybozu::itoa(bitSize);
   344  			cybozu::write(os, s.c_str(), s.size());
   345  			cybozu::writeChar(os, ' ');
   346  
   347  			const char sep = *fp::getIoSeparator(ioMode);
   348  			if (sep) cybozu::writeChar(os, sep);
   349  			g.save(os, ioMode);
   350  			if (sep) cybozu::writeChar(os, sep);
   351  			h.save(os, ioMode);
   352  			if (sep) cybozu::writeChar(os, sep);
   353  		}
   354  		void getStr(std::string& str, int ioMode = 0) const
   355  		{
   356  			str.clear();
   357  			cybozu::StringOutputStream os(str);
   358  			save(os, ioMode);
   359  		}
   360  		std::string getStr(int ioMode = 0) const
   361  		{
   362  			std::string str;
   363  			getStr(str, ioMode);
   364  			return str;
   365  		}
   366  		void setStr(const std::string& str, int ioMode = 0)
   367  		{
   368  			cybozu::StringInputStream is(str);
   369  			load(is, ioMode);
   370  		}
   371  		friend inline std::ostream& operator<<(std::ostream& os, const PublicKey& self)
   372  		{
   373  			self.save(os, fp::detectIoMode(Ec::getIoMode(), os));
   374  			return os;
   375  		}
   376  		friend inline std::istream& operator>>(std::istream& is, PublicKey& self)
   377  		{
   378  			self.load(is, fp::detectIoMode(Ec::getIoMode(), is));
   379  			return is;
   380  		}
   381  		// obsolete
   382  		std::string toStr() const { return getStr(); }
   383  		void fromStr(const std::string& str) { setStr(str); }
   384  	};
   385  	/*
   386  		create table g^i for i in [rangeMin, rangeMax]
   387  	*/
   388  	struct PowerCache {
   389  #if (CYBOZU_CPP_VERSION > CYBOZU_CPP_VERSION_CP03)
   390  		typedef CYBOZU_NAMESPACE_STD::unordered_map<Ec, int> Cache;
   391  #else
   392  		typedef std::map<Ec, int> Cache;
   393  #endif
   394  		Cache cache;
   395  		void init(const Ec& g, int rangeMin, int rangeMax)
   396  		{
   397  			if (rangeMin > rangeMax) throw cybozu::Exception("mcl:ElgamalT:PowerCache:bad range") << rangeMin << rangeMax;
   398  			Ec x;
   399  			x.clear();
   400  			cache[x] = 0;
   401  			for (int i = 1; i <= rangeMax; i++) {
   402  				Ec::add(x, x, g);
   403  				cache[x] = i;
   404  			}
   405  			Ec nf;
   406  			Ec::neg(nf, g);
   407  			x.clear();
   408  			for (int i = -1; i >= rangeMin; i--) {
   409  				Ec::add(x, x, nf);
   410  				cache[x] = i;
   411  			}
   412  		}
   413  		/*
   414  			return m such that g^m = y
   415  		*/
   416  		int getExponent(const Ec& y, bool *b = 0) const
   417  		{
   418  			typename Cache::const_iterator i = cache.find(y);
   419  			if (i == cache.end()) {
   420  				if (b) {
   421  					*b = false;
   422  					return 0;
   423  				}
   424  				throw cybozu::Exception("Elgamal:PowerCache:getExponent:not found") << y;
   425  			}
   426  			if (b) *b = true;
   427  			return i->second;
   428  		}
   429  		void clear()
   430  		{
   431  			cache.clear();
   432  		}
   433  		bool isEmpty() const
   434  		{
   435  			return cache.empty();
   436  		}
   437  	};
   438  	class PrivateKey {
   439  		PublicKey pub;
   440  		Zn z;
   441  		PowerCache cache;
   442  	public:
   443  		/*
   444  			init
   445  			input : g
   446  			output : (h, z)
   447  			Ec = <g>
   448  			h = g^z
   449  		*/
   450  		void init(const Ec& g, size_t bitSize, fp::RandGen rg = fp::RandGen())
   451  		{
   452  			Ec h;
   453  			z.setRand(rg);
   454  			Ec::mul(h, g, z);
   455  			pub.init(bitSize, g, h);
   456  		}
   457  		const PublicKey& getPublicKey() const { return pub; }
   458  		/*
   459  			decode message by brute-force attack
   460  			input : c = (c1, c2)
   461  			output : m
   462  			M = c2 / c1^z
   463  			find m such that M = g^m and |m| < limit
   464  			@memo 7sec@core i3 for m = 1e6
   465  		*/
   466  		void dec(Zn& m, const CipherText& c, int limit = 100000) const
   467  		{
   468  			const Ec& g = pub.getG();
   469  			Ec c1z;
   470  			Ec::mul(c1z, c.c1, z);
   471  			if (c1z == c.c2) {
   472  				m = 0;
   473  				return;
   474  			}
   475  			Ec t1(c1z);
   476  			Ec t2(c.c2);
   477  			for (int i = 1; i < limit; i++) {
   478  				Ec::add(t1, t1, g);
   479  				if (t1 == c.c2) {
   480  					m = i;
   481  					return;
   482  				}
   483  				Ec::add(t2, t2, g);
   484  				if (t2 == c1z) {
   485  					m = -i;
   486  					return;
   487  				}
   488  			}
   489  			throw cybozu::Exception("elgamal:PrivateKey:dec:overflow");
   490  		}
   491  		/*
   492  			powgm = c2 / c1^z = g^m
   493  		*/
   494  		void getPowerg(Ec& powgm, const CipherText& c) const
   495  		{
   496  			Ec c1z;
   497  			Ec::mul(c1z, c.c1, z);
   498  			Ec::sub(powgm, c.c2, c1z);
   499  		}
   500  		/*
   501  			set range of message to decode quickly
   502  		*/
   503  		void setCache(int rangeMin, int rangeMax)
   504  		{
   505  			cache.init(pub.getG(), rangeMin, rangeMax);
   506  		}
   507  		/*
   508  			clear cache
   509  		*/
   510  		void clearCache()
   511  		{
   512  			cache.clear();
   513  		}
   514  		/*
   515  			decode message by lookup table if !cache.isEmpty()
   516  			                  brute-force attack otherwise
   517  			input : c = (c1, c2)
   518  			        b : set false if not found
   519  			return m
   520  		*/
   521  		int dec(const CipherText& c, bool *b = 0) const
   522  		{
   523  			Ec powgm;
   524  			getPowerg(powgm, c);
   525  			return cache.getExponent(powgm, b);
   526  		}
   527  		/*
   528  			check whether c is encrypted zero message
   529  		*/
   530  		bool isZeroMessage(const CipherText& c) const
   531  		{
   532  			Ec c1z;
   533  			Ec::mul(c1z, c.c1, z);
   534  			return c.c2 == c1z;
   535  		}
   536  		template<class InputStream>
   537  		void load(InputStream& is, int ioMode = IoSerialize)
   538  		{
   539  			pub.load(is, ioMode);
   540  			z.load(is, ioMode);
   541  		}
   542  		template<class OutputStream>
   543  		void save(OutputStream& os, int ioMode = IoSerialize) const
   544  		{
   545  			const char sep = *fp::getIoSeparator(ioMode);
   546  			pub.save(os, ioMode);
   547  			if (sep) cybozu::writeChar(os, sep);
   548  			z.save(os, ioMode);
   549  		}
   550  		void getStr(std::string& str, int ioMode = 0) const
   551  		{
   552  			str.clear();
   553  			cybozu::StringOutputStream os(str);
   554  			save(os, ioMode);
   555  		}
   556  		std::string getStr(int ioMode = 0) const
   557  		{
   558  			std::string str;
   559  			getStr(str, ioMode);
   560  			return str;
   561  		}
   562  		void setStr(const std::string& str, int ioMode = 0)
   563  		{
   564  			cybozu::StringInputStream is(str);
   565  			load(is, ioMode);
   566  		}
   567  		friend inline std::ostream& operator<<(std::ostream& os, const PrivateKey& self)
   568  		{
   569  			self.save(os, fp::detectIoMode(Ec::getIoMode(), os));
   570  			return os;
   571  		}
   572  		friend inline std::istream& operator>>(std::istream& is, PrivateKey& self)
   573  		{
   574  			self.load(is, fp::detectIoMode(Ec::getIoMode(), is));
   575  			return is;
   576  		}
   577  		std::string toStr() const { return getStr(); }
   578  		void fromStr(const std::string& str) { setStr(str); }
   579  	};
   580  };
   581  
   582  } // mcl