Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
a0d692d
BIP9 BLS hard fork
ogabrielides Aug 23, 2022
0d59c87
Basic BLS scheme implementation
ogabrielides Sep 20, 2022
18e2a2b
Adaptation for basic BLS
ogabrielides Sep 21, 2022
17d607d
Basic BLS for CoinJoin objects
ogabrielides Sep 27, 2022
87f31ca
Various refactoring
ogabrielides Oct 10, 2022
8211869
Moved activation of BLS HF
ogabrielides Oct 11, 2022
bc7a9a9
build(bls): bump bls-dash depends to latest develop (4da22c2557e39d85…
kwvg Oct 12, 2022
c95f95d
Legacy version of protx register/update/revoke series
ogabrielides Oct 19, 2022
e12ad66
Fix for legacy protx version
ogabrielides Oct 20, 2022
e8a2805
Refactor
ogabrielides Oct 21, 2022
a1ec8fc
BLS Unerialisation fix
ogabrielides Oct 25, 2022
60d8cf0
Correct serialisation of protx objects
ogabrielides Oct 26, 2022
8f0df8a
getVersion helper method for CFinalCommitment
ogabrielides Oct 31, 2022
834182d
Updated unit tests
ogabrielides Oct 31, 2022
8672b18
Removed extra space
ogabrielides Oct 31, 2022
b8a17b3
Renamed CBLSPublicKeyVersionWrapper
ogabrielides Oct 31, 2022
f9ae65c
Serialisation support for CSimplifiedMNListEntry
ogabrielides Nov 2, 2022
4408ce1
Various fixes and refactoring
ogabrielides Nov 9, 2022
350bd17
Updated evo_deterministicmns_tests
ogabrielides Nov 11, 2022
2bda2eb
Deleted old comment
ogabrielides Nov 18, 2022
fc1091f
Correct deployment checks
ogabrielides Nov 20, 2022
2de2366
Correct serialisation of MNAUTH messages
ogabrielides Nov 23, 2022
c131c66
Correct include
ogabrielides Nov 24, 2022
d66e77f
Correct BIP9 checking
ogabrielides Nov 26, 2022
614fedd
Fix for interface_zmq_dash.py
ogabrielides Nov 30, 2022
844072b
use `return`s for protxes
UdjinM6 Nov 27, 2022
8b85bb9
secret key doesn't care about schemes
UdjinM6 Nov 27, 2022
3b13131
let `bls fromsecret` use specific scheme
UdjinM6 Nov 27, 2022
db43d7e
make `mnauth` rpc respect v19
UdjinM6 Nov 27, 2022
00ce0dd
some cleanup
UdjinM6 Nov 27, 2022
fc759d1
SigShares IsValid method
ogabrielides Dec 5, 2022
ba1cd61
some WIP changes
PastaPastaPasta Dec 5, 2022
21f51fa
some fixes to WIP changes
PastaPastaPasta Dec 5, 2022
afe2553
Applied suggestions
ogabrielides Dec 5, 2022
1502892
fix dmstate
UdjinM6 Dec 7, 2022
b97986b
Fix for LazyBLS + corrections
ogabrielides Dec 8, 2022
8577b9c
fix
ogabrielides Dec 8, 2022
a675be6
Migration lazy BLS case
ogabrielides Dec 11, 2022
e1d99c6
Rebase fix
ogabrielides Dec 11, 2022
ebb4063
Linter fixes
ogabrielides Dec 13, 2022
156fcb7
experimental linter, linking fix
ogabrielides Dec 13, 2022
68e2a3d
cleanup
UdjinM6 Dec 13, 2022
d573ecb
chore: wrap bitwise AND in `()`
UdjinM6 Dec 17, 2022
37b66a8
legacy/basic for governance
UdjinM6 Dec 14, 2022
eabbe24
do not allow BASIC_BLS_VERSION protx version before the v19 fork
UdjinM6 Dec 21, 2022
7517277
Add legacy/basic bls versioning to MNHFTx
UdjinM6 Dec 21, 2022
7dd3bec
add bls sig serialization test
UdjinM6 Dec 21, 2022
e65f93a
don't throw exception, serialise all-zero buffer
ogabrielides Dec 29, 2022
16b6bdd
Update src/bls/bls.h
ogabrielides Dec 29, 2022
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
149 changes: 128 additions & 21 deletions src/bls/bls.h
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,6 @@ class CBLSWrapper
*(static_cast<C*>(this)) = C();
}

//TODO: Overwrite function with default value of specificLegacyScheme
void SetByteVector(const std::vector<uint8_t>& vecBytes, const bool specificLegacyScheme)
{
if (vecBytes.size() != SerSize) {
Expand All @@ -125,7 +124,6 @@ class CBLSWrapper
SetByteVector(vecBytes, bls::bls_legacy_scheme.load());
}

//TODO: Overwrite function with default value of specificLegacyScheme
std::vector<uint8_t> ToByteVector(const bool specificLegacyScheme) const
{
if (!fValid) {
Expand All @@ -147,8 +145,7 @@ class CBLSWrapper
return cachedHash;
}

//TODO: Add version with argument (bool specificLegacyScheme)
bool SetHexStr(const std::string& str)
bool SetHexStr(const std::string& str, const bool specificLegacyScheme)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it is better to use enum class instead bool for better code reability.
Otherwise it is more difficult to read code such as "SetHexStr(str, true)" without using IDE's hints.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also this bool can be extra pain in case if it would be once 3rd version of BLS

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, there are two other schemes in the BLS library.

{
if (!IsHex(str)) {
Reset();
Expand All @@ -159,16 +156,20 @@ class CBLSWrapper
Reset();
return false;
}
SetByteVector(b);
SetByteVector(b, specificLegacyScheme);
return IsValid();
}

bool SetHexStr(const std::string& str)
{
return SetHexStr(str, bls::bls_legacy_scheme.load());
}

inline void Serialize(CSizeComputer& s) const
{
s.seek(SerSize);
}

//TODO: Overwrite function with default value of specificLegacyScheme
template <typename Stream>
inline void Serialize(Stream& s, const bool specificLegacyScheme) const
{
Expand All @@ -181,15 +182,14 @@ class CBLSWrapper
Serialize(s, bls::bls_legacy_scheme.load());
}

//TODO: Overwrite function with default value of specificLegacyScheme
template <typename Stream>
inline void Unserialize(Stream& s, const bool specificLegacyScheme, bool checkMalleable = true)
{
std::vector<uint8_t> vecBytes(SerSize, 0);
s.read(reinterpret_cast<char*>(vecBytes.data()), SerSize);
SetByteVector(vecBytes, specificLegacyScheme);

if (checkMalleable && !CheckMalleable(vecBytes)) {
if (checkMalleable && !CheckMalleable(vecBytes, specificLegacyScheme)) {
throw std::ios_base::failure("malleable BLS object");
}
}
Expand All @@ -200,7 +200,6 @@ class CBLSWrapper
Unserialize(s, bls::bls_legacy_scheme.load(), checkMalleable);
}

//TODO: Overwrite function with default value of specificLegacyScheme
inline bool CheckMalleable(const std::vector<uint8_t>& vecBytes, const bool specificLegacyScheme) const
{
if (memcmp(vecBytes.data(), ToByteVector(specificLegacyScheme).data(), SerSize)) {
Expand Down Expand Up @@ -305,6 +304,44 @@ class CBLSPublicKey : public CBLSWrapper<bls::G1Element, BLS_CURVE_PUBKEY_SIZE,

};

class ConstCBLSPublicKeyVersionWrapper {
private:
bool legacy;
bool checkMalleable;
const CBLSPublicKey& obj;
public:
ConstCBLSPublicKeyVersionWrapper(const CBLSPublicKey& obj, bool legacy, bool checkMalleable = true)
: obj(obj)
, legacy(legacy)
, checkMalleable(checkMalleable)
{}
template <typename Stream>
inline void Serialize(Stream& s) const {
obj.Serialize(s, legacy);
}
};

class CBLSPublicKeyVersionWrapper {
private:
bool legacy;
bool checkMalleable;
CBLSPublicKey& obj;
public:
CBLSPublicKeyVersionWrapper(CBLSPublicKey& obj, bool legacy, bool checkMalleable = true)
: obj(obj)
, legacy(legacy)
, checkMalleable(checkMalleable)
{}
template <typename Stream>
inline void Serialize(Stream& s) const {
obj.Serialize(s, legacy);
}
template <typename Stream>
inline void Unserialize(Stream& s) {
obj.Unserialize(s, legacy, checkMalleable);
}
};

class CBLSSignature : public CBLSWrapper<bls::G2Element, BLS_CURVE_SIG_SIZE, CBLSSignature>
{
friend class CBLSSecretKey;
Expand Down Expand Up @@ -332,6 +369,27 @@ class CBLSSignature : public CBLSWrapper<bls::G2Element, BLS_CURVE_SIG_SIZE, CBL
bool Recover(const std::vector<CBLSSignature>& sigs, const std::vector<CBLSId>& ids);
};

class CBLSSignatureVersionWrapper {
private:
bool legacy;
bool checkMalleable;
CBLSSignature& obj;
public:
CBLSSignatureVersionWrapper(CBLSSignature& obj, bool legacy, bool checkMalleable = true)
: obj(obj)
, legacy(legacy)
, checkMalleable(checkMalleable)
{}
template <typename Stream>
inline void Serialize(Stream& s) const {
obj.Serialize(s, legacy);
}
template <typename Stream>
inline void Unserialize(Stream& s, bool checkMalleable = true) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks like a bug for me due to shadowing class's member checkMalleable by this argument.
Either it should be removed from constructor, nor this argument to be removed.

obj.Unserialize(s, legacy, checkMalleable);
}
};

#ifndef BUILD_BITCOIN_INTERNAL
template<typename BLSObject>
class CBLSLazyWrapper
Expand All @@ -341,6 +399,7 @@ class CBLSLazyWrapper

mutable std::vector<uint8_t> vecBytes;
mutable bool bufValid{false};
mutable bool bufLegacyScheme{true};

mutable BLSObject obj;
mutable bool objInitialized{false};
Expand All @@ -349,7 +408,8 @@ class CBLSLazyWrapper

public:
CBLSLazyWrapper() :
vecBytes(BLSObject::SerSize, 0)
vecBytes(BLSObject::SerSize, 0),
bufLegacyScheme(bls::bls_legacy_scheme.load())
{
// the all-zero buf is considered a valid buf, but the resulting object will return false for IsValid
bufValid = true;
Expand All @@ -365,6 +425,7 @@ class CBLSLazyWrapper
{
std::unique_lock<std::mutex> l(r.mutex);
bufValid = r.bufValid;
bufLegacyScheme = r.bufLegacyScheme;
if (r.bufValid) {
vecBytes = r.vecBytes;
} else {
Expand All @@ -386,30 +447,47 @@ class CBLSLazyWrapper
}

template<typename Stream>
inline void Serialize(Stream& s) const
inline void Serialize(Stream& s, const bool specificLegacyScheme) const
{
std::unique_lock<std::mutex> l(mutex);
if (!objInitialized && !bufValid) {
throw std::ios_base::failure("obj and buf not initialized");
// the all-zero buf is considered a valid buf
std::fill(vecBytes.begin(), vecBytes.end(), 0);
bufLegacyScheme = specificLegacyScheme;
bufValid = true;
}
if (!bufValid) {
vecBytes = obj.ToByteVector();
if (!bufValid || (bufLegacyScheme != specificLegacyScheme)) {
vecBytes = obj.ToByteVector(specificLegacyScheme);
bufValid = true;
bufLegacyScheme = specificLegacyScheme;
hash.SetNull();
}
s.write(reinterpret_cast<const char*>(vecBytes.data()), vecBytes.size());
}

template<typename Stream>
inline void Unserialize(Stream& s)
inline void Serialize(Stream& s) const
{
Serialize(s, bls::bls_legacy_scheme.load());
}

template<typename Stream>
inline void Unserialize(Stream& s, const bool specificLegacyScheme) const
{
std::unique_lock<std::mutex> l(mutex);
s.read(reinterpret_cast<char*>(vecBytes.data()), BLSObject::SerSize);
bufValid = true;
bufLegacyScheme = specificLegacyScheme;
objInitialized = false;
hash.SetNull();
}

template<typename Stream>
inline void Unserialize(Stream& s) const
{
Unserialize(s, bls::bls_legacy_scheme.load());
}

void Set(const BLSObject& _obj)
{
std::unique_lock<std::mutex> l(mutex);
Expand All @@ -426,8 +504,17 @@ class CBLSLazyWrapper
return invalidObj;
}
if (!objInitialized) {
obj.SetByteVector(vecBytes);
if (!obj.CheckMalleable(vecBytes)) {
obj.SetByteVector(vecBytes, bufLegacyScheme);
if (!obj.IsValid()) {
// If setting of BLS object using one scheme failed, then we need to attempt again with the opposite scheme.
// This is due to the fact that LazyBLSWrapper receives a serialised buffer but attempts to create actual BLS object when needed.
// That could happen when the fork has been activated and the enforced scheme has switched.
obj.SetByteVector(vecBytes, !bufLegacyScheme);
if (obj.IsValid()) {
bufLegacyScheme = !bufLegacyScheme;
}
}
if (!obj.CheckMalleable(vecBytes, bufLegacyScheme)) {
bufValid = false;
objInitialized = false;
obj = invalidObj;
Expand All @@ -440,7 +527,7 @@ class CBLSLazyWrapper

bool operator==(const CBLSLazyWrapper& r) const
{
if (bufValid && r.bufValid) {
if (bufValid && r.bufValid && bufLegacyScheme == r.bufLegacyScheme) {
return vecBytes == r.vecBytes;
}
if (objInitialized && r.objInitialized) {
Expand All @@ -454,12 +541,13 @@ class CBLSLazyWrapper
return !(*this == r);
}

uint256 GetHash() const
uint256 GetHash(const bool specificLegacyScheme = bls::bls_legacy_scheme.load()) const
{
std::unique_lock<std::mutex> l(mutex);
if (!bufValid) {
vecBytes = obj.ToByteVector();
if (!bufValid || bufLegacyScheme != specificLegacyScheme) {
vecBytes = obj.ToByteVector(specificLegacyScheme);
bufValid = true;
bufLegacyScheme = specificLegacyScheme;
hash.SetNull();
}
if (hash.IsNull()) {
Expand All @@ -472,6 +560,25 @@ class CBLSLazyWrapper
};
using CBLSLazySignature = CBLSLazyWrapper<CBLSSignature>;
using CBLSLazyPublicKey = CBLSLazyWrapper<CBLSPublicKey>;

class CBLSLazyPublicKeyVersionWrapper {
private:
bool legacy;
CBLSLazyPublicKey& obj;
public:
CBLSLazyPublicKeyVersionWrapper(CBLSLazyPublicKey& obj, bool legacy)
: obj(obj)
, legacy(legacy)
{}
template <typename Stream>
inline void Serialize(Stream& s) const {
obj.Serialize(s, legacy);
}
template <typename Stream>
inline void Unserialize(Stream& s) {
obj.Unserialize(s, legacy);
}
};
#endif

using BLSIdVector = std::vector<CBLSId>;
Expand Down
8 changes: 5 additions & 3 deletions src/coinjoin/coinjoin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include <consensus/validation.h>
#include <llmq/chainlocks.h>
#include <llmq/instantsend.h>
#include <llmq/utils.h>
#include <masternode/node.h>
#include <masternode/sync.h>
#include <messagesigner.h>
Expand Down Expand Up @@ -55,7 +56,8 @@ bool CCoinJoinQueue::Sign()
if (!sig.IsValid()) {
return false;
}
vchSig = sig.ToByteVector();
bool legacy_bls_scheme = !llmq::utils::IsV19Active(::ChainActive().Tip());
vchSig = sig.ToByteVector(legacy_bls_scheme);

return true;
}
Expand Down Expand Up @@ -97,12 +99,12 @@ bool CCoinJoinBroadcastTx::Sign()
if (!fMasternodeMode) return false;

uint256 hash = GetSignatureHash();

CBLSSignature sig = WITH_LOCK(activeMasternodeInfoCs, return activeMasternodeInfo.blsKeyOperator->Sign(hash));
if (!sig.IsValid()) {
return false;
}
vchSig = sig.ToByteVector();
bool legacy_bls_scheme = !llmq::utils::IsV19Active(::ChainActive().Tip());
vchSig = sig.ToByteVector(legacy_bls_scheme);

return true;
}
Expand Down
13 changes: 9 additions & 4 deletions src/evo/deterministicmns.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -354,14 +354,19 @@ CSimplifiedMNListDiff CDeterministicMNList::BuildSimplifiedDiff(const CDetermini
CSimplifiedMNListDiff diffRet;
diffRet.baseBlockHash = blockHash;
diffRet.blockHash = to.blockHash;
diffRet.nVersion = llmq::utils::IsV19Active(::ChainActive().Tip()) ? CSimplifiedMNListDiff::BASIC_BLS_VERSION : CSimplifiedMNListDiff::LEGACY_BLS_VERSION;

to.ForEachMN(false, [&](auto& toPtr) {
auto fromPtr = GetMN(toPtr.proTxHash);
if (fromPtr == nullptr) {
CSimplifiedMNListEntry sme(toPtr);
sme.nVersion = diffRet.nVersion;
diffRet.mnList.emplace_back(toPtr);
} else {
CSimplifiedMNListEntry sme1(toPtr);
CSimplifiedMNListEntry sme2(*fromPtr);
sme1.nVersion = diffRet.nVersion;
sme2.nVersion = diffRet.nVersion;
if (sme1 != sme2) {
diffRet.mnList.emplace_back(toPtr);
} else if (extended && (sme1.scriptPayout != sme2.scriptPayout || sme1.scriptOperatorPayout != sme2.scriptOperatorPayout)) {
Expand Down Expand Up @@ -1136,7 +1141,7 @@ bool CheckProRegTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValid
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-protx-payload");
}

if (auto maybe_err = ptx.IsTriviallyValid(); maybe_err.did_err) {
if (auto maybe_err = ptx.IsTriviallyValid(llmq::utils::IsV19Active(pindexPrev)); maybe_err.did_err) {
return state.Invalid(maybe_err.reason, false, REJECT_INVALID, std::string(maybe_err.error_str));
}

Expand Down Expand Up @@ -1241,7 +1246,7 @@ bool CheckProUpServTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CVa
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-protx-payload");
}

if (auto maybe_err = ptx.IsTriviallyValid(); maybe_err.did_err) {
if (auto maybe_err = ptx.IsTriviallyValid(llmq::utils::IsV19Active(pindexPrev)); maybe_err.did_err) {
return state.Invalid(maybe_err.reason, false, REJECT_INVALID, std::string(maybe_err.error_str));
}

Expand Down Expand Up @@ -1296,7 +1301,7 @@ bool CheckProUpRegTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CVal
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-protx-payload");
}

if (auto maybe_err = ptx.IsTriviallyValid(); maybe_err.did_err) {
if (auto maybe_err = ptx.IsTriviallyValid(llmq::utils::IsV19Active(pindexPrev)); maybe_err.did_err) {
return state.Invalid(maybe_err.reason, false, REJECT_INVALID, std::string(maybe_err.error_str));
}

Expand Down Expand Up @@ -1369,7 +1374,7 @@ bool CheckProUpRevTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CVal
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-protx-payload");
}

if (auto maybe_err = ptx.IsTriviallyValid(); maybe_err.did_err) {
if (auto maybe_err = ptx.IsTriviallyValid(llmq::utils::IsV19Active(pindexPrev)); maybe_err.did_err) {
return state.Invalid(maybe_err.reason, false, REJECT_INVALID, std::string(maybe_err.error_str));
}

Expand Down
Loading