5e829a3b1b
Brings in: 1. https://github.com/Chia-Network/bls-signatures/pull/41 2. https://github.com/Chia-Network/bls-signatures/pull/46 3. A few commits from https://github.com/codablock/bls-signatures are now merged into upstream. This removes the need for manual initialization of the BLS library. This is now done internally and in a thread-safe way. Also switch to using tags instead of raw commit hashes. Makes testing easier and also removes the risk of Github deleting commits due to cleanup jobs.
465 lines
10 KiB
C++
465 lines
10 KiB
C++
// Copyright (c) 2018 The Dash Core developers
|
|
// Distributed under the MIT software license, see the accompanying
|
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
|
|
|
#include "bls.h"
|
|
|
|
#include "hash.h"
|
|
#include "random.h"
|
|
#include "tinyformat.h"
|
|
|
|
#ifndef BUILD_BITCOIN_INTERNAL
|
|
#include "support/allocators/mt_pooled_secure.h"
|
|
#endif
|
|
|
|
#include <assert.h>
|
|
#include <string.h>
|
|
|
|
bool CBLSId::InternalSetBuf(const void* buf)
|
|
{
|
|
memcpy(impl.begin(), buf, sizeof(uint256));
|
|
return true;
|
|
}
|
|
|
|
bool CBLSId::InternalGetBuf(void* buf) const
|
|
{
|
|
memcpy(buf, impl.begin(), sizeof(uint256));
|
|
return true;
|
|
}
|
|
|
|
void CBLSId::SetInt(int x)
|
|
{
|
|
impl.SetHex(strprintf("%x", x));
|
|
fValid = true;
|
|
UpdateHash();
|
|
}
|
|
|
|
void CBLSId::SetHash(const uint256& hash)
|
|
{
|
|
impl = hash;
|
|
fValid = true;
|
|
UpdateHash();
|
|
}
|
|
|
|
CBLSId CBLSId::FromInt(int64_t i)
|
|
{
|
|
CBLSId id;
|
|
id.SetInt(i);
|
|
return id;
|
|
}
|
|
|
|
CBLSId CBLSId::FromHash(const uint256& hash)
|
|
{
|
|
CBLSId id;
|
|
id.SetHash(hash);
|
|
return id;
|
|
}
|
|
|
|
bool CBLSSecretKey::InternalSetBuf(const void* buf)
|
|
{
|
|
try {
|
|
impl = bls::PrivateKey::FromBytes((const uint8_t*)buf);
|
|
return true;
|
|
} catch (...) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool CBLSSecretKey::InternalGetBuf(void* buf) const
|
|
{
|
|
impl.Serialize((uint8_t*)buf);
|
|
return true;
|
|
}
|
|
|
|
void CBLSSecretKey::AggregateInsecure(const CBLSSecretKey& o)
|
|
{
|
|
assert(IsValid() && o.IsValid());
|
|
impl = bls::PrivateKey::AggregateInsecure({impl, o.impl});
|
|
UpdateHash();
|
|
}
|
|
|
|
CBLSSecretKey CBLSSecretKey::AggregateInsecure(const std::vector<CBLSSecretKey>& sks)
|
|
{
|
|
if (sks.empty()) {
|
|
return CBLSSecretKey();
|
|
}
|
|
|
|
std::vector<bls::PrivateKey> v;
|
|
v.reserve(sks.size());
|
|
for (auto& sk : sks) {
|
|
v.emplace_back(sk.impl);
|
|
}
|
|
|
|
auto agg = bls::PrivateKey::AggregateInsecure(v);
|
|
CBLSSecretKey ret;
|
|
ret.impl = agg;
|
|
ret.fValid = true;
|
|
ret.UpdateHash();
|
|
return ret;
|
|
}
|
|
|
|
#ifndef BUILD_BITCOIN_INTERNAL
|
|
void CBLSSecretKey::MakeNewKey()
|
|
{
|
|
unsigned char buf[32];
|
|
while (true) {
|
|
GetStrongRandBytes(buf, sizeof(buf));
|
|
try {
|
|
impl = bls::PrivateKey::FromBytes((const uint8_t*)buf);
|
|
break;
|
|
} catch (...) {
|
|
}
|
|
}
|
|
fValid = true;
|
|
UpdateHash();
|
|
}
|
|
#endif
|
|
|
|
bool CBLSSecretKey::SecretKeyShare(const std::vector<CBLSSecretKey>& msk, const CBLSId& _id)
|
|
{
|
|
fValid = false;
|
|
UpdateHash();
|
|
|
|
if (!_id.IsValid()) {
|
|
return false;
|
|
}
|
|
|
|
std::vector<bls::PrivateKey> mskVec;
|
|
mskVec.reserve(msk.size());
|
|
for (const CBLSSecretKey& sk : msk) {
|
|
if (!sk.IsValid()) {
|
|
return false;
|
|
}
|
|
mskVec.emplace_back(sk.impl);
|
|
}
|
|
|
|
try {
|
|
impl = bls::BLS::PrivateKeyShare(mskVec, (const uint8_t*)_id.impl.begin());
|
|
} catch (...) {
|
|
return false;
|
|
}
|
|
|
|
fValid = true;
|
|
UpdateHash();
|
|
return true;
|
|
}
|
|
|
|
CBLSPublicKey CBLSSecretKey::GetPublicKey() const
|
|
{
|
|
if (!IsValid()) {
|
|
return CBLSPublicKey();
|
|
}
|
|
|
|
CBLSPublicKey pubKey;
|
|
pubKey.impl = impl.GetPublicKey();
|
|
pubKey.fValid = true;
|
|
pubKey.UpdateHash();
|
|
return pubKey;
|
|
}
|
|
|
|
CBLSSignature CBLSSecretKey::Sign(const uint256& hash) const
|
|
{
|
|
if (!IsValid()) {
|
|
return CBLSSignature();
|
|
}
|
|
|
|
CBLSSignature sigRet;
|
|
sigRet.impl = impl.SignInsecurePrehashed((const uint8_t*)hash.begin());
|
|
|
|
sigRet.fValid = true;
|
|
sigRet.UpdateHash();
|
|
|
|
return sigRet;
|
|
}
|
|
|
|
bool CBLSPublicKey::InternalSetBuf(const void* buf)
|
|
{
|
|
try {
|
|
impl = bls::PublicKey::FromBytes((const uint8_t*)buf);
|
|
return true;
|
|
} catch (...) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool CBLSPublicKey::InternalGetBuf(void* buf) const
|
|
{
|
|
impl.Serialize((uint8_t*)buf);
|
|
return true;
|
|
}
|
|
|
|
void CBLSPublicKey::AggregateInsecure(const CBLSPublicKey& o)
|
|
{
|
|
assert(IsValid() && o.IsValid());
|
|
impl = bls::PublicKey::AggregateInsecure({impl, o.impl});
|
|
UpdateHash();
|
|
}
|
|
|
|
CBLSPublicKey CBLSPublicKey::AggregateInsecure(const std::vector<CBLSPublicKey>& pks)
|
|
{
|
|
if (pks.empty()) {
|
|
return CBLSPublicKey();
|
|
}
|
|
|
|
std::vector<bls::PublicKey> v;
|
|
v.reserve(pks.size());
|
|
for (auto& pk : pks) {
|
|
v.emplace_back(pk.impl);
|
|
}
|
|
|
|
auto agg = bls::PublicKey::AggregateInsecure(v);
|
|
CBLSPublicKey ret;
|
|
ret.impl = agg;
|
|
ret.fValid = true;
|
|
ret.UpdateHash();
|
|
return ret;
|
|
}
|
|
|
|
bool CBLSPublicKey::PublicKeyShare(const std::vector<CBLSPublicKey>& mpk, const CBLSId& _id)
|
|
{
|
|
fValid = false;
|
|
UpdateHash();
|
|
|
|
if (!_id.IsValid()) {
|
|
return false;
|
|
}
|
|
|
|
std::vector<bls::PublicKey> mpkVec;
|
|
mpkVec.reserve(mpk.size());
|
|
for (const CBLSPublicKey& pk : mpk) {
|
|
if (!pk.IsValid()) {
|
|
return false;
|
|
}
|
|
mpkVec.emplace_back(pk.impl);
|
|
}
|
|
|
|
try {
|
|
impl = bls::BLS::PublicKeyShare(mpkVec, (const uint8_t*)_id.impl.begin());
|
|
} catch (...) {
|
|
return false;
|
|
}
|
|
|
|
fValid = true;
|
|
UpdateHash();
|
|
return true;
|
|
}
|
|
|
|
bool CBLSPublicKey::DHKeyExchange(const CBLSSecretKey& sk, const CBLSPublicKey& pk)
|
|
{
|
|
fValid = false;
|
|
UpdateHash();
|
|
|
|
if (!sk.IsValid() || !pk.IsValid()) {
|
|
return false;
|
|
}
|
|
impl = bls::BLS::DHKeyExchange(sk.impl, pk.impl);
|
|
fValid = true;
|
|
UpdateHash();
|
|
return true;
|
|
}
|
|
|
|
bool CBLSSignature::InternalSetBuf(const void* buf)
|
|
{
|
|
try {
|
|
impl = bls::InsecureSignature::FromBytes((const uint8_t*)buf);
|
|
return true;
|
|
} catch (...) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool CBLSSignature::InternalGetBuf(void* buf) const
|
|
{
|
|
impl.Serialize((uint8_t*)buf);
|
|
return true;
|
|
}
|
|
|
|
void CBLSSignature::AggregateInsecure(const CBLSSignature& o)
|
|
{
|
|
assert(IsValid() && o.IsValid());
|
|
impl = bls::InsecureSignature::Aggregate({impl, o.impl});
|
|
UpdateHash();
|
|
}
|
|
|
|
CBLSSignature CBLSSignature::AggregateInsecure(const std::vector<CBLSSignature>& sigs)
|
|
{
|
|
if (sigs.empty()) {
|
|
return CBLSSignature();
|
|
}
|
|
|
|
std::vector<bls::InsecureSignature> v;
|
|
v.reserve(sigs.size());
|
|
for (auto& pk : sigs) {
|
|
v.emplace_back(pk.impl);
|
|
}
|
|
|
|
auto agg = bls::InsecureSignature::Aggregate(v);
|
|
CBLSSignature ret;
|
|
ret.impl = agg;
|
|
ret.fValid = true;
|
|
ret.UpdateHash();
|
|
return ret;
|
|
}
|
|
|
|
CBLSSignature CBLSSignature::AggregateSecure(const std::vector<CBLSSignature>& sigs,
|
|
const std::vector<CBLSPublicKey>& pks,
|
|
const uint256& hash)
|
|
{
|
|
if (sigs.size() != pks.size() || sigs.empty()) {
|
|
return CBLSSignature();
|
|
}
|
|
|
|
std::vector<bls::Signature> v;
|
|
v.reserve(sigs.size());
|
|
|
|
for (size_t i = 0; i < sigs.size(); i++) {
|
|
bls::AggregationInfo aggInfo = bls::AggregationInfo::FromMsgHash(pks[i].impl, hash.begin());
|
|
v.emplace_back(bls::Signature::FromInsecureSig(sigs[i].impl, aggInfo));
|
|
}
|
|
|
|
auto aggSig = bls::Signature::AggregateSigs(v);
|
|
CBLSSignature ret;
|
|
ret.impl = aggSig.GetInsecureSig();
|
|
ret.fValid = true;
|
|
ret.UpdateHash();
|
|
return ret;
|
|
}
|
|
|
|
void CBLSSignature::SubInsecure(const CBLSSignature& o)
|
|
{
|
|
assert(IsValid() && o.IsValid());
|
|
impl = impl.DivideBy({o.impl});
|
|
UpdateHash();
|
|
}
|
|
|
|
bool CBLSSignature::VerifyInsecure(const CBLSPublicKey& pubKey, const uint256& hash) const
|
|
{
|
|
if (!IsValid() || !pubKey.IsValid()) {
|
|
return false;
|
|
}
|
|
|
|
try {
|
|
return impl.Verify({(const uint8_t*)hash.begin()}, {pubKey.impl});
|
|
} catch (...) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool CBLSSignature::VerifyInsecureAggregated(const std::vector<CBLSPublicKey>& pubKeys, const std::vector<uint256>& hashes) const
|
|
{
|
|
if (!IsValid()) {
|
|
return false;
|
|
}
|
|
assert(!pubKeys.empty() && !hashes.empty() && pubKeys.size() == hashes.size());
|
|
|
|
std::vector<bls::PublicKey> pubKeyVec;
|
|
std::vector<const uint8_t*> hashes2;
|
|
hashes2.reserve(hashes.size());
|
|
pubKeyVec.reserve(pubKeys.size());
|
|
for (size_t i = 0; i < pubKeys.size(); i++) {
|
|
auto& p = pubKeys[i];
|
|
if (!p.IsValid()) {
|
|
return false;
|
|
}
|
|
pubKeyVec.push_back(p.impl);
|
|
hashes2.push_back((uint8_t*)hashes[i].begin());
|
|
}
|
|
|
|
try {
|
|
return impl.Verify(hashes2, pubKeyVec);
|
|
} catch (...) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool CBLSSignature::VerifySecureAggregated(const std::vector<CBLSPublicKey>& pks, const uint256& hash) const
|
|
{
|
|
if (pks.empty()) {
|
|
return false;
|
|
}
|
|
|
|
std::vector<bls::AggregationInfo> v;
|
|
v.reserve(pks.size());
|
|
for (auto& pk : pks) {
|
|
auto aggInfo = bls::AggregationInfo::FromMsgHash(pk.impl, hash.begin());
|
|
v.emplace_back(aggInfo);
|
|
}
|
|
|
|
bls::AggregationInfo aggInfo = bls::AggregationInfo::MergeInfos(v);
|
|
bls::Signature aggSig = bls::Signature::FromInsecureSig(impl, aggInfo);
|
|
return aggSig.Verify();
|
|
}
|
|
|
|
bool CBLSSignature::Recover(const std::vector<CBLSSignature>& sigs, const std::vector<CBLSId>& ids)
|
|
{
|
|
fValid = false;
|
|
UpdateHash();
|
|
|
|
if (sigs.empty() || ids.empty() || sigs.size() != ids.size()) {
|
|
return false;
|
|
}
|
|
|
|
std::vector<bls::InsecureSignature> sigsVec;
|
|
std::vector<const uint8_t*> idsVec;
|
|
sigsVec.reserve(sigs.size());
|
|
idsVec.reserve(sigs.size());
|
|
|
|
for (size_t i = 0; i < sigs.size(); i++) {
|
|
if (!sigs[i].IsValid() || !ids[i].IsValid()) {
|
|
return false;
|
|
}
|
|
sigsVec.emplace_back(sigs[i].impl);
|
|
idsVec.emplace_back(ids[i].impl.begin());
|
|
}
|
|
|
|
try {
|
|
impl = bls::BLS::RecoverSig(sigsVec, idsVec);
|
|
} catch (...) {
|
|
return false;
|
|
}
|
|
|
|
fValid = true;
|
|
UpdateHash();
|
|
return true;
|
|
}
|
|
|
|
#ifndef BUILD_BITCOIN_INTERNAL
|
|
|
|
static std::once_flag init_flag;
|
|
static mt_pooled_secure_allocator<uint8_t>* secure_allocator_instance;
|
|
static void create_secure_allocator()
|
|
{
|
|
// make sure LockedPoolManager is initialized first (ensures destruction order)
|
|
LockedPoolManager::Instance();
|
|
|
|
// static variable in function scope ensures it's initialized when first accessed
|
|
// and destroyed before LockedPoolManager
|
|
static mt_pooled_secure_allocator<uint8_t> a(sizeof(bn_t) + sizeof(size_t));
|
|
secure_allocator_instance = &a;
|
|
}
|
|
|
|
static mt_pooled_secure_allocator<uint8_t>& get_secure_allocator()
|
|
{
|
|
std::call_once(init_flag, create_secure_allocator);
|
|
return *secure_allocator_instance;
|
|
}
|
|
|
|
static void* secure_allocate(size_t n)
|
|
{
|
|
uint8_t* ptr = get_secure_allocator().allocate(n + sizeof(size_t));
|
|
*(size_t*)ptr = n;
|
|
return ptr + sizeof(size_t);
|
|
}
|
|
|
|
static void secure_free(void* p)
|
|
{
|
|
if (!p) {
|
|
return;
|
|
}
|
|
|
|
uint8_t* ptr = (uint8_t*)p - sizeof(size_t);
|
|
size_t n = *(size_t*)ptr;
|
|
return get_secure_allocator().deallocate(ptr, n);
|
|
}
|
|
#endif
|