diff --git a/src/Makefile.am b/src/Makefile.am index 069265f2d22eb..f9b5831945c49 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -160,6 +160,7 @@ BITCOIN_CORE_H = \ blsct/arith/g1point.h \ blsct/arith/mcl_initializer.h \ blsct/arith/scalar.h \ + blsct/keys.h \ chain.h \ chainparams.h \ chainparamsbase.h \ @@ -387,6 +388,7 @@ libbitcoin_node_a_SOURCES = \ blsct/arith/g1point.cpp \ blsct/arith/mcl_initializer.cpp \ blsct/arith/scalar.cpp \ + blsct/keys.cpp \ chain.cpp \ consensus/tx_verify.cpp \ dbwrapper.cpp \ @@ -911,6 +913,7 @@ libbitcoinkernel_la_SOURCES = \ blsct/arith/g1point.cpp \ blsct/arith/mcl_initializer.cpp \ blsct/arith/scalar.cpp \ + blsct/keys.cpp \ chain.cpp \ chainparamsbase.cpp \ chainparams.cpp \ diff --git a/src/Makefile.test.include b/src/Makefile.test.include index 629d068f85345..cb12e5f3bfb9e 100644 --- a/src/Makefile.test.include +++ b/src/Makefile.test.include @@ -84,6 +84,7 @@ BITCOIN_TESTS =\ test/blsct/arith/g1point_tests.cpp \ test/blsct/arith/scalar_tests.cpp \ test/blsct/arith/bls_arith_integration_tests.cpp \ + test/blsct/keys_tests.cpp \ test/bswap_tests.cpp \ test/checkqueue_tests.cpp \ test/coins_tests.cpp \ diff --git a/src/Makefile.test_util.include b/src/Makefile.test_util.include index 363c5820a36e3..7d4960acb7eb8 100644 --- a/src/Makefile.test_util.include +++ b/src/Makefile.test_util.include @@ -12,6 +12,7 @@ TEST_UTIL_H = \ blsct/arith/g1point.h \ blsct/arith/mcl_initializer.h \ blsct/arith/scalar.h \ + blsct/keys.h \ test/util/chainstate.h \ test/util/logging.h \ test/util/mining.h \ @@ -30,6 +31,7 @@ libtest_util_a_SOURCES = \ blsct/arith/g1point.cpp \ blsct/arith/mcl_initializer.cpp \ blsct/arith/scalar.cpp \ + blsct/keys.cpp \ test/util/blockfilter.cpp \ test/util/logging.cpp \ test/util/mining.cpp \ diff --git a/src/blsct/arith/g1point.cpp b/src/blsct/arith/g1point.cpp index 23445c09d6718..1ff1a4747b4ba 100644 --- a/src/blsct/arith/g1point.cpp +++ b/src/blsct/arith/g1point.cpp @@ -161,6 +161,11 @@ G1Point G1Point::Rand() return g * Scalar::Rand(); } +bool G1Point::IsValid() const +{ + return mclBnG1_isValid(&m_p) == 1; +} + bool G1Point::IsUnity() const { return mclBnG1_isZero(&m_p); diff --git a/src/blsct/arith/g1point.h b/src/blsct/arith/g1point.h index f70d159cc0282..27a822e00f408 100644 --- a/src/blsct/arith/g1point.h +++ b/src/blsct/arith/g1point.h @@ -60,6 +60,7 @@ class G1Point bool operator==(const G1Point& b) const; bool operator!=(const G1Point& b) const; + bool IsValid() const; bool IsUnity() const; std::vector GetVch() const; diff --git a/src/blsct/arith/scalar.cpp b/src/blsct/arith/scalar.cpp index 6680fd73e48f9..7606b1ffd90b2 100644 --- a/src/blsct/arith/scalar.cpp +++ b/src/blsct/arith/scalar.cpp @@ -174,6 +174,11 @@ bool Scalar::operator!=(const Scalar &b) const return !operator==(b); } +bool Scalar::IsValid() const +{ + return mclBnFr_isValid(&m_fr) == 1; +} + Scalar Scalar::Invert() const { if (mclBnFr_isZero(&m_fr) == 1) { diff --git a/src/blsct/arith/scalar.h b/src/blsct/arith/scalar.h index d9fa01dbdb4bd..06d300f89cbc1 100644 --- a/src/blsct/arith/scalar.h +++ b/src/blsct/arith/scalar.h @@ -57,6 +57,8 @@ class Scalar { bool operator!=(const Scalar& b) const; bool operator!=(const int& b) const; + bool IsValid() const; + Scalar Invert() const; Scalar Negate() const; Scalar Square() const; diff --git a/src/blsct/keys.cpp b/src/blsct/keys.cpp new file mode 100644 index 0000000000000..782358c147b5b --- /dev/null +++ b/src/blsct/keys.cpp @@ -0,0 +1,163 @@ +// Copyright (c) 2022 The Navcoin developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include + +namespace blsct { + +PublicKey PublicKey::Aggregate(std::vector vPk) +{ + auto retPoint = G1Point(); + bool isZero = true; + + for (auto& pk : vPk) { + G1Point pkG1; + + bool success = pk.GetG1Point(pkG1); + if (!success) + throw std::runtime_error(strprintf("%s: Vector of public keys has an invalid element", __func__)); + + retPoint = isZero ? pkG1 : retPoint + pkG1; + isZero = false; + } + + return PublicKey(retPoint); +} + +uint256 PublicKey::GetHash() const +{ + CHashWriter ss(SER_GETHASH, 0); + ss << data; + return ss.GetHash(); +} + +CKeyID PublicKey::GetID() const +{ + return CKeyID(Hash160(data)); +} + +bool PublicKey::GetG1Point(G1Point& ret) const +{ + try { + ret = G1Point(data); + } catch (...) { + return false; + } + return true; +} + +std::string PublicKey::ToString() const +{ + return HexStr(GetVch()); +}; + +bool PublicKey::operator==(const PublicKey& rhs) const +{ + return GetVch() == rhs.GetVch(); +} + +bool PublicKey::IsValid() const +{ + if (data.size() == 0) return false; + + G1Point g1; + + if (!GetG1Point(g1)) return false; + + return g1.IsValid(); +} + +std::vector PublicKey::GetVch() const +{ + return data; +} + +CKeyID DoublePublicKey::GetID() const +{ + return CKeyID(Hash160(GetVch())); +} + +bool DoublePublicKey::GetViewKey(G1Point& ret) const +{ + try { + ret = G1Point(vk.GetVch()); + } catch (...) { + return false; + } + + return true; +} + +bool DoublePublicKey::GetSpendKey(G1Point& ret) const +{ + try { + ret = G1Point(sk.GetVch()); + } catch (...) { + return false; + } + + return true; +} + +bool DoublePublicKey::operator==(const DoublePublicKey& rhs) const +{ + return vk == rhs.vk && sk == rhs.sk; +} + +bool DoublePublicKey::IsValid() const +{ + return vk.IsValid() && sk.IsValid(); +} + +std::vector DoublePublicKey::GetVkVch() const +{ + return vk.GetVch(); +} + +std::vector DoublePublicKey::GetSkVch() const +{ + return sk.GetVch(); +} + +std::vector DoublePublicKey::GetVch() const +{ + auto ret = vk.GetVch(); + auto toAppend = sk.GetVch(); + + ret.insert(ret.end(), toAppend.begin(), toAppend.end()); + + return ret; +} + +bool PrivateKey::operator==(const PrivateKey& rhs) const +{ + return k == rhs.k; +} + +G1Point PrivateKey::GetG1Point() const +{ + return G1Point::GetBasePoint() * Scalar(std::vector(k.begin(), k.end())); +} + +PublicKey PrivateKey::GetPublicKey() const +{ + return PublicKey(GetG1Point()); +} + +Scalar PrivateKey::GetScalar() const +{ + return Scalar(std::vector(k.begin(), k.end())); +} + +bool PrivateKey::IsValid() const +{ + if (k.size() == 0) return false; + return GetScalar().IsValid(); +} + +void PrivateKey::SetToZero() +{ + k.clear(); +} +} // namespace blsct diff --git a/src/blsct/keys.h b/src/blsct/keys.h new file mode 100644 index 0000000000000..3668765c73ffd --- /dev/null +++ b/src/blsct/keys.h @@ -0,0 +1,122 @@ +// Copyright (c) 2022 The Navcoin developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef KEY_H +#define KEY_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace blsct { +static const std::string subAddressHeader = "SubAddress\0"; + +class PublicKey +{ +private: + std::vector data; + +public: + static constexpr size_t SIZE = 48; + + PublicKey() { data.clear(); } + PublicKey(const G1Point& pk) : data(pk.GetVch()) {} + PublicKey(const std::vector& pk) : data(pk) {} + + SERIALIZE_METHODS(PublicKey, obj) { READWRITE(obj.data); } + + static PublicKey Aggregate(std::vector vPk); + + uint256 GetHash() const; + CKeyID GetID() const; + + std::string ToString() const; + + bool operator==(const PublicKey& rhs) const; + + bool IsValid() const; + + bool GetG1Point(G1Point& ret) const; + std::vector GetVch() const; +}; + +class DoublePublicKey +{ +private: + PublicKey vk; + PublicKey sk; + +public: + static constexpr size_t SIZE = 48 * 2; + + DoublePublicKey() {} + DoublePublicKey(const G1Point& vk_, const G1Point& sk_) : vk(vk_.GetVch()), sk(sk_.GetVch()) {} + DoublePublicKey(const std::vector& vk_, const std::vector& sk_) : vk(vk_), sk(sk_) {} + + SERIALIZE_METHODS(DoublePublicKey, obj) { READWRITE(obj.vk.GetVch(), obj.sk.GetVch()); } + + uint256 GetHash() const; + CKeyID GetID() const; + + bool GetViewKey(G1Point& ret) const; + bool GetSpendKey(G1Point& ret) const; + + bool operator==(const DoublePublicKey& rhs) const; + + bool IsValid() const; + + std::vector GetVkVch() const; + std::vector GetSkVch() const; + std::vector GetVch() const; +}; + +class PrivateKey +{ +private: + CPrivKey k; + +public: + static constexpr size_t SIZE = 32; + + PrivateKey() { k.clear(); } + + PrivateKey(Scalar k_) + { + k.resize(PrivateKey::SIZE); + std::vector v = k_.GetVch(); + memcpy(k.data(), &v.front(), k.size()); + } + + PrivateKey(CPrivKey k_) + { + k.resize(PrivateKey::SIZE); + memcpy(k.data(), &k_.front(), k.size()); + } + + SERIALIZE_METHODS(PrivateKey, obj) { READWRITE(std::vector(obj.k.begin(), obj.k.end())); } + + bool operator==(const PrivateKey& rhs) const; + + G1Point GetG1Point() const; + PublicKey GetPublicKey() const; + Scalar GetScalar() const; + + bool IsValid() const; + + void SetToZero(); + + friend class CCryptoKeyStore; + friend class CBasicKeyStore; +}; + +} // namespace blsct + +#endif // KEY_H diff --git a/src/test/blsct/keys_tests.cpp b/src/test/blsct/keys_tests.cpp new file mode 100644 index 0000000000000..f6b76d5282a1c --- /dev/null +++ b/src/test/blsct/keys_tests.cpp @@ -0,0 +1,130 @@ +// Copyright (c) 2022 The Navcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. +// +#include + +#include +#include + +BOOST_FIXTURE_TEST_SUITE(keys_tests, MclTestingSetup) + +BOOST_AUTO_TEST_CASE(blsct_keys) +{ + // Single Public Key + G1Point generator = G1Point::GetBasePoint(); + + blsct::PublicKey invalidKey; + BOOST_CHECK(!invalidKey.IsValid()); + + blsct::PublicKey keyFromVch(generator.GetVch()); + BOOST_CHECK(keyFromVch.IsValid()); + BOOST_CHECK(generator.GetVch() == keyFromVch.GetVch()); + BOOST_CHECK(keyFromVch.ToString() == + "97f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac58" + "6c55e83ff97a1aeffb3af00adb22c6bb"); + + blsct::PublicKey keyFromPoint(generator); + BOOST_CHECK(keyFromPoint.IsValid()); + BOOST_CHECK(generator.GetVch() == keyFromPoint.GetVch()); + + G1Point point(generator.GetVch()); + G1Point keyPointFromPoint; + G1Point keyPointFromVector; + + bool ret = keyFromVch.GetG1Point(keyPointFromVector); + BOOST_CHECK(ret == true); + + ret = keyFromPoint.GetG1Point(keyPointFromPoint); + BOOST_CHECK(ret == true); + + BOOST_CHECK(point == keyPointFromVector); + BOOST_CHECK(point == keyPointFromPoint); + + G1Point randomPoint = G1Point::Rand(); + + blsct::PublicKey keyFromVchRandom(randomPoint.GetVch()); + BOOST_CHECK(randomPoint.GetVch() == keyFromVchRandom.GetVch()); + + blsct::PublicKey keyFromPointRandom(randomPoint); + BOOST_CHECK(randomPoint.GetVch() == keyFromPointRandom.GetVch()); + + G1Point pointR(randomPoint.GetVch()); + G1Point keyPointFromPointRandom; + G1Point keyPointFromVectorRandom; + + ret = keyFromVchRandom.GetG1Point(keyPointFromVectorRandom); + BOOST_CHECK(ret == true); + + ret = keyFromPointRandom.GetG1Point(keyPointFromPointRandom); + BOOST_CHECK(ret == true); + + BOOST_CHECK(pointR == keyPointFromVectorRandom); + BOOST_CHECK(pointR == keyPointFromPointRandom); + + // Double Public Key + blsct::DoublePublicKey invalidDoublePublicKey; + BOOST_CHECK(!invalidDoublePublicKey.IsValid()); + + blsct::DoublePublicKey doubleKeyFromPoints(generator, pointR); + BOOST_CHECK(doubleKeyFromPoints.IsValid()); + + blsct::DoublePublicKey doubleKeyFromVectors(generator.GetVch(), + pointR.GetVch()); + BOOST_CHECK(doubleKeyFromVectors.IsValid()); + + std::vector serializedDoubleKey = doubleKeyFromPoints.GetVch(); + std::vector serializedViewKey(serializedDoubleKey.begin(), serializedDoubleKey.begin() + blsct::PublicKey::SIZE); + std::vector serializedSpendKey(serializedDoubleKey.begin() + blsct::PublicKey::SIZE, serializedDoubleKey.end()); + BOOST_CHECK(serializedViewKey == generator.GetVch()); + BOOST_CHECK(serializedSpendKey == pointR.GetVch()); + + G1Point viewKey; + + ret = doubleKeyFromPoints.GetViewKey(viewKey); + BOOST_CHECK(ret == true); + BOOST_CHECK(viewKey == generator); + + G1Point spendKey; + + ret = doubleKeyFromPoints.GetSpendKey(spendKey); + BOOST_CHECK(ret == true); + BOOST_CHECK(spendKey == pointR); + + ret = doubleKeyFromVectors.GetViewKey(viewKey); + BOOST_CHECK(ret == true); + BOOST_CHECK(viewKey == generator); + + ret = doubleKeyFromVectors.GetSpendKey(spendKey); + BOOST_CHECK(ret == true); + BOOST_CHECK(spendKey == pointR); + + // Private Key + blsct::PrivateKey invalidPrivateKey; + BOOST_CHECK(!invalidPrivateKey.IsValid()); + + std::vector vectorKey = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 1, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31}; + + blsct::PrivateKey privateKeyFromVector(vectorKey); + BOOST_CHECK(privateKeyFromVector.IsValid()); + BOOST_CHECK(privateKeyFromVector.GetScalar().GetVch() == vectorKey); + + Scalar scalarFromVector(vectorKey); + blsct::PrivateKey privateKeyFromScalar(scalarFromVector); + BOOST_CHECK(privateKeyFromScalar.IsValid()); + BOOST_CHECK(privateKeyFromScalar.GetScalar().GetVch() == vectorKey); + + // G(a+b) == Ga + Gb + blsct::PrivateKey privateKeyFromAddition(privateKeyFromScalar.GetScalar() + + privateKeyFromVector.GetScalar()); + blsct::PublicKey publicKeyFromAddition(privateKeyFromScalar.GetG1Point() + + privateKeyFromVector.GetG1Point()); + BOOST_CHECK(privateKeyFromAddition.GetPublicKey() == publicKeyFromAddition); + + std::vector vecKeys = {privateKeyFromScalar.GetPublicKey(), privateKeyFromVector.GetPublicKey()}; + BOOST_CHECK(blsct::PublicKey::Aggregate(vecKeys) == publicKeyFromAddition); +} + +BOOST_AUTO_TEST_SUITE_END()