Skip to content

Commit

Permalink
Merge remote-tracking branch 'navcoin/master' into btc-master
Browse files Browse the repository at this point in the history
 Conflicts:
	src/key_io.cpp
	src/key_io.h
  • Loading branch information
mxaddict committed Dec 23, 2023
2 parents 96d08c5 + 5dfde9b commit 3013822
Showing 12 changed files with 207 additions and 69 deletions.
20 changes: 7 additions & 13 deletions src/bech32_mod.cpp
Original file line number Diff line number Diff line change
@@ -3,13 +3,15 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <blsct/double_public_key.h>
#include <bech32_mod.h>
#include <util/vector.h>

#include <array>
#include <assert.h>
#include <numeric>
#include <optional>
#include <stdexcept>

namespace bech32_mod
{
@@ -191,6 +193,9 @@ data CreateChecksum(Encoding encoding, const std::string& hrp, const data& value

/** Encode a Bech32 or Bech32m string. */
std::string Encode(Encoding encoding, const std::string& hrp, const data& values) {
if (values.size() != DOUBLE_PUBKEY_DATA_ENC_SIZE) {
throw std::runtime_error("Expected values to be a double public key");
}
// First ensure that the HRP is all lowercase. BIP-173 and BIP350 require an encoder
// to return a lowercase Bech32/Bech32m string, but if given an uppercase HRP, the
// result will always be invalid.
@@ -205,24 +210,13 @@ std::string Encode(Encoding encoding, const std::string& hrp, const data& values
return ret;
}

/** Decode a Bech32 or Bech32m string. */
/** Decode a Bech32 or Bech32m string. Expects
* str to be a valid encoding of DoublePublicKey */
DecodeResult Decode(const std::string& str) {
std::vector<int> errors;
if (!CheckCharacters(str, errors)) return {};
size_t pos = str.rfind('1');

// double public key bech32 string is 165-byte long and consists of:
// - 2-byte hrp
// - 1-byte separator '1'
// - 154-byte key data (96 bytes / 5 bits = 153.6)
// - 8-byte checksum
if (str.size() != 165 // double public key should be encoded to 165-byte bech32 string
|| pos == str.npos // separator '1' should be included
|| pos == 0 // hrp part should not be empty
|| pos + 9 > str.size() // data part should not be empty
) {
return {};
}
data values(str.size() - 1 - pos);
for (size_t i = 0; i < str.size() - 1 - pos; ++i) {
unsigned char c = str[i + pos + 1];
5 changes: 5 additions & 0 deletions src/bech32_mod.h
Original file line number Diff line number Diff line change
@@ -14,6 +14,8 @@
#ifndef BITCOIN_BECH32_MOD_H
#define BITCOIN_BECH32_MOD_H

#include <chainparams.h>
#include <optional>
#include <stdint.h>
#include <string>
#include <vector>
@@ -45,6 +47,9 @@ struct DecodeResult
/** Decode a Bech32 or Bech32m string. */
DecodeResult Decode(const std::string& str);

// 96 bytes / 5 bits = 153.6 -> 154 bytes
constexpr size_t DOUBLE_PUBKEY_DATA_ENC_SIZE = 154;

} // namespace bech32_mod

#endif // BITCOIN_BECH32_MOD_H
4 changes: 1 addition & 3 deletions src/blsct/arith/mcl/mcl_g1point.cpp
Original file line number Diff line number Diff line change
@@ -185,9 +185,7 @@ std::vector<uint8_t> MclG1Point::GetVch() const
bool MclG1Point::SetVch(const std::vector<uint8_t>& b)
{
if (mclBnG1_deserialize(&m_point, &b[0], b.size()) == 0) {
mclBnG1 x;
mclBnG1_clear(&x);
m_point = x;
mclBnG1_clear(&m_point);
return false;
}
return true;
18 changes: 13 additions & 5 deletions src/blsct/double_public_key.cpp
Original file line number Diff line number Diff line change
@@ -3,18 +3,26 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <blsct/double_public_key.h>
#include <blsct/arith/mcl/mcl.h>

namespace blsct {

DoublePublicKey::DoublePublicKey(const std::vector<unsigned char>& keys)
{
if (keys.size() != SIZE) return;
std::vector<unsigned char> vkData(SIZE / 2);
std::vector<unsigned char> skData(SIZE / 2);
std::copy(keys.begin(), keys.begin() + SIZE / 2, vkData.begin());
std::copy(keys.begin() + SIZE / 2, keys.end(), skData.begin());

std::vector<unsigned char> vkData(blsct::PublicKey::SIZE);
std::vector<unsigned char> skData(blsct::PublicKey::SIZE);
std::copy(keys.begin(), keys.begin() + blsct::PublicKey::SIZE, vkData.begin());
std::copy(keys.begin() + blsct::PublicKey::SIZE, keys.end(), skData.begin());

// check vkData and skData are valid serialization of points
MclG1Point p;
if (!p.SetVch(vkData) || !p.SetVch(skData)) return;

vk = vkData;
sk = skData;
is_fully_built = true;
}

CKeyID DoublePublicKey::GetID() const
@@ -69,7 +77,7 @@ bool DoublePublicKey::operator<(const DoublePublicKey& rhs) const

bool DoublePublicKey::IsValid() const
{
return vk.IsValid() && sk.IsValid();
return is_fully_built && vk.IsValid() && sk.IsValid();
}

std::vector<unsigned char> DoublePublicKey::GetVkVch() const
17 changes: 12 additions & 5 deletions src/blsct/double_public_key.h
Original file line number Diff line number Diff line change
@@ -19,14 +19,21 @@ class DoublePublicKey

PublicKey vk;
PublicKey sk;
bool is_fully_built = false;

public:
static constexpr size_t SIZE = 48 * 2;
static constexpr size_t SIZE = blsct::PublicKey::SIZE * 2;

DoublePublicKey() : is_fully_built(true) {}
DoublePublicKey(const PublicKey& vk_, const PublicKey& sk_) : vk(vk_), sk(sk_), is_fully_built(true) {}
DoublePublicKey(const Point& vk_, const Point& sk_) : vk(vk_), sk(sk_), is_fully_built(true) {}

DoublePublicKey(const std::vector<unsigned char>& vk_, const std::vector<unsigned char>& sk_) : vk(vk_), sk(sk_)
{
MclG1Point p;
is_fully_built = p.SetVch(vk_) && p.SetVch(sk_);
}

DoublePublicKey() {}
DoublePublicKey(const PublicKey& vk_, const PublicKey& sk_) : vk(vk_), sk(sk_) {}
DoublePublicKey(const Point& vk_, const Point& sk_) : vk(vk_), sk(sk_) {}
DoublePublicKey(const std::vector<unsigned char>& vk_, const std::vector<unsigned char>& sk_) : vk(vk_), sk(sk_) {}
DoublePublicKey(const std::vector<unsigned char>& keys);

SERIALIZE_METHODS(DoublePublicKey, obj) { READWRITE(obj.vk, obj.sk); }
8 changes: 4 additions & 4 deletions src/kernel/chainparams.cpp
Original file line number Diff line number Diff line change
@@ -142,13 +142,13 @@ class CMainParams : public CChainParams {
vSeeds.emplace_back("seed.bitcoin.wiz.biz."); // Jason Maurice

base58Prefixes[PUBKEY_ADDRESS] = std::vector<unsigned char>(1,0);
base58Prefixes[BLSCT_ADDRESS] = {73,33};
base58Prefixes[SCRIPT_ADDRESS] = std::vector<unsigned char>(1,5);
base58Prefixes[SECRET_KEY] = std::vector<unsigned char>(1,128);
base58Prefixes[EXT_PUBLIC_KEY] = {0x04, 0x88, 0xB2, 0x1E};
base58Prefixes[EXT_SECRET_KEY] = {0x04, 0x88, 0xAD, 0xE4};

bech32_hrp = "bc";
bech32_mod_hrp = "nv";

vFixedSeeds = std::vector<uint8_t>(std::begin(chainparams_seed_main), std::end(chainparams_seed_main));

@@ -249,13 +249,13 @@ class CTestNetParams : public CChainParams {
vSeeds.emplace_back("testnet-seed.bluematt.me."); // Just a static list of stable node(s), only supports x9

base58Prefixes[PUBKEY_ADDRESS] = std::vector<unsigned char>(1,111);
base58Prefixes[BLSCT_ADDRESS] = {73,33};
base58Prefixes[SCRIPT_ADDRESS] = std::vector<unsigned char>(1,196);
base58Prefixes[SECRET_KEY] = std::vector<unsigned char>(1,239);
base58Prefixes[EXT_PUBLIC_KEY] = {0x04, 0x35, 0x87, 0xCF};
base58Prefixes[EXT_SECRET_KEY] = {0x04, 0x35, 0x83, 0x94};

bech32_hrp = "tb";
bech32_mod_hrp = "tn";

vFixedSeeds = std::vector<uint8_t>(std::begin(chainparams_seed_test), std::end(chainparams_seed_test));

@@ -387,13 +387,13 @@ class SigNetParams : public CChainParams {
};

base58Prefixes[PUBKEY_ADDRESS] = std::vector<unsigned char>(1,111);
base58Prefixes[BLSCT_ADDRESS] = {73,33};
base58Prefixes[SCRIPT_ADDRESS] = std::vector<unsigned char>(1,196);
base58Prefixes[SECRET_KEY] = std::vector<unsigned char>(1,239);
base58Prefixes[EXT_PUBLIC_KEY] = {0x04, 0x35, 0x87, 0xCF};
base58Prefixes[EXT_SECRET_KEY] = {0x04, 0x35, 0x83, 0x94};

bech32_hrp = "tb";
bech32_mod_hrp = "tn";

fDefaultConsistencyChecks = false;
m_is_mockable_chain = false;
@@ -517,13 +517,13 @@ class CRegTestParams : public CChainParams
};

base58Prefixes[PUBKEY_ADDRESS] = std::vector<unsigned char>(1,111);
base58Prefixes[BLSCT_ADDRESS] = {73,33};
base58Prefixes[SCRIPT_ADDRESS] = std::vector<unsigned char>(1,196);
base58Prefixes[SECRET_KEY] = std::vector<unsigned char>(1,239);
base58Prefixes[EXT_PUBLIC_KEY] = {0x04, 0x35, 0x87, 0xCF};
base58Prefixes[EXT_SECRET_KEY] = {0x04, 0x35, 0x83, 0x94};

bech32_hrp = "bcrt";
bech32_mod_hrp = "tn";
}
};

3 changes: 2 additions & 1 deletion src/kernel/chainparams.h
Original file line number Diff line number Diff line change
@@ -86,7 +86,6 @@ class CChainParams
SECRET_KEY,
EXT_PUBLIC_KEY,
EXT_SECRET_KEY,
BLSCT_ADDRESS,

MAX_BASE58_TYPES
};
@@ -117,6 +116,7 @@ class CChainParams
const std::vector<std::string>& DNSSeeds() const { return vSeeds; }
const std::vector<unsigned char>& Base58Prefix(Base58Type type) const { return base58Prefixes[type]; }
const std::string& Bech32HRP() const { return bech32_hrp; }
const std::string& Bech32ModHRP() const { return bech32_mod_hrp; }
const std::vector<uint8_t>& FixedSeeds() const { return vFixedSeeds; }
const CCheckpointData& Checkpoints() const { return checkpointData; }

@@ -174,6 +174,7 @@ class CChainParams
std::vector<std::string> vSeeds;
std::vector<unsigned char> base58Prefixes[MAX_BASE58_TYPES];
std::string bech32_hrp;
std::string bech32_mod_hrp;
ChainType m_chain_type;
CBlock genesis;
std::vector<uint8_t> vFixedSeeds;
90 changes: 71 additions & 19 deletions src/key_io.cpp
Original file line number Diff line number Diff line change
@@ -2,10 +2,13 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <key_io.h>

#include <base58.h>
#include <bech32.h>
#include <bech32_mod.h>
#include <blsct/arith/mcl/mcl.h>
#include <blsct/double_public_key.h>
#include <key_io.h>
#include <net.h>
#include <script/interpreter.h>
#include <script/solver.h>
#include <tinyformat.h>
@@ -29,12 +32,11 @@ class DestinationEncoder

std::string operator()(const blsct::DoublePublicKey& id) const
{
std::vector<unsigned char> data = m_params.Base58Prefix(CChainParams::BLSCT_ADDRESS);
auto vchView = id.GetVkVch();
auto vchSpend = id.GetSkVch();
data.insert(data.end(), vchView.begin(), vchView.end());
data.insert(data.end(), vchSpend.begin(), vchSpend.end());
return EncodeBase58Check(data);
return EncodeDoublePublicKey(
m_params,
bech32_mod::Encoding::BECH32M,
id
);
}

std::string operator()(const PKHash& id) const
@@ -93,6 +95,16 @@ class DestinationEncoder

CTxDestination DecodeDestination(const std::string& str, const CChainParams& params, std::string& error_str, std::vector<int>* error_locations)
{
// first try to decode str to a double public key
auto maybe_dpk = DecodeDoublePublicKey(params, str);
if (maybe_dpk) {
auto dpk = maybe_dpk.value();
if (dpk.IsValid()) {
return CTxDestination(dpk);
}
// if invalid, try other types of destinations
}

std::vector<unsigned char> data;
uint160 hash;
error_str = "";
@@ -128,17 +140,7 @@ CTxDestination DecodeDestination(const std::string& str, const CChainParams& par
}
return CNoDestination();
} else if (!is_bech32) {
// Try Base58 decoding without the checksum, using a much larger max length
if (DecodeBase58Check(str, data, 100)) {
// base58-encoded BLSCT addresses.
const std::vector<unsigned char>& blsct_prefix = params.Base58Prefix(CChainParams::BLSCT_ADDRESS);
std::vector<unsigned char> blsctKeysData;
blsctKeysData.resize(2*blsct::PublicKey::SIZE);
if (data.size() == blsctKeysData.size() + blsct_prefix.size() && std::equal(blsct_prefix.begin(), blsct_prefix.end(), data.begin())) {
std::copy(data.begin() + blsct_prefix.size(), data.end(), blsctKeysData.begin());
return blsct::DoublePublicKey(blsctKeysData);
}
} if (!DecodeBase58(str, data, 100)) {
if (!DecodeBase58(str, data, 100)) {
error_str = "Invalid or unsupported Segwit (Bech32) or Base58 encoding.";
} else {
error_str = "Invalid checksum or length of Base58 address (P2PKH or P2SH)";
@@ -329,3 +331,53 @@ bool IsValidDestinationString(const std::string& str)
{
return IsValidDestinationString(str, Params());
}

std::string EncodeDoublePublicKey(
const CChainParams& params,
const bech32_mod::Encoding encoding,
const blsct::DoublePublicKey& dpk
) {
std::vector<uint8_t> dpk_v8 = dpk.GetVch();
std::vector<uint8_t> dpk_v5;
dpk_v5.reserve(DOUBLE_PUBKEY_ENC_SIZE);

// ignoring the return value since this conversion always succeeds
ConvertBits<8, 5, true>([&](uint8_t c) { dpk_v5.push_back(c); }, dpk_v8.begin(), dpk_v8.end());

return Encode(encoding, params.Bech32ModHRP(), dpk_v5);
}

std::optional<blsct::DoublePublicKey> DecodeDoublePublicKey(
const CChainParams& params,
const std::string& str
) {
const auto hrp = ToLower(str.substr(0, params.Bech32ModHRP().size()));

// str needs to be of the expected length and have the expected hrp
if (str.size() != DOUBLE_PUBKEY_ENC_SIZE
|| hrp != params.Bech32ModHRP()
|| str[params.Bech32ModHRP().size()] != '1'
) return std::nullopt;

// decode to 5-bit based byte vector
const auto dec = bech32_mod::Decode(str);

// check if it has expected encoding and the data is of the expected length
if ((dec.encoding != bech32_mod::Encoding::BECH32 && dec.encoding != bech32_mod::Encoding::BECH32M)
|| dec.data.size() != 154
) return std::nullopt;

// The data part consists of two concatenated 48-byte public keys
std::vector<uint8_t> data;
data.reserve(blsct::DoublePublicKey::SIZE);
if (!ConvertBits<5, 8, false>([&](unsigned char c) { data.push_back(c); }, dec.data.begin(), dec.data.end())) {
return std::nullopt;
}

blsct::DoublePublicKey dpk(data);
if (dpk.IsValid()) {
return dpk;
} else {
return std::nullopt;
}
}
21 changes: 21 additions & 0 deletions src/key_io.h
Original file line number Diff line number Diff line change
@@ -7,6 +7,7 @@
#define BITCOIN_KEY_IO_H

#include <addresstype.h>
#include <bech32_mod.h>
#include <blsct/double_public_key.h>
#include <chainparams.h>
#include <key.h>
@@ -28,4 +29,24 @@ CTxDestination DecodeDestination(const std::string& str, std::string& error_msg,
bool IsValidDestinationString(const std::string& str);
bool IsValidDestinationString(const std::string& str, const CChainParams& params);

// double public key after encoding to bech32_mod is 165-byte long consisting of:
// - 2-byte hrp
// - 1-byte separator '1'
// - 154-byte data
// - 8-byte checksum
constexpr size_t DOUBLE_PUBKEY_ENC_SIZE = 2 + 1 + bech32_mod::DOUBLE_PUBKEY_DATA_ENC_SIZE + 8;

/** Encode DoublePublicKey to Bech32 or Bech32m string. Encoding must be one of BECH32 or BECH32M. */
std::string EncodeDoublePublicKey(
const CChainParams& params,
const bech32_mod::Encoding encoding,
const blsct::DoublePublicKey& dpk
);

/** Decode a Bech32 or Bech32m string to a DoublePublicKey. */
std::optional<blsct::DoublePublicKey> DecodeDoublePublicKey(
const CChainParams& params,
const std::string& str
);

#endif // BITCOIN_KEY_IO_H
Loading

0 comments on commit 3013822

Please sign in to comment.