Skip to content

Commit

Permalink
avoid copying of public keys, messages in batch validation
Browse files Browse the repository at this point in the history
  • Loading branch information
arvidn committed Mar 23, 2021
1 parent 53791a2 commit c6e2aa7
Show file tree
Hide file tree
Showing 4 changed files with 63 additions and 48 deletions.
39 changes: 25 additions & 14 deletions src/schemes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -184,8 +184,8 @@ bool CoreMPL::AggregateVerify(const vector<G1Element> &pubkeys,
return CoreMPL::AggregateVerify(pubkeys, std::vector<Bytes>(messages.begin(), messages.end()), signature);
}

bool CoreMPL::AggregateVerify(const vector<G1Element>& pubkeys,
const vector<Bytes> &messages,
bool CoreMPL::AggregateVerify(span<G1Element const> const pubkeys,
span<Bytes const> const messages,
const G2Element& signature)
{
const size_t nPubKeys = pubkeys.size();
Expand Down Expand Up @@ -297,8 +297,8 @@ bool BasicSchemeMPL::AggregateVerify(const vector<G1Element> &pubkeys,
return CoreMPL::AggregateVerify(pubkeys, messages, signature);
}

bool BasicSchemeMPL::AggregateVerify(const vector<G1Element>& pubkeys,
const vector<Bytes> &messages,
bool BasicSchemeMPL::AggregateVerify(span<G1Element const> const pubkeys,
span<Bytes const> const messages,
const G2Element& signature)
{
const size_t nPubKeys = pubkeys.size();
Expand Down Expand Up @@ -420,23 +420,34 @@ bool AugSchemeMPL::AggregateVerify(const vector<G1Element>& pubkeys,
return AugSchemeMPL::AggregateVerify(pubkeys, vecMessagesBytes, signature);
}

bool AugSchemeMPL::AggregateVerify(const vector<G1Element>& pubkeys,
const vector<Bytes>& messages,
bool AugSchemeMPL::AggregateVerify(span<G1Element const> const pubkeys,
span<Bytes const> const messages,
const G2Element& signature)
{
size_t nPubKeys = pubkeys.size();
auto arg_check = VerifyAggregateSignatureArguments(nPubKeys, messages.size(), signature);
if (pubkeys.size() != messages.size()) {
return false;
}

size_t const nPubKeys = pubkeys.size();
auto const arg_check = VerifyAggregateSignatureArguments(nPubKeys, messages.size(), signature);
if (arg_check != CONTINUE) {
return arg_check;
}

vector<vector<uint8_t>> augMessages(nPubKeys);
std::vector<uint8_t> storage;
for (std::size_t i = 0; i < nPubKeys; ++i) {
auto const pubkey = pubkeys[i].Serialize();
storage.insert(storage.end(), pubkey.begin(), pubkey.end());
storage.insert(storage.end(), messages[i].begin(), messages[i].end());
}

std::vector<Bytes> augMessages;
augMessages.reserve(nPubKeys);
uint8_t const* cursor = storage.data();
for (int i = 0; i < nPubKeys; ++i) {
vector<uint8_t>& aug = augMessages[i];
vector<uint8_t>&& pubkey = pubkeys[i].Serialize();
aug.reserve(pubkey.size() + messages[i].size());
aug.insert(aug.end(), pubkey.begin(), pubkey.end());
aug.insert(aug.end(), messages[i].begin(), messages[i].end());
auto const size = G1Element::SIZE + messages[i].size();
augMessages.emplace_back(cursor, size);
cursor += size;
}

return CoreMPL::AggregateVerify(pubkeys, augMessages, signature);
Expand Down
15 changes: 7 additions & 8 deletions src/schemes.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,13 @@

#include "elements.hpp"
#include "privatekey.hpp"
#include "util.hpp"

using std::vector;

// These are all MPL schemes
namespace bls {

class Bytes;

class CoreMPL {

public:
Expand Down Expand Up @@ -83,8 +82,8 @@ class CoreMPL {
const vector<vector<uint8_t>> &messages,
const G2Element &signature);

virtual bool AggregateVerify(const vector<G1Element>& pubkeys,
const vector<Bytes>& messages,
virtual bool AggregateVerify(span<G1Element const> pubkeys,
span<Bytes const> messages,
const G2Element& signature);

PrivateKey DeriveChildSk(const PrivateKey& sk, uint32_t index);
Expand Down Expand Up @@ -112,8 +111,8 @@ class BasicSchemeMPL : public CoreMPL {
const vector<vector<uint8_t>> &messages,
const G2Element &signature) override;

bool AggregateVerify(const vector<G1Element>& pubkeys,
const vector<Bytes>& messages,
bool AggregateVerify(span<G1Element const> pubkeys,
span<Bytes const> messages,
const G2Element& signature) override;
};

Expand Down Expand Up @@ -165,8 +164,8 @@ class AugSchemeMPL : public CoreMPL {
const vector<vector<uint8_t>> &messages,
const G2Element &signature) override;

bool AggregateVerify(const vector<G1Element>& pubkeys,
const vector<Bytes>& messages,
bool AggregateVerify(span<G1Element const> pubkeys,
span<Bytes const> messages,
const G2Element& signature) override;
};

Expand Down
34 changes: 17 additions & 17 deletions src/test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -360,8 +360,8 @@ TEST_CASE("Chia test vectors") {
"4a94d195d7b0231d4afcf06f27f0cc4d3c72162545c240de7d5034a7ef3a2a03c0159de982fb"
"c2e7790aeb455e27beae91d64e077c70b5506dea3");

REQUIRE(BasicSchemeMPL().AggregateVerify({pk1, pk2}, vector<vector<uint8_t>>{message1, message2}, aggSig1));
REQUIRE(!BasicSchemeMPL().AggregateVerify({pk1, pk2}, vector<vector<uint8_t>>{message1, message2}, sig1));
REQUIRE(BasicSchemeMPL().AggregateVerify(std::vector<G1Element>{pk1, pk2}, vector<vector<uint8_t>>{message1, message2}, aggSig1));
REQUIRE(!BasicSchemeMPL().AggregateVerify(std::vector<G1Element>{pk1, pk2}, vector<vector<uint8_t>>{message1, message2}, sig1));
REQUIRE(!BasicSchemeMPL().Verify(pk1, message1, sig2));
REQUIRE(!BasicSchemeMPL().Verify(pk1, message2, sig1));

Expand All @@ -375,7 +375,7 @@ TEST_CASE("Chia test vectors") {

G2Element aggSig2 = BasicSchemeMPL().Aggregate({sig3, sig4, sig5});

REQUIRE(BasicSchemeMPL().AggregateVerify({pk1, pk1, pk2}, vector<vector<uint8_t>>{message3, message4, message5}, aggSig2));
REQUIRE(BasicSchemeMPL().AggregateVerify(std::vector<G1Element>{pk1, pk1, pk2}, vector<vector<uint8_t>>{message3, message4, message5}, aggSig2));
REQUIRE(
Util::HexStr(aggSig2.Serialize()) ==
"a0b1378d518bea4d1100adbc7bdbc4ff64f2c219ed6395cd36fe5d2aa44a4b8e710b607afd9"
Expand Down Expand Up @@ -410,7 +410,7 @@ TEST_CASE("Chia test vectors") {
G2Element aggSigR = AugSchemeMPL().Aggregate({sig3, sig4, sig5});
G2Element aggSig = AugSchemeMPL().Aggregate({aggSigL, aggSigR, sig6});

REQUIRE(AugSchemeMPL().AggregateVerify({pk1, pk2, pk2, pk1, pk1, pk1}, vector<vector<uint8_t>>{message1, message2, message1, message3, message1, message4}, aggSig));
REQUIRE(AugSchemeMPL().AggregateVerify(std::vector<G1Element>{pk1, pk2, pk2, pk1, pk1, pk1}, vector<vector<uint8_t>>{message1, message2, message1, message3, message1, message4}, aggSig));

REQUIRE(
Util::HexStr(aggSig.Serialize()) ==
Expand Down Expand Up @@ -643,7 +643,7 @@ TEST_CASE("Signature tests")
G2Element sig2 = BasicSchemeMPL().Sign(sk2, message);

G2Element aggSig = BasicSchemeMPL().Aggregate({sig1, sig2});
REQUIRE(BasicSchemeMPL().AggregateVerify({pk1, pk2}, vector<vector<uint8_t>>{message, message}, aggSig) == false);
REQUIRE(BasicSchemeMPL().AggregateVerify(std::vector<G1Element>{pk1, pk2}, vector<vector<uint8_t>>{message, message}, aggSig) == false);
}

SECTION("Should verify aggregate with same message under AugScheme/PopScheme")
Expand All @@ -663,12 +663,12 @@ TEST_CASE("Signature tests")
G2Element sig1Aug = AugSchemeMPL().Sign(sk1, message);
G2Element sig2Aug = AugSchemeMPL().Sign(sk2, message);
G2Element aggSigAug = AugSchemeMPL().Aggregate({sig1Aug, sig2Aug});
REQUIRE(AugSchemeMPL().AggregateVerify({pk1, pk2}, vector<vector<uint8_t>>{message, message}, aggSigAug));
REQUIRE(AugSchemeMPL().AggregateVerify(std::vector<G1Element>{pk1, pk2}, vector<vector<uint8_t>>{message, message}, aggSigAug));

G2Element sig1Pop = PopSchemeMPL().Sign(sk1, message);
G2Element sig2Pop = PopSchemeMPL().Sign(sk2, message);
G2Element aggSigPop = PopSchemeMPL().Aggregate({sig1Pop, sig2Pop});
REQUIRE(PopSchemeMPL().AggregateVerify({pk1, pk2}, vector<vector<uint8_t>>{message, message}, aggSigPop));
REQUIRE(PopSchemeMPL().AggregateVerify(std::vector<G1Element>{pk1, pk2}, vector<vector<uint8_t>>{message, message}, aggSigPop));
}

SECTION("Should Aug aggregate many G2Elements, diff message")
Expand Down Expand Up @@ -754,8 +754,8 @@ TEST_CASE("Agg sks") {
REQUIRE(BasicSchemeMPL().Verify(aggPubKey, message, aggSig2));

// Verify aggregate with both keys (Fails since not distinct)
REQUIRE(BasicSchemeMPL().AggregateVerify({pk1, pk2}, vector<vector<uint8_t>>{message, message}, aggSig) == false);
REQUIRE(BasicSchemeMPL().AggregateVerify({pk1, pk2}, vector<vector<uint8_t>>{message, message}, aggSig2) == false);
REQUIRE(BasicSchemeMPL().AggregateVerify(std::vector<G1Element>{pk1, pk2}, vector<vector<uint8_t>>{message, message}, aggSig) == false);
REQUIRE(BasicSchemeMPL().AggregateVerify(std::vector<G1Element>{pk1, pk2}, vector<vector<uint8_t>>{message, message}, aggSig2) == false);

// Try the same with distinct message, and same sk
vector<uint8_t> message2 = {200, 29, 54, 8, 9, 29, 155, 55};
Expand All @@ -777,7 +777,7 @@ TEST_CASE("Agg sks") {
REQUIRE(pkFinal != aggPubKey);

// Cannot verify with aggPubKey (since we have multiple messages)
REQUIRE(BasicSchemeMPL().AggregateVerify({aggPubKey, pk2}, vector<vector<uint8_t>>{message, message2}, aggSigFinal));
REQUIRE(BasicSchemeMPL().AggregateVerify(std::vector<G1Element>{aggPubKey, pk2}, vector<vector<uint8_t>>{message, message2}, aggSigFinal));
}
}

Expand Down Expand Up @@ -887,7 +887,7 @@ TEST_CASE("Advanced") {
// Signatures can be noninteractively combined by anyone
G2Element aggSig = AugSchemeMPL().Aggregate({sig1, sig2});

REQUIRE(AugSchemeMPL().AggregateVerify({pk1, pk2}, vector<vector<uint8_t>>{message, message2}, aggSig));
REQUIRE(AugSchemeMPL().AggregateVerify(std::vector<G1Element>{pk1, pk2}, vector<vector<uint8_t>>{message, message2}, aggSig));

seed[0] = 3;
PrivateKey sk3 = AugSchemeMPL().KeyGen(seed);
Expand All @@ -899,7 +899,7 @@ TEST_CASE("Advanced") {
// Arbitrary trees of aggregates
G2Element aggSigFinal = AugSchemeMPL().Aggregate({aggSig, sig3});

REQUIRE(AugSchemeMPL().AggregateVerify({pk1, pk2, pk3}, vector<vector<uint8_t>>{message, message2, message3}, aggSigFinal));
REQUIRE(AugSchemeMPL().AggregateVerify(std::vector<G1Element>{pk1, pk2, pk3}, vector<vector<uint8_t>>{message, message2, message3}, aggSigFinal));

// If the same message is signed, you can use Proof of Posession (PopScheme) for efficiency
// A proof of possession MUST be passed around with the PK to ensure security.
Expand Down Expand Up @@ -991,7 +991,7 @@ TEST_CASE("Advanced") {
REQUIRE(BasicSchemeMPL().AggregateVerify(vector<Bytes>{vecG1Vector.begin(), vecG1Vector.end()},
vector<Bytes>{vecHashes.begin(), vecHashes.end()},
Bytes(aggVector)));
REQUIRE(BasicSchemeMPL().AggregateVerify({g1_1, g1_3},
REQUIRE(BasicSchemeMPL().AggregateVerify(std::vector<G1Element>{g1_1, g1_3},
vector<Bytes>{vecHashes.begin(), vecHashes.end()},
G2Element::FromByteVector(aggVector)));

Expand All @@ -1014,7 +1014,7 @@ TEST_CASE("Advanced") {
REQUIRE(AugSchemeMPL().AggregateVerify(vector<Bytes>{vecG1AugVector.begin(), vecG1AugVector.end()},
vector<Bytes>{vecHashes.begin(), vecHashes.end()},
Bytes(aggAugVector)));
REQUIRE(AugSchemeMPL().AggregateVerify({g1_1, g1_2},
REQUIRE(AugSchemeMPL().AggregateVerify(std::vector<G1Element>{g1_1, g1_2},
vector<Bytes>{vecHashes.begin(), vecHashes.end()},
G2Element::FromByteVector(aggAugVector)));

Expand Down Expand Up @@ -1068,7 +1068,7 @@ TEST_CASE("Schemes") {

G2Element aggsig = BasicSchemeMPL().Aggregate({sig1, sig2});
vector<uint8_t> aggsigv = BasicSchemeMPL().Aggregate(vector<vector<uint8_t>>{sig1v, sig2v});
REQUIRE(BasicSchemeMPL().AggregateVerify({pk1, pk2}, msgs, aggsig));
REQUIRE(BasicSchemeMPL().AggregateVerify(std::vector<G1Element>{pk1, pk2}, msgs, aggsig));
REQUIRE(BasicSchemeMPL().AggregateVerify({pk1v, pk2v}, msgs, aggsigv));
}

Expand Down Expand Up @@ -1107,7 +1107,7 @@ TEST_CASE("Schemes") {

G2Element aggsig = AugSchemeMPL().Aggregate({sig1, sig2});
vector<uint8_t> aggsigv = AugSchemeMPL().Aggregate(vector<vector<uint8_t>>{sig1v, sig2v});
REQUIRE(AugSchemeMPL().AggregateVerify({pk1, pk2}, msgs, aggsig));
REQUIRE(AugSchemeMPL().AggregateVerify(std::vector<G1Element>{pk1, pk2}, msgs, aggsig));
REQUIRE(AugSchemeMPL().AggregateVerify({pk1v, pk2v}, msgs, aggsigv));
}

Expand Down Expand Up @@ -1146,7 +1146,7 @@ TEST_CASE("Schemes") {

G2Element aggsig = PopSchemeMPL().Aggregate({sig1, sig2});
vector<uint8_t> aggsigv = PopSchemeMPL().Aggregate(vector<vector<uint8_t>>{sig1v, sig2v});
REQUIRE(PopSchemeMPL().AggregateVerify({pk1, pk2}, msgs, aggsig));
REQUIRE(PopSchemeMPL().AggregateVerify(std::vector<G1Element>{pk1, pk2}, msgs, aggsig));
REQUIRE(PopSchemeMPL().AggregateVerify({pk1v, pk2v}, msgs, aggsigv));

// PopVerify
Expand Down
23 changes: 14 additions & 9 deletions src/util.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,33 +19,38 @@
#include <sstream>
#include <string>
#include <vector>
#include <type_traits>

namespace bls {

class BLS;

class Bytes {
const uint8_t* pData;
const size_t nSize;
template <typename T>
class span {
T* pData;
size_t nSize;

public:
explicit Bytes(const uint8_t* pDataIn, const size_t nSizeIn)
explicit span(const T* pDataIn, const size_t nSizeIn)
: pData(pDataIn), nSize(nSizeIn)
{
}
explicit Bytes(const std::vector<uint8_t>& vecBytes)
: pData(vecBytes.data()), nSize(vecBytes.size())

span(const std::vector<typename std::remove_const<T>::type>& cont)
: pData(cont.data()), nSize(cont.size())
{
}

inline const uint8_t* begin() const { return pData; }
inline const uint8_t* end() const { return pData + nSize; }
inline const T* begin() const { return pData; }
inline const T* end() const { return pData + nSize; }

inline size_t size() const { return nSize; }

const uint8_t& operator[](const int nIndex) const { return pData[nIndex]; }
const T& operator[](const int nIndex) const { return pData[nIndex]; }
};

using Bytes = span<uint8_t const>;

class Util {
public:
typedef void *(*SecureAllocCallback)(size_t);
Expand Down

0 comments on commit c6e2aa7

Please sign in to comment.