#pragma once /** @file @brief aggregate signature @author MITSUNARI Shigeo(@herumi) see http://crypto.stanford.edu/~dabo/papers/aggreg.pdf @license modified new BSD license http://opensource.org/licenses/BSD-3-Clause */ #include #include #include #include #ifndef MCLBN_FP_UNIT_SIZE #define MCLBN_FP_UNIT_SIZE 4 #endif #if MCLBN_FP_UNIT_SIZE == 4 #include namespace mcl { using namespace mcl::bn256; } #elif MCLBN_FP_UNIT_SIZE == 6 #include namespace mcl { using namespace mcl::bn384; } #elif MCLBN_FP_UNIT_SIZE == 8 #include namespace mcl { using namespace mcl::bn512; } #else #error "MCLBN_FP_UNIT_SIZE must be 4, 6, or 8" #endif namespace mcl { namespace aggs { /* AGGregate Signature Template class */ template struct AGGST { typedef typename G1::BaseFp Fp; class SecretKey; class PublicKey; class Signature; static G1 P_; static G2 Q_; static std::vector Qcoeff_; public: static void init(const mcl::CurveParam& cp = mcl::BN254) { initPairing(cp); hashAndMapToG1(P_, "0"); hashAndMapToG2(Q_, "0"); precomputeG2(Qcoeff_, Q_); } class Signature : public fp::Serializable { G1 S_; friend class SecretKey; friend class PublicKey; public: template void load(InputStream& is, int ioMode = IoSerialize) { S_.load(is, ioMode); } template void save(OutputStream& os, int ioMode = IoSerialize) const { S_.save(os, ioMode); } friend std::istream& operator>>(std::istream& is, Signature& self) { self.load(is, fp::detectIoMode(G1::getIoMode(), is)); return is; } friend std::ostream& operator<<(std::ostream& os, const Signature& self) { self.save(os, fp::detectIoMode(G1::getIoMode(), os)); return os; } bool operator==(const Signature& rhs) const { return S_ == rhs.S_; } bool operator!=(const Signature& rhs) const { return !operator==(rhs); } /* aggregate sig[0..n) and set *this */ void aggregate(const Signature *sig, size_t n) { G1 S; S.clear(); for (size_t i = 0; i < n; i++) { S += sig[i].S_; } S_ = S; } void aggregate(const std::vector& sig) { aggregate(sig.data(), sig.size()); } /* aggregate verification */ bool verify(const void *const *msgVec, const size_t *sizeVec, const PublicKey *pubVec, size_t n) const { if (n == 0) return false; typedef std::set FpSet; FpSet msgSet; typedef std::vector G1Vec; G1Vec hv(n); for (size_t i = 0; i < n; i++) { Fp h; h.setHashOf(msgVec[i], sizeVec[i]); std::pair ret = msgSet.insert(h); if (!ret.second) throw cybozu::Exception("aggs::verify:same msg"); mapToG1(hv[i], h); } /* e(aggSig, xQ) = prod_i e(hv[i], pub[i].Q) <=> finalExp(e(-aggSig, xQ) * prod_i millerLoop(hv[i], pub[i].xQ)) == 1 */ GT e1, e2; precomputedMillerLoop(e1, -S_, Qcoeff_); millerLoop(e2, hv[0], pubVec[0].xQ_); for (size_t i = 1; i < n; i++) { GT e; millerLoop(e, hv[i], pubVec[i].xQ_); e2 *= e; } e1 *= e2; finalExp(e1, e1); return e1.isOne(); } bool verify(const std::vector& msgVec, const std::vector& pubVec) const { const size_t n = msgVec.size(); if (n != pubVec.size()) throw cybozu::Exception("aggs:Signature:verify:bad size") << msgVec.size() << pubVec.size(); if (n == 0) return false; std::vector mv(n); std::vector sv(n); for (size_t i = 0; i < n; i++) { mv[i] = msgVec[i].c_str(); sv[i] = msgVec[i].size(); } return verify(&mv[0], &sv[0], &pubVec[0], n); } }; class PublicKey : public fp::Serializable { G2 xQ_; friend class SecretKey; friend class Signature; public: template void load(InputStream& is, int ioMode = IoSerialize) { xQ_.load(is, ioMode); } template void save(OutputStream& os, int ioMode = IoSerialize) const { xQ_.save(os, ioMode); } friend std::istream& operator>>(std::istream& is, PublicKey& self) { self.load(is, fp::detectIoMode(G2::getIoMode(), is)); return is; } friend std::ostream& operator<<(std::ostream& os, const PublicKey& self) { self.save(os, fp::detectIoMode(G2::getIoMode(), os)); return os; } bool operator==(const PublicKey& rhs) const { return xQ_ == rhs.xQ_; } bool operator!=(const PublicKey& rhs) const { return !operator==(rhs); } bool verify(const Signature& sig, const void *m, size_t mSize) const { /* H = hash(m) e(S, Q) = e(H, xQ) where S = xH <=> e(S, Q)e(-H, xQ) = 1 <=> finalExp(millerLoop(S, Q)e(-H, x)) = 1 */ G1 H; hashAndMapToG1(H, m, mSize); G1::neg(H, H); GT e1, e2; precomputedMillerLoop(e1, sig.S_, Qcoeff_); millerLoop(e2, H, xQ_); e1 *= e2; finalExp(e1, e1); return e1.isOne(); } bool verify(const Signature& sig, const std::string& m) const { return verify(sig, m.c_str(), m.size()); } }; class SecretKey : public fp::Serializable { Fr x_; friend class PublicKey; friend class Signature; public: template void load(InputStream& is, int ioMode = IoSerialize) { x_.load(is, ioMode); } template void save(OutputStream& os, int ioMode = IoSerialize) const { x_.save(os, ioMode); } friend std::istream& operator>>(std::istream& is, SecretKey& self) { self.load(is, fp::detectIoMode(Fr::getIoMode(), is)); return is; } friend std::ostream& operator<<(std::ostream& os, const SecretKey& self) { self.save(os, fp::detectIoMode(Fr::getIoMode(), os)); return os; } bool operator==(const SecretKey& rhs) const { return x_ == rhs.x_; } bool operator!=(const SecretKey& rhs) const { return !operator==(rhs); } void init() { x_.setByCSPRNG(); } void getPublicKey(PublicKey& pub) const { G2::mul(pub.xQ_, Q_, x_); } void sign(Signature& sig, const void *m, size_t mSize) const { hashAndMapToG1(sig.S_, m, mSize); G1::mul(sig.S_, sig.S_, x_); } void sign(Signature& sig, const std::string& m) const { sign(sig, m.c_str(), m.size()); } }; }; template G1 AGGST::P_; template G2 AGGST::Q_; template std::vector AGGST::Qcoeff_; typedef AGGST<> AGGS; typedef AGGS::SecretKey SecretKey; typedef AGGS::PublicKey PublicKey; typedef AGGS::Signature Signature; } } // mcl::aggs