Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions include/bls/bls.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,11 +72,22 @@ 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 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);
Expand Down
3 changes: 3 additions & 0 deletions include/bls/bls.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -226,6 +227,8 @@ 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;
bool verifyAggregatedHashes(const PublicKey* pubs, const void* hashVec, size_t hashSize, size_t hashCount) const;
/*
verify self(pop) with pub
*/
Expand Down
71 changes: 64 additions & 7 deletions src/bls.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
*/
#include <cybozu/crypto.hpp>
#include <vector>
#include <set>
#include <string>
#define MCLBN_NO_AUTOLINK
#include <bls/bls.hpp>
Expand Down Expand Up @@ -283,10 +284,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)
Expand All @@ -297,25 +296,73 @@ bool Signature::verify(const PublicKey& pub, const std::string& m) const
*/
Fp12 e;
std::vector<Fp6> 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;
pub.getInner().sQ.getStr(str);
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<Fp> FpSet;
FpSet msgSet;
typedef std::vector<G1> G1Vec;
G1Vec hv(hashCount);
for (size_t i = 0; i < hashCount; i++) {
Fp h;
h.setArrayMask((const char*)hashVec + i * hashSize, hashSize);
std::pair<typename FpSet::iterator, bool> 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();
Expand Down Expand Up @@ -434,6 +481,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;
Expand Down
55 changes: 55 additions & 0 deletions src/bls_c.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@

#include <bls/bls.h>

#include <set>

#include "../mcl/src/bn_c_impl.hpp"

/*
Expand Down Expand Up @@ -123,6 +125,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))
Expand All @@ -149,6 +160,50 @@ 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));
}

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<Fp> FpSet;
FpSet msgSet;
typedef std::vector<G1> G1Vec;
G1Vec hv(hashCount);
for (size_t i = 0; i < hashCount; i++) {
Fp h;
h.setArrayMask((const char*)hashVec + i * hashSize, hashSize);
std::pair<typename FpSet::iterator, bool> 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);
Expand Down
35 changes: 35 additions & 0 deletions test/bls_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
#include <cybozu/inttype.hpp>
#include <iostream>
#include <sstream>
#include <array>
#include <cybozu/benchmark.hpp>
#include <cybozu/crypto.hpp>

template<class T>
void streamTest(const T& t)
Expand Down Expand Up @@ -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<char[32]> 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();
Expand Down Expand Up @@ -418,6 +452,7 @@ void testAll()
addTest();
dataTest();
aggregateTest();
verifyAggregateTest();
}
CYBOZU_TEST_AUTO(all)
{
Expand Down