From dcc7507fed6a9dcf8632854951e2e0d41b26c236 Mon Sep 17 00:00:00 2001 From: Alexander Block Date: Thu, 12 Apr 2018 08:14:45 +0200 Subject: [PATCH 1/3] Support signing and verification of hashes instead of messages --- include/bls/bls.h | 7 +++++++ include/bls/bls.hpp | 2 ++ src/bls.cpp | 38 +++++++++++++++++++++++++++++++------- src/bls_c.cpp | 22 ++++++++++++++++++++++ 4 files changed, 62 insertions(+), 7 deletions(-) diff --git a/include/bls/bls.h b/include/bls/bls.h index 21cd5b0e..9312782e 100644 --- a/include/bls/bls.h +++ b/include/bls/bls.h @@ -72,11 +72,18 @@ BLS_DLL_API int blsSecretKeySetLittleEndian(blsSecretKey *sec, const void *buf, BLS_DLL_API void blsGetPublicKey(blsPublicKey *pub, const blsSecretKey *sec); +// calculate the hash of m and sign the hash BLS_DLL_API void blsSign(blsSignature *sig, const blsSecretKey *sec, const void *m, mclSize size); // return 1 if valid BLS_DLL_API int blsVerify(const blsSignature *sig, const blsPublicKey *pub, const void *m, mclSize size); +// sign the hash +BLS_DLL_API void blsSignHash(blsSignature *sig, const blsSecretKey *sec, const void *h, mclSize size); + +// return 1 if valid +BLS_DLL_API int blsVerifyHash(const blsSignature *sig, const blsPublicKey *pub, const void *h, mclSize size); + // return written byte size if success else 0 BLS_DLL_API mclSize blsIdSerialize(void *buf, mclSize maxBufSize, const blsId *id); BLS_DLL_API mclSize blsSecretKeySerialize(void *buf, mclSize maxBufSize, const blsSecretKey *sec); diff --git a/include/bls/bls.hpp b/include/bls/bls.hpp index ca4d0ca4..e1572db5 100644 --- a/include/bls/bls.hpp +++ b/include/bls/bls.hpp @@ -136,6 +136,7 @@ class SecretKey { void getPublicKey(PublicKey& pub) const; // constant time sign void sign(Signature& sig, const std::string& m) const; + void signHash(Signature& sig, const void* hash, size_t hashSize) const; /* make Pop(Proof of Possesion) pop = prv.sign(pub) @@ -226,6 +227,7 @@ class Signature { void getStr(std::string& str, int ioMode = 0) const; void setStr(const std::string& str, int ioMode = 0); bool verify(const PublicKey& pub, const std::string& m) const; + bool verifyHash(const PublicKey& pub, const void *hash, size_t hashSize) const; /* verify self(pop) with pub */ diff --git a/src/bls.cpp b/src/bls.cpp index d83b259e..ba960c9b 100644 --- a/src/bls.cpp +++ b/src/bls.cpp @@ -283,10 +283,8 @@ void Signature::setStr(const std::string& str, int ioMode) getInner().sHm.setStr(str, ioMode); } -bool Signature::verify(const PublicKey& pub, const std::string& m) const +static bool VerifyMappedHash(const G2& sQ, const G1& sHm, const G1& Hm) { - G1 Hm; - HashAndMapToG1(Hm, m); // Hm = Hash(m) #if 1 /* e(P1, Q1) == e(P2, Q2) @@ -297,18 +295,34 @@ bool Signature::verify(const PublicKey& pub, const std::string& m) const */ Fp12 e; std::vector Q2coeff; - precomputeG2(Q2coeff, pub.getInner().sQ); - precomputedMillerLoop2(e, getInner().sHm, getQcoeff(), -Hm, Q2coeff); + precomputeG2(Q2coeff, sQ); + precomputedMillerLoop2(e, sHm, getQcoeff(), -Hm, Q2coeff); finalExp(e, e); return e.isOne(); #else Fp12 e1, e2; - pairing(e1, getInner().sHm, getQ()); // e(s Hm, Q) - pairing(e2, Hm, pub.getInner().sQ); // e(Hm, sQ) + pairing(e1, sHm, getQ()); // e(s Hm, Q) + pairing(e2, Hm, sQ); // e(Hm, sQ) return e1 == e2; #endif } +bool Signature::verify(const PublicKey& pub, const std::string& m) const +{ + G1 Hm; + HashAndMapToG1(Hm, m); // Hm = Hash(m) + return VerifyMappedHash(pub.getInner().sQ, getInner().sHm, Hm); +} + +bool Signature::verifyHash(const PublicKey& pub, const void *hash, size_t hashSize) const +{ + G1 Hm; + Fp t; + t.setArrayMask((const char*)hash, hashSize); + BN::mapToG1(Hm, t); + return VerifyMappedHash(pub.getInner().sQ, getInner().sHm, Hm); +} + bool Signature::verify(const PublicKey& pub) const { std::string str; @@ -434,6 +448,16 @@ void SecretKey::sign(Signature& sig, const std::string& m) const G1::mulCT(sig.getInner().sHm, Hm, getInner().s); } +void SecretKey::signHash(Signature& sig, const void* hash, size_t hashSize) const +{ + G1 Hm; + Fp t; + t.setArrayMask((const char*)hash, hashSize); + BN::mapToG1(Hm, t); +// G1::mul(sig.getInner().sHm, Hm, getInner().s); + G1::mulCT(sig.getInner().sHm, Hm, getInner().s); +} + void SecretKey::getPop(Signature& pop) const { PublicKey pub; diff --git a/src/bls_c.cpp b/src/bls_c.cpp index 75e5a443..a658bbbe 100644 --- a/src/bls_c.cpp +++ b/src/bls_c.cpp @@ -123,6 +123,15 @@ void blsSign(blsSignature *sig, const blsSecretKey *sec, const void *m, mclSize mclBnG1_mulCT(&sig->v, cast(&Hm), &sec->v); } +void blsSignHash(blsSignature *sig, const blsSecretKey *sec, const void *h, mclSize size) +{ + G1 Hm; + Fp t; + t.setArrayMask((const char*)h, size); + BN::mapToG1(Hm, t); + mclBnG1_mulCT(&sig->v, cast(&Hm), &sec->v); +} + /* e(P1, Q1) == e(P2, Q2) <=> finalExp(ML(P1, Q1)) == finalExp(ML(P2, Q2)) @@ -149,6 +158,19 @@ int blsVerify(const blsSignature *sig, const blsPublicKey *pub, const void *m, m return isEqualTwoPairings(*cast(&sig->v), getQcoeff().data(), Hm, *cast(&pub->v)); } +int blsVerifyHash(const blsSignature *sig, const blsPublicKey *pub, const void *h, mclSize size) +{ + G1 Hm; + Fp t; + t.setArrayMask((const char*)h, size); + BN::mapToG1(Hm, t); + /* + e(sHm, Q) = e(Hm, sQ) + e(sig, Q) = e(Hm, pub) + */ + return isEqualTwoPairings(*cast(&sig->v), getQcoeff().data(), Hm, *cast(&pub->v)); +} + mclSize blsIdSerialize(void *buf, mclSize maxBufSize, const blsId *id) { return mclBnFr_serialize(buf, maxBufSize, &id->v); From cb26013bf2ec821ba7c9be021786f17cb5ccb9a5 Mon Sep 17 00:00:00 2001 From: Alexander Block Date: Fri, 14 Sep 2018 11:11:56 +0200 Subject: [PATCH 2/3] Support aggregated verification --- include/bls/bls.h | 4 ++++ include/bls/bls.hpp | 1 + src/bls.cpp | 33 +++++++++++++++++++++++++++++++++ src/bls_c.cpp | 33 +++++++++++++++++++++++++++++++++ 4 files changed, 71 insertions(+) diff --git a/include/bls/bls.h b/include/bls/bls.h index 9312782e..bc48a2e1 100644 --- a/include/bls/bls.h +++ b/include/bls/bls.h @@ -84,6 +84,10 @@ BLS_DLL_API void blsSignHash(blsSignature *sig, const blsSecretKey *sec, const v // return 1 if valid BLS_DLL_API int blsVerifyHash(const blsSignature *sig, const blsPublicKey *pub, const void *h, mclSize size); +// return 1 if valid, 0 if invalid or when duplicated hashes were provided +// verify an aggregated signature given the public keys and message hashes. No duplicate message hashes allowed +BLS_DLL_API int blsVerifyAggregatedHashes(const blsSignature *sig, const blsPublicKey *pubVec, const void *hashVec, mclSize hashSize, mclSize hashCount); + // return written byte size if success else 0 BLS_DLL_API mclSize blsIdSerialize(void *buf, mclSize maxBufSize, const blsId *id); BLS_DLL_API mclSize blsSecretKeySerialize(void *buf, mclSize maxBufSize, const blsSecretKey *sec); diff --git a/include/bls/bls.hpp b/include/bls/bls.hpp index e1572db5..cc6a138c 100644 --- a/include/bls/bls.hpp +++ b/include/bls/bls.hpp @@ -228,6 +228,7 @@ class Signature { void setStr(const std::string& str, int ioMode = 0); bool verify(const PublicKey& pub, const std::string& m) const; bool verifyHash(const PublicKey& pub, const void *hash, size_t hashSize) const; + bool verifyAggregatedHashes(const PublicKey* pubs, const void* hashVec, size_t hashSize, size_t hashCount) const; /* verify self(pop) with pub */ diff --git a/src/bls.cpp b/src/bls.cpp index ba960c9b..4b29f158 100644 --- a/src/bls.cpp +++ b/src/bls.cpp @@ -6,6 +6,7 @@ */ #include #include +#include #include #define MCLBN_NO_AUTOLINK #include @@ -330,6 +331,38 @@ bool Signature::verify(const PublicKey& pub) const return verify(pub, str); } +bool Signature::verifyAggregatedHashes(const PublicKey* pubs, const void* hashVec, size_t hashSize, size_t hashCount) const +{ + if (hashCount == 0 || hashSize == 0) return false; + typedef std::set FpSet; + FpSet msgSet; + typedef std::vector G1Vec; + G1Vec hv(hashCount); + for (size_t i = 0; i < hashCount; i++) { + Fp h; + h.setArrayMask((const char*)hashVec + i * hashSize, hashSize); + std::pair ret = msgSet.insert(h); + if (!ret.second) throw cybozu::Exception("Signature:verifyAggregatedHashes:same msg"); + BN::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; + BN::precomputedMillerLoop(e1, -getInner().sHm, getQcoeff().data()); + BN::millerLoop(e2, hv[0], pubs[0].getInner().sQ); + for (size_t i = 1; i < hashCount; i++) { + GT e; + BN::millerLoop(e, hv[i], pubs[i].getInner().sQ); + e2 *= e; + } + e1 *= e2; + BN::finalExp(e1, e1); + return e1.isOne(); +} + + void Signature::recover(const SignatureVec& sigVec, const IdVec& idVec) { if (sigVec.size() != idVec.size()) throw cybozu::Exception("Signature:recover:bad size") << sigVec.size() << idVec.size(); diff --git a/src/bls_c.cpp b/src/bls_c.cpp index a658bbbe..e48f3bfe 100644 --- a/src/bls_c.cpp +++ b/src/bls_c.cpp @@ -3,6 +3,8 @@ #include +#include + #include "../mcl/src/bn_c_impl.hpp" /* @@ -171,6 +173,37 @@ int blsVerifyHash(const blsSignature *sig, const blsPublicKey *pub, const void * return isEqualTwoPairings(*cast(&sig->v), getQcoeff().data(), Hm, *cast(&pub->v)); } +int blsVerifyAggregatedHashes(const blsSignature *sig, const blsPublicKey *pubVec, const void *hashVec, mclSize hashSize, mclSize hashCount) +{ + if (hashCount == 0 || hashSize == 0) return false; + typedef std::set FpSet; + FpSet msgSet; + typedef std::vector G1Vec; + G1Vec hv(hashCount); + for (size_t i = 0; i < hashCount; i++) { + Fp h; + h.setArrayMask((const char*)hashVec + i * hashSize, hashSize); + std::pair ret = msgSet.insert(h); + if (!ret.second) return 0; + BN::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; + BN::precomputedMillerLoop(e1, -*cast(&sig->v), g_Qcoeff.data()); + BN::millerLoop(e2, hv[0], *cast(&pubVec[0].v)); + for (size_t i = 1; i < hashCount; i++) { + GT e; + BN::millerLoop(e, hv[i], *cast(&pubVec[i].v)); + e2 *= e; + } + e1 *= e2; + BN::finalExp(e1, e1); + return e1.isOne(); +} + mclSize blsIdSerialize(void *buf, mclSize maxBufSize, const blsId *id) { return mclBnFr_serialize(buf, maxBufSize, &id->v); From 34a627538704142beca654a3d7671a3f5a3d117c Mon Sep 17 00:00:00 2001 From: Alexander Block Date: Fri, 14 Sep 2018 12:49:40 +0200 Subject: [PATCH 3/3] Add tests for verifyAggregateTest --- test/bls_test.cpp | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/test/bls_test.cpp b/test/bls_test.cpp index b2a7860a..6104e635 100644 --- a/test/bls_test.cpp +++ b/test/bls_test.cpp @@ -3,7 +3,9 @@ #include #include #include +#include #include +#include template void streamTest(const T& t) @@ -365,6 +367,38 @@ void aggregateTest() CYBOZU_TEST_ASSERT(sig.verify(pub, m)); } +void verifyAggregateTest() +{ + const size_t n = 10; + bls::SecretKey secs[n]; + bls::PublicKey pubs[n]; + bls::Signature sigs[n], sig; + std::vector h(n); + for (size_t i = 0; i < n; i++) { + char msg[128]; + sprintf(msg, "abc-%d", (int)i); + + cybozu::crypto::Hash hash(cybozu::crypto::Hash::N_SHA256); + hash.digest(h[i], msg, strlen(msg)); + + secs[i].init(); + secs[i].getPublicKey(pubs[i]); + secs[i].signHash(sigs[i], h[i], 32); + } + sig = sigs[0]; + for (size_t i = 1; i < n; i++) { + sig.add(sigs[i]); + } + CYBOZU_TEST_ASSERT(sig.verifyAggregatedHashes(pubs, h.data(), 32, n)); + + bls::Signature invalidSig = sigs[0] + sigs[1]; + CYBOZU_TEST_ASSERT(!invalidSig.verifyAggregatedHashes(pubs, h.data(), 32, n)); + + h[0][0]++; + CYBOZU_TEST_ASSERT(!sig.verifyAggregatedHashes(pubs, h.data(), 32, n)); +} + + void dataTest() { const size_t FrSize = bls::getFrByteSize(); @@ -418,6 +452,7 @@ void testAll() addTest(); dataTest(); aggregateTest(); + verifyAggregateTest(); } CYBOZU_TEST_AUTO(all) {