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