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