diff --git a/include/mcl/she.hpp b/include/mcl/she.hpp index 54ec13c..4b7fe0f 100644 --- a/include/mcl/she.hpp +++ b/include/mcl/she.hpp @@ -370,6 +370,25 @@ struct SHET { static bool useDecG1ViaGT_; static bool useDecG2ViaGT_; static bool isG1only_; + /* + auxiliary for ZkpDecGT + @note GT is multiplicative group though treating GT as additive group in comment + */ + struct AuxiliaryForZkpDecGT { + GT P[4]; // [R = e(P, Q), xR, yR, xyR] + + // dst = v[1] a[0] + v[0] a[1] - v[2] a[2] + void f(GT& dst, const GT *v, const Fr *a) const + { + GT t; + GT::pow(dst, v[0], a[1]); + GT::pow(t, v[1], a[0]); + dst *= t; + GT::pow(t, v[2], a[2]); + GT::unitaryInv(t, t); + dst *= t; + } + }; private: template class CipherTextAT : public fp::Serializable > { @@ -566,6 +585,7 @@ private: struct ZkpEqTag; // d_[] = { c, sp, ss, sm } struct ZkpBinEqTag; // d_[] = { d0, d1, sp0, sp1, ss, sp, sm } struct ZkpDecTag; // d_[] = { c, h } + struct ZkpDecGTTag; // d_[] = { d1, d2, d3, h } public: /* Zkp for m = 0 or 1 @@ -580,9 +600,13 @@ public: */ typedef ZkpT ZkpBinEq; /* - Zkp for Dec(c) = m + Zkp for Dec(c) = m for c in G1 */ typedef ZkpT ZkpDec; + /* + Zkp for Dec(c) = m for c in GT + */ + typedef ZkpT ZkpDecGT; typedef CipherTextAT CipherTextG1; typedef CipherTextAT CipherTextG2; @@ -833,6 +857,42 @@ public: d += b; return m; } + // @note GT is multiplicative group though treating GT as additive group in comment + int64_t decWithZkpDec(bool *pok, ZkpDecGT& zkp, const CipherTextGT& c, const AuxiliaryForZkpDecGT& aux) const + { + int64_t m = dec(c, pok); + if (!*pok) return 0; + // A = c - Enc(m; 0, 0, 0) = c - (m R, 0, 0, 0) + GT A[4]; + GT t; + GT::pow(t, aux.P[0], m); // m R + GT::unitaryInv(t, t); + GT::mul(A[0], c.g_[0], t); + A[1] = c.g_[1]; + A[2] = c.g_[2]; + A[3] = c.g_[3]; + // dec(A) = 0 + + Fr b[3]; + GT B[3], X; + for (int i = 0; i < 3; i++) { + b[i].setByCSPRNG(); + GT::pow(B[i], aux.P[0], b[i]); + } + aux.f(X, A + 1, b); + local::Hash hash; + hash << aux.P[1] << aux.P[2] << aux.P[3] << A[0] << A[1] << A[2] << A[3] << B[0] << B[1] << B[2] << X; + Fr *d = &zkp.d_[0]; + Fr &h = zkp.d_[3]; + hash.get(h); + Fr::mul(d[0], h, x_); // h x + Fr::mul(d[1], h, y_); // h y + Fr::mul(d[2], d[1], x_); // h xy + for (int i = 0; i < 3; i++) { + d[i] += b[i]; + } + return m; + } int64_t decWithZkpDec(ZkpDec& zkp, const CipherTextG1& c, const PublicKey& pub) const { bool b; @@ -840,6 +900,13 @@ public: if (!b) throw cybozu::Exception("she:SecretKey:decWithZkpDec"); return ret; } + int64_t decWithZkpDec(ZkpDecGT& zkp, const CipherTextGT& c, const AuxiliaryForZkpDecGT& aux) const + { + bool b; + int64_t ret = decWithZkpDec(&b, zkp, c, aux); + if (!b) throw cybozu::Exception("she:SecretKey:decWithZkpDec"); + return ret; + } template void load(bool *pb, InputStream& is, int ioMode = IoSerialize) { @@ -1284,6 +1351,13 @@ public: ElGamalEnc(c.S_, c.T_, m, QhashTbl_.getWM(), yQmul); } public: + void getAuxiliaryForZkpDecGT(AuxiliaryForZkpDecGT& aux) const + { + aux.P[0] = ePQ_; + pairing(aux.P[1], xP_, Q_); + pairing(aux.P[2], P_, yQ_); + pairing(aux.P[3], xP_, yQ_); + } void encWithZkpBin(CipherTextG1& c, ZkpBin& zkp, int m) const { Fr encRand; @@ -1332,6 +1406,36 @@ public: hash.get(h2); return h == h2; } + bool verify(const CipherTextGT& c, int64_t m, const ZkpDecGT& zkp, const AuxiliaryForZkpDecGT& aux) const + { + const Fr *d = &zkp.d_[0]; + const Fr &h = zkp.d_[3]; + + GT A[4]; + GT t; + GT::pow(t, aux.P[0], m); // m R + GT::unitaryInv(t, t); + GT::mul(A[0], c.g_[0], t); + A[1] = c.g_[1]; + A[2] = c.g_[2]; + A[3] = c.g_[3]; + GT B[3], X; + for (int i = 0; i < 3; i++) { + GT::pow(B[i], aux.P[0], d[i]); + GT::pow(t, aux.P[i+1], h); + GT::unitaryInv(t, t); + B[i] *= t; + } + aux.f(X, A + 1, zkp.d_); + GT::pow(t, A[0], h); + GT::unitaryInv(t, t); + X *= t; + local::Hash hash; + hash << aux.P[1] << aux.P[2] << aux.P[3] << A[0] << A[1] << A[2] << A[3] << B[0] << B[1] << B[2] << X; + Fr h2; + hash.get(h2); + return h == h2; + } bool verify(const CipherTextG2& c, const ZkpBin& zkp) const { const MulG yQmul(yQ_); @@ -1941,6 +2045,8 @@ typedef SHE::ZkpBin ZkpBin; typedef SHE::ZkpEq ZkpEq; typedef SHE::ZkpBinEq ZkpBinEq; typedef SHE::ZkpDec ZkpDec; +typedef SHE::AuxiliaryForZkpDecGT AuxiliaryForZkpDecGT; +typedef SHE::ZkpDecGT ZkpDecGT; inline void init(const mcl::CurveParam& cp = mcl::BN254, size_t hashSize = 1024, size_t tryNum = local::defaultTryNum) { diff --git a/test/she_test.cpp b/test/she_test.cpp index f7095ec..9165a36 100644 --- a/test/she_test.cpp +++ b/test/she_test.cpp @@ -331,7 +331,7 @@ CYBOZU_TEST_AUTO(ZkpBinEq) ZkpBinEqTest(sec, ppub); } -CYBOZU_TEST_AUTO(ZkpDec) +CYBOZU_TEST_AUTO(ZkpDecG1) { const SecretKey& sec = g_sec; PublicKey pub; @@ -350,6 +350,27 @@ CYBOZU_TEST_AUTO(ZkpDec) CYBOZU_TEST_ASSERT(!pub.verify(c, m, zkp)); } +CYBOZU_TEST_AUTO(ZkpDecGT) +{ + const SecretKey& sec = g_sec; + PublicKey pub; + sec.getPublicKey(pub); + AuxiliaryForZkpDecGT aux; + pub.getAuxiliaryForZkpDecGT(aux); + CipherTextGT c; + int m = 123; + pub.enc(c, m); + ZkpDecGT zkp; + CYBOZU_TEST_EQUAL(sec.decWithZkpDec(zkp, c, aux), m); + CYBOZU_TEST_ASSERT(pub.verify(c, m, zkp, aux)); + CYBOZU_TEST_ASSERT(!pub.verify(c, m + 1, zkp, aux)); + CipherTextGT c2; + pub.enc(c2, m); + CYBOZU_TEST_ASSERT(!pub.verify(c2, m, zkp, aux)); + zkp.d_[0] += 1; + CYBOZU_TEST_ASSERT(!pub.verify(c, m, zkp, aux)); +} + CYBOZU_TEST_AUTO(add_sub_mul) { const SecretKey& sec = g_sec;