refactor: further spanification of Dash code (#5586)

## Issue being fixed or feature implemented
Use Spans instead of const std::vector<T>&

## What was done?
Replaced with Span

## How Has This Been Tested?
Building, ran a few tests

## Breaking Changes
Should be none, please review potential lifetime issues in bls_worker;
it scares me a bit and I don't understand how we know these won't
dangle.

## Checklist:
_Go over all the following points, and put an `x` in all the boxes that
apply._
- [x] I have performed a self-review of my own code
- [ ] I have commented my code, particularly in hard-to-understand areas
- [ ] I have added or updated relevant unit/integration/functional/e2e
tests
- [ ] I have made corresponding changes to the documentation
- [x] I have assigned this pull request to a milestone _(for repository
code-owners and collaborators only)_
This commit is contained in:
PastaPastaPasta 2023-10-03 09:52:33 -05:00 committed by GitHub
parent e72eb40024
commit b27765f358
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 127 additions and 123 deletions

View File

@ -10,7 +10,7 @@
#include <iostream>
static void BuildTestVectors(size_t count, size_t invalidCount,
BLSPublicKeyVector& pubKeys, BLSSecretKeyVector& secKeys, BLSSignatureVector& sigs,
std::vector<CBLSPublicKey>& pubKeys, std::vector<CBLSSecretKey>& secKeys, std::vector<CBLSSignature>& sigs,
std::vector<uint256>& msgHashes,
std::vector<bool>& invalid)
{
@ -95,9 +95,9 @@ static void BLS_Sign_Normal(benchmark::Bench& bench)
static void BLS_Verify_Normal(benchmark::Bench& bench)
{
BLSPublicKeyVector pubKeys;
BLSSecretKeyVector secKeys;
BLSSignatureVector sigs;
std::vector<CBLSPublicKey> pubKeys;
std::vector<CBLSSecretKey> secKeys;
std::vector<CBLSSignature> sigs;
std::vector<uint256> msgHashes;
std::vector<bool> invalid;
BuildTestVectors(1000, 10, pubKeys, secKeys, sigs, msgHashes, invalid);
@ -120,9 +120,9 @@ static void BLS_Verify_Normal(benchmark::Bench& bench)
static void BLS_Verify_LargeBlock(size_t txCount, benchmark::Bench& bench, uint32_t epoch_iters)
{
BLSPublicKeyVector pubKeys;
BLSSecretKeyVector secKeys;
BLSSignatureVector sigs;
std::vector<CBLSPublicKey> pubKeys;
std::vector<CBLSSecretKey> secKeys;
std::vector<CBLSSignature> sigs;
std::vector<uint256> msgHashes;
std::vector<bool> invalid;
BuildTestVectors(txCount, 0, pubKeys, secKeys, sigs, msgHashes, invalid);
@ -148,9 +148,9 @@ static void BLS_Verify_LargeBlock1000(benchmark::Bench& bench)
static void BLS_Verify_LargeBlockSelfAggregated(size_t txCount, benchmark::Bench& bench, uint32_t epoch_iters)
{
BLSPublicKeyVector pubKeys;
BLSSecretKeyVector secKeys;
BLSSignatureVector sigs;
std::vector<CBLSPublicKey> pubKeys;
std::vector<CBLSSecretKey> secKeys;
std::vector<CBLSSignature> sigs;
std::vector<uint256> msgHashes;
std::vector<bool> invalid;
BuildTestVectors(txCount, 0, pubKeys, secKeys, sigs, msgHashes, invalid);
@ -175,9 +175,9 @@ static void BLS_Verify_LargeBlockSelfAggregated1000(benchmark::Bench& bench)
static void BLS_Verify_LargeAggregatedBlock(size_t txCount, benchmark::Bench& bench, uint32_t epoch_iters)
{
BLSPublicKeyVector pubKeys;
BLSSecretKeyVector secKeys;
BLSSignatureVector sigs;
std::vector<CBLSPublicKey> pubKeys;
std::vector<CBLSSecretKey> secKeys;
std::vector<CBLSSignature> sigs;
std::vector<uint256> msgHashes;
std::vector<bool> invalid;
BuildTestVectors(txCount, 0, pubKeys, secKeys, sigs, msgHashes, invalid);
@ -203,9 +203,9 @@ static void BLS_Verify_LargeAggregatedBlock1000(benchmark::Bench& bench)
static void BLS_Verify_LargeAggregatedBlock1000PreVerified(benchmark::Bench& bench)
{
BLSPublicKeyVector pubKeys;
BLSSecretKeyVector secKeys;
BLSSignatureVector sigs;
std::vector<CBLSPublicKey> pubKeys;
std::vector<CBLSSecretKey> secKeys;
std::vector<CBLSSignature> sigs;
std::vector<uint256> msgHashes;
std::vector<bool> invalid;
BuildTestVectors(1000, 0, pubKeys, secKeys, sigs, msgHashes, invalid);
@ -224,7 +224,7 @@ static void BLS_Verify_LargeAggregatedBlock1000PreVerified(benchmark::Bench& ben
// Benchmark.
bench.minEpochIterations(10).run([&] {
BLSPublicKeyVector nonvalidatedPubKeys;
std::vector<CBLSPublicKey> nonvalidatedPubKeys;
std::vector<uint256> nonvalidatedHashes;
nonvalidatedPubKeys.reserve(pubKeys.size());
nonvalidatedHashes.reserve(msgHashes.size());
@ -249,9 +249,9 @@ static void BLS_Verify_LargeAggregatedBlock1000PreVerified(benchmark::Bench& ben
static void BLS_Verify_Batched(benchmark::Bench& bench)
{
BLSPublicKeyVector pubKeys;
BLSSecretKeyVector secKeys;
BLSSignatureVector sigs;
std::vector<CBLSPublicKey> pubKeys;
std::vector<CBLSSecretKey> secKeys;
std::vector<CBLSSignature> sigs;
std::vector<uint256> msgHashes;
std::vector<bool> invalid;
BuildTestVectors(1000, 10, pubKeys, secKeys, sigs, msgHashes, invalid);
@ -266,8 +266,8 @@ static void BLS_Verify_Batched(benchmark::Bench& bench)
return;
}
BLSPublicKeyVector testPubKeys;
BLSSignatureVector testSigs;
std::vector<CBLSPublicKey> testPubKeys;
std::vector<CBLSSignature> testSigs;
std::vector<uint256> testMsgHashes;
testPubKeys.reserve(batchSize);
testSigs.reserve(batchSize);
@ -305,9 +305,9 @@ static void BLS_Verify_Batched(benchmark::Bench& bench)
static void BLS_Verify_BatchedParallel(benchmark::Bench& bench)
{
BLSPublicKeyVector pubKeys;
BLSSecretKeyVector secKeys;
BLSSignatureVector sigs;
std::vector<CBLSPublicKey> pubKeys;
std::vector<CBLSSecretKey> secKeys;
std::vector<CBLSSignature> sigs;
std::vector<uint256> msgHashes;
std::vector<bool> invalid;
BuildTestVectors(1000, 10, pubKeys, secKeys, sigs, msgHashes, invalid);

View File

@ -11,7 +11,7 @@ struct Member {
CBLSId id;
BLSVerificationVectorPtr vvec;
BLSSecretKeyVector skShares;
std::vector<CBLSSecretKey> skShares;
};
class DKG
@ -21,7 +21,7 @@ private:
std::vector<Member> members;
std::vector<BLSVerificationVectorPtr> receivedVvecs;
BLSSecretKeyVector receivedSkShares;
std::vector<CBLSSecretKey> receivedSkShares;
BLSVerificationVectorPtr quorumVvec;
CBLSWorker blsWorker;

View File

@ -57,7 +57,7 @@ public:
static constexpr size_t SerSize = _SerSize;
explicit CBLSWrapper() = default;
explicit CBLSWrapper(const std::vector<unsigned char>& vecBytes) : CBLSWrapper<ImplType, _SerSize, C>()
explicit CBLSWrapper(Span<const unsigned char> vecBytes) : CBLSWrapper<ImplType, _SerSize, C>()
{
SetByteVector(vecBytes, bls::bls_legacy_scheme.load());
}
@ -103,7 +103,7 @@ public:
*(static_cast<C*>(this)) = C();
}
void SetByteVector(const std::vector<uint8_t>& vecBytes, const bool specificLegacyScheme)
void SetByteVector(Span<const uint8_t> vecBytes, const bool specificLegacyScheme)
{
if (vecBytes.size() != SerSize) {
Reset();
@ -114,7 +114,7 @@ public:
Reset();
} else {
try {
impl = ImplType::FromBytes(bls::Bytes(vecBytes), specificLegacyScheme);
impl = ImplType::FromBytes(bls::Bytes(vecBytes.data(), vecBytes.size()), specificLegacyScheme);
fValid = true;
} catch (...) {
Reset();
@ -179,7 +179,7 @@ public:
template <typename Stream>
inline void Unserialize(Stream& s, const bool specificLegacyScheme)
{
std::vector<uint8_t> vecBytes(SerSize, 0);
std::array<uint8_t, SerSize> vecBytes{};
s.read(reinterpret_cast<char*>(vecBytes.data()), SerSize);
SetByteVector(vecBytes, specificLegacyScheme);
@ -586,13 +586,7 @@ public:
};
#endif
using BLSIdVector = std::vector<CBLSId>;
using BLSVerificationVector = std::vector<CBLSPublicKey>;
using BLSPublicKeyVector = std::vector<CBLSPublicKey>;
using BLSSecretKeyVector = std::vector<CBLSSecretKey>;
using BLSSignatureVector = std::vector<CBLSSignature>;
using BLSVerificationVectorPtr = std::shared_ptr<BLSVerificationVector>;
using BLSVerificationVectorPtr = std::shared_ptr<std::vector<CBLSPublicKey>>;
bool BLSInit();

View File

@ -13,7 +13,7 @@
#include <utility>
template <typename T>
bool VerifyVectorHelper(const std::vector<T>& vec, size_t start, size_t count)
bool VerifyVectorHelper(Span<T> vec, size_t start, size_t count)
{
if (start == 0 && count == 0) {
count = vec.size();
@ -74,10 +74,10 @@ void CBLSWorker::Stop()
workerPool.stop(true);
}
bool CBLSWorker::GenerateContributions(int quorumThreshold, const BLSIdVector& ids, BLSVerificationVectorPtr& vvecRet, BLSSecretKeyVector& skSharesRet)
bool CBLSWorker::GenerateContributions(int quorumThreshold, Span<CBLSId> ids, BLSVerificationVectorPtr& vvecRet, std::vector<CBLSSecretKey>& skSharesRet)
{
auto svec = BLSSecretKeyVector((size_t)quorumThreshold);
vvecRet = std::make_shared<BLSVerificationVector>((size_t)quorumThreshold);
auto svec = std::vector<CBLSSecretKey>((size_t)quorumThreshold);
vvecRet = std::make_shared<std::vector<CBLSPublicKey>>((size_t)quorumThreshold);
skSharesRet.resize(ids.size());
for (int i = 0; i < quorumThreshold; i++) {
@ -147,7 +147,7 @@ struct Aggregator : public std::enable_shared_from_this<Aggregator<T>> {
// TP can either be a pointer or a reference
template <typename TP>
Aggregator(const std::vector<TP>& _inputVec,
Aggregator(Span<TP> _inputVec,
size_t start, size_t count,
bool _parallel,
ctpl::thread_pool& _workerPool,
@ -175,7 +175,7 @@ struct Aggregator : public std::enable_shared_from_this<Aggregator<T>> {
if (inputVec->size() == 1) {
doneCallback(*(*inputVec)[0]);
} else {
doneCallback(SyncAggregate(*inputVec, 0, inputVec->size()));
doneCallback(SyncAggregate(Span{*inputVec}, 0, inputVec->size()));
}
return;
}
@ -187,7 +187,7 @@ struct Aggregator : public std::enable_shared_from_this<Aggregator<T>> {
if (inputVec->size() == 1) {
doneCallback(*(*inputVec)[0]);
} else {
doneCallback(SyncAggregate(*inputVec, 0, inputVec->size()));
doneCallback(SyncAggregate(Span{*inputVec}, 0, inputVec->size()));
}
});
return;
@ -236,7 +236,7 @@ struct Aggregator : public std::enable_shared_from_this<Aggregator<T>> {
r = *rem[0];
} else {
// multiple intermediate results left which did not add up to a new batch. aggregate them now
r = SyncAggregate(rem, 0, rem.size());
r = SyncAggregate(Span{rem}, 0, rem.size());
}
// all items which are left in the queue are intermediate results, so we must delete them
@ -258,7 +258,7 @@ struct Aggregator : public std::enable_shared_from_this<Aggregator<T>> {
void SyncAggregateAndPushAggQueue(const std::shared_ptr<std::vector<const T*>>& vec, size_t start, size_t count, bool del)
{
// aggregate vec and push the intermediate result onto the work queue
PushAggQueue(SyncAggregate(*vec, start, count));
PushAggQueue(SyncAggregate(Span{*vec}, start, count));
if (del) {
for (size_t i = 0; i < count; i++) {
delete (*vec)[start + i];
@ -304,7 +304,7 @@ struct Aggregator : public std::enable_shared_from_this<Aggregator<T>> {
}
template <typename TP>
T SyncAggregate(const std::vector<TP>& vec, size_t start, size_t count)
T SyncAggregate(Span<TP> vec, size_t start, size_t count)
{
T result = *vec[start];
for (size_t j = 1; j < count; j++) {
@ -336,11 +336,11 @@ struct VectorAggregator : public std::enable_shared_from_this<VectorAggregator<T
using AggregatorType = Aggregator<T>;
using VectorType = std::vector<T>;
using VectorPtrType = std::shared_ptr<VectorType>;
using VectorVectorType = std::vector<VectorPtrType>;
using VectorVectorType = Span<VectorPtrType>;
using DoneCallback = std::function<void(const VectorPtrType& agg)>;
DoneCallback doneCallback;
const VectorVectorType& vecs;
VectorVectorType vecs;
size_t start;
size_t count;
bool parallel;
@ -351,7 +351,7 @@ struct VectorAggregator : public std::enable_shared_from_this<VectorAggregator<T
VectorPtrType result;
size_t vecSize;
VectorAggregator(const VectorVectorType& _vecs,
VectorAggregator(VectorVectorType _vecs,
size_t _start, size_t _count,
bool _parallel, ctpl::thread_pool& _workerPool,
DoneCallback _doneCallback) :
@ -376,7 +376,7 @@ struct VectorAggregator : public std::enable_shared_from_this<VectorAggregator<T
}
auto self(this->shared_from_this());
auto aggregator = std::make_shared<AggregatorType>(std::move(tmp), 0, count, parallel, workerPool, [self, i](const T& agg) {self->CheckDone(agg, i);});
auto aggregator = std::make_shared<AggregatorType>(Span{tmp}, 0, count, parallel, workerPool, [self, i](const T& agg) {self->CheckDone(agg, i);});
aggregator->Start();
}
}
@ -412,8 +412,8 @@ struct ContributionVerifier : public std::enable_shared_from_this<ContributionVe
};
CBLSId forId;
const std::vector<BLSVerificationVectorPtr>& vvecs;
const BLSSecretKeyVector& skShares;
Span<BLSVerificationVectorPtr> vvecs;
Span<CBLSSecretKey> skShares;
size_t batchSize;
bool parallel;
bool aggregated;
@ -427,8 +427,8 @@ struct ContributionVerifier : public std::enable_shared_from_this<ContributionVe
std::atomic<size_t> verifyDoneCount{0};
std::function<void(const std::vector<bool>&)> doneCallback;
ContributionVerifier(CBLSId _forId, const std::vector<BLSVerificationVectorPtr>& _vvecs,
const BLSSecretKeyVector& _skShares, size_t _batchSize,
ContributionVerifier(CBLSId _forId, Span<BLSVerificationVectorPtr> _vvecs,
Span<CBLSSecretKey> _skShares, size_t _batchSize,
bool _parallel, bool _aggregated, ctpl::thread_pool& _workerPool,
std::function<void(const std::vector<bool>&)> _doneCallback) :
forId(std::move(_forId)),
@ -493,7 +493,7 @@ struct ContributionVerifier : public std::enable_shared_from_this<ContributionVe
// aggregate vvecs and skShares of batch in parallel
auto self(this->shared_from_this());
auto vvecAgg = std::make_shared<VectorAggregator<CBLSPublicKey>>(vvecs, batchState.start, batchState.count, parallel, workerPool, [this, self, batchIdx] (const BLSVerificationVectorPtr& vvec) {HandleAggVvecDone(batchIdx, vvec);});
auto skShareAgg = std::make_shared<Aggregator<CBLSSecretKey>>(skShares, batchState.start, batchState.count, parallel, workerPool, [this, self, batchIdx] (const CBLSSecretKey& skShare) {HandleAggSkShareDone(batchIdx, skShare);});
auto skShareAgg = std::make_shared<Aggregator<CBLSSecretKey>>(Span{skShares}, batchState.start, batchState.count, parallel, workerPool, [this, self, batchIdx] (const CBLSSecretKey& skShare) {HandleAggSkShareDone(batchIdx, skShare);});
vvecAgg->Start();
skShareAgg->Start();
@ -594,7 +594,7 @@ struct ContributionVerifier : public std::enable_shared_from_this<ContributionVe
}
};
void CBLSWorker::AsyncBuildQuorumVerificationVector(const std::vector<BLSVerificationVectorPtr>& vvecs,
void CBLSWorker::AsyncBuildQuorumVerificationVector(Span<BLSVerificationVectorPtr> vvecs,
size_t start, size_t count, bool parallel,
std::function<void(const BLSVerificationVectorPtr&)> doneCallback)
{
@ -614,7 +614,7 @@ void CBLSWorker::AsyncBuildQuorumVerificationVector(const std::vector<BLSVerific
agg->Start();
}
std::future<BLSVerificationVectorPtr> CBLSWorker::AsyncBuildQuorumVerificationVector(const std::vector<BLSVerificationVectorPtr>& vvecs,
std::future<BLSVerificationVectorPtr> CBLSWorker::AsyncBuildQuorumVerificationVector(Span<BLSVerificationVectorPtr> vvecs,
size_t start, size_t count, bool parallel)
{
auto p = BuildFutureDoneCallback<BLSVerificationVectorPtr>();
@ -622,7 +622,7 @@ std::future<BLSVerificationVectorPtr> CBLSWorker::AsyncBuildQuorumVerificationVe
return std::move(p.second);
}
BLSVerificationVectorPtr CBLSWorker::BuildQuorumVerificationVector(const std::vector<BLSVerificationVectorPtr>& vvecs,
BLSVerificationVectorPtr CBLSWorker::BuildQuorumVerificationVector(Span<BLSVerificationVectorPtr> vvecs,
size_t start, size_t count, bool parallel)
{
return AsyncBuildQuorumVerificationVector(vvecs, start, count, parallel).get();
@ -630,7 +630,7 @@ BLSVerificationVectorPtr CBLSWorker::BuildQuorumVerificationVector(const std::ve
template <typename T>
void AsyncAggregateHelper(ctpl::thread_pool& workerPool,
const std::vector<T>& vec, size_t start, size_t count, bool parallel,
Span<T> vec, size_t start, size_t count, bool parallel,
std::function<void(const T&)> doneCallback)
{
if (start == 0 && count == 0) {
@ -649,14 +649,14 @@ void AsyncAggregateHelper(ctpl::thread_pool& workerPool,
agg->Start();
}
void CBLSWorker::AsyncAggregateSecretKeys(const BLSSecretKeyVector& secKeys,
void CBLSWorker::AsyncAggregateSecretKeys(Span<CBLSSecretKey> secKeys,
size_t start, size_t count, bool parallel,
std::function<void(const CBLSSecretKey&)> doneCallback)
{
AsyncAggregateHelper(workerPool, secKeys, start, count, parallel, std::move(doneCallback));
}
std::future<CBLSSecretKey> CBLSWorker::AsyncAggregateSecretKeys(const BLSSecretKeyVector& secKeys,
std::future<CBLSSecretKey> CBLSWorker::AsyncAggregateSecretKeys(Span<CBLSSecretKey> secKeys,
size_t start, size_t count, bool parallel)
{
auto p = BuildFutureDoneCallback<CBLSSecretKey>();
@ -664,20 +664,20 @@ std::future<CBLSSecretKey> CBLSWorker::AsyncAggregateSecretKeys(const BLSSecretK
return std::move(p.second);
}
CBLSSecretKey CBLSWorker::AggregateSecretKeys(const BLSSecretKeyVector& secKeys,
CBLSSecretKey CBLSWorker::AggregateSecretKeys(Span<CBLSSecretKey> secKeys,
size_t start, size_t count, bool parallel)
{
return AsyncAggregateSecretKeys(secKeys, start, count, parallel).get();
}
void CBLSWorker::AsyncAggregatePublicKeys(const BLSPublicKeyVector& pubKeys,
void CBLSWorker::AsyncAggregatePublicKeys(Span<CBLSPublicKey> pubKeys,
size_t start, size_t count, bool parallel,
std::function<void(const CBLSPublicKey&)> doneCallback)
{
AsyncAggregateHelper(workerPool, pubKeys, start, count, parallel, std::move(doneCallback));
}
std::future<CBLSPublicKey> CBLSWorker::AsyncAggregatePublicKeys(const BLSPublicKeyVector& pubKeys,
std::future<CBLSPublicKey> CBLSWorker::AsyncAggregatePublicKeys(Span<CBLSPublicKey> pubKeys,
size_t start, size_t count, bool parallel)
{
auto p = BuildFutureDoneCallback<CBLSPublicKey>();
@ -685,14 +685,14 @@ std::future<CBLSPublicKey> CBLSWorker::AsyncAggregatePublicKeys(const BLSPublicK
return std::move(p.second);
}
void CBLSWorker::AsyncAggregateSigs(const BLSSignatureVector& sigs,
void CBLSWorker::AsyncAggregateSigs(Span<CBLSSignature> sigs,
size_t start, size_t count, bool parallel,
std::function<void(const CBLSSignature&)> doneCallback)
{
AsyncAggregateHelper(workerPool, sigs, start, count, parallel, std::move(doneCallback));
}
std::future<CBLSSignature> CBLSWorker::AsyncAggregateSigs(const BLSSignatureVector& sigs,
std::future<CBLSSignature> CBLSWorker::AsyncAggregateSigs(Span<CBLSSignature> sigs,
size_t start, size_t count, bool parallel)
{
auto p = BuildFutureDoneCallback<CBLSSignature>();
@ -707,7 +707,7 @@ CBLSPublicKey CBLSWorker::BuildPubKeyShare(const BLSVerificationVectorPtr& vvec,
return pkShare;
}
void CBLSWorker::AsyncVerifyContributionShares(const CBLSId& forId, const std::vector<BLSVerificationVectorPtr>& vvecs, const BLSSecretKeyVector& skShares,
void CBLSWorker::AsyncVerifyContributionShares(const CBLSId& forId, Span<BLSVerificationVectorPtr> vvecs, Span<CBLSSecretKey> skShares,
bool parallel, bool aggregated, std::function<void(const std::vector<bool>&)> doneCallback)
{
if (!forId.IsValid() || !VerifyVerificationVectors(vvecs)) {
@ -721,7 +721,7 @@ void CBLSWorker::AsyncVerifyContributionShares(const CBLSId& forId, const std::v
verifier->Start();
}
std::future<std::vector<bool> > CBLSWorker::AsyncVerifyContributionShares(const CBLSId& forId, const std::vector<BLSVerificationVectorPtr>& vvecs, const BLSSecretKeyVector& skShares,
std::future<std::vector<bool> > CBLSWorker::AsyncVerifyContributionShares(const CBLSId& forId, Span<BLSVerificationVectorPtr> vvecs, Span<CBLSSecretKey> skShares,
bool parallel, bool aggregated)
{
auto p = BuildFutureDoneCallback<std::vector<bool> >();
@ -729,7 +729,7 @@ std::future<std::vector<bool> > CBLSWorker::AsyncVerifyContributionShares(const
return std::move(p.second);
}
std::vector<bool> CBLSWorker::VerifyContributionShares(const CBLSId& forId, const std::vector<BLSVerificationVectorPtr>& vvecs, const BLSSecretKeyVector& skShares,
std::vector<bool> CBLSWorker::VerifyContributionShares(const CBLSId& forId, Span<BLSVerificationVectorPtr> vvecs, Span<CBLSSecretKey> skShares,
bool parallel, bool aggregated)
{
return AsyncVerifyContributionShares(forId, vvecs, skShares, parallel, aggregated).get();
@ -757,12 +757,12 @@ std::future<bool> CBLSWorker::AsyncVerifyContributionShare(const CBLSId& forId,
return workerPool.push(f);
}
bool CBLSWorker::VerifyVerificationVector(const BLSVerificationVector& vvec, size_t start, size_t count)
bool CBLSWorker::VerifyVerificationVector(Span<CBLSPublicKey> vvec, size_t start, size_t count)
{
return VerifyVectorHelper(vvec, start, count);
}
bool CBLSWorker::VerifyVerificationVectors(const std::vector<BLSVerificationVectorPtr>& vvecs,
bool CBLSWorker::VerifyVerificationVectors(Span<BLSVerificationVectorPtr> vvecs,
size_t start, size_t count)
{
if (start == 0 && count == 0) {

View File

@ -55,7 +55,7 @@ public:
void Start();
void Stop();
bool GenerateContributions(int threshold, const BLSIdVector& ids, BLSVerificationVectorPtr& vvecRet, BLSSecretKeyVector& skSharesRet);
bool GenerateContributions(int threshold, Span<CBLSId> ids, BLSVerificationVectorPtr& vvecRet, std::vector<CBLSSecretKey>& skSharesRet);
// The following functions are all used to aggregate verification (public key) vectors
// Inputs are in the following form:
@ -69,12 +69,12 @@ public:
// [ a1+a2+a3+a4, b1+b2+b3+b4, c1+c2+c3+c4, d1+d2+d3+d4]
// Multiple things can be parallelized here. For example, all 4 entries in the result vector can be calculated in parallel
// Also, each individual vector can be split into multiple batches and aggregating the batches can also be parallelized.
void AsyncBuildQuorumVerificationVector(const std::vector<BLSVerificationVectorPtr>& vvecs,
void AsyncBuildQuorumVerificationVector(Span<BLSVerificationVectorPtr> vvecs,
size_t start, size_t count, bool parallel,
std::function<void(const BLSVerificationVectorPtr&)> doneCallback);
std::future<BLSVerificationVectorPtr> AsyncBuildQuorumVerificationVector(const std::vector<BLSVerificationVectorPtr>& vvecs,
std::future<BLSVerificationVectorPtr> AsyncBuildQuorumVerificationVector(Span<BLSVerificationVectorPtr> vvecs,
size_t start, size_t count, bool parallel);
BLSVerificationVectorPtr BuildQuorumVerificationVector(const std::vector<BLSVerificationVectorPtr>& vvecs,
BLSVerificationVectorPtr BuildQuorumVerificationVector(Span<BLSVerificationVectorPtr> vvecs,
size_t start = 0, size_t count = 0, bool parallel = true);
// The following functions are all used to aggregate single vectors
@ -82,23 +82,23 @@ public:
// [a, b, c, d],
// The result is simply a+b+c+d
// Aggregation is parallelized by splitting up the input vector into multiple batches and then aggregating the individual batch results
void AsyncAggregateSecretKeys(const BLSSecretKeyVector& secKeys,
void AsyncAggregateSecretKeys(Span<CBLSSecretKey>,
size_t start, size_t count, bool parallel,
std::function<void(const CBLSSecretKey&)> doneCallback);
std::future<CBLSSecretKey> AsyncAggregateSecretKeys(const BLSSecretKeyVector& secKeys,
std::future<CBLSSecretKey> AsyncAggregateSecretKeys(Span<CBLSSecretKey> secKeys,
size_t start, size_t count, bool parallel);
CBLSSecretKey AggregateSecretKeys(const BLSSecretKeyVector& secKeys, size_t start = 0, size_t count = 0, bool parallel = true);
CBLSSecretKey AggregateSecretKeys(Span<CBLSSecretKey> secKeys, size_t start = 0, size_t count = 0, bool parallel = true);
void AsyncAggregatePublicKeys(const BLSPublicKeyVector& pubKeys,
void AsyncAggregatePublicKeys(Span<CBLSPublicKey> pubKeys,
size_t start, size_t count, bool parallel,
std::function<void(const CBLSPublicKey&)> doneCallback);
std::future<CBLSPublicKey> AsyncAggregatePublicKeys(const BLSPublicKeyVector& pubKeys,
std::future<CBLSPublicKey> AsyncAggregatePublicKeys(Span<CBLSPublicKey> pubKeys,
size_t start, size_t count, bool parallel);
void AsyncAggregateSigs(const BLSSignatureVector& sigs,
void AsyncAggregateSigs(Span<CBLSSignature> sigs,
size_t start, size_t count, bool parallel,
std::function<void(const CBLSSignature&)> doneCallback);
std::future<CBLSSignature> AsyncAggregateSigs(const BLSSignatureVector& sigs,
std::future<CBLSSignature> AsyncAggregateSigs(Span<CBLSSignature> sigs,
size_t start, size_t count, bool parallel);
// Calculate public key share from public key vector and id. Not parallelized
@ -110,18 +110,18 @@ public:
// result per batch is a single aggregated verification vector and a single aggregated contribution, which are then
// verified with VerifyContributionShare. If verification of the aggregated inputs is successful, the whole batch
// is marked as valid. If the batch verification fails, the individual entries are verified in a non-aggregated manner
void AsyncVerifyContributionShares(const CBLSId& forId, const std::vector<BLSVerificationVectorPtr>& vvecs, const BLSSecretKeyVector& skShares,
void AsyncVerifyContributionShares(const CBLSId& forId, Span<BLSVerificationVectorPtr> vvecs, Span<CBLSSecretKey> skShares,
bool parallel, bool aggregated, std::function<void(const std::vector<bool>&)> doneCallback);
std::future<std::vector<bool> > AsyncVerifyContributionShares(const CBLSId& forId, const std::vector<BLSVerificationVectorPtr>& vvecs, const BLSSecretKeyVector& skShares,
std::future<std::vector<bool> > AsyncVerifyContributionShares(const CBLSId& forId, Span<BLSVerificationVectorPtr> vvecs, Span<CBLSSecretKey> skShares,
bool parallel, bool aggregated);
std::vector<bool> VerifyContributionShares(const CBLSId& forId, const std::vector<BLSVerificationVectorPtr>& vvecs, const BLSSecretKeyVector& skShares,
std::vector<bool> VerifyContributionShares(const CBLSId& forId, Span<BLSVerificationVectorPtr> vvecs, Span<CBLSSecretKey> skShares,
bool parallel = true, bool aggregated = true);
std::future<bool> AsyncVerifyContributionShare(const CBLSId& forId, const BLSVerificationVectorPtr& vvec, const CBLSSecretKey& skContribution);
// Simple verification of vectors. Checks x.IsValid() for every entry and checks for duplicate entries
static bool VerifyVerificationVector(const BLSVerificationVector& vvec, size_t start = 0, size_t count = 0);
static bool VerifyVerificationVectors(const std::vector<BLSVerificationVectorPtr>& vvecs, size_t start = 0, size_t count = 0);
static bool VerifyVerificationVector(Span<CBLSPublicKey> vvec, size_t start = 0, size_t count = 0);
static bool VerifyVerificationVectors(Span<BLSVerificationVectorPtr> vvecs, size_t start = 0, size_t count = 0);
// Internally batched signature signing and verification
void AsyncSign(const CBLSSecretKey& secKey, const uint256& msgHash, const SignDoneCallback& doneCallback);
@ -151,13 +151,13 @@ public:
explicit CBLSWorkerCache(CBLSWorker& _worker) :
worker(_worker) {}
BLSVerificationVectorPtr BuildQuorumVerificationVector(const uint256& cacheKey, const std::vector<BLSVerificationVectorPtr>& vvecs)
BLSVerificationVectorPtr BuildQuorumVerificationVector(const uint256& cacheKey, Span<BLSVerificationVectorPtr> vvecs)
{
return GetOrBuild(cacheKey, vvecCache, [this, &vvecs]() {
return worker.BuildQuorumVerificationVector(vvecs);
});
}
CBLSSecretKey AggregateSecretKeys(const uint256& cacheKey, const BLSSecretKeyVector& skShares)
CBLSSecretKey AggregateSecretKeys(const uint256& cacheKey, Span<CBLSSecretKey> skShares)
{
return GetOrBuild(cacheKey, secretKeyShareCache, [this, &skShares]() {
return worker.AggregateSecretKeys(skShares);

View File

@ -65,7 +65,7 @@ bool CCoinJoinQueue::Sign()
bool CCoinJoinQueue::CheckSignature(const CBLSPublicKey& blsPubKey) const
{
bool legacy_bls_scheme = !llmq::utils::IsV19Active(::ChainActive().Tip());
if (!CBLSSignature(vchSig).VerifyInsecure(blsPubKey, GetSignatureHash(legacy_bls_scheme))) {
if (!CBLSSignature(Span{vchSig}).VerifyInsecure(blsPubKey, GetSignatureHash(legacy_bls_scheme))) {
LogPrint(BCLog::COINJOIN, "CCoinJoinQueue::CheckSignature -- VerifyInsecure() failed\n");
return false;
}
@ -114,7 +114,7 @@ bool CCoinJoinBroadcastTx::Sign()
bool CCoinJoinBroadcastTx::CheckSignature(const CBLSPublicKey& blsPubKey) const
{
bool legacy_bls_scheme = !llmq::utils::IsV19Active(::ChainActive().Tip());
if (!CBLSSignature(vchSig).VerifyInsecure(blsPubKey, GetSignatureHash(legacy_bls_scheme))) {
if (!CBLSSignature(Span{vchSig}).VerifyInsecure(blsPubKey, GetSignatureHash(legacy_bls_scheme))) {
LogPrint(BCLog::COINJOIN, "CCoinJoinBroadcastTx::CheckSignature -- VerifyInsecure() failed\n");
return false;
}

View File

@ -211,11 +211,11 @@ bool CSimplifiedMNListDiff::BuildQuorumChainlockInfo(const CBlockIndex* blockInd
sig = cbcl.value().first;
}
// Get the range of indexes (values) for the current key and merge them into a single std::set
const auto [begin, end] = workBaseBlockIndexMap.equal_range(it->first);
const auto [it_begin, it_end] = workBaseBlockIndexMap.equal_range(it->first);
std::set<uint16_t> idx_set;
std::transform(begin, end, std::inserter(idx_set, idx_set.end()), [](const auto& pair) { return pair.second; });
std::transform(it_begin, it_end, std::inserter(idx_set, idx_set.end()), [](const auto& pair) { return pair.second; });
// Advance the iterator to the next key
it = end;
it = it_end;
// Different CBlockIndex can contain the same CL sig in CbTx (both non-null or null during the first blocks after v20 activation)
// Hence, we need to merge the std::set if another std::set already exists for the same sig.

View File

@ -57,7 +57,7 @@ CDKGMember::CDKGMember(const CDeterministicMNCPtr& _dmn, size_t _idx) :
}
bool CDKGSession::Init(const CBlockIndex* _pQuorumBaseBlockIndex, const std::vector<CDeterministicMNCPtr>& mns, const uint256& _myProTxHash, int _quorumIndex)
bool CDKGSession::Init(const CBlockIndex* _pQuorumBaseBlockIndex, Span<CDeterministicMNCPtr> mns, const uint256& _myProTxHash, int _quorumIndex)
{
m_quorum_base_block_index = _pQuorumBaseBlockIndex;
quorumIndex = _quorumIndex;
@ -353,7 +353,7 @@ void CDKGSession::VerifyPendingContributions()
std::vector<size_t> memberIndexes;
std::vector<BLSVerificationVectorPtr> vvecs;
BLSSecretKeyVector skContributions;
std::vector<CBLSSecretKey> skContributions;
for (const auto& idx : pend) {
const auto& m = members[idx];
@ -941,7 +941,7 @@ void CDKGSession::SendCommitment(CDKGPendingMessages& pendingMessages)
cxxtimer::Timer t1(true);
std::vector<uint16_t> memberIndexes;
std::vector<BLSVerificationVectorPtr> vvecs;
BLSSecretKeyVector skContributions;
std::vector<CBLSSecretKey> skContributions;
if (!dkgManager.GetVerifiedContributions(params.type, m_quorum_base_block_index, qc.validMembers, memberIndexes, vvecs, skContributions)) {
logger.Batch("failed to get valid contributions");
return;
@ -1106,7 +1106,7 @@ void CDKGSession::ReceiveMessage(const CDKGPrematureCommitment& qc, bool& retBan
std::vector<uint16_t> memberIndexes;
std::vector<BLSVerificationVectorPtr> vvecs;
BLSSecretKeyVector skContributions;
std::vector<CBLSSecretKey> skContributions;
BLSVerificationVectorPtr quorumVvec;
if (dkgManager.GetVerifiedContributions(params.type, m_quorum_base_block_index, qc.validMembers, memberIndexes, vvecs, skContributions)) {
quorumVvec = cache.BuildQuorumVerificationVector(::SerializeHash(memberIndexes), vvecs);

View File

@ -59,7 +59,7 @@ public:
template<typename Stream>
inline void Unserialize(Stream& s)
{
BLSVerificationVector tmp1;
std::vector<CBLSPublicKey> tmp1;
CBLSIESMultiRecipientObjects<CBLSSecretKey> tmp2;
s >> llmqType;
@ -69,7 +69,7 @@ public:
s >> tmp2;
s >> sig;
vvec = std::make_shared<BLSVerificationVector>(std::move(tmp1));
vvec = std::make_shared<std::vector<CBLSPublicKey>>(std::move(tmp1));
contributions = std::make_shared<CBLSIESMultiRecipientObjects<CBLSSecretKey>>(std::move(tmp2));
}
@ -273,12 +273,12 @@ private:
std::map<uint256, size_t> membersMap;
std::set<uint256> relayMembers;
BLSVerificationVectorPtr vvecContribution;
BLSSecretKeyVector m_sk_contributions;
std::vector<CBLSSecretKey> m_sk_contributions;
BLSIdVector memberIds;
std::vector<CBLSId> memberIds;
std::vector<BLSVerificationVectorPtr> receivedVvecs;
// these are not necessarily verified yet. Only trust in what was written to the DB
BLSSecretKeyVector receivedSkContributions;
std::vector<CBLSSecretKey> receivedSkContributions;
/// Contains the received unverified/encrypted DKG contributions
std::vector<std::shared_ptr<CBLSIESMultiRecipientObjects<CBLSSecretKey>>> vecEncryptedContributions;
@ -307,7 +307,7 @@ public:
CDKGSession(const Consensus::LLMQParams& _params, CBLSWorker& _blsWorker, CDKGSessionManager& _dkgManager, CDKGDebugManager& _dkgDebugManager, CConnman& _connman) :
params(_params), blsWorker(_blsWorker), cache(_blsWorker), dkgManager(_dkgManager), dkgDebugManager(_dkgDebugManager), connman(_connman) {}
bool Init(const CBlockIndex* pQuorumBaseBlockIndex, const std::vector<CDeterministicMNCPtr>& mns, const uint256& _myProTxHash, int _quorumIndex);
bool Init(const CBlockIndex* pQuorumBaseBlockIndex, Span<CDeterministicMNCPtr> mns, const uint256& _myProTxHash, int _quorumIndex);
[[nodiscard]] std::optional<size_t> GetMyMemberIndex() const { return myIdx; }

View File

@ -67,7 +67,7 @@ void CDKGSessionManager::MigrateDKG()
while (pcursor->Valid()) {
decltype(start_vvec) k;
BLSVerificationVector v;
std::vector<CBLSPublicKey> v;
if (!pcursor->GetKey(k) || std::get<0>(k) != DB_VVEC) {
break;
@ -377,7 +377,7 @@ void CDKGSessionManager::WriteEncryptedContributions(Consensus::LLMQType llmqTyp
db->Write(std::make_tuple(DB_ENC_CONTRIB, llmqType, pQuorumBaseBlockIndex->GetBlockHash(), proTxHash), contributions);
}
bool CDKGSessionManager::GetVerifiedContributions(Consensus::LLMQType llmqType, const CBlockIndex* pQuorumBaseBlockIndex, const std::vector<bool>& validMembers, std::vector<uint16_t>& memberIndexesRet, std::vector<BLSVerificationVectorPtr>& vvecsRet, BLSSecretKeyVector& skContributionsRet) const
bool CDKGSessionManager::GetVerifiedContributions(Consensus::LLMQType llmqType, const CBlockIndex* pQuorumBaseBlockIndex, const std::vector<bool>& validMembers, std::vector<uint16_t>& memberIndexesRet, std::vector<BLSVerificationVectorPtr>& vvecsRet, std::vector<CBLSSecretKey>& skContributionsRet) const
{
LOCK(contributionsCacheCs);
auto members = utils::GetAllQuorumMembers(llmqType, pQuorumBaseBlockIndex);
@ -394,7 +394,7 @@ bool CDKGSessionManager::GetVerifiedContributions(Consensus::LLMQType llmqType,
ContributionsCacheKey cacheKey = {llmqType, pQuorumBaseBlockIndex->GetBlockHash(), proTxHash};
auto it = contributionsCache.find(cacheKey);
if (it == contributionsCache.end()) {
auto vvecPtr = std::make_shared<BLSVerificationVector>();
auto vvecPtr = std::make_shared<std::vector<CBLSPublicKey>>();
CBLSSecretKey skContribution;
if (!db->Read(std::make_tuple(DB_VVEC, llmqType, pQuorumBaseBlockIndex->GetBlockHash(), proTxHash), *vvecPtr)) {
return false;

View File

@ -83,7 +83,7 @@ public:
// Contributions are written while in the DKG
void WriteVerifiedVvecContribution(Consensus::LLMQType llmqType, const CBlockIndex* pQuorumBaseBlockIndex, const uint256& proTxHash, const BLSVerificationVectorPtr& vvec);
void WriteVerifiedSkContribution(Consensus::LLMQType llmqType, const CBlockIndex* pQuorumBaseBlockIndex, const uint256& proTxHash, const CBLSSecretKey& skContribution);
bool GetVerifiedContributions(Consensus::LLMQType llmqType, const CBlockIndex* pQuorumBaseBlockIndex, const std::vector<bool>& validMembers, std::vector<uint16_t>& memberIndexesRet, std::vector<BLSVerificationVectorPtr>& vvecsRet, BLSSecretKeyVector& skContributionsRet) const;
bool GetVerifiedContributions(Consensus::LLMQType llmqType, const CBlockIndex* pQuorumBaseBlockIndex, const std::vector<bool>& validMembers, std::vector<uint16_t>& memberIndexesRet, std::vector<BLSVerificationVectorPtr>& vvecsRet, std::vector<CBLSSecretKey>& skContributionsRet) const;
/// Write encrypted (unverified) DKG contributions for the member with the given proTxHash to the llmqDb
void WriteEncryptedContributions(Consensus::LLMQType llmqType, const CBlockIndex* pQuorumBaseBlockIndex, const uint256& proTxHash, const CBLSIESMultiRecipientObjects<CBLSSecretKey>& contributions);
/// Read encrypted (unverified) DKG contributions for the member with the given proTxHash from the llmqDb

View File

@ -76,15 +76,15 @@ CQuorum::CQuorum(const Consensus::LLMQParams& _params, CBLSWorker& _blsWorker) :
{
}
void CQuorum::Init(CFinalCommitmentPtr _qc, const CBlockIndex* _pQuorumBaseBlockIndex, const uint256& _minedBlockHash, const std::vector<CDeterministicMNCPtr>& _members)
void CQuorum::Init(CFinalCommitmentPtr _qc, const CBlockIndex* _pQuorumBaseBlockIndex, const uint256& _minedBlockHash, Span<CDeterministicMNCPtr> _members)
{
qc = std::move(_qc);
m_quorum_base_block_index = _pQuorumBaseBlockIndex;
members = _members;
members = std::vector(_members.begin(), _members.end());
minedBlockHash = _minedBlockHash;
}
bool CQuorum::SetVerificationVector(const BLSVerificationVector& quorumVecIn)
bool CQuorum::SetVerificationVector(const std::vector<CBLSPublicKey>& quorumVecIn)
{
const auto quorumVecInSerialized = ::SerializeHash(quorumVecIn);
@ -92,7 +92,7 @@ bool CQuorum::SetVerificationVector(const BLSVerificationVector& quorumVecIn)
if (quorumVecInSerialized != qc->quorumVvecHash) {
return false;
}
quorumVvec = std::make_shared<BLSVerificationVector>(quorumVecIn);
quorumVvec = std::make_shared<std::vector<CBLSPublicKey>>(quorumVecIn);
return true;
}
@ -173,9 +173,9 @@ bool CQuorum::ReadContributions(CEvoDB& evoDb)
{
uint256 dbKey = MakeQuorumKey(*this);
BLSVerificationVector qv;
std::vector<CBLSPublicKey> qv;
if (evoDb.Read(std::make_pair(DB_QUORUM_QUORUM_VVEC, dbKey), qv)) {
WITH_LOCK(cs, quorumVvec = std::make_shared<BLSVerificationVector>(std::move(qv)));
WITH_LOCK(cs, quorumVvec = std::make_shared<std::vector<CBLSPublicKey>>(std::move(qv)));
} else {
return false;
}
@ -411,7 +411,7 @@ bool CQuorumManager::BuildQuorumContributions(const CFinalCommitmentPtr& fqc, co
{
std::vector<uint16_t> memberIndexes;
std::vector<BLSVerificationVectorPtr> vvecs;
BLSSecretKeyVector skContributions;
std::vector<CBLSSecretKey> skContributions;
if (!dkgManager.GetVerifiedContributions((Consensus::LLMQType)fqc->llmqType, quorum->m_quorum_base_block_index, fqc->validMembers, memberIndexes, vvecs, skContributions)) {
return false;
}
@ -766,7 +766,7 @@ void CQuorumManager::ProcessMessage(CNode& pfrom, const std::string& msg_type, C
// Check if request has QUORUM_VERIFICATION_VECTOR data
if (request.GetDataMask() & CQuorumDataRequest::QUORUM_VERIFICATION_VECTOR) {
BLSVerificationVector verificationVector;
std::vector<CBLSPublicKey> verificationVector;
vRecv >> verificationVector;
if (pQuorum->SetVerificationVector(verificationVector)) {
@ -794,7 +794,7 @@ void CQuorumManager::ProcessMessage(CNode& pfrom, const std::string& msg_type, C
std::vector<CBLSIESEncryptedObject<CBLSSecretKey>> vecEncrypted;
vRecv >> vecEncrypted;
BLSSecretKeyVector vecSecretKeys;
std::vector<CBLSSecretKey> vecSecretKeys;
vecSecretKeys.resize(vecEncrypted.size());
auto secret = WITH_LOCK(activeMasternodeInfoCs, return *activeMasternodeInfo.blsKeyOperator);
for (const auto i : irange::range(vecEncrypted.size())) {

View File

@ -189,9 +189,9 @@ private:
public:
CQuorum(const Consensus::LLMQParams& _params, CBLSWorker& _blsWorker);
~CQuorum() = default;
void Init(CFinalCommitmentPtr _qc, const CBlockIndex* _pQuorumBaseBlockIndex, const uint256& _minedBlockHash, const std::vector<CDeterministicMNCPtr>& _members);
void Init(CFinalCommitmentPtr _qc, const CBlockIndex* _pQuorumBaseBlockIndex, const uint256& _minedBlockHash, Span<CDeterministicMNCPtr> _members);
bool SetVerificationVector(const BLSVerificationVector& quorumVecIn);
bool SetVerificationVector(const std::vector<CBLSPublicKey>& quorumVecIn);
bool SetSecretKeyShare(const CBLSSecretKey& secretKeyShare);
bool HasVerificationVector() const;

View File

@ -321,7 +321,7 @@ bool BuildQuorumRotationInfo(const CGetQuorumRotationInfo& request, CQuorumRotat
return true;
}
uint256 GetLastBaseBlockHash(const std::vector<const CBlockIndex*>& baseBlockIndexes, const CBlockIndex* blockIndex)
uint256 GetLastBaseBlockHash(Span<const CBlockIndex*> baseBlockIndexes, const CBlockIndex* blockIndex)
{
uint256 hash;
for (const auto baseBlock : baseBlockIndexes) {

View File

@ -209,7 +209,7 @@ public:
bool BuildQuorumRotationInfo(const CGetQuorumRotationInfo& request, CQuorumRotationInfo& response,
const CQuorumManager& qman, const CQuorumBlockProcessor& quorumBlockProcessor, std::string& errorRet);
uint256 GetLastBaseBlockHash(const std::vector<const CBlockIndex*>& baseBlockIndexes, const CBlockIndex* blockIndex);
uint256 GetLastBaseBlockHash(Span<const CBlockIndex*> baseBlockIndexes, const CBlockIndex* blockIndex);
class CQuorumSnapshotManager
{

View File

@ -280,4 +280,14 @@ template <typename T> constexpr auto UCharSpanCast(Span<T> s) -> Span<typename s
/** Like the Span constructor, but for (const) unsigned char member types only. Only works for (un)signed char containers. */
template <typename V> constexpr auto MakeUCharSpan(V&& v) -> decltype(UCharSpanCast(Span{std::forward<V>(v)})) { return UCharSpanCast(Span{std::forward<V>(v)}); }
template<typename C>
[[nodiscard]] constexpr auto begin(const Span<C>& span) noexcept -> C* {
return span.begin();
}
template<typename C>
[[nodiscard]] constexpr auto end(const Span<C>& span) noexcept -> C* {
return span.end();
}
#endif